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