fig 0.1.77 → 0.1.79

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.
Files changed (55) hide show
  1. data/Changes +58 -1
  2. data/bin/fig +1 -1
  3. data/lib/fig.rb +1 -1
  4. data/lib/fig/command.rb +3 -3
  5. data/lib/fig/command/action/dump_package_definition_parsed.rb +5 -4
  6. data/lib/fig/command/action/list_variables/all_configs.rb +2 -5
  7. data/lib/fig/command/action/publish_local.rb +1 -1
  8. data/lib/fig/command/action/role/list_variables_in_a_tree.rb +2 -5
  9. data/lib/fig/command/action/run_command_line.rb +10 -3
  10. data/lib/fig/command/action/run_command_statement.rb +1 -1
  11. data/lib/fig/command/options.rb +8 -7
  12. data/lib/fig/command/options/parser.rb +1 -1
  13. data/lib/fig/environment_variables/case_insensitive.rb +1 -1
  14. data/lib/fig/environment_variables/case_sensitive.rb +1 -1
  15. data/lib/fig/figrc.rb +10 -10
  16. data/lib/fig/{not_found_error.rb → file_not_found_error.rb} +1 -1
  17. data/lib/fig/grammar/v0.rb +174 -173
  18. data/lib/fig/grammar/v0.treetop +27 -21
  19. data/lib/fig/grammar/v1.rb +477 -171
  20. data/lib/fig/grammar/v1.treetop +34 -22
  21. data/lib/fig/operating_system.rb +139 -60
  22. data/lib/fig/package.rb +8 -4
  23. data/lib/fig/package_definition_text_assembler.rb +31 -23
  24. data/lib/fig/parser.rb +3 -5
  25. data/lib/fig/parser_package_build_state.rb +15 -14
  26. data/lib/fig/repository.rb +41 -28
  27. data/lib/fig/repository_package_publisher.rb +20 -25
  28. data/lib/fig/runtime_environment.rb +136 -87
  29. data/lib/fig/statement.rb +15 -116
  30. data/lib/fig/statement/archive.rb +6 -4
  31. data/lib/fig/statement/asset.rb +50 -35
  32. data/lib/fig/statement/command.rb +6 -2
  33. data/lib/fig/statement/configuration.rb +10 -2
  34. data/lib/fig/statement/environment_variable.rb +35 -0
  35. data/lib/fig/statement/grammar_version.rb +6 -2
  36. data/lib/fig/statement/include.rb +6 -2
  37. data/lib/fig/statement/override.rb +6 -2
  38. data/lib/fig/statement/path.rb +7 -8
  39. data/lib/fig/statement/resource.rb +7 -3
  40. data/lib/fig/statement/retrieve.rb +10 -2
  41. data/lib/fig/statement/set.rb +7 -8
  42. data/lib/fig/string_tokenizer.rb +195 -0
  43. data/lib/fig/tokenized_string.rb +22 -0
  44. data/lib/fig/tokenized_string/plain_segment.rb +24 -0
  45. data/lib/fig/tokenized_string/token.rb +18 -0
  46. data/lib/fig/unparser.rb +84 -1
  47. data/lib/fig/unparser/v0.rb +4 -0
  48. data/lib/fig/unparser/v1.rb +7 -7
  49. data/lib/fig/url.rb +12 -1
  50. data/lib/fig/{url_access_error.rb → url_access_disallowed_error.rb} +2 -2
  51. metadata +129 -128
  52. data/lib/fig/grammar/v0_asset_location.rb +0 -162
  53. data/lib/fig/grammar/v0_ish.rb +0 -1356
  54. data/lib/fig/grammar/v1_asset_location.rb +0 -162
  55. data/lib/fig/grammar/v2.rb +0 -1478
@@ -71,12 +71,16 @@ class Fig::Package
71
71
  return @statements.select { |statement| statement.is_a?(Fig::Statement::Retrieve) }
72
72
  end
73
73
 
74
- def archive_urls
75
- return @statements.select{|s| s.is_a?(Fig::Statement::Archive)}.map{|s| s.url}
74
+ def archive_locations
75
+ return @statements.
76
+ select{|s| s.is_a?(Fig::Statement::Archive)}.
77
+ map{|s| s.location}
76
78
  end
77
79
 
78
- def resource_urls
79
- return @statements.select{|s| s.is_a?(Fig::Statement::Resource)}.map{|s|s.url}
80
+ def resource_locations
81
+ return @statements.
82
+ select{|s| s.is_a?(Fig::Statement::Resource)}.
83
+ map{|s| s.location}
80
84
  end
81
85
 
82
86
  def applied_config_names()
@@ -1,3 +1,5 @@
1
+ require 'fig/statement/grammar_version'
2
+ require 'fig/unparser'
1
3
  require 'fig/unparser/v0'
2
4
  require 'fig/unparser/v1'
3
5
 
