tap 0.12.4 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. data/History +34 -0
  2. data/README +62 -41
  3. data/bin/tap +36 -40
  4. data/cmd/console.rb +14 -6
  5. data/cmd/manifest.rb +62 -58
  6. data/cmd/run.rb +49 -31
  7. data/doc/API +84 -0
  8. data/doc/Class Reference +83 -115
  9. data/doc/Examples/Command Line +36 -0
  10. data/doc/Examples/Workflow +40 -0
  11. data/lib/tap/app.rb +293 -214
  12. data/lib/tap/app/node.rb +43 -0
  13. data/lib/tap/app/queue.rb +77 -0
  14. data/lib/tap/app/stack.rb +16 -0
  15. data/lib/tap/app/state.rb +22 -0
  16. data/lib/tap/constants.rb +2 -2
  17. data/lib/tap/env.rb +400 -314
  18. data/lib/tap/env/constant.rb +227 -0
  19. data/lib/tap/env/gems.rb +63 -0
  20. data/lib/tap/env/manifest.rb +89 -0
  21. data/lib/tap/env/minimap.rb +292 -0
  22. data/lib/tap/{support → env}/string_ext.rb +2 -2
  23. data/lib/tap/exe.rb +113 -125
  24. data/lib/tap/join.rb +175 -0
  25. data/lib/tap/joins.rb +9 -0
  26. data/lib/tap/joins/switch.rb +44 -0
  27. data/lib/tap/joins/sync.rb +99 -0
  28. data/lib/tap/root.rb +100 -491
  29. data/lib/tap/root/utils.rb +220 -0
  30. data/lib/tap/{support → root}/versions.rb +31 -29
  31. data/lib/tap/schema.rb +248 -0
  32. data/lib/tap/schema/parser.rb +413 -0
  33. data/lib/tap/schema/utils.rb +82 -0
  34. data/lib/tap/support/intern.rb +19 -6
  35. data/lib/tap/support/templater.rb +8 -3
  36. data/lib/tap/task.rb +175 -171
  37. data/lib/tap/tasks/dump.rb +58 -0
  38. data/lib/tap/tasks/load.rb +62 -0
  39. metadata +30 -73
  40. data/cmd/destroy.rb +0 -27
  41. data/cmd/generate.rb +0 -27
  42. data/doc/Command Reference +0 -105
  43. data/doc/Syntax Reference +0 -234
  44. data/doc/Tutorial +0 -348
  45. data/lib/tap/dump.rb +0 -142
  46. data/lib/tap/file_task.rb +0 -384
  47. data/lib/tap/generator/arguments.rb +0 -13
  48. data/lib/tap/generator/base.rb +0 -176
  49. data/lib/tap/generator/destroy.rb +0 -60
  50. data/lib/tap/generator/generate.rb +0 -93
  51. data/lib/tap/generator/generators/command/command_generator.rb +0 -21
  52. data/lib/tap/generator/generators/command/templates/command.erb +0 -32
  53. data/lib/tap/generator/generators/config/config_generator.rb +0 -98
  54. data/lib/tap/generator/generators/generator/generator_generator.rb +0 -37
  55. data/lib/tap/generator/generators/generator/templates/task.erb +0 -27
  56. data/lib/tap/generator/generators/generator/templates/test.erb +0 -26
  57. data/lib/tap/generator/generators/root/root_generator.rb +0 -84
  58. data/lib/tap/generator/generators/root/templates/MIT-LICENSE +0 -22
  59. data/lib/tap/generator/generators/root/templates/README +0 -14
  60. data/lib/tap/generator/generators/root/templates/Rakefile +0 -84
  61. data/lib/tap/generator/generators/root/templates/Rapfile +0 -11
  62. data/lib/tap/generator/generators/root/templates/gemspec +0 -27
  63. data/lib/tap/generator/generators/root/templates/test/tap_test_helper.rb +0 -3
  64. data/lib/tap/generator/generators/task/task_generator.rb +0 -25
  65. data/lib/tap/generator/generators/task/templates/task.erb +0 -14
  66. data/lib/tap/generator/generators/task/templates/test.erb +0 -19
  67. data/lib/tap/generator/manifest.rb +0 -20
  68. data/lib/tap/generator/preview.rb +0 -69
  69. data/lib/tap/load.rb +0 -64
  70. data/lib/tap/spec.rb +0 -41
  71. data/lib/tap/support/aggregator.rb +0 -65
  72. data/lib/tap/support/audit.rb +0 -333
  73. data/lib/tap/support/constant.rb +0 -143
  74. data/lib/tap/support/constant_manifest.rb +0 -126
  75. data/lib/tap/support/dependencies.rb +0 -54
  76. data/lib/tap/support/dependency.rb +0 -44
  77. data/lib/tap/support/executable.rb +0 -198
  78. data/lib/tap/support/executable_queue.rb +0 -125
  79. data/lib/tap/support/gems.rb +0 -43
  80. data/lib/tap/support/join.rb +0 -144
  81. data/lib/tap/support/joins.rb +0 -12
  82. data/lib/tap/support/joins/switch.rb +0 -27
  83. data/lib/tap/support/joins/sync_merge.rb +0 -38
  84. data/lib/tap/support/manifest.rb +0 -171
  85. data/lib/tap/support/minimap.rb +0 -90
  86. data/lib/tap/support/node.rb +0 -176
  87. data/lib/tap/support/parser.rb +0 -450
  88. data/lib/tap/support/schema.rb +0 -385
  89. data/lib/tap/support/shell_utils.rb +0 -67
  90. data/lib/tap/test.rb +0 -77
  91. data/lib/tap/test/assertions.rb +0 -38
  92. data/lib/tap/test/env_vars.rb +0 -29
  93. data/lib/tap/test/extensions.rb +0 -73
  94. data/lib/tap/test/file_test.rb +0 -362
  95. data/lib/tap/test/file_test_class.rb +0 -15
  96. data/lib/tap/test/regexp_escape.rb +0 -87
  97. data/lib/tap/test/script_test.rb +0 -46
  98. data/lib/tap/test/script_tester.rb +0 -115
  99. data/lib/tap/test/subset_test.rb +0 -260
  100. data/lib/tap/test/subset_test_class.rb +0 -99
  101. data/lib/tap/test/tap_test.rb +0 -109
  102. data/lib/tap/test/utils.rb +0 -231
