Check If a Remote File or Directory Exists with Capistrano

Posted on 15 July 2008 by Johannes Fahrenkrug. Tags: Programming Ruby rails
I have a Rails app that can have custom logos for different deployments. I wanted to make it easy and simply drop the custom images into a shared/images directory and have Capistrano copy them to current/public/images but only when the shared/images directory exists. Naively I tried this:
if "#{shared_path}/images"
  run "cp #{shared_path}/images/* #{release_path}/public/images/"
Haha, cute. This does not work, since it checks for the LOCAL file, not for the file on the remote machine. Others had a similar problem. So what's the solution? For me it was to realize that there are other languages besides Ruby to do the job, namely shell scripting. So to conditionally copy files only if a certain directory exists on the remote machine, use this one liner:
  # if the shared/images directory exists, copy all images from there to the current/public/images directory 
  # to replace logos and stuff like that
  run "if [[ -d #{shared_path}/images ]]; then cp #{shared_path}/images/* #{release_path}/public/images/; fi"


Johannes Fahrenkrug said...

Hey John,

Thank you so much for your comment, those are some very helpful tips!
You know in my case, I don't really depend on the shared/images dir to exists, it's just an optional way to customize the standard logos. That's why the symlink would also only make sense if that optional directory exists, but it's a good tip for the future. Btw, I can also never remember which comes first in ln -s ;-)

- Johannes

July 16, 2008 06:12 AM

John Trupiano said...

Hey Johannes, there are a couple of things that I can think of to help you.

1) Capistrano has basic dependency checking. For instance, I can ensure that a certain file or directory exists on the remote server:

depend(:directory, "#{shared_path}/images")

depend(:file, "#{shared_path}/some_config.xml"

The deploy:check recipe will run through all of your dependencies and let you know if they're satisfied.

2) What I do with assets like you suggest (most notably user-uploaded assets handled by the file_column plugin) is hook onto the deploy:update task, e.g.

after :update_code, :symlink_assets

task :symlink_assets do
run("ln -s #{shared_path}/images #{current_path}/public/images")

I might have the ln arguments backwards...I always forget which goes first, but the idea is that your images folder is actually a symlink up into the shared directory.

I've written some helper functions in my capistrano-extensions gem (see create_shared_file_column_dirs). You may find it a useful starting point.


July 16, 2008 12:06 AM


Please keep it clean, everybody. Comments with profanity will be deleted.

blog comments powered by Disqus