multi_git 0.0.1.alpha1
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.
- data/lib/multi_git/backend.rb +100 -0
- data/lib/multi_git/backend_set.rb +42 -0
- data/lib/multi_git/blob.rb +52 -0
- data/lib/multi_git/builder.rb +19 -0
- data/lib/multi_git/commit.rb +185 -0
- data/lib/multi_git/directory.rb +67 -0
- data/lib/multi_git/error.rb +67 -0
- data/lib/multi_git/executeable.rb +12 -0
- data/lib/multi_git/file.rb +35 -0
- data/lib/multi_git/git_backend/blob.rb +11 -0
- data/lib/multi_git/git_backend/cmd.rb +117 -0
- data/lib/multi_git/git_backend/commit.rb +75 -0
- data/lib/multi_git/git_backend/object.rb +34 -0
- data/lib/multi_git/git_backend/ref.rb +36 -0
- data/lib/multi_git/git_backend/repository.rb +162 -0
- data/lib/multi_git/git_backend/tree.rb +22 -0
- data/lib/multi_git/git_backend.rb +19 -0
- data/lib/multi_git/handle.rb +33 -0
- data/lib/multi_git/jgit_backend/blob.rb +10 -0
- data/lib/multi_git/jgit_backend/commit.rb +45 -0
- data/lib/multi_git/jgit_backend/object.rb +48 -0
- data/lib/multi_git/jgit_backend/ref.rb +117 -0
- data/lib/multi_git/jgit_backend/repository.rb +223 -0
- data/lib/multi_git/jgit_backend/rewindeable_io.rb +33 -0
- data/lib/multi_git/jgit_backend/tree.rb +28 -0
- data/lib/multi_git/jgit_backend.rb +15 -0
- data/lib/multi_git/object.rb +59 -0
- data/lib/multi_git/ref.rb +381 -0
- data/lib/multi_git/repository.rb +190 -0
- data/lib/multi_git/rugged_backend/blob.rb +8 -0
- data/lib/multi_git/rugged_backend/commit.rb +38 -0
- data/lib/multi_git/rugged_backend/object.rb +38 -0
- data/lib/multi_git/rugged_backend/ref.rb +32 -0
- data/lib/multi_git/rugged_backend/repository.rb +160 -0
- data/lib/multi_git/rugged_backend/tree.rb +18 -0
- data/lib/multi_git/rugged_backend.rb +16 -0
- data/lib/multi_git/submodule.rb +7 -0
- data/lib/multi_git/symlink.rb +42 -0
- data/lib/multi_git/tree/builder.rb +184 -0
- data/lib/multi_git/tree.rb +144 -0
- data/lib/multi_git/tree_entry.rb +86 -0
- data/lib/multi_git/utils.rb +57 -0
- data/lib/multi_git/version.rb +3 -0
- data/lib/multi_git.rb +44 -0
- metadata +138 -0
@@ -0,0 +1,381 @@
|
|
1
|
+
require 'multi_git/utils'
|
2
|
+
require 'fileutils'
|
3
|
+
module MultiGit
|
4
|
+
|
5
|
+
# A reference is something that points eihter to another reference or to
|
6
|
+
# an {MultiGit::Object}. So the most noteable method of this class is
|
7
|
+
# {#target}.
|
8
|
+
#
|
9
|
+
# Instances of this classe are immuteable and reuseable. All writing methods
|
10
|
+
# return new instances.
|
11
|
+
#
|
12
|
+
# @abstract
|
13
|
+
module Ref
|
14
|
+
|
15
|
+
# Updates a reference. Different subclasses use different mechanisms
|
16
|
+
# for locking and storing the references. Locks may be acquired in the
|
17
|
+
# constructor and must be released in #destroy! .
|
18
|
+
#
|
19
|
+
# Updaters are inherently neither threadsafe nor reuseable. This should
|
20
|
+
# , however, not be a problem since they are not allocated by users.
|
21
|
+
#
|
22
|
+
# @api developer
|
23
|
+
# @abstract
|
24
|
+
class Updater
|
25
|
+
|
26
|
+
# @return [MultiGit::Object, MultiGit::Ref, nil]
|
27
|
+
attr :target
|
28
|
+
|
29
|
+
# @return [MultiGit::Ref]
|
30
|
+
attr :ref
|
31
|
+
|
32
|
+
# @return [MultiGit::Repository]
|
33
|
+
def repository
|
34
|
+
@ref.repository
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [String]
|
38
|
+
def name
|
39
|
+
@ref.name
|
40
|
+
end
|
41
|
+
|
42
|
+
# @param ref [Ref]
|
43
|
+
def initialize(ref)
|
44
|
+
self.ref = ref
|
45
|
+
end
|
46
|
+
|
47
|
+
# Finally carry out the update.
|
48
|
+
#
|
49
|
+
# @param new [MultiGit::Object, MultiGit::Ref, nil]
|
50
|
+
# @return [MultiGit::Object, MultiGit::Ref, nil]
|
51
|
+
# @abstract
|
52
|
+
def update(new)
|
53
|
+
nx = case new
|
54
|
+
when Ref, nil then new
|
55
|
+
when Object, Builder then repository.write(new)
|
56
|
+
else raise
|
57
|
+
end
|
58
|
+
@target = nx
|
59
|
+
return nx
|
60
|
+
end
|
61
|
+
|
62
|
+
# Release all resources used by this updater.
|
63
|
+
def destroy!
|
64
|
+
end
|
65
|
+
|
66
|
+
# @param ref [Ref]
|
67
|
+
def ref=(ref)
|
68
|
+
@ref = ref
|
69
|
+
@target = ref.target
|
70
|
+
return ref
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
# @api developer
|
76
|
+
class FileUpdater < Updater
|
77
|
+
|
78
|
+
protected
|
79
|
+
|
80
|
+
def open_file(exists)
|
81
|
+
mode = ::File::WRONLY | ::File::TRUNC
|
82
|
+
if !exists
|
83
|
+
begin
|
84
|
+
return ::File.open(file_path, mode | ::File::CREAT)
|
85
|
+
rescue Errno::EEXIST
|
86
|
+
raise Error::ConcurrentRefUpdate
|
87
|
+
end
|
88
|
+
else
|
89
|
+
begin
|
90
|
+
return ::File.open(file_path, mode)
|
91
|
+
rescue Errno::ENOENT
|
92
|
+
raise Error::ConcurrentRefUpdate
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def object_to_ref_str(object)
|
98
|
+
case(object)
|
99
|
+
when nil then ''
|
100
|
+
when MultiGit::Object then object.oid
|
101
|
+
when Ref then "ref: #{object.name}"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def file_path
|
106
|
+
::File.join(repository.git_dir, name)
|
107
|
+
end
|
108
|
+
|
109
|
+
def lock_file_path
|
110
|
+
::File.join(repository.git_dir, name + '.lock')
|
111
|
+
end
|
112
|
+
|
113
|
+
def acquire_lock
|
114
|
+
::File.open(lock_file_path, ::File::CREAT | ::File::RDWR | ::File::EXCL )
|
115
|
+
end
|
116
|
+
|
117
|
+
def release_lock(lock)
|
118
|
+
::File.unlink(lock.path)
|
119
|
+
lock.flock(::File::LOCK_UN)
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
# @api developer
|
125
|
+
class PessimisticFileUpdater < FileUpdater
|
126
|
+
|
127
|
+
def initialize(*_)
|
128
|
+
super
|
129
|
+
@lock = acquire_lock
|
130
|
+
# safe now
|
131
|
+
@ref = @ref.reload
|
132
|
+
end
|
133
|
+
|
134
|
+
def update(new)
|
135
|
+
old = target
|
136
|
+
nx = super
|
137
|
+
if nx
|
138
|
+
str = object_to_ref_str(nx)
|
139
|
+
begin
|
140
|
+
file = open_file(!old.nil?)
|
141
|
+
file.puts(str)
|
142
|
+
file.flush
|
143
|
+
ensure
|
144
|
+
file.close if file
|
145
|
+
end
|
146
|
+
else
|
147
|
+
::File.unlink(file_path)
|
148
|
+
end
|
149
|
+
return nx
|
150
|
+
end
|
151
|
+
|
152
|
+
def destroy!
|
153
|
+
release_lock(@lock)
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
# @api developer
|
159
|
+
class OptimisticFileUpdater < FileUpdater
|
160
|
+
|
161
|
+
def update(new)
|
162
|
+
begin
|
163
|
+
lock = acquire_lock
|
164
|
+
if ::File.exists?(file_path)
|
165
|
+
content = ::File.read(file_path).chomp
|
166
|
+
if content != object_to_ref_str(target)
|
167
|
+
raise Error::ConcurrentRefUpdate
|
168
|
+
end
|
169
|
+
elsif !target.nil?
|
170
|
+
raise Error::ConcurrentRefUpdate
|
171
|
+
end
|
172
|
+
old = target
|
173
|
+
nx = super
|
174
|
+
if nx.nil?
|
175
|
+
if !old
|
176
|
+
return nx
|
177
|
+
end
|
178
|
+
::File.unlink(file_path)
|
179
|
+
else
|
180
|
+
begin
|
181
|
+
file = open_file( !old.nil? )
|
182
|
+
str = object_to_ref_str(nx)
|
183
|
+
file.puts( str )
|
184
|
+
file.flush
|
185
|
+
ensure
|
186
|
+
file.close if file
|
187
|
+
end
|
188
|
+
end
|
189
|
+
return nx
|
190
|
+
ensure
|
191
|
+
release_lock( lock )
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
private
|
196
|
+
|
197
|
+
end
|
198
|
+
|
199
|
+
extend MultiGit::Utils::AbstractMethods
|
200
|
+
|
201
|
+
# The full name of this ref e.g. refs/heads/master for the master branch.
|
202
|
+
# @return [String]
|
203
|
+
attr :name
|
204
|
+
|
205
|
+
# @!attribute [r] target
|
206
|
+
# The target of this ref.
|
207
|
+
# @return [MultiGit::Ref, MultiGit::Object, nil]
|
208
|
+
# @abstract
|
209
|
+
abstract :target
|
210
|
+
|
211
|
+
# @return [MultiGit::Repository]
|
212
|
+
attr :repository
|
213
|
+
|
214
|
+
# @visibility private
|
215
|
+
def initialize(repository, name)
|
216
|
+
@repository = repository
|
217
|
+
@name = name
|
218
|
+
end
|
219
|
+
|
220
|
+
# Rereads this reference from the repository.
|
221
|
+
#
|
222
|
+
# @return [MultiGit::Ref]
|
223
|
+
def reload
|
224
|
+
repository.ref(name)
|
225
|
+
end
|
226
|
+
|
227
|
+
# Resolves symbolic references and returns the final reference.
|
228
|
+
#
|
229
|
+
# @return [MultGit::Ref]
|
230
|
+
def resolve
|
231
|
+
@leaf = begin
|
232
|
+
ref = self
|
233
|
+
loop do
|
234
|
+
break ref unless ref.symbolic?
|
235
|
+
ref = ref.target
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
# @!group Treeish methods
|
241
|
+
|
242
|
+
def [](name)
|
243
|
+
t = resolve.target
|
244
|
+
if t
|
245
|
+
return t[name]
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
alias / []
|
250
|
+
|
251
|
+
def []=(path, options = {}, value)
|
252
|
+
resolve.update(options.fetch(:lock, :pessimistic) ) do |commit|
|
253
|
+
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
# @!endgroup
|
258
|
+
|
259
|
+
# @!group Utility methods
|
260
|
+
|
261
|
+
def direct?
|
262
|
+
name.include?('/')
|
263
|
+
end
|
264
|
+
|
265
|
+
def symbolic?
|
266
|
+
!direct?
|
267
|
+
end
|
268
|
+
|
269
|
+
def exists?
|
270
|
+
!target.nil?
|
271
|
+
end
|
272
|
+
|
273
|
+
# @!endgroup
|
274
|
+
|
275
|
+
# @!group Writing methods
|
276
|
+
|
277
|
+
# Updates the target of this reference.
|
278
|
+
#
|
279
|
+
# The new target of this reference is the result of the passed block. If
|
280
|
+
# you return nil, the ref will be deleted.
|
281
|
+
#
|
282
|
+
# By using the lock param you can control the isolation:
|
283
|
+
#
|
284
|
+
# [:optimistic] If the target is altered during the execution of the
|
285
|
+
# block, a {MultiGit::Error::ConcurrentRefUpdate} is
|
286
|
+
# raised. This is the default as it holds hard locks
|
287
|
+
# only as long as necessary while providing pointfull
|
288
|
+
# isolation.
|
289
|
+
# [:pessimistic] A lock is acquired and held during the execution of the
|
290
|
+
# block. Concurrent updates will wait or fail. This is
|
291
|
+
# good if the block is not retry-able or very small.
|
292
|
+
#
|
293
|
+
# @param lock [:optimistic, :pessimistic]
|
294
|
+
# @yield [current_target] Yields the current target and expects the block to return the new target
|
295
|
+
# @yieldparam current_target [MultiGit::Ref, MultiGit::Object, nil] current target
|
296
|
+
# @yieldreturn [MultiGit::Ref, MultiGit::Object, nil] new target
|
297
|
+
# @return [MultiGit::Ref] The altered ref
|
298
|
+
#
|
299
|
+
# @example
|
300
|
+
# # setup:
|
301
|
+
# dir = `mktemp -d`
|
302
|
+
# repository = MultiGit.open(dir, init: true)
|
303
|
+
# # insert a commit:
|
304
|
+
# builder = MultiGit::Commit::Builder.new
|
305
|
+
# builder.tree['a_file'] = 'some_content'
|
306
|
+
# commit = repository.write(builder)
|
307
|
+
# # update the ref:
|
308
|
+
# ref = repository.ref('refs/heads/master') #=> be_a MultiGit::Ref
|
309
|
+
# ref.update do |current_target|
|
310
|
+
# current_target #=> be_nil
|
311
|
+
# commit
|
312
|
+
# end
|
313
|
+
# # check result:
|
314
|
+
# repository.ref('refs/heads/master').target #=> eql commit
|
315
|
+
# # teardown:
|
316
|
+
# `rm -rf #{dir}`
|
317
|
+
def update( lock = :optimistic )
|
318
|
+
updater_class = case lock
|
319
|
+
when :optimistic then optimistic_updater
|
320
|
+
when :pessimistic then pessimistic_updater
|
321
|
+
end
|
322
|
+
begin
|
323
|
+
updater = updater_class.new(self)
|
324
|
+
updater.update( yield(updater.target) )
|
325
|
+
return reload
|
326
|
+
ensure
|
327
|
+
updater.destroy! if updater
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
def delete
|
332
|
+
update(:pessimistic){ nil }
|
333
|
+
end
|
334
|
+
|
335
|
+
def commit(&block)
|
336
|
+
resolve.update do |current|
|
337
|
+
Commit::Builder.new(current, &block)
|
338
|
+
end
|
339
|
+
return reload
|
340
|
+
end
|
341
|
+
|
342
|
+
#@!endgroup
|
343
|
+
|
344
|
+
# @api private
|
345
|
+
# @visibility private
|
346
|
+
def hash
|
347
|
+
name.hash ^ repository.hash
|
348
|
+
end
|
349
|
+
|
350
|
+
# @api private
|
351
|
+
# @visibility private
|
352
|
+
def eql?(other)
|
353
|
+
return false unless other.kind_of? Ref
|
354
|
+
name == other.name && repository.eql?(other.repository)
|
355
|
+
end
|
356
|
+
|
357
|
+
# @api private
|
358
|
+
# @visibility private
|
359
|
+
def ==(other)
|
360
|
+
eql?(other) && target == other.target
|
361
|
+
end
|
362
|
+
|
363
|
+
# @api private
|
364
|
+
# @visibility private
|
365
|
+
def inspect
|
366
|
+
['<',self.class,' ',repository.inspect,':', name, ' -> ', target.inspect,' >'].join
|
367
|
+
end
|
368
|
+
|
369
|
+
private
|
370
|
+
|
371
|
+
def optimistic_updater
|
372
|
+
OptimisticFileUpdater
|
373
|
+
end
|
374
|
+
|
375
|
+
def pessimistic_updater
|
376
|
+
PessimisticFileUpdater
|
377
|
+
end
|
378
|
+
|
379
|
+
end
|
380
|
+
|
381
|
+
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'set'
|
3
|
+
require 'multi_git/utils'
|
4
|
+
require 'multi_git/error'
|
5
|
+
require 'multi_git/tree_entry'
|
6
|
+
require 'multi_git/symlink'
|
7
|
+
require 'multi_git/directory'
|
8
|
+
require 'multi_git/file'
|
9
|
+
require 'multi_git/executeable'
|
10
|
+
require 'multi_git/submodule'
|
11
|
+
|
12
|
+
# Abstract base class for all repository implementations.
|
13
|
+
# @abstract
|
14
|
+
class MultiGit::Repository
|
15
|
+
|
16
|
+
protected
|
17
|
+
Utils = MultiGit::Utils
|
18
|
+
Error = MultiGit::Error
|
19
|
+
|
20
|
+
VALID_TYPES = Set[:blob, :tree, :commit, :tag]
|
21
|
+
public
|
22
|
+
extend Utils::AbstractMethods
|
23
|
+
|
24
|
+
# @!method git_dir
|
25
|
+
# @abstract
|
26
|
+
# Return the repository base directory
|
27
|
+
# @return [String]
|
28
|
+
abstract :git_dir
|
29
|
+
|
30
|
+
# @!method bare?
|
31
|
+
# @abstract
|
32
|
+
# Is this repository bare?
|
33
|
+
abstract :bare?
|
34
|
+
|
35
|
+
# @!method initialize(directory, options = {})
|
36
|
+
# @param directory [String] a directory
|
37
|
+
# @option options [Boolean] :init init the repository if it doesn't exist
|
38
|
+
# @option options [Boolean] :bare open/init the repository bare
|
39
|
+
|
40
|
+
# @!method read(ref)
|
41
|
+
# Reads a reference.
|
42
|
+
#
|
43
|
+
# @abstract
|
44
|
+
#
|
45
|
+
# @raise [MultiGit::Error::InvalidReference] if ref is not a valid reference
|
46
|
+
# @raise [MultiGit::Error::AmbiguousReference] if ref refers to multiple objects
|
47
|
+
# @raise [MultiGit::Error::BadRevisionSyntax] if ref does not contain a valid ref-syntax
|
48
|
+
# @param [String] ref
|
49
|
+
# @return [MultiGit::Object] object
|
50
|
+
abstract :read
|
51
|
+
|
52
|
+
# @!method include?(oid)
|
53
|
+
# Checks whether this repository contains a given oid.
|
54
|
+
# @abstract
|
55
|
+
# @param [String] oid
|
56
|
+
# @return [Boolean]
|
57
|
+
abstract :include?
|
58
|
+
|
59
|
+
# @!method parse(ref)
|
60
|
+
# Resolves a reference into an oid.
|
61
|
+
# @abstract
|
62
|
+
# @param [String] rev
|
63
|
+
# @raise [MultiGit::Error::InvalidReference] if ref is not a valid reference
|
64
|
+
# @raise [MultiGit::Error::AmbiguousReference] if ref refers to multiple objects
|
65
|
+
# @raise [MultiGit::Error::BadRevisionSyntax] if ref does not contain a valid ref-syntax
|
66
|
+
# @return [String] oid
|
67
|
+
abstract :parse
|
68
|
+
|
69
|
+
# @!method write(content)
|
70
|
+
# Writes something to the repository.
|
71
|
+
#
|
72
|
+
# If called with a String or an IO, this method creates a {MultiGit::Blob} with the
|
73
|
+
# given content. This is the easiest way to create blobs.
|
74
|
+
#
|
75
|
+
# If called with a {MultiGit::Object}, this method determines if the object does already exist
|
76
|
+
# and writes it otherwise.
|
77
|
+
#
|
78
|
+
# If called with a {MultiGit::Builder}, this method inserts the content of the builder to the
|
79
|
+
# repository. This is the easiest way to create trees/commits.
|
80
|
+
#
|
81
|
+
# @abstract
|
82
|
+
# @param [String, IO, MultiGit::Object, MultiGit::Builder] content
|
83
|
+
# @return [MultiGit::Object] the resulting object
|
84
|
+
abstract :write
|
85
|
+
|
86
|
+
# @!method ref(name)
|
87
|
+
# Opens a reference.
|
88
|
+
# @abstract
|
89
|
+
# @param [String] name
|
90
|
+
# @return [MultiGit::Ref] ref
|
91
|
+
abstract :ref
|
92
|
+
|
93
|
+
def branch(name)
|
94
|
+
if name.include? '/'
|
95
|
+
ref('refs/remotes/'+name)
|
96
|
+
else
|
97
|
+
ref('refs/heads/'+name)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def tag(name)
|
102
|
+
ref('refs/tags/'+name)
|
103
|
+
end
|
104
|
+
|
105
|
+
# @!parse alias_method :[], :ref
|
106
|
+
def [](name)
|
107
|
+
ref(name)
|
108
|
+
end
|
109
|
+
|
110
|
+
# @!parse alias_method :<<, :write
|
111
|
+
def <<(*args,&block)
|
112
|
+
write(*args,&block)
|
113
|
+
end
|
114
|
+
|
115
|
+
# @visibility private
|
116
|
+
def inspect
|
117
|
+
if bare?
|
118
|
+
["#<",self.class.name," ",git_dir,">"].join
|
119
|
+
else
|
120
|
+
["#<",self.class.name," ",git_dir," checked out at:",git_work_tree,">"].join
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# @visibility private
|
125
|
+
EC = {
|
126
|
+
Utils::MODE_EXECUTEABLE => MultiGit::Executeable,
|
127
|
+
Utils::MODE_FILE => MultiGit::File,
|
128
|
+
Utils::MODE_SYMLINK => MultiGit::Symlink,
|
129
|
+
Utils::MODE_DIRECTORY => MultiGit::Directory
|
130
|
+
}
|
131
|
+
|
132
|
+
# @visibility private
|
133
|
+
def read_entry(parent = nil, name, mode, oidish)
|
134
|
+
obj = read(oidish)
|
135
|
+
EC[mode].new(parent, name, obj)
|
136
|
+
end
|
137
|
+
protected
|
138
|
+
|
139
|
+
def initialize_options(path, options)
|
140
|
+
options = options.dup
|
141
|
+
options[:expected_bare] = options[:bare]
|
142
|
+
looks_bare = Utils.looks_bare?(path)
|
143
|
+
case(options[:bare])
|
144
|
+
when nil then
|
145
|
+
options[:bare] = looks_bare
|
146
|
+
when false then
|
147
|
+
raise Error::RepositoryBare, path if looks_bare
|
148
|
+
end
|
149
|
+
if !::File.exists?(path)
|
150
|
+
if options[:init]
|
151
|
+
FileUtils.mkdir_p(path)
|
152
|
+
else
|
153
|
+
raise Error::NotARepository, path
|
154
|
+
end
|
155
|
+
end
|
156
|
+
if options[:bare]
|
157
|
+
if looks_bare || options[:init]
|
158
|
+
options[:repository] ||= path
|
159
|
+
else
|
160
|
+
options[:repository] ||= ::File.join(path, '.git')
|
161
|
+
end
|
162
|
+
options.delete(:working_directory)
|
163
|
+
else
|
164
|
+
options[:working_directory] = path
|
165
|
+
options[:repository] ||= ::File.join(path, '.git')
|
166
|
+
end
|
167
|
+
options[:index] ||= ::File.join(options[:repository],'index')
|
168
|
+
return options
|
169
|
+
end
|
170
|
+
|
171
|
+
def verify_bareness(path, options)
|
172
|
+
bareness = options[:expected_bare]
|
173
|
+
return if bareness.nil?
|
174
|
+
if !bareness && bare?
|
175
|
+
raise Error::RepositoryBare, path
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def verify_type_for_mode(type, mode)
|
180
|
+
expected = Utils.type_from_mode(mode)
|
181
|
+
unless type == expected
|
182
|
+
raise Error::WrongTypeForMode.new(expected, type)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def validate_type(type)
|
187
|
+
raise Error::InvalidObjectType, type.inspect unless VALID_TYPES.include?(type)
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'multi_git/commit'
|
2
|
+
require 'multi_git/rugged_backend/object'
|
3
|
+
module MultiGit
|
4
|
+
module RuggedBackend
|
5
|
+
class Commit < Object
|
6
|
+
include MultiGit::Commit
|
7
|
+
|
8
|
+
def tree
|
9
|
+
@tree ||= repository.read(rugged_object.tree_oid)
|
10
|
+
end
|
11
|
+
|
12
|
+
def parents
|
13
|
+
@parents ||= rugged_object.parent_oids.map{|oid| repository.read(oid) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def author
|
17
|
+
MultiGit::Handle.new(rugged_object.author[:name],rugged_object.author[:email])
|
18
|
+
end
|
19
|
+
|
20
|
+
def time
|
21
|
+
rugged_object.author[:time]
|
22
|
+
end
|
23
|
+
|
24
|
+
def committer
|
25
|
+
MultiGit::Handle.new(rugged_object.committer[:name],rugged_object.committer[:email])
|
26
|
+
end
|
27
|
+
|
28
|
+
def commit_time
|
29
|
+
rugged_object.committer[:time]
|
30
|
+
end
|
31
|
+
|
32
|
+
def message
|
33
|
+
rugged_object.message
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'multi_git/object'
|
3
|
+
class MultiGit::RuggedBackend::Object
|
4
|
+
|
5
|
+
include MultiGit::Object
|
6
|
+
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
def initialize( repository, oid, object = nil )
|
10
|
+
@repository = repository
|
11
|
+
@git = repository.__backend__
|
12
|
+
@oid = oid
|
13
|
+
@rugged_object = object
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_io
|
17
|
+
StringIO.new(content)
|
18
|
+
end
|
19
|
+
|
20
|
+
def bytesize
|
21
|
+
rugged_odb.len
|
22
|
+
end
|
23
|
+
|
24
|
+
def content
|
25
|
+
@content ||= rugged_odb.data.freeze
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
|
30
|
+
def rugged_object
|
31
|
+
@rugged_object ||= @git.lookup(@oid)
|
32
|
+
end
|
33
|
+
|
34
|
+
def rugged_odb
|
35
|
+
@rugged_odb ||= @git.read(@oid)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'multi_git/ref'
|
2
|
+
module MultiGit
|
3
|
+
|
4
|
+
module RuggedBackend
|
5
|
+
|
6
|
+
class Ref
|
7
|
+
|
8
|
+
include MultiGit::Ref
|
9
|
+
|
10
|
+
def initialize(repository, name)
|
11
|
+
super(repository, name)
|
12
|
+
@rugged_ref = Rugged::Reference.lookup(repository.__backend__, name)
|
13
|
+
end
|
14
|
+
|
15
|
+
def target
|
16
|
+
return nil unless rugged_ref
|
17
|
+
@target ||= begin
|
18
|
+
if rugged_ref.type == :symbolic
|
19
|
+
repository.ref(rugged_ref.target)
|
20
|
+
else
|
21
|
+
repository.read(rugged_ref.target)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
attr :rugged_ref
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|