#/bin/sh # -*-Perl-*- (for Emacs) vim:set filetype=perl: (for vim) #======================================================================# # Run the right perl version: if [ -x /usr/local/bin/perl ]; then perl=/usr/local/bin/perl elif [ -x /usr/bin/perl ]; then perl=/usr/bin/perl else perl=`which perl| sed 's/.*aliased to *//'` fi exec $perl -x -S $0 "$@" # -x: start from the following line #======================================================================# #! /Good_Path/perl -w # line 17 # Name: pc_bisect # Description: # Performs a binary search between two SVN revisions # to find the offending change that broke an auto-test. # Works in one scecified auto-test directory. use strict; BEGIN { # Make sure ${PENCIL_HOME}/lib/perl is in the Perl path if (-d "$ENV{PENCIL_HOME}/lib/perl") { unshift @INC, "$ENV{PENCIL_HOME}/lib/perl"; } else { if ($0 =~ m!(.*[/\\])!) { unshift @INC, "$1../lib/perl"; } } } use Cwd; use POSIX qw(floor); use Getopt::Long; # ---------------------------------------------------------------------- # my $base_URL = 'https://github.com/pencil-code/pencil-code/'; # repository URL (my $cmdname = $0) =~ s{.*/}{}; my $usage = "Usage: $cmdname [options] Performs a binary search between the two SVN revisions and to find the offending change that broke an auto-test. Works in the scecified auto-test directory . Options: -h, --help \tShow usage overview -D, --pencil-home= \tSet PENCIL_HOME directory to --config-files= \tUse the given (a comma-separated list) as \tconfiguration files, rather than trying to find a \tconfig file based on a host ID. --host-id= \tUse the given as host ID. --parallel \tAllow parallel compilation (passes -j to make) -j, --jobs= \tPass through -j option to make --no-lock \tIgnore and don't write lock file --local-lock \tLet multiple auto-tests run in different working copies (default: off) --debug \tPrint lots of debugging output --fast \tShortcut for the option FFLAGS+=-O0 of pc_build --log-dir= \tDirectory to store the logfiles (default: .) Examples: pc_bisect --no-lock . 82000 82010 # bisect in current directory, without locking for pc_auto-test pc_bisect --log-dir=/my/test/ samples/corona 82000 82010 # bisect in samples/corona with logfiles, make clean on error "; ## Process command line options my (%opts); my $help = 0; eval { Getopt::Long::config("bundling"); # make single-letter opts. case-sensitive }; GetOptions(\%opts, qw( -h --help --debug -D=s --pencil-home=s --config-files=s --host-id=s --parallel -j=n --jobs=n --no-lock --local-lock --fast --log-dir=s ) ) or $help=1, die "Aborting.\n"; if ($opts{'h'} || $opts{'help'}) { $help = 1; die "$usage\n"; } my $debug = ( $opts{'debug'} || 0 ); my $pencil_home = ($opts{'D'} || $opts{'pencil-home'} || $ENV{PENCIL_HOME}); my $config_files = ( $opts{'config-files'} || '' ); my $host_id = ( $opts{'host-id'} || '' ); my $parallel = ( $opts{'parallel'} || 0 ); my $makejobs = ($opts{'j'} || $opts{'jobs'} || '' ); my $nolock = ( $opts{'no-lock'} || 0 ); my $local_lock = ( $opts{'local-lock'} || 0 ); my $fast = ( $opts{'fast'} || '' ); my $log_dir = ( $opts{'log-dir'} || '' ); my $num_args = @ARGV; if ($num_args != 3) { die "Wrong number of arguments!\n$usage\n"; } if (!$pencil_home) { die "ERROR: PENCIL_HOME unknown, please use -D or environment variable!\n"; } my @pc_auto_test = qw/pc_auto-test/; if ($debug) { push @pc_auto_test, "--debug"; } if ($pencil_home) { push @pc_auto_test, "--pencil-home='$pencil_home'"; } if ($config_files) { push @pc_auto_test, "--config-files=$config_files"; } if ($host_id) { push @pc_auto_test, "--host-id=$host_id"; } if ($makejobs) { push @pc_auto_test, "--jobs=$makejobs"; } if ($parallel) { push @pc_auto_test, "--parallel"; } if ($local_lock) { push @pc_auto_test, "--local-lock"; } else { push @pc_auto_test, "--no-lock"; } if ($fast) { push @pc_auto_test, "--fast"; } if ($log_dir) { push @pc_auto_test, "--log-dir='$log_dir'"; } my $test = shift @ARGV; my $good = shift @ARGV; my $bad = shift @ARGV; # consistency checks my $test_dir = "$pencil_home/samples/$test"; if (!-e "$test_dir/reference.out") { die "Not an auto-test directory: \"$test_dir\"\n"; } if ($good < 1) { die "Invalid start revision number: $good\n"; } if ($bad < 2) { die "Invalid end revision number: $bad\n"; } if ($good > $bad) { ($good, $bad) = ($bad, $good); } # Autoflush stdout: $| = 1; # Remember current directory my $cwd = `pwd`; chomp $cwd; # Make sure we are in the top directory and have the right PATH chdir $pencil_home; $ENV{PATH} .= ":$pencil_home/bin"; # store current revision my $current_revision; if (!-d "$pencil_home/.svn") { die "Bisecting works only on SVN checkouts!\n"; } # SVN revision # The following line fails on Norlx51 (ubuntu 12.04) with old SVN client: #$current_revision = `svn info "$pencil_home" --show-item revision`; my $result = `svn info "$pencil_home" --xml`; if ($result =~ /revision\s*=\s*"(\d+)"/is) { $current_revision = $1; } if (!$current_revision) { die "Problem obtaining current SVN revision!\n"; } chomp $current_revision; # bisect my $test_command = "@pc_auto_test --keep-fail-info-on-success --overwrite-fail-info --auto-clean --no-bisect 'samples/$test'"; if ($debug) { print "Test command: |$test_command|\n"; } do { my $num = $bad - $good + 1; my $skip = floor (($num - 1) / 2); my $check = $good + $skip; print "Bisecting interval [ $good | $bad ] at: $check "; if ($debug) { print "\nwith $test_command\n "; } if (test_revision ($check, $test_command)) { # test successful print "=> good!\n"; $good = $check; } else { # test failed print "=> bad!\n"; $bad = $check; } } until ($good >= $bad - 1); set_revision ($current_revision); chdir $cwd; exit 0; # ---------------------------------------------------------------------- sub set_revision { my $revision = shift || 0; if ($revision < 1) { die "Invalid SVN revision number!\n"; } # reset $? = 0; $! = 0; my $result = `svn up --force --accept theirs-conflict -r $revision 2>&1`; if ($?) { die "Could not get SVN revision $revision:\n$!\n$result\n"; } } sub test_revision { my $revision = shift; my $command = shift; # get desired revision set_revision ($revision); # reset $? = 0; $! = 0; # execute auto-test my $result = `nice $command 2>&1`; if ($? && $debug) { print "$command\nRESULT: ".$!."\n\n"; } # $? = 0 means success return ($? == 0); }