fig 0.1.62 → 0.1.64
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/Changes +156 -0
- data/VERSION +1 -1
- data/bin/fig +9 -2
- data/bin/fig-debug +9 -2
- data/lib/fig/applicationconfiguration.rb +3 -2
- data/lib/fig/atexit.rb +37 -0
- data/lib/fig/backtrace.rb +23 -6
- data/lib/fig/command.rb +131 -31
- data/lib/fig/command/coveragesupport.rb +40 -0
- data/lib/fig/command/listing.rb +8 -8
- data/lib/fig/command/optionerror.rb +8 -0
- data/lib/fig/{options.rb → command/options.rb} +248 -144
- data/lib/fig/command/packageload.rb +161 -62
- data/lib/fig/configfileerror.rb +2 -0
- data/lib/fig/environment.rb +350 -246
- data/lib/fig/environmentvariables/casesensitive.rb +1 -1
- data/lib/fig/figrc.rb +78 -78
- data/lib/fig/grammar.treetop +204 -219
- data/lib/fig/log4rconfigerror.rb +2 -0
- data/lib/fig/operatingsystem.rb +382 -334
- data/lib/fig/package.rb +11 -33
- data/lib/fig/packagecache.rb +1 -1
- data/lib/fig/packagedescriptor.rb +103 -21
- data/lib/fig/packagedescriptorparseerror.rb +16 -0
- data/lib/fig/parser.rb +36 -19
- data/lib/fig/parserpackagebuildstate.rb +56 -0
- data/lib/fig/repository.rb +504 -259
- data/lib/fig/statement.rb +30 -12
- data/lib/fig/statement/archive.rb +8 -5
- data/lib/fig/statement/asset.rb +19 -0
- data/lib/fig/statement/command.rb +2 -2
- data/lib/fig/statement/configuration.rb +20 -20
- data/lib/fig/statement/include.rb +13 -34
- data/lib/fig/statement/override.rb +21 -7
- data/lib/fig/statement/path.rb +22 -2
- data/lib/fig/statement/resource.rb +14 -4
- data/lib/fig/statement/retrieve.rb +34 -4
- data/lib/fig/statement/set.rb +22 -2
- data/lib/fig/workingdirectorymaintainer.rb +197 -0
- data/lib/fig/workingdirectorymetadata.rb +45 -0
- metadata +52 -46
- data/lib/fig/retriever.rb +0 -141
- data/lib/fig/statement/publish.rb +0 -15
@@ -5,40 +5,40 @@ require 'fig/parser'
|
|
5
5
|
module Fig; end
|
6
6
|
class Fig::Command; end
|
7
7
|
|
8
|
-
# Parts of the Command class related to loading of the
|
8
|
+
# Parts of the Command class related to loading of the base Package object,
|
9
9
|
# simply to keep the size of command.rb down.
|
10
10
|
module Fig::Command::PackageLoad
|
11
11
|
DEFAULT_FIG_FILE = 'package.fig'
|
12
12
|
|
13
13
|
private
|
14
14
|
|
15
|
-
def
|
15
|
+
def read_in_package_definition_file(config_file)
|
16
16
|
if File.exist?(config_file)
|
17
17
|
@package_loaded_from_path = config_file
|
18
18
|
|
19
19
|
return File.read(config_file)
|
20
20
|
else
|
21
|
-
raise Fig::UserInputError.new(%Q<File
|
21
|
+
raise Fig::UserInputError.new(%Q<File "#{config_file}" does not exist.>)
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
def
|
26
|
-
|
25
|
+
def load_package_definition_file_contents()
|
26
|
+
package_definition_file = @options.package_definition_file()
|
27
27
|
|
28
|
-
if
|
28
|
+
if package_definition_file == :none
|
29
29
|
return nil
|
30
|
-
elsif
|
30
|
+
elsif package_definition_file == '-'
|
31
31
|
@package_loaded_from_path = '<standard input>'
|
32
32
|
|
33
33
|
return $stdin.read
|
34
|
-
elsif
|
34
|
+
elsif package_definition_file.nil?
|
35
35
|
if File.exist?(DEFAULT_FIG_FILE)
|
36
36
|
@package_loaded_from_path = DEFAULT_FIG_FILE
|
37
37
|
|
38
38
|
return File.read(DEFAULT_FIG_FILE)
|
39
39
|
end
|
40
40
|
else
|
41
|
-
return
|
41
|
+
return read_in_package_definition_file(package_definition_file)
|
42
42
|
end
|
43
43
|
|
44
44
|
return
|
@@ -54,84 +54,183 @@ module Fig::Command::PackageLoad
|
|
54
54
|
|
55
55
|
def register_package_with_environment()
|
56
56
|
if @options.updating?
|
57
|
-
@
|
58
|
-
@environment.add_retrieve(
|
57
|
+
@base_package.retrieves.each do |statement|
|
58
|
+
@environment.add_retrieve(statement)
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
-
@environment.register_package(@
|
63
|
-
|
64
|
-
config = base_config()
|
65
|
-
begin
|
66
|
-
@environment.apply_config(@package, config, nil)
|
67
|
-
rescue Fig::NoSuchPackageConfigError => exception
|
68
|
-
raise exception if not @descriptor
|
69
|
-
|
70
|
-
descriptor = exception.descriptor
|
71
|
-
|
72
|
-
raise exception if
|
73
|
-
descriptor.name && descriptor.name != @descriptor.name
|
74
|
-
raise exception if
|
75
|
-
descriptor.version && descriptor.version != @descriptor.version
|
76
|
-
raise exception if descriptor.config != config
|
77
|
-
|
78
|
-
source = nil
|
79
|
-
if @package_loaded_from_path
|
80
|
-
source = @package_loaded_from_path
|
81
|
-
else
|
82
|
-
source =
|
83
|
-
Fig::PackageDescriptor.format(@descriptor.name, @descriptor.version, nil)
|
84
|
-
end
|
85
|
-
source_component = source ? %Q< in #{source}> : ''
|
86
|
-
|
87
|
-
message = %Q<There's no "#{config}" configuration#{source_component}.>
|
88
|
-
message += %q< Specify one that does like this: ">
|
89
|
-
message +=
|
90
|
-
Fig::PackageDescriptor.format(@descriptor.name, @descriptor.version, 'some_existing_config')
|
91
|
-
message += %q<".>
|
92
|
-
|
93
|
-
if @options.publishing?
|
94
|
-
message += ' (Yes, this does work with --publish.)'
|
95
|
-
end
|
96
|
-
|
97
|
-
raise Fig::UserInputError.new(message)
|
98
|
-
end
|
62
|
+
@environment.register_package(@base_package)
|
63
|
+
apply_base_config_to_environment()
|
99
64
|
|
100
65
|
return
|
101
66
|
end
|
102
67
|
|
103
|
-
def
|
104
|
-
if
|
105
|
-
|
68
|
+
def parse_package_definition_file(definition_text)
|
69
|
+
if definition_text.nil?
|
70
|
+
# This package gets a free ride in terms of requiring a base config; we
|
71
|
+
# synthesize it.
|
72
|
+
set_base_package_to_empty_synthetic_one()
|
106
73
|
return
|
107
74
|
end
|
108
75
|
|
109
|
-
|
76
|
+
source_description = derive_package_source_description()
|
77
|
+
@base_package =
|
110
78
|
Fig::Parser.new(@configuration, :check_include_versions).parse_package(
|
111
|
-
Fig::PackageDescriptor.new(
|
79
|
+
Fig::PackageDescriptor.new(
|
80
|
+
nil, nil, nil, :source_description => source_description
|
81
|
+
),
|
82
|
+
'.',
|
83
|
+
source_description,
|
84
|
+
definition_text
|
112
85
|
)
|
113
86
|
|
114
|
-
register_package_with_environment_if_not_listing_or_publishing()
|
115
|
-
|
116
87
|
return
|
117
88
|
end
|
118
89
|
|
119
|
-
def
|
120
|
-
|
90
|
+
def load_package_object_from_file()
|
91
|
+
definition_text = load_package_definition_file_contents()
|
121
92
|
|
122
|
-
|
93
|
+
parse_package_definition_file(definition_text)
|
123
94
|
end
|
124
95
|
|
125
96
|
def load_package_object()
|
126
97
|
if @descriptor.nil?
|
127
|
-
|
98
|
+
load_package_object_from_file()
|
128
99
|
else
|
129
|
-
|
130
|
-
|
100
|
+
@base_package = @repository.get_package(@descriptor)
|
101
|
+
end
|
102
|
+
|
103
|
+
register_package_with_environment_if_not_listing_or_publishing()
|
131
104
|
|
132
|
-
|
105
|
+
return
|
106
|
+
end
|
107
|
+
|
108
|
+
def apply_base_config_to_environment(ignore_base_package = false)
|
109
|
+
begin
|
110
|
+
@environment.apply_config(
|
111
|
+
synthesize_package_for_command_line_options(ignore_base_package),
|
112
|
+
Fig::Package::DEFAULT_CONFIG,
|
113
|
+
nil
|
114
|
+
)
|
115
|
+
rescue Fig::NoSuchPackageConfigError => exception
|
116
|
+
make_no_such_package_exception_descriptive(exception)
|
133
117
|
end
|
134
118
|
|
135
119
|
return
|
136
120
|
end
|
121
|
+
|
122
|
+
def set_base_package_to_empty_synthetic_one()
|
123
|
+
@base_package = Fig::Package.new(
|
124
|
+
nil,
|
125
|
+
nil,
|
126
|
+
'.',
|
127
|
+
[
|
128
|
+
Fig::Statement::Configuration.new(
|
129
|
+
nil,
|
130
|
+
%Q<[synthetic statement created in #{__FILE__} line #{__LINE__}]>,
|
131
|
+
base_config(),
|
132
|
+
[]
|
133
|
+
)
|
134
|
+
]
|
135
|
+
)
|
136
|
+
|
137
|
+
return
|
138
|
+
end
|
139
|
+
|
140
|
+
def synthesize_package_for_command_line_options(ignore_base_package)
|
141
|
+
configuration_statements = []
|
142
|
+
|
143
|
+
if not ignore_base_package
|
144
|
+
configuration_statements << Fig::Statement::Include.new(
|
145
|
+
nil,
|
146
|
+
%Q<[synthetic statement created in #{__FILE__} line #{__LINE__}]>,
|
147
|
+
Fig::PackageDescriptor.new(
|
148
|
+
@base_package.name(), @base_package.version(), base_config()
|
149
|
+
),
|
150
|
+
nil
|
151
|
+
)
|
152
|
+
end
|
153
|
+
|
154
|
+
configuration_statements << @options.environment_statements()
|
155
|
+
|
156
|
+
configuration_statement =
|
157
|
+
Fig::Statement::Configuration.new(
|
158
|
+
nil,
|
159
|
+
%Q<[synthetic statement created in #{__FILE__} line #{__LINE__}]>,
|
160
|
+
Fig::Package::DEFAULT_CONFIG,
|
161
|
+
configuration_statements.flatten()
|
162
|
+
)
|
163
|
+
|
164
|
+
return Fig::Package.new(nil, nil, '.', [configuration_statement])
|
165
|
+
end
|
166
|
+
|
167
|
+
def make_no_such_package_exception_descriptive(exception)
|
168
|
+
if not @descriptor
|
169
|
+
make_no_such_package_exception_descriptive_without_descriptor(exception)
|
170
|
+
end
|
171
|
+
|
172
|
+
check_no_such_package_exception_is_for_command_line_package(exception)
|
173
|
+
source = derive_exception_source()
|
174
|
+
|
175
|
+
message = %Q<There's no "#{base_config()}" config#{source}.>
|
176
|
+
message += %q< Specify one that does like this: ">
|
177
|
+
message +=
|
178
|
+
Fig::PackageDescriptor.format(@descriptor.name, @descriptor.version, 'some_existing_config')
|
179
|
+
message += %q<".>
|
180
|
+
|
181
|
+
if @options.publishing?
|
182
|
+
message += ' (Yes, this does work with --publish.)'
|
183
|
+
end
|
184
|
+
|
185
|
+
raise Fig::UserInputError.new(message)
|
186
|
+
end
|
187
|
+
|
188
|
+
def make_no_such_package_exception_descriptive_without_descriptor(exception)
|
189
|
+
raise exception if config_was_specified_by_user()
|
190
|
+
raise exception if not exception.descriptor.nil?
|
191
|
+
|
192
|
+
source = derive_exception_source()
|
193
|
+
message =
|
194
|
+
%Q<No config was specified and there's no "#{Fig::Package::DEFAULT_CONFIG}" config#{source}.>
|
195
|
+
config_names = @base_package.config_names()
|
196
|
+
if config_names.size > 1
|
197
|
+
message +=
|
198
|
+
%Q< The valid configs are "#{config_names.join('", "')}".>
|
199
|
+
elsif config_names.size == 1
|
200
|
+
message += %Q< The only config is "#{config_names[0]}".>
|
201
|
+
else
|
202
|
+
message += ' Actually, there are no configs.'
|
203
|
+
end
|
204
|
+
|
205
|
+
raise Fig::UserInputError.new(message)
|
206
|
+
end
|
207
|
+
|
208
|
+
def check_no_such_package_exception_is_for_command_line_package(exception)
|
209
|
+
descriptor = exception.descriptor
|
210
|
+
|
211
|
+
raise exception if
|
212
|
+
descriptor.name && descriptor.name != @descriptor.name
|
213
|
+
raise exception if
|
214
|
+
descriptor.version && descriptor.version != @descriptor.version
|
215
|
+
raise exception if descriptor.config != base_config()
|
216
|
+
|
217
|
+
return
|
218
|
+
end
|
219
|
+
|
220
|
+
def derive_exception_source()
|
221
|
+
source = derive_package_source_description()
|
222
|
+
|
223
|
+
return source ? %Q< in #{source}> : ''
|
224
|
+
end
|
225
|
+
|
226
|
+
def derive_package_source_description()
|
227
|
+
if @package_loaded_from_path
|
228
|
+
return @package_loaded_from_path
|
229
|
+
elsif @descriptor
|
230
|
+
return
|
231
|
+
Fig::PackageDescriptor.format(@descriptor.name, @descriptor.version, nil)
|
232
|
+
end
|
233
|
+
|
234
|
+
return nil
|
235
|
+
end
|
137
236
|
end
|
data/lib/fig/configfileerror.rb
CHANGED
data/lib/fig/environment.rb
CHANGED
@@ -10,323 +10,427 @@ require 'fig/statement/path'
|
|
10
10
|
require 'fig/statement/set'
|
11
11
|
require 'fig/userinputerror'
|
12
12
|
|
13
|
-
module Fig
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
13
|
+
module Fig; end
|
14
|
+
|
15
|
+
# Manages the program's metadata, including packages and environment
|
16
|
+
# variables, and sets things up for running commands (from "command"
|
17
|
+
# statements in definition files or from the command-line).
|
18
|
+
class Fig::Environment
|
19
|
+
# Note: when reading this code, understand that the word "retrieve" is a
|
20
|
+
# noun and not a verb, e.g. "retrieve path" means the value of a retrieve
|
21
|
+
# statement and not the action of retrieving a path.
|
22
|
+
|
23
|
+
def initialize(repository, variables_override, working_directory_maintainer)
|
24
|
+
@repository = repository
|
25
|
+
@variables =
|
26
|
+
variables_override || Fig::OperatingSystem.get_environment_variables()
|
27
|
+
@retrieves = {}
|
28
|
+
@packages = {}
|
29
|
+
@working_directory_maintainer = working_directory_maintainer
|
30
|
+
end
|
27
31
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
+
# Returns the value of an envirionment variable
|
33
|
+
def [](name)
|
34
|
+
return @variables[name]
|
35
|
+
end
|
32
36
|
|
33
|
-
|
34
|
-
|
37
|
+
def variables
|
38
|
+
return @variables.clone
|
39
|
+
end
|
40
|
+
|
41
|
+
# Indicates that the values from a particular environment variable path
|
42
|
+
# should be copied to a local directory.
|
43
|
+
def add_retrieve(retrieve_statement)
|
44
|
+
name = retrieve_statement.var
|
45
|
+
if @retrieves.has_key?(name)
|
46
|
+
Fig::Logging.warn \
|
47
|
+
%q<About to overwrite "#{name}" retrieve path of "#{@retrieves[name].path}" with "#{retrieve_statement.path}".>
|
35
48
|
end
|
36
49
|
|
37
|
-
|
38
|
-
|
39
|
-
@retrieve_vars[name] = path
|
50
|
+
@retrieves[name] = retrieve_statement
|
51
|
+
retrieve_statement.added_to_environment(true)
|
40
52
|
|
41
|
-
|
53
|
+
return
|
54
|
+
end
|
55
|
+
|
56
|
+
def register_package(package)
|
57
|
+
name = package.name
|
58
|
+
|
59
|
+
if get_package(name)
|
60
|
+
raise_repository_error(
|
61
|
+
name.nil? \
|
62
|
+
? %Q<There is already a package with the name "#{name}".> \
|
63
|
+
: %q<There is already an unnamed package.>,
|
64
|
+
nil,
|
65
|
+
package
|
66
|
+
)
|
42
67
|
end
|
43
68
|
|
44
|
-
|
45
|
-
name = package.name
|
69
|
+
@packages[name] = package
|
46
70
|
|
47
|
-
|
48
|
-
|
49
|
-
raise RepositoryError.new
|
50
|
-
end
|
71
|
+
return
|
72
|
+
end
|
51
73
|
|
52
|
-
|
74
|
+
def get_package(name)
|
75
|
+
return @packages[name]
|
76
|
+
end
|
53
77
|
|
78
|
+
def apply_config(package, config_name, backtrace)
|
79
|
+
if package.applied_config_names.member?(config_name)
|
54
80
|
return
|
55
81
|
end
|
82
|
+
new_backtrace = backtrace ||
|
83
|
+
Fig::Backtrace.new(
|
84
|
+
nil,
|
85
|
+
Fig::PackageDescriptor.new(package.name, package.version, config_name)
|
86
|
+
)
|
56
87
|
|
57
|
-
|
58
|
-
|
88
|
+
config = package[config_name]
|
89
|
+
config.statements.each do
|
90
|
+
|statement|
|
91
|
+
apply_config_statement(package, statement, new_backtrace)
|
59
92
|
end
|
93
|
+
package.add_applied_config_name(config_name)
|
60
94
|
|
61
|
-
|
62
|
-
|
63
|
-
end
|
95
|
+
return
|
96
|
+
end
|
64
97
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
new_backtrace = backtrace
|
98
|
+
def execute_shell(command)
|
99
|
+
@variables.with_environment do
|
100
|
+
yield command.map{|arg| expand_command_line_argument(arg, nil, nil)}
|
101
|
+
end
|
70
102
|
|
71
|
-
|
72
|
-
|
73
|
-
package.add_applied_config_name(config_name)
|
103
|
+
return
|
104
|
+
end
|
74
105
|
|
75
|
-
|
106
|
+
def execute_config(base_package, descriptor, args, &block)
|
107
|
+
config_name =
|
108
|
+
descriptor.config || find_config_name_in_package(descriptor.name)
|
109
|
+
|
110
|
+
name = descriptor.name || base_package.name
|
111
|
+
package = lookup_package(
|
112
|
+
name,
|
113
|
+
descriptor.version,
|
114
|
+
Fig::Backtrace.new(
|
115
|
+
nil,
|
116
|
+
Fig::PackageDescriptor.new(name, descriptor.version, config_name)
|
117
|
+
)
|
118
|
+
)
|
119
|
+
|
120
|
+
command_statement = package[config_name].command_statement
|
121
|
+
if command_statement
|
122
|
+
execute_command(command_statement, args, package, nil, &block)
|
123
|
+
else
|
124
|
+
raise Fig::UserInputError.new(
|
125
|
+
%Q<The "#{package.to_s}" package with the "#{config_name}" configuration does not contain a command.>
|
126
|
+
)
|
76
127
|
end
|
77
128
|
|
78
|
-
|
79
|
-
|
80
|
-
yield command.map{|arg| expand_command_line_argument(arg)}
|
81
|
-
end
|
129
|
+
return
|
130
|
+
end
|
82
131
|
|
83
|
-
|
132
|
+
# In order for this to work correctly, any Overrides need to be processed
|
133
|
+
# before any other kind of Statement. The Configuration class guarantees
|
134
|
+
# that those come first in its set of Statements.
|
135
|
+
def apply_config_statement(base_package, statement, backtrace)
|
136
|
+
case statement
|
137
|
+
when Fig::Statement::Path
|
138
|
+
prepend_variable(base_package, statement.name, statement.value, backtrace)
|
139
|
+
when Fig::Statement::Set
|
140
|
+
set_variable(base_package, statement.name, statement.value, backtrace)
|
141
|
+
when Fig::Statement::Include
|
142
|
+
include_config(base_package, statement.descriptor, backtrace)
|
143
|
+
when Fig::Statement::Override
|
144
|
+
backtrace.add_override(statement)
|
145
|
+
when Fig::Statement::Command
|
146
|
+
# Skip - has no effect on environment.
|
147
|
+
else
|
148
|
+
raise "Unexpected statement in a config block: #{statement.unparse('')}"
|
84
149
|
end
|
85
150
|
|
86
|
-
|
87
|
-
|
88
|
-
argument =
|
89
|
-
expand_command_line_argument(
|
90
|
-
"#{command.command} #{args.join(' ')}"
|
91
|
-
)
|
151
|
+
return
|
152
|
+
end
|
92
153
|
|
93
|
-
|
94
|
-
|
154
|
+
def include_config(base_package, descriptor, backtrace)
|
155
|
+
resolved_descriptor = nil
|
95
156
|
|
96
|
-
|
157
|
+
# Check to see if this include has been overridden.
|
158
|
+
if backtrace
|
159
|
+
override = backtrace.get_override(
|
160
|
+
descriptor.name || base_package.name
|
161
|
+
)
|
162
|
+
if override
|
163
|
+
resolved_descriptor =
|
164
|
+
Fig::PackageDescriptor.new(
|
165
|
+
descriptor.name, override, descriptor.config
|
166
|
+
)
|
167
|
+
end
|
97
168
|
end
|
169
|
+
resolved_descriptor ||= descriptor
|
170
|
+
|
171
|
+
new_backtrace = Fig::Backtrace.new(backtrace, resolved_descriptor)
|
172
|
+
package = lookup_package(
|
173
|
+
resolved_descriptor.name || base_package.name,
|
174
|
+
resolved_descriptor.version,
|
175
|
+
new_backtrace
|
176
|
+
)
|
177
|
+
apply_config(
|
178
|
+
package,
|
179
|
+
resolved_descriptor.config || Fig::Package::DEFAULT_CONFIG,
|
180
|
+
new_backtrace
|
181
|
+
)
|
182
|
+
|
183
|
+
return
|
184
|
+
end
|
98
185
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
return Package::DEFAULT_CONFIG
|
103
|
-
end
|
186
|
+
def check_unused_retrieves()
|
187
|
+
@retrieves.keys().sort().each do
|
188
|
+
|name|
|
104
189
|
|
105
|
-
|
190
|
+
statement = @retrieves[name]
|
191
|
+
if statement.loaded_but_not_referenced?
|
192
|
+
Fig::Logging.warn \
|
193
|
+
%Q<The #{name} variable was never referenced or didn't need expansion, so "#{statement.unparse('')}"#{statement.position_string} was ignored.>
|
194
|
+
end
|
106
195
|
end
|
196
|
+
end
|
107
197
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
name,
|
115
|
-
descriptor.version,
|
116
|
-
Backtrace.new(
|
117
|
-
nil,
|
118
|
-
PackageDescriptor.new(name, descriptor.version, config_name)
|
119
|
-
)
|
198
|
+
private
|
199
|
+
|
200
|
+
def set_variable(base_package, name, value, backtrace)
|
201
|
+
expanded_value =
|
202
|
+
expand_variable_as_path_and_process_retrieves(
|
203
|
+
name, value, base_package, backtrace
|
120
204
|
)
|
205
|
+
@variables[name] = expanded_value
|
121
206
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
raise UserInputError.new(%Q<The "#{package.to_s}" package with the "#{config_name}" configuration does not contain a command.>)
|
127
|
-
end
|
207
|
+
if Fig::Logging.debug?
|
208
|
+
expanded_message =
|
209
|
+
expanded_value == value ? '' \
|
210
|
+
: %Q< (expanded from "#{value}")>
|
128
211
|
|
129
|
-
|
212
|
+
Fig::Logging.debug(
|
213
|
+
%Q<Set #{name} to "#{expanded_value}"#{expanded_message}.>
|
214
|
+
)
|
130
215
|
end
|
131
216
|
|
132
|
-
|
133
|
-
|
134
|
-
when Statement::Path
|
135
|
-
prepend_variable(base_package, statement.name, statement.value)
|
136
|
-
when Statement::Set
|
137
|
-
set_variable(base_package, statement.name, statement.value)
|
138
|
-
when Statement::Include
|
139
|
-
include_config(
|
140
|
-
base_package, statement.descriptor, statement.overrides, backtrace
|
141
|
-
)
|
142
|
-
when Statement::Command
|
143
|
-
# ignore
|
144
|
-
else
|
145
|
-
fail "Unexpected statement: #{statement}"
|
146
|
-
end
|
217
|
+
return
|
218
|
+
end
|
147
219
|
|
148
|
-
|
220
|
+
def prepend_variable(base_package, name, value, backtrace)
|
221
|
+
expanded_value =
|
222
|
+
expand_variable_as_path_and_process_retrieves(
|
223
|
+
name, value, base_package, backtrace
|
224
|
+
)
|
225
|
+
@variables.prepend_variable(name, expanded_value)
|
226
|
+
|
227
|
+
if Fig::Logging.debug?
|
228
|
+
expanded_message =
|
229
|
+
expanded_value == value ? '' \
|
230
|
+
: %Q< ("#{value}" expanded to "#{expanded_value}")>
|
231
|
+
|
232
|
+
Fig::Logging.debug(
|
233
|
+
%Q<Prepending to #{name} resulted in "#{@variables[name]}"#{expanded_message}.>
|
234
|
+
)
|
149
235
|
end
|
150
236
|
|
151
|
-
|
152
|
-
|
237
|
+
return
|
238
|
+
end
|
153
239
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
240
|
+
def lookup_package(name, version, backtrace)
|
241
|
+
package = get_package(name)
|
242
|
+
if package.nil?
|
243
|
+
if not version
|
244
|
+
raise_repository_error(
|
245
|
+
"No version specified for #{name}.", backtrace, package
|
158
246
|
)
|
159
|
-
if override
|
160
|
-
resolved_descriptor =
|
161
|
-
PackageDescriptor.new(
|
162
|
-
descriptor.name, override, descriptor.config
|
163
|
-
)
|
164
|
-
end
|
165
247
|
end
|
166
|
-
resolved_descriptor ||= descriptor
|
167
248
|
|
168
|
-
|
169
|
-
|
170
|
-
new_backtrace.add_override(override.package_name, override.version)
|
171
|
-
end
|
172
|
-
package = lookup_package(
|
173
|
-
resolved_descriptor.name || base_package.name,
|
174
|
-
resolved_descriptor.version,
|
175
|
-
new_backtrace
|
176
|
-
)
|
177
|
-
apply_config(
|
178
|
-
package,
|
179
|
-
resolved_descriptor.config || Package::DEFAULT_CONFIG,
|
180
|
-
new_backtrace
|
249
|
+
package = @repository.get_package(
|
250
|
+
Fig::PackageDescriptor.new(name, version, nil)
|
181
251
|
)
|
252
|
+
package.backtrace = backtrace
|
253
|
+
@packages[name] = package
|
254
|
+
elsif version && version != package.version
|
255
|
+
raise_repository_error("Version mismatch: #{name}", backtrace, package)
|
256
|
+
end
|
182
257
|
|
183
|
-
|
258
|
+
return package
|
259
|
+
end
|
260
|
+
|
261
|
+
def find_config_name_in_package(name)
|
262
|
+
package = get_package(name)
|
263
|
+
if not package
|
264
|
+
return Fig::Package::DEFAULT_CONFIG
|
184
265
|
end
|
185
266
|
|
186
|
-
|
267
|
+
return package.primary_config_name || Fig::Package::DEFAULT_CONFIG
|
268
|
+
end
|
187
269
|
|
188
|
-
|
189
|
-
|
270
|
+
def execute_command(command_statement, args, package, backtrace)
|
271
|
+
@variables.with_environment do
|
272
|
+
argument =
|
273
|
+
expand_command_line_argument(
|
274
|
+
"#{command_statement.command} #{args.join(' ')}", backtrace, package
|
275
|
+
)
|
190
276
|
|
191
|
-
|
277
|
+
yield expand_at_signs_in_path(argument, package, backtrace).split(' ')
|
192
278
|
end
|
193
279
|
|
194
|
-
|
195
|
-
|
196
|
-
@variables.prepend_variable(name, value)
|
280
|
+
return
|
281
|
+
end
|
197
282
|
|
198
|
-
|
199
|
-
|
283
|
+
def expand_variable_as_path_and_process_retrieves(
|
284
|
+
variable_name, variable_value, base_package, backtrace
|
285
|
+
)
|
286
|
+
return variable_value unless base_package && base_package.name
|
200
287
|
|
201
|
-
|
202
|
-
|
203
|
-
if package.nil?
|
204
|
-
if not version
|
205
|
-
Logging.fatal "No version specified for #{name}."
|
206
|
-
raise RepositoryError.new
|
207
|
-
end
|
288
|
+
variable_value =
|
289
|
+
expand_at_signs_in_path(variable_value, base_package, backtrace)
|
208
290
|
|
209
|
-
|
210
|
-
PackageDescriptor.new(name, version, nil)
|
211
|
-
)
|
212
|
-
package.backtrace = backtrace
|
213
|
-
@packages[name] = package
|
214
|
-
elsif version && version != package.version
|
215
|
-
string_handle = StringIO.new
|
216
|
-
backtrace.dump(string_handle) if backtrace
|
217
|
-
package.backtrace.dump(string_handle) if package.backtrace
|
218
|
-
stacktrace = string_handle.string
|
219
|
-
Logging.fatal \
|
220
|
-
"Version mismatch: #{name}" \
|
221
|
-
+ ( stacktrace.empty? ? '' : "\n#{stacktrace}" )
|
222
|
-
raise RepositoryError.new
|
223
|
-
end
|
291
|
+
return variable_value if not @retrieves.member?(variable_name)
|
224
292
|
|
225
|
-
|
226
|
-
|
293
|
+
return retrieve_files(
|
294
|
+
variable_name, variable_value, base_package, backtrace
|
295
|
+
)
|
296
|
+
end
|
227
297
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
file = expand_path(value, base_package)
|
234
|
-
|
235
|
-
if @retrieve_vars.member?(name)
|
236
|
-
# A '//' in the source file's path tells us to preserve path
|
237
|
-
# information after the '//' when doing a retrieve.
|
238
|
-
if file.split('//').size > 1
|
239
|
-
preserved_path = file.split('//').last
|
240
|
-
target = File.join(
|
241
|
-
translate_retrieve_variables(base_package, name),
|
242
|
-
preserved_path
|
243
|
-
)
|
244
|
-
else
|
245
|
-
target = File.join(
|
246
|
-
translate_retrieve_variables(base_package, name)
|
247
|
-
)
|
248
|
-
if not File.directory?(file)
|
249
|
-
target = File.join(target, File.basename(file))
|
250
|
-
end
|
251
|
-
end
|
252
|
-
@retriever.with_package_version(
|
253
|
-
base_package.name, base_package.version
|
254
|
-
) do
|
255
|
-
@retriever.retrieve(file, target)
|
256
|
-
end
|
257
|
-
file = target
|
258
|
-
end
|
298
|
+
def retrieve_files(variable_name, variable_value, base_package, backtrace)
|
299
|
+
check_source_existence(
|
300
|
+
variable_name, variable_value, base_package, backtrace
|
301
|
+
)
|
259
302
|
|
260
|
-
|
261
|
-
|
303
|
+
destination_path =
|
304
|
+
derive_retrieve_destination(variable_name, variable_value, base_package)
|
262
305
|
|
263
|
-
|
264
|
-
|
265
|
-
|
306
|
+
@working_directory_maintainer.switch_to_package_version(
|
307
|
+
base_package.name, base_package.version
|
308
|
+
)
|
309
|
+
@working_directory_maintainer.retrieve(variable_value, destination_path)
|
266
310
|
|
267
|
-
|
268
|
-
|
311
|
+
return destination_path
|
312
|
+
end
|
269
313
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
( [^\\@]* (?:\\{2})*) # An even number of leading backslashes
|
275
|
-
\@ # The package indicator
|
276
|
-
>x
|
277
|
-
) do |match|
|
278
|
-
backslashes = $1 || ''
|
279
|
-
backslashes + base_package.directory
|
280
|
-
end
|
314
|
+
def check_source_existence(
|
315
|
+
variable_name, variable_value, base_package, backtrace
|
316
|
+
)
|
317
|
+
return if File.exists?(variable_value) || File.symlink?(variable_value)
|
281
318
|
|
282
|
-
|
283
|
-
|
319
|
+
raise_repository_error(
|
320
|
+
%Q<In #{base_package}, the #{variable_name} variable points to a path that does not exist ("#{variable_value}", after expansion).>,
|
321
|
+
backtrace,
|
322
|
+
base_package
|
323
|
+
)
|
324
|
+
end
|
325
|
+
|
326
|
+
def derive_retrieve_destination(variable_name, variable_value, base_package)
|
327
|
+
retrieve_path =
|
328
|
+
get_retrieve_path_with_substitution(variable_name, base_package)
|
284
329
|
|
285
|
-
|
286
|
-
|
287
|
-
|
330
|
+
# A '//' in the variable value tells us to preserve path
|
331
|
+
# information after the '//' when doing a retrieve.
|
332
|
+
if variable_value.include? '//'
|
333
|
+
preserved_path = variable_value.split('//').last
|
288
334
|
|
289
|
-
return
|
335
|
+
return File.join(retrieve_path, preserved_path)
|
290
336
|
end
|
291
337
|
|
292
|
-
|
293
|
-
return
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
)
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
338
|
+
if File.directory?(variable_value)
|
339
|
+
return retrieve_path
|
340
|
+
end
|
341
|
+
|
342
|
+
return File.join(retrieve_path, File.basename(variable_value))
|
343
|
+
end
|
344
|
+
|
345
|
+
def expand_at_signs_in_path(path, base_package, backtrace)
|
346
|
+
expanded_path =
|
347
|
+
replace_at_signs_with_package_references(path, base_package)
|
348
|
+
check_for_bad_escape(expanded_path, path, base_package, backtrace)
|
349
|
+
|
350
|
+
return collapse_backslashes_for_escaped_at_signs(expanded_path)
|
351
|
+
end
|
352
|
+
|
353
|
+
def replace_at_signs_with_package_references(arg, base_package)
|
354
|
+
return arg.gsub(
|
355
|
+
%r<
|
356
|
+
(?: ^ | \G) # Zero-width anchor.
|
357
|
+
( [^\\@]* (?:\\{2})*) # An even number of leading backslashes
|
358
|
+
\@ # The package indicator
|
359
|
+
>x
|
360
|
+
) do |match|
|
361
|
+
backslashes = $1 || ''
|
362
|
+
backslashes + base_package.directory
|
309
363
|
end
|
364
|
+
end
|
365
|
+
|
366
|
+
def expand_command_line_argument(arg, backtrace, package)
|
367
|
+
package_substituted = expand_named_package_references(arg, backtrace)
|
368
|
+
check_for_bad_escape(package_substituted, arg, package, backtrace)
|
310
369
|
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
370
|
+
return collapse_backslashes_for_escaped_at_signs(package_substituted)
|
371
|
+
end
|
372
|
+
|
373
|
+
def expand_named_package_references(arg, backtrace)
|
374
|
+
return arg.gsub(
|
375
|
+
# TODO: Refactor package name regex into PackageDescriptor constant.
|
376
|
+
%r<
|
377
|
+
(?: ^ | \G) # Zero-width anchor.
|
378
|
+
( [^\\@]* (?:\\{2})*) # An even number of leading backslashes
|
379
|
+
\@ # The package indicator
|
380
|
+
( [a-zA-Z0-9_.-]+ ) # Package name
|
318
381
|
>x
|
319
|
-
|
320
|
-
|
382
|
+
) do |match|
|
383
|
+
backslashes = $1 || ''
|
384
|
+
package_name = $2
|
385
|
+
package = get_package(package_name)
|
386
|
+
if package.nil?
|
387
|
+
raise_repository_error(
|
388
|
+
%Q<Command-line referenced the "#{package_name}" package, which has not been referenced by any other package, so there's nothing to substitute with.>,
|
389
|
+
backtrace,
|
390
|
+
nil
|
321
391
|
)
|
322
392
|
end
|
323
|
-
|
324
|
-
return
|
393
|
+
backslashes + package.directory
|
325
394
|
end
|
395
|
+
end
|
326
396
|
|
327
|
-
|
328
|
-
|
329
|
-
|
397
|
+
# The value is expected to have had any @ substitution already done, but
|
398
|
+
# collapsing of escapes not done yet.
|
399
|
+
def check_for_bad_escape(substituted, original, package, backtrace)
|
400
|
+
if substituted =~ %r<
|
401
|
+
(?: ^ | [^\\]) # Start of line or non backslash
|
402
|
+
(?: \\{2})* # Even number of backslashes (including zero)
|
403
|
+
( \\ [^\\@] ) # A bad escape
|
404
|
+
>x
|
405
|
+
raise_repository_error(
|
406
|
+
%Q<Unknown escape "#{$1}" in "#{original}">, backtrace, package
|
407
|
+
)
|
330
408
|
end
|
409
|
+
|
410
|
+
return
|
411
|
+
end
|
412
|
+
|
413
|
+
# After @ substitution, we need to get rid of the backslashes in front of
|
414
|
+
# any escaped @ signs.
|
415
|
+
def collapse_backslashes_for_escaped_at_signs(string)
|
416
|
+
return string.gsub(%r< \\ ([\\@]) >x, '\1')
|
417
|
+
end
|
418
|
+
|
419
|
+
def get_retrieve_path_with_substitution(name, base_package)
|
420
|
+
retrieve_statement = @retrieves[name]
|
421
|
+
retrieve_statement.referenced(true)
|
422
|
+
|
423
|
+
return retrieve_statement.path.gsub(/ \[package\] /x, base_package.name)
|
424
|
+
end
|
425
|
+
|
426
|
+
def raise_repository_error(message, backtrace, package)
|
427
|
+
string_handle = StringIO.new
|
428
|
+
backtrace.dump(string_handle) if backtrace
|
429
|
+
package.backtrace.dump(string_handle) if package && package.backtrace
|
430
|
+
stacktrace = string_handle.string
|
431
|
+
|
432
|
+
raise Fig::RepositoryError.new(
|
433
|
+
message + ( stacktrace.empty? ? '' : "\n#{stacktrace}" )
|
434
|
+
)
|
331
435
|
end
|
332
436
|
end
|