boof-grit 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/API.txt +101 -0
  2. data/History.txt +53 -0
  3. data/LICENSE +22 -0
  4. data/README.md +210 -0
  5. data/VERSION.yml +4 -0
  6. data/examples/ex_add_commit.rb +13 -0
  7. data/examples/ex_index.rb +14 -0
  8. data/lib/grit.rb +68 -0
  9. data/lib/grit/actor.rb +36 -0
  10. data/lib/grit/blame.rb +61 -0
  11. data/lib/grit/blob.rb +126 -0
  12. data/lib/grit/commit.rb +246 -0
  13. data/lib/grit/commit_stats.rb +128 -0
  14. data/lib/grit/config.rb +44 -0
  15. data/lib/grit/diff.rb +70 -0
  16. data/lib/grit/errors.rb +7 -0
  17. data/lib/grit/git-ruby.rb +186 -0
  18. data/lib/grit/git-ruby/commit_db.rb +52 -0
  19. data/lib/grit/git-ruby/file_index.rb +193 -0
  20. data/lib/grit/git-ruby/git_object.rb +350 -0
  21. data/lib/grit/git-ruby/internal/file_window.rb +58 -0
  22. data/lib/grit/git-ruby/internal/loose.rb +137 -0
  23. data/lib/grit/git-ruby/internal/pack.rb +382 -0
  24. data/lib/grit/git-ruby/internal/raw_object.rb +37 -0
  25. data/lib/grit/git-ruby/object.rb +325 -0
  26. data/lib/grit/git-ruby/repository.rb +740 -0
  27. data/lib/grit/git.rb +141 -0
  28. data/lib/grit/index.rb +122 -0
  29. data/lib/grit/lazy.rb +33 -0
  30. data/lib/grit/merge.rb +45 -0
  31. data/lib/grit/ref.rb +177 -0
  32. data/lib/grit/repo.rb +452 -0
  33. data/lib/grit/ruby1.9.rb +7 -0
  34. data/lib/grit/status.rb +151 -0
  35. data/lib/grit/submodule.rb +88 -0
  36. data/lib/grit/tag.rb +66 -0
  37. data/lib/grit/tree.rb +123 -0
  38. data/lib/open3_detach.rb +46 -0
  39. data/test/bench/benchmarks.rb +126 -0
  40. data/test/helper.rb +18 -0
  41. data/test/profile.rb +21 -0
  42. data/test/suite.rb +6 -0
  43. data/test/test_actor.rb +35 -0
  44. data/test/test_blame.rb +32 -0
  45. data/test/test_blame_tree.rb +33 -0
  46. data/test/test_blob.rb +83 -0
  47. data/test/test_commit.rb +207 -0
  48. data/test/test_commit_stats.rb +33 -0
  49. data/test/test_commit_write.rb +20 -0
  50. data/test/test_config.rb +58 -0
  51. data/test/test_diff.rb +18 -0
  52. data/test/test_file_index.rb +56 -0
  53. data/test/test_git.rb +94 -0
  54. data/test/test_grit.rb +32 -0
  55. data/test/test_head.rb +72 -0
  56. data/test/test_index_status.rb +40 -0
  57. data/test/test_merge.rb +17 -0
  58. data/test/test_raw.rb +16 -0
  59. data/test/test_real.rb +19 -0
  60. data/test/test_reality.rb +17 -0
  61. data/test/test_remote.rb +14 -0
  62. data/test/test_repo.rb +381 -0
  63. data/test/test_rubygit.rb +192 -0
  64. data/test/test_rubygit_alt.rb +40 -0
  65. data/test/test_rubygit_index.rb +76 -0
  66. data/test/test_rubygit_iv2.rb +28 -0
  67. data/test/test_submodule.rb +69 -0
  68. data/test/test_tag.rb +103 -0
  69. data/test/test_tree.rb +101 -0
  70. metadata +143 -0
