cruxports/prt-utils/prtwash

418 lines
12 KiB
Bash

#!/bin/bash
#
# prtwash - a simple bash script for cleaning the port tree
# of the CRUX Linux distribution.
#
# Copyright (c) 2003 by Simone Rota <sip@varlock.com>
# Revised 2021 by John McQuah <jmcquah@disroot.org>
#
# *************************************************************************
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU General Public License as published by *
# * the Free Software Foundation; either version 2 of the License, or *
# * (at your option) any later version. *
# * *
# *************************************************************************
#
# Took some inspiration and code from Martin Opel's prtsweep v1.6 script,
# and comments by therealfun on FlySpray bug 1851.
#
# **** USE AT YOUR OWN RISK ****
#
# TODO
# - a summary of files / bytes removed after the
# execution would be useful.
# - verify signatures before sourcing each Pkgfile.
#
VERSION="0.9"
usage() {
echo "Usage: prtwash [-p] [-s] [-d] [-t] [-a] <path> [<path> ...]"
exit 1
}
showversion() {
echo "prtwash" $VERSION
echo "(c) 2003 by Simone Rota, revised 2021 by John McQuah"
echo "This program is distributed under the GNU GPL license"
}
interrupted() {
echo "=======> operation interrupted."
exit 1
}
checkparams() {
# Do some test on given parameters.
if [ "$auto" = "0" ]; then
if [ -z "$prtdirs" ]; then
usage
exit -1
fi
for (( p=0 ; p<=${#prtdirs[@]} ; p++ )); do
if [ -z "${prtdirs[$p]}" ]; then
unset prtdirs[$p]
continue
fi
if [ ! -d "${prtdirs[$p]}" ]; then
echo "WARN: '${prtdirs[$p]}' is not the directory for a port. Skipping."
unset prtdirs[$p]
continue
fi
if [ ! -f "${prtdirs[$p]}"/Pkgfile ]; then
echo "WARN: no Pkgfile found in '${prtdirs[$p]}'. Skipping."
unset prtdirs[$p]
fi
done
fi
}
getoptions () {
# Name says it all.
while getopts bpsdathv opt; do
case "$opt" in
b) removeoldbuilds=1;;
p) removepackage=1;;
s) removesources=1;;
d) removeaddonfiles=1;;
t) test=1;;
a) auto=1;;
h) usage
exit 0
;;
v) showversion
exit 0
;;
\?) usage
exit -1
;;
esac
done
shift $(($OPTIND - 1))
prtdirs=("$@")
}
getdirs() {
# scans /etc/prt-get.conf for port dirs to process
current=""
for s in `sed 's/^[ \t]*//;s/[ \t]*$//' \
$CONF_PGET|grep '^prtdir.*:'|sed 's/:/ /;s/,/ /;s/prtdir//;s/#.*//'`
do
if [ "`echo $s|grep '/'`" != "" ]; then
current=$s
else
if [ "$current" != "" ]; then
singledirs=(${singledirs[*]} $current/$s)
fi
fi
done
for s in `sed 's/^[ \t]*//;s/[ \t]*$//;/:/d' \
$CONF_PGET|grep '^prtdir.*'|sed 's/prtdir//;s/#.*//'`
do
basedirs=(${basedirs[*]} $s)
done
}
remove() {
# Removes a file/directory
if [ "$test" = 1 ]; then
echo "+ (t) removing" $1
else
echo "+ removing" $1
rm -r $1
fi
}
swash() {
# There are faster and safer ways of cleaning a directory shared among all ports than
# to iterate through the ports collection itself.
# Inform the admin that this script is ill-suited for their configuration.
echo "It looks like you have defined common directories for downloads or packages." >&2
echo "For such a configuration, this script is slower and less reliable" >&2
echo "than a custom tool would be." >&2
echo "If you intended to clean out your ports repositories instead," >&2
echo "consider the companion tool prtsweep." >&2
echo "Proceed anyway? (y/n)" >&2
read CONFIRM
if [ "$CONFIRM" != "y" ]; then
exit 0
fi
}
finalwarning() {
echo "Last chance to bail out!" >&2
echo "This script will remove from the common download directories more files " >&2
echo "than perhaps you intended." >&2
echo "Proceed anyway? (y/n)" >&2
read CONFIRM
if [ "$CONFIRM" != "y" ]; then
exit 0
fi
}
nwash() {
if [ "$auto" = 0 ]; then
for p in ${prtdirs[@]}; do
echo "Washing the directory of port $p:"
wash $p
done
exit 0
else
if [ ! -f "$CONF_PGET" ]; then
echo "ERROR: cannot find configuration file '$CONF_PGET'"
exit -1
fi
echo "Analyzing port tree..."
getdirs
# wash base dirs
for d in ${basedirs[*]}; do
if [ -d "$d" ]; then
for p in "$d"/*; do
if [ -d "$p" ]; then
wash $p
fi
done
else
echo "ERROR: directory '$d' not found, check your configuration file!"
fi
done
# wash custom dirs (see prt-get.conf)
for p in ${singledirs[*]}; do
if [ -d "$p" ]; then
wash $p
else
echo "ERROR: directory '$p' not found, check your configuration file!"
fi
done
exit 0
fi
exit 0
}
wash() {
# Does the actual removal work.
local tosave name version source renames pkgfiles packagename portname SAVELOC PKGLOC
local dir=$1
if [ ! -f "$dir"/Pkgfile ]; then
# tested before, the test here is for
# auto (-a) command
echo "WARN: no Pkgfile found in $dir. Skipping."
else
declare -a tosave # array of files not to be deleted
pkgfiles=(`( . $dir/Pkgfile; PKGLOC=$(eval "printf '%s' $PKGGLOB"); \
PKGFILE=$(eval "printf '%s' $BLTGLOB"); \
SAVELOC=$(eval "printf '%s' $SRCGLOB"); \
for (( p=0; p<${#source[@]}; p++ )); do \
[ -n "${renames[$p]}" -a "${renames[$p]}" != "SKIP" ] && source[$p]="ftp://host/${renames[$p]}"; \
done; \
printf '%s ' "${SAVELOC:-$dir}"; \
printf '%s ' "${PKGLOC:-$dir}/$PKGFILE"; \
printf '%s ' "${source[@]}")`)
SAVELOC=${pkgfiles[0]}
packagename=`basename ${pkgfiles[1]}`
PKGLOC=`dirname ${pkgfiles[1]}`
# keep sources
if [ "$removesources" = 0 ]; then
for (( p=2; p<${#pkgfiles[@]}; p++ )) ; do
tosave=( "${tosave[@]}" `get_filename "${pkgfiles[$p]}"` )
done
fi
# new in version 0.3 we (try to) always save files that are
# retrieved by rsync/httpup (non http(s) or ftp in source)
# ie patches, etc. These can be deleted with -d (extra files)
# option
if [ "$removesources" = 1 ] && [ "$removeaddonfiles" = 0 ]; then
for (( p=2; p<${#pkgfiles[@]}; p++ )) ; do
src="${pkgfiles[$p]}"
pkgfiles[$p]=$(get_filename $src)
[ "${src:0:7}" = "ftp://" \
-o "${src:0:8}" = "http://" \
-o "${src:0:6}" = "https://" ] ||
tosave=( "${tosave[@]}" "${pkgfiles[$p]}" )
done
fi
# Now that the distinction between files obtained via rsync/httpup
# and files downloaded during `pkgmk -d` has been encoded in the
# array $tosave, clean up the filenames in the $pkgfiles array.
if [ "$removesources" = 0 ] || [ "$removeaddonfiles" = 1 ]; then
for (( p=2; p<${#pkgfiles[@]}; p++ )) ; do
pkgfiles[$p]=$(get_filename ${pkgfiles[$p]})
done
fi
if [ ! "$removepackage" = 1 ]; then
# keep package
tosave=( "${tosave[@]}" "$packagename" )
fi
if [ ! "$removeaddonfiles" = 1 ]; then
# keep additional and dot files
tosave=( "${tosave[@]}" \
".signature" \
".32bit" \
".footprint" \
".nostrip" \
"README" \
"FAQ" \
"pre-install" \
"post-install" )
fi
# keep Pkgfile. We always want to keep this nice funny file.
tosave=( "${tosave[@]}" "Pkgfile" )
unset pkgfiles[0] pkgfiles[1]
# trust that our parsing of the Pkgfile has not set the wrong source directory.
# But if an absolute path is specified, restrict the `ls -A` output
# to avoid overzealous deletions.
cd $SAVELOC
if [ "${SAVELOC:0:1}" != "/" ]; then
for f in `ls -A`; do
keep $f || remove $f
done
elif [ ${#pkgfiles[@]} -gt 0 ]; then
for f in ${pkgfiles[@]}; do
for match in `ls -A ${f}* 2>/dev/null`; do
keep $match || remove $match
done
done
fi
cd - &>/dev/null
# same trust as to the location of the built packages, if different from SAVELOC.
# Older versions can be discarded too, if $removeoldbuilds = 1.
if [ "$removepackage" = 1 ]; then
(cd $PKGLOC; [ -f $packagename ] && keep "$packagename" || remove "$packagename")
fi
if [ "$removeoldbuilds" = 1 ]; then
portname=$(echo "$packagename" | sed 's/#.*//')
(cd $PKGLOC; for f in `ls ${portname}*.pkg.tar.[bgx]z* 2>/dev/null`; do keep $f || remove $f; done)
fi
fi
}
keep() {
# Checks if filename item is in tosave[] array
# return 0 if present, 1 if not.
item=$1
local excode
excode=1 # assume not in the array until proven otherwise
for i in "${tosave[@]}"; do
if [ "$i" = "$item" ]; then
[ "$test" = "1" ] && echo "= (t) ... keeping $item" || echo "= ... keeping $item"
excode=0
break
fi
done
return $excode
}
get_filename() {
if [[ $1 =~ ^(http|https|ftp|file)://.*/(.+) ]]; then
echo "${BASH_REMATCH[2]}"
else
echo $1
fi
}
printparams() {
echo "removepackage: $removepackage"
echo "removeoldbuilds: $removeoldbuilds"
echo "removesources: $removesources"
echo "removeaddonfiles: $removeaddonfiles"
echo "auto: $auto"
echo "test: $test"
}
###################################################
# Main
###################################################
trap "interrupted" SIGHUP SIGINT SIGQUIT SIGTERM
if [ $# -lt 1 ]; then
usage
exit -1
fi
removepackage=0
removesources=0
removeaddonfiles=0
removeoldbuilds=0
test=0
auto=0
basedirs=()
singledirs=()
prtdirs=()
CONF_PGET="/etc/prt-get.conf"
CONF_PMK="/etc/pkgmk.conf"
getoptions $@
checkparams $@
COMPRESSION_MODE="gz"
if [ -f $PKGCONFIG ]; then
COMPRESS_CFG=$(grep "PKGMK_COMPRESSION_MODE" $CONF_PMK | \
sed 's/[\t w]*#.*//;s/.*=//;s/\"//g')
[ -n "$COMPRESS_CFG" ] && COMPRESSION_MODE=$COMPRESS_CFG
SRCGLOB=$(grep "PKGMK_SOURCE_DIR" $CONF_PMK | sed 's/[\t w]*#.*//; s/.*=//; s/\"//g')
PKGGLOB=$(grep "PKGMK_PACKAGE_DIR" $CONF_PMK | sed 's/[\t w]*#.*//; s/.*=//; s/\"//g')
fi
BLTGLOB='$name#$version-$release.pkg.tar.$COMPRESSION_MODE'
# First determine the type of fs layout the admin configured for source downloads.
# Layouts 1 and 2: at least one directory is shared among all ports (for sources or built packages),
# or the admin has organized downloads in some other way outside of $PORTS_ROOT.
if [ -n "${SRCGLOB}" ] && echo "${SRCGLOB}" | grep -q -v '\$name'; then
swash
nwash
elif [ -n "${PKGGLOB}" ] && echo "${PKGGLOB}" | grep -q -v '\$name'; then
swash
nwash
fi
# Layout 3: separate directories, named according to port, are potentially cluttered with downloads.
# Unlike prtsweep, actually try to follow these dynamically-defined paths and clean them up.
# $PORTS_ROOT might still remain cluttered after this "wash", but the admin can just run prtsweep.
# For such filesystem layouts, the two scripts complement each other nicely.
if [ -z "${SRCGLOB}" -o -z "${PKGGLOB}" ]; then
nwash
elif [ -n "${SRCGLOB}" ] && echo "$SRCGLOB" | grep -q '\$name'; then
nwash
elif [ -n "${PKGGLOB}" ] && echo "$PKGGLOB" | grep -q '\$name'; then
nwash
else
# Should have exited by now, but if not,
# offer another chance to abort.
finalwarning
nwash
fi