capistrano 1.4.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. data/CHANGELOG +140 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README +22 -14
  4. data/bin/cap +1 -8
  5. data/bin/capify +77 -0
  6. data/examples/sample.rb +10 -109
  7. data/lib/capistrano.rb +1 -0
  8. data/lib/capistrano/callback.rb +41 -0
  9. data/lib/capistrano/cli.rb +17 -317
  10. data/lib/capistrano/cli/execute.rb +82 -0
  11. data/lib/capistrano/cli/help.rb +102 -0
  12. data/lib/capistrano/cli/help.txt +53 -0
  13. data/lib/capistrano/cli/options.rb +183 -0
  14. data/lib/capistrano/cli/ui.rb +28 -0
  15. data/lib/capistrano/command.rb +62 -29
  16. data/lib/capistrano/configuration.rb +25 -226
  17. data/lib/capistrano/configuration/actions/file_transfer.rb +35 -0
  18. data/lib/capistrano/configuration/actions/inspect.rb +46 -0
  19. data/lib/capistrano/configuration/actions/invocation.rb +127 -0
  20. data/lib/capistrano/configuration/callbacks.rb +148 -0
  21. data/lib/capistrano/configuration/connections.rb +159 -0
  22. data/lib/capistrano/configuration/execution.rb +126 -0
  23. data/lib/capistrano/configuration/loading.rb +112 -0
  24. data/lib/capistrano/configuration/namespaces.rb +190 -0
  25. data/lib/capistrano/configuration/roles.rb +51 -0
  26. data/lib/capistrano/configuration/servers.rb +75 -0
  27. data/lib/capistrano/configuration/variables.rb +127 -0
  28. data/lib/capistrano/errors.rb +15 -0
  29. data/lib/capistrano/extensions.rb +27 -8
  30. data/lib/capistrano/gateway.rb +54 -29
  31. data/lib/capistrano/logger.rb +11 -11
  32. data/lib/capistrano/recipes/compat.rb +32 -0
  33. data/lib/capistrano/recipes/deploy.rb +483 -0
  34. data/lib/capistrano/recipes/deploy/dependencies.rb +44 -0
  35. data/lib/capistrano/recipes/deploy/local_dependency.rb +46 -0
  36. data/lib/capistrano/recipes/deploy/remote_dependency.rb +65 -0
  37. data/lib/capistrano/recipes/deploy/scm.rb +19 -0
  38. data/lib/capistrano/recipes/deploy/scm/base.rb +180 -0
  39. data/lib/capistrano/recipes/deploy/scm/bzr.rb +86 -0
  40. data/lib/capistrano/recipes/deploy/scm/cvs.rb +151 -0
  41. data/lib/capistrano/recipes/deploy/scm/darcs.rb +85 -0
  42. data/lib/capistrano/recipes/deploy/scm/mercurial.rb +129 -0
  43. data/lib/capistrano/recipes/deploy/scm/perforce.rb +126 -0
  44. data/lib/capistrano/recipes/deploy/scm/subversion.rb +103 -0
  45. data/lib/capistrano/recipes/deploy/strategy.rb +19 -0
  46. data/lib/capistrano/recipes/deploy/strategy/base.rb +64 -0
  47. data/lib/capistrano/recipes/deploy/strategy/checkout.rb +20 -0
  48. data/lib/capistrano/recipes/deploy/strategy/copy.rb +143 -0
  49. data/lib/capistrano/recipes/deploy/strategy/export.rb +20 -0
  50. data/lib/capistrano/recipes/deploy/strategy/remote.rb +52 -0
  51. data/lib/capistrano/recipes/deploy/strategy/remote_cache.rb +47 -0
  52. data/lib/capistrano/recipes/deploy/templates/maintenance.rhtml +53 -0
  53. data/lib/capistrano/recipes/standard.rb +26 -276
  54. data/lib/capistrano/recipes/templates/maintenance.rhtml +1 -1
  55. data/lib/capistrano/recipes/upgrade.rb +33 -0
  56. data/lib/capistrano/server_definition.rb +51 -0
  57. data/lib/capistrano/shell.rb +125 -81
  58. data/lib/capistrano/ssh.rb +80 -36
  59. data/lib/capistrano/task_definition.rb +69 -0
  60. data/lib/capistrano/upload.rb +146 -0
  61. data/lib/capistrano/version.rb +13 -17
  62. data/test/cli/execute_test.rb +132 -0
  63. data/test/cli/help_test.rb +139 -0
  64. data/test/cli/options_test.rb +226 -0
  65. data/test/cli/ui_test.rb +28 -0
  66. data/test/cli_test.rb +17 -0
  67. data/test/command_test.rb +284 -25
  68. data/test/configuration/actions/file_transfer_test.rb +40 -0
  69. data/test/configuration/actions/inspect_test.rb +62 -0
  70. data/test/configuration/actions/invocation_test.rb +195 -0
  71. data/test/configuration/callbacks_test.rb +206 -0
  72. data/test/configuration/connections_test.rb +288 -0
  73. data/test/configuration/execution_test.rb +159 -0
  74. data/test/configuration/loading_test.rb +119 -0
  75. data/test/configuration/namespace_dsl_test.rb +283 -0
  76. data/test/configuration/roles_test.rb +47 -0
  77. data/test/configuration/servers_test.rb +90 -0
  78. data/test/configuration/variables_test.rb +180 -0
  79. data/test/configuration_test.rb +60 -212
  80. data/test/deploy/scm/base_test.rb +55 -0
  81. data/test/deploy/strategy/copy_test.rb +146 -0
  82. data/test/extensions_test.rb +69 -0
  83. data/test/fixtures/cli_integration.rb +5 -0
  84. data/test/fixtures/custom.rb +2 -2
  85. data/test/gateway_test.rb +167 -0
  86. data/test/logger_test.rb +123 -0
  87. data/test/server_definition_test.rb +108 -0
  88. data/test/shell_test.rb +64 -0
  89. data/test/ssh_test.rb +67 -154
  90. data/test/task_definition_test.rb +101 -0
  91. data/test/upload_test.rb +131 -0
  92. data/test/utils.rb +31 -39
  93. data/test/version_test.rb +24 -0
  94. metadata +145 -98
  95. data/THANKS +0 -4
  96. data/lib/capistrano/actor.rb +0 -567
  97. data/lib/capistrano/generators/rails/deployment/deployment_generator.rb +0 -25
  98. data/lib/capistrano/generators/rails/deployment/templates/capistrano.rake +0 -49
  99. data/lib/capistrano/generators/rails/deployment/templates/deploy.rb +0 -122
  100. data/lib/capistrano/generators/rails/loader.rb +0 -20
  101. data/lib/capistrano/scm/base.rb +0 -61
  102. data/lib/capistrano/scm/baz.rb +0 -118
  103. data/lib/capistrano/scm/bzr.rb +0 -70
  104. data/lib/capistrano/scm/cvs.rb +0 -129
  105. data/lib/capistrano/scm/darcs.rb +0 -27
  106. data/lib/capistrano/scm/mercurial.rb +0 -83
  107. data/lib/capistrano/scm/perforce.rb +0 -139
  108. data/lib/capistrano/scm/subversion.rb +0 -128
  109. data/lib/capistrano/transfer.rb +0 -97
  110. data/lib/capistrano/utils.rb +0 -26
  111. data/test/actor_test.rb +0 -402
  112. data/test/scm/cvs_test.rb +0 -196
  113. data/test/scm/subversion_test.rb +0 -145