@@ -8,7 +10,10 @@ class Fig::PackageDefinitionTextAssembler
8
10
  attr_reader :input_statements
9
11
  attr_reader :output_statements
10
12
 
11
- def initialize()
13
+ def initialize(emit_as_input_or_to_be_published_values)
14
+ @emit_as_input_or_to_be_published_values =
15
+ emit_as_input_or_to_be_published_values
16
+
12
17
  @input_statements = []
13
18
  @output_statements = []
14
19
  @header_text = []
@@ -30,6 +35,9 @@ class Fig::PackageDefinitionTextAssembler
30
35
  @output_statements << statements
31
36
  @output_statements.flatten!
32
37
 
38
+ # Version gets determined by other statements, not by existing grammar.
39
+ @output_statements.reject! { |s| s.is_a? Fig::Statement::GrammarVersion }
40
+
33
41
  return
34
42
  end
35
43
 
@@ -52,37 +60,37 @@ class Fig::PackageDefinitionTextAssembler
52
60
  end
53
61
 
54
62
  def assemble_package_definition()
63
+ unparsed_statements, explanations = unparse_statements()
55
64
  definition =
56
- [@header_text, unparse_statements(), @footer_text].flatten.join("\n")
65
+ [@header_text, unparsed_statements, @footer_text].flatten.join("\n")
57
66
  definition.gsub!(/\n{3,}/, "\n\n")
58
67
  definition.strip!
59
68
  definition << "\n"
60
69
 
61
- return definition
70
+ return definition, explanations
62
71
  end
63
72
 
64
73
  private
65
74
 
66
75
  def unparse_statements()
67
- versions = @output_statements.map {|s| s.minimum_grammar_version_required}
68
- version = versions.max || 0
69
-
70
- unparser_class = nil
71
- if version == 1
72
- unparser_class = Fig::Unparser::V1
73
- else
74
- unparser_class = Fig::Unparser::V0
75
- end
76
-
77
- unparser = unparser_class.new :emit_as_to_be_published
78
- text = unparser.unparse(@output_statements)
79
-
80
- # TODO: Until v1 grammar handling is done, ensure we don't emit anything
81
- # old fig versions cannot handle.
82
- if version != 0
83
- raise "Reached a point where something could not be represented by the current grammar. Bailing out.\n\nWould have attempted:\n#{text}"
84
- end
85
-
86
- return text
76
+ unparser_class, explanations = Fig::Unparser.class_for_statements(
77
+ @output_statements, @emit_as_input_or_to_be_published_values
78
+ )
79
+
80
+ grammar_statement =
81
+ Fig::Statement::GrammarVersion.new(
82
+ nil,
83
+ %Q<[synthetic statement created in #{__FILE__} line #{__LINE__}]>,
84
+ %q<Fake grammar version that shouldn't be used because the Unparser should determine what gets emitted.>
85
+ )
86
+
87
+ unparser = unparser_class.new @emit_as_input_or_to_be_published_values
88
+ text = unparser.unparse( [grammar_statement] + @output_statements )
89
+
90
+ explanations.unshift(
91
+ "Publishing using the #{unparser.grammar_description} grammar."
92
+ )
93
+
94
+ return text, explanations
87
95
  end
88
96
  end
@@ -8,7 +8,7 @@ require 'fig/package_parse_error'
8
8
  require 'fig/parser_package_build_state'
9
9
  require 'fig/statement'
10
10
  require 'fig/url'
11
- require 'fig/url_access_error'
11
+ require 'fig/url_access_disallowed_error'
12
12
  require 'fig/user_input_error'
13
13
 
14
14
  module Fig; end
@@ -82,9 +82,7 @@ class Fig::Parser
82
82
  return 0 if not statement
83
83
 
84
84
  version = statement.version
85
- # TODO: restore v1 grammar.
86
- # if version > 1
87
- if version > 0
85
+ if version > 1
88
86
  raise Fig::PackageParseError.new(
89
87
  %Q<Don't know how to parse grammar version #{version}#{statement.position_string()}.>
90
88
  )
@@ -198,7 +196,7 @@ class Fig::Parser
198
196
  end
199
197
  end
200
198
 
201
- raise Fig::URLAccessError.new(bad_urls, descriptor) if not bad_urls.empty?
199
+ raise Fig::URLAccessDisallowedError.new(bad_urls, descriptor) if not bad_urls.empty?
202
200
 
203
201
  return
204
202
  end
@@ -79,19 +79,22 @@ class Fig::ParserPackageBuildState
79
79
  )
80
80
  end
81
81
 
82
- def new_asset_statement(statement_class, keyword_node, url_node)
83
- url = url_node.text_value
82
+ def new_asset_statement(statement_class, keyword_node, location_node)
83
+ raw_location = location_node.text_value
84
84
 
