diff options
author | Stefan Walter <stefan@FreeBSD.org> | 2007-10-21 08:29:06 +0000 |
---|---|---|
committer | Stefan Walter <stefan@FreeBSD.org> | 2007-10-21 08:29:06 +0000 |
commit | 38a5e7305589c35165668250f5d1d734d15c089b (patch) | |
tree | 40ec348c82802faca297a0a21cd0853e5a50c714 /ports-mgmt/pkg_cutleaves | |
parent | 60319e71da734afe7e82f41e9c4dfcd9b3c9452d (diff) | |
download | ports-38a5e7305589c35165668250f5d1d734d15c089b.tar.gz ports-38a5e7305589c35165668250f5d1d734d15c089b.zip |
Notes
Diffstat (limited to 'ports-mgmt/pkg_cutleaves')
-rw-r--r-- | ports-mgmt/pkg_cutleaves/Makefile | 30 | ||||
-rw-r--r-- | ports-mgmt/pkg_cutleaves/distinfo | 3 | ||||
-rw-r--r-- | ports-mgmt/pkg_cutleaves/files/pkg_cutleaves | 324 | ||||
-rw-r--r-- | ports-mgmt/pkg_cutleaves/files/pkg_cutleaves.1 | 140 |
4 files changed, 478 insertions, 19 deletions
diff --git a/ports-mgmt/pkg_cutleaves/Makefile b/ports-mgmt/pkg_cutleaves/Makefile index 1ae29e945ce4..b9a182005173 100644 --- a/ports-mgmt/pkg_cutleaves/Makefile +++ b/ports-mgmt/pkg_cutleaves/Makefile @@ -6,9 +6,10 @@ # PORTNAME= pkg_cutleaves -PORTVERSION= 20061113 +PORTVERSION= 20071021 CATEGORIES= ports-mgmt -MASTER_SITES= http://www.gegenunendlich.de/projects/${PORTNAME}/ +MASTER_SITES= # none +DISTFILES= # none MAINTAINER= stefan@FreeBSD.org COMMENT= Interactive script for deinstalling 'leaf' packages @@ -16,29 +17,26 @@ COMMENT= Interactive script for deinstalling 'leaf' packages NO_BUILD= yes USE_PERL5= yes -WRKSRC= ${WRKDIR}/${PORTNAME} +WRKSRC= ${WRKDIR} MAN1= pkg_cutleaves.1 PLIST_FILES= sbin/pkg_cutleaves +do-extract: + ${MKDIR} ${WRKSRC} + ${CP} ${FILESDIR}/pkg_cutleaves ${FILESDIR}/pkg_cutleaves.1 ${WRKSRC} + post-patch: @${REINPLACE_CMD} -e \ 's,/usr/local/etc/pkg_leaves.exclude,${PREFIX}/etc/pkg_leaves.exclude,' \ ${WRKSRC}/pkg_cutleaves.1 - @${REINPLACE_CMD} -e \ - 's,/usr/local/etc/pkg_leaves.exclude,${PREFIX}/etc/pkg_leaves.exclude,' \ - ${WRKSRC}/pkg_cutleaves - @${REINPLACE_CMD} -e \ - 's,/usr/sbin/pkg_delete,${PKG_DELETE},' \ - ${WRKSRC}/pkg_cutleaves - @${REINPLACE_CMD} -e \ - 's,/usr/local/sbin/pkgdb,${LOCALBASE}/sbin/pkgdb,' \ - ${WRKSRC}/pkg_cutleaves - @${REINPLACE_CMD} -e \ - 's,/var/db/pkg,${PKG_DBDIR},' \ - ${WRKSRC}/pkg_cutleaves - @${REINPLACE_CMD} -e 's,/usr/bin/perl,${PERL},' \ + @${REINPLACE_CMD} \ + -e 's,/usr/local/etc/pkg_leaves.exclude,${PREFIX}/etc/pkg_leaves.exclude,' \ + -e 's,/usr/sbin/pkg_delete,${PKG_DELETE},' \ + -e 's,/usr/local/sbin/pkgdb,${LOCALBASE}/sbin/pkgdb,' \ + -e 's,/var/db/pkg,${PKG_DBDIR},' \ + -e 's,/usr/bin/perl,${PERL},' \ ${WRKSRC}/pkg_cutleaves do-install: diff --git a/ports-mgmt/pkg_cutleaves/distinfo b/ports-mgmt/pkg_cutleaves/distinfo deleted file mode 100644 index 3cf70827a11e..000000000000 --- a/ports-mgmt/pkg_cutleaves/distinfo +++ /dev/null @@ -1,3 +0,0 @@ -MD5 (pkg_cutleaves-20061113.tar.gz) = 5a8f40683f33aaabdfb2215a36c7747c -SHA256 (pkg_cutleaves-20061113.tar.gz) = 130795f1abe381c3a80c3f1af9ffa95fdd4268f9ffeb9d0cf097d1698d0b73c7 -SIZE (pkg_cutleaves-20061113.tar.gz) = 5997 diff --git a/ports-mgmt/pkg_cutleaves/files/pkg_cutleaves b/ports-mgmt/pkg_cutleaves/files/pkg_cutleaves new file mode 100644 index 000000000000..ca52bbecefab --- /dev/null +++ b/ports-mgmt/pkg_cutleaves/files/pkg_cutleaves @@ -0,0 +1,324 @@ +#!/usr/bin/perl +# +# Copyright (c) 2003 Stefan Walter <sw@gegenunendlich.de> +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +# Interactive script for deinstalling "leaf" packages +# +# Syntax: pkg_cutleaves [-cFgLlRx] +# Options: +# -c: Show comments, too; only works with '-l' (ignored otherwise) +# -F: Fix package db after each deinstallation run (via 'pkgdb -F') +# -g: Generate exclude list from kept/installed leaf packages +# -L: Interpret exclude file as list of packages that *should* be installed +# -l: List leaf packages only, don't ask if they should be deinstalled +# -R: Autoprune new leaves +# -x: Honor exclude list in $excludefile + +use Getopt::Std; +use strict; + +my $dbdir = "/var/db/pkg"; +my $excludefile = "/usr/local/etc/pkg_leaves.exclude"; +my $pkgdeinstall = "/usr/sbin/pkg_delete"; +my @pkgdb_args = ("/usr/local/sbin/pkgdb", "-F"); +my $exclpattern; +my %leavestokeep; +my %opt; + +getopts('cFgLlRx', \%opt); +set_excl_pattern(); + +# LIST MODE +if ($opt{l}) { + # Just print out the list of leaves, one per line + my %leaves = get_leaves(); + foreach my $leaf (sort keys %leaves) { + if ($opt{c}) { + print "$leaf - $leaves{$leaf}\n"; + } + else { + print "$leaf\n"; + } + $leavestokeep{$leaf} = 1; + } +} +# LINT MODE +elsif ($opt{L}) { + my @excludes = get_excludelist(); + my @pkgs = get_packages(); + # For each installed package + for my $pkg (@pkgs) { + my ($file, $required) = @$pkg; + # Clobber any exclude patterns that match this package + for (my $i = 0; $i < @excludes; $i++) { + if ($file =~ /\Q@excludes[$i]\E/) { + splice(@excludes, $i--, 1); + } + } + # If matches exclude list and is not a leaf + if ($required && ($file =~ $exclpattern)) { + print "$file matches exclude list, but is not a leaf\n" + } + else { + $leavestokeep{$file} = 1; + } + } + # In exclude list, but not installed + # For each remaining entry in exclude list + foreach my $exclude (@excludes) { + print "Exclude pattern '$exclude' matches no installed packages\n"; + } +} +# INTERACTIVE MODE +else { + my @cutleaves; + my ($i, $again); + + # Get list of leaf packages and put them into a hash + my %leaves = get_leaves(); + # Any leaves to work with? + my $nleaves = keys %leaves; + if ($nleaves > 0) { + # If we don't have superuser rights, notify the user. + if ($< != 0) { + print "You need to have root permissions for deinstalling packages.\n"; + $again = 'n'; + } + else { + $again = 'y'; + } + } + else { + # If not, don't go on, there's nothing to do. + print "** Didn't find any leaves to work with, exiting.\n"; + print "** If this is unexpected, check your exclude file, please.\n"; + $again = 'n'; + } + # Loop while the user wants to + ROUND: while($again eq 'y') { + # Always start with an empty list of leaves to cut + my %leavestocut; + # Initialize counter for progress status + $i = 1; + + LEAVESLOOP: foreach my $leaf (sort keys %leaves) { + print "Package $i of $nleaves:\n"; + print "$leaf - $leaves{$leaf}\n"; + print "$leaf - [keep]/(d)elete/(f)lush marked pkgs/(a)bort? "; + # Get first character of input, without leading whitespace + my ($answer) = (lc(<STDIN>) =~ m/(\S)/); + if ($answer eq 'd') { + print "** Marking $leaf for removal.\n\n"; + $leavestocut{$leaf} = 1; + } + elsif ($answer eq 'f') { + print "\n"; + last LEAVESLOOP; + } + elsif ($answer eq 'a') { + print "\n"; + $opt{aborted} = 1; + last ROUND; + } + else { + print "** Keeping $leaf.\n\n"; + $leavestokeep{$leaf} = 1; + } + $i++; + } # LEAVESLOOP + + AUTOPRUNE: # The -R switch jump + # Initialize 'progress meter' + my $ncuts = keys %leavestocut; + my $noff = 0; + # loop through packages marked for removal and pkg_deinstall them + foreach my $leaf (sort keys %leavestocut) { + $noff++; + print "Deleting $leaf (package $noff of $ncuts).\n"; + my @deinstall_args = ($pkgdeinstall, $leaf); + if ((my $status = system(@deinstall_args) >> 8) != 0) { + print STDERR "\n\n$0: pkg_deinstall returned $status - exiting, fix this first.\n\n"; + last ROUND; + } + push @cutleaves, $leaf; + } + + # Run 'pkgdb -F' if requested + if ($opt{F}) { + print "Running 'pkgdb -F'.\n"; + if ((my $status = system(@pkgdb_args) >> 8) != 0) { + print STDERR "\n\n$0: pkgdb returned $status - exiting, fix this first.\n\n"; + last ROUND; + } + } + + # Get new list of leaf packages and put them into a hash + %leaves = get_leaves(); + + # Ignore all leaves the user already told us to keep + foreach my $leaf (keys %leavestokeep) { + delete $leaves{$leaf} + } + + # Any leaves left? + $nleaves = keys %leaves; + if ($nleaves == 0) { + # If not, don't go on, there's nothing left to do. + print "** Didn't find any new leaves to work with, exiting.\n"; + last ROUND; + } + + if ($opt{R}) { # start autopruning new leaves + print "\n** Autopruning new leaves (Ctrl-C now to stop!) **\n" x 2; + sleep 1; + %leavestocut = %leaves; + goto AUTOPRUNE; + } # AUTOPRUNE + + print "Go on with new leaf packages ((y)es/[no])? "; + # Get first character of input, without leading whitespace + ($again) = (lc(<STDIN>) =~ /(\S)/o); + print "\n"; + } # ROUND + + # print list of removed packages, sorted lexically, and their number + print "** Deinstalled packages:\n"; + foreach my $cutleaf (sort @cutleaves) { + print "$cutleaf\n"; + } + my $noff = @cutleaves; + print "** Number of deinstalled packages: $noff\n"; +} + +# Generate exclude file +if ($opt{g}) { + if ($opt{aborted}) { + die "\n** Skipping exclude file generation on aborted session **\n"; + } + if (-e $excludefile) { + print "\nExclude file ($excludefile) exists! Overwrite ((y)es/[no])? "; + my $answer = <STDIN>; + unless ($answer =~ /^y(es)?$/io) { + exit 0; + } + } + create_excludelist(); +} + +# +# Set the exclude pattern +# +sub set_excl_pattern { + my @excludes = get_excludelist(); + $exclpattern = @excludes + ? join('|', map{qr(\Q$_\E)} @excludes) + : ' '; # default non-exclusive + $exclpattern = qr{^($exclpattern)}o; +} + +# +# Read the exclude list if the file exists +# Parameter: path of the exclude file +# +sub get_excludelist { + my @excludelist; + # XXX: Don't check command line params in a subroutine + if (($opt{x} || $opt{L}) && -f $excludefile && -T $excludefile) { + open(EXCLFILE, $excludefile) + or die "Couldn't open $excludefile!"; + while(my $exclude = <EXCLFILE>) { + chomp($exclude); + # Ignore comments and empty lines, add others to the list + unless ($exclude =~ /(^ *#)|(^ *$)/o) { + push(@excludelist, $exclude); + } + } + close(EXCLFILE) + or warn "Failed to close exclude file ($excludefile): $!\n"; + } + return @excludelist; +} + +# +# Return a list of all packages +# +sub get_packages { + my @pkgs; + opendir(DBDIR, $dbdir) + or die "Can't open package db directory $dbdir!"; + while (defined(my $file = readdir(DBDIR))) { + my $path = join('/', $dbdir, $file); + unless ($file =~ /^\.+$/o || !(-d $path)) { + push @pkgs, [$file, -s $path . '/+REQUIRED_BY', join('/', $path, '+COMMENT')]; + } + } + closedir DBDIR; + return @pkgs; +} + +# +# Get a hash (name => comment) of all leaves +# +sub get_leaves { + my %leaves; + my @pkgs = get_packages(); + foreach my $pkg (@pkgs) { + my ($file, $required, $commentfile) = @$pkg; + unless ($required) { + if ($file =~ $exclpattern) { + $leavestokeep{$file} = 1; + } + else { + # Read package's short description/comment + my $comment; + if ((-s $commentfile) && (open(COMMENT, $commentfile))) { + chomp($comment = <COMMENT>); + } + else { + $comment = 'No short description'; + } + $leaves{$file} = $comment; + } + } + } + return %leaves; +} + +# +# Write the list of exclusions to a file +# +sub create_excludelist { + open(EXCLFILE, ">$excludefile") + or die "Failed to open exclude list ($excludefile): $!\n"; + print EXCLFILE '# Auto-generated exclude list ', scalar localtime, "\n"; + for (sort keys %leavestokeep) { + /^(.+)-\d.+$/o + ? print EXCLFILE $1, "\n" + : warn 'Unable to extract exclude pattern from ', $_, "\n"; + } + print "New exclude list ($excludefile) generated.\n"; +} + diff --git a/ports-mgmt/pkg_cutleaves/files/pkg_cutleaves.1 b/ports-mgmt/pkg_cutleaves/files/pkg_cutleaves.1 new file mode 100644 index 000000000000..b184cf88ee73 --- /dev/null +++ b/ports-mgmt/pkg_cutleaves/files/pkg_cutleaves.1 @@ -0,0 +1,140 @@ +.\" PKG_CUTLEAVES 1 "Jul 2003" FreeBSD +.\" +.Dd July 27, 2003 +.Dt PKG_CUTLEAVES 1 +.Os FreeBSD +.Sh NAME +.Nm pkg_cutleaves +.Nd deinstall 'leaf' packages +.Sh SYNOPSIS +.Nm +.Op Fl cFglRx +.Sh DESCRIPTION +.Nm pkg_cutleaves +finds installed +.Dq Li "leaf" +packages, i.e. packages that are not referenced by any other installed package, +and lets you decide for each one if you want to keep or deinstall it (via +pkg_delete(1)). Once the packages marked for removal have been +flushed/deinstalled, you'll be asked if you want to do another run (i.e. to see +packages that have become 'leaves' now because you've deinstalled the package(s) +that depended on them. +.Ar Note: +see +.Fl R +below to bypass interactive dependency removal). In every run you will be shown +only packages that you haven't marked for keeping, yet. +.Pp +Note that your package registry database should be up to date for this +to work properly, so it might be a good idea to run pkgdb(1) before +running +.Nm . +.Sh OPTIONS +.Pp +The following command line arguments are supported: +.Pp +.Bl -tag -width "-R" -compact +.It Fl c +When listing leaf packages, also print their comments/short +descriptions. Will be ignored unless the +.Fl l +parameter is given, too. +.Pp +.It Fl F +Run +.Dq Li "pkgdb -F" +after each deinstallation run, to make sure the package registry database +is up to date. ( +.Ar Note: +This is mostly for convenience; it shouldn't be necessary to run +.Dq Li "pkgdb -F" +after each run, but it doesn't hurt, either.) +.Pp +.It Fl L +Interpret exclude file as a list of leaf packages that +.Ar should +be installed. Report lint such as lines that match no installed packages +or excluded packages that are not leaves. +.Pp +.It Fl g +Generate the exclude list from kept or installed (when run with +.Fl l +or +.Fl L ) +leaf packages. +.Pp +.It Fl l +List leaf packages only, one per line, and don't ask for anything to be +deinstalled. +.Pp +.It Fl R +Autoprune mode. Automatically deinstall non-required packages on which +the removed leaf packages depended. Will not remove packages on the +exclude list if +.Fl x +is also in effect. +.Pp +.It Fl x +Exclude packages matching expressions given in the exclude file. +.El +.Sh EXAMPLES +.Pp +.Bl -bullet +.It +Interactively cut leaf packages using the current exclude list: +.Pp +.Dl pkg_cutleaves -x +.Pp +.It +List all current leaf packages with comments: +.Pp +.Dl pkg_cutleaves -lc +.Pp +.It +List packages not currently excluded and regenerate a new exclude file +with both the listed and previously excluded packages: +.Pp +.Dl pkg_cutleaves -lxg +.Pp +.It +Interactively cut current leaf packages and remove newly discovered leaves, +i.e. dependencies, automatically: +.Pp +.Dl pkg_cutleaves -R +.Pp +.It +The same as the previous example but use the current exclude list to filter +all first-level leaves and any newly discovered leaves. Generate a new +exclude file with the remaining leaves: +.Pp +.Dl pkg_cutleaves -Rxg +.Pp +.It +Find exclude patterns that match nothing and those that match required packages, +i.e. non-leaves: +.Pp +.Dl pkg_cutleaves -L +.El +.Sh FILES +.Bl -tag +.It Pa /usr/local/etc/pkg_leaves.exclude +An optional list for excluding packages when the +.Fl x +or +.Fl L +options are given. If the beginning of a package's name matches any line (except +comment or empty lines) in this file, the package will not be +listed/offered for removal (e.g., a line saying just +.Ar XFree86 +will exclude all packages with names starting with +.Dq Li "XFree86" +). The list can be auto-generated with the +.Fl g +option. +.El +.Sh SEE ALSO +.Xr pkg_deinstall 1 , +.Xr pkgdb 1 , +.Xr portsclean 1 +.Sh AUTHOR +.An Stefan Walter <sw@gegenunendlich.de> |