Compare commits

..
19 Commits
Author SHA1 Message Date
josh 831b9bf2c7 v1.3.0 2014-02-25 12:18:02 -05:00
josh 031395bb57 add v1.3.0 release notes 2014-02-25 12:17:49 -05:00
josh e3aeb7f4d7 Change Environment#execute() options Hash to contain :env and :options keys for Kernel#system() 2014-02-25 12:14:52 -05:00
josh 6aa5037234 v1.2.0 2014-02-20 16:42:10 -05:00
josh 0d8f661fd4 add :clone option to Environment#clone to control exactly which Environment attributes are cloned 2014-02-19 15:02:46 -05:00
josh e5ca8776a9 allow nil to be passed in to Environment#build_root= 2014-02-19 15:02:18 -05:00
josh 2dde39a0ec standardize on "Rscons" capitalization 2014-02-18 16:14:44 -05:00
josh af0679708c v1.1.0 2014-02-17 16:37:59 -05:00
josh 4b0d0c3957 README: add Release Notes section 2014-02-17 16:15:49 -05:00
josh 202f10b86f README: add example for custom builder with multiple output files 2014-02-17 16:14:10 -05:00
josh 1d47db3144 support passing multiple targets to Cache#up_to_date? and #register_build 2014-02-17 16:10:15 -05:00
josh f7b7a4fefa v1.0.0 2014-02-14 10:46:31 -05:00
josh 00b038ef50 use require_relative instead of require 2014-02-14 10:37:41 -05:00
josh 98f8f38715 remove String#set_suffix monkey patch 2014-02-14 10:36:15 -05:00
josh 2ffb5d525a remove String#absolute_path? monkey patch 2014-02-14 10:32:57 -05:00
josh fa7d17675b remove String#has_suffix? monkey-patch; use String#end_with? 2014-02-14 10:20:32 -05:00
josh b43c473762 README: add link to API documentation at rubydoc.info 2014-02-14 09:57:46 -05:00
josh f278b211f7 README: add more information about custom builders 2014-02-14 09:50:39 -05:00
josh c897bcf06e README.md fixes/tweaks 2014-02-14 09:42:04 -05:00
11 changed files with 285 additions and 130 deletions

No files matched your search