85
- need_to_glob = statement_class.validate_and_process_escapes_in_url!(url) {
86
- |error_description|
85
+ tokenized_location =
86
+ statement_class.validate_and_process_escapes_in_location(raw_location) do
87
+ |error_description|
87
88
 
88
- raise_invalid_value_parse_error(
89
- keyword_node, url_node, 'URL/path', error_description
90
- )
91
- }
89
+ raise_invalid_value_parse_error(
90
+ keyword_node, location_node, 'URL/path', error_description
91
+ )
92
+ end
92
93
 
94
+ location = tokenized_location.to_expanded_string
95
+ need_to_glob = ! tokenized_location.single_quoted?
93
96
  return statement_class.new(
94
- node_location(keyword_node), source_description, url, need_to_glob
97
+ node_location(keyword_node), source_description, location, need_to_glob
95
98
  )
96
99
  end
97
100
 
@@ -161,11 +164,9 @@ class Fig::ParserPackageBuildState
161
164
  statement_class, keyword_node, value_node
162
165
  )
163
166
  name, value = statement_class.parse_name_value(value_node.text_value) {
164
- raise_invalid_value_parse_error(
165
- keyword_node,
166
- value_node,
167
- 'value',
168
- statement_class.const_get(:ARGUMENT_DESCRIPTION)
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)}>
169
170
  )
170
171
  }
