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
data/Changes CHANGED
@@ -1,3 +1,159 @@
1
+ v0.1.64
2
+
3
+ Backwards incompatibilities:
4
+
5
+ - --set and --append command-line options now take priority over package.fig
6
+ files and --include options are now processed after any "include"
7
+ statements.
8
+
9
+ Previously, "fig foo/1.2.3 --set SET=command-line --append
10
+ APPEND=command-line --include command-line/1.2.3" was equivalent to
11
+
12
+ config default
13
+ set SET=command-line
14
+ add APPEND=command-line
15
+ include command-line/1.2.3
16
+
17
+ include foo/1.2.3
18
+ end
19
+
20
+ Now it is equivalent to
21
+
22
+ config default
23
+ include foo/1.2.3
24
+
25
+ set SET=command-line
26
+ add APPEND=command-line
27
+ include command-line/1.2.3
28
+ end
29
+
30
+ (It really is like that: a package is synthesized with statements
31
+ equivalent to the command-line options and that package is run through the
32
+ whole process.)
33
+
34
+ - Retrieve variable names can no longer contain "@", "/", or ".". Since
35
+ environment variable statements only allow alphanumerics and underscore in
36
+ the variable names, any retrieve variable with those characters in its name
37
+ would never have any effect.
38
+
39
+ - Running fig --publish or --publish-local with --resource or --archive
40
+ options without also specifying a --set or --append option is now an error.
41
+
42
+ What would previously happen is that the --resource and --archive options
43
+ were ignored and package.fig locating would happen and the publish would be
44
+ based only on that. Probably not what was intended.
45
+
46
+ E.g.:
47
+
48
+ fig --publish foo/1 --resource=something.txt
49
+
50
+ would ignore the --resource option, look for a package.fig file and publish
51
+ based upon that.
52
+
53
+ - Now fails if you specify both a descriptor and the --file option and you
54
+ aren't publishing. Previously it would silently ignore the --file option,
55
+ which could be a bit more than a little surprising.
56
+
57
+ New features:
58
+
59
+ - Overrides are now independent statements, no longer attached to includes.
60
+ E.g. this
61
+
62
+ config default
63
+ include A/1 override C/3
64
+ include B/1 override C/3
65
+ end
66
+
67
+ is now equivalent to this
68
+
69
+ config default
70
+ override C/3
71
+ include A/1
72
+ include B/1
73
+ end
74
+
75
+ No changes to existing (functioning) package.fig files will be necessary.
76
+ In fact, this will fix some that didn't work due to versionless includes.
77
+
78
+ - You can now specify overrides on the command-line using "--override".
79
+
80
+ - Now checks repository format version and fails if it's different from what
81
+ it knows about.
82
+
83
+ There are no immediate plans to change the repository format, but
84
+ considering the inability to fix the non-unique archive name issue below,
85
+ it behooves us to allow for a format change in the future. If the layout
86
+ does change, then current code could possibly corrupt the future
87
+ repository.
88
+
89
+ - Warns if you attempt to use a "retrieve" statement to write to an absolute
90
+ path; all retrieve destinations are relative.
91
+
92
+ - Now warns about ineffectual "retrieve" statements.
93
+
94
+ - A lot of existence checks have been added, resulting in nicer error
95
+ messages and fewer stack traces.
96
+
97
+ - README.md has had most of its content ripped out. Documentation has been
98
+ greatly expanded and is available at https://github.com/mfoemmel/fig/wiki.
99
+
100
+ - Includes the Fig version in the comments in published .fig files.
101
+
102
+ Bug fixes:
103
+
104
+ - Better command-line parsing. There were a number of scenarios where
105
+ missing or malformed arguments to options would cause incorrect behavior or
106
+ stack traces.
107
+
108
+ - Handling of symlinks is better.
109
+
110
+ - Now checks that archive base names are unique before allowing publishing.
111
+ Previously, if you had something like
112
+
113
+ archive http://somewhere/archive.tar.gz
114
+ archive foo/archive.tar.gz
115
+
116
+ everything would work locally, but the version of the package published to
117
+ the remote repository was corrupt. Given the current repository layout,
118
+ this is not fixable, so we now disallow publishing packages like this.
119
+
120
+ Similarly, we now complain about archives named "resources.tar.gz" because
121
+ Fig creates an archive by that name to hold resources.
122
+
123
+ - Updates should be more robust in the face of simultaneous runs of fig.
124
+
125
+ - Retrieves:
126
+
127
+ * Now saves retrieve metadata prior to an exec(2). Previously, if you ran
128
+ a command, Fig would lose track of what you had in your current
129
+ directory.
130
+
131
+ * Cleanup of retrieves for no-longer-referenced packages now happens, i.e.,
132
+ if a dependency removes a dependency, files are correctly removed.
133
+
134
+ Note that, depending upon the packages involved, switching between two
135
+ base packages can be slower than it was before. In other words, if
136
+ packages "foo" and "bar" have a lot of retrieves of dependences NOT in
137
+ common, running
138
+
139
+ fig --update-if-missing foo/v1.2.3
140
+ fig --update-if-missing bar/v6.5.4
141
+
142
+ will be slower. On the other hand, you won't have a lot of stuff from
143
+ "foo" hanging around that shouldn't be there.
144
+
145
+ v0.1.63.beta.2
146
+ v0.1.63.beta.1
147
+
148
+ - Test releases
149
+
150
+ v0.1.62
151
+
152
+ Bug fixes:
153
+
154
+ - Fixed stack trace when encountering conflicting dependency package
155
+ versions.
156
+
1
157
  v0.1.61
