Ruby/Git?

Hi

I’ve been working with subversion for some time now and thought I’d have
a look at trying one of the distributed SCMs. I read about many of them,
and ended up with a choice between mercurial and git.

Since both seem to be quite similar, and mercurial is written in python,
I was wondering if someone is working (or at least thinking of) writing
ruby wrappers for git, so we could get rid of the stinky shell scripts
from cogito.

Any git users here at all? I wonder if there’s a libgit that could be
wrapped in an extension…

Regards,
Andre

Andre N. wrote:

Hi

Hi.

Any git users here at all? I wonder if there’s a libgit that could be
wrapped in an extension…

Check out the bottom figure caption of Why’s shiny new page:

http://code.whytheluckystiff.net/

Later,

On Thu, 2006-09-28 at 04:20 +0900, Bil K. wrote:

Check out the bottom figure caption of Why’s shiny new page:

Yeah, I saw that… well at least he didn’t have to wait the 2 centuries
it takes to compile Monotone…

Andre

Andre N. [email protected] writes:

On Thu, 2006-09-28 at 04:20 +0900, Bil K. wrote:

Check out the bottom figure caption of Why’s shiny new page:

Yeah, I saw that… well at least he didn’t have to wait the 2 centuries
it takes to compile Monotone…

That’s still nothing compared to darcs and GHC. :slight_smile:

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)
}