summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xscripts/generic/parse_build_log.pl309
1 files changed, 120 insertions, 189 deletions
diff --git a/scripts/generic/parse_build_log.pl b/scripts/generic/parse_build_log.pl
index 5002d07a..e351d780 100755
--- a/scripts/generic/parse_build_log.pl
+++ b/scripts/generic/parse_build_log.pl
@@ -80,35 +80,6 @@ Print this message.
If given, as well as printing out the interesting lines from the log, the script
will attempt to print out a human-readable summary of the error(s).
-This option has no effect when --yaml is given.
-
-=item B<--yaml>
-
-Use YAML instead of plain text output.
-
-The output will consist of a single YAML document with zero or more of the
-following key/value pairs:
-
-=over
-
-=item summary
-
-The human-readable summary of the failure reason (if known).
-Usually one or two sentences.
-
-=item detail
-
-The extracted text from the build log relating to the failure.
-
-=item should_retry
-
-A hint that it might make sense to retry the build/test.
-
-If set, this indicates that the failure extracted from the log may be unrelated
-to the code under test; for example, a temporary network outage.
-
-=back
-
=item B<--limit> LINES
Limit the amount of extracted lines to the given value.
@@ -121,6 +92,12 @@ If omitted, an undefined but reasonable default is used.
Enable some debug messages to STDERR.
Use this to troubleshoot when some log is not parsed in the expected manner.
+=item B<--trim-prefix> REGEX
+
+Remove any matching content from the specified regular expression before
+further analyzing the content. Use this when our log output is filtered
+through an intermediate program that adds a prefix such as a time stamp.
+
=back
=head1 CAVEATS
@@ -135,35 +112,31 @@ use File::Basename;
use File::Slurp qw();
use Getopt::Long qw(GetOptionsFromArray);
use IO::Uncompress::AnyInflate qw(anyinflate $AnyInflateError);
-use Lingua::EN::Inflect qw(inflect PL WORDLIST);
-use Lingua::EN::Numbers qw(num2en);
use List::MoreUtils qw(any apply);
use Pod::Usage;
-use Const::Fast;
use Text::Wrap;
-use YAML qw();
# Contact details of some CI admins who can deal with problems.
# Put a public email address here once we have one!
-const my $CI_CONTACT
- => q{some CI administrator};
+my $CI_CONTACT
+ = q{some CI administrator};
# The max amount of lines we're willing to buffer before giving up,
# when attempting to identify a related chunk of output (e.g. a single
# autotest log).
-const my $MAX_CHUNK_LINES => 5000;
+my $MAX_CHUNK_LINES = 5000;
# The max amount of characters permitted in a line;
# any more than this and we will truncate the line.
# Longer lines could trigger bad performance in some regexes, and it is
# not user-friendly to present such long lines to the reader.
-const my $MAX_LINE_LENGTH => 3500;
+my $MAX_LINE_LENGTH = 3500;
# The max amount of lines to search around any interesting line for
# related text (for example, if a compiler failure message is seen for
# foo.cpp, look up to $RECENT_MAX lines in the past for other messages
# relating to .cpp).
-const my $RECENT_MAX => 60;
+my $RECENT_MAX = 60;
# List of all common error strings returned by strerror();
# This may be generated by:
@@ -177,8 +150,8 @@ const my $RECENT_MAX => 60;
# Note that these are matched case-insensitive, as certain tools seem to use
# messages from this list with slight differences in case.
#
-const my @POSIX_ERROR_STRINGS
- => split /\n/, <<'END_ERROR_STRINGS';
+my @POSIX_ERROR_STRINGS
+ = split /\n/, <<'END_ERROR_STRINGS';
.lib section in a.out corrupted
Accessing a corrupted shared library
Address already in use
@@ -258,6 +231,7 @@ Link has been severed
Link number out of range
Machine is not on the network
Malformed Mach-o file
+Memory page has hardware error
Message too long
Multihop attempted
Name not unique on network
@@ -291,6 +265,7 @@ Object is remote
Operation already in progress
Operation canceled
Operation not permitted
+Operation not possible due to RF-kill
Operation not supported
Operation not supported by device
Operation not supported on socket
@@ -321,6 +296,7 @@ Resource busy
Resource deadlock avoided
Resource temporarily unavailable
Result too large
+Stale file handle
STREAM ioctl timeout
Shared library version mismatch
Socket is already connected
@@ -355,13 +331,13 @@ END_ERROR_STRINGS
# List of any test script contexts where an error indicates that the build may be
# able to succeed if we retry.
-const my %TESTSCRIPT_RETRY_CONTEXTS => map { $_ => 1 } (
+my %TESTSCRIPT_RETRY_CONTEXTS = map { $_ => 1 } (
'determining test script configuration', # usually error in qtqa/testconfig
'setting up git repositories', # usually network outage or similar
);
# All important regular expressions used to extract errors
-const my %RE => (
+my %RE = (
# never matches anything
never_match => qr{a\A}ms,
@@ -482,6 +458,15 @@ const my %RE => (
' \s \Qexited with code \E\d
}xms,
+ # configure output.
+ #
+ configure_begin => qr{
+ Running configuration tests(?: \(phase [12]\))\.\.\.
+ }xms,
+ configure_end => qr{
+ \QDone running configuration tests.\E
+ }xms,
+
# make failed.
#
# Examples:
@@ -514,7 +499,7 @@ const my %RE => (
|
[gn]make # GNU make, nmake
|
- mingw32-make
+ [Mm]ingw32-make
)
(?: \.exe )? # maybe has .exe on the end on Windows
@@ -556,16 +541,19 @@ const my %RE => (
|
- # This comes when make itself segfaults
- \QSegmentation fault: 11\E
+ # This comes when make itself or a tool segfaults
+ (?<errortext>
+ \QSegmentation fault: 11\E
+ .*?
+ )
)
|
(?<errortext>
- \QNo rule to make target `\E
- [^']+
- \Q', needed by `\E
+ \QNo rule to make target \E.
+ [^']+?
+ \Q', needed by \E.
(?<target>
[^']+
)
@@ -633,6 +621,7 @@ const my %RE => (
# foobar.cpp:123: error: quiznux
(?<file>
+ (?:\w:)?
[^:]+
)
@@ -642,11 +631,11 @@ const my %RE => (
\d+
)
- (?: # It is possible to have more than one line number in the error, e.g:
+ (?: # gcc sometimes includes column number after line number, e.g:
:\d+ # mapsgl/frustum_p.h:60:27: (...)
- )* # We do not capture them at the moment.
+ )* # We do not capture this at the moment.
- : \s
+ : \s+
(?<error>
(?:
@@ -672,7 +661,7 @@ const my %RE => (
/bin/sh:
\s+
- line \s \d+:
+ line \s+ \d+:
\s+
\d+ # pid
@@ -691,7 +680,7 @@ const my %RE => (
.+? # rest of command and arguments ...
(?<file> # ...and assume file is the last argument (qmake-specific assumption)
- [^\s]+
+ \S+
)
|
@@ -804,8 +793,8 @@ const my %RE => (
\s+
)
from
- \s
- [^\s]+:\d+ # some/file.cpp:123
+ \s+
+ \S+:\d+ # some/file.cpp:123
[,:] # , or : depending on whether it's the last line
\s*
\z
@@ -864,13 +853,13 @@ const my %RE => (
(?:
(?<linker>
- ld # basename only
+ (?:[a-z0-9.-]+-)?ld # basename only
|
- /[^\s]{1,80}/ld # full path
+ /\S{1,80}/(?:[a-z0-9.-]+-)?ld # full path
)
:
- \s
+ \s+
(?<error>
(?:
@@ -935,14 +924,14 @@ const my %RE => (
.{1,300}? # file part (may be .o, .cpp, or both, with also .text reference)
:
- \s
+ \s+
(?:
- \Qundefined reference to `\E
+ \Qundefined reference to \E
|
- \Qmore undefined references to `\E
+ \Qmore undefined references to \E
|
- \Qmultiple definition of `\E
+ \Qmultiple definition of \E
)
.+
@@ -1029,9 +1018,10 @@ const my %RE => (
\A
\s*
+ (?:\w:)?
[^:]+\.o:
- \s
- \QIn function `\E
+ \s+
+ \QIn function \E
.+
\z
@@ -1077,7 +1067,7 @@ const my %RE => (
.+
-o
- \s
+ \s+
(?<lib>
lib [^\.]+ \. # name always starts with libSomething.
@@ -1088,7 +1078,7 @@ const my %RE => (
\d # mac: libQtCore.5.0.0.dylib
)
- [^\s]+
+ \S+
)
|
@@ -1111,10 +1101,10 @@ const my %RE => (
# silent mode, linking path/to/libWhatever.so
linking
- \s
+ \s+
(?<lib>
- [^\s]+
+ \S+
(?:
\.so
@@ -1122,7 +1112,7 @@ const my %RE => (
\.dylib # must contain at least one .so or .dylib to be a library
)
- [^\s]+
+ \S+
)
\z
@@ -1132,9 +1122,9 @@ const my %RE => (
# silent mode, linking path/to/Something.framework/Something
linking
- \s
+ \s+
- [^\s]+?
+ \S+?
/
(?<lib>
\w+
@@ -1143,7 +1133,7 @@ const my %RE => (
)
/
- [^\s]+
+ \S+
\z
)
@@ -1174,6 +1164,7 @@ const my %RE => (
# path/to/file.pro:123: Parse Error
(?<file>
+ (?:\w:)?
[^:]+?
\.pr[iof]
)
@@ -1191,6 +1182,7 @@ const my %RE => (
\QCannot find file: \E
)
(?<file>
+ (?:\w:)?
[^:]+?
\.pr[iof]
)
@@ -1265,6 +1257,23 @@ const my %RE => (
.*
(?<tool_objcopy>)
+ |
+ # QtPlatformHeaders
+
+ ^QtPlatformHeaders:
+ \s+
+ ERROR:
+ \s+
+ (?<file>
+ (?:\w:)?
+ [^:]+?
+ )
+ \s+
+ includes private header
+ \s+
+ .*
+ (?<tool_QtPlatformHeaders>)
+
# add more as discovered
)
@@ -1380,10 +1389,10 @@ const my %RE => (
.*? # all the arguments to testrunner.pl
[ ]--[ ] # end of the arguments to testrunner.pl
- [^\s]+? # path up to the last directory separator
+ \S+? # path up to the last directory separator
[/\\] # the last directory separator
(?<name>
- [^\s]+ # basename of the test
+ \S+ # basename of the test
)
)
@@ -1396,7 +1405,7 @@ const my %RE => (
[gn]?make
\[ \d+ \]
:
- \s
+ \s+
Entering[ ]directory[ ]
`
@@ -1454,36 +1463,6 @@ const my %RE => (
\QQtQA::App::TestRunner: the test seems to be flaky\E
}xms,
- # The line where a QtQA::TestScript YAML message opens.
- #
- # Captures:
- #
- # type - the type of message (currently 'error' or 'failure')
- #
- yaml_begin => qr{
- \A
- \Q--- !qtqa.qt-project.org/\E
- (?<type>
- .{1,50}
- )
- \z
- }xms,
-
- # The line where a QtQA::TestScript YAML message ends.
- #
- # Captures:
- #
- # type - the type of message (currently 'error' or 'failure')
- #
- yaml_end => qr{
- \A
- \Q... \E\#\Q end qtqa.qt-project.org/\E
- (?<type>
- .{1,50}
- )
- \z
- }xms,
-
# Generic strerror-based pattern.
#
# This pattern will find any line containing an error string commonly returned by strerror()
@@ -1610,7 +1589,7 @@ sub run
$self->set_options_from_args( @args );
- my @log_lines = $self->read_file( );
+ my @log_lines = $self->read_file( $self->{ trim_prefix } );
# We pass through the log twice.
# The first pass determines what caused the build to fail (if anything) ...
@@ -1644,13 +1623,10 @@ sub set_options_from_args
'help' => sub { pod2usage(0) },
'debug' => \$self->{ debug },
'summarize' => \$self->{ summarize },
- 'yaml' => \$self->{ yaml },
'limit=i' => \$self->{ limit_lines },
+ 'trim-prefix=s' => \$self->{ trim_prefix },
) || pod2usage(1);
- # summary is always generated in YAML mode
- $self->{ summarize } ||= $self->{ yaml };
-
# Should be exactly one argument left - the filename.
if (@args > 1) {
print STDERR "Too many arguments: @args\n";
@@ -1671,11 +1647,15 @@ sub set_options_from_args
# - truncates line if too long
sub normalize_line
{
- my ($self, $line) = @_;
+ my ($self, $line, $trim_prefix) = @_;
# Note: don't use Text::Trim here, it's surprisingly slow.
$line =~ s/\s+\z//;
+ if (length $trim_prefix) {
+ $line =~ s/$trim_prefix//;
+ }
+
# Truncate lines exceeding $MAX_LINE_LENGTH to $MAX_LINE_LENGTH
my $length = length($line);
if ($length > $MAX_LINE_LENGTH) {
@@ -1735,7 +1715,7 @@ sub read_file_from_url
sub read_file
{
- my ($self) = @_;
+ my ($self, $trim_prefix) = @_;
my $file = $self->{ file };
@@ -1766,7 +1746,7 @@ sub read_file
@lines = split( qr{\n}, $uncompressed );
# normalize before returning
- @lines = map { $self->normalize_line($_) } @lines;
+ @lines = map { $self->normalize_line($_, $trim_prefix) } @lines;
return @lines;
}
@@ -1945,37 +1925,6 @@ sub testscript_error_should_retry
return;
}
-# Create a handler for an embedded YAML chunk.
-sub yaml_chunk_handler
-{
- my ($self, %chunk) = @_;
-
- $chunk{ begin_re } = $RE{ yaml_begin };
-
- $chunk{ begin_sub } = sub {
- my ($chunk_ref, $line, $out) = @_;
- my $text = "$line\n" . $chunk_ref->{ details };
- my $loaded = eval { YAML::Load( $text ) };
- if ($loaded) {
- # for backwards compatibility: message now named 'message', but used
- # to be named 'error', support both for a while.
- if (my $error = delete $loaded->{ error }) {
- $loaded->{ message } = $error;
- }
- push @{$out->{ yaml_fail }}, $loaded;
-
- # Retry if it makes sense; note that we only retry on errors, not failures
- if ($chunk{ type } eq 'error' && $self->testscript_error_should_retry( $loaded )) {
- $out->{ should_retry } = 1;
- }
- } else {
- warn "log seems to contain a corrupt YAML block:\n$text\nFailed to parse: $@";
- }
- };
-
- return $self->chunk_handler( 'yaml', %chunk );
-}
-
# Create a handler for an embedded qmake chunk.
# Actually, only looks for a "Project ERROR: " line.
# Ideally this would not be necessary, but unfortunately the exit code from
@@ -2005,6 +1954,26 @@ sub qmake_chunk_handler
return $self->chunk_handler( 'qmake', %chunk );
}
+# Create a handler for configure test output.
+# The sole purpose of this handler is to skip the configure output from the
+# log, as it pointlessly triggers the compiler and linker error handlers.
+# We don't try to identify actual configuration failures - the output is
+# rather heterogenous and subject to change, so it would unreasonable to try
+# to keep up. However, the log is rather short when configure actually fails,
+# so it's no problem to have to look inside it.
+sub configure_chunk_handler
+{
+ my ($self, %chunk) = @_;
+
+ $chunk{ begin_re } = $RE{ configure_begin };
+
+ $chunk{ begin_sub } = sub { return 1; };
+
+ $chunk{ read_sub } = sub { };
+
+ return $self->chunk_handler( 'configure', %chunk );
+}
+
# Add a $tool failure identified from $line into $out, a hashref
# being constructed during identify_failures.
sub add_tool_fail
@@ -2122,11 +2091,6 @@ sub identify_failures
);
}
- # opening a YAML error message?
- elsif ($save_failures && $line =~ $RE{ yaml_end }) {
- $chunk_handler = $self->yaml_chunk_handler( type => $+{ type } );
- }
-
# compiler failed?
#
elsif ($save_failures && $line =~ $RE{ compile_fail }) {
@@ -2192,6 +2156,12 @@ sub identify_failures
add_tool_fail( $out, $tool, $line );
}
+ # ignorable configure output?
+ #
+ elsif ($line =~ $RE{ configure_end }) {
+ $chunk_handler = $self->configure_chunk_handler();
+ }
+
# Badly understood glitchy behavior?
elsif ($save_failures && $line =~ $RE{ glitch }) {
$out->{ should_retry } = 1;
@@ -2239,23 +2209,6 @@ sub extract_autotest_fail
return;
}
-sub extract_yaml_fail
-{
- my ($self, %args) = @_;
-
- my $fail = $args{ fail };
- my $lines_ref = $args{ lines_ref };
-
- foreach my $error (@{ $fail->{ yaml_fail } || []} ) {
- my @lines = split( /\n/, $error->{ message } );
- push @{$lines_ref}, @lines;
- # each failure gets one trailing blank line to separate it from others
- push @{$lines_ref}, q{};
- }
-
- return;
-}
-
sub extract
{
my ($self, %args) = @_;
@@ -2298,12 +2251,6 @@ sub extract
$summary = $self->extract_summary( $fail );
}
- # YAML failures (explicit failure messages from the test script(s)) come first.
- $self->extract_yaml_fail(
- fail => $fail,
- lines_ref => \@detail,
- );
-
# Output any autotest failures next.
$self->extract_autotest_fail(
fail => $fail,
@@ -2591,11 +2538,8 @@ sub extract_summary
my $linked_too_early = $fail->{ linker_attempted_to_link_too_early };
if ($linked_too_early) {
my @libs = keys %{ $linked_too_early };
-
- Lingua::EN::Inflect::NUM( scalar(@libs) );
-
my $project = (@libs > 1) ? 'project(s)' : 'project';
- my $that_lib_was = inflect 'PL(that) PL(library) PL(was)';
+ my $that_lib_was = scalar(@libs) > 1 ? 'those libraries were' : 'that library was';
my $lib = WORDLIST( @libs, { conj => q{and/or} } );
$summary .= "\n\nIt seems that some $project tried to link against $lib "
@@ -2663,19 +2607,6 @@ sub output
{
my ($self, $data) = @_;
- if ($self->{ yaml }) {
- my %yamldata = %{ $data || {} };
-
- # in the YAML document, output the lines as a single scalar
- # rather than a list
- if ($yamldata{ detail }) {
- $yamldata{ detail } = join( "\n", @{ $yamldata{ detail } || [] } );
- }
-
- print YAML::Dump( \%yamldata );
- return;
- }
-
my $summary;
my $detail_indent = q{};