Checkpoint

This commit is contained in:
josh committed 2022-01-23 16:44:18 -05:00
1 parent f5ab51c477
commit 125ab4c171
136 files changed
+707 -615

No files matched your search

+1
View File
@@ -10,6 +10,7 @@ require_relative "rscons/configure_op"
require_relative "rscons/default_construction_variables"
require_relative "rscons/environment"
require_relative "rscons/script"
require_relative "rscons/task"
require_relative "rscons/util"
require_relative "rscons/varset"
require_relative "rscons/version"
+44 -97
View File
@@ -31,29 +31,19 @@ module Rscons
ENV.delete("RSCONS_BUILD_DIR")
@n_threads = Util.determine_n_threads
@vars = VarSet.new
@operations = Set.new
@build_step = 0
end
# Check whether a requested operation is active.
# Run the application.
#
# @param op [String]
# Operation name.
# Execute user-specified tasks.
#
# @return [Boolean]
# Whether the requested operation is active.
def operation(op)
@operations.include?(op)
end
# Run the specified operation.
# @api private
#
# @param operation [String]
# The operation to perform (e.g. "clean", "configure", "build", etc...)
# @param script [Script]
# The script.
# @param operation_options [Hash]
# Option values from the CLI for the operation.
# @param tasks_and_params [Array<Array<String>>]
# List of task(s) to execute and possibly parameter(s) for them.
# @param options [Hash]
# Optional parameters.
# @option sub_op [Boolean]
@@ -61,49 +51,30 @@ module Rscons
#
# @return [Integer]
# Process exit code (0 on success).
def run(operation, script, operation_options, options = {})
@start_time = Time.new
def run(script, tasks_and_params, options = {})
@script = script
@operations << operation
puts "Starting '#{operation}' at #{Time.new}" if verbose
rv =
case operation
when "build"
rv = 0
unless Cache.instance["configuration_data"]["configured"]
rv =
if @script.autoconf
run("configure", script, operation_options, sub_op: false)
else
$stderr.puts "Project must be configured first, and autoconf is disabled"
1
end
end
if rv == 0
build(operation_options)
else
rv
end
when "clean"
clean
when "configure"
configure(operation_options)
when "distclean"
distclean
when "install"
run("build", script, operation_options, sub_op: false)
when "uninstall"
uninstall
else
$stderr.puts "Unknown operation: #{operation}"
1
Cache.instance["failed_commands"] = []
begin
tasks_and_params.each do |task_and_params|
task_name, *task_params = task_and_params
Task[task_name].check_execute
end
if verbose and options[:sub_op].nil?
time = Time.new
elapsed = time - @start_time
puts "'#{operation}' complete at #{time} (#{Util.format_elapsed_time(elapsed)})"
0
rescue RsconsError => e
Ansi.write($stderr, :red, e.message, :reset, "\n")
1
end
end
# Show the last failures.
#
# @return [void]
def show_failure
failed_commands = Cache.instance["failed_commands"]
failed_commands.each_with_index do |command, i|
Ansi.write($stdout, :red, "Failed command (#{i + 1}/#{failed_commands.size}):", :reset, "\n")
$stdout.puts Util.command_to_s(command)
end
rv
end
# Get the next build step number.
@@ -125,33 +96,11 @@ module Rscons
end
end
private
# Build the project.
#
# @param options [Hash]
# Options.
#
# @return [Integer]
# Exit code.
def build(options)
begin
Cache.instance["failed_commands"] = []
@script.build
Environment.environments.each do |env|
env.process
end
0
rescue RsconsError => e
Ansi.write($stderr, :red, e.message, :reset, "\n")
1
end
end
# Remove all generated files.
#
# @return [Integer]
# Exit code.
# @api private
#
# @return [void]
def clean
cache = Cache.instance
# remove all built files
@@ -168,49 +117,48 @@ module Rscons
end
end
cache.write
0
end
# Remove the build directory and clear the cache.
#
# @return [Integer]
# Exit code.
# @api private
#
# @return [void]
def distclean
cache = Cache.instance
clean
FileUtils.rm_rf(@build_dir)
cache.clear
0
end
# Configure the project.
#
# @api private
#
# @param options [Hash]
# Options.
#
# @return [Integer]
# Exit code.
def configure(options)
rv = 0
options = options.merge(project_name: @script.project_name)
# @return [void]
def configure
options = {project_name: @script.project_name}
co = ConfigureOp.new(options)
begin
@script.configure(co)
rescue RsconsError => e
if e.message and e.message != ""
$stderr.puts e.message
end
Ansi.write($stderr, :red, "Configuration failed", :reset, "\n")
rv = 1
co.close(false)
raise e
end
co.close(rv == 0)
rv
co.close(true)
end
# Remove installed files.
#
# @api private
#
# @return [Integer]
# Exit code.
#
# @return [void]
def uninstall
cache = Cache.instance
cache.targets(true).each do |target|
@@ -229,7 +177,6 @@ module Rscons
end
end
cache.write
0
end
end
+42 -68
View File
@@ -3,7 +3,7 @@ require "optparse"
# CLI usage string.
USAGE = <<EOF
Usage: #{$0} [global options] [operation] [operation options]
Usage: #{$0} [global options] [task] [task options]
Global options:
-b BUILD, --build=BUILD Set build directory (default: build)
@@ -15,16 +15,7 @@ Global options:
-v, --verbose Run verbosely
--version Show rscons version and exit
Operations:
configure Configure the project
build Build the project
clean Remove build artifacts (but not configuration)
distclean Remove build directory and configuration
install Install project to installation destination
uninstall Uninstall project from installation destination
Configure options:
--prefix=PREFIX Set installation prefix (default: /usr/local)
Tasks:
EOF
module Rscons
@@ -55,27 +46,16 @@ module Rscons
private
def add_global_options(opts)
opts.on("-b", "--build DIR") do |build_dir|
Rscons.application.build_dir = build_dir
end
opts.on("-j NTHREADS") do |n_threads|
Rscons.application.n_threads = n_threads.to_i
end
opts.on("-r", "--color MODE") do |color_mode|
case color_mode
when "off"
Rscons.application.do_ansi_color = false
when "force"
Rscons.application.do_ansi_color = true
def parse_tasks_and_params(argv)
tasks_and_params = []
argv.each do |arg|
if arg.start_with?("-")
tasks_and_params[-1] << arg
else
tasks_and_params << [arg]
end
end
opts.on("-v", "--verbose") do
Rscons.application.verbose = true
end
tasks_and_params
end
def run_toplevel(argv)
@@ -84,19 +64,16 @@ module Rscons
OptionParser.new do |opts|
add_global_options(opts)
opts.on("-b", "--build DIR") do |build_dir|
Rscons.application.build_dir = build_dir
end
opts.on("-f FILE") do |f|
rsconscript = f
end
opts.on("-F", "--show-failure") do
show_failure
exit 0
end
opts.on("--version") do
puts "Rscons version #{Rscons::VERSION}"
Rscons.application.show_failure
exit 0
end
@@ -104,10 +81,35 @@ module Rscons
do_help = true
end
opts.on("-j NTHREADS") do |n_threads|
Rscons.application.n_threads = n_threads.to_i
end
opts.on("-r", "--color MODE") do |color_mode|
case color_mode
when "off"
Rscons.application.do_ansi_color = false
when "force"
Rscons.application.do_ansi_color = true
end
end
opts.on("-v", "--verbose") do
Rscons.application.verbose = true
end
opts.on("--version") do
puts "Rscons version #{Rscons::VERSION}"
exit 0
end
end.order!(argv)
# Retrieve the operation, or default to build.
operation = argv.shift || "build"
tasks_and_params = parse_tasks_and_params(argv)
if tasks_and_params.empty?
tasks_and_params << ["default"]
end
argv.each do |arg|
if arg =~ /^([^=]+)=(.*)$/
@@ -142,35 +144,7 @@ module Rscons
exit 1
end
operation_options = parse_operation_args(operation, argv) || {}
exit Rscons.application.run(operation, script, operation_options)
end
def parse_operation_args(operation, argv)
options = {}
OptionParser.new do |opts|
add_global_options(opts)
case operation
when "configure"
parse_configure_args(opts, argv, options)
end
end.order!(argv)
options
end
def parse_configure_args(opts, argv, options)
opts.on("--prefix PREFIX") do |prefix|
options[:prefix] = prefix
end
end
def show_failure
failed_commands = Cache.instance["failed_commands"]
failed_commands.each_with_index do |command, i|
Ansi.write($stdout, :red, "Failed command (#{i + 1}/#{failed_commands.size}):", :reset, "\n")
$stdout.puts Util.command_to_s(command)
end
exit Rscons.application.run(script, tasks_and_params)
end
end
+10
View File
@@ -14,6 +14,10 @@ module Rscons
# All Environments.
attr_reader :environments
# @return [Environment]
# The Environment that is currently executing a construction block.
attr_accessor :open_environment
# Initialize class instance variables.
def class_init
@environments = []
@@ -109,7 +113,10 @@ module Rscons
@n_threads = Rscons.application.n_threads
if block_given?
Environment.open_environment = self
yield self
Environment.open_environment = nil
process
end
end
@@ -158,7 +165,10 @@ module Rscons
env.instance_variable_set(:@n_threads, @n_threads)
if block_given?
Environment.open_environment = env
yield env
Environment.open_environment = nil
env.process
end
env
end
+66 -34
View File
@@ -5,6 +5,10 @@ module Rscons
# Global DSL methods.
class GlobalDsl
# Create a GlobalDsl.
def initialize(script)
@script = script
end
# Return a list of paths matching the specified pattern(s).
#
@@ -159,6 +163,16 @@ module Rscons
end
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
[
:cd,
:chmod,
@@ -191,12 +205,7 @@ module Rscons
end
# Top-level DSL available to the Rsconscript.
class Dsl < GlobalDsl
# Create a Dsl.
def initialize(script)
@script = script
end
class TopLevelDsl < GlobalDsl
# Set the project name.
def project_name(project_name)
@script.project_name = project_name
@@ -207,14 +216,18 @@ module Rscons
@script.autoconf = autoconf
end
# Enter build block.
def build(&block)
@script.operations["build"] = block
end
# Enter configuration block.
def configure(&block)
@script.operations["configure"] = block
# Shortcut methods to create task blocks for special tasks.
[
:clean,
:distclean,
:configure,
:default,
:install,
:uninstall,
].each do |method_name|
define_method(method_name) do |*args, &block|
task(method_name.to_s, *args, &block)
end
end
end
@@ -222,9 +235,12 @@ module Rscons
class ConfigureDsl < GlobalDsl
# Create a ConfigureDsl.
#
# @param script [Script]
# The Script being evaluated.
# @param configure_op [ConfigureOp]
# The configure operation object.
def initialize(configure_op)
def initialize(script, configure_op)
super(script)
@configure_op = configure_op
end
@@ -263,18 +279,18 @@ module Rscons
attr_accessor :project_name
# @return [Boolean]
# Whether to autoconfigure if the user does not explicitly perform a
# configure operation before building (default: true).
# Whether to autoconfigure if the user does not explicitly configure
# before calling a normal task (default: true).
attr_accessor :autoconf
# @return [Hash]
# Operation lambdas.
attr_reader :operations
# Tasks.
attr_reader :tasks
# Construct a Script.
def initialize
@autoconf = true
@operations = {}
@tasks = {}
end
# Load a script from the specified file.
@@ -285,22 +301,38 @@ module Rscons
# @return [void]
def load(path)
script_contents = File.read(path, mode: "rb")
Dsl.new(self).instance_eval(script_contents, path, 1)
dsl = TopLevelDsl.new(self)
dsl.instance_eval do
task("clean",
desc: "Remove build artifacts (but not configuration)",
autoconf: false) do
Rscons.application.clean
end
task("configure",
desc: "Configure the project",
autoconf: false) do
Rscons.application.configure
end
task("distclean",
desc: "Remove build directory and configuration",
autoconf: false) do
Rscons.application.distclean
end
task("install"
desc: "Install project to configured installation prefix")
task("uninstall",
desc: "Uninstall project",
autoconf: false) do
Rscons.application.uninstall
end
end
dsl.instance_eval(script_contents, path, 1)
end
# Perform build operation.
def build
if build_proc = @operations["build"]
build_proc.call
end
end
# Perform configure operation.
def configure(configure_op)
if operation_lambda = @operations["configure"]
cdsl = ConfigureDsl.new(configure_op)
cdsl.instance_eval(&operation_lambda)
end
# Perform configure action.
def configure(configure_op, action)
cdsl = ConfigureDsl.new(self, configure_op)
cdsl.instance_eval(&action)
end
end
+143
View File
@@ -0,0 +1,143 @@
module Rscons
# A task is a named collection of actions and/or dependencies.
class Task
class << self
# Access a task by name.
#
# @param name [String, nil]
# Task name, or nil to return a Hash of all tasks.
#
# @return [Hash, Task, nil]
# Hash of all tasks if name is nil, otherwise Task with the given name,
# if found.
def [](name)
if name
if task = tasks[name]
task
else
raise RsconsError.new("Task '#{name}' not found")
end
else
tasks
end
end
# Register a newly created task.
#
# @api private
#
# @param task [Task]
# Task to register.
#
# @return [void]
def register(task)
tasks[task.name] = task
end
# Get all registered tasks.
#
# @api private
#
# @return [Hash]
# All registered tasks.
def tasks
@tasks ||= {}
end
end
# @return [Boolean]
# 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
# @return [String]
# Task name.
attr_reader :name
# Construct a task.
#
# @param name [String]
# Task name.
# @param options [Hash]
# Task options.
# @option options [Boolean] :autoconf
# Whether to automatically configure before running this task (default
# true).
def initialize(name, options, &block)
@name = name
@actions = []
@deps = []
@autoconf = true
Task.register(self)
modify(options, &block)
end
# Execute a task's actions.
#
# @return [void]
def execute
@executed = true
if @autoconf
unless Cache.instance["configuration_data"]["configured"]
Task["configure"].check_execute
end
end
@deps.each do |dep|
end
@actions.each do |action|
action[]
end
end
# Check if the task has been executed, and if not execute it.
#
# @return [void]
def check_execute
unless executed?
execute
end
end
# Check if the task has been executed.
#
# @return [Boolean]
# Whether the task has been executed.
def executed?
@executed
end
# Modify a task.
#
# @api private
#
# @return [void]
def modify(options, &block)
if options.include?(:autoconf)
@autoconf = options[:autoconf]
end
if block
if env = Environment.open_environment
@actions << proc do
block[]
env.process
end
else
@actions << block
end
end
end
end
end