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   761 use v5.12.5;
  45         161  
26 45     45   241 use warnings;
  45         105  
  45         2877  
27              
28             our $VERSION = '1.14.3'; # VERSION
29              
30             require Rex::Exporter;
31 45     45   312 use File::Basename qw(basename);
  45         238  
  45         2338  
32 45     45   286 use Rex::Config;
  45         104  
  45         499  
33 45     45   351 use Rex::Commands::Fs;
  45         91  
  45         471  
34 45     45   299 use Rex::Interface::Fs;
  45         105  
  45         301  
35 45     45   1100 use Rex::Helper::Path;
  45         131  
  45         3173  
36 45     45   280 use Rex::Commands::MD5;
  45         87  
  45         780  
37 45     45   279 use Rex::Commands;
  45         116  
  45         255  
38 45     45   553 use Rex::Hook;
  45         108  
  45         2498  
39              
40 45     45   265 use vars qw(@EXPORT);
  45         100  
  45         1581  
41 45     45   226 use base qw(Rex::Exporter);
  45         85  
  45         27143  
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         22 my @new_args = Rex::Hook::run_hook( upload => "before", @_ );
85 3 50       15 if (@new_args) {
86 0         0 @_ = @new_args;
87             }
88 3         27 1;
89 3 50   3 1 18 } or do {
90 0         0 die("Before-Hook failed. Canceling upload() action: $@");
91             };
92             ##############################
93              
94 3         17 my ( $local, $remote ) = @_;
95              
96 3         23 $local = resolv_path( $local, 1 );
97 3         20 $remote = resolv_path($remote);
98              
99 3         89 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       20 unless ($remote) {
104 0         0 $remote = basename($local);
105             }
106              
107 3         39 $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         22 my $old_local = $local; # for the upload location use the given name
118              
119 3 50 33     66 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       49 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       57 if ( is_dir($remote) ) {
131 0         0 $remote = $remote . '/' . basename($old_local);
132             }
133              
134             Rex::get_current_connection()->{reporter}
135 3         18 ->report_resource_start( type => "upload", name => $remote );
136              
137             # first get local md5
138 3         8 my $local_md5;
139             LOCAL {
140 3     3   45 $local_md5 = md5($local);
141 3         83 };
142              
143 3 50       94 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         27 my $remote_md5 = "";
149 3         24 eval { $remote_md5 = md5($remote); };
  3         50  
150              
151 3         25 my $__ret;
152              
153 3 50 33     118 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         48 Rex::Logger::debug("Uploading: $local to $remote");
162              
163             #### check and run before_change hook
164 3         54 Rex::Hook::run_hook( upload => "before_change", $local, $remote );
165             ##############################
166              
167 3         39 $__ret = $fs->upload( $local, $remote );
168              
169             #### check and run after_change hook
170 3         91 Rex::Hook::run_hook( upload => "after_change", $local, $remote, $__ret );
171             ##############################
172              
173 3         48 $__ret = { changed => 1, ret => $__ret };
174              
175             }
176              
177             #### check and run before hook
178 3         53 Rex::Hook::run_hook( upload => "after", @_, $__ret );
179             ##############################
180              
181 3 50       27 if ( $__ret->{changed} ) {
182             Rex::get_current_connection()->{reporter}->report(
183 3         37 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         31 ->report_resource_end( type => "upload", name => $remote );
193              
194 3         58 return $__ret;
195             }
196              
197             1;