#!/bin/sh # # distclean.sh: Clean out distfiles that are not referenced by # any installed packages. # # $Header: /var/cvsroot/scripts/distclean.sh,v 1.4 2005/05/22 14:12:25 mark Exp $ # # Copyright (C) 2005 Mark Rosenstand # # 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. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # See http://www.gnu.org/licenses/gpl.txt for details. # # Try to inherit DISTDIR from portage configs. [ -e /etc/make.globals ] && . /etc/make.globals [ -e /etc/make.conf ] && . /etc/make.conf # Fall back to this in case inheriting from portage fails. [ -z ${DISTDIR} ] && DISTDIR="/usr/portage/distfiles" # Constant value VDB_PATH from portage. PKG_DB_DIR="/var/db/pkg" # Check if /dev/shm exists and is writable, fall back to /tmp if not. [ -d /dev/shm -a -w /dev/shm ] \ && TMP_FILELIST="/dev/shm/distclean.$$" \ || TMP_FILELIST="/tmp/distclean.$$" usage() { echo " distclean.sh: Clean out distfiles that are not referenced by any installed packages. The advantage of doing this is that you can keep a copy of the source code for installed packages without wasting too much disc space. - \"But, why keep the source code around?\" Every time you re-compile a package, you need it. This could be because you changed a USE flag or the maintainer bumped its revision. This happens quite often; for instance, sys-kernel/gentoo-sources typically bumps its revision 10 times for each release. Deleting your distfiles will mean that the next time you re-compile a package, you will have to re-fetch the entire source code, even if the change was to apply a 2 kB patch or just change something in the build instructions. That's 40 MB for sys-kernel/gentoo-sources. This is an awful waste of bandwidth, time and mirror resources. - \"OK, so I won't delete anything in /usr/portage/distfiles.\" /usr/portage/distfiles will steadily grow as you update packages, try out new applications, etc. I wrote this utility because I had 5 GB of distfiles after 6 months of weekly emerge -uD world'ing. Those were reduced to 900 MB the first time I ran this utility. I hope that this script will help others spare some disc space *and* not waste mirror resources. -- Mark Rosenstand Usage: $0 [options] Options: -h, --help This message. -d, --debug Enable output useful for debugging. -v, --verbose Enable more verbose output. -q, --quiet Don't print any non-error messages. -i, --interactive Ask before trying to delete files. -p, --pretend Don't actually delete the files. WARNING: Currently, the last option will always take precedence, so '$0 -q -v' will *not* be quiet. " } die() { echo echo " Error: $1" >/dev/stderr echo exit 1 } # Read parameters. while [ $# -gt 0 ]; do case "$1" in -d|--debug) DEBUG=1 ;; -v|--verbose) VERBOSE=1 ;; -q|--quiet) QUIET=1 ;; -p|--pretend) PRETEND=1 ;; -i|--interactive) INTERACTIVE=1 ;; -h|--help) usage exit 0 ;; *) usage die "$1 is not a valid option." ;; esac shift done check_param_set() { [ ${1} ] && echo "true" || echo "false" } if [ ${DEBUG} ]; then echo echo " Configuration" echo "========================================================" echo " distfiles directory: ${DISTDIR}" echo " package database directory: ${PKG_DB_DIR}" echo " temporary list of files: ${TMP_FILELIST}" echo echo " Parameters" echo "========================================================" echo -n " --debug: "; check_param_set ${DEBUG} echo -n " --verbose: "; check_param_set ${VERBOSE} echo -n " --quiet: "; check_param_set ${QUIET} echo -n " --interactive: "; check_param_set ${INTERACTIVE} echo -n " --pretend: "; check_param_set ${PRETEND} echo fi # Clean out old file list. if [ -f ${TMP_FILELIST} ]; then rm -f ${TMP_FILELIST} || die "Can't remove ${TMP_FILELIST}" fi [ -z ${QUIET} ] \ && echo "Generating list of distfiles used by installed packages..." for CATEGORY in `ls ${PKG_DB_DIR}`; do [ ${VERBOSE} ] && echo "${CATEGORY}/" for PKG in `ls ${PKG_DB_DIR}/${CATEGORY}`; do [ ${VERBOSE} ] && echo " ${PKG}:" FILES=`bzcat ${PKG_DB_DIR}/${CATEGORY}/${PKG}/environment.bz2 \ |grep "^A=" |sed -e 's/A=//;' -e "s/'//g"` for FILE in ${FILES}; do [ ${VERBOSE} ] && echo " ${FILE}" echo "${FILE}" >>${TMP_FILELIST} \ || die "Can't write to ${TMP_FILELIST}" done done done [ -z ${QUIET} ] \ && echo "Checking files in ${DISTDIR} against the list..." for DISTFILE in `ls ${DISTDIR}`; do # Check if the distfile is in the list. if grep -q "^${DISTFILE}$" ${TMP_FILELIST}; then # Print a message if we're being --verbose. [ ${VERBOSE} ] && echo "Keeping ${DISTFILE}" else # Print a message if we're not --quiet. [ -z ${QUIET} ] && echo "Removing ${DISTFILE}" while true; do # Skip all steps if we --pretend. [ ${PRETEND} ] && break # Prompt user if we're --interactive. if [ ${INTERACTIVE} ]; then echo -n "Delete ${DISTFILE}? [Y/n] " read REPLY case "${REPLY}" in yes|y|Y) rm -rf "${DISTDIR}/${DISTFILE}" break ;; no|n|N) break ;; *) echo "Please choose 'yes' or 'no'." continue ;; esac else # Just delete the file if neither of the above. rm -rf "${DISTDIR}/${DISTFILE}" break fi done fi done # Be a good kid and clean up after playing. # Unless we're --debug'ging, of course. [ -z ${DEBUG} ] \ && rm -f ${TMP_FILELIST} \ || echo "List of referenced distfiles saved in ${TMP_FILELIST}." \ exit 0