2
158
 
3
159
  New features:
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.62
1
+ 0.1.64
data/bin/fig CHANGED
@@ -1,10 +1,17 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ if ENV['FIG_COVERAGE']
4
+ require File.expand_path(
5
+ File.join(
6
+ File.dirname(__FILE__), %w< .. lib fig command coveragesupport.rb >
7
+ )
8
+ )
9
+ end
10
+
3
11
  $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), %w< .. lib > ))
4
12
 
5
13
  require 'rubygems'
6
14
 
7
15
  require 'fig/command'
8
16
 
9
- return_code = Fig::Command.new.run_with_exception_handling(ARGV)
10
- exit return_code
17
+ exit Fig::Command.new.run_with_exception_handling ARGV
@@ -1,5 +1,13 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ if ENV['FIG_COVERAGE']
4
+ require File.expand_path(
5
+ File.join(
6
+ File.dirname(__FILE__), %w< .. lib fig command coveragesupport.rb >
7
+ )
8
+ )
9
+ end
10
+
3
11
  $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), %w< .. lib > ))
4
12
 
5
13
  require 'rubygems'
@@ -8,5 +16,4 @@ require 'fig/command'
8
16
 
9
17
  # Identical to regular fig, but doesn't use exception handling so you can see
10
18
  # stack traces.
11
- return_code = Fig::Command.new.run_fig(ARGV)
12
- exit return_code
19
+ exit Fig::Command.new.run_fig ARGV
@@ -1,8 +1,9 @@
1
1
  module Fig; end
2
2
 
3
- # Configuration for the Fig program, as opposed to the configuration in a
4
- # package.
3
+ # Configuration for the Fig program, as opposed to a config in a package.
5
4
  class Fig::ApplicationConfiguration
5
+ attr_reader :remote_repository_url
6
+
6
7
  def initialize(remote_repository_url)
7
8
  @data = []
8
9
  @remote_repository_url = remote_repository_url
@@ -0,0 +1,37 @@
1
+ module Fig; end
2
+
3
+ # This exists because standard Kernel#at_exit blocks don't get run before
4
+ # Kernel#exec.
5
+ class Fig::AtExit
6
+ def self.add(&block)
7
+ EXIT_PROCS << block
8
+
9
+ return
10
+ end
11
+
12
+ def self.execute()
13
+ EXIT_PROCS.each do
14
+ |proc|
15
+
16
+ begin
17
+ proc.call()
18
+ rescue StandardError => exception
19
+ $stderr.puts(
20
+ [
21
+ %q<Got exception from "at exit" processing.>,
22
+ exception.message,
23
+ exception.backtrace
24
+ ].flatten.join("\n")
25
+ )
26
+ end
27
+ end
28
+
29
+ return
30
+ end
31
+
32
+ private
33
+
34
+ EXIT_PROCS = []
35
+
36
+ at_exit { Fig::AtExit.execute() }
37
+ end
@@ -1,7 +1,8 @@
1
+ require 'fig/repositoryerror'
2
+
1
3
  module Fig; end
2
4
 
3
- # Contains traces of file inclusions so that the user can track down which file
4
- # an error occurred in.
5
+ # Keeps track of overrides and can produce package definition stack traces.
5
6
  class Fig::Backtrace
6
7
  attr_reader :overrides
7
8
 
@@ -11,11 +12,21 @@ class Fig::Backtrace
11
12
  @overrides = {}
12
13
  end
13
14
 
14
- def add_override(package_name, version)
15
+ def add_override(statement)
16
+ package_name = statement.package_name
15
17
  # Don't replace an existing override on the stack
16
- return if get_override(package_name)
18
+ return if @parent && @parent.get_override(package_name)
19
+
20
+ new_version = statement.version
21
+ existing_version = @overrides[package_name]
22
+ if existing_version && existing_version != new_version
23
+ stacktrace = dump_to_string()
24
+ raise Fig::RepositoryError.new(
25
+ "Override #{package_name} version conflict (#{existing_version} vs #{new_version})#{statement.position_string}." + ( stacktrace.empty? ? '' : "\n#{stacktrace}" )
26
+ )
27
+ end
17
28
 
18
- @overrides[package_name] = version
29
+ @overrides[package_name] = new_version
19
30
  end
20
31
 
21
32
  # Returns a version.
@@ -31,7 +42,7 @@ class Fig::Backtrace
31
42
  def dump(out)
32
43
  stack = []
33
44
  collect(stack)
34
- i=0
45
+ i = 0
35
46
  for descriptor in stack
36
47
  indent=''
37
48
  i.times { indent += ' ' }
@@ -42,6 +53,12 @@ class Fig::Backtrace
42
53
 
43
54
  protected
44
55
 
56
+ def dump_to_string()
57
+ string_handle = StringIO.new
58
+ dump(string_handle)
59
+ return string_handle.string
60
+ end
61
+
45
62
  def collect(stack)
46
63
  if @parent
47
64
  @parent.collect(stack)
@@ -2,27 +2,28 @@ require 'rubygems'
2
2
  require 'net/ftp'
3
3
  require 'set'
4
4
 
5
+ require 'fig/atexit'
6
+ require 'fig/command/options'
5
7
  require 'fig/environment'
6
8
  require 'fig/figrc'
7
9
  require 'fig/logging'
8
10
  require 'fig/operatingsystem'
9
- require 'fig/options'
10
11
  require 'fig/package'
11
12
  require 'fig/parser'
12
13
  require 'fig/repository'
13
14
  require 'fig/repositoryerror'
14
- require 'fig/retriever'
15
15
  require 'fig/statement/configuration'
16
- require 'fig/statement/publish'
17
16
  require 'fig/userinputerror'
17
+ require 'fig/workingdirectorymaintainer'
18
18
 
19
- # These are a breakout of parts of this class simply to keep the file size down.
19
+ # The following are a break out of parts of this class simply to keep the file
20
+ # size down.
20
21
 
21
22
  # You will need to look in this file for any stuff related to --list-* options.
22
23
  require 'fig/command/listing'
23
24
 
24
25
  # You will need to look in this file for any stuff related to loading the
25
- # primary Package object.
26
+ # base Package object.
26
27
  require 'fig/command/packageload'
27
28
 
28
29
  module Fig; end
@@ -32,17 +33,59 @@ class Fig::Command
32
33
  include Fig::Command::Listing
33
34
  include Fig::Command::PackageLoad
34
35
 
36
+ def self.get_version()
37
+ line = nil
38
+
39
+ begin
40
+ File.open(
41
+ "#{File.expand_path(File.dirname(__FILE__) + '/../../VERSION')}"
42
+ ) do |file|
43
+ line = file.gets
44
+ end
45
+ rescue
46
+ $stderr.puts 'Could not retrieve version number. Something has mucked with your Fig install.'
47
+
48
+ return nil
49
+ end
50
+
51
+ # Note that we accept anything that contains three decimal numbers
52
+ # seperated by periods. This allows for versions like
53
+ # "4.3.2-super-special-version-in-3D".
54
+ if line !~ %r< \b \d+ [.] \d+ [.] \d+ \b >x
55
+ $stderr.puts %Q<"#{line}" does not look like a version number. Something has mucked with your Fig install.>
56
+
57
+ return nil
58
+ end
59
+
60
+ return line
61
+ end
62
+
35
63
  def run_fig(argv)
36
- @options = Fig::Options.new(argv)
64
+ begin
65
+ @options = Fig::Command::Options.new(argv)
66
+ rescue Fig::UserInputError => error
67
+ $stderr.puts error.to_s # Logging isn't set up yet.
68
+ return 1
69
+ end
70
+
37
71
  if not @options.exit_code.nil?
