gifts 0.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.
Files changed (56) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +29 -0
  5. data/Rakefile +9 -0
  6. data/gifts.gemspec +32 -0
  7. data/lib/gifts.rb +22 -0
  8. data/lib/gifts/commit_table.rb +70 -0
  9. data/lib/gifts/database.rb +49 -0
  10. data/lib/gifts/diff_table.rb +55 -0
  11. data/lib/gifts/file_table.rb +51 -0
  12. data/lib/gifts/repo_table.rb +31 -0
  13. data/lib/gifts/table_base.rb +18 -0
  14. data/lib/gifts/term_table.rb +28 -0
  15. data/lib/gifts/user_table.rb +19 -0
  16. data/lib/gifts/version.rb +3 -0
  17. data/spec/.gitkeeper +0 -0
  18. data/vendor/lib/LICENSE-grit +22 -0
  19. data/vendor/lib/LICENSE-grit_ext +22 -0
  20. data/vendor/lib/gifts/grit.rb +73 -0
  21. data/vendor/lib/gifts/grit/actor.rb +52 -0
  22. data/vendor/lib/gifts/grit/blame.rb +70 -0
  23. data/vendor/lib/gifts/grit/blob.rb +126 -0
  24. data/vendor/lib/gifts/grit/commit.rb +324 -0
  25. data/vendor/lib/gifts/grit/commit_stats.rb +128 -0
  26. data/vendor/lib/gifts/grit/config.rb +44 -0
  27. data/vendor/lib/gifts/grit/diff.rb +97 -0
  28. data/vendor/lib/gifts/grit/errors.rb +10 -0
  29. data/vendor/lib/gifts/grit/git-ruby.rb +262 -0
  30. data/vendor/lib/gifts/grit/git-ruby/commit_db.rb +52 -0
  31. data/vendor/lib/gifts/grit/git-ruby/git_object.rb +353 -0
  32. data/vendor/lib/gifts/grit/git-ruby/internal/file_window.rb +58 -0
  33. data/vendor/lib/gifts/grit/git-ruby/internal/loose.rb +137 -0
  34. data/vendor/lib/gifts/grit/git-ruby/internal/pack.rb +398 -0
  35. data/vendor/lib/gifts/grit/git-ruby/internal/raw_object.rb +44 -0
  36. data/vendor/lib/gifts/grit/git-ruby/repository.rb +784 -0
  37. data/vendor/lib/gifts/grit/git.rb +501 -0
  38. data/vendor/lib/gifts/grit/index.rb +222 -0
  39. data/vendor/lib/gifts/grit/lazy.rb +35 -0
  40. data/vendor/lib/gifts/grit/merge.rb +45 -0
  41. data/vendor/lib/gifts/grit/ref.rb +98 -0
  42. data/vendor/lib/gifts/grit/repo.rb +722 -0
  43. data/vendor/lib/gifts/grit/ruby1.9.rb +15 -0
  44. data/vendor/lib/gifts/grit/status.rb +153 -0
  45. data/vendor/lib/gifts/grit/submodule.rb +88 -0
  46. data/vendor/lib/gifts/grit/tag.rb +97 -0
  47. data/vendor/lib/gifts/grit/tree.rb +125 -0
  48. data/vendor/lib/gifts/grit_ext.rb +41 -0
  49. data/vendor/lib/gifts/grit_ext/actor.rb +15 -0
  50. data/vendor/lib/gifts/grit_ext/blob.rb +26 -0
  51. data/vendor/lib/gifts/grit_ext/commit.rb +15 -0
  52. data/vendor/lib/gifts/grit_ext/diff.rb +23 -0
  53. data/vendor/lib/gifts/grit_ext/tag.rb +10 -0
  54. data/vendor/lib/gifts/grit_ext/tree.rb +10 -0
  55. data/vendor/lib/gifts/grit_ext/version.rb +7 -0
  56. metadata +256 -0
