multi_git 0.0.1.alpha1 → 0.0.1.alpha2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -23,6 +23,29 @@ module MultiGit
23
23
  e.with_parent(self) if e
24
24
  end
25
25
 
26
+ # @visibility private
27
+ def walk_pre(&block)
28
+ descend = block.call(self)
29
+ return if descend == false
30
+ each do |child|
31
+ child.walk(:pre, &block)
32
+ end
33
+ end
34
+
35
+ # @visibility private
36
+ def walk_post(&block)
37
+ each do |child|
38
+ child.walk(:post, &block)
39
+ end
40
+ block.call(self)
41
+ end
42
+
43
+ # @visibility private
44
+ def walk_leaves(&block)
45
+ each do |child|
46
+ child.walk(:leaves,&block)
47
+ end
48
+ end
26
49
  end
27
50
 
28
51
  class Builder < TreeEntry::Builder
@@ -36,6 +36,10 @@ module MultiGit
36
36
  class BadRevisionSyntax < InvalidReference
37
37
  end
38
38
 
39
+ class InvalidReferenceName < ArgumentError
40
+ include Error
41
+ end
42
+
39
43
  class WrongTypeForMode < Exception
40
44
  include Error
41
45
 
@@ -121,10 +121,46 @@ module MultiGit::GitBackend
121
121
  end
122
122
  end
123
123
 
124
+ # {include:MultiGit::Repository#ref}
125
+ # @param (see MultiGit::Repository#ref)
126
+ # @raise (see MultiGit::Repository#ref)
127
+ # @return (see MultiGit::Repository#ref)
124
128
  def ref(name)
129
+ validate_ref_name(name)
125
130
  MultiGit::GitBackend::Ref.new(self, name)
126
131
  end
127
132
 
133
+ private
134
+ TRUE_LAMBDA = proc{ true }
135
+ public
136
+
137
+ def each_branch(filter = :all)
138
+ return to_enum(:each_branch, filter) unless block_given?
139
+ which = case filter
140
+ when :all, Regexp then [:a]
141
+ when :local then []
142
+ when :remote then [:r]
143
+ end
144
+ post_filter = TRUE_LAMBDA
145
+ if filter.kind_of? Regexp
146
+ post_filter = filter
147
+ end
148
+ @git['branch', *which].each_line do |line|
149
+ name = line[2..-2]
150
+ next unless post_filter === name
151
+ yield branch(name)
152
+ end
153
+ return self
154
+ end
155
+
156
+ def each_tag
157
+ return to_enum(:each_tag) unless block_given?
158
+ @git['tag'].each_line do |line|
159
+ yield tag(line.chomp)
160
+ end
161
+ return self
162
+ end
163
+
128
164
  # @visibility private
129
165
  MKTREE_FORMAT = "%06o %s %s\t%s\n"
130
166
 
@@ -83,9 +83,16 @@ module MultiGit
83
83
  end
84
84
  end
85
85
 
86
+ # @visibility private
86
87
  def initialize(repository, name)
88
+ if name.kind_of? Java::OrgEclipseJgitLib::Ref
89
+ ref = name
90
+ name = ref.name
91
+ else
92
+ ref = repository.__backend__.getRef(name)
93
+ end
87
94
  super(repository, name)
88
- @java_ref = repository.__backend__.getRef(name)
95
+ @java_ref = ref
89
96
  end
90
97
 
91
98
  def target
@@ -26,6 +26,7 @@ module MultiGit::JGitBackend
26
26
  }
27
27
 
28
28
  REVERSE_OBJECT_TYPE_IDS = Hash[ OBJECT_TYPE_IDS.map{|k,v| [v,k]} ]
29
+
29
30
  public
30
31
 
31
32
  delegate "bare?" => "@git"
@@ -109,9 +110,46 @@ module MultiGit::JGitBackend
109
110
  # @raise (see MultiGit::Repository#ref)
110
111
  # @return (see MultiGit::Repository#ref)
111
112
  def ref(name)
113
+ validate_ref_name(name)
112
114
  Ref.new(self, name)
113
115
  end
114
116
 
117
+ private
118
+ ALL_FILTER = %r{\Arefs/(?:heads|remotes)}
119
+ LOCAL_FILTER = %r{\Arefs/heads}
120
+ REMOTE_FILTER = %r{\Arefs/remotes}
121
+ public
122
+
123
+ def each_branch(filter = :all)
124
+ return to_enum(:each_branch, filter) unless block_given?
125
+ prefix = case filter
126
+ when :all, Regexp then 'refs/'
127
+ when :local then Java::OrgEclipseJgitLib::Constants::R_HEADS
128
+ when :remote then Java::OrgEclipseJgitLib::Constants::R_REMOTES
129
+ end
130
+ refs = @git.ref_database.get_refs(prefix)
131
+ if filter.kind_of? Regexp
132
+ refs.each do |name, ref|
133
+ next unless filter === name[(name.index('/')+1)..-1]
134
+ yield Ref.new(self, ref)
135
+ end
136
+ else
137
+ refs.each do |name, ref|
138
+ yield Ref.new(self, ref)
139
+ end
140
+ end
141
+ return self
142
+ end
143
+
144
+ def each_tag
145
+ return to_enum(:each_branch, filter) unless block_given?
146
+ refs = @git.ref_database.get_refs('refs/tags')
147
+ refs.each do |name, ref|
148
+ yield Ref.new(self, ref)
149
+ end
150
+ return self
151
+ end
152
+
115
153
  # @visibility private
116
154
  # @api private
117
155
  def make_tree(entries)
data/lib/multi_git/ref.rb CHANGED
@@ -77,6 +77,10 @@ module MultiGit
77
77
 
78
78
  protected
79
79
 
80
+ def ensure_dir!
81
+ FileUtils.mkdir_p(::File.dirname(file_path))
82
+ end
83
+
80
84
  def open_file(exists)
81
85
  mode = ::File::WRONLY | ::File::TRUNC
82
86
  if !exists
@@ -126,6 +130,7 @@ module MultiGit
126
130
 
127
131
  def initialize(*_)
128
132
  super
133
+ ensure_dir!
129
134
  @lock = acquire_lock
130
135
  # safe now
131
136
  @ref = @ref.reload
@@ -159,6 +164,7 @@ module MultiGit
159
164
  class OptimisticFileUpdater < FileUpdater
160
165
 
161
166
  def update(new)
167
+ ensure_dir!
162
168
  begin
163
169
  lock = acquire_lock
164
170
  if ::File.exists?(file_path)
@@ -188,7 +194,7 @@ module MultiGit
188
194
  end
189
195
  return nx
190
196
  ensure
191
- release_lock( lock )
197
+ release_lock( lock ) if lock
192
198
  end
193
199
  end
194
200
 
@@ -84,12 +84,27 @@ public
84
84
  abstract :write
85
85
 
86
86
  # @!method ref(name)
87
- # Opens a reference.
87
+ # Opens a reference. A reference is usually known as branch or tag.
88
+ #
89
+ # @example
90
+ # # setup:
91
+ # dir = `mktemp -d`
92
+ # # example:
93
+ # repo = MultiGit.open(dir, init: true) #=> be_a MultiGit::Repository
94
+ # master_branch = repo.ref('refs/heads/master')
95
+ # head = repo.ref('HEAD')
96
+ # # teardown:
97
+ # `rm -rf #{dir}`
98
+ #
88
99
  # @abstract
89
100
  # @param [String] name
90
101
  # @return [MultiGit::Ref] ref
91
102
  abstract :ref
92
103
 
104
+ # Opens a branch
105
+ #
106
+ # @param name [String] branch name
107
+ # @return [Ref]
93
108
  def branch(name)
94
109
  if name.include? '/'
95
110
  ref('refs/remotes/'+name)
@@ -98,10 +113,36 @@ public
98
113
  end
99
114
  end
100
115
 
116
+ # Opens a tag
117
+ #
118
+ # @param name [String] tag name
119
+ # @return [Ref]
101
120
  def tag(name)
102
121
  ref('refs/tags/'+name)
103
122
  end
104
123
 
124
+ # @method each_branch( filter = :all )
125
+ # Yields either all, local or remote branches. If called
126
+ # with a regular expression it will be used to filter the
127
+ # branches by name.
128
+ #
129
+ # @param filter [:all, :local, :remote, Regexp]
130
+ # @yield branch
131
+ # @yieldparam branch [Ref]
132
+ # @return [Enumerable<Ref>] if called without block
133
+ #
134
+ abstract :each_branch
135
+
136
+
137
+ # @method each_tag
138
+ # Yields all tags.
139
+ #
140
+ # @yield tag
141
+ # @yieldparam tag [Ref]
142
+ # @return [Enumerable<Ref>] if called without block
143
+ #
144
+ abstract :each_tag
145
+
105
146
  # @!parse alias_method :[], :ref
106
147
  def [](name)
107
148
  ref(name)
@@ -183,6 +224,14 @@ protected
183
224
  end
184
225
  end
185
226
 
227
+ VALID_REF = %r{\Arefs/heads/\w+|refs/tags/\w+|refs/remotes/\w+/\w+|[A-Z0-9_]+}
228
+
229
+ def validate_ref_name(name)
230
+ unless VALID_REF =~ name
231
+ raise Error::InvalidReferenceName, name
232
+ end
233
+ end
234
+
186
235
  def validate_type(type)
187
236
  raise Error::InvalidObjectType, type.inspect unless VALID_TYPES.include?(type)
188
237
  end
@@ -7,9 +7,16 @@ module MultiGit
7
7
 
8
8
  include MultiGit::Ref
9
9
 
10
+ # @api private
10
11
  def initialize(repository, name)
12
+ if name.kind_of? Rugged::Reference
13
+ ref = name
14
+ name = ref.name
15
+ else
16
+ ref = Rugged::Reference.lookup(repository.__backend__, name)
17
+ end
11
18
  super(repository, name)
12
- @rugged_ref = Rugged::Reference.lookup(repository.__backend__, name)
19
+ @rugged_ref = ref
13
20
  end
14
21
 
15
22
  def target
@@ -86,8 +86,13 @@ module MultiGit::RuggedBackend
86
86
  return OBJECT_CLASSES[object.type].new(self, oid, object)
87
87
  end
88
88
 
89
- def ref(ref)
90
- Ref.new(self, ref)
89
+ # {include:MultiGit::Repository#ref}
90
+ # @param (see MultiGit::Repository#ref)
91
+ # @raise (see MultiGit::Repository#ref)
92
+ # @return (see MultiGit::Repository#ref)
93
+ def ref(name)
94
+ validate_ref_name(name)
95
+ Ref.new(self, name)
91
96
  end
92
97
 
93
98
  # {include:MultiGit::Repository#parse}
@@ -110,6 +115,33 @@ module MultiGit::RuggedBackend
110
115
  @git.include?(oid)
111
116
  end
112
117
 
118
+ TRUE_LAMBDA = proc{ true }
119
+
120
+ def each_branch(filter = :all)
121
+ return to_enum(:each_branch, filter) unless block_given?
122
+ rugged_filter = nil
123
+ if filter == :local || filter == :remote
124
+ rugged_filter = filter
125
+ end
126
+ post_filter = TRUE_LAMBDA
127
+ if filter.kind_of? Regexp
128
+ post_filter = filter
129
+ end
130
+ Rugged::Branch.each(@git, rugged_filter) do |ref|
131
+ next unless post_filter === ref.name
132
+ yield Ref.new(self, ref)
133
+ end
134
+ return self
135
+ end
136
+
137
+ def each_tag
138
+ return to_enum(:each_branch, filter) unless block_given?
139
+ Rugged::Tag.each(@git) do |name|
140
+ yield tag(name)
141
+ end
142
+ return self
143
+ end
144
+
113
145
  # @api private
114
146
  # @visibility private
115
147
  def __backend__
@@ -1,6 +1,9 @@
1
1
  require 'set'
2
2
  require 'multi_git/tree'
3
3
  require 'multi_git/builder'
4
+ require 'multi_git/file'
5
+ require 'multi_git/executeable'
6
+ require 'multi_git/symlink'
4
7
  module MultiGit
5
8
  class Tree::Builder
6
9
 
@@ -75,6 +78,7 @@ module MultiGit
75
78
  module DSL
76
79
 
77
80
  def set(key, *args, &block)
