fig 0.1.77 → 0.1.79

Sign up to get free protection for your applications and to get access to all the features.
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)