171
172
  return statement_class.new(
@@ -6,8 +6,8 @@ require 'tmpdir'
6
6
 
7
7
  require 'fig'
8
8
  require 'fig/at_exit'
9
+ require 'fig/file_not_found_error'
9
10
  require 'fig/logging'
10
- require 'fig/not_found_error'
11
11
  require 'fig/package_cache'
12
12
  require 'fig/package_descriptor'
13
13
  require 'fig/parser'
@@ -212,11 +212,13 @@ class Fig::Repository
212
212
  if @remote_repository_version.nil?
213
213
  temp_dir = base_temp_dir()
214
214
  @operating_system.delete_and_recreate_directory(temp_dir)
215
- remote_version_file = "#{remote_repository_url()}/#{VERSION_FILE_NAME}"
215
+ remote_version_file = Fig::URL.append_path_components(
216
+ remote_repository_url(), [VERSION_FILE_NAME]
217
+ )
216
218
  local_version_file = File.join(temp_dir, "remote-#{VERSION_FILE_NAME}")
217
219
  begin
218
220
  @operating_system.download(remote_version_file, local_version_file)
219
- rescue Fig::NotFoundError
221
+ rescue Fig::FileNotFoundError
220
222
  # The download may create an empty file, so get rid of it.
221
223
  if File.exist?(local_version_file)
222
224
  File.unlink(local_version_file)
@@ -265,17 +267,13 @@ class Fig::Repository
265
267
  temp_dir = package_download_temp_dir(descriptor)
266
268
  begin
267
269
  install_package(descriptor, temp_dir)
268
- rescue Fig::NotFoundError => error
270
+ rescue Fig::FileNotFoundError => error
269
271
  Fig::Logging.fatal \
270
272
  "Package #{descriptor.to_string()} not found in remote repository. (Was looking for #{error.path}.)"
271
273
 
272
- delete_local_package(descriptor)
273
-
274
274
  raise Fig::RepositoryError.new
275
275
  rescue StandardError => exception
276
- Fig::Logging.fatal %Q<Install failed, cleaning up: #{exception}>
277
-
278
- delete_local_package(descriptor)
276
+ Fig::Logging.fatal %Q<Install failed: #{exception}>
279
277
 
280
278
  raise Fig::RepositoryError.new
281
279
  ensure
@@ -289,28 +287,43 @@ class Fig::Repository
289
287
  remote_fig_file = remote_fig_file_for_package(descriptor)
290
288
  local_dir = local_dir_for_package(descriptor)
291
289
  local_fig_file = fig_file_for_package_download(local_dir)
292
- return if not @operating_system.download(remote_fig_file, local_fig_file)
293
290
 
294
- @operating_system.delete_and_recreate_directory(temp_dir)
291
+ if @operating_system.path_up_to_date? remote_fig_file, local_fig_file
292
+ Fig::Logging.debug \
293
+ "Skipping update of #{descriptor.to_string} because it looks like #{local_fig_file} is up-to-date."
294
+ return
295
+ end
296
+
297
+ temp_fig_file = fig_file_for_package_download(temp_dir)
295
298
 
296
- temp_fig_file = fig_file_for_package_download(temp_dir)
299
+ FileUtils.rm_rf temp_dir
300
+ if File.exist? local_dir
301
+ FileUtils.mkdir_p File.dirname(temp_dir)
302
+ FileUtils.cp_r local_dir, temp_dir, :preserve => true
303
+ else
304
+ FileUtils.mkdir_p temp_dir
305
+ end
297
306
 
298
- @operating_system.download(remote_fig_file, temp_fig_file)
307
+ return if ! @operating_system.download(remote_fig_file, temp_fig_file)
299
308
 
300
309
  package = read_package_from_directory(temp_dir, descriptor)
301
310
 
302
- package.archive_urls.each do |archive_url|
303
- if not Fig::URL.is_url?(archive_url)
304
- archive_url = remote_dir_for_package(descriptor) + '/' + archive_url
311
+ remote_package_directory = remote_dir_for_package(descriptor)
312
+ package.archive_locations.each do |archive_location|
313
+ if not Fig::URL.is_url?(archive_location)
314
+ archive_location = Fig::URL.append_path_components(
315
+ remote_package_directory, [archive_location]
316
+ )
305
317
  end
306
- @operating_system.download_and_unpack_archive(archive_url, temp_dir)
318
+ @operating_system.download_and_unpack_archive(archive_location, temp_dir)
307
319
  end
308
- package.resource_urls.each do |resource_url|
309
- if not Fig::URL.is_url?(resource_url)
310
- resource_url =
311
- remote_dir_for_package(descriptor) + '/' + resource_url
320
+ package.resource_locations.each do |resource_location|
321
+ if not Fig::URL.is_url?(resource_location)
322
+ resource_location = Fig::URL.append_path_components(
323
+ remote_package_directory, [resource_location]
324
+ )
312
325
  end
313
- @operating_system.download_resource(resource_url, temp_dir)
326
+ @operating_system.download_resource(resource_location, temp_dir)
314
327
  end
315
328
 
316
329
  FileUtils.rm_rf(local_dir)
@@ -346,12 +359,10 @@ class Fig::Repository
346
359
  return package
347
360
  end
348
361
 
349
- def delete_local_package(descriptor)
350
- FileUtils.rm_rf(local_dir_for_package(descriptor))
351
- end
352
-
353
362
  def remote_fig_file_for_package(descriptor)
354
- "#{remote_dir_for_package(descriptor)}/#{PACKAGE_FILE_IN_REPO}"
363
+ return Fig::URL.append_path_components(
364
+ remote_dir_for_package(descriptor), [PACKAGE_FILE_IN_REPO]
365
+ )
355
366
  end
356
367
 
357
368
  def local_fig_file_for_package(descriptor)
@@ -363,7 +374,9 @@ class Fig::Repository
363
374
  end
364
375
 
365
376
  def remote_dir_for_package(descriptor)
366
- "#{remote_repository_url()}/#{descriptor.name}/#{descriptor.version}"
377
+ return Fig::URL.append_path_components(
378
+ remote_repository_url(), [descriptor.name, descriptor.version]
379
+ )
367
380
  end
368
381
 
369
382
  def local_dir_for_package(descriptor)
@@ -6,8 +6,8 @@ require 'tmpdir'
6
6
 
7
7
  require 'fig'
8
8
  require 'fig/at_exit'
9
+ require 'fig/file_not_found_error'
9
10
  require 'fig/logging'
10
- require 'fig/not_found_error'
11
11
  require 'fig/package_cache'
12
12
  require 'fig/package_definition_text_assembler'
13
13
  require 'fig/package_descriptor'
@@ -37,7 +37,8 @@ class Fig::RepositoryPackagePublisher
37
37
  attr_writer :local_only
38
38
 
39
39
  def initialize()
40
- @text_assembler = Fig::PackageDefinitionTextAssembler.new
40
+ @text_assembler =
41
+ Fig::PackageDefinitionTextAssembler.new :emit_as_to_be_published
41
42
 
42
43
  return
43
44
  end
@@ -111,7 +112,11 @@ class Fig::RepositoryPackagePublisher
111
112
  add_output_statements_and_create_resource_archive()
112
113
  add_unparsed_text()
113
114
 
114
- file_content = @text_assembler.assemble_package_definition()
115
+ file_content, explanations = @text_assembler.assemble_package_definition()
116
+ if Fig::Logging.debug?
117
+ explanations.each {|explanation| Fig::Logging.debug explanation}
118
+ end
119
+
115
120
  begin
116
121
  Fig::Parser.new(nil, false).parse_package(
117
122
  @descriptor,
@@ -161,17 +166,6 @@ class Fig::RepositoryPackagePublisher
161
166
  def assemble_output_statements()
162
167
  @resource_paths = []
163
168
 
164
- if (
165
- @text_assembler.input_statements.empty? \
166
- || ! @text_assembler.input_statements[0].is_a?(Fig::Statement::GrammarVersion)
167
- )
168
- @text_assembler.add_output Fig::Statement::GrammarVersion.new(
169
- nil,
170
- %Q<[synthetic statement created in #{__FILE__} line #{__LINE__}]>,
171
- 0 # Grammar version
172
- )
173
- end
174
-
175
169
  @text_assembler.input_statements.each do
176
170
  |statement|
177
171
 
@@ -186,11 +180,11 @@ class Fig::RepositoryPackagePublisher
186
180
  end
187
181
 
188
182
  def add_asset_to_output_statements(asset_statement)
189
- if Fig::URL.is_url? asset_statement.url
183
+ if Fig::URL.is_url? asset_statement.location
190
184
  @text_assembler.add_output asset_statement
191
185
  elsif asset_statement.is_a? Fig::Statement::Archive
192
186
  if asset_statement.requires_globbing?
193
- expand_globs_from( [asset_statement.url] ).each do
187
+ expand_globs_from( [asset_statement.location] ).each do
194
188
  |file|
195
189
 
196
190
  @text_assembler.add_output(
@@ -206,9 +200,9 @@ class Fig::RepositoryPackagePublisher
206
200
  @text_assembler.add_output asset_statement
207
201
  end
208
202
  elsif asset_statement.requires_globbing?
209
- @resource_paths.concat expand_globs_from( [asset_statement.url] )
203
+ @resource_paths.concat expand_globs_from( [asset_statement.location] )
210
204
  else
211
- @resource_paths << asset_statement.url
205
+ @resource_paths << asset_statement.location
212
206
  end
213
207
 
214
208
  return
@@ -220,7 +214,7 @@ class Fig::RepositoryPackagePublisher
220
214
 
221
215
  file = Fig::Repository::RESOURCES_FILE
222
216
  @operating_system.create_archive(file, @resource_paths)
223
- Fig::AtExit.add { File.delete(file) }
217
+ Fig::AtExit.add { FileUtils.rm_f(file) }
224
218
 
225
219
  @text_assembler.add_output(
226
220
  Fig::Statement::Archive.new(
@@ -249,19 +243,20 @@ class Fig::RepositoryPackagePublisher
249
243
 
250
244
  def publish_asset(asset_statement)
251
245
  asset_name = asset_statement.asset_name()
252
- asset_remote = "#{@remote_dir_for_package}/#{asset_name}"
246
+ asset_remote =
247
+ Fig::URL.append_path_components @remote_dir_for_package, [asset_name]
253
248
 
254
- if Fig::URL.is_url? asset_statement.url
249
+ if Fig::URL.is_url? asset_statement.location
255
250
  asset_local = File.join(publish_temp_dir(), asset_name)
256
251
 
257
252
  begin
258
- @operating_system.download(asset_statement.url, asset_local)
259
- rescue Fig::NotFoundError
260
- Fig::Logging.fatal "Could not download #{asset_statement.url}."
253
+ @operating_system.download(asset_statement.location, asset_local)
254
+ rescue Fig::FileNotFoundError
255
+ Fig::Logging.fatal "Could not download #{asset_statement.location}."
261
256
  raise Fig::RepositoryError.new
262
257
  end
263
258
  else
264
- asset_local = asset_statement.url
259
+ asset_local = asset_statement.location
265
260
  check_asset_path(asset_local)
266
261
  end
267
262
 
@@ -9,7 +9,7 @@ require 'fig/statement/include'
9
9
  require 'fig/statement/path'
10
10
  require 'fig/statement/set'
11
11
  require 'fig/user_input_error'
12
- require 'fig/unparser/v0'
12
+ require 'fig/unparser'
13
13
 
14
14
  module Fig; end
15
15
 
@@ -99,37 +99,31 @@ class Fig::RuntimeEnvironment
99
99
  return
100
100
  end
101
101
 
102
- def execute_shell(command)
102
+ def execute_command_line(base_package, base_config, descriptor, command_line)
103
+ package, * =
104
+ determine_package_for_execution(base_package, base_config, descriptor)
105
+
106
+ expanded_command_line =
107
+ command_line.map {
108
+ |argument| expand_command_line_argument(argument, base_package)
109
+ }
110
+
103
111
  @variables.with_environment do
104
- yield command.map{|arg| expand_command_line_argument(arg, nil, nil)}
112
+ yield expanded_command_line
105
113
  end
106
114
 
107
115
  return
108
116
  end
109
117
 
110
- def execute_config(base_package, base_config, descriptor, args, &block)
111
- config_name =
112
- determine_config_to_executed(base_package, base_config, descriptor)
113
-
114
- package = nil
115
-
116
- if descriptor
117
- name = descriptor.name || base_package.name
118
- package = lookup_package(
119
- name,
120
- descriptor.version,
121
- Fig::IncludeBacktrace.new(
122
- nil,
123
- Fig::PackageDescriptor.new(name, descriptor.version, config_name)
124
- )
125
- )
126
- else
127
- package = base_package
128
- end
118
+ def execute_config(
119
+ base_package, base_config, descriptor, extra_arguments, &block
120
+ )
121
+ package, config_name =
122
+ determine_package_for_execution(base_package, base_config, descriptor)
129
123
 
130
124
  command_statement = package[config_name].command_statement
131
125
  if command_statement
132
- execute_command(command_statement, args, package, nil, &block)
126
+ execute_command(command_statement, extra_arguments, package, &block)
133
127
  else
134
128
  raise Fig::UserInputError.new(
135
129
  %Q<The "#{package.to_s}" package with the "#{config_name}" configuration does not contain a command.>
@@ -140,35 +134,35 @@ class Fig::RuntimeEnvironment
140
134
  end
141
135
 
142
136
  # In order for this to work correctly, any Overrides need to be processed
143
- # before any other kind of Statement. The Configuration class guarantees
144
- # that those come first in its set of Statements.
145
- def apply_config_statement(base_package, statement, backtrace)
137
+ # before any other kind of Statement. The Statement::Configuration class
138
+ # guarantees that those come first in its set of Statements.
139
+ def apply_config_statement(package, statement, backtrace)
146
140
  case statement
147
141
  when Fig::Statement::Path
148
- prepend_variable(base_package, statement.name, statement.value, backtrace)
142
+ prepend_variable(package, statement, backtrace)
149
143
  when Fig::Statement::Set
150
- set_variable(base_package, statement.name, statement.value, backtrace)
144
+ set_variable(package, statement, backtrace)
151
145
  when Fig::Statement::Include
152
- include_config(base_package, statement.descriptor, backtrace)
146
+ include_config(package, statement.descriptor, backtrace)
153
147
  when Fig::Statement::Override
154
148
  backtrace.add_override(statement)
155
149
  when Fig::Statement::Command
156
150
  # Skip - has no effect on environment.
157
151
  else
158
- unparser = Fig::Unparser::V0.new :emit_as_to_be_published
159
- text = unparser.unparse([statement]).strip
160
- raise "Unexpected statement in a config block: #{text}"
152
+ text, * =
153
+ Fig::Unparser.determine_version_and_unparse(statement, :emit_as_input)
154
+ raise "Unexpected statement in a config block: #{text.strip}"
161
155
  end
162
156
 
163
157
  return
164
158
  end
165
159
 
166
- def include_config(base_package, descriptor, backtrace)
160
+ def include_config(starting_package, descriptor, backtrace)
167
161
  resolved_descriptor = nil
168
162
 
169
163
  # Check to see if this include has been overridden.
170
164
  if backtrace
171
- override_package_name = descriptor.name || base_package.name
165
+ override_package_name = descriptor.name || starting_package.name
172
166
  override = backtrace.get_override(override_package_name)
173
167
  if override
174
168
  resolved_descriptor =
@@ -181,7 +175,7 @@ class Fig::RuntimeEnvironment
181
175
 
182
176
  new_backtrace = Fig::IncludeBacktrace.new(backtrace, resolved_descriptor)
183
177
  package = lookup_package(
184
- resolved_descriptor.name || base_package.name,
178
+ resolved_descriptor.name || starting_package.name,
185
179
  resolved_descriptor.version,
186
180
  new_backtrace
187
181
  )
@@ -200,24 +194,26 @@ class Fig::RuntimeEnvironment
200
194
 
201
195
  statement = @retrieves[name]
202
196
  if statement.loaded_but_not_referenced?
203
- unparser = Fig::Unparser::V0.new :emit_as_to_be_published
204
- text = unparser.unparse([statement]).strip
197
+ text, * = Fig::Unparser.determine_version_and_unparse(
198
+ [statement], :emit_as_input
199
+ )
205
200
  Fig::Logging.warn \
206
- %Q<The #{name} variable was never referenced or didn't need expansion, so "#{text}"#{statement.position_string} was ignored.>
201
+ %Q<The #{name} variable was never referenced or didn't need expansion, so "#{text.strip}"#{statement.position_string} was ignored.>
207
202
  end
208
203
  end
209
204
  end
210
205
 
211
206
  private
212
207
 
213
- def set_variable(base_package, name, value, backtrace)
214
- expanded_value =
215
- expand_variable_as_path_and_process_retrieves(
216
- name, value, base_package, backtrace
217
- )
208
+ def set_variable(package, statement, backtrace)
209
+ expanded_value = expand_variable_as_path_and_process_retrieves(
210
+ statement, package, backtrace
211
+ )
212
+ name = statement.name
218
213
  @variables[name] = expanded_value
219
214
 
220
215
  if Fig::Logging.debug?
216
+ value = statement.value
221
217
  expanded_message =
222
218
  expanded_value == value ? '' \
223
219
  : %Q< (expanded from "#{value}")>
@@ -230,14 +226,15 @@ class Fig::RuntimeEnvironment
230
226
  return
231
227
  end
232
228
 
233
- def prepend_variable(base_package, name, value, backtrace)
234
- expanded_value =
235
- expand_variable_as_path_and_process_retrieves(
236
- name, value, base_package, backtrace
237
- )
229
+ def prepend_variable(package, statement, backtrace)
230
+ expanded_value = expand_variable_as_path_and_process_retrieves(
231
+ statement, package, backtrace
232
+ )
233
+ name = statement.name
238
234
  @variables.prepend_variable(name, expanded_value)
239
235
 
240
236
  if Fig::Logging.debug?
237
+ value = statement.value
241
238
  expanded_message =
242
239
  expanded_value == value ? '' \
243
240
  : %Q< ("#{value}" expanded to "#{expanded_value}")>
@@ -275,6 +272,31 @@ class Fig::RuntimeEnvironment
275
272
  return package
276
273
  end
277
274
 
275
+ def determine_package_for_execution(base_package, base_config, descriptor)
276
+ config_name =
277
+ determine_config_to_executed(base_package, base_config, descriptor)
278
+
279
+ package = nil
280
+
281
+ if descriptor
282
+ package_name = descriptor.name || base_package.name
283
+ package = lookup_package(
284
+ package_name,
285
+ descriptor.version,
286
+ Fig::IncludeBacktrace.new(
287
+ nil,
288
+ Fig::PackageDescriptor.new(
289
+ package_name, descriptor.version, config_name
290
+ )
291
+ )
292
+ )
293
+ else
294
+ package = base_package
295
+ end
296
+
297
+ return [package, config_name]
298
+ end
299
+
278
300
  def determine_config_to_executed(base_package, base_config, descriptor)
279
301
  return base_config if base_config
280
302
 
@@ -301,44 +323,44 @@ class Fig::RuntimeEnvironment
301
323
  return package.primary_config_name || Fig::Package::DEFAULT_CONFIG
302
324
  end
303
325
 
304
- def execute_command(command_statement, args, package, backtrace)
326
+ def execute_command(command_statement, extra_arguments, package)
305
327
  @variables.with_environment do
306
328
  argument =
307
329
  expand_command_line_argument(
308
- "#{command_statement.command} #{args.join(' ')}", backtrace, package
330
+ "#{command_statement.command} #{extra_arguments.join(' ')}", package
309
331
  )
310
332
 
311
- yield expand_at_signs_in_path(argument, package, backtrace).split(' ')
333
+ yield argument.split(' ')
312
334
  end
313
335
 
314
336
  return
315
337
  end
316
338
 
317
339
  def expand_variable_as_path_and_process_retrieves(
318
- variable_name, variable_value, base_package, backtrace
340
+ statement, package, backtrace
319
341
  )
320
- return variable_value unless base_package && base_package.name
342
+ return statement.value unless package && package.name
321
343
 
322
344
  variable_value =
323
- expand_at_signs_in_path(variable_value, base_package, backtrace)
345
+ expand_at_signs_in_path(statement.value, package, backtrace)
324
346
 
325
- return variable_value if not @retrieves.member?(variable_name)
347
+ return variable_value if not @retrieves.member?(statement.name)
326
348
 
327
349
  return retrieve_files(
328
- variable_name, variable_value, base_package, backtrace
350
+ statement.name, variable_value, package, backtrace
329
351
  )
330
352
  end
331
353
 
332
- def retrieve_files(variable_name, variable_value, base_package, backtrace)
354
+ def retrieve_files(variable_name, variable_value, package, backtrace)
333
355
  check_source_existence(
334
- variable_name, variable_value, base_package, backtrace
356
+ variable_name, variable_value, package, backtrace
335
357
  )
336
358
 
337
359
  destination_path =
338
- derive_retrieve_destination(variable_name, variable_value, base_package)
360
+ derive_retrieve_destination(variable_name, variable_value, package)
339
361
 
340
362
  @working_directory_maintainer.switch_to_package_version(
341
- base_package.name, base_package.version
363
+ package.name, package.version
342
364
  )
343
365
  @working_directory_maintainer.retrieve(variable_value, destination_path)
344
366
 
@@ -346,20 +368,20 @@ class Fig::RuntimeEnvironment
346
368
  end
347
369
 
348
370
  def check_source_existence(
349
- variable_name, variable_value, base_package, backtrace
371
+ variable_name, variable_value, package, backtrace
350
372
  )
351
373
  return if File.exists?(variable_value) || File.symlink?(variable_value)
352
374
 
353
375
  raise_repository_error(
354
- %Q<In #{base_package}, the #{variable_name} variable points to a path that does not exist ("#{variable_value}", after expansion).>,
376
+ %Q<In #{package}, the #{variable_name} variable points to a path that does not exist ("#{variable_value}", after expansion).>,
355
377
  backtrace,
356
- base_package
378
+ package
357
379
  )
358
380
  end
359
381
 
360
- def derive_retrieve_destination(variable_name, variable_value, base_package)
382
+ def derive_retrieve_destination(variable_name, variable_value, package)
361
383
  retrieve_path =
362
- get_retrieve_path_with_substitution(variable_name, base_package)
384
+ get_retrieve_path_with_substitution(variable_name, package)
363
385
 
364
386
  # A '//' in the variable value tells us to preserve path
365
387
  # information after the '//' when doing a retrieve.
@@ -376,56 +398,83 @@ class Fig::RuntimeEnvironment
376
398
  return File.join(retrieve_path, File.basename(variable_value))
377
399
  end
378
400
 
379
- def expand_at_signs_in_path(path, base_package, backtrace)
401
+ def expand_at_signs_in_path(path, package, backtrace)
380
402
  expanded_path =
381
- replace_at_signs_with_package_references(path, base_package)
382
- check_for_bad_escape(expanded_path, path, base_package, backtrace)
403
+ replace_at_signs_with_package_references(path, package)
404
+ check_for_bad_escape(expanded_path, path, package, backtrace)
383
405
 
384
406
  return collapse_backslashes_for_escaped_at_signs(expanded_path)
385
407
  end
386
408
 
387
- def replace_at_signs_with_package_references(arg, base_package)
388
- return arg.gsub(
409
+ def replace_at_signs_with_package_references(argument, package)
410
+ return argument.gsub(
389
411
  %r<
390
412
  (?: ^ | \G) # Zero-width anchor.
391
- ( [^\\@]* (?:\\{2})*) # An even number of leading backslashes
413
+ ( [^\\@]* ) # A bunch of not-slashes-or-at-signs
414
+ ( \\* ) # Any leading backslashes
392
415
  \@ # The package indicator
393
416
  >x
394
417
  ) do |match|
395
- backslashes = $1 || ''
396
- backslashes + base_package.directory
418
+ frontmatter, backslashes = $1, $2
419
+
420
+ replacement = backslashes.length % 2 == 1 ? '@' : package.directory
421
+
422
+ "#{frontmatter}#{backslashes}#{replacement}"
397
423
  end
398
424
  end
399
425
 
400
- def expand_command_line_argument(arg, backtrace, package)
401
- package_substituted = expand_named_package_references(arg, backtrace)
402
- check_for_bad_escape(package_substituted, arg, package, backtrace)
426
+ def expand_command_line_argument(argument, package)
427
+ package_substituted = expand_package_references(argument, package)
428
+ check_for_bad_escape(package_substituted, argument, package, nil)
403
429
 
404
430
  return collapse_backslashes_for_escaped_at_signs(package_substituted)
405
431
  end
406
432
 
407
- def expand_named_package_references(arg, backtrace)
408
- return arg.gsub(
433
+ def expand_package_references(argument, package)
434
+ return argument.gsub(
409
435
  # TODO: Refactor package name regex into PackageDescriptor constant.
410
436
  %r<
411
437
  (?: ^ | \G) # Zero-width anchor.
412
- ( [^\\@]* (?:\\{2})*) # An even number of leading backslashes
438
+ ( [^\\@]* ) # A bunch of not-slashes-or-at-signs
439
+ ( \\* ) # Any leading backslashes
413
440
  \@ # The package indicator
414
- ( [a-zA-Z0-9_.-]+ ) # Package name
441
+ ( [a-zA-Z0-9_.-]* ) # Package name
415
442
  >x
416
443
  ) do |match|
417
- backslashes = $1 || ''
418
- package_name = $2
444
+ frontmatter, backslashes, package_name = $1, $2, $3
445
+
446
+ expand_package_reference(
447
+ frontmatter, backslashes, package_name, package
448
+ )
449
+ end
450
+ end
451
+
452
+ def expand_package_reference(
453
+ frontmatter, backslashes, package_name, starting_package
454
+ )
455
+ if backslashes.length % 2 == 1
456
+ return "#{frontmatter}#{backslashes}@#{package_name}"
457
+ end
458
+
459
+ package = nil
460
+ if ! package_name.empty?
419
461
  package = get_package(package_name)
420
462
  if package.nil?
421
463
  raise_repository_error(
422
464
  %Q<Command-line referenced the "#{package_name}" package, which has not been referenced by any other package, so there's nothing to substitute with.>,
423
- backtrace,
465
+ nil,
424
466
  nil
425
467
  )
426
468
  end
427
- backslashes + package.directory
469
+ else
470
+ package = starting_package
428
471
  end
472
+
473
+ if package && package.directory
474
+ return "#{frontmatter}#{backslashes}#{package.directory}"
475
+ end
476
+
477
+ return "#{frontmatter}#{backslashes}@"
429
478
  end
430
479
 
431
480
  # The value is expected to have had any @ substitution already done, but
@@ -450,11 +499,11 @@ class Fig::RuntimeEnvironment
450
499
  return string.gsub(%r< \\ ([\\@]) >x, '\1')
451
500
  end
452
501
 
453
- def get_retrieve_path_with_substitution(name, base_package)
454
- retrieve_statement = @retrieves[name]
502
+ def get_retrieve_path_with_substitution(variable_name, package)
503
+ retrieve_statement = @retrieves[variable_name]
455
504
  retrieve_statement.referenced(true)
456
505
 
457
- return retrieve_statement.path.gsub(/ \[package\] /x, base_package.name)
506
+ return retrieve_statement.path.gsub(/ \[package\] /x, package.name)
458
507
  end
459
508
 
460
509
  def raise_repository_error(message, backtrace, package)