#!/usr/bin/perl

# Copyright (C) 2004 Simon Josefsson.
#
# This file is part of Autobuild.
#
# Autobuild is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# Autobuild is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Autobuild; see the file COPYING.  If not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
# MA 02111-1307, USA.

use strict;
use Getopt::Long;

# Parse command line parameters.
my $Verbose;
my ($PrintHelp, $PrintVersion);
my ($Abort, $DryRun, $Html);
my ($OutDir) = ".";
my ($Project, $Revision, $Mode, $Hostname, $Hosttype,
    $Buildtype, $Timestamp, $Status);
GetOptions ('help|usage|h' => \$PrintHelp,
	    'version|V'    => \$PrintVersion,
	    'verbose|v'    => \$Verbose,
	    'html'         => \$Html,
	    'abort|a'      => \$Abort,
	    'dry-run|n'    => \$DryRun,
	    'outdir|o=s'   => \$OutDir,
	    'p|project=s'  => \$Project,
	    'revision=s'   => \$Revision,
	    'mode=s'       => \$Mode,
	    'Hosttype=s'   => \$Hosttype,
	    'Buildtype=s'  => \$Buildtype,
	    'Hostname=s'   => \$Hostname,
	    'Timestamp=s'  => \$Timestamp,
	    'Status=s'     => \$Status);

# Handle --help.
if ($PrintHelp) {
    print "Usage: $0 [OPTION]... [FILE]...\n";
    print "\n";
    print "Read and parse build logs to find project name, revision, build mode,\n";
    print "build host type, build type (for cross compile builds), hostname, and\n";
    print "timestamp, then produce a file (named depending on the extracted\n";
    print "parameters) with the build log.\n";
    print "\n";
    print "Mandatory arguments to long options are mandatory for short options too.\n";
    print "\n";
    print "      --abort             Abort if guessing values fail.\n";
    print "                          With the exceptions of build mode\n";
    print "                          (falls back to 'default') and\n";
    print "                          the status (falls back to 'fail').\n";
    print "  -n, --dry-run           Just parse, don't write file.\n";
    print "      --html              Create HTML output instead of text.\n";
    print "                          Need Emacs and htmlize.el.\n";
    print "  -o, --outdir=DIR        Create files in specified directory.\n";
    print "\n";
    print "For use when autobuild fail to guess the values properly:\n";
    print "  -p, --project=STRING    Specify project name.\n";
    print "      --revision=STRING   Specify project revision.\n";
    print "      --mode=STRING       Specify build mode (typically 'default').\n";
    print "      --hosttype=STRING   Specify host type (e.g., i686-pc-linux-gnu).\n";
    print "      --buildtype=STRING  Specify build type (e.g., m68k-uclinux-elf).\n";
    print "                          Different from hosttype for cross compiles.\n";
    print "      --hostname=STRING   Specify name of host log was created on.\n";
    print "      --timestamp=STRING  Specify when build was made.\n";
    print "                          Any date format will work, but\n";
    print "                          'YYYY-MM-DDTHH:MM:SS' is recommended.\n";
    print "      --status=STRING     Outcome of build.\n";
    print "                          Any string will work, but \"ok\" and\n";
    print "                          \"fail\" are recommended for the two\n";
    print "                          basic outcomes.\n";
    print "\n";
    print "Other options:\n";
    print "\n";
    print "  -v, --verbose           Explain what is being done.\n";
    print "      --help              Display this help and exit.\n";
    print "      --version           Output version information and exit.\n";
    print "\n";
    print "Report bugs to <bug-autobuild\@josefsson.org>.\n";
    exit 0;
}

# Handle --verison.
if ($PrintVersion) {
    print "autobuild (autobuild) 1.4\n";
    print "\n";
    print "Copyright (C) 2004 Simon Josefsson\n";
    print "This is free software; see the source for copying conditions.  There is NO\n";
    print "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n";
    exit 0;
}

# Declarations.
my ($tmpfile) = "$OutDir/.autobuild.$$";

# Always clean up in case of failure.
sub END { unlink $tmpfile; }

# Core.
open OUT, "> $tmpfile" or die "Can't open temporary file: $!";

my ($project, $revision, $mode, $hostname, $hosttype,
    $buildtype, $timestamp, $status);

# Initialize variables.
$project = $Project;
$revision = $Revision;
$mode = $Mode;
$hostname = $Hostname;
$hosttype = $Hosttype;
$buildtype = $Buildtype;
$timestamp = $Timestamp;
$status = $Status;

while (<>) {
    if (m,\r\n$,) {
	chop; chop;
	$_ = $_ . "\n";
    }

    # These override everything (except command line parameters).
    $project = $1 if !$Project && m,autobuild project... (.*),;
    $revision = $1 if !$Revision && m,autobuild revision... (.*),;
    $mode = $1 if !$Mode && m,autobuild mode... (.*),;
    $hostname = $1 if !$Hostname && m,autobuild hostname... (.*),;
    $hosttype = $1 if !$Hosttype && m,autobuild hosttype... (.*),;
    $buildtype = $1 if !$Buildtype && m,autobuild buildtype... (.*),;
    $timestamp = $1 if !$Timestamp && m,autobuild timestamp... (.*),;

    # GNU Autoconf host/build output.
    $hosttype = $1 if !$hosttype && m,checking host system type... ([a-z0-9_.-]+),;
    $buildtype = $1 if !$buildtype && m,checking build system type... ([a-z0-9_.-]+),;

    # Automake self test output.
    $status = "ok" if !$status && m,All [0-9]+ tests passed,;
    $status = "almost" if !$status && m,[0-9]+ of [0-9]+ tests failed,;

    # Works for GNU make.
    $project = $1 if !$project && m,make\[[0-9]+\]: Entering directory `.*/([a-z]+)-[0-9.]+/.*',;
    $revision = $1 if !$revision && m,make\[[0-9]+\]: Entering directory `.*/[a-z]+-([0-9.]+)/.*',;

    # Telnet string.
    $hostname = $1 if !$hostname && m,Trying (.*)\.\.\.,;
    $hostname = $1 if !$hostname && m,Connected to (.*)\.,;

    # SSH string.
    $hostname = $1 if !$hostname && m,Connection to (.*) closed.,;

    # If output mention a tar.gz archive.
    $project = $1 if !$project && m,/([a-z]+)-[0-9.]+.tar.gz,;
    $revision = $1 if !$revision && m,/[a-z]+-([0-9.]+).tar.gz,;

    print OUT $_;

    if (eof) {
	if (!$Abort) {
	    $project = "unknown" if !$project;
	    $revision = "0" if $revision eq "";
	    $hostname = "unknown" if !$hostname;
	    $hosttype = "unknown" if !$hosttype;
	    $buildtype = "unknown" if !$buildtype;
	    $timestamp = "unknown" if !$timestamp;
	}
	$mode = "default" if !$mode;
	$status = "fail" if !$status;

	if ($Verbose) {
	    print STDERR "Project: $project\n" if $project;
	    print STDERR "Revision: $revision\n" if $revision ne "";
	    print STDERR "Mode: $mode\n" if $mode;
	    print STDERR "Hosttype: $hosttype\n" if $hosttype;
	    print STDERR "Buildtype: $buildtype\n" if $buildtype;
	    print STDERR "Hostname: $hostname\n" if $hostname;
	    print STDERR "Timestamp: $timestamp\n" if $timestamp;
	    print STDERR "Status: $status\n" if $status;
	}

	close OUT;

	die "Could not guess all required values" .
	    ($Verbose ? "" : " (use -v to print values)")."\n"
	    if $Abort && (!$project || !$revision || !$hostname || !$hosttype
			  || !$buildtype || !$timestamp || !$status);

	if (!$DryRun) {
	    my ($outbase, $outfile) = "$OutDir/autobuild,project=$project,revision=$revision,mode=$mode,hosttype=$hosttype,buildtype=$buildtype,hostname=$hostname,timestamp=$timestamp,status=$status,log";
	    if ($Html) {
		$outfile = $outbase . ".html";
		system ("emacs --eval '(let ((htmlize-before-hook (lambda () (compilation-mode) (font-lock-fontify-buffer)))) (htmlize-file \"$tmpfile\" \"$outfile\") (kill-emacs))'");
	    } else {
		$outfile = $outbase . ".txt";
		rename $tmpfile, $outfile;
	    }
	    print "$outfile\n";
	}

	open OUT, "> $tmpfile" or die "Can't open temporary file: $!";

	# Reset variables.
	$project = $Project;
	$revision = $Revision;
	$mode = $Mode;
	$hostname = $Hostname;
	$hosttype = $Hosttype;
	$buildtype = $Buildtype;
	$timestamp = $Timestamp;
	$status = $Status;
    }
}