+85 -11
View File
@@ -27,7 +27,7 @@ called from your Rakefile.
### Example: Building a C Program
```ruby
RScons::Environment.new do |env|
Rscons::Environment.new do |env|
env["CFLAGS"] << "-Wall"
env.Program("program", Dir["**/*.c"])
end
@@ -36,7 +36,7 @@ end
### Example: Building a D Program
```ruby
RScons::Environment.new do |env|
Rscons::Environment.new do |env|
env["DFLAGS"] << "-Wall"
env.Program("program", Dir["**/*.d"])
end
@@ -45,7 +45,7 @@ end
### Example: Cloning an Environment
```ruby
main_env = RScons::Environment.new do |env|
main_env = Rscons::Environment.new do |env|
# Store object files from sources under "src" in "build/main"
env.build_dir("src", "build/main")
env["CFLAGS"] = ["-DSOME_DEFINE", "-O3"]
@@ -64,6 +64,11 @@ end
### Example: Custom Builder
Custom builders are implemented as classes which extend from `Rscons::Builder`.
The builder must have a `run` method which is called to invoke the builder.
The `run` method should return the name of the target built on success, and
`false` on failure.
```ruby
class GenerateFoo < Rscons::Builder
def run(target, sources, cache, env, vars)
@@ -73,10 +78,12 @@ class GenerateFoo < Rscons::Builder
#define GENERATED 42
EOF
end
target
end
end
Rscons::Environment.new do |env|
env.add_builder(GenerateFoo.new)
env.GenerateFoo("foo.h", [])
env.Program("a.out", Dir["*.c"])
end
@@ -93,16 +100,46 @@ class CmdBuilder < Rscons::Builder
system(cmd)
cache.register_build(target, cmd, sources, env)
end
target
end
end
Rscons::Environment.new do |env|
env.add_builder(CmdBuilder.new)
env.CmdBuilder("foo.gen", "foo_gen.cfg")
end
```
### Example: Custom Builder That Generates Multiple Output Files
```ruby
class CModuleGenerator < Rscons::Builder
def run(target, sources, cache, env, vars)
c_fname = target
h_fname = target.sub(/\.c$/, ".h")
cmd = ["generate_c_and_h", sources.first, c_fname, h_fname]
unless cache.up_to_date?([c_fname, h_fname], cmd, sources, env)
cache.mkdir_p(File.dirname(target))
system(cmd)
cache.register_build([c_fname, h_fname], cmd, sources, env)
end
target
end
end
Rscons::Environment.new do |env|
env.add_builder(CModuleGenerator.new)
env.CModuleGenerator("build/foo.c", "foo_gen.cfg")
end
```
### Example: Custom Builder Using Builder#standard_build()
The `standard_build` method from the `Rscons::Builder` base class can be used
when the builder needs to execute a system command to produce the target file.
The `standard_build` method will return the correct value so its return value
can be used as the return value from the `run` method.
```ruby
class CmdBuilder < Rscons::Builder
def run(target, sources, cache, env, vars)
@@ -112,6 +149,7 @@ class CmdBuilder < Rscons::Builder
end
Rscons::Environment.new do |env|
env.add_builder(CmdBuilder.new)
env.CmdBuilder("foo.gen", "foo_gen.cfg")
end
```
@@ -131,6 +169,19 @@ Rscons::Environment.new do |env|
end
```
Each build hook block will be invoked for every build operation, so the block
should test the target or sources if its action should only apply to some
subset of build targets or source files.
The `build_op` parameter to the build hook block is a Hash describing the
build operation with the following keys:
* `:builder` - `Builder` instance in use
* `:target` - `String` name of the target file
* `:sources` - `Array` of the source files
* `:vars` - `Rscons::VarSet` containing the construction variables to use
The build hook can overwrite entries in `build_op[:vars]` to alter the
construction variables in use for this specific build operation.
### Example: Creating a static library
```ruby
@@ -149,8 +200,8 @@ Rscons ships with a number of default builders:
* Object, which compiles source files to produce an object file
* Program, which links object files to produce an executable
If you want to create an Environment that does not contain any (or select)
builders, you can use the `exclude_builders` key to the Environment constructor.
If you want to create an Environment that does not contain any builders,
you can use the `exclude_builders` key to the Environment constructor.
### Managing Environments
@@ -158,7 +209,8 @@ An Rscons::Environment consists of:
* a collection of construction variables
* a collection of builders
* a mapping of build directories
* a mapping of build directories from source directories
* a default build root to apply if no build directories are matched
* a collection of targets to build
* a collection of build hooks
@@ -178,12 +230,34 @@ cloned_env["CPPPATH"] << "three"
`base_env["CPPPATH"]` will not include "three".
### Construction Variables
### Construction Variable Naming
The default construction variables that Rscons uses are named using uppercase
strings.
Rscons options are lowercase symbols.
Lowercase strings are reserved as user-defined construction variables.
* uppercase strings - the default construction variables that Rscons uses
* lowercase symbols - Rscons options
* lowercase strings - reserved as user-defined construction variables
### API documentation
Documentation for the complete Rscons API can be found at
http://rubydoc.info/github/holtrop/rscons/frames.
## Release Notes
### v1.3.0
- change Environment#execute() options parameter to accept the following options keys:
- :env to pass an environment Hash to Kernel#system
- :options to pass an options Hash to Kernel#system
### v1.2.0
- add :clone option to Environment#clone to control exactly which Environment attributes are cloned
- allow nil to be passed in to Environment#build_root=
### v1.1.0
- Change Cache#up_to_date?() and #register_build() to accept a single target
file or an array of target file names
## Contributing
+21 -10
View File
@@ -1,15 +1,13 @@
require "rscons/builder"
require "rscons/cache"
require "rscons/environment"
require "rscons/varset"
require "rscons/version"
require "rscons/monkey/string"
require_relative "rscons/builder"
require_relative "rscons/cache"
require_relative "rscons/environment"
require_relative "rscons/varset"
require_relative "rscons/version"
# default builders
require "rscons/builders/library"
require "rscons/builders/object"
require "rscons/builders/program"
require_relative "rscons/builders/library"
require_relative "rscons/builders/object"
require_relative "rscons/builders/program"
# Namespace module for rscons classes
module Rscons
@@ -37,4 +35,17 @@ module Rscons
end
Cache.clear
end
# Return whether the given path is an absolute filesystem path or not
# @param path [String] the path to examine
def self.absolute_path?(path)
path =~ %r{^(/|\w:[\\/])}
end
# Return a new path by changing the suffix in path to suffix.
# @param path [String] the path to alter
# @param suffix [String] the new filename suffix
def self.set_suffix(path, suffix)
path.sub(/\.[^.]*$/, suffix)
end
end
+1 -1
View File
@@ -1,6 +1,6 @@
module Rscons
module Builders
# A default RScons builder that produces a static library archive.
# A default Rscons builder that produces a static library archive.
class Rscons::Builders::Library < Rscons::Builder
def default_variables(env)
{
+5 -5
View File
@@ -1,6 +1,6 @@
module Rscons
module Builders
# A default RScons builder which knows how to produce an object file from
# A default Rscons builder which knows how to produce an object file from
# various types of source files.
class Object < Builder
KNOWN_SUFFIXES = {
@@ -46,8 +46,8 @@ module Rscons
end
def produces?(target, source, env)
target.has_suffix?(env['OBJSUFFIX']) and KNOWN_SUFFIXES.find do |compiler, suffix_var|
source.has_suffix?(env[suffix_var])
target.end_with?(*env['OBJSUFFIX']) and KNOWN_SUFFIXES.find do |compiler, suffix_var|
source.end_with?(*env[suffix_var])
end
end
@@ -55,10 +55,10 @@ module Rscons
vars = vars.merge({
'_TARGET' => target,
'_SOURCES' => sources,
'_DEPFILE' => target.set_suffix('.mf'),
'_DEPFILE' => Rscons.set_suffix(target, '.mf'),
})
com_prefix = KNOWN_SUFFIXES.find do |compiler, suffix_var|
sources.first.has_suffix?(env[suffix_var])
sources.first.end_with?(*env[suffix_var])
end.tap do |v|
v.nil? and raise "Error: unknown input file type: #{sources.first.inspect}"
end.first
+3 -3
View File
@@ -1,6 +1,6 @@
module Rscons
module Builders
# A default RScons builder that knows how to link object files into an
# A default Rscons builder that knows how to link object files into an
# executable program.
class Rscons::Builders::Program < Rscons::Builder
def default_variables(env)
@@ -21,9 +21,9 @@ module Rscons
return false unless objects
ld = if env["LD"]
env["LD"]
elsif sources.find {|s| s.has_suffix?(env["DSUFFIX"])}
elsif sources.find {|s| s.end_with?(*env["DSUFFIX"])}
env["DC"]
elsif sources.find {|s| s.has_suffix?(env["CXXSUFFIX"])}
elsif sources.find {|s| s.end_with?(*env["CXXSUFFIX"])}
env["CXX"]
else
env["CC"]
+55 -50
View File
@@ -85,16 +85,17 @@ module Rscons
end
end
# Check if a target is up to date
# @param target [String] The name of the target file.
# @param command [Array] The command used to build the target.
# Check if target(s) are up to date
# @param targets [String, Array] The name(s) of the target file(s).
# @param command [String, Array] The command used to build the target.
# @param deps [Array] List of the target's dependency files.
# @param env [Environment] The Rscons::Environment.
# @param options [Hash] Optional options. Can contain the following keys:
# :strict_deps::
# Only consider a target up to date if its list of dependencies is
# exactly equal (including order) to the cached list of dependencies
# @return true value if the target is up to date, meaning that:
# @return true if the targets are all up to date, meaning that,
# for each target:
# - the target exists on disk
# - the cache has information for the target
# - the target's checksum matches its checksum when it was last built
@@ -104,65 +105,69 @@ module Rscons
# exactly equal to those cached
# - each cached dependency file's current checksum matches the checksum
# stored in the cache file
def up_to_date?(target, command, deps, env, options = {})
# target file must exist on disk
return false unless File.exists?(target)
def up_to_date?(targets, command, deps, env, options = {})
Array(targets).each do |target|
# target file must exist on disk
return false unless File.exists?(target)
# target must be registered in the cache
return false unless @cache[:targets].has_key?(target)
# target must be registered in the cache
return false unless @cache[:targets].has_key?(target)
# target must have the same checksum as when it was built last
return false unless @cache[:targets][target][:checksum] == lookup_checksum(target)
# target must have the same checksum as when it was built last
return false unless @cache[:targets][target][:checksum] == lookup_checksum(target)
# command used to build target must be identical
return false unless @cache[:targets][target][:command] == command
# command used to build target must be identical
return false unless @cache[:targets][target][:command] == command
cached_deps = @cache[:targets][target][:deps] || []
cached_deps_fnames = cached_deps.map { |dc| dc[:fname] }
if options[:strict_deps]
# depedencies passed in must exactly equal those in the cache
return false unless deps == cached_deps_fnames
else
# all dependencies passed in must exist in cache (but cache may have more)
return false unless (Set.new(deps) - Set.new(cached_deps_fnames)).empty?
end
cached_deps = @cache[:targets][target][:deps] || []
cached_deps_fnames = cached_deps.map { |dc| dc[:fname] }
if options[:strict_deps]
# depedencies passed in must exactly equal those in the cache
return false unless deps == cached_deps_fnames
else
# all dependencies passed in must exist in cache (but cache may have more)
return false unless (Set.new(deps) - Set.new(cached_deps_fnames)).empty?
end
# set of user dependencies must match
user_deps = env.get_user_deps(target) || []
cached_user_deps = @cache[:targets][target][:user_deps] || []
cached_user_deps_fnames = cached_user_deps.map { |dc| dc[:fname] }
return false unless user_deps == cached_user_deps_fnames
# set of user dependencies must match
user_deps = env.get_user_deps(target) || []
cached_user_deps = @cache[:targets][target][:user_deps] || []
cached_user_deps_fnames = cached_user_deps.map { |dc| dc[:fname] }
return false unless user_deps == cached_user_deps_fnames
# all cached dependencies must have their checksums match
(cached_deps + cached_user_deps).each do |dep_cache|
return false unless dep_cache[:checksum] == lookup_checksum(dep_cache[:fname])
# all cached dependencies must have their checksums match
(cached_deps + cached_user_deps).each do |dep_cache|
return false unless dep_cache[:checksum] == lookup_checksum(dep_cache[:fname])
end
end
true
end
# Store cache information about a target built by a builder
# @param target [String] The name of the target.
# @param command [Array] The command used to build the target.
# Store cache information about target(s) built by a builder
# @param targets [String, Array] The name of the target(s) built.
# @param command [String, Array] The command used to build the target.
# @param deps [Array] List of dependencies for the target.
# @param env [Environment] The Rscons::Environment.
def register_build(target, command, deps, env)
@cache[:targets][target.encode(__ENCODING__)] = {
command: command,
checksum: calculate_checksum(target),
deps: deps.map do |dep|
{
fname: dep.encode(__ENCODING__),
checksum: lookup_checksum(dep),
}
end,
user_deps: (env.get_user_deps(target) || []).map do |dep|
{
fname: dep.encode(__ENCODING__),
checksum: lookup_checksum(dep),
}
end,
}
def register_build(targets, command, deps, env)
Array(targets).each do |target|
@cache[:targets][target.encode(__ENCODING__)] = {
command: command,
checksum: calculate_checksum(target),
deps: deps.map do |dep|
{
fname: dep.encode(__ENCODING__),
checksum: lookup_checksum(dep),
}
end,
user_deps: (env.get_user_deps(target) || []).map do |dep|
{
fname: dep.encode(__ENCODING__),
checksum: lookup_checksum(dep),
}
end,
}
end
end
# Return a list of targets that have been built
+52 -18
View File
@@ -2,7 +2,7 @@ require 'set'
require 'fileutils'
module Rscons
# The Environment class is the main programmatic interface to RScons. It
# The Environment class is the main programmatic interface to Rscons. It
# contains a collection of construction variables, options, builders, and
# rules for building targets.
class Environment
@@ -15,7 +15,8 @@ module Rscons
# String or +nil+
attr_reader :build_root
def build_root=(build_root)
@build_root = build_root.gsub('\\', '/')
@build_root = build_root
@build_root.gsub!('\\', '/') if @build_root
end
# Create an Environment object.
@@ -50,24 +51,53 @@ module Rscons
end
# Make a copy of the Environment object.
# The cloned environment will contain a copy of all environment options,
# construction variables, and builders (unless :exclude_builders => true is
# passed as an option). It will not contain a copy of the targets, build
# hooks, build directories, or the build root. If a block is given, the
# Environment object is yielded to the block and when the block returns,
# the {#process} method is automatically called. The possible options keys
# match those documented in the #initialize method.
#
# By default, a cloned environment will contain a copy of all environment
# options, construction variables, and builders, but not a copy of the
# targets, build hooks, build directories, or the build root.
#
# Exactly which items are cloned are controllable via the optional :clone
# parameter, which can be :none, :all, or a set or array of any of the
# following:
# - :variables to clone construction variables (on by default)
# - :builders to clone the builders (on by default)
# - :build_root to clone the build root (off by default)
# - :build_dirs to clone the build directories (off by default)
# - :build_hooks to clone the build hooks (off by default)
#
# If a block is given, the Environment object is yielded to the block and
# when the block returns, the {#process} method is automatically called.
#
# Any options that #initialize receives can also be specified here.
#
# @return a new {Environment} object.
def clone(options = {})
clone = options[:clone] || Set[:variables, :builders]
clone = Set[:variables, :builders, :build_root, :build_dirs, :build_hooks] if clone == :all
clone = Set[] if clone == :none
clone = Set.new(clone) if clone.is_a?(Array)
clone.delete(:builders) if options[:exclude_builders]
env = self.class.new(
echo: options[:echo] || @echo,
build_root: options[:build_root],
exclude_builders: true)
unless options[:exclude_builders]
if clone.include?(:builders)
@builders.each do |builder_name, builder|
env.add_builder(builder)
end
end
env.append(@varset.clone)
env.append(@varset.clone) if clone.include?(:variables)
env.build_root = @build_root if clone.include?(:build_root)
if clone.include?(:build_dirs)
@build_dirs.each do |src_dir, obj_dir|
env.build_dir(src_dir, obj_dir)
end
end
if clone.include?(:build_hooks)
@build_hooks.each do |build_hook_block|
env.add_build_hook(&build_hook_block)
end
end
if block_given?
yield env
@@ -102,7 +132,7 @@ module Rscons
# Return the file name to be built from source_fname with suffix suffix.
# This method takes into account the Environment's build directories.
def get_build_fname(source_fname, suffix)
build_fname = source_fname.set_suffix(suffix).gsub('\\', '/')
build_fname = Rscons.set_suffix(source_fname, suffix).gsub('\\', '/')
found_match = @build_dirs.find do |src_dir, obj_dir|
if src_dir.is_a?(Regexp)
build_fname.sub!(src_dir, obj_dir)
@@ -111,7 +141,7 @@ module Rscons
end
end
if @build_root and not found_match
unless source_fname.absolute_path? or build_fname.start_with?("#{@build_root}/")
unless Rscons.absolute_path?(source_fname) or build_fname.start_with?("#{@build_root}/")
build_fname = "#{@build_root}/#{build_fname}"
end
end
@@ -194,7 +224,9 @@ module Rscons
# @param short_desc [String] Message to print if the Environment's echo
# mode is set to :short
# @param command [Array] The command to execute.
# @param options [Hash] Optional options to pass to Kernel#system.
# @param options [Hash] Optional options, possible keys:
# - :env - environment Hash to pass to Kernel#system.
# - :options - options Hash to pass to Kernel#system.
def execute(short_desc, command, options = {})
print_command = proc do
puts command.map { |c| c =~ /\s/ ? "'#{c}'" : c }.join(' ')
@@ -204,7 +236,9 @@ module Rscons
elsif @echo == :short
puts short_desc
end
system(*command, options).tap do |result|
env_args = options[:env] ? [options[:env]] : []
options_args = options[:options] ? [options[:options]] : []
system(*env_args, *command, *options_args).tap do |result|
unless result or @echo == :command
$stdout.write "Failed command was: "
print_command.call
@@ -246,7 +280,7 @@ module Rscons
# Build a list of source files into files containing one of the suffixes
# given by suffixes.
# This method is used internally by RScons builders.
# This method is used internally by Rscons builders.
# @param sources [Array] List of source files to build.
# @param suffixes [Array] List of suffixes to try to convert source files into.
# @param cache [Cache] The Cache.
@@ -254,7 +288,7 @@ module Rscons
# Return a list of the converted file names.
def build_sources(sources, suffixes, cache, vars)
sources.map do |source|
if source.has_suffix?(suffixes)
if source.end_with?(*suffixes)
source
else
converted = nil
@@ -294,7 +328,7 @@ module Rscons
end
# Parse dependencies for a given target from a Makefile.
# This method is used internally by RScons builders.
# This method is used internally by Rscons builders.
# @param mf_fname [String] File name of the Makefile to read.
# @param target [String] Name of the target to gather dependencies for.
def self.parse_makefile_deps(mf_fname, target)
-25
View File
@@ -1,25 +0,0 @@
# Standard Ruby String class.
class String
# Check if the given string ends with any of the supplied suffixes
# @param suffix [String, Array] The suffix to look for.
# @return a true value if the string ends with one of the suffixes given.
def has_suffix?(suffix)
if suffix
suffix = [suffix] if suffix.is_a?(String)
suffix = suffix.flatten
suffix.find {|s| self.end_with?(s)}
end
end
# Return a new string with the suffix (dot character and extension) changed
# to the given suffix.
# @param suffix [String] The new suffix.
def set_suffix(suffix = '')
sub(/\.[^.]*$/, suffix)
end
# Return whether the string represents an absolute filesystem path
def absolute_path?
self =~ %r{^(/|\w:[\\/])}
end
end
+1 -1
View File
@@ -1,4 +1,4 @@
module Rscons
# gem version
VERSION = "0.3.1"
VERSION = "1.3.0"
end
+58 -2
View File
@@ -218,9 +218,9 @@ describe Rscons do
end
it 'allows Ruby classes as custom builders to be used to construct files' do
test_dir('custom_builder')
test_dir('custom_builder')
class MySource < Rscons::Builder
def run(target, sources, user_deps, cache, env, vars = {})
def run(target, sources, cache, env, vars)
File.open(target, 'w') do |fh|
fh.puts <<EOF
#define THE_VALUE 5678
@@ -241,6 +241,39 @@ EOF
`./program`.should == "The value is 5678\n"
end
it 'supports custom builders with multiple targets' do
test_dir('custom_builder')
class CHGen < Rscons::Builder
def run(target, sources, cache, env, vars)
c_fname = target
h_fname = target.sub(/\.c$/, ".h")
unless cache.up_to_date?([c_fname, h_fname], "", sources, env)
puts "CHGen #{c_fname}"
File.open(c_fname, "w") {|fh| fh.puts "int THE_VALUE = 42;"}
File.open(h_fname, "w") {|fh| fh.puts "extern int THE_VALUE;"}
cache.register_build([c_fname, h_fname], "", sources, env)
end
target
end
end
env = Rscons::Environment.new do |env|
env.add_builder(CHGen.new)
env.CHGen("inc.c", ["program.c"])
env.Program("program", Dir["*.c"] + ["inc.c"])
end
lines.should == ["CHGen inc.c", "CC program.o", "CC inc.o", "LD program"]
File.exists?("inc.c").should be_true
File.exists?("inc.h").should be_true
`./program`.should == "The value is 42\n"
File.open("inc.c", "w") {|fh| fh.puts "int THE_VALUE = 33;"}
env.process
lines.should == ["CHGen inc.c"]
`./program`.should == "The value is 42\n"
end
it 'allows cloning Environment objects' do
test_dir('clone_env')
@@ -265,6 +298,29 @@ EOF
]
end
it 'allows cloning all attributes of an Environment object' do
test_dir('clone_env')
env1 = Rscons::Environment.new(echo: :command) do |env|
env.build_dir('src', 'build')
env['CFLAGS'] = '-O2'
env.add_build_hook do |build_op|
build_op[:vars]['CPPFLAGS'] = '-DSTRING="Hello"'
end
env.Program('program', Dir['src/*.c'])
end
env2 = env1.clone(clone: :all) do |env|
env.Program('program2', Dir['src/*.c'])
end
lines.should == [
%q{gcc -c -o build/program.o -MMD -MF build/program.mf -DSTRING="Hello" -O2 src/program.c},
%q{gcc -o program build/program.o},
%q{gcc -o program2 build/program.o},
]
end
it 'builds a C++ program with one source file' do
test_dir('simple_cc')
Rscons::Environment.new do |env|
+4 -4
View File
@@ -219,7 +219,7 @@ module Rscons
it "prints the short description and executes the command" do
env = Environment.new(echo: :short)
env.should_receive(:puts).with("short desc")
env.should_receive(:system).with("a", "command", {}).and_return(true)
env.should_receive(:system).with("a", "command").and_return(true)
env.execute("short desc", ["a", "command"])
end
end
@@ -228,7 +228,7 @@ module Rscons
it "prints the short description, executes the command, and prints the failed command line" do
env = Environment.new(echo: :short)
env.should_receive(:puts).with("short desc")
env.should_receive(:system).with("a", "command", {}).and_return(false)
env.should_receive(:system).with("a", "command").and_return(false)
$stdout.should_receive(:write).with("Failed command was: ")
env.should_receive(:puts).with("a command")
env.execute("short desc", ["a", "command"])
@@ -240,8 +240,8 @@ module Rscons
it "prints the command executed and executes the command" do
env = Environment.new(echo: :command)
env.should_receive(:puts).with("a command '--arg=val with spaces'")
env.should_receive(:system).with("a", "command", "--arg=val with spaces", opt: :val).and_return(false)
env.execute("short desc", ["a", "command", "--arg=val with spaces"], opt: :val)
env.should_receive(:system).with({modified: :environment}, "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