jugyo-grit 2.4.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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(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,391 @@
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
+ index_file ||= @name[0...-4] + 'idx'
50
+
51
+ begin
52
+ idxfile = File.open(index_file, 'rb')
53
+ rescue Errno::ENOENT => boom
54
+ # file went away. bail out without yielding.
55
+ return
56
+ end
57
+
58
+ # read header
59
+ sig = idxfile.read(4)
60
+ ver = idxfile.read(4).unpack("N")[0]
61
+
62
+ if sig == PACK_IDX_SIGNATURE
63
+ if(ver != 2)
64
+ raise PackFormatError, "pack #@name has unknown pack file version #{ver}"
65
+ end
66
+ @version = 2
67
+ else
68
+ @version = 1
69
+ end
70
+
71
+ idx = FileWindow.new(idxfile, @version)
72
+ yield idx
73
+ idx.unmap
74
+ ensure
75
+ idxfile.close if idxfile
76
+ end
77
+
78
+ def with_packfile
79
+ begin
80
+ packfile = File.open(@name, 'rb')
81
+ rescue Errno::ENOENT
82
+ # file went away. bail out without yielding.
83
+ return
84
+ end
85
+ yield packfile
86
+ ensure
87
+ packfile.close if packfile
88
+ end
89
+
90
+ def cache_objects
91
+ @cache = {}
92
+ with_packfile do |packfile|
93
+ each_entry do |sha, offset|
94
+ data, type = unpack_object(packfile, offset, {:caching => true})
95
+ if data
96
+ @cache[sha] = RawObject.new(OBJ_TYPES[type], data)
97
+ end
98
+ end
99
+ end
100
+ end
101
+
102
+ def name
103
+ @name
104
+ end
105
+
106
+ def close
107
+ # shouldnt be anything open now
108
+ end
109
+
110
+ # given an index file, list out the shas that it's packfile contains
111
+ def get_shas
112
+ shas = []
113
+ each_sha1 { |sha| shas << sha.unpack("H*")[0] }
114
+ shas
115
+ end
116
+
117
+ def [](sha1)
118
+ if obj = @cache[sha1]
119
+ return obj
120
+ end
121
+
122
+ offset = find_object(sha1)
123
+ return nil if !offset
124
+ @cache[sha1] = obj = parse_object(offset)
125
+ return obj
126
+ end
127
+
128
+ def init_pack
129
+ with_idx do |idx|
130
+ @offsets = [0]
131
+ FanOutCount.times do |i|
132
+ pos = idx[i * IdxOffsetSize,IdxOffsetSize].unpack('N')[0]
133
+ if pos < @offsets[i]
134
+ raise PackFormatError, "pack #@name has discontinuous index #{i}"
135
+ end
136
+ @offsets << pos
137
+ end
138
+ @size = @offsets[-1]
139
+ end
140
+ end
141
+
142
+ def each_entry
143
+ with_idx do |idx|
144
+ if @version == 2
145
+ data = read_data_v2(idx)
146
+ data.each do |sha1, crc, offset|
147
+ yield sha1, offset
148
+ end
149
+ else
150
+ pos = OffsetStart
151
+ @size.times do
152
+ offset = idx[pos,OffsetSize].unpack('N')[0]
153
+ sha1 = idx[pos+OffsetSize,SHA1Size]
154
+ pos += EntrySize
155
+ yield sha1, offset
156
+ end
157
+ end
158
+ end
159
+ end
160
+
161
+ def read_data_v2(idx)
162
+ data = []
163
+ pos = OffsetStart
164
+ @size.times do |i|
165
+ data[i] = [idx[pos,SHA1Size], 0, 0]
166
+ pos += SHA1Size
167
+ end
168
+ @size.times do |i|
169
+ crc = idx[pos,CrcSize]
170
+ data[i][1] = crc
171
+ pos += CrcSize
172
+ end
173
+ @size.times do |i|
174
+ offset = idx[pos,OffsetSize].unpack('N')[0]
175
+ data[i][2] = offset
176
+ pos += OffsetSize
177
+ end
178
+ data
179
+ end
180
+ private :read_data_v2
181
+
182
+ def each_sha1
183
+ with_idx do |idx|
184
+ if @version == 2
185
+ data = read_data_v2(idx)
186
+ data.each do |sha1, crc, offset|
187
+ yield sha1
188
+ end
189
+ else
190
+ pos = SHA1Start
191
+ @size.times do
192
+ sha1 = idx[pos,SHA1Size]
193
+ pos += EntrySize
194
+ yield sha1
195
+ end
196
+ end
197
+ end
198
+ end
199
+
200
+ def find_object_in_index(idx, sha1)
201
+ slot = sha1.getord(0)
202
+ return nil if !slot
203
+ first, last = @offsets[slot,2]
204
+ while first < last
205
+ mid = (first + last) / 2
206
+ if @version == 2
207
+ midsha1 = idx[OffsetStart + (mid * SHA1Size), SHA1Size]
208
+ cmp = midsha1 <=> sha1
209
+
210
+ if cmp < 0
211
+ first = mid + 1
212
+ elsif cmp > 0
213
+ last = mid
214
+ else
215
+ pos = OffsetStart + (@size * (SHA1Size + CrcSize)) + (mid * OffsetSize)
216
+ offset = idx[pos, OffsetSize].unpack('N')[0]
217
+ return offset
218
+ end
219
+ else
220
+ midsha1 = idx[SHA1Start + mid * EntrySize,SHA1Size]
221
+ cmp = midsha1 <=> sha1
222
+
223
+ if cmp < 0
224
+ first = mid + 1
225
+ elsif cmp > 0
226
+ last = mid
227
+ else
228
+ pos = OffsetStart + mid * EntrySize
229
+ offset = idx[pos,OffsetSize].unpack('N')[0]
230
+ return offset
231
+ end
232
+ end
233
+ end
234
+ nil
235
+ end
236
+
237
+ def find_object(sha1)
238
+ obj = nil
239
+ with_idx do |idx|
240
+ obj = find_object_in_index(idx, sha1)
241
+ end
242
+ obj
243
+ end
244
+ private :find_object
245
+
246
+ def parse_object(offset)
247
+ obj = nil
248
+ with_packfile do |packfile|
249
+ data, type = unpack_object(packfile, offset)
250
+ obj = RawObject.new(OBJ_TYPES[type], data)
251
+ end
252
+ obj
253
+ end
254
+ protected :parse_object
255
+
256
+ def unpack_object(packfile, offset, options = {})
257
+ obj_offset = offset
258
+ packfile.seek(offset)
259
+
260
+ c = packfile.read(1).getord(0)
261
+ size = c & 0xf
262
+ type = (c >> 4) & 7
263
+ shift = 4
264
+ offset += 1
265
+ while c & 0x80 != 0
266
+ c = packfile.read(1).getord(0)
267
+ size |= ((c & 0x7f) << shift)
268
+ shift += 7
269
+ offset += 1
270
+ end
271
+
272
+ return [false, false] if !(type == OBJ_COMMIT || type == OBJ_TREE) && options[:caching]
273
+
274
+ case type
275
+ when OBJ_OFS_DELTA, OBJ_REF_DELTA
276
+ data, type = unpack_deltified(packfile, type, offset, obj_offset, size, options)
277
+ #puts type
278
+ when OBJ_COMMIT, OBJ_TREE, OBJ_BLOB, OBJ_TAG
279
+ data = unpack_compressed(offset, size)
280
+ else
281
+ raise PackFormatError, "invalid type #{type}"
282
+ end
283
+ [data, type]
284
+ end
285
+ private :unpack_object
286
+
287
+ def unpack_deltified(packfile, type, offset, obj_offset, size, options = {})
288
+ packfile.seek(offset)
289
+ data = packfile.read(SHA1Size)
290
+
291
+ if type == OBJ_OFS_DELTA
292
+ i = 0
293
+ c = data.getord(i)
294
+ base_offset = c & 0x7f
295
+ while c & 0x80 != 0
296
+ c = data.getord(i += 1)
297
+ base_offset += 1
298
+ base_offset <<= 7
299
+ base_offset |= c & 0x7f
300
+ end
301
+ base_offset = obj_offset - base_offset
302
+ offset += i + 1
303
+ else
304
+ base_offset = find_object(data)
305
+ offset += SHA1Size
306
+ end
307
+
308
+ base, type = unpack_object(packfile, base_offset)
309
+
310
+ return [false, false] if !(type == OBJ_COMMIT || type == OBJ_TREE) && options[:caching]
311
+
312
+ delta = unpack_compressed(offset, size)
313
+ [patch_delta(base, delta), type]
314
+ end
315
+ private :unpack_deltified
316
+
317
+ def unpack_compressed(offset, destsize)
318
+ outdata = ""
319
+ with_packfile do |packfile|
320
+ packfile.seek(offset)
321
+ zstr = Zlib::Inflate.new
322
+ while outdata.size < destsize
323
+ indata = packfile.read(4096)
324
+ if indata.size == 0
325
+ raise PackFormatError, 'error reading pack data'
326
+ end
327
+ outdata << zstr.inflate(indata)
328
+ end
329
+ if outdata.size > destsize
330
+ raise PackFormatError, 'error reading pack data'
331
+ end
332
+ zstr.close
333
+ end
334
+ outdata
335
+ end
336
+ private :unpack_compressed
337
+
338
+ def patch_delta(base, delta)
339
+ src_size, pos = patch_delta_header_size(delta, 0)
340
+ if src_size != base.size
341
+ raise PackFormatError, 'invalid delta data'
342
+ end
343
+
344
+ dest_size, pos = patch_delta_header_size(delta, pos)
345
+ dest = ""
346
+ while pos < delta.size
347
+ c = delta.getord(pos)
348
+ pos += 1
349
+ if c & 0x80 != 0
350
+ pos -= 1
351
+ cp_off = cp_size = 0
352
+ cp_off = delta.getord(pos += 1) if c & 0x01 != 0
353
+ cp_off |= delta.getord(pos += 1) << 8 if c & 0x02 != 0
354
+ cp_off |= delta.getord(pos += 1) << 16 if c & 0x04 != 0
355
+ cp_off |= delta.getord(pos += 1) << 24 if c & 0x08 != 0
356
+ cp_size = delta.getord(pos += 1) if c & 0x10 != 0
357
+ cp_size |= delta.getord(pos += 1) << 8 if c & 0x20 != 0
358
+ cp_size |= delta.getord(pos += 1) << 16 if c & 0x40 != 0
359
+ cp_size = 0x10000 if cp_size == 0
360
+ pos += 1
361
+ dest << base[cp_off,cp_size]
362
+ elsif c != 0
363
+ dest << delta[pos,c]
364
+ pos += c
365
+ else
366
+ raise PackFormatError, 'invalid delta data'
367
+ end
368
+ end
369
+ dest
370
+ end
371
+ private :patch_delta
372
+
373
+ def patch_delta_header_size(delta, pos)
374
+ size = 0
375
+ shift = 0
376
+ begin
377
+ c = delta.getord(pos)
378
+ if c == nil
379
+ raise PackFormatError, 'invalid delta header'
380
+ end
381
+ pos += 1
382
+ size |= (c & 0x7f) << shift
383
+ shift += 7
384
+ end while c & 0x80 != 0
385
+ [size, pos]
386
+ end
387
+ private :patch_delta_header_size
388
+ end
389
+ end
390
+ end
391
+ end