File Coverage

blib/lib/WE_Frontend/Publish/Rsync.pm
Criterion Covered Total %
statement 85 168 50.6
branch 27 80 33.7
condition 10 33 30.3
subroutine 9 10 90.0
pod 0 2 0.0
total 131 293 44.7


line stmt bran cond sub pod time code
1             # -*- perl -*-
2              
3             #
4             # $Id: Rsync.pm,v 1.16 2004/12/23 10:53:41 eserte Exp $
5             # Author: Slaven Rezic
6             #
7             # Copyright (C) 2002 Online Office Berlin. All rights reserved.
8             # Copyright (C) 2002 Slaven Rezic.
9             # This is free software; you can redistribute it and/or modify it under the
10             # terms of the GNU General Public License, see the file COPYING.
11              
12             #
13             # Mail: slaven@rezic.de
14             # WWW: http://we-framework.sourceforge.net
15             #
16              
17             package WE_Frontend::Publish::Rsync;
18              
19             # package WE_Frontend::Main;
20              
21 2     2   1106 use strict;
  2         5  
  2         109  
22 2     2   10 use vars qw($VERSION);
  2         4  
  2         164  
23             $VERSION = sprintf("%d.%02d", q$Revision: 1.16 $ =~ /(\d+)\.(\d+)/);
24              
25 2     2   569 use WE_Frontend::Publish;
  2         5  
  2         47  
26              
27 2     2   14 use File::Basename;
  2         4  
  2         4309  
