Index: ChangeLog
from Clement Vasseur <clement.vasseur(a)lrde.epita.fr>
* auto-build/auto_build.pl: Rename to...
* auto-build/auto-build: ...this.
2004-07-13 Clement Vasseur <clement.vasseur(a)lrde.epita.fr>
Index: auto-build/auto-build
--- auto-build/auto-build (revision 0)
+++ auto-build/auto-build (revision 79)
@@ -0,0 +1,643 @@
+#!/usr/bin/perl -w
+#
+# Auto Build System - auto-build
+# Copyright (C) 2004 LRDE - EPITA Research and Development Laboratory
+#
+# This program 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 of the License, or
+# (at your option) any later version.
+#
+# This program 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 this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+# Authors:
+# Clement Vasseur <clement.vasseur(a)lrde.epita.fr>
+# Nicolas Pouillard <nicolas.pouillard(a)lrde.epita.fr>
+
+# Any contribution should follow the Perl style guide: perldoc perlstyle
+# This script should remain self-contained and it should not depend on any
+# module besides the ones in the standard Perl 5.8 installation.
+
+my $VERSION = 0.1;
+
+=pod
+
+=head1 NAME
+
+auto-build
+
+=head1 SYNOPSIS
+
+auto-build [options] packages.list
+
+ -m, --man display the manual
+ -h, --help print this help and exit
+ -V, --version print version information and exit
+ -d, --delay=DELAY redo a build cycle after DELAY minutes
+
+=head1 DESCRIPTION
+
+=cut
+
+use strict;
+use Getopt::Long;
+use Pod::Usage;
+
+my $report_dir;
+my $build_dir;
+my $inst_dir;
+my @packages;
+
+my %variables;
+my @colors;
+my %deps;
+
+my $packages;
+my $man = 0;
+my $help = 0;
+my $delay = 0;
+
+GetOptions(
+ 'man|m' => \$man,
+ 'help|h|?' => \$help,
+ 'version|V' => \&version,
+ 'delay|d=i' => \$delay,
+ '<>' => sub { $packages = $_[0] },
+) or pod2usage(-verbose => 0);
+
+pod2usage(-verbose => 1) if $help;
+pod2usage(-verbose => 2) if $man;
+pod2usage(-verbose => 0) unless defined $packages;
+
+&read_pkg_list($packages);
+&create_dir($report_dir);
+&create_dir($build_dir);
+&create_dir($inst_dir);
+&prepare_pkgs;
+
+while (1) {
+ &auto_build;
+ last if $delay == 0;
+ sleep $delay * 60;
+}
+
+sub auto_build {
+ &gen_summary;
+
+ foreach my $pkg (@packages) {
+ print "$pkg->{'name'}\n";
+
+ next if &check_revision($pkg);
+ &gen_pkg_report($pkg);
+
+ my $ok = 1;
+ foreach my $dep (@{$deps{$pkg->{'name'}}}) {
+ foreach (@packages) {
+ $ok = 0 if $_->{'name'} eq $dep
+ and ($_->{'status'} eq 'failed' or $_->{'status'}
eq 'skipped');
+ }
+ unless ($ok) {
+ &set_status($pkg, 'skipped');
+ last;
+ }
+ }
+
+ &build_pkg($pkg) if $ok;
+ }
+}
+
+sub xopen {
+ my $filename = shift;
+ my $name = $filename;
+ my $FILE;
+
+ $name =~ s/^>//;
+ open $FILE, $filename
+ or die "$0: unable to open `$name': $!\n";
+ return $FILE;
+}
+
+sub xclose {
+ my $FILE = shift;
+ close $FILE or die "$0: unable to close `$FILE': $!\n";
+}
+
+sub header {
+ my ($filename, $title) = @_;
+ my $FILE = &xopen(">$filename");
+ select $FILE;
+
+ print <<HTML;
+<html>
+ <head>
+ <title>$title</title>
+ </head>
+ <body>
+HTML
+
+ return $FILE;
+}
+
+sub footer {
+ print <<HTML;
+ <hr/>
+ <h4>Generated by <i>auto-build</i> version $VERSION</h4>
+ </body>
+</html>
+HTML
+
+ select STDOUT;
+ my $FILE = shift;
+ &xclose($FILE);
+}
+
+sub read_pkg_list {
+ my $filename = shift;
+ my $LIST = &xopen($filename);
+ my $section;
+
+ while (<$LIST>) {
+ s/\s*\#.*$//;
+ next if m/^\s*$/;
+ chomp;
+
+ while (s/\s*\\\s*$/ /) {
+ my $l = <$LIST>;
+ $l =~ s/^\s*//;
+ $l =~ s/\s*\#.*$//;
+ $_ .= $l;
+ chomp;
+ }
+
+ unless (defined $report_dir) {
+ $report_dir = $_;
+ next;
+ }
+
+ unless (defined $build_dir) {
+ $build_dir = $_;
+ next;
+ }
+
+ unless (defined $inst_dir) {
+ $inst_dir = $_;
+ next;
+ }
+
+ if (m/^\s*color\s+(\w+)\s+\"(.*?)\"\s*$/) {
+ push @colors, [ $2, $1 ];
+
+ } elsif (m/^\s*section\s+\"(.*)\"\s*$/) {
+ $section = $1;
+
+ } elsif (m/^([\w\-]+)\s*=\s*(.*?)\s*$/) {
+ $variables{$1} = $2;
+
+ } elsif (m/^([\w\-]+)\s*$/) {
+ push @packages, {
+ 'name' => $1,
+ 'section' => $section,
+ 'opt' => '',
+ 'cfg' => '',
+ 'rev' => '0'
+ };
+
+ } elsif (m/^\s*(\w\w\w)\s*:\s*(.*?)\s*$/) {
+ my $field = $1;
+ my $value = $2;
+
+ my $err = 1;
+ foreach ('url', 'cfg', 'opt', 'env', 'dif')
{
+ if ($field eq $_) {
+ $err = 0;
+ last;
+ }
+ }
+
+ die "$filename:$.: invalid field `$field'\n" if $err;
+ while ($value =~ m/\$\{([\w\-]+)\}/) {
+ if (defined $variables{$1}) {
+ $value =~ s/\$\{([\w\-]+)\}/$variables{$1}/;
+ } else {
+ $value =~ s/\$\{([\w\-]+)\}/$inst_dir\/$1/;
+ push @{$deps{$packages[-1]->{'name'}}}, $1;
+ }
+ }
+ $packages[-1]->{$field} = $value;
+
+ } else {
+ die "$filename:$.: syntax error\n";
+ }
+ }
+
+ &xclose($LIST);
+ (defined $report_dir and defined $build_dir and $inst_dir)
+ or die "$0: `report', `build' and `inst' directories must be
defined\n";
+}
+
+sub create_dir {
+ my $dir = shift;
+ return if -d $dir;
+ system("/bin/mkdir -p \"$dir\"")
+ and die "$0: unable to mkdir `$dir'\n";
+}
+
+sub delete_dir {
+ my $dir = shift;
+ return unless -d $dir;
+ system("/bin/chmod -fR u+w \"$dir\"; /bin/rm -rf
\"$dir\"")
+ and die "$0: unable to remove `$dir'\n";
+}
+
+sub ch_dir {
+ my $dir = shift;
+ chdir $dir or die "$0: unable to chdir `$dir': $!\n";
+}
+
+sub time_to_str {
+ $_ = shift;
+ my $t = '';
+
+ if (defined $_ and $_ ne '') {
+ $t = ($_ % 60) . "s";
+ $t = (($_/60) % 60) . "m$t" if $_ >= 60;
+ $t = (($_/(60 * 60)) % 60) . "h$t" if $_ >= 60 * 60;
+ }
+
+ return $t;
+}
+
+sub gen_summary {
+ my $SUMMARY = &header("$report_dir/index.html", "Auto Build
System");
+ my $section = '';
+
+ print <<HTML;
+ <h1>Auto Build System</h1>
+ <hr/>
+ <table>
+HTML
+
+ foreach my $pkg (@packages) {
+ if ($pkg->{'section'} ne $section) {
+ if ($section ne '') {
+ print <<HTML;
+ <tr>
+ <td>
+
+ </td>
+ </tr>
+HTML
+ }
+ $section = $pkg->{'section'};
+ print <<HTML;
+ <tr>
+ <td>
+ <h3>$section</h3>
+ </td>
+ </tr>
+HTML
+ }
+
+ $pkg->{'status'} = '' unless defined $pkg->{'status'};
+
+ my $color = "black";
+ my $time = &time_to_str($pkg->{'time'});
+
+ $color = "red" if $pkg->{'status'} eq "failed";
+ $color = "green" if $pkg->{'status'} eq "succeeded";
+ $color = "gray" if $pkg->{'status'} eq "skipped";
+
+ print <<HTML;
+ <tr>
+ <td><a
href=\"$pkg->{'name'}/$pkg->{'name'}.html\">$pkg->{'name'}</a></td>
+ <td> </td>
+ <td><font
color=\"$color\">$pkg->{'status'}</font></td>
+ <td> </td>
+ <td><font color=\"gray\">$time</font></td>
+ </tr>
+HTML
+ }
+
+ print " </table>\n";
+ &footer($SUMMARY);
+}
+
+sub gen_pkg_report {
+ my $pkg = shift;
+ my $filename =
"$report_dir/$pkg->{'name'}/$pkg->{'name'}.html";
+ my $REPORT = &header("$filename", "$pkg->{'name'}
report");
+
+ my ($ts, $tf) = ('', '');
+ $ts = localtime $pkg->{'time_started'} if defined
$pkg->{'time_started'};
+ $tf = localtime $pkg->{'time_finished'} if defined
$pkg->{'time_finished'};
+
+ print <<HTML;
+ <h1>$pkg->{'name'}</h1>
+ <hr/>
+ <h3>Build started: $ts</h3>
+ <table cellpadding=\"8\">
+HTML
+
+ foreach my $step (@{$pkg->{'steps'}}) {
+ next unless defined $step->{'name'};
+ if (defined $step->{'status'}) {
+ my $color = "black";
+ $color = "green" if $step->{'status'} eq
"succeeded";
+ $color = "red" if $step->{'status'} eq "failed";
+
+ my $time = &time_to_str($step->{'time'});
+
+ print <<HTML;
+ <tr>
+ <td><a
href=\"$step->{'name'}.html\">$step->{'name'}</a></td>
+ <td><font
color=\"$color\">$step->{'status'}</font></td>
+ <td><font color=\"gray\">$time</font></td>
+ </tr>
+HTML
+ } else {
+ print <<HTML;
+ <tr>
+ <td>$step->{'name'}</td>
+ </tr>
+HTML
+ }
+ }
+
+ print <<HTML;
+ </table>
+ <h3>Build finished: $tf</h3>
+HTML
+
+ if (defined $pkg->{'archives'}) {
+ foreach (@{$pkg->{'archives'}}) {
+ print " <a href=\"$_\">$_</a><br/>\n" if -f
$_;
+ }
+ }
+
+ &footer($REPORT);
+}
+
+sub set_status {
+ $_[0]->{'status'} = $_[1];
+ print " $_[1]\n";
+ &gen_summary;
+}
+
+sub gen_log_page {
+ my $pkg = shift;
+ my $step = shift;
+ my $filename =
"$report_dir/$pkg->{'name'}/$step->{'name'}.html";
+ my $REPORT = &header("$filename", "$pkg->{'name'} -
$step->{'name'}");
+
+ print <<HTML;
+ <h1>$step->{'name'}</h1>
+ <h4>$step->{'cmd'}</h4>
+ <hr/>
+ <a href="$step->{'name'}.log">Log</a>
+HTML
+
+ &footer($REPORT);
+}
+
+sub run {
+ my $pkg = shift;
+ my $step = shift;
+ my $status = $step->{'name'};
+ my $out = "$report_dir/$pkg->{'name'}/$status";
+
+ &set_status($pkg, $status);
+ &gen_log_page($pkg, $step);
+
+ my $t = time;
+ my $exit_code = system("$step->{'cmd'} >$out.log
2>&1");
+ $step->{'time'} = time - $t;
+
+ my $REPORT = &header("$out.html", "$pkg->{'name'} -
$status");
+
+ print <<HTML;
+ <h1>$step->{'name'}</h1>
+ <h4>$step->{'cmd'}</h4>
+ <hr/>
+ <pre>
+HTML
+
+ my $LOG = &xopen("$out.log");
+ my $archives_ready;
+
+ while (<$LOG>) {
+ my $color;
+ foreach my $c (@colors) {
+ $color = $c->[1] if m/^$c->[0]/;
+ last if defined $color;
+ }
+ if ($status eq 'check') {
+ if (($archives_ready and m/^($archives_ready\.tar\.(gz|bz2))$/)
+ or m/^(.*\.tar\.(gz|bz2)) is ready for distribution$/) {
+ push @{$pkg->{'archives'}}, $1;
+ system("/bin/cp \"$1\"
\"$report_dir/$pkg->{'name'}\"")
+ and die "$0: unable to cp `$1' to
`$report_dir/$pkg->{'name'}': $!\n"
;
+ }
+ $archives_ready = $1 if m/^(.*) archives ready for distribution: $/;
+ }
+ print "<font color=\"$color\">" if $color;
+ print;
+ print "</font>" if $color;
+ }
+
+ print " </pre>\n";
+ &xclose($LOG);
+ &footer($REPORT);
+ return undef if $exit_code;
+ return 1;
+}
+
+sub check_revision {
+ my $pkg = shift;
+ my $revfile = "$inst_dir/$pkg->{'name'}/.rev";
+ my $rev;
+
+ if ($pkg->{'url'} =~ m|^svn:(.*/([^/]+))$|) {
+ chomp($rev = `svn log -q \"https:$1\" 2>/dev/null | grep '^r' |
head -n 1`)
;
+ $rev =~ s/^r(\d+).*$/$1/;
+ } elsif ($pkg->{'url'} =~ m/^((ht|f)tp:.*)$/) {
+ chomp($rev = `wget -qnv -O - \"$1\" | md5sum`);
+ }
+ $pkg->{'rev'} = $rev;
+
+ if (-f $revfile) {
+ chomp($rev = `cat \"$revfile\"`);
+ unlink $revfile if $pkg->{'rev'} ne $rev;
+ }
+ if (-f $revfile) {
+ chomp($pkg->{'time'} = `cat
\"$inst_dir/$pkg->{'name'}/.time\"`);
+ &set_status($pkg, 'succeeded');
+ return 1;
+ }
+ return undef;
+}
+
+sub get_package {
+ my $pkg = shift;
+ my @steps;
+ $_ = $pkg->{'url'};
+
+ if (m|^http://.*/([^/]+)/?$|
+ or m|^ftp://.*/([^/]+)/?$|) {
+ $_ = "file://$1";
+ push @steps, {
+ 'name' => 'download',
+ 'cmd' => "wget -nv \"$pkg->{'url'}\""
+ };
+ }
+
+ if (m|^file://(.*)$|) {
+ my $file = $_ = $1;
+ my $c;
+
+ $c = "z" if m/\.tar\.gz$/ or m/\.tgz$/;
+ $c = "j" if m/\.tar\.bz2$/ or m/\.tbz2$/;
+ $pkg->{'dir'} = $file;
+
+ if (defined $c) {
+ push @steps, {
+ 'name' => 'unpack',
+ 'cmd' => "tar -x${c}vf \"$file\""
+ }, {
+ 'dir' => "tar -t${c}f \"$file\" | head -n 1 | cut -d
'/' -f 0-1",
+ };
+ }
+
+ } elsif (m|^svn://(.*/([^/]+))/?$|) {
+ my $repository = "https://$1";
+ $pkg->{'dir'} = $2;
+
+ push @steps, {
+ 'name' => 'checkout',
+ 'cmd' => "svn checkout \"$repository\""
+ }, {
+ 'dir' => "echo \"$pkg->{'dir'}\"",
+ 'name' => 'bootstrap',
+ 'cmd' => '(./bootstrap || ./bootstrap.sh || autoreconf -fvi)'
+ };
+
+ } elsif (m|^prcs://(.*)$|) {
+ $pkg->{'dir'} = $1;
+
+ push @steps, {
+ 'dir' => "echo \"$1\"",
+ 'name' => 'checkout',
+ 'cmd' => "prcs checkout \"$1\""
+ }, {
+ 'name' => 'bootstrap',
+ 'cmd' => '(./bootstrap || ./bootstrap.sh || autoreconf -fvi)'
+ };
+
+ } else {
+ die "$0: invalid URL `$_': unknown protocol\n";
+ }
+
+ return @steps;
+}
+
+sub prepare_pkgs {
+ foreach my $pkg (@packages) {
+ my @steps = &get_package($pkg);
+ my $dir = "$report_dir/$pkg->{'name'}";
+ &create_dir($dir);
+
+ push @steps, {
+ 'name' => 'patch',
+ 'cmd' => "patch -p0 -t -i
\"$pkg->{'dif'}\""
+ } if defined $pkg->{'dif'};
+ push @steps, {
+ 'name' => 'configure',
+ 'cmd' => "./configure --prefix=$inst_dir/$pkg->{'name'}
$pkg->{'cfg'}"
+ }, {
+ 'name' => 'build', 'cmd' => 'make'
+ };
+ my $dcf = '';
+ defined $pkg->{'cfg'} and $pkg->{'cfg'} ne ''
+ and $dcf = "DISTCHECK_CONFIGURE_FLAGS=\"$pkg->{'cfg'}\"
";
+ push @steps, {
+ 'name' => 'check',
+ 'cmd' => "make ${dcf}distcheck"
+ } unless $pkg->{'opt'} =~ m/\bno-check\b/;
+ push @steps, {
+ 'rm' => "$inst_dir/$pkg->{'name'}"
+ },{
+ 'name' => 'install', 'cmd' => 'make install'
+ };
+ $pkg->{'steps'} = \@steps;
+ next if &check_revision($pkg);
+ &gen_pkg_report($pkg) unless -f "$dir/$pkg->{'name'}.html";
+ }
+}
+
+sub build_pkg {
+ my $pkg = shift;
+ my %env = %ENV;
+
+ if (defined $pkg->{'env'}) {
+ foreach (split /\s*,\s*/, $pkg->{'env'}) {
+ if (m/^\s*(\w+)\s*=\s*\"(.*)\"\s*$/) {
+ my ($v, $w) = ($1, $2);
+ $w =~ s/\$(\w+)/$ENV{$1}/;
+ $ENV{$v} = $w;
+ }
+ }
+ }
+
+ my $st;
+ my $dir = "$build_dir/$pkg->{'name'}";
+ &delete_dir($dir);
+ &create_dir($dir);
+ &ch_dir($dir);
+ $pkg->{'time_started'} = time;
+ foreach my $step (@{$pkg->{'steps'}}) {
+ $step->{'status'} = "running";
+ &gen_pkg_report($pkg);
+ &delete_dir($step->{'rm'}) if defined $step->{'rm'};
+ if (defined $step->{'dir'}) {
+ chomp($pkg->{'dir'} = `$step->{'dir'}`);
+ &create_dir($pkg->{'dir'});
+ &ch_dir($pkg->{'dir'});
+ }
+ if (not defined $step->{'cmd'}
+ or &run($pkg, $step)) {
+ $step->{'status'} = $st = "succeeded";
+ next;
+ }
+ $step->{'status'} = $st = "failed";
+ last;
+ }
+
+ $pkg->{'time_finished'} = time;
+ $pkg->{'time'} = $pkg->{'time_finished'} -
$pkg->{'time_started'};
+ %ENV = %env;
+ &gen_pkg_report($pkg);
+ &ch_dir($build_dir);
+ &set_status($pkg, $st);
+ if ($st eq "succeeded") {
+ system("echo \"$pkg->{'rev'}\" >
\"$inst_dir/$pkg->{'name'}/.rev\"");
+ system("echo \"$pkg->{'time'}\" >
\"$inst_dir/$pkg->{'name'}/.time\"");
+ &delete_dir($pkg->{'name'});
+ }
+}
+
+sub version {
+ print "auto-build (Auto Build System) $VERSION\n",
+ "Written by Clement Vasseur and Nicolas Pouillard.\n\n",
+ "Copyright (C) 2004 LRDE - EPITA Research and Development Laboratory.\n",
+ "This is free software; see the source for copying conditions. ",
+ "There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A ",
+ "PARTICULAR PURPOSE.\n";
+ exit 0;
+}
Property changes on: auto-build/auto-build
___________________________________________________________________
Name: svn:executable
+ *
Index: auto-build/auto_build.pl
--- auto-build/auto_build.pl (revision 78)
+++ auto-build/auto_build.pl (revision 79)
@@ -1,643 +0,0 @@
-#!/usr/bin/perl -w
-#
-# Auto Build System - auto-build
-# Copyright (C) 2004 LRDE - EPITA Research and Development Laboratory
-#
-# This program 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 of the License, or
-# (at your option) any later version.
-#
-# This program 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 this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-
-# Authors:
-# Clement Vasseur <clement.vasseur(a)lrde.epita.fr>
-# Nicolas Pouillard <nicolas.pouillard(a)lrde.epita.fr>
-
-# Any contribution should follow the Perl style guide: perldoc perlstyle
-# This script should remain self-contained and it should not depend on any
-# module besides the ones in the standard Perl 5.8 installation.
-
-my $VERSION = 0.1;
-
-=pod
-
-=head1 NAME
-
-auto-build
-
-=head1 SYNOPSIS
-
-auto-build [options] packages.list
-
- -m, --man display the manual
- -h, --help print this help and exit
- -V, --version print version information and exit
- -d, --delay=DELAY redo a build cycle after DELAY minutes
-
-=head1 DESCRIPTION
-
-=cut
-
-use strict;
-use Getopt::Long;
-use Pod::Usage;
-
-my $report_dir;
-my $build_dir;
-my $inst_dir;
-my @packages;
-
-my %variables;
-my @colors;
-my %deps;
-
-my $packages;
-my $man = 0;
-my $help = 0;
-my $delay = 0;
-
-GetOptions(
- 'man|m' => \$man,
- 'help|h|?' => \$help,
- 'version|V' => \&version,
- 'delay|d=i' => \$delay,
- '<>' => sub { $packages = $_[0] },
-) or pod2usage(-verbose => 0);
-
-pod2usage(-verbose => 1) if $help;
-pod2usage(-verbose => 2) if $man;
-pod2usage(-verbose => 0) unless defined $packages;
-
-&read_pkg_list($packages);
-&create_dir($report_dir);
-&create_dir($build_dir);
-&create_dir($inst_dir);
-&prepare_pkgs;
-
-while (1) {
- &auto_build;
- last if $delay == 0;
- sleep $delay * 60;
-}
-
-sub auto_build {
- &gen_summary;
-
- foreach my $pkg (@packages) {
- print "$pkg->{'name'}\n";
-
- next if &check_revision($pkg);
- &gen_pkg_report($pkg);
-
- my $ok = 1;
- foreach my $dep (@{$deps{$pkg->{'name'}}}) {
- foreach (@packages) {
- $ok = 0 if $_->{'name'} eq $dep
- and ($_->{'status'} eq 'failed' or $_->{'status'}
eq 'skipped');
- }
- unless ($ok) {
- &set_status($pkg, 'skipped');
- last;
- }
- }
-
- &build_pkg($pkg) if $ok;
- }
-}
-
-sub xopen {
- my $filename = shift;
- my $name = $filename;
- my $FILE;
-
- $name =~ s/^>//;
- open $FILE, $filename
- or die "$0: unable to open `$name': $!\n";
- return $FILE;
-}
-
-sub xclose {
- my $FILE = shift;
- close $FILE or die "$0: unable to close `$FILE': $!\n";
-}
-
-sub header {
- my ($filename, $title) = @_;
- my $FILE = &xopen(">$filename");
- select $FILE;
-
- print <<HTML;
-<html>
- <head>
- <title>$title</title>
- </head>
- <body>
-HTML
-
- return $FILE;
-}
-
-sub footer {
- print <<HTML;
- <hr/>
- <h4>Generated by <i>auto-build</i> version $VERSION</h4>
- </body>
-</html>
-HTML
-
- select STDOUT;
- my $FILE = shift;
- &xclose($FILE);
-}
-
-sub read_pkg_list {
- my $filename = shift;
- my $LIST = &xopen($filename);
- my $section;
-
- while (<$LIST>) {
- s/\s*\#.*$//;
- next if m/^\s*$/;
- chomp;
-
- while (s/\s*\\\s*$/ /) {
- my $l = <$LIST>;
- $l =~ s/^\s*//;
- $l =~ s/\s*\#.*$//;
- $_ .= $l;
- chomp;
- }
-
- unless (defined $report_dir) {
- $report_dir = $_;
- next;
- }
-
- unless (defined $build_dir) {
- $build_dir = $_;
- next;
- }
-
- unless (defined $inst_dir) {
- $inst_dir = $_;
- next;
- }
-
- if (m/^\s*color\s+(\w+)\s+\"(.*?)\"\s*$/) {
- push @colors, [ $2, $1 ];
-
- } elsif (m/^\s*section\s+\"(.*)\"\s*$/) {
- $section = $1;
-
- } elsif (m/^([\w\-]+)\s*=\s*(.*?)\s*$/) {
- $variables{$1} = $2;
-
- } elsif (m/^([\w\-]+)\s*$/) {
- push @packages, {
- 'name' => $1,
- 'section' => $section,
- 'opt' => '',
- 'cfg' => '',
- 'rev' => '0'
- };
-
- } elsif (m/^\s*(\w\w\w)\s*:\s*(.*?)\s*$/) {
- my $field = $1;
- my $value = $2;
-
- my $err = 1;
- foreach ('url', 'cfg', 'opt', 'env', 'dif')
{
- if ($field eq $_) {
- $err = 0;
- last;
- }
- }
-
- die "$filename:$.: invalid field `$field'\n" if $err;
- while ($value =~ m/\$\{([\w\-]+)\}/) {
- if (defined $variables{$1}) {
- $value =~ s/\$\{([\w\-]+)\}/$variables{$1}/;
- } else {
- $value =~ s/\$\{([\w\-]+)\}/$inst_dir\/$1/;
- push @{$deps{$packages[-1]->{'name'}}}, $1;
- }
- }
- $packages[-1]->{$field} = $value;
-
- } else {
- die "$filename:$.: syntax error\n";
- }
- }
-
- &xclose($LIST);
- (defined $report_dir and defined $build_dir and $inst_dir)
- or die "$0: `report', `build' and `inst' directories must be
defined\n";
-}
-
-sub create_dir {
- my $dir = shift;
- return if -d $dir;
- system("/bin/mkdir -p \"$dir\"")
- and die "$0: unable to mkdir `$dir'\n";
-}
-
-sub delete_dir {
- my $dir = shift;
- return unless -d $dir;
- system("/bin/chmod -fR u+w \"$dir\"; /bin/rm -rf
\"$dir\"")
- and die "$0: unable to remove `$dir'\n";
-}
-
-sub ch_dir {
- my $dir = shift;
- chdir $dir or die "$0: unable to chdir `$dir': $!\n";
-}
-
-sub time_to_str {
- $_ = shift;
- my $t = '';
-
- if (defined $_ and $_ ne '') {
- $t = ($_ % 60) . "s";
- $t = (($_/60) % 60) . "m$t" if $_ >= 60;
- $t = (($_/(60 * 60)) % 60) . "h$t" if $_ >= 60 * 60;
- }
-
- return $t;
-}
-
-sub gen_summary {
- my $SUMMARY = &header("$report_dir/index.html", "Auto Build
System");
- my $section = '';
-
- print <<HTML;
- <h1>Auto Build System</h1>
- <hr/>
- <table>
-HTML
-
- foreach my $pkg (@packages) {
- if ($pkg->{'section'} ne $section) {
- if ($section ne '') {
- print <<HTML;
- <tr>
- <td>
-
- </td>
- </tr>
-HTML
- }
- $section = $pkg->{'section'};
- print <<HTML;
- <tr>
- <td>
- <h3>$section</h3>
- </td>
- </tr>
-HTML
- }
-
- $pkg->{'status'} = '' unless defined $pkg->{'status'};
-
- my $color = "black";
- my $time = &time_to_str($pkg->{'time'});
-
- $color = "red" if $pkg->{'status'} eq "failed";
- $color = "green" if $pkg->{'status'} eq "succeeded";
- $color = "gray" if $pkg->{'status'} eq "skipped";
-
- print <<HTML;
- <tr>
- <td><a
href=\"$pkg->{'name'}/$pkg->{'name'}.html\">$pkg->{'name'}</a></td>
- <td> </td>
- <td><font
color=\"$color\">$pkg->{'status'}</font></td>
- <td> </td>
- <td><font color=\"gray\">$time</font></td>
- </tr>
-HTML
- }
-
- print " </table>\n";
- &footer($SUMMARY);
-}
-
-sub gen_pkg_report {
- my $pkg = shift;
- my $filename =
"$report_dir/$pkg->{'name'}/$pkg->{'name'}.html";
- my $REPORT = &header("$filename", "$pkg->{'name'}
report");
-
- my ($ts, $tf) = ('', '');
- $ts = localtime $pkg->{'time_started'} if defined
$pkg->{'time_started'};
- $tf = localtime $pkg->{'time_finished'} if defined
$pkg->{'time_finished'};
-
- print <<HTML;
- <h1>$pkg->{'name'}</h1>
- <hr/>
- <h3>Build started: $ts</h3>
- <table cellpadding=\"8\">
-HTML
-
- foreach my $step (@{$pkg->{'steps'}}) {
- next unless defined $step->{'name'};
- if (defined $step->{'status'}) {
- my $color = "black";
- $color = "green" if $step->{'status'} eq
"succeeded";
- $color = "red" if $step->{'status'} eq "failed";
-
- my $time = &time_to_str($step->{'time'});
-
- print <<HTML;
- <tr>
- <td><a
href=\"$step->{'name'}.html\">$step->{'name'}</a></td>
- <td><font
color=\"$color\">$step->{'status'}</font></td>
- <td><font color=\"gray\">$time</font></td>
- </tr>
-HTML
- } else {
- print <<HTML;
- <tr>
- <td>$step->{'name'}</td>
- </tr>
-HTML
- }
- }
-
- print <<HTML;
- </table>
- <h3>Build finished: $tf</h3>
-HTML
-
- if (defined $pkg->{'archives'}) {
- foreach (@{$pkg->{'archives'}}) {
- print " <a href=\"$_\">$_</a><br/>\n" if -f
$_;
- }
- }
-
- &footer($REPORT);
-}
-
-sub set_status {
- $_[0]->{'status'} = $_[1];
- print " $_[1]\n";
- &gen_summary;
-}
-
-sub gen_log_page {
- my $pkg = shift;
- my $step = shift;
- my $filename =
"$report_dir/$pkg->{'name'}/$step->{'name'}.html";
- my $REPORT = &header("$filename", "$pkg->{'name'} -
$step->{'name'}");
-
- print <<HTML;
- <h1>$step->{'name'}</h1>
- <h4>$step->{'cmd'}</h4>
- <hr/>
- <a href="$step->{'name'}.log">Log</a>
-HTML
-
- &footer($REPORT);
-}
-
-sub run {
- my $pkg = shift;
- my $step = shift;
- my $status = $step->{'name'};
- my $out = "$report_dir/$pkg->{'name'}/$status";
-
- &set_status($pkg, $status);
- &gen_log_page($pkg, $step);
-
- my $t = time;
- my $exit_code = system("$step->{'cmd'} >$out.log
2>&1");
- $step->{'time'} = time - $t;
-
- my $REPORT = &header("$out.html", "$pkg->{'name'} -
$status");
-
- print <<HTML;
- <h1>$step->{'name'}</h1>
- <h4>$step->{'cmd'}</h4>
- <hr/>
- <pre>
-HTML
-
- my $LOG = &xopen("$out.log");
- my $archives_ready;
-
- while (<$LOG>) {
- my $color;
- foreach my $c (@colors) {
- $color = $c->[1] if m/^$c->[0]/;
- last if defined $color;
- }
- if ($status eq 'check') {
- if (($archives_ready and m/^($archives_ready\.tar\.(gz|bz2))$/)
- or m/^(.*\.tar\.(gz|bz2)) is ready for distribution$/) {
- push @{$pkg->{'archives'}}, $1;
- system("/bin/cp \"$1\"
\"$report_dir/$pkg->{'name'}\"")
- and die "$0: unable to cp `$1' to
`$report_dir/$pkg->{'name'}': $!\n"
;
- }
- $archives_ready = $1 if m/^(.*) archives ready for distribution: $/;
- }
- print "<font color=\"$color\">" if $color;
- print;
- print "</font>" if $color;
- }
-
- print " </pre>\n";
- &xclose($LOG);
- &footer($REPORT);
- return undef if $exit_code;
- return 1;
-}
-
-sub check_revision {
- my $pkg = shift;
- my $revfile = "$inst_dir/$pkg->{'name'}/.rev";
- my $rev;
-
- if ($pkg->{'url'} =~ m|^svn:(.*/([^/]+))$|) {
- chomp($rev = `svn log -q \"https:$1\" 2>/dev/null | grep '^r' |
head -n 1`)
;
- $rev =~ s/^r(\d+).*$/$1/;
- } elsif ($pkg->{'url'} =~ m/^((ht|f)tp:.*)$/) {
- chomp($rev = `wget -qnv -O - \"$1\" | md5sum`);
- }
- $pkg->{'rev'} = $rev;
-
- if (-f $revfile) {
- chomp($rev = `cat \"$revfile\"`);
- unlink $revfile if $pkg->{'rev'} ne $rev;
- }
- if (-f $revfile) {
- chomp($pkg->{'time'} = `cat
\"$inst_dir/$pkg->{'name'}/.time\"`);
- &set_status($pkg, 'succeeded');
- return 1;
- }
- return undef;
-}
-
-sub get_package {
- my $pkg = shift;
- my @steps;
- $_ = $pkg->{'url'};
-
- if (m|^http://.*/([^/]+)/?$|
- or m|^ftp://.*/([^/]+)/?$|) {
- $_ = "file://$1";
- push @steps, {
- 'name' => 'download',
- 'cmd' => "wget -nv \"$pkg->{'url'}\""
- };
- }
-
- if (m|^file://(.*)$|) {
- my $file = $_ = $1;
- my $c;
-
- $c = "z" if m/\.tar\.gz$/ or m/\.tgz$/;
- $c = "j" if m/\.tar\.bz2$/ or m/\.tbz2$/;
- $pkg->{'dir'} = $file;
-
- if (defined $c) {
- push @steps, {
- 'name' => 'unpack',
- 'cmd' => "tar -x${c}vf \"$file\""
- }, {
- 'dir' => "tar -t${c}f \"$file\" | head -n 1 | cut -d
'/' -f 0-1",
- };
- }
-
- } elsif (m|^svn://(.*/([^/]+))/?$|) {
- my $repository = "https://$1";
- $pkg->{'dir'} = $2;
-
- push @steps, {
- 'name' => 'checkout',
- 'cmd' => "svn checkout \"$repository\""
- }, {
- 'dir' => "echo \"$pkg->{'dir'}\"",
- 'name' => 'bootstrap',
- 'cmd' => '(./bootstrap || ./bootstrap.sh || autoreconf -fvi)'
- };
-
- } elsif (m|^prcs://(.*)$|) {
- $pkg->{'dir'} = $1;
-
- push @steps, {
- 'dir' => "echo \"$1\"",
- 'name' => 'checkout',
- 'cmd' => "prcs checkout \"$1\""
- }, {
- 'name' => 'bootstrap',
- 'cmd' => '(./bootstrap || ./bootstrap.sh || autoreconf -fvi)'
- };
-
- } else {
- die "$0: invalid URL `$_': unknown protocol\n";
- }
-
- return @steps;
-}
-
-sub prepare_pkgs {
- foreach my $pkg (@packages) {
- my @steps = &get_package($pkg);
- my $dir = "$report_dir/$pkg->{'name'}";
- &create_dir($dir);
-
- push @steps, {
- 'name' => 'patch',
- 'cmd' => "patch -p0 -t -i
\"$pkg->{'dif'}\""
- } if defined $pkg->{'dif'};
- push @steps, {
- 'name' => 'configure',
- 'cmd' => "./configure --prefix=$inst_dir/$pkg->{'name'}
$pkg->{'cfg'}"
- }, {
- 'name' => 'build', 'cmd' => 'make'
- };
- my $dcf = '';
- defined $pkg->{'cfg'} and $pkg->{'cfg'} ne ''
- and $dcf = "DISTCHECK_CONFIGURE_FLAGS=\"$pkg->{'cfg'}\"
";
- push @steps, {
- 'name' => 'check',
- 'cmd' => "make ${dcf}distcheck"
- } unless $pkg->{'opt'} =~ m/\bno-check\b/;
- push @steps, {
- 'rm' => "$inst_dir/$pkg->{'name'}"
- },{
- 'name' => 'install', 'cmd' => 'make install'
- };
- $pkg->{'steps'} = \@steps;
- next if &check_revision($pkg);
- &gen_pkg_report($pkg) unless -f "$dir/$pkg->{'name'}.html";
- }
-}
-
-sub build_pkg {
- my $pkg = shift;
- my %env = %ENV;
-
- if (defined $pkg->{'env'}) {
- foreach (split /\s*,\s*/, $pkg->{'env'}) {
- if (m/^\s*(\w+)\s*=\s*\"(.*)\"\s*$/) {
- my ($v, $w) = ($1, $2);
- $w =~ s/\$(\w+)/$ENV{$1}/;
- $ENV{$v} = $w;
- }
- }
- }
-
- my $st;
- my $dir = "$build_dir/$pkg->{'name'}";
- &delete_dir($dir);
- &create_dir($dir);
- &ch_dir($dir);
- $pkg->{'time_started'} = time;
- foreach my $step (@{$pkg->{'steps'}}) {
- $step->{'status'} = "running";
- &gen_pkg_report($pkg);
- &delete_dir($step->{'rm'}) if defined $step->{'rm'};
- if (defined $step->{'dir'}) {
- chomp($pkg->{'dir'} = `$step->{'dir'}`);
- &create_dir($pkg->{'dir'});
- &ch_dir($pkg->{'dir'});
- }
- if (not defined $step->{'cmd'}
- or &run($pkg, $step)) {
- $step->{'status'} = $st = "succeeded";
- next;
- }
- $step->{'status'} = $st = "failed";
- last;
- }
-
- $pkg->{'time_finished'} = time;
- $pkg->{'time'} = $pkg->{'time_finished'} -
$pkg->{'time_started'};
- %ENV = %env;
- &gen_pkg_report($pkg);
- &ch_dir($build_dir);
- &set_status($pkg, $st);
- if ($st eq "succeeded") {
- system("echo \"$pkg->{'rev'}\" >
\"$inst_dir/$pkg->{'name'}/.rev\"");
- system("echo \"$pkg->{'time'}\" >
\"$inst_dir/$pkg->{'name'}/.time\"");
- &delete_dir($pkg->{'name'});
- }
-}
-
-sub version {
- print "auto-build (Auto Build System) $VERSION\n",
- "Written by Clement Vasseur and Nicolas Pouillard.\n\n",
- "Copyright (C) 2004 LRDE - EPITA Research and Development Laboratory.\n",
- "This is free software; see the source for copying conditions. ",
- "There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A ",
- "PARTICULAR PURPOSE.\n";
- exit 0;
-}