tap 0.12.1 → 0.12.2

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.
data/History CHANGED
@@ -1,3 +1,11 @@
1
+ == 0.12.2 / 2009-02-23
2
+
3
+ * Added --no-yaml option to Dump and Load
4
+ * Added --aggregate option to Join
5
+ * Updated Dump behavior to merge inputs before process
6
+ * Reworked App so that it is not a Root
7
+ * Added the ability to load workflows via 'tap run'
8
+
1
9
  == 0.12.1 / 2009-02-18
2
10
 
3
11
  Maintenance release with updates to Dump and Load tasks.
data/README CHANGED
@@ -91,6 +91,7 @@ Tap comes with generators. To get started:
91
91
  - Some inconsequential tests on JRuby fail due to bugs in JRuby itself.
92
92
  - Joins, Parser, and Schema require additional documentation and may be
93
93
  reworked in a future release. The workflow syntax should remain the same.
94
+ - Audit.dump only works for certain cases. Merges frequently cause trouble.
94
95
 
95
96
  == Installation
96
97
 
@@ -1,4 +1,4 @@
1
- # tap console {options}
1
+ # tap console [options]
2
2
  #
3
3
  # Opens up an IRB session with Tap initialized to the configurations
4
4
  # in tap.yml. Access the Tap::App.instance through 'app', and
@@ -1,4 +1,4 @@
1
- # tap manifest
1
+ # tap manifest [options]
2
2
  #
3
3
  # Prints information about the current tap environment.
4
4
  #
data/cmd/run.rb CHANGED
@@ -1,4 +1,4 @@
1
- # tap run {options} -- {task options} task INPUTS...
1
+ # tap run FILEPATHS... [options] -- [SCHEMA]
2
2
  #
3
3
  # examples:
4
4
  # tap run --help Prints this help
@@ -8,6 +8,16 @@
8
8
  env = Tap::Env.instance
9
9
  app = Tap::App.instance
10
10
 
11
+ #
12
+ # divide argv
13
+ #
14
+
15
+ run_argv = []
16
+ break_regexp = Tap::Support::Parser::BREAK
17
+ while !ARGV.empty? && ARGV[0] !~ break_regexp
18
+ run_argv << ARGV.shift
19
+ end
20
+
11
21
  #
12
22
  # handle options
13
23
  #
@@ -38,19 +48,31 @@ ConfigParser.new do |opts|
38
48
  exit
39
49
  end
40
50
 
41
- end.parse!(ARGV)
51
+ end.parse!(run_argv, app.config)
42
52
 
43
53
  #
44
54
  # build and run the argv
45
55
  #
46
56
 
47
- env.set_signals
48
- env.build(ARGV)
57
+ run_argv.each do |path|
58
+ unless File.exists?(path)
59
+ puts "No such file or directory - #{path}"
60
+ puts "(did you mean 'tap run -- #{path}'?)"
61
+ exit
62
+ end
63
+
64
+ schema = Tap::Support::Schema.load_file(path)
65
+ env.build(schema, app)
66
+ end
67
+
68
+ schema = Tap::Support::Schema.parse(ARGV)
49
69
  ARGV.clear
70
+ env.build(schema, app)
50
71
 
51
72
  if app.queue.empty?
52
73
  puts "no task specified"
53
74
  exit
54
75
  end
55
76
 
77
+ env.set_signals
56
78
  app.run
@@ -248,8 +248,7 @@ inputs.
248
248
 
249
249
  http://tap.rubyforge.org/images/App.png
250
250
 
251
- Instances of Tap::App coordinate the execution of tasks. Apps are basically a
252
- subclass of Root with an ExecutableQueue.
251
+ Instances of Tap::App coordinate the execution of tasks.
253
252
 
254
253
  Task initialization requires an App, which is by default Tap::App.instance.
255
254
  Tasks use their app for logging, dependency-resolution, checks, and to enque
@@ -370,5 +369,4 @@ http://tap.rubyforge.org/images/Run-Env.png
370
369
 
371
370
  Tap::Exe adds several configurations (ex before/after) which only get loaded
