File Coverage

lib/Rex/Commands/Upload.pm
Criterion Covered Total %
statement 69 80 86.2
branch 9 18 50.0
condition 3 9 33.3
subroutine 14 14 100.0
pod 1 1 100.0
total 96 122 78.6


line stmt bran cond sub pod time code
1             #
2             # (c) Jan Gehring
3             #
4              
5             =head1 NAME
6              
7             Rex::Commands::Upload - Upload a local file to a remote server
8              
9             =head1 DESCRIPTION
10              
11             With this module you can upload a local file via sftp to a remote host.
12              
13             =head1 SYNOPSIS
14              
15             task "upload", "remoteserver", sub {
16             upload "localfile", "/remote/file";
17             };
18              
19             =head1 EXPORTED FUNCTIONS
20              
21             =cut
22              
23             package Rex::Commands::Upload;
24              
25 45     45   611 use v5.12.5;
  45         150  
26 45     45   232 use warnings;
  45         89  
  45         2883  
27              
28             our $VERSION = '1.14.2.3'; # TRIAL VERSION
29              
30             require Rex::Exporter;
31 45     45   325 use File::Basename qw(basename);
  45         197  
  45         2471  
32 45     45   302 use Rex::Config;
  45         182  
  45         420  
33 45     45   373 use Rex::Commands::Fs;
  45         110  
  45         550  
34 45     45   327 use Rex::Interface::Fs;
  45         95  
  45         285  
35 45     45   1079 use Rex::Helper::Path;
  45         112  
  45         3182  
36 45     45   304 use Rex::Commands::MD5;
  45         140  
  45         275  
37 45     45   300 use Rex::Commands;
  45         103  
  45         285  
38 45     45   581 use Rex::Hook;
  45         106  
  45         2518  
39              
40 45     45   258 use vars qw(@EXPORT);
  45         90  
  45         1615  
41 45     45   257 use base qw(Rex::Exporter);
  45         103  
  45         28156  
42              
43             @EXPORT = qw(upload);
44              
45             =head2 upload($local, $remote)
46              
47             Perform an upload. If $remote is a directory the file will be uploaded to that directory.
48              
49             task "upload", "remoteserver", sub {
50             upload "localfile", "/path";
51             };
52              
53             This function supports the following L:
54              
55             =over 4
56              
57             =item before
58              
59             This gets executed before anything is done. All original parameters are passed to it.
60              
61             The return value of this hook overwrites the original parameters of the function-call.
62              
63             =item before_change
64              
65             This gets executed right before the new file is written. The local file name, and the remote file name are passed as parameters.
66              
67             =item after_change
68              
69             This gets executed right after the file was written. On top of the local file name, and the remote file name, any returned results are passed as parameters.
70              
71             =item after
72              
73             This gets executed right before the C function returns. All original parameters, and any results returned are passed to it.
74              
75             =back
76              
77              
78             =cut
79              
80             sub upload {
81              
82             #### check and run before hook
83             eval {
84 3         18 my @new_args = Rex::Hook::run_hook( upload => "before", @_ );
85 3 50       19 if (@new_args) {
86 0         0 @_ = @new_args;
87             }
88 3         20 1;
89 3 50   3 1 13 } or do {
90 0         0 die("Before-Hook failed. Canceling upload() action: $@");
91             };
92             ##############################
93              
94 3         15 my ( $local, $remote ) = @_;
95              
96 3         20 $local = resolv_path( $local, 1 );
97 3         11 $remote = resolv_path($remote);
98              
99 3         68 my $fs = Rex::Interface::Fs->create;
100              
101             # if remote not set, use name of local.
102             # must be done before the next line.
103 3 50       26 unless ($remote) {
104 0         0 $remote = basename($local);
105             }
106              
107 3         37 $local = Rex::Helper::Path::get_file_path( $local, caller() );
108              
109             # if there is a file called filename.environment then use this file
110             # ex:
111             # upload "files/hosts", "/etc/hosts";
112             #
113             # rex -E live ...
114             # will first look if files/hosts.live is available, if not it will
115             # use files/hosts
116              
117 3         16 my $old_local = $local; # for the upload location use the given name
118              
119 3 50 33     50 if ( Rex::Config->get_environment
120             && -f "$local." . Rex::Config->get_environment )
121             {
122 0         0 $local = "$local." . Rex::Config->get_environment;
123             }
124              
125 3 50       71 if ( !-f $local ) {
126 0         0 Rex::Logger::info("File Not Found: $local");
127 0         0 die("File $local not found.");
128             }
129              
130 3 50       70 if ( is_dir($remote) ) {
131 0         0 $remote = $remote . '/' . basename($old_local);
132             }
133              
134             Rex::get_current_connection()->{reporter}
135 3         29 ->report_resource_start( type => "upload", name => $remote );
136              
137             # first get local md5
138 3         9 my $local_md5;
139             LOCAL {
140 3     3   50 $local_md5 = md5($local);
141 3         84 };
142              
143 3 50       73 if ( !$local_md5 ) {
144 0         0 die("Error getting local md5 sum of $local");
145             }
146              
147             # than get remote md5 to test if we need to upload the file
148 3         19 my $remote_md5 = "";
149 3         21 eval { $remote_md5 = md5($remote); };
  3         47  
150              
151 3         22 my $__ret;
152              
153 3 50 33     70 if ( $local_md5 && $remote_md5 && $local_md5 eq $remote_md5 ) {
      33        
154 0         0 Rex::Logger::debug(
155             "local md5 and remote md5 are the same: $local_md5 eq $remote_md5. Not uploading."
156             );
157 0         0 $__ret = { changed => 0, ret => 0 };
158             }
159             else {
160              
161 3         56 Rex::Logger::debug("Uploading: $local to $remote");
162              
163             #### check and run before_change hook
164 3         59 Rex::Hook::run_hook( upload => "before_change", $local, $remote );
165             ##############################
166              
167 3         38 $__ret = $fs->upload( $local, $remote );
168              
169             #### check and run after_change hook
170 3         83 Rex::Hook::run_hook( upload => "after_change", $local, $remote, $__ret );
171             ##############################
172              
173 3         42 $__ret = { changed => 1, ret => $__ret };
174              
175             }
176              
177             #### check and run before hook
178 3         59 Rex::Hook::run_hook( upload => "after", @_, $__ret );
179             ##############################
180              
181 3 50       31 if ( $__ret->{changed} ) {
182             Rex::get_current_connection()->{reporter}->report(
183 3         25 changed => 1,
184             message => "File uploaded. old md5: $remote_md5 new md5: $local_md5"
185             );
186             }
187             else {
188 0         0 Rex::get_current_connection()->{reporter}->report( changed => 0, );
189             }
190              
191             Rex::get_current_connection()->{reporter}
192 3         32 ->report_resource_end( type => "upload", name => $remote );
193              
194 3         54 return $__ret;
195             }
196              
197             1;