1#
2# (c) Jan Gehring <jan.gehring@gmail.com>
3#
4# vim: set ts=2 sw=2 tw=0:
5# vim: set expandtab:
6
7package Rex::Interface::Exec::Base;
8
9use 5.010001;
10use strict;
11use warnings;
12use Carp;
13use Rex::Helper::Run;
14
15our $VERSION = '1.13.4'; # VERSION
16
17sub new {
18  my $that  = shift;
19  my $proto = ref($that) || $that;
20  my $self  = {@_};
21
22  bless( $self, $proto );
23
24  return $self;
25}
26
27sub exec { die("Must be implemented by Interface Class"); }
28
29sub _continuous_read {
30  my ( $self, $line, $option ) = @_;
31  my $cb = $option->{continuous_read} || undef;
32
33  if ( defined($cb) && ref($cb) eq 'CODE' ) {
34    &$cb($line);
35  }
36}
37
38sub _end_if_matched {
39  my ( $self, $line, $option ) = @_;
40  my $regex = $option->{end_if_matched} || undef;
41
42  if ( defined($regex) && ref($regex) eq 'Regexp' && $line =~ m/$regex/ ) {
43    return 1;
44  }
45  return;
46}
47
48sub execute_line_based_operation {
49  my ( $self, $line, $option ) = @_;
50
51  $self->_continuous_read( $line, $option );
52  return $self->_end_if_matched( $line, $option );
53}
54
55sub can_run {
56  my ( $self, $commands_to_check, $check_with_command ) = @_;
57
58  $check_with_command ||= "which";
59
60  my $exec  = Rex::Interface::Exec->create;
61  my $cache = Rex::get_cache();
62
63  for my $command ( @{$commands_to_check} ) {
64
65    my $cache_key_name = $cache->gen_key_name("can_run.cmd/$command");
66    if ( $cache->valid($cache_key_name) ) {
67      return $cache->get($cache_key_name);
68    }
69
70    my @output = Rex::Helper::Run::i_run "$check_with_command $command",
71      fail_ok => 1;
72
73    next if ( $? != 0 );
74    next if ( grep { /^no $command in/ } @output ); # for solaris
75
76    $cache->set( $cache_key_name, $output[0] );
77
78    return $output[0];
79  }
80
81  return undef;
82}
83
84sub direct_exec {
85  my ( $self, $exec, $option ) = @_;
86
87  Rex::Commands::profiler()->start("direct_exec: $exec");
88
89  my $class_name = ref $self;
90
91  Rex::Logger::debug("$class_name/executing: $exec");
92  my ( $out, $err ) = $self->_exec( $exec, $option );
93
94  Rex::Commands::profiler()->end("direct_exec: $exec");
95
96  Rex::Logger::debug($out) if ($out);
97  if ($err) {
98    Rex::Logger::debug("========= ERR ============");
99    Rex::Logger::debug($err);
100    Rex::Logger::debug("========= ERR ============");
101  }
102
103  if (wantarray) { return ( $out, $err ); }
104
105  return $out;
106}
107
108sub _exec {
109  my ($self) = @_;
110  my $class_name = ref $self;
111  die("_exec method must be overwritten by class ($class_name).");
112}
113
114sub shell {
115  my ($self) = @_;
116
117  Rex::Logger::debug("Detecting shell...");
118
119  my $cache = Rex::get_cache();
120  if ( $cache->valid("shell") ) {
121    Rex::Logger::debug( "Found shell in cache: " . $cache->get("shell") );
122    return Rex::Interface::Shell->create( $cache->get("shell") );
123  }
124
125  my %shells = Rex::Interface::Shell->get_shell_provider;
126  for my $shell ( keys %shells ) {
127    Rex::Logger::debug( "Searching for shell: " . $shell );
128    $shells{$shell}->require;
129    if ( $shells{$shell}->detect($self) ) {
130      Rex::Logger::debug( "Found shell and using: " . $shell );
131      $cache->set( "shell", $shell );
132      return Rex::Interface::Shell->create($shell);
133    }
134  }
135
136  return Rex::Interface::Shell->create("sh");
137}
138
1391;
140