tap 0.18.0 → 0.19.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History +21 -0
- data/MIT-LICENSE +17 -15
- data/README +13 -30
- data/bin/tap +19 -24
- data/cmd/console.rb +1 -12
- data/cmd/manifest.rb +14 -19
- data/cmd/run.rb +96 -86
- data/doc/API +194 -54
- data/doc/Examples/Command Line +27 -1
- data/lib/tap.rb +2 -1
- data/lib/tap/app.rb +613 -166
- data/lib/tap/app/api.rb +115 -0
- data/lib/tap/app/queue.rb +36 -37
- data/lib/tap/app/state.rb +2 -1
- data/lib/tap/env.rb +454 -270
- data/lib/tap/env/constant.rb +83 -33
- data/lib/tap/env/context.rb +61 -0
- data/lib/tap/env/manifest.rb +140 -50
- data/lib/tap/env/minimap.rb +55 -39
- data/lib/tap/join.rb +71 -53
- data/lib/tap/joins/sync.rb +3 -1
- data/lib/tap/middleware.rb +4 -25
- data/lib/tap/middlewares/debugger.rb +75 -0
- data/lib/tap/parser.rb +268 -0
- data/lib/tap/prompt.rb +36 -0
- data/lib/tap/root.rb +3 -3
- data/lib/tap/signals.rb +26 -0
- data/lib/tap/signals/class_methods.rb +222 -0
- data/lib/tap/signals/help.rb +40 -0
- data/lib/tap/signals/module_methods.rb +20 -0
- data/lib/tap/signals/signal.rb +68 -0
- data/lib/tap/task.rb +28 -79
- data/lib/tap/tasks/dump.rb +6 -0
- data/lib/tap/tasks/load.rb +9 -37
- data/lib/tap/templater.rb +12 -1
- data/lib/tap/version.rb +1 -1
- metadata +22 -16
- data/doc/Class Reference +0 -330
- data/lib/tap/exe.rb +0 -130
- data/lib/tap/schema.rb +0 -374
- data/lib/tap/schema/parser.rb +0 -425
- data/lib/tap/schema/utils.rb +0 -56
data/lib/tap/app/api.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'configurable'
|
2
|
+
require 'tap/signals/help'
|
3
|
+
|
4
|
+
module Tap
|
5
|
+
class App
|
6
|
+
|
7
|
+
# Api implements the application interface described in the
|
8
|
+
# API[link:files/doc/API.html] document, and provides additional
|
9
|
+
# functionality shared by the Tap base classes.
|
10
|
+
class Api
|
11
|
+
class << self
|
12
|
+
|
13
|
+
# The type of the class.
|
14
|
+
attr_reader :type
|
15
|
+
|
16
|
+
def inherited(child) # :nodoc:
|
17
|
+
super
|
18
|
+
|
19
|
+
type = self.type || child.to_s.split('::').last.downcase
|
20
|
+
child.instance_variable_set(:@type, type)
|
21
|
+
|
22
|
+
unless child.respond_to?(:desc)
|
23
|
+
child.lazy_attr(:desc, type)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns a ConfigParser setup to parse the configurations for the
|
28
|
+
# subclass. The parser is also setup to print usage (using the desc
|
29
|
+
# for the subclass) and exit for the '-h' and '--help' options.
|
30
|
+
#
|
31
|
+
# The parse method uses parser by default, so subclasses can simply
|
32
|
+
# modify parser and ensure parse still works correctly.
|
33
|
+
def parser
|
34
|
+
opts = ConfigParser.new
|
35
|
+
|
36
|
+
unless configurations.empty?
|
37
|
+
opts.separator "configurations:"
|
38
|
+
opts.add(configurations)
|
39
|
+
opts.separator ""
|
40
|
+
end
|
41
|
+
|
42
|
+
opts.separator "options:"
|
43
|
+
|
44
|
+
# add option to print help
|
45
|
+
opts.on("-h", "--help", "Print this help") do
|
46
|
+
puts "#{self}#{desc.empty? ? '' : ' -- '}#{desc.to_s}"
|
47
|
+
puts help
|
48
|
+
puts opts
|
49
|
+
exit
|
50
|
+
end
|
51
|
+
|
52
|
+
opts
|
53
|
+
end
|
54
|
+
|
55
|
+
# Parses the argv into an instance of self. Internally parse parses
|
56
|
+
# an argh then calls build, but there is no requirement that this
|
57
|
+
# occurs in subclasses.
|
58
|
+
def parse(argv=ARGV, app=Tap::App.instance)
|
59
|
+
parse!(argv.dup, app)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Same as parse, but removes arguments destructively.
|
63
|
+
def parse!(argv=ARGV, app=Tap::App.instance)
|
64
|
+
parser = self.parser
|
65
|
+
argv = parser.parse!(argv, :add_defaults => false)
|
66
|
+
|
67
|
+
[build({'config' => parser.nested_config}, app), argv]
|
68
|
+
end
|
69
|
+
|
70
|
+
# Returns an instance of self. By default build calls new with the
|
71
|
+
# configurations specified by spec['config'], and app.
|
72
|
+
def build(spec={}, app=Tap::App.instance)
|
73
|
+
new(spec['config'] || {}, app)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Returns a help string that formats the desc documentation.
|
77
|
+
def help
|
78
|
+
lines = desc.kind_of?(Lazydoc::Comment) ? desc.wrap(77, 2, nil) : []
|
79
|
+
lines.collect! {|line| " #{line}"}
|
80
|
+
unless lines.empty?
|
81
|
+
line = '-' * 80
|
82
|
+
lines.unshift(line)
|
83
|
+
lines.push(line)
|
84
|
+
end
|
85
|
+
|
86
|
+
lines.join("\n")
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
include Configurable
|
91
|
+
include Signals
|
92
|
+
|
93
|
+
signal :help, :class => Help, :bind => nil # signals help
|
94
|
+
|
95
|
+
# The App receiving self during enq
|
96
|
+
attr_reader :app
|
97
|
+
|
98
|
+
def initialize(config={}, app=Tap::App.instance)
|
99
|
+
@app = app
|
100
|
+
initialize_config(config)
|
101
|
+
end
|
102
|
+
|
103
|
+
# By default associations returns nil.
|
104
|
+
def associations
|
105
|
+
end
|
106
|
+
|
107
|
+
# By default to_spec returns a hash like {'config' => config} where
|
108
|
+
# config is a stringified representation of the configurations for self.
|
109
|
+
def to_spec
|
110
|
+
config = self.config.to_hash {|hash, key, value| hash[key.to_s] = value }
|
111
|
+
{'config' => config}
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
data/lib/tap/app/queue.rb
CHANGED
@@ -5,71 +5,70 @@ module Tap
|
|
5
5
|
|
6
6
|
# Queue allows thread-safe enqueing and dequeing of nodes and inputs for
|
7
7
|
# execution.
|
8
|
+
#
|
9
|
+
# === API
|
10
|
+
#
|
11
|
+
# The following methods are required in alternative implementations of an
|
12
|
+
# applicaton queue, where a job is a [node, inputs] array:
|
13
|
+
#
|
14
|
+
# enq(node, inputs) # pushes the job onto the queue
|
15
|
+
# unshift(node, inputs) # unshifts the job onto the queue
|
16
|
+
# deq # shifts a job off the queue
|
17
|
+
# size # returns the number of jobs in the queue
|
18
|
+
# clear # clears the queue, returns current jobs
|
19
|
+
# synchronize # yields to the block
|
20
|
+
# to_a # returns the queue as an array
|
21
|
+
#
|
22
|
+
# Note that synchronize must be implemented even if it does nothing but
|
23
|
+
# yield to the block.
|
8
24
|
class Queue < Monitor
|
9
25
|
|
10
|
-
attr_reader :queue
|
11
|
-
|
12
26
|
# Creates a new Queue
|
13
27
|
def initialize
|
14
28
|
super
|
15
29
|
@queue = []
|
16
30
|
end
|
17
31
|
|
18
|
-
#
|
19
|
-
|
20
|
-
def clear
|
32
|
+
# Enqueues the node and inputs as a job.
|
33
|
+
def enq(node, inputs)
|
21
34
|
synchronize do
|
22
|
-
|
23
|
-
@queue = []
|
24
|
-
current
|
35
|
+
@queue.push [node, inputs]
|
25
36
|
end
|
26
37
|
end
|
27
38
|
|
28
|
-
#
|
29
|
-
def
|
39
|
+
# Enqueues the node and inputs, but to the top of the queue.
|
40
|
+
def unshift(node, inputs)
|
30
41
|
synchronize do
|
31
|
-
queue.
|
42
|
+
@queue.unshift [node, inputs]
|
32
43
|
end
|
33
44
|
end
|
34
45
|
|
35
|
-
#
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
# Enqueues the method and inputs.
|
41
|
-
def enq(method, inputs)
|
42
|
-
synchronize do
|
43
|
-
queue.push [method, inputs]
|
44
|
-
end
|
46
|
+
# Dequeues the next job as an array like [node, inputs]. Returns nil if
|
47
|
+
# the queue is empty.
|
48
|
+
def deq
|
49
|
+
synchronize { @queue.shift }
|
45
50
|
end
|
46
51
|
|
47
|
-
#
|
48
|
-
def
|
52
|
+
# Returns the number of enqueued jobs.
|
53
|
+
def size
|
49
54
|
synchronize do
|
50
|
-
queue.
|
55
|
+
@queue.size
|
51
56
|
end
|
52
57
|
end
|
53
58
|
|
54
|
-
#
|
55
|
-
def
|
59
|
+
# Clears self and returns an array of the currently enqueued jobs.
|
60
|
+
def clear
|
56
61
|
synchronize do
|
57
|
-
|
58
|
-
|
59
|
-
|
62
|
+
current = @queue
|
63
|
+
@queue = []
|
64
|
+
current
|
60
65
|
end
|
61
66
|
end
|
62
67
|
|
63
|
-
#
|
64
|
-
# [method, inputs]. Returns nil if the queue is empty.
|
65
|
-
def deq
|
66
|
-
synchronize { queue.shift }
|
67
|
-
end
|
68
|
-
|
69
|
-
# Converts self to an array.
|
68
|
+
# Returns the enqueued jobs as an array.
|
70
69
|
def to_a
|
71
70
|
synchronize do
|
72
|
-
queue.dup
|
71
|
+
@queue.dup
|
73
72
|
end
|
74
73
|
end
|
75
74
|
end
|
data/lib/tap/app/state.rb
CHANGED
@@ -15,7 +15,8 @@ module Tap
|
|
15
15
|
# State.state_str(0) # => 'READY'
|
16
16
|
# State.state_str(12) # => nil
|
17
17
|
def state_str(state)
|
18
|
-
constants.
|
18
|
+
const = constants.find {|const_name| const_get(const_name) == state }
|
19
|
+
const ? const.to_s : nil
|
19
20
|
end
|
20
21
|
end
|
21
22
|
end
|
data/lib/tap/env.rb
CHANGED
@@ -1,24 +1,243 @@
|
|
1
1
|
require 'tap/root'
|
2
|
+
require 'tap/env/constant'
|
3
|
+
require 'tap/env/context'
|
2
4
|
require 'tap/env/manifest'
|
3
5
|
require 'tap/templater'
|
4
6
|
autoload(:YAML, 'yaml')
|
5
7
|
|
6
8
|
module Tap
|
7
|
-
|
9
|
+
|
10
|
+
# == Description
|
11
|
+
#
|
12
|
+
# Env provides access to an execution environment spanning many directories,
|
13
|
+
# such as the working directory plus a series of gem directories. Envs merge
|
14
|
+
# the files from each directory into an abstract directory that may be
|
15
|
+
# globbed and accessed as a single unit. For example:
|
16
|
+
#
|
17
|
+
# # /one
|
18
|
+
# # |-- a.rb
|
19
|
+
# # `-- b.rb
|
20
|
+
# #
|
21
|
+
# # /two
|
22
|
+
# # |-- b.rb
|
23
|
+
# # `-- c.rb
|
24
|
+
# env = Env.new('/one')
|
25
|
+
# env << Env.new('/two')
|
26
|
+
#
|
27
|
+
# env.collect {|e| e.root.root}
|
28
|
+
# # => ["/one", "/two"]
|
29
|
+
#
|
30
|
+
# env.glob(:root, "*.rb")
|
31
|
+
# # => [
|
32
|
+
# # "/one/a.rb",
|
33
|
+
# # "/one/b.rb",
|
34
|
+
# # "/two/c.rb"
|
35
|
+
# # ]
|
36
|
+
#
|
37
|
+
# As illustrated, files in the nested environment are accessible within the
|
38
|
+
# nesting environment. Envs provide methods for finding files associated
|
39
|
+
# with a specific class, and allow the generation of manifests that provide
|
40
|
+
# succinct access to various environment resources.
|
41
|
+
#
|
42
|
+
# Usage of Envs is fairly straightforward, but the internals and default
|
43
|
+
# setup require some study as they have to span numerous functional domains.
|
44
|
+
# The most common features are detailed below.
|
45
|
+
#
|
46
|
+
# ==== Class Paths
|
47
|
+
#
|
48
|
+
# Class paths are a kind of inheritance for files associated with a class.
|
49
|
+
# Say we had the following classes:
|
50
|
+
#
|
51
|
+
# class A; end
|
52
|
+
# class B < A; end
|
53
|
+
#
|
54
|
+
# The naturally associated directories are 'a' and 'b'. To look these up:
|
55
|
+
#
|
56
|
+
# env.class_path(:root, A) # => "/one/a"
|
57
|
+
# env.class_path(:root, B) # => "/one/b"
|
58
|
+
#
|
59
|
+
# And to look up an associated file:
|
60
|
+
#
|
61
|
+
# env.class_path(:root, A, "index.html") # => "/one/a/index.html"
|
62
|
+
# env.class_path(:root, B, "index.html") # => "/one/b/index.html"
|
63
|
+
#
|
64
|
+
# A block may be given to filter paths, for instance to test if a given file
|
65
|
+
# exists. The class_path method will check each env then roll up the
|
66
|
+
# inheritance hierarchy until the block returns true.
|
67
|
+
#
|
68
|
+
# FileUtils.touch("/two/a/index.html")
|
69
|
+
#
|
70
|
+
# visited_paths = []
|
71
|
+
# env.class_path(:root, B, "index.html) do |path|
|
72
|
+
# visited_paths << path
|
73
|
+
# File.exists?(path)
|
74
|
+
# end # => "/two/a/index.html"
|
75
|
+
#
|
76
|
+
# visited_paths
|
77
|
+
# # => [
|
78
|
+
# # "/one/b/index.html",
|
79
|
+
# # "/two/b/index.html",
|
80
|
+
# # "/one/a/index.html",
|
81
|
+
# # "/two/a/index.html"
|
82
|
+
# # ]
|
83
|
+
#
|
84
|
+
# This behavior is very useful for associating views with a class.
|
85
|
+
#
|
86
|
+
# ==== Manifest
|
87
|
+
#
|
88
|
+
# Envs can generate manifests of various resources so they may be identified
|
89
|
+
# using minipaths (see Minimap for details regarding minipaths). Command
|
90
|
+
# files used by the tap executable are one example of a resource, and the
|
91
|
+
# constants used in building a workflow are another.
|
92
|
+
#
|
93
|
+
# Manifest are generated by defining a builder, typically a block, that
|
94
|
+
# receives an env and returns an array of the associated resources.
|
95
|
+
# Using the same env as above:
|
96
|
+
#
|
97
|
+
# manifest = env.manifest {|e| e.root.glob(:root, "*.rb") }
|
98
|
+
#
|
99
|
+
# manifest.seek("a") # => "/one/a.rb"
|
100
|
+
# manifest.seek("b") # => "/one/b.rb"
|
101
|
+
# manifest.seek("c") # => "/two/c.rb"
|
102
|
+
#
|
103
|
+
# As illustrated, seek finds the first entry across all envs that matches the
|
104
|
+
# input minipath. A minipath for the env may be prepended to only search
|
105
|
+
# within a specific env.
|
106
|
+
#
|
107
|
+
# manifest.seek("one:b") # => "/one/b.rb"
|
108
|
+
# manifest.seek("two:b") # => "/two/b.rb"
|
109
|
+
#
|
110
|
+
# Env caches a manifest of constants identified by {constant attributes}[http://tap.rubyforge.org/lazydoc]
|
111
|
+
# in files specified by under the Env.const_paths. These constants are used
|
112
|
+
# when interpreting signals from the command line. Constants may be manually
|
113
|
+
# registered to the constants manifest and classified by type like this:
|
114
|
+
#
|
115
|
+
# class CustomTask
|
116
|
+
# def call; end
|
117
|
+
# end
|
118
|
+
# env.register(CustomTask).register_as(:task, "this is a custom task")
|
119
|
+
#
|
120
|
+
# const = env.constants.seek('custom_task')
|
121
|
+
# const.const_name # => "CustomTask"
|
122
|
+
# const.types # => {:task => "this is a custom task"}
|
123
|
+
# const.constantize # => CustomTask
|
124
|
+
#
|
125
|
+
# == Setup
|
126
|
+
#
|
127
|
+
# Envs may be manually setup in code by individually generating instances
|
128
|
+
# and nesting them. More commonly envs are defined in configuration files
|
129
|
+
# and instantiated by specifying where the files are located. The default
|
130
|
+
# config basename is 'tap.yml'; any env_paths specified in the config file
|
131
|
+
# will be added.
|
132
|
+
#
|
133
|
+
# This type of instantiation is recursive:
|
134
|
+
#
|
135
|
+
# # [/one/tap.yml]
|
136
|
+
# # env_paths: [/two]
|
137
|
+
# #
|
138
|
+
# # [/two/tap.yml]
|
139
|
+
# # env_paths: [/three]
|
140
|
+
# #
|
141
|
+
#
|
142
|
+
# env = Env.new("/one", :basename => 'tap.yml')
|
143
|
+
# env.collect {|e| e.root.root}
|
144
|
+
# # => ["/one", "/two", "/three"]
|
145
|
+
#
|
146
|
+
# Gem directories are fair game. Env allows specific gems to be specified
|
147
|
+
# by name (via the 'gems' config), and if a gem has a tap.yml file then it
|
148
|
+
# will be used to configure the gem env. Alternatively, an env may be set
|
149
|
+
# to automatically discover and nest gem environments. In this case gems
|
150
|
+
# are discovered when they have a tap.yml file.
|
151
|
+
#
|
152
|
+
# ==== ENV configs
|
153
|
+
#
|
154
|
+
# Configurations may be also specified as an ENV variables. This type of
|
155
|
+
# configuration is very useful on the command line. Config variables
|
156
|
+
# should be prefixed by TAP_ and named like the capitalized config key
|
157
|
+
# (ex: TAP_GEMS or TAP_ENV_PATHS). See the
|
158
|
+
# {Command Line Examples}[link:files/doc/Examples/Command%20Line.html]
|
159
|
+
# to see ENV configs in action.
|
160
|
+
#
|
161
|
+
# These configurations may be accessed from Env#config, and are
|
162
|
+
# automatically incorporated by Env#setup.
|
163
|
+
#
|
8
164
|
class Env
|
9
165
|
autoload(:Gems, 'tap/env/gems')
|
10
166
|
|
11
167
|
class << self
|
12
|
-
attr_writer :instance
|
13
168
|
|
14
|
-
|
15
|
-
|
169
|
+
# Returns the Env configs specified in ENV. Config variables are
|
170
|
+
# prefixed by TAP_ and named like the capitalized config key
|
171
|
+
# (ex: TAP_GEMS or TAP_ENV_PATHS).
|
172
|
+
def config(env_vars=ENV)
|
173
|
+
config = {}
|
174
|
+
env_vars.each_pair do |key, value|
|
175
|
+
if key =~ /\ATAP_(.*)\z/
|
176
|
+
config[$1.downcase] = value
|
177
|
+
end
|
178
|
+
end
|
179
|
+
config
|
16
180
|
end
|
17
181
|
|
18
|
-
|
182
|
+
# Initializes and activates an env as described in the config file under
|
183
|
+
# dir. The config file should be a relative path and will be used for
|
184
|
+
# determining configuration files under each env_path.
|
185
|
+
#
|
186
|
+
# The env configuration is determined by merging the following in order:
|
187
|
+
# * defaults {root => dir, gems => all}
|
188
|
+
# * ENV configs
|
189
|
+
# * config_file configs
|
190
|
+
#
|
191
|
+
# The HOME directory for Tap will be added as an additonal environment
|
192
|
+
# if not already added somewhere in the env hierarchy. By default all
|
193
|
+
# gems will be included in the Env.
|
194
|
+
def setup(dir=Dir.pwd, config_file=CONFIG_FILE)
|
195
|
+
# setup configurations
|
196
|
+
config = {'root' => dir, 'gems' => :all}
|
197
|
+
|
198
|
+
user_config_file = config_file ? File.join(dir, config_file) : nil
|
199
|
+
user = load_config(user_config_file)
|
200
|
+
|
201
|
+
config.merge!(self.config)
|
202
|
+
config.merge!(user)
|
203
|
+
|
204
|
+
# keys must be symbolized as they are immediately
|
205
|
+
# used to initialize the Env configs
|
206
|
+
config = config.inject({}) do |options, (key, value)|
|
207
|
+
options[key.to_sym || key] = value
|
208
|
+
options
|
209
|
+
end
|
210
|
+
|
211
|
+
# instantiate
|
212
|
+
context = Context.new(:basename => config_file)
|
213
|
+
env = new(config, context)
|
214
|
+
|
215
|
+
# add the tap env if necessary
|
216
|
+
unless env.any? {|e| e.root.root == HOME }
|
217
|
+
env.push new(HOME, context)
|
218
|
+
end
|
219
|
+
|
220
|
+
env.activate
|
221
|
+
env
|
222
|
+
end
|
223
|
+
|
224
|
+
# Generates an Env for the specified gem or Gem::Specification. The
|
225
|
+
# gemspec for the gem is used to determine the env configuration in
|
226
|
+
# the following way:
|
227
|
+
#
|
228
|
+
# root: the gem path
|
229
|
+
# gems: all gem dependencies with a config_file
|
230
|
+
# const_paths: the gem require paths
|
231
|
+
# set_const_paths: false (because RubyGems sets them for you)
|
232
|
+
#
|
233
|
+
# Configurations specified in the gem config_file override these
|
234
|
+
# defaults.
|
235
|
+
def setup_gem(gem_name, context=Context.new)
|
236
|
+
spec = Gems.gemspec(gem_name)
|
19
237
|
path = spec.full_gem_path
|
20
|
-
basename = context[:basename]
|
21
238
|
|
239
|
+
# determine gem dependencies that have a config_file;
|
240
|
+
# these will be set as the gems for the new Env
|
22
241
|
dependencies = []
|
23
242
|
spec.dependencies.each do |dependency|
|
24
243
|
unless dependency.type == :runtime
|
@@ -32,8 +251,8 @@ module Tap
|
|
32
251
|
next
|
33
252
|
end
|
34
253
|
|
35
|
-
if
|
36
|
-
next
|
254
|
+
if config_file = context.config_file(gemspec.full_gem_path)
|
255
|
+
next unless File.exists?(config_file)
|
37
256
|
end
|
38
257
|
|
39
258
|
dependencies << gemspec
|
@@ -42,12 +261,14 @@ module Tap
|
|
42
261
|
config = {
|
43
262
|
'root' => path,
|
44
263
|
'gems' => dependencies,
|
45
|
-
'
|
46
|
-
'
|
264
|
+
'const_paths' => spec.require_paths,
|
265
|
+
'set_const_paths' => false
|
47
266
|
}
|
48
267
|
|
49
|
-
|
50
|
-
|
268
|
+
# override the default configs with whatever configs
|
269
|
+
# are specified in the gem config file
|
270
|
+
if config_file = context.config_file(path)
|
271
|
+
config.merge!(load_config(config_file))
|
51
272
|
end
|
52
273
|
|
53
274
|
new(config, context)
|
@@ -55,6 +276,8 @@ module Tap
|
|
55
276
|
|
56
277
|
# Loads configurations from path as YAML. Returns an empty hash if the path
|
57
278
|
# loads to nil or false (as happens for empty files), or doesn't exist.
|
279
|
+
#
|
280
|
+
# Raises a ConfigError if the configurations do not load properly.
|
58
281
|
def load_config(path)
|
59
282
|
return {} unless path
|
60
283
|
|
@@ -64,88 +287,42 @@ module Tap
|
|
64
287
|
raise ConfigError.new($!, path)
|
65
288
|
end
|
66
289
|
end
|
67
|
-
|
68
|
-
def scan_dir(load_path, pattern='**/*.rb')
|
69
|
-
Dir.chdir(load_path) do
|
70
|
-
Dir.glob(pattern).each do |require_path|
|
71
|
-
next unless File.file?(require_path)
|
72
|
-
|
73
|
-
default_const_name = require_path.chomp('.rb').camelize
|
74
|
-
|
75
|
-
# note: the default const name has to be set here to allow for implicit
|
76
|
-
# constant attributes. An error can arise if the same path is globed
|
77
|
-
# from two different dirs... no surefire solution.
|
78
|
-
Lazydoc[require_path].default_const_name = default_const_name
|
79
|
-
|
80
|
-
# scan for constants
|
81
|
-
Lazydoc::Document.scan(File.read(require_path)) do |const_name, type, comment|
|
82
|
-
const_name = default_const_name if const_name.empty?
|
83
|
-
constant = Constant.new(const_name, require_path, comment)
|
84
|
-
yield(type, constant)
|
85
|
-
|
86
|
-
###############################################################
|
87
|
-
# [depreciated] manifest as a task key will be removed at 1.0
|
88
|
-
if type == 'manifest'
|
89
|
-
warn "depreciation: ::task should be used instead of ::manifest as a resource key (#{require_path})"
|
90
|
-
yield('task', constant)
|
91
|
-
end
|
92
|
-
###############################################################
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def scan(path, key='[a-z_]+')
|
99
|
-
Lazydoc::Document.scan(File.read(path), key) do |const_name, type, comment|
|
100
|
-
if const_name.empty?
|
101
|
-
unless const_name = Lazydoc[path].default_const_name
|
102
|
-
raise "could not determine a constant name for #{type} in: #{path.inspect}"
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
constant = Constant.new(const_name, path, comment)
|
107
|
-
yield(type, constant)
|
108
|
-
|
109
|
-
###############################################################
|
110
|
-
# [depreciated] manifest as a task key will be removed at 1.0
|
111
|
-
if type == 'manifest'
|
112
|
-
warn "depreciation: ::task should be used instead of ::manifest as a resource key (#{require_path})"
|
113
|
-
yield('task', constant)
|
114
|
-
end
|
115
|
-
###############################################################
|
116
|
-
end
|
117
|
-
end
|
118
290
|
end
|
119
|
-
self.instance = nil
|
120
291
|
|
121
|
-
include Enumerable
|
122
292
|
include Configurable
|
293
|
+
include Enumerable
|
123
294
|
include Minimap
|
124
295
|
|
125
|
-
#
|
126
|
-
|
127
|
-
|
128
|
-
#
|
129
|
-
#
|
130
|
-
|
131
|
-
# If the key is not compound, $2 is nil and $1 is the key.
|
132
|
-
COMPOUND_KEY = /^((?:[A-z]:(?:\/|\\))?.*?)(?::(.*))?$/
|
133
|
-
|
296
|
+
# The config file path
|
297
|
+
CONFIG_FILE = "tap.yml"
|
298
|
+
|
299
|
+
# The home directory for Tap
|
300
|
+
HOME = File.expand_path("#{File.dirname(__FILE__)}/../..")
|
301
|
+
|
134
302
|
# An array of nested Envs, by default comprised of the env_path
|
135
|
-
# + gem environments (in that order).
|
303
|
+
# + gem environments (in that order). Envs can be manually set
|
304
|
+
# to override these defaults.
|
136
305
|
attr_reader :envs
|
137
306
|
|
307
|
+
# A Context tracking information shared among a set of envs.
|
138
308
|
attr_reader :context
|
139
309
|
|
140
|
-
attr_reader :manifests
|
141
|
-
|
142
310
|
# The Root directory structure for self.
|
143
|
-
nest(:root, Root, :
|
311
|
+
nest(:root, Root, :init => false)
|
144
312
|
|
145
|
-
# Specify gems to add as nested Envs. Gems may be specified
|
146
|
-
#
|
147
|
-
#
|
148
|
-
#
|
313
|
+
# Specify gems to add as nested Envs. Gems may be specified by name
|
314
|
+
# and/or version, like 'gemname >= 1.2'; by default the latest version
|
315
|
+
# of the gem is selected.
|
316
|
+
#
|
317
|
+
# Several special values also exist:
|
318
|
+
#
|
319
|
+
# :NONE, :none indicates no gems (same as nil, false)
|
320
|
+
# :LATEST the latest version of all gems
|
321
|
+
# :ALL all gems
|
322
|
+
# :latest the latest version of all gems with a config file
|
323
|
+
# :all all gems with a config file
|
324
|
+
#
|
325
|
+
# Gems are not activated by Env.
|
149
326
|
config_attr :gems, [] do |input|
|
150
327
|
input = yaml_load(input) if input.kind_of?(String)
|
151
328
|
|
@@ -156,9 +333,12 @@ module Tap
|
|
156
333
|
# latest and all, no filter
|
157
334
|
Gems.select_gems(input == :LATEST)
|
158
335
|
when :latest, :all
|
159
|
-
# latest and all, filtering by
|
336
|
+
# latest and all, filtering by the existence of a
|
337
|
+
# config file; all gems are selected if no config
|
338
|
+
# file can be determined.
|
160
339
|
Gems.select_gems(input == :latest) do |spec|
|
161
|
-
|
340
|
+
config_file = context.config_file(spec.full_gem_path)
|
341
|
+
config_file == nil || File.exists?(config_file)
|
162
342
|
end
|
163
343
|
else
|
164
344
|
# resolve gem names manually
|
@@ -170,46 +350,45 @@ module Tap
|
|
170
350
|
reset_envs
|
171
351
|
end
|
172
352
|
|
173
|
-
# Specify directories to load as nested Envs.
|
353
|
+
# Specify directories to load as nested Envs. Configurations for the
|
354
|
+
# env are loaded from the config file under dir, if it exists.
|
174
355
|
config_attr :env_paths, [] do |input|
|
175
356
|
@env_paths = resolve_paths(input)
|
176
357
|
reset_envs
|
177
358
|
end
|
178
359
|
|
179
|
-
# Designates
|
180
|
-
#
|
181
|
-
config_attr :
|
182
|
-
raise "
|
183
|
-
@
|
360
|
+
# Designates directories searched for constants. The const_paths are
|
361
|
+
# added to $LOAD_PATH on activation if set_const_paths is specified.
|
362
|
+
config_attr :const_paths, [:lib] do |input|
|
363
|
+
raise "const_paths cannot be modified once active" if active?
|
364
|
+
@const_paths = resolve_paths(input)
|
184
365
|
end
|
185
366
|
|
186
|
-
# If set to true
|
187
|
-
config_attr :
|
188
|
-
raise "
|
189
|
-
@
|
367
|
+
# If set to true const_paths are added to $LOAD_PATH on activation.
|
368
|
+
config_attr :set_const_paths, true do |input|
|
369
|
+
raise "set_const_paths cannot be modified once active" if active?
|
370
|
+
@set_const_paths = Configurable::Validation.boolean[input]
|
190
371
|
end
|
191
372
|
|
192
|
-
# Initializes a new Env linked to the specified directory.
|
193
|
-
#
|
194
|
-
#
|
195
|
-
# load configurations for nested envs.
|
373
|
+
# Initializes a new Env linked to the specified directory. Configurations
|
374
|
+
# for the env will be loaded from the config file (as determined by the
|
375
|
+
# context) if it exists.
|
196
376
|
#
|
197
|
-
#
|
198
|
-
# case,
|
199
|
-
#
|
377
|
+
# A configuration hash may be manually provided in the place of dir. In
|
378
|
+
# that case, no configurations will be loaded, even if the config file
|
379
|
+
# exists.
|
200
380
|
#
|
201
|
-
#
|
202
|
-
#
|
381
|
+
# Context can be specified as a Context, or a Hash used to initialize a
|
382
|
+
# Context.
|
203
383
|
def initialize(config_or_dir=Dir.pwd, context={})
|
204
|
-
@active = false
|
205
|
-
@manifests = {}
|
206
|
-
@context = context
|
207
384
|
|
208
385
|
# setup root
|
209
386
|
config = nil
|
210
387
|
@root = case config_or_dir
|
211
|
-
when Root
|
212
|
-
|
388
|
+
when Root
|
389
|
+
config_or_dir
|
390
|
+
when String
|
391
|
+
Root.new(config_or_dir)
|
213
392
|
else
|
214
393
|
config = config_or_dir
|
215
394
|
|
@@ -221,24 +400,28 @@ module Tap
|
|
221
400
|
root.kind_of?(Root) ? root : Root.new(root)
|
222
401
|
end
|
223
402
|
|
224
|
-
|
225
|
-
|
226
|
-
|
403
|
+
# note registration requires root.root, and so the
|
404
|
+
# setup of context must follow the setup of root.
|
405
|
+
@context = case context
|
406
|
+
when Context
|
407
|
+
context
|
408
|
+
when Hash
|
409
|
+
Context.new(context)
|
410
|
+
else raise "cannot convert #{context.inspect} to Tap::Env::Context"
|
411
|
+
end
|
412
|
+
@context.register(self)
|
227
413
|
|
228
|
-
|
229
|
-
|
230
|
-
end
|
231
|
-
instances << self
|
232
|
-
|
233
|
-
# set these for reset_env
|
414
|
+
# these need to be set for reset_env
|
415
|
+
@active = false
|
234
416
|
@gems = nil
|
235
417
|
@env_paths = nil
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
418
|
+
|
419
|
+
# only load configurations if configs were not provided
|
420
|
+
config ||= Env.load_config(@context.config_file(@root.root))
|
421
|
+
initialize_config(config)
|
422
|
+
|
423
|
+
# set the invert flag
|
424
|
+
@invert = false
|
242
425
|
end
|
243
426
|
|
244
427
|
# Sets envs removing duplicates and instances of self. Setting envs
|
@@ -265,6 +448,7 @@ module Tap
|
|
265
448
|
end
|
266
449
|
self
|
267
450
|
end
|
451
|
+
alias_method :<<, :push
|
268
452
|
|
269
453
|
# Passes each nested env to the block in order, starting with self.
|
270
454
|
def each
|
@@ -306,33 +490,29 @@ module Tap
|
|
306
490
|
|
307
491
|
# Activates self by doing the following, in order:
|
308
492
|
#
|
309
|
-
# * sets Env.instance to self (unless already set)
|
310
493
|
# * activate nested environments
|
311
|
-
# * unshift
|
494
|
+
# * unshift const_paths to $LOAD_PATH (if set_const_paths is true)
|
312
495
|
#
|
313
|
-
# Once active, the current envs and
|
496
|
+
# Once active, the current envs and const_paths are frozen and cannot be
|
314
497
|
# modified until deactivated. Returns true if activate succeeded, or
|
315
498
|
# false if self is already active.
|
316
499
|
def activate
|
317
500
|
return false if active?
|
318
501
|
|
319
502
|
@active = true
|
320
|
-
unless self.class.instance(false)
|
321
|
-
self.class.instance = self
|
322
|
-
end
|
323
503
|
|
324
|
-
# freeze envs and
|
504
|
+
# freeze envs and const paths
|
325
505
|
@envs.freeze
|
326
|
-
@
|
506
|
+
@const_paths.freeze
|
327
507
|
|
328
508
|
# activate nested envs
|
329
509
|
envs.reverse_each do |env|
|
330
510
|
env.activate
|
331
511
|
end
|
332
512
|
|
333
|
-
# add
|
334
|
-
if
|
335
|
-
|
513
|
+
# add const paths
|
514
|
+
if set_const_paths
|
515
|
+
const_paths.reverse_each do |path|
|
336
516
|
$LOAD_PATH.unshift(path)
|
337
517
|
end
|
338
518
|
|
@@ -345,12 +525,19 @@ module Tap
|
|
345
525
|
# Deactivates self by doing the following in order:
|
346
526
|
#
|
347
527
|
# * deactivates nested environments
|
348
|
-
# * removes
|
349
|
-
# * sets Env.instance to nil (if set to self)
|
350
|
-
# * clears cached manifest data
|
528
|
+
# * removes const_paths from $LOAD_PATH (if set_const_paths is true)
|
351
529
|
#
|
352
|
-
# Once deactivated, envs and
|
530
|
+
# Once deactivated, envs and const_paths are unfrozen and may be modified.
|
353
531
|
# Returns true if deactivate succeeded, or false if self is not active.
|
532
|
+
#
|
533
|
+
# ==== Note
|
534
|
+
#
|
535
|
+
# Deactivation does not necessarily leave $LOAD_PATH in the same condition
|
536
|
+
# as before activation. A pre-existing $LOAD_PATH entry can go missing if
|
537
|
+
# it is also registered as an env load_path (deactivation doesn't know to
|
538
|
+
# leave such paths alone).
|
539
|
+
#
|
540
|
+
# Deactivation, like constant unloading should be done with caution.
|
354
541
|
def deactivate
|
355
542
|
return false unless active?
|
356
543
|
@active = false
|
@@ -360,20 +547,14 @@ module Tap
|
|
360
547
|
env.deactivate
|
361
548
|
end
|
362
549
|
|
363
|
-
# remove
|
364
|
-
|
550
|
+
# remove const paths
|
551
|
+
const_paths.each do |path|
|
365
552
|
$LOAD_PATH.delete(path)
|
366
|
-
end if
|
553
|
+
end if set_const_paths
|
367
554
|
|
368
|
-
# unfreeze envs and
|
555
|
+
# unfreeze envs and const paths
|
369
556
|
@envs = @envs.dup
|
370
|
-
@
|
371
|
-
|
372
|
-
# clear cached data
|
373
|
-
klass = self.class
|
374
|
-
if klass.instance(false) == self
|
375
|
-
klass.instance = nil
|
376
|
-
end
|
557
|
+
@const_paths = @const_paths.dup
|
377
558
|
|
378
559
|
true
|
379
560
|
end
|
@@ -383,6 +564,16 @@ module Tap
|
|
383
564
|
@active
|
384
565
|
end
|
385
566
|
|
567
|
+
# Globs the abstract directory for files in the specified directory alias,
|
568
|
+
# matching the pattern. The expanded path of each matching file is
|
569
|
+
# returned.
|
570
|
+
def glob(dir, pattern="**/*")
|
571
|
+
hlob(dir, pattern).values.sort!
|
572
|
+
end
|
573
|
+
|
574
|
+
# Same as glob but returns results as a hash of (relative_path, path)
|
575
|
+
# pairs. In short the hash defines matching files in the abstract
|
576
|
+
# directory, linked to the actual path for these files.
|
386
577
|
def hlob(dir, pattern="**/*")
|
387
578
|
results = {}
|
388
579
|
each do |env|
|
@@ -395,11 +586,11 @@ module Tap
|
|
395
586
|
results
|
396
587
|
end
|
397
588
|
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
def path(dir, *paths)
|
589
|
+
# Returns the path to the specified file, as determined by root.
|
590
|
+
#
|
591
|
+
# If a block is given, a path for each env will be yielded until the block
|
592
|
+
# returns a true value. Returns nil if the block never returns true.
|
593
|
+
def path(dir = :root, *paths)
|
403
594
|
each do |env|
|
404
595
|
path = env.root.path(dir, *paths)
|
405
596
|
return path if !block_given? || yield(path)
|
@@ -413,13 +604,12 @@ module Tap
|
|
413
604
|
#
|
414
605
|
# path(dir, module_path, *paths)
|
415
606
|
#
|
416
|
-
# By default
|
607
|
+
# By default 'module_path' is 'module.to_s.underscore' but modules can
|
417
608
|
# specify an alternative by providing a module_path method.
|
418
609
|
#
|
419
|
-
#
|
420
|
-
# the path
|
421
|
-
# is returned. Returns nil if the block never returns true.
|
422
|
-
#
|
610
|
+
# Paths are yielded to the block until the block returns true, at which
|
611
|
+
# point the current the path is returned. If no block is given, the
|
612
|
+
# first path is returned. Returns nil if the block never returns true.
|
423
613
|
def module_path(dir, modules, *paths, &block)
|
424
614
|
paths.compact!
|
425
615
|
while current = modules.shift
|
@@ -446,111 +636,119 @@ module Tap
|
|
446
636
|
module_path(dir, superclasses, *paths, &block)
|
447
637
|
end
|
448
638
|
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
639
|
+
# Generates a Manifest for self using the block as a builder. The builder
|
640
|
+
# receives an env and should return an array of resources, each of which
|
641
|
+
# can be minimappped. Minimapping requires that the resource is either
|
642
|
+
# a path string, or provides a 'path' method that returns a path string.
|
643
|
+
# Alternatively, a Minimap may be returned.
|
644
|
+
#
|
645
|
+
# If a type is specified, then the manifest cache will be linked to the
|
646
|
+
# context cache.
|
647
|
+
def manifest(type=nil, &block) # :yields: env
|
648
|
+
cache = type ? (context.cache[type] ||= {}) : {}
|
649
|
+
Manifest.new(self, block, cache)
|
650
|
+
end
|
651
|
+
|
652
|
+
# Returns a manifest of Constants located in .rb files under each of the
|
653
|
+
# const_paths. Constants are identified using Lazydoc constant attributes;
|
654
|
+
# all attributes are registered to the constants for classification
|
655
|
+
# (for example as a task, join, etc).
|
656
|
+
def constants
|
657
|
+
@constants ||= manifest(:constants) do |env|
|
658
|
+
constants = {}
|
659
|
+
|
660
|
+
env.const_paths.each do |load_path|
|
457
661
|
next unless File.directory?(load_path)
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
662
|
+
Constant.scan(load_path, "**/*.rb", constants)
|
663
|
+
end
|
664
|
+
|
665
|
+
constants.keys.sort!.collect! do |key|
|
666
|
+
constants[key]
|
462
667
|
end
|
463
|
-
|
464
|
-
registry
|
465
|
-
end
|
466
|
-
end
|
467
|
-
|
468
|
-
def register(type, override=false, &block)
|
469
|
-
type = type.to_sym
|
470
|
-
|
471
|
-
# error for existing, or overwrite
|
472
|
-
case
|
473
|
-
when override
|
474
|
-
builders.delete(type)
|
475
|
-
registries.each {|root, registry| registry.delete(type) }
|
476
|
-
when builders.has_key?(type)
|
477
|
-
raise "a builder is already registered for: #{type.inspect}"
|
478
|
-
when registries.any? {|root, registry| registry.has_key?(type) }
|
479
|
-
raise "entries are already registered for: #{type.inspect}"
|
480
668
|
end
|
481
|
-
|
482
|
-
builders[type] = block
|
483
669
|
end
|
484
670
|
|
485
|
-
|
486
|
-
#
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
671
|
+
# Seeks a constant for the key, constantizing if necessary. If invert is
|
672
|
+
# true, this method seeks and returns a key for the input constant. In
|
673
|
+
# both cases AGET returns nil if no key-constant pair can be found.
|
674
|
+
def [](key, invert=invert?)
|
675
|
+
if invert
|
676
|
+
const_name = key.to_s
|
677
|
+
constants.unseek(true) do |const|
|
678
|
+
const_name == const.const_name
|
679
|
+
end
|
680
|
+
else
|
681
|
+
if constant = constants.seek(key)
|
682
|
+
constant.constantize
|
683
|
+
else
|
684
|
+
nil
|
685
|
+
end
|
491
686
|
end
|
492
687
|
end
|
493
688
|
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
builder = builders[type]
|
499
|
-
builder ? builder.call(self) : []
|
500
|
-
end
|
501
|
-
|
502
|
-
manifests[type] ||= Manifest.new(self, type)
|
689
|
+
# Indicates AGET looks up constants from keys (false), or keys from
|
690
|
+
# constants (true).
|
691
|
+
def invert?
|
692
|
+
@invert
|
503
693
|
end
|
504
694
|
|
505
|
-
|
506
|
-
|
695
|
+
# Inverts the AGET lookup for self.
|
696
|
+
def invert!
|
697
|
+
@invert = !@invert
|
698
|
+
self
|
507
699
|
end
|
508
700
|
|
509
|
-
|
510
|
-
|
511
|
-
|
701
|
+
# Returns a duplicate of self with inverted AGET lookup.
|
702
|
+
def invert
|
703
|
+
dup.invert!
|
512
704
|
end
|
513
705
|
|
514
|
-
#
|
515
|
-
#
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
each do |env|
|
542
|
-
manifest = env.manifest(type)
|
543
|
-
if value = manifest.find(&block)
|
544
|
-
key = manifest.minihash(true)[value]
|
545
|
-
return key_only ? key : "#{minihash(true)[env]}:#{key}"
|
546
|
-
end
|
706
|
+
# Scans the files matched under the directory and pattern for constants
|
707
|
+
# and adds them to the existing constants for self.
|
708
|
+
def scan(dir, pattern="**/*.rb")
|
709
|
+
new_entries = {}
|
710
|
+
entries = constants.entries(self)
|
711
|
+
entries.each {|const| new_entries[const.const_name] = const }
|
712
|
+
|
713
|
+
Constant.scan(root[dir], pattern, new_entries)
|
714
|
+
|
715
|
+
entries.replace(new_entries.keys)
|
716
|
+
entries.sort!.collect! {|key| new_entries[key] }
|
717
|
+
entries
|
718
|
+
end
|
719
|
+
|
720
|
+
# Registers a constant with self. The constant is stored as a new
|
721
|
+
# Constant in the constants manifest. Returns the new Constant.
|
722
|
+
# If the constant is already registered, the existing Constant is
|
723
|
+
# returned.
|
724
|
+
def register(constant)
|
725
|
+
const_name = constant.to_s
|
726
|
+
entries = constants.entries(self)
|
727
|
+
|
728
|
+
# try to find the existing Constant before making a new constant
|
729
|
+
unless constant = entries.find {|const| const.const_name == const_name}
|
730
|
+
constant = Constant.new(const_name)
|
731
|
+
entries << constant
|
732
|
+
entries.replace entries.sort_by {|const| const.const_name }
|
547
733
|
end
|
548
|
-
|
549
|
-
|
734
|
+
|
735
|
+
constant
|
550
736
|
end
|
551
737
|
|
552
|
-
#
|
553
|
-
#
|
738
|
+
# When no template is specified, inspect generates a fairly standard
|
739
|
+
# inspection string. When a template is provided, inspect builds a
|
740
|
+
# Templater for each env with the following local variables:
|
741
|
+
#
|
742
|
+
# variable value
|
743
|
+
# env the current env
|
744
|
+
# env_keys a minihash for all envs
|
745
|
+
#
|
746
|
+
# If a block is given, the globals and templater are yielded before
|
747
|
+
# any templater is built; this allows each env to add env-specific
|
748
|
+
# variables. After this preparation, each templater is built with
|
749
|
+
# the globals and the results concatenated.
|
750
|
+
#
|
751
|
+
# The template is built with filename, if specified (for debugging).
|
554
752
|
def inspect(template=nil, globals={}, filename=nil) # :yields: templater, globals
|
555
753
|
if template == nil
|
556
754
|
return "#<#{self.class}:#{object_id} root='#{root.root}'>"
|
@@ -565,27 +763,13 @@ module Tap
|
|
565
763
|
templater.build(globals, filename)
|
566
764
|
end.join
|
567
765
|
end
|
568
|
-
|
766
|
+
|
569
767
|
protected
|
570
768
|
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
def basename # :nodoc:
|
576
|
-
context[:basename]
|
577
|
-
end
|
578
|
-
|
579
|
-
def builders # :nodoc:
|
580
|
-
context[:builders] ||= {}
|
581
|
-
end
|
582
|
-
|
583
|
-
def instances # :nodoc:
|
584
|
-
context[:instances] ||= []
|
585
|
-
end
|
586
|
-
|
587
|
-
def instance(path) # :nodoc:
|
588
|
-
instances.find {|env| env.root.root == path }
|
769
|
+
# helper for Minimap; note that specifying env.root.root via path
|
770
|
+
# is not possible because path is required for other purposes.
|
771
|
+
def entry_to_path(env) # :nodoc:
|
772
|
+
env.root.root
|
589
773
|
end
|
590
774
|
|
591
775
|
# resets envs using the current env_paths and gems. does nothing
|
@@ -593,15 +777,15 @@ module Tap
|
|
593
777
|
def reset_envs # :nodoc:
|
594
778
|
if env_paths && gems
|
595
779
|
self.envs = env_paths.collect do |path|
|
596
|
-
instance(path) || Env.new(path, context)
|
780
|
+
context.instance(path) || Env.new(path, context)
|
597
781
|
end + gems.collect do |spec|
|
598
|
-
instance(spec.full_gem_path) || Env.
|
782
|
+
context.instance(spec.full_gem_path) || Env.setup_gem(spec, context)
|
599
783
|
end
|
600
784
|
end
|
601
785
|
end
|
602
786
|
|
603
|
-
# arrayifies, compacts, and resolves input paths using root
|
604
|
-
# removes duplicates. in short:
|
787
|
+
# arrayifies, compacts, and resolves input paths using root.
|
788
|
+
# also removes duplicates. in short:
|
605
789
|
#
|
606
790
|
# resolve_paths ['lib', nil, 'lib', 'alt] # => [root['lib'], root['alt']]
|
607
791
|
#
|