fig 0.1.62 → 0.1.64

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