@@ -0,0 +1,19 @@
1
+ module Gifts
2
+ class UserTable < TableBase
3
+ def table_name
4
+ "user"
5
+ end
6
+
7
+ def define_schema
8
+ Groonga::Schema.define do |schema|
9
+ schema.create_table(table_name, type: :hash) do |table|
10
+ table.string("name")
11
+ end
12
+ end
13
+ end
14
+
15
+ def add(name)
16
+ db_user = table[name] || table.add(name, name: name)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ module Gifts
2
+ VERSION = "0.0.1"
3
+ end
File without changes
@@ -0,0 +1,22 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2007-2009 Tom Preston-Werner
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ 'Software'), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Saito
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,73 @@
1
+ # core
2
+ require 'fileutils'
3
+ require 'time'
4
+
5
+ # stdlib
6
+ require 'timeout'
7
+ require 'logger'
8
+ require 'digest/sha1'
9
+
10
+ # third party
11
+
12
+ begin
13
+ require 'mime/types'
14
+ require 'rubygems'
15
+ rescue LoadError
16
+ require 'rubygems'
17
+ begin
18
+ gem "mime-types", ">=0"
19
+ require 'mime/types'
20
+ rescue Gem::LoadError => e
21
+ puts "WARNING: Gem LoadError: #{e.message}"
22
+ end
23
+ end
24
+
25
+ # ruby 1.9 compatibility
26
+ require 'gifts/grit/ruby1.9'
27
+
28
+ # internal requires
29
+ require 'gifts/grit/lazy'
30
+ require 'gifts/grit/errors'
31
+ require 'gifts/grit/git-ruby'
32
+ require 'gifts/grit/git' unless defined? Gifts::Grit::Git
33
+ require 'gifts/grit/ref'
34
+ require 'gifts/grit/tag'
35
+ require 'gifts/grit/commit'
36
+ require 'gifts/grit/commit_stats'
37
+ require 'gifts/grit/tree'
38
+ require 'gifts/grit/blob'
39
+ require 'gifts/grit/actor'
40
+ require 'gifts/grit/diff'
41
+ require 'gifts/grit/config'
42
+ require 'gifts/grit/repo'
43
+ require 'gifts/grit/index'
44
+ require 'gifts/grit/status'
45
+ require 'gifts/grit/submodule'
46
+ require 'gifts/grit/blame'
47
+ require 'gifts/grit/merge'
48
+
49
+ module Gifts::Grit
50
+ VERSION = '2.5.0'
51
+
52
+ class << self
53
+ # Set +debug+ to true to log all git calls and responses
54
+ attr_accessor :debug
55
+ attr_accessor :use_git_ruby
56
+ attr_accessor :no_quote
57
+
58
+ # The standard +logger+ for debugging git calls - this defaults to a plain STDOUT logger
59
+ attr_accessor :logger
60
+ def log(str)
61
+ logger.debug { str }
62
+ end
63
+ end
64
+ self.debug = false
65
+ self.use_git_ruby = true
66
+ self.no_quote = false
67
+
68
+ @logger ||= ::Logger.new(STDOUT)
69
+
70
+ def self.version
71
+ VERSION
72
+ end
73
+ end
@@ -0,0 +1,52 @@
1
+ module Gifts::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
+ #
15
+ # str - The String in this format: 'John Doe <jdoe@example.com>'
16
+ #
17
+ # Returns Git::Actor.
18
+ def self.from_string(str)
19
+ case str
20
+ when /<.+>/
21
+ m, name, email = *str.match(/(.*) <(.+?)>/)
22
+ return self.new(name, email)
23
+ else
24
+ return self.new(str, nil)
25
+ end
26
+ end
27
+
28
+ # Outputs an actor string for Git commits.
29
+ #
30
+ # actor = Actor.new('bob', 'bob@email.com')
31
+ # actor.output(time) # => "bob <bob@email.com> UNIX_TIME +0700"
32
+ #
33
+ # time - The Time the commit was authored or committed.
34
+ #
35
+ # Returns a String.
36
+ def output(time)
37
+ offset = time.utc_offset / 60
38
+ "%s <%s> %d %+.2d%.2d" % [
39
+ @name,
40
+ @email || "null",
41
+ time.to_i,
42
+ offset / 60,
43
+ offset.abs % 60]
44
+ end
45
+
46
+ # Pretty object inspection
47
+ def inspect
48
+ %Q{#<Gifts::Grit::Actor "#{@name} <#{@email}>">}
49
+ end
50
+ end # Actor
51
+
52
+ end # Gifts::Grit
@@ -0,0 +1,70 @@
1
+ module Gifts::Grit
2
+
3
+ class Blame
4
+
5
+ attr_reader :lines
6
+
7
+ def initialize(repo, file, commit, lines=nil)
8
+ @repo = repo
9
+ @file = file
10
+ @commit = commit
11
+ if lines.nil?
12
+ @lines = []
13
+ load_blame
14
+ else
15
+ @lines = lines
16
+ end
17
+ end
18
+
19
+ def load_blame
20
+ output = @repo.git.blame({'p' => true}, @commit, '--', @file)
21
+ process_raw_blame(output)
22
+ end
23
+
24
+ def process_raw_blame(output)
25
+ lines, final = [], []
26
+ info, commits = {}, {}
27
+
28
+ # process the output
29
+ output.split("\n").each do |line|
30
+ if line[0, 1] == "\t"
31
+ lines << line[1, line.size]
32
+ elsif m = /^(\w{40}) (\d+) (\d+)/.match(line)
33
+ commit_id, old_lineno, lineno = m[1], m[2].to_i, m[3].to_i
34
+ commits[commit_id] = nil if !commits.key?(commit_id)
35
+ info[lineno] = [commit_id, old_lineno]
36
+ end
37
+ end
38
+
39
+ # load all commits in single call
40
+ @repo.batch(*commits.keys).each do |commit|
41
+ commits[commit.id] = commit
42
+ end
43
+
44
+ # get it together
45
+ info.sort.each do |lineno, (commit_id, old_lineno)|
46
+ commit = commits[commit_id]
47
+ final << BlameLine.new(lineno, old_lineno, commit, lines[lineno - 1])
48
+ end
49
+
50
+ @lines = final
51
+ end
52
+
53
+ # Pretty object inspection
54
+ def inspect
55
+ %Q{#<Gifts::Grit::Blame "#{@file} <#{@commit}>">}
56
+ end
57
+
58
+ class BlameLine
59
+ attr_accessor :lineno, :oldlineno, :commit, :line
60
+ def initialize(lineno, oldlineno, commit, line)
61
+ @lineno = lineno
62
+ @oldlineno = oldlineno
63
+ @commit = commit
64
+ @line = line
65
+ end
66
+ end
67
+
68
+ end # Blame
69
+
70
+ end # Gifts::Grit
@@ -0,0 +1,126 @@
1
+ module Gifts::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 Gifts::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 Gifts::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: [Gifts::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{#<Gifts::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 # Gifts::Grit
@@ -0,0 +1,324 @@
1
+ module Gifts::Grit
2
+
3
+ class Commit
4
+ extend Lazy
5
+
6
+ attr_reader :id
7
+ attr_reader :repo
8
+ lazy_reader :parents
9
+ lazy_reader :tree
10
+ lazy_reader :author
11
+ lazy_reader :authored_date
12
+ lazy_reader :committer
13
+ lazy_reader :committed_date
14
+ lazy_reader :message
15
+ lazy_reader :short_message
16
+
17
+ # Parses output from the `git-cat-file --batch'.
18
+ #
19
+ # repo - Gifts::Grit::Repo instance.
20
+ # sha - String SHA of the Commit.
21
+ # size - Fixnum size of the object.
22
+ # object - Parsed String output from `git cat-file --batch`.
23
+ #
24
+ # Returns an Array of Gifts::Grit::Commit objects.
25
+ def self.parse_batch(repo, sha, size, object)
26
+ info, message = object.split("\n\n", 2)
27
+
28
+ lines = info.split("\n")
29
+ tree = lines.shift.split(' ', 2).last
30
+ parents = []
31
+ parents << lines.shift[7..-1] while lines.first[0, 6] == 'parent'
32
+ author, authored_date = Gifts::Grit::Commit.actor(lines.shift)
33
+ committer, committed_date = Gifts::Grit::Commit.actor(lines.shift)
34
+
35
+ Gifts::Grit::Commit.new(
36
+ repo, sha, parents, tree,
37
+ author, authored_date,
38
+ committer, committed_date,
39
+ message.to_s.split("\n"))
40
+ end
41
+
42
+ # Instantiate a new Commit
43
+ # +id+ is the id of the commit
44
+ # +parents+ is an array of commit ids (will be converted into Commit instances)
45
+ # +tree+ is the correspdonding tree id (will be converted into a Tree object)
46
+ # +author+ is the author string
47
+ # +authored_date+ is the authored Time
48
+ # +committer+ is the committer string
49
+ # +committed_date+ is the committed Time
50
+ # +message+ is an array of commit message lines
51
+ #
52
+ # Returns Gifts::Grit::Commit (baked)
53
+ def initialize(repo, id, parents, tree, author, authored_date, committer, committed_date, message)
54
+ @repo = repo
55
+ @id = id
56
+ @parents = parents.map { |p| Commit.create(repo, :id => p) }
57
+ @tree = Tree.create(repo, :id => tree)
58
+ @author = author
59
+ @authored_date = authored_date
60
+ @committer = committer
61
+ @committed_date = committed_date
62
+ @message = message.join("\n")
63
+ @short_message = message.find { |x| !x.strip.empty? } || ''
64
+ end
65
+
66
+ def id_abbrev
67
+ @id_abbrev ||= @repo.git.rev_parse({}, self.id).chomp[0, 7]
68
+ end
69
+
70
+ # Create an unbaked Commit containing just the specified attributes
71
+ # +repo+ is the Repo
72
+ # +atts+ is a Hash of instance variable data
73
+ #
74
+ # Returns Gifts::Grit::Commit (unbaked)
75
+ def self.create(repo, atts)
76
+ self.allocate.create_initialize(repo, atts)
77
+ end
78
+
79
+ # Initializer for Commit.create
80
+ # +repo+ is the Repo
81
+ # +atts+ is a Hash of instance variable data
82
+ #
83
+ # Returns Gifts::Grit::Commit (unbaked)
84
+ def create_initialize(repo, atts)
85
+ @repo = repo
86
+ atts.each do |k, v|
87
+ instance_variable_set("@#{k}", v)
88
+ end
89
+ self
90
+ end
91
+
92
+ def lazy_source
93
+ self.class.find_all(@repo, @id, {:max_count => 1}).first
94
+ end
95
+
96
+ # Count the number of commits reachable from this ref
97
+ # +repo+ is the Repo
98
+ # +ref+ is the ref from which to begin (SHA1 or name)
99
+ #
100
+ # Returns Integer
101
+ def self.count(repo, ref)
102
+ repo.git.rev_list({}, ref).size / 41
103
+ end
104
+
105
+ # Find all commits matching the given criteria.
106
+ # +repo+ is the Repo
107
+ # +ref+ is the ref from which to begin (SHA1 or name) or nil for --all
108
+ # +options+ is a Hash of optional arguments to git
109
+ # :max_count is the maximum number of commits to fetch
110
+ # :skip is the number of commits to skip
111
+ #
112
+ # Returns Gifts::Grit::Commit[] (baked)
113
+ def self.find_all(repo, ref, options = {})
114
+ allowed_options = [:max_count, :skip, :since]
115
+
116
+ default_options = {:pretty => "raw"}
117
+ actual_options = default_options.merge(options)
118
+
119
+ if ref
120
+ output = repo.git.rev_list(actual_options, ref)
121
+ else
122
+ output = repo.git.rev_list(actual_options.merge(:all => true))
123
+ end
124
+
125
+ self.list_from_string(repo, output)
126
+ rescue Gifts::Grit::GitRuby::Repository::NoSuchShaFound
127
+ []
128
+ end
129
+
130
+ # Parse out commit information into an array of baked Commit objects
131
+ # +repo+ is the Repo
132
+ # +text+ is the text output from the git command (raw format)
133
+ #
134
+ # Returns Gifts::Grit::Commit[] (baked)
135
+ #
136
+ # really should re-write this to be more accepting of non-standard commit messages
137
+ # - it broke when 'encoding' was introduced - not sure what else might show up
138
+ #
139
+ def self.list_from_string(repo, text)
140
+ text_gpgless = text.gsub(/gpgsig -----BEGIN PGP SIGNATURE-----[\n\r](.*[\n\r])*? -----END PGP SIGNATURE-----[\n\r]/, "")
141
+ lines = text_gpgless.split("\n")
142
+
143
+ commits = []
144
+
145
+ while !lines.empty?
146
+ # GITLAB patch
147
+ # Skip all garbage unless we get real commit
148
+ while !lines.empty? && lines.first !~ /^commit [a-zA-Z0-9]*$/
149
+ lines.shift
150
+ end
151
+
152
+ id = lines.shift.split.last
153
+ tree = lines.shift.split.last
154
+
155
+ parents = []
156
+ parents << lines.shift.split.last while lines.first =~ /^parent/
157
+
158
+ author_line = lines.shift
159
+ author_line << lines.shift if lines[0] !~ /^committer /
160
+ author, authored_date = self.actor(author_line)
161
+
162
+ committer_line = lines.shift
163
+ committer_line << lines.shift if lines[0] && lines[0] != '' && lines[0] !~ /^encoding/
164
+ committer, committed_date = self.actor(committer_line)
165
+
166
+ # not doing anything with this yet, but it's sometimes there
167
+ encoding = lines.shift.split.last if lines.first =~ /^encoding/
168
+
169
+ # GITLAB patch
170
+ # Skip Signature and other raw data
171
+ lines.shift while lines.first =~ /^ /
172
+
173
+ lines.shift
174
+
175
+ message_lines = []
176
+ message_lines << lines.shift[4..-1] while lines.first =~ /^ {4}/
177
+
178
+ lines.shift while lines.first && lines.first.empty?
179
+
180
+ commits << Commit.new(repo, id, parents, tree, author, authored_date, committer, committed_date, message_lines)
181
+ end
182
+
183
+ commits
184
+ end
185
+
186
+ # Show diffs between two trees.
187
+ #
188
+ # repo - The current Gifts::Grit::Repo instance.
189
+ # a - A String named commit.
190
+ # b - An optional String named commit. Passing an array assumes you
191
+ # wish to omit the second named commit and limit the diff to the
192
+ # given paths.
193
+ # paths - An optional Array of paths to limit the diff.
194
+ # options - An optional Hash of options. Merged into {:full_index => true}.
195
+ #
196
+ # Returns Gifts::Grit::Diff[] (baked)
197
+ def self.diff(repo, a, b = nil, paths = [], options = {})
198
+ if b.is_a?(Array)
199
+ paths = b
200
+ b = nil
201
+ end
202
+ paths.unshift("--") unless paths.empty?
203
+ paths.unshift(b) unless b.nil?
204
+ paths.unshift(a)
205
+ options = {full_index: true, no_color: true, no_ext_diff: true, M: true}.update(options)
206
+ text = repo.git.native(:diff, options, *paths)
207
+ Diff.list_from_string(repo, text, a)
208
+ end
209
+
210
+ def show
211
+ if parents.size > 1
212
+ diff = @repo.git.native(:diff, {:full_index => true}, "#{parents[0].id}...#{parents[1].id}")
213
+ else
214
+ diff = @repo.git.show({:full_index => true, :pretty => 'raw'}, @id)
215
+ end
216
+
217
+ if diff =~ /diff --git "?a/
218
+ diff = diff.sub(/.+?(diff --git "?a)/m, '\1')
219
+ else
220
+ diff = ''
221
+ end
222
+ Diff.list_from_string(@repo, diff, @id)
223
+ end
224
+
225
+ # Shows diffs between the commit's parent and the commit.
226
+ #
227
+ # options - An optional Hash of options, passed to Gifts::Grit::Commit.diff.
228
+ #
229
+ # Returns Gifts::Grit::Diff[] (baked)
230
+ def diffs(options = {})
231
+ if parents.empty?
232
+ show
233
+ else
234
+ self.class.diff(@repo, parents.first.id, @id, [], options)
235
+ end
236
+ end
237
+
238
+ def stats
239
+ stats = @repo.commit_stats(self.sha, 1)[0][-1]
240
+ end
241
+
242
+ # Convert this Commit to a String which is just the SHA1 id
243
+ def to_s
244
+ @id
245
+ end
246
+
247
+ def sha
248
+ @id
249
+ end
250
+
251
+ def date
252
+ @committed_date
253
+ end
254
+
255
+ def to_patch
256
+ @repo.git.format_patch({'1' => true, :stdout => true}, to_s)
257
+ end
258
+
259
+ def notes
260
+ ret = {}
261
+ notes = Note.find_all(@repo)
262
+ notes.each do |note|
263
+ if n = note.commit.tree/(self.id)
264
+ ret[note.name] = n.data
265
+ end
266
+ end
267
+ ret
268
+ end
269
+
270
+ # Calculates the commit's Patch ID. The Patch ID is essentially the SHA1
271
+ # of the diff that the commit is introducing.
272
+ #
273
+ # Returns the 40 character hex String if a patch-id could be calculated
274
+ # or nil otherwise.
275
+ def patch_id
276
+ show = @repo.git.show({}, @id)
277
+ patch_line = @repo.git.native(:patch_id, :input => show)
278
+ if patch_line =~ /^([0-9a-f]{40}) [0-9a-f]{40}\n$/
279
+ $1
280
+ else
281
+ nil
282
+ end
283
+ end
284
+
285
+ # Pretty object inspection
286
+ def inspect
287
+ %Q{#<Gifts::Grit::Commit "#{@id}">}
288
+ end
289
+
290
+ # private
291
+
292
+ # Parse out the actor (author or committer) info
293
+ #
294
+ # Returns [String (actor name and email), Time (acted at time)]
295
+ def self.actor(line)
296
+ m, actor, epoch = *line.match(/^.+? (.*) (\d+) .*$/)
297
+ [Actor.from_string(actor), Time.at(epoch.to_i)]
298
+ end
299
+
300
+ def author_string
301
+ "%s <%s> %s %+05d" % [author.name, author.email, authored_date.to_i, 800]
302
+ end
303
+
304
+ def to_hash
305
+ {
306
+ 'id' => id,
307
+ 'parents' => parents.map { |p| { 'id' => p.id } },
308
+ 'tree' => tree.id,
309
+ 'message' => message,
310
+ 'author' => {
311
+ 'name' => author.name,
312
+ 'email' => author.email
313
+ },
314
+ 'committer' => {
315
+ 'name' => committer.name,
316
+ 'email' => committer.email
317
+ },
318
+ 'authored_date' => authored_date.xmlschema,
319
+ 'committed_date' => committed_date.xmlschema,
320
+ }
321
+ end
322
+ end # Commit
323
+
324
+ end # Gifts::Grit