schacon-grit 0.9.4 → 1.1.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/lib/grit/blame.rb ADDED
@@ -0,0 +1,61 @@
1
+ module Grit
2
+
3
+ class Blame
4
+
5
+ attr_reader :lines
6
+
7
+ def initialize(repo, file, commit)
8
+ @repo = repo
9
+ @file = file
10
+ @commit = commit
11
+ @lines = []
12
+ load_blame
13
+ end
14
+
15
+ def load_blame
16
+ output = @repo.git.blame({'p' => true}, @commit, '--', @file)
17
+ process_raw_blame(output)
18
+ end
19
+
20
+ def process_raw_blame(output)
21
+ lines, final = [], []
22
+ info, commits = {}, {}
23
+
24
+ # process the output
25
+ output.split("\n").each do |line|
26
+ if line[0, 1] == "\t"
27
+ lines << line[1, line.size]
28
+ elsif m = /^(\w{40}) (\d+) (\d+)/.match(line)
29
+ if !commits[m[1]]
30
+ commits[m[1]] = @repo.commit(m[1])
31
+ end
32
+ info[m[3].to_i] = [commits[m[1]], m[2].to_i]
33
+ end
34
+ end
35
+
36
+ # get it together
37
+ info.sort.each do |lineno, commit|
38
+ final << BlameLine.new(lineno, commit[1], commit[0], lines[lineno - 1])
39
+ end
40
+
41
+ @lines = final
42
+ end
43
+
44
+ # Pretty object inspection
45
+ def inspect
46
+ %Q{#<Grit::Blame "#{@file} <#{@commit}>">}
47
+ end
48
+
49
+ class BlameLine
50
+ attr_accessor :lineno, :oldlineno, :commit, :line
51
+ def initialize(lineno, oldlineno, commit, line)
52
+ @lineno = lineno
53
+ @oldlineno = oldlineno
54
+ @commit = commit
55
+ @line = line
56
+ end
57
+ end
58
+
59
+ end # Blame
60
+
61
+ end # Grit
data/lib/grit/blob.rb CHANGED
@@ -104,14 +104,23 @@ module Grit
104
104
  info = nil
105
105
  end
106
106
  end
107
-
107
+
108
108
  blames
109
109
  end
110
110
 
111
+ def basename
112
+ File.basename(name)
113
+ end
114
+
111
115
  # Pretty object inspection
112
116
  def inspect
113
117
  %Q{#<Grit::Blob "#{@id}">}
114
118
  end
119
+
120
+ # Compares blobs by name
121
+ def <=>(other)
122
+ name <=> other.name
123
+ end
115
124
  end # Blob
116
-
125
+
117
126
  end # Grit
data/lib/grit/commit.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Grit
2
-
2
+
3
3
  class Commit
4
4
  attr_reader :id
5
5
  lazy_reader :parents
@@ -10,7 +10,8 @@ module Grit
10
10
  lazy_reader :committed_date
11
11
  lazy_reader :message
12
12
  lazy_reader :short_message
13
-
13
+ lazy_reader :author_string
14
+
14
15
  # Instantiate a new Commit
15
16
  # +id+ is the id of the commit
16
17
  # +parents+ is an array of commit ids (will be converted into Commit instances)
@@ -34,11 +35,11 @@ module Grit
34
35
  @message = message.join("\n")
35
36
  @short_message = message[0] || ''
36
37
  end
37
-
38
+
38
39
  def id_abbrev
39
40
  @id_abbrev ||= @repo.git.rev_parse({}, self.id).chomp[0, 7]
40
41
  end
41
-
42
+
42
43
  # Create an unbaked Commit containing just the specified attributes
43
44
  # +repo+ is the Repo
44
45
  # +atts+ is a Hash of instance variable data
@@ -47,7 +48,7 @@ module Grit
47
48
  def self.create(repo, atts)
48
49
  self.allocate.create_initialize(repo, atts)
49
50
  end
50
-
51
+
51
52
  # Initializer for Commit.create
52
53
  # +repo+ is the Repo
53
54
  # +atts+ is a Hash of instance variable data
@@ -60,11 +61,11 @@ module Grit
60
61
  end
61
62
  self
62
63
  end
63
-
64
+
64
65
  def lazy_source
65
66
  self.class.find_all(@repo, @id, {:max_count => 1}).first
66
67
  end
67
-
68
+
68
69
  # Count the number of commits reachable from this ref
69
70
  # +repo+ is the Repo
70
71
  # +ref+ is the ref from which to begin (SHA1 or name)
@@ -73,7 +74,7 @@ module Grit
73
74
  def self.count(repo, ref)
74
75
  repo.git.rev_list({}, ref).size / 41
75
76
  end
76
-
77
+
77
78
  # Find all commits matching the given criteria.
78
79
  # +repo+ is the Repo
79
80
  # +ref+ is the ref from which to begin (SHA1 or name) or nil for --all
@@ -84,21 +85,21 @@ module Grit
84
85
  # Returns Grit::Commit[] (baked)
85
86
  def self.find_all(repo, ref, options = {})
86
87
  allowed_options = [:max_count, :skip, :since]
87
-
88
+
88
89
  default_options = {:pretty => "raw"}
89
90
  actual_options = default_options.merge(options)
90
-
91
+
91
92
  if ref
92
93
  output = repo.git.rev_list(actual_options, ref)
93
94
  else
94
95
  output = repo.git.rev_list(actual_options.merge(:all => true))
95
96
  end
96
-
97
+
97
98
  self.list_from_string(repo, output)
98
99
  rescue Grit::GitRuby::Repository::NoSuchShaFound
99
100
  []
100
101
  end
101
-
102
+
102
103
  # Parse out commit information into an array of baked Commit objects
103
104
  # +repo+ is the Repo
104
105
  # +text+ is the text output from the git command (raw format)
@@ -110,40 +111,40 @@ module Grit
110
111
  #
111
112
  def self.list_from_string(repo, text)
112
113
  lines = text.split("\n")
113
-
114
+
114
115
  commits = []
115
-
116
+
116
117
  while !lines.empty?
117
118
  id = lines.shift.split.last
118
119
  tree = lines.shift.split.last
119
-
120
+
120
121
  parents = []
121
122
  parents << lines.shift.split.last while lines.first =~ /^parent/
122
-
123
+
123
124
  author, authored_date = self.actor(lines.shift)
124
125
  committer, committed_date = self.actor(lines.shift)
125
-
126
+
126
127
  # not doing anything with this yet, but it's sometimes there
127
128
  encoding = lines.shift.split.last if lines.first =~ /^encoding/
128
-
129
+
129
130
  lines.shift
130
-
131
+
131
132
  message_lines = []
132
133
  message_lines << lines.shift[4..-1] while lines.first =~ /^ {4}/
133
-
134
+
134
135
  lines.shift while lines.first && lines.first.empty?
135
-
136
+
136
137
  commits << Commit.new(repo, id, parents, tree, author, authored_date, committer, committed_date, message_lines)
137
138
  end
138
-
139
+
139
140
  commits
140
141
  end
141
-
142
+
142
143
  # Show diffs between two trees:
143
144
  # +repo+ is the Repo
144
145
  # +a+ is a named commit
145
- # +b+ is an optional named commit. Passing an array assumes you
146
- # wish to omit the second named commit and limit the diff to the
146
+ # +b+ is an optional named commit. Passing an array assumes you
147
+ # wish to omit the second named commit and limit the diff to the
147
148
  # given paths.
148
149
  # +paths* is an array of paths to limit the diff.
149
150
  #
@@ -174,10 +175,14 @@ module Grit
174
175
  if parents.empty?
175
176
  show
176
177
  else
177
- self.class.diff(@repo, parents.first.id, @id)
178
+ self.class.diff(@repo, parents.first.id, @id)
178
179
  end
179
180
  end
180
181
 
182
+ def stats
183
+ stats = @repo.commit_stats(self.sha, 1)[0][-1]
184
+ end
185
+
181
186
  # Convert this Commit to a String which is just the SHA1 id
182
187
  def to_s
183
188
  @id
@@ -186,18 +191,22 @@ module Grit
186
191
  def sha
187
192
  @id
188
193
  end
189
-
194
+
190
195
  def date
191
196
  @committed_date
192
197
  end
193
-
198
+
199
+ def to_patch
200
+ @repo.git.format_patch({'1' => true, :stdout => true}, to_s)
201
+ end
202
+
194
203
  # Pretty object inspection
195
204
  def inspect
196
205
  %Q{#<Grit::Commit "#{@id}">}
197
206
  end
198
-
207
+
199
208
  # private
200
-
209
+
201
210
  # Parse out the actor (author or committer) info
202
211
  #
203
212
  # Returns [String (actor name and email), Time (acted at time)]
@@ -206,6 +215,10 @@ module Grit
206
215
  [Actor.from_string(actor), Time.at(epoch.to_i)]
207
216
  end
208
217
 
218
+ def author_string
219
+ "%s <%s> %s %+05d" % [author.name, author.email, authored_date.to_i, 800]
220
+ end
221
+
209
222
  def to_hash
210
223
  {
211
224
  'id' => id,
@@ -225,5 +238,5 @@ module Grit
225
238
  }
226
239
  end
227
240
  end # Commit
228
-
241
+
229
242
  end # Grit
@@ -62,12 +62,12 @@ module Grit
62
62
  lines.shift
63
63
 
64
64
  message_lines = []
65
- message_lines << lines.shift[4..-1] while lines.first =~ /^ {4}/
65
+ message_lines << lines.shift[4..-1] while lines.first =~ /^ {4}/ || lines.first == ''
66
66
 
67
67
  lines.shift while lines.first && lines.first.empty?
68
68
 
69
69
  files = []
70
- while lines.first =~ /^(\d+)\s+(\d+)\s+(.+)/
70
+ while lines.first =~ /^([-\d]+)\s+([-\d]+)\s+(.+)/
71
71
  (additions, deletions, filename) = lines.shift.split
72
72
  additions = additions.to_i
73
73
  deletions = deletions.to_i
@@ -88,6 +88,13 @@ module Grit
88
88
  %Q{#<Grit::CommitStats "#{@id}">}
89
89
  end
90
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
+
91
98
  # private
92
99
 
93
100
  def to_hash
@@ -99,6 +106,23 @@ module Grit
99
106
  'total' => total
100
107
  }
101
108
  end
109
+
102
110
  end # CommitStats
103
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
+
104
128
  end # Grit
data/lib/grit/diff.rb CHANGED
@@ -2,21 +2,21 @@ module Grit
2
2
 
3
3
  class Diff
4
4
  attr_reader :a_path, :b_path
5
- attr_reader :a_commit, :b_commit
5
+ attr_reader :a_blob, :b_blob
6
6
  attr_reader :a_mode, :b_mode
7
7
  attr_reader :new_file, :deleted_file
8
8
  attr_reader :diff
9
9
 
10
- def initialize(repo, a_path, b_path, a_commit, b_commit, a_mode, b_mode, new_file, deleted_file, diff)
10
+ def initialize(repo, a_path, b_path, a_blob, b_blob, a_mode, b_mode, new_file, deleted_file, diff)
11
11
  @repo = repo
12
12
  @a_path = a_path
13
13
  @b_path = b_path
14
- @a_commit = a_commit =~ /^0{40}$/ ? nil : Commit.create(repo, :id => a_commit)
15
- @b_commit = b_commit =~ /^0{40}$/ ? nil : Commit.create(repo, :id => b_commit)
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
16
  @a_mode = a_mode
17
17
  @b_mode = b_mode
18
- @new_file = new_file
19
- @deleted_file = deleted_file
18
+ @new_file = new_file || @a_blob.nil?
19
+ @deleted_file = deleted_file || @b_blob.nil?
20
20
  @diff = diff
21
21
  end
22
22
 
@@ -51,7 +51,7 @@ module Grit
51
51
  deleted_file = true
52
52
  end
53
53
 
54
- m, a_commit, b_commit, b_mode = *lines.shift.match(%r{^index ([0-9A-Fa-f]+)\.\.([0-9A-Fa-f]+) ?(.+)?$})
54
+ m, a_blob, b_blob, b_mode = *lines.shift.match(%r{^index ([0-9A-Fa-f]+)\.\.([0-9A-Fa-f]+) ?(.+)?$})
55
55
  b_mode.strip! if b_mode
56
56
 
57
57
  diff_lines = []
@@ -60,7 +60,7 @@ module Grit
60
60
  end
61
61
  diff = diff_lines.join("\n")
62
62
 
63
- diffs << Diff.new(repo, a_path, b_path, a_commit, b_commit, a_mode, b_mode, new_file, deleted_file, diff)
63
+ diffs << Diff.new(repo, a_path, b_path, a_blob, b_blob, a_mode, b_mode, new_file, deleted_file, diff)
64
64
  end
65
65
 
66
66
  diffs
data/lib/grit/git-ruby.rb CHANGED
@@ -39,9 +39,9 @@ module Grit
39
39
  end
40
40
 
41
41
  # git diff --full-index 'ec037431382e83c3e95d4f2b3d145afbac8ea55d' 'f1ec1aea10986159456846b8a05615b87828d6c6'
42
- def diff(options, sha1, sha2)
43
- try_run { ruby_git.diff(sha1, sha2, options) }
44
- end
42
+ #def diff(options, sha1, sha2)
43
+ # try_run { ruby_git.diff(sha1, sha2, options) }
44
+ #end
45
45
 
46
46
  def rev_list(options, ref = 'master')
47
47
  options.delete(:skip) if options[:skip].to_i == 0
@@ -72,8 +72,8 @@ module Grit
72
72
  (sha1, sha2) = string.split('..')
73
73
  return [rev_parse({}, sha1), rev_parse({}, sha2)]
74
74
  end
75
-
76
- if /\w{40}/.match(string) # passing in a sha - just no-op it
75
+
76
+ if /^[0-9a-f]{40}$/.match(string) # passing in a sha - just no-op it
77
77
  return string.chomp
78
78
  end
79
79
 
@@ -103,6 +103,87 @@ module Grit
103
103
  return method_missing('rev-parse', {}, string).chomp
104
104
  end
105
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
+
106
187
  def file_size(ref)
107
188
  try_run { ruby_git.cat_file_size(ref).to_s }
108
189
  end
@@ -113,7 +194,7 @@ module Grit
113
194
 
114
195
  def blame_tree(commit, path = nil)
115
196
  begin
116
- path = path.to_a.join('/').to_s + '/' if (path && path != '')
197
+ path = [path].join('/').to_s + '/' if (path && path != '')
117
198
  path = '' if !path.is_a? String
118
199
  commits = file_index.last_commits(rev_parse({}, commit), looking_for(commit, path))
119
200
  clean_paths(commits)