autoproj 2.4.0 → 2.5.0.pre1
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +5 -5
- data/README.md +4 -2
- data/autoproj.gemspec +9 -4
- data/bin/autoproj_bootstrap +10 -8
- data/bin/autoproj_install +10 -8
- data/lib/autoproj.rb +11 -0
- data/lib/autoproj/aruba_minitest.rb +66 -0
- data/lib/autoproj/autobuild_extensions/git.rb +6 -5
- data/lib/autoproj/cli/commit.rb +28 -13
- data/lib/autoproj/cli/exec.rb +42 -7
- data/lib/autoproj/cli/main.rb +53 -8
- data/lib/autoproj/cli/reset.rb +3 -2
- data/lib/autoproj/cli/status.rb +4 -1
- data/lib/autoproj/cli/versions.rb +3 -3
- data/lib/autoproj/cli/watch.rb +159 -0
- data/lib/autoproj/cli/which.rb +45 -7
- data/lib/autoproj/configuration.rb +69 -17
- data/lib/autoproj/environment.rb +1 -1
- data/lib/autoproj/exceptions.rb +5 -0
- data/lib/autoproj/installation_manifest.rb +2 -2
- data/lib/autoproj/ops/atomic_write.rb +36 -0
- data/lib/autoproj/ops/cached_env.rb +36 -0
- data/lib/autoproj/ops/import.rb +1 -1
- data/lib/autoproj/ops/install.rb +10 -8
- data/lib/autoproj/ops/watch.rb +37 -0
- data/lib/autoproj/ops/which.rb +45 -0
- data/lib/autoproj/package_managers/bundler_manager.rb +3 -3
- data/lib/autoproj/package_managers/pip_manager.rb +2 -1
- data/lib/autoproj/test.rb +1 -2
- data/lib/autoproj/version.rb +1 -1
- data/lib/autoproj/workspace.rb +18 -32
- metadata +58 -28
data/lib/autoproj/cli/main.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
require 'tty/color'
|
3
3
|
require 'autoproj/cli/main_test'
|
4
4
|
require 'autoproj/cli/main_plugin'
|
5
|
+
require 'autoproj/reporter'
|
5
6
|
|
6
7
|
module Autoproj
|
7
8
|
module CLI
|
@@ -34,13 +35,13 @@ def default_report_on_package_failures
|
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
37
|
-
def run_autoproj_cli(filename, classname, report_options, *args, **extra_options)
|
38
|
+
def run_autoproj_cli(filename, classname, report_options, *args, tool_failure_mode: :exit_silent, **extra_options)
|
38
39
|
require "autoproj/cli/#{filename}"
|
39
40
|
if Autobuild::Subprocess.transparent_mode = options[:tool]
|
40
41
|
Autobuild.silent = true
|
41
42
|
Autobuild.color = false
|
42
43
|
report_options[:silent] = true
|
43
|
-
report_options[:on_package_failures] =
|
44
|
+
report_options[:on_package_failures] = tool_failure_mode
|
44
45
|
extra_options[:silent] = true
|
45
46
|
end
|
46
47
|
|
@@ -83,6 +84,13 @@ def envsh
|
|
83
84
|
run_autoproj_cli(:envsh, :Envsh, Hash[])
|
84
85
|
end
|
85
86
|
|
87
|
+
desc 'watch', 'watch workspace for changes', hide: true
|
88
|
+
option :show_events, type: :boolean, default: false,
|
89
|
+
desc: "whether detected events should be displayed"
|
90
|
+
def watch
|
91
|
+
run_autoproj_cli(:watch, :Watch, Hash[])
|
92
|
+
end
|
93
|
+
|
86
94
|
desc 'status [PACKAGES]', 'displays synchronization status between this workspace and the package(s) source'
|
87
95
|
option :local, type: :boolean, default: false,
|
88
96
|
desc: 'only use locally available information (mainly for distributed version control systems such as git)'
|
@@ -195,7 +203,21 @@ def build(*packages)
|
|
195
203
|
report_options[:on_package_failures] = :report
|
196
204
|
end
|
197
205
|
|
198
|
-
run_autoproj_cli(:build, :Build,
|
206
|
+
failures = run_autoproj_cli(:build, :Build, report_options, *packages,
|
207
|
+
tool_failure_mode: :report_silent)
|
208
|
+
if !failures.empty?
|
209
|
+
Autobuild.silent = false
|
210
|
+
packages_failed = failures.
|
211
|
+
map do |e|
|
212
|
+
if e.respond_to?(:target) && e.target.respond_to?(:name)
|
213
|
+
e.target.name
|
214
|
+
end
|
215
|
+
end.compact
|
216
|
+
if !packages_failed.empty?
|
217
|
+
Autobuild.error "#{packages_failed.size} packages failed: #{packages_failed.sort.join(", ")}"
|
218
|
+
end
|
219
|
+
exit 1
|
220
|
+
end
|
199
221
|
end
|
200
222
|
|
201
223
|
desc 'cache CACHE_DIR', 'create or update a cache directory that can be given to AUTOBUILD_CACHE_DIR'
|
@@ -343,12 +365,12 @@ def tag(tag_name = nil, *packages)
|
|
343
365
|
run_autoproj_cli(:tag, :Tag, Hash[], tag_name, *packages)
|
344
366
|
end
|
345
367
|
|
346
|
-
desc 'commit [PACKAGES]', 'save the package current versions as a new commit in the main build configuration'
|
368
|
+
desc 'commit [TAG_NAME] [PACKAGES]', 'save the package current versions as a new commit in the main build configuration'
|
347
369
|
long_desc <<-EOD
|
348
370
|
The commit subcommand stores the state of all packages (or of the packages
|
349
371
|
selected on the command line) into a new commit in the currently checked-out
|
350
372
|
branch of the build configuration. This state can be retrieved later on by using
|
351
|
-
"autoproj reset"
|
373
|
+
"autoproj reset". If a TAG_NAME is provided, the commit will be tagged.
|
352
374
|
|
353
375
|
If given no arguments, will list the existing tags
|
354
376
|
EOD
|
@@ -356,6 +378,8 @@ def tag(tag_name = nil, *packages)
|
|
356
378
|
desc: 'commit the package set state as well (enabled by default)'
|
357
379
|
option :keep_going, aliases: :k, type: :boolean, banner: '',
|
358
380
|
desc: 'do not stop on build or checkout errors'
|
381
|
+
option :tag, aliases: :t, type: :string,
|
382
|
+
desc: 'the tag name to use'
|
359
383
|
option :message, aliases: :m, type: :string,
|
360
384
|
desc: 'the message to use for the new commit (the default is to mention the creation of the tag)'
|
361
385
|
def commit(*packages)
|
@@ -453,15 +477,36 @@ def manifest(*name)
|
|
453
477
|
end
|
454
478
|
|
455
479
|
desc 'exec', "runs a command, applying the workspace's environment first"
|
480
|
+
option :use_cache, type: :boolean, default: nil,
|
481
|
+
desc: "use the cached environment instead of "\
|
482
|
+
"loading the whole configuration"
|
456
483
|
def exec(*args)
|
457
484
|
require 'autoproj/cli/exec'
|
458
|
-
|
485
|
+
Autoproj.report(on_package_failures: default_report_on_package_failures, debug: options[:debug], silent: true) do
|
486
|
+
opts = Hash.new
|
487
|
+
use_cache = options[:use_cache]
|
488
|
+
if !use_cache.nil?
|
489
|
+
opts[:use_cached_env] = use_cache
|
490
|
+
end
|
491
|
+
CLI::Exec.new.run(*args, **opts)
|
492
|
+
end
|
459
493
|
end
|
460
494
|
|
461
|
-
desc 'which', "resolves the full path to a command
|
495
|
+
desc 'which', "resolves the full path to a command "\
|
496
|
+
" within the Autoproj workspace"
|
497
|
+
option :use_cache, type: :boolean, default: nil,
|
498
|
+
desc: "use the cached environment instead of "\
|
499
|
+
"loading the whole configuration"
|
462
500
|
def which(cmd)
|
463
501
|
require 'autoproj/cli/which'
|
464
|
-
|
502
|
+
Autoproj.report(on_package_failures: default_report_on_package_failures, debug: options[:debug], silent: true) do
|
503
|
+
opts = Hash.new
|
504
|
+
use_cache = options[:use_cache]
|
505
|
+
if !use_cache.nil?
|
506
|
+
opts[:use_cached_env] = use_cache
|
507
|
+
end
|
508
|
+
CLI::Which.new.run(cmd, **opts)
|
509
|
+
end
|
465
510
|
end
|
466
511
|
end
|
467
512
|
end
|
data/lib/autoproj/cli/reset.rb
CHANGED
@@ -7,12 +7,13 @@ module Autoproj
|
|
7
7
|
module CLI
|
8
8
|
class Reset < InspectionTool
|
9
9
|
def run(ref_name, options)
|
10
|
-
|
10
|
+
ws.load_config
|
11
|
+
pkg = ws.manifest.main_package_set.create_autobuild_package
|
11
12
|
importer = pkg.importer
|
12
13
|
if !importer || !importer.kind_of?(Autobuild::Git)
|
13
14
|
raise CLIInvalidArguments, "cannot use autoproj reset if the main configuration is not managed by git"
|
14
15
|
end
|
15
|
-
|
16
|
+
|
16
17
|
# Check if the reflog entry exists
|
17
18
|
begin
|
18
19
|
importer.rev_parse(pkg, ref_name)
|
data/lib/autoproj/cli/status.rb
CHANGED
@@ -90,6 +90,9 @@ def status_of_package(package_description, only_local: false, snapshot: false)
|
|
90
90
|
begin importer.snapshot(pkg, nil, exact_state: false, only_local: only_local)
|
91
91
|
rescue Autobuild::PackageException
|
92
92
|
Hash.new
|
93
|
+
rescue Exception => e
|
94
|
+
package_status.msg << Autoproj.color(" failed to fetch snapshotting information (#{e})", :red)
|
95
|
+
return package_status
|
93
96
|
end
|
94
97
|
if snapshot_overrides_vcs?(importer, package_description.vcs, snapshot_version)
|
95
98
|
non_nil_values = snapshot_version.delete_if { |k, v| !v }
|
@@ -198,7 +201,7 @@ def each_package_status(packages, parallel: ws.config.parallel_import_level, sna
|
|
198
201
|
Autoproj.warn "Interrupted, waiting for pending jobs to finish"
|
199
202
|
raise
|
200
203
|
rescue Exception => e
|
201
|
-
Autoproj.error "internal error: #{e}, waiting for pending jobs to finish"
|
204
|
+
Autoproj.error "internal error (#{e.class}): #{e}, waiting for pending jobs to finish"
|
202
205
|
raise
|
203
206
|
ensure
|
204
207
|
executor.shutdown
|
@@ -9,7 +9,7 @@ class Versions < InspectionTool
|
|
9
9
|
DEFAULT_VERSIONS_FILE_BASENAME = Ops::Snapshot::DEFAULT_VERSIONS_FILE_BASENAME
|
10
10
|
|
11
11
|
def default_versions_file
|
12
|
-
File.join(
|
12
|
+
File.join( ws.overrides_dir, DEFAULT_VERSIONS_FILE_BASENAME )
|
13
13
|
end
|
14
14
|
|
15
15
|
def validate_options(packages, options = Hash.new)
|
@@ -32,9 +32,9 @@ def run(user_selection, options)
|
|
32
32
|
packages, *, config_selected =
|
33
33
|
finalize_setup(user_selection,
|
34
34
|
recursive: options[:deps])
|
35
|
-
|
35
|
+
|
36
36
|
ops = Ops::Snapshot.new(ws.manifest, keep_going: options[:keep_going])
|
37
|
-
|
37
|
+
|
38
38
|
if user_selection.empty?
|
39
39
|
snapshot_package_sets = (options[:config] != false)
|
40
40
|
snapshot_packages = !options[:config]
|
@@ -0,0 +1,159 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
require 'autoproj/cli/inspection_tool'
|
3
|
+
require 'autoproj/ops/watch'
|
4
|
+
module Autoproj
|
5
|
+
module CLI
|
6
|
+
class Watch < InspectionTool
|
7
|
+
attr_reader :notifier
|
8
|
+
|
9
|
+
def initialize(*args)
|
10
|
+
super(*args)
|
11
|
+
@show_events = false
|
12
|
+
end
|
13
|
+
|
14
|
+
def validate_options(unused, options = {})
|
15
|
+
_, options = super(unused, options)
|
16
|
+
@show_events = options[:show_events]
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def show_events?
|
21
|
+
@show_events
|
22
|
+
end
|
23
|
+
|
24
|
+
def update_workspace
|
25
|
+
initialize_and_load
|
26
|
+
|
27
|
+
source_packages, _ = finalize_setup([])
|
28
|
+
@source_packages_dirs = source_packages.map do |pkg_name|
|
29
|
+
ws.manifest.find_autobuild_package(pkg_name).srcdir
|
30
|
+
end
|
31
|
+
@pkg_sets_dirs = ws.manifest.each_package_set.map do |pkg_set|
|
32
|
+
pkg_set.raw_local_dir
|
33
|
+
end
|
34
|
+
export_env_sh(shell_helpers: ws.config.shell_helpers?)
|
35
|
+
end
|
36
|
+
|
37
|
+
def load_info_from_installation_manifest
|
38
|
+
installation_manifest =
|
39
|
+
begin
|
40
|
+
Autoproj::InstallationManifest.from_workspace_root(ws.root_dir)
|
41
|
+
rescue ConfigError
|
42
|
+
end
|
43
|
+
|
44
|
+
@source_packages_dirs = []
|
45
|
+
@package_sets = []
|
46
|
+
|
47
|
+
@source_packages_dirs = installation_manifest.each_package.
|
48
|
+
map(&:srcdir)
|
49
|
+
@package_sets = installation_manifest.each_package_set.
|
50
|
+
map(&:raw_local_dir)
|
51
|
+
end
|
52
|
+
|
53
|
+
def callback
|
54
|
+
notifier.stop
|
55
|
+
end
|
56
|
+
|
57
|
+
def create_file_watcher(file)
|
58
|
+
notifier.watch(file, :modify) do |e|
|
59
|
+
Autobuild.message "#{e.absolute_name} modified" if show_events?
|
60
|
+
callback
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def create_dir_watcher(dir, included_paths: [], excluded_paths: [], inotify_flags: [])
|
65
|
+
strip_dir_range = ((dir.size + 1)..-1)
|
66
|
+
notifier.watch(dir, :move, :create, :delete, :modify, :dont_follow, *inotify_flags) do |e|
|
67
|
+
file_name = e.absolute_name[strip_dir_range]
|
68
|
+
included = included_paths.empty? ||
|
69
|
+
included_paths.any? { |rx| rx === file_name }
|
70
|
+
if included
|
71
|
+
included = !excluded_paths.any? { |rx| rx === file_name }
|
72
|
+
end
|
73
|
+
next if !included
|
74
|
+
Autobuild.message "#{e.absolute_name} changed" if show_events?
|
75
|
+
callback
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def create_src_pkg_watchers
|
80
|
+
@source_packages_dirs.each do |pkg_srcdir|
|
81
|
+
next unless File.exist? pkg_srcdir
|
82
|
+
create_dir_watcher(pkg_srcdir, included_paths: ["manifest.xml"])
|
83
|
+
|
84
|
+
manifest_file = File.join(pkg_srcdir, 'manifest.xml')
|
85
|
+
next unless File.exist? manifest_file
|
86
|
+
create_file_watcher(manifest_file)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def start_watchers
|
91
|
+
create_file_watcher(ws.config.path)
|
92
|
+
create_src_pkg_watchers
|
93
|
+
create_dir_watcher(ws.config_dir,
|
94
|
+
excluded_paths: [/(^|#{File::SEPARATOR})\./],
|
95
|
+
inotify_flags: [:recursive])
|
96
|
+
FileUtils.mkdir_p ws.remotes_dir
|
97
|
+
create_dir_watcher(ws.remotes_dir,
|
98
|
+
excluded_paths: [/(^|#{File::SEPARATOR})\./],
|
99
|
+
inotify_flags: [:recursive])
|
100
|
+
end
|
101
|
+
|
102
|
+
def cleanup_notifier
|
103
|
+
notifier.watchers.dup.each_value(&:close)
|
104
|
+
notifier.close
|
105
|
+
end
|
106
|
+
|
107
|
+
def assert_watchers_available
|
108
|
+
return if RbConfig::CONFIG['target_os'] =~ /linux/
|
109
|
+
puts 'error: Workspace watching not available on this platform'
|
110
|
+
exit 1
|
111
|
+
end
|
112
|
+
|
113
|
+
def setup_notifier
|
114
|
+
assert_watchers_available
|
115
|
+
|
116
|
+
require 'rb-inotify'
|
117
|
+
@notifier = INotify::Notifier.new
|
118
|
+
end
|
119
|
+
|
120
|
+
def cleanup
|
121
|
+
if @marker_io
|
122
|
+
Ops.watch_cleanup_marker(@marker_io)
|
123
|
+
end
|
124
|
+
if @notifier
|
125
|
+
cleanup_notifier
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def restart
|
130
|
+
cleanup
|
131
|
+
args = []
|
132
|
+
args << "--show-events" if show_events?
|
133
|
+
exec($PROGRAM_NAME, 'watch', *args)
|
134
|
+
end
|
135
|
+
|
136
|
+
def run(**)
|
137
|
+
@marker_io = Ops.watch_create_marker(ws.root_dir)
|
138
|
+
begin
|
139
|
+
update_workspace
|
140
|
+
rescue Exception => e
|
141
|
+
puts "ERROR: #{e.message}"
|
142
|
+
load_info_from_installation_manifest
|
143
|
+
end
|
144
|
+
setup_notifier
|
145
|
+
start_watchers
|
146
|
+
|
147
|
+
puts 'Watching workspace, press ^C to quit...'
|
148
|
+
notifier.run
|
149
|
+
|
150
|
+
puts 'Workspace changed...'
|
151
|
+
restart
|
152
|
+
rescue Interrupt
|
153
|
+
puts 'Exiting...'
|
154
|
+
ensure
|
155
|
+
cleanup
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
data/lib/autoproj/cli/which.rb
CHANGED
@@ -1,14 +1,52 @@
|
|
1
|
-
require 'autoproj
|
1
|
+
require 'autoproj'
|
2
|
+
require 'autoproj/ops/cached_env'
|
3
|
+
require 'autoproj/ops/which'
|
4
|
+
require 'autoproj/ops/watch'
|
5
|
+
|
2
6
|
module Autoproj
|
3
7
|
module CLI
|
4
|
-
class Which
|
5
|
-
def
|
6
|
-
|
7
|
-
|
8
|
+
class Which
|
9
|
+
def initialize
|
10
|
+
@root_dir = Autoproj.find_workspace_dir
|
11
|
+
if !@root_dir
|
12
|
+
require 'autoproj/workspace'
|
13
|
+
# Will do all sorts of error reporting,
|
14
|
+
# or may be able to resolve
|
15
|
+
@root_dir = Workspace.default.root_dir
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def load_cached_env
|
20
|
+
env = Ops.load_cached_env(@root_dir)
|
21
|
+
return if !env
|
22
|
+
|
23
|
+
Autobuild::Environment.
|
24
|
+
environment_from_export(env, ENV)
|
25
|
+
end
|
26
|
+
|
27
|
+
def run(cmd, use_cached_env: Ops.watch_running?(@root_dir))
|
28
|
+
if use_cached_env
|
29
|
+
env = load_cached_env
|
30
|
+
end
|
31
|
+
|
32
|
+
if !env
|
33
|
+
require 'autoproj'
|
34
|
+
require 'autoproj/cli/inspection_tool'
|
35
|
+
ws = Workspace.from_dir(@root_dir)
|
36
|
+
loader = InspectionTool.new(ws)
|
37
|
+
loader.initialize_and_load
|
38
|
+
loader.finalize_setup(Array.new)
|
39
|
+
env = ws.full_env.resolved_env
|
40
|
+
end
|
8
41
|
|
9
|
-
|
10
|
-
|
42
|
+
path = env['PATH'].split(File::PATH_SEPARATOR)
|
43
|
+
puts Ops.which(cmd, path_entries: path)
|
44
|
+
rescue ExecutableNotFound => e
|
45
|
+
require 'autoproj' # make sure everything is available for error reporting
|
11
46
|
raise CLIInvalidArguments, e.message, e.backtrace
|
47
|
+
rescue Exception
|
48
|
+
require 'autoproj' # make sure everything is available for error reporting
|
49
|
+
raise
|
12
50
|
end
|
13
51
|
end
|
14
52
|
end
|
@@ -1,3 +1,9 @@
|
|
1
|
+
require 'backports/2.4.0/float/dup'
|
2
|
+
require 'backports/2.4.0/fixnum/dup'
|
3
|
+
require 'backports/2.4.0/nil_class/dup'
|
4
|
+
require 'backports/2.4.0/false_class/dup'
|
5
|
+
require 'backports/2.4.0/true_class/dup'
|
6
|
+
|
1
7
|
module Autoproj
|
2
8
|
# Class that does the handling of configuration options as well as
|
3
9
|
# loading/saving on disk
|
@@ -23,6 +29,18 @@ def initialize(path = nil)
|
|
23
29
|
@declared_options = Hash.new
|
24
30
|
@displayed_options = Hash.new
|
25
31
|
@path = path
|
32
|
+
@modified = false
|
33
|
+
end
|
34
|
+
|
35
|
+
# Whether the configuration was changed since the last call to {#load}
|
36
|
+
# or {#save}
|
37
|
+
def modified?
|
38
|
+
@modified
|
39
|
+
end
|
40
|
+
|
41
|
+
# Resets the modified? flag to false
|
42
|
+
def reset_modified
|
43
|
+
@modified = false
|
26
44
|
end
|
27
45
|
|
28
46
|
# Deletes the current value for an option
|
@@ -32,7 +50,9 @@ def initialize(path = nil)
|
|
32
50
|
# @param [String] the option name
|
33
51
|
# @return the deleted value
|
34
52
|
def reset(name)
|
53
|
+
@modified = config.has_key?(name)
|
35
54
|
config.delete(name)
|
55
|
+
overrides.delete(name)
|
36
56
|
end
|
37
57
|
|
38
58
|
# Sets a configuration option
|
@@ -43,7 +63,12 @@ def reset(name)
|
|
43
63
|
# user about this value next time it is needed. Otherwise, it will be
|
44
64
|
# asked about it, the new value being used as default
|
45
65
|
def set(key, value, user_validated = false)
|
46
|
-
config
|
66
|
+
if config.has_key?(key)
|
67
|
+
@modified = (config[key][0] != value)
|
68
|
+
else
|
69
|
+
@modified = true
|
70
|
+
end
|
71
|
+
config[key] = [value.dup, user_validated]
|
47
72
|
end
|
48
73
|
|
49
74
|
# Override a known option value
|
@@ -53,6 +78,16 @@ def override(option_name, value)
|
|
53
78
|
overrides[option_name] = value
|
54
79
|
end
|
55
80
|
|
81
|
+
# Remove a specific override
|
82
|
+
def reset_overrides(name)
|
83
|
+
@overrides.delete(name)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Remove all overrides
|
87
|
+
def reset_overrides
|
88
|
+
@overrides.clear
|
89
|
+
end
|
90
|
+
|
56
91
|
# Tests whether a value is set for the given option name
|
57
92
|
#
|
58
93
|
# @return [Boolean]
|
@@ -63,23 +98,31 @@ def has_value_for?(name)
|
|
63
98
|
# Get the value for a given option
|
64
99
|
def get(key, *default_value)
|
65
100
|
if overrides.has_key?(key)
|
66
|
-
return overrides[key]
|
101
|
+
return overrides[key].dup
|
67
102
|
end
|
68
103
|
|
104
|
+
has_value = config.has_key?(key)
|
69
105
|
value, validated = config[key]
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
106
|
+
|
107
|
+
if !declared?(key)
|
108
|
+
if has_value
|
109
|
+
return value.dup
|
110
|
+
elsif default_value.empty?
|
111
|
+
raise ConfigError, "undeclared option '#{key}'"
|
112
|
+
else
|
113
|
+
default_value.first.dup
|
114
|
+
end
|
74
115
|
else
|
75
|
-
if
|
116
|
+
if validated
|
76
117
|
doc = declared_options[key].short_doc
|
77
118
|
if doc[-1, 1] != "?"
|
78
119
|
doc = "#{doc}:"
|
79
120
|
end
|
80
121
|
displayed_options[key] = value
|
122
|
+
value.dup
|
123
|
+
else
|
124
|
+
configure(key).dup
|
81
125
|
end
|
82
|
-
value
|
83
126
|
end
|
84
127
|
end
|
85
128
|
|
@@ -135,6 +178,7 @@ def configure(option_name)
|
|
135
178
|
current_value = current_value.first
|
136
179
|
end
|
137
180
|
value = opt.ask(current_value)
|
181
|
+
@modified = true
|
138
182
|
config[option_name] = [value, true]
|
139
183
|
displayed_options[option_name] = value
|
140
184
|
value
|
@@ -143,14 +187,15 @@ def configure(option_name)
|
|
143
187
|
end
|
144
188
|
end
|
145
189
|
|
146
|
-
def load(
|
147
|
-
|
148
|
-
|
149
|
-
reconfigure: false
|
150
|
-
|
151
|
-
if h = YAML.load(File.read(options[:path]))
|
190
|
+
def load(path: self.path, reconfigure: false)
|
191
|
+
current_keys = @config.keys
|
192
|
+
if h = YAML.load(File.read(path))
|
152
193
|
h.each do |key, value|
|
153
|
-
|
194
|
+
current_keys.delete(key)
|
195
|
+
set(key, value, !reconfigure)
|
196
|
+
end
|
197
|
+
if current_keys.empty?
|
198
|
+
@modified = false
|
154
199
|
end
|
155
200
|
end
|
156
201
|
end
|
@@ -160,11 +205,14 @@ def reconfigure!
|
|
160
205
|
config.each do |key, (value, _user_validated)|
|
161
206
|
new_config[key] = [value, false]
|
162
207
|
end
|
208
|
+
@modified = true
|
163
209
|
@config = new_config
|
164
210
|
end
|
165
211
|
|
166
|
-
def save(path = self.path)
|
167
|
-
|
212
|
+
def save(path = self.path, force: false)
|
213
|
+
return if !modified? && !force
|
214
|
+
|
215
|
+
Ops.atomic_write(path) do |io|
|
168
216
|
h = Hash.new
|
169
217
|
config.each do |key, value|
|
170
218
|
h[key] = value.first
|
@@ -172,6 +220,7 @@ def save(path = self.path)
|
|
172
220
|
|
173
221
|
io.write YAML.dump(h)
|
174
222
|
end
|
223
|
+
@modified = false
|
175
224
|
end
|
176
225
|
|
177
226
|
def each_reused_autoproj_installation
|
@@ -474,6 +523,9 @@ def to_hash
|
|
474
523
|
@config.each do |key, (value, _)|
|
475
524
|
result[key] = value
|
476
525
|
end
|
526
|
+
overrides.each do |key, value|
|
527
|
+
result[key] = value
|
528
|
+
end
|
477
529
|
result
|
478
530
|
end
|
479
531
|
end
|