cucumber_fm-core 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENCE +20 -0
- data/lib/cucumber_f_m/aggregator.rb +65 -0
- data/lib/cucumber_f_m/comment_module/comment.rb +7 -0
- data/lib/cucumber_f_m/config.rb +37 -0
- data/lib/cucumber_f_m/cvs/git.rb +7 -0
- data/lib/cucumber_f_m/feature.rb +141 -0
- data/lib/cucumber_f_m/feature_element/background.rb +10 -0
- data/lib/cucumber_f_m/feature_element/comment.rb +13 -0
- data/lib/cucumber_f_m/feature_element/component/comments.rb +21 -0
- data/lib/cucumber_f_m/feature_element/component/information/component.rb +16 -0
- data/lib/cucumber_f_m/feature_element/component/tags.rb +108 -0
- data/lib/cucumber_f_m/feature_element/component/title.rb +26 -0
- data/lib/cucumber_f_m/feature_element/component/total_estimation.rb +42 -0
- data/lib/cucumber_f_m/feature_element/example.rb +7 -0
- data/lib/cucumber_f_m/feature_element/info.rb +13 -0
- data/lib/cucumber_f_m/feature_element/narrative.rb +7 -0
- data/lib/cucumber_f_m/feature_element/scenario.rb +15 -0
- data/lib/cucumber_f_m/feature_element/scenario_outline.rb +23 -0
- data/lib/cucumber_f_m/feature_element/step.rb +7 -0
- data/lib/cucumber_f_m/statistic.rb +31 -0
- data/lib/cucumber_f_m/tag_filter.rb +85 -0
- data/lib/cucumber_feature_manager.rb +164 -0
- data/lib/grit/lib/grit.rb +75 -0
- data/lib/grit/lib/grit/actor.rb +36 -0
- data/lib/grit/lib/grit/blame.rb +61 -0
- data/lib/grit/lib/grit/blob.rb +126 -0
- data/lib/grit/lib/grit/commit.rb +247 -0
- data/lib/grit/lib/grit/commit_stats.rb +128 -0
- data/lib/grit/lib/grit/config.rb +44 -0
- data/lib/grit/lib/grit/diff.rb +70 -0
- data/lib/grit/lib/grit/errors.rb +7 -0
- data/lib/grit/lib/grit/git-ruby.rb +267 -0
- data/lib/grit/lib/grit/git-ruby/commit_db.rb +52 -0
- data/lib/grit/lib/grit/git-ruby/file_index.rb +193 -0
- data/lib/grit/lib/grit/git-ruby/git_object.rb +350 -0
- data/lib/grit/lib/grit/git-ruby/internal/file_window.rb +58 -0
- data/lib/grit/lib/grit/git-ruby/internal/loose.rb +137 -0
- data/lib/grit/lib/grit/git-ruby/internal/pack.rb +384 -0
- data/lib/grit/lib/grit/git-ruby/internal/raw_object.rb +37 -0
- data/lib/grit/lib/grit/git-ruby/object.rb +325 -0
- data/lib/grit/lib/grit/git-ruby/repository.rb +767 -0
- data/lib/grit/lib/grit/git.rb +323 -0
- data/lib/grit/lib/grit/index.rb +122 -0
- data/lib/grit/lib/grit/lazy.rb +33 -0
- data/lib/grit/lib/grit/merge.rb +45 -0
- data/lib/grit/lib/grit/ref.rb +74 -0
- data/lib/grit/lib/grit/repo.rb +482 -0
- data/lib/grit/lib/grit/ruby1.9.rb +7 -0
- data/lib/grit/lib/grit/status.rb +151 -0
- data/lib/grit/lib/grit/submodule.rb +88 -0
- data/lib/grit/lib/grit/tag.rb +16 -0
- data/lib/grit/lib/grit/tree.rb +123 -0
- data/lib/grit/lib/open3_detach.rb +46 -0
- data/spec/cucumber_f_m/aggregator_spec.rb +210 -0
- data/spec/cucumber_f_m/comment_module/comment_spec.rb +4 -0
- data/spec/cucumber_f_m/config_spec.rb +27 -0
- data/spec/cucumber_f_m/cvs/git_spec.rb +40 -0
- data/spec/cucumber_f_m/feature_all_tags_to_scenario_spec.rb +7 -0
- data/spec/cucumber_f_m/feature_file_manipulation_spec.rb +29 -0
- data/spec/cucumber_f_m/feature_module/background_spec.rb +30 -0
- data/spec/cucumber_f_m/feature_module/comment_spec.rb +23 -0
- data/spec/cucumber_f_m/feature_module/example_spec.rb +5 -0
- data/spec/cucumber_f_m/feature_module/info_spec.rb +30 -0
- data/spec/cucumber_f_m/feature_module/narrative_spec.rb +7 -0
- data/spec/cucumber_f_m/feature_module/scenario_outline_spec.rb +39 -0
- data/spec/cucumber_f_m/feature_module/scenario_spec.rb +33 -0
- data/spec/cucumber_f_m/feature_module/step_spec.rb +7 -0
- data/spec/cucumber_f_m/feature_module/tag_spec.rb +96 -0
- data/spec/cucumber_f_m/feature_spec.rb +229 -0
- data/spec/cucumber_f_m/tag_filter_spec.rb +191 -0
- data/spec/cucumber_feature_manager_spec.rb +59 -0
- data/spec/data/feature_manager/some_ruby_file.rb +0 -0
- data/spec/spec_helper.rb +1 -0
- metadata +141 -0
@@ -0,0 +1,128 @@
|
|
1
|
+
module Grit
|
2
|
+
|
3
|
+
class CommitStats
|
4
|
+
|
5
|
+
attr_reader :id, :files, :additions, :deletions, :total
|
6
|
+
|
7
|
+
# Instantiate a new CommitStats
|
8
|
+
# +id+ is the id of the commit
|
9
|
+
# +files+ is an array of :
|
10
|
+
# [ [filename, adds, deletes, total],
|
11
|
+
# [filename, adds, deletes, total],
|
12
|
+
# [filename, adds, deletes, total] ]
|
13
|
+
#
|
14
|
+
# Returns Grit::CommitStats (baked)
|
15
|
+
def initialize(repo, id, files)
|
16
|
+
@repo = repo
|
17
|
+
@id = id
|
18
|
+
@files = files
|
19
|
+
@additions = files.inject(0) { |total, a| total += a[1] }
|
20
|
+
@deletions = files.inject(0) { |total, a| total += a[2] }
|
21
|
+
@total = files.inject(0) { |total, a| total += a[3] }
|
22
|
+
end
|
23
|
+
|
24
|
+
# Find all commit stats matching the given criteria.
|
25
|
+
# +repo+ is the Repo
|
26
|
+
# +ref+ is the ref from which to begin (SHA1 or name) or nil for --all
|
27
|
+
# +options+ is a Hash of optional arguments to git
|
28
|
+
# :max_count is the maximum number of commits to fetch
|
29
|
+
# :skip is the number of commits to skip
|
30
|
+
#
|
31
|
+
# Returns assoc array [sha, Grit::Commit[] (baked)]
|
32
|
+
def self.find_all(repo, ref, options = {})
|
33
|
+
allowed_options = [:max_count, :skip, :since]
|
34
|
+
|
35
|
+
default_options = {:numstat => true}
|
36
|
+
actual_options = default_options.merge(options)
|
37
|
+
|
38
|
+
if ref
|
39
|
+
output = repo.git.log(actual_options, ref)
|
40
|
+
else
|
41
|
+
output = repo.git.log(actual_options.merge(:all => true))
|
42
|
+
end
|
43
|
+
|
44
|
+
self.list_from_string(repo, output)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Parse out commit information into an array of baked Commit objects
|
48
|
+
# +repo+ is the Repo
|
49
|
+
# +text+ is the text output from the git command (raw format)
|
50
|
+
#
|
51
|
+
# Returns assoc array [sha, Grit::Commit[] (baked)]
|
52
|
+
def self.list_from_string(repo, text)
|
53
|
+
lines = text.split("\n")
|
54
|
+
|
55
|
+
commits = []
|
56
|
+
|
57
|
+
while !lines.empty?
|
58
|
+
id = lines.shift.split.last
|
59
|
+
|
60
|
+
lines.shift
|
61
|
+
lines.shift
|
62
|
+
lines.shift
|
63
|
+
|
64
|
+
message_lines = []
|
65
|
+
message_lines << lines.shift[4..-1] while lines.first =~ /^ {4}/ || lines.first == ''
|
66
|
+
|
67
|
+
lines.shift while lines.first && lines.first.empty?
|
68
|
+
|
69
|
+
files = []
|
70
|
+
while lines.first =~ /^([-\d]+)\s+([-\d]+)\s+(.+)/
|
71
|
+
(additions, deletions, filename) = lines.shift.split
|
72
|
+
additions = additions.to_i
|
73
|
+
deletions = deletions.to_i
|
74
|
+
total = additions + deletions
|
75
|
+
files << [filename, additions, deletions, total]
|
76
|
+
end
|
77
|
+
|
78
|
+
lines.shift while lines.first && lines.first.empty?
|
79
|
+
|
80
|
+
commits << [id, CommitStats.new(repo, id, files)]
|
81
|
+
end
|
82
|
+
|
83
|
+
commits
|
84
|
+
end
|
85
|
+
|
86
|
+
# Pretty object inspection
|
87
|
+
def inspect
|
88
|
+
%Q{#<Grit::CommitStats "#{@id}">}
|
89
|
+
end
|
90
|
+
|
91
|
+
# Convert to an easy-to-traverse structure
|
92
|
+
def to_diffstat
|
93
|
+
files.map do |metadata|
|
94
|
+
DiffStat.new(*metadata)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# private
|
99
|
+
|
100
|
+
def to_hash
|
101
|
+
{
|
102
|
+
'id' => id,
|
103
|
+
'files' => files,
|
104
|
+
'additions' => additions,
|
105
|
+
'deletions' => deletions,
|
106
|
+
'total' => total
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
end # CommitStats
|
111
|
+
|
112
|
+
class DiffStat
|
113
|
+
attr_reader :filename, :additions, :deletions
|
114
|
+
|
115
|
+
def initialize(filename, additions, deletions, total=nil)
|
116
|
+
@filename, @additions, @deletions = filename, additions, deletions
|
117
|
+
end
|
118
|
+
|
119
|
+
def net
|
120
|
+
additions - deletions
|
121
|
+
end
|
122
|
+
|
123
|
+
def inspect
|
124
|
+
"#{filename}: +#{additions} -#{deletions}"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
end # Grit
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Grit
|
2
|
+
|
3
|
+
class Config
|
4
|
+
def initialize(repo)
|
5
|
+
@repo = repo
|
6
|
+
end
|
7
|
+
|
8
|
+
def []=(key, value)
|
9
|
+
@repo.git.config({}, key, value)
|
10
|
+
@data = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def [](key)
|
14
|
+
data[key]
|
15
|
+
end
|
16
|
+
|
17
|
+
def fetch(key, default = nil)
|
18
|
+
data[key] || default || raise(IndexError.new("key not found"))
|
19
|
+
end
|
20
|
+
|
21
|
+
def keys
|
22
|
+
data.keys
|
23
|
+
end
|
24
|
+
|
25
|
+
protected
|
26
|
+
def data
|
27
|
+
@data ||= load_config
|
28
|
+
end
|
29
|
+
|
30
|
+
def load_config
|
31
|
+
hash = {}
|
32
|
+
config_lines.map do |line|
|
33
|
+
key, value = line.split(/=/, 2)
|
34
|
+
hash[key] = value
|
35
|
+
end
|
36
|
+
hash
|
37
|
+
end
|
38
|
+
|
39
|
+
def config_lines
|
40
|
+
@repo.git.config(:list => true).split(/\n/)
|
41
|
+
end
|
42
|
+
end # Config
|
43
|
+
|
44
|
+
end # Grit
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Grit
|
2
|
+
|
3
|
+
class Diff
|
4
|
+
attr_reader :a_path, :b_path
|
5
|
+
attr_reader :a_blob, :b_blob
|
6
|
+
attr_reader :a_mode, :b_mode
|
7
|
+
attr_reader :new_file, :deleted_file
|
8
|
+
attr_reader :diff
|
9
|
+
|
10
|
+
def initialize(repo, a_path, b_path, a_blob, b_blob, a_mode, b_mode, new_file, deleted_file, diff)
|
11
|
+
@repo = repo
|
12
|
+
@a_path = a_path
|
13
|
+
@b_path = b_path
|
14
|
+
@a_blob = a_blob =~ /^0{40}$/ ? nil : Blob.create(repo, :id => a_blob)
|
15
|
+
@b_blob = b_blob =~ /^0{40}$/ ? nil : Blob.create(repo, :id => b_blob)
|
16
|
+
@a_mode = a_mode
|
17
|
+
@b_mode = b_mode
|
18
|
+
@new_file = new_file || @a_blob.nil?
|
19
|
+
@deleted_file = deleted_file || @b_blob.nil?
|
20
|
+
@diff = diff
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.list_from_string(repo, text)
|
24
|
+
lines = text.split("\n")
|
25
|
+
|
26
|
+
diffs = []
|
27
|
+
|
28
|
+
while !lines.empty?
|
29
|
+
m, a_path, b_path = *lines.shift.match(%r{^diff --git a/(.+?) b/(.+)$})
|
30
|
+
|
31
|
+
if lines.first =~ /^old mode/
|
32
|
+
m, a_mode = *lines.shift.match(/^old mode (\d+)/)
|
33
|
+
m, b_mode = *lines.shift.match(/^new mode (\d+)/)
|
34
|
+
end
|
35
|
+
|
36
|
+
if lines.empty? || lines.first =~ /^diff --git/
|
37
|
+
diffs << Diff.new(repo, a_path, b_path, nil, nil, a_mode, b_mode, false, false, nil)
|
38
|
+
next
|
39
|
+
end
|
40
|
+
|
41
|
+
new_file = false
|
42
|
+
deleted_file = false
|
43
|
+
|
44
|
+
if lines.first =~ /^new file/
|
45
|
+
m, b_mode = lines.shift.match(/^new file mode (.+)$/)
|
46
|
+
a_mode = nil
|
47
|
+
new_file = true
|
48
|
+
elsif lines.first =~ /^deleted file/
|
49
|
+
m, a_mode = lines.shift.match(/^deleted file mode (.+)$/)
|
50
|
+
b_mode = nil
|
51
|
+
deleted_file = true
|
52
|
+
end
|
53
|
+
|
54
|
+
m, a_blob, b_blob, b_mode = *lines.shift.match(%r{^index ([0-9A-Fa-f]+)\.\.([0-9A-Fa-f]+) ?(.+)?$})
|
55
|
+
b_mode.strip! if b_mode
|
56
|
+
|
57
|
+
diff_lines = []
|
58
|
+
while lines.first && lines.first !~ /^diff/
|
59
|
+
diff_lines << lines.shift
|
60
|
+
end
|
61
|
+
diff = diff_lines.join("\n")
|
62
|
+
|
63
|
+
diffs << Diff.new(repo, a_path, b_path, a_blob, b_blob, a_mode, b_mode, new_file, deleted_file, diff)
|
64
|
+
end
|
65
|
+
|
66
|
+
diffs
|
67
|
+
end
|
68
|
+
end # Diff
|
69
|
+
|
70
|
+
end # Grit
|
@@ -0,0 +1,267 @@
|
|
1
|
+
require 'grit/git-ruby/repository'
|
2
|
+
require 'grit/git-ruby/file_index'
|
3
|
+
|
4
|
+
module Grit
|
5
|
+
|
6
|
+
# the functions in this module intercept the calls to git binary
|
7
|
+
# made buy the grit objects and attempts to run them in pure ruby
|
8
|
+
# if it will be faster, or if the git binary is not available (!!TODO!!)
|
9
|
+
module GitRuby
|
10
|
+
|
11
|
+
attr_accessor :ruby_git_repo, :git_file_index
|
12
|
+
|
13
|
+
def init(options)
|
14
|
+
if options.size == 0
|
15
|
+
Grit::GitRuby::Repository.init(@git_dir)
|
16
|
+
else
|
17
|
+
method_missing('init', options)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def cat_file(options, ref)
|
22
|
+
if options[:t]
|
23
|
+
file_type(ref)
|
24
|
+
elsif options[:s]
|
25
|
+
file_size(ref)
|
26
|
+
elsif options[:p]
|
27
|
+
try_run { ruby_git.cat_file(ref) }
|
28
|
+
end
|
29
|
+
rescue Grit::GitRuby::Repository::NoSuchShaFound
|
30
|
+
''
|
31
|
+
end
|
32
|
+
|
33
|
+
# lib/grit/tree.rb:16: output = repo.git.ls_tree({}, treeish, *paths)
|
34
|
+
def ls_tree(options, treeish, *paths)
|
35
|
+
sha = rev_parse({}, treeish)
|
36
|
+
ruby_git.ls_tree(sha, paths.flatten, options.delete(:r))
|
37
|
+
rescue Grit::GitRuby::Repository::NoSuchShaFound
|
38
|
+
''
|
39
|
+
end
|
40
|
+
|
41
|
+
# git diff --full-index 'ec037431382e83c3e95d4f2b3d145afbac8ea55d' 'f1ec1aea10986159456846b8a05615b87828d6c6'
|
42
|
+
def diff(options, sha1, sha2 = nil)
|
43
|
+
try_run { ruby_git.diff(sha1, sha2, options) }
|
44
|
+
end
|
45
|
+
|
46
|
+
def rev_list(options, ref = 'master')
|
47
|
+
options.delete(:skip) if options[:skip].to_i == 0
|
48
|
+
allowed_options = [:max_count, :since, :until, :pretty] # this is all I can do right now
|
49
|
+
if ((options.keys - allowed_options).size > 0)
|
50
|
+
return method_missing('rev-list', options, ref)
|
51
|
+
elsif (options.size == 0)
|
52
|
+
# pure rev-list
|
53
|
+
begin
|
54
|
+
return file_index.commits_from(rev_parse({}, ref)).join("\n") + "\n"
|
55
|
+
rescue
|
56
|
+
return method_missing('rev-list', options, ref)
|
57
|
+
end
|
58
|
+
else
|
59
|
+
aref = rev_parse({}, ref)
|
60
|
+
if aref.is_a? Array
|
61
|
+
return method_missing('rev-list', options, ref)
|
62
|
+
else
|
63
|
+
return try_run { ruby_git.rev_list(aref, options) }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def rev_parse(options, string)
|
69
|
+
raise RuntimeError, "invalid string: #{string}" unless string.is_a?(String)
|
70
|
+
|
71
|
+
if string =~ /\.\./
|
72
|
+
(sha1, sha2) = string.split('..')
|
73
|
+
return [rev_parse({}, sha1), rev_parse({}, sha2)]
|
74
|
+
end
|
75
|
+
|
76
|
+
if /^[0-9a-f]{40}$/.match(string) # passing in a sha - just no-op it
|
77
|
+
return string.chomp
|
78
|
+
end
|
79
|
+
|
80
|
+
head = File.join(@git_dir, 'refs', 'heads', string)
|
81
|
+
return File.read(head).chomp if File.file?(head)
|
82
|
+
|
83
|
+
head = File.join(@git_dir, 'refs', 'remotes', string)
|
84
|
+
return File.read(head).chomp if File.file?(head)
|
85
|
+
|
86
|
+
head = File.join(@git_dir, 'refs', 'tags', string)
|
87
|
+
return File.read(head).chomp if File.file?(head)
|
88
|
+
|
89
|
+
## check packed-refs file, too
|
90
|
+
packref = File.join(@git_dir, 'packed-refs')
|
91
|
+
if File.file?(packref)
|
92
|
+
File.readlines(packref).each do |line|
|
93
|
+
if m = /^(\w{40}) refs\/.+?\/(.*?)$/.match(line)
|
94
|
+
next if !Regexp.new(Regexp.escape(string) + '$').match(m[3])
|
95
|
+
return m[1].chomp
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
## !! more - partials and such !!
|
101
|
+
|
102
|
+
# revert to calling git - grr
|
103
|
+
return method_missing('rev-parse', options, string).chomp
|
104
|
+
end
|
105
|
+
|
106
|
+
def refs(options, prefix)
|
107
|
+
refs = []
|
108
|
+
already = {}
|
109
|
+
Dir.chdir(@git_dir) do
|
110
|
+
files = Dir.glob(prefix + '/**/*')
|
111
|
+
files.each do |ref|
|
112
|
+
next if !File.file?(ref)
|
113
|
+
id = File.read(ref).chomp
|
114
|
+
name = ref.sub("#{prefix}/", '')
|
115
|
+
if !already[name]
|
116
|
+
refs << "#{name} #{id}"
|
117
|
+
already[name] = true
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
if File.file?('packed-refs')
|
122
|
+
File.readlines('packed-refs').each do |line|
|
123
|
+
if m = /^(\w{40}) (.*?)$/.match(line)
|
124
|
+
next if !Regexp.new('^' + prefix).match(m[2])
|
125
|
+
name = m[2].sub("#{prefix}/", '')
|
126
|
+
if !already[name]
|
127
|
+
refs << "#{name} #{m[1]}"
|
128
|
+
already[name] = true
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
refs.join("\n")
|
136
|
+
end
|
137
|
+
|
138
|
+
def tags(options, prefix)
|
139
|
+
refs = []
|
140
|
+
already = {}
|
141
|
+
|
142
|
+
Dir.chdir(repo.path) do
|
143
|
+
files = Dir.glob(prefix + '/**/*')
|
144
|
+
|
145
|
+
files.each do |ref|
|
146
|
+
next if !File.file?(ref)
|
147
|
+
|
148
|
+
id = File.read(ref).chomp
|
149
|
+
name = ref.sub("#{prefix}/", '')
|
150
|
+
|
151
|
+
if !already[name]
|
152
|
+
refs << "#{name} #{id}"
|
153
|
+
already[name] = true
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
if File.file?('packed-refs')
|
158
|
+
lines = File.readlines('packed-refs')
|
159
|
+
lines.each_with_index do |line, i|
|
160
|
+
if m = /^(\w{40}) (.*?)$/.match(line)
|
161
|
+
next if !Regexp.new('^' + prefix).match(m[2])
|
162
|
+
name = m[2].sub("#{prefix}/", '')
|
163
|
+
|
164
|
+
# Annotated tags in packed-refs include a reference
|
165
|
+
# to the commit object on the following line.
|
166
|
+
next_line = lines[i + 1]
|
167
|
+
|
168
|
+
id =
|
169
|
+
if next_line && next_line[0] == ?^
|
170
|
+
next_line[1..-1].chomp
|
171
|
+
else
|
172
|
+
m[1]
|
173
|
+
end
|
174
|
+
|
175
|
+
if !already[name]
|
176
|
+
refs << "#{name} #{id}"
|
177
|
+
already[name] = true
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
refs.join("\n")
|
185
|
+
end
|
186
|
+
|
187
|
+
def file_size(ref)
|
188
|
+
try_run { ruby_git.cat_file_size(ref).to_s }
|
189
|
+
end
|
190
|
+
|
191
|
+
def file_type(ref)
|
192
|
+
try_run { ruby_git.cat_file_type(ref).to_s }
|
193
|
+
end
|
194
|
+
|
195
|
+
def blame_tree(commit, path = nil)
|
196
|
+
begin
|
197
|
+
path = [path].join('/').to_s + '/' if (path && path != '')
|
198
|
+
path = '' if !path.is_a? String
|
199
|
+
commits = file_index.last_commits(rev_parse({}, commit), looking_for(commit, path))
|
200
|
+
clean_paths(commits)
|
201
|
+
rescue FileIndex::IndexFileNotFound
|
202
|
+
{}
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def file_index
|
207
|
+
@git_file_index ||= FileIndex.new(@git_dir)
|
208
|
+
end
|
209
|
+
|
210
|
+
def ruby_git
|
211
|
+
@ruby_git_repo ||= Repository.new(@git_dir)
|
212
|
+
end
|
213
|
+
|
214
|
+
private
|
215
|
+
|
216
|
+
def try_run
|
217
|
+
ret = ''
|
218
|
+
Timeout.timeout(self.class.git_timeout) do
|
219
|
+
ret = yield
|
220
|
+
end
|
221
|
+
@bytes_read += ret.size
|
222
|
+
|
223
|
+
#if @bytes_read > 5242880 # 5.megabytes
|
224
|
+
# bytes = @bytes_read
|
225
|
+
# @bytes_read = 0
|
226
|
+
# raise Grit::Git::GitTimeout.new(command, bytes)
|
227
|
+
#end
|
228
|
+
|
229
|
+
ret
|
230
|
+
rescue Timeout::Error => e
|
231
|
+
bytes = @bytes_read
|
232
|
+
@bytes_read = 0
|
233
|
+
raise Grit::Git::GitTimeout.new(command, bytes)
|
234
|
+
end
|
235
|
+
|
236
|
+
def looking_for(commit, path = nil)
|
237
|
+
tree_sha = ruby_git.get_subtree(rev_parse({}, commit), path)
|
238
|
+
|
239
|
+
looking_for = []
|
240
|
+
ruby_git.get_object_by_sha1(tree_sha).entry.each do |e|
|
241
|
+
if path && !(path == '' || path == '.' || path == './')
|
242
|
+
file = File.join(path, e.name)
|
243
|
+
else
|
244
|
+
file = e.name
|
245
|
+
end
|
246
|
+
file += '/' if e.type == :directory
|
247
|
+
looking_for << file
|
248
|
+
end
|
249
|
+
looking_for
|
250
|
+
end
|
251
|
+
|
252
|
+
def clean_paths(commit_array)
|
253
|
+
new_commits = {}
|
254
|
+
commit_array.each do |file, sha|
|
255
|
+
file = file.chop if file[file.size - 1 , 1] == '/'
|
256
|
+
new_commits[file] = sha
|
257
|
+
end
|
258
|
+
new_commits
|
259
|
+
end
|
260
|
+
|
261
|
+
# TODO
|
262
|
+
# git grep -n 'foo' 'master'
|
263
|
+
# git log --pretty='raw' --max-count='1' 'master' -- 'LICENSE'
|
264
|
+
# git log --pretty='raw' --max-count='1' 'master' -- 'test'
|
265
|
+
|
266
|
+
end
|
267
|
+
end
|