Capistrano, OS X


#1

If you installed your copy of ruby via DarwinPorts, the hashbang lines
at the top of your dispatch.* scripts says “#!/opt/local/bin/ruby”. This
is a problem, if you’re deployin via Capistrano to a host with a
different path to ruby (which would be practially all of them:-)

Here’s a fix. Add this “fix_hashbangs.rb” script to your script
directory.

Don’t forget to make it executable, and check it in to your Subversion
repository.

#!/usr/bin/env ruby
current_path = ARGV[0]
new_hashbang = ARGV[1]
f_names = %w(dispatch.cgi dispatch.rb dispatch.fcgi)
f_names.each do |name|
puts ls -al "#{current_path}/public/#{name}"
File.open("#{current_path}/public/#{name}", “r+”) do |f|
f_contents = f.read
f_contents.gsub!(/^#!.+$/, new_hashbang)
f.rewind
f.write(f_contents)
end
end

Add the following in deploy.rb, with the path to ruby on your production
server in the second argument:

task :before_restart do
run “#{current_path}/script/fix_hashbangs.rb #{current_path}
‘#!/path/to/ruby’”
end

Now your dispatch.* files will be edited automatically when you deploy.

–Al Evans


#2

On Apr 21, 2006, at 06:33 PM, Al Evans wrote:

If you installed your copy of ruby via DarwinPorts, the hashbang lines
at the top of your dispatch.* scripts says “#!/opt/local/bin/ruby”.
This
is a problem, if you’re deployin via Capistrano to a host with a
different path to ruby (which would be practially all of them:-)

I’m not trying to knock DarwinPorts, because I think it’s a really
nice package system, but I’ve got just enough Unix admin in me to
really not like the installing in /opt/local when /usr/local is
specifically designed to hold locally installed packages.

So, my recommendation for not having any hashbang line issues with
any of your Ruby script files is to run, don’t walk, over to
hivelogic.com and follow the steps outlined in his outstanding Rails
install article:

http://www.hivelogic.com/articles/2005/12/01/
ruby_rails_lighttpd_mysql_tiger

Yes, you will need break out your XCode installer CD from your Tiger
disc set (or download the installer from Apple’s Developer site:
developer.apple.com), but I’d argue that you should have those tools
installed, anyway. If only to get the Property List Editor so you can
easily look inside, and modify, .plist files.

Once you have XCode installed, following the steps in the article is
a breeze. And you end up with a much “cleaner” install of all the
pieces you need for Rails. I’ve followed this procedure for 4 OS X
boxes, including the Tiger Server XServe that we use for Production
deployment.

-Brian


#3

On 4/21/06, Brian V Hughes removed_email_address@domain.invalid wrote:

I’m not trying to knock DarwinPorts, because I think it’s a really
nice package system, but I’ve got just enough Unix admin in me to
really not like the installing in /opt/local when /usr/local is
specifically designed to hold locally installed packages.

Brian’s right: /opt/local/ is a poor place to be installing these files.

So, you can either install everything yourself in /usr/local – the
correct place – or, if you’d rather use DarwinPorts – as you
probably should, since it greatly simplifies and improves your
installation / de-installation process and setup – you can just tell
it to use /usr/local instead of /opt/local.

To do so, you’ll need to install it from source. But once that’s
done, you won’t need to install anything else from source. (Quite
possibly ever again, depending on your needs.)

The official instructions are here:

http://darwinports.opendarwin.org/docs/ch01s03.html

To summarize:

Download and extract the DP source tarball from

http://www.darwinports.org/downloads/

cd darwinports/base

./configure --prefix=’/usr/local’

make

sudo make install

Adding the “–prefix=’/usr/local’” is the key.

Hope that helps.

For the record, the DP FAQ entry on this point explains why they chose
the directory they did:

http://wiki.opendarwin.org/index.php/DarwinPorts:FAQ#Why_is_.2Fopt.2Flocal_the_default_install_location_for_DarwinPorts.3F


Chris B.

http://hypsometry.com/ : website edification
http://uvlist.org/ : free classifieds for the Upper Valley


#4

“Brian” == Brian V Hughes writes:

I’ve got just enough Unix admin in me to really not like the
installing in /opt/local when /usr/local is specifically designed to
hold locally installed packages.

Not to knock the way you admin your systems, but that opinion is not
universal among Unix sysadmins. Some (me, for example) keep /usr/local
for things we’ve installed manually, and really don’t like it if some
packaging system decides to stomp all over them.

Also, having each packaging system use its own hierarchy makes it
possible to have more than one of them installed. Using both
DarwinPorts and Fink works fine today, since one lives in /opt/local
and one in /sw/fink. If they both tried to live in /usr/local, it
would not work so well.

I was about to start looking at Capistrano for deployment at work. If
it has problems with Ruby being installed in different places on
different machines, I may not bother. How big a problem is it, really?

	     Calle D. <removed_email_address@domain.invalid>
	 http://www.livejournal.com/users/cdybedahl/

“But that was in the gauzy realm of meat and oxygen, not this real
world
here on the screen.” – archbishopm, LiveJournal


#5

Calle D. wrote:

“Brian” == Brian V Hughes writes:

I’ve got just enough Unix admin in me to really not like the
installing in /opt/local when /usr/local is specifically designed to
hold locally installed packages.

Not to knock the way you admin your systems, but that opinion is not
universal among Unix sysadmins. Some (me, for example) keep /usr/local
for things we’ve installed manually, and really don’t like it if some
packaging system decides to stomp all over them.

Yeah, what he said! I don’t like package managers that much, and I
certainly don’t want them mixing their stuff with my stuff:-) My
personal policy is that if it’s in /usr/local, then the source, or at
leat the .tgx file, is in /usr/local/src.

