Compare commits

...
23 Commits
Author SHA1 Message Date
David Dollar 533139ea9f 0.33.1 2012-01-16 09:18:48 -05:00
David Dollar 86e2056a24 Merge pull request #129 from fnichol/resolve-home-template
Expand template path under user's home directory (foreman export).
2012-01-16 06:17:43 -08:00
Fletcher Nichol ab29963ee4 Expand template path under user's home directory.
* File.join won't expand `~` into `ENV['HOME']`
  (http://ruby-doc.org/core-1.9.3/File.html#method-c-expand_path)
* The FakeFS File.exists? implementation calls FileSystem#find
  (https://github.com/defunkt/fakefs/blob/master/lib/fakefs/file_system.rb#L22-33)
  containing a call to FileSystem#normalize_path which expands the
  path variable passed in
  (https://github.com/defunkt/fakefs/blob/master/lib/fakefs/file_system.rb#L91-98)
* The file system mocking library sets up a false expectation that `~`
  will be expanded in the #export_template method and consequently the
  production code can't use the template directory
* To guard against future regressions such as fixes/updates to FakeFS or
  using an alternate file system mocking library, the specs were updated
  to explicitly set `ENV['HOME']`
2012-01-15 19:09:52 -07:00
David Dollar cf269c39da 0.33.0 2012-01-15 13:00:45 -05:00
David Dollar 76cd2e794b Revert "Merge pull request #125 from brainopia/master"
It appears that this is causing issues with process termination.

This reverts commit d2c9ce0f34, reversing
changes made to 98337c92e1.
2012-01-15 12:59:47 -05:00
David Dollar 83748cb538 0.32.0 2012-01-12 15:25:43 -08:00
David Dollar d2c9ce0f34 Merge pull request #125 from brainopia/master
Support for complex cmds in Procfile
2012-01-12 15:23:15 -08:00
David Dollar 98337c92e1 Merge pull request #121 from Viximo/feature/run
Add "exec" action to allow execution of commands within the app environment
2012-01-09 16:02:42 -08:00
Matt Griffin 33d738b3f8 Return some whitespace that was accidentally removed 2012-01-09 17:15:20 -05:00
Matt Griffin 9432989fbe 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.
2012-01-09 17:11:32 -05:00
brainopia 66b1483a75 Remove old cruft 2012-01-08 10:18:48 +07:00
brainopia 64bd4db128 In case someone wants to use bin/runner directly 2012-01-08 10:15:23 +07:00
brainopia b561555f3a Fix for double fork 2012-01-08 09:42:51 +07:00
brainopia baa7b7685c Use ruby exec which works with escaped cmd and replaces shell 2012-01-07 20:19:57 +07:00
brainopia cfa6e6f259 Fix foreman to work with cmds containing pipes and redirects 2012-01-07 18:19:54 +07:00
Matt Griffin a34bc59721 Add "exec" action to allow execution of arbitrary commands with the app's environment. 2012-01-04 15:22:10 -05:00
David Dollar 07e8ca4a4b tweak readme 2012-01-04 12:36:34 -05:00
David Dollar 342d30bbb8 0.31.0 2012-01-04 12:16:51 -05:00
David Dollar 268dd6240e make fork more robust 2012-01-04 12:15:55 -05:00
David Dollar 9e60b3e1a4 remove unnecessary debug 2012-01-04 12:15:38 -05:00
David Dollar 1c6285f8af add more information when shutting down 2012-01-04 12:15:17 -05:00
David Dollar fff15bc627 Merge pull request #110 from lstoll/master
Different port range for each process type on 'foreman start'
2011-12-24 22:47:36 -08:00
Lincoln Stoll a66157d611 Use different port ranges for each process type 2011-12-25 15:46:21 +11:00
11 changed files with 121 additions and 19 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
PATH PATH
remote: . remote: .
specs: specs:
foreman (0.30.1) foreman (0.33.1)
term-ansicolor (~> 1.0.5) term-ansicolor (~> 1.0.5)
thor (>= 0.13.6) thor (>= 0.13.6)
+2 -1
View File
@@ -20,7 +20,8 @@ http://blog.daviddollar.org/2011/05/06/introducing-foreman.html
## Manual ## Manual
See the [man page](http://ddollar.github.com/foreman) for usage. * [man page](http://ddollar.github.com/foreman)
* [wiki](http://github.com/ddollar/foreman/wiki)
## Authorship ## Authorship
+23 -3
View File
@@ -5,15 +5,23 @@ require "thor"
require "yaml" require "yaml"
class Foreman::CLI < Thor class Foreman::CLI < Thor
class_option :procfile, :type => :string, :aliases => "-f", :desc => "Default: Procfile" class_option :procfile, :type => :string, :aliases => "-f", :desc => "Default: Procfile"
desc "start", "Start the application" desc "start", "Start the application"
method_option :env, :type => :string, :aliases => "-e", :desc => "Specify an environment file to load, defaults to .env" 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 :port, :type => :numeric, :aliases => "-p"
method_option :concurrency, :type => :string, :aliases => "-c", :banner => '"alpha=5,bar=3"' 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 def start
check_procfile! check_procfile!
engine.start engine.start
@@ -53,7 +61,20 @@ class Foreman::CLI < Thor
error "no processes defined" unless engine.procfile.entries.length > 0 error "no processes defined" unless engine.procfile.entries.length > 0
display "valid procfile detected (#{engine.procfile.process_names.join(', ')})" display "valid procfile detected (#{engine.procfile.process_names.join(', ')})"
end end
desc "run COMMAND", "Run a command using your application's environment"
def run(*args)
engine.apply_environment!
begin
exec args.join(" ")
rescue Errno::EACCES
error "not executable: #{args.first}"
rescue Errno::ENOENT
error "command not found: #{args.first}"
end
end
private ###################################################################### private ######################################################################
def check_procfile! def check_procfile!
@@ -87,5 +108,4 @@ private ######################################################################
defaults = YAML::load_file(".foreman") || {} defaults = YAML::load_file(".foreman") || {}
Thor::CoreExt::HashWithIndifferentAccess.new(defaults.merge(original_options)) Thor::CoreExt::HashWithIndifferentAccess.new(defaults.merge(original_options))
end end
end end
+2 -1
View File
@@ -58,7 +58,7 @@ private ######################################################################
procfile.entries.each do |entry| procfile.entries.each do |entry|
reader, writer = IO.pipe reader, writer = IO.pipe
entry.spawn(concurrency[entry.name], writer, @directory, @environment, base_port).each do |process| entry.spawn(concurrency[entry.name], writer, @directory, @environment, port_for(entry, 1, base_port)).each do |process|
running_processes[process.pid] = process running_processes[process.pid] = process
readers[process] = reader readers[process] = reader
end end
@@ -71,6 +71,7 @@ private ######################################################################
def kill_all(signal="SIGTERM") def kill_all(signal="SIGTERM")
running_processes.each do |pid, process| running_processes.each do |pid, process|
info "sending #{signal} to pid #{pid}"
Process.kill(signal, pid) rescue Errno::ESRCH Process.kill(signal, pid) rescue Errno::ESRCH
end end
end end
+1 -1
View File
@@ -26,7 +26,7 @@ private ######################################################################
def export_template(exporter, file, template_root) def export_template(exporter, file, template_root)
if template_root && File.exist?(file_path = File.join(template_root, file)) if template_root && File.exist?(file_path = File.join(template_root, file))
File.read(file_path) File.read(file_path)
elsif File.exist?(file_path = File.join("~/.foreman/templates", file)) elsif File.exist?(file_path = File.expand_path(File.join("~/.foreman/templates", file)))
File.read(file_path) File.read(file_path)
else else
File.read(File.expand_path("../../../../data/export/#{exporter}/#{file}", __FILE__)) File.read(File.expand_path("../../../../data/export/#{exporter}/#{file}", __FILE__))
+7 -10
View File
@@ -28,21 +28,18 @@ class Foreman::Process
private private
def fork_with_io(command) def fork_with_io(command)
io = case RUBY_VERSION reader, writer = IO.pipe
when /^1\.9\./ pid = fork do
IO.popen([Foreman.runner, replace_command_env(command)], "w+") trap("INT", "IGNORE")
when /^1\.8\./ $stdout.reopen writer
full_command = replace_command_env(command).gsub("'", "\\'") reader.close
IO.popen("#{Foreman.runner} '#{full_command}'", "w+") exec Foreman.runner, replace_command_env(command)
else
raise "Unknown Ruby version: #{RUBY_VERSION}"
end end
[ io, io.pid ] [ reader, pid ]
end end
def run_process(command, pipe) def run_process(command, pipe)
io, @pid = fork_with_io(command) io, @pid = fork_with_io(command)
trap("SIGTERM") { "got sigterm for %d" % @pid }
output pipe, "started with pid %d" % @pid output pipe, "started with pid %d" % @pid
Thread.new do Thread.new do
until io.eof? until io.eof?
+1 -1
View File
@@ -1,5 +1,5 @@
module Foreman module Foreman
VERSION = "0.30.1" VERSION = "0.33.1"
end end
+49
View File
@@ -89,5 +89,54 @@ describe "Foreman::CLI" do
end end
end end
end end
describe "run" do
describe "with a valid Procfile" do
before { write_procfile }
describe "and a command" do
let(:command) { ["ls", "-l"] }
before(:each) do
stub(subject).exec
end
it "should load the environment file" do
write_env
preserving_env do
subject.run *command
ENV["FOO"].should == "bar"
end
ENV["FOO"].should be_nil
end
it "should runute the command as a string" do
mock(subject).exec(command.join(" "))
subject.run *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.run 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.run command
end
end
end
end
end
end end
+7 -1
View File
@@ -38,13 +38,19 @@ describe Foreman::Export::Upstart do
end end
context "with alternate templates from home dir" do context "with alternate templates from home dir" do
let(:default_template_root) {File.expand_path("~/.foreman/templates")} let(:default_template_root) {File.expand_path("#{ENV['HOME']}/.foreman/templates")}
before do before do
ENV['_FOREMAN_SPEC_HOME'] = ENV['HOME']
ENV['HOME'] = "/home/appuser"
FileUtils.mkdir_p default_template_root FileUtils.mkdir_p default_template_root
File.open("#{default_template_root}/master.conf.erb", "w") { |f| f.puts "default_alternate_template" } File.open("#{default_template_root}/master.conf.erb", "w") { |f| f.puts "default_alternate_template" }
end end
after do
ENV['HOME'] = ENV.delete('_FOREMAN_SPEC_HOME')
end
it "can export with alternate template files" do it "can export with alternate template files" do
upstart.export("/tmp/init") upstart.export("/tmp/init")
+18
View File
@@ -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
+10
View File
@@ -63,6 +63,16 @@ def example_export_file(filename)
data data
end end
def preserving_env
old_env = ENV.to_hash
begin
yield
ensure
ENV.clear
ENV.update(old_env)
end
end
RSpec.configure do |config| RSpec.configure do |config|
config.color_enabled = true config.color_enabled = true
config.include FakeFS::SpecHelpers config.include FakeFS::SpecHelpers