28              
29             sub _rsyncexe {
30 2     2   4 my $self = shift;
31 2 50 33     8 ($self->Config->staging->stagingext &&
32             $self->Config->staging->stagingext->{'rsyncexe'}
33             ? $self->Config->staging->stagingext->{'rsyncexe'}
34             : 'rsync'
35             );
36             }
37              
38             sub _deleteold {
39 2     2   5 my $self = shift;
40 2 50 33     7 ($self->Config->staging->stagingext &&
41             $self->Config->staging->stagingext->{'deleteold'}
42             ? $self->Config->staging->stagingext->{'deleteold'}
43             : 0
44             );
45             }
46              
47             # for compatibility:
48             sub WE_Frontend::Main::publish_rsync {
49 2     2   13 my($self, %args) = @_;
50 2         14 publish_rsync($self, %args);
51             }
52              
53             sub publish_rsync {
54 2     2 0 10 my($self, %args) = @_;
55              
56 2         15 my $do_exec = !delete $args{-n};
57 2         10 my $v = delete $args{-verbose};
58 2         13 my $since = delete $args{-since};
59 2 100       13 if (defined $since) {
60 1         27 warn "The -since option is ignored with publish_rsync!";
61             }
62 2         13 my $liveuser = $self->Config->staging->user;
63 2         20 my $livedirectory = $self->Config->staging->directory;
64 2         21 my $livecgidirectory = $self->Config->staging->cgidirectory;
65 2         19 my $livehost = $self->Config->staging->host;
66 2         20 my $pubhtmldir = $self->Config->paths->pubhtmldir;
67 2         20 my $cgidir = $self->Config->paths->cgidir;
68 2         40 my @extracgi = (ref $self->Config->project->stagingextracgi eq 'ARRAY'
69 2 50       22 ? @{ $self->Config->project->stagingextracgi }
70             : ()
71             );
72             # rsync 2.5.1 seems to be reliable, but previous version could hang.
73             # So give the user the chance to change the rsync executable path.
74 2         42 my $rsyncexe = $self->WE_Frontend::Publish::Rsync::_rsyncexe;
75 2         33 my $deleteold = $self->WE_Frontend::Publish::Rsync::_deleteold;
76              
77 2 50 33     29 if (defined $liveuser && !defined $livehost) {
78 0         0 die "\$livehost should be also set if \$liveuser is set";
79             }
80 2 50 33     14 if (!defined $pubhtmldir || $pubhtmldir eq '') {
81 0         0 die "The publish html directory is missing (config member WEsiteinfo->paths->pubhtmldir)";
82             }
83 2 50 33     27 if (@extracgi && (!defined $livecgidirectory || $livecgidirectory eq '')) {
      33        
84 0         0 die "Extra CGI scripts are defined (@extracgi),
85             but the WEsiteinfo->staging->cgidirectory config is missing";
86             }
87              
88 2 50       6 if ($v) {
89 0         0 print <
90             Using Rsync Protocol.
91 0 0       0 Rsync remote host: @{[ defined $livehost ? $livehost : "localhost" ]}
  0 0       0  
92 0 0       0 Rsync remote user: @{[ defined $liveuser ? $liveuser : "current" ]}
93             Rsync remote directory: $livedirectory
94 0 0       0 @{[ @extracgi ? "Rsync remote CGI directory: $livecgidirectory" : "" ]}
95             @{[ $deleteold ? "Delete unused remote files" : "Leave unused remote files" ]}
96             EOF
97             }
98              
99             # XXX same as in Rdist.pm
100 2         5 my @cvs_exclude_pat = @{ WE_Frontend::Publish->cvs_exclude };
  2         23  
101 2         9 my @we_exclude_pat = @{ WE_Frontend::Publish->we_exclude };
  2         10  
102 2         13 my @exclude_pat = (@cvs_exclude_pat, @we_exclude_pat);
103 2         5 my @exclude;
104             my %additional;
105 2 50       13 if ($self->Config->project->stagingexceptpat) {
106 0         0 push @exclude_pat, @{ $self->Config->project->stagingexceptpat };
  0         0  
107             }
108 2 50       24 if ($self->Config->project->stagingexcept) {
109 0         0 push @exclude, @{ $self->Config->project->stagingexcept };
  0         0  
110             }
111             #XXX not yet used:
112 2 50       24 if ($self->Config->project->stagingadditional) {
113 0         0 %additional = %{ $self->Config->project->stagingadditional };
  0         0  
114             }
115              
116 2         18 my @directories;
117             my @files;
118              
119             # first create target directories
120 0         0 my @mkdircmd;
121 2         7 $mkdircmd[0] = "mkdir -p $livedirectory";
122 2 50       6 if (@extracgi) {
123 2         13 $mkdircmd[0] .= "; mkdir -p $livecgidirectory";
124             }
125 2 50       8 if (defined $livehost) {
126 0         0 unshift @mkdircmd, ('ssh', '-l', $liveuser, $livehost);
127             }
128              
129 2 50       8 if (!$do_exec) {
130 0         0 print join(" ", @mkdircmd), "\n";
131             } else {
132 2         7 _system(@mkdircmd);
133             }
134              
135 2         20 my($rsync1, $rsync2, $src1, $src2, $cmd, $cmd2);
136             # Don't spread confusion! Now the rsync commands are constructed.
137             # They consist of
138             # $cmd = $rsync1 $src1 $rsync2 targetdirectory1
139             # $cmd2 = $rsync1 $src2 $rsync2 targetdirectory2
140              
141 2         130 $rsync1 = $rsyncexe; # command and first parameters
142 2 50       19 if (!$do_exec) {
143 0         0 $rsync1 .= ' -n';
144             }
145 2         11 $rsync1 .= " -v"; # be verbose
146 2         61 $rsync1 .= " -l"; # XXX check for destination system and revert to -L if necessary
147 2 50       9 if (defined $livehost) {
148 0         0 $rsync1 .= " -z"; # compress if remote
149 0         0 $rsync1 .= " -e ssh"; # just in case there's an old rsync defaulting to rsh
150             }
151 2 50       15 if ($deleteold) {
152 0         0 $rsync1 .= " --delete";
153             }
154              
155 2         203 $src1 = ""
156             # in/excludes
157             . " " . join(" ", map "--exclude \"$_\"", @exclude_pat)
158             . " " . join(" ", map "--exclude \"/$_\"", @exclude)
159             # source
160             . " -r $pubhtmldir/";
161              
162 2         10 $src2 = ""
163             # in/excludes
164             . " " . join(" ", map "--exclude \"/$_\"", @exclude)
165             . " --exclude .cvsignore"
166             # source
167 2         33 . " " . join(" ", map { "$cgidir/$_" } @extracgi);
168              
169 2         8 $rsync2 = " "; # destination without directory
170 2 50 33     16 if (defined $liveuser && defined $livehost) {
171 0         0 $rsync2 .= " $liveuser\@$livehost:";
172             }
173              
174 2 50 33     136 if ($self->Config->project->projectext &&
175             $self->Config->project->projectext->{'extrastagingsub'}) {
176 0 0       0 if ($do_exec) {
177 0         0 $self->Config->project->projectext->{'extrastagingsub'}->();
178             } else {
179 0         0 print "Call subroutine " . $self->Config->project->projectext->{'extrastagingsub'} . "\n";
180             }
181             }
182              
183             # rsync is often in /usr/local/bin
184 2         120 local $ENV{PATH} = $ENV{PATH} . ":/usr/local/bin";
185              
186 2         19 $cmd .= "$rsync1$src1$rsync2$livedirectory";
187 2 50       18 if (!$do_exec) {
188 0         0 print "exec $cmd\n";
189             } else {
190 2 50 33     18 if (defined $v && $v > 1) {
191 0         0 print "Command: $cmd\n";
192             }
193 2         13 _system($cmd);
194 2 50       39 if ($?/256 != 0) {
195 0         0 my $error = "Error code @{[ $?/256 ]} while doing: $cmd
  0         0  
196             PATH is $ENV{PATH}";
197 0 0       0 print "$error\n" if $v;
198 0         0 die $error;
199             }
200             }
201              
202 2 50       20 if (@extracgi) {
203 2         13 $cmd2 = "$rsync1$src2$rsync2$livecgidirectory";
204 2 50       27 if (!$do_exec) {
205 0         0 print "exec $cmd2\n";
206             } else {
207 2 50 33     20 if (defined $v && $v > 1) {
208 0         0 print "Command: $cmd2\n";
209             }
210 2         18 _system($cmd2);
211 2 50       89 if ($?/256 != 0) {
212 0         0 my $error = "Error code @{[ $?/256 ]} while doing: $cmd2
  0         0  
213             PATH is $ENV{PATH}";
214 0 0       0 print "$error\n" if $v;
215 0         0 die $error;
216             }
217             }
218             }
219              
220 2         730 return;
221             }
222              
223             # Apache.pm-friendly system()
224             sub _system {
225 6     6   90 my $cmd = shift;
226 6         30725 open(SYS, "$cmd|");
227 6         50160 while() {
228 27         194873 print $_;
229             }
230 6         558 close SYS;
231             }
232              
233             sub publish_files {
234 0     0 0   my($self, $selected_files, %args) = @_;
235              
236 0           my $do_exec = !delete $args{-n};
237 0           my $v = delete $args{-verbose};
238              
239 0           require File::Temp;
240              
241             # rsync is often in /usr/local/bin
242 0           local $ENV{PATH} = $ENV{PATH} . ":/usr/local/bin";
243              
244 0           my(@files, %dir);
245 0           for my $file (@$selected_files) {
246 0           push @files, $file;
247 0           my @p = split m|/|, $file;
248 0           for my $i (0 .. $#p-1) {
249 0           $dir{join "/", @p[0 .. $i]}++;
250             }
251             }
252              
253 0           my($fh, $file) = File::Temp::tempfile(UNLINK => 1);
254 0           my @all_files = (keys(%dir), @files);
255 0           my $include = join("\n", map { "/$_" } sort @all_files) . "\n";
  0            
256 0           print $fh $include;
257 0           close $fh;
258              
259 0 0         if ($v) {
260 0           print STDERR "Include:\n$include\n";
261             }
262              
263             #my @rsync_args = ("-r", "-a", "-p", "-t"); # XXX -a?
264 0           my @rsync_args = ("-rptgoD", "-vz", "-L", "--copy-unsafe-links"); # XXX -a?
265 0 0         if (!$do_exec) { push @rsync_args, "-n" }
  0            
266             # if ($v) { push @rsync_args, "-Pv" }
267 0 0         if ($self->WE_Frontend::Publish::Rsync::_deleteold) {
268 0           push @rsync_args, "--delete";
269             }
270            
271 0           my $liveuser = $self->Config->staging->user;
272 0           my $livehost = $self->Config->staging->host;
273 0           my $liversakey = $self->Config->staging->rsakey;
274              
275 0 0 0       if (defined $liveuser && defined $liversakey){
276 0           push @rsync_args, "-e ssh -l $liveuser -i $liversakey";
277             }
278              
279 0           my $from = $self->Config->paths->pubhtmldir;
280 0           $from =~ s{ (?
281              
282 0           my $to = $self->Config->staging->directory;
283 0           $to =~ s{ (?
284            
285 0 0         if (defined $livehost) {
286 0           $to = "$livehost:$to";
287             }
288              
289 0           my @cmd = ($self->WE_Frontend::Publish::Rsync::_rsyncexe, @rsync_args);
290 0           push @cmd, ("--include-from=$file", "--exclude=**");
291 0           push @cmd, $from, $to;
292 0           warn "@cmd";
293              
294 0           my $ret = 1;
295 0 0         if ($do_exec) {
296 0 0         system(@cmd) and do {
297 0           warn "Error code is $?, please see man rsync for explanation.
298             PATH is $ENV{PATH}";
299 0           $ret = 0;
300             };
301             }
302              
303 0           unlink $file;
304              
305 0           $ret;
306             }
307              
308             1;
309              
310             __END__