lib/gitrb/repository.rb in gitrb-0.0.5 vs lib/gitrb/repository.rb in gitrb-0.0.6
- old
+ new
@@ -20,16 +20,28 @@
class NotFound < StandardError; end
class Repository
attr_reader :path, :index, :root, :branch, :lock_file, :head, :encoding
+ SHA_PATTERN = /[A-Fa-f0-9]{5,40}/
+ REVISION_PATTERN = /[\w\-\.]+([\^~](\d+)?)*/
+
+ # Encoding stuff
+ DEFAULT_ENCODING = 'utf-8'
+
+ if RUBY_VERSION > '1.9'
+ def set_encoding(s); s.force_encoding(@encoding); end
+ else
+ def set_encoding(s); s; end
+ end
+
# Initialize a repository.
def initialize(options = {})
@bare = options[:bare] || false
@branch = options[:branch] || 'master'
@logger = options[:logger] || Logger.new(nil)
- @encoding = options[:encoding] || 'utf-8'
+ @encoding = options[:encoding] || DEFAULT_ENCODING
@path = options[:path]
@path.chomp!('/')
@path += '/.git' if !@bare
@@ -47,22 +59,10 @@
load_packs
load
end
- # Encode string
- if RUBY_VERSION > '1.9'
- def encode(s)
- # We have binary data which has to be encoded
- s.force_encoding(@encoding)
- end
- else
- def encode(s)
- s
- end
- end
-
# Bare repository?
def bare?
@bare
end
@@ -87,13 +87,19 @@
Thread.current['gitrb_repository_lock']
end
# Diff
def diff(from, to, path = nil)
- from = from.id if Commit === from
- to = to.id if Commit === to
- Diff.new(from, to, git_diff('--full-index', from, to, '--', path))
+ if from && !(Commit === from)
+ raise ArgumentError if !(String === from)
+ from = Reference.new(:repository => self, :id => from)
+ end
+ if !(Commit === to)
+ raise ArgumentError if !(String === to)
+ to = Reference.new(:repository => self, :id => to)
+ end
+ Diff.new(from, to, git_diff_tree('--root', '-u', '--full-index', from && from.id, to.id, '--', path))
end
# All changes made inside a transaction are atomic. If some
# exception occurs the transaction will be rolled back.
#
@@ -153,52 +159,65 @@
:committer => User.new(data[6], data[7], Time.at(data[8].to_i)),
:message => message.strip)
end
commits
rescue => ex
- return [] if ex.message =~ /bad default revision 'HEAD'/
+ return [] if ex.message =~ /bad default revision 'HEAD'/i
raise
end
# Get an object by its id.
#
# Returns a tree, blob, commit or tag object.
def get(id)
- return nil if id.nil? || id.length < 5
- list = @objects.find(id).to_a
- return list.first if list.size == 1
+ raise NotFound, "No id given" if id.nil?
+ if id =~ SHA_PATTERN
+ raise NotFound, "Sha too short" if id.length < 5
+ list = @objects.find(id).to_a
+ return list.first if list.size == 1
+ elsif id =~ REVISION_PATTERN
+ list = git_rev_parse(id).split("\n") rescue nil
+ raise NotFound, "Revision not found" if !list || list.empty?
+ raise NotFound, "Revision is ambiguous" if list.size > 1
+ id = list.first
+ end
@logger.debug "gitrb: Loading #{id}"
path = object_path(id)
if File.exists?(path) || (glob = Dir.glob(path + '*')).size >= 1
if glob
- raise NotFound, "Sha not unique" if glob.size > 1
- path = glob[0]
+ raise NotFound, "Sha is ambiguous" if glob.size > 1
+ path = glob.first
+ id = path[-41..-40] + path[-38..-1]
end
- buf = File.open(path, "rb") { |f| f.read }
+ buf = File.open(path, 'rb') { |f| f.read }
raise NotFound, "Not a loose object: #{id}" if !legacy_loose_object?(buf)
header, content = Zlib::Inflate.inflate(buf).split("\0", 2)
type, size = header.split(' ', 2)
raise NotFound, "Bad object: #{id}" if content.length != size.to_i
else
- list = @packs.find(id).to_a
- raise NotFound, "Object not found" if list.size != 1
+ trie = @packs.find(id)
+ raise NotFound, "Object not found" if !trie
+ id += trie.key[-(41 - id.length)...-1]
+
+ list = trie.to_a
+ raise NotFound, "Sha is ambiguous" if list.size > 1
+
pack, offset = list.first
content, type = pack.get_object(offset)
end
- raise NotFound, "Object not found" if !type
-
@logger.debug "gitrb: Loaded #{id}"
- object = Gitrb::Object.factory(type, :repository => self, :id => encode(id), :data => content)
+ set_encoding(id)
+ object = Gitrb::Object.factory(type, :repository => self, :id => id, :data => content)
@objects.insert(id, object)
object
end
def get_tree(id) get_type(id, 'tree') end
@@ -223,10 +242,11 @@
end
end
@logger.debug "gitrb: Stored #{id}"
+ set_encoding(id)
object.repository = self
object.id = id
@objects.insert(id, object)
object
@@ -240,14 +260,15 @@
cmd = cmd[4..-1].tr('_', '-')
cmd = "git #{cmd} #{args} 2>&1"
@logger.debug "gitrb: #{cmd}"
+ # Read in binary mode (ascii-8bit) and convert afterwards
out = if block_given?
- IO.popen(cmd, &block)
- else
- `#{cmd}`.chomp
+ IO.popen(cmd, 'rb', &block)
+ else
+ set_encoding IO.popen(cmd, 'rb') {|io| io.read }
end
if $?.exitstatus > 0
return '' if $?.exitstatus == 1 && out == ''
raise RuntimeError, "#{cmd}: #{out}"
@@ -383,10 +404,10 @@
def write_head_id(id)
File.open(head_path, "wb") {|file| file.write(id) }
end
def legacy_loose_object?(buf)
- Util.ord(buf, 0) == 0x78 && ((Util.ord(buf, 0) << 8) + Util.ord(buf, 1)) % 31 == 0
+ buf[0].ord == 0x78 && ((buf[0].ord << 8) | buf[1].ord) % 31 == 0
end
end
end