Permalink
Browse files

added bunches of options to the log() function (since, until, path_li…

…miter, etc)

added rev-list and diff_data(tree1, tree2), which are both helpful
  • Loading branch information...
1 parent cbe5952 commit 781dc3e28ee1bc82b706414bba1b5ff4e1b1b97c @schacon committed Apr 5, 2008
View
@@ -49,9 +49,13 @@ case command
when 'init'
GitRuby.init
when 'clone'
- GitRuby.clone(ARGV[1], ARGV[2])
+ if ARGV[2]
+ GitRuby.clone(ARGV[1], ARGV[2], :logger => Logger.new(STDERR))
+ else
+ puts 'please specify a name'
+ end
when 'ls-files'
- @git.index.to_s
+ puts @git.index.to_s
when 'checkout'
@git.checkout(ARGV[1])
when 'add'
@@ -65,9 +69,9 @@ when 'log'
puts l.contents
puts
end
-when 'log-shas'
+when 'rev-list'
# gitr log-shas
- puts @git.log
+ puts @git.lib.rev_list
when 'cat-file'
# gitr cat-file
puts @git.cat_file(ARGV[1])
@@ -91,6 +95,10 @@ when 'ls-tree'
tree.trees.sort.each do |name, c|
puts [[c.mode, c.type, c.sha].join(" "), name].join("\t")
end
+when 'done'
+ puts '<LtCG>i dont care who you are, thats funny right there...</LtCG>'
+else
+ puts 'command not found'
end
# todo:
View
@@ -168,10 +168,23 @@ def gblob(objectish)
# returns a Git::Log object with count commits
- def log(count = 30)
+ # :first_parent => true
+ def log(count = nil)
GitRuby::Log.new(self, count)
end
+ # rev-list returns a list of commit shas
+ # :object => tree-ish to start from
+ # :count => @count
+ # :since => @since # should be a Time object
+ # :until => @until # should be a Time object
+ # :between => @between # should be an array of 2 Time objects
+
+ # :path_limiter => @path
+ def rev_list(options = {})
+ self.lib.rev_list(options)
+ end
+
# this is a convenience method for accessing the class that wraps all the actual 'git' calls.
def lib
@lib ||= GitRuby::Lib.new(self, @logger)
View
@@ -285,16 +285,37 @@ def process_commit_data(data, sha = nil)
end
def full_log_commits(opts = {})
- # can do this in pure ruby
+ data = log_data(opts)
+ text = data.map { |a,b| b }.join("\n")
+ return process_commit_data(text)
+ end
+
+ def rev_list(opts = {})
+ data = log_data(opts)
+ data.map { |a,b| a }
+ end
+
+ def log_data(opts)
+ # resolve options
sha = revparse(opts[:object] || branch_current || 'master')
- count = opts[:count] || 30
+ if opts[:between] && opts[:between].size == 2
+ opts[:since] = opts[:between][0]
+ opts[:until] = opts[:between][1]
+ end
+ if opts[:path_limiter] && opts[:path_limiter][0,1] != '.'
+ opts[:path_limiter] = File.join('.', opts[:path_limiter])
+ end
if /\w{40}$/.match(sha) # valid sha
repo = get_raw_repo
- return process_commit_data(repo.log(sha, count))
+ return repo.log(sha, opts)
end
end
+ def diff_data(tree_sha1, tree_sha2)
+ get_raw_repo.quick_diff(tree_sha1, tree_sha2)
+ end
+
def revparse(string)
if /\w{40}/.match(string) # passing in a sha - just no-op it
return string
@@ -397,13 +418,7 @@ def object_contents(sha)
end
def ls_tree(sha)
- data = {'blob' => {}, 'tree' => {}}
-
- get_raw_repo.object(revparse(sha)).entry.each do |e|
- data[e.format_type][e.name] = {:mode => e.format_mode, :sha => e.sha1}
- end
-
- data
+ get_raw_repo.ls_tree(revparse(sha))
end
def branches_all
@@ -48,22 +48,122 @@ def cat_file(sha)
object(sha).raw_content
end
- def log(sha, count = 30)
- output = ''
- i = 0
-
- while sha && (i < count) do
+ def log(sha, options = {})
+ walk_log(sha, 0, options)
+ end
+
+ def walk_log(sha, count, opts)
+ array = []
+
+ if (sha && (!opts[:count] || (count < opts[:count])))
o = get_raw_object_by_sha1(sha)
c = GitRuby::Raw::Object.from_raw(o)
+
+ add_sha = true
+
+ if opts[:since] && opts[:since].is_a?(Time) && (opts[:since] > c.committer.date)
+ add_sha = false
+ end
+ if opts[:until] && opts[:until].is_a?(Time) && (opts[:until] < c.committer.date)
+ add_sha = false
+ end
+
+ # follow all parents unless '--first-parent' is specified #
+ subarray = []
+
+ if !c.parent.first && opts[:path_limiter] # check for the last commit
+ add_sha = false
+ end
+
+ if opts[:first_parent]
+ psha = c.parent.first
+ subarray += walk_log(psha, count + 1, opts)
+ if psha && !files_changed?(c.tree, object(psha).tree, opts[:path_limiter])
+ add_sha = false
+ end
+ else
+ c.parent.each do |psha|
+ subarray += walk_log(psha, count + 1, opts)
+ if psha && !files_changed?(c.tree, object(psha).tree, opts[:path_limiter])
+ add_sha = false
+ end
+ end
+ end
- output += "commit #{sha}\n"
- output += o.content + "\n\n"
+ if add_sha
+ output = "commit #{sha}\n"
+ output += o.content + "\n\n"
+ array << [sha, output]
+ end
- sha = c.parent.first
- i += 1
+ array += subarray
+
end
- output
+ array
+ end
+
+ # returns true if the files in path_limiter were changed, or no path limiter
+ def files_changed?(tree_sha1, tree_sha2, path_limiter = nil)
+ if path_limiter
+ mod = quick_diff(tree_sha1, tree_sha2)
+ files = mod.map { |c| c.first }
+ path_limiter.to_a.each do |filepath|
+ if files.include?(filepath)
+ return true
+ end
+ end
+ return false
+ end
+ true
+ end
+
+ def quick_diff(tree1, tree2, path = '.')
+ # handle empty trees
+ changed = []
+
+ t1 = ls_tree(tree1) if tree1
+ t2 = ls_tree(tree2) if tree2
+
+ # finding files that are different
+ t1['blob'].each do |file, hsh|
+ t2_file = t2['blob'][file] rescue nil
+ full = File.join(path, file)
+ if !t2_file
+ changed << [full, 'added', hsh[:sha], nil] # not in parent
+ elsif (hsh[:sha] != t2_file[:sha])
+ changed << [full, 'modified', hsh[:sha], t2_file[:sha]] # file changed
+ end
+ end if t1
+ t2['blob'].each do |file, hsh|
+ if !t1['blob'][file]
+ changed << [File.join(path, file), 'removed', nil, hsh[:sha]]
+ end if t1
+ end if t2
+
+ t1['tree'].each do |dir, hsh|
+ t2_tree = t2['tree'][dir] rescue nil
+ full = File.join(path, dir)
+ if !t2_tree
+ changed += quick_diff(hsh[:sha], nil, full) # recurse
+ elsif (hsh[:sha] != t2_tree[:sha])
+ changed += quick_diff(hsh[:sha], t2_tree[:sha], full) # recurse
+ end
+ end if t1
+ t2['tree'].each do |dir, hsh|
+ full = File.join(path, dir)
+ changed += quick_diff(nil, hsh[:sha], full) # recurse
+ end if t2
+
+ changed
+ end
+
+ def ls_tree(sha)
+ data = {'blob' => {}, 'tree' => {}}
+ self.object(sha).entry.each do |e|
+ data[e.format_type][e.name] = {:mode => e.format_mode, :sha => e.sha1}
+ end
+ data
end
def get_object_by_sha1(sha1)
View
@@ -32,7 +32,7 @@ def teardown
def with_temp_bare
in_temp_dir do |path|
- g = Git.clone(@wbare, 'new')
+ g = GitRuby.clone(@wbare, 'new')
Dir.chdir('new') do
yield g
end
View
@@ -14,6 +14,16 @@ def test_dumb_checkout
end
end
+ def test_diff_data
+ tr1 = 'e8bd03b163f82fba4560c11839d49361a78dec85'
+ tr2 = '33edabb4334cbe849a477a0d2893cdb768fa3091'
+ diff = @git.lib.diff_data(tr1, tr2)
+ assert_equal './example.txt', diff.first[0]
+ assert_equal 'modified', diff.first[1]
+ assert_equal '8a3fb747983bf2a7f4ef136af4bfcf7993a19307', diff.first[2]
+ assert_equal 'a115413501949f4f09811fd1aaecf136c012c7d7', diff.first[3]
+ end
+
def test_revparse
#self.lib.revparse(objectish)
end
View
@@ -1,14 +1,66 @@
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../test_helper'
+require 'date'
class TestLog < Test::Unit::TestCase
def setup
set_file_paths
+ @start_date = Time.local(2007, 11, 8, 11, 20, 38);
+ @end_date = Time.local(2007, 11, 9, 10, 29, 14)
+ @full_size = @git.rev_list.size
end
def test_log
+ assert @git.log.map { |c| c.sha }.include?('291b6be488d6abc586d3ee03ca61238766625a75')
end
- def test_log_shas
+ def test_rev_list
+ assert @git.rev_list.include?('d5b9587b65731e25216743b0caca72051a760211')
end
+
+ def test_since
+ part = @git.rev_list(:since => @start_date).size
+ assert @full_size > part
+ assert part > 0
+ end
+
+ def test_count
+ assert_equal 20, @git.rev_list(:count => 20).size
+ assert_equal 15, @git.rev_list(:count => 15).size
+ end
+
+ def test_until
+ part = @git.rev_list(:until => @start_date).size
+ assert @full_size > part
+ assert part > 0
+ end
+
+ def test_between
+ part = @git.rev_list(:between => [@start_date, @end_date]).size
+ none = @git.rev_list(:between => [@end_date, @start_date]).size
+ assert @full_size > part
+ assert part > none
+ assert_equal 0, none
+ end
+
+ def test_first_parent
+ part = @git.rev_list(:first_parent => true).size
+ assert part > 0
+ end
+
+ def test_path_limiter
+ part1 = @git.rev_list(:path_limiter => './example.txt')
+ part2 = @git.rev_list(:path_limiter => './scott/text.txt')
+ assert @full_size > part1.size
+ assert part1.size > part2.size
+ assert part2.size > 0
+ end
+
+ def test_multi
+ part = @git.rev_list(:path_limiter => './example.txt', :between => [@start_date, @end_date])
+ assert_equal part.size, 57
+ part = @git.rev_list(:path_limiter => './example.txt')
+ assert_equal part.size, 67
+ end
+
end
@@ -22,13 +22,13 @@ def test_packed_log
end
def test_commit_object
- g = Git.bare(@wbare)
+ g = GitRuby.bare(@wbare)
c = g.gcommit("v2.5")
assert_equal('test', c.message)
end
def test_lstree
- g = Git.bare(@wbare)
+ g = GitRuby.bare(@wbare)
c = g.object("v2.5").gtree
sha = c.sha

0 comments on commit 781dc3e

Please sign in to comment.