gifts 0.0.1

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