372
371
  for the present directory, and methods for building and executing workflows
373
- from command line inputs. Tap::Exe is a singleton, and is special because it
374
- wraps Tap::App.instance.
372
+ from command line inputs.
@@ -1,6 +1,5 @@
1
1
  require 'logger'
2
2
 
3
- require 'tap/root'
4
3
  require 'tap/support/aggregator'
5
4
  require 'tap/support/dependencies'
6
5
  require 'tap/support/executable_queue'
@@ -123,7 +122,7 @@ module Tap
123
122
  # app.run
124
123
  # array # => [1, 2, 3]
125
124
  #
126
- class App < Root
125
+ class App < Monitor
127
126
  class << self
128
127
  # Sets the current app instance
129
128
  attr_writer :instance
@@ -134,7 +133,9 @@ module Tap
134
133
  @instance ||= App.new
135
134
  end
136
135
  end
137
-
136
+
137
+ include Configurable
138
+
138
139
  # The application logger
139
140
  attr_reader :logger
140
141
 
@@ -157,6 +158,7 @@ module Tap
157
158
  # will be collected by self).
158
159
  attr_reader :on_complete_block
159
160
 
161
+ config :audit, true, &c.switch # Signal auditing
160
162
  config :debug, false, &c.flag # Flag debugging
161
163
  config :force, false, &c.flag # Force execution at checkpoints
162
164
  config :quiet, false, &c.flag # Suppress logging
@@ -179,13 +181,11 @@ module Tap
179
181
  def state_str(state)
180
182
  constants.inject(nil) {|str, s| const_get(s) == state ? s.to_s : str}
181
183
  end
182
- end
183
-
184
- include MonitorMixin
184
+ end
185
185
 
186
186
  # Creates a new App with the given configuration.
187
187
  def initialize(config={}, logger=DEFAULT_LOGGER, &block)
188
- super()
188
+ super() # monitor
189
189
 
190
190
  @state = State::READY
191
191
  @queue = Support::ExecutableQueue.new
@@ -193,7 +193,7 @@ module Tap
193
193
  @dependencies = Support::Dependencies.new
194
194
  @on_complete_block = block
195
195
 
196
- reconfigure(config)
196
+ initialize_config(config)
197
197
  self.logger = logger
198
198
  end
199
199
 
@@ -1,4 +1,5 @@
1
1
  require 'tap/support/constant_manifest'
2
+ autoload(:YAML, 'yaml')
2
3
 
3
4
  module Tap
4
5
  module Support
@@ -5,9 +5,8 @@ require 'tap/support/schema'
5
5
  module Tap
6
6
  class Exe < Env
7
7
  class << self
8
- def instantiate(path=Dir.pwd)
9
- app = App.instance.reconfigure(:root => path)
10
- exe = super(app)
8
+ def instantiate(path_or_root=Dir.pwd)
9
+ exe = super
11
10
 
12
11
  # add all gems if no gems are specified (Note this is VERY SLOW ~ 1/3 the overhead for tap)
13
12
  exe.gems = :all if !File.exists?(Tap::Env::DEFAULT_CONFIG_FILE)
@@ -39,17 +38,9 @@ module Tap
39
38
  end
40
39
  end
41
40
 
42
- # The Root directory structure for self.
43
- nest(:root, Tap::App) do |config|
44
- case config
45
- when App then config
46
- when String then App.new(:root => config)
47
- else App.new(config)
48
- end
49
- end
50
-
51
41
  config :before, nil
52
42
  config :after, nil
43
+
53
44
  # Specify files to require when self is activated.
54
45
  config :requires, [], &c.array_or_nil
55
46
 
@@ -63,15 +54,6 @@ module Tap
63
54
  # The global config file path
64
55
  GLOBAL_CONFIG_FILE = File.join(GLOBAL_HOME, "tap.yml")
65
56
 
66
- def initialize(app=App.instance)
67
- super(app)
68
- end
69
-
70
- # Alias for root (Exe should have a Tap::App as root)
71
- def app
72
- root
73
- end
74
-
75
57
  def activate
