Using Bazaar With Capistrano on Rails Machine

  • How to convert a Subversion repository to Bazaar using Tailor.
  • Modifying your deploy.rb to use Bazaar for Capistrano deployment.

Why?

I have been using the standard Rails Machine Capistrano setup (as described in the original Five-Minute Rails Application Deployment page). The only alteration I have made to this is the use of SVK as a local wrapper for Subversion. (I started writing this blog post some months ago, and the Rails Machine instructions now suggest using Git rather than Subversion for version control.)

My setup has served me well overall, but apart from not getting to use Bazaar (which I really enjoy), I have 2 gripes with it:

  • If I am starting a new project which I plan to deploy on Rails Machine, I have to either start over with a new repository when I am ready to deploy (losing my repository history up to that point), or I have to manually upload and import my repository contents after creating a blank repository as per the Five Minute guide.
  • If I remove a project from Rails Machine, I have the same problem in reverse. I need to manually export and recreate the repository elsewhere if I want to keep it.

These aren’t everyday issues, I probably have to deal with this sort of situation only a few times every year. But, when I was starting a new project recently I began working with Bazaar and, when the time came to deploy, I decided to try to find a way around switching to Subversion. After that, I became anxious to convert all my deployed projects to the same setup.

So, my new approach is:

  • A local Bazaar repository for development, pushed to some other remote location for backup and remote access.
  • A Capistrano deployment recipe based on the Copy strategy. The Copy strategy is very straightforward, and it avoids the need to install Bazaar (and all the extra bits needed for SSH) on your deployment server.

Get Out of Subversion

The first step in the process is to convert my existing Subversion repositories to Bazaar. You can, of course, choose to ignore your version history and just import the current version of your project into a blank Bazaar repository. You lose your version history this way, but for some projects the simplicity of this approach might outweigh the posterity value of having the full code history.

There is, however, a tool which will let you export your whole repository history from Subversion into Bazaar. There are, in fact, several such tools, but I am going to use Tailor which supports several version control systems (including Git).

Unless you happen to have darcs already installed, I don’t suggest you try to get the latest development version of Tailor. Much easier to just download a released version of Tailor. If you do decide to install darcs, read this page first, especially the part about how the GHC can take 3 hours to compile.

Using Tailor

Preliminaries

Tailor needs a directory in which it can do its dirty work. To ensure we always start with a clean setup, I prefer to write a script to prepare the environment:

mkdir ~/tailor-tmp
rm ~/tailor-tmp/tailor.state

rm -rf ~/tailor-tmp/work/
mkdir ~/tailor-tmp/work/

This can and should be run prior to each time you actually run tailor. (The workflow I am describing here is for a once-off use of Tailor to convert a repository. Tailor can also be used to keep 2 repositories in sync, in which case of course you would not delete the working directory and state file.)

Creating a Config File

The tailor documentation describes the options available to you in the config file, but it’s not written in a way which makes it easy to write a file from scratch. I eventually figured out a recipe which worked for me by getting Tailor to create a blank config file and then tweaking it.

You can get Tailor to generate a blank config file as easily as:

tailor --verbose > blank-tailor-config.tailor

However, moving into ~/tailor-tmp first and passing a few simple tailor switches makes the config file much more complete:

cd ~/tailor-tmp
tailor --verbose -s svn -t bzr -R /path/to/repo > blank-tailor-config.tailor

This gives you:


[DEFAULT]
verbose = True

[project]
target = bzr:target
start-revision = INITIAL
root-directory = /Users/ana/tailor-temp
state-file = tailor.state
source = svn:source
subdir = .

[bzr:target]

[svn:source]
repository = /path/to/repo


You can read more about all these options in the projects section of the Tailor documentation.

The only item we need to change in [DEFAULT] or [project] is to set

subdir = work

The subdir is where Tailor does its magic, and it’s crucial to start with an empty subdirectory each time you run Tailor, hence this directory (along with the tailor.state file) is deleted and recreated in the prepare.sh script.

