capistrano 2.1.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.md +89 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +674 -0
- data/README.md +226 -0
- data/Rakefile +5 -0
- data/bin/cap +2 -3
- data/bin/capify +7 -77
- data/capistrano-public_cert.pem +22 -0
- data/capistrano.gemspec +35 -0
- data/features/deploy.feature +52 -0
- data/features/installation.feature +16 -0
- data/features/remote_file_task.feature +14 -0
- data/features/step_definitions/assertions.rb +90 -0
- data/features/step_definitions/cap_commands.rb +8 -0
- data/features/step_definitions/setup.rb +25 -0
- data/features/support/env.rb +12 -0
- data/features/support/remote_command_helpers.rb +20 -0
- data/lib/Capfile +3 -0
- data/lib/capistrano/all.rb +16 -0
- data/lib/capistrano/application.rb +60 -0
- data/lib/capistrano/configuration/question.rb +42 -0
- data/lib/capistrano/configuration/server.rb +133 -0
- data/lib/capistrano/configuration/servers/role_filter.rb +86 -0
- data/lib/capistrano/configuration/servers.rb +53 -58
- data/lib/capistrano/configuration.rb +84 -30
- data/lib/capistrano/console.rb +1 -0
- data/lib/capistrano/defaults.rb +13 -0
- data/lib/capistrano/deploy.rb +3 -0
- data/lib/capistrano/dotfile.rb +3 -0
- data/lib/capistrano/dsl/env.rb +64 -0
- data/lib/capistrano/dsl/paths.rb +94 -0
- data/lib/capistrano/dsl/stages.rb +15 -0
- data/lib/capistrano/dsl/task_enhancements.rb +53 -0
- data/lib/capistrano/dsl.rb +48 -0
- data/lib/capistrano/git.rb +1 -0
- data/lib/capistrano/hg.rb +1 -0
- data/lib/capistrano/i18n.rb +34 -0
- data/lib/capistrano/install.rb +1 -0
- data/lib/capistrano/setup.rb +21 -0
- data/lib/capistrano/tasks/console.rake +21 -0
- data/lib/capistrano/tasks/deploy.rake +204 -0
- data/lib/capistrano/tasks/framework.rake +67 -0
- data/lib/capistrano/tasks/git.rake +62 -0
- data/lib/capistrano/tasks/hg.rake +39 -0
- data/lib/capistrano/tasks/install.rake +39 -0
- data/lib/capistrano/templates/Capfile +26 -0
- data/lib/capistrano/templates/deploy.rb.erb +40 -0
- data/lib/capistrano/templates/stage.rb.erb +42 -0
- data/lib/capistrano/version.rb +1 -20
- data/lib/capistrano/version_validator.rb +37 -0
- data/lib/capistrano.rb +0 -2
- data/spec/integration/dsl_spec.rb +344 -0
- data/spec/integration_spec_helper.rb +7 -0
- data/spec/lib/capistrano/application_spec.rb +61 -0
- data/spec/lib/capistrano/configuration/question_spec.rb +54 -0
- data/spec/lib/capistrano/configuration/server_spec.rb +249 -0
- data/spec/lib/capistrano/configuration/servers/role_filter_spec.rb +140 -0
- data/spec/lib/capistrano/configuration/servers_spec.rb +184 -0
- data/spec/lib/capistrano/configuration_spec.rb +101 -0
- data/spec/lib/capistrano/dsl/env_spec.rb +10 -0
- data/spec/lib/capistrano/dsl/paths_spec.rb +69 -0
- data/spec/lib/capistrano/dsl_spec.rb +63 -0
- data/spec/lib/capistrano/version_validator_spec.rb +103 -0
- data/spec/lib/capistrano_spec.rb +8 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/support/.gitignore +1 -0
- data/spec/support/Vagrantfile +13 -0
- data/spec/support/matchers.rb +5 -0
- data/spec/support/tasks/database.cap +11 -0
- data/spec/support/test_app.rb +138 -0
- metadata +251 -179
- data/CHANGELOG +0 -512
- data/MIT-LICENSE +0 -20
- data/README +0 -43
- data/examples/sample.rb +0 -14
- data/lib/capistrano/callback.rb +0 -45
- data/lib/capistrano/cli/execute.rb +0 -82
- data/lib/capistrano/cli/help.rb +0 -102
- data/lib/capistrano/cli/help.txt +0 -53
- data/lib/capistrano/cli/options.rb +0 -183
- data/lib/capistrano/cli/ui.rb +0 -28
- data/lib/capistrano/cli.rb +0 -47
- data/lib/capistrano/command.rb +0 -161
- data/lib/capistrano/configuration/actions/file_transfer.rb +0 -35
- data/lib/capistrano/configuration/actions/inspect.rb +0 -46
- data/lib/capistrano/configuration/actions/invocation.rb +0 -134
- data/lib/capistrano/configuration/callbacks.rb +0 -148
- data/lib/capistrano/configuration/connections.rb +0 -159
- data/lib/capistrano/configuration/execution.rb +0 -126
- data/lib/capistrano/configuration/loading.rb +0 -198
- data/lib/capistrano/configuration/namespaces.rb +0 -196
- data/lib/capistrano/configuration/roles.rb +0 -51
- data/lib/capistrano/configuration/variables.rb +0 -127
- data/lib/capistrano/errors.rb +0 -15
- data/lib/capistrano/extensions.rb +0 -57
- data/lib/capistrano/gateway.rb +0 -131
- data/lib/capistrano/logger.rb +0 -59
- data/lib/capistrano/recipes/compat.rb +0 -32
- data/lib/capistrano/recipes/deploy/dependencies.rb +0 -44
- data/lib/capistrano/recipes/deploy/local_dependency.rb +0 -46
- data/lib/capistrano/recipes/deploy/remote_dependency.rb +0 -96
- data/lib/capistrano/recipes/deploy/scm/accurev.rb +0 -169
- data/lib/capistrano/recipes/deploy/scm/base.rb +0 -192
- data/lib/capistrano/recipes/deploy/scm/bzr.rb +0 -86
- data/lib/capistrano/recipes/deploy/scm/cvs.rb +0 -151
- data/lib/capistrano/recipes/deploy/scm/darcs.rb +0 -85
- data/lib/capistrano/recipes/deploy/scm/git.rb +0 -191
- data/lib/capistrano/recipes/deploy/scm/mercurial.rb +0 -129
- data/lib/capistrano/recipes/deploy/scm/perforce.rb +0 -126
- data/lib/capistrano/recipes/deploy/scm/subversion.rb +0 -114
- data/lib/capistrano/recipes/deploy/scm.rb +0 -19
- data/lib/capistrano/recipes/deploy/strategy/base.rb +0 -64
- data/lib/capistrano/recipes/deploy/strategy/checkout.rb +0 -20
- data/lib/capistrano/recipes/deploy/strategy/copy.rb +0 -144
- data/lib/capistrano/recipes/deploy/strategy/export.rb +0 -20
- data/lib/capistrano/recipes/deploy/strategy/remote.rb +0 -52
- data/lib/capistrano/recipes/deploy/strategy/remote_cache.rb +0 -47
- data/lib/capistrano/recipes/deploy/strategy.rb +0 -19
- data/lib/capistrano/recipes/deploy/templates/maintenance.rhtml +0 -53
- data/lib/capistrano/recipes/deploy.rb +0 -494
- data/lib/capistrano/recipes/standard.rb +0 -37
- data/lib/capistrano/recipes/templates/maintenance.rhtml +0 -53
- data/lib/capistrano/recipes/upgrade.rb +0 -33
- data/lib/capistrano/server_definition.rb +0 -51
- data/lib/capistrano/shell.rb +0 -256
- data/lib/capistrano/ssh.rb +0 -109
- data/lib/capistrano/task_definition.rb +0 -69
- data/lib/capistrano/upload.rb +0 -146
- data/test/cli/execute_test.rb +0 -132
- data/test/cli/help_test.rb +0 -139
- data/test/cli/options_test.rb +0 -226
- data/test/cli/ui_test.rb +0 -28
- data/test/cli_test.rb +0 -17
- data/test/command_test.rb +0 -309
- data/test/configuration/actions/file_transfer_test.rb +0 -40
- data/test/configuration/actions/inspect_test.rb +0 -62
- data/test/configuration/actions/invocation_test.rb +0 -202
- data/test/configuration/callbacks_test.rb +0 -206
- data/test/configuration/connections_test.rb +0 -288
- data/test/configuration/execution_test.rb +0 -159
- data/test/configuration/loading_test.rb +0 -127
- data/test/configuration/namespace_dsl_test.rb +0 -297
- data/test/configuration/roles_test.rb +0 -47
- data/test/configuration/servers_test.rb +0 -90
- data/test/configuration/variables_test.rb +0 -180
- data/test/configuration_test.rb +0 -81
- data/test/deploy/scm/accurev_test.rb +0 -23
- data/test/deploy/scm/base_test.rb +0 -55
- data/test/deploy/scm/git_test.rb +0 -112
- data/test/deploy/strategy/copy_test.rb +0 -147
- data/test/extensions_test.rb +0 -69
- data/test/fixtures/cli_integration.rb +0 -5
- data/test/fixtures/config.rb +0 -5
- data/test/fixtures/custom.rb +0 -3
- data/test/gateway_test.rb +0 -167
- data/test/logger_test.rb +0 -123
- data/test/server_definition_test.rb +0 -108
- data/test/shell_test.rb +0 -64
- data/test/ssh_test.rb +0 -97
- data/test/task_definition_test.rb +0 -101
- data/test/upload_test.rb +0 -131
- data/test/utils.rb +0 -42
- data/test/version_test.rb +0 -24
data/lib/capistrano/gateway.rb
DELETED
@@ -1,131 +0,0 @@
|
|
1
|
-
if RUBY_VERSION == "1.8.6"
|
2
|
-
begin
|
3
|
-
require 'fastthread'
|
4
|
-
rescue LoadError
|
5
|
-
warn "You are running Ruby 1.8.6, which has a bug in its threading implementation."
|
6
|
-
warn "You are liable to encounter deadlocks running Capistrano, unless you install"
|
7
|
-
warn "the fastthread library, which is available as a gem:"
|
8
|
-
warn " gem install fastthread"
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
require 'thread'
|
13
|
-
require 'capistrano/errors'
|
14
|
-
require 'capistrano/ssh'
|
15
|
-
require 'capistrano/server_definition'
|
16
|
-
|
17
|
-
Thread.abort_on_exception = true
|
18
|
-
|
19
|
-
module Capistrano
|
20
|
-
|
21
|
-
# Black magic. It uses threads and Net::SSH to set up a connection to a
|
22
|
-
# gateway server, through which connections to other servers may be
|
23
|
-
# tunnelled.
|
24
|
-
#
|
25
|
-
# It is used internally by Capistrano, but may be useful on its own, as well.
|
26
|
-
#
|
27
|
-
# Usage:
|
28
|
-
#
|
29
|
-
# gateway = Capistrano::Gateway.new(Capistrano::ServerDefinition.new('gateway.example.com'))
|
30
|
-
#
|
31
|
-
# sess1 = gateway.connect_to(Capistrano::ServerDefinition.new('hidden.example.com'))
|
32
|
-
# sess2 = gateway.connect_to(Capistrano::ServerDefinition.new('other.example.com'))
|
33
|
-
class Gateway
|
34
|
-
# The Thread instance driving the gateway connection.
|
35
|
-
attr_reader :thread
|
36
|
-
|
37
|
-
# The Net::SSH session representing the gateway connection.
|
38
|
-
attr_reader :session
|
39
|
-
|
40
|
-
MAX_PORT = 65535
|
41
|
-
MIN_PORT = 1024
|
42
|
-
|
43
|
-
def initialize(server, options={}) #:nodoc:
|
44
|
-
@options = options
|
45
|
-
@next_port = MAX_PORT
|
46
|
-
@terminate_thread = false
|
47
|
-
@port_guard = Mutex.new
|
48
|
-
|
49
|
-
mutex = Mutex.new
|
50
|
-
waiter = ConditionVariable.new
|
51
|
-
|
52
|
-
mutex.synchronize do
|
53
|
-
@thread = Thread.new do
|
54
|
-
logger.trace "starting connection to gateway `#{server}'" if logger
|
55
|
-
SSH.connect(server, @options) do |@session|
|
56
|
-
logger.trace "gateway connection established" if logger
|
57
|
-
mutex.synchronize { waiter.signal }
|
58
|
-
@session.loop do
|
59
|
-
!@terminate_thread
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
waiter.wait(mutex)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
# Shuts down all forwarded connections and terminates the gateway.
|
69
|
-
def shutdown!
|
70
|
-
# cancel all active forward channels
|
71
|
-
session.forward.active_locals.each do |lport, host, port|
|
72
|
-
session.forward.cancel_local(lport)
|
73
|
-
end
|
74
|
-
|
75
|
-
# terminate the gateway thread
|
76
|
-
@terminate_thread = true
|
77
|
-
|
78
|
-
# wait for the gateway thread to stop
|
79
|
-
thread.join
|
80
|
-
end
|
81
|
-
|
82
|
-
# Connects to the given server by opening a forwarded port from the local
|
83
|
-
# host to the server, via the gateway, and then opens and returns a new
|
84
|
-
# Net::SSH connection via that port.
|
85
|
-
def connect_to(server)
|
86
|
-
connection = nil
|
87
|
-
logger.debug "establishing connection to `#{server}' via gateway" if logger
|
88
|
-
local_port = next_port
|
89
|
-
|
90
|
-
thread = Thread.new do
|
91
|
-
begin
|
92
|
-
local_host = ServerDefinition.new("127.0.0.1", :user => server.user, :port => local_port)
|
93
|
-
session.forward.local(local_port, server.host, server.port || 22)
|
94
|
-
connection = SSH.connect(local_host, @options)
|
95
|
-
connection.xserver = server
|
96
|
-
logger.trace "connected: `#{server}' (via gateway)" if logger
|
97
|
-
rescue Errno::EADDRINUSE
|
98
|
-
local_port = next_port
|
99
|
-
retry
|
100
|
-
rescue Exception => e
|
101
|
-
warn "#{e.class}: #{e.message}"
|
102
|
-
warn e.backtrace.join("\n")
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
thread.join
|
107
|
-
if connection.nil?
|
108
|
-
error = ConnectionError.new("could not establish connection to `#{server}'")
|
109
|
-
error.hosts = [server]
|
110
|
-
raise error
|
111
|
-
end
|
112
|
-
|
113
|
-
connection
|
114
|
-
end
|
115
|
-
|
116
|
-
private
|
117
|
-
|
118
|
-
def logger
|
119
|
-
@options[:logger]
|
120
|
-
end
|
121
|
-
|
122
|
-
def next_port
|
123
|
-
@port_guard.synchronize do
|
124
|
-
port = @next_port
|
125
|
-
@next_port -= 1
|
126
|
-
@next_port = MAX_PORT if @next_port < MIN_PORT
|
127
|
-
port
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
data/lib/capistrano/logger.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
module Capistrano
|
2
|
-
class Logger #:nodoc:
|
3
|
-
attr_accessor :level
|
4
|
-
attr_reader :device
|
5
|
-
|
6
|
-
IMPORTANT = 0
|
7
|
-
INFO = 1
|
8
|
-
DEBUG = 2
|
9
|
-
TRACE = 3
|
10
|
-
|
11
|
-
MAX_LEVEL = 3
|
12
|
-
|
13
|
-
def initialize(options={})
|
14
|
-
output = options[:output] || $stderr
|
15
|
-
if output.respond_to?(:puts)
|
16
|
-
@device = output
|
17
|
-
else
|
18
|
-
@device = File.open(output.to_str, "a")
|
19
|
-
@needs_close = true
|
20
|
-
end
|
21
|
-
|
22
|
-
@options = options
|
23
|
-
@level = 0
|
24
|
-
end
|
25
|
-
|
26
|
-
def close
|
27
|
-
device.close if @needs_close
|
28
|
-
end
|
29
|
-
|
30
|
-
def log(level, message, line_prefix=nil)
|
31
|
-
if level <= self.level
|
32
|
-
indent = "%*s" % [MAX_LEVEL, "*" * (MAX_LEVEL - level)]
|
33
|
-
message.each do |line|
|
34
|
-
if line_prefix
|
35
|
-
device.puts "#{indent} [#{line_prefix}] #{line.strip}\n"
|
36
|
-
else
|
37
|
-
device.puts "#{indent} #{line.strip}\n"
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def important(message, line_prefix=nil)
|
44
|
-
log(IMPORTANT, message, line_prefix)
|
45
|
-
end
|
46
|
-
|
47
|
-
def info(message, line_prefix=nil)
|
48
|
-
log(INFO, message, line_prefix)
|
49
|
-
end
|
50
|
-
|
51
|
-
def debug(message, line_prefix=nil)
|
52
|
-
log(DEBUG, message, line_prefix)
|
53
|
-
end
|
54
|
-
|
55
|
-
def trace(message, line_prefix=nil)
|
56
|
-
log(TRACE, message, line_prefix)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
# A collection of compatibility scripts, to ease the transition between
|
2
|
-
# Capistrano 1.x and Capistrano 2.x.
|
3
|
-
|
4
|
-
# Depends on the deployment system
|
5
|
-
load 'deploy'
|
6
|
-
|
7
|
-
map = { "diff_from_last_deploy" => "deploy:pending:diff",
|
8
|
-
"update" => "deploy:update",
|
9
|
-
"update_code" => "deploy:update_code",
|
10
|
-
"symlink" => "deploy:symlink",
|
11
|
-
"restart" => "deploy:restart",
|
12
|
-
"rollback" => "deploy:rollback",
|
13
|
-
"cleanup" => "deploy:cleanup",
|
14
|
-
"disable_web" => "deploy:web:disable",
|
15
|
-
"enable_web" => "deploy:web:enable",
|
16
|
-
"cold_deploy" => "deploy:cold",
|
17
|
-
"deploy_with_migrations" => "deploy:migrations" }
|
18
|
-
|
19
|
-
map.each do |old, new|
|
20
|
-
desc "DEPRECATED: See #{new}."
|
21
|
-
eval "task(#{old.inspect}) do
|
22
|
-
warn \"[DEPRECATED] `#{old}' is deprecated. Use `#{new}' instead.\"
|
23
|
-
find_and_execute_task(#{new.inspect})
|
24
|
-
end"
|
25
|
-
end
|
26
|
-
|
27
|
-
desc "DEPRECATED: See deploy:start."
|
28
|
-
task :spinner do
|
29
|
-
warn "[DEPRECATED] `spinner' is deprecated. Use `deploy:start' instead."
|
30
|
-
set :runner, fetch(:spinner_user, "app")
|
31
|
-
deploy.start
|
32
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
require 'capistrano/recipes/deploy/local_dependency'
|
2
|
-
require 'capistrano/recipes/deploy/remote_dependency'
|
3
|
-
|
4
|
-
module Capistrano
|
5
|
-
module Deploy
|
6
|
-
class Dependencies
|
7
|
-
include Enumerable
|
8
|
-
|
9
|
-
attr_reader :configuration
|
10
|
-
|
11
|
-
def initialize(configuration)
|
12
|
-
@configuration = configuration
|
13
|
-
@dependencies = []
|
14
|
-
yield self if block_given?
|
15
|
-
end
|
16
|
-
|
17
|
-
def check
|
18
|
-
yield self
|
19
|
-
self
|
20
|
-
end
|
21
|
-
|
22
|
-
def remote
|
23
|
-
dep = RemoteDependency.new(configuration)
|
24
|
-
@dependencies << dep
|
25
|
-
dep
|
26
|
-
end
|
27
|
-
|
28
|
-
def local
|
29
|
-
dep = LocalDependency.new(configuration)
|
30
|
-
@dependencies << dep
|
31
|
-
dep
|
32
|
-
end
|
33
|
-
|
34
|
-
def each
|
35
|
-
@dependencies.each { |d| yield d }
|
36
|
-
self
|
37
|
-
end
|
38
|
-
|
39
|
-
def pass?
|
40
|
-
all? { |d| d.pass? }
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
module Capistrano
|
2
|
-
module Deploy
|
3
|
-
class LocalDependency
|
4
|
-
attr_reader :configuration
|
5
|
-
attr_reader :message
|
6
|
-
|
7
|
-
def initialize(configuration)
|
8
|
-
@configuration = configuration
|
9
|
-
@success = true
|
10
|
-
end
|
11
|
-
|
12
|
-
def command(command)
|
13
|
-
@message ||= "`#{command}' could not be found in the path on the local host"
|
14
|
-
@success = find_in_path(command)
|
15
|
-
self
|
16
|
-
end
|
17
|
-
|
18
|
-
def or(message)
|
19
|
-
@message = message
|
20
|
-
self
|
21
|
-
end
|
22
|
-
|
23
|
-
def pass?
|
24
|
-
@success
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
# Searches the path, looking for the given utility. If an executable
|
30
|
-
# file is found that matches the parameter, this returns true.
|
31
|
-
def find_in_path(utility)
|
32
|
-
path = (ENV['PATH'] || "").split(File::PATH_SEPARATOR)
|
33
|
-
suffixes = RUBY_PLATFORM =~ /mswin/ ? %w(.bat .exe .com .cmd) : [""]
|
34
|
-
|
35
|
-
path.each do |dir|
|
36
|
-
suffixes.each do |sfx|
|
37
|
-
file = File.join(dir, utility + sfx)
|
38
|
-
return true if File.executable?(file)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
false
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
@@ -1,96 +0,0 @@
|
|
1
|
-
module Capistrano
|
2
|
-
module Deploy
|
3
|
-
class RemoteDependency
|
4
|
-
attr_reader :configuration
|
5
|
-
attr_reader :hosts
|
6
|
-
|
7
|
-
def initialize(configuration)
|
8
|
-
@configuration = configuration
|
9
|
-
@success = true
|
10
|
-
end
|
11
|
-
|
12
|
-
def directory(path, options={})
|
13
|
-
@message ||= "`#{path}' is not a directory"
|
14
|
-
try("test -d #{path}", options)
|
15
|
-
self
|
16
|
-
end
|
17
|
-
|
18
|
-
def writable(path, options={})
|
19
|
-
@message ||= "`#{path}' is not writable"
|
20
|
-
try("test -w #{path}", options)
|
21
|
-
self
|
22
|
-
end
|
23
|
-
|
24
|
-
def command(command, options={})
|
25
|
-
@message ||= "`#{command}' could not be found in the path"
|
26
|
-
try("which #{command}", options)
|
27
|
-
self
|
28
|
-
end
|
29
|
-
|
30
|
-
def gem(name, version, options={})
|
31
|
-
@message ||= "gem `#{name}' #{version} could not be found"
|
32
|
-
gem_cmd = configuration.fetch(:gem_command, "gem")
|
33
|
-
try("#{gem_cmd} specification --version '#{version}' #{name} 2>&1 | awk 'BEGIN { s = 0 } /^name:/ { s = 1; exit }; END { if(s == 0) exit 1 }'", options)
|
34
|
-
self
|
35
|
-
end
|
36
|
-
|
37
|
-
def match(command, expect, options={})
|
38
|
-
expect = Regexp.new(Regexp.escape(expect.to_s)) unless expect.is_a?(Regexp)
|
39
|
-
|
40
|
-
output_per_server = {}
|
41
|
-
try("#{command} ", options) do |ch, stream, out|
|
42
|
-
output_per_server[ch[:server]] ||= ''
|
43
|
-
output_per_server[ch[:server]] += out
|
44
|
-
end
|
45
|
-
|
46
|
-
# It is possible for some of these commands to return a status != 0
|
47
|
-
# (for example, rake --version exits with a 1). For this check we
|
48
|
-
# just care if the output matches, so we reset the success flag.
|
49
|
-
@success = true
|
50
|
-
|
51
|
-
errored_hosts = []
|
52
|
-
output_per_server.each_pair do |server, output|
|
53
|
-
next if output =~ expect
|
54
|
-
errored_hosts << server
|
55
|
-
end
|
56
|
-
|
57
|
-
if errored_hosts.any?
|
58
|
-
@hosts = errored_hosts.join(', ')
|
59
|
-
output = output_per_server[errored_hosts.first]
|
60
|
-
@message = "the output #{output.inspect} from #{command.inspect} did not match #{expect.inspect}"
|
61
|
-
@success = false
|
62
|
-
end
|
63
|
-
|
64
|
-
self
|
65
|
-
end
|
66
|
-
|
67
|
-
def or(message)
|
68
|
-
@message = message
|
69
|
-
self
|
70
|
-
end
|
71
|
-
|
72
|
-
def pass?
|
73
|
-
@success
|
74
|
-
end
|
75
|
-
|
76
|
-
def message
|
77
|
-
s = @message.dup
|
78
|
-
s << " (#{@hosts})" if @hosts && @hosts.any?
|
79
|
-
s
|
80
|
-
end
|
81
|
-
|
82
|
-
private
|
83
|
-
|
84
|
-
def try(command, options)
|
85
|
-
return unless @success # short-circuit evaluation
|
86
|
-
configuration.run(command, options) do |ch,stream,out|
|
87
|
-
warn "#{ch[:server]}: #{out}" if stream == :err
|
88
|
-
yield ch, stream, out if block_given?
|
89
|
-
end
|
90
|
-
rescue Capistrano::CommandError => e
|
91
|
-
@success = false
|
92
|
-
@hosts = e.hosts.join(', ')
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
@@ -1,169 +0,0 @@
|
|
1
|
-
require 'capistrano/recipes/deploy/scm/base'
|
2
|
-
require 'rexml/xpath'
|
3
|
-
require 'rexml/document'
|
4
|
-
|
5
|
-
module Capistrano
|
6
|
-
module Deploy
|
7
|
-
module SCM
|
8
|
-
# Accurev bridge for use by Capistrano. This implementation does not
|
9
|
-
# implement all features of a Capistrano SCM module. The ones that are
|
10
|
-
# left out are either exceedingly difficult to implement with Accurev
|
11
|
-
# or are considered bad form.
|
12
|
-
#
|
13
|
-
# When using this module in a project, the following variables are used:
|
14
|
-
# * :repository - This should match the depot that code lives in. If your code
|
15
|
-
# exists in a subdirectory, you can append the path depot.
|
16
|
-
# eg. foo-depot/bar_dir
|
17
|
-
# * :stream - The stream in the depot that code should be pulled from. If
|
18
|
-
# left blank, the depot stream will be used
|
19
|
-
# * :revision - Should be in the form 'stream/transaction'.
|
20
|
-
class Accurev < Base
|
21
|
-
include REXML
|
22
|
-
default_command 'accurev'
|
23
|
-
|
24
|
-
# Defines pseudo-revision value for the most recent changes to be deployed.
|
25
|
-
def head
|
26
|
-
"#{stream}/highest"
|
27
|
-
end
|
28
|
-
|
29
|
-
# Given an Accurev revision identifier, this method returns an identifier that
|
30
|
-
# can be used for later SCM calls. This returned identifier will not
|
31
|
-
# change as a result of further SCM activity.
|
32
|
-
def query_revision(revision)
|
33
|
-
internal_revision = InternalRevision.parse(revision)
|
34
|
-
return revision unless internal_revision.psuedo_revision?
|
35
|
-
|
36
|
-
logger.debug("Querying for real revision for #{internal_revision}")
|
37
|
-
rev_stream = internal_revision.stream
|
38
|
-
|
39
|
-
logger.debug("Determining what type of stream #{rev_stream} is...")
|
40
|
-
stream_xml = yield show_streams_for(rev_stream)
|
41
|
-
stream_doc = Document.new(stream_xml)
|
42
|
-
type = XPath.first(stream_doc, '//streams/stream/@type').value
|
43
|
-
|
44
|
-
case type
|
45
|
-
when 'snapshot'
|
46
|
-
InternalRevision.new(rev_stream, 'highest').to_s
|
47
|
-
else
|
48
|
-
logger.debug("Getting latest transaction id in #{rev_stream}")
|
49
|
-
# Doing another yield for a second Accurev call. Hopefully this is ok.
|
50
|
-
hist_xml = yield scm(:hist, '-ftx', '-s', rev_stream, '-t', 'now.1')
|
51
|
-
hist_doc = Document.new(hist_xml)
|
52
|
-
transaction_id = XPath.first(hist_doc, '//AcResponse/transaction/@id').value
|
53
|
-
InternalRevision.new(stream, transaction_id).to_s
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
# Pops a copy of the code for the specified Accurev revision identifier.
|
58
|
-
# The revision identifier is represented as a stream & transaction ID combo.
|
59
|
-
# Accurev can only pop a particular transaction if a stream is created on the server
|
60
|
-
# with a time basis of that transaction id. Therefore, we will create a stream with
|
61
|
-
# the required criteria and pop that.
|
62
|
-
def export(revision_id, destination)
|
63
|
-
revision = InternalRevision.parse(revision_id)
|
64
|
-
logger.debug("Exporting #{revision.stream}/#{revision.transaction_id} to #{destination}")
|
65
|
-
|
66
|
-
commands = [
|
67
|
-
change_or_create_stream("#{revision.stream}-capistrano-deploy", revision),
|
68
|
-
"mkdir -p #{destination}",
|
69
|
-
scm_quiet(:pop, "-Rv #{stream}", "-L #{destination}", "'/./#{subdir}'")
|
70
|
-
]
|
71
|
-
if subdir
|
72
|
-
commands.push(
|
73
|
-
"mv #{destination}/#{subdir}/* #{destination}",
|
74
|
-
"rm -rf #{File.join(destination, subdir)}"
|
75
|
-
)
|
76
|
-
end
|
77
|
-
commands.join(' && ')
|
78
|
-
end
|
79
|
-
|
80
|
-
# Returns the command needed to show the changes that exist between the two revisions.
|
81
|
-
def log(from, to=head)
|
82
|
-
logger.info("Getting transactions between #{from} and #{to}")
|
83
|
-
from_rev = InternalRevision.parse(from)
|
84
|
-
to_rev = InternalRevision.parse(to)
|
85
|
-
|
86
|
-
[
|
87
|
-
scm(:hist, '-s', from_rev.stream, '-t', "#{to_rev.transaction_id}-#{from_rev.transaction_id}"),
|
88
|
-
"sed -e '/transaction #{from_rev.transaction_id}/ { Q }'"
|
89
|
-
].join(' | ')
|
90
|
-
end
|
91
|
-
|
92
|
-
# Returns the command needed to show the diff between what is deployed and what is
|
93
|
-
# pending. Because Accurev can not do this task without creating some streams,
|
94
|
-
# two time basis streams will be created for the purposes of doing the diff.
|
95
|
-
def diff(from, to=head)
|
96
|
-
from = InternalRevision.parse(from)
|
97
|
-
to = InternalRevision.parse(to)
|
98
|
-
|
99
|
-
from_stream = "#{from.stream}-capistrano-diff-from"
|
100
|
-
to_stream = "#{to.stream}-capistrano-diff-to"
|
101
|
-
|
102
|
-
[
|
103
|
-
change_or_create_stream(from_stream, from),
|
104
|
-
change_or_create_stream(to_stream, to),
|
105
|
-
scm(:diff, '-v', from_stream, '-V', to_stream, '-a')
|
106
|
-
].join(' && ')
|
107
|
-
end
|
108
|
-
|
109
|
-
private
|
110
|
-
def depot
|
111
|
-
repository.split('/')[0]
|
112
|
-
end
|
113
|
-
|
114
|
-
def stream
|
115
|
-
variable(:stream) || depot
|
116
|
-
end
|
117
|
-
|
118
|
-
def subdir
|
119
|
-
repository.split('/')[1..-1].join('/') unless repository.index('/').nil?
|
120
|
-
end
|
121
|
-
|
122
|
-
def change_or_create_stream(name, revision)
|
123
|
-
[
|
124
|
-
scm_quiet(:mkstream, '-b', revision.stream, '-s', name, '-t', revision.transaction_id),
|
125
|
-
scm_quiet(:chstream, '-b', revision.stream, '-s', name, '-t', revision.transaction_id)
|
126
|
-
].join('; ')
|
127
|
-
end
|
128
|
-
|
129
|
-
def show_streams_for(stream)
|
130
|
-
scm :show, '-fx', '-s', stream, :streams
|
131
|
-
end
|
132
|
-
|
133
|
-
def scm_quiet(*args)
|
134
|
-
scm(*args) + (variable(:scm_verbose) ? '' : '&> /dev/null')
|
135
|
-
end
|
136
|
-
|
137
|
-
class InternalRevision
|
138
|
-
attr_reader :stream, :transaction_id
|
139
|
-
|
140
|
-
def self.parse(string)
|
141
|
-
match = /([^\/]+)(\/(.+)){0,1}/.match(string)
|
142
|
-
raise "Unrecognized revision identifier: #{string}" unless match
|
143
|
-
|
144
|
-
stream = match[1]
|
145
|
-
transaction_id = match[3] || 'highest'
|
146
|
-
InternalRevision.new(stream, transaction_id)
|
147
|
-
end
|
148
|
-
|
149
|
-
def initialize(stream, transaction_id)
|
150
|
-
@stream = stream
|
151
|
-
@transaction_id = transaction_id
|
152
|
-
end
|
153
|
-
|
154
|
-
def psuedo_revision?
|
155
|
-
@transaction_id == 'highest'
|
156
|
-
end
|
157
|
-
|
158
|
-
def to_s
|
159
|
-
"#{stream}/#{transaction_id}"
|
160
|
-
end
|
161
|
-
|
162
|
-
def ==(other)
|
163
|
-
(stream == other.stream) && (transaction_id == other.transaction_id)
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|