Index: head/Tools/scripts/bump_revision.pl =================================================================== --- head/Tools/scripts/bump_revision.pl (revision 506465) +++ head/Tools/scripts/bump_revision.pl (revision 506466) @@ -1,213 +1,286 @@ -#!/usr/bin/env perl +#!/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 envionment, for security reasons, and is considered +# good Perl practice. +# +# You must use either the -l (shaLlow, avoid grandparent dependencies, +# slower) or -g option (include grandparend dependencies) option. +# # MAINTAINER= mandree@FreeBSD.org # -use Getopt::Std; use strict; -use warnings; +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/; +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 </] - -c - Just check - -n - No tmpdir, just use dirname(INDEX) - -u - Your freebsd.org username. Defaults to \$ENV{USER}. - -i - Use this for INDEX name. Defaults to /usr/ports/INDEX. +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 - 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 - Set portsdir, if different from /usr/ports. -Improvements, suggestions,questions -> gerald\@FreeBSD.org +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"); + 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 $INDEX = "/usr/ports/INDEX"; -my $USER = $ENV{USER}; +my $osversion = `uname -r`; +chomp $osversion; +$osversion =~ s/\..*//; + +my $shallow = 0; +my ($portsdir, $INDEX); { $opt_i = ""; $opt_u = ""; - getopts("cni: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); - $USER = $opt_u if ($opt_u); + if (!-f $INDEX) { $INDEX = "$portsdir/INDEX"; } - die "$INDEX doesn't seem to exist. Please check the value supplied with -i or use -i." unless(-f $INDEX); + die "$INDEX doesn't seem to exist. Please check the value supplied with -i, or use -i /path/to/INDEX." unless(-f $INDEX); } -my $PORT = $ARGV[0]; -usage() unless($PORT); +usage() unless(@ARGV); -my $CVSROOT = $ENV{CVSROOT} // ':ext:$USER\@pcvs.freebsd.org:/home/pcvs'; +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); - foreach my $line (@lines) { - my @a = split(/\|/, $line); - my @b = split(/\//, $a[1]); + my @a; + my @b; + my $port; + map { + @a = split(/\|/, $_); + @b = split(/\//, $a[1]); - my $port = $b[-2]."/".$b[-1]; + $port = $b[-2]."/".$b[-1]; - $index{$port}{portname} = $b[-1]; - $index{$port}{portnameversion} = $a[0]; - $index{$port}{portdir} = $a[1]; - $index{$port}{comment} = $a[3]; - $index{$port}{deps} = (); + @{ $index{$port} }{'portname', 'portnameversion', 'portdir', 'comment', 'deps'} + = ($b[-1], $a[0], $a[1], $a[3], ()); if ($a[8]) { @b = split(" ", $a[8]); - foreach my $b (@b) { - $index{$port}{deps}{$b} = 1; - } + @{ $index{$port}{deps} }{@b} = (1) x @b; } - } - my @k = keys(%index); - print "- Processed ", $#k+1, " entries.\n"; + + } @lines; + print "- Processed ", scalar keys(%index), " entries.\n"; } -# -# See if the port does really exists. -# If specified as category/portname, that should be enough. -# If specified as portname, check all indexes for existence or duplicates. -# -unless (defined $index{$PORT}) { - my $count = 0; - my $n = ""; - foreach my $p (keys(%index)) { - if ($p =~ /\/$PORT$/) { - $n .= " " if ($n); - $n .= $p; - $count++; +my %DEPPORTS = (); + +foreach my $PORT (@ARGV) { + # + # See if the port does 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"; } } - if ($count == 0) { - die "Cannot find ${PORT} in ${INDEX}."; - } elsif ($count == 1) { - $PORT = $n; - } else { - die "Found ${PORT} more than once in ${INDEX}: $n. Try category/portname."; + + 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"; + + foreach my $p (keys(%index)) { + if (defined $index{$p}{'deps'}{$PORTNAMEVERSION}) { + $DEPPORTS{$p} = 1; + } + } + print "- Found ", scalar keys(%DEPPORTS), " ports depending on $PORT.\n"; } } -my $PORTNAMEVERSION = $index{$PORT}{portnameversion}; -print "Found $PORT as $PORTNAMEVERSION\n"; - # -# Figure out all the ports depending on this one. +# In shallow mode, strip all those who don't have a direct dependency # -my %DEPPORTS = (); -my $ports = ""; -{ - print "Searching for ports depending on $PORT\n"; - foreach my $p (keys(%index)) { - if (defined $index{$p}{deps}{$PORTNAMEVERSION}) { - $DEPPORTS{$p} = 1; - $ports .= " " if ($ports); - $ports .= "ports/$p"; +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 = ; + chomp @lines; + my $deps = join(" ", @lines); + my %deps = map { $_ =~ s[/usr/ports/][]; ($_ => 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}; } } - my @k = keys(%DEPPORTS); - print "- Found ", $#k+1, " ports depending on it.\n"; + 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) # - -my $TMPDIR = File::Basename::dirname($INDEX); -unless ($opt_n) { - $TMPDIR = getcwd() . "/.tmpdir.$$"; +unless ($opt_n or $opt_c) { + $TMPDIR = ".bump_revsion_pl_tmpdir.$$"; + print "svn checkout into $TMPDIR...\n"; mkdir($TMPDIR, 0755); chdir($TMPDIR); - system "cvs -d $CVSROOT co -T $ports"; - 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 (keys(%DEPPORTS)) { + 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 <