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