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