diff options
-rw-r--r-- | README | 35 | ||||
-rw-r--r-- | lib/git.rb | 5 | ||||
-rw-r--r-- | lib/git/base.rb | 10 | ||||
-rw-r--r-- | lib/git/commit.rb | 4 | ||||
-rw-r--r-- | lib/git/lib.rb | 46 | ||||
-rw-r--r-- | lib/git/log.rb | 62 | ||||
-rw-r--r-- | lib/git/object.rb | 64 | ||||
-rw-r--r-- | tests/files/working/example.txt | 64 | ||||
-rw-r--r-- | tests/units/test_log.rb | 29 | ||||
-rw-r--r-- | tests/units/test_object.rb | 58 |
10 files changed, 263 insertions, 114 deletions
@@ -25,7 +25,6 @@ Git::Remote << Git::Repository require 'git' - # needs read permission only g = Git.open (working_dir = '.') @@ -37,21 +36,20 @@ g.index.writable? g.repo g.dir -********** - g.log # returns array of Git::Commit objects -g.log.stat -g.log.stat.summary g.log.since('2 weeks ago') g.log.between('v2.5', 'v2.6') -g.log('Makefile').since('v2.5') +g.log.since('v2.5').file('Makefile') +g.log.each {|l| puts l.sha } -g.status +********** + + +g.object('HEAD^').to_s # git show / git rev-parse + +g.rev_parse('HEAD^') +g.rev_parse('v2.5:Makefile') # returns Git::Object -g.diff -g.diff_cached -g.diff(commit1, commit2) -g.diff("commit1..commit2") g.file('flim/ChangeLog').tags.each {|tag,rev| p [tag,rev.to_s]} g.file('flim/ChangeLog').logs.each { |log| log.sha } @@ -60,13 +58,10 @@ g.branches # returns Git::Branch objects g.branches.local g.branches.remote -g.show(Git::Sha) -g.show('HEAD^') -g.show('HEAD^', Git::File) -g.show(Git::Object) +g.status + +g.tag # returns array of Git::Tag objects -g.rev_parse('HEAD^') -g.rev_parse('v2.5:Makefile') # returns Git::Object g.grep('hello') g.grep('hello', Git::Tag) @@ -74,9 +69,13 @@ g.grep('hello', Git::Tag) g.ls_files g.ls_files(:stage => true) +g.diff +g.diff_cached +g.diff(commit1, commit2) +g.diff("commit1..commit2") + g.diff_tree(Git::Tree, Git::Tree) -g.tag # returns array of Git::Tag objects c = Git::Commit.new("HEAD^^") c = Git::Commit.new("394839") @@ -15,13 +15,8 @@ require 'git/working_directory' require 'git/log' require 'git/object' -require 'git/commit' - =begin -require 'git/object/blob' -require 'git/object/tree' -require 'git/object/tag' require 'git/author' require 'git/ref' diff --git a/lib/git/base.rb b/lib/git/base.rb index c943b86..3c10389 100644 --- a/lib/git/base.rb +++ b/lib/git/base.rb @@ -49,6 +49,11 @@ module Git @index end + # factory methods + + def object(objectish) + Git::Object.new(self, objectish) + end def log(count = 30) Git::Log.new(self, count) @@ -57,11 +62,6 @@ module Git def lib Git::Lib.new(self) end - - private - - def is_git_dir(dir) - end end diff --git a/lib/git/commit.rb b/lib/git/commit.rb deleted file mode 100644 index 1cd5d1d..0000000 --- a/lib/git/commit.rb +++ /dev/null @@ -1,4 +0,0 @@ -module Git - class Commit < Git::Object - end -end
\ No newline at end of file diff --git a/lib/git/lib.rb b/lib/git/lib.rb index 3df049c..595f294 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -1,21 +1,57 @@ module Git + + class GitExecuteError < StandardError + end + class Lib - + @base = nil def initialize(base) @base = base end - def log_shas(count) - command('log', "-#{count} --pretty=oneline").split("\n").map { |l| Git::Commit.new(l.split.first) } + def log_commits(opts) + arr_opts = ['--pretty=oneline'] + arr_opts << "-#{opts[:count]}" if opts[:count] + arr_opts << "--since=\"#{opts[:since]}\"" if opts[:since].is_a? String + arr_opts << "#{opts[:between][0]}..#{opts[:between][1].to_s}" if (opts[:between] && opts[:between].size == 2) + arr_opts << opts[:file] if opts[:file].is_a? String + + command('log', arr_opts).split("\n").map { |l| Git::Commit.new(l.split.first) } + end + + def revparse(string) + command('rev-parse', string) + end + + def object_type(sha) + command('cat-file', ['-t', sha]) + end + + def object_size(sha) + command('cat-file', ['-s', sha]) + end + + def object_contents(sha) + command('cat-file', ['-p', sha]) end private def command(cmd, opts) - ENV['GIT_DIR'] = @base.repo.path - `git #{cmd} #{opts}` + ENV['GIT_DIR'] = @base.repo.path + ENV['GIT_INDEX_FILE'] = @base.index.path + ENV['GIT_WORK_DIR'] = @base.dir.path + Dir.chdir(@base.dir.path) do + opts = opts.to_a.join(' ') + #puts "git #{cmd} #{opts}" + out = `git #{cmd} #{opts} 2>&1`.chomp + if $?.exitstatus != 0 + raise Git::GitExecuteError.new(out) + end + out + end end end diff --git a/lib/git/log.rb b/lib/git/log.rb index fab605e..d11a6fa 100644 --- a/lib/git/log.rb +++ b/lib/git/log.rb @@ -7,29 +7,79 @@ module Git @base = nil @commits = nil + @file = nil + @count = nil + @since = nil + @between = nil + + @dirty_flag = nil + def initialize(base, count = 30) + dirty_log @base = base - @commits = @base.lib.log_shas(count) + @count = count + end + + def file(file) + dirty_log + @file = file + return self + end + + def since(date) + dirty_log + @since = date + return self + end + + def between(sha1, sha2 = nil) + dirty_log + @between = [@base.lib.revparse(sha1), @base.lib.revparse(sha2)] + return self + end + + def to_s + self.map { |c| c.sha }.join("\n") end + + # forces git log to run + def size - @commits.size + check_log + @commits.size rescue nil end def each + check_log @commits.each do |c| yield c end end def first - @commits.first + check_log + @commits.first rescue nil end - def to_s - self.map { |c| c.sha }.join("\n") - end + private + def dirty_log + @dirty_flag = true + end + + def check_log + if @dirty_flag + run_log + @dirty_flag = false + end + end + + # actually run the 'git log' command + def run_log + @commits = @base.lib.log_commits(:count => @count, :file => @file, :since => @since, :between => @between) + end + end end
\ No newline at end of file diff --git a/lib/git/object.rb b/lib/git/object.rb index 0252fdb..9346b87 100644 --- a/lib/git/object.rb +++ b/lib/git/object.rb @@ -1,16 +1,68 @@ module Git class Object - attr_accessor :sha, :type - def initialize(sha) - @sha = sha - end + class AbstractObject + attr_accessor :sha, :size, :type + + @base = nil + + def initialize(base, sha) + @base = base + @sha = sha + @size = @base.lib.object_size(@sha) + setup + end - def cat_file + def contents + @base.lib.object_contents(@sha) + end + + def contents_array + self.contents.split("\n") + end + + def setup + raise NotImplementedError + end + end + - def raw + class Blob < AbstractObject + def setup + @type = 'blob' + end + end + + class Tree < AbstractObject + def setup + @type = 'tree' + end + end + + class Commit < AbstractObject + def setup + @type = 'commit' + end end + + + class << self + # if we're calling this, we don't know what type it is yet + # so this is our little factory method + def new(base, objectish) + sha = base.lib.revparse(objectish) + type = base.lib.object_type(sha) + + klass = + case type + when /blob/: Blob + when /commit/: Commit + when /tree/: Tree + end + klass::new(base, sha) + end + end end end
\ No newline at end of file diff --git a/tests/files/working/example.txt b/tests/files/working/example.txt index 8a3fb74..1f09f2e 100644 --- a/tests/files/working/example.txt +++ b/tests/files/working/example.txt @@ -1,63 +1 @@ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +replace with new text diff --git a/tests/units/test_log.rb b/tests/units/test_log.rb index 4dd6a2f..ddd4988 100644 --- a/tests/units/test_log.rb +++ b/tests/units/test_log.rb @@ -10,10 +10,10 @@ class TestInit < Test::Unit::TestCase def test_get_log_entries log = @git.log - assert(log.first.is_a? Git::Commit) + assert(log.first.is_a?(Git::Commit)) end - def test_get_log_entries + def test_get_log_entries assert_equal(30, @git.log.size) assert_equal(50, @git.log(50).size) assert_equal(10, @git.log(10).size) @@ -23,4 +23,29 @@ class TestInit < Test::Unit::TestCase assert_equal(@git.log.to_s.split("\n").first, @git.log.first.sha) end + def test_get_log_since + l = @git.log.since("2 seconds ago") + assert_equal(0, l.size) + + l = @git.log.since("2 years ago") + assert_equal(30, l.size) + end + + def test_get_log_since_file + l = @git.log.file('example.txt') + assert_equal(30, l.size) + + l = @git.log.between('v2.5').file('example.txt') + assert_equal(1, l.size) + + l = @git.log.between('v2.5', 'test').file('example.txt') + assert_equal(1, l.size) + end + + def test_log_file_noexist + assert_raise Git::GitExecuteError do + @git.log.file('no-exist.txt').size + end + end + end diff --git a/tests/units/test_object.rb b/tests/units/test_object.rb new file mode 100644 index 0000000..610a640 --- /dev/null +++ b/tests/units/test_object.rb @@ -0,0 +1,58 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../test_helper' + +class TestInit < Test::Unit::TestCase + def setup + set_file_paths + @git = Git.open(@wdir) + end + + def test_commit + o = @git.object('1cc8667014381') + assert(o.is_a?(Git::Object::Commit)) + + o = @git.object('HEAD') + assert(o.is_a?(Git::Object::Commit)) + assert_equal('commit', o.type) + + o = @git.object('test_object') + assert(o.is_a?(Git::Object::Commit)) + assert_equal('commit', o.type) + end + + def test_commit_contents + o = @git.object('1cc8667014381') + assert_equal('tree 94c827875e2cadb8bc8d4cdd900f19aa9e8634c7', o.contents_array[0]) + assert_equal('parent 546bec6f8872efa41d5d97a369f669165ecda0de', o.contents_array[1]) + end + + def test_tree + o = @git.object('1cc8667014381^{tree}') + assert(o.is_a?(Git::Object::Tree)) + + o = @git.object('94c827875e2cadb8bc8d4cdd900f19aa9e8634c7') + assert(o.is_a?(Git::Object::Tree)) + assert_equal('tree', o.type) + end + + def test_tree_contents + o = @git.object('1cc8667014381^{tree}') + assert_equal('040000 tree 6b790ddc5eab30f18cabdd0513e8f8dac0d2d3ed ex_dir', o.contents_array.first) + end + + def test_blob + o = @git.object('ba492c62b6') + assert(o.is_a?(Git::Object::Blob)) + + o = @git.object('v2.5:example.txt') + assert(o.is_a?(Git::Object::Blob)) + assert_equal('blob', o.type) + end + + def test_blob_contents + o = @git.object('v2.6:example.txt') + assert_equal('replace with new text', o.contents) + end + +end
\ No newline at end of file |