tap 0.12.1 → 0.12.2

Sign up to get free protection for your applications and to get access to all the features.
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