1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
#!/usr/bin/perl -w
# ./sha2rsync.pl <rlist> <llist> <torsync>
# <rlist> is the filename of sha256sums fetched from server
# <llist> is the filename of sha256sums generated locally
# <torsync> is the filename of the list of files to upload
# <rlist> and <llist> 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.
# <rlist> and <llist> are parsed only once.
# the script cannot currently handle any other type of input
# the script will generate <torsync>, a list of files suitable for
# using with "rsync --files-from=<torsync>"
# if <rlist> doesn't exist, all files in <llist> are added to the
# upload list.
# if <rlist> exists, the <llist> files are added if:
# - they're not present in <rlist>
# - they're present in <rlist> AND their checksums differ
# the script will clobber <torsync>
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 @additional_files = qw(
packages/Packages.asc
packages/Packages.sig
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";
}
|