davetron5000-grit 1.1.2

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.
Files changed (70) hide show
  1. data/API.txt +101 -0
  2. data/History.txt +49 -0
  3. data/LICENSE +22 -0
  4. data/README.md +216 -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/actor.rb +41 -0
  9. data/lib/grit/blame.rb +61 -0
  10. data/lib/grit/blob.rb +126 -0
  11. data/lib/grit/commit.rb +242 -0
  12. data/lib/grit/commit_stats.rb +128 -0
  13. data/lib/grit/config.rb +44 -0
  14. data/lib/grit/diff.rb +70 -0
  15. data/lib/grit/errors.rb +7 -0
  16. data/lib/grit/git-ruby/commit_db.rb +52 -0
  17. data/lib/grit/git-ruby/file_index.rb +193 -0
  18. data/lib/grit/git-ruby/git_object.rb +350 -0
  19. data/lib/grit/git-ruby/internal/file_window.rb +58 -0
  20. data/lib/grit/git-ruby/internal/loose.rb +137 -0
  21. data/lib/grit/git-ruby/internal/pack.rb +382 -0
  22. data/lib/grit/git-ruby/internal/raw_object.rb +37 -0
  23. data/lib/grit/git-ruby/object.rb +325 -0
  24. data/lib/grit/git-ruby/repository.rb +736 -0
  25. data/lib/grit/git-ruby.rb +186 -0
  26. data/lib/grit/git.rb +140 -0
  27. data/lib/grit/index.rb +122 -0
  28. data/lib/grit/lazy.rb +33 -0
  29. data/lib/grit/merge.rb +45 -0
  30. data/lib/grit/ref.rb +99 -0
  31. data/lib/grit/repo.rb +447 -0
  32. data/lib/grit/ruby1.9.rb +7 -0
  33. data/lib/grit/status.rb +151 -0
  34. data/lib/grit/submodule.rb +88 -0
  35. data/lib/grit/tag.rb +66 -0
  36. data/lib/grit/tree.rb +123 -0
  37. data/lib/grit.rb +68 -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 +51 -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 +206 -0
  48. data/test/test_commit_stats.rb +33 -0
  49. data/test/test_commit_write.rb +54 -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 +84 -0
  54. data/test/test_grit.rb +32 -0
  55. data/test/test_head.rb +47 -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 +347 -0
  63. data/test/test_rubygit.rb +188 -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 +67 -0
  69. data/test/test_tree.rb +101 -0
  70. metadata +141 -0
@@ -0,0 +1,242 @@
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 to_hash
223
+ {
224
+ 'id' => id,
225
+ 'parents' => parents.map { |p| { 'id' => p.id } },
226
+ 'tree' => tree.id,
227
+ 'message' => message,
228
+ 'author' => {
229
+ 'name' => author.name,
230
+ 'email' => author.email
231
+ },
232
+ 'committer' => {
233
+ 'name' => committer.name,
234
+ 'email' => committer.email
235
+ },
236
+ 'authored_date' => authored_date.xmlschema,
237
+ 'committed_date' => committed_date.xmlschema,
238
+ }
239
+ end
240
+ end # Commit
241
+
242
+ end # Grit
@@ -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,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
19
+ @deleted_file = deleted_file
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,7 @@
1
+ module Grit
2
+ class InvalidGitRepositoryError < StandardError
3
+ end
4
+
5
+ class NoSuchPathError < StandardError
6
+ end
7
+ end
@@ -0,0 +1,52 @@
1
+ begin
2
+ require 'sequel'
3
+
4
+ module Grit
5
+
6
+ class CommitDb
7
+
8
+ SCHEMA_VERSION = 1
9
+
10
+ attr_accessor :db, :git
11
+
12
+ def initialize(git_obj, index_location = nil)
13
+ @git = git_obj
14
+ db_file = File.join(index_location || @git.git_dir, 'commit_db')
15
+ if !File.exists?(db_file)
16
+ @db = Sequel.open "sqlite:///#{db_file}"
17
+ setup_tables
18
+ else
19
+ @db = Sequel.open "sqlite:///#{db_file}"
20
+ end
21
+ end
22
+
23
+ def rev_list(branch, options)
24
+ end
25
+
26
+ def update_db(branch = nil)
27
+ # find all refs/heads, for each
28
+ # add branch if not there
29
+ # go though all commits in branch
30
+ # add new commit_branches a
31
+ # and commit_nodes for each new one
32
+ # stop if reach commit that already has branch and node links
33
+ end
34
+
35
+ def setup_tables
36
+ @db << "create table meta (meta_key text, meta_value text)"
37
+ @db[:meta] << {:meta_key => 'schema', :meta_value => SCHEMA_VERSION}
38
+
39
+ @db << "create table commits (id integer, sha text, author_date integer)"
40
+ @db << "create table nodes (id integer, path text, type text)"
41
+ @db << "create table branches (id integer, ref text, commit_id integer)"
42
+
43
+ @db << "create table commit_branches (commit_id integer, branch_id integer)"
44
+ @db << "create table commit_nodes (commit_id integer, node_id integer, node_sha string)"
45
+ end
46
+
47
+ end
48
+ end
49
+
50
+ rescue LoadError
51
+ # no commit db
52
+ end