forked from capistrano/capistrano
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added CVS module for SwitchTower (very, very experimental!)
git-svn-id: http://svn.rubyonrails.org/rails/trunk/switchtower@2027 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
- Loading branch information
Showing
3 changed files
with
243 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |