schacon-grit 0.9.1

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.
Files changed (47) hide show
  1. data/History.txt +13 -0
  2. data/Manifest.txt +57 -0
  3. data/README.txt +213 -0
  4. data/Rakefile +29 -0
  5. data/grit.gemspec +60 -0
  6. data/lib/grit.rb +53 -0
  7. data/lib/grit/actor.rb +36 -0
  8. data/lib/grit/blob.rb +117 -0
  9. data/lib/grit/commit.rb +221 -0
  10. data/lib/grit/commit_stats.rb +104 -0
  11. data/lib/grit/config.rb +44 -0
  12. data/lib/grit/diff.rb +70 -0
  13. data/lib/grit/errors.rb +7 -0
  14. data/lib/grit/git-ruby.rb +175 -0
  15. data/lib/grit/git-ruby/commit_db.rb +52 -0
  16. data/lib/grit/git-ruby/file_index.rb +186 -0
  17. data/lib/grit/git-ruby/git_object.rb +344 -0
  18. data/lib/grit/git-ruby/internal/loose.rb +136 -0
  19. data/lib/grit/git-ruby/internal/mmap.rb +59 -0
  20. data/lib/grit/git-ruby/internal/pack.rb +332 -0
  21. data/lib/grit/git-ruby/internal/raw_object.rb +37 -0
  22. data/lib/grit/git-ruby/object.rb +319 -0
  23. data/lib/grit/git-ruby/repository.rb +675 -0
  24. data/lib/grit/git.rb +130 -0
  25. data/lib/grit/head.rb +83 -0
  26. data/lib/grit/index.rb +102 -0
  27. data/lib/grit/lazy.rb +31 -0
  28. data/lib/grit/ref.rb +95 -0
  29. data/lib/grit/repo.rb +381 -0
  30. data/lib/grit/status.rb +149 -0
  31. data/lib/grit/tag.rb +71 -0
  32. data/lib/grit/tree.rb +100 -0
  33. data/test/test_actor.rb +35 -0
  34. data/test/test_blob.rb +79 -0
  35. data/test/test_commit.rb +184 -0
  36. data/test/test_config.rb +58 -0
  37. data/test/test_diff.rb +18 -0
  38. data/test/test_git.rb +70 -0
  39. data/test/test_grit.rb +32 -0
  40. data/test/test_head.rb +41 -0
  41. data/test/test_real.rb +19 -0
  42. data/test/test_reality.rb +17 -0
  43. data/test/test_remote.rb +14 -0
  44. data/test/test_repo.rb +277 -0
  45. data/test/test_tag.rb +25 -0
  46. data/test/test_tree.rb +96 -0
  47. metadata +110 -0
@@ -0,0 +1,675 @@
1
+ #
2
+ # converted from the gitrb project
3
+ #
4
+ # authors:
5
+ # Matthias Lederhofer <matled@gmx.net>
6
+ # Simon 'corecode' Schubert <corecode@fs.ei.tum.de>
7
+ # Scott Chacon <schacon@gmail.com>
8
+ #
9
+ # provides native ruby access to git objects and pack files
10
+ #
11
+ require 'grit/git-ruby/internal/raw_object'
12
+ require 'grit/git-ruby/internal/pack'
13
+ require 'grit/git-ruby/internal/loose'
14
+ require 'grit/git-ruby/git_object'
15
+
16
+ require 'rubygems'
17
+ require 'diff/lcs'
18
+ require 'diff/lcs/hunk'
19
+
20
+ # have to do this so it doesn't interfere with Grit::Diff
21
+ module Difference
22
+ include Diff
23
+ end
24
+
25
+ module Grit
26
+ module GitRuby
27
+ class Repository
28
+
29
+ class NoSuchShaFound < StandardError
30
+ end
31
+
32
+ class NoSuchPath < StandardError
33
+ end
34
+
35
+ attr_accessor :git_dir, :options
36
+
37
+ def initialize(git_dir, options = {})
38
+ @git_dir = git_dir
39
+ @options = options
40
+ end
41
+
42
+ # returns the loose objects object lazily
43
+ def loose
44
+ @loose ||= initloose
45
+ end
46
+
47
+ # returns the array of pack list objects
48
+ def packs
49
+ @packs ||= initpacks
50
+ end
51
+
52
+
53
+ # prints out the type, shas and content of all of the pack files
54
+ def show
55
+ packs.each do |p|
56
+ puts p.name
57
+ puts
58
+ p.each_sha1 do |s|
59
+ puts "**#{p[s].type}**"
60
+ if p[s].type.to_s == 'commit'
61
+ puts s.unpack('H*')
62
+ puts p[s].content
63
+ end
64
+ end
65
+ puts
66
+ end
67
+ end
68
+
69
+
70
+ # returns a raw object given a SHA1
71
+ def get_raw_object_by_sha1(sha1o)
72
+ sha1 = [sha1o.chomp].pack("H*")
73
+ # try packs
74
+ packs.each do |pack|
75
+ o = pack[sha1]
76
+ return pack[sha1] if o
77
+ end
78
+
79
+ # try loose storage
80
+ loose.each do |lsobj|
81
+ o = lsobj[sha1]
82
+ return o if o
83
+ end
84
+
85
+ # try packs again, maybe the object got packed in the meantime
86
+ initpacks
87
+ packs.each do |pack|
88
+ o = pack[sha1]
89
+ return o if o
90
+ end
91
+
92
+ # puts "*#{sha1o}*"
93
+ raise NoSuchShaFound
94
+ end
95
+
96
+ def cached(key, object, do_cache = true)
97
+ object
98
+ end
99
+
100
+ # returns GitRuby object of any type given a SHA1
101
+ def get_object_by_sha1(sha1)
102
+ r = get_raw_object_by_sha1(sha1)
103
+ return nil if !r
104
+ GitObject.from_raw(r)
105
+ end
106
+
107
+ # writes a raw object into the git repo
108
+ def put_raw_object(content, type)
109
+ loose.first.put_raw_object(content, type)
110
+ end
111
+
112
+ # returns true or false if that sha exists in the db
113
+ def object_exists?(sha1)
114
+ sha_hex = [sha1].pack("H*")
115
+ return true if in_packs?(sha_hex)
116
+ return true if in_loose?(sha_hex)
117
+ initpacks
118
+ return true if in_packs?(sha_hex) #maybe the object got packed in the meantime
119
+ false
120
+ end
121
+
122
+ # returns true if the hex-packed sha is in the packfiles
123
+ def in_packs?(sha_hex)
124
+ # try packs
125
+ packs.each do |pack|
126
+ return true if pack[sha_hex]
127
+ end
128
+ false
129
+ end
130
+
131
+ # returns true if the hex-packed sha is in the loose objects
132
+ def in_loose?(sha_hex)
133
+ loose.each do |lsobj|
134
+ return true if lsobj[sha_hex]
135
+ end
136
+ false
137
+ end
138
+
139
+
140
+ # returns the file type (as a symbol) of this sha
141
+ def cat_file_type(sha)
142
+ get_raw_object_by_sha1(sha).type
143
+ end
144
+
145
+ # returns the file size (as an int) of this sha
146
+ def cat_file_size(sha)
147
+ get_raw_object_by_sha1(sha).content.size
148
+ end
149
+
150
+ # returns the raw file contents of this sha
151
+ def cat_file(sha)
152
+ get_object_by_sha1(sha).raw_content
153
+ end
154
+
155
+ # returns a 2-d hash of the tree
156
+ # ['blob']['FILENAME'] = {:mode => '100644', :sha => SHA}
157
+ # ['tree']['DIRNAME'] = {:mode => '040000', :sha => SHA}
158
+ def list_tree(sha)
159
+ data = {'blob' => {}, 'tree' => {}, 'link' => {}, 'commit' => {}}
160
+ get_object_by_sha1(sha).entry.each do |e|
161
+ data[e.format_type][e.name] = {:mode => e.format_mode, :sha => e.sha1}
162
+ end
163
+ data
164
+ end
165
+
166
+ # returns the raw (cat-file) output for a tree
167
+ # if given a commit sha, it will print the tree of that commit
168
+ # if given a path limiter array, it will limit the output to those
169
+ def ls_tree(sha, paths = [])
170
+ if paths.size > 0
171
+ # pathing
172
+ part = []
173
+ paths.each do |path|
174
+ part += ls_tree_path(sha, path)
175
+ end
176
+ return part.join("\n")
177
+ else
178
+ get_raw_tree(sha)
179
+ end
180
+ end
181
+
182
+ def get_raw_tree(sha)
183
+ o = get_raw_object_by_sha1(sha)
184
+ if o.type == :commit
185
+ tree = cat_file(get_object_by_sha1(sha).tree)
186
+ elsif o.type == :tag
187
+ commit_sha = get_object_by_sha1(sha).object
188
+ tree = cat_file(get_object_by_sha1(commit_sha).tree)
189
+ else
190
+ tree = cat_file(sha)
191
+ end
192
+ return tree
193
+ end
194
+
195
+ # return array of tree entries
196
+ ## TODO : refactor this to remove the fugly
197
+ def ls_tree_path(sha, path, append = nil)
198
+ tree = get_raw_tree(sha)
199
+ if path =~ /\//
200
+ paths = path.split('/')
201
+ last = path[path.size - 1, 1]
202
+ if (last == '/') && (paths.size == 1)
203
+ append = append ? File.join(append, paths.first) : paths.first
204
+ dir_name = tree.split("\n").select { |p| p.split("\t")[1] == paths.first }.first
205
+ raise NoSuchPath if !dir_name
206
+ next_sha = dir_name.split(' ')[2]
207
+ tree = get_raw_tree(next_sha)
208
+ tree = tree.split("\n")
209
+ if append
210
+ mod_tree = []
211
+ tree.each do |ent|
212
+ (info, fpath) = ent.split("\t")
213
+ mod_tree << [info, File.join(append, fpath)].join("\t")
214
+ end
215
+ mod_tree
216
+ else
217
+ tree
218
+ end
219
+ else
220
+ next_path = paths.shift
221
+ dir_name = tree.split("\n").select { |p| p.split("\t")[1] == next_path }.first
222
+ raise NoSuchPath if !dir_name
223
+ next_sha = dir_name.split(' ')[2]
224
+ next_path = append ? File.join(append, next_path) : next_path
225
+ if (last == '/')
226
+ ls_tree_path(next_sha, paths.join("/") + '/', next_path)
227
+ else
228
+ ls_tree_path(next_sha, paths.join("/"), next_path)
229
+ end
230
+ end
231
+ else
232
+ tree = tree.split("\n")
233
+ tree = tree.select { |p| p.split("\t")[1] == path }
234
+ if append
235
+ mod_tree = []
236
+ tree.each do |ent|
237
+ (info, fpath) = ent.split("\t")
238
+ mod_tree << [info, File.join(append, fpath)].join("\t")
239
+ end
240
+ mod_tree
241
+ else
242
+ tree
243
+ end
244
+ end
245
+ end
246
+
247
+ # returns an array of GitRuby Commit objects
248
+ # [ [sha, raw_output], [sha, raw_output], [sha, raw_output] ... ]
249
+ #
250
+ # takes the following options:
251
+ # :since - Time object specifying that you don't want commits BEFORE this
252
+ # :until - Time object specifying that you don't want commit AFTER this
253
+ # :first_parent - tells log to only walk first parent
254
+ # :path_limiter - string or array of strings to limit path
255
+ # :max_count - number to limit the output
256
+ def log(sha, options = {})
257
+ @already_searched = {}
258
+ walk_log(sha, options)
259
+ end
260
+
261
+ def truncate_arr(arr, sha)
262
+ new_arr = []
263
+ arr.each do |a|
264
+ if a[0] == sha
265
+ return new_arr
266
+ end
267
+ new_arr << a
268
+ end
269
+ return new_arr
270
+ end
271
+
272
+ def rev_list(sha, options)
273
+ if sha.is_a? Array
274
+ (end_sha, sha) = sha
275
+ end
276
+
277
+ log = log(sha, options)
278
+ log = log.sort { |a, b| a[2] <=> b[2] }.reverse
279
+
280
+ if end_sha
281
+ log = truncate_arr(log, end_sha)
282
+ end
283
+
284
+ # shorten the list if it's longer than max_count (had to get everything in branches)
285
+ if options[:max_count]
286
+ if (opt_len = options[:max_count].to_i) < log.size
287
+ log = log[0, opt_len]
288
+ end
289
+ end
290
+
291
+ if options[:pretty] == 'raw'
292
+ log.map {|k, v| v }.join('')
293
+ else
294
+ log.map {|k, v| k }.join("\n")
295
+ end
296
+ end
297
+
298
+ # called by log() to recursively walk the tree
299
+ def walk_log(sha, opts, total_size = 0)
300
+ return [] if @already_searched[sha] # to prevent rechecking branches
301
+ @already_searched[sha] = true
302
+
303
+ array = []
304
+ if (sha)
305
+ o = get_raw_object_by_sha1(sha)
306
+ if o.type == :tag
307
+ commit_sha = get_object_by_sha1(sha).object
308
+ c = get_object_by_sha1(commit_sha)
309
+ else
310
+ c = GitObject.from_raw(o)
311
+ end
312
+
313
+ return [] if c.type != :commit
314
+
315
+ add_sha = true
316
+
317
+ if opts[:since] && opts[:since].is_a?(Time) && (opts[:since] > c.committer.date)
318
+ add_sha = false
319
+ end
320
+ if opts[:until] && opts[:until].is_a?(Time) && (opts[:until] < c.committer.date)
321
+ add_sha = false
322
+ end
323
+
324
+ # follow all parents unless '--first-parent' is specified #
325
+ subarray = []
326
+
327
+ if !c.parent.first && opts[:path_limiter] # check for the last commit
328
+ add_sha = false
329
+ end
330
+
331
+ if (!opts[:max_count] || ((array.size + total_size) < opts[:max_count]))
332
+
333
+ if !opts[:path_limiter]
334
+ output = c.raw_log(sha)
335
+ array << [sha, output, c.committer.date]
336
+ end
337
+
338
+ if (opts[:max_count] && (array.size + total_size) >= opts[:max_count])
339
+ return array
340
+ end
341
+
342
+ c.parent.each do |psha|
343
+ if psha && !files_changed?(c.tree, get_object_by_sha1(psha).tree,
344
+ opts[:path_limiter])
345
+ add_sha = false
346
+ end
347
+ subarray += walk_log(psha, opts, (array.size + total_size))
348
+ next if opts[:first_parent]
349
+ end
350
+
351
+ if opts[:path_limiter] && add_sha
352
+ output = c.raw_log(sha)
353
+ array << [sha, output, c.committer.date]
354
+ end
355
+
356
+ if add_sha
357
+ array += subarray
358
+ end
359
+ end
360
+
361
+ end
362
+
363
+ array
364
+ end
365
+
366
+ def diff(commit1, commit2, options = {})
367
+ patch = ''
368
+
369
+ commit_obj1 = get_object_by_sha1(commit1)
370
+ tree1 = commit_obj1.tree
371
+ if commit2
372
+ tree2 = get_object_by_sha1(commit2).tree
373
+ else
374
+ tree2 = get_object_by_sha1(commit_obj1.parent.first).tree
375
+ end
376
+
377
+ qdiff = quick_diff(tree1, tree2)
378
+
379
+ qdiff.sort.each do |diff_arr|
380
+ format, lines, output = :unified, 3, ''
381
+ file_length_difference = 0
382
+
383
+ fileA = (diff_arr[2]) ? cat_file(diff_arr[2]) : ''
384
+ fileB = (diff_arr[3]) ? cat_file(diff_arr[3]) : ''
385
+
386
+ sha1 = (diff_arr[2]) ? diff_arr[2] : '0000000000000000000000000000000000000000'
387
+ sha2 = (diff_arr[3]) ? diff_arr[3] : '0000000000000000000000000000000000000000'
388
+
389
+ data_old = fileA.split(/\n/).map! { |e| e.chomp }
390
+ data_new = fileB.split(/\n/).map! { |e| e.chomp }
391
+
392
+ diffs = Difference::LCS.diff(data_old, data_new)
393
+ next if diffs.empty?
394
+
395
+ header = 'diff --git a/' + diff_arr[0].gsub('./', '') + ' b/' + diff_arr[0].gsub('./', '')
396
+ if options[:full_index]
397
+ header << "\n" + 'index ' + sha1 + '..' + sha2
398
+ header << ' 100644' if diff_arr[3] # hard coding this because i don't think we use it
399
+ else
400
+ header << "\n" + 'index ' + sha1[0,7] + '..' + sha2[0,7]
401
+ header << ' 100644' if diff_arr[3] # hard coding this because i don't think we use it
402
+ end
403
+ header << "\n--- " + 'a/' + diff_arr[0].gsub('./', '')
404
+ header << "\n+++ " + 'b/' + diff_arr[0].gsub('./', '')
405
+ header += "\n"
406
+
407
+ oldhunk = hunk = nil
408
+
409
+ diffs.each do |piece|
410
+ begin
411
+ hunk = Difference::LCS::Hunk.new(data_old, data_new, piece, lines, file_length_difference)
412
+ file_length_difference = hunk.file_length_difference
413
+
414
+ next unless oldhunk
415
+
416
+ if lines > 0 && hunk.overlaps?(oldhunk)
417
+ hunk.unshift(oldhunk)
418
+ else
419
+ output << oldhunk.diff(format)
420
+ end
421
+ ensure
422
+ oldhunk = hunk
423
+ output << "\n"
424
+ end
425
+ end
426
+
427
+ output << oldhunk.diff(format)
428
+ output << "\n"
429
+
430
+ patch << header + output.lstrip
431
+ end
432
+ patch
433
+ rescue
434
+ '' # one of the trees was bad or lcs isn't there - no diff
435
+ end
436
+
437
+ # takes 2 tree shas and recursively walks them to find out what
438
+ # files or directories have been modified in them and returns an
439
+ # array of changes
440
+ # [ [full_path, 'added', tree1_hash, nil],
441
+ # [full_path, 'removed', nil, tree2_hash],
442
+ # [full_path, 'modified', tree1_hash, tree2_hash]
443
+ # ]
444
+ def quick_diff(tree1, tree2, path = '.', recurse = true)
445
+ # handle empty trees
446
+ changed = []
447
+ return changed if tree1 == tree2
448
+
449
+ t1 = list_tree(tree1) if tree1
450
+ t2 = list_tree(tree2) if tree2
451
+
452
+ # finding files that are different
453
+ t1['blob'].each do |file, hsh|
454
+ t2_file = t2['blob'][file] rescue nil
455
+ full = File.join(path, file)
456
+ if !t2_file
457
+ changed << [full, 'added', hsh[:sha], nil] # not in parent
458
+ elsif (hsh[:sha] != t2_file[:sha])
459
+ changed << [full, 'modified', hsh[:sha], t2_file[:sha]] # file changed
460
+ end
461
+ end if t1
462
+ t2['blob'].each do |file, hsh|
463
+ if !t1 || !t1['blob'][file]
464
+ changed << [File.join(path, file), 'removed', nil, hsh[:sha]]
465
+ end
466
+ end if t2
467
+
468
+ t1['tree'].each do |dir, hsh|
469
+ t2_tree = t2['tree'][dir] rescue nil
470
+ full = File.join(path, dir)
471
+ if !t2_tree
472
+ if recurse
473
+ changed += quick_diff(hsh[:sha], nil, full, true)
474
+ else
475
+ changed << [full, 'added', hsh[:sha], nil] # not in parent
476
+ end
477
+ elsif (hsh[:sha] != t2_tree[:sha])
478
+ if recurse
479
+ changed += quick_diff(hsh[:sha], t2_tree[:sha], full, true)
480
+ else
481
+ changed << [full, 'modified', hsh[:sha], t2_tree[:sha]] # file changed
482
+ end
483
+ end
484
+ end if t1
485
+ t2['tree'].each do |dir, hsh|
486
+ t1_tree = t1['tree'][dir] rescue nil
487
+ full = File.join(path, dir)
488
+ if !t1_tree
489
+ if recurse
490
+ changed += quick_diff(nil, hsh[:sha], full, true)
491
+ else
492
+ changed << [full, 'removed', nil, hsh[:sha]]
493
+ end
494
+ end
495
+ end if t2
496
+
497
+ changed
498
+ end
499
+
500
+ # returns true if the files in path_limiter were changed, or no path limiter
501
+ # used by the log() function when passed with a path_limiter
502
+ def files_changed?(tree_sha1, tree_sha2, path_limiter = nil)
503
+ if path_limiter
504
+ mod = quick_diff(tree_sha1, tree_sha2)
505
+ files = mod.map { |c| c.first }
506
+ path_limiter.to_a.each do |filepath|
507
+ if files.include?(filepath)
508
+ return true
509
+ end
510
+ end
511
+ return false
512
+ end
513
+ true
514
+ end
515
+
516
+ def get_subtree(commit_sha, path)
517
+ tree_sha = get_object_by_sha1(commit_sha).tree
518
+
519
+ if path && !(path == '' || path == '.' || path == './')
520
+ paths = path.split('/')
521
+ paths.each do |path|
522
+ tree = get_object_by_sha1(tree_sha)
523
+ if entry = tree.entry.select { |e| e.name == path }.first
524
+ tree_sha = entry.sha1 rescue nil
525
+ else
526
+ return false
527
+ end
528
+ end
529
+ end
530
+
531
+ tree_sha
532
+ end
533
+
534
+ def blame_tree(commit_sha, path)
535
+ # find subtree
536
+ tree_sha = get_subtree(commit_sha, path)
537
+ return {} if !tree_sha
538
+
539
+ looking_for = []
540
+ get_object_by_sha1(tree_sha).entry.each do |e|
541
+ looking_for << File.join('.', e.name)
542
+ end
543
+
544
+ @already_searched = {}
545
+ commits = look_for_commits(commit_sha, path, looking_for)
546
+
547
+ # cleaning up array
548
+ arr = {}
549
+ commits.each do |commit_array|
550
+ key = commit_array[0].gsub('./', '')
551
+ arr[key] = commit_array[1]
552
+ end
553
+ arr
554
+ end
555
+
556
+ def look_for_commits(commit_sha, path, looking_for, options = {})
557
+ return [] if @already_searched[commit_sha] # to prevent rechecking branches
558
+
559
+ @already_searched[commit_sha] = true
560
+
561
+ commit = get_object_by_sha1(commit_sha)
562
+ tree_sha = get_subtree(commit_sha, path)
563
+
564
+ found_data = []
565
+
566
+ # at the beginning of the branch
567
+ if commit.parent.size == 0
568
+ looking_for.each do |search|
569
+ # prevents the rare case of multiple branch starting points with
570
+ # files that have never changed
571
+ if found_data.assoc(search)
572
+ found_data << [search, commit_sha]
573
+ end
574
+ end
575
+ return found_data
576
+ end
577
+
578
+ # go through the parents recursively, looking for somewhere this has been changed
579
+ commit.parent.each do |pc|
580
+ diff = quick_diff(tree_sha, get_subtree(pc, path), '.', false)
581
+
582
+ # remove anything found
583
+ looking_for.each do |search|
584
+ if match = diff.assoc(search)
585
+ found_data << [search, commit_sha, match]
586
+ looking_for.delete(search)
587
+ end
588
+ end
589
+
590
+ if looking_for.size <= 0 # we're done
591
+ return found_data
592
+ end
593
+
594
+ found_data += look_for_commits(pc, path, looking_for) # recurse into parent
595
+ return found_data if options[:first_parent]
596
+ end
597
+
598
+ ## TODO : find most recent commit with change in any parent
599
+ found_data
600
+ end
601
+
602
+ def close
603
+ @packs.each do |pack|
604
+ pack.close
605
+ end if @packs
606
+ end
607
+
608
+ protected
609
+
610
+ def git_path(path)
611
+ return "#@git_dir/#{path}"
612
+ end
613
+
614
+ private
615
+
616
+ def initloose
617
+ @loose = []
618
+ load_loose(git_path('objects'))
619
+ load_alternate_loose(git_path('objects'))
620
+ @loose
621
+ end
622
+
623
+ def load_alternate_loose(path)
624
+ # load alternate loose, too
625
+ alt = File.join(path, 'info/alternates')
626
+ if File.exists?(alt)
627
+ File.readlines(alt).each do |line|
628
+ load_loose(line.chomp)
629
+ load_alternate_loose(line.chomp)
630
+ end
631
+ end
632
+ end
633
+
634
+ def load_loose(path)
635
+ return if !File.exists?(path)
636
+ @loose << Grit::GitRuby::Internal::LooseStorage.new(path)
637
+ end
638
+
639
+ def initpacks
640
+ close
641
+ @packs = []
642
+ load_packs(git_path("objects/pack"))
643
+ load_alternate_packs(git_path('objects'))
644
+ @packs
645
+ end
646
+
647
+ def load_alternate_packs(path)
648
+ alt = File.join(path, 'info/alternates')
649
+ if File.exists?(alt)
650
+ File.readlines(alt).each do |line|
651
+ full_pack = File.join(line.chomp, 'pack')
652
+ load_packs(full_pack)
653
+ load_alternate_packs(File.join(line.chomp))
654
+ end
655
+ end
656
+ end
657
+
658
+ def load_packs(path)
659
+ return if !File.exists?(path)
660
+ Dir.open(path) do |dir|
661
+ dir.each do |entry|
662
+ next if !(entry =~ /\.pack$/i)
663
+ pack = Grit::GitRuby::Internal::PackStorage.new(File.join(path,entry))
664
+ if @options[:map_packfile]
665
+ pack.cache_objects
666
+ end
667
+ @packs << pack
668
+ end
669
+ end
670
+ end
671
+
672
+ end
673
+
674
+ end
675
+ end