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/intern.rb
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
module Tap
|
2
|
-
# Generates an Intern module to override the specified method_name. Intern
|
3
|
-
# modules are useful to override a tiny bit of functionality without having
|
4
|
-
# to generate a full subclass.
|
5
|
-
#
|
6
|
-
# An Intern module:
|
7
|
-
#
|
8
|
-
# - adds an accessor for <method_name>_block
|
9
|
-
# - overrides <method_name> to call the block, prepending self to
|
10
|
-
# the input arguments
|
11
|
-
#
|
12
|
-
# For example:
|
13
|
-
#
|
14
|
-
# array = [1,2,3].extend Intern(:last)
|
15
|
-
#
|
16
|
-
# array.last # => 3
|
17
|
-
# array.last_block = lambda {|arr| arr.first }
|
18
|
-
# array.last # => 3
|
19
|
-
#
|
20
|
-
def self.Intern(method_name)
|
21
|
-
mod = INTERN_MODULES[method_name.to_sym]
|
22
|
-
return mod unless mod == nil
|
23
|
-
|
24
|
-
mod = INTERN_MODULES[method_name.to_sym] = Module.new
|
25
|
-
mod.module_eval %Q{
|
26
|
-
attr_accessor :#{method_name}_block
|
27
|
-
|
28
|
-
def #{method_name}(*inputs)
|
29
|
-
return super unless #{method_name}_block
|
30
|
-
inputs.unshift(self)
|
31
|
-
|
32
|
-
arity = #{method_name}_block.arity
|
33
|
-
n = inputs.length
|
34
|
-
unless n == arity || (arity < 0 && (-1-n) <= arity)
|
35
|
-
raise ArgumentError.new("wrong number of arguments (\#{n} for \#{arity})")
|
36
|
-
end
|
37
|
-
|
38
|
-
#{method_name}_block.call(*inputs)
|
39
|
-
end
|
40
|
-
}
|
41
|
-
mod
|
42
|
-
end
|
43
|
-
|
44
|
-
# An array of already-declared intern modules,
|
45
|
-
# keyed by method_name.
|
46
|
-
INTERN_MODULES = {}
|
47
|
-
|
48
|
-
# An Intern module for :process.
|
49
|
-
Intern = Tap::Intern(:process)
|
50
|
-
end
|
data/lib/tap/joins.rb
DELETED
data/lib/tap/prompt.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
require 'tap/app/api'
|
2
|
-
require 'readline'
|
3
|
-
|
4
|
-
module Tap
|
5
|
-
|
6
|
-
# :startdoc::prompt
|
7
|
-
#
|
8
|
-
# A prompt to signal a running app. Any signals that return app (ie /run
|
9
|
-
# /stop /terminate) will exit the prompt.
|
10
|
-
class Prompt < App::Api
|
11
|
-
|
12
|
-
def call
|
13
|
-
puts "starting prompt (help for help):"
|
14
|
-
loop do
|
15
|
-
begin
|
16
|
-
line = Readline.readline('--/', true).strip
|
17
|
-
next if line.empty?
|
18
|
-
|
19
|
-
args = Shellwords.shellwords(line)
|
20
|
-
"/#{args.shift}" =~ Tap::Parser::SIGNAL
|
21
|
-
|
22
|
-
result = app.call('obj' => $1, 'sig' => $2, 'args' => args)
|
23
|
-
if result == app
|
24
|
-
break
|
25
|
-
else
|
26
|
-
puts "=> #{result}"
|
27
|
-
end
|
28
|
-
rescue
|
29
|
-
puts $!.message
|
30
|
-
puts $!.backtrace if app.debug?
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
data/lib/tap/root/utils.rb
DELETED
@@ -1,220 +0,0 @@
|
|
1
|
-
require 'tap/root/versions'
|
2
|
-
autoload(:FileUtils, 'fileutils')
|
3
|
-
|
4
|
-
module Tap
|
5
|
-
class Root
|
6
|
-
|
7
|
-
# A variety of utility methods for working with paths.
|
8
|
-
module Utils
|
9
|
-
include Versions
|
10
|
-
|
11
|
-
# Regexp to match a windows-style root path.
|
12
|
-
WIN_ROOT_PATTERN = /^[A-z]:\//
|
13
|
-
|
14
|
-
module_function
|
15
|
-
|
16
|
-
# Returns the path of 'path' relative to dir. Both dir and path will
|
17
|
-
# be expanded to dir_string, if specified, before the relative path is
|
18
|
-
# determined. Returns nil if the path is not relative to dir.
|
19
|
-
#
|
20
|
-
# relative_path('dir', "dir/path/to/file.txt") # => "path/to/file.txt"
|
21
|
-
#
|
22
|
-
def relative_path(dir, path, dir_string=Dir.pwd)
|
23
|
-
if dir_string
|
24
|
-
dir = File.expand_path(dir, dir_string)
|
25
|
-
path = File.expand_path(path, dir_string)
|
26
|
-
end
|
27
|
-
return nil unless Utils.relative?(dir, path, false)
|
28
|
-
|
29
|
-
# use dir.length + 1 to remove a leading '/'. If dir.length + 1 >= expanded.length
|
30
|
-
# as in: relative_path('/path', '/path') then the first arg returns nil, and an
|
31
|
-
# empty string is returned
|
32
|
-
path[(dir.chomp("/").length + 1)..-1] || ""
|
33
|
-
end
|
34
|
-
|
35
|
-
# Generates a target path translated from the source_dir to the
|
36
|
-
# target_dir. Raises an error if the path is not relative to the
|
37
|
-
# source_dir.
|
38
|
-
#
|
39
|
-
# translate("/path/to/file.txt", "/path", "/another/path") # => '/another/path/to/file.txt'
|
40
|
-
#
|
41
|
-
def translate(path, source_dir, target_dir)
|
42
|
-
unless relative_path = relative_path(source_dir, path)
|
43
|
-
raise ArgumentError, "\n#{path}\nis not relative to:\n#{source_dir}"
|
44
|
-
end
|
45
|
-
File.join(target_dir, relative_path)
|
46
|
-
end
|
47
|
-
|
48
|
-
# Returns the path, exchanging the extension with extname. Extname may
|
49
|
-
# optionally omit the leading period.
|
50
|
-
#
|
51
|
-
# exchange('path/to/file.txt', '.html') # => 'path/to/file.html'
|
52
|
-
# exchange('path/to/file.txt', 'rb') # => 'path/to/file.rb'
|
53
|
-
#
|
54
|
-
def exchange(path, extname)
|
55
|
-
"#{path.chomp(File.extname(path))}#{extname[0] == ?. ? '' : '.'}#{extname}"
|
56
|
-
end
|
57
|
-
|
58
|
-
# Lists all unique paths matching the input glob patterns.
|
59
|
-
def glob(*patterns)
|
60
|
-
Dir[*patterns].uniq
|
61
|
-
end
|
62
|
-
|
63
|
-
# Lists all unique versions of path matching the glob version patterns. If
|
64
|
-
# no patterns are specified, then all versions of path will be returned.
|
65
|
-
def version_glob(path, *vpatterns)
|
66
|
-
paths = []
|
67
|
-
|
68
|
-
vpatterns << "*" if vpatterns.empty?
|
69
|
-
vpatterns.each do |vpattern|
|
70
|
-
paths.concat Dir.glob(version(path, vpattern))
|
71
|
-
|
72
|
-
# extra work to include the default version path for any version
|
73
|
-
paths << path if vpattern == "*" && File.exists?(path)
|
74
|
-
end
|
75
|
-
|
76
|
-
paths.uniq
|
77
|
-
end
|
78
|
-
|
79
|
-
# Path suffix glob. Globs along the paths for the specified suffix
|
80
|
-
# pattern.
|
81
|
-
def suffix_glob(suffix_pattern, *paths)
|
82
|
-
paths.collect! {|path| File.join(path, suffix_pattern) }
|
83
|
-
Dir[*paths].uniq
|
84
|
-
end
|
85
|
-
|
86
|
-
# Like Dir.chdir but makes the directory, if necessary, when mkdir is
|
87
|
-
# specified. chdir raises an error for non-existant directories, as well
|
88
|
-
# as non-directory inputs.
|
89
|
-
def chdir(dir, mkdir=false, &block)
|
90
|
-
dir = File.expand_path(dir)
|
91
|
-
|
92
|
-
unless File.directory?(dir)
|
93
|
-
if !File.exists?(dir) && mkdir
|
94
|
-
FileUtils.mkdir_p(dir)
|
95
|
-
else
|
96
|
-
raise ArgumentError, "not a directory: #{dir}"
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
Dir.chdir(dir, &block)
|
101
|
-
end
|
102
|
-
|
103
|
-
# Prepares the input path by making the parent directory for path. If a
|
104
|
-
# block is given, a file is created at path and passed to it; in this
|
105
|
-
# way files with non-existant parent directories are readily made.
|
106
|
-
#
|
107
|
-
# Returns path.
|
108
|
-
def prepare(path)
|
109
|
-
dirname = File.dirname(path)
|
110
|
-
FileUtils.mkdir_p(dirname) unless File.exists?(dirname)
|
111
|
-
File.open(path, "w") {|io| yield(io) } if block_given?
|
112
|
-
path
|
113
|
-
end
|
114
|
-
|
115
|
-
# The path root type indicating windows, *nix, or some unknown style of
|
116
|
-
# paths (:win, :nix, :unknown).
|
117
|
-
def path_root_type
|
118
|
-
@path_root_type ||= case
|
119
|
-
when RUBY_PLATFORM =~ /mswin/ && File.expand_path(".") =~ WIN_ROOT_PATTERN then :win
|
120
|
-
when File.expand_path(".")[0] == ?/ then :nix
|
121
|
-
else :unknown
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
# Returns true if the input path appears to be an expanded path, based on
|
126
|
-
# path_root_type.
|
127
|
-
#
|
128
|
-
# If root_type == :win returns true if the path matches WIN_ROOT_PATTERN.
|
129
|
-
#
|
130
|
-
# expanded?('C:/path') # => true
|
131
|
-
# expanded?('c:/path') # => true
|
132
|
-
# expanded?('D:/path') # => true
|
133
|
-
# expanded?('path') # => false
|
134
|
-
#
|
135
|
-
# If root_type == :nix, then expanded? returns true if the path begins
|
136
|
-
# with '/'.
|
137
|
-
#
|
138
|
-
# expanded?('/path') # => true
|
139
|
-
# expanded?('path') # => false
|
140
|
-
#
|
141
|
-
# Otherwise expanded? always returns nil.
|
142
|
-
def expanded?(path, root_type=path_root_type)
|
143
|
-
case root_type
|
144
|
-
when :win
|
145
|
-
path =~ WIN_ROOT_PATTERN ? true : false
|
146
|
-
when :nix
|
147
|
-
path[0] == ?/
|
148
|
-
else
|
149
|
-
nil
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
# Returns true if path is relative to dir. Both path and dir will be
|
154
|
-
# expanded relative to dir_string, if specified.
|
155
|
-
def relative?(dir, path, dir_string=Dir.pwd)
|
156
|
-
if dir_string
|
157
|
-
dir = File.expand_path(dir, dir_string)
|
158
|
-
path = File.expand_path(path, dir_string)
|
159
|
-
end
|
160
|
-
|
161
|
-
path.rindex(dir, 0) == 0
|
162
|
-
end
|
163
|
-
|
164
|
-
# Trivial indicates when a path does not have content to load. Returns
|
165
|
-
# true if the file at path is empty, non-existant, a directory, or nil.
|
166
|
-
def trivial?(path)
|
167
|
-
path == nil || !File.file?(path) || File.size(path) == 0
|
168
|
-
end
|
169
|
-
|
170
|
-
# Empty returns true when dir is an existing directory that has no files.
|
171
|
-
def empty?(dir)
|
172
|
-
File.directory?(dir) && (Dir.entries(dir) - ['.', '..']).empty?
|
173
|
-
end
|
174
|
-
|
175
|
-
# Returns the path segments for the given path, splitting along the path
|
176
|
-
# divider. Env paths are always represented by a string, if only an
|
177
|
-
# empty string.
|
178
|
-
#
|
179
|
-
# os divider example
|
180
|
-
# windows '\' split('C:\path\to\file') # => ["C:", "path", "to", "file"]
|
181
|
-
# *nix '/' split('/path/to/file') # => ["", "path", "to", "file"]
|
182
|
-
#
|
183
|
-
# The path is always expanded relative to the expand_dir; so '.' and
|
184
|
-
# '..' are resolved. However, unless expand_path == true, only the
|
185
|
-
# segments relative to the expand_dir are returned.
|
186
|
-
#
|
187
|
-
# On windows (note that expanding paths allows the use of slashes or
|
188
|
-
# backslashes):
|
189
|
-
#
|
190
|
-
# Dir.pwd # => 'C:/'
|
191
|
-
# split('path\to\..\.\to\file') # => ["C:", "path", "to", "file"]
|
192
|
-
# split('path/to/.././to/file', false) # => ["path", "to", "file"]
|
193
|
-
#
|
194
|
-
# On *nix (or more generally systems with '/' roots):
|
195
|
-
#
|
196
|
-
# Dir.pwd # => '/'
|
197
|
-
# split('path/to/.././to/file') # => ["", "path", "to", "file"]
|
198
|
-
# split('path/to/.././to/file', false) # => ["path", "to", "file"]
|
199
|
-
#
|
200
|
-
def split(path, expand_path=true, expand_dir=Dir.pwd)
|
201
|
-
path = if expand_path
|
202
|
-
File.expand_path(path, expand_dir)
|
203
|
-
else
|
204
|
-
# normalize the path by expanding it, then
|
205
|
-
# work back to the relative path as needed
|
206
|
-
expanded_dir = File.expand_path(expand_dir)
|
207
|
-
expanded_path = File.expand_path(path, expand_dir)
|
208
|
-
expanded_path.index(expanded_dir) != 0 ? expanded_path : relative_path(expanded_dir, expanded_path)
|
209
|
-
end
|
210
|
-
|
211
|
-
segments = path.scan(/[^\/]+/)
|
212
|
-
|
213
|
-
# add back the root path as needed on *nix
|
214
|
-
segments.unshift "" if path[0] == ?/
|
215
|
-
segments
|
216
|
-
end
|
217
|
-
|
218
|
-
end
|
219
|
-
end
|
220
|
-
end
|
data/lib/tap/root/versions.rb
DELETED
@@ -1,138 +0,0 @@
|
|
1
|
-
module Tap
|
2
|
-
class Root
|
3
|
-
# Version provides methods for adding, removing, and incrementing versions
|
4
|
-
# at the end of paths. Versions are all formatted like:
|
5
|
-
# 'path-version.extension'.
|
6
|
-
#
|
7
|
-
module Versions
|
8
|
-
|
9
|
-
# Adds a version to the path. Versioned paths follow the format:
|
10
|
-
# 'path-version.extension'. If no version is specified, then the
|
11
|
-
# path is returned.
|
12
|
-
#
|
13
|
-
# version("path/to/file.txt", 1.0) # => "path/to/file-1.0.txt"
|
14
|
-
#
|
15
|
-
def version(path, version)
|
16
|
-
version = version.to_s.strip
|
17
|
-
if version.empty?
|
18
|
-
path
|
19
|
-
else
|
20
|
-
extname = File.extname(path)
|
21
|
-
path.chomp(extname) + '-' + version + extname
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
# Increments the version of the path by the specified increment.
|
26
|
-
#
|
27
|
-
# increment("path/to/file-1.0.txt", "0.0.1") # => "path/to/file-1.0.1.txt"
|
28
|
-
# increment("path/to/file.txt", 1.0) # => "path/to/file-1.0.txt"
|
29
|
-
#
|
30
|
-
def increment(path, increment)
|
31
|
-
path, version = deversion(path)
|
32
|
-
|
33
|
-
# split the version and increment into integer arrays of equal length
|
34
|
-
increment, version = [increment, version].collect do |vstr|
|
35
|
-
begin
|
36
|
-
vstr.to_s.split(/\./).collect {|v| v.to_i}
|
37
|
-
rescue
|
38
|
-
raise "Bad version or increment: #{vstr}"
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
if increment.length > version.length
|
43
|
-
version.concat Array.new(increment.length - version.length, 0)
|
44
|
-
end
|
45
|
-
|
46
|
-
# add the increment to version
|
47
|
-
0.upto(version.length-1) do |i|
|
48
|
-
version[i] += (increment[i] || 0)
|
49
|
-
end
|
50
|
-
|
51
|
-
self.version(path, version.join("."))
|
52
|
-
end
|
53
|
-
|
54
|
-
# Splits the version from the input path, then returns the path and
|
55
|
-
# version. If no version is specified, then the returned version will be
|
56
|
-
# nil.
|
57
|
-
#
|
58
|
-
# deversion("path/to/file-1.0.txt") # => ["path/to/file.txt", "1.0"]
|
59
|
-
# deversion("path/to/file.txt") # => ["path/to/file.txt", nil]
|
60
|
-
#
|
61
|
-
def deversion(path)
|
62
|
-
extname = File.extname(path)
|
63
|
-
extname = '' if extname =~ /^\.\d+$/
|
64
|
-
path =~ /^(.*)-(\d(\.?\d)*)#{extname}$/ ? [$1 + extname, $2] : [path, nil]
|
65
|
-
end
|
66
|
-
|
67
|
-
# A <=> comparison for versions. compare_versions can take strings,
|
68
|
-
# integers, or even arrays representing the parts of a version.
|
69
|
-
#
|
70
|
-
# compare_versions("1.0.0", "0.9.9") # => 1
|
71
|
-
# compare_versions(1.1, 1.1) # => 0
|
72
|
-
# compare_versions([0,9], [0,9,1]) # => -1
|
73
|
-
def compare_versions(a,b)
|
74
|
-
a, b = [a,b].collect {|item| to_integer_array(item) }
|
75
|
-
|
76
|
-
# equalize the lengths of the integer arrays
|
77
|
-
d = b.length - a.length
|
78
|
-
case
|
79
|
-
when d < 0 then b.concat Array.new(-d, 0)
|
80
|
-
when d > 0 then a.concat Array.new(d, 0)
|
81
|
-
end
|
82
|
-
|
83
|
-
a <=> b
|
84
|
-
end
|
85
|
-
|
86
|
-
# Version unique. Select the latest or earliest versions of each file
|
87
|
-
# in the array. For paths that have no version, vniq considers any
|
88
|
-
# version to beat no version. The order of paths is preserved by
|
89
|
-
# default, but the extra sort doing so may be turned off.
|
90
|
-
#
|
91
|
-
# paths = [
|
92
|
-
# "/path/to/two-0.0.1.txt",
|
93
|
-
# "/path/to/one-0.0.1.txt",
|
94
|
-
# "/path/to/one.txt",
|
95
|
-
# "/path/to/two-1.0.1.txt",
|
96
|
-
# "/path/to/three.txt"]
|
97
|
-
#
|
98
|
-
# vniq(paths)
|
99
|
-
# # => [
|
100
|
-
# # "/path/to/one-0.0.1.txt",
|
101
|
-
# # "/path/to/two-1.0.1.txt",
|
102
|
-
# # "/path/to/three.txt"]
|
103
|
-
#
|
104
|
-
def vniq(array, earliest=false, preserve_order=true)
|
105
|
-
unique = {}
|
106
|
-
array.sort.each do |path|
|
107
|
-
base, version = deversion(path)
|
108
|
-
(unique[base] ||= []) << version
|
109
|
-
end
|
110
|
-
|
111
|
-
results = []
|
112
|
-
unique.each_pair do |base, versions|
|
113
|
-
versions = versions.sort {|a, b| compare_versions(a,b) }
|
114
|
-
winner = earliest ? versions.shift : versions.pop
|
115
|
-
results << version(base, winner)
|
116
|
-
end
|
117
|
-
|
118
|
-
results = results.sort_by do |path|
|
119
|
-
array.index(path)
|
120
|
-
end if preserve_order
|
121
|
-
|
122
|
-
results
|
123
|
-
end
|
124
|
-
|
125
|
-
private
|
126
|
-
|
127
|
-
# Converts an input argument (typically a string or an array) to an
|
128
|
-
# array of integers. Splits version string on "."
|
129
|
-
def to_integer_array(arg)
|
130
|
-
arr = case arg
|
131
|
-
when Array then arg
|
132
|
-
else arg.to_s.split('.')
|
133
|
-
end
|
134
|
-
arr.collect {|i| i.to_i}
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|