Skip to content
This repository
Browse code

SwitchTower: use a timestamp as the release name, instead of the revi…

…sion number. Various tweaks and fixes to the supported scm modules.

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@2046 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
commit affb615a8a5da2d41383741fd51871261550925e 1 parent 6a4d446
Jamis Buck authored August 24, 2005
2  switchtower/CHANGELOG
... ...
@@ -1,5 +1,7 @@
1 1
 *SVN*
2 2
 
  3
+* Changed behavior of checkout to use the timestamp as the release name, instead of the revision number
  4
+
3 5
 * Added CVS module (very very experimental!)
4 6
 
5 7
 * Works with public keys now, for passwordless deployment
4  switchtower/README
@@ -21,7 +21,9 @@ As with the rest of Rails, if you can abide by these assumptions, you can use Sw
21 21
 
22 22
 == Usage
23 23
 
24  
-More documentation is always pending, but you'll want to see the user manual for detailed usage instructions. In general, you'll use SwitchTower as follows:
  24
+More documentation is always pending, but you'll want to see the user manual for detailed usage instructions. (The manual is online at http://manuals.rubyonrails.com/read/book/17).
  25
+
  26
+In general, you'll use SwitchTower as follows:
25 27
 
26 28
 * Create a deployment recipe ("deploy.rb") for your application. You can use the sample recipe in examples/sample.rb as a starting point.
27 29
 * Use the +switchtower+ script to execute your recipe (see below).
2  switchtower/lib/switchtower/actor.rb
@@ -248,7 +248,7 @@ def releases
248 248
           buffer << out if str == :out
249 249
           raise "could not determine releases #{out.inspect}" if str == :err
250 250
         end
251  
-        @releases = buffer.split.map { |i| i.to_i }.sort
  251
+        @releases = buffer.split.sort
252 252
       end
253 253
 
254 254
       @releases
13  switchtower/lib/switchtower/configuration.rb
@@ -26,12 +26,17 @@ class Configuration
26 26
     # The load paths used for locating recipe files.
27 27
     attr_reader :load_paths
28 28
 
  29
+    # The time (in UTC) at which this configuration was created, used for
  30
+    # determining the release path.
  31
+    attr_reader :now
  32
+
29 33
     def initialize(actor_class=Actor) #:nodoc:
30 34
       @roles = Hash.new { |h,k| h[k] = [] }
31 35
       @actor = actor_class.new(self)
32 36
       @logger = Logger.new
33 37
       @load_paths = [".", File.join(File.dirname(__FILE__), "recipes")]
34 38
       @variables = {}
  39
+      @now = Time.now.utc
35 40
 
36 41
       set :application, nil
37 42
       set :repository,  nil
@@ -165,10 +170,10 @@ def shared_path
165 170
       File.join(deploy_to, shared_dir)
166 171
     end
167 172
 
168  
-    # Return the full path to the named revision (defaults to the most current
169  
-    # revision in the repository).
170  
-    def release_path(revision=source.latest_revision)
171  
-      File.join(releases_path, revision)
  173
+    # Return the full path to the named release. If a release is not specified,
  174
+    # +now+ is used (the time at which the configuration was created).
  175
+    def release_path(release=now.strftime("%Y%m%d%H%M%S"))
  176
+      File.join(releases_path, release)
172 177
     end
173 178
 
174 179
     def respond_to?(sym) #:nodoc:
18  switchtower/lib/switchtower/scm/base.rb
... ...
@@ -0,0 +1,18 @@
  1
+module SwitchTower
  2
+  module SCM
  3
+
  4
+    # The ancestor class of the various SCM module implementations.
  5
+    class Base
  6
+      attr_reader :configuration
  7
+
  8
+      def initialize(configuration) #:nodoc:
  9
+        @configuration = configuration
  10
+      end
  11
+
  12
+      def checkout(actor)
  13
+        raise NotImplementedError, "subclasses must implement checkout"
  14
+      end
  15
+    end
  16
+
  17
+  end
  18
+end
18  switchtower/lib/switchtower/scm/cvs.rb
... ...
@@ -1,4 +1,5 @@
1 1
 require 'time'
  2