76
58
  if super
77
59
 
@@ -117,9 +99,8 @@ module Tap
117
99
  end
118
100
  end
119
101
  end
120
-
121
- def build(argv=ARGV, app=app)
122
- schema = argv.kind_of?(Support::Schema) ? argv : Support::Schema.parse(argv)
102
+
103
+ def build(schema, app=Tap::App.instance)
123
104
  schema.build(app) do |args|
124
105
  task = args.shift
125
106
  const = tasks.search(task)
@@ -90,13 +90,12 @@ module Tap
90
90
 
91
91
  # Constructs a filepath using the dir, name, and the specified paths.
92
92
  #
93
- # t = FileTask.new
94
- # t.app[:data, true] = "/data"
95
- # t.name # => "tap/file_task"
96
- # t.filepath(:data, "result.txt") # => "/data/tap/file_task/result.txt"
93
+ # t = FileTask.new
94
+ # t.name # => "tap/file_task"
95
+ # t.filepath('data', "result.txt") # => File.expand_path("data/tap/file_task/result.txt")
97
96
  #
98
- def filepath(dir, *paths)
99
- app.filepath(dir, name, *paths)
97
+ def filepath(dir, *paths)
98
+ File.expand_path(File.join(dir, name, *paths))
100
99
  end
101
100
 
102
101
  # Makes a backup filepath relative to backup_dir by using name, the
@@ -69,6 +69,7 @@ module Tap
69
69
  lazy_attr :args, :manifest
70
70
  lazy_register :manifest, Arguments
71
71
 
72
+ config :destination_root, Dir.pwd # The destination root directory
72
73
  config :pretend, false, &c.flag # Run but rollback any changes.
73
74
  config :force, false, &c.flag # Overwrite files that already exist.
74
75
  config :skip, false, &c.flag # Skip files that already exist.
@@ -115,6 +116,11 @@ module Tap
115
116
  actions.collect {|action| yield(action) }
116
117
  end
117
118
 
119
+ # Constructs a path relative to destination_root.
120
+ def path(*paths)
121
+ File.expand_path(File.join(*paths), destination_root)
122
+ end
123
+
118
124
  # Peforms a directory action (ex generate or destroy). Must be
119
125
  # overridden by one of the action mixins (ex Generate or Destroy).
120
126
  def directory(target, options={})
@@ -10,12 +10,12 @@ module Tap::Generator::Generators
10
10
  class CommandGenerator < Tap::Generator::Base
11
11
 
12
12
  def manifest(m, command_name)
13
- m.directory app['cmd']
13
+ m.directory path('cmd')
14
14
 
15
15
  template_files do |source, target|
16
- m.template app.filepath('cmd', "#{command_name}.rb"), source, :command_name => command_name
16
+ m.template path('cmd', "#{command_name}.rb"), source, :command_name => command_name
17
17
  end
18
18
  end
19
19
 
20
20
  end
21
- end
21
+ end
@@ -33,7 +33,7 @@ module Tap::Generator::Generators
33
33
 
34
34
  # setup formatting
35
35
  leader = default == nil ? '# ' : ''
36
- config = {key => default}.to_yaml[5..-1]
36
+ config = YAML.dump({key => default})[5..-1]
37
37
  "#{lines.join("\n")}#{leader}#{config.strip}\n\n"
38
38
  end
39
39
  end
@@ -48,7 +48,7 @@ module Tap::Generator::Generators
48
48
 
49
49
  # setup formatting
50
50
  leader = default == nil ? '# ' : ''
51
- config = {key => default}.to_yaml[5..-1]
51
+ config = YAML.dump({key => default})[5..-1]
52
52
  "#{leader}#{config.strip}\n"
53
53
  end
54
54
  end
@@ -72,14 +72,14 @@ module Tap::Generator::Generators
72
72
  # setup
73
73
  tasc = lookup(name)
74
74
  config_name ||= tasc.default_name
75
- config_file = app.filepath('config', config_name)
75
+ config_file = path('config', config_name)
76
76
  config_file += ".yml" if File.extname(config_file).empty?
