rhomobile-grit 2.4.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.
@@ -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
data/lib/grit/diff.rb ADDED
@@ -0,0 +1,79 @@
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, :renamed_file
8
+ attr_reader :similarity_index
9
+ attr_accessor :diff
10
+
11
+ def initialize(repo, a_path, b_path, a_blob, b_blob, a_mode, b_mode, new_file, deleted_file, diff, renamed_file = false, similarity_index = 0)
12
+ @repo = repo
13
+ @a_path = a_path
14
+ @b_path = b_path
15
+ @a_blob = a_blob =~ /^0{40}$/ ? nil : Blob.create(repo, :id => a_blob)
16
+ @b_blob = b_blob =~ /^0{40}$/ ? nil : Blob.create(repo, :id => b_blob)
17
+ @a_mode = a_mode
18
+ @b_mode = b_mode
19
+ @new_file = new_file || @a_blob.nil?
20
+ @deleted_file = deleted_file || @b_blob.nil?
21
+ @renamed_file = renamed_file
22
+ @similarity_index = similarity_index.to_i
23
+ @diff = diff
24
+ end
25
+
26
+ def self.list_from_string(repo, text)
27
+ lines = text.split("\n")
28
+
29
+ diffs = []
30
+
31
+ while !lines.empty?
32
+ m, a_path, b_path = *lines.shift.match(%r{^diff --git a/(.+?) b/(.+)$})
33
+
34
+ if lines.first =~ /^old mode/
35
+ m, a_mode = *lines.shift.match(/^old mode (\d+)/)
36
+ m, b_mode = *lines.shift.match(/^new mode (\d+)/)
37
+ end
38
+
39
+ if lines.empty? || lines.first =~ /^diff --git/
40
+ diffs << Diff.new(repo, a_path, b_path, nil, nil, a_mode, b_mode, false, false, nil)
41
+ next
42
+ end
43
+
44
+ sim_index = 0
45
+ new_file = false
46
+ deleted_file = false
47
+ renamed_file = false
48
+
49
+ if lines.first =~ /^new file/
50
+ m, b_mode = lines.shift.match(/^new file mode (.+)$/)
51
+ a_mode = nil
52
+ new_file = true
53
+ elsif lines.first =~ /^deleted file/
54
+ m, a_mode = lines.shift.match(/^deleted file mode (.+)$/)
55
+ b_mode = nil
56
+ deleted_file = true
57
+ elsif lines.first =~ /^similarity index (\d+)\%/
58
+ sim_index = $1.to_i
59
+ renamed_file = true
60
+ 2.times { lines.shift } # shift away the 2 `rename from/to ...` lines
61
+ end
62
+
63
+ m, a_blob, b_blob, b_mode = *lines.shift.match(%r{^index ([0-9A-Fa-f]+)\.\.([0-9A-Fa-f]+) ?(.+)?$})
64
+ b_mode.strip! if b_mode
65
+
66
+ diff_lines = []
67
+ while lines.first && lines.first !~ /^diff/
68
+ diff_lines << lines.shift
69
+ end
70
+ diff = diff_lines.join("\n")
71
+
72
+ diffs << Diff.new(repo, a_path, b_path, a_blob, b_blob, a_mode, b_mode, new_file, deleted_file, diff, renamed_file, sim_index)
73
+ end
74
+
75
+ diffs
76
+ end
77
+ end # Diff
78
+
79
+ end # Grit
@@ -0,0 +1,10 @@
1
+ module Grit
2
+ class InvalidGitRepositoryError < StandardError
3
+ end
4
+
5
+ class NoSuchPathError < StandardError
6
+ end
7
+
8
+ class InvalidObjectType < StandardError
9
+ end
10
+ end
@@ -0,0 +1,275 @@
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, *args)
14
+ if options.size == 0
15
+ Grit::GitRuby::Repository.init(@git_dir)
16
+ else
17
+ method_missing('init', options, *args)
18
+ end
19
+ end
20
+
21
+ def cat_file(options, sha)
22
+ if options[:t]
23
+ file_type(sha)
24
+ elsif options[:s]
25
+ file_size(sha)
26
+ elsif options[:p]
27
+ try_run { ruby_git.cat_file(sha) }
28
+ end
29
+ rescue Grit::GitRuby::Repository::NoSuchShaFound
30
+ ''
31
+ end
32
+
33
+ def cat_ref(options, ref)
34
+ sha = rev_parse({}, ref)
35
+ cat_file(options, sha)
36
+ end
37
+
38
+ # lib/grit/tree.rb:16: output = repo.git.ls_tree({}, treeish, *paths)
39
+ def ls_tree(options, treeish, *paths)
40
+ sha = rev_parse({}, treeish)
41
+ ruby_git.ls_tree(sha, paths.flatten, options.delete(:r))
42
+ rescue Grit::GitRuby::Repository::NoSuchShaFound
43
+ ''
44
+ end
45
+
46
+ # git diff --full-index 'ec037431382e83c3e95d4f2b3d145afbac8ea55d' 'f1ec1aea10986159456846b8a05615b87828d6c6'
47
+ def diff(options, sha1, sha2 = nil)
48
+ try_run { ruby_git.diff(sha1, sha2, options) }
49
+ end
50
+
51
+ def rev_list(options, *refs)
52
+ refs = ['master'] if refs.empty?
53
+ options.delete(:skip) if options[:skip].to_i == 0
54
+ allowed_options = [:max_count, :since, :until, :pretty] # this is all I can do right now
55
+ if ((options.keys - allowed_options).size > 0) || refs.size > 1
56
+ method_missing('rev-list', options, *refs)
57
+ elsif (options.size == 0)
58
+ # pure rev-list
59
+ ref = refs.first
60
+ begin
61
+ file_index.commits_from(rev_parse({}, ref)).join("\n") + "\n"
62
+ rescue
63
+ method_missing('rev-list', options, *refs)
64
+ end
65
+ else
66
+ ref = refs.first
67
+ aref = rev_parse({}, ref)
68
+ if aref.is_a? Array
69
+ method_missing('rev-list', options, *refs)
70
+ else
71
+ try_run { ruby_git.rev_list(aref, options) }
72
+ end
73
+ end
74
+ end
75
+
76
+ def rev_parse(options, string)
77
+ raise RuntimeError, "invalid string: #{string.inspect}" unless string.is_a?(String)
78
+
79
+ if string =~ /\.\./
80
+ (sha1, sha2) = string.split('..')
81
+ return [rev_parse({}, sha1), rev_parse({}, sha2)]
82
+ end
83
+
84
+ if /^[0-9a-f]{40}$/.match(string) # passing in a sha - just no-op it
85
+ return string.chomp
86
+ end
87
+
88
+ head = File.join(@git_dir, 'refs', 'heads', string)
89
+ return File.read(head).chomp if File.file?(head)
90
+
91
+ head = File.join(@git_dir, 'refs', 'remotes', string)
92
+ return File.read(head).chomp if File.file?(head)
93
+
94
+ head = File.join(@git_dir, 'refs', 'tags', string)
95
+ return File.read(head).chomp if File.file?(head)
96
+
97
+ ## check packed-refs file, too
98
+ packref = File.join(@git_dir, 'packed-refs')
99
+ if File.file?(packref)
100
+ File.readlines(packref).each do |line|
101
+ if m = /^(\w{40}) refs\/.+?\/(.*?)$/.match(line)
102
+ next if !Regexp.new(Regexp.escape(string) + '$').match(m[3])
103
+ return m[1].chomp
104
+ end
105
+ end
106
+ end
107
+
108
+ ## !! more - partials and such !!
109
+
110
+ # revert to calling git - grr
111
+ return method_missing('rev-parse', options, string).chomp
112
+ end
113
+
114
+ def refs(options, prefix)
115
+ refs = []
116
+ already = {}
117
+ Dir.chdir(@git_dir) do
118
+ files = Dir.glob(prefix + '/**/*')
119
+ files.each do |ref|
120
+ next if !File.file?(ref)
121
+ id = File.read(ref).chomp
122
+ name = ref.sub("#{prefix}/", '')
123
+ if !already[name]
124
+ refs << "#{name} #{id}"
125
+ already[name] = true
126
+ end
127
+ end
128
+
129
+ if File.file?('packed-refs')
130
+ File.readlines('packed-refs').each do |line|
131
+ if m = /^(\w{40}) (.*?)$/.match(line)
132
+ next if !Regexp.new('^' + prefix).match(m[2])
133
+ name = m[2].sub("#{prefix}/", '')
134
+ if !already[name]
135
+ refs << "#{name} #{m[1]}"
136
+ already[name] = true
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
142
+
143
+ refs.join("\n")
144
+ end
145
+
146
+ def tags(options, prefix)
147
+ refs = []
148
+ already = {}
149
+
150
+ Dir.chdir(repo.path) do
151
+ files = Dir.glob(prefix + '/**/*')
152
+
153
+ files.each do |ref|
154
+ next if !File.file?(ref)
155
+
156
+ id = File.read(ref).chomp
157
+ name = ref.sub("#{prefix}/", '')
158
+
159
+ if !already[name]
160
+ refs << "#{name} #{id}"
161
+ already[name] = true
162
+ end
163
+ end
164
+
165
+ if File.file?('packed-refs')
166
+ lines = File.readlines('packed-refs')
167
+ lines.each_with_index do |line, i|
168
+ if m = /^(\w{40}) (.*?)$/.match(line)
169
+ next if !Regexp.new('^' + prefix).match(m[2])
170
+ name = m[2].sub("#{prefix}/", '')
171
+
172
+ # Annotated tags in packed-refs include a reference
173
+ # to the commit object on the following line.
174
+ next_line = lines[i + 1]
175
+
176
+ id =
177
+ if next_line && next_line[0] == ?^
178
+ next_line[1..-1].chomp
179
+ else
180
+ m[1]
181
+ end
182
+
183
+ if !already[name]
184
+ refs << "#{name} #{id}"
185
+ already[name] = true
186
+ end
187
+ end
188
+ end
189
+ end
190
+ end
191
+
192
+ refs.join("\n")
193
+ end
194
+
195
+ def file_size(ref)
196
+ try_run { ruby_git.cat_file_size(ref).to_s }
197
+ end
198
+
199
+ def file_type(ref)
200
+ try_run { ruby_git.cat_file_type(ref).to_s }
201
+ end
202
+
203
+ def blame_tree(commit, path = nil)
204
+ begin
205
+ path = [path].join('/').to_s + '/' if (path && path != '')
206
+ path = '' if !path.is_a? String
207
+ commits = file_index.last_commits(rev_parse({}, commit), looking_for(commit, path))
208
+ clean_paths(commits)
209
+ rescue FileIndex::IndexFileNotFound
210
+ {}
211
+ end
212
+ end
213
+
214
+ def file_index
215
+ @git_file_index ||= FileIndex.new(@git_dir)
216
+ end
217
+
218
+ def ruby_git
219
+ @ruby_git_repo ||= Repository.new(@git_dir)
220
+ end
221
+
222
+ private
223
+
224
+ def try_run
225
+ ret = ''
226
+ Timeout.timeout(self.class.git_timeout) do
227
+ ret = yield
228
+ end
229
+ @bytes_read += ret.size
230
+
231
+ #if @bytes_read > 5242880 # 5.megabytes
232
+ # bytes = @bytes_read
233
+ # @bytes_read = 0
234
+ # raise Grit::Git::GitTimeout.new(command, bytes)
235
+ #end
236
+
237
+ ret
238
+ rescue Timeout::Error => e
239
+ bytes = @bytes_read
240
+ @bytes_read = 0
241
+ raise Grit::Git::GitTimeout.new(command, bytes)
242
+ end
243
+
244
+ def looking_for(commit, path = nil)
245
+ tree_sha = ruby_git.get_subtree(rev_parse({}, commit), path)
246
+
247
+ looking_for = []
248
+ ruby_git.get_object_by_sha1(tree_sha).entry.each do |e|
249
+ if path && !(path == '' || path == '.' || path == './')
250
+ file = File.join(path, e.name)
251
+ else
252
+ file = e.name
253
+ end
254
+ file += '/' if e.type == :directory
255
+ looking_for << file
256
+ end
257
+ looking_for
258
+ end
259
+
260
+ def clean_paths(commit_array)
261
+ new_commits = {}
262
+ commit_array.each do |file, sha|
263
+ file = file.chop if file[file.size - 1 , 1] == '/'
264
+ new_commits[file] = sha
265
+ end
266
+ new_commits
267
+ end
268
+
269
+ # TODO
270
+ # git grep -n 'foo' 'master'
271
+ # git log --pretty='raw' --max-count='1' 'master' -- 'LICENSE'
272
+ # git log --pretty='raw' --max-count='1' 'master' -- 'test'
273
+
274
+ end
275
+ end