mirror of
https://github.com/capistrano/capistrano
synced 2023-03-27 23:21:18 -04:00
Added CVS module for SwitchTower (very, very experimental!)
git-svn-id: http://svn.rubyonrails.org/rails/trunk/switchtower@2027 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
parent
5246654ab7
commit
d89f08f780
3 changed files with 243 additions and 0 deletions
|
@ -1,5 +1,7 @@
|
|||
*SVN*
|
||||
|
||||
* Added CVS module (very very experimental!)
|
||||
|
||||
* Works with public keys now, for passwordless deployment
|
||||
|
||||
* Subversion module recognizes the password prompt for HTTP authentication
|
||||
|
|
82
lib/switchtower/scm/cvs.rb
Normal file
82
lib/switchtower/scm/cvs.rb
Normal file
|
@ -0,0 +1,82 @@
|
|||
require 'time'
|
||||
|
||||
module SwitchTower
|
||||
module SCM
|
||||
|
||||
# An SCM module for using CVS as your source control tool. You can
|
||||
# specify it by placing the following line in your configuration:
|
||||
#
|
||||
# set :scm, :cvs
|
||||
#
|
||||
# Also, this module accepts a <tt>:cvs</tt> configuration variable,
|
||||
# which (if specified) will be used as the full path to the cvs
|
||||
# executable on the remote machine:
|
||||
#
|
||||
# set :cvs, "/opt/local/bin/cvs"
|
||||
#
|
||||
# You can specify the location of your local copy (used to query
|
||||
# the revisions, etc.) via the <tt>:local</tt> variable, which defaults to
|
||||
# ".".
|
||||
#
|
||||
# Also, you can specify the CVS_RSH variable to use on the remote machine(s)
|
||||
# via the <tt>:cvs_rsh</tt> variable. This defaults to the value of the
|
||||
# CVS_RSH environment variable locally, or if it is not set, to "ssh".
|
||||
class Cvs
|
||||
attr_reader :configuration
|
||||
|
||||
def initialize(configuration) #:nodoc:
|
||||
@configuration = configuration
|
||||
end
|
||||
|
||||
# Return a string representing the date of the last revision (CVS is
|
||||
# seriously retarded, in that it does not give you a way to query when
|
||||
# the last revision was made to the repository, so this is a fairly
|
||||
# expensive operation...)
|
||||
def latest_revision
|
||||
return @latest_revision if @latest_revision
|
||||
configuration.logger.debug "querying latest revision..."
|
||||
@latest_revision = cvs_log(configuration.local).
|
||||
split(/\r?\n/).
|
||||
grep(/^date: (.*?);/) { Time.parse($1).strftime("%FT%T") }.
|
||||
sort.
|
||||
last
|
||||
end
|
||||
|
||||
# Check out (on all servers associated with the current task) the latest
|
||||
# revision. Uses the given actor instance to execute the command.
|
||||
def checkout(actor)
|
||||
cvs = configuration[:cvs] || "cvs"
|
||||
cvs_rsh = configuration[:cvs_rsh] || ENV['CVS_RSH'] || "ssh"
|
||||
|
||||
command = <<-CMD
|
||||
if [[ -d #{actor.release_path} ]]; then
|
||||
cd #{actor.release_path};
|
||||
CVS_RSH="#{cvs_rsh}" #{cvs} -q up -d#{latest_revision};
|
||||
else
|
||||
cd #{configuration.releases_path};
|
||||
CVS_RSH="#{cvs_rsh}" #{cvs} -d #{configuration.repository} -q co -D #{latest_revision} -d #{latest_revision} #{actor.application};
|
||||
fi
|
||||
CMD
|
||||
actor.run(command) do |ch, stream, out|
|
||||
prefix = "#{stream} :: #{ch[:host]}"
|
||||
actor.logger.info out, prefix
|
||||
if out =~ %r{password:}
|
||||
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
|
||||
|
||||
private
|
||||
|
||||
def cvs_log(path)
|
||||
`cd #{path || "."} && cvs -q log -N -rHEAD`
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
159
test/scm/cvs_test.rb
Normal file
159
test/scm/cvs_test.rb
Normal file
|
@ -0,0 +1,159 @@
|
|||
$:.unshift File.dirname(__FILE__) + "/../../lib"
|
||||
|
||||
require File.dirname(__FILE__) + "/../utils"
|
||||
require 'test/unit'
|
||||
require 'switchtower/scm/cvs'
|
||||
|
||||
class ScmCvsTest < Test::Unit::TestCase
|
||||
class CvsTest < SwitchTower::SCM::Cvs
|
||||
attr_accessor :story
|
||||
attr_reader :last_path
|
||||
|
||||
def cvs_log(path)
|
||||
@last_path = path
|
||||
story.shift
|
||||
end
|
||||
end
|
||||
|
||||
class MockChannel
|
||||
attr_reader :sent_data
|
||||
|
||||
def send_data(data)
|
||||
@sent_data ||= []
|
||||
@sent_data << data
|
||||
end
|
||||
|
||||
def [](name)
|
||||
"value"
|
||||
end
|
||||
end
|
||||
|
||||
class MockActor
|
||||
attr_reader :command
|
||||
attr_reader :channels
|
||||
attr_accessor :story
|
||||
|
||||
def initialize(config)
|
||||
@config = config
|
||||
end
|
||||
|
||||
def run(command)
|
||||
@command = command
|
||||
@channels ||= []
|
||||
@channels << MockChannel.new
|
||||
story.each { |stream, line| yield @channels.last, stream, line }
|
||||
end
|
||||
|
||||
def method_missing(sym, *args)
|
||||
@config.send(sym, *args)
|
||||
end
|
||||
end
|
||||
|
||||
def setup
|
||||
@config = MockConfiguration.new
|
||||
@config[:repository] = ":ext:joetester@rubyforge.org:/hello/world"
|
||||
@config[:local] = "/hello/world"
|
||||
@config[:cvs] = "/path/to/cvs"
|
||||
@config[:password] = "chocolatebrownies"
|
||||
@scm = CvsTest.new(@config)
|
||||
@actor = MockActor.new(@config)
|
||||
@log_msg = <<MSG.strip
|
||||
RCS file: /var/cvs/copland/copland/LICENSE,v
|
||||
Working file: LICENSE
|
||||
head: 1.1
|
||||
branch:
|
||||
locks: strict
|
||||
access list:
|
||||
keyword substitution: kv
|
||||
total revisions: 1; selected revisions: 1
|
||||
description:
|
||||
----------------------------
|
||||
revision 1.1
|
||||
date: 2004/08/29 04:23:36; author: minam; state: Exp;
|
||||
New implementation.
|
||||
=============================================================================
|
||||
|
||||
RCS file: /var/cvs/copland/copland/Rakefile,v
|
||||
Working file: Rakefile
|
||||
head: 1.7
|
||||
branch:
|
||||
locks: strict
|
||||
access list:
|
||||
keyword substitution: kv
|
||||
total revisions: 7; selected revisions: 1
|
||||
description:
|
||||
----------------------------
|
||||
revision 1.7
|
||||
date: 2004/09/15 16:35:01; author: minam; state: Exp; lines: +2 -1
|
||||
Rakefile now publishes package documentation from doc/packages instead of
|
||||
doc/packrat. Updated "latest updates" in manual.
|
||||
=============================================================================
|
||||
|
||||
RCS file: /var/cvs/copland/copland/TODO,v
|
||||
Working file: TODO
|
||||
head: 1.18
|
||||
branch:
|
||||
locks: strict
|
||||
access list:
|
||||
keyword substitution: kv
|
||||
total revisions: 18; selected revisions: 1
|
||||
description:
|
||||
----------------------------
|
||||
revision 1.18
|
||||
date: 2004/10/12 02:21:02; author: minam; state: Exp; lines: +4 -1
|
||||
Added RubyConf 2004 presentation.
|
||||
=============================================================================
|
||||
|
||||
RCS file: /var/cvs/copland/copland/Attic/build-gemspec.rb,v
|
||||
Working file: build-gemspec.rb
|
||||
head: 1.5
|
||||
branch:
|
||||
locks: strict
|
||||
access list:
|
||||
keyword substitution: kv
|
||||
total revisions: 5; selected revisions: 1
|
||||
description:
|
||||
----------------------------
|
||||
revision 1.5
|
||||
date: 2004/08/29 04:10:17; author: minam; state: dead; lines: +0 -0
|
||||
Here we go -- point of no return. Deleting existing implementation to make
|
||||
way for new implementation.
|
||||
=============================================================================
|
||||
|
||||
RCS file: /var/cvs/copland/copland/copland.gemspec,v
|
||||
Working file: copland.gemspec
|
||||
head: 1.12
|
||||
branch:
|
||||
locks: strict
|
||||
access list:
|
||||
keyword substitution: kv
|
||||
total revisions: 13; selected revisions: 1
|
||||
description:
|
||||
----------------------------
|
||||
revision 1.12
|
||||
date: 2004/09/11 21:45:58; author: minam; state: Exp; lines: +4 -4
|
||||
Minor change in how version is communicated to gemspec.
|
||||
=============================================================================
|
||||
MSG
|
||||
@scm.story = [ @log_msg ]
|
||||
end
|
||||
|
||||
def test_latest_revision
|
||||
@scm.story = [ @log_msg ]
|
||||
assert_equal "2004-10-12T02:21:02", @scm.latest_revision
|
||||
assert_equal "/hello/world", @scm.last_path
|
||||
end
|
||||
|
||||
def test_checkout
|
||||
@actor.story = []
|
||||
assert_nothing_raised { @scm.checkout(@actor) }
|
||||
assert_nil @actor.channels.last.sent_data
|
||||
assert_match %r{/path/to/cvs}, @actor.command
|
||||
end
|
||||
|
||||
def test_checkout_needs_ssh_password
|
||||
@actor.story = [[:out, "joetester@rubyforge.org's password: "]]
|
||||
assert_nothing_raised { @scm.checkout(@actor) }
|
||||
assert_equal ["chocolatebrownies\n"], @actor.channels.last.sent_data
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue