#!/usr/bin/perl -w # Copyright (C) 2011 Apple Inc. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # Filters the output of build-webkit into a more human-readable format. use strict; use warnings; use CGI qw(escapeHTML); use File::Basename; use FindBin; use lib $FindBin::Bin; use Getopt::Long; use VCSUtils; use constant { STYLE_PLAIN => 0, STYLE_HEADER => 1, STYLE_SUCCESS => 2, STYLE_ALERT => 3, HTML_HEADER =>< Build Log HTMLHEADER HTML_FOOTER =>< HTMLFOOTER }; sub printLine($$); sub setLogfileOption($$); sub setOutputFormatOption($$); sub usageAndExit(); # Defined in VCSUtils. sub possiblyColored($$); my $showHelp; my $outputPath = "&STDOUT"; my $outputFormat = "text"; my $useColor = -t STDOUT; my $unfilteredOutputPath = "build.log"; my $logUnfilteredOutput; sub usageAndExit() { print STDERR <<__END__; Usage: @{[ basename($0) ]} [options] buildlog1 [buildlog2 ...] build-webkit | @{[ basename($0) ]} [options] -h|--help Show this help message Output Options: -o|--output Path for output (default: STDOUT) -f|--format Output format (default: $outputFormat) text: Plain text html: Standalone HTML document --[no-]color ANSI color output for text (default: on, if -o is STDOUT) Unfiltered Logging Options: -l|--log Save unfiltered output to file (see --log-file) --logfile Path to save unfiltered output (implies --log, default: $unfilteredOutputPath) __END__ exit 1; } my $getOptionsResult = GetOptions( 'h|help' => \$showHelp, 'o|output=s' => \$outputPath, 'f|format=s' => \&setOutputFormatOption, 'color!' => \$useColor, 'l|log' => \$logUnfilteredOutput, 'logfile=s' => \&setLogfileOption, ); if (-t STDIN || $showHelp || !$getOptionsResult) { usageAndExit(); } open(OUTPUT_HANDLE, ">$outputPath") or die "Failed to open $outputPath : $!"; if ($logUnfilteredOutput) { open(UNFILTERED_OUTPUT_HANDLE, ">$unfilteredOutputPath") or die "Failed to open $unfilteredOutputPath : $!"; } print OUTPUT_HANDLE HTML_HEADER if ($outputFormat eq "html"); my $buildFinished; my $buildFailed = 0; while (my $line = <>) { print UNFILTERED_OUTPUT_HANDLE $line if $logUnfilteredOutput; chomp($line); next if $line =~ /^\s*$/; next if $line =~ /^Build settings from command line:/; next if $line =~ /make: Nothing to be done for `all'\./; next if $line =~ /^JavaScriptCore\/create_hash_table/; next if $line =~ /JavaScriptCore.framework\/PrivateHeaders\/create_hash_table/; next if $line =~ /^JavaScriptCore\/pcre\/dftables/; next if $line =~ /^Creating hashtable for /; next if $line =~ /^Wrote output to /; next if $line =~ /^(touch|perl|cat|rm -f|bison|flex|python|\/usr\/bin\/g\+\+|gperf|echo|sed|if \[ \-f|WebCore\/generate-export-file) /; next if $line =~ /^UNDOCUMENTED: /; next if $line =~ /libtool.*has no symbols/; next if $line =~ /^# Lower case all the values, as CSS values are case-insensitive$/; next if $line =~ /^if sort /; next if $line =~ /^ /; next if $line =~ /^printf /; next if $line =~ /^offlineasm: Nothing changed/; next if $line =~ /^Showing first/; if ($line =~ /^={10}/) { printLine($line, STYLE_SUCCESS); $buildFinished = 1; } elsif ($line =~ /^===/) { printLine($line, STYLE_HEADER); } elsif ($line =~ /Checking Dependencies|Check dependencies/) { printLine($line, STYLE_PLAIN); } elsif ($line =~ /\*\* BUILD SUCCEEDED \*\*/) { printLine("Build Succeeded", STYLE_SUCCESS); } elsif ($line =~ /^(PhaseScriptExecution|CompileC|Distributed-CompileC|Ld|PBXCp|CpResource|CopyPNGFile|CopyTiffFile|CpHeader|Processing|ProcessInfoPlistFile|ProcessPCH|ProcessPCH\+\+|Touch|Libtool|CopyStringsFile|Mig|CreateUniversalBinary|Analyze|ProcessProductPackaging|CodeSign|SymLink|Updating|CompileXIB|StripNIB|CopyPlistFile|GenerateDSYMFile) ("[^"]+"|\S+)?/) { my ($command, $path) = ($1, basename($2)); $path =~ s/"//g; printLine("$command $path", STYLE_PLAIN); } elsif ($line =~ /^\/\S+?(strip|WebCoreExportFileGenerator) .*?(\/|\> )(\S+)/) { my ($command, $path) = (basename($1), basename($3)); printLine("$command $path", STYLE_PLAIN); } elsif ($line =~ /^offlineasm\: /) { printLine($line, STYLE_PLAIN); } elsif ($line =~ /^Generating message.*(header|receiver) for (\S+)\.\.\./) { my ($command, $path) = ($1, basename($2)); printLine("Generating message $command $path", STYLE_PLAIN); } elsif ($line =~ /^(\S+\/cc).*?(\S+)\.(out|exp)/) { my ($command, $path) = (basename($1), basename($2)); printLine("$command $path", STYLE_PLAIN); } else { # This only gets hit if stderr is redirected to stdout. if ($line =~ /\*\* BUILD FAILED \*\*/) { $buildFailed = 1; } printLine($line, $buildFinished ? STYLE_SUCCESS : STYLE_ALERT); } } print OUTPUT_HANDLE HTML_FOOTER if ($outputFormat eq "html"); close(OUTPUT_HANDLE); close(UNFILTERED_OUTPUT_HANDLE) if ($logUnfilteredOutput); exit $buildFailed; sub printLine($$) { my ($line, $style) = @_; if ($outputFormat eq "html") { $line = escapeHTML($line); if ($style == STYLE_HEADER) { print OUTPUT_HANDLE "

$line

"; } elsif ($style == STYLE_SUCCESS) { print OUTPUT_HANDLE "

$line

"; } elsif ($style == STYLE_ALERT) { print OUTPUT_HANDLE "

$line

"; } else { print OUTPUT_HANDLE "

$line

"; } } else { if ($useColor) { my $colors = "reset"; if ($style == STYLE_HEADER) { $colors = "blue"; } if ($style == STYLE_SUCCESS) { $colors = "green"; } if ($style == STYLE_ALERT) { $colors = "red"; } print OUTPUT_HANDLE possiblyColored($colors, $line); } else { print OUTPUT_HANDLE $line; } } print OUTPUT_HANDLE "\n"; } sub setLogfileOption($$) { my ($opt, $value) = @_; $unfilteredOutputPath = $value; $logUnfilteredOutput = 1; } sub setOutputFormatOption($$) { my ($opt, $value) = @_; $value = lc($value); if ($value ne "html" && $value ne "text") { die "The $opt option must be either \"html\" or \"text\""; } $outputFormat = $value; }