Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
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...
commit 781dc3e28ee1bc82b706414bba1b5ff4e1b1b97c 1 parent cbe5952
Scott Chacon authored
16 bin/gitr
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:
15 lib/git-ruby/base.rb
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)
35 lib/git-ruby/lib.rb
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
120 lib/git-ruby/raw/repository.rb
View
@@ -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)
2  tests/test_helper.rb
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
10 tests/units/test_lib.rb
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
54 tests/units/test_log.rb
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
4 tests/units/test_raw_internals.rb
View
@@ -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
Please sign in to comment.
Something went wrong with that request. Please try again.