77
77
 
78
78
  # generate the dumps
79
79
  dumps = Configurable::Utils.dump_file(tasc.configurations, config_file, nest, true, &format_block)
80
80
 
81
81
  # now put the dumps to the manifest
82
- m.directory(app['config'])
82
+ m.directory(path('config'))
83
83
 
84
84
  dumps.each do |path, content|
85
85
  next if content.empty? && !blanks
@@ -9,26 +9,26 @@ module Tap::Generator::Generators
9
9
 
10
10
  def manifest(m, const_name)
11
11
  const = Tap::Support::Constant.new(const_name.camelize)
12
- dir = app.filepath('lib', const.path)
12
+ dir = path('lib', const.path)
13
13
 
14
14
  # make the directory
15
15
  m.directory dir
16
16
 
17
17
  # make the generator
18
- m.template app.filepath(dir, "#{const.basename}_generator.rb"), "task.erb", :const => const
18
+ m.template path(dir, "#{const.basename}_generator.rb"), "task.erb", :const => const
19
19
 
20
20
  # make the templates directory
21
- m.directory app.filepath(dir, 'templates')
21
+ m.directory path(dir, 'templates')
22
22
 
23
23
  # make a template file
24
24
  # (note it's easier to do this as a file since erb is
25
25
  # added, and would have to be escaped in a template)
26
- m.file app.filepath(dir, 'templates', 'template_file.erb') do |file|
26
+ m.file path(dir, 'templates', 'template_file.erb') do |file|
27
27
  file << "# A sample template file.\nkey: <%= key %>\n"
28
28
  end
29
29
 
30
30
  if test
31
- test_path = app.filepath('test', "#{const.path}_generator_test.rb")
31
+ test_path = path('test', "#{const.path}_generator_test.rb")
32
32
  m.directory File.dirname(test_path)
33
33
  m.template test_path, "test.erb", :const => const
34
34
  end
@@ -62,7 +62,7 @@ module Tap::Generator::Generators
62
62
 
63
63
  # setup formatting
64
64
  leader = key == 'root' || default == nil ? '# ' : ''
65
- config = {key => default}.to_yaml[5..-1]
65
+ config = YAML.dump({key => default})[5..-1]
66
66
  "#{lines.join("\n")}#{leader}#{config.strip}\n\n"
67
67
  end
68
68
  end if config_file
@@ -10,12 +10,12 @@ module Tap::Generator::Generators
10
10
  def manifest(m, const_name)
11
11
  const = Tap::Support::Constant.new(const_name.camelize)
12
12
 
13
- task_path = app.filepath('lib', "#{const.path}.rb")
13
+ task_path = path('lib', "#{const.path}.rb")
14
14
  m.directory File.dirname(task_path)
15
15
  m.template task_path, "task.erb", :const => const
16
16
 
17
17
  if test
18
- test_path = app.filepath('test', "#{const.path}_test.rb")
18
+ test_path = path('test', "#{const.path}_test.rb")
19
19
  m.directory File.dirname(test_path)
20
20
  m.template test_path, "test.erb", :const => const
21
21
  end
@@ -10,7 +10,7 @@ module Tap
10
10
  #
11
11
  # class Sample < Tap::Generator::Base
12
12
  # def manifest(m)
13
- # dir = app.filepath(:root, 'dir')
13
+ # dir = path('dir')
14
14
  #
15
15
  # m.directory dir
16
16
  # m.file(File.join(dir, 'file.txt')) {|io| io << "content"}
@@ -27,14 +27,7 @@ module Tap
27
27
  #
28
28
  # assert_equal "content", s.preview['dir/file.txt']
29
29
  #
30
- # Note that relative filepaths are determined from app.root for the
31
- # instance; in tests like the one above, it may be prudent to reset
32
- # the Tap::App.instance like so:
33
- #
34
- # def setup
35
- # Tap::App.instance = Tap::App.new
36
- # end
37
- #
30
+ # Note that relative filepaths are relative to destination_root.
38
31
  module Preview
39
32
 
