Add shortcut method for creating environments - close #149

Add env() method to create environments.
Process all environments created at build script top level before
executing any autoconf-enabled tasks, or if no tasks are specified by
the user.
This commit is contained in:
josh committed 2022-02-12 21:59:52 -05:00
1 parent 6d5f44d4e5
commit ef7e9259cb
129 files changed
+742 -901

No files matched your search

+65 -4
View File
@@ -39,15 +39,32 @@ module Rscons
#
# @api private
#
# @param tasks [Array<String>]
# @param rsconscript [String]
# Build script file name.
# @param tasks_and_params [Hash<String => Hash<String => String>>]
# List of task(s) to execute.
# @param show_tasks [Boolean]
# Flag to show tasks and exit.
#
# @return [Integer]
# Process exit code (0 on success).
def run(tasks)
def run(rsconscript, tasks_and_params, show_tasks)
Cache.instance["failed_commands"] = []
tasks.each do |task|
Task[task].check_execute
@script.load(rsconscript)
if show_tasks
show_script_tasks
return 0
end
apply_task_params(tasks_and_params)
if tasks_and_params.empty?
check_process_environments
if Task.tasks["default"]
Task["default"].check_execute
end
else
tasks_and_params.each do |task_name, params|
Task[task_name].check_execute
end
end
0
end
@@ -111,6 +128,20 @@ module Rscons
end
end
# Check if environments need to be processed.
#
# @api private
#
# @return [void]
def check_process_environments
unless @_processed_environments
Environment[].each do |env|
env.process
end
@_processed_environments = true
end
end
# Configure the project.
#
# @api private
@@ -158,6 +189,36 @@ module Rscons
cache.write
end
private
def show_script_tasks
puts "Tasks:"
Task[].each do |task_name, task|
if task.description
puts %[ #{sprintf("%-27s", task_name)} #{task.description}]
task.params.each do |param_name, param|
arg_text = "--#{param_name}"
if param.takes_arg
arg_text += "=#{param_name.upcase}"
end
puts %[ #{sprintf("%-25s", "#{arg_text}")} #{param.description}]
end
end
end
end
def apply_task_params(tasks_and_params)
tasks_and_params.each do |task_name, task_params|
task_params.each do |param_name, param_value|
if param = Task[task_name].params[param_name]
param.value = param_value
else
raise RsconsError.new("Unknown parameter #{param_name.inspect} for task #{task_name}")
end
end
end
end
end
end
+32 -71
View File
@@ -28,41 +28,32 @@ module Rscons
private
def parse_task_params(task, argv)
task_params = {}
while argv.size > 0
if argv[0].start_with?("-")
valid_arg = false
if argv[0] =~ /^--(\S+?)(?:=(.*))?$/
param_name, value = $1, $2
if param = Task[task].params[param_name]
param.value = value || argv[0]
argv.slice!(0)
valid_arg = true
end
end
unless valid_arg
$stderr.puts "Invalid task '#{task}' argument '#{argv[0].split("=").first}'"
$stderr.puts usage
exit 2
end
if argv[0] =~ /^--(\S+?)(?:=(.*))?$/
param_name, param_value = $1, $2
param_value ||= true
task_params[param_name] = param_value
argv.slice!(0)
else
return
break
end
end
task_params
end
def parse_tasks_and_params(argv)
tasks = []
tasks_and_params = {}
while argv.size > 0
task = argv.shift
parse_task_params(task, argv)
tasks << task
tasks_and_params[task] = parse_task_params(task, argv)
end
tasks
tasks_and_params
end
def run_toplevel(argv)
rsconscript = nil
do_help = false
show_tasks = false
OptionParser.new do |opts|
@@ -80,7 +71,8 @@ module Rscons
end
opts.on("-h", "--help") do
do_help = true
puts usage
return 0
end
opts.on("-j NTHREADS") do |n_threads|
@@ -96,6 +88,10 @@ module Rscons
end
end
opts.on("-T", "--tasks") do
show_tasks = true
end
opts.on("-v", "--verbose") do
Rscons.application.verbose = true
end
@@ -107,6 +103,9 @@ module Rscons
end.order!(argv)
# Parse the rest of the command line.
tasks_and_params = parse_tasks_and_params(argv)
# Find the build script.
if rsconscript
unless File.exists?(rsconscript)
@@ -119,40 +118,16 @@ module Rscons
end
end
# Anything else requires a build script, so complain if we didn't find
# one.
unless rsconscript
$stderr.puts "Could not find the Rsconscript to execute."
$stderr.puts "Looked for: #{DEFAULT_RSCONSCRIPTS.join(", ")}"
return 1
end
begin
# Load the build script.
if rsconscript
Rscons.application.script.load(rsconscript)
end
# Do help after loading the build script (if found) so that any
# script-defined tasks and task options can be displayed.
if do_help
puts usage
return 0
end
# Anything else requires a build script, so complain if we didn't find
# one.
unless rsconscript
$stderr.puts "Could not find the Rsconscript to execute."
$stderr.puts "Looked for: #{DEFAULT_RSCONSCRIPTS.join(", ")}"
return 1
end
# Parse the rest of the command line. This is done after loading the
# build script so that script-defined tasks and task options can be
# taken into account.
tasks = parse_tasks_and_params(argv)
# If no user specified tasks, run "default" task.
if tasks.empty?
tasks << "default"
end
# Finally, with the script fully loaded and command-line parsed, run
# the application to execute all required tasks.
Rscons.application.run(tasks)
Rscons.application.run(rsconscript, tasks_and_params, show_tasks)
rescue RsconsError => e
Ansi.write($stderr, :red, e.message, :reset, "\n")
1
@@ -160,7 +135,7 @@ module Rscons
end
def usage
usage = <<EOF
<<EOF
Usage: #{$0} [global options] [[task] [task options] ...]
Global options:
@@ -170,24 +145,10 @@ Global options:
-h, --help Show rscons help and exit
-j N, --nthreads=N Set number of threads (local default: #{Rscons.application.n_threads})
-r COLOR, --color=COLOR Set color mode (off, auto, force)
-T, --tasks Show task list and parameters and exit
-v, --verbose Run verbosely
--version Show rscons version and exit
Tasks:
EOF
Task[].each do |name, task|
if task.desc
usage += %[ #{sprintf("%-27s", name)} #{task.desc}\n]
task.params.each do |name, param|
arg_text = "--#{name}"
if param.takes_arg
arg_text += "=#{name.upcase}"
end
usage += %[ #{sprintf("%-25s", "#{arg_text}")} #{param.description}\n]
end
end
end
usage
end
end
+49 -27
View File
@@ -10,16 +10,13 @@ module Rscons
class << self
# @return [Array<Environment>]
# All Environments.
attr_reader :environments
# @return [Environment]
# The Environment that is currently executing a construction block.
attr_accessor :open_environment
attr_accessor :running_environment
# Initialize class instance variables.
def class_init
@environments_by_name = {}
@environments = []
end
@@ -36,9 +33,24 @@ module Rscons
# Register an Environment.
def register(env)
@environments ||= []
@environments << env
if env.name
@environments_by_name[env.name] = env
end
end
# Get an Environment by name.
#
# @param name [String]
# Environment name.
def [](name = nil)
if name
@environments_by_name[name]
else
@environments
end
end
end
# @return [Hash] Set of !{"builder_name" => builder_object} pairs.
@@ -61,28 +73,36 @@ module Rscons
# Create an Environment object.
#
# @overload initialize(name, options)
# @overload initialize(options)
#
# @param name [String]
# Environment name. This determines the folder name used to store all
# environment build files under the top-level build directory.
# @param options [Hash]
# @option options [Symbol] :echo
# :command, :short, or :off (default :short)
# @option options [Boolean] :exclude_builders
# Whether to omit adding default builders (default false)
# @option options [String, nil] :name
# Environment name. This determines the folder name used to store all
# environment build files under the top-level build directory.
# @option options [String, Array<String>] :use
# Use flag(s). If specified, any configuration flags which were saved
# with a corresponding `:use` value will be applied to this Environment.
#
# If a block is given, the Environment object is yielded to the block and
# when the block returns, the {#process} method is automatically called.
def initialize(options = {})
def initialize(*args, &block)
@id = self.class.get_id
if args.first.is_a?(String)
@name = args.slice!(0)
else
@name = "e.#{@id}"
end
options = args.first || {}
Rscons.application.check_configure
unless Cache.instance["configuration_data"]["configured"]
raise "Project must be configured before creating an Environment"
end
super(options)
@id = self.class.get_id
self.class.register(self)
# Hash of Thread object => {Command} or {Builder}.
@threads = {}
@registered_build_dependencies = {}
@@ -109,15 +129,13 @@ module Rscons
else
:short
end
@name = options[:name] || "e.#{@id}"
@build_root = "#{Rscons.application.build_dir}/#{@name}"
@n_threads = Rscons.application.n_threads
if block_given?
Environment.open_environment = self
yield self
Environment.open_environment = nil
process
self.class.register(self)
if block
Environment.running_environment = self
block[self]
Environment.running_environment = nil
end
end
@@ -140,7 +158,11 @@ module Rscons
# Any options that #initialize receives can also be specified here.
#
# @return [Environment] The newly created {Environment} object.
def clone(options = {})
def clone(*args, &block)
if args.first.is_a?(String)
name = args.slice!(0)
end
options = args.first || {}
options = options.dup
clone = options[:clone] || :all
clone = Set[:variables, :builders, :build_hooks] if clone == :all
@@ -148,7 +170,9 @@ module Rscons
clone = Set.new(clone) if clone.is_a?(Array)
clone.delete(:builders) if options[:exclude_builders]
options[:echo] ||= @echo
env = self.class.new(options.merge(exclude_builders: true))
new_args = name ? [name] : []
new_args << options.merge(exclude_builders: true)
env = self.class.new(*new_args)
if clone.include?(:builders)
@builders.each do |builder_name, builder|
env.add_builder(builder)
@@ -164,12 +188,10 @@ module Rscons
end
end
env.instance_variable_set(:@n_threads, @n_threads)
if block_given?
Environment.open_environment = env
yield env
Environment.open_environment = nil
env.process
if block
Environment.running_environment = self
block[env]
Environment.running_environment = nil
end
env
end
+7 -7
View File
@@ -93,6 +93,11 @@ module Rscons
end
end
# Create an environment.
def env(*args, &block)
Environment.new(*args, &block)
end
# Construct a task parameter.
#
# @param name [String]
@@ -235,13 +240,8 @@ module Rscons
end
# Create or modify a task.
def task(name, options = {}, &block)
if task = Task.tasks[name]
task.modify(options, &block)
else
task = Task.new(name, options, &block)
end
task
def task(*args, &block)
Util.task(*args, &block)
end
[
+10 -13
View File
@@ -95,13 +95,9 @@ module Rscons
# Whether to automatically configure before running this task.
attr_reader :autoconf
# @return [Array<String>]
# Task dependencies.
attr_reader :deps
# @return [String, nil]
# Task description, if given.
attr_reader :desc
attr_reader :description
# @return [String]
# Task name.
@@ -122,8 +118,8 @@ module Rscons
# true).
def initialize(name, options, &block)
@autoconf = true
@deps = []
@desc = nil
@dependencies = []
@description = nil
@name = name
@params = {}
@actions = []
@@ -153,9 +149,10 @@ module Rscons
@executed = true
if @autoconf
Rscons.application.check_configure
Rscons.application.check_process_environments
end
@deps.each do |dep|
Task[dep].check_execute
@dependencies.each do |dependency|
Task[dependency].check_execute
end
if @name == "configure"
Rscons.application.configure
@@ -193,10 +190,10 @@ module Rscons
@autoconf = options[:autoconf]
end
if options.include?(:desc)
@desc = options[:desc]
@description = options[:desc]
end
if options.include?(:deps)
@deps += Array(options[:deps])
if options.include?(:depends)
@dependencies += Array(options[:depends])
end
if options.include?(:params)
Array(options[:params]).each do |param|
@@ -204,7 +201,7 @@ module Rscons
end
end
if block
if env = Environment.open_environment
if env = Environment.running_environment
@actions << proc do
block[]
env.process
+10
View File
@@ -191,6 +191,16 @@ module Rscons
deps
end
# Create or modify a task.
def task(name, options = {}, &block)
if task = Task.tasks[name]
task.modify(options, &block)
else
task = Task.new(name, options, &block)
end
task
end
# Wait for any of a number of threads to complete.
#
# @param threads [Array<Thread>]