I was about to start looking at Capistrano for deployment at work. If
it has problems with Ruby being installed in different places on
different machines, I may not bother. How big a problem is it, really?

The solution I gave above takes care of the problem. Another solution
(offered by someone more into the zen of “convention over configuration”
than I am) is just to make soft links to ruby on your development
machine everywhere your deployment machine might expect to find it, then
hand edit your dispatch.* files immediately after you generate the
project to match what your deployment machine(s) expect.

I have ruby installed in “unexpected” places on both my development and
deployment platforms, and it works fine. I also had to set the PATH in
.bashrc on the remote machine for the ssh commands to be happy.

But being able to type “rake deploy” and have everything happen
automatically is very cool:-)

–Al Evans

–Al Evans


#6

Kerry B. wrote:

Isn’t the easiest solution to just use “#!/usr/bin/env ruby” instead
of a hardcoded path?

On the host I use for deployment, the fcgi process is executed via
suexec. I suspect the PATH would be set to whatever’s in /etc/profile,
which would not include my local copy of ruby/rails/etc. So it would use
whatever ruby was pointed to by /usr/bin/env, which would probably not
be mine. If you look, you’ll find the hashbang lines in all ruby files
in a new rails application are “#!/usr/bin/env ruby”, EXCEPT for
public/dispatch.*, which are absolute paths.

–Al Evans


#7

“Kerry” == Kerry B. removed_email_address@domain.invalid writes:

Isn’t the easiest solution to just use “#!/usr/bin/env ruby” instead
of a hardcoded path?

Possibly easiest, but since it translates to “Whichever Ruby happens
to currently be first in $PATH” it’s not really the most reliable.
It’s my experience that this kind of thing will come bite you in the
ass at 3AM a Sunday morning when the application is restarted by your
on-call colleague who for some bizarre reason has his PATH set so it
gets run by a Ruby NFS-mounted from a flaky server in Kuala Lumpur.

	     Calle D. <removed_email_address@domain.invalid>
	 http://www.livejournal.com/users/cdybedahl/
 "And don't try to tell us there is no way to go but up, because the
  truth is, there is *always* more down." -- Gunn, Angel: the Series

#8

On Apr 22, 2006, at 04:04 AM, Calle D. wrote:

Not to knock the way you admin your systems, but that opinion is not
universal among Unix sysadmins. Some (me, for example) keep /usr/local
for things we’ve installed manually, and really don’t like it if some
packaging system decides to stomp all over them.

This, of course, is why I don’t use packaging systems on any of my OS
X boxes. RedHat is a different story, since the entire OS is
maintained though a package system, but I don’t admin any RedHat
boxes. We’ve got actual RedHat admin experts here at Dartmouth. :slight_smile:

Also, having each packaging system use its own hierarchy makes it
possible to have more than one of them installed. Using both
DarwinPorts and Fink works fine today, since one lives in /opt/local
and one in /sw/fink. If they both tried to live in /usr/local, it
would not work so well.

Good point. I actually didn’t know that they did that. But, as I’ve
said, I’m not a real sys admin and I’ve never used package systems
under OS X. I just don’t have that many extra things installed. And
for those that I do, it’s really not that hard to build them from
scratch. In most cases it’s just 3 or 4 commands on the command line.

I was about to start looking at Capistrano for deployment at work. If
it has problems with Ruby being installed in different places on
different machines, I may not bother. How big a problem is it, really?

This depends on the shell that you use for SSH and how that shell’s
default PATH variable is set. If the default PATH doesn’t look in /
usr/local/ (or where ever) first, then you’re going to run into
problems. There are three ways to get around this:

  • Replace the /usr/bin/ruby with a symlink
  • Enable the SSH flag that lets you set ENV vars on non-login
    sessions (which is what cap uses)
  • Recompile the shell you use to have a different default PATH

There are plenty of pros and cons to each of these. For the
production Rails Xserve we use at Dartmouth, we went with the second
option (which has worked flawlessly). If that server had more than
4-5 actual user logins, we probably would have gone with the first,
because there are some security implications when you go with the
second. We never really considered going with the third option, but
that might appeal to some…

-Brian


#9

On Apr 22, 2006, at 2:04 AM, Calle D. wrote:

Also, having each packaging system use its own hierarchy makes it
possible to have more than one of them installed. Using both
DarwinPorts and Fink works fine today, since one lives in /opt/local
and one in /sw/fink. If they both tried to live in /usr/local, it
would not work so well.

I was about to start looking at Capistrano for deployment at work. If
it has problems with Ruby being installed in different places on
different machines, I may not bother. How big a problem is it, really?

In defense of Capistrano, this isn’t a problem with cap. It’s a
“problem” with whatever application you’re deploying via cap.
Capistrano itself does not invoke Ruby on the remote hosts–it simply
gets the app installed. If the dispatch.fcgi has the shebang line set
wrong for the remote host, that’s not capistrano’s fault.

Anyway, done defending. :slight_smile:

  • Jamis

#10

On 22 Apr 2006, at 9:04 am, Calle D. wrote:

I was about to start looking at Capistrano for deployment at work. If
it has problems with Ruby being installed in different places on
different machines, I may not bother. How big a problem is it, really?

Isn’t the easiest solution to just use “#!/usr/bin/env ruby” instead
of a hardcoded path?

Kerry