81
+ options = {}
78
82
  case(args.size)
79
83
  when 0
80
84
  raise ArgumentError, "Expected a value or a block" unless block
@@ -98,7 +102,7 @@ module MultiGit
98
102
  if parts.any?{|p| p == ".." }
99
103
  raise MultiGit::Error::InvalidTraversal, "Traversal to parent directories is currently not supported while setting."
100
104
  end
101
- return traverse_set( self, parts, value, true)
105
+ return traverse_set( self, parts, value, options.fetch(:create,true))
102
106
  end
103
107
 
104
108
  alias []= set
@@ -142,7 +146,11 @@ module MultiGit
142
146
  elsif create == :overwrite || ( entry.nil? && create )
143
147
  entry = MultiGit::Directory::Builder.new(current, part)
144
148
  else
145
- raise MultiGit::Error::InvalidTraversal, "Can't traverse to #{path} from #{self.inspect}: #{current.inspect} doesn't contain an entry named #{part.inspect}" unless entry
149
+ if entry.nil?
150
+ raise MultiGit::Error::InvalidTraversal, "#{current.inspect} doesn't contain an entry named #{part.inspect}"
151
+ else
152
+ raise MultiGit::Error::InvalidTraversal, "#{current.inspect} does contain an entry named #{part.inspect} but it's not a directory. To overwrite files specify create: :overwrite."
153
+ end
146
154
  end
147
155
  end
148
156
  current.entry_set(part, traverse_set(entry, rest, value, create))
@@ -1,4 +1,5 @@
1
1
  require 'multi_git/object'
2
+ require 'multi_git/walkable'
2
3
  require 'forwardable'
3
4
  module MultiGit
4
5
  module Tree
@@ -9,6 +10,7 @@ module MultiGit
9
10
  module Base
10
11
 
11
12
  include Enumerable
13
+ include Walkable
12
14
 
13
15
  def type
14
16
  :tree
@@ -92,6 +94,19 @@ module MultiGit
92
94
  alias / traverse
93
95
  alias [] traverse
94
96
 
97
+ def glob( pattern, flags = 0 )
98
+ return to_enum(:glob, pattern, flags) unless block_given?
99
+ l = path.size
100
+ flags |= ::File::FNM_PATHNAME
101
+ walk_pre do |object|
102
+ if ::File.fnmatch(pattern, object.path[l..-1], flags)
103
+ yield object
104
+ false
105
+ end
106
+ end
107
+ return self
108
+ end
109
+
95
110
  # @yield [MultiGit::TreeEntry]
96
111
  def each
97
112
  return to_enum unless block_given?
@@ -101,6 +116,27 @@ module MultiGit
101
116
  return self
102
117
  end
103
118
 
119
+ # @visibility private
120
+ def walk_pre(&block)
121
+ each do |child|
122
+ child.walk(:pre, &block)
123
+ end
124
+ end
125
+
126
+ # @visibility private
127
+ def walk_post(&block)
128
+ each do |child|
129
+ child.walk(:post, &block)
130
+ end
131
+ end
132
+
133
+ # @visibility private
134
+ def walk_leaves(&block)
135
+ each do |child|
136
+ child.walk(:leaves,&block)
137
+ end
138
+ end
139
+
104
140
  # @return [Integer] number of entries
105
141
  def size
106
142
  entries.size
@@ -125,6 +161,10 @@ module MultiGit
125
161
  ['#<',self.class.name,' ',oid,' repository:', repository.inspect,'>'].join
126
162
  end
127
163
 
164
+ def path
165
+ ''
166
+ end
167
+
128
168
  protected
129
169
  # @return [Hash<String, MultiGit::TreeEntry>]
130
170
  def entries
@@ -1,6 +1,7 @@
1
1
  require 'multi_git/utils'
2
2
  require 'multi_git/object'
3
3
  require 'multi_git/builder'
4
+ require 'multi_git/walkable'
4
5
  module MultiGit
5
6
 
6
7
  base = Class.new
@@ -8,16 +9,18 @@ module MultiGit
8
9
  # @!parse
9
10
  # class TreeEntry < TreeEntry::Base
10
11
  # end
11
- class TreeEntry < base
12
- Base = superclass
13
- end
12
+ TreeEntry = Class.new(base)
14
13
 
15
14
  # A tree entry is like a {MultiGit::Object} or a {MultiGit::Builder} but it
16
15
  # also has knows it's parent tree.
17
16
  class TreeEntry
18
17
 
18
+ Base = superclass
19
+
19
20
  class Base
20
21
 
22
+ include Walkable
23
+
21
24
  # @return [String]
22
25
  attr :name
23
26
  # @return [MultiGit::Tree::Base]
@@ -43,6 +46,16 @@ module MultiGit
43
46
  self.class.new(parent, name, @object)
44
47
  end
45
48
 
49
+ def path
50
+ @path ||= begin
51
+ if parent && parent.path != ''
52
+ [parent.path,SLASH, name].join
53
+ else
54
+ name
55
+ end
56
+ end
57
+ end
58
+
46
59
  end
47
60
 
48
61
  class Builder < Base
@@ -81,6 +94,11 @@ module MultiGit
81
94
  self.class::Builder.new(parent, name, object)
82
95
  end
83
96
 
97
+ def inspect
98
+ ['#<', self.class.name,' ',path,' ', oid, '>'].join
99
+ end
100
+
101
+
84
102
  end
85
103
 
86
104
  end
@@ -1,3 +1,3 @@
1
1
  module MultiGit
2
- VERSION = '0.0.1.alpha1'
2
+ VERSION = '0.0.1.alpha2'
3
3
  end
@@ -0,0 +1,38 @@
1
+ module MultiGit
2
+
3
+ module Walkable
4
+
5
+ # @visibility private
6
+ # @api private
7
+ MODES = [:pre, :post, :leaves]
8
+
9
+ # works like each, but recursive
10
+ #
11
+ # @param mode [:pre, :post, :leaves]
12
+ def walk( mode = :pre, &block )
13
+ raise ArgumentError, "Unknown walk mode #{mode.inspect}. Use either :pre, :post or :leaves" unless MODES.include? mode
14
+ return to_enum(:walk, mode) unless block
15
+ case(mode)
16
+ when :pre then walk_pre(&block)
17
+ when :post then walk_post(&block)
18
+ when :leaves then walk_leaves(&block)
19
+ end
20
+ end
21
+
22
+ protected
23
+
24
+ def walk_pre
25
+ yield self
26
+ end
27
+
28
+ def walk_post
29
+ yield self
30
+ end
31
+
32
+ def walk_leaves
33
+ yield self
34
+ end
35
+
36
+ end
37
+
38
+ end
data/lib/multi_git.rb CHANGED
@@ -13,6 +13,8 @@ private
13
13
  BACKENDS[:rugged, priority: 1] = RuggedBackend
14
14
  BACKENDS[ :jgit, priority: 2] = JGitBackend
15
15
 
16
+ SLASH = '/'.freeze
17
+
16
18
  public
17
19
 
18
20
  extend SingleForwardable
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: multi_git
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.alpha1
4
+ version: 0.0.1.alpha2
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-24 00:00:00.000000000 Z
12
+ date: 2013-05-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -59,7 +59,7 @@ dependencies:
59
59
  - - '>='
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
- description:
62
+ description: multi_git is aimed to be the best git interface for ruby
63
63
  email: hannes.georg@googlemail.com
64
64
  executables: []
65
65
  extensions: []
@@ -107,9 +107,10 @@ files:
107
107
  - lib/multi_git/tree_entry.rb
108
108
  - lib/multi_git/builder.rb
109
109
  - lib/multi_git/directory.rb
110
+ - lib/multi_git/walkable.rb
110
111
  - lib/multi_git/tree/builder.rb
111
112
  - lib/multi_git.rb
112
- homepage: https://github.com/hannesg/ridley-git
113
+ homepage: https://github.com/hannesg/multi_git
113
114
  licenses: []
114
115
  post_install_message:
115
116
  rdoc_options: []
@@ -133,6 +134,6 @@ rubyforge_project:
133
134
  rubygems_version: 1.8.25
134
135
  signing_key:
135
136
  specification_version: 3
136
- summary: Use all the gits
137
+ summary: Use all the git
137
138
  test_files: []
138
139
  has_rdoc: