Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

138 lines (119 sloc) 4.044 kb
#
# converted from the gitrb project
#
# authors:
# Matthias Lederhofer <matled@gmx.net>
# Simon 'corecode' Schubert <corecode@fs.ei.tum.de>
# Scott Chacon <schacon@gmail.com>
#
# provides native ruby access to git objects and pack files
#
require 'zlib'
require 'digest/sha1'
require 'grit/git-ruby/internal/raw_object'
module Grit
module GitRuby
module Internal
class LooseObjectError < StandardError
end
class LooseStorage
def initialize(directory)
@directory = directory
end
def [](sha1)
sha1 = sha1.unpack("H*")[0]
begin
return nil unless sha1[0...2] && sha1[2..39]
path = @directory + '/' + sha1[0...2] + '/' + sha1[2..39]
get_raw_object(open(path, 'rb') { |f| f.read })
rescue Errno::ENOENT
nil
end
end
def get_raw_object(buf)
if buf.bytesize < 2
raise LooseObjectError, "object file too small"
end
if legacy_loose_object?(buf)
content = Zlib::Inflate.inflate(buf)
header, content = content.split(/\0/, 2)
if !header || !content
raise LooseObjectError, "invalid object header"
end
type, size = header.split(/ /, 2)
if !%w(blob tree commit tag).include?(type) || size !~ /^\d+$/
raise LooseObjectError, "invalid object header"
end
type = type.to_sym
size = size.to_i
else
type, size, used = unpack_object_header_gently(buf)
content = Zlib::Inflate.inflate(buf[used..-1])
end
raise LooseObjectError, "size mismatch" if content.bytesize != size
return RawObject.new(type, content)
end
# currently, I'm using the legacy format because it's easier to do
# this function takes content and a type and writes out the loose object and returns a sha
def put_raw_object(content, type)
size = content.bytesize.to_s
LooseStorage.verify_header(type, size)
header = "#{type} #{size}\0"
store = header + content
sha1 = Digest::SHA1.hexdigest(store)
path = @directory+'/'+sha1[0...2]+'/'+sha1[2..40]
if !File.exists?(path)
content = Zlib::Deflate.deflate(store)
FileUtils.mkdir_p(@directory+'/'+sha1[0...2])
File.open(path, 'wb') do |f|
f.write content
end
end
return sha1
end
# simply figure out the sha
def self.calculate_sha(content, type)
size = content.bytesize.to_s
verify_header(type, size)
header = "#{type} #{size}\0"
store = header + content
Digest::SHA1.hexdigest(store)
end
def self.verify_header(type, size)
if !%w(blob tree commit tag).include?(type) || size !~ /^\d+$/
raise LooseObjectError, "invalid object header"
end
end
# private
def unpack_object_header_gently(buf)
used = 0
c = buf.getord(used)
used += 1
type = (c >> 4) & 7;
size = c & 15;
shift = 4;
while c & 0x80 != 0
if buf.bytesize <= used
raise LooseObjectError, "object file too short"
end
c = buf.getord(used)
used += 1
size += (c & 0x7f) << shift
shift += 7
end
type = OBJ_TYPES[type]
if ![:blob, :tree, :commit, :tag].include?(type)
raise LooseObjectError, "invalid loose object type"
end
return [type, size, used]
end
private :unpack_object_header_gently
def legacy_loose_object?(buf)
word = (buf.getord(0) << 8) + buf.getord(1)
buf.getord(0) == 0x78 && word % 31 == 0
end
private :legacy_loose_object?
end
end
end
end
Jump to Line
Something went wrong with that request. Please try again.