cucumber_fm-core 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. data/LICENCE +20 -0
  2. data/lib/cucumber_f_m/aggregator.rb +65 -0
  3. data/lib/cucumber_f_m/comment_module/comment.rb +7 -0
  4. data/lib/cucumber_f_m/config.rb +37 -0
  5. data/lib/cucumber_f_m/cvs/git.rb +7 -0
  6. data/lib/cucumber_f_m/feature.rb +141 -0
  7. data/lib/cucumber_f_m/feature_element/background.rb +10 -0
  8. data/lib/cucumber_f_m/feature_element/comment.rb +13 -0
  9. data/lib/cucumber_f_m/feature_element/component/comments.rb +21 -0
  10. data/lib/cucumber_f_m/feature_element/component/information/component.rb +16 -0
  11. data/lib/cucumber_f_m/feature_element/component/tags.rb +108 -0
  12. data/lib/cucumber_f_m/feature_element/component/title.rb +26 -0
  13. data/lib/cucumber_f_m/feature_element/component/total_estimation.rb +42 -0
  14. data/lib/cucumber_f_m/feature_element/example.rb +7 -0
  15. data/lib/cucumber_f_m/feature_element/info.rb +13 -0
  16. data/lib/cucumber_f_m/feature_element/narrative.rb +7 -0
  17. data/lib/cucumber_f_m/feature_element/scenario.rb +15 -0
  18. data/lib/cucumber_f_m/feature_element/scenario_outline.rb +23 -0
  19. data/lib/cucumber_f_m/feature_element/step.rb +7 -0
  20. data/lib/cucumber_f_m/statistic.rb +31 -0
  21. data/lib/cucumber_f_m/tag_filter.rb +85 -0
  22. data/lib/cucumber_feature_manager.rb +164 -0
  23. data/lib/grit/lib/grit.rb +75 -0
  24. data/lib/grit/lib/grit/actor.rb +36 -0
  25. data/lib/grit/lib/grit/blame.rb +61 -0
  26. data/lib/grit/lib/grit/blob.rb +126 -0
  27. data/lib/grit/lib/grit/commit.rb +247 -0
  28. data/lib/grit/lib/grit/commit_stats.rb +128 -0
  29. data/lib/grit/lib/grit/config.rb +44 -0
  30. data/lib/grit/lib/grit/diff.rb +70 -0
  31. data/lib/grit/lib/grit/errors.rb +7 -0
  32. data/lib/grit/lib/grit/git-ruby.rb +267 -0
  33. data/lib/grit/lib/grit/git-ruby/commit_db.rb +52 -0
  34. data/lib/grit/lib/grit/git-ruby/file_index.rb +193 -0
  35. data/lib/grit/lib/grit/git-ruby/git_object.rb +350 -0
  36. data/lib/grit/lib/grit/git-ruby/internal/file_window.rb +58 -0
  37. data/lib/grit/lib/grit/git-ruby/internal/loose.rb +137 -0
  38. data/lib/grit/lib/grit/git-ruby/internal/pack.rb +384 -0
  39. data/lib/grit/lib/grit/git-ruby/internal/raw_object.rb +37 -0
  40. data/lib/grit/lib/grit/git-ruby/object.rb +325 -0
  41. data/lib/grit/lib/grit/git-ruby/repository.rb +767 -0
  42. data/lib/grit/lib/grit/git.rb +323 -0
  43. data/lib/grit/lib/grit/index.rb +122 -0
  44. data/lib/grit/lib/grit/lazy.rb +33 -0
  45. data/lib/grit/lib/grit/merge.rb +45 -0
  46. data/lib/grit/lib/grit/ref.rb +74 -0
  47. data/lib/grit/lib/grit/repo.rb +482 -0
  48. data/lib/grit/lib/grit/ruby1.9.rb +7 -0
  49. data/lib/grit/lib/grit/status.rb +151 -0
  50. data/lib/grit/lib/grit/submodule.rb +88 -0
  51. data/lib/grit/lib/grit/tag.rb +16 -0
  52. data/lib/grit/lib/grit/tree.rb +123 -0
  53. data/lib/grit/lib/open3_detach.rb +46 -0
  54. data/spec/cucumber_f_m/aggregator_spec.rb +210 -0
  55. data/spec/cucumber_f_m/comment_module/comment_spec.rb +4 -0
  56. data/spec/cucumber_f_m/config_spec.rb +27 -0
  57. data/spec/cucumber_f_m/cvs/git_spec.rb +40 -0
  58. data/spec/cucumber_f_m/feature_all_tags_to_scenario_spec.rb +7 -0
  59. data/spec/cucumber_f_m/feature_file_manipulation_spec.rb +29 -0
  60. data/spec/cucumber_f_m/feature_module/background_spec.rb +30 -0
  61. data/spec/cucumber_f_m/feature_module/comment_spec.rb +23 -0
  62. data/spec/cucumber_f_m/feature_module/example_spec.rb +5 -0
  63. data/spec/cucumber_f_m/feature_module/info_spec.rb +30 -0
  64. data/spec/cucumber_f_m/feature_module/narrative_spec.rb +7 -0
  65. data/spec/cucumber_f_m/feature_module/scenario_outline_spec.rb +39 -0
  66. data/spec/cucumber_f_m/feature_module/scenario_spec.rb +33 -0
  67. data/spec/cucumber_f_m/feature_module/step_spec.rb +7 -0
  68. data/spec/cucumber_f_m/feature_module/tag_spec.rb +96 -0
  69. data/spec/cucumber_f_m/feature_spec.rb +229 -0
  70. data/spec/cucumber_f_m/tag_filter_spec.rb +191 -0
  71. data/spec/cucumber_feature_manager_spec.rb +59 -0
  72. data/spec/data/feature_manager/some_ruby_file.rb +0 -0
  73. data/spec/spec_helper.rb +1 -0
  74. metadata +141 -0