@@ -0,0 +1,85 @@
1
+ require 'capistrano/recipes/deploy/scm/base'
2
+
3
+ module Capistrano
4
+ module Deploy
5
+ module SCM
6
+
7
+ # Implements the Capistrano SCM interface for the darcs revision
8
+ # control system (http://www.abridgegame.org/darcs/).
9
+ class Darcs < Base
10
+ # Sets the default command name for this SCM. Users may override this
11
+ # by setting the :scm_command variable.
12
+ default_command "darcs"
13
+
14
+ # Because darcs does not have any support for pseudo-ids, we'll just
15
+ # return something here that we can use in the helpers below for
16
+ # determining whether we need to look up the latest revision.
17
+ def head
18
+ :head
19
+ end
20
+
21
+ # Returns the command that will check out the given revision to the
22
+ # given destination. The 'revision' parameter must be the 'hash' value
23
+ # for the revision in question, as given by 'darcs changes --xml-output'.
24
+ def checkout(revision, destination)
25
+ scm :get, verbose, "--repo-name=#{destination}", "--to-match='hash #{revision}'", repository
26
+ end
27
+
28
+ # Tries to update the destination repository in-place, to bring it up
29
+ # to the given revision. Note that because darcs' "pull" operation
30
+ # does not support a "to-match" argument (or similar), this basically
31
+ # nukes the destination directory and re-gets it.
32
+ def sync(revision, destination)
33
+ ["rm -rf #{destination}", checkout(revision, destination)].join(" && ")
34
+ end
35
+
36
+ # Darcs does not have a real 'export' option; there is 'darcs dist',
37
+ # but that presupposes a utility that can untar and ungzip the dist
38
+ # file. We'll cheat and just do a get, followed by a deletion of the
39
+ # _darcs metadata directory.
40
+ def export(revision, destination)
41
+ [checkout(revision, destination), "rm -rf #{destination}/_darcs"].join(" && ")
42
+ end
43
+
44
+ # Returns the command that will do a "darcs diff" for the two revisions.
45
+ # Each revision must be the 'hash' identifier of a darcs revision.
46
+ def diff(from, to=nil)
47
+ scm :diff, "--from-match 'hash #{from}'", to && "--to-match 'hash #{to}'"
48
+ end
49
+
50
+ # Returns the log of changes between the two revisions. Each revision
51
+ # must be the 'hash' identifier of a darcs revision.
52
+ def log(from, to=nil)
53
+ scm :changes, "--from-match 'hash #{from}'", to && "--to-match 'hash #{to}'", "--repo=#{repository}"
54
+ end
55
+
56
+ # Attempts to translate the given revision identifier to a "real"
57
+ # revision. If the identifier is a symbol, it is assumed to be a
58
+ # pseudo-id. Otherwise, it will be immediately returned. If it is a
59
+ # pseudo-id, a set of commands to execute will be yielded, and the
60
+ # result of executing those commands must be returned by the block.
61
+ # This method will then extract the actual revision hash from the
62
+ # returned data.
63
+ def query_revision(revision)
64
+ case revision
65
+ when :head
66
+ xml = yield(scm(:changes, "--last 1", "--xml-output", "--repo=#{repository}"))
67
+ return xml[/hash='(.*?)'/, 1]
68
+ else return revision
69
+ end
70
+ end
71
+
72
+ private
73
+
74
+ def verbose
75
+ case variable(:scm_verbose)
76
+ when nil then "-q"
77
+ when false then nil
78
+ else "-v"
79
+ end
80
+ end
81
+ end
82
+
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,129 @@
1
+ # Copyright 2007 Matthew Elder <sseses@gmail.com>
2
+ # based on work by Tobias Luetke
3
+
4
+ require 'capistrano/recipes/deploy/scm/base'
5
+
6
+ module Capistrano
7
+ module Deploy
8
+ module SCM
9
+
10
+ # Implements the Capistrano SCM interface for the Mercurial revision
11
+ # control system (http://www.selenic.com/mercurial/).
12
+ # Latest updates at http://tackletechnology.org/oss/cap2-mercurial
13
+ class Mercurial < Base
14
+ # Sets the default command name for this SCM. Users may override this
15
+ # by setting the :scm_command variable.
16
+ default_command "hg"
17
+
18
+ # For mercurial HEAD == tip except that it bases this assumption on what
19
+ # tip is in the current repository (so push before you deploy)
20
+ def head
21
+ "tip"
22
+ end
23
+
24
+ # Clone the repository and update to the specified changeset.
25
+ def checkout(changeset, destination)
26
+ clone(destination) + " && " + update(changeset, destination)
27
+ end
28
+
29
+ # Pull from the repository and update to the specified changeset.
30
+ def sync(changeset, destination)
31
+ pull(destination) + " && " + update(changeset, destination)
32
+ end
33
+
34
+ # One day we will have hg archive, although i think its not needed
35
+ def export(revision, destination)
36
+ raise NotImplementedError, "`diff' is not implemented by #{self.class.name}" +
37
+ "use checkout strategy"
38
+ end
39
+
40
+ # Compute the difference between the two changesets +from+ and +to+
41
+ # as a unified diff.
42
+ def diff(from, to=nil)
43
+ scm :diff,
44
+ "--rev #{from}",
45
+ (to ? "--rev #{to}" : nil)
46
+ end
47
+
48
+ # Return a log of all changes between the two specified changesets,
49
+ # +from+ and +to+, inclusive or the log for +from+ if +to+ is omitted.
50
+ def log(from, to=nil)
51
+ scm :log,
52
+ verbose,
53
+ "--rev #{from}" +
54
+ (to ? ":#{to}" : "")
55
+ end
56
+
57
+ # Translates a tag to a changeset if needed or just returns changeset.
58
+ def query_revision(changeset)
59
+ cmd = scm :log,
60
+ verbose,
61
+ "-r #{changeset}",
62
+ "--template '{node|short}'"
63
+ yield cmd
64
+ end
65
+
66
+ # Determine response for SCM prompts
67
+ # user/pass can come from ssh and http distribution methods
68
+ # yes/no is for when ssh asks you about fingerprints
69
+ def handle_data(state, stream, text)
70
+ logger.info "[#{stream}] #{text}"
71
+ case text
72
+ when /^user:/mi
73
+ if variable(:scm_user)
74
+ "#{variable(:scm_user)}\n"
75
+ else
76
+ raise "No variable :scm_user specified and Mercurial asked!\n" +
77
+ "Prompt was: #{text}"
78
+ end
79
+ when /^password:/mi
80
+ if variable(:scm_password)
81
+ "#{variable(:scm_password)}\n"
82
+ else
83
+ raise "No variable :scm_password specified and Mercurial asked!\n" +
84
+ "Prompt was: #{text}"
85
+ end
86
+ when /yes\/no/i
87
+ "yes\n"
88
+ end
89
+ end
90
+
91
+ private
92
+
93
+ # Fine grained mercurial commands
94
+ def clone(destination)
95
+ scm :clone,
96
+ verbose,
97
+ "--noupdate", # do not update to tip when cloning is done
98
+ repository, # clone which repository?
99
+ destination # and put the clone where?
100
+ end
101
+
102
+ def pull(destination)
103
+ scm :pull,
104
+ verbose,
105
+ "--repository #{destination}", # pull changes into what?
106
+ repository # and pull the changes from?
107
+ end
108
+
109
+ def update(changeset, destination)
110
+ scm :update,
111
+ verbose,
112
+ "--repository #{destination}", # update what?
113
+ "--clean", # ignore untracked changes
114
+ changeset # update to this changeset
115
+ end
116
+
117
+ # verbosity configuration grokking :)
118
+ def verbose
119
+ case variable(:scm_verbose)
120
+ when nil: nil
121
+ when false: "--quiet"
122
+ else "--verbose"
123
+ end
124
+ end
125
+
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,126 @@
1
+ require 'capistrano/recipes/deploy/scm/base'
2
+
3
+ # Notes:
4
+ # no global verbose flag for scm_verbose
5
+ # sync, checkout and export are just sync in p4
6
+ #
7
+ module Capistrano
8
+ module Deploy
9
+ module SCM
10
+
11
+ # Implements the Capistrano SCM interface for the Perforce revision
12
+ # control system (http://www.perforce.com).
13
+ class Perforce < Base
14
+ # Sets the default command name for this SCM. Users may override this
15
+ # by setting the :scm_command variable.
16
+ default_command "p4"
17
+
18
+ # Perforce understands '#head' to refer to the latest revision in the
19
+ # depot.
20
+ def head
21
+ 'head'
22
+ end
23
+
24
+ # Returns the command that will sync the given revision to the given
25
+ # destination directory. The perforce client has a fixed destination so
26
+ # the files must be copied from there to their intended resting place.
27
+ def checkout(revision, destination)
28
+ p4_sync(revision, destination, "-f")
29
+ end
30
+
31
+ # Returns the command that will sync the given revision to the given
32
+ # destination directory. The perforce client has a fixed destination so
33
+ # the files must be copied from there to their intended resting place.
34
+ def sync(revision, destination)
35
+ p4_sync(revision, destination, "-f")
36
+ end
37
+
38
+ # Returns the command that will sync the given revision to the given
39
+ # destination directory. The perforce client has a fixed destination so
40
+ # the files must be copied from there to their intended resting place.
41
+ def export(revision, destination)
42
+ p4_sync(revision, destination, "-f")
43
+ end
44
+
45
+ # Returns the command that will do an "p4 diff2" for the two revisions.
46
+ def diff(from, to=head)
47
+ scm authentication, :diff2, "-u -db", "//#{p4client}/...#{rev_no(from)}", "//#{p4client}/...#{rev_no(to)}"
48
+ end
49
+
50
+ # Returns a "p4 changes" command for the two revisions.
51
+ def log(from=1, to=head)
52
+ scm authentication, :changes, "-s submitted", "//#{p4client}/...#{rev_no(from)},#(rev_no(to)}"
53
+ end
54
+
55
+ def query_revision(revision)
56
+ return revision if revision.to_s =~ /^\d+$/
57
+ command = scm(authentication, :changes, "-s submitted", "-m 1", "//#{p4client}/...#{rev_no(revision)}")
58
+ yield(command)[/Change (\d+) on/, 1]
59
+ end
60
+
61
+ # Determines what the response should be for a particular bit of text
62
+ # from the SCM. Password prompts, connection requests, passphrases,
63
+ # etc. are handled here.
64
+ def handle_data(state, stream, text)
65
+ case text
66
+ when /\(P4PASSWD\) invalid or unset\./i
67
+ raise Capistrano::Error, "scm_password (or p4passwd) is incorrect or unset"
68
+ when /Can.t create a new user.*/i
69
+ raise Capistrano::Error, "scm_username (or p4user) is incorrect or unset"
70
+ when /Perforce client error\:/i
71
+ raise Capistrano::Error, "p4port is incorrect or unset"
72
+ when /Client \'[\w\-\_\.]+\' unknown.*/i
73
+ raise Capistrano::Error, "p4client is incorrect or unset"
74
+ end
75
+ end
76
+
77
+ private
78
+
79
+ # Builds the set of authentication switches that perforce understands.
80
+ def authentication
81
+ [ p4port && "-p #{p4port}",
82
+ p4user && "-u #{p4user}",
83
+ p4passwd && "-P #{p4passwd}",
84
+ p4client && "-c #{p4client}" ].compact.join(" ")
85
+ end
86
+
87
+ # Returns the command that will sync the given revision to the given
88
+ # destination directory with specific options. The perforce client has
89
+ # a fixed destination so the files must be copied from there to their
90
+ # intended resting place.
91
+ def p4_sync(revision, destination, options="")
92
+ p4client_root = "`#{command} #{authentication} client -o | grep ^Root | cut -f2`"
93
+ scm authentication, :sync, options, "#{rev_no(revision)}", "&& cp -rf #{p4client_root} #{destination}"
94
+ end
95
+
96
+ def p4client
97
+ variable(:p4client)
98
+ end
99
+
100
+ def p4port
101
+ variable(:p4port)
102
+ end
103
+
104
+ def p4user
105
+ variable(:p4user) || variable(:scm_username)
106
+ end
107
+
108
+ def p4passwd
109
+ variable(:p4passwd) || variable(:scm_password)
110
+ end
111
+
112
+ def rev_no(revision)
113
+ case revision.to_s
114
+ when "head"
115
+ "#head"
116
+ when /^\d+/
117
+ "@#{revision}"
118
+ else
119
+ revision
120
+ end
121
+ end
122
+ end
123
+
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,103 @@
1
+ require 'capistrano/recipes/deploy/scm/base'
2
+ require 'yaml'
3
+
4
+ module Capistrano
5
+ module Deploy
6
+ module SCM
7
+
8
+ # Implements the Capistrano SCM interface for the Subversion revision
9
+ # control system (http://subversion.tigris.org).
10
+ class Subversion < Base
11
+ # Sets the default command name for this SCM. Users may override this
12
+ # by setting the :scm_command variable.
13
+ default_command "svn"
14
+
15
+ # Subversion understands 'HEAD' to refer to the latest revision in the
16
+ # repository.
17
+ def head
18
+ "HEAD"
19
+ end
20
+
21
+ # Returns the command that will check out the given revision to the
22
+ # given destination.
23
+ def checkout(revision, destination)
24
+ scm :checkout, verbose, authentication, "-r#{revision}", repository, destination
25
+ end
26
+
27
+ # Returns the command that will do an "svn update" to the given
28
+ # revision, for the working copy at the given destination.
29
+ def sync(revision, destination)
30
+ scm :update, verbose, authentication, "-r#{revision}", destination
31
+ end
32
+
33
+ # Returns the command that will do an "svn export" of the given revision
34
+ # to the given destination.
35
+ def export(revision, destination)
36
+ scm :export, verbose, authentication, "-r#{revision}", repository, destination
37
+ end
38
+
39
+ # Returns the command that will do an "svn diff" for the two revisions.
40
+ def diff(from, to=nil)
41
+ scm :diff, repository, authentication, "-r#{from}:#{to || head}"
42
+ end
43
+
44
+ # Returns an "svn log" command for the two revisions.
45
+ def log(from, to=nil)
46
+ scm :log, repository, authentication, "-r#{from}:#{to || head}"
47
+ end
48
+
49
+ # Attempts to translate the given revision identifier to a "real"
50
+ # revision. If the identifier is an integer, it will simply be returned.
51
+ # Otherwise, this will yield a string of the commands it needs to be
52
+ # executed (svn info), and will extract the revision from the response.
53
+ def query_revision(revision)
54
+ return revision if revision =~ /^\d+$/
55
+ result = yield(scm(:info, repository, authentication, "-r#{revision}"))
56
+ YAML.load(result)['Revision']
57
+ end
58
+
59
+ # Determines what the response should be for a particular bit of text
60
+ # from the SCM. Password prompts, connection requests, passphrases,
61
+ # etc. are handled here.
62
+ def handle_data(state, stream, text)
63
+ logger.info "[#{stream}] #{text}"
64
+ case text
65
+ when /\bpassword.*:/i
66
+ # subversion is prompting for a password
67
+ "#{variable(:scm_password) || variable(:password)}\n"
68
+ when %r{\(yes/no\)}
69
+ # subversion is asking whether or not to connect
70
+ "yes\n"
71
+ when /passphrase/i
72
+ # subversion is asking for the passphrase for the user's key
73
+ "#{variable(:scm_passphrase)}\n"
74
+ when /The entry \'(.+?)\' is no longer a directory/
75
+ raise Capisrano::Error, "subversion can't update because directory '#{$1}' was replaced. Please add it to svn:ignore."
76
+ when /accept \(t\)emporarily/
77
+ # subversion is asking whether to accept the certificate
78
+ "t\n"
79
+ end
80
+ end
81
+
82
+ private
83
+
84
+ # If a username or password is configured for the SCM, return the
85
+ # command-line switches for those values.
86
+ def authentication
87
+ auth = ""
88
+ auth << "--username #{variable(:scm_username)} " if variable(:scm_username)
89
+ auth << "--password #{variable(:scm_password)} " if variable(:scm_password)
90
+ auth << "--no-auth-cache" if !auth.empty?
91
+ auth
92
+ end
93
+
94
+ # If verbose output is requested, return nil, otherwise return the
95
+ # command-line switch for "quiet" ("-q").
96
+ def verbose
97
+ variable(:scm_verbose) ? nil : "-q"
98
+ end
99
+ end
100
+
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,19 @@
1
+ module Capistrano
2
+ module Deploy
3
+ module Strategy
4
+ def self.new(strategy, config={})
5
+ strategy_file = "capistrano/recipes/deploy/strategy/#{strategy}"
6
+ require(strategy_file)
7
+
8
+ strategy_const = strategy.to_s.capitalize.gsub(/_(.)/) { $1.upcase }
9
+ if const_defined?(strategy_const)
10
+ const_get(strategy_const).new(config)
11
+ else
12
+ raise Capistrano::Error, "could not find `#{name}::#{strategy_const}' in `#{strategy_file}'"
13
+ end
14
+ rescue LoadError
15
+ raise Capistrano::Error, "could not find any strategy named `#{strategy}'"
16
+ end
17
+ end
18
+ end
19
+ end