Skip to content

Commit d07a2c0

Browse files
author
scott Chacon
committed
added files from the gitrb project, which seems abandoned, but which is great code
1 parent 2cef1e6 commit d07a2c0

File tree

7 files changed

+749
-0
lines changed

7 files changed

+749
-0
lines changed

lib/git/raw/git.rb

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
require 'git/internal/object'
2+
require 'git/internal/pack'
3+
require 'git/internal/loose'
4+
require 'git/object'
5+
6+
module Git
7+
class Repository
8+
def initialize(git_dir)
9+
@git_dir = git_dir
10+
@loose = Internal::LooseStorage.new(git_path("objects"))
11+
@packs = []
12+
initpacks
13+
end
14+
15+
def git_path(path)
16+
return "#@git_dir/#{path}"
17+
end
18+
19+
def get_object_by_sha1(sha1)
20+
r = get_raw_object_by_sha1(sha1)
21+
return nil if !r
22+
Object.from_raw(r, self)
23+
end
24+
25+
def get_raw_object_by_sha1(sha1)
26+
sha1 = [sha1].pack("H*")
27+
28+
# try packs
29+
@packs.each do |pack|
30+
o = pack[sha1]
31+
return o if o
32+
end
33+
34+
# try loose storage
35+
o = @loose[sha1]
36+
return o if o
37+
38+
# try packs again, maybe the object got packed in the meantime
39+
initpacks
40+
@packs.each do |pack|
41+
o = pack[sha1]
42+
return o if o
43+
end
44+
45+
nil
46+
end
47+
48+
def initpacks
49+
@packs.each do |pack|
50+
pack.close
51+
end
52+
@packs = []
53+
Dir.open(git_path("objects/pack/")) do |dir|
54+
dir.each do |entry|
55+
if entry =~ /\.pack$/i
56+
@packs << Git::Internal::PackStorage.new(git_path("objects/pack/" \
57+
+ entry))
58+
end
59+
end
60+
end
61+
end
62+
end
63+
end

lib/git/raw/internal/loose.rb

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
require 'zlib'
2+
require 'digest/sha1'
3+
4+
require 'git/raw/internal/object'
5+
6+
module Git module Raw module Internal
7+
class LooseObjectError < StandardError
8+
end
9+
10+
class LooseStorage
11+
def initialize(directory)
12+
@directory = directory
13+
end
14+
15+
def [](sha1)
16+
sha1 = sha1.unpack("H*")[0]
17+
18+
path = @directory+'/'+sha1[0...2]+'/'+sha1[2..40]
19+
begin
20+
get_raw_object(File.read(path))
21+
rescue Errno::ENOENT
22+
nil
23+
end
24+
end
25+
26+
def get_raw_object(buf)
27+
if buf.length < 2
28+
raise LooseObjectError, "object file too small"
29+
end
30+
31+
if legacy_loose_object?(buf)
32+
content = Zlib::Inflate.inflate(buf)
33+
header, content = content.split(/\0/, 2)
34+
if !header || !content
35+
raise LooseObjectError, "invalid object header"
36+
end
37+
type, size = header.split(/ /, 2)
38+
if !%w(blob tree commit tag).include?(type) || size !~ /^\d+$/
39+
raise LooseObjectError, "invalid object header"
40+
end
41+
type = type.to_sym
42+
size = size.to_i
43+
else
44+
type, size, used = unpack_object_header_gently(buf)
45+
content = Zlib::Inflate.inflate(buf[used..-1])
46+
end
47+
raise LooseObjectError, "size mismatch" if content.length != size
48+
return RawObject.new(type, content)
49+
end
50+
51+
# private
52+
def unpack_object_header_gently(buf)
53+
used = 0
54+
c = buf[used]
55+
used += 1
56+
57+
type = (c >> 4) & 7;
58+
size = c & 15;
59+
shift = 4;
60+
while c & 0x80 != 0
61+
if buf.length <= used
62+
raise LooseObjectError, "object file too short"
63+
end
64+
c = buf[used]
65+
used += 1
66+
67+
size += (c & 0x7f) << shift
68+
shift += 7
69+
end
70+
type = OBJ_TYPES[type]
71+
if ![:blob, :tree, :commit, :tag].include?(type)
72+
raise LooseObjectError, "invalid loose object type"
73+
end
74+
return [type, size, used]
75+
end
76+
private :unpack_object_header_gently
77+
78+
def legacy_loose_object?(buf)
79+
word = (buf[0] << 8) + buf[1]
80+
buf[0] == 0x78 && word % 31 == 0
81+
end
82+
private :legacy_loose_object?
83+
end
84+
end end
85+
86+
if $0 == __FILE__
87+
require 'find'
88+
ARGV.each do |path|
89+
storage = Git::Internal::LooseStorage.new(path)
90+
Find.find(path) do |p|
91+
next if !/\/([0-9a-f]{2})\/([0-9a-f]{38})$/.match(p)
92+
obj = storage[[$1+$2].pack("H*")]
93+
puts "%s %s" % [obj.sha1.unpack("H*")[0], obj.type]
94+
end
95+
end
96+
end

lib/git/raw/internal/mmap.rb

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
begin
2+
require 'mmap'
3+
rescue LoadError
4+
5+
module Git module Raw module Internal
6+
class Mmap
7+
def initialize(file)
8+
@file = file
9+
@offset = nil
10+
end
11+
12+
def unmap
13+
@file = nil
14+
end
15+
16+
def [](*idx)
17+
idx = idx[0] if idx.length == 1
18+
case idx
19+
when Range
20+
offset = idx.first
21+
len = idx.last - idx.first + idx.exclude_end? ? 0 : 1
22+
when Fixnum
23+
offset = idx
24+
len = nil
25+
when Array
26+
offset, len = idx
27+
else
28+
raise RuntimeError, "invalid index param: #{idx.class}"
29+
end
30+
if @offset != offset
31+
@file.seek(offset)
32+
end
33+
@offset = offset + len ? len : 1
34+
if not len
35+
@file.read(1)[0]
36+
else
37+
@file.read(len)
38+
end
39+
end
40+
end
41+
end end
42+
43+
end # rescue LoadError
44+

lib/git/raw/internal/object.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
require 'digest/sha1'
2+
3+
module Git module Raw module Internal
4+
OBJ_NONE = 0
5+
OBJ_COMMIT = 1
6+
OBJ_TREE = 2
7+
OBJ_BLOB = 3
8+
OBJ_TAG = 4
9+
10+
OBJ_TYPES = [nil, :commit, :tree, :blob, :tag].freeze
11+
12+
class RawObject
13+
attr_accessor :type, :content
14+
def initialize(type, content)
15+
@type = type
16+
@content = content
17+
end
18+
19+
def sha1
20+
Digest::SHA1.digest("%s %d\0" % [@type, @content.length] + @content)
21+
end
22+
end
23+
end end

0 commit comments

Comments
 (0)