#!/usr/bin/perl eval "exec perl -S $0 $*" if $running_under_some_shell; # $Id: patclean.SH 1 2006-08-24 12:32:52Z rmanfredi $ # # Copyright (c) 1991-1997, 2004-2006, Raphael Manfredi # # You may redistribute only under the terms of the Artistic Licence, # as specified in the README file that comes with the distribution. # You may reuse parts of this distribution only within the terms of # that same Artistic Licence; a copy of which may be found at the root # of the source tree for dist 4.0. # # $Log: patclean.SH,v $ # Revision 3.0.1.2 1994/01/24 14:30:17 ram # patch16: now prefix error messages with program's name # patch16: added ~/.dist_profile awareness # # Revision 3.0.1.1 1993/08/19 06:42:33 ram # patch1: leading config.sh searching was not aborting properly # # Revision 3.0 1993/08/18 12:10:41 ram # Baseline for dist 3.0 netwide release. # $version = '3.5'; $patchlevel = '0'; $RCSEXT = ',v' unless $RCSEXT; $progname = &profile; # Read ~/.dist_profile require 'getopts.pl'; &usage unless $#ARGV >= 0; &usage unless &Getopts("ahnmV"); if ($opt_V) { print STDERR "$progname $version PL$patchlevel\n"; exit 0; } elsif ($opt_h) { &usage; } $RCSEXT = ',v' unless $RCSEXT; $ENV{'DIST'} = '/dev/null'; # Disable ~/.dist_profile chop($pwd = `pwd`) unless -f '.package'; until (-f '.package') { die "$progname: no .package file! Run packinit.\n" unless $pwd; chdir '..' || die "$progname: can't cd ..: $!\n"; $pwd =~ s|(.*)/(.*)|$1|; $prefix = $2 . '/' . $prefix; } if ($prefix) { for (@ARGV) { s/^/$prefix/ unless m|^[-/]|; } } # We now are at the top level &readpackage; if ($opt_n) { &newer; # Look for files newer than patchlevel.h } elsif ($opt_a) { open(MANI,"MANIFEST.new") || die "$progname: can't read MANIFEST.new: $!\n"; @ARGV = (); while () { s|^\./||; next if m|^patchlevel.h|; # This file is built by hand chop; ($_) = split(' '); next if -d; push(@ARGV,$_); } close MANI; } elsif ($opt_m) { open(MODS,"bugs/.mods$bnum") || die "$progname: no modification found.\n"; @ARGV = (); while () { next if m|^patchlevel.h$|; # This file is built by hand chop; ($_) = split(' '); push(@ARGV,$_); } close MODS; } # Set a temporary file for check outs $TMPFILE = "/tmp/cl$$.tmp"; # Now loop over each file specified, doing a 'rcsclean' foreach $file (@ARGV) { if (-f $file) { $files = &rcsargs($file); @files = split(' ', $files); $rlog = `rlog -rlastpat- $files 2>&1`; ($revs) = ($rlog =~ /selected revisions: (\d+)/); if (!$revs) { print "$progname: $file has never been checked in--checking in...\n"; system 'perl', '-S', 'patcil', '-p', $file; $revs = 2; # At least null trunk + new fresh revision } # Look whether there is a branch if ($revs == 1) { $rlog = `rlog -r$revbranch $files 2>&1`; ($revs) = ($rlog =~ /selected revisions: (\d+)/); $revs++; # add the base revision } # We must only give the name of the RCS revision file, i.e. $files[1] if ($revs == 1) { system "co -q -p$baserev $files[1] > $TMPFILE"; } else { system "co -q -p$revbranch $files[1] > $TMPFILE"; } if ($? == 0) { system 'cmp', '-s', $file, $TMPFILE; if ($? == 0) { unlink $file; print "$progname: $file removed.\n"; } else { # Check in file and make sure all was ok system 'perl', '-S', 'patcil', '-p', $file; system "co -q -p$revbranch $files[1] > $TMPFILE"; if ($? == 0) { system 'cmp', '-s', $file, $TMPFILE; if ($? == 0) { unlink $file; print "$progname: $file removed.\n"; } else { print "$progname: $file NOT removed.\n"; } } else { print "$progname: could not check out--$file NOT removed.\n"; } } } else { print "$progname: no revision--$file NOT removed.\n"; } } } unlink "$TMPFILE"; sub usage { print STDERR <.newer") || die "Can't create .newer.\n"; open(MANI,"MANIFEST.new"); while () { ($name,$foo) = split; $mani{$name} = 1; } close MANI; while () { s|^\./||; chop; next if m|^MANIFEST|; next if m|^PACKLIST$|; if (!$mani{$_}) { next if m|^MANIFEST.new$|; next if m|^Changes$|; next if m|^Wanted$|; next if m|^.package$|; next if m|^bugs|; next if m|^users$|; next if m|^UU/|; next if m|^RCS/|; next if m|/RCS/|; next if m|^config.sh$|; next if m|/config.sh$|; next if m|^make.out$|; next if m|/make.out$|; next if m|^all$|; next if m|/all$|; next if m|^core$|; next if m|/core$|; next if m|^toto|; next if m|/toto|; next if m|^\.|; next if m|/\.|; next if m|\.o$|; next if m|\.old$|; next if m|\.orig$|; next if m|~$|; next if $mani{$_ . ".SH"}; next if m|(.*)\.c$| && $mani{$1 . ".y"}; next if m|(.*)\.c$| && $mani{$1 . ".l"}; next if (-x $_ && !m|^Configure$|); } print NEWER $_,"\n"; } close FIND; close NEWER; print "Please remove unwanted files...\n"; sleep(2); system '${EDITOR-vi} .newer'; die "Aborted.\n" unless -s '.newer' > 1; @ARGV = split(' ',`cat .newer`); } sub readpackage { if (! -f '.package') { if ( -f '../.package' || -f '../../.package' || -f '../../../.package' || -f '../../../../.package' ) { die "Run in top level directory only.\n"; } else { die "No .package file! Run packinit.\n"; } } open(PACKAGE,'.package'); while () { next if /^:/; next if /^#/; if (($var,$val) = /^\s*(\w+)=(.*)/) { $val = "\"$val\"" unless $val =~ /^['"]/; eval "\$$var = $val;"; } } close PACKAGE; } sub rcsargs { local($result) = ''; local($_); while ($_ = shift(@_)) { if ($_ =~ /^-/) { $result .= $_ . ' '; } elsif ($#_ >= 0 && do equiv($_,$_[0])) { $result .= $_ . ' ' . $_[0] . ' '; shift(@_); } else { $result .= $_ . ' ' . do other($_) . ' '; } } $result; } sub equiv { local($s1, $s2) = @_; $s1 =~ s|.*/||; $s2 =~ s|.*/||; if ($s1 eq $s2) { 0; } elsif ($s1 =~ s/$RCSEXT$// || $s2 =~ s/$RCSEXT$//) { $s1 eq $s2; } else { 0; } } sub other { local($s1) = @_; ($dir,$file) = ('./',$s1) unless local($dir,$file) = ($s1 =~ m|(.*/)(.*)|); $dir = $TOPDIR . $dir if -d $TOPDIR . "$dir/RCS"; local($wasrcs) = ($file =~ s/$RCSEXT$//); if ($wasrcs) { `mkdir $dir` unless -d $dir; $dir =~ s|RCS/||; } else { $dir .= 'RCS/'; `mkdir $dir` unless -d $dir; $file .= $RCSEXT; } "$dir$file"; } # Perform ~name expansion ala ksh... # (banish csh from your vocabulary ;-) sub tilda_expand { local($path) = @_; return $path unless $path =~ /^~/; $path =~ s:^~([^/]+):(getpwnam($1))[$[+7]:e; # ~name $path =~ s:^~:$ENV{'HOME'} || (getpwuid($<))[$[+7]:e; # ~ $path; } # Set up profile components into %Profile, add any profile-supplied options # into @ARGV and return the command invocation name. sub profile { local($profile) = &tilda_expand($ENV{'DIST'} || '~/.dist_profile'); local($me) = $0; # Command name $me =~ s|.*/(.*)|$1|; # Keep only base name return $me unless -s $profile; local(*PROFILE); # Local file descriptor local($options) = ''; # Options we get back from profile unless (open(PROFILE, $profile)) { warn "$me: cannot open $profile: $!\n"; return; } local($_); local($component); while () { next if /^\s*#/; # Skip comments next unless /^$me/o; if (s/^$me://o) { # progname: options chop; $options .= $_; # Merge options if more than one line } elsif (s/^$me-([^:]+)://o) { # progname-component: value $component = $1; chop; s/^\s+//; # Trim leading and trailing spaces s/\s+$//; $Profile{$component} = $_; } } close PROFILE; return unless $options; require 'shellwords.pl'; local(@opts); eval '@opts = &shellwords($options)'; # Protect against mismatched quotes unshift(@ARGV, @opts); return $me; # Return our invocation name }