fig 0.1.81 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/Changes +87 -0
  2. data/lib/fig.rb +1 -1
  3. data/lib/fig/command.rb +5 -0
  4. data/lib/fig/command/action/dump_package_definition_for_command_line.rb +62 -0
  5. data/lib/fig/command/action/dump_package_definition_parsed.rb +19 -2
  6. data/lib/fig/command/action/list_local.rb +9 -1
  7. data/lib/fig/command/action/list_remote.rb +9 -1
  8. data/lib/fig/command/action/role/list_variables_in_a_tree.rb +1 -1
  9. data/lib/fig/command/action/run_command_line.rb +1 -1
  10. data/lib/fig/command/action/run_command_statement.rb +4 -2
  11. data/lib/fig/command/options.rb +50 -18
  12. data/lib/fig/command/options/parser.rb +16 -15
  13. data/lib/fig/command/package_applier.rb +5 -3
  14. data/lib/fig/grammar/v0.rb +287 -289
  15. data/lib/fig/grammar/v0.treetop +66 -42
  16. data/lib/fig/grammar/v1.rb +629 -533
  17. data/lib/fig/grammar/v1.treetop +102 -39
  18. data/lib/fig/grammar_monkey_patches.rb +21 -0
  19. data/lib/fig/operating_system.rb +53 -36
  20. data/lib/fig/package_descriptor.rb +1 -12
  21. data/lib/fig/parser.rb +8 -33
  22. data/lib/fig/parser_package_build_state.rb +92 -31
  23. data/lib/fig/repository_package_publisher.rb +2 -2
  24. data/lib/fig/runtime_environment.rb +54 -120
  25. data/lib/fig/statement.rb +6 -6
  26. data/lib/fig/statement/asset.rb +1 -13
  27. data/lib/fig/statement/command.rb +47 -0
  28. data/lib/fig/statement/environment_variable.rb +64 -3
  29. data/lib/fig/statement/grammar_version.rb +4 -0
  30. data/lib/fig/statement/include.rb +4 -0
  31. data/lib/fig/statement/override.rb +4 -0
  32. data/lib/fig/statement/path.rb +40 -16
  33. data/lib/fig/statement/retrieve.rb +61 -5
  34. data/lib/fig/statement/set.rb +16 -19
  35. data/lib/fig/string_tokenizer.rb +63 -25
  36. data/lib/fig/tokenized_string.rb +31 -5
  37. data/lib/fig/tokenized_string/plain_segment.rb +32 -2
  38. data/lib/fig/tokenized_string/token.rb +12 -0
  39. data/lib/fig/unparser.rb +27 -12
  40. data/lib/fig/unparser/v0.rb +4 -5
  41. data/lib/fig/unparser/v1.rb +43 -6
  42. data/lib/fig/url.rb +13 -0
  43. 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
- attr_reader :descriptor
19
- attr_reader :source_description
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
- path_node.text_value
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, value = statement_class.parse_name_value(value_node.text_value) {
167
- description = statement_class.const_get(:ARGUMENT_DESCRIPTION)
168
- raise Fig::PackageParseError.new(
169
- %Q<Invalid #{keyword_node.text_value} statement: "#{value_node.text_value}" #{description}#{node_location_description(value_node)}>
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 new_command_statement(keyword_node, command_node)
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
- command_node.value.text_value
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.debug?
117
- explanations.each {|explanation| Fig::Logging.debug explanation}
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.var
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 execute_command_line(base_package, base_config, descriptor, command_line)
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 do
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 execute_config(
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
- execute_command(command_statement, extra_arguments, package, &block)
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
- value = statement.value
214
+ tokenized_value = statement.tokenized_value
215
+ escaped_value = tokenized_value.to_escaped_string
217
216
  expanded_message =
218
- expanded_value == value ? '' \
219
- : %Q< (expanded from "#{value}")>
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
- value = statement.value
237
+ tokenized_value = statement.tokenized_value
238
+ escaped_value = tokenized_value.to_escaped_string
238
239
  expanded_message =
239
- expanded_value == value ? '' \
240
- : %Q< ("#{value}" expanded to "#{expanded_value}")>
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 execute_command(command_statement, extra_arguments, package)
327
- @variables.with_environment do
328
- command =
329
- expand_command_line_argument(
330
- [command_statement.command, extra_arguments].flatten.join(' '),
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
- yield command
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
- return statement.value unless package && package.name
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 expand_at_signs_in_path(path, package, backtrace)
403
- expanded_path =
404
- replace_at_signs_with_package_references(path, package)
405
- check_for_bad_escape(expanded_path, path, package, backtrace)
406
-
407
- return collapse_backslashes_for_escaped_at_signs(expanded_path)
408
- end
409
-
410
- def replace_at_signs_with_package_references(argument, package)
411
- return argument.gsub(
412
- %r<
413
- (?: ^ | \G) # Zero-width anchor.
414
- ( [^\\@]* ) # A bunch of not-slashes-or-at-signs
415
- ( \\* ) # Any leading backslashes
416
- \@ # The package indicator
417
- >x
418
- ) do |match|
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
- return "#{frontmatter}#{backslashes}@"
479
- end
425
+ if package && package.directory
426
+ next package.directory
427
+ end
480
428
 
481
- # The value is expected to have had any @ substitution already done, but
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.path.gsub(/ \[package\] /x, package.name)
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)