问题
I'm trying to write a task for Capistrano 3 that involves executing 'composer install' within the directory of the current release. It looks something like this:
namespace :composer do
desc 'Install dependencies with Composer'
task :install do
on roles(:web) do
within release_path do
execute "#{fetch(:composer_command)} install"
end
end
end
end
composer_command
is set in the staging and production files - in my particular case to php /home/user/composer.phar
For some reason this command does not actually run in the current release directory, but instead runs in the parent directory (containing current, shared, releases, etc)
I delved into this a bit further and found that when I ran a single word command, like:
within release_path do
execute "pwd"
end
It works just fine, and runs the command in the current release directory. But... when I run a command with spaces, like:
within release_path do
execute "pwd && ls"
end
It runs in the parent directory, and not the directory set by the within
block.
Can someone shed some light on this? Thanks!
回答1:
Smells like a Cap 3 bug.
I suggest just guaranteeing you are where you want to be from the shell perspective:
execute "cd '#{release_path}'; #{fetch(:composer_command)} install"
回答2:
You can retain all the niceties of within()
, with()
, default_env
, etc, while still keeping the natural string syntax:
within release_path do
execute *%w[ pip install -r requirements.txt ]
end
回答3:
A couple of tips:
1) Capistrano uses SSHKit for a lot of things, among which command execution. In order to simplify using Composer you could configure the command map (in deploy.rb
or production.rb
, etc), here are 2 examples:
SSHKit.config.command_map[:composer] = "#{shared_path.join('composer.phar')}"
SSHKit.config.command_map[:composer] = '/usr/bin/env composer.phar'
Next you can execute it like so:
execute :composer, :install
2) From a security perspective it's wise to disable the php setting allow_url_fopen
, but unfortunately Composer needs it enabled to function. You can use this trick to leave it disabled globally:
SSHKit.config.command_map[:composer] = "/usr/bin/env php -d allow_url_fopen=On #{shared_path.join('composer.phar')}"
Check out iniscan for more security advise on php settings.
3) Composer has an option -d, --working-dir
, which you can point to the directory containing the composer.json
file in order to run Composer from any other directory. This should solve your problem:
execute :composer, '-d', release_path, :install
4) You may want to take a look at the capistrano-composer project :)
回答4:
Actually, your use of the within
function is almost correct. You have supplied it an entire string as a command, but the doc points out that this results in unreliable behaviour (which I have experienced myself).
Let the first argument to execute
be a symbol instead of a string (which contains whitespace):
within release_path do
execute fetch(:composer_command).to_sym, "install"
execute :pwd
execute :ls
end
回答5:
just for reference here is the Capistrano Doc explaining why within {}
does not work with arguments with whitespace. I hope this helps.
来源:https://stackoverflow.com/questions/19452983/capistrano-3-execute-within-a-directory