Skip to content

Commit

Permalink
Permit autoproj to perform configuration noninteractively by relying …
Browse files Browse the repository at this point in the history
…on the default values
  • Loading branch information
2maz committed Feb 28, 2019
1 parent 8ab9481 commit 1c049fb
Show file tree
Hide file tree
Showing 7 changed files with 201 additions and 15 deletions.
31 changes: 24 additions & 7 deletions lib/autoproj/build_option.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,35 @@ def doc
end
end

# Return either the current value if it is not nil, or use
# a default value
#
# @return [value, Boolean] Current value, and flag whether this is a
# default value
def ensure_value(current_value)
if !current_value.nil?
return current_value.to_s, false
elsif options[:default]
return options[:default].to_str, true
else
return '', true
end
end

# Ask the user for the setting of this option
# by providing the current value as input and falling
# back to default values if needed
#
# @param [String] current_value the option's current value
# @param [String] doc a string to override the default option banner
def ask(current_value, doc = nil)
default_value =
if !current_value.nil? then current_value.to_s
elsif options[:default] then options[:default].to_str
else ''
end
value,_ = ensure_value(current_value)

STDOUT.print " #{doc || self.doc} [#{default_value}] "
STDOUT.print " #{doc || self.doc} [#{value}] "
STDOUT.flush
answer = STDIN.readline.chomp
if answer == ''
answer = default_value
answer = value
end
validate(answer)

Expand Down
4 changes: 3 additions & 1 deletion lib/autoproj/cli/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -176,11 +176,13 @@ def self.validate_options(args, options)
debug: false,
color: TTY::Color.color?,
progress: TTY::Color.color?,
parallel: nil
parallel: nil,
interactive: nil

Autoproj.silent = options[:silent]
Autobuild.color = options[:color]
Autobuild.progress_display_enabled = options[:progress]
Autoproj::Configuration.interactive = options[:interactive]

if options[:verbose]
Autoproj.verbose = true
Expand Down
2 changes: 2 additions & 0 deletions lib/autoproj/cli/main.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class Main < Thor
desc: 'enables or disables colored display (enabled by default if the terminal supports it)'
class_option :progress, type: :boolean, default: TTY::Color.color?,
desc: 'enables or disables progress display (enabled by default if the terminal supports it)'
class_option 'interactive', type: :boolean, default: nil,
desc: 'tell autoproj to run (non)interactively'

stop_on_unknown_option! :exec
check_unknown_options! except: :exec
Expand Down
49 changes: 45 additions & 4 deletions lib/autoproj/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ module Autoproj
# Class that does the handling of configuration options as well as
# loading/saving on disk
class Configuration
class << self
attr_accessor :interactive
end

# Set of currently known options
#
# These are the values that are going to be saved on disk. Use
Expand Down Expand Up @@ -177,10 +181,18 @@ def configure(option_name)
if current_value = config[option_name]
current_value = current_value.first
end
value = opt.ask(current_value)
is_default = false
if interactive?
value = opt.ask(current_value, nil)
else
value, is_default = opt.ensure_value(current_value)
Autoproj.info " using: #{value} (noninteractive mode)"
end
@modified = true
config[option_name] = [value, true]
displayed_options[option_name] = value
if !is_default
config[option_name] = [value, true]
displayed_options[option_name] = value
end
value
else
raise ConfigError.new, "undeclared option '#{option_name}'"
Expand Down Expand Up @@ -440,6 +452,31 @@ def randomize_layout=(value)
set('randomize_layout', value, true)
end

# Sets whether the configuration should be done interactively
# by asking the user, or non-interactively by using the provided default
# value of an option
#
# @return [Boolean]
# @see interactive?
def interactive=(flag)
set('interactive', flag, true)
end

# Returns true if the configuration should be performed interactively
#
# @return [Boolean]
# @see interactive=
def interactive?
if !Configuration.interactive.nil?
return Configuration.interactive
elsif ENV['AUTOPROJ_NONINTERACTIVE'] == '1'
return false
elsif has_value_for?("interactive")
return get('interactive')
end
true
end

DEFAULT_UTILITY_SETUP = Hash[
'doc' => true,
'test' => false]
Expand Down Expand Up @@ -545,7 +582,11 @@ def prefer_indep_over_os_packages?
def to_hash
result = Hash.new
@config.each do |key, (value, _)|
result[key] = value
if declared_options.include?(key)
result[key] = declared_options[key].ensure_value(value)
else
result[key] = value
end
end
overrides.each do |key, value|
result[key] = value
Expand Down
9 changes: 6 additions & 3 deletions lib/autoproj/test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ def ws_create_os_package_resolver
os_package_manager: 'os')
end

