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/cmd/console.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
# usage: tap console [options]
|
2
|
-
#
|
3
|
-
# Opens up an IRB session with the Tap environment initialized as specified
|
4
|
-
# in tap.yml. Access a Tap::App instance through 'app' and the execution
|
5
|
-
# environment through 'env'. For example:
|
6
|
-
#
|
7
|
-
# % tap console
|
8
|
-
# >> app.env[:dump]
|
9
|
-
# => Tap::Tasks::Dump
|
10
|
-
# >> app.info
|
11
|
-
# => "state: 0 (READY) queue: 0"
|
12
|
-
# >>
|
13
|
-
#
|
14
|
-
|
15
|
-
ConfigParser.new do |opts|
|
16
|
-
opts.separator ""
|
17
|
-
opts.separator "options:"
|
18
|
-
|
19
|
-
opts.on("-h", "--help", "Show this message") do
|
20
|
-
puts Lazydoc.usage(__FILE__)
|
21
|
-
puts opts
|
22
|
-
exit
|
23
|
-
end
|
24
|
-
end.parse!(ARGV)
|
25
|
-
|
26
|
-
require "irb"
|
27
|
-
|
28
|
-
def app
|
29
|
-
@app ||= Tap::App.instance
|
30
|
-
end
|
31
|
-
|
32
|
-
IRB.start
|
33
|
-
|
34
|
-
# Handles a bug in IRB that causes exit to throw :IRB_EXIT
|
35
|
-
# and consequentially make a warning message, even on a
|
36
|
-
# clean exit. This module resets exit to the original
|
37
|
-
# aliased method.
|
38
|
-
module CleanExit # :nodoc:
|
39
|
-
def exit(ret = 0)
|
40
|
-
__exit__(ret)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
IRB.CurrentContext.extend CleanExit
|
data/cmd/manifest.rb
DELETED
@@ -1,118 +0,0 @@
|
|
1
|
-
# usage: tap manifest [options] [filter]
|
2
|
-
#
|
3
|
-
# Prints a manifest of all resources in the current tap environment. Env
|
4
|
-
# keys may be provided to select a specific set of environments to list.
|
5
|
-
#
|
6
|
-
# % tap manifest
|
7
|
-
# % tap manifest tap-tasks
|
8
|
-
#
|
9
|
-
options = {}
|
10
|
-
ConfigParser.new do |opts|
|
11
|
-
|
12
|
-
opts.separator ""
|
13
|
-
opts.separator "options:"
|
14
|
-
|
15
|
-
opts.on("-h", "--help", "Show this message") do
|
16
|
-
puts Lazydoc.usage(__FILE__)
|
17
|
-
puts opts
|
18
|
-
exit
|
19
|
-
end
|
20
|
-
end.parse!(ARGV)
|
21
|
-
|
22
|
-
template = %Q{<% unless manifests.empty? %>
|
23
|
-
#{'-' * 80}
|
24
|
-
<%= (env_key + ':').ljust(width) %> (<%= env.root.root %>)
|
25
|
-
<% manifests.each do |type, entries| %>
|
26
|
-
<%= type %>
|
27
|
-
<% entries.each do |key, paths| %>
|
28
|
-
<%= key.ljust(width) %> (<%= paths.join(', ') %>)
|
29
|
-
<% end %>
|
30
|
-
<% end %>
|
31
|
-
<% end %>
|
32
|
-
}
|
33
|
-
|
34
|
-
# filter envs to manifest
|
35
|
-
env = Tap::App.instance.env
|
36
|
-
env_keys = env.minihash(true)
|
37
|
-
filter = if ARGV.empty?
|
38
|
-
env_keys.keys
|
39
|
-
else
|
40
|
-
ARGV.collect do |name|
|
41
|
-
env.minimatch(name) or raise "could not find an env matching: #{name}"
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
# build the summary
|
46
|
-
constants = env.constants
|
47
|
-
summary = env.inspect(template, :width => 10) do |templater, globals|
|
48
|
-
current = templater.env
|
49
|
-
manifests = []
|
50
|
-
templater.manifests = manifests
|
51
|
-
next unless filter.include?(current)
|
52
|
-
|
53
|
-
# determine the width of the keys
|
54
|
-
width = globals[:width]
|
55
|
-
env_key = env_keys[current]
|
56
|
-
templater.env_key = env_key
|
57
|
-
width = env_key.length if width < env_key.length
|
58
|
-
|
59
|
-
# build up the entries for each type of resource
|
60
|
-
types = {}
|
61
|
-
constants.entries(current).minimap.each do |key, const|
|
62
|
-
paths = const.require_paths.collect do |path|
|
63
|
-
current.root.relative_path(:root, path) || path
|
64
|
-
end.uniq
|
65
|
-
|
66
|
-
width = key.length if width < key.length
|
67
|
-
|
68
|
-
const.types.keys.each do |type|
|
69
|
-
(types[type] ||= []) << [key, paths]
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
manifests.concat types.to_a.sort_by {|type, minimap| type }
|
74
|
-
globals[:width] = width
|
75
|
-
end
|
76
|
-
puts summary
|
77
|
-
|
78
|
-
if ARGV.empty?
|
79
|
-
templaters = []
|
80
|
-
visited = []
|
81
|
-
globals = env.recursive_inject([nil, nil]) do |(leader, last), current|
|
82
|
-
current_leader = if leader
|
83
|
-
leader.to_s + (last == current ? "`- " : "|- ")
|
84
|
-
else
|
85
|
-
""
|
86
|
-
end
|
87
|
-
|
88
|
-
templaters << Tap::Templater.new("<%= leader %><%= env_key %> \n",
|
89
|
-
:env_key => env_keys[current],
|
90
|
-
:leader => current_leader
|
91
|
-
)
|
92
|
-
|
93
|
-
if leader
|
94
|
-
leader += (last == current ? ' ' : '| ')
|
95
|
-
else
|
96
|
-
leader = ""
|
97
|
-
end
|
98
|
-
|
99
|
-
visited << current
|
100
|
-
current.envs.reverse_each do |e|
|
101
|
-
unless visited.include?(e)
|
102
|
-
last = e
|
103
|
-
break
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
[leader, last]
|
108
|
-
end
|
109
|
-
|
110
|
-
tree = templaters.collect do |templater|
|
111
|
-
templater.build
|
112
|
-
end.join
|
113
|
-
|
114
|
-
puts '-' * 80
|
115
|
-
puts
|
116
|
-
puts tree
|
117
|
-
puts
|
118
|
-
end
|
data/cmd/run.rb
DELETED
@@ -1,145 +0,0 @@
|
|
1
|
-
# usage: tap run [args] [options] -- [SCHEMA]
|
2
|
-
#
|
3
|
-
# examples:
|
4
|
-
# tap run --help Prints this help
|
5
|
-
# tap run -- task --help Prints help for task
|
6
|
-
# tap run -- load hello --: dump Say hello
|
7
|
-
#
|
8
|
-
|
9
|
-
app = Tap::App.instance
|
10
|
-
|
11
|
-
opts = {}
|
12
|
-
parser = ConfigParser.bind(app.config) do |psr|
|
13
|
-
psr.separator ""
|
14
|
-
psr.separator "configurations:"
|
15
|
-
|
16
|
-
psr.add Tap::App.configurations
|
17
|
-
|
18
|
-
psr.separator ""
|
19
|
-
psr.separator "options:"
|
20
|
-
|
21
|
-
psr.on("-h", "--help", "Show this message") do
|
22
|
-
puts Lazydoc.usage(__FILE__)
|
23
|
-
puts psr
|
24
|
-
exit(0)
|
25
|
-
end
|
26
|
-
|
27
|
-
psr.on('-s', '--serialize', 'Serialize the workflow') do
|
28
|
-
opts[:serialize] = true
|
29
|
-
end
|
30
|
-
|
31
|
-
psr.on('-t', '--manifest', 'Print a list of available resources') do
|
32
|
-
constants = app.env.constants
|
33
|
-
|
34
|
-
tasks, joins, middleware = %w{task join middleware}.collect do |type|
|
35
|
-
constants.summarize do |constant|
|
36
|
-
constant.types[type]
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
unless tasks.empty?
|
41
|
-
puts "=== tasks ===" unless middleware.empty? && joins.empty?
|
42
|
-
puts tasks
|
43
|
-
end
|
44
|
-
|
45
|
-
unless joins.empty?
|
46
|
-
puts "=== joins ===" unless tasks.empty? && middleware.empty?
|
47
|
-
puts joins
|
48
|
-
end
|
49
|
-
|
50
|
-
unless middleware.empty?
|
51
|
-
puts "=== middleware ===" unless tasks.empty? && joins.empty?
|
52
|
-
puts middleware
|
53
|
-
end
|
54
|
-
|
55
|
-
exit(0)
|
56
|
-
end
|
57
|
-
|
58
|
-
psr.on('-T', '--tasks', 'Print a list of available tasks') do
|
59
|
-
constants = app.env.constants
|
60
|
-
tasks = constants.summarize do |constant|
|
61
|
-
constant.types['task']
|
62
|
-
end
|
63
|
-
|
64
|
-
puts tasks
|
65
|
-
exit(0)
|
66
|
-
end
|
67
|
-
|
68
|
-
psr.on('-u', '--quick-queue', 'Removes thread-safety from queue') do
|
69
|
-
mod = Module.new do
|
70
|
-
def synchronize
|
71
|
-
yield
|
72
|
-
end
|
73
|
-
end
|
74
|
-
app.queue.extend(mod)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
#
|
79
|
-
# build and run
|
80
|
-
#
|
81
|
-
|
82
|
-
# Traps interrupt the normal flow of the program and so I assume thread safety
|
83
|
-
# is an issue (ex if the INT occurs during an enque and a signal specifies
|
84
|
-
# another enque). A safer way to go is to enque the prompt... when the prompt
|
85
|
-
# is executed the app won't be be doing anything else so thread safety
|
86
|
-
# shouldn't be an issue.
|
87
|
-
Signal.trap('INT') do
|
88
|
-
puts
|
89
|
-
puts "Interrupt! Signals from an interruption are not thread-safe."
|
90
|
-
|
91
|
-
require 'tap/prompt'
|
92
|
-
prompt = Tap::Prompt.new
|
93
|
-
call_prompt = true
|
94
|
-
3.times do
|
95
|
-
print "Wait for thread-safe break? (y/n): "
|
96
|
-
|
97
|
-
case gets.strip
|
98
|
-
when /^y(es)?$/i
|
99
|
-
puts "waiting for break..."
|
100
|
-
app.queue.unshift(prompt, [])
|
101
|
-
call_prompt = false
|
102
|
-
break
|
103
|
-
|
104
|
-
when /^no?$/i
|
105
|
-
break
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
if call_prompt
|
110
|
-
prompt.call
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
begin
|
115
|
-
loop do
|
116
|
-
break if ARGV.empty?
|
117
|
-
parser.scan(ARGV,
|
118
|
-
:option_break => Tap::Parser::BREAK,
|
119
|
-
:keep_break => true
|
120
|
-
) do |path|
|
121
|
-
YAML.load_file(path).each do |spec|
|
122
|
-
app.call(spec)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
break if ARGV.empty?
|
127
|
-
ARGV.replace app.call('sig' => 'parse', 'args' => ARGV)
|
128
|
-
end
|
129
|
-
|
130
|
-
if opts[:serialize]
|
131
|
-
YAML.dump(app.serialize, $stdout)
|
132
|
-
exit(0)
|
133
|
-
end
|
134
|
-
|
135
|
-
opts = nil
|
136
|
-
parser = nil
|
137
|
-
app.run
|
138
|
-
|
139
|
-
rescue
|
140
|
-
raise if app.debug?
|
141
|
-
puts $!.message
|
142
|
-
exit(1)
|
143
|
-
end
|
144
|
-
|
145
|
-
exit(0)
|
data/doc/Examples/Workflow
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
= Workflow Examples
|
2
|
-
|
3
|
-
=== Sequence
|
4
|
-
|
5
|
-
A simple sequence using the --: syntax.
|
6
|
-
|
7
|
-
% tap run -- load 'goodnight moon' --: dump
|
8
|
-
goodnight moon
|
9
|
-
|
10
|
-
=== Sequence (canonical)
|
11
|
-
|
12
|
-
The more canonical way of specifying a sequence.
|
13
|
-
|
14
|
-
% tap run -- load 'goodnight moon' -- dump --[0][1]
|
15
|
-
goodnight moon
|
16
|
-
|
17
|
-
=== Fork
|
18
|
-
|
19
|
-
Multiple outputs for a single input.
|
20
|
-
|
21
|
-
% tap run -- load 'goodnight moon' -- dump -- dump --[0][1,2]
|
22
|
-
goodnight moon
|
23
|
-
goodnight moon
|
24
|
-
|
25
|
-
=== Merge
|
26
|
-
|
27
|
-
Multiple inputs for a single output; note that as seen in the output, dump
|
28
|
-
receives the inputs in serial, whenever they happen to be ready.
|
29
|
-
|
30
|
-
% tap run -- load goodnight -- load moon -- dump --[0,1][2]
|
31
|
-
goodnight
|
32
|
-
moon
|
33
|
-
|
34
|
-
=== Synchronized Merge
|
35
|
-
|
36
|
-
Similar to a merge, but the results of each input are collected into an array
|
37
|
-
before being passed to dump. The printout is: ['goodnight', 'moon'].to_s
|
38
|
-
|
39
|
-
% tap run -- load goodnight -- load moon -- dump --[0,1][2].sync
|
40
|
-
goodnightmoon
|
data/lib/tap/app/node.rb
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
module Tap
|
2
|
-
class App
|
3
|
-
|
4
|
-
# Node adds the node API[link:files/doc/API.html] to objects responding
|
5
|
-
# to call. Additional helper methods are added to simplify the
|
6
|
-
# construction of workflows; they are not required by the API.
|
7
|
-
module Node
|
8
|
-
|
9
|
-
# The joins called when call completes
|
10
|
-
attr_accessor :joins
|
11
|
-
|
12
|
-
# Interns a new node by extending the block with Node.
|
13
|
-
def self.intern(&block)
|
14
|
-
block.extend self
|
15
|
-
end
|
16
|
-
|
17
|
-
# Sets up required variables for extended objects.
|
18
|
-
def self.extended(obj) # :nodoc:
|
19
|
-
obj.instance_variable_set(:@joins, [])
|
20
|
-
end
|
21
|
-
|
22
|
-
# Sets the block as a join for self.
|
23
|
-
def on_complete(&block) # :yields: result
|
24
|
-
self.joins << block if block
|
25
|
-
self
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
data/lib/tap/env/context.rb
DELETED
@@ -1,61 +0,0 @@
|
|
1
|
-
module Tap
|
2
|
-
class Env
|
3
|
-
|
4
|
-
# Context instances track information shared by a set of Env instances, for
|
5
|
-
# instance cached manifest data. Caching cross-env data in a shared space
|
6
|
-
# simplifies managment of this data, especially when dumping and loading it
|
7
|
-
# from a static file.
|
8
|
-
#
|
9
|
-
# Contexts also ensure that only one env in initialized to a given
|
10
|
-
# directory (at least among envs that share the same context). This
|
11
|
-
# prevents errors that arise when one env eventually nests itself.
|
12
|
-
class Context
|
13
|
-
|
14
|
-
# A hash of cached manifest data
|
15
|
-
attr_reader :cache
|
16
|
-
|
17
|
-
# The config file basename
|
18
|
-
attr_reader :basename
|
19
|
-
|
20
|
-
# An array of Env instances registered with self
|
21
|
-
attr_reader :instances
|
22
|
-
|
23
|
-
# Initializes a new Context. Options can specify a cache or a basename.
|
24
|
-
def initialize(options={})
|
25
|
-
options = {
|
26
|
-
:cache => {},
|
27
|
-
:basename => nil
|
28
|
-
}.merge(options)
|
29
|
-
|
30
|
-
@cache = options[:cache]
|
31
|
-
@basename = options[:basename]
|
32
|
-
@instances = []
|
33
|
-
end
|
34
|
-
|
35
|
-
# Registers env with self by adding env to instances. Raises an error
|
36
|
-
# if instances contains an env with the same root directory.
|
37
|
-
def register(env)
|
38
|
-
path = env.root.root
|
39
|
-
|
40
|
-
if instance(path)
|
41
|
-
raise "context already has an env for: #{path}"
|
42
|
-
end
|
43
|
-
|
44
|
-
instances << env
|
45
|
-
self
|
46
|
-
end
|
47
|
-
|
48
|
-
# Gets the instance for the directory currently in instances, or nil
|
49
|
-
# if such an instance does not exist.
|
50
|
-
def instance(dir)
|
51
|
-
instances.find {|env| env.root.root == dir }
|
52
|
-
end
|
53
|
-
|
54
|
-
# Returns the config filepath for the directory (ie basename under dir).
|
55
|
-
# If basename is nil, then config_file always return nil.
|
56
|
-
def config_file(dir)
|
57
|
-
basename ? File.join(dir, basename) : nil
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
data/lib/tap/env/gems.rb
DELETED
@@ -1,63 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
|
3
|
-
module Tap
|
4
|
-
class Env
|
5
|
-
|
6
|
-
# Methods for working with {RubyGems}[http://www.rubygems.org/].
|
7
|
-
module Gems
|
8
|
-
module_function
|
9
|
-
|
10
|
-
# Returns the gemspec for the specified gem. A gem version
|
11
|
-
# can be specified in the name, like 'gem >= 1.2'. The gem
|
12
|
-
# is not activated by this method.
|
13
|
-
def gemspec(gem_name)
|
14
|
-
return gem_name if gem_name.kind_of?(Gem::Specification)
|
15
|
-
|
16
|
-
dependency = if gem_name.kind_of?(Gem::Dependency)
|
17
|
-
gem_name
|
18
|
-
else
|
19
|
-
# figure the version of the gem, by default >= 0.0.0
|
20
|
-
gem_name.to_s =~ /^([^~<=>]*)(.*)$/
|
21
|
-
name, version = $1.strip, $2
|
22
|
-
return nil if name.empty?
|
23
|
-
version = Gem::Requirement.default if version.empty?
|
24
|
-
|
25
|
-
# note the last gem matching the dependency requirements
|
26
|
-
# is the latest matching gem
|
27
|
-
Gem::Dependency.new(name, version)
|
28
|
-
end
|
29
|
-
|
30
|
-
Gem.source_index.search(dependency).last
|
31
|
-
end
|
32
|
-
|
33
|
-
# Selects gem specs for which the block returns true. If
|
34
|
-
# latest is specified, only the latest version of each
|
35
|
-
# gem will be passed to the block.
|
36
|
-
def select_gems(latest=true)
|
37
|
-
specs = latest ?
|
38
|
-
Gem.source_index.latest_specs :
|
39
|
-
Gem.source_index.gems.collect {|(name, spec)| spec }
|
40
|
-
|
41
|
-
# this song and dance is to ensure that specs are sorted
|
42
|
-
# by name (ascending) then version (descending) so that
|
43
|
-
# the latest version of a spec appears first
|
44
|
-
specs_by_name = {}
|
45
|
-
specs.each do |spec|
|
46
|
-
next unless !block_given? || yield(spec)
|
47
|
-
(specs_by_name[spec.name] ||= []) << spec
|
48
|
-
end
|
49
|
-
|
50
|
-
specs = []
|
51
|
-
specs_by_name.keys.sort.each do |name|
|
52
|
-
specs_by_name[name].sort_by do |spec|
|
53
|
-
spec.version
|
54
|
-
end.reverse_each do |spec|
|
55
|
-
specs << spec
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
specs
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|