cucumber_fm-core 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 (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