@@ -0,0 +1,323 @@
1
+ require 'tempfile'
2
+ module Grit
3
+
4
+ class Git
5
+ class GitTimeout < RuntimeError
6
+ attr_reader :command, :bytes_read
7
+
8
+ def initialize(command = nil, bytes_read = nil)
9
+ @command = command
10
+ @bytes_read = bytes_read
11
+ end
12
+ end
13
+
14
+ undef_method :clone
15
+
16
+ include GitRuby
17
+
18
+ def exist?
19
+ File.exist?(self.git_dir)
20
+ end
21
+
22
+ def put_raw_object(content, type)
23
+ ruby_git.put_raw_object(content, type)
24
+ end
25
+
26
+ def object_exists?(object_id)
27
+ ruby_git.object_exists?(object_id)
28
+ end
29
+
30
+ def select_existing_objects(object_ids)
31
+ object_ids.select do |object_id|
32
+ object_exists?(object_id)
33
+ end
34
+ end
35
+
36
+ class << self
37
+ attr_accessor :git_binary, :git_timeout, :git_max_size
38
+ end
39
+
40
+ if RUBY_PLATFORM.downcase =~ /mswin(?!ce)|mingw|bccwin/
41
+ self.git_binary = "git" # using search path
42
+ else
43
+ self.git_binary = "/usr/bin/env git"
44
+ end
45
+ self.git_timeout = 10
46
+ self.git_max_size = 5242880 # 5.megabytes
47
+
48
+ def self.with_timeout(timeout = 10.seconds)
49
+ old_timeout = Grit::Git.git_timeout
50
+ Grit::Git.git_timeout = timeout
51
+ yield
52
+ Grit::Git.git_timeout = old_timeout
53
+ end
54
+
55
+ attr_accessor :git_dir, :bytes_read, :work_tree
56
+
57
+ def initialize(git_dir)
58
+ self.git_dir = git_dir
59
+ self.work_tree = git_dir.gsub(/\/\.git$/,'')
60
+ self.bytes_read = 0
61
+ end
62
+
63
+ def shell_escape(str)
64
+ str.to_s.gsub("'", "\\\\'").gsub(";", '\\;')
65
+ end
66
+ alias_method :e, :shell_escape
67
+
68
+ # Check if a normal file exists on the filesystem
69
+ # +file+ is the relative path from the Git dir
70
+ #
71
+ # Returns Boolean
72
+ def fs_exist?(file)
73
+ File.exist?(File.join(self.git_dir, file))
74
+ end
75
+
76
+ # Read a normal file from the filesystem.
77
+ # +file+ is the relative path from the Git dir
78
+ #
79
+ # Returns the String contents of the file
80
+ def fs_read(file)
81
+ File.read(File.join(self.git_dir, file))
82
+ end
83
+
84
+ # Write a normal file to the filesystem.
85
+ # +file+ is the relative path from the Git dir
86
+ # +contents+ is the String content to be written
87
+ #
88
+ # Returns nothing
89
+ def fs_write(file, contents)
90
+ path = File.join(self.git_dir, file)
91
+ FileUtils.mkdir_p(File.dirname(path))
92
+ File.open(path, 'w') do |f|
93
+ f.write(contents)
94
+ end
95
+ end
96
+
97
+ # Delete a normal file from the filesystem
98
+ # +file+ is the relative path from the Git dir
99
+ #
100
+ # Returns nothing
101
+ def fs_delete(file)
102
+ FileUtils.rm_rf(File.join(self.git_dir, file))
103
+ end
104
+
105
+ # Move a normal file
106
+ # +from+ is the relative path to the current file
107
+ # +to+ is the relative path to the destination file
108
+ #
109
+ # Returns nothing
110
+ def fs_move(from, to)
111
+ FileUtils.mv(File.join(self.git_dir, from), File.join(self.git_dir, to))
112
+ end
113
+
114
+ # Make a directory
115
+ # +dir+ is the relative path to the directory to create
116
+ #
117
+ # Returns nothing
118
+ def fs_mkdir(dir)
119
+ FileUtils.mkdir_p(File.join(self.git_dir, dir))
120
+ end
121
+
122
+ # Chmod the the file or dir and everything beneath
123
+ # +file+ is the relative path from the Git dir
124
+ #
125
+ # Returns nothing
126
+ def fs_chmod(mode, file = '/')
127
+ FileUtils.chmod_R(mode, File.join(self.git_dir, file))
128
+ end
129
+
130
+ def list_remotes
131
+ remotes = []
132
+ Dir.chdir(File.join(self.git_dir, 'refs/remotes')) do
133
+ remotes = Dir.glob('*')
134
+ end
135
+ remotes
136
+ rescue
137
+ []
138
+ end
139
+
140
+ def create_tempfile(seed, unlink = false)
141
+ path = Tempfile.new(seed).path
142
+ File.unlink(path) if unlink
143
+ return path
144
+ end
145
+
146
+ def commit_from_sha(id)
147
+ git_ruby_repo = GitRuby::Repository.new(self.git_dir)
148
+ object = git_ruby_repo.get_object_by_sha1(id)
149
+
150
+ if object.type == :commit
151
+ id
152
+ elsif object.type == :tag
153
+ object.object
154
+ else
155
+ ''
156
+ end
157
+ end
158
+
159
+ def check_applies(head_sha, applies_sha)
160
+ git_index = create_tempfile('index', true)
161
+ (o1, exit1) = raw_git("git read-tree #{head_sha} 2>/dev/null", git_index)
162
+ (o2, exit2) = raw_git("git diff #{applies_sha}^ #{applies_sha} | git apply --check --cached >/dev/null 2>/dev/null", git_index)
163
+ return (exit1 + exit2)
164
+ end
165
+
166
+ def get_patch(applies_sha)
167
+ git_index = create_tempfile('index', true)
168
+ (patch, exit2) = raw_git("git diff #{applies_sha}^ #{applies_sha}", git_index)
169
+ patch
170
+ end
171
+
172
+ def apply_patch(head_sha, patch)
173
+ git_index = create_tempfile('index', true)
174
+
175
+ git_patch = create_tempfile('patch')
176
+ File.open(git_patch, 'w+') { |f| f.print patch }
177
+
178
+ raw_git("git read-tree #{head_sha} 2>/dev/null", git_index)
179
+ (op, exit) = raw_git("git apply --cached < #{git_patch}", git_index)
180
+ if exit == 0
181
+ return raw_git("git write-tree", git_index).first.chomp
182
+ end
183
+ false
184
+ end
185
+
186
+ # RAW CALLS WITH ENV SETTINGS
187
+ def raw_git_call(command, index)
188
+ tmp = ENV['GIT_INDEX_FILE']
189
+ ENV['GIT_INDEX_FILE'] = index
190
+ out = `#{command}`
191
+ after = ENV['GIT_INDEX_FILE'] # someone fucking with us ??
192
+ ENV['GIT_INDEX_FILE'] = tmp
193
+ if after != index
194
+ raise 'environment was changed for the git call'
195
+ end
196
+ [out, $?.exitstatus]
197
+ end
198
+
199
+ def raw_git(command, index)
200
+ output = nil
201
+ Dir.chdir(self.git_dir) do
202
+ output = raw_git_call(command, index)
203
+ end
204
+ output
205
+ end
206
+ # RAW CALLS WITH ENV SETTINGS END
207
+
208
+
209
+
210
+ # Run the given git command with the specified arguments and return
211
+ # the result as a String
212
+ # +cmd+ is the command
213
+ # +options+ is a hash of Ruby style options
214
+ # +args+ is the list of arguments (to be joined by spaces)
215
+ #
216
+ # Examples
217
+ # git.rev_list({:max_count => 10, :header => true}, "master")
218
+ #
219
+ # Returns String
220
+ def method_missing(cmd, options = {}, *args)
221
+ run('', cmd, '', options, args)
222
+ end
223
+
224
+ # Bypass any pure Ruby implementations and go straight to the native Git command
225
+ #
226
+ # Returns String
227
+ def native(cmd, options = {}, *args)
228
+ method_missing(cmd, options, *args)
229
+ end
230
+
231
+ def run(prefix, cmd, postfix, options, args)
232
+ timeout = options.delete(:timeout) rescue nil
233
+ timeout = true if timeout.nil?
234
+
235
+ opt_args = transform_options(options)
236
+
237
+ if RUBY_PLATFORM.downcase =~ /mswin(?!ce)|mingw|bccwin/
238
+ ext_args = args.reject { |a| a.empty? }.map { |a| (a == '--' || a[0].chr == '|') ? a : "\"#{e(a)}\"" }
239
+ call = "#{prefix}#{Git.git_binary} --git-dir=\"#{self.git_dir}\" #{cmd.to_s.gsub(/_/, '-')} #{(opt_args + ext_args).join(' ')}#{e(postfix)}"
240
+ else
241
+ ext_args = args.reject { |a| a.empty? }.map { |a| (a == '--' || a[0].chr == '|') ? a : "'#{e(a)}'" }
242
+ call = "#{prefix}#{Git.git_binary} --git-dir='#{self.git_dir}' #{cmd.to_s.gsub(/_/, '-')} #{(opt_args + ext_args).join(' ')}#{e(postfix)}"
243
+ end
244
+
245
+ Grit.log(call) if Grit.debug
246
+ response, err = timeout ? sh(call) : wild_sh(call)
247
+ Grit.log(response) if Grit.debug
248
+ Grit.log(err) if Grit.debug
249
+ response
250
+ end
251
+
252
+ def sh(command)
253
+ ret, err = '', ''
254
+ Open3.popen3(command) do |_, stdout, stderr|
255
+ Timeout.timeout(self.class.git_timeout) do
256
+ while tmp = stdout.read(1024)
257
+ ret += tmp
258
+ if (@bytes_read += tmp.size) > self.class.git_max_size
259
+ bytes = @bytes_read
260
+ @bytes_read = 0
261
+ raise GitTimeout.new(command, bytes)
262
+ end
263
+ end
264
+ end
265
+
266
+ while tmp = stderr.read(1024)
267
+ err += tmp
268
+ end
269
+ end
270
+ [ret, err]
271
+ rescue Timeout::Error, Grit::Git::GitTimeout
272
+ bytes = @bytes_read
273
+ @bytes_read = 0
274
+ raise GitTimeout.new(command, bytes)
275
+ end
276
+
277
+ def wild_sh(command)
278
+ ret, err = '', ''
279
+ Open3.popen3(command) do |_, stdout, stderr|
280
+ while tmp = stdout.read(1024)
281
+ ret += tmp
282
+ end
283
+
284
+ while tmp = stderr.read(1024)
285
+ err += tmp
286
+ end
287
+ end
288
+ [ret, err]
289
+ end
290
+
291
+ # Transform Ruby style options into git command line options
292
+ # +options+ is a hash of Ruby style options
293
+ #
294
+ # Returns String[]
295
+ # e.g. ["--max-count=10", "--header"]
296
+ def transform_options(options)
297
+ args = []
298
+ options.keys.each do |opt|
299
+ if opt.to_s.size == 1
300
+ if options[opt] == true
301
+ args << "-#{opt}"
302
+ elsif options[opt] == false
303
+ # ignore
304
+ else
305
+ val = options.delete(opt)
306
+ args << "-#{opt.to_s} '#{e(val)}'"
307
+ end
308
+ else
309
+ if options[opt] == true
310
+ args << "--#{opt.to_s.gsub(/_/, '-')}"
311
+ elsif options[opt] == false
312
+ # ignore
313
+ else
314
+ val = options.delete(opt)
315
+ args << "--#{opt.to_s.gsub(/_/, '-')}='#{e(val)}'"
316
+ end
317
+ end
318
+ end
319
+ args
320
+ end
321
+ end # Git
322
+
323
+ end # Grit
@@ -0,0 +1,122 @@
1
+ module Grit
2
+
3
+ class Index
4
+ attr_accessor :repo, :tree, :current_tree
5
+
6
+ def initialize(repo)
7
+ self.repo = repo
8
+ self.tree = {}
9
+ self.current_tree = nil
10
+ end
11
+
12
+ # Add a file to the index
13
+ # +path+ is the path (including filename)
14
+ # +data+ is the binary contents of the file
15
+ #
16
+ # Returns nothing
17
+ def add(file_path, data)
18
+ path = file_path.split('/')
19
+ filename = path.pop
20
+
21
+ current = self.tree
22
+
23
+ path.each do |dir|
24
+ current[dir] ||= {}
25
+ node = current[dir]
26
+ current = node
27
+ end
28
+
29
+ current[filename] = data
30
+ end
31
+
32
+ # Sets the current tree
33
+ # +tree+ the branch/tag/sha... to use - a string
34
+ #
35
+ # Returns index (self)
36
+ def read_tree(tree)
37
+ self.current_tree = self.repo.tree(tree)
38
+ end
39
+
40
+ # Commit the contents of the index
41
+ # +message+ is the commit message [nil]
42
+ # +parents+ is one or more commits to attach this commit to to form a new head [nil]
43
+ # +actor+ is the details of the user making the commit [nil]
44
+ # +last_tree+ is a tree to compare with - to avoid making empty commits [nil]
45
+ # +head+ is the branch to write this head to [master]
46
+ #
47
+ # Returns a String of the SHA1 of the commit
48
+ def commit(message, parents = nil, actor = nil, last_tree = nil, head = 'master')
49
+ tree_sha1 = write_tree(self.tree, self.current_tree)
50
+ return false if tree_sha1 == last_tree # don't write identical commits
51
+
52
+ contents = []
53
+ contents << ['tree', tree_sha1].join(' ')
54
+ parents.each do |p|
55
+ contents << ['parent', p].join(' ') if p
56
+ end if parents
57
+
58
+ if actor
59
+ name = actor.name
60
+ email = actor.email
61
+ else
62
+ config = Config.new(self.repo)
63
+ name = config['user.name']
64
+ email = config['user.email']
65
+ end
66
+
67
+ author_string = "#{name} <#{email}> #{Time.now.to_i} -0700" # !! TODO : gotta fix this
68
+ contents << ['author', author_string].join(' ')
69
+ contents << ['committer', author_string].join(' ')
70
+ contents << ''
71
+ contents << message
72
+
73
+ commit_sha1 = self.repo.git.put_raw_object(contents.join("\n"), 'commit')
74
+
75
+ self.repo.update_ref(head, commit_sha1)
76
+ end
77
+
78
+ # Recursively write a tree to the index
79
+ # +tree+ is the tree
80
+ #
81
+ # Returns the SHA1 String of the tree
82
+ def write_tree(tree, now_tree = nil)
83
+ tree_contents = {}
84
+
85
+ # fill in original tree
86
+ now_tree.contents.each do |obj|
87
+ sha = [obj.id].pack("H*")
88
+ k = obj.name
89
+ k += '/' if (obj.class == Grit::Tree)
90
+ tree_contents[k] = "%s %s\0%s" % [obj.mode.to_s, obj.name, sha]
91
+ end if now_tree
92
+
93
+ # overwrite with new tree contents
94
+ tree.each do |k, v|
95
+ case v
96
+ when String
97
+ sha = write_blob(v)
98
+ sha = [sha].pack("H*")
99
+ str = "%s %s\0%s" % ['100644', k, sha]
100
+ tree_contents[k] = str
101
+ when Hash
102
+ ctree = now_tree/k if now_tree
103
+ sha = write_tree(v, ctree)
104
+ sha = [sha].pack("H*")
105
+ str = "%s %s\0%s" % ['040000', k, sha]
106
+ tree_contents[k + '/'] = str
107
+ end
108
+ end
109
+ tr = tree_contents.sort.map { |k, v| v }.join('')
110
+ self.repo.git.put_raw_object(tr, 'tree')
111
+ end
112
+
113
+ # Write the blob to the index
114
+ # +data+ is the data to write
115
+ #
116
+ # Returns the SHA1 String of the blob
117
+ def write_blob(data)
118
+ self.repo.git.put_raw_object(data, 'blob')
119
+ end
120
+ end # Index
121
+
122
+ end # Grit
@@ -0,0 +1,33 @@
1
+ ##
2
+ # Allows attributes to be declared as lazy, meaning that they won't be
3
+ # computed until they are asked for.
4
+ #
5
+ # Works by delegating each lazy_reader to a cached lazy_source method.
6
+ #
7
+ # class Person
8
+ # lazy_reader :eyes
9
+ #
10
+ # def lazy_source
11
+ # OpenStruct.new(:eyes => 2)
12
+ # end
13
+ # end
14
+ #
15
+ # >> Person.new.eyes
16
+ # => 2
17
+ #
18
+ module Lazy
19
+ def lazy_reader(*args)
20
+ args.each do |arg|
21
+ ivar = "@#{arg}"
22
+ define_method(arg) do
23
+ if instance_variable_defined?(ivar)
24
+ val = instance_variable_get(ivar)
25
+ return val if val
26
+ end
27
+ instance_variable_set(ivar, (@lazy_source ||= lazy_source).send(arg))
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ Object.extend Lazy unless Object.ancestors.include? Lazy