From f1366b39891402b0db9de661ad181089bfd79053 Mon Sep 17 00:00:00 2001 From: scott Chacon Date: Fri, 23 Nov 2007 11:16:46 -0800 Subject: got log and cat-file moved to pure ruby --- camping/gitweb.rb | 13 ++--- lib/git/lib.rb | 27 ++++++++-- lib/git/raw/repository.rb | 109 ++++++++++++++++++++++++++++++++++++++ tests/units/test_raw_internals.rb | 41 +++++++------- 4 files changed, 162 insertions(+), 28 deletions(-) create mode 100644 lib/git/raw/repository.rb diff --git a/camping/gitweb.rb b/camping/gitweb.rb index 092649d..8dc40ba 100644 --- a/camping/gitweb.rb +++ b/camping/gitweb.rb @@ -13,6 +13,7 @@ require 'lib/git' # todo # - diff/patch between any two objects # - expand patch to entire file +# - set title properly # - grep / search function # - prettify : http://projects.wh.techno-weenie.net/changesets/3030 # - add user model (add/remove repos) @@ -90,10 +91,7 @@ module GitWeb::Controllers class View < R '/view/(\d+)' def get repo_id @repo = Repository.find repo_id - logger = Logger.new('/tmp/git.log') - logger.level = Logger::INFO - - @git = Git.bare(@repo.path, :log => logger) + @git = Git.bare(@repo.path) render :view end end @@ -109,7 +107,10 @@ module GitWeb::Controllers class Commit < R '/commit/(\d+)/(\w+)' def get repo_id, sha @repo = Repository.find repo_id - @git = Git.bare(@repo.path) + logger = Logger.new('/tmp/git.log') + logger.level = Logger::INFO + + @git = Git.bare(@repo.path, :log => logger) @commit = @git.gcommit(sha) render :commit end @@ -212,7 +213,7 @@ module GitWeb::Views body :onload => "sh_highlightDocument();" do before = Time.now().usec self << yield - self << ((Time.now().usec - before).to_f / 60).to_s + ' sec' + self << '
' + ((Time.now().usec - before).to_f / 60).to_s + ' sec' end end end diff --git a/lib/git/lib.rb b/lib/git/lib.rb index eb06875..9c6a041 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -13,6 +13,7 @@ module Git @path = nil @logger = nil + @raw_repo = nil def initialize(base = nil, logger = nil) if base.is_a?(Git::Base) @@ -75,6 +76,15 @@ module Git end def full_log_commits(opts = {}) + if !(opts[:since] || opts[:between] || opts[:path_limiter]) + # can do this in pure ruby + sha = revparse(opts[:object] || branch_current || 'master') + count = opts[:count] || 30 + + repo = Git::Raw::Repository.new(@git_dir) + return process_commit_data(repo.log(sha, count)) + end + arr_opts = ['--pretty=raw'] arr_opts << "-#{opts[:count]}" if opts[:count] arr_opts << "--since=\"#{opts[:since]}\"" if opts[:since].is_a? String @@ -92,10 +102,13 @@ module Git end head = File.join(@git_dir, 'refs', 'heads', string) - return File.read(head) if File.file?(head) + return File.read(head).chomp if File.file?(head) head = File.join(@git_dir, 'refs', 'remotes', string) - return File.read(head) if File.file?(head) + return File.read(head).chomp if File.file?(head) + + head = File.join(@git_dir, 'refs', 'tags', string) + return File.read(head).chomp if File.file?(head) command('rev-parse', string) end @@ -111,17 +124,22 @@ module Git def object_size(sha) command('cat-file', ['-s', sha]).to_i end + + def get_raw_repo + @raw_repo ||= Git::Raw::Repository.new(@git_dir) + end # returns useful array of raw commit object data def commit_data(sha) sha = sha.to_s - cdata = command_lines('cat-file', ['commit', sha]) + cdata = get_raw_repo.cat_file(revparse(sha)) + #cdata = command_lines('cat-file', ['commit', sha]) process_commit_data(cdata, sha) end def process_commit_data(data, sha = nil) in_message = false - + if sha hsh = {'sha' => sha, 'message' => '', 'parent' => []} else @@ -129,6 +147,7 @@ module Git end data.each do |line| + line = line.chomp if in_message && line != '' hsh['message'] += line + "\n" end diff --git a/lib/git/raw/repository.rb b/lib/git/raw/repository.rb new file mode 100644 index 0000000..4a1c897 --- /dev/null +++ b/lib/git/raw/repository.rb @@ -0,0 +1,109 @@ +require 'git/raw/internal/object' +require 'git/raw/internal/pack' +require 'git/raw/internal/loose' +require 'git/raw/object' + +module Git + module Raw + + class Repository + def initialize(git_dir) + @git_dir = git_dir + @loose = Raw::Internal::LooseStorage.new(git_path("objects")) + @packs = [] + initpacks + end + + def show + @packs.each do |p| + puts p.name + puts + p.each_sha1 do |s| + puts "**#{p[s].type}**" + if p[s].type.to_s == 'commit' + puts s.unpack('H*') + puts p[s].content + end + end + puts + end + end + + def cat_file(sha) + get_raw_object_by_sha1(sha).content rescue nil + end + + def log(sha, count = 30) + output = '' + i = 0 + + while sha && (i < count) do + o = get_raw_object_by_sha1(sha) + c = Git::Raw::Object.from_raw(o) + + output += "commit #{sha}\n" + output += o.content + "\n" + + sha = c.parent.first + i += 1 + end + + output + end + + def get_object_by_sha1(sha1) + r = get_raw_object_by_sha1(sha1) + return nil if !r + Object.from_raw(r, self) + end + + def get_raw_object_by_sha1(sha1) + sha1 = [sha1].pack("H*") + + # try packs + @packs.each do |pack| + o = pack[sha1] + return o if o + end + + # try loose storage + o = @loose[sha1] + return o if o + + # try packs again, maybe the object got packed in the meantime + initpacks + @packs.each do |pack| + o = pack[sha1] + return o if o + end + + nil + end + + protected + + def git_path(path) + return "#@git_dir/#{path}" + end + + private + + def initpacks + @packs.each do |pack| + pack.close + end + @packs = [] + Dir.open(git_path("objects/pack/")) do |dir| + dir.each do |entry| + if entry =~ /\.pack$/i + @packs << Git::Raw::Internal::PackStorage.new(git_path("objects/pack/" \ + + entry)) + end + end + end + end + + end + + end +end diff --git a/tests/units/test_raw_internals.rb b/tests/units/test_raw_internals.rb index 4299a2b..1437845 100644 --- a/tests/units/test_raw_internals.rb +++ b/tests/units/test_raw_internals.rb @@ -1,5 +1,5 @@ #!/usr/bin/env ruby - +require 'logger' require File.dirname(__FILE__) + '/../test_helper' class TestRawInternals < Test::Unit::TestCase @@ -10,26 +10,31 @@ class TestRawInternals < Test::Unit::TestCase def test_raw_log g = Git.bare(@wbare) - #g.repack + t_log(g) + end + + def test_packed_log + g = Git.bare(@wbare) + g.repack + t_log(g) + end + + def test_commit_object + g = Git.bare(@wbare, :log => Logger.new(STDOUT)) - c = g.object("HEAD") - puts sha = c.sha + c = g.gcommit("v2.5") + assert_equal('test', c.message) + end + + def t_log(g) + c = g.object("v2.5") + sha = c.sha repo = Git::Raw::Repository.new(@wbare) - while sha do - o = repo.get_raw_object_by_sha1(sha) - c = Git::Raw::Object.from_raw(o) - - sha = c.parent.first - puts sha - end - - g.log(60).each do |c| - puts c.sha - end - - puts c.inspect + raw_out = repo.log(sha) + assert_equal('commit 546bec6f8872efa41d5d97a369f669165ecda0de', raw_out.split("\n").first) + assert_equal('546bec6f8872efa41d5d97a369f669165ecda0de', c.log(30).first.sha) end - + end \ No newline at end of file -- cgit