40
33
  # A hash of (relative_path, content) pairs representing
@@ -45,10 +38,10 @@ module Tap
45
38
  base.instance_variable_set(:@preview, {})
46
39
  end
47
40
 
48
- # Returns the path of path, relative to app.root. If path
49
- # is app.root, '.' will be returned.
41
+ # Returns the path of path, relative to destination_root. If path
42
+ # is destination_root, '.' will be returned.
50
43
  def relative_path(path)
51
- path = app.relative_filepath(:root, path) || path
44
+ path = Root.relative_filepath(destination_root, path, destination_root) || path
52
45
  path.empty? ? "." : path
53
46
  end
54
47
 
@@ -143,7 +143,7 @@ module Tap
143
143
  end
144
144
  end
145
145
 
146
- audit = Audit.new(self, send(method_name, *inputs), previous)
146
+ audit = Audit.new(self, send(method_name, *inputs), app.audit ? previous : nil)
147
147
  if complete_block = on_complete_block || app.on_complete_block
148
148
  complete_block.call(audit)
149
149
  else
@@ -36,6 +36,19 @@ module Tap
36
36
  synchronize { size == 0 }
37
37
  end
38
38
 
39
+ def has?(entry)
40
+ synchronize do
41
+ entry_id = entry.object_id
42
+
43
+ @rounds.each do |round|
44
+ round.each do |enqued_entry|
45
+ return true if entry_id == enqued_entry.object_id
46
+ end
47
+ end
48
+ false
49
+ end
50
+ end
51
+
39
52
  # Enqueues the method and inputs. Raises an error if the
40
53
  # method is not an Executable.
41
54
  def enq(method, inputs)
@@ -68,7 +81,7 @@ module Tap
68
81
  check_method(method)
69
82
  end
70
83
 
71
- @rounds << round.dup
84
+ @rounds << round
72
85
  end
73
86
  end
74
87
 
@@ -23,6 +23,10 @@ module Tap
23
23
  # than executed immediately.
24
24
  config :stack, false, :short => 'k', &c.boolean
25
25
 
26
+ # Aggregates results and enques them to the target
27
+ # in a trailing round.
28
+ config :aggregate, false, :short => 'a', &c.boolean
29
+
26
30
  # Initializes a new join with the specified configuration.
27
31
  def initialize(config={})
28
32
  initialize_config(config)
@@ -69,12 +73,43 @@ module Tap
69
73
  # stack the executable is enqued the executable is executed
70
74
  #
71
75
  def enq(executable, *_results)
72
- unpack(_results) do |_result|
73
- if stack
74
- executable.enq(*_result)
75
- else
76
- executable._execute(*_result)
76
+ case
77
+ when aggregate
78
+
79
+ case
80
+ when iterate, splat, stack
81
+ raise "iterate, splat, or stack and aggregate"
82
+ else collect(executable, _results)
83
+ end
84
+
85
+ else
86
+ unpack(_results) do |_result|
87
+ case
88
+ when stack
89
+ executable.enq(*_result)
90
+ else
91
+ executable._execute(*_result)
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ # returns the aggregator for self
98
+ def aggregator # :nodoc:
99
+ @aggregator ||= {}
100
+ end
101
+
102
+ # helper method to aggregate audited results
103
+ def collect(executable, inputs) # :nodoc:
104
+ queue = executable.app.queue
105
+ entry = aggregator[executable]
106
+
107
+ queue.synchronize do
108
+ unless queue.has?(entry)
109
+ entry = aggregator[executable] = [executable, []]
110
+ queue.concat [entry]
77
111
  end
112
+ entry[1].concat(inputs)
78
113
  end
79
114
  end
80
115
 
@@ -209,10 +209,6 @@ module Tap
209
209
  argv = opts.parse!(argv, {}, false)
210
210
 
211
211
  # load configurations
212
- if config_path == nil && name != nil
213
- config_path = app.filepath('config', "#{name}.yml")
214
- end
215
-
216
212
  config = load_config(config_path)
217
213
 
218
214
  # build and reconfigure the instance