def ws_create(dir = make_tmpdir)
def ws_create(dir = make_tmpdir, partial_config: false)
require 'autoproj/ops/main_config_switcher'
FileUtils.cp_r Ops::MainConfigSwitcher::MAIN_CONFIGURATION_TEMPLATE, File.join(dir, 'autoproj')
FileUtils.mkdir_p File.join(dir, '.autoproj')
Expand All @@ -280,8 +280,11 @@ def ws_create(dir = make_tmpdir)
@ws = Workspace.new(
dir, os_package_resolver: ws_os_package_resolver,
package_managers: ws_package_managers)
ws.config.set 'osdeps_mode', 'all'
ws.config.set 'apt_dpkg_update', true

if !partial_config
ws.config.set 'osdeps_mode', 'all'
ws.config.set 'apt_dpkg_update', true
end
ws.config.set 'GITHUB', 'http,ssh', true
ws.config.set 'GITORIOUS', 'http,ssh', true
ws.config.set 'gems_install_path', File.join(dir, 'gems')
Expand Down
42 changes: 42 additions & 0 deletions test/cli/test_reconfigure.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
require 'autoproj/test'
require 'autoproj/cli/main'
require 'autoproj/cli/reconfigure'
require 'timeout'

module Autoproj
module CLI
describe Reconfigure do
attr_reader :ws
before do
option_name = "custom-configuration-option"
default_value = "option-defaultvalue"

@ws = ws_create(make_tmpdir, partial_config: true)
end
after do
Autoproj.verbose = false
end
describe "#reconfigure" do
def run_command(*args)
capture_subprocess_io do
ENV['AUTOPROJ_CURRENT_ROOT'] = ws.root_path.to_s
in_ws do
Main.start([*args,"--debug"], debug: true)
end
end
end

it "reconfigure should run interactively" do
assert_raises Timeout::Error do
Timeout.timeout(3) do
run_command 'reconfigure'
end
end
end
it "reconfigure should run non interactively" do
run_command 'reconfigure','--no-interactive'
end
end
end
end
end
79 changes: 79 additions & 0 deletions test/test_configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,85 @@ module Autoproj
refute @config.modified?
end
end
describe "#interactive" do
it "set interactive mode" do
@config.interactive = false
assert !@config.interactive?

@config.interactive = true
assert @config.interactive?
end

it "disables interactive configuration setting through config option" do
option_name = "custom-configuration-option"
default_value = "option-defaultvalue"
@config.declare(option_name,"string",default: default_value)

@config.interactive = false

Timeout.timeout(3) do
@config.configure(option_name)
end
assert @config.get(option_name) == default_value
end

it "disables interactive configuration setting through ENV" do
option_name = "custom-configuration-option"
default_value = "option-defaultvalue"
@config.declare(option_name,"string",default: default_value)

ENV['AUTOPROJ_NONINTERACTIVE'] = '1'

assert !@config.interactive?
begin
Timeout.timeout(3) do
@config.configure(option_name)
end
assert @config.get(option_name) == default_value
ensure
ENV.delete('AUTOPROJ_NONINTERACTIVE')
end
end
it "use interactive configuration by default" do
option_name = "custom-configuration-option"
default_value = "option-defaultvalue"
@config.declare(option_name,"string",default: default_value)
assert @config.interactive?
assert_raises Timeout::Error do
Timeout.timeout(3) do
@config.configure(option_name)
end
end
end
it "skip saving default value" do
option_a_name = "custom-configuration-option-a"
default_a_value = "option-a-defaultvalue"

option_b_name = "custom-configuration-option-b"
default_b_value = "option-b-default-value"
b_value = "option-b-value"

@config.declare(option_a_name,"string",default: default_a_value)
@config.declare(option_b_name,"string",default: default_b_value)

@config.interactive = false
@config.configure(option_a_name)
@config.set(option_b_name, b_value)
@config.configure(option_b_name)

assert !@config.has_value_for?(option_a_name)
assert @config.has_value_for?(option_b_name)

tempfile = Tempfile.new("skip-saving-config")
@config.save(tempfile)

loaded_config = Configuration.new(tempfile)
loaded_config.load
assert !loaded_config.has_value_for?(option_a_name)
assert loaded_config.has_value_for?(option_b_name)
assert loaded_config.get(option_b_name) == b_value
end
end
end
end

Expand Down

0 comments on commit 1c049fb

Please sign in to comment.