#!/usr/bin/perl -w # ./sha2rsync.pl # is the filename of sha256sums fetched from server # is the filename of sha256sums generated locally # is the filename of the list of files to upload # and are files formatted as follows: #checksum *pathtofile # both files must be sorted based on pathtofile: the script performs # in-place merge (O(n+m)) of both lists based on that assumption. # and are parsed only once. # the script cannot currently handle any other type of input # the script will generate , a list of files suitable for # using with "rsync --files-from=" # if doesn't exist, all files in are added to the # upload list. # if exists, the files are added if: # - they're not present in # - they're present in AND their checksums differ # the script will clobber use strict; use warnings; use integer; die ("wrong number of arguments!") if ($#ARGV+1 != 3); my $shapat = qr/^(\w+) \*(.+)$/; my $rlist = $ARGV[0]; my $llist = $ARGV[1]; my $torsync = $ARGV[2]; my $rlist_fh = undef; my $llist_fh = undef; my $torsync_fh = undef; open($torsync_fh, ">", $torsync) or die("can't create output file!"); open($llist_fh, "<", $llist) or die("can't read local list!"); open($rlist_fh, "<", $rlist) or $rlist_fh = undef; my $lline = readline($llist_fh); my $rline = defined($rlist_fh) ? readline($rlist_fh) : undef; MAINLOOP: while () { # run this loop as long as we have content from both rlist and llist last (MAINLOOP) unless (defined($lline) && defined($rline)); chomp($lline); my ($lcsum, $lfname) = $lline =~ $shapat; chomp($rline); my ($rcsum, $rfname) = $rline =~ $shapat; # compare current remote and local filenames my $rtlcmp = ($rfname cmp $lfname); while ($rtlcmp < 0) { # remote fname is before current local fname: remote file doesn't exist localy $rline = readline($rlist_fh); next (MAINLOOP); } while ($rtlcmp > 0) { # remote fname is after current local fname: local file doesn't exist remotely add_file($lfname); # add lfname to upload list $lline = readline($llist_fh); next (MAINLOOP); } # if we end here, rtlcmp == 0: fnames matched, the file exist localy and remotely # fetch next line of both streams for the next iteration $lline = readline($llist_fh); $rline = readline($rlist_fh); # and skip if csums match next (MAINLOOP) if ($lcsum eq $rcsum); # otherwise add the file as it's different add_file($lfname); } # deal with remainder of llist if any while (defined($lline)) { chomp($lline); my ($lcsum, $lfname) = $lline =~ $shapat; add_file($lfname); $lline = readline($llist_fh); } # unconditionally add some mandatory files to rsynclist # add them last so they're transferred last: if everything else transferred correctly my @feeds = qw(base luci packages routing telephony); my @additional_files; for my $feed (@feeds) { push @additional_files, ( "$feed/packages.adb.asc", "$feed/packages.adb.sig", "$feed/Packages.asc", "$feed/Packages.sig", ); } push @additional_files, qw( sha256sums.asc sha256sums.sig sha256sums ); (my $basedir = $llist) =~ s!/[^/]+$!!; foreach my $file (@additional_files) { if (-f "$basedir/$file") { add_file($file); } } exit (0); sub add_file { my $fname = shift; print $torsync_fh "$fname\n"; }