144 lines
3.0 KiB
Plaintext
144 lines
3.0 KiB
Plaintext
|
#!/usr/bin/perl
|
||
|
#
|
||
|
# /etc/ports/drivers/rsync: rsync(1) driver script for ports(8)
|
||
|
#
|
||
|
|
||
|
use warnings;
|
||
|
use strict;
|
||
|
use File::Basename;
|
||
|
|
||
|
my $host = '';
|
||
|
my $collection = '';
|
||
|
my $destination = '';
|
||
|
my %new_checkouts;
|
||
|
my %old_checkouts;
|
||
|
|
||
|
sub error
|
||
|
{
|
||
|
my $message = shift;
|
||
|
print "Error: $message ($!)\nUpdating failed\n";
|
||
|
exit 1;
|
||
|
}
|
||
|
|
||
|
sub warning
|
||
|
{
|
||
|
my $message = shift;
|
||
|
print "Warning: $message ($!)\n";
|
||
|
}
|
||
|
|
||
|
if ($#ARGV < 0)
|
||
|
{
|
||
|
print "Usage: $0 <file>\n";
|
||
|
exit 1;
|
||
|
}
|
||
|
|
||
|
open(FILE, $ARGV[0]) or error("Couldn't open $ARGV[0]");
|
||
|
while (<FILE>)
|
||
|
{
|
||
|
chomp;
|
||
|
if (/^host=(.*)/) { $host = $1; }
|
||
|
elsif (/^collection=(.*)/) { $collection = $1; }
|
||
|
elsif (/^destination=(.*)/) { $destination = $1; }
|
||
|
}
|
||
|
close(FILE);
|
||
|
|
||
|
if ($host eq '') { error("Host field not set in $ARGV[0]"); }
|
||
|
if ($collection eq '') { error("Collection field not set in $ARGV[0]"); }
|
||
|
if ($destination eq '') { error("Destination field not set in $ARGV[0]"); }
|
||
|
|
||
|
if (-e "$destination/.checkouts")
|
||
|
{
|
||
|
# read the old .checkouts file into memory
|
||
|
open(FILE, "$destination/.checkouts") or error("Couldn't read checkouts from $destination/.checkouts");
|
||
|
while (<FILE>)
|
||
|
{
|
||
|
chomp;
|
||
|
$old_checkouts{$_} = 1;
|
||
|
}
|
||
|
close(FILE);
|
||
|
}
|
||
|
|
||
|
print "Updating file list from " . $host . "::$collection\n";
|
||
|
|
||
|
# get the remote file list (new .checkouts)
|
||
|
open(PIPE, 'rsync -crz --no-human-readable ' . $host . '::' . $collection . '|') or error("Couldn't open pipe to rsync");
|
||
|
while (<PIPE>)
|
||
|
{
|
||
|
chomp;
|
||
|
|
||
|
next if /^MOTD:/; # ignore MOTD lines
|
||
|
s/^(.{43})//; # ignore the first 43 characters (mode, date etc...)
|
||
|
next if /^.$/; # ignore the . directory
|
||
|
|
||
|
$new_checkouts{$_} = 1;
|
||
|
}
|
||
|
close(PIPE);
|
||
|
error("Running rsync failed") unless $? == 0;
|
||
|
|
||
|
print "Updating collection " . basename($destination) . "\n";
|
||
|
|
||
|
# now really run rsync
|
||
|
open(PIPE, 'rsync -crz --no-human-readable --log-format "%o %n" ' . $host . "::$collection $destination|") or error("Couldn't open pipe to rsync");
|
||
|
while (<PIPE>)
|
||
|
{
|
||
|
chomp;
|
||
|
|
||
|
if (/^recv (.*)/)
|
||
|
{
|
||
|
if ($old_checkouts{$1})
|
||
|
{
|
||
|
s/^recv/ Edit/;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
s/^recv/ Checkout/;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
print $_ . "\n";
|
||
|
}
|
||
|
close(PIPE);
|
||
|
error("Running rsync failed") unless $? == 0;
|
||
|
|
||
|
# save new checkouts into .checkouts
|
||
|
open(FILE, ">$destination/.checkouts") or error("Couldn't save checkouts to $destination/.checkouts");
|
||
|
foreach my $checkout (sort keys %new_checkouts)
|
||
|
{
|
||
|
print FILE "$checkout\n";
|
||
|
}
|
||
|
close(FILE);
|
||
|
|
||
|
# use chroot as an additional safety measure when removing files
|
||
|
chroot($destination) or error("Couldn't chroot into $destination");
|
||
|
chdir('/');
|
||
|
|
||
|
# iterate through old checkouts, remove obsolete files
|
||
|
foreach my $checkout (sort keys %old_checkouts)
|
||
|
{
|
||
|
if (!$new_checkouts{$checkout})
|
||
|
{
|
||
|
if (-f $checkout)
|
||
|
{
|
||
|
print " Delete $checkout\n";
|
||
|
unlink($checkout) or warning("Couldn't delete $checkout");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# iterate through old checkouts, remove obsolete directories
|
||
|
foreach my $checkout (sort keys %old_checkouts)
|
||
|
{
|
||
|
if (!$new_checkouts{$checkout})
|
||
|
{
|
||
|
if (-d $checkout)
|
||
|
{
|
||
|
print " Delete $checkout\n";
|
||
|
rmdir($checkout) or warning("Couldn't delete $checkout");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
print "Finished successfully\n";
|
||
|
|
||
|
# End of file
|