capistrano 1.4.2 → 2.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.
- data/CHANGELOG +140 -4
- data/MIT-LICENSE +1 -1
- data/README +22 -14
- data/bin/cap +1 -8
- data/bin/capify +77 -0
- data/examples/sample.rb +10 -109
- data/lib/capistrano.rb +1 -0
- data/lib/capistrano/callback.rb +41 -0
- data/lib/capistrano/cli.rb +17 -317
- data/lib/capistrano/cli/execute.rb +82 -0
- data/lib/capistrano/cli/help.rb +102 -0
- data/lib/capistrano/cli/help.txt +53 -0
- data/lib/capistrano/cli/options.rb +183 -0
- data/lib/capistrano/cli/ui.rb +28 -0
- data/lib/capistrano/command.rb +62 -29
- data/lib/capistrano/configuration.rb +25 -226
- data/lib/capistrano/configuration/actions/file_transfer.rb +35 -0
- data/lib/capistrano/configuration/actions/inspect.rb +46 -0
- data/lib/capistrano/configuration/actions/invocation.rb +127 -0
- data/lib/capistrano/configuration/callbacks.rb +148 -0
- data/lib/capistrano/configuration/connections.rb +159 -0
- data/lib/capistrano/configuration/execution.rb +126 -0
- data/lib/capistrano/configuration/loading.rb +112 -0
- data/lib/capistrano/configuration/namespaces.rb +190 -0
- data/lib/capistrano/configuration/roles.rb +51 -0
- data/lib/capistrano/configuration/servers.rb +75 -0
- data/lib/capistrano/configuration/variables.rb +127 -0
- data/lib/capistrano/errors.rb +15 -0
- data/lib/capistrano/extensions.rb +27 -8
- data/lib/capistrano/gateway.rb +54 -29
- data/lib/capistrano/logger.rb +11 -11
- data/lib/capistrano/recipes/compat.rb +32 -0
- data/lib/capistrano/recipes/deploy.rb +483 -0
- data/lib/capistrano/recipes/deploy/dependencies.rb +44 -0
- data/lib/capistrano/recipes/deploy/local_dependency.rb +46 -0
- data/lib/capistrano/recipes/deploy/remote_dependency.rb +65 -0
- data/lib/capistrano/recipes/deploy/scm.rb +19 -0
- data/lib/capistrano/recipes/deploy/scm/base.rb +180 -0
- data/lib/capistrano/recipes/deploy/scm/bzr.rb +86 -0
- data/lib/capistrano/recipes/deploy/scm/cvs.rb +151 -0
- data/lib/capistrano/recipes/deploy/scm/darcs.rb +85 -0
- data/lib/capistrano/recipes/deploy/scm/mercurial.rb +129 -0
- data/lib/capistrano/recipes/deploy/scm/perforce.rb +126 -0
- data/lib/capistrano/recipes/deploy/scm/subversion.rb +103 -0
- data/lib/capistrano/recipes/deploy/strategy.rb +19 -0
- data/lib/capistrano/recipes/deploy/strategy/base.rb +64 -0
- data/lib/capistrano/recipes/deploy/strategy/checkout.rb +20 -0
- data/lib/capistrano/recipes/deploy/strategy/copy.rb +143 -0
- data/lib/capistrano/recipes/deploy/strategy/export.rb +20 -0
- data/lib/capistrano/recipes/deploy/strategy/remote.rb +52 -0
- data/lib/capistrano/recipes/deploy/strategy/remote_cache.rb +47 -0
- data/lib/capistrano/recipes/deploy/templates/maintenance.rhtml +53 -0
- data/lib/capistrano/recipes/standard.rb +26 -276
- data/lib/capistrano/recipes/templates/maintenance.rhtml +1 -1
- data/lib/capistrano/recipes/upgrade.rb +33 -0
- data/lib/capistrano/server_definition.rb +51 -0
- data/lib/capistrano/shell.rb +125 -81
- data/lib/capistrano/ssh.rb +80 -36
- data/lib/capistrano/task_definition.rb +69 -0
- data/lib/capistrano/upload.rb +146 -0
- data/lib/capistrano/version.rb +13 -17
- data/test/cli/execute_test.rb +132 -0
- data/test/cli/help_test.rb +139 -0
- data/test/cli/options_test.rb +226 -0
- data/test/cli/ui_test.rb +28 -0
- data/test/cli_test.rb +17 -0
- data/test/command_test.rb +284 -25
- data/test/configuration/actions/file_transfer_test.rb +40 -0
- data/test/configuration/actions/inspect_test.rb +62 -0
- data/test/configuration/actions/invocation_test.rb +195 -0
- data/test/configuration/callbacks_test.rb +206 -0
- data/test/configuration/connections_test.rb +288 -0
- data/test/configuration/execution_test.rb +159 -0
- data/test/configuration/loading_test.rb +119 -0
- data/test/configuration/namespace_dsl_test.rb +283 -0
- data/test/configuration/roles_test.rb +47 -0
- data/test/configuration/servers_test.rb +90 -0
- data/test/configuration/variables_test.rb +180 -0
- data/test/configuration_test.rb +60 -212
- data/test/deploy/scm/base_test.rb +55 -0
- data/test/deploy/strategy/copy_test.rb +146 -0
- data/test/extensions_test.rb +69 -0
- data/test/fixtures/cli_integration.rb +5 -0
- data/test/fixtures/custom.rb +2 -2
- data/test/gateway_test.rb +167 -0
- data/test/logger_test.rb +123 -0
- data/test/server_definition_test.rb +108 -0
- data/test/shell_test.rb +64 -0
- data/test/ssh_test.rb +67 -154
- data/test/task_definition_test.rb +101 -0
- data/test/upload_test.rb +131 -0
- data/test/utils.rb +31 -39
- data/test/version_test.rb +24 -0
- metadata +145 -98
- data/THANKS +0 -4
- data/lib/capistrano/actor.rb +0 -567
- data/lib/capistrano/generators/rails/deployment/deployment_generator.rb +0 -25
- data/lib/capistrano/generators/rails/deployment/templates/capistrano.rake +0 -49
- data/lib/capistrano/generators/rails/deployment/templates/deploy.rb +0 -122
- data/lib/capistrano/generators/rails/loader.rb +0 -20
- data/lib/capistrano/scm/base.rb +0 -61
- data/lib/capistrano/scm/baz.rb +0 -118
- data/lib/capistrano/scm/bzr.rb +0 -70
- data/lib/capistrano/scm/cvs.rb +0 -129
- data/lib/capistrano/scm/darcs.rb +0 -27
- data/lib/capistrano/scm/mercurial.rb +0 -83
- data/lib/capistrano/scm/perforce.rb +0 -139
- data/lib/capistrano/scm/subversion.rb +0 -128
- data/lib/capistrano/transfer.rb +0 -97
- data/lib/capistrano/utils.rb +0 -26
- data/test/actor_test.rb +0 -402
- data/test/scm/cvs_test.rb +0 -196
- data/test/scm/subversion_test.rb +0 -145
@@ -0,0 +1,75 @@
|
|
1
|
+
module Capistrano
|
2
|
+
class Configuration
|
3
|
+
module Servers
|
4
|
+
# Identifies all servers that the given task should be executed on.
|
5
|
+
# The options hash accepts the same arguments as #find_servers, and any
|
6
|
+
# preexisting options there will take precedence over the options in
|
7
|
+
# the task.
|
8
|
+
def find_servers_for_task(task, options={})
|
9
|
+
find_servers(task.options.merge(options))
|
10
|
+
end
|
11
|
+
|
12
|
+
# Attempts to find all defined servers that match the given criteria.
|
13
|
+
# The options hash may include a :hosts option (which should specify
|
14
|
+
# an array of host names or ServerDefinition instances), a :roles
|
15
|
+
# option (specifying an array of roles), an :only option (specifying
|
16
|
+
# a hash of key/value pairs that any matching server must match), and
|
17
|
+
# an :exception option (like :only, but the inverse).
|
18
|
+
#
|
19
|
+
# Additionally, if the HOSTS environment variable is set, it will take
|
20
|
+
# precedence over any other options. Similarly, the ROLES environment
|
21
|
+
# variable will take precedence over other options. If both HOSTS and
|
22
|
+
# ROLES are given, HOSTS wins.
|
23
|
+
#
|
24
|
+
# Usage:
|
25
|
+
#
|
26
|
+
# # return all known servers
|
27
|
+
# servers = find_servers
|
28
|
+
#
|
29
|
+
# # find all servers in the app role that are not exempted from
|
30
|
+
# # deployment
|
31
|
+
# servers = find_servers :roles => :app,
|
32
|
+
# :except => { :no_release => true }
|
33
|
+
#
|
34
|
+
# # returns the given hosts, translated to ServerDefinition objects
|
35
|
+
# servers = find_servers :hosts => "jamis@example.host.com"
|
36
|
+
def find_servers(options={})
|
37
|
+
hosts = server_list_from(ENV['HOSTS'] || options[:hosts])
|
38
|
+
roles = role_list_from(ENV['ROLES'] || options[:roles] || self.roles.keys)
|
39
|
+
only = options[:only] || {}
|
40
|
+
except = options[:except] || {}
|
41
|
+
|
42
|
+
if hosts.any?
|
43
|
+
hosts.uniq
|
44
|
+
else
|
45
|
+
servers = roles.inject([]) { |list, role| list.concat(self.roles[role]) }
|
46
|
+
servers = servers.select { |server| only.all? { |key,value| server.options[key] == value } }
|
47
|
+
servers = servers.reject { |server| except.any? { |key,value| server.options[key] == value } }
|
48
|
+
servers.uniq
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
protected
|
53
|
+
|
54
|
+
def server_list_from(hosts)
|
55
|
+
hosts = hosts.split(/,/) if String === hosts
|
56
|
+
hosts = build_list(hosts)
|
57
|
+
hosts.map { |s| String === s ? ServerDefinition.new(s.strip) : s }
|
58
|
+
end
|
59
|
+
|
60
|
+
def role_list_from(roles)
|
61
|
+
roles = roles.split(/,/) if String === roles
|
62
|
+
roles = build_list(roles)
|
63
|
+
roles.map do |role|
|
64
|
+
role = String === role ? role.strip.to_sym : role
|
65
|
+
raise ArgumentError, "unknown role `#{role}'" unless self.roles.key?(role)
|
66
|
+
role
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def build_list(list)
|
71
|
+
Array(list).map { |item| item.respond_to?(:call) ? item.call : item }.flatten
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
module Capistrano
|
4
|
+
class Configuration
|
5
|
+
module Variables
|
6
|
+
def self.included(base) #:nodoc:
|
7
|
+
%w(initialize respond_to? method_missing).each do |m|
|
8
|
+
base_name = m[/^\w+/]
|
9
|
+
punct = m[/\W+$/]
|
10
|
+
base.send :alias_method, "#{base_name}_without_variables#{punct}", m
|
11
|
+
base.send :alias_method, m, "#{base_name}_with_variables#{punct}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# The hash of variables that have been defined in this configuration
|
16
|
+
# instance.
|
17
|
+
attr_reader :variables
|
18
|
+
|
19
|
+
# Set a variable to the given value.
|
20
|
+
def set(variable, *args, &block)
|
21
|
+
if variable.to_s !~ /^[_a-z]/
|
22
|
+
raise ArgumentError, "invalid variable `#{variable}' (variables must begin with an underscore, or a lower-case letter)"
|
23
|
+
end
|
24
|
+
|
25
|
+
if !block_given? && args.empty? || block_given? && !args.empty?
|
26
|
+
raise ArgumentError, "you must specify exactly one of either a value or a block"
|
27
|
+
end
|
28
|
+
|
29
|
+
if args.length > 1
|
30
|
+
raise ArgumentError, "wrong number of arguments (#{args.length} for 1)"
|
31
|
+
end
|
32
|
+
|
33
|
+
value = args.empty? ? block : args.first
|
34
|
+
sym = variable.to_sym
|
35
|
+
protect(sym) { @variables[sym] = value }
|
36
|
+
end
|
37
|
+
|
38
|
+
alias :[]= :set
|
39
|
+
|
40
|
+
# Removes any trace of the given variable.
|
41
|
+
def unset(variable)
|
42
|
+
sym = variable.to_sym
|
43
|
+
protect(sym) do
|
44
|
+
@original_procs.delete(sym)
|
45
|
+
@variables.delete(sym)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns true if the variable has been defined, and false otherwise.
|
50
|
+
def exists?(variable)
|
51
|
+
@variables.key?(variable.to_sym)
|
52
|
+
end
|
53
|
+
|
54
|
+
# If the variable was originally a proc value, it will be reset to it's
|
55
|
+
# original proc value. Otherwise, this method does nothing. It returns
|
56
|
+
# true if the variable was actually reset.
|
57
|
+
def reset!(variable)
|
58
|
+
sym = variable.to_sym
|
59
|
+
protect(sym) do
|
60
|
+
if @original_procs.key?(sym)
|
61
|
+
@variables[sym] = @original_procs.delete(sym)
|
62
|
+
true
|
63
|
+
else
|
64
|
+
false
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Access a named variable. If the value of the variable responds_to? :call,
|
70
|
+
# #call will be invoked (without parameters) and the return value cached
|
71
|
+
# and returned.
|
72
|
+
def fetch(variable, *args)
|
73
|
+
if !args.empty? && block_given?
|
74
|
+
raise ArgumentError, "you must specify either a default value or a block, but not both"
|
75
|
+
end
|
76
|
+
|
77
|
+
sym = variable.to_sym
|
78
|
+
protect(sym) do
|
79
|
+
if !@variables.key?(sym)
|
80
|
+
return args.first unless args.empty?
|
81
|
+
return yield(variable) if block_given?
|
82
|
+
raise IndexError, "`#{variable}' not found"
|
83
|
+
end
|
84
|
+
|
85
|
+
if @variables[sym].respond_to?(:call)
|
86
|
+
@original_procs[sym] = @variables[sym]
|
87
|
+
@variables[sym] = @variables[sym].call
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
@variables[sym]
|
92
|
+
end
|
93
|
+
|
94
|
+
def [](variable)
|
95
|
+
fetch(variable, nil)
|
96
|
+
end
|
97
|
+
|
98
|
+
def initialize_with_variables(*args) #:nodoc:
|
99
|
+
initialize_without_variables(*args)
|
100
|
+
@variables = {}
|
101
|
+
@original_procs = {}
|
102
|
+
@variable_locks = Hash.new { |h,k| h[k] = Mutex.new }
|
103
|
+
|
104
|
+
set :ssh_options, {}
|
105
|
+
set :logger, logger
|
106
|
+
end
|
107
|
+
private :initialize_with_variables
|
108
|
+
|
109
|
+
def protect(variable)
|
110
|
+
@variable_locks[variable.to_sym].synchronize { yield }
|
111
|
+
end
|
112
|
+
private :protect
|
113
|
+
|
114
|
+
def respond_to_with_variables?(sym) #:nodoc:
|
115
|
+
@variables.has_key?(sym) || respond_to_without_variables?(sym)
|
116
|
+
end
|
117
|
+
|
118
|
+
def method_missing_with_variables(sym, *args, &block) #:nodoc:
|
119
|
+
if args.length == 0 && block.nil? && @variables.has_key?(sym)
|
120
|
+
self[sym]
|
121
|
+
else
|
122
|
+
method_missing_without_variables(sym, *args, &block)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Capistrano
|
2
|
+
class Error < RuntimeError; end
|
3
|
+
|
4
|
+
class CaptureError < Error; end
|
5
|
+
class NoSuchTaskError < Error; end
|
6
|
+
class NoMatchingServersError < Error; end
|
7
|
+
|
8
|
+
class RemoteError < Error
|
9
|
+
attr_accessor :hosts
|
10
|
+
end
|
11
|
+
|
12
|
+
class ConnectionError < RemoteError; end
|
13
|
+
class UploadError < RemoteError; end
|
14
|
+
class CommandError < RemoteError; end
|
15
|
+
end
|
@@ -1,23 +1,35 @@
|
|
1
|
-
require 'capistrano/actor'
|
2
|
-
|
3
1
|
module Capistrano
|
4
|
-
class ExtensionProxy
|
5
|
-
def initialize(
|
6
|
-
@
|
2
|
+
class ExtensionProxy #:nodoc:
|
3
|
+
def initialize(config, mod)
|
4
|
+
@config = config
|
7
5
|
extend(mod)
|
8
6
|
end
|
9
7
|
|
10
8
|
def method_missing(sym, *args, &block)
|
11
|
-
@
|
9
|
+
@config.send(sym, *args, &block)
|
12
10
|
end
|
13
11
|
end
|
14
12
|
|
13
|
+
# Holds the set of registered plugins, keyed by name (where the name is a
|
14
|
+
# symbol).
|
15
15
|
EXTENSIONS = {}
|
16
16
|
|
17
|
+
# Register the given module as a plugin with the given name. It will henceforth
|
18
|
+
# be available via a proxy object on Configuration instances, accessible by
|
19
|
+
# a method with the given name.
|
17
20
|
def self.plugin(name, mod)
|
21
|
+
name = name.to_sym
|
18
22
|
return false if EXTENSIONS.has_key?(name)
|
19
23
|
|
20
|
-
Capistrano::
|
24
|
+
methods = Capistrano::Configuration.public_instance_methods +
|
25
|
+
Capistrano::Configuration.protected_instance_methods +
|
26
|
+
Capistrano::Configuration.private_instance_methods
|
27
|
+
|
28
|
+
if methods.include?(name.to_s)
|
29
|
+
raise Capistrano::Error, "registering a plugin named `#{name}' would shadow a method on Capistrano::Configuration with the same name"
|
30
|
+
end
|
31
|
+
|
32
|
+
Capistrano::Configuration.class_eval <<-STR, __FILE__, __LINE__+1
|
21
33
|
def #{name}
|
22
34
|
@__#{name}_proxy ||= Capistrano::ExtensionProxy.new(self, Capistrano::EXTENSIONS[#{name.inspect}])
|
23
35
|
end
|
@@ -27,12 +39,19 @@ module Capistrano
|
|
27
39
|
return true
|
28
40
|
end
|
29
41
|
|
42
|
+
# Unregister the plugin with the given name.
|
30
43
|
def self.remove_plugin(name)
|
44
|
+
name = name.to_sym
|
31
45
|
if EXTENSIONS.delete(name)
|
32
|
-
Capistrano::
|
46
|
+
Capistrano::Configuration.send(:remove_method, name)
|
33
47
|
return true
|
34
48
|
end
|
35
49
|
|
36
50
|
return false
|
37
51
|
end
|
52
|
+
|
53
|
+
def self.configuration(*args) #:nodoc:
|
54
|
+
warn "[DEPRECATION] Capistrano.configuration is deprecated. Use Capistrano::Configuration.instance instead"
|
55
|
+
Capistrano::Configuration.instance(*args)
|
56
|
+
end
|
38
57
|
end
|
data/lib/capistrano/gateway.rb
CHANGED
@@ -1,5 +1,18 @@
|
|
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
|
+
|
1
12
|
require 'thread'
|
13
|
+
require 'capistrano/errors'
|
2
14
|
require 'capistrano/ssh'
|
15
|
+
require 'capistrano/server_definition'
|
3
16
|
|
4
17
|
Thread.abort_on_exception = true
|
5
18
|
|
@@ -9,17 +22,16 @@ module Capistrano
|
|
9
22
|
# gateway server, through which connections to other servers may be
|
10
23
|
# tunnelled.
|
11
24
|
#
|
12
|
-
# It is used internally by
|
25
|
+
# It is used internally by Capistrano, but may be useful on its own, as well.
|
13
26
|
#
|
14
27
|
# Usage:
|
15
28
|
#
|
16
|
-
#
|
17
|
-
# gateway = Capistrano::Gateway.new('gateway.example.com', config)
|
29
|
+
# gateway = Capistrano::Gateway.new(Capistrano::ServerDefinition.new('gateway.example.com'))
|
18
30
|
#
|
19
|
-
# sess1 = gateway.connect_to('hidden.example.com')
|
20
|
-
# sess2 = gateway.connect_to('other.example.com')
|
31
|
+
# sess1 = gateway.connect_to(Capistrano::ServerDefinition.new('hidden.example.com'))
|
32
|
+
# sess2 = gateway.connect_to(Capistrano::ServerDefinition.new('other.example.com'))
|
21
33
|
class Gateway
|
22
|
-
# The
|
34
|
+
# The Thread instance driving the gateway connection.
|
23
35
|
attr_reader :thread
|
24
36
|
|
25
37
|
# The Net::SSH session representing the gateway connection.
|
@@ -28,8 +40,8 @@ module Capistrano
|
|
28
40
|
MAX_PORT = 65535
|
29
41
|
MIN_PORT = 1024
|
30
42
|
|
31
|
-
def initialize(server,
|
32
|
-
@
|
43
|
+
def initialize(server, options={}) #:nodoc:
|
44
|
+
@options = options
|
33
45
|
@next_port = MAX_PORT
|
34
46
|
@terminate_thread = false
|
35
47
|
@port_guard = Mutex.new
|
@@ -37,30 +49,34 @@ module Capistrano
|
|
37
49
|
mutex = Mutex.new
|
38
50
|
waiter = ConditionVariable.new
|
39
51
|
|
40
|
-
|
41
|
-
@
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
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
|
46
62
|
end
|
47
|
-
end
|
48
63
|
|
49
|
-
|
64
|
+
waiter.wait(mutex)
|
65
|
+
end
|
50
66
|
end
|
51
67
|
|
52
68
|
# Shuts down all forwarded connections and terminates the gateway.
|
53
69
|
def shutdown!
|
54
70
|
# cancel all active forward channels
|
55
|
-
|
56
|
-
|
71
|
+
session.forward.active_locals.each do |lport, host, port|
|
72
|
+
session.forward.cancel_local(lport)
|
57
73
|
end
|
58
74
|
|
59
75
|
# terminate the gateway thread
|
60
76
|
@terminate_thread = true
|
61
77
|
|
62
78
|
# wait for the gateway thread to stop
|
63
|
-
|
79
|
+
thread.join
|
64
80
|
end
|
65
81
|
|
66
82
|
# Connects to the given server by opening a forwarded port from the local
|
@@ -68,32 +84,41 @@ module Capistrano
|
|
68
84
|
# Net::SSH connection via that port.
|
69
85
|
def connect_to(server)
|
70
86
|
connection = nil
|
71
|
-
|
87
|
+
logger.debug "establishing connection to `#{server}' via gateway" if logger
|
72
88
|
local_port = next_port
|
73
89
|
|
74
90
|
thread = Thread.new do
|
75
91
|
begin
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
@config.logger.trace "connection to #{server} via gateway established"
|
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
|
82
97
|
rescue Errno::EADDRINUSE
|
83
98
|
local_port = next_port
|
84
99
|
retry
|
85
100
|
rescue Exception => e
|
86
|
-
|
87
|
-
|
101
|
+
warn "#{e.class}: #{e.message}"
|
102
|
+
warn e.backtrace.join("\n")
|
88
103
|
end
|
89
104
|
end
|
90
105
|
|
91
106
|
thread.join
|
92
|
-
|
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
|
93
114
|
end
|
94
115
|
|
95
116
|
private
|
96
117
|
|
118
|
+
def logger
|
119
|
+
@options[:logger]
|
120
|
+
end
|
121
|
+
|
97
122
|
def next_port
|
98
123
|
@port_guard.synchronize do
|
99
124
|
port = @next_port
|
data/lib/capistrano/logger.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module Capistrano
|
2
2
|
class Logger #:nodoc:
|
3
3
|
attr_accessor :level
|
4
|
+
attr_reader :device
|
4
5
|
|
5
6
|
IMPORTANT = 0
|
6
7
|
INFO = 1
|
@@ -10,13 +11,12 @@ module Capistrano
|
|
10
11
|
MAX_LEVEL = 3
|
11
12
|
|
12
13
|
def initialize(options={})
|
13
|
-
output = options[:output] ||
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
@needs_close = true
|
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
20
|
end
|
21
21
|
|
22
22
|
@options = options
|
@@ -24,17 +24,17 @@ module Capistrano
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def close
|
27
|
-
|
27
|
+
device.close if @needs_close
|
28
28
|
end
|
29
29
|
|
30
30
|
def log(level, message, line_prefix=nil)
|
31
31
|
if level <= self.level
|
32
32
|
indent = "%*s" % [MAX_LEVEL, "*" * (MAX_LEVEL - level)]
|
33
|
-
message.
|
33
|
+
message.each do |line|
|
34
34
|
if line_prefix
|
35
|
-
|
35
|
+
device.puts "#{indent} [#{line_prefix}] #{line.strip}\n"
|
36
36
|
else
|
37
|
-
|
37
|
+
device.puts "#{indent} #{line.strip}\n"
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|