Compare commits

...
20 Commits
Author SHA1 Message Date
josh e900e74342 v1.14.0 2017-08-03 15:55:54 -04:00
josh 62ae3f162d add v1.14.0 release notes 2017-08-03 15:55:38 -04:00
josh 099d26f33c Add Rscons::VarSet#values_at - close #45 2017-08-03 15:54:24 -04:00
josh 89562c584a Environment#print_builder_run_message should support string commands - close #44 2017-08-03 14:10:53 -04:00
josh a9aeaf2356 v1.13.0 2017-07-14 16:24:27 -04:00
josh 5409b3cb34 add v1.13.0 release notes 2017-07-14 16:24:04 -04:00
josh 6d04500c13 Add ability to record side-effect file production - close #43 2017-07-14 16:17:01 -04:00
josh 45e30662d2 add YARD comment for Rscons::Ansi to get to 100% coverage 2017-07-12 15:51:00 -04:00
josh 8f7e044bfd fix YARD @option tag 2017-07-12 15:50:13 -04:00
josh dbea6f0a26 v1.12.0 2017-07-11 16:16:01 -04:00
josh c923eb5c7c add v1.12.0 release notes 2017-07-11 16:14:49 -04:00
josh 529d9aacaa colorize a couple other builders' output messages 2017-07-11 16:12:38 -04:00
josh 65c1bac4f9 be more colorful - close #41 2017-07-11 13:52:01 -04:00
josh 775363ddbd cloned Environments should inherit n_threads - close #42 2017-07-11 10:29:25 -04:00
josh 2a96495e83 wait for in-progress subcommands to complete on build failure - close #39 2017-06-26 22:44:49 -04:00
josh 15e52e488c env.depends should imply env.build_after - close #40 2017-06-21 10:44:52 -04:00
josh c0b12132f0 1.11.1 release notes 2017-06-14 09:58:09 -04:00
josh 9141cf91e7 v1.11.1 2017-06-14 09:57:11 -04:00
josh 7f7e6ef3da fix circular build dependency detection logic 2017-06-14 09:56:51 -04:00
josh 60b3fdbcac update YARD documentation link 2017-06-14 09:12:13 -04:00
22 changed files with 428 additions and 78 deletions

No files matched your search

