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 has options => (is => 'ro', required => 1);
14 has env => (is => 'ro', required => 1);
16 has log_level => (is => 'rw');
18 has stdin => (is => 'lazy');
19 has stdout => (is => 'lazy');
20 has stderr => (is => 'lazy');
22 sub _build_stdin { shift->env->{stdin} }
23 sub _build_stdout { shift->env->{stdout} }
24 sub _build_stderr { shift->env->{stderr} }
26 has config => (is => 'lazy');
30 my $file = $self->options->{config} || '.tak/default.conf';
32 Config::Settings->new->parse_file($file);
38 has local_client => (is => 'lazy');
40 sub _build_local_client {
42 Tak::Client::Router->new(service => Tak::Router->new);
51 my @level_names = qw(fatal error warn info debug trace);
52 my $options = $self->options;
53 my $level = 2 + ($options->{verbose}||0) - ($options->{quiet}||0);
54 my $upto = $level_names[$level];
55 $self->log_level($upto);
56 Log::Contextual::set_logger(
57 Log::Contextual::SimpleLogger->new({
59 coderef => sub { print STDERR '<local> ', @_ },
65 my ($self, $string, $argv) = @_;
66 my @spec = split ';', $string;
68 GetOptionsFromArray($argv, \%opt, @spec);
74 my @argv = @{$self->env->{argv}};
75 unless (@argv && $argv[0]) {
76 return $self->local_help;
78 my $cmd = shift(@argv);
79 if (my $code = $self->can("local_$cmd")) {
80 return $self->_run($cmd, $code, @argv);
81 } elsif ($code = $self->can("each_$cmd")) {
82 return $self->_run_each($cmd, $code, @argv);
84 $self->stderr->print("No such command: ${cmd}\n");
85 return $self->local_help;
89 my ($self, $file) = @_;
90 $self->_load_file_in_my_script($file);
95 $self->stderr->print("Help unimplemented\n");
98 sub _maybe_parse_options {
99 my ($self, $code, $argv) = @_;
100 if (my $proto = prototype($code)) {
101 $self->_parse_options($proto, $argv);
108 my ($self, $cmd, $code, @argv) = @_;
109 my $opt = $self->_maybe_parse_options($code, \@argv);
110 $self->$code($opt, @argv);
114 my ($self, $cmd, $code, @argv) = @_;
115 my @targets = $self->_host_list_for($cmd);
117 $self->stderr->print("No targets for ${cmd}\n");
120 my $opt = $self->_maybe_parse_options($code, \@argv);
121 if (my $prepare = $self->can("prepare_$cmd")) {
122 $self->$prepare($opt, @argv);
124 $self->local_client->ensure(connector => 'Tak::ConnectorService');
125 foreach my $target (@targets) {
126 my $remote = $self->_connection_to($target);
127 $self->$code($remote, $opt, @argv);
132 my ($self, $command) = @_;
133 my @host_spec = map split(' ', $_), @{$self->options->{host}};
137 my ($self, $target) = @_;
138 log_debug { "Connecting to ${target}" };
139 my @path = $self->local_client->do(
140 connector => create => $target, log_level => $self->log_level
142 my ($local, $remote) =
143 map $self->local_client->curry(connector => connection => @path => $_),
145 $local->ensure(module_sender => 'Tak::ModuleSender');
147 module_loader => 'Tak::ModuleLoader',
148 expose => { module_sender => [ 'remote', 'module_sender' ] }
150 $remote->do(module_loader => 'enable');
151 log_debug { "Setup connection to ${target}" };
152 Tak::Client::RemoteRouter->new(
153 %$remote, host => $target