diff --git a/bin/foreman-runner b/bin/foreman-runner
index e8adb5c..2e73701 100755
--- a/bin/foreman-runner
+++ b/bin/foreman-runner
@@ -1,6 +1,6 @@
#!/bin/sh
#
-#/ Usage: foreman-runner [-d
]
+#/ Usage: foreman-runner [-d ] [...]
#/
#/ Run a command with exec, optionally changing directory first
@@ -27,10 +27,6 @@ done
shift $((OPTIND-1))
-command=$1
+[ -z "$1" ] && usage
-if [ -z "$1" ]; then
- usage
-fi
-
-exec $1
+exec "$@"
diff --git a/lib/foreman/cli.rb b/lib/foreman/cli.rb
index 85498dc..acaa5f4 100644
--- a/lib/foreman/cli.rb
+++ b/lib/foreman/cli.rb
@@ -2,6 +2,7 @@ require "foreman"
require "foreman/helpers"
require "foreman/engine"
require "foreman/export"
+require "shellwords"
require "thor"
require "yaml"
@@ -59,12 +60,12 @@ class Foreman::CLI < Thor
puts "valid procfile detected (#{engine.procfile.process_names.join(', ')})"
end
- desc "run COMMAND", "Run a command using your application's environment"
+ desc "run COMMAND [ARGS...]", "Run a command using your application's environment"
def run(*args)
engine.apply_environment!
begin
- exec args.join(" ")
+ exec args.shelljoin
rescue Errno::EACCES
error "not executable: #{args.first}"
rescue Errno::ENOENT
diff --git a/lib/foreman/process.rb b/lib/foreman/process.rb
index 8f31d8b..ebd8529 100644
--- a/lib/foreman/process.rb
+++ b/lib/foreman/process.rb
@@ -62,7 +62,7 @@ private
$stdout.reopen writer
$stderr.reopen writer
reader.close
- exec Foreman.runner, "-d", basedir, command
+ exec Foreman.runner, "-d", basedir, *command.shellsplit
end
end
[ reader, pid ]
diff --git a/spec/foreman/cli_spec.rb b/spec/foreman/cli_spec.rb
index 4473330..d45e747 100644
--- a/spec/foreman/cli_spec.rb
+++ b/spec/foreman/cli_spec.rb
@@ -144,7 +144,7 @@ describe "Foreman::CLI", :fakefs do
before { write_procfile }
describe "and a command" do
- let(:command) { ["ls", "-l"] }
+ let(:command) { ["ls", "-l", "foo bar"] }
before(:each) do
stub(subject).exec
@@ -160,8 +160,8 @@ describe "Foreman::CLI", :fakefs do
ENV["FOO"].should be_nil
end
- it "should runute the command as a string" do
- mock(subject).exec(command.join(" "))
+ it "should exec the argument list as a shell command" do
+ mock(subject).exec(command.shelljoin)
subject.run *command
end
end
diff --git a/spec/foreman/process_spec.rb b/spec/foreman/process_spec.rb
index d8380db..1f2d1ea 100644
--- a/spec/foreman/process_spec.rb
+++ b/spec/foreman/process_spec.rb
@@ -121,11 +121,25 @@ describe Foreman::Process do
output.should include('777')
end
- it 'should handle arguments' do
- pending
+ it 'should handle multi-word arguments (old test)' do
+ # TODO: This test used to be marked pending; it now passes,
+ # but is very slow. The next test is a fast replacement.
run %{ sh -c "trap '' TERM; sleep 10" }
subject.should be_alive
end
+
+ it 'should handle multi-word arguments' do
+ # We have to be a little clever here since Foreman will always
+ # print a status message that includes the command.
+ run %{ sh -c 'echo abcdef | tr a-c x | tr d-f y' }
+ output.should include('xxxyyy')
+ end
+
+ it 'should not clobber "$x"-subexpressions' do
+ pending 'this conflicts with the variable interpolation hack'
+ run %{ sh -c 'echo \$abcdef | tr \$ %' }
+ output.should include('%abcdef')
+ end
end
end
end