From: Matt S Trout Date: Wed, 18 Jul 2012 18:39:35 +0000 (+0000) Subject: working automatic prompting X-Git-Tag: v0.002002~11 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=scpubgit%2FObject-Remote.git;a=commitdiff_plain;h=1b315002f7e87ede72405474f0efab1864769fac working automatic prompting --- diff --git a/lib/Object/Remote/Connector/LocalSudo.pm b/lib/Object/Remote/Connector/LocalSudo.pm index aa19ced..0ff34b3 100644 --- a/lib/Object/Remote/Connector/LocalSudo.pm +++ b/lib/Object/Remote/Connector/LocalSudo.pm @@ -1,20 +1,32 @@ package Object::Remote::Connector::LocalSudo; use Symbol qw(gensym); +use Module::Runtime qw(use_module); use IPC::Open3; use Moo; extends 'Object::Remote::Connector::Local'; -has password_callback => (is => 'ro'); +has target_user => (is => 'ro', required => 1); + +has password_callback => (is => 'lazy'); + +sub _build_password_callback { + my ($self) = @_; + my $pw_prompt = use_module('Object::Remote::Prompt')->can('prompt_pw'); + my $user = $self->target_user; + return sub { + $pw_prompt->("sudo password for ${user}", undef, { cache => 1 }) + } +} sub _sudo_perl_command { - my ($self, $target_user) = @_; + my ($self) = @_; return - 'sudo', '-S', '-u', $target_user, '-p', "[sudo] password please\n", + 'sudo', '-S', '-u', $self->target_user, '-p', "[sudo] password please\n", 'perl', '-MPOSIX=dup2', '-e', 'print STDERR "GO\n"; exec(@ARGV);', - $self->_perl_command($target_user); + $self->_perl_command($self->target_user); } sub _start_perl { @@ -70,7 +82,7 @@ push @Object::Remote::Connection::Guess, sub { for ($_[0]) { # username followed by @ if (defined and !ref and /^ ([^\@]*?) \@ $/x) { - return __PACKAGE__->new->connect($1); + return __PACKAGE__->new(target_user => $1)->connect; } } return; diff --git a/lib/Object/Remote/Prompt.pm b/lib/Object/Remote/Prompt.pm new file mode 100644 index 0000000..29a8661 --- /dev/null +++ b/lib/Object/Remote/Prompt.pm @@ -0,0 +1,72 @@ +package Object::Remote::Prompt; + +use strictures 1; +use IO::Handle; +use Exporter; + +our @EXPORT = qw(prompt prompt_pw); + +our ($prompt, $prompt_pw); + +sub _local_prompt { + _local_prompt_core(0, @_); +} + +sub _local_prompt_pw { + _local_prompt_core(1, @_); +} + +our %Prompt_Cache; + +sub _local_prompt_core { + my ($pw, $message, $default, $opts) = @_; + + if ($opts->{cache} and my $hit = $Prompt_Cache{$message}) { + return $hit; + } + + STDOUT->autoflush(1); + + system('stty -echo') if $pw; + + print STDOUT "${message}: "; + chomp(my $res = ); + + print STDOUT "\n" if $pw; + system('stty echo') if $pw; + + $Prompt_Cache{$message} = $res if $opts->{cache}; + + return $res; +} + +sub prompt { + die "User input wanted - $_[0] - but no prompt available" + unless $prompt; + goto &$prompt; +} + +sub prompt_pw { + die "User input wanted - $_[0] - but no password prompt available" + unless $prompt_pw; + goto &$prompt_pw; +} + +if (-t STDIN) { + $prompt = \&_local_prompt; + $prompt_pw = \&_local_prompt_pw; +} + +sub set_local_prompt_command { + ($prompt, $prompt_pw) = @_; + return; +} + +sub maybe_set_prompt_command_on { + return unless $prompt; + my ($conn) = @_; + $conn->remote_sub('Object::Remote::Prompt::set_local_prompt_command') + ->($prompt, $prompt_pw); +} + +1; diff --git a/lib/Object/Remote/Role/Connector/PerlInterpreter.pm b/lib/Object/Remote/Role/Connector/PerlInterpreter.pm index 312ee4c..f304a8d 100644 --- a/lib/Object/Remote/Role/Connector/PerlInterpreter.pm +++ b/lib/Object/Remote/Role/Connector/PerlInterpreter.pm @@ -26,6 +26,8 @@ around connect => sub { class => 'Object::Remote::ModuleLoader', args => { module_sender => $self->module_sender } )->disarm_free; + require Object::Remote::Prompt; + Object::Remote::Prompt::maybe_set_prompt_command_on($conn); return $conn; }; diff --git a/xt/local-sudo.t b/xt/local-sudo.t index b7e28c0..ef2f1fd 100644 --- a/xt/local-sudo.t +++ b/xt/local-sudo.t @@ -4,21 +4,12 @@ use Test::More; use lib 'xt/lib'; use Object::Remote; -use Object::Remote::Connector::LocalSudo; my $user = $ENV{TEST_SUDOUSER} or plan skip_all => q{Requires TEST_SUDOUSER to be set}; -my $pw; - -my $connector = Object::Remote::Connector::LocalSudo->new( - password_callback => sub { - $pw ||= prompt 'Sudo password', -echo => '*'; - } -); - -my $remote = TestFindUser->new::on($connector->connect($user)); +my $remote = TestFindUser->new::on("${user}\@"); my $remote_user = $remote->user; like $remote_user, qr/^\d+$/, 'returned an int'; isnt $remote_user, $<, 'ran as different user';