summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README35
-rw-r--r--lib/git.rb5
-rw-r--r--lib/git/base.rb10
-rw-r--r--lib/git/commit.rb4
-rw-r--r--lib/git/lib.rb46
-rw-r--r--lib/git/log.rb62
-rw-r--r--lib/git/object.rb64
-rw-r--r--tests/files/working/example.txt64
-rw-r--r--tests/units/test_log.rb29
-rw-r--r--tests/units/test_object.rb58
10 files changed, 263 insertions, 114 deletions
diff --git a/README b/README
index a5f93f8..b47fac0 100644
--- a/README
+++ b/README
@@ -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")
diff --git a/lib/git.rb b/lib/git.rb
index c8e14ad..91c3e0f 100644
--- a/lib/git.rb
+++ b/lib/git.rb
@@ -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