@@ -1,385 +0,0 @@
1
- require 'tap/support/node'
2
- require 'tap/support/joins'
3
- autoload(:Shellwords, 'shellwords')
4
-
5
- module Tap
6
- module Support
7
- autoload(:Parser, 'tap/support/parser')
8
-
9
- class Schema
10
- module Utils
11
- module_function
12
-
13
- # Shell quotes the input string by enclosing in quotes if
14
- # str has no quotes, or double quotes if str has no double
15
- # quotes. Returns the str if it has not whitespace, quotes
16
- # or double quotes.
17
- #
18
- # Raises an ArgumentError if str has both quotes and double
19
- # quotes.
20
- def shell_quote(str)
21
- return str unless str =~ /[\s'"]/
22
-
23
- quote = str.include?("'")
24
- double_quote = str.include?('"')
25
-
26
- case
27
- when !quote then "'#{str}'"
28
- when !double_quote then "\"#{str}\""
29
- else raise ArgumentError, "cannot shell quote: #{str}"
30
- end
31
- end
32
-
33
- # Formats a round string.
34
- #
35
- # format_round(1, [1,2,3]) # => "+1[1,2,3]"
36
- #
37
- def format_round(round, indicies)
38
- "+#{round}[#{indicies.join(',')}]"
39
- end
40
-
41
- # Formats a sequence string.
42
- #
43
- # format_sequence(1, [2,3], {}) # => "1:2:3"
44
- #
45
- def format_sequence(source_index, outputs, options)
46
- ([source_index] + outputs).join(":") + format_options(options)
47
- end
48
-
49
- # Formats a global instance string.
50
- #
51
- # format_instance(1) # => "*1"
52
- #
53
- def format_instance(index)
54
- "*#{index}"
55
- end
56
-
57
- # Formats a fork string.
58
- #
59
- # format_fork(1, [2,3],{}) # => "1[2,3]"
60
- #
61
- def format_fork(source_index, outputs, options)
62
- "#{source_index[0]}[#{outputs.join(',')}]#{format_options(options)}"
63
- end
64
-
65
- # Formats a merge string (note the target index is
66
- # provided first).
67
- #
68
- # format_merge(1, [2,3],{}) # => "1{2,3}"
69
- #
70
- def format_merge(target_index, inputs, options)
71
- "#{target_index[0]}{#{inputs.join(',')}}#{format_options(options)}"
72
- end
73
-
74
- # Formats a sync_merge string (note the target index
75
- # is provided first).
76
- #
77
- # format_sync_merge(1, [2,3],{}) # => "1(2,3)"
78
- #
79
- def format_sync_merge(target_index, inputs, options)
80
- "#{target_index[0]}(#{inputs.join(',')})#{format_options(options)}"
81
- end
82
-
83
- # Formats an options hash into a string. Raises an error
84
- # for unknown options.
85
- #
86
- # format_options({:iterate => true}) # => "i"
87
- #
88
- def format_options(options)
89
- options_str = []
90
- options.each_pair do |key, value|
91
- unless config = Join.configurations[key]
92
- raise "unknown key in: #{options} (#{key})"
93
- end
94
-
95
- if value
96
- options_str << config.attributes[:short]
97
- end
98
- end
99
- options_str.sort.join
100
- end
101
- end
102
-
103
- include Utils
104
-
105
- class << self
106
- def parse(argv=ARGV)
107
- Support::Parser.new(argv).schema
108
- end
109
-
110
- def load(argv)
111
- parser = Parser.new
112
- parser.load(argv)
113
- parser.schema
114
- end
115
-
116
- # Loads a schema from the specified path. Raises an error if no such
117
- # file existts.
118
- def load_file(path)
119
- argv = YAML.load_file(path)
120
- argv ? load(argv) : new
121
- end
122
- end
123
-
124
- # An array of the nodes registered in self.
125
- attr_reader :nodes
126
-
127
- def initialize(nodes=[])
128
- @nodes = nodes
129
- end
130
-
131
- # Retrieves the node at index, or instantiates a new Node if one does
132
- # not already exists.
133
- def [](index)
134
- nodes[index] ||= Node.new
135
- end
136
-
137
- # Returns the index of the node in nodes.
138
- def index(node)
139
- nodes.index(node)
140
- end
141
-
142
- # Shortcut to collect the indicies of each node in nodes. Returns nil if
143
- # nodes is nil.
144
- def indicies(nodes)
145
- nodes ? nodes.collect {|node| index(node) } : nodes
146
- end
147
-
148
- # Returns an array of the argvs for each nodes.
149
- def argvs
150
- nodes.collect do |node|
151
- node == nil ? nil : node.argv
152
- end
153
- end
154
-
155
- # Returns a collection of nodes sorted into arrays by round.
156
- def rounds
157
- rounds = []
158
- nodes.each do |node|
159
- next unless node
160
- round = node.round
161
- (rounds[round] ||= []) << node if round
162
- end
163
- rounds
164
- end
165
-
166
- # Returns a collection of nodes sorted into arrays by natural round.
167
- def natural_rounds
168
- rounds = []
169
- nodes.each do |node|
170
- next unless node
171
- round = node.natural_round
172
- (rounds[round] ||= []) << node if round
173
- end
174
- rounds
175
- end
176
-
177
- # Returns a collection of global nodes.
178
- def globals
179
- globals = []
180
- nodes.each do |node|
181
- if node && node.global?
182
- globals << node
183
- end
184
- end
185
- globals
186
- end
187
-
188
- # Returns an array of joins among nodes in self.
189
- def joins
190
- joins = []
191
-
192
- nodes.each do |node|
193
- next unless node
194
- if join = node.output_join
195
- joins << join
196
- end
197
- end
198
-
199
- nodes.each do |node|
200
- next unless node
201
- if join = node.input_join
202
- joins << join
203
- end
204
- end
205
-
206
- joins.uniq
207
- end
208
-
209
- # Sets a join between the nodes at the input and output indicies.
210
- # Returns the new join.
211
- def set(join_class, inputs, outputs, options={})
212
- unless inputs && !inputs.empty?
213
- raise ArgumentError, "no input nodes specified"
214
- end
215
-
216
- join = [join_class.new(options), [],[]]
217
-
218
- inputs.each {|index| self[index].output = join }
219
- outputs.each {|index| self[index].input = join }
220
-
221
- join
222
- end
223
-
224
- # Removes all nil nodes, nodes with empty argvs, and orphaned joins.
225
- # Additionally reassigns rounds by shifting later rounds up to fill
226
- # any nils in the rounds array.
227
- #
228
- # Returns self.
229
- #
230
- #--
231
- # Note: the algorithm for cleaning up joins can likely be optimized.
232
- def cleanup
233
- # remove nil and empty nodes
234
- nodes.delete_if do |node|
235
- node == nil || node.argv.empty?
236
- end
237
-
238
- # cleanup joins
239
- joins.each do |join, input_nodes, output_nodes|
240
-
241
- # remove missing output nodes
242
- output_nodes.delete_if {|node| !nodes.include?(node) }
243
-
244
- # remove missing input nodes; the removed nodes need
245
- # to be preserved in case an orphan join results and
246
- # the natural round before cleanup needs to be
247
- # determined.
248
- remaining_nodes, removed_nodes = input_nodes.partition {|node| nodes.include?(node) }
249
-
250
- case
251
- when remaining_nodes.empty?
252
- # orphan join: reassign output nodes to natural round
253
- orphan_round = Node.natural_round(removed_nodes)
254
- output_nodes.dup.each {|node| node.round = orphan_round }
255
- else
256
- input_nodes.replace(remaining_nodes)
257
- end
258
- end
259
-
260
- # reassign rounds
261
- index = 0
262
- rounds.compact.each do |round|
263
- round.each {|node| node.round = index }
264
- index += 1
265
- end
266
-
267
- self
268
- end
269
-
270
- def build(app)
271
- cleanup
272
-
273
- # instantiate the nodes
274
- tasks = {}
275
- nodes.each do |node|
276
- tasks[node] = yield(node.argv) if node
277
- end
278
-
279
- # instantiate and reconfigure globals
280
- instances = []
281
- globals.each do |node|
282
- task, args = tasks.delete(node)
283
- instance = task.class.instance
284
-
285
- if instances.include?(instance)
286
- raise "global specified multple times: #{instance}"
287
- end
288
-
289
- instance.reconfigure(task.config.to_hash)
290
- instance.enq(*args)
291
- instances << instance
292
- end
293
-
294
- # build the workflow
295
- joins.each do |join, input_nodes, output_nodes|
296
- sources = input_nodes.collect {|node| tasks[node][0] }
297
- targets = output_nodes.collect {|node| tasks[node][0] }
298
-
299
- join.join(sources, targets)
300
- end
301
-
302
- # build rounds
303
- queues = rounds.compact.collect do |round|
304
- round.collect {|node| tasks.delete(node) }
305
- end
306
-
307
- # notify any args that will be overlooked
308
- tasks.each_pair do |node, (task, args)|
309
- next if args.empty?
310
- warn "warning: ignoring args for node (#{index(node)}) #{task} [#{args.join(' ')}]"
311
- end
312
-
313
- # enque
314
- queues.each {|queue| app.queue.concat(queue) }
315
- app
316
- end
317
-
318
- # Creates an array dump of the contents of self.
319
- def dump
320
- cleanup
321
-
322
- # add argvs
323
- array = argvs
324
-
325
- # add global declarations
326
- globals.each do |node|
327
- array << format_instance(index(node))
328
- end
329
-
330
- # add round declarations
331
- index = 0
332
- rounds.each do |nodes|
333
-
334
- # skip round 0 as it is implicit
335
- if index > 0
336
- indicies = nodes.collect {|node| index(node) }
337
- array << format_round(index, indicies)
338
- end
339
-
340
- index += 1
341
- end
342
-
343
- # add join declarations
344
- joins.each do |join, input_nodes, output_nodes|
345
- inputs = input_nodes.collect {|node| nodes.index(node) }
346
- outputs = output_nodes.collect {|node| nodes.index(node) }
347
-
348
- array << case join
349
- when Joins::SyncMerge then format_sync_merge(outputs, inputs, join.options)
350
- when Join
351
- if inputs.length == 1
352
- if outputs.length == 1
353
- format_sequence(inputs, outputs, join.options)
354
- else
355
- format_fork(inputs, outputs, join.options)
356
- end
357
- else
358
- format_merge(outputs, inputs, join.options)
359
- end
360
- else raise "unknown join type: #{join.class} ([#{inputs.join(',')}], [#{outputs.join(',')}])"
361
- end
362
- end
363
-
364
- array
365
- end
366
-
367
- # Constructs a command-line string for the schema, ex:
368
- # '-- a -- b --0:1'.
369
- def to_s
370
- args = []
371
- dump.each do |obj|
372
- if obj.kind_of?(Array)
373
- args << "--"
374
- args.concat obj.collect {|arg| shell_quote(arg) }
375
- else
376
- args << "--#{obj}"
377
- end
378
- end
379
-
380
- args.join(' ')
381
- end
382
-
383
- end
384
- end
385
- end
@@ -1,67 +0,0 @@
1
- autoload(:Tempfile, 'tempfile')
2
-
3
- module Tap
4
- module Support
5
- # Provides several shell utility methods for calling programs.
6
- #
7
- # == Windows
8
- # MSDOS has command line length limits specific to the version of Windows being
9
- # run (from http://www.ss64.com/nt/cmd.html):
10
- #
11
- # Windows NT:: 256 characters
12
- # Windows 2000:: 2046 characters
13
- # Windows XP:: 8190 characters
14
- #
15
- # Commands longer than these limits fail, usually with something like: 'the input
16
- # line is too long'
17
- module ShellUtils
18
-
19
- # Run the system command +cmd+, passing the result to the block, if given.
20
- # Raises an error if the command fails. Uses the same semantics as
21
- # Kernel::exec and Kernel::system.
22
- #
23
- # Based on FileUtils#sh from Rake.
24
- def sh(*cmd) # :yields: ok, status
25
- ok = system(*cmd)
26
-
27
- if block_given?
28
- yield(ok, $?)
29
- else
30
- ok or raise "Command failed with status (#{$?.exitstatus}): [#{ cmd.join(' ')}]"
31
- end
32
- end
33
-
34
- # Runs the system command +cmd+ using sh, redirecting the output to the
35
- # specified file path. Uses the redirection command:
36
- #
37
- # "> \"#{path}\" 2>&1 #{cmd}"
38
- #
39
- # This redirection has been tested on Windows, OS X, and Fedora. See
40
- # http://www.robvanderwoude.com/redirection.html for pointers on
41
- # redirection. The website notes that this style of redirection SHOULD
42
- # NOT be used with commands that contain other redirections.
43
- def redirect_sh(cmd, path, &block) # :yields: ok, status
44
- sh( "> \"#{path}\" 2>&1 #{cmd}", &block)
45
- end
46
-
47
- # Runs the system command +cmd+ and returns the output as a string.
48
- def capture_sh(cmd, quiet=false, &block) # :yields: ok, status, tempfile_path
49
- tempfile = Tempfile.new('shell_utils')
50
- tempfile.close
51
- redirect_sh(cmd, tempfile.path) do |ok, status|
52
- if block_given?
53
- yield(ok, $?, tempfile.path)
54
- else
55
- ok or raise %Q{Command failed with status (#{$?.exitstatus}): [#{cmd}]
56
- -------------- command output -------------------
57
- #{File.read(tempfile.path)}
58
- -------------------------------------------------
59
- }
60
- end
61
- end
62
-
63
- quiet == true ? "" : File.read(tempfile.path)
64
- end
65
- end
66
- end
67
- end