capistrano 2.8.0 → 3.19.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/.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/cli/ui.rb
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
require 'highline'
|
|
2
|
-
|
|
3
|
-
# work around problem where HighLine detects an eof on $stdin and raises an
|
|
4
|
-
# error.
|
|
5
|
-
HighLine.track_eof = false
|
|
6
|
-
|
|
7
|
-
module Capistrano
|
|
8
|
-
class CLI
|
|
9
|
-
module UI
|
|
10
|
-
def self.included(base) #:nodoc:
|
|
11
|
-
base.extend(ClassMethods)
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
module ClassMethods
|
|
15
|
-
# Return the object that provides UI-specific methods, such as prompts
|
|
16
|
-
# and more.
|
|
17
|
-
def ui
|
|
18
|
-
@ui ||= HighLine.new
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
# Prompt for a password using echo suppression.
|
|
22
|
-
def password_prompt(prompt="Password: ")
|
|
23
|
-
ui.ask(prompt) { |q| q.echo = false }
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# Debug mode prompt
|
|
27
|
-
def debug_prompt(cmd)
|
|
28
|
-
ui.say("Preparing to execute command: #{cmd}")
|
|
29
|
-
prompt = "Execute ([Yes], No, Abort) "
|
|
30
|
-
ui.ask("#{prompt}? ") do |q|
|
|
31
|
-
q.overwrite = false
|
|
32
|
-
q.default = 'y'
|
|
33
|
-
q.validate = /(y(es)?)|(no?)|(a(bort)?|\n)/i
|
|
34
|
-
q.responses[:not_valid] = prompt
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
end
|
data/lib/capistrano/cli.rb
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
require 'capistrano'
|
|
2
|
-
require 'capistrano/cli/execute'
|
|
3
|
-
require 'capistrano/cli/help'
|
|
4
|
-
require 'capistrano/cli/options'
|
|
5
|
-
require 'capistrano/cli/ui'
|
|
6
|
-
|
|
7
|
-
module Capistrano
|
|
8
|
-
# The CLI class encapsulates the behavior of capistrano when it is invoked
|
|
9
|
-
# as a command-line utility. This allows other programs to embed Capistrano
|
|
10
|
-
# and preserve its command-line semantics.
|
|
11
|
-
class CLI
|
|
12
|
-
# The array of (unparsed) command-line options
|
|
13
|
-
attr_reader :args
|
|
14
|
-
|
|
15
|
-
# Create a new CLI instance using the given array of command-line parameters
|
|
16
|
-
# to initialize it. By default, +ARGV+ is used, but you can specify a
|
|
17
|
-
# different set of parameters (such as when embedded cap in a program):
|
|
18
|
-
#
|
|
19
|
-
# require 'capistrano/cli'
|
|
20
|
-
# Capistrano::CLI.parse(%W(-vvvv -f config/deploy update_code)).execute!
|
|
21
|
-
#
|
|
22
|
-
# Note that you can also embed cap directly by creating a new Configuration
|
|
23
|
-
# instance and setting it up, The above snippet, redone using the
|
|
24
|
-
# Configuration class directly, would look like:
|
|
25
|
-
#
|
|
26
|
-
# require 'capistrano'
|
|
27
|
-
# require 'capistrano/cli'
|
|
28
|
-
# config = Capistrano::Configuration.new
|
|
29
|
-
# config.logger.level = Capistrano::Logger::TRACE
|
|
30
|
-
# config.set(:password) { Capistrano::CLI.password_prompt }
|
|
31
|
-
# config.load "config/deploy"
|
|
32
|
-
# config.update_code
|
|
33
|
-
#
|
|
34
|
-
# There may be times that you want/need the additional control offered by
|
|
35
|
-
# manipulating the Configuration directly, but generally interfacing with
|
|
36
|
-
# the CLI class is recommended.
|
|
37
|
-
def initialize(args)
|
|
38
|
-
@args = args.dup
|
|
39
|
-
$stdout.sync = true # so that Net::SSH prompts show up
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# Mix-in the actual behavior
|
|
43
|
-
include Execute, Options, UI
|
|
44
|
-
include Help # needs to be included last, because it overrides some methods
|
|
45
|
-
|
|
46
|
-
end
|
|
47
|
-
end
|
data/lib/capistrano/command.rb
DELETED
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
require 'benchmark'
|
|
2
|
-
require 'capistrano/errors'
|
|
3
|
-
require 'capistrano/processable'
|
|
4
|
-
|
|
5
|
-
module Capistrano
|
|
6
|
-
|
|
7
|
-
# This class encapsulates a single command to be executed on a set of remote
|
|
8
|
-
# machines, in parallel.
|
|
9
|
-
class Command
|
|
10
|
-
include Processable
|
|
11
|
-
|
|
12
|
-
class Tree
|
|
13
|
-
attr_reader :configuration
|
|
14
|
-
attr_reader :branches
|
|
15
|
-
attr_reader :fallback
|
|
16
|
-
|
|
17
|
-
include Enumerable
|
|
18
|
-
|
|
19
|
-
class Branch
|
|
20
|
-
attr_accessor :command, :callback
|
|
21
|
-
attr_reader :options
|
|
22
|
-
|
|
23
|
-
def initialize(command, options, callback)
|
|
24
|
-
@command = command.strip.gsub(/\r?\n/, "\\\n")
|
|
25
|
-
@callback = callback || Capistrano::Configuration.default_io_proc
|
|
26
|
-
@options = options
|
|
27
|
-
@skip = false
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def last?
|
|
31
|
-
options[:last]
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def skip?
|
|
35
|
-
@skip
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def skip!
|
|
39
|
-
@skip = true
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def match(server)
|
|
43
|
-
true
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def to_s
|
|
47
|
-
command.inspect
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
class ConditionBranch < Branch
|
|
52
|
-
attr_accessor :configuration
|
|
53
|
-
attr_accessor :condition
|
|
54
|
-
|
|
55
|
-
class Evaluator
|
|
56
|
-
attr_reader :configuration, :condition, :server
|
|
57
|
-
|
|
58
|
-
def initialize(config, condition, server)
|
|
59
|
-
@configuration = config
|
|
60
|
-
@condition = condition
|
|
61
|
-
@server = server
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def in?(role)
|
|
65
|
-
configuration.roles[role].include?(server)
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def result
|
|
69
|
-
eval(condition, binding)
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def method_missing(sym, *args, &block)
|
|
73
|
-
if server.respond_to?(sym)
|
|
74
|
-
server.send(sym, *args, &block)
|
|
75
|
-
elsif configuration.respond_to?(sym)
|
|
76
|
-
configuration.send(sym, *args, &block)
|
|
77
|
-
else
|
|
78
|
-
super
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def initialize(configuration, condition, command, options, callback)
|
|
84
|
-
@configuration = configuration
|
|
85
|
-
@condition = condition
|
|
86
|
-
super(command, options, callback)
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
def match(server)
|
|
90
|
-
Evaluator.new(configuration, condition, server).result
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def to_s
|
|
94
|
-
"#{condition.inspect} :: #{command.inspect}"
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def initialize(config)
|
|
99
|
-
@configuration = config
|
|
100
|
-
@branches = []
|
|
101
|
-
yield self if block_given?
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def when(condition, command, options={}, &block)
|
|
105
|
-
branches << ConditionBranch.new(configuration, condition, command, options, block)
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
def else(command, &block)
|
|
109
|
-
@fallback = Branch.new(command, {}, block)
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
def branches_for(server)
|
|
113
|
-
seen_last = false
|
|
114
|
-
matches = branches.select do |branch|
|
|
115
|
-
success = !seen_last && !branch.skip? && branch.match(server)
|
|
116
|
-
seen_last = success && branch.last?
|
|
117
|
-
success
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
matches << fallback if matches.empty? && fallback
|
|
121
|
-
return matches
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
def each
|
|
125
|
-
branches.each { |branch| yield branch }
|
|
126
|
-
yield fallback if fallback
|
|
127
|
-
return self
|
|
128
|
-
end
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
attr_reader :tree, :sessions, :options
|
|
132
|
-
|
|
133
|
-
def self.process(tree, sessions, options={})
|
|
134
|
-
new(tree, sessions, options).process!
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
# Instantiates a new command object. The +command+ must be a string
|
|
138
|
-
# containing the command to execute. +sessions+ is an array of Net::SSH
|
|
139
|
-
# session instances, and +options+ must be a hash containing any of the
|
|
140
|
-
# following keys:
|
|
141
|
-
#
|
|
142
|
-
# * +logger+: (optional), a Capistrano::Logger instance
|
|
143
|
-
# * +data+: (optional), a string to be sent to the command via it's stdin
|
|
144
|
-
# * +env+: (optional), a string or hash to be interpreted as environment
|
|
145
|
-
# variables that should be defined for this command invocation.
|
|
146
|
-
def initialize(tree, sessions, options={}, &block)
|
|
147
|
-
if String === tree
|
|
148
|
-
tree = Tree.new(nil) { |t| t.else(tree, &block) }
|
|
149
|
-
elsif block
|
|
150
|
-
raise ArgumentError, "block given with tree argument"
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
@tree = tree
|
|
154
|
-
@sessions = sessions
|
|
155
|
-
@options = options
|
|
156
|
-
@channels = open_channels
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
# Processes the command in parallel on all specified hosts. If the command
|
|
160
|
-
# fails (non-zero return code) on any of the hosts, this will raise a
|
|
161
|
-
# Capistrano::CommandError.
|
|
162
|
-
def process!
|
|
163
|
-
elapsed = Benchmark.realtime do
|
|
164
|
-
loop do
|
|
165
|
-
break unless process_iteration { @channels.any? { |ch| !ch[:closed] } }
|
|
166
|
-
end
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
logger.trace "command finished in #{(elapsed * 1000).round}ms" if logger
|
|
170
|
-
|
|
171
|
-
if (failed = @channels.select { |ch| ch[:status] != 0 }).any?
|
|
172
|
-
commands = failed.inject({}) { |map, ch| (map[ch[:command]] ||= []) << ch[:server]; map }
|
|
173
|
-
message = commands.map { |command, list| "#{command.inspect} on #{list.join(',')}" }.join("; ")
|
|
174
|
-
error = CommandError.new("failed: #{message}")
|
|
175
|
-
error.hosts = commands.values.flatten
|
|
176
|
-
raise error
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
self
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
# Force the command to stop processing, by closing all open channels
|
|
183
|
-
# associated with this command.
|
|
184
|
-
def stop!
|
|
185
|
-
@channels.each do |ch|
|
|
186
|
-
ch.close unless ch[:closed]
|
|
187
|
-
end
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
private
|
|
191
|
-
|
|
192
|
-
def logger
|
|
193
|
-
options[:logger]
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
def open_channels
|
|
197
|
-
sessions.map do |session|
|
|
198
|
-
server = session.xserver
|
|
199
|
-
tree.branches_for(server).map do |branch|
|
|
200
|
-
session.open_channel do |channel|
|
|
201
|
-
channel[:server] = server
|
|
202
|
-
channel[:host] = server.host
|
|
203
|
-
channel[:options] = options
|
|
204
|
-
channel[:branch] = branch
|
|
205
|
-
|
|
206
|
-
request_pty_if_necessary(channel) do |ch, success|
|
|
207
|
-
if success
|
|
208
|
-
logger.trace "executing command", ch[:server] if logger
|
|
209
|
-
cmd = replace_placeholders(channel[:branch].command, ch)
|
|
210
|
-
|
|
211
|
-
if options[:shell] == false
|
|
212
|
-
shell = nil
|
|
213
|
-
else
|
|
214
|
-
shell = "#{options[:shell] || "sh"} -c"
|
|
215
|
-
cmd = cmd.gsub(/'/) { |m| "'\\''" }
|
|
216
|
-
cmd = "'#{cmd}'"
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
command_line = [environment, shell, cmd].compact.join(" ")
|
|
220
|
-
ch[:command] = command_line
|
|
221
|
-
|
|
222
|
-
ch.exec(command_line)
|
|
223
|
-
ch.send_data(options[:data]) if options[:data]
|
|
224
|
-
else
|
|
225
|
-
# just log it, don't actually raise an exception, since the
|
|
226
|
-
# process method will see that the status is not zero and will
|
|
227
|
-
# raise an exception then.
|
|
228
|
-
logger.important "could not open channel", ch[:server] if logger
|
|
229
|
-
ch.close
|
|
230
|
-
end
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
channel.on_data do |ch, data|
|
|
234
|
-
ch[:branch].callback[ch, :out, data]
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
channel.on_extended_data do |ch, type, data|
|
|
238
|
-
ch[:branch].callback[ch, :err, data]
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
channel.on_request("exit-status") do |ch, data|
|
|
242
|
-
ch[:status] = data.read_long
|
|
243
|
-
end
|
|
244
|
-
|
|
245
|
-
channel.on_close do |ch|
|
|
246
|
-
ch[:closed] = true
|
|
247
|
-
end
|
|
248
|
-
end
|
|
249
|
-
end
|
|
250
|
-
end.flatten
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
def request_pty_if_necessary(channel)
|
|
254
|
-
if options[:pty]
|
|
255
|
-
channel.request_pty do |ch, success|
|
|
256
|
-
yield ch, success
|
|
257
|
-
end
|
|
258
|
-
else
|
|
259
|
-
yield channel, true
|
|
260
|
-
end
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
def replace_placeholders(command, channel)
|
|
264
|
-
command.gsub(/\$CAPISTRANO:HOST\$/, channel[:host])
|
|
265
|
-
end
|
|
266
|
-
|
|
267
|
-
# prepare a space-separated sequence of variables assignments
|
|
268
|
-
# intended to be prepended to a command, so the shell sets
|
|
269
|
-
# the environment before running the command.
|
|
270
|
-
# i.e.: options[:env] = {'PATH' => '/opt/ruby/bin:$PATH',
|
|
271
|
-
# 'TEST' => '( "quoted" )'}
|
|
272
|
-
# environment returns:
|
|
273
|
-
# "env TEST=(\ \"quoted\"\ ) PATH=/opt/ruby/bin:$PATH"
|
|
274
|
-
def environment
|
|
275
|
-
return if options[:env].nil? || options[:env].empty?
|
|
276
|
-
@environment ||= if String === options[:env]
|
|
277
|
-
"env #{options[:env]}"
|
|
278
|
-
else
|
|
279
|
-
options[:env].inject("env") do |string, (name, value)|
|
|
280
|
-
value = value.to_s.gsub(/[ "]/) { |m| "\\#{m}" }
|
|
281
|
-
string << " #{name}=#{value}"
|
|
282
|
-
end
|
|
283
|
-
end
|
|
284
|
-
end
|
|
285
|
-
end
|
|
286
|
-
end
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
require 'capistrano/transfer'
|
|
2
|
-
|
|
3
|
-
module Capistrano
|
|
4
|
-
class Configuration
|
|
5
|
-
module Actions
|
|
6
|
-
module FileTransfer
|
|
7
|
-
|
|
8
|
-
# Store the given data at the given location on all servers targetted
|
|
9
|
-
# by the current task. If <tt>:mode</tt> is specified it is used to
|
|
10
|
-
# set the mode on the file.
|
|
11
|
-
def put(data, path, options={})
|
|
12
|
-
opts = options.dup
|
|
13
|
-
upload(StringIO.new(data), path, opts)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# Get file remote_path from FIRST server targeted by
|
|
17
|
-
# the current task and transfer it to local machine as path.
|
|
18
|
-
#
|
|
19
|
-
# get "#{deploy_to}/current/log/production.log", "log/production.log.web"
|
|
20
|
-
def get(remote_path, path, options={}, &block)
|
|
21
|
-
download(remote_path, path, options.merge(:once => true), &block)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def upload(from, to, options={}, &block)
|
|
25
|
-
mode = options.delete(:mode)
|
|
26
|
-
transfer(:up, from, to, options, &block)
|
|
27
|
-
if mode
|
|
28
|
-
mode = mode.is_a?(Numeric) ? mode.to_s(8) : mode.to_s
|
|
29
|
-
run "chmod #{mode} #{to}", options
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def download(from, to, options={}, &block)
|
|
34
|
-
transfer(:down, from, to, options, &block)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def transfer(direction, from, to, options={}, &block)
|
|
38
|
-
execute_on_servers(options) do |servers|
|
|
39
|
-
targets = servers.map { |s| sessions[s] }
|
|
40
|
-
if dry_run
|
|
41
|
-
logger.debug "transfering: #{[direction, from, to, targets, options.merge(:logger => logger).inspect ] * ', '}"
|
|
42
|
-
else
|
|
43
|
-
Transfer.process(direction, from, to, targets, options.merge(:logger => logger), &block)
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
end
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
require 'capistrano/errors'
|
|
2
|
-
|
|
3
|
-
module Capistrano
|
|
4
|
-
class Configuration
|
|
5
|
-
module Actions
|
|
6
|
-
module Inspect
|
|
7
|
-
|
|
8
|
-
# Streams the result of the command from all servers that are the
|
|
9
|
-
# target of the current task. All these streams will be joined into a
|
|
10
|
-
# single one, so you can, say, watch 10 log files as though they were
|
|
11
|
-
# one. Do note that this is quite expensive from a bandwidth
|
|
12
|
-
# perspective, so use it with care.
|
|
13
|
-
#
|
|
14
|
-
# The command is invoked via #invoke_command.
|
|
15
|
-
#
|
|
16
|
-
# Usage:
|
|
17
|
-
#
|
|
18
|
-
# desc "Run a tail on multiple log files at the same time"
|
|
19
|
-
# task :tail_fcgi, :roles => :app do
|
|
20
|
-
# stream "tail -f #{shared_path}/log/fastcgi.crash.log"
|
|
21
|
-
# end
|
|
22
|
-
def stream(command, options={})
|
|
23
|
-
invoke_command(command, options) do |ch, stream, out|
|
|
24
|
-
puts out if stream == :out
|
|
25
|
-
warn "[err :: #{ch[:server]}] #{out}" if stream == :err
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# Executes the given command on the first server targetted by the
|
|
30
|
-
# current task, collects it's stdout into a string, and returns the
|
|
31
|
-
# string. The command is invoked via #invoke_command.
|
|
32
|
-
def capture(command, options={})
|
|
33
|
-
output = ""
|
|
34
|
-
invoke_command(command, options.merge(:once => true)) do |ch, stream, data|
|
|
35
|
-
case stream
|
|
36
|
-
when :out then output << data
|
|
37
|
-
when :err then warn "[err :: #{ch[:server]}] #{data}"
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
output
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|