3 use Getopt::Long qw(GetOptionsFromArray :config posix_defaults bundling);
6 use Tak::Client::Router;
7 use Tak::Client::RemoteRouter;
9 use Log::Contextual qw(:log);
10 use Log::Contextual::SimpleLogger;
13 with 'Tak::Role::ScriptActions';
15 has options => (is => 'ro', required => 1);
16 has env => (is => 'ro', required => 1);
18 has log_level => (is => 'rw');
20 has stdin => (is => 'lazy');
21 has stdout => (is => 'lazy');
22 has stderr => (is => 'lazy');
24 sub _build_stdin { shift->env->{stdin} }
25 sub _build_stdout { shift->env->{stdout} }
26 sub _build_stderr { shift->env->{stderr} }
28 has config => (is => 'lazy');
32 my $file = $self->options->{config} || '.tak/default.conf';
34 Config::Settings->new->parse_file($file);
40 has local_client => (is => 'lazy');
42 sub _build_local_client {
44 Tak::Client::Router->new(service => Tak::Router->new);
53 my @level_names = qw(fatal error warn info debug trace);
54 my $options = $self->options;
55 my $level = 2 + ($options->{verbose}||0) - ($options->{quiet}||0);
56 my $upto = $level_names[$level];
57 $self->log_level($upto);
58 Log::Contextual::set_logger(
59 Log::Contextual::SimpleLogger->new({
61 coderef => sub { print STDERR '<local> ', @_ },
67 my ($self, $string, $argv) = @_;
68 my @spec = split ';', $string;
70 GetOptionsFromArray($argv, \%opt, @spec);
76 my @argv = @{$self->env->{argv}};
77 unless (@argv && $argv[0]) {
78 return $self->local_help;
80 my $cmd = shift(@argv);
82 if (my $code = $self->can("local_$cmd")) {
83 return $self->_run($cmd, $code, @argv);
84 } elsif ($code = $self->can("each_$cmd")) {
85 return $self->_run_each($cmd, $code, @argv);
86 } elsif ($code = $self->can("every_$cmd")) {
87 return $self->_run_every($cmd, $code, @argv);
89 $self->stderr->print("No such command: ${cmd}\n");
90 return $self->local_help;
94 my ($self, $file) = @_;
95 $self->_load_file_in_my_script($file);
100 $self->stderr->print("Help unimplemented\n");
103 sub _maybe_parse_options {
104 my ($self, $code, $argv) = @_;
105 if (my $proto = prototype($code)) {
106 $self->_parse_options($proto, $argv);
113 my ($self, $cmd, $code, @argv) = @_;
114 my $opt = $self->_maybe_parse_options($code, \@argv);
115 $self->$code($opt, @argv);
119 my ($self, $cmd, $code, @argv) = @_;
120 my @targets = $self->_host_list_for($cmd);
122 $self->stderr->print("No targets for ${cmd}\n");
125 my $opt = $self->_maybe_parse_options($code, \@argv);
126 $self->local_client->ensure(connector => 'Tak::ConnectorService');
127 foreach my $target (@targets) {
128 my $remote = $self->_connection_to($target);
129 $self->$code($remote, $opt, @argv);
134 my ($self, $cmd, $code, @argv) = @_;
135 my @targets = $self->_host_list_for($cmd);
137 $self->stderr->print("No targets for ${cmd}\n");
140 my $opt = $self->_maybe_parse_options($code, \@argv);
141 $self->local_client->ensure(connector => 'Tak::ConnectorService');
142 my @remotes = map $self->_connection_to($_), @targets;
143 $self->$code(\@remotes, $opt, @argv);
147 my ($self, $command) = @_;
148 my @host_spec = map split(' ', $_), @{$self->options->{host}};
149 unshift(@host_spec, '-') if $self->options->{local};
154 my ($self, $target) = @_;
155 log_debug { "Connecting to ${target}" };
156 my @path = $self->local_client->do(
157 connector => create => $target, log_level => $self->log_level
159 my ($local, $remote) =
160 map $self->local_client->curry(connector => connection => @path => $_),
162 $local->ensure(module_sender => 'Tak::ModuleSender');
164 module_loader => 'Tak::ModuleLoader',
165 expose => { module_sender => [ 'remote', 'module_sender' ] }
167 $remote->do(module_loader => 'enable');
168 log_debug { "Setup connection to ${target}" };
169 Tak::Client::RemoteRouter->new(
170 %$remote, host => $target