38
72
  return @options.exit_code
39
73
  end
40
74
  @descriptor = @options.descriptor
41
75
 
76
+ if @options.help?
77
+ return @options.help
78
+ end
79
+
80
+ if @options.version?
81
+ return emit_version()
82
+ end
83
+
42
84
  configure()
43
85
 
44
86
  if @options.clean?
45
87
  check_required_package_descriptor('to clean')
88
+ ensure_descriptor_and_file_were_not_both_specified()
46
89
  @repository.clean(@descriptor)
47
90
  return 0
48
91
  end
@@ -55,26 +98,30 @@ class Fig::Command
55
98
  return publish()
56
99
  end
57
100
 
101
+ ensure_descriptor_and_file_were_not_both_specified()
102
+
58
103
  load_package_object()
59
104
 
60
105
  if @options.listing()
61
106
  handle_post_parse_list_options()
62
107
  elsif @options.get()
63
- puts @environment[@options.get()]
108
+ # Ruby v1.8 emits "nil" for nil, whereas ruby v1.9 emits the empty
109
+ # string, so, for consistency, we need to ensure that we always emit the
110
+ # empty string.
111
+ puts @environment[@options.get()] || ''
64
112
  elsif @options.shell_command
65
113
  @environment.execute_shell(@options.shell_command) do
66
114
  |command| @operating_system.shell_exec command
67
115
  end
68
116
  elsif @descriptor
69
- @environment.include_config(@package, @descriptor, {}, nil)
117
+ @environment.include_config(@base_package, @descriptor, nil)
70
118
  @environment.execute_config(
71
- @package,
119
+ @base_package,
72
120
  @descriptor,
73
121
  @options.command_extra_argv || []
74
122
  ) { |cmd| @operating_system.shell_exec cmd }
75
123
  elsif not @repository.updating?
76
- $stderr.puts "Nothing to do.\n"
77
- $stderr.puts Fig::Options::USAGE
124
+ $stderr.puts "Nothing to do.\n\n"
78
125
  $stderr.puts %q<Run "fig --help" for a full list of commands.>
79
126
  return 1
80
127
  end
@@ -95,7 +142,7 @@ class Fig::Command
95
142
  return 1
96
143
  rescue OptionParser::InvalidOption => error
97
144
  $stderr.puts error.to_s
98
- $stderr.puts Fig::Options::USAGE
145
+ $stderr.puts Fig::Command::Options::USAGE
99
146
  return 1
100
147
  rescue Fig::RepositoryError => error
101
148
  log_error_message(error)
@@ -103,6 +150,15 @@ class Fig::Command
103
150
  end
104
151
  end
105
152
 
153
+ def emit_version()
154
+ version = Fig::Command.get_version()
155
+ return 1 if version.nil?
156
+
157
+ puts File.basename($0) + ' v' + version
158
+
159
+ return 0
160
+ end
161
+
106
162
  private
107
163
 
108
164
  def derive_remote_url()
@@ -128,11 +184,10 @@ class Fig::Command
128
184
  def configure()
129
185
  Fig::Logging.initialize_pre_configuration(@options.log_level())
130
186
 
131
- remote_url = derive_remote_url()
132
187
 
