Andre N. [email protected] writes:
wrapped in an extension…
I gave it a try some months ago, but lost interest.
require ‘dl/import’
require ‘dl/struct’
module Git
extend DL::Importable
dlload “/Users/chris/src/git/libgit.bundle”
extern “const char *setup_git_directory()”
extern “int git_config (void*)”
extern “int git_default_config (const char *, const char *)”
extern “int get_sha1 (const char *, unsigned char *)”
extern “void *parse_tree_indirect(const unsigned char *)”
extern “int read_tree_recursive(void*, const char*, int, int, const
char*, void*)”
extern “int read_tree_recursive(void*, int, int, int, int, void*)”
extern “int sha1_object_info(const unsigned char*, void*, long*)”
extern “void* read_sha1_file(const unsigned char*, void*, long*)”
extern “int index_fd(unsigned char *, int, void *, int, const char *)”
extern “int index_pipe(unsigned char *, int, int, const char *)”
extern “void* parse_object(const unsigned char *)”
Object = struct [
“long flags”,
“char sha1[20]”,
]
TreeStruct = struct [
“void *object”,
“void *buffer”,
“long size”,
]
def self.config
git_config(symbol(‘git_default_config’, ‘ISS’))
end
def self.hash_object(thing, type=“blob”)
buf = DL.malloc(20)
if thing.kind_of? String # filename
rstat = File.stat thing
stat = DL::PtrData.new(rstat.object_id*2).to_a('P', 5).last
file = File.open(thing)
index_fd(buf, file.fileno, stat, 0, type) # will close
elsif thing.kind_of? IO
index_pipe(buf, thing.fileno, 0, type)
else
raise "Can't hash #{thing}"
end
SHA1.new buf.to_s(20)
end
class Commit
def initialize(string)
replace string
end
def replace(string)
head, @body = string.split("\n\n", 2)
@fields = {}
head.each { |line|
field, value = line.chomp.split(" ", 2)
if field == "tree" || field == "parent"
value = SHA1[value]
end
if field == "parent"
(@fields[field] ||= []) << value
else
@fields[field] = value
end
}
end
def title
@body[/.*/]
end
def [](field)
@fields[field]
end
end
class SHA1
attr_reader :data
def self.[](str)
if str.size == 20
new str
elsif str.size == 40
p str
new [str].pack("H*")
else
raise "Can't make hash object from #{str}"
end
end
def initialize(sha = '\0'*20)
@data = sha
end
def inspect
type
"#<%s:0x%x %s %s(%d)>" % [self.class.name, object_id, type, to_s,
@size]
end
def to_s
@data.unpack("C*").map { |byte| "%02x" % byte }.join
end
def type
buf = DL.malloc(16)
buf2 = DL.malloc(4)
Git.sha1_object_info(@data, buf, buf2)
@size = buf2.to_s(4).unpack("L").first
@type = buf.to_s
end
def read
buf = DL.malloc(16)
buf2 = DL.malloc(4)
buf3 = Git.read_sha1_file(@data, buf, buf2)
@size = buf2.to_s(4).unpack("L").first
@type = buf.to_s
data = buf3.to_s(@size)
case @type
when "commit"
Commit.new data
else
raise "Can't deal with #{@type} yet."
end
end
def size
type
@size
end
def parse
obj = Git.parse_object @data
Object.new obj
end
end
class Tree
def initialize(sha1)
@tree = TreeStruct.new Git.parse_tree_indirect(sha1.data)
end
READ_TREE = DL.callback("IPPIPII") {
|sha1, base, baselen, pathname, mode, stage|
s = Git::SHA1.new(sha1.to_s(20))
if base
path = base.to_s(baselen)
else
path = ""
end
path << pathname.to_s
id = path.slice!(0, 4).unpack("L").first
block = ObjectSpace._id2ref(id & ~1)
block.call [s, path, mode, stage]
id & 1
}
def each(recursive=false, &block)
Git.read_tree_recursive(@tree, [block.object_id | (recursive ? 1 :
0)].
pack(“L”), 4, 0, nil, READ_TREE)
end
end
def self.sha1(name)
buffer = DL.malloc(20)
p buffer.to_s(20)
get_sha1(name, buffer)
SHA1.new buffer.to_s(20)
end
def self.parse_tree(sha)
Tree.new parse_tree_indirect(sha.data)
end
end
Dir.chdir(File.expand_path(“~/src/git”)) {
p Git.setup_git_directory
p Git.config
x = Git.sha1(“HEAD”)
p x
p x.type
commit = x.read
while commit[‘parent’]
p commit.title
commit = commit[‘parent’].first.read
end
Git::Tree.new(x).each { |sh1, file|
p [sh1, Git::SHA1.new(sh1.parse.sha1.pack(“c*”))]
p file
}
}
END
x=Time.now
Dir.chdir(“testrep”)
1000.times {
git-hash-object Makefile
}
p Time.now-x
END
head = Git.sha1(“HEAD”)
p head
p head.type
tree = Git.parse_tree(head)
p tree
read_tree = DL.callback(“IPPIPII”) {
|sha1, base, baselen, pathname, mode, stage|
s = Git::SHA1.new(sha1.to_s(20))
p s
p s.type
if base
path = base.to_s(baselen)
else
path = “”
end
path << pathname.to_s
p path
p mode.to_s(8)
p stage
1
}
p Git.read_tree_recursive(tree, 0, 0, 0, 0, read_tree)
}