mirror of
https://github.com/capistrano/capistrano
synced 2023-03-27 23:21:18 -04:00
Enhance sudo helper to return command. Also make run helper use the sudo password detection callback, so that sudo can be used in more complex scenarios.
This commit is contained in:
parent
461ca9611e
commit
b45290e6ae
3 changed files with 34 additions and 18 deletions
|
@ -1,5 +1,7 @@
|
|||
*unreleased*
|
||||
|
||||
* Enhance the sudo helper so it can be used to return the command, instead of executing it [Jamis Buck]
|
||||
|
||||
* Revert "make sudo helper play nicely with complex command chains", since it broke stuff [Jamis Buck]
|
||||
|
||||
* Make set(:default_shell, false) work for not using a shell on a per-command basis [Ryan McGeary]
|
||||
|
|
|
@ -50,31 +50,45 @@ module Capistrano
|
|||
|
||||
options = add_default_command_options(options)
|
||||
|
||||
if cmd.include?(sudo)
|
||||
block = sudo_behavior_callback(block)
|
||||
end
|
||||
|
||||
execute_on_servers(options) do |servers|
|
||||
targets = servers.map { |s| sessions[s] }
|
||||
Command.process(cmd, targets, options.merge(:logger => logger), &block)
|
||||
end
|
||||
end
|
||||
|
||||
# Like #run, but executes the command via <tt>sudo</tt>. This assumes
|
||||
# that the sudo password (if required) is the same as the password for
|
||||
# logging in to the server.
|
||||
# Returns the command string used by capistrano to invoke a comamnd via
|
||||
# sudo.
|
||||
#
|
||||
# Also, this module accepts a <tt>:sudo</tt> configuration variable,
|
||||
# run "#{sudo :as => 'bob'} mkdir /path/to/dir"
|
||||
#
|
||||
# It can also be invoked like #run, but executing the command via sudo.
|
||||
# This assumes that the sudo password (if required) is the same as the
|
||||
# password for logging in to the server.
|
||||
#
|
||||
# sudo "mkdir /path/to/dir"
|
||||
#
|
||||
# Also, this method understands a <tt>:sudo</tt> configuration variable,
|
||||
# which (if specified) will be used as the full path to the sudo
|
||||
# executable on the remote machine:
|
||||
#
|
||||
# set :sudo, "/opt/local/bin/sudo"
|
||||
def sudo(command, options={}, &block)
|
||||
block ||= self.class.default_io_proc
|
||||
def sudo(*parameters, &block)
|
||||
options = parameters.last.is_a?(Hash) ? parameters.pop.dup : {}
|
||||
command = parameters.first
|
||||
user = options[:as] && "-u #{options.delete(:as)}"
|
||||
|
||||
options = options.dup
|
||||
as = options.delete(:as)
|
||||
sudo_command = [fetch(:sudo, "sudo"), "-p '#{sudo_prompt}'", user].compact.join(" ")
|
||||
|
||||
user = as && "-u #{as}"
|
||||
command = [fetch(:sudo, "sudo"), "-p '#{sudo_prompt}'", user, command].compact.join(" ")
|
||||
|
||||
run(command, options, &sudo_behavior_callback(block))
|
||||
if command
|
||||
command = sudo_command + " " + command
|
||||
run(command, options, &block)
|
||||
else
|
||||
return sudo_command
|
||||
end
|
||||
end
|
||||
|
||||
# Returns a Proc object that defines the behavior of the sudo
|
||||
|
@ -90,13 +104,13 @@ module Capistrano
|
|||
Proc.new do |ch, stream, out|
|
||||
if out =~ /^#{Regexp.escape(sudo_prompt)}/
|
||||
ch.send_data "#{self[:password]}\n"
|
||||
elsif out =~ /try again/
|
||||
elsif out =~ /^Sorry, try again/
|
||||
if prompt_host.nil? || prompt_host == ch[:server]
|
||||
prompt_host = ch[:server]
|
||||
logger.important out, "#{stream} :: #{ch[:server]}"
|
||||
reset! :password
|
||||
end
|
||||
else
|
||||
elsif fallback
|
||||
fallback.call(ch, stream, out)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -149,7 +149,7 @@ class ConfigurationActionsInvocationTest < Test::Unit::TestCase
|
|||
ch.stubs(:[]).with(:host).returns("capistrano")
|
||||
ch.stubs(:[]).with(:server).returns(server("capistrano"))
|
||||
@config.expects(:reset!).with(:password)
|
||||
@config.sudo_behavior_callback(nil)[ch, nil, "blah blah try again blah blah"]
|
||||
@config.sudo_behavior_callback(nil)[ch, nil, "Sorry, try again."]
|
||||
end
|
||||
|
||||
def test_sudo_behavior_callback_with_incorrect_password_on_subsequent_prompts
|
||||
|
@ -164,9 +164,9 @@ class ConfigurationActionsInvocationTest < Test::Unit::TestCase
|
|||
|
||||
@config.expects(:reset!).with(:password).times(2)
|
||||
|
||||
callback[ch, nil, "blah blah try again blah blah"]
|
||||
callback[ch2, nil, "blah blah try again blah blah"] # shouldn't call reset!
|
||||
callback[ch, nil, "blah blah try again blah blah"]
|
||||
callback[ch, nil, "Sorry, try again."]
|
||||
callback[ch2, nil, "Sorry, try again."] # shouldn't call reset!
|
||||
callback[ch, nil, "Sorry, try again."]
|
||||
end
|
||||
|
||||
def test_sudo_behavior_callback_should_defer_to_fallback_for_other_output
|
||||
|
|
Loading…
Add table
Reference in a new issue