multi_git 0.0.1.alpha1 → 0.0.1.alpha2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: