gifts 0.0.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 (56) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +29 -0
  5. data/Rakefile +9 -0
  6. data/gifts.gemspec +32 -0
  7. data/lib/gifts.rb +22 -0
  8. data/lib/gifts/commit_table.rb +70 -0
  9. data/lib/gifts/database.rb +49 -0
  10. data/lib/gifts/diff_table.rb +55 -0
  11. data/lib/gifts/file_table.rb +51 -0
  12. data/lib/gifts/repo_table.rb +31 -0
  13. data/lib/gifts/table_base.rb +18 -0
  14. data/lib/gifts/term_table.rb +28 -0
  15. data/lib/gifts/user_table.rb +19 -0
  16. data/lib/gifts/version.rb +3 -0
  17. data/spec/.gitkeeper +0 -0
  18. data/vendor/lib/LICENSE-grit +22 -0
  19. data/vendor/lib/LICENSE-grit_ext +22 -0
  20. data/vendor/lib/gifts/grit.rb +73 -0
  21. data/vendor/lib/gifts/grit/actor.rb +52 -0
  22. data/vendor/lib/gifts/grit/blame.rb +70 -0
  23. data/vendor/lib/gifts/grit/blob.rb +126 -0
  24. data/vendor/lib/gifts/grit/commit.rb +324 -0
  25. data/vendor/lib/gifts/grit/commit_stats.rb +128 -0
  26. data/vendor/lib/gifts/grit/config.rb +44 -0
  27. data/vendor/lib/gifts/grit/diff.rb +97 -0
  28. data/vendor/lib/gifts/grit/errors.rb +10 -0
  29. data/vendor/lib/gifts/grit/git-ruby.rb +262 -0
  30. data/vendor/lib/gifts/grit/git-ruby/commit_db.rb +52 -0
  31. data/vendor/lib/gifts/grit/git-ruby/git_object.rb +353 -0
  32. data/vendor/lib/gifts/grit/git-ruby/internal/file_window.rb +58 -0
  33. data/vendor/lib/gifts/grit/git-ruby/internal/loose.rb +137 -0
  34. data/vendor/lib/gifts/grit/git-ruby/internal/pack.rb +398 -0
  35. data/vendor/lib/gifts/grit/git-ruby/internal/raw_object.rb +44 -0
  36. data/vendor/lib/gifts/grit/git-ruby/repository.rb +784 -0
  37. data/vendor/lib/gifts/grit/git.rb +501 -0
  38. data/vendor/lib/gifts/grit/index.rb +222 -0
  39. data/vendor/lib/gifts/grit/lazy.rb +35 -0
  40. data/vendor/lib/gifts/grit/merge.rb +45 -0
  41. data/vendor/lib/gifts/grit/ref.rb +98 -0
  42. data/vendor/lib/gifts/grit/repo.rb +722 -0
  43. data/vendor/lib/gifts/grit/ruby1.9.rb +15 -0
  44. data/vendor/lib/gifts/grit/status.rb +153 -0
  45. data/vendor/lib/gifts/grit/submodule.rb +88 -0
  46. data/vendor/lib/gifts/grit/tag.rb +97 -0
  47. data/vendor/lib/gifts/grit/tree.rb +125 -0
  48. data/vendor/lib/gifts/grit_ext.rb +41 -0
  49. data/vendor/lib/gifts/grit_ext/actor.rb +15 -0
  50. data/vendor/lib/gifts/grit_ext/blob.rb +26 -0
  51. data/vendor/lib/gifts/grit_ext/commit.rb +15 -0
  52. data/vendor/lib/gifts/grit_ext/diff.rb +23 -0
  53. data/vendor/lib/gifts/grit_ext/tag.rb +10 -0
  54. data/vendor/lib/gifts/grit_ext/tree.rb +10 -0
  55. data/vendor/lib/gifts/grit_ext/version.rb +7 -0
  56. metadata +256 -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 'gifts/grit/git-ruby/internal/raw_object'
15
+
16
+ module Gifts::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(open(path, 'rb') { |f| f.read })
33
+ rescue Errno::ENOENT
34
+ nil
35
+ end
36
+ end
37
+
38
+ def get_raw_object(buf)
39
+ if buf.bytesize < 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.bytesize != 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.bytesize.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.bytesize.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.bytesize <= 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,398 @@
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 'gifts/grit/git-ruby/internal/raw_object'
14
+ require 'gifts/grit/git-ruby/internal/file_window'
15
+
16
+ PACK_SIGNATURE = "PACK"
17
+ PACK_IDX_SIGNATURE = "\377tOc".b
18
+
19
+ module Gifts::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
+ ExtendedOffsetSize = 8
34
+ CrcSize = 4
35
+ OffsetStart = FanOutCount * IdxOffsetSize
36
+ SHA1Start = OffsetStart + OffsetSize
37
+ EntrySize = OffsetSize + SHA1Size
38
+ EntrySizeV2 = SHA1Size + CrcSize + OffsetSize
39
+
40
+ def initialize(file)
41
+ if file =~ /\.idx$/
42
+ file = file[0...-3] + 'pack'
43
+ end
44
+ @name = file
45
+ @cache = {}
46
+ init_pack
47
+ end
48
+
49
+ def with_idx(index_file = nil)
50
+ index_file ||= @name[0...-4] + 'idx'
51
+
52
+ begin
53
+ idxfile = File.open(index_file, 'rb')
54
+ rescue Errno::ENOENT => boom
55
+ # file went away. bail out without yielding.
56
+ return
57
+ end
58
+
59
+ # read header
60
+ sig = idxfile.read(4)
61
+ ver = idxfile.read(4).unpack("N")[0]
62
+
63
+ if sig == PACK_IDX_SIGNATURE
64
+ if(ver != 2)
65
+ raise PackFormatError, "pack #@name has unknown pack file version #{ver}"
66
+ end
67
+ @version = 2
68
+ else
69
+ @version = 1
70
+ end
71
+
72
+ idx = FileWindow.new(idxfile, @version)
73
+ yield idx
74
+ idx.unmap
75
+ ensure
76
+ idxfile.close if idxfile
77
+ end
78
+
79
+ def with_packfile
80
+ begin
81
+ packfile = File.open(@name, 'rb')
82
+ rescue Errno::ENOENT
83
+ # file went away. bail out without yielding.
84
+ return
85
+ end
86
+ yield packfile
87
+ ensure
88
+ packfile.close if packfile
89
+ end
90
+
91
+ def cache_objects
92
+ @cache = {}
93
+ with_packfile do |packfile|
94
+ each_entry do |sha, offset|
95
+ data, type = unpack_object(packfile, offset, {:caching => true})
96
+ if data
97
+ @cache[sha] = RawObject.new(OBJ_TYPES[type], data)
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ def name
104
+ @name
105
+ end
106
+
107
+ def close
108
+ # shouldnt be anything open now
109
+ end
110
+
111
+ # given an index file, list out the shas that it's packfile contains
112
+ def get_shas
113
+ shas = []
114
+ each_sha1 { |sha| shas << sha.unpack("H*")[0] }
115
+ shas
116
+ end
117
+
118
+ def [](sha1)
119
+ if obj = @cache[sha1]
120
+ return obj
121
+ end
122
+
123
+ offset = find_object(sha1)
124
+ return nil if !offset
125
+ @cache[sha1] = obj = parse_object(offset)
126
+ return obj
127
+ end
128
+
129
+ def init_pack
130
+ with_idx do |idx|
131
+ @offsets = [0]
132
+ FanOutCount.times do |i|
133
+ pos = idx[i * IdxOffsetSize,IdxOffsetSize].unpack('N')[0]
134
+ if pos < @offsets[i]
135
+ raise PackFormatError, "pack #@name has discontinuous index #{i}"
136
+ end
137
+ @offsets << pos
138
+ end
139
+ @size = @offsets[-1]
140
+ end
141
+ end
142
+
143
+ def each_entry
144
+ with_idx do |idx|
145
+ if @version == 2
146
+ data = read_data_v2(idx)
147
+ data.each do |sha1, crc, offset|
148
+ yield sha1, offset
149
+ end
150
+ else
151
+ pos = OffsetStart
152
+ @size.times do
153
+ offset = idx[pos,OffsetSize].unpack('N')[0]
154
+ sha1 = idx[pos+OffsetSize,SHA1Size]
155
+ pos += EntrySize
156
+ yield sha1, offset
157
+ end
158
+ end
159
+ end
160
+ end
161
+
162
+ def read_data_v2(idx)
163
+ data = []
164
+ pos = OffsetStart
165
+ @size.times do |i|
166
+ data[i] = [idx[pos,SHA1Size], 0, 0]
167
+ pos += SHA1Size
168
+ end
169
+ @size.times do |i|
170
+ crc = idx[pos,CrcSize]
171
+ data[i][1] = crc
172
+ pos += CrcSize
173
+ end
174
+ @size.times do |i|
175
+ offset = idx[pos,OffsetSize].unpack('N')[0]
176
+ data[i][2] = offset
177
+ pos += OffsetSize
178
+ end
179
+ data
180
+ end
181
+ private :read_data_v2
182
+
183
+ def each_sha1
184
+ with_idx do |idx|
185
+ if @version == 2
186
+ data = read_data_v2(idx)
187
+ data.each do |sha1, crc, offset|
188
+ yield sha1
189
+ end
190
+ else
191
+ pos = SHA1Start
192
+ @size.times do
193
+ sha1 = idx[pos,SHA1Size]
194
+ pos += EntrySize
195
+ yield sha1
196
+ end
197
+ end
198
+ end
199
+ end
200
+
201
+ def find_object_in_index(idx, sha1)
202
+ slot = sha1.getord(0)
203
+ return nil if !slot
204
+ first, last = @offsets[slot,2]
205
+ while first < last
206
+ mid = (first + last) / 2
207
+ if @version == 2
208
+ midsha1 = idx[OffsetStart + (mid * SHA1Size), SHA1Size]
209
+ cmp = midsha1 <=> sha1
210
+
211
+ if cmp < 0
212
+ first = mid + 1
213
+ elsif cmp > 0
214
+ last = mid
215
+ else
216
+ pos = OffsetStart + (@size * (SHA1Size + CrcSize)) + (mid * OffsetSize)
217
+ offset = idx[pos, OffsetSize].unpack('N')[0]
218
+ if offset & 0x80000000 > 0
219
+ offset &= 0x7fffffff
220
+ pos = OffsetStart + (@size * (SHA1Size + CrcSize + OffsetSize)) + (offset * ExtendedOffsetSize)
221
+ words = idx[pos, ExtendedOffsetSize].unpack('NN')
222
+ offset = (words[0] << 32) | words[1]
223
+ end
224
+ return offset
225
+ end
226
+ else
227
+ midsha1 = idx[SHA1Start + mid * EntrySize,SHA1Size]
228
+ cmp = midsha1 <=> sha1
229
+
230
+ if cmp < 0
231
+ first = mid + 1
232
+ elsif cmp > 0
233
+ last = mid
234
+ else
235
+ pos = OffsetStart + mid * EntrySize
236
+ offset = idx[pos,OffsetSize].unpack('N')[0]
237
+ return offset
238
+ end
239
+ end
240
+ end
241
+ nil
242
+ end
243
+
244
+ def find_object(sha1)
245
+ obj = nil
246
+ with_idx do |idx|
247
+ obj = find_object_in_index(idx, sha1)
248
+ end
249
+ obj
250
+ end
251
+ private :find_object
252
+
253
+ def parse_object(offset)
254
+ obj = nil
255
+ with_packfile do |packfile|
256
+ data, type = unpack_object(packfile, offset)
257
+ obj = RawObject.new(OBJ_TYPES[type], data)
258
+ end
259
+ obj
260
+ end
261
+ protected :parse_object
262
+
263
+ def unpack_object(packfile, offset, options = {})
264
+ obj_offset = offset
265
+ packfile.seek(offset)
266
+
267
+ c = packfile.read(1).getord(0)
268
+ size = c & 0xf
269
+ type = (c >> 4) & 7
270
+ shift = 4
271
+ offset += 1
272
+ while c & 0x80 != 0
273
+ c = packfile.read(1).getord(0)
274
+ size |= ((c & 0x7f) << shift)
275
+ shift += 7
276
+ offset += 1
277
+ end
278
+
279
+ return [false, false] if !(type == OBJ_COMMIT || type == OBJ_TREE) && options[:caching]
280
+
281
+ case type
282
+ when OBJ_OFS_DELTA, OBJ_REF_DELTA
283
+ data, type = unpack_deltified(packfile, type, offset, obj_offset, size, options)
284
+ #puts type
285
+ when OBJ_COMMIT, OBJ_TREE, OBJ_BLOB, OBJ_TAG
286
+ data = unpack_compressed(offset, size)
287
+ else
288
+ raise PackFormatError, "invalid type #{type}"
289
+ end
290
+ [data, type]
291
+ end
292
+ private :unpack_object
293
+
294
+ def unpack_deltified(packfile, type, offset, obj_offset, size, options = {})
295
+ packfile.seek(offset)
296
+ data = packfile.read(SHA1Size)
297
+
298
+ if type == OBJ_OFS_DELTA
299
+ i = 0
300
+ c = data.getord(i)
301
+ base_offset = c & 0x7f
302
+ while c & 0x80 != 0
303
+ c = data.getord(i += 1)
304
+ base_offset += 1
305
+ base_offset <<= 7
306
+ base_offset |= c & 0x7f
307
+ end
308
+ base_offset = obj_offset - base_offset
309
+ offset += i + 1
310
+ else
311
+ base_offset = find_object(data)
312
+ offset += SHA1Size
313
+ end
314
+
315
+ base, type = unpack_object(packfile, base_offset)
316
+
317
+ return [false, false] if !(type == OBJ_COMMIT || type == OBJ_TREE) && options[:caching]
318
+
319
+ delta = unpack_compressed(offset, size)
320
+ [patch_delta(base, delta), type]
321
+ end
322
+ private :unpack_deltified
323
+
324
+ def unpack_compressed(offset, destsize)
325
+ outdata = ""
326
+ with_packfile do |packfile|
327
+ packfile.seek(offset)
328
+ zstr = Zlib::Inflate.new
329
+ while outdata.size < destsize
330
+ indata = packfile.read(4096)
331
+ if indata.size == 0
332
+ raise PackFormatError, 'error reading pack data'
333
+ end
334
+ outdata << zstr.inflate(indata)
335
+ end
336
+ if outdata.size > destsize
337
+ raise PackFormatError, 'error reading pack data'
338
+ end
339
+ zstr.close
340
+ end
341
+ outdata
342
+ end
343
+ private :unpack_compressed
344
+
345
+ def patch_delta(base, delta)
346
+ src_size, pos = patch_delta_header_size(delta, 0)
347
+ if src_size != base.size
348
+ raise PackFormatError, 'invalid delta data'
349
+ end
350
+
351
+ dest_size, pos = patch_delta_header_size(delta, pos)
352
+ dest = ""
353
+ while pos < delta.size
354
+ c = delta.getord(pos)
355
+ pos += 1
356
+ if c & 0x80 != 0
357
+ pos -= 1
358
+ cp_off = cp_size = 0
359
+ cp_off = delta.getord(pos += 1) if c & 0x01 != 0
360
+ cp_off |= delta.getord(pos += 1) << 8 if c & 0x02 != 0
361
+ cp_off |= delta.getord(pos += 1) << 16 if c & 0x04 != 0
362
+ cp_off |= delta.getord(pos += 1) << 24 if c & 0x08 != 0
363
+ cp_size = delta.getord(pos += 1) if c & 0x10 != 0
364
+ cp_size |= delta.getord(pos += 1) << 8 if c & 0x20 != 0
365
+ cp_size |= delta.getord(pos += 1) << 16 if c & 0x40 != 0
366
+ cp_size = 0x10000 if cp_size == 0
367
+ pos += 1
368
+ dest << base[cp_off,cp_size]
369
+ elsif c != 0
370
+ dest << delta[pos,c]
371
+ pos += c
372
+ else
373
+ raise PackFormatError, 'invalid delta data'
374
+ end
375
+ end
376
+ dest
377
+ end
378
+ private :patch_delta
379
+
380
+ def patch_delta_header_size(delta, pos)
381
+ size = 0
382
+ shift = 0
383
+ begin
384
+ c = delta.getord(pos)
385
+ if c == nil
386
+ raise PackFormatError, 'invalid delta header'
387
+ end
388
+ pos += 1
389
+ size |= (c & 0x7f) << shift
390
+ shift += 7
391
+ end while c & 0x80 != 0
392
+ [size, pos]
393
+ end
394
+ private :patch_delta_header_size
395
+ end
396
+ end
397
+ end
398
+ end