#!/usr/bin/perl -w # # Bootstrap # # Script to export a given BK source tree into a separate directory # and create the source distribution to be used for all binary builds # # Use the "--help" option for more info! # # written by Lenz Grimmer <lenz@mysql.com> # use Cwd; use Getopt::Long; Getopt::Long::Configure ("bundling"); # Include helper functions $LOGGER= "$ENV{HOME}/bin/logger.pm"; if (-f $LOGGER) { do "$LOGGER"; } else { die "ERROR: $LOGGER cannot be found!\n"; } # Some predefined settings $build_command= "BUILD/compile-dist"; $PWD= cwd(); $opt_docdir= $PWD . "/mysqldoc"; $opt_archive_log= undef; $opt_build_command= undef; $opt_changelog= undef; $opt_delete= undef; $opt_directory= $PWD; $opt_dry_run= undef; $opt_export_only= undef; $opt_help= $opt_verbose= 0; $opt_log= undef; $opt_mail= "build\@mysql.com"; $opt_pull= undef; $opt_revision= undef; $opt_suffix= ""; $opt_test= undef; $opt_skip_check= undef; $opt_skip_manual= undef; $opt_win_dist= undef; $opt_quiet= undef; $version= "unknown"; $major=$minor=$release=0; GetOptions( "archive-log|a", "build-command|b=s", "changelog|c:s", "directory|d=s", "delete", "docdir=s", "dry-run", "export-only|e", "help|h", "log|l:s", "mail|m=s", "pull|p", "revision|r=s", "skip-check|s", "skip-manual", "suffix=s", "test|t", "verbose|v", "win-dist|w", "quiet|q", ) || print_help(""); # # Override predefined build command # if (defined $opt_build_command) { $build_command= $opt_build_command; } print_help("") if ($opt_help); defined($REPO=$ARGV[0]) || print_help("Please enter the BK repository to be used!"); # # Override predefined Log file name # if (defined $opt_log) { if ($opt_log ne "") { if ($opt_log =~ /^\/.*/) { $LOGFILE= $opt_log; } else { $LOGFILE= $PWD . "/" . $opt_log; } } } $LOGFILE= $PWD . "/Bootstrap-" . $REPO . ".log" unless ($LOGFILE); &logger("Starting build"); &abort("The directory \"$REPO\" could not be found!") if (!-d $REPO); &logger("Using $REPO as the BK parent repository"); system ("bk help > /dev/null") == 0 or &abort("Cannot execute BitKeeper binary!"); system ("bk root $REPO > /dev/null 2>&1") == 0 or &abort("$REPO does not seem to be a valid BK repository!"); if (($opt_directory ne $PWD) && (!-d $opt_directory && !$opt_dry_run)) { &abort("Could not find target directory \"$opt_directory\"!"); } &logger("Logging to $LOGFILE") if (defined $opt_log); # # Pull recent changes first # if ($opt_pull) { &bk_pull("$REPO"); &bk_pull("$opt_docdir") unless ($opt_skip_manual); } # # Use a temporary name until we know the version number # $target_dir= $opt_directory . "/mysql-" . $$ . "-" . time() . ".tmp"; &logger("Using temporary directory $target_dir"); &abort("Target directory $target_dir already exists!") if (-d $target_dir && !$opt_dry_run); # # Export the BK tree # $command= "bk export "; $command.= "-r " . $opt_revision . " " if $opt_revision; $command.= "-v " if ($opt_verbose || defined $opt_log); $command.= $REPO . " " . $target_dir; &logger("Exporting $REPO"); &run_command($command, "Could not create $target_dir!"); # # Make sure we can write all files # $command= "find $target_dir -type f -print0 | xargs --null chmod u+w"; &run_command($command, "Failed to fix file permissions!"); # # Try to obtain version number from newly extracted configure.in # $CONF="$target_dir/configure.in"; &abort("Could not find \"$CONF\" to determine version!") if (!-f $CONF && !$opt_dry_run); # # The following can only be done, if the tree has actually been # exported - it cannot be performed in a dry run. # if (!$opt_dry_run) { open (CONF, $CONF) or &abort("Unable to open \"$CONF\": $!"); @conf= <CONF>; close CONF; foreach (@conf) { m/^AM_INIT_AUTOMAKE\(mysql, ([1-9]\.[0-9]{1,2}\.[0-9]{1,2}.*)\)/; $version= $1; ($major, $minor, $release) = split(/\./,$version); } &logger("Found version string: $version"); # # Add suffix to version string and write out the modified file # if ($opt_suffix) { $opt_suffix= "-" . &ymd() if ($opt_suffix eq "YMD"); &logger("Replacing $version with $version$opt_suffix"); foreach (@conf) { s/^AM_INIT_AUTOMAKE.*/AM_INIT_AUTOMAKE\(mysql, $version$opt_suffix\)/; } open(CONF,">$CONF") or &abort("Unable to open \"$CONF\": $!"); print CONF @conf; close(CONF); } } # # Rename directory according to the version number found in configure.in # of the extracted tree (plus suffix, if requested) # $temp_name= $target_dir; $target_dir= $opt_directory . "/mysql-" . $version . $opt_suffix . "-build"; if (-d $target_dir) { &logger("Target directory $target_dir already exists!"); if ($opt_delete) { &logger("Deleting $target_dir..."); $command= "rm "; $command.= "-v " if ($opt_verbose || defined $opt_log); $command.= "$target_dir"; &run_command($command, "Could not delete $target_dir!"); } else { &logger("Renaming $target_dir to $target_dir.old." . $$); $command= "mv "; $command.= "-v " if ($opt_verbose || defined $opt_log); $command.= "$target_dir $target_dir.old." . $$; &run_command($command, "Could not rename $target_dir!"); } } &logger("Renaming temporary directory to $target_dir"); $command= "mv "; $command.= "-v " if ($opt_verbose || defined $opt_log); $command.= "$temp_name $target_dir"; &run_command($command, "Could not rename $temp_name!"); # # Add a ChangeLog (make dist will pick it up automatically) # if (defined $opt_changelog) { # # Use some magic to obtain the correct ChangeSet number that identifies # the last tagged ChangeSet (this relies heavily on our current tagging # practice!) # my $revision= ""; if ($opt_changelog eq "last") { if (!$opt_revision) { $revision= `bk changes -t -d':REV:::TAG:' -n $REPO | grep mysql-$major.$minor | head -1 | cut -f1 -d ":"`; } else { $revision= `bk changes -r..$opt_revision -t -d':REV:' -n $REPO | head -2 | tail -1`; } chomp($revision); $opt_changelog= $revision; } $msg= "Adding $target_dir/ChangeLog"; $msg.= " (down to revision $opt_changelog)" if $opt_changelog ne ""; &logger($msg); $command= "bk changes -v"; $command.= " -r" if ($opt_changelog ne "" || $opt_revision); $command.= $opt_changelog if $opt_changelog ne ""; $command.= ".." if ($opt_changelog ne "" && !$opt_revision); $command.= ".." . $opt_revision if $opt_revision; $command.= " " . $REPO . " > $target_dir/ChangeLog"; &logger($command); # We cannot use run_command here because of output redirection unless ($opt_dry_run) { system($command) == 0 or &abort("Could not create $target_dir/ChangeLog!"); } } # # Add the latest manual from the mysqldoc tree # unless ($opt_skip_manual) { &logger("Updating manual files"); foreach $file qw/internals manual reservedwords/ { system ("bk cat $opt_docdir/Docs/$file.texi > $target_dir/Docs/$file.texi") == 0 or &abort("Could not update $file.texi in $target_dir/Docs/!"); } &run_command("rm -f $target_dir/Docs/Images/Makefile*", "Could not remove Makefiles in $target_dir/Docs/Images/!"); &run_command("cp $opt_docdir/Docs/Images/*.* $target_dir/Docs/Images", "Could not copy image files in $target_dir/Docs/Images/!"); } # # Abort here, if we just wanted to export the tree # if ($opt_export_only) { &logger("SUCCESS: Export finished successfully."); exit 0; } # # Enter the target directory first # &logger("Entering $target_dir"); if (!$opt_dry_run) { chdir($target_dir) or &abort("Cannot chdir to $target_dir: $!"); } # # Now build the source distribution # &logger("Compiling..."); $command= $build_command; &run_command($command, "Compilation failed!"); # # Testing the built binary by running "make test" (optional) # if ($opt_test) { &logger ("Running test suite"); $command= "make test"; &run_command($command, "\"make test\" failed!"); } # # Pack it all up # &logger("Creating source distribution"); $command= "make dist"; &run_command($command, "make dist failed!"); # # Package the Windows source # if ($opt_win_dist) { &logger ("Creating Windows source package"); $command= "./scripts/make_win_src_distribution --tar --zip"; &run_command($command, "make_win_src_distribution failed!"); } # # Run "make distcheck" to verify the source archive # if (!$opt_skip_check) { &logger ("Checking source distribution"); $command= "make distcheck"; &run_command($command, "make distcheck failed!"); } # # All done when we came down here # &logger("SUCCESS: Build finished successfully.") if (!$opt_dry_run); # # Move the log file into the Log dir of the target dir # if ($opt_archive_log) { my $logdir= $target_dir . "/Logs"; &logger("Moving $LOGFILE to $logdir"); mkdir "$logdir" if (! -d $logdir); $command= "mv "; $command.= "-v " if ($opt_verbose || defined $opt_log); $command.= "$LOGFILE $logdir"; &run_command($command, "Could not move $LOGFILE to $logdir!"); } exit 0; # # Run a BK pull on the given BK tree # sub bk_pull { my $bk_tree= $_[0]; &logger("Updating BK tree $bk_tree to latest ChangeSet first"); chdir ($bk_tree) or &abort("Could not chdir to $bk_tree!"); &run_command("bk pull", "Could not update $bk_tree!"); chdir ($PWD) or &abort("Could not chdir to $PWD!"); } # # Print the help text message (with an optional message on top) # sub print_help { my $message= $_[0]; if ($message ne "") { print "\n"; print "ERROR: $message\n"; } print <<EOF; Usage: Bootstrap [options] <bk repository> Creates a MySQL source distribution to be used for the release builds. It checks out (exports) a clear-text version of the given local BitKeeper repository, creates and adds a Changelog file (if requested), adds the latest manual files from the mysqldoc BK tree and builds a source distribution (*.tar.gz) file. Optionally, the test suite and the distribution check can be run before the source archive is being created. Options: -a, --archive-log Move the log file into the Logs directory of the exported tree after a successful build -b, --build-command=<cmd> Use <cmd> to compile the sources before packing the distribution. (default is "$build_command") -c, --changelog[=<rev>] Add a ChangeLog [down to revision <rev>] This will automatically be included in the source distribution. To get a ChangeLog down to the last tagged Changeset, simply use "last" as the revision number. --delete Delete an already existing distribution directory in the target directory instead of renaming it. -d, --directory=<dir> Specify the target directory (default is "$opt_directory") --docdir=<dir> Use the MySQL documentation BK tree located in <dir> (default is "$opt_docdir") --dry-run Dry run without executing -e, --export-only Just export (and add the ChangeLog, if requested), do not build or test the source distribution -h, --help Print this help message -l, --log[=<filename>] Write a log file [to <filename>] (default is "./Bootstrap-<bk repository>.log") -m, --mail=<address> Mail a failure report to the given address (and include a log file snippet, if logging is enabled) Note that the \@-Sign needs to be quoted! Example: --mail=user\\\@domain.com Default: build\@mysql.com -q, --quiet Be quiet -p, --pull Update the source BK trees before building -r, --revision=<rev> Export the tree as of revision <rev> (default is up to the latest revision) -s, --skip-check Skip checking the distribution with "make distcheck" --skip-manual Skip updating the manual from the mysqldoc tree --suffix=<suffix> Append <suffix> to the version number in configure.in. Using the special suffix "YMD" will add the current date as the suffix (e.g. "-20020518"). -t, --test Run the test suite after build -v, --verbose Be verbose -w, --win-dist Also make Windows source distribution Example: Bootstrap -c last -v -l -- mysql-4.0 EOF exit 1; }