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/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
|