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 {
for ($_[0]) {
# username followed by @
if (defined and !ref and /^ ([^\@]*?) \@ $/x) {
- return __PACKAGE__->new->connect($1);
+ return __PACKAGE__->new(target_user => $1)->connect;
}
}
return;
--- /dev/null
+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 = <STDIN>);
+
+ 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;
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;
};
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';