Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Capistrano 3 execute within a directory

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!

like image 330
Rahul Sekhar Avatar asked Oct 18 '13 15:10

Rahul Sekhar


3 Answers

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"
like image 167
Electrawn Avatar answered Nov 08 '22 05:11

Electrawn


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
like image 11
bricker Avatar answered Nov 08 '22 05:11

bricker


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 :)

like image 7
Jasper N. Brouwer Avatar answered Nov 08 '22 05:11

Jasper N. Brouwer