tap 0.19.0 → 1.3.0
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 +100 -45
- data/MIT-LICENSE +1 -1
- data/README +95 -51
- data/bin/tap +11 -57
- data/bin/tapexe +84 -0
- data/doc/API +91 -139
- data/doc/Configuration +93 -0
- data/doc/Examples/Command Line +10 -42
- data/doc/Examples/Tapfile +124 -0
- data/doc/Ruby to Ruby +87 -0
- data/doc/Workflow Syntax +185 -0
- data/lib/tap.rb +74 -5
- data/lib/tap/app.rb +217 -310
- data/lib/tap/app/api.rb +44 -23
- data/lib/tap/app/queue.rb +11 -12
- data/lib/tap/app/stack.rb +4 -4
- data/lib/tap/declarations.rb +200 -0
- data/lib/tap/declarations/context.rb +31 -0
- data/lib/tap/declarations/description.rb +33 -0
- data/lib/tap/env.rb +133 -779
- data/lib/tap/env/cache.rb +87 -0
- data/lib/tap/env/constant.rb +94 -39
- data/lib/tap/env/path.rb +71 -0
- data/lib/tap/join.rb +42 -78
- data/lib/tap/joins/gate.rb +85 -0
- data/lib/tap/joins/switch.rb +4 -2
- data/lib/tap/joins/sync.rb +3 -3
- data/lib/tap/middleware.rb +5 -5
- data/lib/tap/middlewares/debugger.rb +18 -58
- data/lib/tap/parser.rb +115 -183
- data/lib/tap/root.rb +162 -239
- data/lib/tap/signal.rb +72 -0
- data/lib/tap/signals.rb +20 -2
- data/lib/tap/signals/class_methods.rb +38 -43
- data/lib/tap/signals/configure.rb +19 -0
- data/lib/tap/signals/help.rb +5 -7
- data/lib/tap/signals/load.rb +49 -0
- data/lib/tap/signals/module_methods.rb +1 -0
- data/lib/tap/task.rb +46 -275
- data/lib/tap/tasks/dump.rb +21 -16
- data/lib/tap/tasks/list.rb +184 -0
- data/lib/tap/tasks/load.rb +4 -4
- data/lib/tap/tasks/prompt.rb +128 -0
- data/lib/tap/tasks/signal.rb +42 -0
- data/lib/tap/tasks/singleton.rb +35 -0
- data/lib/tap/tasks/stream.rb +64 -0
- data/lib/tap/utils.rb +83 -0
- data/lib/tap/version.rb +2 -2
- data/lib/tap/workflow.rb +124 -0
- data/tap.yml +0 -0
- metadata +59 -24
- data/cmd/console.rb +0 -43
- data/cmd/manifest.rb +0 -118
- data/cmd/run.rb +0 -145
- data/doc/Examples/Workflow +0 -40
- data/lib/tap/app/node.rb +0 -29
- data/lib/tap/env/context.rb +0 -61
- data/lib/tap/env/gems.rb +0 -63
- data/lib/tap/env/manifest.rb +0 -179
- data/lib/tap/env/minimap.rb +0 -308
- data/lib/tap/intern.rb +0 -50
- data/lib/tap/joins.rb +0 -9
- data/lib/tap/prompt.rb +0 -36
- data/lib/tap/root/utils.rb +0 -220
- data/lib/tap/root/versions.rb +0 -138
- data/lib/tap/signals/signal.rb +0 -68
data/lib/tap/app/api.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
require '
|
2
|
-
require 'tap/signals/help'
|
1
|
+
require 'tap/app'
|
3
2
|
|
4
3
|
module Tap
|
5
4
|
class App
|
@@ -30,7 +29,7 @@ module Tap
|
|
30
29
|
#
|
31
30
|
# The parse method uses parser by default, so subclasses can simply
|
32
31
|
# modify parser and ensure parse still works correctly.
|
33
|
-
def parser
|
32
|
+
def parser(app)
|
34
33
|
opts = ConfigParser.new
|
35
34
|
|
36
35
|
unless configurations.empty?
|
@@ -42,34 +41,44 @@ module Tap
|
|
42
41
|
opts.separator "options:"
|
43
42
|
|
44
43
|
# add option to print help
|
45
|
-
opts.on("
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
44
|
+
opts.on("--help", "Print this help") do
|
45
|
+
lines = ["#{self}#{desc.empty? ? '' : ' -- '}#{desc.to_s}"]
|
46
|
+
lines << help
|
47
|
+
lines << "usage: tap #{to_s.underscore} #{respond_to?(:args) ? args : nil}"
|
48
|
+
lines << nil
|
49
|
+
lines << opts
|
50
|
+
raise lines.join("\n")
|
50
51
|
end
|
51
52
|
|
52
53
|
opts
|
53
54
|
end
|
54
55
|
|
56
|
+
def parse(argv=ARGV, app=Tap::App.current, &block)
|
57
|
+
parse!(argv.dup, app, &block)
|
58
|
+
end
|
59
|
+
|
55
60
|
# Parses the argv into an instance of self. Internally parse parses
|
56
61
|
# an argh then calls build, but there is no requirement that this
|
57
62
|
# occurs in subclasses.
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
argv = parser.parse!(argv, :add_defaults => false)
|
63
|
+
#
|
64
|
+
# Returns the instance. If a block is given, the instance and any
|
65
|
+
# remaining arguments will be yielded to it.
|
66
|
+
def parse!(argv=ARGV, app=Tap::App.current)
|
67
|
+
parser = self.parser(app)
|
68
|
+
args = parser.parse!(argv, :add_defaults => false)
|
69
|
+
obj = build(convert_to_spec(parser, args), app)
|
66
70
|
|
67
|
-
|
71
|
+
if block_given?
|
72
|
+
yield(obj, args)
|
73
|
+
else
|
74
|
+
parser.warn_ignored_args(args)
|
75
|
+
obj
|
76
|
+
end
|
68
77
|
end
|
69
|
-
|
78
|
+
|
70
79
|
# Returns an instance of self. By default build calls new with the
|
71
80
|
# configurations specified by spec['config'], and app.
|
72
|
-
def build(spec={}, app=Tap::App.
|
81
|
+
def build(spec={}, app=Tap::App.current)
|
73
82
|
new(spec['config'] || {}, app)
|
74
83
|
end
|
75
84
|
|
@@ -85,17 +94,23 @@ module Tap
|
|
85
94
|
|
86
95
|
lines.join("\n")
|
87
96
|
end
|
97
|
+
|
98
|
+
protected
|
99
|
+
|
100
|
+
def convert_to_spec(parser, args)
|
101
|
+
{'config' => parser.nested_config}
|
102
|
+
end
|
88
103
|
end
|
89
104
|
|
90
105
|
include Configurable
|
91
106
|
include Signals
|
92
107
|
|
93
|
-
|
108
|
+
define_signal :help, Help # signals help
|
94
109
|
|
95
|
-
# The
|
110
|
+
# The app for self
|
96
111
|
attr_reader :app
|
97
112
|
|
98
|
-
def initialize(config={}, app=Tap::App.
|
113
|
+
def initialize(config={}, app=Tap::App.current)
|
99
114
|
@app = app
|
100
115
|
initialize_config(config)
|
101
116
|
end
|
@@ -108,7 +123,13 @@ module Tap
|
|
108
123
|
# config is a stringified representation of the configurations for self.
|
109
124
|
def to_spec
|
110
125
|
config = self.config.to_hash {|hash, key, value| hash[key.to_s] = value }
|
111
|
-
{'config' => config}
|
126
|
+
config.empty? ? {} : {'config' => config}
|
127
|
+
end
|
128
|
+
|
129
|
+
# Provides an abbreviated version of the default inspect, with only the
|
130
|
+
# class, object_id, and configurations listed.
|
131
|
+
def inspect
|
132
|
+
"#<#{self.class.to_s}:#{object_id} #{config.to_hash.inspect} >"
|
112
133
|
end
|
113
134
|
end
|
114
135
|
end
|
data/lib/tap/app/queue.rb
CHANGED
@@ -3,16 +3,16 @@ require 'monitor'
|
|
3
3
|
module Tap
|
4
4
|
class App
|
5
5
|
|
6
|
-
# Queue allows thread-safe enqueing and dequeing of
|
6
|
+
# Queue allows thread-safe enqueing and dequeing of tasks and inputs for
|
7
7
|
# execution.
|
8
8
|
#
|
9
9
|
# === API
|
10
10
|
#
|
11
11
|
# The following methods are required in alternative implementations of an
|
12
|
-
# applicaton queue, where a job is a [
|
12
|
+
# applicaton queue, where a job is a [task, input] array:
|
13
13
|
#
|
14
|
-
# enq(
|
15
|
-
# unshift(
|
14
|
+
# enq(task, input) # pushes the job onto the queue
|
15
|
+
# unshift(task, input) # unshifts the job onto the queue
|
16
16
|
# deq # shifts a job off the queue
|
17
17
|
# size # returns the number of jobs in the queue
|
18
18
|
# clear # clears the queue, returns current jobs
|
@@ -29,22 +29,21 @@ module Tap
|
|
29
29
|
@queue = []
|
30
30
|
end
|
31
31
|
|
32
|
-
# Enqueues the
|
33
|
-
def enq(
|
32
|
+
# Enqueues the task and input.
|
33
|
+
def enq(task, input)
|
34
34
|
synchronize do
|
35
|
-
@queue.push [
|
35
|
+
@queue.push [task, input]
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
-
# Enqueues the
|
40
|
-
def unshift(
|
39
|
+
# Enqueues the task and input, but to the top of the queue.
|
40
|
+
def unshift(task, input)
|
41
41
|
synchronize do
|
42
|
-
@queue.unshift [
|
42
|
+
@queue.unshift [task, input]
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
-
# Dequeues the next job
|
47
|
-
# the queue is empty.
|
46
|
+
# Dequeues the next job. Returns nil if the queue is empty.
|
48
47
|
def deq
|
49
48
|
synchronize { @queue.shift }
|
50
49
|
end
|
data/lib/tap/app/stack.rb
CHANGED
@@ -11,13 +11,13 @@ module Tap
|
|
11
11
|
@app = app
|
12
12
|
end
|
13
13
|
|
14
|
-
# Checks app for termination and then calls the
|
14
|
+
# Checks app for termination and then calls the task with the input:
|
15
15
|
#
|
16
|
-
#
|
16
|
+
# task.call(input)
|
17
17
|
#
|
18
|
-
def call(
|
18
|
+
def call(task, input)
|
19
19
|
app.check_terminate
|
20
|
-
|
20
|
+
task.call(input)
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
require 'tap/join'
|
2
|
+
require 'tap/workflow'
|
3
|
+
require 'tap/declarations/description'
|
4
|
+
require 'tap/declarations/context'
|
5
|
+
require 'tap/parser'
|
6
|
+
require 'tap/tasks/singleton'
|
7
|
+
|
8
|
+
module Tap
|
9
|
+
module Declarations
|
10
|
+
def env
|
11
|
+
app.env
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns a new node that executes block on call.
|
15
|
+
def node(var=nil, &node) # :yields: *args
|
16
|
+
def node.joins; @joins ||= []; end
|
17
|
+
app.set(var, node) if var
|
18
|
+
node
|
19
|
+
end
|
20
|
+
|
21
|
+
# Generates a join between the inputs and outputs. Join resolves the
|
22
|
+
# class using env and initializes a new instance with the configs and
|
23
|
+
# self.
|
24
|
+
def join(inputs, outputs, config={}, clas=Tap::Join, &block)
|
25
|
+
inputs = [inputs] unless inputs.kind_of?(Array)
|
26
|
+
outputs = [outputs] unless outputs.kind_of?(Array)
|
27
|
+
|
28
|
+
obj = app.init(clas, config, app)
|
29
|
+
obj.join(inputs, outputs, &block)
|
30
|
+
obj
|
31
|
+
end
|
32
|
+
|
33
|
+
# Sets the description for use by the next task declaration.
|
34
|
+
def desc(str)
|
35
|
+
@desc = Lazydoc.register_caller(Description)
|
36
|
+
@desc.desc = str
|
37
|
+
@desc
|
38
|
+
end
|
39
|
+
|
40
|
+
def singleton(&block)
|
41
|
+
baseclass(Tap::Tasks::Singleton, &block)
|
42
|
+
end
|
43
|
+
|
44
|
+
def baseclass(baseclass=Tap::Task)
|
45
|
+
current = @baseclass
|
46
|
+
begin
|
47
|
+
@baseclass = env.constant(baseclass) unless baseclass.nil?
|
48
|
+
yield if block_given?
|
49
|
+
ensure
|
50
|
+
@baseclass = current if block_given?
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Nests tasks within the named module for the duration of the block.
|
55
|
+
# Namespaces may be nested.
|
56
|
+
def namespace(namespace)
|
57
|
+
current = @namespace
|
58
|
+
begin
|
59
|
+
unless namespace.nil? || namespace.kind_of?(Module)
|
60
|
+
const_name = namespace.to_s.camelize
|
61
|
+
unless current.const_defined?(const_name)
|
62
|
+
current.const_set(const_name, Module.new)
|
63
|
+
end
|
64
|
+
namespace = current.const_get(const_name)
|
65
|
+
end
|
66
|
+
|
67
|
+
@namespace = namespace unless namespace.nil?
|
68
|
+
yield if block_given?
|
69
|
+
ensure
|
70
|
+
@namespace = current if block_given?
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def declare(baseclass, const_name, configs={}, &block)
|
75
|
+
const_name = const_name.to_s.camelize
|
76
|
+
subclass = Class.new(env.constant(baseclass))
|
77
|
+
@namespace.const_set(const_name, subclass)
|
78
|
+
|
79
|
+
# define configs
|
80
|
+
configs.each_pair do |key, value|
|
81
|
+
# specifying a desc prevents lazydoc registration of these lines
|
82
|
+
opts = {:desc => ""}
|
83
|
+
opts[:short] = key if key.to_s.length == 1
|
84
|
+
config_block = Configurable::Validation.guess(value)
|
85
|
+
subclass.send(:config, key, value, opts, &config_block)
|
86
|
+
end
|
87
|
+
|
88
|
+
# define process
|
89
|
+
if block
|
90
|
+
# determine arity, correcting for the self arg
|
91
|
+
arity = block.arity
|
92
|
+
arity -= arity > 0 ? 1 : -1
|
93
|
+
signature = Array.new(arity < 0 ? arity.abs - 1 : arity, 'arg')
|
94
|
+
signature << '*args' if arity < 0
|
95
|
+
|
96
|
+
# prevents assessment of process args by lazydoc
|
97
|
+
subclass.const_attrs[:process] = signature.join(' ')
|
98
|
+
subclass.send(:define_method, :process) do |*args|
|
99
|
+
block.call(self, *args)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# register documentation
|
104
|
+
constant = env.set(subclass, nil)
|
105
|
+
|
106
|
+
if @desc
|
107
|
+
subclass.desc = @desc
|
108
|
+
constant.register_as(subclass.type, @desc)
|
109
|
+
@desc = nil
|
110
|
+
end
|
111
|
+
|
112
|
+
subclass
|
113
|
+
end
|
114
|
+
|
115
|
+
def task(const_name, configs={}, baseclass=@baseclass, &block)
|
116
|
+
@desc ||= Lazydoc.register_caller(Description)
|
117
|
+
const_name, prerequisites = parse_prerequisites(const_name)
|
118
|
+
|
119
|
+
if prerequisites.nil?
|
120
|
+
return declare(baseclass, const_name, configs, &block)
|
121
|
+
end
|
122
|
+
|
123
|
+
tasc = declare(Tap::Workflow, const_name, configs) do |workflow|
|
124
|
+
psr = Parser.new
|
125
|
+
args = psr.parse!(prerequisites)
|
126
|
+
warn "ignoring args: #{args.inspect}" unless args.empty?
|
127
|
+
psr.build_to(app)
|
128
|
+
|
129
|
+
obj = init("#{const_name.to_s.underscore}/task", workflow.config.to_hash)
|
130
|
+
setup = lambda {|input| exe(obj, input) }
|
131
|
+
|
132
|
+
[setup, obj]
|
133
|
+
end
|
134
|
+
|
135
|
+
namespace(const_name) do
|
136
|
+
declare(baseclass, 'Task', configs, &block)
|
137
|
+
end
|
138
|
+
|
139
|
+
tasc
|
140
|
+
end
|
141
|
+
|
142
|
+
def work(const_name, definition, configs={}, baseclass=Tap::Workflow, &block)
|
143
|
+
unless definition.kind_of?(String)
|
144
|
+
raise "workflow definition must be a string: #{definition.inspect}"
|
145
|
+
end
|
146
|
+
|
147
|
+
@desc ||= Lazydoc.register_caller(Description)
|
148
|
+
block ||= lambda {|config| node(0) }
|
149
|
+
task({const_name => definition}, configs, baseclass, &block)
|
150
|
+
end
|
151
|
+
|
152
|
+
protected
|
153
|
+
|
154
|
+
def initialize_declare(baseclass=Tap::Task, namespace=Object)
|
155
|
+
@desc = nil
|
156
|
+
@baseclass = baseclass
|
157
|
+
@namespace = namespace
|
158
|
+
end
|
159
|
+
|
160
|
+
private
|
161
|
+
|
162
|
+
def parse_prerequisites(const_name)
|
163
|
+
prerequisites = nil
|
164
|
+
|
165
|
+
if const_name.is_a?(Hash)
|
166
|
+
hash = const_name
|
167
|
+
case hash.length
|
168
|
+
when 0
|
169
|
+
const_name = nil
|
170
|
+
when 1
|
171
|
+
const_name = hash.keys[0]
|
172
|
+
prerequisites = hash[const_name]
|
173
|
+
else
|
174
|
+
raise ArgumentError, "multiple task names specified: #{hash.keys.inspect}"
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
if const_name.nil?
|
179
|
+
raise ArgumentError, "no constant name specified"
|
180
|
+
end
|
181
|
+
|
182
|
+
case prerequisites
|
183
|
+
when nil
|
184
|
+
when String
|
185
|
+
prerequisites = Utils.shellsplit(prerequisites)
|
186
|
+
when Array
|
187
|
+
argv = []
|
188
|
+
prerequisites.each do |prereq|
|
189
|
+
argv << '-!'
|
190
|
+
argv << prereq.to_s
|
191
|
+
end
|
192
|
+
prerequisites = argv
|
193
|
+
else
|
194
|
+
prerequisites = ['-!', prerequisites.to_s]
|
195
|
+
end
|
196
|
+
|
197
|
+
[const_name, prerequisites]
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Tap
|
2
|
+
module Declarations
|
3
|
+
class Context
|
4
|
+
include Declarations
|
5
|
+
include Tap::Utils
|
6
|
+
|
7
|
+
attr_reader :app
|
8
|
+
|
9
|
+
def initialize(app, ns=nil)
|
10
|
+
@app = app
|
11
|
+
initialize_declare
|
12
|
+
namespace(ns)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Runs the command with system and raises an error if the command
|
16
|
+
# fails.
|
17
|
+
def sh(*cmd)
|
18
|
+
app.log :sh, cmd.join(' ')
|
19
|
+
system(*cmd) or raise "Command failed with status (#{$?.exitstatus}): [#{cmd.join(' ')}]"
|
20
|
+
end
|
21
|
+
|
22
|
+
def node(num)
|
23
|
+
app.get(num.to_s)
|
24
|
+
end
|
25
|
+
|
26
|
+
def method_missing(sym, *args, &block)
|
27
|
+
app.send(sym, *args, &block)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Tap
|
2
|
+
module Declarations
|
3
|
+
# :startdoc:::-
|
4
|
+
# A special type of Lazydoc::Comment designed to handle the comment syntax
|
5
|
+
# for task declarations.
|
6
|
+
#
|
7
|
+
# Description instances can be assigned a description, or they may parse
|
8
|
+
# one directly from the comment. Comment lines with the constant attribute
|
9
|
+
# '::' will have the value set as desc.
|
10
|
+
# :startdoc:::+
|
11
|
+
class Description < Lazydoc::Comment
|
12
|
+
|
13
|
+
# The description for self.
|
14
|
+
attr_accessor :desc
|
15
|
+
|
16
|
+
# Parses in-comment descriptions from prepended lines, if present.
|
17
|
+
def prepend(line)
|
18
|
+
if line =~ /\s::(?:\s+(.*?)\s*)?$/
|
19
|
+
self.desc = $1.to_s
|
20
|
+
false
|
21
|
+
else
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Resolves and returns the description.
|
27
|
+
def to_s
|
28
|
+
resolve
|
29
|
+
desc.to_s
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|