capistrano 2.2.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +29 -0
- data/README +4 -7
- data/bin/cap +0 -0
- data/bin/capify +0 -0
- data/lib/capistrano/command.rb +32 -38
- data/lib/capistrano/configuration/actions/file_transfer.rb +21 -13
- data/lib/capistrano/configuration/actions/invocation.rb +1 -1
- data/lib/capistrano/configuration/connections.rb +30 -20
- data/lib/capistrano/errors.rb +1 -1
- data/lib/capistrano/processable.rb +53 -0
- data/lib/capistrano/recipes/deploy/remote_dependency.rb +6 -0
- data/lib/capistrano/recipes/deploy/scm/git.rb +26 -11
- data/lib/capistrano/recipes/deploy/scm/none.rb +44 -0
- data/lib/capistrano/recipes/deploy/strategy/base.rb +6 -0
- data/lib/capistrano/recipes/deploy/strategy/copy.rb +74 -3
- data/lib/capistrano/recipes/deploy.rb +15 -13
- data/lib/capistrano/role.rb +0 -14
- data/lib/capistrano/server_definition.rb +5 -0
- data/lib/capistrano/shell.rb +21 -17
- data/lib/capistrano/ssh.rb +24 -58
- data/lib/capistrano/transfer.rb +216 -0
- data/lib/capistrano/version.rb +1 -1
- data/test/cli/execute_test.rb +1 -1
- data/test/cli/help_test.rb +1 -1
- data/test/cli/options_test.rb +1 -1
- data/test/cli/ui_test.rb +1 -1
- data/test/cli_test.rb +1 -1
- data/test/command_test.rb +31 -51
- data/test/configuration/actions/file_transfer_test.rb +21 -19
- data/test/configuration/actions/inspect_test.rb +1 -1
- data/test/configuration/actions/invocation_test.rb +6 -6
- data/test/configuration/callbacks_test.rb +1 -1
- data/test/configuration/connections_test.rb +11 -12
- data/test/configuration/execution_test.rb +1 -1
- data/test/configuration/loading_test.rb +1 -1
- data/test/configuration/namespace_dsl_test.rb +1 -1
- data/test/configuration/roles_test.rb +1 -1
- data/test/configuration/servers_test.rb +1 -1
- data/test/configuration/variables_test.rb +1 -1
- data/test/configuration_test.rb +1 -1
- data/test/deploy/scm/accurev_test.rb +1 -1
- data/test/deploy/scm/base_test.rb +1 -1
- data/test/deploy/scm/git_test.rb +10 -6
- data/test/deploy/scm/mercurial_test.rb +1 -1
- data/test/deploy/strategy/copy_test.rb +120 -27
- data/test/extensions_test.rb +1 -1
- data/test/logger_test.rb +1 -1
- data/test/server_definition_test.rb +1 -1
- data/test/shell_test.rb +27 -1
- data/test/ssh_test.rb +27 -21
- data/test/task_definition_test.rb +1 -1
- data/test/transfer_test.rb +160 -0
- data/test/utils.rb +30 -34
- data/test/version_test.rb +1 -1
- metadata +26 -14
- data/lib/capistrano/gateway.rb +0 -131
- data/lib/capistrano/upload.rb +0 -152
- data/test/gateway_test.rb +0 -167
- data/test/upload_test.rb +0 -131
data/test/extensions_test.rb
CHANGED
data/test/logger_test.rb
CHANGED
data/test/shell_test.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require "
|
1
|
+
require "utils"
|
2
2
|
require 'capistrano/configuration'
|
3
3
|
require 'capistrano/shell'
|
4
4
|
|
@@ -61,4 +61,30 @@ class ShellTest < Test::Unit::TestCase
|
|
61
61
|
@shell.expects(:process_command).with("on", "app,db", "hello world")
|
62
62
|
assert @shell.read_and_execute
|
63
63
|
end
|
64
|
+
|
65
|
+
def test_task_command_with_bang_gets_processed_by_exec_tasks
|
66
|
+
while_testing_post_exec_commands do
|
67
|
+
@shell.expects(:read_line).returns("!deploy")
|
68
|
+
@shell.expects(:exec_tasks).with(["deploy"])
|
69
|
+
assert @shell.read_and_execute
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_normal_command_gets_processed_by_exec_command
|
74
|
+
while_testing_post_exec_commands do
|
75
|
+
@shell.expects(:read_line).returns("uptime")
|
76
|
+
@shell.expects(:exec_command).with("uptime",nil)
|
77
|
+
@shell.expects(:connect)
|
78
|
+
assert @shell.read_and_execute
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def while_testing_post_exec_commands(&block)
|
86
|
+
@shell.instance_variable_set(:@mutex,Mutex.new)
|
87
|
+
yield
|
88
|
+
end
|
89
|
+
|
64
90
|
end
|
data/test/ssh_test.rb
CHANGED
@@ -1,89 +1,95 @@
|
|
1
|
-
require "
|
1
|
+
require "utils"
|
2
2
|
require 'capistrano/ssh'
|
3
3
|
|
4
4
|
class SSHTest < Test::Unit::TestCase
|
5
5
|
def setup
|
6
|
-
|
7
|
-
|
6
|
+
Capistrano::ServerDefinition.stubs(:default_user).returns("default-user")
|
7
|
+
@options = { :password => nil,
|
8
8
|
:port => 22,
|
9
9
|
:auth_methods => %w(publickey hostbased) }
|
10
10
|
@server = server("capistrano")
|
11
11
|
end
|
12
12
|
|
13
13
|
def test_connect_with_bare_server_without_options_or_config_with_public_key_succeeding_should_only_loop_once
|
14
|
-
Net::SSH.expects(:start).with(@server.host, @options).returns(success = Object.new)
|
14
|
+
Net::SSH.expects(:start).with(@server.host, "default-user", @options).returns(success = Object.new)
|
15
15
|
assert_equal success, Capistrano::SSH.connect(@server)
|
16
16
|
end
|
17
17
|
|
18
18
|
def test_connect_with_bare_server_without_options_with_public_key_failing_should_try_password
|
19
|
-
Net::SSH.expects(:start).with(@server.host, @options).raises(Net::SSH::AuthenticationFailed)
|
20
|
-
Net::SSH.expects(:start).with(@server.host, @options.merge(:password => "f4b13n", :auth_methods => %w(password keyboard-interactive))).returns(success = Object.new)
|
19
|
+
Net::SSH.expects(:start).with(@server.host, "default-user", @options).raises(Net::SSH::AuthenticationFailed)
|
20
|
+
Net::SSH.expects(:start).with(@server.host, "default-user", @options.merge(:password => "f4b13n", :auth_methods => %w(password keyboard-interactive))).returns(success = Object.new)
|
21
21
|
assert_equal success, Capistrano::SSH.connect(@server, :password => "f4b13n")
|
22
22
|
end
|
23
23
|
|
24
24
|
def test_connect_with_bare_server_without_options_public_key_and_password_failing_should_raise_error
|
25
|
-
Net::SSH.expects(:start).with(@server.host, @options).raises(Net::SSH::AuthenticationFailed)
|
26
|
-
Net::SSH.expects(:start).with(@server.host, @options.merge(:password => "f4b13n", :auth_methods => %w(password keyboard-interactive))).raises(Net::SSH::AuthenticationFailed)
|
25
|
+
Net::SSH.expects(:start).with(@server.host, "default-user", @options).raises(Net::SSH::AuthenticationFailed)
|
26
|
+
Net::SSH.expects(:start).with(@server.host, "default-user", @options.merge(:password => "f4b13n", :auth_methods => %w(password keyboard-interactive))).raises(Net::SSH::AuthenticationFailed)
|
27
27
|
assert_raises(Net::SSH::AuthenticationFailed) do
|
28
28
|
Capistrano::SSH.connect(@server, :password => "f4b13n")
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
32
|
def test_connect_with_bare_server_and_user_via_public_key_should_pass_user_to_net_ssh
|
33
|
-
Net::SSH.expects(:start).with(@server.host,
|
33
|
+
Net::SSH.expects(:start).with(@server.host, "jamis", @options).returns(success = Object.new)
|
34
34
|
assert_equal success, Capistrano::SSH.connect(@server, :user => "jamis")
|
35
35
|
end
|
36
36
|
|
37
37
|
def test_connect_with_bare_server_and_user_via_password_should_pass_user_to_net_ssh
|
38
|
-
Net::SSH.expects(:start).with(@server.host,
|
39
|
-
Net::SSH.expects(:start).with(@server.host, @options.merge(:
|
38
|
+
Net::SSH.expects(:start).with(@server.host, "jamis", @options).raises(Net::SSH::AuthenticationFailed)
|
39
|
+
Net::SSH.expects(:start).with(@server.host, "jamis", @options.merge(:password => "f4b13n", :auth_methods => %w(password keyboard-interactive))).returns(success = Object.new)
|
40
40
|
assert_equal success, Capistrano::SSH.connect(@server, :user => "jamis", :password => "f4b13n")
|
41
41
|
end
|
42
42
|
|
43
43
|
def test_connect_with_bare_server_with_explicit_port_should_pass_port_to_net_ssh
|
44
|
-
Net::SSH.expects(:start).with(@server.host, @options.merge(:port => 1234)).returns(success = Object.new)
|
44
|
+
Net::SSH.expects(:start).with(@server.host, "default-user", @options.merge(:port => 1234)).returns(success = Object.new)
|
45
45
|
assert_equal success, Capistrano::SSH.connect(@server, :port => 1234)
|
46
46
|
end
|
47
47
|
|
48
48
|
def test_connect_with_server_with_user_should_pass_user_to_net_ssh
|
49
49
|
server = server("jamis@capistrano")
|
50
|
-
Net::SSH.expects(:start).with(server.host,
|
50
|
+
Net::SSH.expects(:start).with(server.host, "jamis", @options).returns(success = Object.new)
|
51
51
|
assert_equal success, Capistrano::SSH.connect(server)
|
52
52
|
end
|
53
53
|
|
54
54
|
def test_connect_with_server_with_port_should_pass_port_to_net_ssh
|
55
55
|
server = server("capistrano:1235")
|
56
|
-
Net::SSH.expects(:start).with(server.host, @options.merge(:port => 1235)).returns(success = Object.new)
|
56
|
+
Net::SSH.expects(:start).with(server.host, "default-user", @options.merge(:port => 1235)).returns(success = Object.new)
|
57
57
|
assert_equal success, Capistrano::SSH.connect(server)
|
58
58
|
end
|
59
59
|
|
60
60
|
def test_connect_with_server_with_user_and_port_should_pass_user_and_port_to_net_ssh
|
61
61
|
server = server("jamis@capistrano:1235")
|
62
|
-
Net::SSH.expects(:start).with(server.host, @options.merge(:
|
62
|
+
Net::SSH.expects(:start).with(server.host, "jamis", @options.merge(:port => 1235)).returns(success = Object.new)
|
63
|
+
assert_equal success, Capistrano::SSH.connect(server)
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_connect_with_server_with_other_ssh_options_should_pass_ssh_options_to_net_ssh
|
67
|
+
server = server("jamis@capistrano:1235", :ssh_options => { :keys => %w(some_valid_key), :auth_methods => %w(a_method), :hmac => 'none' })
|
68
|
+
Net::SSH.expects(:start).with(server.host, "jamis", @options.merge(:port => 1235, :keys => %w(some_valid_key), :auth_methods => %w(a_method), :hmac => 'none' )).returns(success = Object.new)
|
63
69
|
assert_equal success, Capistrano::SSH.connect(server)
|
64
70
|
end
|
65
71
|
|
66
72
|
def test_connect_with_ssh_options_should_use_ssh_options
|
67
73
|
ssh_options = { :username => "JamisMan", :port => 8125 }
|
68
|
-
Net::SSH.expects(:start).with(@server.host, @options.merge(:
|
74
|
+
Net::SSH.expects(:start).with(@server.host, "JamisMan", @options.merge(:port => 8125)).returns(success = Object.new)
|
69
75
|
assert_equal success, Capistrano::SSH.connect(@server, {:ssh_options => ssh_options})
|
70
76
|
end
|
71
77
|
|
72
78
|
def test_connect_with_options_and_ssh_options_should_see_options_override_ssh_options
|
73
79
|
ssh_options = { :username => "JamisMan", :port => 8125, :forward_agent => true }
|
74
|
-
Net::SSH.expects(:start).with(@server.host, @options.merge(:
|
75
|
-
assert_equal success, Capistrano::SSH.connect(@server,
|
80
|
+
Net::SSH.expects(:start).with(@server.host, "jamis", @options.merge(:port => 1235, :forward_agent => true)).returns(success = Object.new)
|
81
|
+
assert_equal success, Capistrano::SSH.connect(@server, :ssh_options => ssh_options, :user => "jamis", :port => 1235)
|
76
82
|
end
|
77
83
|
|
78
84
|
def test_connect_with_ssh_options_should_see_server_options_override_ssh_options
|
79
85
|
ssh_options = { :username => "JamisMan", :port => 8125, :forward_agent => true }
|
80
86
|
server = server("jamis@capistrano:1235")
|
81
|
-
Net::SSH.expects(:start).with(server.host, @options.merge(:
|
87
|
+
Net::SSH.expects(:start).with(server.host, "jamis", @options.merge(:port => 1235, :forward_agent => true)).returns(success = Object.new)
|
82
88
|
assert_equal success, Capistrano::SSH.connect(server, {:ssh_options => ssh_options})
|
83
89
|
end
|
84
90
|
|
85
91
|
def test_connect_should_add_xserver_accessor_to_connection
|
86
|
-
Net::SSH.expects(:start).with(@server.host, @options).returns(success = Object.new)
|
92
|
+
Net::SSH.expects(:start).with(@server.host, "default-user", @options).returns(success = Object.new)
|
87
93
|
assert_equal success, Capistrano::SSH.connect(@server)
|
88
94
|
assert success.respond_to?(:xserver)
|
89
95
|
assert success.respond_to?(:xserver)
|
@@ -91,7 +97,7 @@ class SSHTest < Test::Unit::TestCase
|
|
91
97
|
end
|
92
98
|
|
93
99
|
def test_connect_should_not_retry_if_custom_auth_methods_are_given
|
94
|
-
Net::SSH.expects(:start).with(@server.host, @options.merge(:auth_methods => %w(publickey))).raises(Net::SSH::AuthenticationFailed)
|
100
|
+
Net::SSH.expects(:start).with(@server.host, "default-user", @options.merge(:auth_methods => %w(publickey))).raises(Net::SSH::AuthenticationFailed)
|
95
101
|
assert_raises(Net::SSH::AuthenticationFailed) { Capistrano::SSH.connect(@server, :ssh_options => { :auth_methods => %w(publickey) }) }
|
96
102
|
end
|
97
103
|
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
require 'utils'
|
2
|
+
require 'capistrano/transfer'
|
3
|
+
|
4
|
+
class TransferTest < Test::Unit::TestCase
|
5
|
+
def test_class_process_should_delegate_to_instance_process
|
6
|
+
Capistrano::Transfer.expects(:new).with(:up, "from", "to", %w(a b c), {}).returns(mock('transfer', :process! => nil)).yields
|
7
|
+
yielded = false
|
8
|
+
Capistrano::Transfer.process(:up, "from", "to", %w(a b c), {}) { yielded = true }
|
9
|
+
assert yielded
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_default_transport_is_sftp
|
13
|
+
transfer = Capistrano::Transfer.new(:up, "from", "to", [])
|
14
|
+
assert_equal :sftp, transfer.transport
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_active_is_true_when_any_sftp_transfers_are_active
|
18
|
+
returns = [false, false, true]
|
19
|
+
sessions = [session('app1', :sftp), session('app2', :sftp), session('app3', :sftp)].each { |s| s.xsftp.expects(:upload).returns(stub('operation', :active? => returns.shift)) }
|
20
|
+
transfer = Capistrano::Transfer.new(:up, "from", "to", sessions, :via => :sftp)
|
21
|
+
assert_equal true, transfer.active?
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_active_is_false_when_all_sftp_transfers_are_not_active
|
25
|
+
sessions = [session('app1', :sftp), session('app2', :sftp)].each { |s| s.xsftp.expects(:upload).returns(stub('operation', :active? => false)) }
|
26
|
+
transfer = Capistrano::Transfer.new(:up, "from", "to", sessions, :via => :sftp)
|
27
|
+
assert_equal false, transfer.active?
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_active_is_true_when_any_scp_transfers_are_active
|
31
|
+
returns = [false, false, true]
|
32
|
+
sessions = [session('app1', :scp), session('app2', :scp), session('app3', :scp)].each do |s|
|
33
|
+
channel = stub('channel', :[]= => nil, :active? => returns.shift)
|
34
|
+
s.scp.expects(:upload).returns(channel)
|
35
|
+
end
|
36
|
+
transfer = Capistrano::Transfer.new(:up, "from", "to", sessions, :via => :scp)
|
37
|
+
assert_equal true, transfer.active?
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_active_is_false_when_all_scp_transfers_are_not_active
|
41
|
+
sessions = [session('app1', :scp), session('app2', :scp), session('app3', :scp)].each do |s|
|
42
|
+
channel = stub('channel', :[]= => nil, :active? => false)
|
43
|
+
s.scp.expects(:upload).returns(channel)
|
44
|
+
end
|
45
|
+
transfer = Capistrano::Transfer.new(:up, "from", "to", sessions, :via => :scp)
|
46
|
+
assert_equal false, transfer.active?
|
47
|
+
end
|
48
|
+
|
49
|
+
[:up, :down].each do |direction|
|
50
|
+
define_method("test_sftp_#{direction}load_from_file_to_file_should_normalize_from_and_to") do
|
51
|
+
sessions = [session('app1', :sftp), session('app2', :sftp)]
|
52
|
+
|
53
|
+
sessions.each do |session|
|
54
|
+
session.xsftp.expects("#{direction}load".to_sym).with("from-#{session.xserver.host}", "to-#{session.xserver.host}",
|
55
|
+
:properties => { :server => session.xserver, :host => session.xserver.host })
|
56
|
+
end
|
57
|
+
|
58
|
+
transfer = Capistrano::Transfer.new(direction, "from-$CAPISTRANO:HOST$", "to-$CAPISTRANO:HOST$", sessions)
|
59
|
+
end
|
60
|
+
|
61
|
+
define_method("test_scp_#{direction}load_from_file_to_file_should_normalize_from_and_to") do
|
62
|
+
sessions = [session('app1', :scp), session('app2', :scp)]
|
63
|
+
|
64
|
+
sessions.each do |session|
|
65
|
+
session.scp.expects("#{direction}load".to_sym).returns({}).with("from-#{session.xserver.host}", "to-#{session.xserver.host}", :via => :scp)
|
66
|
+
end
|
67
|
+
|
68
|
+
transfer = Capistrano::Transfer.new(direction, "from-$CAPISTRANO:HOST$", "to-$CAPISTRANO:HOST$", sessions, :via => :scp)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_sftp_upload_from_IO_to_file_should_clone_the_IO_for_each_connection
|
73
|
+
sessions = [session('app1', :sftp), session('app2', :sftp)]
|
74
|
+
io = StringIO.new("from here")
|
75
|
+
|
76
|
+
sessions.each do |session|
|
77
|
+
session.xsftp.expects(:upload).with do |from, to, opts|
|
78
|
+
from != io && from.is_a?(StringIO) && from.string == io.string &&
|
79
|
+
to == "/to/here-#{session.xserver.host}" &&
|
80
|
+
opts[:properties][:server] == session.xserver &&
|
81
|
+
opts[:properties][:host] == session.xserver.host
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
transfer = Capistrano::Transfer.new(:up, StringIO.new("from here"), "/to/here-$CAPISTRANO:HOST$", sessions)
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_scp_upload_from_IO_to_file_should_clone_the_IO_for_each_connection
|
89
|
+
sessions = [session('app1', :scp), session('app2', :scp)]
|
90
|
+
io = StringIO.new("from here")
|
91
|
+
|
92
|
+
sessions.each do |session|
|
93
|
+
channel = mock('channel')
|
94
|
+
channel.expects(:[]=).with(:server, session.xserver)
|
95
|
+
channel.expects(:[]=).with(:host, session.xserver.host)
|
96
|
+
session.scp.expects(:upload).returns(channel).with do |from, to, opts|
|
97
|
+
from != io && from.is_a?(StringIO) && from.string == io.string &&
|
98
|
+
to == "/to/here-#{session.xserver.host}"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
transfer = Capistrano::Transfer.new(:up, StringIO.new("from here"), "/to/here-$CAPISTRANO:HOST$", sessions, :via => :scp)
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_process_should_block_until_transfer_is_no_longer_active
|
106
|
+
transfer = Capistrano::Transfer.new(:up, "from", "to", [])
|
107
|
+
transfer.expects(:process_iteration).times(4).yields.returns(true,true,true,false)
|
108
|
+
transfer.expects(:active?).times(4)
|
109
|
+
transfer.process!
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_errors_raised_for_a_sftp_session_should_abort_session_and_continue_with_remaining_sessions
|
113
|
+
s = session('app1')
|
114
|
+
error = ExceptionWithSession.new(s)
|
115
|
+
transfer = Capistrano::Transfer.new(:up, "from", "to", [])
|
116
|
+
transfer.expects(:process_iteration).raises(error).times(3).returns(true, false)
|
117
|
+
txfr = mock('transfer', :abort! => true)
|
118
|
+
txfr.expects(:[]=).with(:failed, true)
|
119
|
+
txfr.expects(:[]=).with(:error, error)
|
120
|
+
transfer.expects(:session_map).returns(s => txfr)
|
121
|
+
transfer.process!
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_errors_raised_for_a_scp_session_should_abort_session_and_continue_with_remaining_sessions
|
125
|
+
s = session('app1')
|
126
|
+
error = ExceptionWithSession.new(s)
|
127
|
+
transfer = Capistrano::Transfer.new(:up, "from", "to", [], :via => :scp)
|
128
|
+
transfer.expects(:process_iteration).raises(error).times(3).returns(true, false)
|
129
|
+
txfr = mock('channel', :close => true)
|
130
|
+
txfr.expects(:[]=).with(:failed, true)
|
131
|
+
txfr.expects(:[]=).with(:error, error)
|
132
|
+
transfer.expects(:session_map).returns(s => txfr)
|
133
|
+
transfer.process!
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
class ExceptionWithSession < ::Exception
|
139
|
+
attr_reader :session
|
140
|
+
|
141
|
+
def initialize(session)
|
142
|
+
@session = session
|
143
|
+
super()
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def session(host, mode=nil)
|
148
|
+
session = stub('session', :xserver => stub('server', :host => host))
|
149
|
+
case mode
|
150
|
+
when :sftp
|
151
|
+
sftp = stub('sftp')
|
152
|
+
session.expects(:sftp).with(false).returns(sftp)
|
153
|
+
sftp.expects(:connect).yields(sftp).returns(sftp)
|
154
|
+
session.stubs(:xsftp).returns(sftp)
|
155
|
+
when :scp
|
156
|
+
session.stubs(:scp).returns(stub('scp'))
|
157
|
+
end
|
158
|
+
session
|
159
|
+
end
|
160
|
+
end
|
data/test/utils.rb
CHANGED
@@ -1,42 +1,38 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
gem 'mocha'
|
7
|
-
rescue LoadError
|
8
|
-
end
|
9
|
-
|
10
|
-
require 'test/unit'
|
11
|
-
require 'mocha'
|
12
|
-
require 'capistrano/server_definition'
|
1
|
+
begin
|
2
|
+
require 'rubygems'
|
3
|
+
gem 'mocha'
|
4
|
+
rescue LoadError
|
5
|
+
end
|
13
6
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
7
|
+
require 'test/unit'
|
8
|
+
require 'mocha'
|
9
|
+
require 'capistrano/server_definition'
|
18
10
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
end
|
11
|
+
module TestExtensions
|
12
|
+
def server(host, options={})
|
13
|
+
Capistrano::ServerDefinition.new(host, options)
|
14
|
+
end
|
24
15
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
16
|
+
def namespace(fqn=nil)
|
17
|
+
space = stub(:roles => {}, :fully_qualified_name => fqn, :default_task => nil)
|
18
|
+
yield(space) if block_given?
|
19
|
+
space
|
20
|
+
end
|
30
21
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
return task
|
36
|
-
end
|
22
|
+
def role(space, name, *args)
|
23
|
+
opts = args.last.is_a?(Hash) ? args.pop : {}
|
24
|
+
space.roles[name] ||= []
|
25
|
+
space.roles[name].concat(args.map { |h| Capistrano::ServerDefinition.new(h, opts) })
|
37
26
|
end
|
38
27
|
|
39
|
-
|
40
|
-
|
28
|
+
def new_task(name, namespace=@namespace, options={}, &block)
|
29
|
+
block ||= Proc.new {}
|
30
|
+
task = Capistrano::TaskDefinition.new(name, namespace, options, &block)
|
31
|
+
assert_equal block, task.body
|
32
|
+
return task
|
41
33
|
end
|
42
34
|
end
|
35
|
+
|
36
|
+
class Test::Unit::TestCase
|
37
|
+
include TestExtensions
|
38
|
+
end
|
data/test/version_test.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: capistrano
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jamis Buck
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-02
|
12
|
+
date: 2008-05-02 00:00:00 -06:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -19,10 +19,7 @@ dependencies:
|
|
19
19
|
requirements:
|
20
20
|
- - ">="
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version:
|
23
|
-
- - <
|
24
|
-
- !ruby/object:Gem::Version
|
25
|
-
version: 1.99.0
|
22
|
+
version: 2.0.0
|
26
23
|
version:
|
27
24
|
- !ruby/object:Gem::Dependency
|
28
25
|
name: net-sftp
|
@@ -31,10 +28,25 @@ dependencies:
|
|
31
28
|
requirements:
|
32
29
|
- - ">="
|
33
30
|
- !ruby/object:Gem::Version
|
34
|
-
version:
|
35
|
-
|
31
|
+
version: 2.0.0
|
32
|
+
version:
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: net-scp
|
35
|
+
version_requirement:
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.0.0
|
41
|
+
version:
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: net-ssh-gateway
|
44
|
+
version_requirement:
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
36
48
|
- !ruby/object:Gem::Version
|
37
|
-
version: 1.
|
49
|
+
version: 1.0.0
|
38
50
|
version:
|
39
51
|
- !ruby/object:Gem::Dependency
|
40
52
|
name: highline
|
@@ -83,8 +95,8 @@ files:
|
|
83
95
|
- lib/capistrano/configuration.rb
|
84
96
|
- lib/capistrano/errors.rb
|
85
97
|
- lib/capistrano/extensions.rb
|
86
|
-
- lib/capistrano/gateway.rb
|
87
98
|
- lib/capistrano/logger.rb
|
99
|
+
- lib/capistrano/processable.rb
|
88
100
|
- lib/capistrano/recipes
|
89
101
|
- lib/capistrano/recipes/compat.rb
|
90
102
|
- lib/capistrano/recipes/deploy
|
@@ -99,6 +111,7 @@ files:
|
|
99
111
|
- lib/capistrano/recipes/deploy/scm/darcs.rb
|
100
112
|
- lib/capistrano/recipes/deploy/scm/git.rb
|
101
113
|
- lib/capistrano/recipes/deploy/scm/mercurial.rb
|
114
|
+
- lib/capistrano/recipes/deploy/scm/none.rb
|
102
115
|
- lib/capistrano/recipes/deploy/scm/perforce.rb
|
103
116
|
- lib/capistrano/recipes/deploy/scm/subversion.rb
|
104
117
|
- lib/capistrano/recipes/deploy/scm.rb
|
@@ -122,7 +135,7 @@ files:
|
|
122
135
|
- lib/capistrano/shell.rb
|
123
136
|
- lib/capistrano/ssh.rb
|
124
137
|
- lib/capistrano/task_definition.rb
|
125
|
-
- lib/capistrano/
|
138
|
+
- lib/capistrano/transfer.rb
|
126
139
|
- lib/capistrano/version.rb
|
127
140
|
- lib/capistrano.rb
|
128
141
|
- examples/sample.rb
|
@@ -160,13 +173,12 @@ files:
|
|
160
173
|
- test/fixtures/cli_integration.rb
|
161
174
|
- test/fixtures/config.rb
|
162
175
|
- test/fixtures/custom.rb
|
163
|
-
- test/gateway_test.rb
|
164
176
|
- test/logger_test.rb
|
165
177
|
- test/server_definition_test.rb
|
166
178
|
- test/shell_test.rb
|
167
179
|
- test/ssh_test.rb
|
168
180
|
- test/task_definition_test.rb
|
169
|
-
- test/
|
181
|
+
- test/transfer_test.rb
|
170
182
|
- test/utils.rb
|
171
183
|
- test/version_test.rb
|
172
184
|
- README
|
@@ -194,7 +206,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
194
206
|
requirements: []
|
195
207
|
|
196
208
|
rubyforge_project: capistrano
|
197
|
-
rubygems_version: 1.
|
209
|
+
rubygems_version: 1.1.1
|
198
210
|
signing_key:
|
199
211
|
specification_version: 2
|
200
212
|
summary: Capistrano is a utility and framework for executing commands in parallel on multiple remote machines, via SSH.
|
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
|