capistrano 3.4.1 → 3.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +7 -5
- data/.rubocop.yml +49 -0
- data/.travis.yml +5 -4
- data/CHANGELOG.md +72 -9
- data/CONTRIBUTING.md +61 -93
- data/DEVELOPMENT.md +122 -0
- data/Gemfile +2 -2
- data/LICENSE.txt +1 -1
- data/README.md +121 -43
- data/RELEASING.md +16 -0
- data/Rakefile +4 -1
- data/bin/cap +1 -1
- data/capistrano.gemspec +16 -21
- data/features/doctor.feature +11 -0
- data/features/step_definitions/assertions.rb +17 -17
- data/features/step_definitions/cap_commands.rb +0 -1
- data/features/step_definitions/setup.rb +12 -8
- data/features/support/env.rb +5 -5
- data/features/support/remote_command_helpers.rb +8 -6
- data/features/support/vagrant_helpers.rb +5 -4
- data/issue_template.md +21 -0
- data/lib/Capfile +5 -1
- data/lib/capistrano/all.rb +9 -10
- data/lib/capistrano/application.rb +36 -26
- data/lib/capistrano/configuration.rb +56 -41
- data/lib/capistrano/configuration/empty_filter.rb +9 -0
- data/lib/capistrano/configuration/filter.rb +18 -47
- data/lib/capistrano/configuration/host_filter.rb +30 -0
- data/lib/capistrano/configuration/null_filter.rb +9 -0
- data/lib/capistrano/configuration/plugin_installer.rb +33 -0
- data/lib/capistrano/configuration/question.rb +10 -7
- data/lib/capistrano/configuration/role_filter.rb +30 -0
- data/lib/capistrano/configuration/server.rb +22 -23
- data/lib/capistrano/configuration/servers.rb +6 -7
- data/lib/capistrano/configuration/variables.rb +136 -0
- data/lib/capistrano/defaults.rb +13 -3
- data/lib/capistrano/deploy.rb +1 -1
- data/lib/capistrano/doctor.rb +5 -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/variables_doctor.rb +66 -0
- data/lib/capistrano/dotfile.rb +1 -2
- data/lib/capistrano/dsl.rb +12 -14
- data/lib/capistrano/dsl/env.rb +11 -42
- data/lib/capistrano/dsl/paths.rb +12 -13
- data/lib/capistrano/dsl/stages.rb +2 -4
- data/lib/capistrano/dsl/task_enhancements.rb +5 -7
- data/lib/capistrano/framework.rb +1 -1
- data/lib/capistrano/git.rb +17 -9
- data/lib/capistrano/hg.rb +4 -4
- data/lib/capistrano/i18n.rb +24 -24
- data/lib/capistrano/immutable_task.rb +29 -0
- data/lib/capistrano/install.rb +1 -1
- data/lib/capistrano/plugin.rb +95 -0
- data/lib/capistrano/scm.rb +7 -20
- data/lib/capistrano/setup.rb +19 -5
- data/lib/capistrano/svn.rb +9 -5
- data/lib/capistrano/tasks/console.rake +4 -8
- data/lib/capistrano/tasks/deploy.rake +75 -62
- data/lib/capistrano/tasks/doctor.rake +19 -0
- data/lib/capistrano/tasks/framework.rake +13 -14
- data/lib/capistrano/tasks/git.rake +10 -11
- data/lib/capistrano/tasks/hg.rake +7 -7
- data/lib/capistrano/tasks/install.rake +14 -15
- data/lib/capistrano/tasks/svn.rake +7 -7
- data/lib/capistrano/templates/Capfile +3 -3
- data/lib/capistrano/templates/deploy.rb.erb +6 -5
- data/lib/capistrano/upload_task.rb +1 -1
- data/lib/capistrano/version.rb +1 -1
- data/lib/capistrano/version_validator.rb +4 -6
- data/spec/integration/dsl_spec.rb +286 -239
- data/spec/integration_spec_helper.rb +3 -5
- data/spec/lib/capistrano/application_spec.rb +22 -14
- data/spec/lib/capistrano/configuration/empty_filter_spec.rb +17 -0
- data/spec/lib/capistrano/configuration/filter_spec.rb +82 -84
- data/spec/lib/capistrano/configuration/host_filter_spec.rb +61 -0
- data/spec/lib/capistrano/configuration/null_filter_spec.rb +17 -0
- data/spec/lib/capistrano/configuration/question_spec.rb +12 -16
- data/spec/lib/capistrano/configuration/role_filter_spec.rb +64 -0
- data/spec/lib/capistrano/configuration/server_spec.rb +102 -110
- data/spec/lib/capistrano/configuration/servers_spec.rb +124 -141
- data/spec/lib/capistrano/configuration_spec.rb +150 -61
- data/spec/lib/capistrano/doctor/environment_doctor_spec.rb +44 -0
- data/spec/lib/capistrano/doctor/gems_doctor_spec.rb +61 -0
- data/spec/lib/capistrano/doctor/output_helpers_spec.rb +47 -0
- data/spec/lib/capistrano/doctor/variables_doctor_spec.rb +79 -0
- data/spec/lib/capistrano/dsl/paths_spec.rb +58 -50
- data/spec/lib/capistrano/dsl/task_enhancements_spec.rb +62 -32
- data/spec/lib/capistrano/dsl_spec.rb +6 -8
- data/spec/lib/capistrano/git_spec.rb +35 -7
- data/spec/lib/capistrano/hg_spec.rb +14 -5
- data/spec/lib/capistrano/immutable_task_spec.rb +31 -0
- data/spec/lib/capistrano/plugin_spec.rb +84 -0
- data/spec/lib/capistrano/scm_spec.rb +6 -7
- data/spec/lib/capistrano/svn_spec.rb +40 -14
- data/spec/lib/capistrano/upload_task_spec.rb +7 -7
- data/spec/lib/capistrano/version_validator_spec.rb +37 -45
- data/spec/lib/capistrano_spec.rb +2 -3
- data/spec/spec_helper.rb +8 -8
- data/spec/support/Vagrantfile +9 -10
- data/spec/support/tasks/database.rake +3 -3
- data/spec/support/tasks/fail.rake +4 -3
- data/spec/support/tasks/failed.rake +2 -2
- data/spec/support/tasks/plugin.rake +6 -0
- data/spec/support/tasks/root.rake +4 -4
- data/spec/support/test_app.rb +31 -30
- metadata +93 -14
data/features/support/env.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
PROJECT_ROOT = File.expand_path(
|
2
|
-
VAGRANT_ROOT = File.join(PROJECT_ROOT,
|
3
|
-
VAGRANT_BIN = ENV[
|
1
|
+
PROJECT_ROOT = File.expand_path("../../../", __FILE__)
|
2
|
+
VAGRANT_ROOT = File.join(PROJECT_ROOT, "spec/support")
|
3
|
+
VAGRANT_BIN = ENV["VAGRANT_BIN"] || "vagrant"
|
4
4
|
|
5
5
|
at_exit do
|
6
|
-
if ENV[
|
6
|
+
if ENV["KEEP_RUNNING"]
|
7
7
|
VagrantHelpers.run_vagrant_command("rm -rf /home/vagrant/var")
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
require_relative
|
11
|
+
require_relative "../../spec/support/test_app"
|
@@ -1,22 +1,24 @@
|
|
1
1
|
module RemoteCommandHelpers
|
2
2
|
def test_dir_exists(path)
|
3
|
-
exists?(
|
3
|
+
exists?("d", path)
|
4
4
|
end
|
5
5
|
|
6
6
|
def test_symlink_exists(path)
|
7
|
-
exists?(
|
7
|
+
exists?("L", path)
|
8
8
|
end
|
9
9
|
|
10
10
|
def test_file_exists(path)
|
11
|
-
exists?(
|
11
|
+
exists?("f", path)
|
12
12
|
end
|
13
13
|
|
14
14
|
def exists?(type, path)
|
15
|
-
%{[ -#{type} "#{path}" ]}
|
15
|
+
%Q{[ -#{type} "#{path}" ]}
|
16
16
|
end
|
17
17
|
|
18
|
-
def safely_remove_file(
|
19
|
-
run_vagrant_command("rm #{test_file}")
|
18
|
+
def safely_remove_file(_path)
|
19
|
+
run_vagrant_command("rm #{test_file}")
|
20
|
+
rescue
|
21
|
+
VagrantHelpers::VagrantSSHCommandError
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
@@ -1,10 +1,12 @@
|
|
1
|
+
require "English"
|
2
|
+
|
1
3
|
module VagrantHelpers
|
2
4
|
extend self
|
3
5
|
|
4
6
|
class VagrantSSHCommandError < RuntimeError; end
|
5
7
|
|
6
8
|
at_exit do
|
7
|
-
if ENV[
|
9
|
+
if ENV["KEEP_RUNNING"]
|
8
10
|
puts "Vagrant vm will be left up because KEEP_RUNNING is set."
|
9
11
|
puts "Rerun without KEEP_RUNNING set to cleanup the vm."
|
10
12
|
else
|
@@ -19,17 +21,16 @@ module VagrantHelpers
|
|
19
21
|
puts "[vagrant] #{line}"
|
20
22
|
end
|
21
23
|
end
|
22
|
-
|
24
|
+
$CHILD_STATUS
|
23
25
|
end
|
24
26
|
|
25
27
|
def run_vagrant_command(command)
|
26
28
|
if (status = vagrant_cli_command("ssh -c #{command.inspect}")).success?
|
27
29
|
true
|
28
30
|
else
|
29
|
-
|
31
|
+
raise VagrantSSHCommandError, status
|
30
32
|
end
|
31
33
|
end
|
32
|
-
|
33
34
|
end
|
34
35
|
|
35
36
|
World(VagrantHelpers)
|
data/issue_template.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
**Important:** GitHub issues are for feature requests or bug reports. The Capistrano team recommends you use [Stack Overflow](http://stackoverflow.com/questions/tagged/capistrano) for general questions. For more details, please see our [contribution policy](https://github.com/capistrano/capistrano/blob/master/CONTRIBUTING.md).
|
2
|
+
|
3
|
+
---
|
4
|
+
|
5
|
+
#### Steps to reproduce
|
6
|
+
|
7
|
+
1. Lorem.
|
8
|
+
2. Ipsum..
|
9
|
+
3. Dolor...
|
10
|
+
|
11
|
+
#### Expected behaviour
|
12
|
+
|
13
|
+
Tell us what should happen
|
14
|
+
|
15
|
+
#### Actual behaviour
|
16
|
+
|
17
|
+
Tell us what happens instead
|
18
|
+
|
19
|
+
#### Your configuration
|
20
|
+
|
21
|
+
Paste Capistrano's `doctor` output here (`cap <stage> doctor`):
|
data/lib/Capfile
CHANGED
data/lib/capistrano/all.rb
CHANGED
@@ -1,17 +1,16 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "rake"
|
2
|
+
require "sshkit"
|
3
3
|
|
4
|
-
require
|
4
|
+
require "io/console"
|
5
5
|
|
6
6
|
Rake.application.options.trace = true
|
7
7
|
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require
|
8
|
+
require "capistrano/version"
|
9
|
+
require "capistrano/version_validator"
|
10
|
+
require "capistrano/i18n"
|
11
|
+
require "capistrano/dsl"
|
12
|
+
require "capistrano/application"
|
13
|
+
require "capistrano/configuration"
|
14
14
|
|
15
15
|
module Capistrano
|
16
|
-
|
17
16
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
module Capistrano
|
2
2
|
class Application < Rake::Application
|
3
|
-
|
4
3
|
def initialize
|
5
4
|
super
|
6
5
|
@rakefiles = %w{capfile Capfile capfile.rb Capfile.rb} << capfile
|
@@ -21,11 +20,11 @@ module Capistrano
|
|
21
20
|
switch =~ /--#{Regexp.union(not_applicable_to_capistrano)}/
|
22
21
|
end
|
23
22
|
|
24
|
-
super.push(version, dry_run, roles, hostfilter)
|
23
|
+
super.push(version, dry_run, roles, hostfilter, print_config_variables)
|
25
24
|
end
|
26
25
|
|
27
26
|
def handle_options
|
28
|
-
options.rakelib = [
|
27
|
+
options.rakelib = ["rakelib"]
|
29
28
|
options.trace_output = $stderr
|
30
29
|
|
31
30
|
OptionParser.new do |opts|
|
@@ -48,11 +47,10 @@ module Capistrano
|
|
48
47
|
end
|
49
48
|
|
50
49
|
standard_rake_options.each { |args| opts.on(*args) }
|
51
|
-
opts.environment(
|
50
|
+
opts.environment("RAKEOPT")
|
52
51
|
end.parse!
|
53
52
|
end
|
54
53
|
|
55
|
-
|
56
54
|
def top_level_tasks
|
57
55
|
if tasks_without_stage_dependency.include?(@top_level_tasks.first)
|
58
56
|
@top_level_tasks
|
@@ -63,13 +61,10 @@ module Capistrano
|
|
63
61
|
|
64
62
|
def display_error_message(ex)
|
65
63
|
unless options.backtrace
|
66
|
-
|
67
|
-
whitelist = (@imported.dup << loc[0]).map{|f| File.absolute_path(f, loc[1])}
|
68
|
-
pattern = %r@^(?!#{whitelist.map{|p| Regexp.quote(p)}.join('|')})@
|
69
|
-
Rake.application.options.suppress_backtrace_pattern = pattern
|
70
|
-
end
|
64
|
+
Rake.application.options.suppress_backtrace_pattern = backtrace_pattern if backtrace_pattern
|
71
65
|
trace "(Backtrace restricted to imported tasks)"
|
72
66
|
end
|
67
|
+
|
73
68
|
super
|
74
69
|
end
|
75
70
|
|
@@ -83,10 +78,18 @@ module Capistrano
|
|
83
78
|
|
84
79
|
private
|
85
80
|
|
81
|
+
def backtrace_pattern
|
82
|
+
loc = Rake.application.find_rakefile_location
|
83
|
+
return unless loc
|
84
|
+
|
85
|
+
whitelist = (@imported.dup << loc[0]).map { |f| File.absolute_path(f, loc[1]) }
|
86
|
+
/^(?!#{whitelist.map { |p| Regexp.quote(p) }.join('|')})/
|
87
|
+
end
|
88
|
+
|
86
89
|
def load_imports
|
87
90
|
if options.show_tasks
|
88
|
-
invoke
|
89
|
-
set(:stage,
|
91
|
+
invoke "load:defaults"
|
92
|
+
set(:stage, "")
|
90
93
|
Dir[deploy_config_path].each { |f| add_import f }
|
91
94
|
end
|
92
95
|
|
@@ -95,46 +98,53 @@ module Capistrano
|
|
95
98
|
|
96
99
|
# allows the `cap install` task to load without a capfile
|
97
100
|
def capfile
|
98
|
-
File.expand_path(File.join(File.dirname(__FILE__),
|
101
|
+
File.expand_path(File.join(File.dirname(__FILE__), "..", "Capfile"))
|
99
102
|
end
|
100
103
|
|
101
104
|
def version
|
102
|
-
[
|
105
|
+
["--version", "-V",
|
103
106
|
"Display the program version.",
|
104
|
-
lambda
|
107
|
+
lambda do |_value|
|
105
108
|
puts "Capistrano Version: #{Capistrano::VERSION} (Rake Version: #{Rake::VERSION})"
|
106
109
|
exit
|
107
|
-
|
110
|
+
end
|
108
111
|
]
|
109
112
|
end
|
110
113
|
|
111
114
|
def dry_run
|
112
|
-
[
|
115
|
+
["--dry-run", "-n",
|
113
116
|
"Do a dry run without executing actions",
|
114
|
-
lambda
|
117
|
+
lambda do |_value|
|
115
118
|
Configuration.env.set(:sshkit_backend, SSHKit::Backend::Printer)
|
116
|
-
|
119
|
+
end
|
117
120
|
]
|
118
121
|
end
|
119
122
|
|
120
123
|
def roles
|
121
|
-
[
|
124
|
+
["--roles ROLES", "-r",
|
122
125
|
"Run SSH commands only on hosts matching these roles",
|
123
|
-
lambda
|
126
|
+
lambda do |value|
|
124
127
|
Configuration.env.add_cmdline_filter(:role, value)
|
125
|
-
|
128
|
+
end
|
126
129
|
]
|
127
130
|
end
|
128
131
|
|
129
132
|
def hostfilter
|
130
|
-
[
|
133
|
+
["--hosts HOSTS", "-z",
|
131
134
|
"Run SSH commands only on matching hosts",
|
132
|
-
lambda
|
135
|
+
lambda do |value|
|
133
136
|
Configuration.env.add_cmdline_filter(:host, value)
|
134
|
-
|
137
|
+
end
|
135
138
|
]
|
136
139
|
end
|
137
140
|
|
141
|
+
def print_config_variables
|
142
|
+
["--print-config-variables", "-p",
|
143
|
+
"Display the defined config variables before starting the deployment tasks.",
|
144
|
+
lambda do |_value|
|
145
|
+
Configuration.env.set(:print_config_variables, true)
|
146
|
+
end
|
147
|
+
]
|
148
|
+
end
|
138
149
|
end
|
139
|
-
|
140
150
|
end
|
@@ -1,15 +1,14 @@
|
|
1
|
-
require_relative
|
2
|
-
require_relative
|
3
|
-
require_relative
|
4
|
-
require_relative
|
1
|
+
require_relative "configuration/filter"
|
2
|
+
require_relative "configuration/question"
|
3
|
+
require_relative "configuration/plugin_installer"
|
4
|
+
require_relative "configuration/server"
|
5
|
+
require_relative "configuration/servers"
|
6
|
+
require_relative "configuration/variables"
|
5
7
|
|
6
8
|
module Capistrano
|
7
|
-
class
|
8
|
-
|
9
|
-
def initialize(config = nil)
|
10
|
-
@config ||= config
|
11
|
-
end
|
9
|
+
class ValidationError < Exception; end
|
12
10
|
|
11
|
+
class Configuration
|
13
12
|
def self.env
|
14
13
|
@env ||= new
|
15
14
|
end
|
@@ -18,38 +17,49 @@ module Capistrano
|
|
18
17
|
@env = new
|
19
18
|
end
|
20
19
|
|
20
|
+
extend Forwardable
|
21
|
+
attr_reader :variables
|
22
|
+
def_delegators :variables,
|
23
|
+
:set, :fetch, :fetch_for, :delete, :keys, :validate
|
24
|
+
|
25
|
+
def initialize(values={})
|
26
|
+
@variables = Variables.new(values)
|
27
|
+
end
|
28
|
+
|
21
29
|
def ask(key, default=nil, options={})
|
22
30
|
question = Question.new(key, default, options)
|
23
31
|
set(key, question)
|
24
32
|
end
|
25
33
|
|
26
|
-
def
|
27
|
-
|
34
|
+
def set_if_empty(key, value=nil, &block)
|
35
|
+
set(key, value, &block) unless keys.include?(key)
|
28
36
|
end
|
29
37
|
|
30
|
-
def
|
31
|
-
|
38
|
+
def append(key, *values)
|
39
|
+
set(key, Array(fetch(key)).concat(values))
|
32
40
|
end
|
33
41
|
|
34
|
-
def
|
35
|
-
|
42
|
+
def remove(key, *values)
|
43
|
+
set(key, Array(fetch(key)) - values)
|
36
44
|
end
|
37
45
|
|
38
|
-
def
|
39
|
-
value =
|
40
|
-
|
41
|
-
value
|
46
|
+
def any?(key)
|
47
|
+
value = fetch(key)
|
48
|
+
if value && value.respond_to?(:any?)
|
49
|
+
value.any?
|
50
|
+
else
|
51
|
+
!fetch(key).nil?
|
42
52
|
end
|
43
|
-
return value
|
44
53
|
end
|
45
54
|
|
46
|
-
def
|
47
|
-
|
55
|
+
def is_question?(key)
|
56
|
+
value = fetch_for(key, nil)
|
57
|
+
!value.nil? && value.is_a?(Question)
|
48
58
|
end
|
49
59
|
|
50
60
|
def role(name, hosts, options={})
|
51
61
|
if name == :all
|
52
|
-
raise ArgumentError
|
62
|
+
raise ArgumentError, "#{name} reserved name for role. Please choose another name"
|
53
63
|
end
|
54
64
|
|
55
65
|
servers.add_role(name, hosts, options)
|
@@ -79,14 +89,14 @@ module Capistrano
|
|
79
89
|
|
80
90
|
def configure_backend
|
81
91
|
backend.configure do |sshkit|
|
82
|
-
sshkit
|
92
|
+
configure_sshkit_output(sshkit)
|
83
93
|
sshkit.output_verbosity = fetch(:log_level)
|
84
94
|
sshkit.default_env = fetch(:default_env)
|
85
95
|
sshkit.backend = fetch(:sshkit_backend, SSHKit::Backend::Netssh)
|
86
96
|
sshkit.backend.configure do |backend|
|
87
97
|
backend.pty = fetch(:pty)
|
88
98
|
backend.connection_timeout = fetch(:connection_timeout)
|
89
|
-
backend.ssh_options = (backend.ssh_options || {}).merge(fetch(:ssh_options,{}))
|
99
|
+
backend.ssh_options = (backend.ssh_options || {}).merge(fetch(:ssh_options, {}))
|
90
100
|
end
|
91
101
|
end
|
92
102
|
end
|
@@ -97,9 +107,11 @@ module Capistrano
|
|
97
107
|
|
98
108
|
def setup_filters
|
99
109
|
@filters = cmdline_filters.clone
|
100
|
-
@filters << Filter.new(:role, ENV[
|
101
|
-
@filters << Filter.new(:host, ENV[
|
102
|
-
fh = fetch_for(:filter,{})
|
110
|
+
@filters << Filter.new(:role, ENV["ROLES"]) if ENV["ROLES"]
|
111
|
+
@filters << Filter.new(:host, ENV["HOSTS"]) if ENV["HOSTS"]
|
112
|
+
fh = fetch_for(:filter, {}) || {}
|
113
|
+
@filters << Filter.new(:host, fh[:hosts]) if fh[:hosts]
|
114
|
+
@filters << Filter.new(:role, fh[:roles]) if fh[:roles]
|
103
115
|
@filters << Filter.new(:host, fh[:host]) if fh[:host]
|
104
116
|
@filters << Filter.new(:role, fh[:role]) if fh[:role]
|
105
117
|
end
|
@@ -108,9 +120,17 @@ module Capistrano
|
|
108
120
|
cmdline_filters << Filter.new(type, values)
|
109
121
|
end
|
110
122
|
|
111
|
-
def filter
|
123
|
+
def filter(list)
|
112
124
|
setup_filters if @filters.nil?
|
113
|
-
@filters.reduce(list) { |l,f| f.filter l }
|
125
|
+
@filters.reduce(list) { |l, f| f.filter l }
|
126
|
+
end
|
127
|
+
|
128
|
+
def dry_run?
|
129
|
+
fetch(:sshkit_backend) == SSHKit::Backend::Printer
|
130
|
+
end
|
131
|
+
|
132
|
+
def install_plugin(plugin, load_hooks:true)
|
133
|
+
installer.install(plugin, load_hooks: load_hooks)
|
114
134
|
end
|
115
135
|
|
116
136
|
private
|
@@ -123,20 +143,15 @@ module Capistrano
|
|
123
143
|
@servers ||= Servers.new
|
124
144
|
end
|
125
145
|
|
126
|
-
def
|
127
|
-
@
|
146
|
+
def installer
|
147
|
+
@installer ||= PluginInstaller.new
|
128
148
|
end
|
129
149
|
|
130
|
-
def
|
131
|
-
|
132
|
-
|
133
|
-
else
|
134
|
-
config.fetch(key, default)
|
135
|
-
end
|
136
|
-
end
|
150
|
+
def configure_sshkit_output(sshkit)
|
151
|
+
format_args = [fetch(:format)]
|
152
|
+
format_args.push(fetch(:format_options)) if any?(:format_options)
|
137
153
|
|
138
|
-
|
139
|
-
x.respond_to?(:call) && ( !x.respond_to?(:arity) || x.arity == 0)
|
154
|
+
sshkit.use_format(*format_args)
|
140
155
|
end
|
141
156
|
end
|
142
157
|
end
|