From a34bc597213ed1d771bb8ddc930fdfcf75ec9470 Mon Sep 17 00:00:00 2001 From: Matt Griffin Date: Wed, 4 Jan 2012 14:45:49 -0500 Subject: [PATCH 1/3] Add "exec" action to allow execution of arbitrary commands with the app's environment. --- lib/foreman/cli.rb | 11 +++++++++ spec/foreman/cli_spec.rb | 49 ++++++++++++++++++++++++++++++++++++++++ spec/helper_spec.rb | 18 +++++++++++++++ spec/spec_helper.rb | 10 ++++++++ 4 files changed, 88 insertions(+) create mode 100644 spec/helper_spec.rb diff --git a/lib/foreman/cli.rb b/lib/foreman/cli.rb index 0e82a04..63ff006 100644 --- a/lib/foreman/cli.rb +++ b/lib/foreman/cli.rb @@ -53,7 +53,18 @@ class Foreman::CLI < Thor error "no processes defined" unless engine.procfile.entries.length > 0 display "valid procfile detected (#{engine.procfile.process_names.join(', ')})" end + + desc "exec COMMAND", "Run a command using your application's environment" + def exec(*args) + engine.apply_environment! + Kernel.exec args.join(" ") + rescue Errno::EACCES + error "not executable: #{args.first}" + rescue Errno::ENOENT + error "command not found: #{args.first}" + end + private ###################################################################### def check_procfile! diff --git a/spec/foreman/cli_spec.rb b/spec/foreman/cli_spec.rb index 2250d08..2e6d94c 100644 --- a/spec/foreman/cli_spec.rb +++ b/spec/foreman/cli_spec.rb @@ -89,5 +89,54 @@ describe "Foreman::CLI" do end end end + + describe "exec" do + describe "with a valid Procfile" do + before { write_procfile } + + describe "and a command" do + let(:command) { ["ls", "-l"] } + + before(:each) do + stub(Kernel).exec + end + + it "should load the environment file" do + write_env + preserving_env do + subject.exec *command + ENV["FOO"].should == "bar" + end + + ENV["FOO"].should be_nil + end + + it "should execute the command as a string" do + mock(Kernel).exec(command.join(" ")) + subject.exec *command + end + end + + describe "and a non-existent command" do + let(:command) { "iuhtngrglhulhdfg" } + + it "should print an error" do + mock_error(subject, "command not found: #{command}") do + subject.exec command + end + end + end + + describe "and a non-executable command" do + let(:command) { __FILE__ } + + it "should print an error" do + mock_error(subject, "not executable: #{command}") do + subject.exec command + end + end + end + end + end end diff --git a/spec/helper_spec.rb b/spec/helper_spec.rb new file mode 100644 index 0000000..6fd5efe --- /dev/null +++ b/spec/helper_spec.rb @@ -0,0 +1,18 @@ +require "spec_helper" + +describe "spec helpers" do + describe "#preserving_env" do + after { ENV.delete "FOO" } + + it "should remove added environment vars" do + preserving_env { ENV["FOO"] = "baz" } + ENV["FOO"].should == nil + end + + it "should reset modified environment vars" do + ENV["FOO"] = "bar" + preserving_env { ENV["FOO"] = "baz"} + ENV["FOO"].should == "bar" + end + end +end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 5a901bc..e22bd7a 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -63,6 +63,16 @@ def example_export_file(filename) data end +def preserving_env + old_env = ENV.to_hash + begin + yield + ensure + ENV.clear + ENV.update(old_env) + end +end + RSpec.configure do |config| config.color_enabled = true config.include FakeFS::SpecHelpers From 9432989fbeb29df49f82a453c9c713fb9242b97e Mon Sep 17 00:00:00 2001 From: Matt Griffin Date: Mon, 9 Jan 2012 17:11:32 -0500 Subject: [PATCH 2/3] Steal the run method back from Thor so that it can be used in place for exec for running commands in the foreman environment. Fix some error reporting. --- lib/foreman/cli.rb | 27 +++++++++++++++++---------- spec/foreman/cli_spec.rb | 16 ++++++++-------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/lib/foreman/cli.rb b/lib/foreman/cli.rb index 63ff006..f8c025b 100644 --- a/lib/foreman/cli.rb +++ b/lib/foreman/cli.rb @@ -5,15 +5,21 @@ require "thor" require "yaml" class Foreman::CLI < Thor - class_option :procfile, :type => :string, :aliases => "-f", :desc => "Default: Procfile" - desc "start", "Start the application" method_option :env, :type => :string, :aliases => "-e", :desc => "Specify an environment file to load, defaults to .env" method_option :port, :type => :numeric, :aliases => "-p" method_option :concurrency, :type => :string, :aliases => "-c", :banner => '"alpha=5,bar=3"' + class << self + # Hackery. Take the run method away from Thor so that we can redefine it. + def is_thor_reserved_word?(word, type) + return false if word == 'run' + super + end + end + def start check_procfile! engine.start @@ -54,15 +60,17 @@ class Foreman::CLI < Thor display "valid procfile detected (#{engine.procfile.process_names.join(', ')})" end - desc "exec COMMAND", "Run a command using your application's environment" + desc "run COMMAND", "Run a command using your application's environment" - def exec(*args) + def run(*args) engine.apply_environment! - Kernel.exec args.join(" ") - rescue Errno::EACCES - error "not executable: #{args.first}" - rescue Errno::ENOENT - error "command not found: #{args.first}" + begin + exec args.join(" ") + rescue Errno::EACCES + error "not executable: #{args.first}" + rescue Errno::ENOENT + error "command not found: #{args.first}" + end end private ###################################################################### @@ -98,5 +106,4 @@ private ###################################################################### defaults = YAML::load_file(".foreman") || {} Thor::CoreExt::HashWithIndifferentAccess.new(defaults.merge(original_options)) end - end diff --git a/spec/foreman/cli_spec.rb b/spec/foreman/cli_spec.rb index 2e6d94c..8b9285f 100644 --- a/spec/foreman/cli_spec.rb +++ b/spec/foreman/cli_spec.rb @@ -90,7 +90,7 @@ describe "Foreman::CLI" do end end - describe "exec" do + describe "run" do describe "with a valid Procfile" do before { write_procfile } @@ -98,22 +98,22 @@ describe "Foreman::CLI" do let(:command) { ["ls", "-l"] } before(:each) do - stub(Kernel).exec + stub(subject).exec end it "should load the environment file" do write_env preserving_env do - subject.exec *command + subject.run *command ENV["FOO"].should == "bar" end ENV["FOO"].should be_nil end - it "should execute the command as a string" do - mock(Kernel).exec(command.join(" ")) - subject.exec *command + it "should runute the command as a string" do + mock(subject).exec(command.join(" ")) + subject.run *command end end @@ -122,7 +122,7 @@ describe "Foreman::CLI" do it "should print an error" do mock_error(subject, "command not found: #{command}") do - subject.exec command + subject.run command end end end @@ -132,7 +132,7 @@ describe "Foreman::CLI" do it "should print an error" do mock_error(subject, "not executable: #{command}") do - subject.exec command + subject.run command end end end From 33d738b3f8e4859a8adb8247e7349acf5f8d9c5a Mon Sep 17 00:00:00 2001 From: Matt Griffin Date: Mon, 9 Jan 2012 17:15:20 -0500 Subject: [PATCH 3/3] Return some whitespace that was accidentally removed --- lib/foreman/cli.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/foreman/cli.rb b/lib/foreman/cli.rb index f8c025b..cb259c0 100644 --- a/lib/foreman/cli.rb +++ b/lib/foreman/cli.rb @@ -5,7 +5,9 @@ require "thor" require "yaml" class Foreman::CLI < Thor + class_option :procfile, :type => :string, :aliases => "-f", :desc => "Default: Procfile" + desc "start", "Start the application" method_option :env, :type => :string, :aliases => "-e", :desc => "Specify an environment file to load, defaults to .env"