be more colorful - close #41
This commit is contained in:
parent
775363ddbd
commit
65c1bac4f9
@ -1,3 +1,4 @@
|
||||
require_relative "rscons/ansi"
|
||||
require_relative "rscons/build_target"
|
||||
require_relative "rscons/builder"
|
||||
require_relative "rscons/cache"
|
||||
@ -50,6 +51,10 @@ module Rscons
|
||||
# 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
|
||||
|
||||
# Remove all generated files.
|
||||
#
|
||||
# @return [void]
|
||||
|
52
lib/rscons/ansi.rb
Normal file
52
lib/rscons/ansi.rb
Normal file
@ -0,0 +1,52 @@
|
||||
module Rscons
|
||||
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
|
@ -39,6 +39,15 @@ module Rscons
|
||||
Rscons.n_threads = n_threads.to_i
|
||||
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
|
||||
puts "Rscons version #{Rscons::VERSION}"
|
||||
exit 0
|
||||
|
@ -331,7 +331,7 @@ module Rscons
|
||||
setup_info: job[:setup_info])
|
||||
unless result
|
||||
failure = "Failed to build #{job[:target]}"
|
||||
$stderr.puts failure
|
||||
Ansi.write($stderr, :red, failure, :reset, "\n")
|
||||
next
|
||||
end
|
||||
end
|
||||
@ -358,10 +358,10 @@ module Rscons
|
||||
end
|
||||
else
|
||||
unless @echo == :command
|
||||
$stdout.puts "Failed command was: #{command_to_s(tc.command)}"
|
||||
print_failed_command(tc.command)
|
||||
end
|
||||
failure = "Failed to build #{tc.build_operation[:target]}"
|
||||
$stderr.puts failure
|
||||
Ansi.write($stderr, :red, failure, :reset, "\n")
|
||||
break
|
||||
end
|
||||
end
|
||||
@ -412,16 +412,12 @@ module Rscons
|
||||
#
|
||||
# @return [true,false,nil] Return value from Kernel.system().
|
||||
def execute(short_desc, command, options = {})
|
||||
if @echo == :command
|
||||
puts command_to_s(command)
|
||||
elsif @echo == :short
|
||||
puts short_desc
|
||||
end
|
||||
print_builder_run_message(short_desc, command)
|
||||
env_args = options[:env] ? [options[:env]] : []
|
||||
options_args = options[:options] ? [options[:options]] : []
|
||||
system(*env_args, *Rscons.command_executer, *command, *options_args).tap do |result|
|
||||
unless result or @echo == :command
|
||||
$stdout.puts "Failed command was: #{command_to_s(command)}"
|
||||
print_failed_command(command)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -657,7 +653,7 @@ module Rscons
|
||||
call_build_hooks[:post]
|
||||
else
|
||||
unless @echo == :command
|
||||
$stdout.puts "Failed command was: #{command_to_s(tc.command)}"
|
||||
print_failed_command(tc.command)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -844,7 +840,7 @@ module Rscons
|
||||
varset_hash = @varset.to_h
|
||||
varset_hash.keys.sort_by(&:to_s).each do |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
|
||||
|
||||
@ -857,6 +853,34 @@ module Rscons
|
||||
@n_threads || Rscons.n_threads
|
||||
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
|
||||
message = command_to_s(command) if command
|
||||
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
|
||||
|
||||
# Add a build target.
|
||||
@ -889,13 +913,7 @@ module Rscons
|
||||
#
|
||||
# @return [void]
|
||||
def start_threaded_command(tc)
|
||||
if @echo == :command
|
||||
puts command_to_s(tc.command)
|
||||
elsif @echo == :short
|
||||
if tc.short_description
|
||||
puts tc.short_description
|
||||
end
|
||||
end
|
||||
print_builder_run_message(tc.short_description, tc.command)
|
||||
|
||||
env_args = tc.system_env ? [tc.system_env] : []
|
||||
options_args = tc.system_options ? [tc.system_options] : []
|
||||
|
@ -769,6 +769,29 @@ EOF
|
||||
expect(lines(result.stdout)).to eq ["165"]
|
||||
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
|
||||
it "allows a builder to call Environment#run_builder in a non-threaded manner" do
|
||||
test_dir("simple")
|
||||
@ -791,6 +814,21 @@ EOF
|
||||
]
|
||||
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
|
||||
test_dir("simple")
|
||||
File.open("simple.c", "wb") do |fh|
|
||||
|
33
spec/rscons/ansi_spec.rb
Normal file
33
spec/rscons/ansi_spec.rb
Normal 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
|
@ -190,38 +190,6 @@ module Rscons
|
||||
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
|
||||
it "calls the original method missing when the target method is not a known builder" do
|
||||
env = Environment.new
|
||||
|
Loading…
x
Reference in New Issue
Block a user