source: gsdl/trunk/bin/script/schedule.pl@ 17941

Last change on this file since 17941 was 17941, checked in by kjdon, 15 years ago

made schedule option only visible for expert mode, and made frequency default to daily instead of hourly

  • Property svn:executable set to *
File size: 17.6 KB
Line 
1#!/usr/bin/perl -w
2
3###########################################################################
4#
5# schedule.pl --
6# A component of the Greenstone digital library software
7# from the New Zealand Digital Library Project at the
8# University of Waikato, New Zealand.
9#
10# Copyright (C) 1999 New Zealand Digital Library Project
11#
12# This program is free software; you can redistribute it and/or modify
13# it under the terms of the GNU General Public License as published by
14# the Free Software Foundation; either version 2 of the License, or
15# (at your option) any later version.
16#
17# This program is distributed in the hope that it will be useful,
18# but WITHOUT ANY WARRANTY; without even the implied warranty of
19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20# GNU General Public License for more details.
21#
22# You should have received a copy of the GNU General Public License
23# along with this program; if not, write to the Free Software
24# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25#
26###########################################################################
27
28package schedule;
29
30BEGIN {
31 die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
32 die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
33 unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
34 unshift (@INC, "$ENV{'GSDLHOME'}/perllib/cpan");
35 unshift (@INC, "$ENV{'GSDLHOME'}/perllib/plugins");
36 unshift (@INC, "$ENV{'GSDLHOME'}/perllib/plugouts");
37 unshift (@INC, "$ENV{'GSDLHOME'}/perllib/classify");
38
39 if (defined $ENV{'GSDLEXTS'}) {
40 my @extensions = split(/:/,$ENV{'GSDLEXTS'});
41 foreach my $e (@extensions) {
42 my $ext_prefix = "$ENV{'GSDLHOME'}/ext/$e";
43
44 unshift (@INC, "$ext_prefix/perllib");
45 unshift (@INC, "$ext_prefix/perllib/cpan");
46 }
47 }
48}
49
50use strict;
51no strict 'refs';
52no strict 'subs';
53
54use FileHandle;
55use Fcntl;
56use printusage;
57use parse2;
58use parse3;
59use gsprintf 'gsprintf';
60if($ENV{'GSDLOS'} eq "windows") {
61 eval("require \"Win32.pm\" ");
62}
63
64my $frequency_list =
65 [ { 'name' => "hourly",
66 'desc' => "{schedule.frequency.hourly}" },
67 { 'name' => "daily",
68 'desc' => "{schedule.frequency.daily}" },
69 { 'name' => "weekly",
70 'desc' => "{schedule.frequency.weekly}" }
71 ];
72
73my $action_list =
74 [ { 'name' => "add",
75 'desc' => "{schedule.action.add}" },
76 { 'name' => "update",
77 'desc' => "{schedule.action.update}" },
78 { 'name' => "delete",
79 'desc' => "{schedule.action.delete}" }
80 ];
81
82my $arguments =
83 [
84 { 'name' => "schedule",
85 'desc' => "{schedule.schedule}",
86 'type' => "flag",
87 'reqd' => "no",
88 'modegli' => "4" },
89 { 'name' => "frequency",
90 'desc' => "{schedule.frequency}",
91 'type' => "enum",
92 'list' => $frequency_list,
93 'deft' => "daily",
94 'reqd' => "no",
95 'modegli' => "4" },
96 { 'name' => "action",
97 'desc' => "{schedule.action}",
98 'type' => "enum",
99 'list' => $action_list,
100 'deft' => "add",
101 'reqd' => "no",
102 'modegli' => "4" },
103 { 'name' => "import",
104 'desc' => "{schedule.import}",
105 'type' => "quotestr",
106 'deft' => "",
107 'reqd' => "yes",
108 'hiddengli' => "yes" },
109 { 'name' => "build",
110 'desc' => "{schedule.build}",
111 'type' => "quotestr",
112 'deft' => "",
113 'reqd' => "yes",
114 'hiddengli' => "yes" },
115 { 'name' => "colname",
116 'desc' => "{schedule.colname}",
117 'type' => "string",
118 'deft' => "",
119 'reqd' => "no",
120 'hiddengli' => "yes" },
121 { 'name' => "xml",
122 'desc' => "{scripts.xml}",
123 'type' => "flag",
124 'reqd' => "no",
125 'hiddengli' => "yes" },
126 { 'name' => "language",
127 'desc' => "{scripts.language}",
128 'type' => "string",
129 'reqd' => "no",
130 'hiddengli' => "yes" },
131 { 'name' => "email",
132 'desc' => "{schedule.email}",
133 'type' => "flag",
134 'reqd' => "no",
135 'modegli' => "4" },
136 { 'name' => "toaddr",
137 'desc' => "{schedule.toaddr}",
138 'type' => "string",
139 'reqd' => "no",
140 'deft' => "",
141 'modegli' => "4" },
142 { 'name' => "fromaddr",
143 'desc' => "{schedule.fromaddr}",
144 'type' => "string",
145 'deft' => "",
146 'reqd' => "no",
147 'modegli' => "4" },
148 { 'name' => "smtp",
149 'desc' => "{schedule.smtp}",
150 'type' => "string",
151 'deft' => "",
152 'reqd' => "no",
153 'modegli' => "4" },
154 { 'name' => "out",
155 'desc' => "{schedule.out}",
156 'type' => "string",
157 'deft' => "STDERR",
158 'reqd' => "no",
159 'hiddengli' => "yes" },
160 { 'name' => "gli",
161 'desc' => "{schedule.gli}",
162 'type' => "flag",
163 'reqd' => "no",
164 'hiddengli' => "yes" }
165 ];
166
167
168my $options = { 'name' => "schedule.pl",
169 'desc' => "Interaction with Cron",
170 'args' => $arguments };
171
172&main();
173
174sub main {
175
176 #params
177 my ($action, $frequency, $import, $build, $colname, $xml, $language,
178 $email, $toaddr, $fromaddr, $smtp, $gli, $out);
179
180 #other vars
181 my ($i,$numArgs,$os,$erase,$erase2,$copy,$newpl,$gsdl,$path,$cronf,
182 $nf,$of,$opf, $cronstr, $ecmd,$ecmd2, $record, $cronrec,$ncronf);
183
184 #some defaults
185 $action = "add";
186 $frequency = "hourly";
187 $import = "";
188 $build = "";
189 $colname = "";
190 $xml = 0;
191 $email = 0;
192 $gli = 0;
193 $language = "";
194 $out = "STDERR";
195
196
197 $gsdl = $ENV{'GSDLHOME'};
198 $os = $ENV{'GSDLOS'};
199 $path = $ENV{'PATH'};
200
201 my $service = "schedule";
202
203 #For this to work, we need to know if -gli exists
204
205 $numArgs=$#ARGV+1;
206 $i = 0;
207 while($i < $numArgs)
208 {
209 if($ARGV[$i] =~ /gli/) {
210 $gli = 1;
211 }
212 $i++;
213 }
214
215 #We are using two different parsers here, because the GLI in linux (and probably darwin) will not take
216 #an entire double-quoted string as an argument, while if schedule.pl is
217 #executed from the command line, the entire double-quoted string is taken
218 #as an argument. For Windows, it seems that it does.
219 my $hashParsingResult = {};
220 my $intArgLeftAfterParsing;
221 if($gli && ($os eq "linux" || $os eq "darwin")) {
222 $intArgLeftAfterParsing = parse3::parse(\@ARGV, $arguments, $hashParsingResult, "allow_extra_options");
223 } else {
224 $intArgLeftAfterParsing = parse2::parse(\@ARGV, $arguments, $hashParsingResult, "allow_extra_options");
225
226 }
227
228 #check for extra options
229 if ($intArgLeftAfterParsing == -1 || $intArgLeftAfterParsing > 0 || (@ARGV && $ARGV[0] =~ /^\-+h/))
230 {
231 &PrintUsage::print_txt_usage($options, "{schedule.params}");
232 die "\n";
233 }
234
235 foreach my $strVariable (keys %$hashParsingResult)
236 {
237 eval "\$$strVariable = \$hashParsingResult->{\"\$strVariable\"}";
238 }
239
240 if ($xml) {
241 &PrintUsage::print_xml_usage($options);
242 print "\n";
243 return;
244
245 }
246
247 if ($gli) { # the gli wants strings to be in UTF-8
248 &gsprintf::output_strings_in_UTF8;
249 }
250
251 if($action eq "add" || $action eq "update") {
252 if($email) {
253 if($smtp eq "" || $toaddr eq "" || $fromaddr eq "" || $smtp =~ /^-/ || $toaddr =~ /^-/ || $fromaddr =~ /^-/) {
254 &gsprintf($out, "{schedule.error.email} \n");
255 die "\n";
256 }
257
258
259 if($import eq "" || $build eq "") {
260 &gsprintf($out, "{schedule.error.importbuild} \n");
261 die "\n";
262 }
263 }
264 }
265 if($colname eq "") {
266 &gsprintf($out, "{schedule.error.colname} \n");
267 die "\n";
268 }
269
270 #not sure if this is always set?
271 #language may be passed in too
272 if($language eq "" && exists($ENV{'GSDLLANG'})) {
273 $language = $ENV{'GSDLLANG'};
274 }
275 elsif($language eq "") {
276 $language = "en";
277 }
278
279 $newpl = "cron.pl";
280
281 if($action eq "delete") {
282
283 print STDERR "<Delete>\n" if $gli;
284
285 if($os =~ /^linux$/ || $os =~ /^darwin$/) {
286 system("\\rm $gsdl/collect/$colname/$newpl 2>/dev/null");
287 system("\\rm $gsdl/collect/$colname/cronjob 2>/dev/null");
288 } else { #in windows
289
290 system("del $gsdl\\\\collect\\\\$colname\\\\$newpl 2>nul"); #nul is windows equivalent to /dev/null
291
292 }
293
294
295 &gsprintf($out, "{schedule.deleted}\n");
296 }
297 else {
298 #For the Scheduling monitor
299 print STDERR "<Schedule>\n" if $gli;
300
301 if ($os =~ /^linux$/ || $os =~ /^darwin$/) {
302
303 $import = $import." 2>$gsdl/collect/$colname/log/\$logfile";
304 $build = $build." 2>>$gsdl/collect/$colname/log/\$logfile";
305 $erase = "\\\\rm -r $gsdl/collect/$colname/index 2>>$gsdl/collect/$colname/log/\$logfile";
306 $erase2 = "mkdir $gsdl/collect/$colname/index 2>>$gsdl/collect/$colname/log/\$logfile";
307 $copy = "mv $gsdl/collect/$colname/building/* $gsdl/collect/$colname/index/ 2>>$gsdl/collect/$colname/log/\$logfile";
308 if($email) {
309 #first,we need to add backslashes before the 'at' symbol.
310 $toaddr =~ s/\@/\\\@/g;
311 $fromaddr =~ s/\@/\\\@/g;
312
313 $ecmd = "$gsdl/bin/script/sendmail.pl -to $toaddr -from $fromaddr -smtp $smtp -msgfile $gsdl/collect/$colname/log/\$logfile -subject \\\"Results of build for collection $colname\\\" 2>>$gsdl/collect/$colname/log/\$logfile";
314
315 $ecmd2 = "$gsdl/bin/script/sendmail.pl -to $toaddr -from $fromaddr -smtp $smtp -msgfile $gsdl/etc/cronlock.txt -subject \\\"Results of build for collection $colname\\\" 2>>$gsdl/collect/$colname/log/\$logfile";
316 }
317
318 } else { #in windows
319
320 $gsdl =~ s/\\/\\\\/g;
321 $path =~ s/\\/\\\\/g;
322
323 $import =~ s/\\/\\\\/g;
324 $build =~ s/\\/\\\\/g;
325
326 $import =~ s/exe/exe\\\"/g;
327 $import =~ s/pl/pl\\\"/g;
328 $build =~ s/exe/exe\\\"/g;
329 $build =~ s/pl/pl\\\"/g;
330
331
332 my $prompt = substr($gsdl,0,2);
333
334 $import =~ s/$prompt/\\\"$prompt/g;
335 $build =~ s/$prompt/\\\"$prompt/g;
336
337 #not the best solution - won't work if someone chooses something weird
338 $import =~ s/\\collect/\\collect\\\"/;
339 $build =~ s/\\collect/\\collect\\\"/;
340
341 $import = "$import 2>\\\"$gsdl\\\\collect\\\\$colname\\\\log\\\\\$logfile\\\" ";
342 $build = "$build 2>>\\\"$gsdl\\\\collect\\\\$colname\\\\log\\\\\$logfile\\\" ";
343
344
345 $erase = "rd \\\/S \\\/Q \\\"$gsdl\\\\collect\\\\$colname\\\\index\\\" 2>>\\\"$gsdl\\\\collect\\\\$colname\\\\log\\\\\$logfile\\\" ";
346 $erase2 = "md \\\"$gsdl\\\\collect\\\\$colname\\\\index\\\" 2>>\\\"$gsdl\\\\collect\\\\$colname\\\\log\\\\\$logfile\\\" ";
347 $copy = "xcopy \\\/E \\\/Y \\\"$gsdl\\\\collect\\\\$colname\\\\building\\\\*\\\" \\\"$gsdl\\\\collect\\\\$colname\\\\index\\\\\\\" >>\\\"$gsdl\\\\collect\\\\$colname\\\\log\\\\\$logfile\\\" ";
348 if($email) {
349 $toaddr =~ s/\@/\\\@/g;
350 $fromaddr =~ s/\@/\\\@/g;
351 $ecmd = "\\\"$gsdl\\\\bin\\\\windows\\\\perl\\\\bin\\\\perl.exe\\\" -S \\\"$gsdl\\\\bin\\\\script\\\\sendmail.pl\\\" -to $toaddr -from $fromaddr -smtp $smtp -msgfile \\\"$gsdl\\\\collect\\\\$colname\\\\log\\\\\$logfile\\\" -subject \\\"Results of build for collection $colname\\\" >>\\\"$gsdl\\\\collect\\\\$colname\\\\log\\\\\$logfile\\\" ";
352
353 $ecmd2 = "\\\"$gsdl\\\\bin\\\\windows\\\\perl\\\\bin\\\\perl.exe\\\" -S \\\"$gsdl\\\\bin\\\\script\\\\sendmail.pl\\\" -to $toaddr -from $fromaddr -smtp $smtp -msgfile \\\"$gsdl\\\\etc\\\\cronlock.txt\\\" -subject \\\"Results of build for collection $colname\\\" >>\\\"$gsdl\\\\collect\\\\$colname\\\\log\\\\\$logfile\\\" ";
354 }
355 }
356
357
358 $nf = new FileHandle() ||
359 (&gsprintf(STDERR, "{common.cannot_open_output_file}: $!\n", $out) && die);
360
361 open($nf, ">$gsdl/collect/$colname/$newpl") ||
362 (&gsprintf(STDERR, "{common.cannot_open_output_file}: $!\n", $out) && die);
363
364
365 print $nf "\#!/usr/bin/perl";
366 print $nf "\n\n";
367
368
369 #we need to set environment variables for import and build
370 print $nf "\$ENV{'GSDLHOME'}=\"$gsdl\"\;\n";
371 print $nf "\$ENV{'GSDLOS'}=\"$os\"\;\n";
372 print $nf "\$ENV{'GSDLLANG'}=\"$language\"\;\n";
373 print $nf "\$ENV{'PATH'}=\"$path\"\;\n";
374
375 print $nf "\$logfile = \"cron\".time\(\).\".txt\"\;\n";
376
377 if($os =~ /^windows$/) {
378 print $nf "if\(-e \\\"$gsdl\\\\collect\\\\$colname\\\\etc\\\\cron.lck\\\" \"\)\{ \n";
379 } else {
380 print $nf "if\(-e \"$gsdl/collect/$colname/etc/cron.lck\"\) \{ \n";
381 }
382 if($email) {
383 print $nf " system(\"$ecmd2\")\;\n";
384 }
385 else {
386 if($os eq "windows") {
387 print $nf " system(\"more \\\"$gsdl\\\\etc\\\\cronlock.txt\\\" >\\\"$gsdl\\\\collect\\\\$colname\\\\log\\\\\$logfile\\\"\"\)\;\n";
388 } else {
389 print $nf " system(\"more $gsdl/etc/cronlock/txt > $gsdl/collect/$colname/log/\$logfile \"\)\;\n";
390 }
391
392 }
393 print $nf "\} else \{\n";
394
395 if($os eq "linux" || $os eq "darwin") {
396 $import =~ s/\"//;
397 $import =~ s/\"//;
398 $build =~ s/\"//;
399 $build =~ s/\"//;
400 }
401
402 if($os =~ /^windows$/) {
403 print $nf "system(\"echo lock \>\\\"$gsdl\\\\collect\\\\$colname\\\\etc\\\\cron.lck\\\"\")\;\n";
404 } else {
405 print $nf "system(\"echo lock >$gsdl/collect/$colname/etc/cron.lck\")\;\n";
406 }
407
408 print $nf " system(\"$import\")\;\n";
409 print $nf " system(\"$build\")\;\n";
410
411 print $nf " system(\"$erase\")\;\n";
412 print $nf " system(\"$erase2\")\;\n";
413
414 print $nf " system(\"$copy\")\;\n";
415 if($email) {
416 print $nf " system(\"$ecmd\")\;\n";
417 }
418
419
420 #need to set permissions in linux
421 if($os =~ /^linux$/ || $os =~ /^darwin$/) {
422 print $nf "system(\"chmod -R 755 $gsdl/collect/$colname/index/*\")\;\n";
423 print $nf "system(\"\\\\rm $gsdl/collect/$colname/etc/cron.lck\")\;\n";
424 } else {
425 print $nf "system(\"del \\\"$gsdl\\\\collect\\\\$colname\\\\etc\\\\cron.lck\\\" \")\;\n";
426 }
427
428
429
430 print $nf "\}\n";
431
432 close($nf);
433 if($os =~ /^linux$/ || $os =~ /^darwin$/) {
434 system("chmod 755 $gsdl/collect/$colname/cron.pl");
435 }
436
437 &gsprintf($out, "{schedule.scheduled}\n");
438 }
439
440 #next, we need to create a crontab file. For now, a crontab will be set up
441 #to run at midnight either nightly or weekly.
442 $gsdl =~ s/\\\\/\\/g;
443 if ($os =~ /^linux$/ || $os =~ /^darwin$/)
444 {
445 $cronf="cronjob";
446 open($nf, ">$gsdl/collect/$colname/$cronf") ||
447 (&gsprintf(STDERR, "{common.cannot_open_output_file}: $!\n", $out) && die);
448
449 #see if there is an existing crontab
450 system("crontab -l >$gsdl/collect/$colname/outfile 2>/dev/null");
451
452 $opf = new FileHandle();
453 open($opf, "$gsdl/collect/$colname/outfile") ||
454 (&gsprintf(STDERR, "{common.cannot_open_output_file}: $!\n", $out) && die);
455 $record = <$opf>;
456
457 #if there is an existing crontab file
458 #preserve all records and change existing record for
459 #current collection
460 if ($record)
461 {
462 do
463 {
464 if($record !~ /$colname/)
465 {
466 print $nf $record;
467 }
468 } while($record = <$opf>);
469
470 close($opf);
471 }
472
473
474 if($action =~ /^add$/ || $action =~ /^update$/)
475 {
476 if($frequency eq "hourly") {
477 $cronrec = "50 * * * * $gsdl/collect/$colname/cron.pl";
478 }
479 elsif($frequency eq "daily") {
480 $cronrec = "00 0 * * * $gsdl/collect/$colname/cron.pl";
481 }
482 elsif($frequency eq "weekly") {
483 $cronrec = "59 11 * * 0 $gsdl/collect/$colname/cron.pl";
484 }
485
486 $cronrec = $cronrec." 2>/dev/null\n";
487
488 print $nf $cronrec;
489 }
490
491 close($nf);
492
493 #this makes the cronjob official
494 #still needs to be done for existing records
495 system("crontab $gsdl/collect/$colname/$cronf 2>/dev/null");
496
497 #cleanup
498 system("\\rm $gsdl/collect/$colname/outfile");
499 system("\\rm $gsdl/collect/$colname/$cronf");
500
501 if($action eq "add" || $action eq "update") {
502 &gsprintf($out, "{schedule.cron}\n");
503 }
504
505 } else {
506
507 #for windows, we will put crontab file in the same place. some limitations
508 #1) the absolute path to greenstone cannot have spaces if one is going to do this
509 #2) cron.exe needs to be started manually before doing this
510 #3) greenstone may have to be shut down completely to do this or lock problems occur
511
512 $cronf="crontab"; #pycron.exe expects this filename!
513 $ncronf="crontab.new";
514 #check to see if crontab file exists
515 if(-e "$gsdl/collect/$cronf")
516 {
517
518 open($of, "$gsdl/collect/$cronf") ||
519 (&gsprintf(STDERR, "{common.cannot_open_output_file}: $!\n", $out) && die);
520
521
522 open($nf, ">$gsdl/collect/$ncronf") ||
523 (&gsprintf(STDERR, "{common.cannot_open_output_file}: $!\n", $out) && die);
524
525 while($record = <$of>)
526 {
527 if($record !~ /$colname/)
528 {
529 print $nf $record;
530 }
531 }
532 close($of);
533 close($nf);
534
535 system("del \"$gsdl\\collect\\$cronf\"");
536 system("move \"$gsdl\\collect\\$ncronf\" \"$gsdl\\collect\\$cronf\"");
537
538
539 my $shortf = Win32::GetShortPathName($gsdl);
540
541 my $command = "$shortf\\bin\\windows\\silentstart $shortf\\bin\\windows\\perl\\bin\\perl $shortf\\collect\\$colname\\cron.pl\n";
542
543 if($action =~ /^add$/ || $action =~ /^update$/)
544 {
545 open($nf, ">>$gsdl/collect/$cronf") ||
546 (&gsprintf(STDERR, "{common.cannot_open_output_file}: $!\n", $out) && die);
547
548 if($frequency eq "hourly") {
549 print $nf "50 * * * * $command";
550 }
551 elsif($frequency eq "daily") {
552 print $nf "00 0 * * * $command";
553 }
554 elsif($frequency eq "weekly") {
555 print $nf "59 11 * * 0 $command";
556 }
557 close($nf);
558 }
559
560 } else {
561
562 my $shortf = Win32::GetShortPathName($gsdl);
563
564 my $command = "$shortf\\bin\\windows\\silentstart $shortf\\bin\\windows\\perl\\bin\\perl $shortf\\collect\\$colname\\cron.pl\n";
565
566
567 if($action =~ /^add$/ || $action =~ /^update$/)
568 {
569 open($nf, ">$gsdl/collect/$cronf") ||
570 (&gsprintf(STDERR, "{common.cannot_open_output_file}: $!\n", $out) && die);
571 if($frequency eq "hourly") {
572 print $nf "50 * * * * $command";
573 }
574 elsif($frequency eq "daily") {
575 print $nf "00 0 * * * $command";
576 }
577 elsif($frequency eq "weekly") {
578 print $nf "59 11 * * 0 $command";
579 }
580
581 close($nf);
582 }
583 }
584
585 if($action eq "update" || $action eq "add") {
586 &gsprintf($out, "{schedule.cron}\n");
587 }
588 }
589
590 #For the scheduling monitor
591 print STDERR "<Done>\n" if $gli;
592
593
594
595} #end sub main
Note: See TracBrowser for help on using the repository browser.