@@ -11,6 +11,9 @@ module Tap
11
11
  #
12
12
  # % tap run -- [task] --: dump FILEPATH
13
13
  #
14
+ # Results may be printed directly, without conversion to YAML by using the
15
+ # --no-yaml option.
16
+ #
14
17
  # :startdoc::manifest-
15
18
  #
16
19
  # Dumps are organized so that arguments passed on the command line are
@@ -33,9 +36,13 @@ module Tap
33
36
  end
34
37
  end
35
38
 
39
+ lazy_attr :args, :setup
40
+ lazy_register :setup, Lazydoc::Arguments
41
+
36
42
  config :date_format, '%Y-%m-%d %H:%M:%S' # the date format
37
43
  config :audit, true, &c.switch # include the audit trails
38
44
  config :date, true, &c.switch # include a date
45
+ config :yaml, true, &c.switch # dump as yaml (vs string)
39
46
 
40
47
  # The dump target, by default $stdout. Target may be a filepath,
41
48
  # in which case dumps append the file.
@@ -69,8 +76,8 @@ module Tap
69
76
  end
70
77
 
71
78
  # this is the overridden part
72
- send(method_name, *previous)
73
- audit = Support::Audit.new(self, inputs, previous)
79
+ audit = Support::Audit.new(self, inputs, app.audit ? previous : nil)
80
+ send(method_name, audit)
74
81
 
75
82
  if complete_block = on_complete_block || app.on_complete_block
76
83
  complete_block.call(audit)
@@ -83,19 +90,21 @@ module Tap
83
90
 
84
91
  # Prints the _audit to the target. The return value of process is
85
92
  # not recorded in the audit trail.
86
- def process(*_audits)
93
+ def process(_audit)
87
94
  open_io do |io|
88
95
  if date
89
96
  io.puts "# date: #{Time.now.strftime(date_format)}"
90
97
  end
91
98
 
92
- _audits.each do |_audit|
93
- if audit
94
- io.puts "# audit:"
95
- io.puts "# #{_audit.dump.gsub("\n", "\n# ")}"
96
- end
99
+ if audit
100
+ io.puts "# audit:"
101
+ io.puts "# #{_audit.dump.gsub("\n", "\n# ")}"
102
+ end
97
103
 
104
+ if yaml
98
105
  YAML::dump(_audit.value, io)
106
+ else
107
+ io << _audit.value.to_s
99
108
  end
100
109
  end
101
110
  end
@@ -3,22 +3,28 @@ module Tap
3
3
  # :startdoc::manifest the default load task
4
4
  #
5
5
  # Loads YAML-formatted data and makes the result available for other tasks.
6
+ # Use the --no-yaml configuration to read the data without loading as YAML.
7
+ #
6
8
  # Load is typically used as a gateway task to other tasks.
7
9
  #
8
10
  # % tap run -- load FILEPATH --: [task]
9
11
  #
10
12
  class Load < Tap::Task
11
13
 
14
+ config :yaml, true, &c.switch # load as yaml (vs string)
15
+
12
16
  # Loads the input as YAML. Input may be an IO, StringIO, or a filepath.
13
17
  # The loaded object is returned directly.
14
18
  def process(input)
15
- case input
19
+ str = case input
16
20
  when StringIO, IO
17
- YAML.load(input.read)
21
+ input.read
18
22
  else
19
23
  log :load, input
20
- YAML.load_file(input)
24
+ File.read(input)
21
25
  end
26
+
27
+ yaml ? YAML.load(str) : str
22
28
  end
23
29
  end
24
30
  end
@@ -73,7 +73,7 @@ module Tap
73
73
 
74
74
  # The configurations used to initialize self.app
75
75
  def app_config
76
- method_root.config.to_hash.merge(:quiet => true, :debug => true)
76
+ {:quiet => true, :debug => true}
77
77
  end
78
78
 
79
79
  # Reconfigures app with the input configurations for the
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.1
4
+ version: 0.12.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Chiang
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-02-18 00:00:00 -07:00
12
+ date: 2009-02-23 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency