autoproj 2.4.0 → 2.5.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|