Skip to content

Commit

Permalink
attempt to auto-detect path of pid file (fixes sosedoff#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
Adam Spiers committed Sep 2, 2013
1 parent 00a5f2e commit e5e4108
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 6 deletions.
3 changes: 3 additions & 0 deletions NEWS.md
Expand Up @@ -14,6 +14,9 @@ Significant changes since 0.1.10 are as follows. Backwards-incompatible changes
* Add `unicorn_options` variable which allows passing of arbitrary options to unicorn.
* Added `app_subdir` to support app running in a subdirectory.
* Updated documentation in [README](README.md) to fix inaccuracies and ambiguities.
* `unicorn_pid` defaults to attempting to auto-detect from unicorn config file.
This avoids having to keep two paths in sync.
https://github.com/sosedoff/capistrano-unicorn/issues/7
* Also added the `unicorn:show_vars` task to make it easier to debug
config variable values client-side.
* Defer calculation of `unicorn-roles`.
Expand Down
8 changes: 4 additions & 4 deletions README.md
Expand Up @@ -55,6 +55,8 @@ cap unicorn:reload
## Configuration

You can modify any of the following Capistrano variables in your `deploy.rb` config.
You can use the `unicorn:show_vars` task to check that the values you have specified
are set correctly.

### Environment parameters

Expand All @@ -79,13 +81,11 @@ You can modify any of the following Capistrano variables in your `deploy.rb` con
### Absolute path parameters

- `app_path` - Set path to app root. Default to `current_path + app_subdir`.
- `unicorn_pid` - Set unicorn PID file path. Default to `#{current_path}/tmp/pids/unicorn.pid`
- `unicorn_pid` - Set unicorn PID file path. By default, attempts to auto-detect from unicorn config file. On failure, falls back to value in `unicorn_default_pid`
- `unicorn_default_pid` - See above. Default to `#{current_path}/tmp/pids/unicorn.pid`
- `bundle_gemfile` - Set path to Gemfile. Default to `#{app_path}/Gemfile`
- `unicorn_config_path` - Set the directory where unicorn config files reside. Default to `#{current_path}/config`.

You can use the `unicorn:show_vars` task to test the impact of your
`deploy.rb`.

## Available Tasks

To get a list of all capistrano tasks, run `cap -T`:
Expand Down
46 changes: 45 additions & 1 deletion lib/capistrano-unicorn/capistrano_integration.rb
@@ -1,3 +1,5 @@
require 'tempfile'

require 'capistrano'
require 'capistrano/version'

Expand Down Expand Up @@ -46,12 +48,54 @@ def self.load_into(capistrano_config)
# If you find the following confusing, try running 'cap unicorn:show_vars' -
# it might help :-)
_cset(:app_path) { current_path + app_subdir }
_cset(:unicorn_pid) { app_path + "/tmp/pids/unicorn.pid" }
_cset(:bundle_gemfile) { app_path + '/Gemfile' }
_cset(:unicorn_config_path) { app_path + '/' + unicorn_config_rel_path }
_cset(:unicorn_config_file_path) { app_path + '/' + unicorn_config_rel_file_path }
_cset(:unicorn_config_stage_file_path) \
{ app_path + '/' + unicorn_config_stage_rel_file_path }
_cset(:unicorn_default_pid) { app_path + "/tmp/pids/unicorn.pid" }
_cset(:unicorn_pid) do
extracted_pid = extract_pid_file
if extracted_pid
extracted_pid
else
logger.important "err :: failed to auto-detect pid from #{local_unicorn_config}"
logger.important "err :: falling back to default: #{unicorn_default_pid}"
unicorn_default_pid
end
end
end

def local_unicorn_config
File.exist?(unicorn_config_rel_file_path) ?
unicorn_config_rel_file_path
: unicorn_config_stage_rel_file_path
end

def extract_pid_file
tmp = Tempfile.new('unicorn.rb')
begin
conf = local_unicorn_config
tmp.write <<-EOF.gsub(/^ */, '')
config_file = "#{conf}"
# stub working_directory to avoid chdir failure since this will
# run client-side:
def working_directory(path); end
instance_eval(File.read(config_file), config_file) if config_file
puts set[:pid]
exit 0
EOF
tmp.close
extracted_pid = `unicorn -c "#{tmp.path}"`
$?.success? ? extracted_pid.rstrip : nil
rescue StandardError => e
return nil
ensure
tmp.close
tmp.unlink
end
end

# Check if a remote process exists using its pid file
Expand Down
35 changes: 34 additions & 1 deletion spec/capistrano_integration_spec.rb
Expand Up @@ -26,14 +26,47 @@
end

shared_examples_for "an app in path" do |app_path|
let(:shell) { :` } # ` } work around confused emacs ruby-mode

specify "app_path should default to #{app_path}" do
@configuration.fetch(:app_path).should == app_path
end

specify "pid file should default correctly" do
it "should default to a sensible pid file when auto-detection failed" do
@configuration.should_receive(shell).with(/unicorn -c /).and_return('') do |cmd|
$?.should_receive(:success?).and_return(false)
end
@configuration.logger.stub(:important)
@configuration.fetch(:unicorn_pid).should == app_path + "/tmp/pids/unicorn.pid"
end

shared_examples "auto-detect pid file from unicorn config" do
|pid_file, primary_exists, config_file|
which_config = primary_exists ? 'primary' : 'stage'
it "should auto-detect pid file from #{which_config} unicorn config" do
# Tempfile.new in Ruby 1.9.2 will call File.exist?
allow(File).to receive(:exist?).with(/tmp/)

File.should_receive(:exist?).with('config/unicorn.rb').and_return(primary_exists)
tmpfile = nil
@configuration.should_receive(shell).with(/unicorn -c /) do |cmd|
(cmd =~ /^unicorn -c "(.+)"$/).should be_true
tmpfile = $~[1]
tmpfile.should include("tmp")
File.read(tmpfile).should include(%!config_file = "#{config_file}"!)
$?.should_receive(:success?).and_return(true)
pid_file
end
@configuration.fetch(:unicorn_pid).should == pid_file
end
end

include_examples "auto-detect pid file from unicorn config", \
'/path/to/pid/from/config/file', true, "config/unicorn.rb"

include_examples "auto-detect pid file from unicorn config", \
'/path/to/pid/from/stage/config/file', false, "config/unicorn/production.rb"

specify "Gemfile should default correctly" do
@configuration.fetch(:bundle_gemfile).should == app_path + "/Gemfile"
end
Expand Down

0 comments on commit e5e4108

Please sign in to comment.