/[webwml]/webwml/check_trans.pl
ViewVC logotype

Contents of /webwml/check_trans.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.44 - (show annotations) (download)
Tue Nov 27 21:18:01 2001 UTC (11 years, 5 months ago) by alfie
Branch: MAIN
Changes since 1.43: +5 -1 lines
File MIME type: text/plain
Added $DWWW_LANG handling, like already in copypage.pl available.
1 #!/usr/bin/perl -w
2
3 # This is a little utility designed to keep track of translations
4 # in the Debian web site CVS repository.
5
6 # For information about translation revisions please see
7 # http://www.debian.org/devel/website/uptodate
8
9 # This is GPL'ed code.
10 # Copyright 1998 Paolo Molaro <lupus@debian.org>.
11 # Copyright 2000,2001 Martin Quinson <mquinson@ens-lyon.fr>.
12
13 # Invocation:
14 # check_trans.pl [-vqdlM] [-C dir] [-p pattern] [-s subtree]
15 # [-m email -n N] [-g] [-t outputtype]
16 # [language]
17
18 # It needs to be run from the top level webwml directory.
19 # If you don't specify a language on the command line, the language name
20 # will be loaded from a file called language.conf, if such a file exists.
21
22 # For example:
23 # $ check_trans.pl -v italian
24 # You may also check only some subtrees as in:
25 # $ check_trans.pl -s devel italian
26
27 # Options:
28 # -v enable verbose mode
29 # -q just don't whine about missing files
30 # -Q enable really quiet mode
31 # -C <dir> go to <dir> directory before running this script
32 # -d output CVS diffs
33 # -l output CVS log messages
34 # -T output translated diffs
35 # -p <pattern> include only files matching <pattern>,
36 # default is *.html|*.wml
37 # -s <subtree> check only that subtree
38 # -t <type> choose output type (default is `text')
39 # -M display differences for all 'Makefile's
40
41 # Options useful when sending mails:
42 # -m <email> sends mails to translation maintainers
43 # PLEASE CAREFULLY READ THE BELOW TEXT ABOUT MAKING MAILS!
44 # <email> is the default recipient
45 # (it should be the list used for organisation,
46 # e.g. debian-l10n-french@lists.debian.org)
47 # -g debuG
48 # -n <1|2|3> send mails of priority upper or equal to
49 # 1 (monthly), 2 (weekly) or 3 (daily)
50
51 # Making Mails
52 # If you want to, this script send mails to the maintainer of the mails.
53 # BEWARE, SOME PEOPLE DO NOT LIKE TO RECEIVE AUTOMATIC MAILS!
54
55 # PREREQUISITES:
56 # You will need two databases:
57 # - one in which to see which translator maintains which file
58 # it must be named "./$langto/international/$langto/current_status.pl"
59 # (where $langto equals "french", "italian" or so)
60 # See webwml/french/international/french/current_status.pl" for example.
61 # - one in which to get info about translators and the frequency at
62 # which they want to get mails. It must be named
63 # webwml/$langto/international/$langto/translator.db.pl
64 # Please refer to the French one for more info.
65
66 # USAGE:
67 # If you give the "-g" option, all mails are sent to the default addressee
68 # (i.e. the one given as value to the -m option), without respect to their
69 # normal addressee. It is useful if you want to run it for yourself,
70 # and for debugging.
71 # Without that option, it sends real mails to real addresses.
72 # MAKE SURE THE ADDRESSEES REALLY WANT TO GET THESE MAILS
73
74 use strict;
75 use Getopt::Std;
76 use IO::Handle;
77 use Date::Parse;
78
79 # These modules reside under webwml/Perl
80 use lib ($0 =~ m|(.*)/|, $1 or ".") ."/Perl";
81 use Local::Cvsinfo;
82 use Local::WmlDiffTrans;
83 use Webwml::TransCheck;
84 use Webwml::TransIgnore;
85
86 # TODO:
87 # get the revisions from $lang/intl/$lang so diffing works
88 # need to quote dirnames?
89 # use a file to bind a file to a translator?
90
91 # global db variables
92 my $translations_status;
93 my $translators;# the ref resulting of require
94 my %translators;# the real hash
95
96 # misc hardcoded things
97 my $maintainer = "mquinson\@ens-lyon.fr"; # the default e-mail at which to bitch :-)
98
99 # options (note: with perl 5.6, this could change to our())
100 use vars qw($opt_C $opt_M $opt_Q $opt_d $opt_g $opt_l $opt_m $opt_n $opt_p $opt_q $opt_s $opt_t $opt_T $opt_v);
101 $opt_n = 5; # an invalid default
102 $opt_s = '';
103 $opt_C = '.';
104 $opt_t = 'text';
105
106 unless (getopts('vgdqQC:m:s:Tt:p:ln:M'))
107 {
108 open SELF, "<$0" or die "Unable to display help: $!\n";
109 HELP: while (<SELF>)
110 {
111 print, next if /^$/;
112 last HELP if (/^use/);
113 s/^# ?//;
114 next if /^!/;
115 print;
116 }
117 exit;
118 }
119
120 die "you can't have both verbose and quiet, doh!\n" if (($opt_v) && ($opt_Q));
121
122 warn "Checking subtree $opt_s only\n" if (($opt_v) && ($opt_s));
123
124 # include only files matching $filename
125 my $filename = $opt_p || '(\.wml$)|(\.html$)';
126
127 # Go to desired directory
128 chdir($opt_C) || die "Cannot go to $opt_C\n";
129
130 my $cvs = Local::Cvsinfo->new();
131 $cvs->options(
132 recursive => 1,
133 matchfile => [ $filename ],
134 skipdir => [ "template" ],
135 );
136 # This object is used to retrieve information when original is
137 # not English
138 my $altcvs = $cvs->new();
139
140 # Global .transignore
141 my $globtrans = Webwml::TransIgnore->new(".");
142
143 # language configuration
144 my $defaultlanguage = 'italian';
145 if (exists $ENV{DWWW_LANG})
146 {
147 $defaultlanguage = $ENV{DWWW_LANG};
148 }
149 elsif (open CONF, "<language.conf")
150 {
151 $defaultlanguage = <CONF>;
152 chomp $defaultlanguage;
153 close CONF;
154 }
155
156 my $from = 'english';
157 my $to = shift || $defaultlanguage;
158 $to =~ s%/$%%; # Remove slash from the end
159
160 my $langto = $to;
161 $langto =~ s,^([^/]*).*$,$1,;
162 if (-e "./$langto/international/$langto/current_status.pl" &&
163 -e "./$langto/international/$langto/translator.db.pl") {
164 print "READ PAGES DB: $langto/international/$langto/current_status.pl\n"
165 if $opt_v;
166 push(@INC,"./$langto/international/$langto");
167 require 'current_status.pl';
168 print "READ TRANSLATOR DB: $langto/international/$langto/translator.db.pl\n"
169 if $opt_v;
170 require 'translator.db.pl';
171 %translators=%{init_translators()};
172 } else {
173 die "I need my DBs to send mails !\n Please read the comments in the script and try again\n" if $opt_m;
174 }
175
176 if ($opt_m) {
177 unless ($opt_n =~ m,[123],) {
178 die "Invalid priority. Please set -n value to 1, 2 or 3.\n".
179 "(assuming you know what you're doing)\n";
180 }
181 }
182
183 $from = "$from/$opt_s";
184 $to = "$to/$opt_s";
185
186 init_mails();
187
188 print "\$translations = {\n" if $opt_t eq 'perl';
189
190 $cvs->readinfo($from);
191 foreach my $path (@{$cvs->dirs()}) {
192 my $tpath = $path;
193 $tpath =~ s/^$from/$to/o;
194 my $transignore = Webwml::TransIgnore->new($tpath);
195 next unless $transignore->found();
196 warn "Loading $tpath/.transignore\n" if $opt_v;
197 foreach (@{$transignore->local()}) {
198 s/^$to/$from/o;
199 $cvs->removefile($_);
200 }
201 }
202
203 foreach (sort @{$cvs->files()}) {
204 my ($path, $tpath);
205 $path = $_;
206 $tpath = $path;
207 $tpath =~ s/^$from/$to/o;
208 check_file($tpath,
209 $cvs->revision($path),
210 str2time($cvs->date($path)),
211 get_translators_from_db($tpath));
212 }
213
214 print "}; 1;\n" if $opt_t eq 'perl';
215
216 send_mails();
217
218 if ($opt_M) {
219 foreach my $makefile (split(/\n/, `find $from -name Makefile -print`)) {
220 my $destination = $makefile;
221 $destination =~ s/^$from/$to/o;
222 if (-e $destination) {
223 STDOUT->flush;
224 system("diff -u $destination $makefile");
225 STDOUT->flush;
226 }
227 }
228 }
229
230 sub verify_send {
231 return 1 unless ($opt_m);
232 # returns true whether we have to send this part to this guy
233 my $name=shift;
234 my $part=shift;
235 $name =~ s,<.*?>,,;
236 $name =~ s,^ *(.*?) *$,$1,;
237 print "$name is unknown\n" unless defined($translators{$name});
238 # print "pri=$opt_n ; maint_pri=${translators{$name}{$part}}\n";
239 return $opt_m # if we have to send any mail
240 && defined($translators{$name}) # if this guy is known
241 && defined($translators{$name}{$part}) # we know something about the wanted frequency
242 && ($opt_n <= $translators{$name}{$part}); # check if the frequency is ok
243 }
244
245 sub get_translators_from_db {
246 my $id=shift;
247 my $res='';
248
249 $id=~ s,^$langto/,,;
250 $id=~ s/\.wml$//;
251 if (defined(%{$$translations_status{$id}})
252 && defined ($$translations_status{$id}{'translation_maintainer'})) {
253 foreach my $n (sort @{$$translations_status{$id}{'translation_maintainer'}}) {
254 $res .= " $n";
255 }
256 } else {
257 $res = "";
258 }
259 return $res;
260 }
261
262 sub init_mails {
263 return unless $opt_m;
264 eval q{use MIME::Lite};
265 foreach my $name (keys %translators) {
266 return if defined $translators{$name}{"msg"};
267 $translators{$name}{"msg"} = MIME::Lite->new(
268 From => "Script watching translation state <$maintainer>",
269 To => ($opt_g ? $opt_m : $translators{$name}{"email"}),
270 Subject => ($name eq "list" ?
271 "Translations for the Debian web site unmaintained" :
272 "Translations for the Debian web site maintained by $name"
273 ),
274 Type => 'multipart/mixed');
275 my $str= "Hello,\n".
276 "This is an automatically generated mail sent to you\n".
277 "because you are the official translator of some pages\n".
278 "in ".ucfirst($langto)." of the Debian web site.\n".
279 "\n".
280 "I sent you what I think you want. (i.e. what is in my DB).\n".
281 " That is to say:\n";
282 foreach my $n (qw(summary logs diff tdiff file)) {
283 $str.=" ".$n.": ".
284 ($translators{$name}{$n} != 0 ?
285 ($translators{$name}{$n} != 1 ?
286 ($translators{$name}{$n} != 2 ?
287 ($translators{$name}{$n} != 3 ?
288 "dunno (error in DB !!)":
289 "daily"):
290 "weekly"):
291 "monthly"):
292 "never")."\n";
293 }
294 if ($name eq "list") {
295 $str .= " missing: ".($translators{$name}{"missing"} != 0 ?
296 ($translators{$name}{"missing"} != 1 ?
297 ($translators{$name}{"missing"} != 2 ?
298 ($translators{$name}{"missing"} != 3 ?
299 "dunno (error in DB !!)":
300 "daily"):
301 "weekly"):
302 "monthly"):
303 "never")."\n";
304 }
305 $str.=" Compression=".$translators{$name}{"compress"}." (not implemented)\n\n";
306 $str.=" You can ask to change:\n".
307 " - the frequency of these mails\n".
308 " (never, monthly, weekly, daily)\n".
309 " - the parts you want\n".
310 " - The list of the work to do in a summarized form\n".
311 " - diff between the version you translated and the current one\n".
312 " - log between the version you translated and the current one\n".
313 " - the file you translated (so that you don't have to download it manually)\n".
314 " - your email address\n".
315 " - the compression level (none, gzip or bzip2), even if I'll ignore it\n".
316 " because this feature is not implemented yet ;)\n".
317 "\n".
318 "For more information, contact your team coordinator, or\n".
319 "the maintainer of this script ($maintainer).\n".
320 "\n".
321 "Thanks, and sorry for the annoyance.\n";
322
323 $translators{$name}{"msg"}->attach(
324 Type => 'TEXT',
325 Data => $str);
326 $translators{$name}{"send"}=0;
327 }
328 }
329
330 sub send_mails {
331 #Makes the mails and send them
332 return unless $opt_m;
333 foreach my $name (sort keys %translators) {
334 $translators{$name}{"msg"}->attach(
335 Type => 'TEXT',
336 Filename => 'NeedToUpdate_summary',
337 Data => $translators{$name}{"part_summary"})
338 if defined($translators{$name}{"part_summary"});
339 $translators{$name}{"msg"}->attach(
340 Type => 'TEXT',
341 Filename => 'Missing_summary',
342 Data => $translators{$name}{"part_missing"})
343 if defined($translators{$name}{"part_missing"});
344 foreach my $part (qw (file logs diff tdiff)) {
345 if (defined($translators{$name}{"part_$part"})) {
346 foreach my $file (sort keys %{$translators{$name}{"part_$part"}}) {
347 $translators{$name}{"msg"}->attach(
348 Type => 'TEXT',
349 Filename => "$file.$part",
350 Data => $translators{$name}{"part_$part"}{$file});
351 }
352 }
353 }
354 if ($translators{$name}{"send"}) {
355 print "send mail to $name\n";
356 if (($name =~ m,mquinson,) || ($opt_g && $opt_m eq $maintainer)) {
357 print "Well, detourned to $maintainer\n";
358 $translators{$name}{"msg"}->send;
359 }
360 # $translators{$name}{"msg"}->print_header;
361 $translators{$name}{"msg"}->send;
362 } else {
363 print "didn't send mail to $name: nothing to say to him\n";
364 }
365 }
366 }
367
368 sub add_part {
369 my $name = shift;
370 my $part = shift;
371 my $txt = shift;
372 $name =~ s,<.*?>,,;
373 $name =~ s,^ *(.*?) *$,$1,;
374 if (verify_send($name,$part)) {
375 $translators{$name}{"part_$part"}.=$txt;
376 $translators{$name}{"send"}=1;
377 }
378 }
379
380 sub add_sub_part {
381 my $name = shift;
382 my $part = shift;
383 my $subpart=shift;
384 my $txt = shift;
385 $name =~ s,<.*?>,,;
386 $name =~ s,^ *(.*?) *$,$1,;
387 # print "add_sub_part($name)(part=$part)($subpart):$txt" if $opt_v;
388 STDOUT->flush;
389 if (verify_send($name,$part)) {
390 # print "YES\n";
391 $translators{$name}{"part_$part"}{$subpart}.= "$txt";
392 $translators{$name}{"send"}=1;
393 }
394 # print "no\n";
395 }
396
397 sub get_diff_txt {
398 my ($oldr, $revision, $oldname, $name) = @_;
399 my $cmd;
400
401 # Get old revision file
402 $cmd = "cvs -z3 update -r $oldr -p $oldname 2>/dev/null";
403 # print "!get_diff_txt: cvs -z3 update -r ".$oldr." -p ".$oldname."\n";
404 my @old_rev_file_lines = qx($cmd);
405
406 # Get translation file
407 open (FILE,"$name") || die ("Can't open `$name' for read");
408 my @translation_file_lines;
409 while (<FILE>) {
410 $translation_file_lines[scalar @translation_file_lines] = $_;
411 }
412 close FILE || die ("Can't close $name after reading");
413
414 # Get diff lines
415 $cmd = "cvs -z3 diff -u -r$oldr -r $revision $oldname 2>/dev/null";
416 # print "get_diff_txt: $cmd: cvs -z3 diff -u -r$oldr -r $revision $oldname\n";
417 my @diff_lines = qx($cmd);
418
419 my $txt = Local::WmlDiffTrans::find_trans_parts(\@old_rev_file_lines,
420 \@translation_file_lines,
421 \@diff_lines);
422
423 return $txt;
424 }
425
426 sub check_file {
427 my ($name, $revision, $mtime, $translator) = @_;
428 my ($oldr, $oldname, $original);
429 warn "Checking $name, English revision $revision\n" if $opt_v;
430 my $docname = $name;
431 $docname =~ s#^$langto/##;
432 $docname =~ s#\.wml$##;
433 unless (-r $name) {
434 (my $iname = $name) =~ s/^$to\///;
435 if (!$globtrans->is_global($iname)) {
436 unless (($opt_q) || ($opt_Q)) {
437 if ($opt_t eq 'perl') {
438 print "'$docname' => {\n\t'type' => 'Web',\n";
439 print "\t'revision' => '$revision',\n";
440 print "\t'mtime' => '$mtime',\n";
441 print "\t'status' => 1,\n";
442 print "},\n";
443 } else {
444 print "Missing $name version $revision\n";
445 }
446 add_part("list","missing","Missing $name version $revision\n");
447 }
448 } else {
449 warn "Ignored $name\n" if $opt_v;
450 }
451 return;
452 }
453 my $transcheck = Webwml::TransCheck->new($name);
454 $oldr = $transcheck->revision() || 0;
455 if (!$oldr && ($name =~ m#$langto/international/$langto#i)) {
456 # This document is original, check for
457 # english/international/$langto...
458 $name =~ s{^$to}{$from};
459 $transcheck = Webwml::TransCheck->new($name);
460 $oldr = $transcheck->revision() || 0;
461 }
462 $translator = $transcheck->maintainer() || "";
463 $original = $transcheck->original();
464 warn "Found translation for $oldr\n" if $opt_v and $oldr;
465 warn "Translated by $translator\n" if $opt_v and $translator;
466 warn "Original is $original\n" if $opt_v and $original;
467 if ($original) {
468 my ($fromname, $fromdir);
469 $fromname = $name;
470 $fromname =~ s{^[^/]+}{$original};
471 $fromdir = $fromname;
472 $fromdir =~ s{/+[^/]+$}{};
473 $altcvs->reset();
474 $altcvs->readinfo($fromdir, matchfile => [$fromname]);
475 $revision = $altcvs->revision($fromname);
476 warn "Original is $original, revision $revision\n" if $opt_v;
477 }
478
479 $translator =~ s/^\s+//;
480 $translator =~ s/\s+$//;
481
482 my $str;
483 my $status = 8;
484 (my $numrev) = $revision =~ m/^1\.(\d+)$/; $numrev ||= "0";
485 (my $numoldr) = $oldr =~ m/^1\.(\d+)$/; $numoldr ||= "0";
486 if (!$oldr) {
487 $oldr = '1.1';
488 $str = "Unknown status of $name (revision should be $revision)";
489 } elsif ($oldr eq $revision) {
490 $status = 4;
491 } elsif ($numoldr > $numrev) {
492 $str = "Broken revision number $oldr for $name, it should be $revision";
493 } else {
494 $str = "NeedToUpdate $name from version $oldr to version $revision";
495 $status = 3;
496 }
497 $str .= " (maintainer: $translator)" if $translator;
498 if ($opt_t eq 'perl') {
499 print "'$docname' => {\n\t'type' => 'Web',\n";
500 print "\t'revision' => '$revision',\n";
501 print "\t'mtime' => '$mtime',\n";
502 print "\t'base_revision' => '$oldr',\n";
503 print "\t'translation_maintainer' => ['$translator'],\n" if $translator;
504 print "\t'status' => $status,\n";
505 print "},\n";
506 } elsif ($str && $oldr ne $revision) {
507 $str .= "\n";
508 print $str unless ($opt_Q);
509 }
510
511 return if (defined($oldr) && ($oldr eq $revision));
512
513 $oldname = $name;
514 $oldname =~ s/^$to/$from/;
515
516 my @logrev = split(/\./, $oldr);
517 $logrev[$#logrev] ++;
518 my $logoldr = join('.', @logrev);
519
520 if ($opt_m) {
521 $translator = "list" if ($translator eq "");
522 add_part($translator,"summary",$str);
523 add_sub_part($translator,"diff",$name,
524 join("",qx(cvs -z3 diff -u -r'$oldr' -r $revision $oldname)));
525 add_sub_part($translator,"tdiff",$name,
526 get_diff_txt("$oldr","$revision","$oldname","$name"));
527
528 add_sub_part($translator,"logs",$name,
529 join("",qx(cvs -z3 log -r$logoldr:$revision $oldname)));
530 add_sub_part($translator,"file",$name,
531 join("",qx(cat $name)));
532 }
533
534 if ($opt_d) {
535 STDOUT->flush;
536 my $cvsline = "cvs -z3 log -r'$logoldr:$revision' '$oldname'";
537 warn "Running $cvsline\n" if (($opt_v) && ($opt_l));
538 system($cvsline) if $opt_l;
539 STDOUT->flush if $opt_l;
540 $cvsline = "cvs -z3 diff -u -r '$oldr' -r '$revision' '$oldname'";
541 warn "Running $cvsline\n" if $opt_v;
542 system($cvsline);
543 STDOUT->flush;
544 }
545
546 if ($opt_T) {
547 print get_diff_txt("$oldr", "$revision", "$oldname", "$name")."\n";
548 }
549 }

  ViewVC Help
Powered by ViewVC 1.1.5