#!/usr/bin/perl -w ######################################################################## # # prtsweep # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # This is a script for removing rubbish from a CRUX port tree. # Distributed under the terms of the GPL license. # # Partial Changelog: # 1.2.1 - First rewrite in perl # 1.2 - Added support for renamed sources # 1.1.3 - Replace .md5sum with .signature in the KEEP_FILES list # ######################################################################## use strict; use Cwd qw(cwd getcwd); use File::Path; our $version = "1.2.1"; our %options = ( auto => 0, dryrun => 0, rmdir => 0, pkgtoo => 0, quiet => 0 ); our @portdirs; our $argports; sub print_usage { print <) { if (/^SHA256 \(.+\) =.*$/) { $_ =~ s/^SHA256 \((.+)\) =.*$/$1/; push (@signed, $_) } } close (FILE); return @signed ; } sub rm_emptydir { my $port = shift; my $nf = shift; my $msg = ($options{rmdir}==1) ? "\n": " use -d to remove empty directories.\n"; my $modal = ($options{dryrun}==1) ? "would be" : ""; $msg = ($nf == 0) ? "$msg $port: empty directory $modal deleted.\n" : "$msg cannot remove $port: directory not empty\n"; print $msg; rmdir ($port) if (($nf == 0) and ($options{dryrun} == 0)); } sub sweep { my $port = shift; while ($port =~ s/\/\//\//g) {} $port =~ s/\/$//; my @path = split /\//, $port; print "=======> $port\n" unless $options{quiet}==1; my @wanted = parse_signature ("$port/.signature"); my $builtpkg=($options{pkgtoo} != 1) ? $path[-1].'#.*pkg\.tar.*' : 'ReallyLongStringThatWouldNeverMatchAnyBuiltPackage'; $builtpkg =~ s/\+/\\\+/; opendir (DIR, $port) or return; foreach my $f (sort(readdir(DIR))) { next if ( $f eq "." or $f eq ".." ); $f =~ s/\+/\\\+/; # plus sign in filenames interferes with regex search if ((grep /$f/, @wanted) >= 1 or ($f =~ /$builtpkg/)) { print "... keeping file $port/$f.\n" unless $options{quiet} == 1; } else { my $ft=remove_notify("$port/$f"); remove_forreal("$port/$f", $ft) if $options{dryrun} == 0; } } closedir (DIR); } sub remove_notify { my $path=shift; my $type = (-d $path) ? "directory" : "file"; my $append = ($options{dryrun}==1) ? "(dry run)\n" : "\n"; print "+ removing $type $path $append"; return $type; } sub remove_forreal { my $path = shift; my $type = shift; if ($type eq "file") { unlink "$path" or return; } else { rmtree ($path,0,1); } } sub do_sweep { my $port = shift; my $nf = 0; if (! -f "$port/.signature") { opendir (PORTDIR,$port) or die "cannot open $port for reading\n"; foreach my $f (readdir PORTDIR) { next if ($f eq '.' or $f eq '..'); $nf += 1; } closedir (PORTDIR); print "no signature file, $port does not define a valid port."; rm_emptydir($port,$nf); } else { sweep($port); } } sub getportdirs { my $collection; my @basedirs; my $portetc = "/etc/ports/"; opendir (PORTS_DEFS,$portetc) or die "cannot open $portetc for reading"; foreach (readdir PORTS_DEFS) { next if ($_ eq '.' or $_ eq '..'); if (/.*(rsync|httpup)$/) { open SYNC, $portetc.$_ or die "cannot open $portetc.$_"; while () { $collection=$2 if /^(destination|ROOT_DIR)=(.+)$/; } close SYNC; push (@basedirs , $collection); } elsif (/.*git$/) { open SYNC, $portetc.$_ or die "cannot open $portetc.$_"; while () { $collection="/usr/ports/$1" if /^NAME=(.+)$/; } close SYNC; push (@basedirs , $collection); } else {} } closedir PORTS_DEFS; return @basedirs ; } # main parse_args(); print_usage() if ((2*$argports-1)*(1-2*$options{auto}) < 0); if ($options{auto} == 1) { my @basedirs = getportdirs(); foreach my $collection (@basedirs) { print "====> Sweeping port collection $collection\n"; foreach my $port (list_subdirs($collection)) { do_sweep($port); } } } else { foreach my $port (@portdirs) { do_sweep($port); } }