capistrano 2.8.0 → 3.19.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.docker/Dockerfile +7 -0
- data/.docker/ssh_key_rsa +49 -0
- data/.docker/ssh_key_rsa.pub +1 -0
- data/.docker/ubuntu_setup.sh +23 -0
- data/.github/issue_template.md +19 -0
- data/.github/pull_request_template.md +22 -0
- data/.github/release-drafter.yml +25 -0
- data/.github/workflows/ci.yml +80 -0
- data/.github/workflows/release-drafter.yml +18 -0
- data/.gitignore +23 -8
- data/.rubocop.yml +62 -0
- data/CHANGELOG.md +1 -0
- data/CONTRIBUTING.md +63 -0
- data/DEVELOPMENT.md +112 -0
- data/Gemfile +42 -9
- data/LICENSE.txt +21 -0
- data/README.md +221 -0
- data/RELEASING.md +17 -0
- data/Rakefile +17 -8
- data/UPGRADING-3.7.md +86 -0
- data/bin/cap +2 -3
- data/bin/capify +7 -89
- data/capistrano.gemspec +29 -43
- data/docker-compose.yml +8 -0
- data/features/configuration.feature +28 -0
- data/features/deploy.feature +92 -0
- data/features/deploy_failure.feature +17 -0
- data/features/doctor.feature +11 -0
- data/features/installation.feature +21 -0
- data/features/sshconnect.feature +11 -0
- data/features/stage_failure.feature +9 -0
- data/features/step_definitions/assertions.rb +162 -0
- data/features/step_definitions/cap_commands.rb +21 -0
- data/features/step_definitions/setup.rb +91 -0
- data/features/subdirectory.feature +9 -0
- data/features/support/docker_gateway.rb +53 -0
- data/features/support/env.rb +1 -0
- data/features/support/remote_command_helpers.rb +29 -0
- data/features/support/remote_ssh_helpers.rb +33 -0
- data/lib/Capfile +3 -0
- data/lib/capistrano/all.rb +17 -0
- data/lib/capistrano/application.rb +153 -0
- data/lib/capistrano/configuration/empty_filter.rb +9 -0
- data/lib/capistrano/configuration/filter.rb +26 -0
- data/lib/capistrano/configuration/host_filter.rb +29 -0
- data/lib/capistrano/configuration/null_filter.rb +9 -0
- data/lib/capistrano/configuration/plugin_installer.rb +51 -0
- data/lib/capistrano/configuration/question.rb +76 -0
- data/lib/capistrano/configuration/role_filter.rb +29 -0
- data/lib/capistrano/configuration/scm_resolver.rb +149 -0
- data/lib/capistrano/configuration/server.rb +137 -0
- data/lib/capistrano/configuration/servers.rb +56 -96
- data/lib/capistrano/configuration/validated_variables.rb +110 -0
- data/lib/capistrano/configuration/variables.rb +79 -94
- data/lib/capistrano/configuration.rb +178 -33
- data/lib/capistrano/console.rb +1 -0
- data/lib/capistrano/defaults.rb +36 -0
- data/lib/capistrano/deploy.rb +3 -0
- data/lib/capistrano/doctor/environment_doctor.rb +19 -0
- data/lib/capistrano/doctor/gems_doctor.rb +45 -0
- data/lib/capistrano/doctor/output_helpers.rb +79 -0
- data/lib/capistrano/doctor/servers_doctor.rb +105 -0
- data/lib/capistrano/doctor/variables_doctor.rb +74 -0
- data/lib/capistrano/doctor.rb +6 -0
- data/lib/capistrano/dotfile.rb +2 -0
- data/lib/capistrano/dsl/env.rb +43 -0
- data/lib/capistrano/dsl/paths.rb +89 -0
- data/lib/capistrano/dsl/stages.rb +31 -0
- data/lib/capistrano/dsl/task_enhancements.rb +61 -0
- data/lib/capistrano/dsl.rb +95 -0
- data/lib/capistrano/framework.rb +2 -0
- data/lib/capistrano/i18n.rb +46 -0
- data/lib/capistrano/immutable_task.rb +30 -0
- data/lib/capistrano/install.rb +1 -0
- data/lib/capistrano/plugin.rb +95 -0
- data/lib/capistrano/proc_helpers.rb +13 -0
- data/lib/capistrano/scm/git.rb +105 -0
- data/lib/capistrano/scm/hg.rb +55 -0
- data/lib/capistrano/scm/plugin.rb +13 -0
- data/lib/capistrano/scm/svn.rb +56 -0
- data/lib/capistrano/scm/tasks/git.rake +84 -0
- data/lib/capistrano/scm/tasks/hg.rake +53 -0
- data/lib/capistrano/scm/tasks/svn.rake +53 -0
- data/lib/capistrano/scm.rb +115 -0
- data/lib/capistrano/setup.rb +36 -0
- data/lib/capistrano/tasks/console.rake +25 -0
- data/lib/capistrano/tasks/deploy.rake +280 -0
- data/lib/capistrano/tasks/doctor.rake +24 -0
- data/lib/capistrano/tasks/framework.rake +67 -0
- data/lib/capistrano/tasks/install.rake +41 -0
- data/lib/capistrano/templates/Capfile +38 -0
- data/lib/capistrano/templates/deploy.rb.erb +39 -0
- data/lib/capistrano/templates/stage.rb.erb +61 -0
- data/lib/capistrano/upload_task.rb +9 -0
- data/lib/capistrano/version.rb +1 -14
- data/lib/capistrano/version_validator.rb +32 -0
- data/lib/capistrano.rb +0 -3
- data/spec/integration/dsl_spec.rb +632 -0
- data/spec/integration_spec_helper.rb +5 -0
- data/spec/lib/capistrano/application_spec.rb +60 -0
- data/spec/lib/capistrano/configuration/empty_filter_spec.rb +17 -0
- data/spec/lib/capistrano/configuration/filter_spec.rb +109 -0
- data/spec/lib/capistrano/configuration/host_filter_spec.rb +71 -0
- data/spec/lib/capistrano/configuration/null_filter_spec.rb +17 -0
- data/spec/lib/capistrano/configuration/plugin_installer_spec.rb +98 -0
- data/spec/lib/capistrano/configuration/question_spec.rb +92 -0
- data/spec/lib/capistrano/configuration/role_filter_spec.rb +80 -0
- data/spec/lib/capistrano/configuration/scm_resolver_spec.rb +56 -0
- data/spec/lib/capistrano/configuration/server_spec.rb +309 -0
- data/spec/lib/capistrano/configuration/servers_spec.rb +331 -0
- data/spec/lib/capistrano/configuration_spec.rb +357 -0
- data/spec/lib/capistrano/doctor/environment_doctor_spec.rb +44 -0
- data/spec/lib/capistrano/doctor/gems_doctor_spec.rb +67 -0
- data/spec/lib/capistrano/doctor/output_helpers_spec.rb +47 -0
- data/spec/lib/capistrano/doctor/servers_doctor_spec.rb +86 -0
- data/spec/lib/capistrano/doctor/variables_doctor_spec.rb +89 -0
- data/spec/lib/capistrano/dsl/paths_spec.rb +228 -0
- data/spec/lib/capistrano/dsl/task_enhancements_spec.rb +108 -0
- data/spec/lib/capistrano/dsl_spec.rb +125 -0
- data/spec/lib/capistrano/immutable_task_spec.rb +31 -0
- data/spec/lib/capistrano/plugin_spec.rb +84 -0
- data/spec/lib/capistrano/scm/git_spec.rb +194 -0
- data/spec/lib/capistrano/scm/hg_spec.rb +109 -0
- data/spec/lib/capistrano/scm/svn_spec.rb +137 -0
- data/spec/lib/capistrano/scm_spec.rb +103 -0
- data/spec/lib/capistrano/upload_task_spec.rb +19 -0
- data/spec/lib/capistrano/version_validator_spec.rb +118 -0
- data/spec/lib/capistrano_spec.rb +7 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/support/matchers.rb +5 -0
- data/spec/support/tasks/database.rake +11 -0
- data/spec/support/tasks/fail.rake +8 -0
- data/spec/support/tasks/failed.rake +5 -0
- data/spec/support/tasks/plugin.rake +6 -0
- data/spec/support/tasks/root.rake +11 -0
- data/spec/support/test_app.rb +205 -0
- metadata +234 -208
- data/.rvmrc +0 -1
- data/CHANGELOG +0 -954
- data/README.mdown +0 -76
- data/lib/capistrano/callback.rb +0 -45
- data/lib/capistrano/cli/execute.rb +0 -85
- data/lib/capistrano/cli/help.rb +0 -125
- data/lib/capistrano/cli/help.txt +0 -81
- data/lib/capistrano/cli/options.rb +0 -243
- data/lib/capistrano/cli/ui.rb +0 -40
- data/lib/capistrano/cli.rb +0 -47
- data/lib/capistrano/command.rb +0 -286
- data/lib/capistrano/configuration/actions/file_transfer.rb +0 -51
- data/lib/capistrano/configuration/actions/inspect.rb +0 -46
- data/lib/capistrano/configuration/actions/invocation.rb +0 -298
- data/lib/capistrano/configuration/callbacks.rb +0 -148
- data/lib/capistrano/configuration/connections.rb +0 -230
- data/lib/capistrano/configuration/execution.rb +0 -143
- data/lib/capistrano/configuration/loading.rb +0 -197
- data/lib/capistrano/configuration/namespaces.rb +0 -197
- data/lib/capistrano/configuration/roles.rb +0 -73
- data/lib/capistrano/errors.rb +0 -19
- data/lib/capistrano/ext/string.rb +0 -5
- data/lib/capistrano/extensions.rb +0 -57
- data/lib/capistrano/logger.rb +0 -59
- data/lib/capistrano/processable.rb +0 -53
- data/lib/capistrano/recipes/compat.rb +0 -32
- data/lib/capistrano/recipes/deploy/assets.rb +0 -57
- data/lib/capistrano/recipes/deploy/dependencies.rb +0 -44
- data/lib/capistrano/recipes/deploy/local_dependency.rb +0 -54
- data/lib/capistrano/recipes/deploy/remote_dependency.rb +0 -111
- data/lib/capistrano/recipes/deploy/scm/accurev.rb +0 -169
- data/lib/capistrano/recipes/deploy/scm/base.rb +0 -196
- data/lib/capistrano/recipes/deploy/scm/bzr.rb +0 -86
- data/lib/capistrano/recipes/deploy/scm/cvs.rb +0 -153
- data/lib/capistrano/recipes/deploy/scm/darcs.rb +0 -96
- data/lib/capistrano/recipes/deploy/scm/git.rb +0 -282
- data/lib/capistrano/recipes/deploy/scm/mercurial.rb +0 -137
- data/lib/capistrano/recipes/deploy/scm/none.rb +0 -44
- data/lib/capistrano/recipes/deploy/scm/perforce.rb +0 -138
- data/lib/capistrano/recipes/deploy/scm/subversion.rb +0 -121
- data/lib/capistrano/recipes/deploy/scm.rb +0 -19
- data/lib/capistrano/recipes/deploy/strategy/base.rb +0 -88
- data/lib/capistrano/recipes/deploy/strategy/checkout.rb +0 -20
- data/lib/capistrano/recipes/deploy/strategy/copy.rb +0 -224
- 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 -57
- 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 -568
- data/lib/capistrano/recipes/standard.rb +0 -37
- data/lib/capistrano/recipes/templates/maintenance.rhtml +0 -53
- data/lib/capistrano/role.rb +0 -102
- data/lib/capistrano/server_definition.rb +0 -56
- data/lib/capistrano/shell.rb +0 -260
- data/lib/capistrano/ssh.rb +0 -101
- data/lib/capistrano/task_definition.rb +0 -75
- data/lib/capistrano/transfer.rb +0 -216
- data/rvmrc.sample +0 -1
- data/test/cli/execute_test.rb +0 -132
- data/test/cli/help_test.rb +0 -165
- data/test/cli/options_test.rb +0 -329
- data/test/cli/ui_test.rb +0 -28
- data/test/cli_test.rb +0 -17
- data/test/command_test.rb +0 -289
- data/test/configuration/actions/file_transfer_test.rb +0 -61
- data/test/configuration/actions/inspect_test.rb +0 -65
- data/test/configuration/actions/invocation_test.rb +0 -247
- data/test/configuration/callbacks_test.rb +0 -220
- data/test/configuration/connections_test.rb +0 -420
- data/test/configuration/execution_test.rb +0 -175
- data/test/configuration/loading_test.rb +0 -132
- data/test/configuration/namespace_dsl_test.rb +0 -311
- data/test/configuration/roles_test.rb +0 -144
- data/test/configuration/servers_test.rb +0 -183
- data/test/configuration/variables_test.rb +0 -190
- data/test/configuration_test.rb +0 -88
- data/test/deploy/local_dependency_test.rb +0 -76
- data/test/deploy/remote_dependency_test.rb +0 -135
- data/test/deploy/scm/accurev_test.rb +0 -23
- data/test/deploy/scm/base_test.rb +0 -55
- data/test/deploy/scm/bzr_test.rb +0 -51
- data/test/deploy/scm/darcs_test.rb +0 -37
- data/test/deploy/scm/git_test.rb +0 -184
- data/test/deploy/scm/mercurial_test.rb +0 -134
- data/test/deploy/scm/none_test.rb +0 -35
- data/test/deploy/scm/subversion_test.rb +0 -32
- data/test/deploy/strategy/copy_test.rb +0 -321
- 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/logger_test.rb +0 -123
- data/test/recipes_test.rb +0 -25
- data/test/role_test.rb +0 -11
- data/test/server_definition_test.rb +0 -121
- data/test/shell_test.rb +0 -90
- data/test/ssh_test.rb +0 -113
- data/test/task_definition_test.rb +0 -116
- data/test/transfer_test.rb +0 -160
- data/test/utils.rb +0 -37
data/lib/capistrano/role.rb
DELETED
@@ -1,102 +0,0 @@
|
|
1
|
-
module Capistrano
|
2
|
-
class Role
|
3
|
-
include Enumerable
|
4
|
-
|
5
|
-
def initialize(*list)
|
6
|
-
@static_servers = []
|
7
|
-
@dynamic_servers = []
|
8
|
-
push(*list)
|
9
|
-
end
|
10
|
-
|
11
|
-
def each(&block)
|
12
|
-
servers.each &block
|
13
|
-
end
|
14
|
-
|
15
|
-
def push(*list)
|
16
|
-
options = list.last.is_a?(Hash) ? list.pop : {}
|
17
|
-
list.each do |item|
|
18
|
-
if item.respond_to?(:call)
|
19
|
-
@dynamic_servers << DynamicServerList.new(item, options)
|
20
|
-
else
|
21
|
-
@static_servers << self.class.wrap_server(item, options)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
alias_method :<<, :push
|
26
|
-
|
27
|
-
def servers
|
28
|
-
@static_servers + dynamic_servers
|
29
|
-
end
|
30
|
-
alias_method :to_ary, :servers
|
31
|
-
|
32
|
-
def empty?
|
33
|
-
servers.empty?
|
34
|
-
end
|
35
|
-
|
36
|
-
def clear
|
37
|
-
@dynamic_servers.clear
|
38
|
-
@static_servers.clear
|
39
|
-
end
|
40
|
-
|
41
|
-
def include?(server)
|
42
|
-
servers.include?(server)
|
43
|
-
end
|
44
|
-
|
45
|
-
protected
|
46
|
-
|
47
|
-
# This is the combination of a block, a hash of options, and a cached value.
|
48
|
-
class DynamicServerList
|
49
|
-
def initialize (block, options)
|
50
|
-
@block = block
|
51
|
-
@options = options
|
52
|
-
@cached = []
|
53
|
-
@is_cached = false
|
54
|
-
end
|
55
|
-
|
56
|
-
# Convert to a list of ServerDefinitions
|
57
|
-
def to_ary
|
58
|
-
unless @is_cached
|
59
|
-
@cached = Role::wrap_list(@block.call(@options), @options)
|
60
|
-
@is_cached = true
|
61
|
-
end
|
62
|
-
@cached
|
63
|
-
end
|
64
|
-
|
65
|
-
# Clear the cached value
|
66
|
-
def reset!
|
67
|
-
@cached.clear
|
68
|
-
@is_cached = false
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
# Attribute reader for the cached results of executing the blocks in turn
|
73
|
-
def dynamic_servers
|
74
|
-
@dynamic_servers.inject([]) { |list, item| list.concat item }
|
75
|
-
end
|
76
|
-
|
77
|
-
# Wraps a string in a ServerDefinition, if it isn't already.
|
78
|
-
# This and wrap_list should probably go in ServerDefinition in some form.
|
79
|
-
def self.wrap_server (item, options)
|
80
|
-
item.is_a?(ServerDefinition) ? item : ServerDefinition.new(item, options)
|
81
|
-
end
|
82
|
-
|
83
|
-
# Turns a list, or something resembling a list, into a properly-formatted
|
84
|
-
# ServerDefinition list. Keep an eye on this one -- it's entirely too
|
85
|
-
# magical for its own good. In particular, if ServerDefinition ever inherits
|
86
|
-
# from Array, this will break.
|
87
|
-
def self.wrap_list (*list)
|
88
|
-
options = list.last.is_a?(Hash) ? list.pop : {}
|
89
|
-
if list.length == 1
|
90
|
-
if list.first.nil?
|
91
|
-
return []
|
92
|
-
elsif list.first.is_a?(Array)
|
93
|
-
list = list.first
|
94
|
-
end
|
95
|
-
end
|
96
|
-
options.merge! list.pop if list.last.is_a?(Hash)
|
97
|
-
list.map do |item|
|
98
|
-
self.wrap_server item, options
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
@@ -1,56 +0,0 @@
|
|
1
|
-
module Capistrano
|
2
|
-
class ServerDefinition
|
3
|
-
include Comparable
|
4
|
-
|
5
|
-
attr_reader :host
|
6
|
-
attr_reader :user
|
7
|
-
attr_reader :port
|
8
|
-
attr_reader :options
|
9
|
-
|
10
|
-
# The default user name to use when a user name is not explicitly provided
|
11
|
-
def self.default_user
|
12
|
-
ENV['USER'] || ENV['USERNAME'] || "not-specified"
|
13
|
-
end
|
14
|
-
|
15
|
-
def initialize(string, options={})
|
16
|
-
@user, @host, @port = string.match(/^(?:([^;,:=]+)@|)(.*?)(?::(\d+)|)$/)[1,3]
|
17
|
-
|
18
|
-
@options = options.dup
|
19
|
-
user_opt, port_opt = @options.delete(:user), @options.delete(:port)
|
20
|
-
|
21
|
-
@user ||= user_opt
|
22
|
-
@port ||= port_opt
|
23
|
-
|
24
|
-
@port = @port.to_i if @port
|
25
|
-
end
|
26
|
-
|
27
|
-
def <=>(server)
|
28
|
-
[host, port, user] <=> [server.host, server.port, server.user]
|
29
|
-
end
|
30
|
-
|
31
|
-
# Redefined, so that Array#uniq will work to remove duplicate server
|
32
|
-
# definitions, based solely on their host names.
|
33
|
-
def eql?(server)
|
34
|
-
host == server.host &&
|
35
|
-
user == server.user &&
|
36
|
-
port == server.port
|
37
|
-
end
|
38
|
-
|
39
|
-
alias :== :eql?
|
40
|
-
|
41
|
-
# Redefined, so that Array#uniq will work to remove duplicate server
|
42
|
-
# definitions, based on their connection information.
|
43
|
-
def hash
|
44
|
-
@hash ||= [host, user, port].hash
|
45
|
-
end
|
46
|
-
|
47
|
-
def to_s
|
48
|
-
@to_s ||= begin
|
49
|
-
s = host
|
50
|
-
s = "#{user}@#{s}" if user
|
51
|
-
s = "#{s}:#{port}" if port && port != 22
|
52
|
-
s
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
data/lib/capistrano/shell.rb
DELETED
@@ -1,260 +0,0 @@
|
|
1
|
-
require 'thread'
|
2
|
-
require 'capistrano/processable'
|
3
|
-
|
4
|
-
module Capistrano
|
5
|
-
# The Capistrano::Shell class is the guts of the "shell" task. It implements
|
6
|
-
# an interactive REPL interface that users can employ to execute tasks and
|
7
|
-
# commands. It makes for a GREAT way to monitor systems, and perform quick
|
8
|
-
# maintenance on one or more machines.
|
9
|
-
class Shell
|
10
|
-
include Processable
|
11
|
-
|
12
|
-
# A Readline replacement for platforms where readline is either
|
13
|
-
# unavailable, or has not been installed.
|
14
|
-
class ReadlineFallback #:nodoc:
|
15
|
-
HISTORY = []
|
16
|
-
|
17
|
-
def self.readline(prompt)
|
18
|
-
STDOUT.print(prompt)
|
19
|
-
STDOUT.flush
|
20
|
-
STDIN.gets
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
# The configuration instance employed by this shell
|
25
|
-
attr_reader :configuration
|
26
|
-
|
27
|
-
# Instantiate a new shell and begin executing it immediately.
|
28
|
-
def self.run(config)
|
29
|
-
new(config).run!
|
30
|
-
end
|
31
|
-
|
32
|
-
# Instantiate a new shell
|
33
|
-
def initialize(config)
|
34
|
-
@configuration = config
|
35
|
-
end
|
36
|
-
|
37
|
-
# Start the shell running. This method will block until the shell
|
38
|
-
# terminates.
|
39
|
-
def run!
|
40
|
-
setup
|
41
|
-
|
42
|
-
puts <<-INTRO
|
43
|
-
====================================================================
|
44
|
-
Welcome to the interactive Capistrano shell! This is an experimental
|
45
|
-
feature, and is liable to change in future releases. Type 'help' for
|
46
|
-
a summary of how to use the shell.
|
47
|
-
--------------------------------------------------------------------
|
48
|
-
INTRO
|
49
|
-
|
50
|
-
loop do
|
51
|
-
break if !read_and_execute
|
52
|
-
end
|
53
|
-
|
54
|
-
@bgthread.kill
|
55
|
-
end
|
56
|
-
|
57
|
-
def read_and_execute
|
58
|
-
command = read_line
|
59
|
-
|
60
|
-
case command
|
61
|
-
when "?", "help" then help
|
62
|
-
when "quit", "exit" then
|
63
|
-
puts "exiting"
|
64
|
-
return false
|
65
|
-
when /^set -(\w)\s*(\S+)/
|
66
|
-
set_option($1, $2)
|
67
|
-
when /^(?:(with|on)\s*(\S+))?\s*(\S.*)?/i
|
68
|
-
process_command($1, $2, $3)
|
69
|
-
else
|
70
|
-
raise "eh?"
|
71
|
-
end
|
72
|
-
|
73
|
-
return true
|
74
|
-
end
|
75
|
-
|
76
|
-
private
|
77
|
-
|
78
|
-
# Present the prompt and read a single line from the console. It also
|
79
|
-
# detects ^D and returns "exit" in that case. Adds the input to the
|
80
|
-
# history, unless the input is empty. Loops repeatedly until a non-empty
|
81
|
-
# line is input.
|
82
|
-
def read_line
|
83
|
-
loop do
|
84
|
-
command = reader.readline("cap> ")
|
85
|
-
|
86
|
-
if command.nil?
|
87
|
-
command = "exit"
|
88
|
-
puts(command)
|
89
|
-
else
|
90
|
-
command.strip!
|
91
|
-
end
|
92
|
-
|
93
|
-
unless command.empty?
|
94
|
-
reader::HISTORY << command
|
95
|
-
return command
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
# Display a verbose help message.
|
101
|
-
def help
|
102
|
-
puts <<-HELP
|
103
|
-
--- HELP! ---------------------------------------------------
|
104
|
-
"Get me out of this thing. I just want to quit."
|
105
|
-
-> Easy enough. Just type "exit", or "quit". Or press ctrl-D.
|
106
|
-
|
107
|
-
"I want to execute a command on all servers."
|
108
|
-
-> Just type the command, and press enter. It will be passed,
|
109
|
-
verbatim, to all defined servers.
|
110
|
-
|
111
|
-
"What if I only want it to execute on a subset of them?"
|
112
|
-
-> No problem, just specify the list of servers, separated by
|
113
|
-
commas, before the command, with the `on' keyword:
|
114
|
-
|
115
|
-
cap> on app1.foo.com,app2.foo.com echo ping
|
116
|
-
|
117
|
-
"Nice, but can I specify the servers by role?"
|
118
|
-
-> You sure can. Just use the `with' keyword, followed by the
|
119
|
-
comma-delimited list of role names:
|
120
|
-
|
121
|
-
cap> with app,db echo ping
|
122
|
-
|
123
|
-
"Can I execute a Capistrano task from within this shell?"
|
124
|
-
-> Yup. Just prefix the task with an exclamation mark:
|
125
|
-
|
126
|
-
cap> !deploy
|
127
|
-
HELP
|
128
|
-
end
|
129
|
-
|
130
|
-
# Determine which servers the given task requires a connection to, and
|
131
|
-
# establish connections to them if necessary. Return the list of
|
132
|
-
# servers (names).
|
133
|
-
def connect(task)
|
134
|
-
servers = configuration.find_servers_for_task(task)
|
135
|
-
needing_connections = servers - configuration.sessions.keys
|
136
|
-
unless needing_connections.empty?
|
137
|
-
puts "[establishing connection(s) to #{needing_connections.join(', ')}]"
|
138
|
-
configuration.establish_connections_to(needing_connections)
|
139
|
-
end
|
140
|
-
servers
|
141
|
-
end
|
142
|
-
|
143
|
-
# Execute the given command. If the command is prefixed by an exclamation
|
144
|
-
# mark, it is assumed to refer to another capistrano task, which will
|
145
|
-
# be invoked. Otherwise, it is executed as a command on all associated
|
146
|
-
# servers.
|
147
|
-
def exec(command)
|
148
|
-
@mutex.synchronize do
|
149
|
-
if command[0] == ?!
|
150
|
-
exec_tasks(command[1..-1].split)
|
151
|
-
else
|
152
|
-
servers = connect(configuration.current_task)
|
153
|
-
exec_command(command, servers)
|
154
|
-
end
|
155
|
-
end
|
156
|
-
ensure
|
157
|
-
STDOUT.flush
|
158
|
-
end
|
159
|
-
|
160
|
-
# Given an array of task names, invoke them in sequence.
|
161
|
-
def exec_tasks(list)
|
162
|
-
list.each do |task_name|
|
163
|
-
task = configuration.find_task(task_name)
|
164
|
-
raise Capistrano::NoSuchTaskError, "no such task `#{task_name}'" unless task
|
165
|
-
connect(task)
|
166
|
-
configuration.execute_task(task)
|
167
|
-
end
|
168
|
-
rescue Capistrano::NoMatchingServersError, Capistrano::NoSuchTaskError => error
|
169
|
-
warn "error: #{error.message}"
|
170
|
-
end
|
171
|
-
|
172
|
-
# Execute a command on the given list of servers.
|
173
|
-
def exec_command(command, servers)
|
174
|
-
command = command.gsub(/\bsudo\b/, "sudo -p '#{configuration.sudo_prompt}'")
|
175
|
-
processor = configuration.sudo_behavior_callback(Configuration.default_io_proc)
|
176
|
-
sessions = servers.map { |server| configuration.sessions[server] }
|
177
|
-
options = configuration.add_default_command_options({})
|
178
|
-
cmd = Command.new(command, sessions, options.merge(:logger => configuration.logger), &processor)
|
179
|
-
previous = trap("INT") { cmd.stop! }
|
180
|
-
cmd.process!
|
181
|
-
rescue Capistrano::Error => error
|
182
|
-
warn "error: #{error.message}"
|
183
|
-
ensure
|
184
|
-
trap("INT", previous)
|
185
|
-
end
|
186
|
-
|
187
|
-
# Return the object that will be used to query input from the console.
|
188
|
-
# The returned object will quack (more or less) like Readline.
|
189
|
-
def reader
|
190
|
-
@reader ||= begin
|
191
|
-
require 'readline'
|
192
|
-
Readline
|
193
|
-
rescue LoadError
|
194
|
-
ReadlineFallback
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
# Prepare every little thing for the shell. Starts the background
|
199
|
-
# thread and generally gets things ready for the REPL.
|
200
|
-
def setup
|
201
|
-
configuration.logger.level = Capistrano::Logger::INFO
|
202
|
-
|
203
|
-
@mutex = Mutex.new
|
204
|
-
@bgthread = Thread.new do
|
205
|
-
loop do
|
206
|
-
@mutex.synchronize { process_iteration(0.1) }
|
207
|
-
end
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
# Set the given option to +value+.
|
212
|
-
def set_option(opt, value)
|
213
|
-
case opt
|
214
|
-
when "v" then
|
215
|
-
puts "setting log verbosity to #{value.to_i}"
|
216
|
-
configuration.logger.level = value.to_i
|
217
|
-
when "o" then
|
218
|
-
case value
|
219
|
-
when "vi" then
|
220
|
-
puts "using vi edit mode"
|
221
|
-
reader.vi_editing_mode
|
222
|
-
when "emacs" then
|
223
|
-
puts "using emacs edit mode"
|
224
|
-
reader.emacs_editing_mode
|
225
|
-
else
|
226
|
-
puts "unknown -o option #{value.inspect}"
|
227
|
-
end
|
228
|
-
else
|
229
|
-
puts "unknown setting #{opt.inspect}"
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
|
-
# Process a command. Interprets the scope_type (must be nil, "with", or
|
234
|
-
# "on") and the command. If no command is given, then the scope is made
|
235
|
-
# effective for all subsequent commands. If the scope value is "all",
|
236
|
-
# then the scope is unrestricted.
|
237
|
-
def process_command(scope_type, scope_value, command)
|
238
|
-
env_var = case scope_type
|
239
|
-
when "with" then "ROLES"
|
240
|
-
when "on" then "HOSTS"
|
241
|
-
end
|
242
|
-
|
243
|
-
old_var, ENV[env_var] = ENV[env_var], (scope_value == "all" ? nil : scope_value) if env_var
|
244
|
-
if command
|
245
|
-
begin
|
246
|
-
exec(command)
|
247
|
-
ensure
|
248
|
-
ENV[env_var] = old_var if env_var
|
249
|
-
end
|
250
|
-
else
|
251
|
-
puts "scoping #{scope_type} #{scope_value}"
|
252
|
-
end
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
|
-
# All open sessions, needed to satisfy the Command::Processable include
|
257
|
-
def sessions
|
258
|
-
configuration.sessions.values
|
259
|
-
end
|
260
|
-
end
|
data/lib/capistrano/ssh.rb
DELETED
@@ -1,101 +0,0 @@
|
|
1
|
-
begin
|
2
|
-
require 'rubygems'
|
3
|
-
gem 'net-ssh', ">= 2.0.10"
|
4
|
-
rescue LoadError, NameError
|
5
|
-
end
|
6
|
-
|
7
|
-
require 'net/ssh'
|
8
|
-
|
9
|
-
module Capistrano
|
10
|
-
# A helper class for dealing with SSH connections.
|
11
|
-
class SSH
|
12
|
-
# Patch an accessor onto an SSH connection so that we can record the server
|
13
|
-
# definition object that defines the connection. This is useful because
|
14
|
-
# the gateway returns connections whose "host" is 127.0.0.1, instead of
|
15
|
-
# the host on the other side of the tunnel.
|
16
|
-
module Server #:nodoc:
|
17
|
-
def self.apply_to(connection, server)
|
18
|
-
connection.extend(Server)
|
19
|
-
connection.xserver = server
|
20
|
-
connection
|
21
|
-
end
|
22
|
-
|
23
|
-
attr_accessor :xserver
|
24
|
-
end
|
25
|
-
|
26
|
-
# An abstraction to make it possible to connect to the server via public key
|
27
|
-
# without prompting for the password. If the public key authentication fails
|
28
|
-
# this will fall back to password authentication.
|
29
|
-
#
|
30
|
-
# +server+ must be an instance of ServerDefinition.
|
31
|
-
#
|
32
|
-
# If a block is given, the new session is yielded to it, otherwise the new
|
33
|
-
# session is returned.
|
34
|
-
#
|
35
|
-
# If an :ssh_options key exists in +options+, it is passed to the Net::SSH
|
36
|
-
# constructor. Values in +options+ are then merged into it, and any
|
37
|
-
# connection information in +server+ is added last, so that +server+ info
|
38
|
-
# takes precedence over +options+, which takes precendence over ssh_options.
|
39
|
-
def self.connect(server, options={})
|
40
|
-
connection_strategy(server, options) do |host, user, connection_options|
|
41
|
-
connection = Net::SSH.start(host, user, connection_options)
|
42
|
-
Server.apply_to(connection, server)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
# Abstracts the logic for establishing an SSH connection (which includes
|
47
|
-
# testing for connection failures and retrying with a password, and so forth,
|
48
|
-
# mostly made complicated because of the fact that some of these variables
|
49
|
-
# might be lazily evaluated and try to do something like prompt the user,
|
50
|
-
# which should only happen when absolutely necessary.
|
51
|
-
#
|
52
|
-
# This will yield the hostname, username, and a hash of connection options
|
53
|
-
# to the given block, which should return a new connection.
|
54
|
-
def self.connection_strategy(server, options={}, &block)
|
55
|
-
methods = [ %w(publickey hostbased), %w(password keyboard-interactive) ]
|
56
|
-
password_value = nil
|
57
|
-
|
58
|
-
# construct the hash of ssh options that should be passed more-or-less
|
59
|
-
# directly to Net::SSH. This will be the general ssh options, merged with
|
60
|
-
# the server-specific ssh-options.
|
61
|
-
ssh_options = (options[:ssh_options] || {}).merge(server.options[:ssh_options] || {})
|
62
|
-
|
63
|
-
# load any SSH configuration files that were specified in the SSH options. This
|
64
|
-
# will load from ~/.ssh/config and /etc/ssh_config by default (see Net::SSH
|
65
|
-
# for details). Merge the explicitly given ssh_options over the top of the info
|
66
|
-
# from the config file.
|
67
|
-
ssh_options = Net::SSH.configuration_for(server.host, ssh_options.fetch(:config, true)).merge(ssh_options)
|
68
|
-
|
69
|
-
# Once we've loaded the config, we don't need Net::SSH to do it again.
|
70
|
-
ssh_options[:config] = false
|
71
|
-
|
72
|
-
ssh_options[:verbose] = :debug if options[:verbose] && options[:verbose] > 0
|
73
|
-
|
74
|
-
user = server.user || options[:user] || ssh_options[:username] ||
|
75
|
-
ssh_options[:user] || ServerDefinition.default_user
|
76
|
-
port = server.port || options[:port] || ssh_options[:port]
|
77
|
-
|
78
|
-
# the .ssh/config file might have changed the host-name on us
|
79
|
-
host = ssh_options.fetch(:host_name, server.host)
|
80
|
-
|
81
|
-
ssh_options[:port] = port if port
|
82
|
-
|
83
|
-
# delete these, since we've determined which username to use by this point
|
84
|
-
ssh_options.delete(:username)
|
85
|
-
ssh_options.delete(:user)
|
86
|
-
|
87
|
-
begin
|
88
|
-
connection_options = ssh_options.merge(
|
89
|
-
:password => password_value,
|
90
|
-
:auth_methods => ssh_options[:auth_methods] || methods.shift
|
91
|
-
)
|
92
|
-
|
93
|
-
yield host, user, connection_options
|
94
|
-
rescue Net::SSH::AuthenticationFailed
|
95
|
-
raise if methods.empty? || ssh_options[:auth_methods]
|
96
|
-
password_value = options[:password]
|
97
|
-
retry
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
@@ -1,75 +0,0 @@
|
|
1
|
-
require 'capistrano/server_definition'
|
2
|
-
|
3
|
-
module Capistrano
|
4
|
-
# Represents the definition of a single task.
|
5
|
-
class TaskDefinition
|
6
|
-
attr_reader :name, :namespace, :options, :body, :desc, :on_error, :max_hosts
|
7
|
-
|
8
|
-
def initialize(name, namespace, options={}, &block)
|
9
|
-
|
10
|
-
if name.to_s =~ /^(?:before_|after_)/
|
11
|
-
Kernel.warn("[Deprecation Warning] Naming tasks with before_ and after_ is deprecated, please see the new before() and after() methods. (Offending task name was #{name})")
|
12
|
-
end
|
13
|
-
|
14
|
-
@name, @namespace, @options = name, namespace, options
|
15
|
-
@desc = @options.delete(:desc)
|
16
|
-
@on_error = options.delete(:on_error)
|
17
|
-
@max_hosts = options[:max_hosts] && options[:max_hosts].to_i
|
18
|
-
@body = block or raise ArgumentError, "a task requires a block"
|
19
|
-
@servers = nil
|
20
|
-
end
|
21
|
-
|
22
|
-
# Returns the task's fully-qualified name, including the namespace
|
23
|
-
def fully_qualified_name
|
24
|
-
@fully_qualified_name ||= begin
|
25
|
-
if namespace.default_task == self
|
26
|
-
namespace.fully_qualified_name
|
27
|
-
else
|
28
|
-
[namespace.fully_qualified_name, name].compact.join(":")
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
# Returns the description for this task, with newlines collapsed and
|
34
|
-
# whitespace stripped. Returns the empty string if there is no
|
35
|
-
# description for this task.
|
36
|
-
def description(rebuild=false)
|
37
|
-
@description = nil if rebuild
|
38
|
-
@description ||= begin
|
39
|
-
description = @desc || ""
|
40
|
-
|
41
|
-
indentation = description[/\A\s+/]
|
42
|
-
if indentation
|
43
|
-
reformatted_description = ""
|
44
|
-
description.strip.each_line do |line|
|
45
|
-
line = line.chomp.sub(/^#{indentation}/, "")
|
46
|
-
line = line.gsub(/#{indentation}\s*/, " ") if line[/^\S/]
|
47
|
-
reformatted_description << line << "\n"
|
48
|
-
end
|
49
|
-
description = reformatted_description
|
50
|
-
end
|
51
|
-
|
52
|
-
description.strip.gsub(/\r\n/, "\n")
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
# Returns the first sentence of the full description. If +max_length+ is
|
57
|
-
# given, the result will be truncated if it is longer than +max_length+,
|
58
|
-
# and an ellipsis appended.
|
59
|
-
def brief_description(max_length=nil)
|
60
|
-
brief = description[/^.*?\.(?=\s|$)/] || description
|
61
|
-
|
62
|
-
if max_length && brief.length > max_length
|
63
|
-
brief = brief[0,max_length-3] + "..."
|
64
|
-
end
|
65
|
-
|
66
|
-
brief
|
67
|
-
end
|
68
|
-
|
69
|
-
# Indicates whether the task wants to continue, even if a server has failed
|
70
|
-
# previously
|
71
|
-
def continue_on_error?
|
72
|
-
@on_error == :continue
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|