This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Upgrade Socket to 2.004
[perl5.git] / Porting / bisect-runner.pl
index 92c6852..e0dd65d 100755 (executable)
@@ -53,7 +53,6 @@ my %defines =
     (
      usedevel => '',
      optimize => '-g',
-     cc => (`ccache --version`, $?) ? 'cc' : 'ccache cc',
      ld => 'cc',
      ($linux64 ? (libpth => \@paths) : ()),
     );
@@ -61,9 +60,13 @@ my %defines =
 unless(GetOptions(\%options,
                   'target=s', 'make=s', 'jobs|j=i', 'expect-pass=i',
                   'expect-fail' => sub { $options{'expect-pass'} = 0; },
-                  'clean!', 'one-liner|e=s', 'match=s', 'force-manifest',
-                  'force-regen', 'test-build', 'A=s@', 'l', 'w',
-                  'check-args', 'check-shebang!', 'usage|help|?', 'validate',
+                  'clean!', 'one-liner|e=s', 'c', 'l', 'w', 'match=s',
+                  'no-match=s' => sub {
+                      $options{match} = $_[1];
+                      $options{'expect-pass'} = 0;
+                  },
+                  'force-manifest', 'force-regen', 'test-build', 'validate',
+                  'check-args', 'check-shebang!', 'usage|help|?', 'A=s@',
                   'D=s@' => sub {
                       my (undef, $val) = @_;
                       if ($val =~ /\A([^=]+)=(.*)/s) {
@@ -84,13 +87,14 @@ my ($target, $j, $match) = @options{qw(target jobs match)};
 @ARGV = ('sh', '-c', 'cd t && ./perl TEST base/*.t')
     if $options{validate} && !@ARGV;
 
-pod2usage(exitval => 255, verbose => 1) if $options{usage};
+pod2usage(exitval => 0, verbose => 2) if $options{usage};
 pod2usage(exitval => 255, verbose => 1)
     unless @ARGV || $match || $options{'test-build'} || defined $options{'one-liner'};
 pod2usage(exitval => 255, verbose => 1)
     if !$options{'one-liner'} && ($options{l} || $options{w});
 
-check_shebang($ARGV[0]) if $options{'check-shebang'} && @ARGV;
+check_shebang($ARGV[0])
+    if $options{'check-shebang'} && @ARGV && !$options{match};
 
 exit 0 if $options{'check-args'};
 
@@ -110,6 +114,8 @@ bisect.pl - use git bisect to pinpoint changes
     .../Porting/bisect.pl --expect-fail --match '\buseithreads\b'
     # When did this test program stop working?
     .../Porting/bisect.pl -- ./perl -Ilib ../test_prog.pl
+    # When did this test start failing?
+    .../Porting/bisect.pl -- ./perl -Ilib t/TEST op/sort.t
     # When did this first become valid syntax?
     .../Porting/bisect.pl --target=miniperl --end=v5.10.0 \
          --expect-fail -e 'my $a := 2;'
@@ -134,11 +140,11 @@ Which commit caused this example code to start working?
 
 =item *
 
-Which commit added the first to match this regex?
+Which commit added the first file to match this regex?
 
 =item *
 
-Which commit removed the last to match this regex?
+Which commit removed the last file to match this regex?
 
 =back
 
@@ -148,10 +154,12 @@ end revisions.
 By default F<bisect.pl> will process all options, then use the rest of the
 command line as arguments to list C<system> to run a test case. By default,
 the test case should pass (exit with 0) on earlier perls, and fail (exit
-non-zero) on I<blead>. F<bisect.pl> will use F<bisect-runner.pl> to find the
-earliest stable perl version on which the test case passes, check that it
-fails on blead, and then use F<bisect-runner.pl> with C<git bisect run> to
-find the commit which caused the failure.
+non-zero) on I<blead> (note that running most of perl's test files directly
+won't do this, you'll need to run them through a harness to get the proper
+error code). F<bisect.pl> will use F<bisect-runner.pl> to find the earliest
+stable perl version on which the test case passes, check that it fails on
+blead, and then use F<bisect-runner.pl> with C<git bisect run> to find the
+commit which caused the failure.
 
 Because the test case is the complete argument to C<system>, it is easy to
 run something other than the F<perl> built, if necessary. If you need to run
@@ -279,6 +287,12 @@ which interferes with detecting errors in the example code itself.
 
 =item *
 
+-c
+
+Add C<-c> to the command line, to cause perl to exit after syntax checking.
+
+=item *
+
 -l
 
 Add C<-l> to the command line with C<-e>
@@ -295,8 +309,8 @@ a full test case, instead of using C<bisect.pl>'s C<-e> shortcut.
 
 Add C<-w> to the command line with C<-e>
 
-It's not valid to pass C<-l> or C<-w> to C<bisect.pl> unless you are also
-using C<-e>
+It's not valid to pass C<-c>,  C<-l> or C<-w> to C<bisect.pl> unless you are
+also using C<-e>
 
 =item *
 
@@ -349,14 +363,43 @@ I<number of CPUs>. Otherwise defaults to 2.
 
 --match pattern
 
-Instead of running a test program to determine I<pass> or I<fail>, pass
-if the given regex matches, and hence search for the commit that removes
-the last matching file.
+=item *
+
+--no-match pattern
+
+Instead of running a test program to determine I<pass> or I<fail>,
+C<--match> will pass if the given regex matches, and hence search for the
+commit that removes the last matching file. C<--no-match> inverts the test,
+to search for the first commit that adds files that match.
+
+The remaining command line arguments are treated as glob patterns for files
+to match against. If none are specified, then they default as follows:
+
+=over 4
+
+=item *
 
 If no I<target> is specified, the match is against all files in the
-repository (which is fast). If a I<target> is specified, that target is
-built, and the match is against only the built files. C<--expect-fail> can
-be used with C<--match> to search for a commit that adds files that match.
+repository (which is fast).
+
+=item *
+
+If a I<target> is specified, that target is built, and the match is against
+only the built files.
+
+=back
+
+Treating the command line arguments as glob patterns should not cause
+problems, as the perl distribution has never shipped or built files with
+names that contain characters which are globbing metacharacters.
+
+Anything which is not a readable file is ignored, instead of generating an
+error. (If you want an error, run C<grep> or C<ack> as a test case). This
+permits one to easily search in a file that changed its name. For example:
+
+    .../Porting/bisect.pl --match 'Pod.*Functions' 'pod/buildtoc*'
+
+C<--no-match ...> is implemented as C<--expect-fail --match ...>
 
 =item *
 
@@ -478,6 +521,15 @@ Display the usage information and exit.
 
 die "$0: Can't build $target" if defined $target && !grep {@targets} $target;
 
+unless (exists $defines{cc}) {
+    # If it fails, the heuristic of 63f9ec3008baf7d6 is noisy, and hence
+    # confusing.
+    # FIXME - really it should be replaced with a proper test of
+    # "can we build something?" and a helpful diagnostic if we can't.
+    # For now, simply move it here.
+    $defines{cc} = (`ccache -V`, $?) ? 'cc' : 'ccache cc';
+}
+
 $j = "-j$j" if $j =~ /\A\d+\z/;
 
 if (exists $options{make}) {
@@ -774,12 +826,21 @@ sub report_and_exit {
 }
 
 sub match_and_exit {
-    my $target = shift;
+    my ($target, @globs) = @_;
     my $matches = 0;
     my $re = qr/$match/;
     my @files;
 
-    {
+    if (@globs) {
+        require File::Glob;
+        foreach (sort map { File::Glob::bsd_glob($_)} @globs) {
+            if (!-f $_ || !-r _) {
+                warn "Skipping matching '$_' as it is not a readable file\n";
+            } else {
+                push @files, $_;
+            }
+        }
+    } else {
         local $/ = "\0";
         @files = defined $target ? `git ls-files -o -z`: `git ls-files -z`;
         chomp @files;
@@ -809,7 +870,7 @@ sub match_and_exit {
 system 'git clean -dxf </dev/null' and die;
 
 if (!defined $target) {
-    match_and_exit() if $match;
+    match_and_exit(undef, @ARGV) if $match;
     $target = 'test_prep';
 }
 
@@ -914,7 +975,7 @@ if (-f 'config.sh') {
 }
 
 if ($target =~ /config\.s?h/) {
-    match_and_exit($target) if $match && -f $target;
+    match_and_exit($target, @ARGV) if $match && -f $target;
     report_and_exit(!-f $target, 'could build', 'could not build', $target)
         if $options{'test-build'};
 
@@ -997,13 +1058,14 @@ if ($options{'test-build'}) {
     skip("could not build $real_target");
 }
 
-match_and_exit($real_target) if $match;
+match_and_exit($real_target, @ARGV) if $match;
 
 if (defined $options{'one-liner'}) {
     my $exe = $target =~ /^(?:perl$|test)/ ? 'perl' : 'miniperl';
     unshift @ARGV, '-e', $options{'one-liner'};
-    unshift @ARGV, '-l' if $options{l};
-    unshift @ARGV, '-w' if $options{w};
+    foreach (qw(c l w)) {
+        unshift @ARGV, "-$_" if $options{$_};
+    }
     unshift @ARGV, "./$exe", '-Ilib';
 }