+require 'switchtower/scm/base'
2 3
 
3 4
 module SwitchTower
4 5
   module SCM
@@ -21,13 +22,7 @@ module SCM
21 22
     # Also, you can specify the CVS_RSH variable to use on the remote machine(s)
22 23
     # via the <tt>:cvs_rsh</tt> variable. This defaults to the value of the
23 24
     # CVS_RSH environment variable locally, or if it is not set, to "ssh".
24  
-    class Cvs
25  
-      attr_reader :configuration
26  
-
27  
-      def initialize(configuration) #:nodoc:
28  
-        @configuration = configuration
29  
-      end
30  
-
  25
+    class Cvs < Base
31 26
       # Return a string representing the date of the last revision (CVS is
32 27
       # seriously retarded, in that it does not give you a way to query when
33 28
       # the last revision was made to the repository, so this is a fairly
@@ -37,7 +32,7 @@ def latest_revision
37 32
         configuration.logger.debug "querying latest revision..."
38 33
         @latest_revision = cvs_log(configuration.local).
39 34
           split(/\r?\n/).
40  
-          grep(/^date: (.*?);/) { Time.parse($1).strftime("%FT%T") }.
  35
+          grep(/^date: (.*?);/) { Time.parse($1).strftime("%F %T") }.
41 36
           sort.
42 37
           last
43 38
       end
@@ -49,12 +44,9 @@ def checkout(actor)
49 44
         cvs_rsh = configuration[:cvs_rsh] || ENV['CVS_RSH'] || "ssh"
50 45
 
51 46
         command = <<-CMD
52  
-          if [[ -d #{actor.release_path} ]]; then
53  
-            cd #{actor.release_path};
54  
-            CVS_RSH="#{cvs_rsh}" #{cvs} -q up -d#{latest_revision};
55  
-          else
  47
+          if [[ ! -d #{actor.release_path} ]]; then
56 48
             cd #{configuration.releases_path};
57  
-            CVS_RSH="#{cvs_rsh}" #{cvs} -d #{configuration.repository} -q co -D #{latest_revision} -d #{latest_revision} #{actor.application};
  49
+            CVS_RSH="#{cvs_rsh}" #{cvs} -d #{configuration.repository} -Q co -D "#{latest_revision}" -d #{File.basename(actor.release_path)} #{actor.application};
58 50
           fi
59 51
         CMD
60 52
         actor.run(command) do |ch, stream, out|
25  switchtower/lib/switchtower/scm/darcs.rb
... ...
@@ -1,4 +1,4 @@
1  
-require 'time'
  1
+require 'switchtower/scm/base'
2 2
 
3 3
 module SwitchTower
4 4
   module SCM
@@ -13,26 +13,7 @@ module SCM
13 13
     # executable on the remote machine:
14 14
     #
15 15
     #   set :darcs, "/opt/local/bin/darcs"
16  
-    class Darcs
17  
-      attr_reader :configuration
18  
-
19  
-      def initialize(configuration) #:nodoc:
20  
-        @configuration = configuration
21  
-      end
22  
-
23  
-      # Return an integer identifying the last known revision (patch) in the
24  
-      # darcs repository. (This integer is currently the 14-digit timestamp
25  
-      # of the last known patch.)
26  
-      def latest_revision
27  
-        unless @latest_revision
28  
-          configuration.logger.debug "querying latest revision..."
29  
-          @latest_revision = Time.
30  
-            parse(`darcs changes --last 1 --repo #{configuration.repository}`).
31  
-            strftime("%Y%m%d%H%M%S").to_i
32  
-        end
33  
-        @latest_revision
34  
-      end
35  
-
  16
+    class Darcs < Base
36 17
       # Check out (on all servers associated with the current task) the latest
37 18
       # revision. Uses the given actor instance to execute the command.
38 19
       def checkout(actor)
@@ -40,7 +21,7 @@ def checkout(actor)
40 21
 
41 22
         command = <<-CMD
42 23
           if [[ ! -d #{actor.release_path} ]]; then
43  
-            #{darcs} get --set-scripts-executable #{configuration.repository} #{actor.release_path};
  24
+            #{darcs} get -q --set-scripts-executable #{configuration.repository} #{actor.release_path};
44 25
           fi
45 26
         CMD
46 27
         actor.run(command)
14  switchtower/lib/switchtower/scm/subversion.rb
... ...
@@ -1,3 +1,5 @@
  1
+require 'switchtower/scm/base'
  2
+
1 3
 module SwitchTower
2 4
   module SCM
3 5
 
@@ -12,13 +14,7 @@ module SCM
12 14
     # executable on the remote machine:
13 15
     #
14 16
     #   set :svn, "/opt/local/bin/svn"
15  
-    class Subversion
16  
-      attr_reader :configuration
17  
-
18  
-      def initialize(configuration) #:nodoc:
19  
-        @configuration = configuration
20  
-      end
21  
-
  17
+    class Subversion < Base
22 18
       # Return an integer identifying the last known revision in the svn
23 19
       # repository. (This integer is currently the revision number.) If latest
24 20
       # revision does not exist in the given repository, this routine will
@@ -64,9 +60,9 @@ def checkout(actor)
64 60
               prefix
65 61
             ch.send_data "yes\n"
66 62
           elsif out =~ %r{passphrase}
67  
-            message = "subversion needs your key's passphrase and cannot proceed"
  63
+            message = "subversion needs your key's passphrase, sending empty string"
68 64
             actor.logger.info message, prefix
69  
-            raise message
  65
+            ch.send_data "\n"
70 66
           elsif out =~ %r{The entry \'(\w+)\' is no longer a directory}
71 67
             message = "subversion can't update because directory '#{$1}' was replaced. Please add it to svn:ignore."
72 68
             actor.logger.info message, prefix
4  switchtower/test/configuration_test.rb
@@ -18,7 +18,6 @@ def define_task(*args, &block)
18 18
 
19 19
   class MockSCM
20 20
     attr_reader   :configuration
21  
-    attr_accessor :latest_revision
22 21
 
23 22
     def initialize(config)
24 23
       @configuration = config
@@ -184,8 +183,7 @@ def test_shared_path_custom
184 183
 
185 184
   def test_release_path_implicit
186 185
     @config.set :deploy_to, "/start/of/path"
187  
-    @config.source.latest_revision = 2257
188  
-    assert_equal "/start/of/path/releases/2257", @config.release_path
  186
+    assert_equal "/start/of/path/releases/#{@config.now.strftime("%Y%m%d%H%M%S")}", @config.release_path
189 187
   end
190 188
 
191 189
   def test_release_path_explicit
7  switchtower/test/scm/cvs_test.rb
@@ -44,6 +44,10 @@ def run(command)
44 44
       story.each { |stream, line| yield @channels.last, stream, line }
45 45
     end
46 46
 
  47
+    def release_path
  48
+      (@config[:now] || Time.now.utc).strftime("%Y%m%d%H%M%S")
  49
+    end
  50
+
47 51
     def method_missing(sym, *args)
48 52
       @config.send(sym, *args)
49 53
     end
@@ -55,6 +59,7 @@ def setup
55 59
     @config[:local] = "/hello/world"
56 60
     @config[:cvs] = "/path/to/cvs"
57 61
     @config[:password] = "chocolatebrownies"
  62
+    @config[:now] = Time.utc(2005,8,24,12,0,0)
58 63
     @scm = CvsTest.new(@config)
59 64
     @actor = MockActor.new(@config)
60 65
     @log_msg = <<MSG.strip
@@ -140,7 +145,7 @@ def setup
140 145
 
141 146
   def test_latest_revision
142 147
     @scm.story = [ @log_msg ]
143  
-    assert_equal "2004-10-12T02:21:02", @scm.latest_revision
  148
+    assert_equal "2004-10-12 02:21:02", @scm.latest_revision
144 149
     assert_equal "/hello/world", @scm.last_path
145 150
   end
146 151
 

0 notes on commit affb615

Please sign in to comment.
Something went wrong with that request. Please try again.