133
188
  @configuration = Fig::FigRC.find(
134
189
  @options.figrc(),
135
- remote_url,
190
+ derive_remote_url(),
136
191
  @options.login?,
137
192
  @options.home(),
138
193
  @options.no_figrc?
@@ -146,8 +201,7 @@ class Fig::Command
146
201
  @operating_system = Fig::OperatingSystem.new(@options.login?)
147
202
  @repository = Fig::Repository.new(
148
203
  @operating_system,
149
- File.expand_path(File.join(@options.home(), 'repos')),
150
- remote_url,
204
+ @options.home(),
151
205
  @configuration,
152
206
  nil, # remote_user
153
207
  @options.update?,
@@ -155,15 +209,13 @@ class Fig::Command
155
209
  check_include_statements_versions?
156
210
  )
157
211
 
158
- @retriever = Fig::Retriever.new('.')
159
-
160
- at_exit { @retriever.save_metadata() }
212
+ @working_directory_maintainer = Fig::WorkingDirectoryMaintainer.new('.')
161
213
 
162
- @environment = prepare_environment
163
-
164
- @options.non_command_package_statements().each do |statement|
165
- @environment.apply_config_statement(nil, statement, nil)
214
+ Fig::AtExit.add do
215
+ @working_directory_maintainer.prepare_for_shutdown(@options.updating?)
166
216
  end
217
+
218
+ prepare_environment()
167
219
  end
168
220
 
169
221
  def prepare_environment()
@@ -172,7 +224,18 @@ class Fig::Command
172
224
  environment_variables = Fig::OperatingSystem.get_environment_variables({})
173
225
  end
174
226
 
175
- return Fig::Environment.new(@repository, environment_variables, @retriever)
227
+ @environment = Fig::Environment.new(
228
+ @repository, environment_variables, @working_directory_maintainer
229
+ )
230
+
231
+ Fig::AtExit.add { @environment.check_unused_retrieves() }
232
+
233
+ return
234
+ end
235
+
236
+ def config_was_specified_by_user()
237
+ return ! @options.config().nil? ||
238
+ @descriptor && ! @descriptor.config().nil?
176
239
  end
177
240
 
178
241
  def base_config()
@@ -181,6 +244,29 @@ class Fig::Command
181
244
  Fig::Package::DEFAULT_CONFIG
182
245
  end
183
246
 
247
+ # If the user has specified a descriptor, than any package.fig or --file
248
+ # option is ignored. Thus, in order to avoid confusing the user, we make
249
+ # specifying both an error.
250
+ #
251
+ # The one exception to this rule is when we are publishing, which should
252
+ # already have been invoked by the time this is called.
253
+ def ensure_descriptor_and_file_were_not_both_specified()
254
+ file = @options.package_definition_file()
255
+
256
+ # If the user specified --no-file, even though it's kind of superfluous,
257
+ # we'll let it slide because the user doesn't think that any file will be
258
+ # processed.
259
+ file_specified = ! file.nil? && file != :none
260
+
261
+ if @descriptor and file_specified
262
+ raise Fig::UserInputError.new(
263
+ %Q<Cannot specify both a package descriptor (#{@descriptor.original_string}) and the --file option (#{file}).>
264
+ )
265
+ end
266
+
267
+ return
268
+ end
269
+
184
270
  def check_required_package_descriptor(operation_description)
185
271
  if not @descriptor
186
272
  raise Fig::UserInputError.new(
@@ -209,31 +295,45 @@ class Fig::Command
209
295
  check_required_package_descriptor('to publish')
210
296
 
211
297
  if @descriptor.name.nil? || @descriptor.version.nil?
212
- raise Fig::UserInputError.new('Please specify a package name and a version name.')
298
+ raise Fig::UserInputError.new(
299
+ 'Please specify a package name and a version name.'
300
+ )
301
+ end
302
+ if @descriptor.name == '_meta'
303
+ raise Fig::UserInputError.new(
304
+ %q<Due to implementation issues, cannot create a package named "_meta".>
305
+ )
213
306
  end
214
307
 
215
- if not @options.non_command_package_statements().empty?
308
+ publish_statements = nil
309
+ if not @options.environment_statements().empty?
216
310
  publish_statements =
217
311
  @options.resources() +
218
312
  @options.archives() +
219
313
  [
220
314
  Fig::Statement::Configuration.new(
315
+ nil,
221
316
  nil,
222
317
  Fig::Package::DEFAULT_CONFIG,
223
- @options.non_command_package_statements()
318
+ @options.environment_statements()
224
319
  )
225
320
  ]
226
- publish_statements << Fig::Statement::Publish.new()
321
+ elsif not @options.resources().empty? or not @options.archives().empty?
322
+ raise Fig::UserInputError.new(
323
+ '--resource/--archive options were specified, but no --set/--append option was given. Will not publish.'
324
+ )
227
325
  else
228
- load_package_file()
229
- if not @package.statements.empty?
230
- publish_statements = @package.statements
326
+ load_package_object_from_file()
327
+ if not @base_package.statements.empty?
328
+ publish_statements = @base_package.statements
231
329
  else
232
330
  $stderr.puts 'Nothing to publish.'
233
331
  return 1
234
332
  end
235
333
  end
236
334
 
335
+ apply_base_config_to_environment(:ignore_base_package)
336
+
237
337
  if @options.publish?
238
338
  Fig::Logging.info "Checking status of #{@descriptor.to_string()}..."
239
339