Using start-revision = INITIAL is not the same as start-revision = 1. start-revision = INITIAL uses --stop-on-copy to help calculate when the current repository was created and, hence, when it should start its export. If you are working off a repository which was forked midway through its life, but you nonetheless want the entire history, then set start-revision = 2 (or whenever the trunk/ directory was added to the repository, probably revision 2 if Capistrano created your repository for you). You might also decide to look at your log and skip over the first few irrelevant commits.

Next, we have to tell Tailor where our source repository is. The source repository is the remote Subversion repository on your Rails Machine server. You should replace /path/to/repo with the actual location of your remote repository, and then to indicate that we only want the trunk, we add module = trunk.

[svn:source]
repository = svn+ssh://deploy@subdomain.railsmachina.com/var/www/apps/appname/repos
module = trunk

If you need branches or tags, then you can run Tailor again and export these separately, or if you want to keep a Subversion-style setup (i.e. trunk/ branches/ tags/) you can set module = /. Or, take a look at the svn-tags and svn-branches options in the Tailor docs.

We don’t need to specify a target repository, since Tailor will automatically initialize a blank Bazaar repository when it runs.

Once the config file is all ready, actually running tailor is a one-liner:

tailor --configfile config.tailor

If you have set up SSH keys, then you can sit back and relax, watching the verbose output. If you don’t have SSH keys, you will need to enter your password several times during the process, at least once for every revision which is exported.

If all goes smoothly, then the ~/tailor-tmp/work directory will be a bazaar repository. You can copy this cleanly by branching it:

bzr branch ~/tailor-tmp/work ~/bzr-repositories/projectname

You should bzr push this to a remote location for safe-keeping.

If you have multiple repositories to export, all you need to change is the source repository location and you can run the script again.

Troubleshooting Tailor

If you get strange error messages, make sure you have deleted all temporary files. If in doubt, backup your config file and remove the entire ~/tailor-tmp/ directory and start over. (Note: there is no need to have the config file stored in ~/tailor-tmp/, it can be anywhere.)

It’s possible that Bazaar will choke on importing some portion of your Subversion output. I have stumbled across bizarre combinations of adding and deleting directories which confuse Bazaar. Hopefully these minor bugs have all been fixed in the latest version. If this happens to you, do file a bug. If you can’t get around it, then best option I can suggest is to start the import at a higher revision. If Bazaar doesn’t like revision 11, then set start-revision = 12 in your config file and live with the loss.

Using Capistrano with Bazaar

There are just a few settings to change in deploy.rb to use your new Bazaar repository for deployment.

Change the :repository switch from something like this:

set :repository, "svn+ssh://#{user}@#{domain}#{deploy_to}/repos/trunk"

to something like this:

set :repository, "."
set :deploy_via, :copy
set :copy_strategy, :export
set :copy_cache, true

And you’ll need to specify the form of version control being used. Since Subversion is the default, there may be a commented-out line of code in your deploy.rb like this:

#set :scm,"subversion"

Uncomment this line and use the string “bzr” to indicate Bazaar:

set :scm, "bzr"

There is one final tweak necessary, and this is a slight alteration to the railsmachine gem itself.

You’ll need to add bzr to the list of allowed version control systems, and you’ll need to create an empty file named bzr.rb in the lib/railsmachiine/recipes/scm/ directory.

With these changes made, you should now be able to cap deploy from your new Bazaar repository.




Jesse Newland 24 Mar 2009

Thanks for the post and the kind words about Rails Machine! I just wanted to clarify something really quick - it's always been possible to deploy to Rails Machine with a pre-existing source control repository. For details on how to do this, please see the "If you're already using Source Control" section of our Five Minute Application Deployment page:

https://support.railsmachine.com/index.php?pg=kb.page&id=12

I'll also try to work with the guys to remove the concept of 'allowed version control systems' - we have additional support for git and svn (like importing existing repos, etc) but that shouldn't preclude you from using any other source control system that Capistrano supports (like bzr - http://times.usefulinc.com/2006/09/29-rails-bzr)