How can you check to see if a file exists (on the remote server) in Capistrano?
@knocte is correct that capture
is problematic because normally everyone targets deployments to more than one host (and capture only gets the output from the first one). In order to check across all hosts, you'll need to use invoke_command
instead (which is what capture
uses internally). Here is an example where I check to ensure a file exists across all matched servers:
def remote_file_exists?(path)
results = []
invoke_command("if [ -e '#{path}' ]; then echo -n 'true'; fi") do |ch, stream, out|
results << (out == 'true')
end
results.all?
end
Note that invoke_command
uses run
by default -- check out the options you can pass for more control.
Checking directory existence in Capistrano task fails
All Ruby methods that you use in your Capistrano tasks run on your local machine.
For example:
File.directory?
File.symlink?
These are always evaluated on your local filesystem. Capistrano never runs Ruby code on the remote server. These methods always return false
for you because they are trying to find e.g. "#{release_path}/public"
on your local computer, which of course does not exist.
To run code on the server, the tools available to you are Capistrano's test
and execute
methods. These take in a command string that is executed remotely via SSH.
If you want to test if a remote path is a directory, you cannot use Ruby; you have to use something that can be run in a remote shell. Here is one way to test if a path is a directory, for example:
is_directory = test("[ -d #{release_path}/public ]")
Likewise, to test if a path is a symlink:
is_symbolic_link = test("[ -h #{release_path}/public ]")
File.read() fails in my Capistrano task (file *does* exist)
Figured it out.
File.read()
is being performed on my local machine, not on the remote one. Ugh.
What I needed to do was something like this:
within release_path do
execute "cat #{pid_file}"
end
My actual task is:
desc 'Restart application'
task :restart do
on roles(:app), in: :sequence, wait: 5 do
pid_file = fetch(:pid_file)
within release_path do
execute "((ls #{pid_file} && ps -p `cat #{pid_file}`) && kill -9 `cat #{pid_file}`) || true"
execute "(ls #{pid_file} && /bin/rm #{pid_file}) || true"
# RESTART COMMAND GOES HERE
end
end
end
Capistrano: linked file database.yml does not exist on my.server.ipadress
Just create /home/deploy/myrailsapp/shared/config/database.yml
file manually and adjust it.
Capistrano doesn't create (or manage) configuration file out of the box. So, you should do it manually or automate use own Capistrano
scripts, Puppet
, Chef
, Ansible
tools.
Is there a way to tell Capistrano to deploy a Local Repository to a Remote Server?
The setting that you are looking for is:
set :deploy_via, :copy
That creates a local .tar.gz
file in your /tmp/
directory and pushes that to the server during deployment.
If you look at the source code, specifically lib/capistrano/recipes/deploy/strategy/copy.rb
, you'll see a large block of comments beginning with the following.
# This class implements the strategy for deployments which work
# by preparing the source code locally, compressing it, copying the
# file to each target host, and uncompressing it to the deployment
# directory.
This article was written for an older version, but it's still quite interesting and covers deployment options and optimizations.
Keep unversioned files when deploying with Capistrano
Personally, I think the best way to deal with those kind of things is to store them in the shared folder and create a task in capistrano to create symlinks to the shared assets.
Here's an example from one of my projects:
set :shared_assets, %w{public/images/products public/images/barcodes}
namespace :assets do
namespace :symlinks do
desc "Setup application symlinks for shared assets"
task :setup, :roles => [:app, :web] do
shared_assets.each { |link| run "mkdir -p #{shared_path}/#{link}" }
end
desc "Link assets for current deploy to the shared location"
task :update, :roles => [:app, :web] do
shared_assets.each { |link| run "ln -nfs #{shared_path}/#{link} #{release_path}/#{link}" }
end
end
end
before "deploy:setup" do
assets.symlinks.setup
end
before "deploy:symlink" do
assets.symlinks.update
end
Related Topics
Ruby 'Pg' Gem Linking to Wrong Copy of Libpq.5.Dylib (On Osx)
Getting Ruby 1.8.7 Installed on Mountain Lion (10.8)
Error Installing Gems That Use Native Extensions on Ubuntu, Ruby 1.9.2 via Rvm
Deploying Sinatra App (With Config.Ru) on Heroku Cedar Stack
How to Get the Parent's Class Name in Ruby
Does Dependency Injection Exist in Rails
After Gem Update: Test Fail with "Asset Was Not Declared to Be Precompiled in Production"
How to Write Negative Loop in Ruby Like For(I=Index; I >= 0; I --)
How to Check If a Param Is True or False
Does Objective-C Support Mixin Like Ruby
Purpose of & (Ampersand) in Ruby for Procs and Calling Methods