add Application class; update CLI and Script for new architecture

This commit is contained in:
Josh Holtrop 2018-10-21 01:03:40 -04:00
parent ea6ae1be10
commit ac89a122d8
8 changed files with 199 additions and 164 deletions

View File

@ -1,4 +1,5 @@
require_relative "rscons/ansi"
require_relative "rscons/application"
require_relative "rscons/build_target"
require_relative "rscons/builder"
require_relative "rscons/cache"
@ -48,18 +49,13 @@ module Rscons
class << self
# @return [Integer]
# The number of threads to use when scheduling subprocesses.
attr_accessor :n_threads
# @return [Boolean]
# Whether to output ANSI color escape sequences.
attr_accessor :do_ansi_color
# @since 1.16.0
# @return [VarSet]
# Access any variables set on the rscons command-line.
attr_reader :vars
# Access the Application singleton.
#
# @return [Application]
# The Application singleton.
def application
@application ||= Application.new
end
# Remove all generated files.
#
@ -200,46 +196,8 @@ module Rscons
end.sort
end
private
# Determine the number of threads to use by default.
#
# @return [Integer]
# The number of threads to use by default.
def determine_n_threads
# If the user specifies the number of threads in the environment, then
# respect that.
if ENV["RSCONS_NTHREADS"] =~ /^(\d+)$/
return $1.to_i
end
# Otherwise try to figure out how many threads are available on the
# host hardware.
begin
case RbConfig::CONFIG["host_os"]
when /linux/
return File.read("/proc/cpuinfo").scan(/^processor\s*:/).size
when /mswin|mingw/
if `wmic cpu get NumberOfLogicalProcessors /value` =~ /NumberOfLogicalProcessors=(\d+)/
return $1.to_i
end
when /darwin/
if `sysctl -n hw.ncpu` =~ /(\d+)/
return $1.to_i
end
end
rescue
end
# If we can't figure it out, default to 1.
1
end
end
@n_threads = determine_n_threads
@vars = VarSet.new
end
# Unbuffer $stdout

View File

@ -12,7 +12,7 @@ module Rscons
#
# @return [void]
def write(io, *message)
do_color = Rscons.do_ansi_color
do_color = Rscons.application.do_ansi_color
if do_color.nil?
do_color = do_ansi?(io)
end

72
lib/rscons/application.rb Normal file
View File

@ -0,0 +1,72 @@
module Rscons
# Functionality for an instance of the rscons application invocation.
class Application
# @return [Boolean]
# Whether to output ANSI color escape sequences.
attr_accessor :do_ansi_color
# @return [Integer]
# The number of threads to use when scheduling subprocesses.
attr_accessor :n_threads
# @return [VarSet]
# Access any variables set on the rscons command-line.
attr_reader :vars
def initialize
@vars = VarSet.new
@n_threads = determine_n_threads
end
# Run the specified operation.
#
# @param operation [String]
# The operation to perform (e.g. "clean", "configure", "build", etc...)
#
# @return [Integer]
# Process exit code (0 on success).
def run(operation)
# TODO
0
end
private
# Determine the number of threads to use by default.
#
# @return [Integer]
# The number of threads to use by default.
def determine_n_threads
# If the user specifies the number of threads in the environment, then
# respect that.
if ENV["RSCONS_NTHREADS"] =~ /^(\d+)$/
return $1.to_i
end
# Otherwise try to figure out how many threads are available on the
# host hardware.
begin
case RbConfig::CONFIG["host_os"]
when /linux/
return File.read("/proc/cpuinfo").scan(/^processor\s*:/).size
when /mswin|mingw/
if `wmic cpu get NumberOfLogicalProcessors /value` =~ /NumberOfLogicalProcessors=(\d+)/
return $1.to_i
end
when /darwin/
if `sysctl -n hw.ncpu` =~ /(\d+)/
return $1.to_i
end
end
rescue
end
# If we can't figure it out, default to 1.
1
end
end
end

View File

@ -22,7 +22,7 @@ Configure options:
--prefix=PREFIX Set installation prefix (default: /usr/local)
Build options:
-j N, --nthreads=N Set number of threads (local default: #{Rscons.n_threads})
-j N, --nthreads=N Set number of threads (local default: #{Rscons.application.n_threads})
EOF
@ -44,56 +44,45 @@ module Rscons
def run(argv)
argv = argv.dup
rsconsfile = nil
do_help = false
OptionParser.new do |opts|
opts.banner = "Usage: #{$0} [options]"
opts.on("-f FILE", "Execute FILE (default Rsconsfile)") do |f|
opts.on("-f FILE") do |f|
rsconsfile = f
end
opts.on("-j NTHREADS", "Use NTHREADS parallel jobs (local default #{Rscons.n_threads})") do |n_threads|
Rscons.n_threads = n_threads.to_i
opts.on("-j NTHREADS") do |n_threads|
Rscons.application.n_threads = n_threads.to_i
end
opts.on("-r", "--color MODE", "Set color mode (off, auto, force)") do |color_mode|
opts.on("-r", "--color MODE") do |color_mode|
case color_mode
when "off"
Rscons.do_ansi_color = false
Rscons.application.do_ansi_color = false
when "force"
Rscons.do_ansi_color = true
Rscons.application.do_ansi_color = true
end
end
opts.on("--version", "Show version") do
opts.on("--version") do
puts "Rscons version #{Rscons::VERSION}"
exit 0
end
opts.on("-h", "--help", "Show this help.") do
puts USAGE
exit 0
opts.on("-h", "--help") do
do_help = true
end
end.order!(argv)
if argv.empty?
puts USAGE
exit 0
end
case argv.first
when "clean"
Rscons.clean
exit 0
when "configure"
# TODO
exit 0
end
# Retrieve the operation, or default to build.
operation = argv.shift || "build"
argv.each do |arg|
if arg =~ /^([^=]+)=(.*)$/
Rscons.vars[$1] = $2
Rscons.application.vars[$1] = $2
end
end
@ -113,13 +102,15 @@ module Rscons
end
end
begin
load rsconsfile
rescue Rscons::BuildError => e
exit 1
end
script = Script.new
script.load(rsconsfile)
exit 0
if do_help
puts USAGE
exit 0
else
exit Rscons.application.run(operation)
end
end
end

View File

@ -19,7 +19,8 @@ module Rscons
# @return [Integer]
# The number of threads to use for this Environment. If nil (the
# default), the global Rscons.n_threads default value will be used.
# default), the global Rscons.application.n_threads default value will be
# used.
attr_writer :n_threads
# Set the build root.
@ -871,7 +872,7 @@ module Rscons
# @return [Integer]
# Number of threads to use for parallelized builds in this Environment.
def n_threads
@n_threads || Rscons.n_threads
@n_threads || Rscons.application.n_threads
end
# Print the builder run message, depending on the Environment's echo mode.

View File

@ -4,22 +4,30 @@ module Rscons
# the DSL for the build script to use.
class Script
class << self
# @return [String, nil]
# Project name.
attr_accessor :project_name
# Load a script from the specified file.
#
# @param path [String]
# File name of the rscons script to load.
#
# @return [Script]
# The loaded script state.
def load(path)
script_contents = File.read(path, mode: "rb")
script = Script.new
script.instance_eval(script_contents, path, 1)
script
end
# @return [Boolean]
# Whether to autoconfigure if the user does not explicitly perform a
# configure operation before building (default: true).
attr_accessor :autoconf
# Construct a Script.
def initialize
@project_name = nil
@autoconf = true
end
# Load a script from the specified file.
#
# @param path [String]
# File name of the rscons script to load.
#
# @return [void]
def load(path)
script_contents = File.read(path, mode: "rb")
self.instance_eval(script_contents, path, 1)
end
end

View File

@ -0,0 +1,71 @@
module Rscons
describe Application do
describe ".determine_n_threads" do
context "when specified by environment variable" do
before(:each) do
expect(ENV).to receive(:[]).with("RSCONS_NTHREADS").and_return("3")
end
it "returns the user-specified number of threads to use" do
expect(Rscons.application.__send__(:determine_n_threads)).to eq(3)
end
end
context "when not specified by environment variable" do
before(:each) do
expect(ENV).to receive(:[]).with("RSCONS_NTHREADS").and_return(nil)
end
context "on Linux" do
before(:each) do
expect(RbConfig::CONFIG).to receive(:[]).with("host_os").and_return("linux")
end
it "returns the number of processors from /proc/cpuinfo" do
expect(File).to receive(:read).with("/proc/cpuinfo").and_return(<<EOF)
processor : 0
processor : 1
EOF
expect(Rscons.application.__send__(:determine_n_threads)).to eq(2)
end
end
context "on Windows" do
before(:each) do
expect(RbConfig::CONFIG).to receive(:[]).with("host_os").and_return("mingw")
end
it "returns the number of logical processors that wmic reports" do
expect(Rscons).to receive(:`).with("wmic cpu get NumberOfLogicalProcessors /value").and_return("NumberOfLogicalProcessors=7")
expect(Rscons.application.__send__(:determine_n_threads)).to eq(7)
end
end
context "on Darwin" do
before(:each) do
expect(RbConfig::CONFIG).to receive(:[]).with("host_os").and_return("darwin")
end
it "returns the number of threads that sysctl reports" do
expect(Rscons).to receive(:`).with("sysctl -n hw.ncpu").and_return("6")
expect(Rscons.application.__send__(:determine_n_threads)).to eq(6)
end
end
context "on an unknown platform" do
before(:each) do
expect(RbConfig::CONFIG).to receive(:[]).with("host_os").and_return("other")
end
it "returns 1" do
expect(Rscons.application.__send__(:determine_n_threads)).to eq(1)
end
end
context "when an error occurs" do
it "returns 1" do
expect(RbConfig::CONFIG).to receive(:[]).with("host_os").and_raise("foo")
expect(Rscons.application.__send__(:determine_n_threads)).to eq(1)
end
end
end
end
end
end

View File

@ -150,70 +150,4 @@ describe Rscons do
end
end
end
describe ".determine_n_threads" do
context "when specified by environment variable" do
before(:each) do
expect(ENV).to receive(:[]).with("RSCONS_NTHREADS").and_return("3")
end
it "returns the user-specified number of threads to use" do
expect(Rscons.__send__(:determine_n_threads)).to eq(3)
end
end
context "when not specified by environment variable" do
before(:each) do
expect(ENV).to receive(:[]).with("RSCONS_NTHREADS").and_return(nil)
end
context "on Linux" do
before(:each) do
expect(RbConfig::CONFIG).to receive(:[]).with("host_os").and_return("linux")
end
it "returns the number of processors from /proc/cpuinfo" do
expect(File).to receive(:read).with("/proc/cpuinfo").and_return(<<EOF)
processor : 0
processor : 1
EOF
expect(Rscons.__send__(:determine_n_threads)).to eq(2)
end
end
context "on Windows" do
before(:each) do
expect(RbConfig::CONFIG).to receive(:[]).with("host_os").and_return("mingw")
end
it "returns the number of logical processors that wmic reports" do
expect(Rscons).to receive(:`).with("wmic cpu get NumberOfLogicalProcessors /value").and_return("NumberOfLogicalProcessors=7")
expect(Rscons.__send__(:determine_n_threads)).to eq(7)
end
end
context "on Darwin" do
before(:each) do
expect(RbConfig::CONFIG).to receive(:[]).with("host_os").and_return("darwin")
end
it "returns the number of threads that sysctl reports" do
expect(Rscons).to receive(:`).with("sysctl -n hw.ncpu").and_return("6")
expect(Rscons.__send__(:determine_n_threads)).to eq(6)
end
end
context "on an unknown platform" do
before(:each) do
expect(RbConfig::CONFIG).to receive(:[]).with("host_os").and_return("other")
end
it "returns 1" do
expect(Rscons.__send__(:determine_n_threads)).to eq(1)
end
end
context "when an error occurs" do
it "returns 1" do
expect(RbConfig::CONFIG).to receive(:[]).with("host_os").and_raise("foo")
expect(Rscons.__send__(:determine_n_threads)).to eq(1)
end
end
end
end
end