+1 -1
View File
@@ -1,7 +1,7 @@
PATH PATH
remote: . remote: .
specs: specs:
rscons (1.11.0) rscons (1.13.0)
json (~> 1.0) json (~> 1.0)
GEM GEM
+35 -1
View File
@@ -560,10 +560,44 @@ env.depends("my_app", "config/link.ld", "README.txt", *Dir.glob("assets/**/*"))
### API documentation ### API documentation
Documentation for the complete Rscons API can be found at Documentation for the complete Rscons API can be found at
http://rubydoc.info/github/holtrop/rscons/frames. http://www.rubydoc.info/github/holtrop/rscons/master.
## Release Notes ## Release Notes
### v1.14.0
#### New Features
- #45 - Add Rscons::VarSet#values_at
#### Fixes
- #44 - Environment#print_builder_run_message should support string commands
### v1.13.0
#### New Features
- #43 - Add ability to record side-effect file production
### v1.12.0
#### New Features
- #40 - env.depends should imply env.build_after
- #41 - be more colorful
#### Fixes
- #39 - wait for in-progress subcommands to complete on build failure
- #42 - cloned Environments should inherit n_threads
### v1.11.1
#### Fixes
- fix the circular build dependency detection logic
### v1.11.0 ### v1.11.0
#### New Features #### New Features
@@ -0,0 +1,5 @@
Rscons::Environment.new do |env|
env.echo = :command
env.Install("inst.exe", "install.rb")
end
@@ -0,0 +1,13 @@
class MyBuilder < Rscons::Builder
def run(options)
env, target = options.values_at(:env, :target)
env.print_builder_run_message("MyBuilder #{target}", "MyBuilder #{target} command")
target
end
end
Rscons::Environment.new do |env|
env.echo = :command
env.add_builder(MyBuilder.new)
env.MyBuilder("foo")
end
+14
View File
@@ -0,0 +1,14 @@
Rscons::Environment.new do |env|
env["build_root"] = env.build_root
env["inc_h"] = "inc.h"
env.Copy("copy_inc.h", "${inc_h}")
env.depends("${build_root}/program.o", "${inc_h}")
env.Program("program.exe", ["program.c", "inc.c"])
env.Command("inc.c",
[],
"CMD" => %w[ruby gen.rb ${_TARGET}],
"CMD_DESC" => "Generating")
env.produces("inc.c", "inc.h")
end
+7
View File
@@ -0,0 +1,7 @@
base_env = Rscons::Environment.new do |env|
env.n_threads = 165
end
my_env = base_env.clone
puts my_env.n_threads
@@ -0,0 +1,22 @@
class TestBuilder < Rscons::Builder
def run(options)
target, env, vars, cache = options.values_at(:target, :env, :vars, :cache)
if target == "two"
return false unless File.exists?("one")
end
wait_time = env.expand_varref("${wait_time}", vars)
command = ["ruby", "-e", "require 'fileutils'; sleep #{wait_time}; FileUtils.touch('#{target}');"]
standard_threaded_build("TestBuilder", target, command, [], env, cache)
end
def finalize(options)
standard_finalize(options)
end
end
Rscons::Environment.new do |env|
env.add_builder(TestBuilder.new)
env.TestBuilder("one", [], "wait_time" => "3")
env.TestBuilder("two", [], "wait_time" => "0")
env.depends("two", "one")
end
@@ -0,0 +1,20 @@
class Fail < Rscons::Builder
def run(options)
target, cache, env, vars = options.values_at(:target, :cache, :env, :vars)
wait_time = env.expand_varref("${wait_time}", vars)
ruby_command = %[sleep #{wait_time}; exit 2]
command = %W[ruby -e #{ruby_command}]
standard_threaded_build("Fail #{target}", target, command, [], env, cache)
end
def finalize(options)
standard_finalize(options)
end
end
Rscons::Environment.new do |env|
env.add_builder(Fail.new)
4.times do |i|
wait_time = i + 1
env.Fail("foo_#{wait_time}", [], "wait_time" => wait_time.to_s)
end
end
+5
View File
@@ -1,3 +1,4 @@
require_relative "rscons/ansi"
require_relative "rscons/build_target" require_relative "rscons/build_target"
require_relative "rscons/builder" require_relative "rscons/builder"
require_relative "rscons/cache" require_relative "rscons/cache"
@@ -50,6 +51,10 @@ module Rscons
# The number of threads to use when scheduling subprocesses. # The number of threads to use when scheduling subprocesses.
attr_accessor :n_threads attr_accessor :n_threads
# @return [Boolean]
# Whether to output ANSI color escape sequences.
attr_accessor :do_ansi_color
# Remove all generated files. # Remove all generated files.
# #
# @return [void] # @return [void]
+53
View File
@@ -0,0 +1,53 @@
module Rscons
# Module to contain logic to write ANSI color escape codes.
module Ansi
class << self
# Write a message to an IO with ANSI escape codes.
#
# @param io [IO]
# The IO to write to.
# @param message [Array<String, Symbol>]
# Strings to be printed, with Symbols representing ANSI escape codes.
#
# @return [void]
def write(io, *message)
do_color = Rscons.do_ansi_color
if do_color.nil?
do_color = do_ansi?(io)
end
out = ""
message.each do |m|
if m.is_a?(String)
out += m
elsif do_color
case m
when :red
out += "\e[0;31m"
when :cyan
out += "\e[0;36m"
when :reset
out += "\e[0m"
end
end
end
io.write(out)
end
private
# Determine whether to output ANSI color escape codes.
#
# @return [Boolean]
# Whether to output ANSI color escape codes.
def do_ansi?(io)
if RUBY_PLATFORM =~ /mingw/
(ENV["TERM"] == "xterm") && %w[fifo characterSpecial].include?(io.stat.ftype)
else
io.tty?
end
end
end
end
end
+1 -1
View File
@@ -231,7 +231,7 @@ module Rscons
# @param env [Environment] The Environment executing the builder. # @param env [Environment] The Environment executing the builder.
# @param cache [Cache] The Cache object. # @param cache [Cache] The Cache object.
# @param options [Hash] Options. # @param options [Hash] Options.
# @options options [String] :stdout # @option options [String] :stdout
# File name to redirect standard output to. # File name to redirect standard output to.
# #
# @return [String,ThreadedCommand] # @return [String,ThreadedCommand]
+2 -2
View File
@@ -17,10 +17,10 @@ module Rscons
if File.directory?(target) if File.directory?(target)
target target
elsif File.exists?(target) elsif File.exists?(target)
$stderr.puts "Error: `#{target}' already exists and is not a directory" Ansi.write($stderr, :red, "Error: `#{target}' already exists and is not a directory", :reset, "\n")
false false
else else
puts "Directory #{target}" env.print_builder_run_message("Directory #{target}", nil)
cache.mkdir_p(target) cache.mkdir_p(target)
target target
end end
+1 -1
View File
@@ -43,7 +43,7 @@ module Rscons
# Check the cache and copy if necessary # Check the cache and copy if necessary
unless cache.up_to_date?(dest, :Copy, [src], env) unless cache.up_to_date?(dest, :Copy, [src], env)
unless printed_message unless printed_message
puts "#{name} #{target}" env.print_builder_run_message("#{name} #{target}", nil)
printed_message = true printed_message = true
end end
cache.mkdir_p(File.dirname(dest)) cache.mkdir_p(File.dirname(dest))
+9 -1
View File
@@ -39,6 +39,15 @@ module Rscons
Rscons.n_threads = n_threads.to_i Rscons.n_threads = n_threads.to_i
end end
opts.on("-r", "--color MODE", "Set color mode (off, auto, force)") do |color_mode|
case color_mode
when "off"
Rscons.do_ansi_color = false
when "force"
Rscons.do_ansi_color = true
end
end
opts.on_tail("--version", "Show version") do opts.on_tail("--version", "Show version") do
puts "Rscons version #{Rscons::VERSION}" puts "Rscons version #{Rscons::VERSION}"
exit 0 exit 0
@@ -70,7 +79,6 @@ module Rscons
begin begin
load rsconsfile load rsconsfile
rescue Rscons::BuildError => e rescue Rscons::BuildError => e
$stderr.puts e.message
exit 1 exit 1
end end
+79 -19
View File
@@ -45,8 +45,9 @@ module Rscons
def initialize(options = {}) def initialize(options = {})
@threaded_commands = Set.new @threaded_commands = Set.new
@registered_build_dependencies = {} @registered_build_dependencies = {}
@side_effects = {}
@varset = VarSet.new @varset = VarSet.new
@job_set = JobSet.new(@registered_build_dependencies) @job_set = JobSet.new(@registered_build_dependencies, @side_effects)
@user_deps = {} @user_deps = {}
@builders = {} @builders = {}
@build_dirs = [] @build_dirs = []
@@ -118,6 +119,7 @@ module Rscons
env.add_post_build_hook(&build_hook_block) env.add_post_build_hook(&build_hook_block)
end end
end end
env.instance_variable_set(:@n_threads, @n_threads)
if block_given? if block_given?
yield env yield env
@@ -302,13 +304,19 @@ module Rscons
# @return [void] # @return [void]
def process def process
cache = Cache.instance cache = Cache.instance
failure = nil
begin begin
while @job_set.size > 0 or @threaded_commands.size > 0 while @job_set.size > 0 or @threaded_commands.size > 0
if failure
@job_set.clear!
job = nil
else
targets_still_building = @threaded_commands.map do |tc| targets_still_building = @threaded_commands.map do |tc|
tc.build_operation[:target] tc.build_operation[:target]
end end
job = @job_set.get_next_job_to_run(targets_still_building) job = @job_set.get_next_job_to_run(targets_still_building)
end
# TODO: have Cache determine when checksums may be invalid based on # TODO: have Cache determine when checksums may be invalid based on
# file size and/or timestamp. # file size and/or timestamp.
@@ -323,7 +331,9 @@ module Rscons
allow_delayed_execution: true, allow_delayed_execution: true,
setup_info: job[:setup_info]) setup_info: job[:setup_info])
unless result unless result
raise BuildError.new("Failed to build #{job[:target]}") failure = "Failed to build #{job[:target]}"
Ansi.write($stderr, :red, failure, :reset, "\n")
next
end end
end end
@@ -349,9 +359,11 @@ module Rscons
end end
else else
unless @echo == :command unless @echo == :command
$stdout.puts "Failed command was: #{command_to_s(tc.command)}" print_failed_command(tc.command)
end end
raise BuildError.new("Failed to build #{tc.build_operation[:target]}") failure = "Failed to build #{tc.build_operation[:target]}"
Ansi.write($stderr, :red, failure, :reset, "\n")
break
end end
end end
@@ -359,6 +371,9 @@ module Rscons
ensure ensure
cache.write cache.write
end end
if failure
raise BuildError.new(failure)
end
end end
# Clear all targets registered for the Environment. # Clear all targets registered for the Environment.
@@ -398,16 +413,12 @@ module Rscons
# #
# @return [true,false,nil] Return value from Kernel.system(). # @return [true,false,nil] Return value from Kernel.system().
def execute(short_desc, command, options = {}) def execute(short_desc, command, options = {})
if @echo == :command print_builder_run_message(short_desc, command)
puts command_to_s(command)
elsif @echo == :short
puts short_desc
end
env_args = options[:env] ? [options[:env]] : [] env_args = options[:env] ? [options[:env]] : []
options_args = options[:options] ? [options[:options]] : [] options_args = options[:options] ? [options[:options]] : []
system(*env_args, *Rscons.command_executer, *command, *options_args).tap do |result| system(*env_args, *Rscons.command_executer, *command, *options_args).tap do |result|
unless result or @echo == :command unless result or @echo == :command
$stdout.puts "Failed command was: #{command_to_s(command)}" print_failed_command(command)
end end
end end
end end
@@ -451,6 +462,7 @@ module Rscons
user_deps = user_deps.map {|ud| expand_varref(ud)} user_deps = user_deps.map {|ud| expand_varref(ud)}
@user_deps[target] ||= [] @user_deps[target] ||= []
@user_deps[target] = (@user_deps[target] + user_deps).uniq @user_deps[target] = (@user_deps[target] + user_deps).uniq
build_after(target, user_deps)
end end
# Manually record the given target(s) as needing to be built after the # Manually record the given target(s) as needing to be built after the
@@ -491,6 +503,26 @@ module Rscons
end end
end end
# Manually record the given side effect file(s) as being produced when the
# named target is produced.
#
# @since 1.13.0
#
# @param target [String]
# Target of a build operation.
# @param side_effects [Array<String>]
# File(s) produced when the target file is produced.
#
# @return [void]
def produces(target, *side_effects)
target = expand_path(expand_varref(target))
side_effects = Array(side_effects).map do |side_effect|
expand_path(expand_varref(side_effect))
end.flatten
@side_effects[target] ||= []
@side_effects[target] += side_effects
end
# Return the list of user dependencies for a given target. # Return the list of user dependencies for a given target.
# #
# @param target [String] Target file name. # @param target [String] Target file name.
@@ -642,7 +674,7 @@ module Rscons
call_build_hooks[:post] call_build_hooks[:post]
else else
unless @echo == :command unless @echo == :command
$stdout.puts "Failed command was: #{command_to_s(tc.command)}" print_failed_command(tc.command)
end end
end end
end end
@@ -829,7 +861,7 @@ module Rscons
varset_hash = @varset.to_h varset_hash = @varset.to_h
varset_hash.keys.sort_by(&:to_s).each do |var| varset_hash.keys.sort_by(&:to_s).each do |var|
var_str = var.is_a?(Symbol) ? var.inspect : var var_str = var.is_a?(Symbol) ? var.inspect : var
puts "#{var_str} => #{varset_hash[var].inspect}" Ansi.write($stdout, :cyan, var_str, :reset, " => #{varset_hash[var].inspect}\n")
end end
end end
@@ -842,6 +874,40 @@ module Rscons
@n_threads || Rscons.n_threads @n_threads || Rscons.n_threads
end end
# Print the builder run message, depending on the Environment's echo mode.
#
# @param short_description [String]
# Builder short description, printed if the echo mode is :short.
# @param command [Array<String>]
# Builder command, printed if the echo mode is :command.
#
# @return [void]
def print_builder_run_message(short_description, command)
case @echo
when :command
if command.is_a?(Array)
message = command_to_s(command)
elsif command.is_a?(String)
message = command
elsif short_description.is_a?(String)
message = short_description
end
when :short
message = short_description if short_description
end
Ansi.write($stdout, :cyan, message, :reset, "\n") if message
end
# Print a failed command.
#
# @param command [Array<String>]
# Builder command.
#
# @return [void]
def print_failed_command(command)
Ansi.write($stdout, :red, "Failed command was: #{command_to_s(command)}", :reset, "\n")
end
private private
# Add a build target. # Add a build target.
@@ -874,13 +940,7 @@ module Rscons
# #
# @return [void] # @return [void]
def start_threaded_command(tc) def start_threaded_command(tc)
if @echo == :command print_builder_run_message(tc.short_description, tc.command)
puts command_to_s(tc.command)
elsif @echo == :short
if tc.short_description
puts tc.short_description
end
end
env_args = tc.system_env ? [tc.system_env] : [] env_args = tc.system_env ? [tc.system_env] : []
options_args = tc.system_options ? [tc.system_options] : [] options_args = tc.system_options ? [tc.system_options] : []
+19 -17
View File
@@ -9,9 +9,14 @@ module Rscons
# @param build_dependencies [Hash] # @param build_dependencies [Hash]
# Hash mapping targets to a set of build dependencies. A job will not be # Hash mapping targets to a set of build dependencies. A job will not be
# returned as ready to run if any of its dependencies are still building. # returned as ready to run if any of its dependencies are still building.
def initialize(build_dependencies) # @param side_effects [Hash]
# Hash mapping targets to a set of side-effect files. A job will not be
# returned as ready to run if any of its dependencies is a side-effect
# of another target that has not yet been built.
def initialize(build_dependencies, side_effects)
@jobs = {} @jobs = {}
@build_dependencies = build_dependencies @build_dependencies = build_dependencies
@side_effects = side_effects
end end
# Add a job to the JobSet. # Add a job to the JobSet.
@@ -47,24 +52,16 @@ module Rscons
# @return [nil, Hash] # @return [nil, Hash]
# The next job to run. # The next job to run.
def get_next_job_to_run(targets_still_building) def get_next_job_to_run(targets_still_building)
targets_skipped = Set.new targets_not_built_yet = targets_still_building + @jobs.keys
side_effects = targets_not_built_yet.map do |target|
@side_effects[target] || []
end.flatten
targets_not_built_yet += side_effects
@jobs.keys.each do |target| @jobs.keys.each do |target|
skip = false skip = false
(@jobs[target][0][:sources] + (@build_dependencies[target] || []).to_a).each do |src| (@jobs[target][0][:sources] + (@build_dependencies[target] || []).to_a).each do |src|
if @jobs.include?(src) if targets_not_built_yet.include?(src)
if targets_skipped.include?(src) or (src == target)
# We have encountered a circular dependency.
raise "Circular build dependency for #{src}"
end
# Skip this target because it depends on another target later in
# the job set.
targets_skipped << target
skip = true
break
end
if targets_still_building.include?(src)
# Skip this target because it depends on another target that is
# still being built.
skip = true skip = true
break break
end end
@@ -79,7 +76,12 @@ module Rscons
return job return job
end end
nil # If there is a job to run, and nothing is still building, but we did
# not find a job to run above, then there might be a circular dependency
# introduced by the user.
if (@jobs.size > 0) and targets_still_building.empty?
raise "Could not find a runnable job. Possible circular dependency for #{@jobs.keys.first}"
end
end end
# Remove all jobs from the JobSet. # Remove all jobs from the JobSet.
+13
View File
@@ -143,6 +143,19 @@ module Rscons
end end
end end
# Return an array containing the values associated with the given keys.
#
# @param keys [Array<String, Symbol>]
# Keys to look up in the VarSet.
#
# @return [Array]
# An array containing the values associated with the given keys.
def values_at(*keys)
keys.map do |key|
self[key]
end
end
private private
# Move all VarSet variables into the copy-on-access list. # Move all VarSet variables into the copy-on-access list.
+1 -1
View File
@@ -1,4 +1,4 @@
module Rscons module Rscons
# gem version # gem version
VERSION = "1.11.0" VERSION = "1.14.0"
end end
+86 -2
View File
@@ -735,17 +735,79 @@ EOF
it "raises an error for a circular dependency" do it "raises an error for a circular dependency" do
test_dir("simple") test_dir("simple")
result = run_test(rsconsfile: "error_circular_dependency.rb") result = run_test(rsconsfile: "error_circular_dependency.rb")
expect(result.stderr).to match /Circular build dependency for (foo|bar|baz)/ expect(result.stderr).to match /Possible circular dependency for (foo|bar|baz)/
expect(result.status).to_not eq 0 expect(result.status).to_not eq 0
end end
it "raises an error for a circular dependency where a build target contains itself in its source list" do it "raises an error for a circular dependency where a build target contains itself in its source list" do
test_dir("simple") test_dir("simple")
result = run_test(rsconsfile: "error_circular_dependency2.rb") result = run_test(rsconsfile: "error_circular_dependency2.rb")
expect(result.stderr).to match /Circular build dependency for foo/ expect(result.stderr).to match /Possible circular dependency for foo/
expect(result.status).to_not eq 0 expect(result.status).to_not eq 0
end end
it "orders builds to respect user dependencies" do
test_dir("simple")
result = run_test(rsconsfile: "user_dep_build_order.rb", rscons_args: %w[-j4])
expect(result.stderr).to eq ""
end
it "waits for all parallelized builds to complete if one fails" do
test_dir("simple")
result = run_test(rsconsfile: "wait_for_builds_on_failure.rb", rscons_args: %w[-j4])
expect(result.status).to_not eq 0
expect(result.stderr).to match /Failed to build foo_1/
expect(result.stderr).to match /Failed to build foo_2/
expect(result.stderr).to match /Failed to build foo_3/
expect(result.stderr).to match /Failed to build foo_4/
end
it "clones n_threads attribute when cloning an Environment" do
test_dir("simple")
result = run_test(rsconsfile: "clone_n_threads.rb")
expect(result.stderr).to eq ""
expect(lines(result.stdout)).to eq ["165"]
end
it "prints a builder's short description with 'command' echo mode if there is no command" do
test_dir("build_dir")
result = run_test(rsconsfile: "echo_command_ruby_builder.rb")
expect(result.stderr).to eq ""
expect(lines(result.stdout)).to eq ["Install inst.exe"]
end
it "supports a string for a builder's echoed 'command' with Environment#print_builder_run_message" do
test_dir("build_dir")
result = run_test(rsconsfile: "echo_command_string.rb")
expect(result.stderr).to eq ""
expect(lines(result.stdout)).to eq ["MyBuilder foo command"]
end
context "colored output" do
it "does not output in color with --color=off" do
test_dir("simple")
result = run_test(rscons_args: %w[--color=off])
expect(result.stderr).to eq ""
expect(result.stdout).to_not match(/\e\[/)
end
it "displays output in color with --color=force" do
test_dir("simple")
result = run_test(rscons_args: %w[--color=force])
expect(result.stderr).to eq ""
expect(result.stdout).to match(/\e\[/)
File.open("simple.c", "wb") do |fh|
fh.write("foobar")
end
result = run_test(rscons_args: %w[--color=force])
expect(result.stderr).to match(/\e\[/)
end
end
context "backward compatibility" do context "backward compatibility" do
it "allows a builder to call Environment#run_builder in a non-threaded manner" do it "allows a builder to call Environment#run_builder in a non-threaded manner" do
test_dir("simple") test_dir("simple")
@@ -768,6 +830,21 @@ EOF
] ]
end end
it "prints the failed build command for a non-threaded builder" do
test_dir("simple")
File.open("simple.c", "wb") do |fh|
fh.write(<<EOF)
void one()
{
}
EOF
end
result = run_test(rsconsfile: "build_sources.rb")
expect(result.status).to_not eq 0
expect(result.stderr).to match /main/
expect(result.stdout).to match /Failed command was: gcc/
end
it "prints the failed build command for a threaded builder when called via Environment#run_builder without delayed execution" do it "prints the failed build command for a threaded builder when called via Environment#run_builder without delayed execution" do
test_dir("simple") test_dir("simple")
File.open("simple.c", "wb") do |fh| File.open("simple.c", "wb") do |fh|
@@ -1245,6 +1322,13 @@ EOF
result = run_test(rsconsfile: "build_after.rb", rscons_args: %w[-j 4]) result = run_test(rsconsfile: "build_after.rb", rscons_args: %w[-j 4])
expect(result.stderr).to eq "" expect(result.stderr).to eq ""
end end
it "allows the user to specify side-effect files produced by another builder" do
test_dir("custom_builder")
result = run_test(rsconsfile: "produces.rb", rscons_args: %w[-j 4])
expect(result.stderr).to eq ""
expect(File.exists?("copy_inc.h")).to be_truthy
end
end end
context "CLI" do context "CLI" do
+33
View File
@@ -0,0 +1,33 @@
module Rscons
describe Ansi do
describe ".do_ansi?" do
context "on Windows" do
it "returns true when IO is a fifo on an xterm" do
stub_const("RUBY_PLATFORM", "mingw")
expect(ENV).to receive(:[]).with("TERM").and_return("xterm")
io = double
expect(io).to receive(:stat).and_return(Struct.new(:ftype).new("fifo"))
expect(Ansi.__send__(:do_ansi?, io)).to be_truthy
end
it "returns false when TERM is not set appropriately" do
stub_const("RUBY_PLATFORM", "mingw")
expect(ENV).to receive(:[]).with("TERM").and_return(nil)
io = double
expect(Ansi.__send__(:do_ansi?, io)).to be_falsey
end
end
context "on POSIX" do
it "returns true when IO is a TTY" do
stub_const("RUBY_PLATFORM", "linux")
io = double
expect(io).to receive(:tty?).and_return(true)
expect(Ansi.__send__(:do_ansi?, io)).to be_truthy
end
end
end
end
end
-32
View File
@@ -190,38 +190,6 @@ module Rscons
end end
end end
describe "#execute" do
context "with echo: :short" do
context "with no errors" do
it "prints the short description and executes the command" do
env = Environment.new(echo: :short)
expect(env).to receive(:puts).with("short desc")
expect(env).to receive(:system).with(*Rscons.command_executer, "a", "command").and_return(true)
env.execute("short desc", ["a", "command"])
end
end
context "with errors" do
it "prints the short description, executes the command, and prints the failed command line" do
env = Environment.new(echo: :short)
expect(env).to receive(:puts).with("short desc")
expect(env).to receive(:system).with(*Rscons.command_executer, "a", "command").and_return(false)
expect($stdout).to receive(:puts).with("Failed command was: a command")
env.execute("short desc", ["a", "command"])
end
end
end
context "with echo: :command" do
it "prints the command executed and executes the command" do
env = Environment.new(echo: :command)
expect(env).to receive(:puts).with("a command '--arg=val with spaces'")
expect(env).to receive(:system).with({modified: :environment}, *Rscons.command_executer, "a", "command", "--arg=val with spaces", {opt: :val}).and_return(false)
env.execute("short desc", ["a", "command", "--arg=val with spaces"], env: {modified: :environment}, options: {opt: :val})
end
end
end
describe "#method_missing" do describe "#method_missing" do
it "calls the original method missing when the target method is not a known builder" do it "calls the original method missing when the target method is not a known builder" do
env = Environment.new env = Environment.new
+9
View File
@@ -199,5 +199,14 @@ module Rscons
end end
end end
describe "#values_at" do
it "returns an array of the values associated with the given keys" do
v = VarSet.new({"fuz" => "a string", "foo" => 42, "bar" => :baz,
"qax" => [3, 6], "qux" => {a: :b}})
expect(v.values_at).to eq []
expect(v.values_at(*%w[fuz qux qax])).to eq ["a string", {a: :b}, [3, 6]]
end
end
end end
end end