davetron5000-grit 1.1.2

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 (70) hide show
  1. data/API.txt +101 -0
  2. data/History.txt +49 -0
  3. data/LICENSE +22 -0
  4. data/README.md +216 -0
  5. data/VERSION.yml +4 -0
  6. data/examples/ex_add_commit.rb +13 -0
  7. data/examples/ex_index.rb +14 -0
  8. data/lib/grit/actor.rb +41 -0
  9. data/lib/grit/blame.rb +61 -0
  10. data/lib/grit/blob.rb +126 -0
  11. data/lib/grit/commit.rb +242 -0
  12. data/lib/grit/commit_stats.rb +128 -0
  13. data/lib/grit/config.rb +44 -0
  14. data/lib/grit/diff.rb +70 -0
  15. data/lib/grit/errors.rb +7 -0
  16. data/lib/grit/git-ruby/commit_db.rb +52 -0
  17. data/lib/grit/git-ruby/file_index.rb +193 -0
  18. data/lib/grit/git-ruby/git_object.rb +350 -0
  19. data/lib/grit/git-ruby/internal/file_window.rb +58 -0
  20. data/lib/grit/git-ruby/internal/loose.rb +137 -0
  21. data/lib/grit/git-ruby/internal/pack.rb +382 -0
  22. data/lib/grit/git-ruby/internal/raw_object.rb +37 -0
  23. data/lib/grit/git-ruby/object.rb +325 -0
  24. data/lib/grit/git-ruby/repository.rb +736 -0
  25. data/lib/grit/git-ruby.rb +186 -0
  26. data/lib/grit/git.rb +140 -0
  27. data/lib/grit/index.rb +122 -0
  28. data/lib/grit/lazy.rb +33 -0
  29. data/lib/grit/merge.rb +45 -0
  30. data/lib/grit/ref.rb +99 -0
  31. data/lib/grit/repo.rb +447 -0
  32. data/lib/grit/ruby1.9.rb +7 -0
  33. data/lib/grit/status.rb +151 -0
  34. data/lib/grit/submodule.rb +88 -0
  35. data/lib/grit/tag.rb +66 -0
  36. data/lib/grit/tree.rb +123 -0
  37. data/lib/grit.rb +68 -0
  38. data/lib/open3_detach.rb +46 -0
  39. data/test/bench/benchmarks.rb +126 -0
  40. data/test/helper.rb +18 -0
  41. data/test/profile.rb +21 -0
  42. data/test/suite.rb +6 -0
  43. data/test/test_actor.rb +51 -0
  44. data/test/test_blame.rb +32 -0
  45. data/test/test_blame_tree.rb +33 -0
  46. data/test/test_blob.rb +83 -0
  47. data/test/test_commit.rb +206 -0
  48. data/test/test_commit_stats.rb +33 -0
  49. data/test/test_commit_write.rb +54 -0
  50. data/test/test_config.rb +58 -0
  51. data/test/test_diff.rb +18 -0
  52. data/test/test_file_index.rb +56 -0
  53. data/test/test_git.rb +84 -0
  54. data/test/test_grit.rb +32 -0
  55. data/test/test_head.rb +47 -0
  56. data/test/test_index_status.rb +40 -0
  57. data/test/test_merge.rb +17 -0
  58. data/test/test_raw.rb +16 -0
  59. data/test/test_real.rb +19 -0
  60. data/test/test_reality.rb +17 -0
  61. data/test/test_remote.rb +14 -0
  62. data/test/test_repo.rb +347 -0
  63. data/test/test_rubygit.rb +188 -0
  64. data/test/test_rubygit_alt.rb +40 -0
  65. data/test/test_rubygit_index.rb +76 -0
  66. data/test/test_rubygit_iv2.rb +28 -0
  67. data/test/test_submodule.rb +69 -0
  68. data/test/test_tag.rb +67 -0
  69. data/test/test_tree.rb +101 -0
  70. metadata +141 -0
@@ -0,0 +1,137 @@
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
+
12
+ require 'zlib'
13
+ require 'digest/sha1'
14
+ require 'grit/git-ruby/internal/raw_object'
15
+
16
+ module Grit
17
+ module GitRuby
18
+ module Internal
19
+ class LooseObjectError < StandardError
20
+ end
21
+
22
+ class LooseStorage
23
+ def initialize(directory)
24
+ @directory = directory
25
+ end
26
+
27
+ def [](sha1)
28
+ sha1 = sha1.unpack("H*")[0]
29
+ begin
30
+ return nil unless sha1[0...2] && sha1[2..39]
31
+ path = @directory + '/' + sha1[0...2] + '/' + sha1[2..39]
32
+ get_raw_object(File.open(path, 'rb').read)
33
+ rescue Errno::ENOENT
34
+ nil
35
+ end
36
+ end
37
+
38
+ def get_raw_object(buf)
39
+ if buf.length < 2
40
+ raise LooseObjectError, "object file too small"
41
+ end
42
+
43
+ if legacy_loose_object?(buf)
44
+ content = Zlib::Inflate.inflate(buf)
45
+ header, content = content.split(/\0/, 2)
46
+ if !header || !content
47
+ raise LooseObjectError, "invalid object header"
48
+ end
49
+ type, size = header.split(/ /, 2)
50
+ if !%w(blob tree commit tag).include?(type) || size !~ /^\d+$/
51
+ raise LooseObjectError, "invalid object header"
52
+ end
53
+ type = type.to_sym
54
+ size = size.to_i
55
+ else
56
+ type, size, used = unpack_object_header_gently(buf)
57
+ content = Zlib::Inflate.inflate(buf[used..-1])
58
+ end
59
+ raise LooseObjectError, "size mismatch" if content.length != size
60
+ return RawObject.new(type, content)
61
+ end
62
+
63
+ # currently, I'm using the legacy format because it's easier to do
64
+ # this function takes content and a type and writes out the loose object and returns a sha
65
+ def put_raw_object(content, type)
66
+ size = content.length.to_s
67
+ LooseStorage.verify_header(type, size)
68
+
69
+ header = "#{type} #{size}\0"
70
+ store = header + content
71
+
72
+ sha1 = Digest::SHA1.hexdigest(store)
73
+ path = @directory+'/'+sha1[0...2]+'/'+sha1[2..40]
74
+
75
+ if !File.exists?(path)
76
+ content = Zlib::Deflate.deflate(store)
77
+
78
+ FileUtils.mkdir_p(@directory+'/'+sha1[0...2])
79
+ File.open(path, 'wb') do |f|
80
+ f.write content
81
+ end
82
+ end
83
+ return sha1
84
+ end
85
+
86
+ # simply figure out the sha
87
+ def self.calculate_sha(content, type)
88
+ size = content.length.to_s
89
+ verify_header(type, size)
90
+ header = "#{type} #{size}\0"
91
+ store = header + content
92
+
93
+ Digest::SHA1.hexdigest(store)
94
+ end
95
+
96
+ def self.verify_header(type, size)
97
+ if !%w(blob tree commit tag).include?(type) || size !~ /^\d+$/
98
+ raise LooseObjectError, "invalid object header"
99
+ end
100
+ end
101
+
102
+ # private
103
+ def unpack_object_header_gently(buf)
104
+ used = 0
105
+ c = buf.getord(used)
106
+ used += 1
107
+
108
+ type = (c >> 4) & 7;
109
+ size = c & 15;
110
+ shift = 4;
111
+ while c & 0x80 != 0
112
+ if buf.length <= used
113
+ raise LooseObjectError, "object file too short"
114
+ end
115
+ c = buf.getord(used)
116
+ used += 1
117
+
118
+ size += (c & 0x7f) << shift
119
+ shift += 7
120
+ end
121
+ type = OBJ_TYPES[type]
122
+ if ![:blob, :tree, :commit, :tag].include?(type)
123
+ raise LooseObjectError, "invalid loose object type"
124
+ end
125
+ return [type, size, used]
126
+ end
127
+ private :unpack_object_header_gently
128
+
129
+ def legacy_loose_object?(buf)
130
+ word = (buf.getord(0) << 8) + buf.getord(1)
131
+ buf.getord(0) == 0x78 && word % 31 == 0
132
+ end
133
+ private :legacy_loose_object?
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,382 @@
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
+
12
+ require 'zlib'
13
+ require 'grit/git-ruby/internal/raw_object'
14
+ require 'grit/git-ruby/internal/file_window'
15
+
16
+ PACK_SIGNATURE = "PACK"
17
+ PACK_IDX_SIGNATURE = "\377tOc"
18
+
19
+ module Grit
20
+ module GitRuby
21
+ module Internal
22
+ class PackFormatError < StandardError
23
+ end
24
+
25
+ class PackStorage
26
+ OBJ_OFS_DELTA = 6
27
+ OBJ_REF_DELTA = 7
28
+
29
+ FanOutCount = 256
30
+ SHA1Size = 20
31
+ IdxOffsetSize = 4
32
+ OffsetSize = 4
33
+ CrcSize = 4
34
+ OffsetStart = FanOutCount * IdxOffsetSize
35
+ SHA1Start = OffsetStart + OffsetSize
36
+ EntrySize = OffsetSize + SHA1Size
37
+ EntrySizeV2 = SHA1Size + CrcSize + OffsetSize
38
+
39
+ def initialize(file)
40
+ if file =~ /\.idx$/
41
+ file = file[0...-3] + 'pack'
42
+ end
43
+ @name = file
44
+ @cache = {}
45
+ init_pack
46
+ end
47
+
48
+ def with_idx(index_file = nil)
49
+ if !index_file
50
+ index_file = @name
51
+ idxfile = File.open(@name[0...-4]+'idx', 'rb')
52
+ else
53
+ idxfile = File.open(index_file, 'rb')
54
+ end
55
+
56
+ # read header
57
+ sig = idxfile.read(4)
58
+ ver = idxfile.read(4).unpack("N")[0]
59
+
60
+ if sig == PACK_IDX_SIGNATURE
61
+ if(ver != 2)
62
+ raise PackFormatError, "pack #@name has unknown pack file version #{ver}"
63
+ end
64
+ @version = 2
65
+ else
66
+ @version = 1
67
+ end
68
+
69
+ idx = FileWindow.new(idxfile, @version)
70
+ yield idx
71
+ idx.unmap
72
+ idxfile.close
73
+ end
74
+
75
+ def with_packfile
76
+ packfile = File.open(@name, 'rb')
77
+ yield packfile
78
+ packfile.close
79
+ end
80
+
81
+ def cache_objects
82
+ @cache = {}
83
+ with_packfile do |packfile|
84
+ each_entry do |sha, offset|
85
+ data, type = unpack_object(packfile, offset, {:caching => true})
86
+ if data
87
+ @cache[sha] = RawObject.new(OBJ_TYPES[type], data)
88
+ end
89
+ end
90
+ end
91
+ end
92
+
93
+ def name
94
+ @name
95
+ end
96
+
97
+ def close
98
+ # shouldnt be anything open now
99
+ end
100
+
101
+ # given an index file, list out the shas that it's packfile contains
102
+ def get_shas
103
+ shas = []
104
+ each_sha1 { |sha| shas << sha.unpack("H*")[0] }
105
+ shas
106
+ end
107
+
108
+ def [](sha1)
109
+ if obj = @cache[sha1]
110
+ return obj
111
+ end
112
+
113
+ offset = find_object(sha1)
114
+ return nil if !offset
115
+ @cache[sha1] = obj = parse_object(offset)
116
+ return obj
117
+ end
118
+
119
+ def init_pack
120
+ with_idx do |idx|
121
+ @offsets = [0]
122
+ FanOutCount.times do |i|
123
+ pos = idx[i * IdxOffsetSize,IdxOffsetSize].unpack('N')[0]
124
+ if pos < @offsets[i]
125
+ raise PackFormatError, "pack #@name has discontinuous index #{i}"
126
+ end
127
+ @offsets << pos
128
+ end
129
+ @size = @offsets[-1]
130
+ end
131
+ end
132
+
133
+ def each_entry
134
+ with_idx do |idx|
135
+ if @version == 2
136
+ data = read_data_v2(idx)
137
+ data.each do |sha1, crc, offset|
138
+ yield sha1, offset
139
+ end
140
+ else
141
+ pos = OffsetStart
142
+ @size.times do
143
+ offset = idx[pos,OffsetSize].unpack('N')[0]
144
+ sha1 = idx[pos+OffsetSize,SHA1Size]
145
+ pos += EntrySize
146
+ yield sha1, offset
147
+ end
148
+ end
149
+ end
150
+ end
151
+
152
+ def read_data_v2(idx)
153
+ data = []
154
+ pos = OffsetStart
155
+ @size.times do |i|
156
+ data[i] = [idx[pos,SHA1Size], 0, 0]
157
+ pos += SHA1Size
158
+ end
159
+ @size.times do |i|
160
+ crc = idx[pos,CrcSize]
161
+ data[i][1] = crc
162
+ pos += CrcSize
163
+ end
164
+ @size.times do |i|
165
+ offset = idx[pos,OffsetSize].unpack('N')[0]
166
+ data[i][2] = offset
167
+ pos += OffsetSize
168
+ end
169
+ data
170
+ end
171
+ private :read_data_v2
172
+
173
+ def each_sha1
174
+ with_idx do |idx|
175
+ if @version == 2
176
+ data = read_data_v2(idx)
177
+ data.each do |sha1, crc, offset|
178
+ yield sha1
179
+ end
180
+ else
181
+ pos = SHA1Start
182
+ @size.times do
183
+ sha1 = idx[pos,SHA1Size]
184
+ pos += EntrySize
185
+ yield sha1
186
+ end
187
+ end
188
+ end
189
+ end
190
+
191
+ def find_object_in_index(idx, sha1)
192
+ slot = sha1.getord(0)
193
+ return nil if !slot
194
+ first, last = @offsets[slot,2]
195
+ while first < last
196
+ mid = (first + last) / 2
197
+ if @version == 2
198
+ midsha1 = idx[OffsetStart + (mid * SHA1Size), SHA1Size]
199
+ cmp = midsha1 <=> sha1
200
+
201
+ if cmp < 0
202
+ first = mid + 1
203
+ elsif cmp > 0
204
+ last = mid
205
+ else
206
+ pos = OffsetStart + (@size * (SHA1Size + CrcSize)) + (mid * OffsetSize)
207
+ offset = idx[pos, OffsetSize].unpack('N')[0]
208
+ return offset
209
+ end
210
+ else
211
+ midsha1 = idx[SHA1Start + mid * EntrySize,SHA1Size]
212
+ cmp = midsha1 <=> sha1
213
+
214
+ if cmp < 0
215
+ first = mid + 1
216
+ elsif cmp > 0
217
+ last = mid
218
+ else
219
+ pos = OffsetStart + mid * EntrySize
220
+ offset = idx[pos,OffsetSize].unpack('N')[0]
221
+ return offset
222
+ end
223
+ end
224
+ end
225
+ nil
226
+ end
227
+
228
+ def find_object(sha1)
229
+ obj = nil
230
+ with_idx do |idx|
231
+ obj = find_object_in_index(idx, sha1)
232
+ end
233
+ obj
234
+ end
235
+ private :find_object
236
+
237
+ def parse_object(offset)
238
+ obj = nil
239
+ with_packfile do |packfile|
240
+ data, type = unpack_object(packfile, offset)
241
+ obj = RawObject.new(OBJ_TYPES[type], data)
242
+ end
243
+ obj
244
+ end
245
+ protected :parse_object
246
+
247
+ def unpack_object(packfile, offset, options = {})
248
+ obj_offset = offset
249
+ packfile.seek(offset)
250
+
251
+ c = packfile.read(1).getord(0)
252
+ size = c & 0xf
253
+ type = (c >> 4) & 7
254
+ shift = 4
255
+ offset += 1
256
+ while c & 0x80 != 0
257
+ c = packfile.read(1).getord(0)
258
+ size |= ((c & 0x7f) << shift)
259
+ shift += 7
260
+ offset += 1
261
+ end
262
+
263
+ return [false, false] if !(type == OBJ_COMMIT || type == OBJ_TREE) && options[:caching]
264
+
265
+ case type
266
+ when OBJ_OFS_DELTA, OBJ_REF_DELTA
267
+ data, type = unpack_deltified(packfile, type, offset, obj_offset, size, options)
268
+ #puts type
269
+ when OBJ_COMMIT, OBJ_TREE, OBJ_BLOB, OBJ_TAG
270
+ data = unpack_compressed(offset, size)
271
+ else
272
+ raise PackFormatError, "invalid type #{type}"
273
+ end
274
+ [data, type]
275
+ end
276
+ private :unpack_object
277
+
278
+ def unpack_deltified(packfile, type, offset, obj_offset, size, options = {})
279
+ packfile.seek(offset)
280
+ data = packfile.read(SHA1Size)
281
+
282
+ if type == OBJ_OFS_DELTA
283
+ i = 0
284
+ c = data.getord(i)
285
+ base_offset = c & 0x7f
286
+ while c & 0x80 != 0
287
+ c = data.getord(i += 1)
288
+ base_offset += 1
289
+ base_offset <<= 7
290
+ base_offset |= c & 0x7f
291
+ end
292
+ base_offset = obj_offset - base_offset
293
+ offset += i + 1
294
+ else
295
+ base_offset = find_object(data)
296
+ offset += SHA1Size
297
+ end
298
+
299
+ base, type = unpack_object(packfile, base_offset)
300
+
301
+ return [false, false] if !(type == OBJ_COMMIT || type == OBJ_TREE) && options[:caching]
302
+
303
+ delta = unpack_compressed(offset, size)
304
+ [patch_delta(base, delta), type]
305
+ end
306
+ private :unpack_deltified
307
+
308
+ def unpack_compressed(offset, destsize)
309
+ outdata = ""
310
+ with_packfile do |packfile|
311
+ packfile.seek(offset)
312
+ zstr = Zlib::Inflate.new
313
+ while outdata.size < destsize
314
+ indata = packfile.read(4096)
315
+ if indata.size == 0
316
+ raise PackFormatError, 'error reading pack data'
317
+ end
318
+ outdata += zstr.inflate(indata)
319
+ end
320
+ if outdata.size > destsize
321
+ raise PackFormatError, 'error reading pack data'
322
+ end
323
+ zstr.close
324
+ end
325
+ outdata
326
+ end
327
+ private :unpack_compressed
328
+
329
+ def patch_delta(base, delta)
330
+ src_size, pos = patch_delta_header_size(delta, 0)
331
+ if src_size != base.size
332
+ raise PackFormatError, 'invalid delta data'
333
+ end
334
+
335
+ dest_size, pos = patch_delta_header_size(delta, pos)
336
+ dest = ""
337
+ while pos < delta.size
338
+ c = delta.getord(pos)
339
+ pos += 1
340
+ if c & 0x80 != 0
341
+ pos -= 1
342
+ cp_off = cp_size = 0
343
+ cp_off = delta.getord(pos += 1) if c & 0x01 != 0
344
+ cp_off |= delta.getord(pos += 1) << 8 if c & 0x02 != 0
345
+ cp_off |= delta.getord(pos += 1) << 16 if c & 0x04 != 0
346
+ cp_off |= delta.getord(pos += 1) << 24 if c & 0x08 != 0
347
+ cp_size = delta.getord(pos += 1) if c & 0x10 != 0
348
+ cp_size |= delta.getord(pos += 1) << 8 if c & 0x20 != 0
349
+ cp_size |= delta.getord(pos += 1) << 16 if c & 0x40 != 0
350
+ cp_size = 0x10000 if cp_size == 0
351
+ pos += 1
352
+ dest += base[cp_off,cp_size]
353
+ elsif c != 0
354
+ dest += delta[pos,c]
355
+ pos += c
356
+ else
357
+ raise PackFormatError, 'invalid delta data'
358
+ end
359
+ end
360
+ dest
361
+ end
362
+ private :patch_delta
363
+
364
+ def patch_delta_header_size(delta, pos)
365
+ size = 0
366
+ shift = 0
367
+ begin
368
+ c = delta.getord(pos)
369
+ if c == nil
370
+ raise PackFormatError, 'invalid delta header'
371
+ end
372
+ pos += 1
373
+ size |= (c & 0x7f) << shift
374
+ shift += 7
375
+ end while c & 0x80 != 0
376
+ [size, pos]
377
+ end
378
+ private :patch_delta_header_size
379
+ end
380
+ end
381
+ end
382
+ end
@@ -0,0 +1,37 @@
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
+ #
8
+ # provides native ruby access to git objects and pack files
9
+ #
10
+
11
+ require 'digest/sha1'
12
+
13
+ module Grit
14
+ module GitRuby
15
+ module Internal
16
+ OBJ_NONE = 0
17
+ OBJ_COMMIT = 1
18
+ OBJ_TREE = 2
19
+ OBJ_BLOB = 3
20
+ OBJ_TAG = 4
21
+
22
+ OBJ_TYPES = [nil, :commit, :tree, :blob, :tag].freeze
23
+
24
+ class RawObject
25
+ attr_accessor :type, :content
26
+ def initialize(type, content)
27
+ @type = type
28
+ @content = content
29
+ end
30
+
31
+ def sha1
32
+ Digest::SHA1.digest("%s %d\0" % [@type, @content.length] + @content)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end