Skip to content

Instantly share code, notes, and snippets.

@randy-girard
Created September 29, 2010 19:55
Show Gist options
  • Select an option

  • Save randy-girard/603424 to your computer and use it in GitHub Desktop.

Select an option

Save randy-girard/603424 to your computer and use it in GitHub Desktop.
New Capistrano CVS Deploy Recipe
# My new_cvs.rb file. Just drop it into capistrano/recipes/deploy/scm/
# Adds these variables:
# set :scm, :new_cvs
# set :branch, "some_branch_name"
# set :cvs_rsh, "ssh"
#
# Author: Randy Girard
# Website: http://www.freezzo.com
require 'capistrano/recipes/deploy/scm/base'
module Capistrano
module Deploy
module SCM
# Implements the Capistrano SCM interface for the CVS revision
# control system.
class NewCvs < Base
# Sets the default command name for this SCM. Users may override this
# by setting the :scm_command variable.
default_command "cvs"
# CVS understands 'HEAD' to refer to the latest revision in the
# repository.
def head
"HEAD"
end
# Grabs the branch variable from the deploy file.
def branch
variable(:branch) || nil
end
# Returns the command that will check out the given revision to the
# given destination.
def checkout(revision, destination)
[ prep_destination(destination),
scm(verbose, cvs_root, :checkout, cvs_revision(revision), cvs_destination(destination), variable(:scm_module))
].join(' && ')
end
# Returns the command that will do an "cvs update" to the given
# revision, for the working copy at the given destination.
def sync(revision, destination)
[ prep_destination(destination),
scm(verbose, cvs_root, :update, cvs_revision(revision), cvs_destination(destination))
].join(' && ')
end
# Returns the command that will do an "cvs export" of the given revision
# to the given destination.
def export(revision, destination)
[ prep_destination(destination),
scm(verbose, cvs_root, :export, cvs_revision(revision), cvs_destination(destination), variable(:scm_module))
].join(' && ')
end
# Returns the command that will do an "cvs diff" for the two revisions.
def diff(from, to=nil)
rev_type = revision_type(from)
if rev_type == :date
range_args = "-D '#{from}' -D '#{to || 'now'}'"
else
range_args = "-r '#{from}' -r '#{to || head}'"
end
scm cvs_root, :diff, range_args
end
# Returns an "cvs log" command for the two revisions.
def log(from, to=nil)
rev_type = revision_type(from)
if rev_type == :date
range_arg = "-d '#{from}<#{to || 'now'}'"
else
range_arg = "-r '#{from}:#{to || head}'"
end
scm cvs_root, :log, range_arg
end
# Unfortunately, cvs doesn't support the concept of a revision number like
# subversion and other SCM's do. For now, we'll rely on getting the timestamp
# of the latest checkin under the revision that's passed to us.
def query_revision(revision)
# If a branch is set, return that as the revision
return branch if revision_type(branch) == :tag
return revision if revision_type(revision) == :date
revision = yield(scm(cvs_root, :log, "-r#{revision}")).
grep(/^date:/).
map { |line| line[/^date: (.*?);/, 1] }.
sort.last + " UTC"
# This converts the revision date from YYYY-MM-DD to YYYY/MM/DD so the rest
# of this module can handle it.
if revision =~ /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2}).*UTC/
revision = "#{$1}/#{$2}/#{$3} #{$4}:#{$5}:#{$6} UTC"
puts "Override revision to #{revision}"
end
return revision
end
# Determines what the response should be for a particular bit of text
# from the SCM. Password prompts, connection requests, passphrases,
# etc. are handled here.
def handle_data(state, stream, text)
logger.info "[#{stream}] #{text}"
case text
when /\bpassword.*:/i
# prompting for a password
"#{variable(:scm_password) || variable(:password)}\n"
when %r{\(yes/no\)}
# let's be agreeable...
"yes\n"
end
end
private
# Constructs the CVSROOT command-line option
def cvs_root
root = ""
root << "-d #{repository} " if repository
root
end
# Constructs the destination dir command-line option
def cvs_destination(destination)
dest = ""
if destination
dest_parts = destination.split(/\//);
dest << "-d #{dest_parts.pop}"
end
dest
end
# attempts to guess what type of revision we're working with
def revision_type(rev)
return :date if rev =~ /^\d{4}\/\d{2}\/\d{2} \d{2}:\d{2}:\d{2} UTC$/ # i.e 2007-05-15 08:13:25 UTC
return :date if rev =~ /^\d{4}\/\d{2}\/\d{2} \d{2}:\d{2}:\d{2}$/ # i.e 2007-05-15 08:13:25
return :revision if rev =~ /^\d/ # i.e. 1.2.1
return :tag # i.e. RELEASE_1_2
end
# constructs the appropriate command-line switch for specifying a
# "revision" in CVS. This could be a tag, branch, revision (i.e. 1.3)
# or a date (to be used with -d)
def cvs_revision(rev)
revision = ""
revision << case revision_type(rev)
when :date
"-D \"#{rev}\"" if revision_type(rev) == :date
when :revision
"-r #{rev}"
# Added this for branch support
when :tag
"-r #{rev}"
else
"-r #{head}"
end
return revision
end
# If verbose output is requested, return nil, otherwise return the
# command-line switch for "quiet" ("-Q").
def verbose
variable(:scm_verbose) ? nil : "-Q"
end
def prep_destination(destination)
dest_parts = destination.split(/\//);
checkout_dir = dest_parts.pop
dest = dest_parts.join('/')
out = []
# In my particular setup, I need this setup on the remote host.
out << "export CVS_RSH=#{variable(:cvs_rsh)}" if variable(:cvs_rsh)
out << "mkdir -p #{ dest } && cd #{ dest }"
out.join(" && ")
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment