amp-git 0.1.0

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 (48) hide show
  1. data/.document +5 -0
  2. data/.gitignore +23 -0
  3. data/Gemfile +15 -0
  4. data/LICENSE +20 -0
  5. data/README.rdoc +17 -0
  6. data/Rakefile +68 -0
  7. data/VERSION +1 -0
  8. data/features/amp-git.feature +9 -0
  9. data/features/step_definitions/amp-git_steps.rb +0 -0
  10. data/features/support/env.rb +4 -0
  11. data/lib/amp-git/encoding/binary_delta.rb +171 -0
  12. data/lib/amp-git/repo_format/changeset.rb +348 -0
  13. data/lib/amp-git/repo_format/commit_object.rb +87 -0
  14. data/lib/amp-git/repo_format/index.rb +169 -0
  15. data/lib/amp-git/repo_format/loose_object.rb +78 -0
  16. data/lib/amp-git/repo_format/packfile.rb +263 -0
  17. data/lib/amp-git/repo_format/packfile_index.rb +196 -0
  18. data/lib/amp-git/repo_format/raw_object.rb +56 -0
  19. data/lib/amp-git/repo_format/staging_area.rb +215 -0
  20. data/lib/amp-git/repo_format/tag_object.rb +87 -0
  21. data/lib/amp-git/repo_format/tree_object.rb +98 -0
  22. data/lib/amp-git/repo_format/versioned_file.rb +133 -0
  23. data/lib/amp-git/repositories/local_repository.rb +192 -0
  24. data/lib/amp-git/repository.rb +57 -0
  25. data/lib/amp-git.rb +49 -0
  26. data/lib/amp_plugin.rb +1 -0
  27. data/spec/amp-git_spec.rb +15 -0
  28. data/spec/repository_spec.rb +74 -0
  29. data/spec/spec.opts +1 -0
  30. data/spec/spec_helper.rb +29 -0
  31. data/test/index_tests/index +0 -0
  32. data/test/index_tests/test_helper.rb +16 -0
  33. data/test/index_tests/test_index.rb +69 -0
  34. data/test/packfile_tests/hasindex.idx +0 -0
  35. data/test/packfile_tests/hasindex.pack +0 -0
  36. data/test/packfile_tests/pack-4e1941122fd346526b0a3eee2d92f3277a0092cd.pack +0 -0
  37. data/test/packfile_tests/pack-d23ff2538f970371144ae7182c28730b11eb37c1.idx +0 -0
  38. data/test/packfile_tests/test_helper.rb +16 -0
  39. data/test/packfile_tests/test_packfile.rb +75 -0
  40. data/test/packfile_tests/test_packfile_index_v2.rb +90 -0
  41. data/test/packfile_tests/test_packfile_with_index.rb +76 -0
  42. data/test/test_commit_object.rb +60 -0
  43. data/test/test_git_delta.rb +67 -0
  44. data/test/test_helper.rb +71 -0
  45. data/test/test_loose_object.rb +51 -0
  46. data/test/test_tag_object.rb +72 -0
  47. data/test/test_tree_object.rb +55 -0
  48. metadata +215 -0
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
22
+ .hg*
23
+ *.gemspec
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ # This is an install-only file - it's not used by the application
2
+ source "http://rubygems.org"
3
+ source "http://gems.github.com"
4
+
5
+ gem 'amp-front', '>= 0.1.0'
6
+ gem 'amp-core', '>= 0.1.0'
7
+
8
+ group :development do
9
+ gem 'jeweler'
10
+ gem 'rspec', '< 2.0.0'
11
+ gem 'yard'
12
+ gem 'cucumber'
13
+ gem 'devver-construct', :require => 'construct'
14
+ gem 'minitest'
15
+ end
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Michael Edgar
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,17 @@
1
+ = amp-git
2
+
3
+ Description goes here.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
13
+ * Send me a pull request. Bonus points for topic branches.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2010 Michael Edgar. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,68 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = 'amp-git'
8
+ gem.summary = %Q{The git plugin for Amp.}
9
+ gem.description = %Q{This gem provides git support to Amp. It is bundled with Amp itself.}
10
+ gem.email = 'michael.j.edgar@dartmouth.edu'
11
+ gem.homepage = 'http://github.com/michaeledgar/amp-git'
12
+ gem.authors = ['Michael Edgar']
13
+ gem.add_dependency 'amp-front', '>= 0.1.0'
14
+ gem.add_dependency 'amp-core', '>= 0.1.0'
15
+ gem.add_development_dependency 'rspec', '>= 1.2.9'
16
+ gem.add_development_dependency 'yard', '>= 0'
17
+ gem.add_development_dependency 'cucumber', '>= 0'
18
+ gem.add_development_dependency 'minitest', '>= 1.7'
19
+ gem.add_development_dependency 'devver-construct', '>= 1.1.0'
20
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
21
+ end
22
+ Jeweler::GemcutterTasks.new
23
+ rescue LoadError
24
+ puts 'Jeweler (or a dependency) not available. Install it with: gem install jeweler'
25
+ end
26
+
27
+ require 'spec/rake/spectask'
28
+ Spec::Rake::SpecTask.new(:spec) do |spec|
29
+ spec.libs << 'lib' << 'spec'
30
+ spec.spec_files = FileList['spec/**/*_spec.rb']
31
+ end
32
+
33
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
34
+ spec.libs << 'lib' << 'spec'
35
+ spec.pattern = 'spec/**/*_spec.rb'
36
+ spec.rcov = true
37
+ end
38
+
39
+ require 'rake/testtask'
40
+ Rake::TestTask.new do |t|
41
+ t.libs << 'test'
42
+ t.test_files = FileList['test/**/test*.rb']
43
+ t.verbose = true
44
+ end
45
+
46
+ task :spec => :check_dependencies
47
+
48
+ begin
49
+ require 'cucumber/rake/task'
50
+ Cucumber::Rake::Task.new(:features)
51
+
52
+ task :features => :check_dependencies
53
+ rescue LoadError
54
+ task :features do
55
+ abort 'Cucumber is not available. In order to run features, you must: sudo gem install cucumber'
56
+ end
57
+ end
58
+
59
+ task :default => [:spec, :test]
60
+
61
+ begin
62
+ require 'yard'
63
+ YARD::Rake::YardocTask.new
64
+ rescue LoadError
65
+ task :yardoc do
66
+ abort 'YARD is not available. In order to run yardoc, you must: sudo gem install yard'
67
+ end
68
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,9 @@
1
+ Feature: something something
2
+ In order to something something
3
+ A user something something
4
+ something something something
5
+
6
+ Scenario: something something
7
+ Given inspiration
8
+ When I create a sweet new gem
9
+ Then everyone should see how awesome I am
File without changes
@@ -0,0 +1,4 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
2
+ require 'amp-git'
3
+
4
+ require 'spec/expectations'
@@ -0,0 +1,171 @@
1
+ ##################################################################
2
+ # Licensing Information #
3
+ # #
4
+ # The following code is licensed, as standalone code, under #
5
+ # the Ruby License, unless otherwise directed within the code. #
6
+ # #
7
+ # For information on the license of this code when distributed #
8
+ # with and used in conjunction with the other modules in the #
9
+ # Amp project, please see the root-level LICENSE file. #
10
+ # #
11
+ # © Michael J. Edgar and Ari Brown, 2009-2010 #
12
+ # #
13
+ ##################################################################
14
+
15
+ # This was written by reading the Git Book. No source code was
16
+ # examined to produce this code. It is the original work of its
17
+ # creators, Michael Edgar and Ari Brown.
18
+ #
19
+ # http://git.rsbx.net/Documents/Git_Data_Formats.txt
20
+
21
+ module Amp
22
+ module Core
23
+ module Repositories
24
+ module Git
25
+
26
+ ##
27
+ # All of git's specific encoding classes.
28
+ module Encoding
29
+ class DeltaError < StandardError; end
30
+
31
+ ##
32
+ # Handles the binary delta format that are found in Git's packfiles.
33
+ # The format is detailed in the link above.
34
+ class BinaryDelta
35
+ attr_accessor :base_length, :result_length, :hunks
36
+
37
+ ##
38
+ # Parses a git-format binary delta from a string.
39
+ #
40
+ # @param [String] delta the delta to parse
41
+ def initialize(delta)
42
+ fp = StringIO.new(delta)
43
+ @base_length = read_little_endian_base128(fp)
44
+ @result_length = read_little_endian_base128(fp)
45
+ @hunks = []
46
+ while !fp.eof?
47
+ @hunks << Hunk.parse(fp)
48
+ end
49
+ end
50
+
51
+ ##
52
+ # Applies the binary delta to an original text. Returns the patched
53
+ # data.
54
+ #
55
+ # @param [String] original the text to patch with the delta
56
+ # @return the patched data
57
+ def apply(original)
58
+ if original.size != @base_length
59
+ raise DeltaError.new("Expected input data to be #{@base_length} bytes, but was #{original.size} bytes.")
60
+ end
61
+ output = StringIO.new
62
+ @hunks.each do |hunk|
63
+ hunk.apply(output, original)
64
+ end
65
+ if output.string.size != @result_length
66
+ raise DeltaError.new("Expected patched data to be #{@result_length} bytes, but was #{output.string.size} bytes.")
67
+ end
68
+ output.string
69
+ end
70
+
71
+ private
72
+
73
+ ##
74
+ # Reads a little endian, base-128 value from a stream.
75
+ # This is a variable-length integer, where bytes 0 to N-1 have an MSB
76
+ # of 1, and byte N has an MSB of 0.
77
+ #
78
+ # @param [IO, #read] fp the input stream to read the value from
79
+ # @return [Integer] the encoded integer
80
+ def read_little_endian_base128(fp)
81
+ result = shift = 0
82
+ begin
83
+ byte = Support::StringUtils.ord(fp.read(1))
84
+ result |= (byte & 0x7f) << shift
85
+ shift += 7
86
+ end while byte & 0x80 > 0
87
+ result
88
+ end
89
+
90
+ ##
91
+ # @api private
92
+ class Hunk
93
+ ##
94
+ # Parses a hunk from the input stream. Each hunk is an action: either a
95
+ # a copy from an input stream, or an "insert" which inserts specified
96
+ # data.
97
+ def self.parse(fp)
98
+ opcode = Support::StringUtils.ord(fp.read(1))
99
+ if opcode & 0x80 == 0
100
+ InsertHunk.new(opcode, fp)
101
+ else
102
+ CopyHunk.new(opcode, fp)
103
+ end
104
+ end
105
+ end
106
+
107
+ ##
108
+ # A Hunk that performs an insert operation. One of two types of delta
109
+ # hunks in the git binary delta format.
110
+ class InsertHunk
111
+ ##
112
+ # Creates a new insert hunk.
113
+ #
114
+ # @param [Fixnum] opcode the opcode that identifies this hunk's properties.
115
+ # @param [IO, #read] fp the input stream we're reading this delta from
116
+ def initialize(opcode, fp)
117
+ @data = fp.read(opcode & 0x7f)
118
+ end
119
+
120
+ ##
121
+ # Applies the Hunk with a given output buffer with an input string.
122
+ #
123
+ # @param [IO, #write] output the output buffer we're building up
124
+ # @param [String] input the original data. ignored for InsertHunk.
125
+ def apply(output, input)
126
+ output.write @data
127
+ end
128
+ end
129
+
130
+ ##
131
+ # A Hunk that performs a copy operation. One of two types of delta
132
+ # hunks in the git binary delta format.
133
+ class CopyHunk
134
+ ##
135
+ # Creates a new copy hunk.
136
+ #
137
+ # @param [Fixnum] opcode the opcode that identifies this hunk's properties.
138
+ # @param [IO, #read] fp the input stream we're reading this delta from
139
+ def initialize(opcode, fp)
140
+ @offset = @length = 0
141
+ shift = 0
142
+ 0.upto(3) do
143
+ @offset |= Support::StringUtils.ord(fp.read(1)) << shift if opcode & 0x01 > 0
144
+ opcode >>= 1
145
+ shift += 8
146
+ end
147
+ shift = 0
148
+ 0.upto(2) do
149
+ @length |= Support::StringUtils.ord(fp.read(1)) << shift if opcode & 0x01 > 0
150
+ opcode >>= 1
151
+ shift += 8
152
+ end
153
+ @length = 1 << 16 if @length == 0
154
+ end
155
+
156
+ ##
157
+ # Applies the Hunk with a given output buffer with an input string.
158
+ #
159
+ # @param [IO, #write] output the output buffer we're building up
160
+ # @param [String] input the original data. Used for copies.
161
+ def apply(output, input)
162
+ output.write input[@offset...@offset + @length]
163
+ end
164
+ end
165
+
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,348 @@
1
+ ##################################################################
2
+ # Licensing Information #
3
+ # #
4
+ # The following code is licensed, as standalone code, under #
5
+ # the Ruby License, unless otherwise directed within the code. #
6
+ # #
7
+ # For information on the license of this code when distributed #
8
+ # with and used in conjunction with the other modules in the #
9
+ # Amp project, please see the root-level LICENSE file. #
10
+ # #
11
+ # © Michael J. Edgar and Ari Brown, 2009-2010 #
12
+ # #
13
+ ##################################################################
14
+
15
+ require 'time'
16
+
17
+ module Amp
18
+ module Git
19
+
20
+ ##
21
+ # A Changeset is a simple way of accessing the repository within a certain
22
+ # revision. For example, if the user specifies revision # 36, or revision
23
+ # 3adf21, then we can look those up, and work within the repository at the
24
+ # moment of that revision.
25
+ class Changeset < Amp::Core::Repositories::AbstractChangeset
26
+
27
+ attr_accessor :repo
28
+ attr_reader :revision
29
+ alias_method :repository, :repo
30
+
31
+ def initialize(repo, rev)
32
+ @repo = repo
33
+ if short_name.kind_of?(Integer)
34
+ @revision = rev
35
+ @node_id = convert_rev_to_node(rev)
36
+ else
37
+ @revision = convert_node_to_rev(rev)
38
+ @node_id = rev
39
+ end
40
+ end
41
+
42
+ def node; @node_id; end
43
+
44
+
45
+ ##
46
+ # Compares 2 changesets so we can sort them and whatnot
47
+ #
48
+ # @param [Changeset] other a changeset we will compare against
49
+ # @return [Integer] -1, 0, or 1. Typical comparison.
50
+ def <=>(other)
51
+ date <=> other.date
52
+ end
53
+
54
+ ##
55
+ # Iterates over every tracked file at this point in time.
56
+ #
57
+ # @return [Changeset] self, because that's how #each works
58
+ def each(&b)
59
+ all_files.each( &b)
60
+ self
61
+ end
62
+
63
+ ##
64
+ # the nodes that this node inherits from
65
+ #
66
+ # @return [Array<Abstract Changeset>]
67
+ def parents
68
+ parse!
69
+ @parents
70
+ end
71
+
72
+ ##
73
+ # Retrieve +filename+
74
+ #
75
+ # @return [AbstractVersionedFile]
76
+ def get_file(filename)
77
+ VersionedFile.new @repo, file, :revision => node
78
+ end
79
+ alias_method :[], :get_file
80
+
81
+ ##
82
+ # When was the changeset made?
83
+ #
84
+ # @return [Time]
85
+ def date
86
+ parse!
87
+ @date
88
+ end
89
+
90
+ ##
91
+ # The user who made the changeset
92
+ #
93
+ # @return [String] the user who made the changeset
94
+ def user
95
+ parse!
96
+ @user
97
+ end
98
+
99
+ ##
100
+ # Which branch this changeset belongs to
101
+ #
102
+ # @return [String] the user who made the changeset
103
+ def branch
104
+ parse!
105
+ raise NotImplementedError.new("branch() must be implemented by subclasses of AbstractChangeset.")
106
+ end
107
+
108
+ ##
109
+ # @return [String]
110
+ def description
111
+ parse!
112
+ @description
113
+ end
114
+
115
+ ##
116
+ # What files have been altered in this changeset?
117
+ #
118
+ # @return [Array<String>]
119
+ def altered_files
120
+ parse!
121
+ @altered_files
122
+ end
123
+
124
+ ##
125
+ # Returns a list of all files that are tracked at this current revision.
126
+ #
127
+ # @return [Array<String>] the files tracked at the given revision
128
+ def all_files
129
+ parse!
130
+ @all_files
131
+ end
132
+
133
+ # Is this changeset a working changeset?
134
+ #
135
+ # @return [Boolean] is the changeset representing the working directory?
136
+ def working?
137
+ false
138
+ end
139
+
140
+ private
141
+
142
+
143
+ ##
144
+ # Converts a semi-reliable revision # into a git changeset node.
145
+ def convert_rev_to_node(rev)
146
+ %x(git rev-list --reverse HEAD).split("\n")[rev - 1]
147
+ end
148
+
149
+ ##
150
+ # Converts a git changeset node into a semi-reliable revision #
151
+ def convert_node_to_rev(node)
152
+ %x(git rev-list --reverse HEAD | grep -n #{node} | cut -d: -f1).to_i
153
+ end
154
+
155
+
156
+ # yeah, i know, you could combine these all into one for a clean sweep.
157
+ # but it's clearer this way
158
+ def parse!
159
+ return if @parsed
160
+
161
+ # the parents
162
+ log_data = `git log -1 #{node}^ 2> /dev/null`
163
+
164
+ # DETERMINING PARENTS
165
+ dad = log_data[/^commit (.+)$/, 1]
166
+ dad = dad ? dad[0..6] : nil
167
+ mom = nil
168
+
169
+ if log_data =~ /^Merge: (.+)\.\.\. (.+)\.\.\.$/ # Merge: 1c002dd... 35cfb2b...
170
+ dad = $1 # just have them both use the short name, nbd
171
+ mom = $2
172
+ end
173
+
174
+ @parents = [dad, mom].compact.map {|r| Changeset.new repo, r }
175
+
176
+ # the actual changeset
177
+ log_data = `git log -1 #{node} 2> /dev/null`
178
+
179
+ # DETERMINING DATE
180
+ @date = Time.parse log_data[/^Date:\s+(.+)$/, 1]
181
+
182
+ # DETERMINING USER
183
+ @user = log_data[/^Author:\s+(.+)$/, 1]
184
+
185
+ # DETERMINING DESCRIPTION
186
+ @description = log_data.split("\n")[4..-1].map {|l| l.strip }.join "\n"
187
+
188
+ # ALTERED FILES
189
+ @altered_files = `git log -1 #{node} --pretty=oneline --name-only 2> /dev/null`.split("\n")[1..-1]
190
+
191
+ # ALL FILES
192
+ # @all_files is also sorted. Hooray!
193
+ @all_files = `git ls-tree -r #{node}`.split("\n").map do |line|
194
+ # 100644 blob cdbeb2a42b714a4db49293c87fec4e180d07d44f .autotest
195
+ line[/^\d+ \w+ \w+\s+(.+)$/, 1]
196
+ end
197
+
198
+ @parsed = true
199
+ end
200
+
201
+ end
202
+
203
+ class WorkingDirectoryChangeset < Amp::Repositories::AbstractChangeset
204
+
205
+ attr_accessor :repo
206
+ alias_method :repository, :repo
207
+
208
+ def initialize(repo, opts={:text => ''})
209
+ @repo = repo
210
+ @text = opts[:text]
211
+ @date = Time.parse opts[:date].to_s
212
+ @user = opts[:user]
213
+ @parents = opts[:parents].map {|p| Changeset.new(@repo, p) } if opts[:parents]
214
+ @status = opts[:changes]
215
+ end
216
+
217
+ ##
218
+ # the nodes that this node inherits from
219
+ #
220
+ # @return [Array<Abstract Changeset>]
221
+ def parents
222
+ @parents || (parse! && @parents)
223
+ end
224
+
225
+ def revision; nil; end
226
+
227
+ ##
228
+ # Retrieve +filename+
229
+ #
230
+ # @return [AbstractVersionedFile]
231
+ def get_file(filename)
232
+ VersionedWorkingFile.new @repo, filename
233
+ end
234
+ alias_method :[], :get_file
235
+
236
+ ##
237
+ # When was the changeset made?
238
+ #
239
+ # @return [Time]
240
+ def date
241
+ Time.now
242
+ end
243
+
244
+ ##
245
+ # The user who made the changeset
246
+ #
247
+ # @return [String] the user who made the changeset
248
+ def user
249
+ @user ||= @repo.config.username
250
+ end
251
+
252
+ ##
253
+ # Which branch this changeset belongs to
254
+ #
255
+ # @return [String] the user who made the changeset
256
+ def branch
257
+ @branch ||= `git branch 2> /dev/null`[/\*\s(.+)$/, 1]
258
+ end
259
+
260
+ ##
261
+ # @return [String]
262
+ def description
263
+ @text || ''
264
+ end
265
+
266
+ def status
267
+ @status ||= @repo.status :unknown => true
268
+ end
269
+
270
+ ##
271
+ # Iterates over every tracked file at this point in time.
272
+ #
273
+ # @return [Changeset] self, because that's how #each works
274
+ def each(&b)
275
+ all_files.each( &b)
276
+ self
277
+ end
278
+
279
+ ##
280
+ # Returns a list of all files that are tracked at this current revision.
281
+ #
282
+ # @return [Array<String>] the files tracked at the given revision
283
+ def all_files
284
+ @all_files ||= `git ls-files 2> /dev/null`.split("\n")
285
+ end
286
+
287
+ # Is this changeset a working changeset?
288
+ #
289
+ # @return [Boolean] is the changeset representing the working directory?
290
+ def working?
291
+ true
292
+ end
293
+
294
+ ##
295
+ # Recursively walk the directory tree, getting all files that +match+ says
296
+ # are good.
297
+ #
298
+ # @param [Amp::Match] match how to select the files in the tree
299
+ # @param [Boolean] check_ignored (false) should we check for ignored files?
300
+ # @return [Array<String>] an array of filenames in the tree that match +match+
301
+ def walk(match, check_ignored = false)
302
+ tree = @repo.staging_area.walk true, check_ignored, match
303
+ tree.keys.sort
304
+ end
305
+
306
+ # What files have been altered in this changeset?
307
+ def altered_files; `git show --name-only #{node} 2> /dev/null`.split("\n"); end
308
+ # What files have changed?
309
+ def modified; status[:modified]; end
310
+ # What files have we added?
311
+ def added; status[:added]; end
312
+ # What files have been removed?
313
+ def removed; status[:removed]; end
314
+ # What files have been deleted (but not officially)?
315
+ def deleted; status[:deleted]; end
316
+ # What files are hanging out, but untracked?
317
+ def unknown; status[:unknown]; end
318
+ # What files are pristine since the last revision?
319
+ def clean; status[:normal]; end
320
+
321
+ # yeah, i know, you could combine these all into one for a clean sweep.
322
+ # but it's clearer this way
323
+ def parse!
324
+ return if @parsed
325
+
326
+ log_data = `git log -1 HEAD 2> /dev/null`
327
+
328
+ unless log_data.empty?
329
+ # DETERMINING PARENTS
330
+ commit = log_data[/^commit (.+)$/, 1]
331
+ dad = commit ? commit[0..6] : nil
332
+ mom = nil
333
+
334
+ if log_data =~ /^Merge: (.+)\.\.\. (.+)\.\.\.$/ # Merge: 1c002dd... 35cfb2b...
335
+ dad = $1 # just have them both use the short name, nbd
336
+ mom = $2
337
+ end
338
+
339
+ @parents = [dad, mom].compact.map {|p| Changeset.new @repo, p }
340
+ else
341
+ @parents = []
342
+ end
343
+ @parsed = true
344
+ end
345
+
346
+ end
347
+ end
348
+ end