#!/sw/bin/perl -w use strict; use File::Find; use Cwd; # install_submission ... my $testing=0; my $MAIL_PROG='/projects/CGAL/admin_scripts/send_cgal_mail'; my ($submission, $packagedir, $oldpackagedir, $download_dir, $console_output, $tempdir, $check_source_file_prog, @reply_list); my $WGET; my $LOCKCMD="/sw/bin/lockfile"; umask 002; sub init_variables() { if ($testing) { $packagedir='/users/geert/tmp/inst_www/packages'; $oldpackagedir='/users/geert/tmp/inst_www/old_packages'; $download_dir='/users/geert/tmp/inst_www/download'; $console_output=1; $check_source_file_prog= '/users/geert/CGAL/Geert/maintenance/package_handling/check_headers'; } else { $packagedir='/users/www/CGAL/Members/Develop/updates/packages'; $oldpackagedir='/projects/CGAL/old_packages'; $download_dir='/projects/CGAL/submissions/download'; $console_output=0; $check_source_file_prog= '/projects/CGAL/admin_scripts/check_headers'; } @reply_list = ('geert@cs.uu.nl'); $WGET="/projects/CGAL/admin_scripts/get_cgal_html"; } $ENV{PATH}= '/sw/bin:/sbin:/usr/sbin:/usr/bsd:/bin:/usr/bin:/usr/bin/X11'; my $ACTUAL_LOGFILE="/tmp/install_www_submission.log.$$"; # write to logfile # sub log_header($) { if ( $console_output ) { print "$_[0]\n"; } print LOGFILE "-------------------------------------------------------\n"; print LOGFILE " $_[0]\n"; print LOGFILE "-------------------------------------------------------\n"; } sub log_msg($) { if ( $console_output ) { print "$0: $_[0]\n"; } print LOGFILE " $_[0]\n"; } sub log_done() { if ( $console_output ) { print " done\n-------------------------------------------------------\n" } print LOGFILE "-------------------------------------------------------\n"; print LOGFILE " DONE\n"; print LOGFILE "-------------------------------------------------------\n"; } sub print_usage() { print STDERR "usage: $0 \n"; } sub make_package_name($) { $_ = $_[0]; # remove the directory path s|.*/||; # remove trailing blanks s|\s*$||; # remove suffixes s|\.gz$||; s|\.tar$||; s|\.zip$||; s|\.tgz$||; # remove version # s|([-\.\d]+)+[a-zA-Z]?$||; # or should that be s|([-\.]\d+)+[a-zA-Z]?$||; return $_; } sub belongs_to_release($) # parameter 1 is the name of the package { open PACKAGES_TO_INCLUDE, "$packagedir/include_in_release" or die; while () { chomp; if (/^\s*$_[0]\s*$/) { close PACKAGES_TO_INCLUDE; return 1; } } close PACKAGES_TO_INCLUDE; return 0; } sub create_package_dir() { $tempdir="$packagedir/TMP$$"; mkdir($tempdir, 0775) ; } sub unpack_package($) { my ($full_file_name); $full_file_name = shift; chdir $tempdir; if ( $full_file_name =~ /\.tar\s*$/) { system 'gtar', 'xf', "$full_file_name"; } elsif ($full_file_name =~ /\.zip\s*$/) { system('unzip', '-oqq', "$full_file_name"); } elsif ($full_file_name =~ /\.tgz\s*$/ or $full_file_name =~ /\.tar.gz\s*$/) { system("gunzip -c $full_file_name | gtar xf -"); } else { return 0; } return !$?; } sub gzip_if_psfile { if ($_ =~ /\.ps\s*$/ and -f $_) { system('gzip',"$_"); } } sub compress_psfiles() { if (-d 'doc_ps') { find(\&gzip_if_psfile, "doc_ps"); } } sub get_version($) { my ($version_string, $date); open VERSION, $_[0] or return (); while () { next if (/^\s*$/); if ( /^\s*(\d+(?:[\.]\d+)*)\s*\((.*)\)\s*$/ ) { $version_string = $1; $date = $2; $_ = ; close VERSION; if (/^\s*[Mm]aintainer\s*:\s*(.*)$/ ) { return ($version_string,$date, $1); } else { return ($version_string,$date); } } close VERSION; return (); } close VERSION; return (); } sub check_version($) { my $package_name = shift; my ($new_version_string, $new_date, $package_maintainer, $old_version_string, $old_date, $old_package_maintainer, @nversion, @oversion); ($new_version_string, $new_date,$package_maintainer) = get_version('version'); if (!defined($new_version_string)) { log_msg "Failed to parse version file"; return (); } if (!defined($package_maintainer)) { log_msg "Version file does not contain a maintainer line!"; return (); } ($old_version_string, $old_date, $old_package_maintainer) = get_version("$packagedir/$package_name/version"); if (!defined($old_version_string)) { return ($new_version_string, $old_version_string, $package_maintainer); } my ($new_nr,$old_nr); @nversion = split /\./, $new_version_string; @oversion = split /\./, $old_version_string; my $version_ok = 0; while (@nversion) { $new_nr = shift @nversion; $old_nr = shift @oversion; $old_nr = 0 if !defined($old_nr); if ($new_nr < $old_nr) { last; } if ($new_nr > $old_nr) { $version_ok = 1; last; } } if (defined($old_package_maintainer)) { if ($old_package_maintainer =~ /\<(.*)\>/) { push(@reply_list, $1); } } if ( $package_maintainer ne $old_package_maintainer) { log_msg "Alert: Maintainer changed from '$old_package_maintainer'" . " to '$package_maintainer'"; } if ($version_ok ) { return ($new_version_string,$old_version_string, $package_maintainer); } else { log_msg "Version $new_version_string is not bigger than $old_version_string"; return (); } } my @source_files_to_check; sub add_codefiles { if ( $_ =~ /\.(C|h)\s*$/ and -f $_) { push @source_files_to_check, $File::Find::name; } } sub check_codefiles($$) { my $package_name = $_[0]; my $package_maintainer = $_[1]; @source_files_to_check = (); if (-d 'include') { find(\&add_codefiles, "include"); } if (-d 'src') { find(\&add_codefiles, "src"); } if (-d 'config') { find(\&add_codefiles, "config"); } my $source_file; foreach $source_file (@source_files_to_check) { system("$check_source_file_prog -u -d \"\" -p \"$package_name\" -m \"$package_maintainer\" $source_file >tmpmsg.$$"); open CHECK_MSGS, ") { chomp; log_msg($_); } close CHECK_MSGS; unlink "tmpmsg.$$"; } } sub append_maintainer_file_to_version_file() { open(MAINTAINER,'maintainer') or return; $_ = ; if (/^\s*$/) { close(MAINTAINER); return; } open(VERSION,'>>version'); if ($_ !~ /^maintainer\s*:/) { print VERSION "maintainer: "; } print VERSION $_; close(VERSION); while () { if ($_ =~ /\<(.*@.*)\>/) { push(@reply_list, $1); } } close(MAINTAINER); } sub filenames_of_package_ok($) { my $rc; $rc = system("/projects/CGAL/admin_scripts/check_filenames_of_package \"$_[0]\" . >tmpmsg.$$"); open CHECK_MSGS, ") { chomp; log_msg($_); } close CHECK_MSGS; unlink "tmpmsg.$$"; $rc >>= 8; if ($rc == 1) { log_msg("ERROR: sorry, there was an internal error at Utrecht.") } if ($rc == 2) { log_msg("ERROR: Your submissions contains files that are in use in another package") } return ($rc == 0); } sub check_for_ignored_files() { my %expected_names; my @expected_names = ("include", "test", "examples", "demo", "src", "version","doc_tex","stlport","winutils","auxiliary", "developer_scripts","scripts","cgal_config.bat", "install.txt","INSTALL.win32", "submission_info","maintainer","description.txt", "changes.txt","long_description.txt","doc_ps"); my @files_in_directory; opendir THISDIR, "." or die "Cannot open current directory: $!"; @files_in_directory = grep !/^\.\.?$/, readdir THISDIR; closedir THISDIR; for (@expected_names) { $expected_names{$_}++; } for (@files_in_directory) { if (!$expected_names{$_}) { log_msg "WARNING: toplevel file $_ will not go into releases!"; } } } sub check_package($) { my ($version, $prev_version, $package_maintainer); if ( ! -f 'version' ) { log_msg "ERROR: File version is missing!"; return 0; } if (-f 'maintainer') { append_maintainer_file_to_version_file(); } if ( ! (($version, $prev_version, $package_maintainer) = check_version($_[0])) ) { log_msg "ERROR: version file does not pass the checks!"; return 0; } if ( ! -f 'description.txt' ) { log_msg "WARNING: File description.txt is missing!"; } else { my $word_count; $word_count = `cat description.txt| wc -w`; if ($word_count > 50) { log_msg "WARNING: File description.txt contains more than 50 words!"; } my $rc; $rc = system("sed -e 's//\\>/g' < description.txt > descr"); if ($rc == 0) { rename 'descr', 'description.txt'; } else { unlink 'descr'; } } # if ( ! -f 'changes.txt' ) { # log_msg "WARNING: File changes.txt is missing!"; # } check_for_ignored_files(); if ( ! filenames_of_package_ok($_[0])) { return 0; } check_codefiles("$_[0] ($version)", "$package_maintainer"); if (defined($prev_version)) { log_msg "Version $version will replace $prev_version"; } else { log_msg "Version $version will be installed"; } return 1; } sub compress_package($) { my $package_name = shift; compress_psfiles; system 'zip', '-q', '-r', $package_name, glob("*"); return !$?; } sub remove_files() { my ($file); opendir THISDIR, "." or die; foreach $file (readdir THISDIR) { if (-d $file) { next if $file eq '.'; next if $file eq '..'; next if $file eq 'doc_ps'; system 'rm', '-rf', "$file"; } elsif (-f $file) { next if $file =~ /\.zip$/; next if $file eq 'version'; next if $file eq 'description.txt'; next if $file eq 'long_description.txt'; next if $file eq 'changes.txt'; next if $file eq 'submission_info'; unlink $file; } } closedir THISDIR; } sub move_packagedir($) { my $package_name = shift; # first remove the earlier version (if it exists) if ( -d "$oldpackagedir/$package_name" ) { # log_msg "removing directory $oldpackagedir/$package_name" system('rm', '-rf', "$oldpackagedir/$package_name"); } # move existing version to old packages if ( -d "$packagedir/$package_name" ) { # log_msg "moving directory $packagedir/$package_name to $oldpackagedir/$package_name" print STDERR 'cp',' -r'," $packagedir/$package_name ", $oldpackagedir ,"\n"; (system('cp','-r',"$packagedir/$package_name", $oldpackagedir)==0) or die; (system('rm','-r',"$packagedir/$package_name")==0) or die; } # log_msg "moving directory $tempdir to $packagedir/$package_name" rename($tempdir, "$packagedir/$package_name") or die; system 'chgrp', '-R', 'cgal', "$packagedir/$package_name"; system 'chmod', '-R', 'ug+w,a+r', "$packagedir/$package_name" ; } sub install_submission($$) { my ($file_name, $file_pathname, $package_name); $file_name = shift; $package_name = shift; $file_pathname = "$download_dir/$file_name"; if (! unpack_package( $file_pathname) ) { log_msg("Failed to unpack $file_pathname"); return 0; } if (!check_package($package_name)) { return 0; } if (!compress_package($package_name)) { log_msg "ERROR: Failed to compress $file_name"; return 0; } remove_files; move_packagedir($package_name); return 1; } sub do_submission($) { my ($url, $cur_dir,$file_name,$package_name); $url = shift; ($file_name) = ($url =~ m|^.*/(.*?)\s*$|); $package_name = make_package_name($file_name); if ($package_name !~ /^[a-zA-Z_]\w*$/) { log_header "ERROR: Filename $file_name was turned into the illegal package name $package_name"; return 0; } if (!belongs_to_release($package_name) ) { log_msg "WARNING: package $package_name will not go into releases"; log_msg "Send a separate mail to cgal_submit if you want that"; } unlink glob("$download_dir/*") if (! $testing); log_header "downloading $url"; # my $logfileno = fileno(LOGFILE); # die "Log file not open" if ! defined($logfileno); $cur_dir =cwd(); my $lockfile = "$download_dir/$package_name.lock"; if ( system("$LOCKCMD", "-r", '10', $lockfile) != 0) { log_msg "ERROR: could not acquire lock on file $lockfile!"; return 0; } if (chdir "$download_dir") { system("$WGET $url"); chdir $cur_dir; } if ( ! -f "$download_dir/$file_name" ) { log_msg "ERROR: download failed!"; return 0; } chdir($tempdir); open SUBMISSION_INFO, ">submission_info"; print SUBMISSION_INFO "URL: $url.\n"; close SUBMISSION_INFO; if (install_submission("$file_name",$package_name) ) { log_header "Package was successfully installed!"; } else { log_header "ERROR: Installation of the package failed!"; unlink $lockfile; return 0; } unlink $lockfile; return 1; } #----------------------------------- # # main loop # #----------------------------------- if ($#ARGV < 0) { print "Too few arguments:",$#ARGV,"\n"; print_usage; exit 1; } my $starting_directory = cwd(); if ($starting_directory =~ m'CGAL/Geert/maintenance') { $testing=1; } init_variables(); $SIG{INT}='IGNORE'; $SIG{QUIT} = 'IGNORE'; $SIG{TERM} = 'IGNORE'; unlink $ACTUAL_LOGFILE; system("echo >$ACTUAL_LOGFILE"); open LOGFILE, ">$ACTUAL_LOGFILE"; foreach $submission ( @ARGV) { if (!create_package_dir) { log_msg "Failed to create temporary directory $tempdir"; exit 1; } do_submission($submission); chdir($starting_directory); if (-d "$tempdir") { system('rm', '-rf', "$tempdir"); } } close LOGFILE; @reply_list = sort(@reply_list); my $prev = ""; my @rlist; foreach (@reply_list) { if ($_ ne $prev) { $prev = $_; push(@rlist, $prev); } } $ARGV[0] =~ s|.*/||; system "cat $ACTUAL_LOGFILE | $MAIL_PROG \"CGAL submission $ARGV[0]\" @rlist"; unlink $ACTUAL_LOGFILE; exit 0;