- When using a non-default ports tree (-p PATH), strip that from the requisite origins, too. - Fix the counters when multiple ports are given on the command line, i. e. we are bumping depends if more requisites are updated at once.
289 lines
7.5 KiB
Perl
Executable File
289 lines
7.5 KiB
Perl
Executable File
#!/usr/bin/env perl -wT
|
|
|
|
# $FreeBSD$
|
|
|
|
#
|
|
# This script helps with bumping the PORTREVISION of all ports that depend on a
|
|
# set of ports, for instance, when in the latter set one of the ports bumped the
|
|
# .so library version.
|
|
#
|
|
# It is best executed with the working directory set to the base of a
|
|
# ports tree, such as /usr/ports.
|
|
#
|
|
# The shebang line above includes -T (taint) to be more distrustful
|
|
# about the environment, for security reasons, and is considered
|
|
# good Perl practice.
|
|
#
|
|
# You can use either the -l (shaLlow, avoid grandparent dependencies,
|
|
# slower) or -g option (include grandparent dependencies) option.
|
|
#
|
|
# MAINTAINER= mandree@FreeBSD.org
|
|
#
|
|
|
|
use strict;
|
|
use Getopt::Std;
|
|
use Carp 'verbose';
|
|
use Cwd;
|
|
use Data::Dumper;
|
|
use File::Basename;
|
|
|
|
use vars qw/$opt_c $opt_n $opt_i $opt_u $opt_l $opt_g $opt_p/;
|
|
|
|
# launder environment
|
|
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
|
|
$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin';
|
|
|
|
sub usage {
|
|
print <<EOF;
|
|
Usage: $0 [options] [<category>/]<portname>
|
|
|
|
Options:
|
|
-l - shaLlow, only bump ports with direct dependencies.
|
|
-g - Grandchildren, also bump for indirect dependencies (default).
|
|
-c - Check only (dry-run), do not change Makefiles.
|
|
-n - No tmpdir, just use the directory where INDEX resides.
|
|
-i <filename> - Use this for INDEX name. Defaults to \${PORTSDIR}/INDEX-n,
|
|
where n is the major version of the OS, or \${PORTSDIR}/INDEX if missing.
|
|
-p <dirname> - Set portsdir, if different from /usr/ports.
|
|
|
|
Improvements, suggestions,questions -> mandree\@FreeBSD.org
|
|
EOF
|
|
exit 1;
|
|
}
|
|
|
|
# flush STDOUT for each and every write even if writing to a pipe.
|
|
$| = 1;
|
|
|
|
sub bumpMakefile {
|
|
|
|
my ($p) = @_;
|
|
|
|
my $makefile = "$p/Makefile";
|
|
my $fin;
|
|
unless(open($fin, $makefile)) {
|
|
print "-- Cannot open Makefile of $p, ignored.\n";
|
|
next;
|
|
}
|
|
my @lines = <$fin>;
|
|
if ($!) { die "Error while reading $makefile: $!. Aborting"; }
|
|
close($fin) or die "Can't close $makefile b/c $!";
|
|
chomp(@lines);
|
|
|
|
my $revision = 1;
|
|
|
|
foreach my $line (@lines) {
|
|
last if ($line =~ /^MAINTAINER/);
|
|
$revision += $1 if ($line =~ /PORTREVISION\??=[ \t]*(\d+)$/);
|
|
}
|
|
|
|
my $printedrev = 0;
|
|
open(my $fout, '>', "$makefile.bumped");
|
|
foreach my $line (@lines) {
|
|
if (!$printedrev) {
|
|
if ($line =~ /^CATEGORIES??=/ || $line =~ /^PORTEPOCH??=/) {
|
|
print $fout "PORTREVISION= $revision\n";
|
|
$printedrev = 1;
|
|
# Fall through!
|
|
}
|
|
if ($line =~ /^PORTREVISION\?=/) {
|
|
print $fout "PORTREVISION?= $revision\n";
|
|
$printedrev = 1;
|
|
next;
|
|
}
|
|
if ($line =~ /^PORTREVISION=/) {
|
|
print $fout "PORTREVISION= $revision\n";
|
|
$printedrev = 1;
|
|
next;
|
|
}
|
|
}
|
|
print $fout "$line\n";
|
|
}
|
|
close($fout) or die "Can't close $makefile b/c $!";
|
|
rename "$makefile.bumped", $makefile or die "Can't rename $makefile.bumped to $makefile: $!";
|
|
}
|
|
|
|
my $osversion = `uname -r`;
|
|
chomp $osversion;
|
|
$osversion =~ s/\..*//;
|
|
|
|
my $shallow = 0;
|
|
my ($portsdir, $INDEX);
|
|
{
|
|
$opt_i = "";
|
|
$opt_u = "";
|
|
getopts("cgi:lnu:p:");
|
|
$shallow = $opt_l if $opt_l;
|
|
if ($opt_l and $opt_g) {
|
|
die "Options -g and -l given, which are mutually exclusive. Pick either.";
|
|
}
|
|
if (not $opt_l and not $opt_g) {
|
|
warn "Neither -g nor -l given. Defaulting to -g";
|
|
$opt_g = 1;
|
|
}
|
|
$portsdir = $opt_p ? $opt_p : '/usr/ports';
|
|
|
|
$INDEX = "$portsdir/INDEX-$osversion";
|
|
$INDEX = $opt_i if ($opt_i);
|
|
if (!-f $INDEX) { $INDEX = "$portsdir/INDEX"; }
|
|
|
|
die "$INDEX doesn't seem to exist. Please check the value supplied with -i, or use -i /path/to/INDEX." unless(-f $INDEX);
|
|
}
|
|
usage() unless(@ARGV);
|
|
|
|
my $TMPDIR = File::Basename::dirname($INDEX);
|
|
|
|
#
|
|
# Sanity checking
|
|
#
|
|
if (-d "$TMPDIR/.svn" and not $opt_n and not $opt_c) {
|
|
die "$TMPDIR/.svn exists, cowardly refusing to proceed.\n";
|
|
}
|
|
|
|
#
|
|
# Read the index, save some interesting keys
|
|
#
|
|
my %index = ();
|
|
{
|
|
print "Reading $INDEX\n";
|
|
open(my $fin, '<', "$INDEX") or die "Cannot open $INDEX for reading.";
|
|
my @lines = <$fin>;
|
|
if ($!) { die "Error while reading $INDEX: $! Aborting"; }
|
|
chomp(@lines);
|
|
close($fin);
|
|
|
|
my @a;
|
|
my @b;
|
|
my $port;
|
|
map {
|
|
@a = split(/\|/, $_);
|
|
@b = split(/\//, $a[1]);
|
|
|
|
$port = $b[-2]."/".$b[-1];
|
|
|
|
@{ $index{$port} }{'portname', 'portnameversion', 'origin', 'comment', 'deps'}
|
|
= ($b[-1], $a[0], $port, $a[3], ());
|
|
|
|
if ($a[8]) {
|
|
@b = split(" ", $a[8]);
|
|
@{ $index{$port}{deps} }{@b} = (1) x @b;
|
|
}
|
|
|
|
} @lines;
|
|
print "- Processed ", scalar keys(%index), " entries.\n";
|
|
}
|
|
|
|
my %DEPPORTS = ();
|
|
|
|
foreach my $PORT (@ARGV) {
|
|
#
|
|
# See if the port really exists.
|
|
# If specified as category/portname, that should be enough.
|
|
# If specified as portname, check all categories for existence or duplicates.
|
|
#
|
|
unless (defined $index{$PORT}) {
|
|
my @found = grep /\/$PORT$/, keys(%index);
|
|
my $count = @found;
|
|
|
|
if ($count == 0) {
|
|
die "Cannot find ${PORT} in ${INDEX}.";
|
|
} elsif ($count == 1) {
|
|
$PORT = $found[0];
|
|
} else {
|
|
my $n = join(" ", @found);
|
|
die "Found ${PORT} more than once in ${INDEX}: $n. Try category/$PORT.\nAborting";
|
|
}
|
|
}
|
|
|
|
my $PORTNAMEVERSION = $index{$PORT}{portnameversion};
|
|
print "Found $PORT as $PORTNAMEVERSION\n";
|
|
|
|
#
|
|
# Figure out all the ports depending on this one.
|
|
#
|
|
{
|
|
print "Searching for ports depending on $PORT\n";
|
|
my $count = 0;
|
|
|
|
foreach my $p (keys(%index)) {
|
|
if (defined $index{$p}{'deps'}{$PORTNAMEVERSION}) {
|
|
$DEPPORTS{$p} = 1;
|
|
++$count;
|
|
}
|
|
}
|
|
print "- Found $count ports depending on $PORT.\n";
|
|
}
|
|
}
|
|
|
|
#
|
|
# In shallow mode, strip all those who don't have a direct dependency
|
|
#
|
|
sub direct_dependency($@) {
|
|
my ($port, @requisites) = @_;
|
|
open F, '-|', '/usr/bin/make', '-C', $port, qw/-V _RUN_DEPENDS -V _LIB_DEPENDS/ or die "cannot launch make: $!";
|
|
my @lines = <F>;
|
|
chomp @lines;
|
|
my $deps = join(" ", @lines);
|
|
my %deps = map { $_ =~ s[/usr/ports/][]; $_ =~ s[$portsdir/][]; ($_ => 1) } split " ", $deps;
|
|
if ($!) { die "cannot read depends from make: $!"; }
|
|
close F or die "cannot read depends from make: $!";
|
|
my $required = grep { $_ } map { defined $deps{$_} } @requisites;
|
|
return $required;
|
|
}
|
|
|
|
if ($shallow) {
|
|
my $n = keys %DEPPORTS;
|
|
my $idx = 1;
|
|
foreach my $p (keys %DEPPORTS) {
|
|
print "- Checking requisites of port $idx/$n...\r";
|
|
++$idx;
|
|
unless (direct_dependency($p, @ARGV)) {
|
|
delete $DEPPORTS{$p};
|
|
}
|
|
}
|
|
print "- Found ", scalar keys(%DEPPORTS), " ports depending directly on either of @ARGV.\n";
|
|
}
|
|
|
|
my $ports = join(" ", keys %DEPPORTS);
|
|
|
|
#
|
|
# Create a temp directory and cvs checkout the ports
|
|
# (don't do error checking, too complicated right now)
|
|
#
|
|
unless ($opt_n or $opt_c) {
|
|
$TMPDIR = ".bump_revsion_pl_tmpdir.$$";
|
|
print "svn checkout into $TMPDIR...\n";
|
|
mkdir($TMPDIR, 0755);
|
|
chdir($TMPDIR);
|
|
system "svn checkout --depth=immediates svn+ssh://svn.freebsd.org/ports/head/ ports" and die "SVN checkout failed (wait value $?), aborting";
|
|
chdir('ports');
|
|
system "svn update --set-depth=infinity $ports" and die "SVN checkout failed (wait value $?), aborting";
|
|
}
|
|
|
|
#
|
|
# Bump portrevisions
|
|
#
|
|
{
|
|
print "Updating Makefiles\n";
|
|
foreach my $p (sort keys(%DEPPORTS)) {
|
|
print "- Updating Makefile of $p\n";
|
|
next if $opt_c;
|
|
bumpMakefile "$p";
|
|
}
|
|
}
|
|
|
|
#
|
|
# Commit the changes. Not automated.
|
|
#
|
|
unless ($opt_c) {
|
|
print <<EOF;
|
|
All PORTREVISIONs have been updated. You are nearly done, only one
|
|
thing remains: Committing to the ports tree. This program is not
|
|
going to do that for you, you have to do it manually.
|
|
|
|
\$ cd $TMPDIR
|
|
\$ svn commit
|
|
|
|
Then, remove the temp directory ($TMPDIR).
|
|
EOF
|
|
}
|