gecko-dev/config/fast-update.pl
2010-05-13 14:19:50 +02:00

313 lines
7.3 KiB
Perl
Executable File

#!/usr/bin/env perl
#
# fast-update.pl [-h hours] [-m module] [-r branch]
#
# This command, fast-update.pl, does a (fast) cvs update of the current
# directory. It is fast because the cvs up command is only run on those
# directories / sub-directories where changes have occurred since the
# last fast-update.
#
# The last update time is stored in a ".fast-update" file in the current
# directory. Thus one can choose to only fast-update a branch of the tree
# and then fast-update the whole tree later.
#
# The first time this command is run in a directory the last cvs update
# time is assumed to be the timestamp of the CVS/Entries file.
#
use Getopt::Long;
my $filename = ".fast-update";
my $start_time = time();
my $branch;
my $module="SeaMonkeyAll";
my $maxdirs=5;
my $rootdir = "";
my $hours = 0;
my @dirs = ();
my $dirlocal = 0;
&GetOptions('d=s@' => \@dirs, 'h=s' => \$hours, 'm=s' => \$module, 'r=s' => \$branch, 'l' => \$dirlocal);
#print "dirs = (@dirs), hours = ($hours), module = ($module), branch = ($branch), dirlocal = ($dirlocal)\n";
if (scalar(@dirs) > 0) {
# put .fast-update in the first directory listed
$filename = "$dirs[0]/$filename";
$filename =~ s#mozilla/*##;
}
if (!$hours) {
$hours = get_hours_since_last_update();
}
if (!$hours) {
$hours = 24;
}
# pull out the current directory
# if there is no such file, this will all just fail, which is ok
open REPOSITORY, "<CVS/Repository";
$rootdir = <REPOSITORY>;
$rootdir =~ tr/\r\n//d; # Remove newlines
close REPOSITORY;
# try to guess the current branch by looking at all the
# files in CVS/Entries
if (!$branch) {
my $foundbranch =0;
open ENTRIES, "<CVS/Entries";
while (<ENTRIES>) {
chop;
@entry = split(/\//);
my ($type, $file, $ver, $date, $unknown, $tag) = @entry;
# the tag usually starts with "T"
$thisbranch = substr($tag, 1);
# look for more than one branch
if ($type eq "") {
if ($foundbranch and ($lastbranch ne $thisbranch)) {
die "Multiple branches in this directory, cannot determine branch\n";
}
$foundbranch = 1;
$lastbranch = $thisbranch;
}
}
$branch = $lastbranch if ($foundbranch);
close ENTRIES;
}
# check for a static Tag
# (at least that is what I think this does)
# (bonsai does not report changes when the Tag starts with 'N')
# (I do not really understand all this)
if ($branch) {
open TAG, "<CVS/Tag";
my $line = <TAG>;
if ($line =~ /^N/) {
print "static tag, ignore branch\n";
$branch = '';
}
close TAG;
}
my $url = "http://bonsai.mozilla.org/cvsquery.cgi?module=${module}&branch=${branch}&branchtype=match&sortby=File&date=hours&hours=${hours}&cvsroot=%2Fcvsroot";
my $dir_string = "";
if (scalar(@dirs) > 0) {
$dir_string = join(' ', @dirs);
my $esc_dir = escape($dir_string);
$url .= "&dir=$esc_dir";
}
if ($dirlocal) {
$url .= "&dirtype=local";
}
print "Contacting bonsai for updates to ${module} ";
print "on the ${branch} branch " if ($branch);
print "in the last ${hours} hours ";
print "within the $rootdir directory..\n" if ($rootdir);
print "\n" unless ($rootdir);
#print "url = $url\n";
# first try wget, then try lynx, then try curl
# this is my lame way of checking if a command succeeded AND getting
# output from it. I'd love a better way. -alecf@netscape.com
my $have_checkins = 0;
open CHECKINS,"wget --quiet --output-document=- \"$url\"|" or
die "Error opening wget: $!\n";
$header = <CHECKINS> and $have_checkins=1;
if (!$have_checkins) {
open CHECKINS, "lynx -source '$url'|" or die "Error opening lynx: $!\n";
$header = <CHECKINS> and $have_checkins = 1;
}
if (!$have_checkins) {
open CHECKINS, "curl -s '$url'|" or die "Error opening curl $!\n";
$header = <CHECKINS> and $have_checkins = 1;
}
$have_checkins || die "Couldn't get checkins\n";
open REALOUT, ">.fast-update.bonsai.html" || die "argh $!\n";
print "Processing checkins...";
while (<CHECKINS>) {
print REALOUT $_;
if (/js_file_menu\((.*),\s*\'(.*)\'\s*,\s*(.*),\s*(.*),\s*(.*),\s*(.*)\)/) {
my ($repos, $dir, $file, $rev, $branch, $event) =
($1, $2, $3, $4, $5, $6);
$dir =~ s/\/Attic$//;
push @dirlist, $dir;
}
}
print "done.\n";
close REALOUT;
unlink '.fast-update.bonsai.html';
my $lastdir = "";
my @uniquedirs;
foreach $dir (sort @dirlist) {
next if ($lastdir eq $dir);
my $strippeddir = "";
$lastdir = $dir;
# now strip out $rootdir
if ($rootdir) {
# only deal with directories that start with $rootdir
if (substr($dir, 0, (length $rootdir)) eq $rootdir) {
if ($dir eq $rootdir) {
$strippeddir = ".";
} else {
$strippeddir = substr($dir,(length $rootdir) + 1 );
}
}
} else {
$strippeddir = $dir;
}
if ($strippeddir) {
push @uniquedirs, $strippeddir;
}
}
my $status = 0;
if (scalar(@uniquedirs)) {
print "Updating tree... (" . scalar(@uniquedirs) . " directories)\n";
my $i=0;
my $dirlist = "";
foreach $dir (sort @uniquedirs) {
if (!-d $dir) {
cvs_up_parent($dir);
}
$dirlist .= "\"$dir\" ";
$i++;
if ($i == 5) {
$status |= spawn("cvs -z3 -q -f up -l -d $dirlist\n");
$dirlist = "";
$i=0;
}
}
if ($i) {
$status |= spawn("cvs -z3 -q -f up -l -d $dirlist\n");
}
}
else {
print "No directories to update.\n";
}
close CHECKINS;
if ($status == 0) {
set_last_update_time($filename, $start_time);
print "successfully updated ";
}
else {
print "error while updating ";
}
if ($module ne "all") {
print "$module/";
}
if (scalar(@dirs) > 0) {
print $dir_string;
}
print "\n";
exit $status;
sub cvs_up_parent {
my ($dir) = @_;
my $pdir = $dir;
$pdir =~ s|/*[^/]*/*$||;
#$pdir =~ s|/$||;
#$pdir =~ s|[^/]*$||;
#$pdir =~ s|/$||;
if (!$pdir) {
$pdir = '.';
}
if (!-d $pdir) {
cvs_up_parent($pdir);
}
$status |= system "cvs -z3 -q -f up -d -l $pdir\n";
}
sub get_hours_since_last_update {
# get the last time this command was run
my $last_time = get_last_update_time($filename);
if (!defined($last_time)) {
#
# This must be the first use of fast-update.pl so use the timestamp
# of a file that:
# 1) is managed by cvs
# 2) the user should not be tampering with
# 3) that gets updated fairly frequently.
#
$last_time = (stat "CVS/Entries")[9];
if (defined($last_time)) {
$last_time -= 3600*24; # for safety go back a bit
print "use fallback time of ".localtime($last_time)."\n";
}
}
if(!defined($last_time)) {
print "last_time not defined\n";
}
# figure the hours (rounded up) since the last fast-update
my $hours = int(($start_time - $last_time + 3600)/3600);
print "last updated $hours hour(s) ago at ".localtime($last_time)."\n";
return $hours;
}
# returns time of last update if known
sub get_last_update_time {
my ($filename) = @_;
if (!-r $filename) {
return undef;
}
open FILE, "<$filename";
my $line = <FILE>;
if (!defined(line)) {
return undef;
}
# print "line = $line";
$line =~ /^(\d+):/;
return $1;
}
sub set_last_update_time {
my ($filename, $time) = @_;
my $time_str = localtime($time);
open FILE, ">$filename";
print FILE "$time: last fast-update.pl at ".localtime($time)."\n";
}
# URL-encode data
sub escape {
my ($toencode) = @_;
$toencode=~s/([^a-zA-Z0-9_.-])/uc sprintf("%%%02x",ord($1))/eg;
return $toencode;
}
sub spawn {
my ($procname) = @_;
return system "$procname";
}