fig 0.1.81 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Changes +87 -0
- data/lib/fig.rb +1 -1
- data/lib/fig/command.rb +5 -0
- data/lib/fig/command/action/dump_package_definition_for_command_line.rb +62 -0
- data/lib/fig/command/action/dump_package_definition_parsed.rb +19 -2
- data/lib/fig/command/action/list_local.rb +9 -1
- data/lib/fig/command/action/list_remote.rb +9 -1
- data/lib/fig/command/action/role/list_variables_in_a_tree.rb +1 -1
- data/lib/fig/command/action/run_command_line.rb +1 -1
- data/lib/fig/command/action/run_command_statement.rb +4 -2
- data/lib/fig/command/options.rb +50 -18
- data/lib/fig/command/options/parser.rb +16 -15
- data/lib/fig/command/package_applier.rb +5 -3
- data/lib/fig/grammar/v0.rb +287 -289
- data/lib/fig/grammar/v0.treetop +66 -42
- data/lib/fig/grammar/v1.rb +629 -533
- data/lib/fig/grammar/v1.treetop +102 -39
- data/lib/fig/grammar_monkey_patches.rb +21 -0
- data/lib/fig/operating_system.rb +53 -36
- data/lib/fig/package_descriptor.rb +1 -12
- data/lib/fig/parser.rb +8 -33
- data/lib/fig/parser_package_build_state.rb +92 -31
- data/lib/fig/repository_package_publisher.rb +2 -2
- data/lib/fig/runtime_environment.rb +54 -120
- data/lib/fig/statement.rb +6 -6
- data/lib/fig/statement/asset.rb +1 -13
- data/lib/fig/statement/command.rb +47 -0
- data/lib/fig/statement/environment_variable.rb +64 -3
- data/lib/fig/statement/grammar_version.rb +4 -0
- data/lib/fig/statement/include.rb +4 -0
- data/lib/fig/statement/override.rb +4 -0
- data/lib/fig/statement/path.rb +40 -16
- data/lib/fig/statement/retrieve.rb +61 -5
- data/lib/fig/statement/set.rb +16 -19
- data/lib/fig/string_tokenizer.rb +63 -25
- data/lib/fig/tokenized_string.rb +31 -5
- data/lib/fig/tokenized_string/plain_segment.rb +32 -2
- data/lib/fig/tokenized_string/token.rb +12 -0
- data/lib/fig/unparser.rb +27 -12
- data/lib/fig/unparser/v0.rb +4 -5
- data/lib/fig/unparser/v1.rb +43 -6
- data/lib/fig/url.rb +13 -0
- metadata +44 -42
@@ -14,11 +14,10 @@ require 'fig/statement/set'
|
|
14
14
|
|
15
15
|
module Fig; end
|
16
16
|
|
17
|
+
# The state of a Package while it is being built by a Parser.
|
17
18
|
class Fig::ParserPackageBuildState
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
def initialize(descriptor, source_description)
|
19
|
+
def initialize(grammar_version, descriptor, source_description)
|
20
|
+
@grammar_version = grammar_version
|
22
21
|
@descriptor = descriptor
|
23
22
|
@source_description = source_description
|
24
23
|
end
|
@@ -40,7 +39,7 @@ class Fig::ParserPackageBuildState
|
|
40
39
|
location = node_location(node)
|
41
40
|
|
42
41
|
return Fig::Statement.position_description(
|
43
|
-
location[0], location[1], source_description
|
42
|
+
location[0], location[1], @source_description
|
44
43
|
)
|
45
44
|
end
|
46
45
|
|
@@ -64,8 +63,8 @@ class Fig::ParserPackageBuildState
|
|
64
63
|
end
|
65
64
|
|
66
65
|
return Fig::Package.new(
|
67
|
-
descriptor.name,
|
68
|
-
descriptor.version,
|
66
|
+
@descriptor.name,
|
67
|
+
@descriptor.version,
|
69
68
|
directory,
|
70
69
|
statement_objects
|
71
70
|
)
|
@@ -74,7 +73,7 @@ class Fig::ParserPackageBuildState
|
|
74
73
|
def new_grammar_version_statement(keyword_node, version_node)
|
75
74
|
return Fig::Statement::GrammarVersion.new(
|
76
75
|
node_location(keyword_node),
|
77
|
-
source_description,
|
76
|
+
@source_description,
|
78
77
|
version_node.text_value.to_i
|
79
78
|
)
|
80
79
|
end
|
@@ -94,26 +93,29 @@ class Fig::ParserPackageBuildState
|
|
94
93
|
location = tokenized_location.to_expanded_string
|
95
94
|
need_to_glob = ! tokenized_location.single_quoted?
|
96
95
|
return statement_class.new(
|
97
|
-
node_location(keyword_node), source_description, location, need_to_glob
|
96
|
+
node_location(keyword_node), @source_description, location, need_to_glob
|
98
97
|
)
|
99
98
|
end
|
100
99
|
|
101
100
|
def new_retrieve_statement(keyword_node, variable_name_node, path_node)
|
101
|
+
tokenized_path =
|
102
|
+
Fig::Statement::Retrieve.tokenize_path(path_node.text_value) do
|
103
|
+
|error_description|
|
104
|
+
|
105
|
+
raise_invalid_value_parse_error(
|
106
|
+
keyword_node, path_node, 'path', error_description
|
107
|
+
)
|
108
|
+
end
|
109
|
+
|
102
110
|
return Fig::Statement::Retrieve.new(
|
103
111
|
node_location(keyword_node),
|
104
|
-
source_description,
|
112
|
+
@source_description,
|
105
113
|
variable_name_node.text_value,
|
106
|
-
|
114
|
+
tokenized_path
|
107
115
|
)
|
108
116
|
end
|
109
117
|
|
110
118
|
def new_configuration_statement(keyword_node, name_node, statements)
|
111
|
-
if Fig::Parser.strict_keyword? name_node.text_value
|
112
|
-
raise_invalid_value_parse_error(
|
113
|
-
keyword_node, name_node, 'name', 'is a keyword.'
|
114
|
-
)
|
115
|
-
end
|
116
|
-
|
117
119
|
statement_objects = statements.elements.map do
|
118
120
|
|statement|
|
119
121
|
|
@@ -122,7 +124,7 @@ class Fig::ParserPackageBuildState
|
|
122
124
|
|
123
125
|
return Fig::Statement::Configuration.new(
|
124
126
|
node_location(keyword_node),
|
125
|
-
source_description,
|
127
|
+
@source_description,
|
126
128
|
name_node.text_value,
|
127
129
|
statement_objects
|
128
130
|
)
|
@@ -138,9 +140,9 @@ class Fig::ParserPackageBuildState
|
|
138
140
|
|
139
141
|
return Fig::Statement::Include.new(
|
140
142
|
node_location(keyword_node),
|
141
|
-
source_description,
|
143
|
+
@source_description,
|
142
144
|
include_descriptor,
|
143
|
-
descriptor
|
145
|
+
@descriptor
|
144
146
|
)
|
145
147
|
end
|
146
148
|
|
@@ -154,7 +156,7 @@ class Fig::ParserPackageBuildState
|
|
154
156
|
|
155
157
|
return Fig::Statement::Override.new(
|
156
158
|
node_location(keyword_node),
|
157
|
-
source_description,
|
159
|
+
@source_description,
|
158
160
|
override_descriptor.name,
|
159
161
|
override_descriptor.version
|
160
162
|
)
|
@@ -163,25 +165,55 @@ class Fig::ParserPackageBuildState
|
|
163
165
|
def new_environment_variable_statement(
|
164
166
|
statement_class, keyword_node, value_node
|
165
167
|
)
|
166
|
-
name
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
168
|
+
name = value = nil
|
169
|
+
|
170
|
+
if @grammar_version == 0
|
171
|
+
name, value = statement_class.parse_v0_name_value(value_node.text_value) {
|
172
|
+
|description|
|
173
|
+
raise_invalid_statement_parse_error(
|
174
|
+
keyword_node, value_node, description
|
175
|
+
)
|
176
|
+
}
|
177
|
+
else
|
178
|
+
name, value = statement_class.parse_name_value(value_node.text_value) {
|
179
|
+
|description|
|
180
|
+
raise_invalid_statement_parse_error(
|
181
|
+
keyword_node, value_node, description
|
182
|
+
)
|
183
|
+
}
|
184
|
+
end
|
185
|
+
|
172
186
|
return statement_class.new(
|
173
|
-
node_location(keyword_node), source_description, name, value
|
187
|
+
node_location(keyword_node), @source_description, name, value
|
174
188
|
)
|
175
189
|
end
|
176
190
|
|
177
|
-
def
|
191
|
+
def new_v0_command_statement(keyword_node, command_line_node)
|
192
|
+
tokenized_command =
|
193
|
+
Fig::Statement::Command.validate_and_process_escapes_in_argument(
|
194
|
+
command_line_node.text_value
|
195
|
+
) {
|
196
|
+
|description|
|
197
|
+
raise_invalid_statement_parse_error(
|
198
|
+
keyword_node, command_line_node, description
|
199
|
+
)
|
200
|
+
}
|
201
|
+
|
202
|
+
return Fig::Statement::Command.new(
|
203
|
+
node_location(keyword_node), @source_description, [tokenized_command]
|
204
|
+
)
|
205
|
+
end
|
206
|
+
|
207
|
+
def new_v1_command_statement(keyword_node, command_line)
|
178
208
|
return Fig::Statement::Command.new(
|
179
209
|
node_location(keyword_node),
|
180
|
-
source_description,
|
181
|
-
|
210
|
+
@source_description,
|
211
|
+
tokenize_v1_command_line(keyword_node, command_line)
|
182
212
|
)
|
183
213
|
end
|
184
214
|
|
215
|
+
private
|
216
|
+
|
185
217
|
def raise_invalid_value_parse_error(
|
186
218
|
keyword_node, value_node, value_name, description
|
187
219
|
)
|
@@ -189,4 +221,33 @@ class Fig::ParserPackageBuildState
|
|
189
221
|
%Q<Invalid #{value_name} for #{keyword_node.text_value} statement: "#{value_node.text_value}" #{description}#{node_location_description(value_node)}>
|
190
222
|
)
|
191
223
|
end
|
224
|
+
|
225
|
+
def raise_invalid_statement_parse_error(keyword_node, value_node, description)
|
226
|
+
raise Fig::PackageParseError.new(
|
227
|
+
%Q<Invalid #{keyword_node.text_value} statement: "#{value_node.text_value}" #{description}#{node_location_description(value_node)}>
|
228
|
+
)
|
229
|
+
end
|
230
|
+
|
231
|
+
def tokenize_v1_command_line(keyword_node, command_line)
|
232
|
+
tokenized_command_line = []
|
233
|
+
|
234
|
+
command_line.each do
|
235
|
+
|argument_node|
|
236
|
+
|
237
|
+
unparsed = argument_node.text_value
|
238
|
+
next if unparsed.empty?
|
239
|
+
|
240
|
+
tokenized_command_line <<
|
241
|
+
Fig::Statement::Command.validate_and_process_escapes_in_argument(
|
242
|
+
unparsed
|
243
|
+
) {
|
244
|
+
|description|
|
245
|
+
raise_invalid_statement_parse_error(
|
246
|
+
keyword_node, argument_node, description
|
247
|
+
)
|
248
|
+
}
|
249
|
+
end
|
250
|
+
|
251
|
+
return tokenized_command_line
|
252
|
+
end
|
192
253
|
end
|
@@ -113,8 +113,8 @@ class Fig::RepositoryPackagePublisher
|
|
113
113
|
add_unparsed_text()
|
114
114
|
|
115
115
|
file_content, explanations = @text_assembler.assemble_package_definition()
|
116
|
-
if Fig::Logging.
|
117
|
-
explanations.each {|explanation| Fig::Logging.
|
116
|
+
if Fig::Logging.info?
|
117
|
+
explanations.each {|explanation| Fig::Logging.info explanation}
|
118
118
|
end
|
119
119
|
|
120
120
|
begin
|
@@ -42,7 +42,7 @@ class Fig::RuntimeEnvironment
|
|
42
42
|
# Indicates that the values from a particular environment variable path
|
43
43
|
# should be copied to a local directory.
|
44
44
|
def add_retrieve(retrieve_statement)
|
45
|
-
name = retrieve_statement.
|
45
|
+
name = retrieve_statement.variable
|
46
46
|
if @retrieves.has_key?(name)
|
47
47
|
Fig::Logging.warn \
|
48
48
|
%q<About to overwrite "#{name}" retrieve path of "#{@retrieves[name].path}" with "#{retrieve_statement.path}".>
|
@@ -99,7 +99,7 @@ class Fig::RuntimeEnvironment
|
|
99
99
|
return
|
100
100
|
end
|
101
101
|
|
102
|
-
def
|
102
|
+
def expand_command_line(base_package, base_config, descriptor, command_line)
|
103
103
|
package, * =
|
104
104
|
determine_package_for_execution(base_package, base_config, descriptor)
|
105
105
|
|
@@ -108,14 +108,12 @@ class Fig::RuntimeEnvironment
|
|
108
108
|
|argument| expand_command_line_argument(argument, base_package)
|
109
109
|
}
|
110
110
|
|
111
|
-
@variables.with_environment
|
112
|
-
yield expanded_command_line
|
113
|
-
end
|
111
|
+
@variables.with_environment { yield expanded_command_line }
|
114
112
|
|
115
113
|
return
|
116
114
|
end
|
117
115
|
|
118
|
-
def
|
116
|
+
def expand_command_statement_from_config(
|
119
117
|
base_package, base_config, descriptor, extra_arguments, &block
|
120
118
|
)
|
121
119
|
package, config_name =
|
@@ -123,7 +121,7 @@ class Fig::RuntimeEnvironment
|
|
123
121
|
|
124
122
|
command_statement = package[config_name].command_statement
|
125
123
|
if command_statement
|
126
|
-
|
124
|
+
expand_command(command_statement, extra_arguments, package, &block)
|
127
125
|
else
|
128
126
|
raise Fig::UserInputError.new(
|
129
127
|
%Q<The "#{package.to_s}" package with the "#{config_name}" configuration does not contain a command.>
|
@@ -213,10 +211,12 @@ class Fig::RuntimeEnvironment
|
|
213
211
|
@variables[name] = expanded_value
|
214
212
|
|
215
213
|
if Fig::Logging.debug?
|
216
|
-
|
214
|
+
tokenized_value = statement.tokenized_value
|
215
|
+
escaped_value = tokenized_value.to_escaped_string
|
217
216
|
expanded_message =
|
218
|
-
expanded_value ==
|
219
|
-
|
217
|
+
expanded_value == escaped_value \
|
218
|
+
? '' \
|
219
|
+
: %Q< (expanded from "#{escaped_value}")>
|
220
220
|
|
221
221
|
Fig::Logging.debug(
|
222
222
|
%Q<Set #{name} to "#{expanded_value}"#{expanded_message}.>
|
@@ -234,10 +234,12 @@ class Fig::RuntimeEnvironment
|
|
234
234
|
@variables.prepend_variable(name, expanded_value)
|
235
235
|
|
236
236
|
if Fig::Logging.debug?
|
237
|
-
|
237
|
+
tokenized_value = statement.tokenized_value
|
238
|
+
escaped_value = tokenized_value.to_escaped_string
|
238
239
|
expanded_message =
|
239
|
-
expanded_value ==
|
240
|
-
|
240
|
+
expanded_value == escaped_value \
|
241
|
+
? '' \
|
242
|
+
: %Q< ("#{escaped_value}" expanded to "#{expanded_value}")>
|
241
243
|
|
242
244
|
Fig::Logging.debug(
|
243
245
|
%Q<Prepending to #{name} resulted in "#{@variables[name]}"#{expanded_message}.>
|
@@ -323,27 +325,29 @@ class Fig::RuntimeEnvironment
|
|
323
325
|
return package.primary_config_name || Fig::Package::DEFAULT_CONFIG
|
324
326
|
end
|
325
327
|
|
326
|
-
def
|
327
|
-
|
328
|
-
command
|
329
|
-
expand_command_line_argument(
|
330
|
-
|
331
|
-
package
|
332
|
-
)
|
328
|
+
def expand_command(command_statement, extra_arguments, package)
|
329
|
+
expanded_command_line =
|
330
|
+
[ command_statement.command, extra_arguments ].flatten.map {
|
331
|
+
|argument| expand_command_line_argument(argument, package)
|
332
|
+
}
|
333
333
|
|
334
|
-
|
334
|
+
if command_statement.command.size == 1
|
335
|
+
expanded_command_line = [ expanded_command_line.join(' ') ]
|
335
336
|
end
|
336
337
|
|
338
|
+
@variables.with_environment { yield expanded_command_line }
|
339
|
+
|
337
340
|
return
|
338
341
|
end
|
339
342
|
|
340
343
|
def expand_variable_as_path_and_process_retrieves(
|
341
344
|
statement, package, backtrace
|
342
345
|
)
|
343
|
-
|
346
|
+
tokenized_value = statement.tokenized_value
|
347
|
+
return tokenized_value.to_expanded_string { '@' } \
|
348
|
+
unless package && package.name
|
344
349
|
|
345
|
-
variable_value =
|
346
|
-
expand_at_signs_in_path(statement.value, package, backtrace)
|
350
|
+
variable_value = tokenized_value.to_expanded_string { package.directory }
|
347
351
|
|
348
352
|
return variable_value if not @retrieves.member?(statement.name)
|
349
353
|
|
@@ -399,112 +403,42 @@ class Fig::RuntimeEnvironment
|
|
399
403
|
return File.join(retrieve_path, File.basename(variable_value))
|
400
404
|
end
|
401
405
|
|
402
|
-
def
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
frontmatter, backslashes = $1, $2
|
420
|
-
|
421
|
-
replacement = backslashes.length % 2 == 1 ? '@' : package.directory
|
422
|
-
|
423
|
-
"#{frontmatter}#{backslashes}#{replacement}"
|
424
|
-
end
|
425
|
-
end
|
426
|
-
|
427
|
-
def expand_command_line_argument(argument, package)
|
428
|
-
package_substituted = expand_package_references(argument, package)
|
429
|
-
check_for_bad_escape(package_substituted, argument, package, nil)
|
430
|
-
|
431
|
-
return collapse_backslashes_for_escaped_at_signs(package_substituted)
|
432
|
-
end
|
433
|
-
|
434
|
-
def expand_package_references(argument, package)
|
435
|
-
return argument.gsub(
|
436
|
-
# TODO: Refactor package name regex into PackageDescriptor constant.
|
437
|
-
%r<
|
438
|
-
(?: ^ | \G) # Zero-width anchor.
|
439
|
-
( [^\\@]* ) # A bunch of not-slashes-or-at-signs
|
440
|
-
( \\* ) # Any leading backslashes
|
441
|
-
\@ # The package indicator
|
442
|
-
( [a-zA-Z0-9_.-]* ) # Package name
|
443
|
-
>x
|
444
|
-
) do |match|
|
445
|
-
frontmatter, backslashes, package_name = $1, $2, $3
|
446
|
-
|
447
|
-
expand_package_reference(
|
448
|
-
frontmatter, backslashes, package_name, package
|
449
|
-
)
|
450
|
-
end
|
451
|
-
end
|
452
|
-
|
453
|
-
def expand_package_reference(
|
454
|
-
frontmatter, backslashes, package_name, starting_package
|
455
|
-
)
|
456
|
-
if backslashes.length % 2 == 1
|
457
|
-
return "#{frontmatter}#{backslashes}@#{package_name}"
|
458
|
-
end
|
459
|
-
|
460
|
-
package = nil
|
461
|
-
if ! package_name.empty?
|
462
|
-
package = get_package(package_name)
|
463
|
-
if package.nil?
|
464
|
-
raise_repository_error(
|
465
|
-
%Q<Command-line referenced the "#{package_name}" package, which has not been referenced by any other package, so there's nothing to substitute with.>,
|
466
|
-
nil,
|
467
|
-
nil
|
468
|
-
)
|
406
|
+
def expand_command_line_argument(argument, starting_package)
|
407
|
+
return argument.to_expanded_string() do
|
408
|
+
|token|
|
409
|
+
|
410
|
+
package_name = token.raw_value
|
411
|
+
package = nil
|
412
|
+
if package_name.empty?
|
413
|
+
package = starting_package
|
414
|
+
else
|
415
|
+
package = get_package(package_name)
|
416
|
+
if package.nil?
|
417
|
+
raise_repository_error(
|
418
|
+
%Q<Command-line referenced the "#{package_name}" package, which has not been referenced by any other package, so there's nothing to substitute with.>,
|
419
|
+
nil,
|
420
|
+
nil
|
421
|
+
)
|
422
|
+
end
|
469
423
|
end
|
470
|
-
else
|
471
|
-
package = starting_package
|
472
|
-
end
|
473
|
-
|
474
|
-
if package && package.directory
|
475
|
-
return "#{frontmatter}#{backslashes}#{package.directory}"
|
476
|
-
end
|
477
424
|
|
478
|
-
|
479
|
-
|
425
|
+
if package && package.directory
|
426
|
+
next package.directory
|
427
|
+
end
|
480
428
|
|
481
|
-
|
482
|
-
# collapsing of escapes not done yet.
|
483
|
-
def check_for_bad_escape(substituted, original, package, backtrace)
|
484
|
-
if substituted =~ %r<
|
485
|
-
(?: ^ | [^\\]) # Start of line or non backslash
|
486
|
-
(?: \\{2})* # Even number of backslashes (including zero)
|
487
|
-
( \\ [^\\@] ) # A bad escape
|
488
|
-
>x
|
489
|
-
raise_repository_error(
|
490
|
-
%Q<Unknown escape "#{$1}" in "#{original}">, backtrace, package
|
491
|
-
)
|
429
|
+
next '@'
|
492
430
|
end
|
493
|
-
|
494
|
-
return
|
495
|
-
end
|
496
|
-
|
497
|
-
# After @ substitution, we need to get rid of the backslashes in front of
|
498
|
-
# any escaped @ signs.
|
499
|
-
def collapse_backslashes_for_escaped_at_signs(string)
|
500
|
-
return string.gsub(%r< \\ ([\\@]) >x, '\1')
|
501
431
|
end
|
502
432
|
|
503
433
|
def get_retrieve_path_with_substitution(variable_name, package)
|
504
434
|
retrieve_statement = @retrieves[variable_name]
|
505
435
|
retrieve_statement.referenced(true)
|
506
436
|
|
507
|
-
return retrieve_statement.
|
437
|
+
return retrieve_statement.tokenized_path.to_expanded_string() do
|
438
|
+
|token|
|
439
|
+
|
440
|
+
package.name
|
441
|
+
end
|
508
442
|
end
|
509
443
|
|
510
444
|
def raise_repository_error(message, backtrace, package)
|