]> git.pld-linux.org Git - projects/distfiles.git/blame - file-fetcher.pl
- make vim modeline match file style
[projects/distfiles.git] / file-fetcher.pl
CommitLineData
7ebf9245 1#!/usr/bin/perl -w
b396edfa 2# $Id$
7ebf9245 3
56ea0f1e 4use IPC::Run qw(run);
5
7a0595ea 6$commits_list = "pld-cvs-commit\@lists.pld-linux.org";
7ebf9245 7
b5c674c5 8$spool_dir = "./spool";
01806192
MM
9$copy_dir = "src"; # relative to ftp root
10$no_url_dir = "./upload";
11$df_server = "distfiles.pld-linux.org";
51fe5d4e 12$df_scp = "plddist\@ep09.pld-linux.org:ftp";
62f7358e 13$user_agent = "PLD/distfiles";
7ebf9245
MM
14
15@md5 = ();
ccbaa374 16@url = ();
7ebf9245
MM
17$problems = "";
18$normal_out = "";
19$requester = "";
20$file = "";
47f8fda7
MM
21$fetched_count = 0;
22$force_reply = 0;
bca91c1b 23$req_login = "nobody";
cba859d3 24$spec = "";
44cd280f 25@files = ();
7ebf9245
MM
26
27# try lookup some file in spool, exit if it cannot be done
28sub find_file_in_spool()
29{
30 opendir(DIR, $spool_dir) || die "can't opendir $spool_dir: $!";
31 while (1) {
32 my $f = readdir(DIR);
33 defined $f or last;
34 -f "$spool_dir/$f" or next;
35 $file = "$spool_dir/$f";
36 last;
37 }
38 closedir(DIR);
39
40 exit 0 if ($file eq "");
41}
42
43# read file from spool, and try unlink it. if cannot unlink -- exit
576dff03 44# sets $requester (email), $problems, @md5 (arrays of md5's)
ccbaa374 45# and @url (map from md5 to urls)
7ebf9245
MM
46sub read_spool_file()
47{
48 open(F, "< $file") || exit 0;
49 $requester = <F>;
50 chomp $requester;
576dff03 51 $requester =~ /^[a-zA-Z_0-9@.-]+$/
7a1a3819 52 or die "$file: evil requester: $requester";
bca91c1b
MM
53 $req_login = "";
54 $requester =~ /^([^@]+)\@/ and $req_login = $1;
576dff03 55 $req_login =~ /^[a-z0-9A-Z_.]+$/ or die "$file: evil requester $requester";
cba859d3 56 $spec = <F>;
bf2219c8 57 chomp $spec;
cba859d3 58 $spec =~ s/\.spec$//;
bf2219c8 59
47f8fda7
MM
60 my $flags = <F>;
61 $force_reply++ if ($flags =~ /force-reply/);
576dff03 62
7ebf9245
MM
63 while (<F>) {
64 if (/^ERROR/) {
65 s/^ERROR: //;
66 $problems .= $_;
f2a640bf 67 next;
7ebf9245 68 }
8ecb7fad 69 if (/^([a-f0-9]{32})\s+((ftp|http|https|no-url|no-url-copy):\/\/([a-z0-9A-Z;:\=\?&\@\+\~\.,\-\/_]|\%[0-9])+(#\/[a-zA-Z0-9\._-]+)?)\s*$/) {
e4708e3e 70 if (/\/$/) {
7a1a3819 71 $problems .= "$file: cannot fetch dir";
e4708e3e 72 } else {
7a1a3819
ER
73 push @md5, $1;
74 push @url, $2;
e4708e3e 75 }
76 } else {
7a1a3819 77 $problems .= "FILE: $file: corrupted";
e4708e3e 78 }
7ebf9245
MM
79 }
80 close(F);
81
82 unlink($file) || exit 0;
83}
84
44cd280f
MM
85sub basename($)
86{
87 my $f = shift;
88 $f =~ s|.*/||;
89 return $f;
90}
91
01806192 92sub by_md5($$)
7ebf9245
MM
93{
94 my ($md5, $url) = @_;
7ebf9245 95 $md5 =~ /^(.)(.)/;
01806192 96 return "/by-md5/$1/$2/$md5/" . basename($url);
6ce39ee7
MM
97}
98
01806192 99sub got_on_distfiles($$)
6ce39ee7 100{
01806192
MM
101 my ($md5, $url) = @_;
102 my $p = by_md5($md5, $url);
103 my $l = `lftp -c 'debug 0; open $df_server; quote size $p'`;
104 return $l =~ /^213 /;
105}
106
107sub copy_to_df($$)
108{
109 my ($from, $to) = @_;
110 my $cmd = "scp -r -B -q $from $df_scp/$to";
111 open(E, "$cmd 2>&1 |") or die;
112 my $oops = "";
113 while (<E>) {
114 $oops .= $_;
115 }
219df45c
MM
116 $oops .= "\nThe command has exited with a non-zero status."
117 unless (close (E));
01806192
MM
118 $problems .= "scp problems: $cmd:\n$oops\n"
119 if ($oops ne "");
120 return ($oops ne "");
6ce39ee7
MM
121}
122
b5c674c5 123sub move_file($$$)
6ce39ee7 124{
b5c674c5 125 my ($md5, $url, $local_copy) = @_;
6ce39ee7 126
01806192 127 my $bn = basename($url);
576dff03 128
01806192
MM
129 if ($local_copy ne "$tmp_dir/$md5/$bn") {
130 if (system("mv -f \"$local_copy\" \"$tmp_dir/$md5/$bn\"")) {
131 $problems .= "FATAL: cannot move $local_copy to $tmp_dir\n";
132 return;
133 }
134 $local_copy = "$tmp_dir/$md5/$bn";
135 }
576dff03 136
01806192
MM
137 if (open(D, "> $tmp_dir/$md5/$bn.desc")) {
138 print D "URL: $url\n";
d286a317 139 print D "Login: $req_login\n";
01806192
MM
140 print D "MD5: $md5\n";
141 print D 'Fetched-by: $Id$'."\n";
142 print D "Time: " . time . "\n";
143 close(D);
7ebf9245 144 } else {
01806192
MM
145 $problems .= "ERROR: cannot write $bn.desc\n";
146 }
147
148 my $dir = by_md5($md5, $url);
149 $dir =~ s|/[^/]+/[^/]+$||;
150 if (copy_to_df("$tmp_dir/$md5/", $dir) == 0) {
576dff03 151 $normal_out .=
44cd280f
MM
152 "STORED: $url\n" .
153 "\t$md5 " . basename($url) . "\n" .
01806192 154 "\tSize: " . (-s $local_copy) . " bytes\n";
47f8fda7 155 $fetched_count++;
7ebf9245
MM
156 }
157}
158
b5c674c5
MM
159sub make_src_symlink($$)
160{
161 my ($md5, $url) = @_;
576dff03 162
01806192 163 return unless ($url =~ /^no-url/);
576dff03 164
01806192
MM
165 my $b = basename($url);
166 if (open(S, "> $tmp_dir/$b.link")) {
b5c674c5 167 if ($url =~ /^no-url-copy/) {
01806192 168 print S (".." . by_md5($md5, $url));
b5c674c5 169 } else {
01806192 170 print S "REMOVE";
b5c674c5 171 }
01806192
MM
172 close(S);
173 copy_to_df("$tmp_dir/$b.link", "$copy_dir/$b.link");
b5c674c5 174 } else {
01806192 175 $problems .= "ERROR: cannot write $tmp_dir/$b.link\n";
b5c674c5
MM
176 }
177}
178
179sub md5($)
180{
181 my $file = shift;
56ea0f1e 182 my $in = "";
183 my $md5 = "";
184 my $err = "";
185 my @cmd = ("md5sum", $file);
186
187 run \@cmd, \$in, \$md5, \$err;
188 if ($err ne "") {
189 chomp($err);
a6b09732 190 $problems .= "FATAL: " . $err . "\n";
191 return "error";
56ea0f1e 192 }
193 chomp $md5;
b5c674c5
MM
194 $md5 =~ /^([a-f0-9]{32})/ and $md5 = $1;
195 return $md5;
196}
197
198sub handle_no_url($$)
199{
200 my ($md5, $url) = @_;
576dff03 201
e4708e3e 202 unless ($url =~ m#://([^/]+)#) {
203 $problems .= "$url: corrupted! (no-url)";
204 return;
205 }
b5c674c5 206 my $basename = $1;
bca91c1b 207 my $file = "$no_url_dir/$req_login/$basename";
b5c674c5
MM
208
209 if (-f $file) {
210 my $computed_md5 = md5($file);
211 if ($computed_md5 ne $md5) {
212 $problems .= "FATAL: $file md5 mismatch, needed $md5, got $computed_md5\n";
213 } else {
214 move_file($md5, $url, $file);
215 make_src_symlink($md5, $url);
216 }
217 } else {
bca91c1b 218 $problems .= "FATAL: $file was not uploaded\n";
b5c674c5
MM
219 }
220}
221
7ebf9245
MM
222sub fetch_file($$)
223{
224 my ($md5, $url) = @_;
225 my $out = "";
08ea99b9 226 my $all_out = "";
01806192
MM
227 my $bn = basename($url);
228 my $local = "$tmp_dir/$md5/$bn";
8f58f574
JB
229 my $cmd = "wget -nv --no-check-certificate --user-agent=$user_agent -O $local \"$url\"";
230 my $cmd2 = "wget -nv --no-check-certificate --user-agent=$user_agent --passive-ftp -O $local \"$url\"";
b5c674c5 231
01806192 232 push @files, $bn;
44cd280f 233
01806192 234 if (got_on_distfiles($md5, $url)) {
576dff03 235 $normal_out .=
7a1a3819
ER
236 "ALREADY GOT: $url\n" .
237 "\t$md5 " . basename($url) . "\n";
b5c674c5 238 make_src_symlink($md5, $url);
6ce39ee7
MM
239 return;
240 }
01806192 241
2ae8fdec 242 mkdir("$tmp_dir/$md5");
576dff03 243
b5c674c5
MM
244 if ($url =~ /^no-url/) {
245 handle_no_url($md5, $url);
246 return;
247 }
576dff03 248
7ebf9245
MM
249 open(W, "$cmd 2>&1 |");
250 while (<W>) {
08ea99b9 251 $all_out .= $_;
7ebf9245
MM
252 /URL:.*\s+\-\>\s+.*/ and next;
253 $out .= $_;
254 }
255 close(W);
256 if ($out ne "") {
257 $problems .= "$cmd:\n$out\n\n";
258 }
d1c674a4 259 if ( $? ) {
260 $problems .= sprintf "$cmd:\nexited with code %d (0x%02x)\n\n",
261 $? >> 8,
262 $? & 0xff;
263 }
e23ae36a 264 if (-f $local && -s $local == 0 && $url =~ /^ftp:/) {
f4f705aa 265 $out = "";
c0467b40 266 open(W, "$cmd2 2>&1 |");
267 while (<W>) {
f4f705aa 268 $all_out .= "\n\t\t$_";
c0467b40 269 /URL:.*\s+\-\>\s+.*/ and next;
270 $out .= $_;
271 }
272 close(W);
273 if ($out ne "") {
d1c674a4 274 $problems .= "$cmd2:\n$out\n\n";
275 }
276 if ( $? ) {
277 $problems .= sprintf "$cmd2:\nexited with code %d (0x%02x)\n\n",
278 $? >> 8,
279 $? & 0xff;
c0467b40 280 }
281 }
4db63fc1 282 if (-r $local && -s $local > 0) {
01806192 283 my $computed_md5 = md5($local);
7ebf9245
MM
284 if ($computed_md5 ne $md5) {
285 $problems .= "FATAL: $url md5 mismatch, needed $md5, got $computed_md5\n";
286 } else {
d642cf7e 287 my $testcmd = "file \"$local\" |";
288 my $testres = "";
a14ed9b7 289 if ($url =~ /^(http|https):/ && $local =~ /\.(tar\.(bz2|gz)|tgz|zip|jar|xpi)$/) {
d642cf7e 290 open(T, $testcmd) or die;
291 $testres = <T>;
292 close(T);
293 }
294 if ($testres =~ /empty|(ASCII|HTML|SGML).*text/) {
295 $testres =~ s/.*://;
296 $problems .= "FATAL: data returned from $url: $testres";
297 } else {
298 move_file($md5, $url, $local);
299 }
7ebf9245 300 }
4db63fc1 301 } elsif (-f $local && -s $local > 0) {
302 $problems .= "FATAL: $url ($md5) was not fetched ($cmd: $all_out): file is not readable\n";
d1c674a4 303 } elsif (-f $local && not -s $local) {
304 $problems .= "FATAL: $url ($md5) was not fetched ($cmd: $all_out): file exists but has 0 length\n";
7ebf9245 305 } else {
08ea99b9 306 $problems .= "FATAL: $url ($md5) was not fetched ($cmd: $all_out)\n";
7ebf9245 307 }
01806192
MM
308 # save space
309 unlink($local);
7ebf9245
MM
310}
311
312sub fetch_files()
313{
314 $problems .= "\n\n" if ($problems ne "");
ccbaa374 315 foreach $i (0..$#md5) {
316 fetch_file($md5[$i], $url[$i]);
7ebf9245
MM
317 }
318}
319
320sub send_email()
321{
9a1e36f3
MM
322 open(EMAIL, "| /usr/sbin/sendmail -t");
323 #open(EMAIL, "| cat");
44cd280f 324 my $marker = "";
7ebf9245 325 if ($problems ne "") {
44cd280f 326 $marker = "ERRORS: ";
7ebf9245 327 }
04550b88
MM
328 my $req_login;
329 $requester =~ /^(.*)\@/ and $req_login = $1;
44cd280f
MM
330
331 splice(@files, 10, @files - 10, "...")
332 if (@files > 10);
576dff03
ER
333
334 print EMAIL
04550b88 335"From: $req_login <$requester>
482655f9
MM
336To: $commits_list
337Cc: $requester
8408fdb0 338Subject: DISTFILES: ${spec}: ${marker}@{files}
e157986d
MM
339Message-ID: <$$." . time . "\@distfiles.pld-linux.org>
340X-distfiles-program: file-fetcher.pl
341X-distfiles-version: " . '$Id$' . "
7ebf9245
MM
342
343$problems
47f8fda7
MM
344Files fetched: $fetched_count
345
7ebf9245 346$normal_out
e157986d
MM
347
348--
d8cd573c 349Virtually Yours: distfiles.
7ebf9245
MM
350";
351 close(EMAIL) or die;
352}
353
01806192
MM
354sub make_tmp_dir()
355{
356 my $id = `uuidgen 2>/dev/null`;
357 chomp $id;
358 $id = rand if (!defined $id or $id eq "");
359 $tmp_dir = "./tmp/$id";
360 mkdir($tmp_dir) or die;
361}
362
363sub clean_tmp_dir()
364{
365 system("rm -rf $tmp_dir")
366 if ($tmp_dir ne "" && -d $tmp_dir);
367}
368
2e33bbbc
MM
369umask(002);
370
7ebf9245
MM
371find_file_in_spool();
372read_spool_file();
01806192 373make_tmp_dir();
7ebf9245 374fetch_files();
47f8fda7 375send_email() unless (!$force_reply and $problems eq "" and $fetched_count == 0);
01806192 376clean_tmp_dir();
319fb6c1
ER
377
378# vim: ts=2:sw=2:et:fdm=marker
This page took 0.084113 seconds and 4 git commands to generate.