data/lib/grit/actor.rb ADDED
@@ -0,0 +1,36 @@
1
+ module Grit
2
+
3
+ class Actor
4
+ attr_reader :name
5
+ attr_reader :email
6
+
7
+ def initialize(name, email)
8
+ @name = name
9
+ @email = email
10
+ end
11
+ alias_method :to_s, :name
12
+
13
+ # Create an Actor from a string.
14
+ # +str+ is the string, which is expected to be in regular git format
15
+ #
16
+ # Format
17
+ # John Doe <jdoe@example.com>
18
+ #
19
+ # Returns Actor
20
+ def self.from_string(str)
21
+ case str
22
+ when /<.+>/
23
+ m, name, email = *str.match(/(.*) <(.+?)>/)
24
+ return self.new(name, email)
25
+ else
26
+ return self.new(str, nil)
27
+ end
28
+ end
29
+
30
+ # Pretty object inspection
31
+ def inspect
32
+ %Q{#<Grit::Actor "#{@name} <#{@email}>">}
33
+ end
34
+ end # Actor
35
+
36
+ end # Grit
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 ADDED
@@ -0,0 +1,126 @@
1
+ module Grit
2
+
3
+ class Blob
4
+ DEFAULT_MIME_TYPE = "text/plain"
5
+
6
+ attr_reader :id
7
+ attr_reader :mode
8
+ attr_reader :name
9
+
10
+ # Create an unbaked Blob containing just the specified attributes
11
+ # +repo+ is the Repo
12
+ # +atts+ is a Hash of instance variable data
13
+ #
14
+ # Returns Grit::Blob (unbaked)
15
+ def self.create(repo, atts)
16
+ self.allocate.create_initialize(repo, atts)
17
+ end
18
+
19
+ # Initializer for Blob.create
20
+ # +repo+ is the Repo
21
+ # +atts+ is a Hash of instance variable data
22
+ #
23
+ # Returns Grit::Blob (unbaked)
24
+ def create_initialize(repo, atts)
25
+ @repo = repo
26
+ atts.each do |k, v|
27
+ instance_variable_set("@#{k}".to_sym, v)
28
+ end
29
+ self
30
+ end
31
+
32
+ # The size of this blob in bytes
33
+ #
34
+ # Returns Integer
35
+ def size
36
+ @size ||= @repo.git.cat_file({:s => true}, id).chomp.to_i
37
+ end
38
+
39
+ # The binary contents of this blob.
40
+ #
41
+ # Returns String
42
+ def data
43
+ @data ||= @repo.git.cat_file({:p => true}, id)
44
+ end
45
+
46
+ # The mime type of this file (based on the filename)
47
+ #
48
+ # Returns String
49
+ def mime_type
50
+ guesses = MIME::Types.type_for(self.name) rescue []
51
+ guesses.first ? guesses.first.simplified : DEFAULT_MIME_TYPE
52
+ end
53
+
54
+ # The blame information for the given file at the given commit
55
+ #
56
+ # Returns Array: [Grit::Commit, Array: [<line>]]
57
+ def self.blame(repo, commit, file)
58
+ data = repo.git.blame({:p => true}, commit, '--', file)
59
+
60
+ commits = {}
61
+ blames = []
62
+ info = nil
63
+
64
+ data.split("\n").each do |line|
65
+ parts = line.split(/\s+/, 2)
66
+ case parts.first
67
+ when /^[0-9A-Fa-f]{40}$/
68
+ case line
69
+ when /^([0-9A-Fa-f]{40}) (\d+) (\d+) (\d+)$/
70
+ _, id, origin_line, final_line, group_lines = *line.match(/^([0-9A-Fa-f]{40}) (\d+) (\d+) (\d+)$/)
71
+ info = {:id => id}
72
+ blames << [nil, []]
73
+ when /^([0-9A-Fa-f]{40}) (\d+) (\d+)$/
74
+ _, id, origin_line, final_line = *line.match(/^([0-9A-Fa-f]{40}) (\d+) (\d+)$/)
75
+ info = {:id => id}
76
+ end
77
+ when /^(author|committer)/
78
+ case parts.first
79
+ when /^(.+)-mail$/
80
+ info["#{$1}_email".intern] = parts.last
81
+ when /^(.+)-time$/
82
+ info["#{$1}_date".intern] = Time.at(parts.last.to_i)
83
+ when /^(author|committer)$/
84
+ info[$1.intern] = parts.last
85
+ end
86
+ when /^filename/
87
+ info[:filename] = parts.last
88
+ when /^summary/
89
+ info[:summary] = parts.last
90
+ when ''
91
+ c = commits[info[:id]]
92
+ unless c
93
+ c = Commit.create(repo, :id => info[:id],
94
+ :author => Actor.from_string(info[:author] + ' ' + info[:author_email]),
95
+ :authored_date => info[:author_date],
96
+ :committer => Actor.from_string(info[:committer] + ' ' + info[:committer_email]),
97
+ :committed_date => info[:committer_date],
98
+ :message => info[:summary])
99
+ commits[info[:id]] = c
100
+ end
101
+ _, text = *line.match(/^\t(.*)$/)
102
+ blames.last[0] = c
103
+ blames.last[1] << text
104
+ info = nil
105
+ end
106
+ end
107
+
108
+ blames
109
+ end
110
+
111
+ def basename
112
+ File.basename(name)
113
+ end
114
+
115
+ # Pretty object inspection
116
+ def inspect
117
+ %Q{#<Grit::Blob "#{@id}">}
118
+ end
119
+
120
+ # Compares blobs by name
121
+ def <=>(other)
122
+ name <=> other.name
123
+ end
124
+ end # Blob
125
+
126
+ end # Grit
@@ -0,0 +1,246 @@
1
+ module Grit
2
+
3
+ class Commit
4
+ attr_reader :id
5
+ lazy_reader :parents
6
+ lazy_reader :tree
7
+ lazy_reader :author
8
+ lazy_reader :authored_date
9
+ lazy_reader :committer
10
+ lazy_reader :committed_date
11
+ lazy_reader :message
12
+ lazy_reader :short_message
13
+ lazy_reader :author_string
14
+
15
+ # Instantiate a new Commit
16
+ # +id+ is the id of the commit
17
+ # +parents+ is an array of commit ids (will be converted into Commit instances)
18
+ # +tree+ is the correspdonding tree id (will be converted into a Tree object)
19
+ # +author+ is the author string
20
+ # +authored_date+ is the authored Time
21
+ # +committer+ is the committer string
22
+ # +committed_date+ is the committed Time
23
+ # +message+ is an array of commit message lines
24
+ #
25
+ # Returns Grit::Commit (baked)
26
+ def initialize(repo, id, parents, tree, author, authored_date, committer, committed_date, message)
27
+ @repo = repo
28
+ @id = id
29
+ @parents = parents.map { |p| Commit.create(repo, :id => p) }
30
+ @tree = Tree.create(repo, :id => tree)
31
+ @author = author
32
+ @authored_date = authored_date
33
+ @committer = committer
34
+ @committed_date = committed_date
35
+ @message = message.join("\n")
36
+ @short_message = message[0] || ''
37
+ end
38
+
39
+ def id_abbrev
40
+ @id_abbrev ||= @repo.git.rev_parse({}, self.id).chomp[0, 7]
41
+ end
42
+
43
+ # Create an unbaked Commit containing just the specified attributes
44
+ # +repo+ is the Repo
45
+ # +atts+ is a Hash of instance variable data
46
+ #
47
+ # Returns Grit::Commit (unbaked)
48
+ def self.create(repo, atts)
49
+ self.allocate.create_initialize(repo, atts)
50
+ end
51
+
52
+ # Initializer for Commit.create
53
+ # +repo+ is the Repo
54
+ # +atts+ is a Hash of instance variable data
55
+ #
56
+ # Returns Grit::Commit (unbaked)
57
+ def create_initialize(repo, atts)
58
+ @repo = repo
59
+ atts.each do |k, v|
60
+ instance_variable_set("@#{k}", v)
61
+ end
62
+ self
63
+ end
64
+
65
+ def lazy_source
66
+ self.class.find_all(@repo, @id, {:max_count => 1}).first
67
+ end
68
+
69
+ # Count the number of commits reachable from this ref
70
+ # +repo+ is the Repo
71
+ # +ref+ is the ref from which to begin (SHA1 or name)
72
+ #
73
+ # Returns Integer
74
+ def self.count(repo, ref)
75
+ repo.git.rev_list({}, ref).size / 41
76
+ end
77
+
78
+ # Find all commits matching the given criteria.
79
+ # +repo+ is the Repo
80
+ # +ref+ is the ref from which to begin (SHA1 or name) or nil for --all
81
+ # +options+ is a Hash of optional arguments to git
82
+ # :max_count is the maximum number of commits to fetch
83
+ # :skip is the number of commits to skip
84
+ #
85
+ # Returns Grit::Commit[] (baked)
86
+ def self.find_all(repo, ref, options = {})
87
+ allowed_options = [:max_count, :skip, :since]
88
+
89
+ default_options = {:pretty => "raw"}
90
+ actual_options = default_options.merge(options)
91
+
92
+ if ref
93
+ output = repo.git.rev_list(actual_options, ref)
94
+ else
95
+ output = repo.git.rev_list(actual_options.merge(:all => true))
96
+ end
97
+
98
+ self.list_from_string(repo, output)
99
+ rescue Grit::GitRuby::Repository::NoSuchShaFound
100
+ []
101
+ end
102
+
103
+ # Parse out commit information into an array of baked Commit objects
104
+ # +repo+ is the Repo
105
+ # +text+ is the text output from the git command (raw format)
106
+ #
107
+ # Returns Grit::Commit[] (baked)
108
+ #
109
+ # really should re-write this to be more accepting of non-standard commit messages
110
+ # - it broke when 'encoding' was introduced - not sure what else might show up
111
+ #
112
+ def self.list_from_string(repo, text)
113
+ lines = text.split("\n")
114
+
115
+ commits = []
116
+
117
+ while !lines.empty?
118
+ id = lines.shift.split.last
119
+ tree = lines.shift.split.last
120
+
121
+ parents = []
122
+ parents << lines.shift.split.last while lines.first =~ /^parent/
123
+
124
+ author, authored_date = self.actor(lines.shift)
125
+ committer, committed_date = self.actor(lines.shift)
126
+
127
+ # not doing anything with this yet, but it's sometimes there
128
+ encoding = lines.shift.split.last if lines.first =~ /^encoding/
129
+
130
+ lines.shift
131
+
132
+ message_lines = []
133
+ message_lines << lines.shift[4..-1] while lines.first =~ /^ {4}/
134
+
135
+ lines.shift while lines.first && lines.first.empty?
136
+
137
+ commits << Commit.new(repo, id, parents, tree, author, authored_date, committer, committed_date, message_lines)
138
+ end
139
+
140
+ commits
141
+ end
142
+
143
+ # Show diffs between two trees:
144
+ # +repo+ is the Repo
145
+ # +a+ is a named commit
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
148
+ # given paths.
149
+ # +paths* is an array of paths to limit the diff.
150
+ #
151
+ # Returns Grit::Diff[] (baked)
152
+ def self.diff(repo, a, b = nil, paths = [])
153
+ if b.is_a?(Array)
154
+ paths = b
155
+ b = nil
156
+ end
157
+ paths.unshift("--") unless paths.empty?
158
+ paths.unshift(b) unless b.nil?
159
+ paths.unshift(a)
160
+ text = repo.git.diff({:full_index => true}, *paths)
161
+ Diff.list_from_string(repo, text)
162
+ end
163
+
164
+ def show
165
+ diff = @repo.git.show({:full_index => true, :pretty => 'raw'}, @id)
166
+ if diff =~ /diff --git a/
167
+ diff = diff.sub(/.+?(diff --git a)/m, '\1')
168
+ else
169
+ diff = ''
170
+ end
171
+ Diff.list_from_string(@repo, diff)
172
+ end
173
+
174
+ def diffs
175
+ if parents.empty?
176
+ show
177
+ else
178
+ self.class.diff(@repo, parents.first.id, @id)
179
+ end
180
+ end
181
+
182
+ def stats
183
+ stats = @repo.commit_stats(self.sha, 1)[0][-1]
184
+ end
185
+
186
+ # Convert this Commit to a String which is just the SHA1 id
187
+ def to_s
188
+ @id
189
+ end
190
+
191
+ def sha
192
+ @id
193
+ end
194
+
195
+ def date
196
+ @committed_date
197
+ end
198
+
199
+ def to_patch
200
+ @repo.git.format_patch({'1' => true, :stdout => true}, to_s)
201
+ end
202
+
203
+ # Pretty object inspection
204
+ def inspect
205
+ %Q{#<Grit::Commit "#{@id}">}
206
+ end
207
+
208
+ # private
209
+
210
+ # Parse out the actor (author or committer) info
211
+ #
212
+ # Returns [String (actor name and email), Time (acted at time)]
213
+ def self.actor(line)
214
+ m, actor, epoch = *line.match(/^.+? (.*) (\d+) .*$/)
215
+ [Actor.from_string(actor), Time.at(epoch.to_i)]
216
+ end
217
+
218
+ def author_string
219
+ "%s <%s> %s %+05d" % [author.name, author.email, authored_date.to_i, 800]
220
+ end
221
+
222
+ def ==(other)
223
+ self.class === other and id == other.id
224
+ end
225
+
226
+ def to_hash
227
+ {
228
+ 'id' => id,
229
+ 'parents' => parents.map { |p| { 'id' => p.id } },
230
+ 'tree' => tree.id,
231
+ 'message' => message,
232
+ 'author' => {
233
+ 'name' => author.name,
234
+ 'email' => author.email
235
+ },
236
+ 'committer' => {
237
+ 'name' => committer.name,
238
+ 'email' => committer.email
239
+ },
240
+ 'authored_date' => authored_date.xmlschema,
241
+ 'committed_date' => committed_date.xmlschema,
242
+ }
243
+ end
244
+ end # Commit
245
+
246
+ end # Grit