source: trunk/bio/scripts/project_build @ 26002

Revision 26002, 25.8 KB checked in by alex, 9 months ago (diff)

Avoids pointless warning on blank lines in property files

  • Property svn:executable set to *
Line 
1#!/usr/bin/perl
2
3# Run an InterMine production build and dump the database occasionally.
4# The project.xml in the current directory controls which actions to
5# run/merge/postprocess.
6# The database to dump will be found by reading the properties from $HOME/.intermine/<mine_name>.properties
7# where <mine_name> is the name of the directory where the script is run
8
9use strict;
10use warnings;
11
12use Getopt::Std;
13use Cwd;
14
15use XML::Parser::PerlSAX;
16use Text::Glob qw(glob_to_regex);
17
18my @ant_command = ("ant");
19
20my $dump_file_prefix;
21my $dump_host;
22my $project_file = 'project.xml';
23my $pgpass_file = "$ENV{HOME}/.pgpass";
24my $default_port = '5432';
25my $final_dump_name = 'final-dump';
26my $final_marker = 'final';
27
28sub read_properties {
29    my $file = shift;
30   
31    open(my $in, '<', "$file") or die "cannot open $file: $!\n";
32   
33    my %properties;
34   
35    while (<$in>) {
36        next if /^\s*#/;
37        chomp;
38        my ($k, $v) = split(/\s*=\s*/, $_, 2);
39        next unless $k;
40        $properties{$k} = $v;
41    }
42    close($in) or die "Problem reading from $file: $!\n"; 
43
44    return %properties;
45}
46
47sub usage
48{
49  die <<"HELP";
50usage:
51  $0 [-v] [-b] [-l | -r] [-T] [-u | -U] [-V <version>] [-D dest_database_name] [-a <actions>] dump_host dump_prefix
52
53flags:
54 -v is passed to ant
55 -l attempt to restart by reading the last dump file
56 -r attempt to restart just after the last dump point _without_ loading a dump
57 -b run build-db before starting build and drop any existing backup databases
58 -n parse files and report actions, but don't execute anything
59 -V set the release number to pass to ant (as -Drelease=release_number)
60 -T instead of making backup copies of the database in the
61    server using the "CREATE DATABASE foo WITH TEMPLATE bar" command,
62    dump and reload to restart.
63 -E Set the default database encoding (defaults to SQL_ASCII if not passed)
64 -D set the destination database for the completed build; the database will be
65    copied to this name in the same postgres server that the build used
66 -a set the list of actions to perform - the list must be a subset of the
67    sources/postprocesses in the project.xml file.
68     - The -l and -r operate as usual.
69     - To run all steps starting at <some_action> use a dash after the action
70       name: -a <some_action>-
71     - To perform only the final dump use: -a $final_dump_name
72     - The action names can be patterns: -a 'flymine-static,*dmel*'
73     - To refer to dump step and skip its corresponding action use the action
74       name with "-dump" appended
75          eg -a fly-fish-dump-  (starts with the fly-fish dump then continues)
76             -a fly-fish-dump,flymine-static,create-references,$final_dump_name
77 -u Build userprofile database if not already populated
78 -U Build userprofile database even if already populated
79
80dump_host is the host to run pg_dump and pg_restore on
81
82With the -t flag, one dump is made the end of the build with the name
83dump_prefix.final
84
85Without the -t flag, a dump is made after integrating each source in the
86project.xml that has dump="true" set.  A final dump is also made.
87
88example:
89  $0 prod1 /tmp/production_dump
90HELP
91}
92
93if (!-f $project_file) {
94  warn "can't find $project_file in the current directory\n";
95  usage();
96}
97
98my $verbose = 0;
99my $load_last = 0;
100my $restart = 0;
101
102# if true, don't execute anything just print what will happen
103my $dry_run = 0;
104
105# if true don't dump and reload, instead do backup copies in the server using
106# the "CREATE DATABASE foo WITH TEMPLATE bar" command
107my $server_backup = 1;
108
109my $db_encoding = 'SQL_ASCII';
110
111# if true, run build-db before starting the integration
112my $run_build_db = 0;
113my $dest_db;
114
115my $release;
116my @required_actions_list = ();
117my $start_action = undef;
118
119# Process command-line opts
120my %opts = ();
121
122if (!getopts('vrlbTnuUE:D:a:V:', \%opts)) {
123  usage();
124}
125
126if ($opts{v}) {
127  $verbose = 1;
128  push @ant_command, '-v';
129}
130
131if ($opts{l}) {
132  $load_last = 1;
133}
134
135if ($opts{r}) {
136  $restart = 1;
137}
138
139if ($opts{n}) {
140  $dry_run = 1;
141}
142
143if ($opts{T}) {
144  $server_backup = 0;
145}
146
147if (defined $opts{E}) {
148    $db_encoding = $opts{E};
149}
150
151if ($opts{b}) {
152  $run_build_db = 1;
153}
154
155if ($opts{D}) {
156  $dest_db = $opts{D};
157}
158
159my $build_userprofile_db;
160if ($opts{u} or $opts{U}) {
161#    $build_userprofile_db = 1;
162}
163my $overwrite_userprofile_ok;
164if ($opts{U}) {
165#    $overwrite_userprofile_ok = 1;
166}
167
168if (exists $opts{a}) {
169  my $arg = $opts{a};
170  if ($arg =~ /^.*,.*-$/) {
171    warn "error: can't use commas and '-' in -a <actions> argument: $arg\n";
172    usage;
173  }
174  if ($arg =~ /(.*)-$/) {
175    $start_action = $1;
176  } else {
177    @required_actions_list = split (',', $arg);
178  }
179}
180
181if ($opts{V}) {
182  $release = $opts{V};
183  push @ant_command, "-Drelease=$release"
184}
185
186if (@ARGV == 2) {
187  $dump_host = $ARGV[0];
188  $dump_file_prefix = $ARGV[1];
189} else {
190  usage;
191}
192
193my $log_file = "pbuild.log";
194my $mode = ($run_build_db) ? '>' : '>>'; 
195open(LOG, $mode, $log_file) or die "can't open $log_file: $!\n";
196
197my $old_handle = select(LOG);
198$| = 1; # autoflush
199select $old_handle;
200
201my $current_directory = (getcwd() =~ m:.*/(.*):)[0];
202
203my $properties_file = "$ENV{HOME}/.intermine/$current_directory.properties";
204if (defined $release) {
205  $properties_file .= ".$release";
206}
207
208my @psql_command = 'psql';
209my @dump_command = qw[pg_dump -F c -i];
210my @load_command = qw[pg_restore -1 -i];
211my @dropdb_command = qw[dropdb];
212my @createdb_command = (qw[createdb -E ], $db_encoding);
213
214sub log_message
215{
216  my $message = shift;
217  my $verbose = shift;
218
219  if (defined $message) {
220    print LOG "$message\n";
221    if (defined $verbose && $verbose) {
222      print STDERR "$message\n";
223    }
224  } else {
225    print LOG "\n";
226  }
227}
228
229sub log_and_print
230{
231  log_message shift, 1;
232}
233
234# run a command and exit the script if it returns a non-zero
235sub run_and_check_status
236{
237  my $command_name = $_[0];
238
239  log_and_print `date`, "\n\n";
240  log_and_print "starting command: @_\n";
241
242  my $result = 0;
243
244  if (!$dry_run) {
245    open F, "@_ |" or die "can't run @_: $?\n";
246
247    while (<F>) {
248      chomp;
249      log_message "  [$command_name] $_";
250    }
251
252    close F;
253
254    $result = $?;
255  }
256
257  log_and_print `date`, "\n\n";
258  log_and_print "finished\n\n";
259
260  if ($result != 0) {
261    warn "ERROR: $result\n";
262  }
263
264  if (!$dry_run && $result != 0) {
265    log_and_print "failed with exit code $?: @_\n";
266    print STDERR "check log: $log_file\n";
267    exit 1;
268  }
269}
270
271sub spawn
272{
273  my $pass = shift;
274  my @spawn_args = @_;
275
276  if (!defined $dump_host || $dump_host eq 'localhost') {
277    $ENV{PAGER} = "/bin/cat";
278    @spawn_args = "sh -c '@spawn_args'";
279  } else {
280    unshift @spawn_args, "ssh", $dump_host;
281  }
282
283  if ($dry_run) {
284    log_and_print "command to run: @spawn_args\n";
285  } else {
286    my $pid = open(my $PROCESS, '-|', @spawn_args) 
287        or die "Could not execute @spawn_args\n";
288    while (<$PROCESS>) {
289        if (/error/i) {
290            die "Error returned by @spawn_args\n";
291        } 
292    }
293    close $PROCESS;
294  }
295}
296
297sub run_build_db
298{
299  log_and_print `date`, "\n";
300  log_and_print "\nbuilding db: @ant_command build-db\n";
301
302  my $saved_dir = getcwd;
303  chdir "$saved_dir/dbmodel" or die "can't change directory into: $saved_dir/dbmodel\n";
304
305  run_and_check_status @ant_command, "clean";
306  run_and_check_status @ant_command, "build-db";
307
308  chdir $saved_dir
309    or die "can't return to previous directory ($saved_dir) after $saved_dir/dbmodel\n";
310}
311
312sub dropdb_backups
313{
314  my ($db, $user, $pass, $host, $port, $database_names_ref, $actions_ref) = @_;
315
316  my @database_names = @$database_names_ref;
317
318  my @actions = @$actions_ref;
319
320  for my $action (@actions) {
321    my $action_type = $action->{type};
322    my @action_args = @{$action->{args}};
323
324    if ($action_type eq 'dump') {
325      my $action_name = $action_args[0];
326      my $backup_name = "$db:$action_name";
327      if (grep {$_ eq $backup_name} @database_names) {
328        my @params = ('-U', $user, '-h', $host, $backup_name);
329
330        log_and_print `date`, "\n";
331        log_and_print "\ndropping old backup database: @dropdb_command @params\n";
332
333        spawn($pass, @dropdb_command, @params);
334      }
335    }
336  }
337}
338
339sub create_prod_db
340{
341  my ($db, $user, $pass, $host, $port, $suffix) = @_;
342
343  my @params = ('-U', $user, '-h', $host, $db);
344
345  log_and_print `date`, "\n";
346  log_and_print "\ncreating database: @createdb_command @params\n";
347
348  eval {
349    # ignore error - it's OK if the database doesn't exist
350    spawn($pass, @createdb_command, @params);
351  };
352
353  run_build_db();
354}
355
356sub copy_db
357{
358  my ($db, $user, $pass, $host, $port, $to_db) = @_;
359
360  my @params = ('-U', $user, '-h', $host, '-T', $db, $to_db);
361
362  log_and_print `date`, "\n\n";
363  log_and_print "\nmaking db copy: @createdb_command @params\n";
364
365  # retry a few times because sometimes the createdb fails with a "no
366  # such file or directory" error because some table/index files
367  # (temporary tables maybe) disappear while being copied
368  for (my $i = 1; $i <= 25; $i++) {
369    eval {
370      spawn($pass, @createdb_command, @params);
371    };
372    if ($@) {
373      my $pause = $i * 5;
374      warn "failure ($@) - will try again in $pause seconds ...\n";
375      sleep($pause);
376    } else {
377      last;
378    }
379  }
380
381  die "$@\n" if $@;
382}
383
384sub make_server_backup
385{
386  my ($db, $user, $pass, $host, $port, $suffix) = @_;
387
388  copy_db($db, $user, $pass, $host, $port, "$db:$suffix");
389
390  log_and_print `date`, "\n\n";
391  log_and_print "finished backup\n\n";
392}
393
394sub server_restore
395{
396  my ($db, $user, $pass, $host, $port, $suffix) = @_;
397
398  my @params = ('-U', $user, '-h', $host);
399
400  if (defined $port) {
401    unshift @params, "-p", $port;
402  }
403
404  log_and_print `date`, "\n\n";
405  log_and_print "\nrunning: @dropdb_command @params $db\n";
406
407  eval {
408    # ignore failures
409    spawn($pass, @dropdb_command, @params, $db);
410  };
411
412  log_and_print `date`, "\n\n";
413  log_and_print "\nrunning: @createdb_command @params -T $db:$suffix $db\n";
414
415  spawn($pass, @createdb_command, @params, '-T', "$db:$suffix", $db);
416
417  log_and_print `date`, "\n\n";
418  log_and_print "finished restore - now analysing\n\n";
419
420  my $saved_dir = getcwd;
421  chdir "$saved_dir/dbmodel" or die "can't change directory into: $saved_dir/dbmodel\n";
422
423  run_and_check_status @ant_command, "analyse-db-production";
424
425  chdir $saved_dir
426    or die "can't return to previous directory ($saved_dir) after $saved_dir/dbmodel\n";
427
428  log_and_print `date`, "\n\n";
429  log_and_print "finished analysing\n\n";
430}
431
432sub dump_db
433{
434  my $db = shift;
435  my $user = shift;
436  my $pass = shift;
437  my $host = shift;
438  my $port = shift;
439  my $out_file = shift;
440
441  my @params = ('-U', $user, '-h', $host, '-f', $out_file, $db);
442
443  if (defined $port) {
444    unshift @params, "-p", $port;
445  }
446
447  log_and_print `date`, "\n\n";
448  log_and_print "\ndumping: @dump_command @params\n";
449
450  my @spawn_args = ($pass, "@dump_command @params");
451
452  spawn(@spawn_args);
453
454  log_and_print `date`, "\n\n";
455  log_and_print "finished dump\n\n";
456}
457
458sub load_db
459{
460  my $db = shift;
461  my $user = shift;
462  my $pass = shift;
463  my $host = shift;
464  my $port = shift;
465  my $in_file = shift;
466
467  my @params = ('-U', $user, '-h', $host);
468
469  if (defined $port) {
470    unshift @params, "-p", $port;
471  }
472
473  log_and_print `date`, "\n\n";
474  log_and_print "\nrunning: @dropdb_command @params $db\n";
475
476  eval {
477    # ignore failures
478    spawn($pass, @dropdb_command, @params, $db);
479  };
480
481  log_and_print `date`, "\n\n";
482  log_and_print "\nrunning: @createdb_command @params $db\n";
483
484  spawn($pass, @createdb_command, @params, $db);
485
486  push @params, '-d', $db, $in_file;
487
488  log_and_print `date`, "\n\n";
489  log_and_print "\nrunning: @load_command @params\n";
490
491  spawn($pass, @load_command, @params);
492
493  log_and_print `date`, "\n\n";
494  log_and_print "finished load - now analysing\n\n";
495
496  my $saved_dir = getcwd;
497  chdir "$saved_dir/dbmodel" or die "can't change directory into: $saved_dir/dbmodel\n";
498
499  run_and_check_status @ant_command, "analyse-db-production";
500
501  chdir $saved_dir
502    or die "can't return to previous directory ($saved_dir) after $saved_dir/dbmodel\n";
503
504  log_and_print `date`, "\n\n";
505  log_and_print "finished analysing\n\n";
506}
507
508package ProjectXML::Handler;
509
510use vars qw{ $AUTOLOAD };
511
512sub new {
513  my $type = shift;
514  my $self = ( $#_ == 0 ) ? shift : { @_ };
515
516  $self->{sources} = [];
517  return bless $self, $type;
518}
519
520sub start_element
521{
522  my $self = shift;
523  my $args = shift;
524
525  my $element_name = $args->{Name};
526  my $action_name = $args->{Attributes}{name};
527  my $dump_flag = (exists $args->{Attributes}{dump} and $args->{Attributes}{dump} eq 'true');
528  my $index_flag = exists $args->{Attributes}{index};
529
530  if ($element_name eq 'source') {
531    push @{$self->{actions}}, {
532                               type => 'integrate',
533                               args => ["-Dsource=$action_name"],
534                               name => $action_name
535                              };
536  } elsif ($element_name eq 'post-process') {
537      push @{$self->{actions}}, {
538                                 type => 'postprocess',
539                                 args => ["-Daction=$action_name"],
540                                 name => $action_name
541                                };
542  } elsif ($element_name eq 'property' and $action_name eq 'intermine.properties.file') {
543      $self->{properties_file} = $args->{Attributes}{value};
544  } else {
545      return;
546  }
547
548  if ($dump_flag) {
549    push @{$self->{actions}}, {
550                               type => 'dump',
551                               args => ["$action_name"],
552                               name => "$action_name-dump"
553                             };
554  }
555
556  if ($index_flag) {
557    push @{$self->{actions}}, {
558                               type => 'index',
559                               args => ["$action_name"],
560                               name => "$action_name-index"
561                              };
562  }
563}
564
565sub processing_instruction { }
566sub ignorable_whitespace { }
567
568# Others
569sub AUTOLOAD {
570    my $self = shift;
571
572    my $method = $AUTOLOAD;
573    $method =~ s/.*:://;
574    return if $method eq 'DESTROY';
575
576    print "UNRECOGNIZED $method\n";
577}
578
5791;
580
581
582package main;
583
584# add missing lines to .pgpass so that createdb and co never ask for a password
585sub fix_pgpass
586{
587  my ($db, $user, $pass, $host, $port) = @_;
588
589  if (-f $pgpass_file) {
590    open PGPASS, '<', $pgpass_file or die "can't open $pgpass_file: $!\n";
591
592    while (my $line = <PGPASS>) {
593      chomp $line;
594
595      my ($line_host, $line_port, $line_db, $line_user, $line_pass) =
596        split (/:/, $line);
597
598      if ($line_host eq $host &&
599          ($line_port eq $default_port && !defined $port ||
600           defined $port && $line_port eq $port) &&
601          ($line_db eq '*' || $line_db eq $db) &&
602          $line_user eq $user &&
603          $line_pass eq $pass) {
604        # match
605        chmod 0600, $pgpass_file or die "can't change mode of $pgpass_file: $!\n";
606        return;
607      }
608    }
609
610    close PGPASS;
611  }
612
613  open PGPASS, '>>', $pgpass_file
614    or die "can't open $pgpass_file for appending: $!\n";
615
616  my $out_port;
617
618  if (defined $port) {
619    $out_port = $port;
620  } else {
621    $out_port = $default_port;
622  }
623
624  print PGPASS "$host:$out_port:*:$user:$pass\n";
625
626  close PGPASS or die "can't close $pgpass_file: $!\n";
627
628  chmod 0600, $pgpass_file or die "can't change mode of $pgpass_file: $!\n";
629}
630
631sub userprofile_db_already_populated {
632    my $properties_file = shift;
633    my $userprofiledb;
634    my $psql_opt = q{-c '\d'};
635
636    open (my $props, '<', $ENV{HOME}.'/.intermine/'.$properties_file) 
637        or die "Cannot open $project_file for reading, $!";
638    while (<$props>) {
639        if (/\Qdb.userprofile-production.datasource.databaseName\E/) {
640            (undef, $userprofiledb) = split(/=/);
641            last;
642        }
643    }
644    close $props or die "Could not close $project_file after reading, $!";
645
646    my $command  = join(' ', @psql_command, $psql_opt, $userprofiledb);
647    my $results = qx/$command/;
648    if ($results =~ /(?:psql: FATAL database.*does not exist|No relations found)/) {
649        return 0; # database does not exist, or is empty
650    } elsif ($results =~ /List of Relations.*\d+ rows/s) {
651        return 1; #database exists and is populated
652    } else {
653        die "Unknown psql response status: $results";
654    }
655}
656
657
658sub get_actions
659{
660  my $handler = ProjectXML::Handler->new();
661  my $parser = XML::Parser::PerlSAX->new(Handler => $handler);
662
663 
664  $parser->parse(Source => { SystemId => $project_file });
665
666  if (!defined $handler->{actions}) {
667      die "invalid project.xml file, unable to continue build";
668  }
669
670  my @actions = @{$handler->{actions}};
671
672  if (@actions && $actions[-1]{type} ne 'dump') {
673    push @actions, {
674                    type => 'dump',
675                    args => [$final_marker],
676                    name => $final_dump_name,
677                   };
678  }
679
680  if (defined $dest_db) {
681    push @actions, {
682                    type => 'copy',
683                    args => [$dest_db],
684                    name => "copy_to_$dest_db"
685                   };
686  }
687
688  my $properties_file = $handler->{properties_file};
689
690  if ($build_userprofile_db) {
691      if ($overwrite_userprofile_ok 
692              or userprofile_db_already_populated($properties_file) ) {
693          push @actions, {
694              type => 'webapp',
695              args => ['build-db-userprofile'],
696              name => 'Build_Userprofile_DB',
697          };
698     }
699  };
700
701  my @return_actions = ();
702
703  if (defined $start_action) {
704    my $seen_start = 0;
705
706    # we're restarting so remove all actions before start_action
707    for my $action (@actions) {
708      if ($seen_start || $action->{name} eq $start_action) {
709        push @return_actions, $action;
710        $seen_start = 1;
711      }
712    }
713
714    if (!$seen_start) {
715      warn "error: start action $start_action not found in $project_file\n";
716      usage;
717    }
718  } else {
719    my @actions_not_found = @required_actions_list;
720
721    if (@required_actions_list) {
722      my %action_map = map {($_->{name}, $_)} @actions;
723
724      # remove all not in required list
725      for my $req_action_pattern (@required_actions_list) {
726        my $req_action_re = glob_to_regex($req_action_pattern);
727        for my $action (@actions) {
728          my $action_name = $action->{name};
729          if ($action_name =~ /$req_action_re/) {
730            push @return_actions, $action;
731          }
732        }
733      }
734
735      if (!@return_actions) {
736        warn "error:  not found in $project_file\n";
737        usage;
738      }
739
740      if ($verbose) {
741        my $action_names = join ',', map { $_->{name} } @return_actions;
742        warn "running actions: $action_names\n";
743      }
744    } else {
745      # default - use all actions from project.xml
746      @return_actions = @actions;
747    }
748  }
749
750  return @return_actions;
751}
752
753
754# find the last existing backup file
755sub get_restart_suffix_file
756{
757  my ($dump_file_prefix, @actions) = @_;
758
759  my %remote_suffixes = ();
760
761  my $command;
762
763  if ($dump_host eq 'localhost') {
764    $command = qq{ls -1 $dump_file_prefix.*};
765  } else {
766    $command = qq{ssh $dump_host "ls -1 $dump_file_prefix.*"};
767  }
768
769  open LS_OUTPUT, qq{$command|};
770
771  while (my $line = <LS_OUTPUT>) {
772    chomp $line;
773    if ($line =~ /$dump_file_prefix.(.*)/) {
774      $remote_suffixes{$1} = 1;
775    }
776  }
777
778  my $restart_dump_suffix = undef;
779
780  for my $action (@actions) {
781    my $action_type = $action->{type};
782    my @action_args = @{$action->{args}};
783
784    if ($action_type eq 'dump') {
785      if (exists $remote_suffixes{$action_args[0]}) {
786        $restart_dump_suffix = $action_args[0];
787      }
788    }
789  }
790
791  close LS_OUTPUT;
792
793  return $restart_dump_suffix;
794}
795
796sub get_database_names
797{
798  my ($db, $user, $pass, $host, $port, @actions) = @_;
799
800  my @database_names = ();
801
802  my @params = ('-U', $user, '-h', $host, '-d', 'postgres', '-l');
803
804  if (defined $port) {
805    push @params, "-p", $port;
806  }
807
808  my $command = "@psql_command @params";
809
810  log_and_print `date`, "\n\n";
811  log_and_print "\nrunning: $command\n";
812
813  open PSQL, "$command|"
814  or die "can't open pipe to $command: $!\n";
815
816  while (my $line = <PSQL>) {
817    chomp $line;
818    if ($line =~ /^\s*(\S+)/) {
819      push @database_names, $1;
820    }
821  }
822
823  close LS_OUTPUT;
824
825  return @database_names;
826}
827
828# find the last existing backup suffix by asking the postgres server
829sub get_restart_suffix_server
830{
831  my ($db, $database_names_ref, $actions_ref) = @_;
832
833  my @actions = @{$actions_ref};
834
835  my %remote_suffixes = ();
836
837  for my $database_name (@{$database_names_ref}) {
838    if ($database_name =~ /$db:(\S+)/) {
839      $remote_suffixes{$1} = 1;
840    }
841  }
842
843  my $restart_suffix = undef;
844
845  for my $action (@actions) {
846    my $action_type = $action->{type};
847    my @action_args = @{$action->{args}};
848
849    if ($action_type eq 'dump') {
850      if (exists $remote_suffixes{$action_args[0]}) {
851        $restart_suffix = $action_args[0];
852      }
853    }
854  }
855
856  close LS_OUTPUT;
857
858  return $restart_suffix;
859}
860
861log_and_print "reading properties from: $properties_file\n";
862
863my %properties = read_properties($properties_file);
864my ($prod_host, $prod_db, $prod_user, $prod_pass) = @properties{qw/
865        db.production.datasource.serverName
866        db.production.datasource.databaseName
867        db.production.datasource.user
868        db.production.datasource.password
869/};
870
871my $prod_port;
872
873if ($prod_host =~ /(.+):(\d+)/) {
874  $prod_host = $1;
875  $prod_port = $2;
876}
877
878log_message "found properties:";
879log_message "  prod_host: $prod_host";
880log_message "  prod_port: " . (defined($prod_port) ? $prod_port : "default");
881log_message "  prod_db: $prod_db";
882log_message "  prod_user: $prod_user";
883log_message "  prod_pass: $prod_pass";
884log_message;
885
886fix_pgpass($prod_db, $prod_user, $prod_pass, $prod_host, $prod_port);
887
888my @actions = get_actions();
889
890my $restart_dump_suffix = undef;
891
892my @database_names = get_database_names($prod_db, $prod_user, $prod_pass,
893                                        $prod_host, $prod_port);
894
895if (grep {$_ eq $prod_db } @database_names) {
896  if ($verbose) {
897    log_and_print ("not creating $prod_db as it already exists\n");
898  }
899
900  if ($run_build_db) {
901    run_build_db();
902    dropdb_backups($prod_db, $prod_user, $prod_pass, $prod_host, $prod_port,
903                   [@database_names], [@actions]);
904    # if we're starting from scratch, don't try to load old databases
905    @database_names = ();
906  }
907} else {
908  create_prod_db($prod_db, $prod_user, $prod_pass, $prod_host, $prod_port);
909  dropdb_backups($prod_db, $prod_user, $prod_pass, $prod_host, $prod_port,
910                 [@database_names], [@actions]);
911  # if we're starting from scratch, don't try to load old databases
912  @database_names = ();
913}
914
915if (($load_last || $restart) && !$run_build_db) {
916  my $restart_file_suffix = get_restart_suffix_file($dump_file_prefix, @actions);
917
918  if ($server_backup) {
919    if (defined $restart_file_suffix && $restart_file_suffix eq $final_marker) {
920      log_and_print ("backup with .$final_marker suffix exists - " .
921                     "build finished - exiting\n");
922      exit(0);
923    } else {
924      $restart_dump_suffix =
925        get_restart_suffix_server($prod_db, \@database_names, \@actions);
926    }
927  } else {
928    $restart_dump_suffix = $restart_file_suffix;
929  }
930
931  if (defined $restart_dump_suffix) {
932    if ($restart_dump_suffix eq $final_marker) {
933      log_and_print ("backup with .$final_marker suffix exists - " .
934                     "build finished - exiting\n");
935      exit(0);
936    } else {
937      if ($load_last) {
938        if ($server_backup) {
939          log_and_print "\nrestarting using database: $prod_db:$restart_dump_suffix\n";
940          server_restore ($prod_db, $prod_user, $prod_pass, $prod_host, $prod_port,
941                          $restart_dump_suffix);
942        } else {
943          my $dump_file_name = "$dump_file_prefix.$restart_dump_suffix";
944          log_and_print "\nrestarting from $dump_file_name\n";
945          load_db ($prod_db, $prod_user, $prod_pass, $prod_host, $prod_port,
946                   $dump_file_name);
947        }
948      } else {
949        log_and_print ("\nrestarting build at stage: $restart_dump_suffix - " .
950                       "NOT restoring from backup\n");
951      }
952    }
953  } else {
954    warn "no backup file found\n";
955  }
956}
957
958my $seen_start_action = 0;
959
960if ((!$load_last && !$restart) || !defined $restart_dump_suffix) {
961  # always start at the beginning of the command list if we aren't restarting
962  $seen_start_action = 1;
963}
964
965my @action_times = ();
966
967
968for my $action (@actions) {
969  my $action_name = $action->{name};
970  my $action_type = $action->{type};
971  my @action_args = @{$action->{args}};
972
973  if ($seen_start_action) {
974    my $start_time = time();
975
976    if ($action_type =~ /^(?:integrate|postprocess|webapp)$/) {
977      my $saved_dir = getcwd;
978      chdir $action_type
979        or die "can't change directory into: $saved_dir/$action_type\n";     
980      run_and_check_status @ant_command, @action_args;
981      chdir $saved_dir
982        or die "can't return to previous directory ($saved_dir) after $action_type\n";
983    } elsif ($action_type eq 'dump') {
984        if (@action_args != 1) {
985          die "dump: needs one parameter at: $action: @action_args\n";
986        }
987        if ($server_backup && $action_name ne $final_dump_name) {
988          make_server_backup ($prod_db, $prod_user, $prod_pass, $prod_host, $prod_port,
989                              $action_args[0]);
990        } else {
991          dump_db ($prod_db, $prod_user, $prod_pass, $prod_host, $prod_port,
992                   "$dump_file_prefix.$action_args[0]");
993        }
994    } elsif ($action_type eq 'copy') {
995        copy_db($prod_db, $prod_user, $prod_pass, $prod_host, $prod_port, $action_args[0]);
996    } else {
997        die qq{unknown action: "$action_type"\n};
998    }
999   
1000 
1001
1002    my $end_time = time();
1003    my $action_time = $end_time - $start_time;
1004
1005    if ($verbose) {
1006      log_and_print qq(action $action_name took $action_time seconds\n);
1007    }
1008
1009    push @action_times, [$action_name, $action_time];
1010  } else {
1011    if ($action_type eq 'dump' && $action_args[0] eq $restart_dump_suffix) {
1012      $seen_start_action = 1;
1013    }
1014  }
1015}
1016
1017my ($key, $value);
1018
1019format STDOUT_TOP =
1020
1021action name                                   time in seconds
1022-------------------------------------------------------------
1023.
1024
1025format STDOUT =
1026@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @>>>>>>>>>>>>>
1027$key, $value
1028.
1029
1030my $total_time = 0;
1031
1032for my $name_and_time (@action_times) {
1033  ($key, $value) = @$name_and_time;
1034  $total_time += $value;
1035  write;
1036}
1037
1038if ($total_time > 0) {
1039  print "\n";
1040
1041  $key = 'total';
1042  $value = $total_time;
1043  write;
1044}
Note: See TracBrowser for help on using the repository browser.