jump to navigation

Patching Capistrano to use CVS over SSH September 11, 2007

Posted by reidmix in Capistrano, Code, Command Line, CVS, Monkey Patch, Ruby, SSH.
trackback

At work we still use CVS as our versioning repository and most of our systems rely on CVS to build and deploy into production. Currently there is no effort to transition to SVN, so we need to develop a patch to Capistrano to allow our projects to deploy to our development lab. We needed to extend Capistrano handle SSH logins to CVS and handle CVS repository directories.

Overall, both changes needed to be applied to the checkout method in Capistrano’s Cvs class.

We use SSH as the underlying communication mechanism for CVS but there is a difference in the password prompt: SSH’s is capitalized. We just need to make the prompt check case insensitive with the i switch:

if out =~ %r{password:}i

When setting up Capistrano (v1.4) for use in our development lab, the :application configuration is not sufficient to identify our rails project the CVS tree. We are not cool enough to setup or use modules to map into our repository directories, so our projects are usually in some form of webdev/project/appname. To handle this, i create an additional configuration parameter called :project in the deploy.rb:

set :project, "cvs/dir/to/myproj"

And we no longer use the application name for the CVS path, we use the project variable:

project = configuration[:project] || actor.application
command = <<-CMD
  cd #{configuration.releases_path};
  CVS_RSH="#{cvs_rsh}" #{cvs} -d #{configuration.repository} -Q #{op} -D "#{configuration.revision}" #{branch_option} -d #{File.basename(actor.release_path)} #{project};
CMD

The hardest part is patching Capistrano. Capistrano’s code gets loaded well after any library or environment gets loaded. The trick is to use the method_added hook to wait for the checkout method to get loaded and then alias the method to the patched one, we need to keep a variable around to check if we’ve patched the method so we don’t end up in an infinite loop:

@@checkout_patched = false
def Cvs.method_added(id)
  if id.id2name == "checkout"
    unless @@checkout_patched
      @@checkout_patched = true
      alias_method :checkout, :checkout_patch
    end
  end
end

I’ve not checked to see how these changes work or differ in Capistrano 2. But with all these elements together using Capistrano v1.4, I can drop this file in my lib directory or create a plugin with it. Together, here is the full patch which I have in a file called capistrano_cvs_ext.rb:

module Capistrano
  module SCM
    class Cvs < Base
      @@checkout_patched = false
      def Cvs.method_added(id)
        if id.id2name == "checkout"
          unless @@checkout_patched
            @@checkout_patched = true
            alias_method :checkout, :checkout_patch
          end
        end
      end

      def checkout_patch(actor)
        cvs = configuration[:cvs] || "cvs"
        cvs_rsh = configuration[:cvs_rsh] || ENV['CVS_RSH'] || "ssh"

        if "HEAD" == configuration.branch then
            branch_option = ""
        else
            branch_option = "-r #{configuration.branch}"
        end

        # cvs has a root and repository, repository is not the same as application name as it can be a path
        op = configuration[:checkout] || "co"
        project = configuration[:project] || actor.application

        command = <<-CMD
          cd #{configuration.releases_path};
          CVS_RSH="#{cvs_rsh}" #{cvs} -d #{configuration.repository} -Q #{op} -D "#{configuration.revision}" #{branch_option} -d #{File.basename(actor.release_path)} #{project};
        CMD

        run_checkout(actor, command) do |ch, stream, out|
          prefix = "#{stream} :: #{ch[:host]}"
          actor.logger.info out, prefix
          if out =~ %r{password:}i  # SSH asks for "Password" with a capital P
            actor.logger.info "CVS is asking for a password", prefix
            ch.send_data "#{actor.password}n"
          elsif out =~ %r{^Enter passphrase}
            message = "CVS needs your key's passphrase and cannot proceed"
            actor.logger.info message, prefix
            raise message
          end
        end
      end
    end
  end
end
Advertisements

Comments»

1. reidmix - September 11, 2007

Not loving wordpress’s insistence on removing my indenting on my code and conversion of my less-than symbols into “lt” character entities. 😦

2. Maximus - December 20, 2007

I would like to see a continuation of the topic

3. Anp - May 2, 2008

h!……

Thank You so much ……

I am searching for the deployment using Capistarno and CVS as our company is using CVS for a while….
and they started a new project on Rails………
Can you suggest me something more for reading about good practises for deployment for a newbie. From a Local CVS to Public server runs on Apache + Mongrel……………

Thanks,

4. reidmix - October 28, 2008

You can check out capistrano links on delicious, find info about it here:
http://capify.org/2008/7/10/capistrano-links-on-del-icio-us


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: