index : pacman | |
Archlinux32 fork of pacman | gitolite user |
summaryrefslogtreecommitdiff |
-rw-r--r-- | contrib/paccache.sh.in | 366 |
diff --git a/contrib/paccache.sh.in b/contrib/paccache.sh.in deleted file mode 100644 index 02fae527..00000000 --- a/contrib/paccache.sh.in +++ /dev/null @@ -1,366 +0,0 @@ -#!/bin/bash -# -# pacache - flexible pacman cache cleaning -# -# Copyright (C) 2011 Dave Reisner <dreisner@archlinux.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. -# -# 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. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - - -shopt -s extglob - -declare -r myname='paccache' -declare -r myver='@PACKAGE_VERSION@' - -declare -a cachedirs=() candidates=() cmdopts=() whitelist=() blacklist=() -declare -i delete=0 dryrun=0 filecount=0 move=0 needsroot=0 totalsaved=0 verbose=0 -declare delim=$'\n' keep=3 movedir= scanarch= - -QUIET=0 -USE_COLOR='y' - -m4_include(../scripts/library/output_format.sh) -m4_include(../scripts/library/parseopts.sh) - -die() { - error "$@" - exit 1 -} - -get_cachedir_from_config() { - local key value - - while IFS=$'= \t' read -r key value _; do - if [[ $key = CacheDir ]]; then - echo "$value" - return 0 - fi - done <"$1" - - return 1 -} - -# reads a list of files on stdin and prints out deletion candidates -pkgfilter() { - # there's whitelist and blacklist parameters passed to this - # script after the block of awk. - - awk -v keep="$1" -v scanarch="$2" ' - function basename(str) { - sub(".*/", "", str); - return str; - } - - function parse_filename(filename, parts, count, i, pkgname, arch) { - - count = split(basename(filename), parts, "-") - - i = 1 - pkgname = parts[i++] - while (i <= count - 3) { - pkgname = pkgname "-" parts[i++] - } - - arch = substr(parts[count], 1, index(parts[count], ".") - 1) - - # filter on whitelist or blacklist - if (wlen && !whitelist[pkgname]) return - if (blen && blacklist[pkgname]) return - - if ("" == packages[pkgname,arch]) { - packages[pkgname,arch] = filename - } else { - packages[pkgname,arch] = packages[pkgname,arch] SUBSEP filename - } - } - - BEGIN { - # create whitelist - wlen = ARGV[1]; delete ARGV[1] - for (i = 2; i < 2 + wlen; i++) { - whitelist[ARGV[i]] = 1 - delete ARGV[i] - } - - # create blacklist - blen = ARGV[i]; delete ARGV[i] - while (i++ < ARGC) { - blacklist[ARGV[i]] = 1 - delete ARGV[i] - } - - # read package filenames - while (getline < "/dev/stdin") { - parse_filename($0) - } - - for (pkglist in packages) { - # idx[1,2] = idx[pkgname,arch] - split(pkglist, idx, SUBSEP) - - # enforce architecture match if specified - if (!scanarch || scanarch == idx[2]) { - count = split(packages[idx[1], idx[2]], pkgs, SUBSEP) - for(i = 1; i <= count - keep; i++) { - print pkgs[i] - } - } - } - }' "${@:3}" -} - -m4_include(../scripts/library/size_to_human.sh) - -runcmd() { - if (( needsroot && EUID != 0 )); then - msg "Privilege escalation required" - if sudo -v &>/dev/null && sudo -l &>/dev/null; then - sudo "$@" - else - die 'Unable to escalate privileges using sudo' - fi - else - "$@" - fi -} - -summarize() { - (( QUIET )) && return - - local -i filecount=$1; shift - local seenarch= seen= arch= name= - local -r pkg_re='(.+)-[^-]+-[0-9]+-([^.]+)\.pkg.*' - - if (( delete )); then - printf -v output 'finished: %d packages removed' "$filecount" - elif (( move )); then - printf -v output "finished: %d packages moved to '%s'" "$filecount" "$movedir" - elif (( dryrun )); then - if (( verbose )); then - msg "Candidate packages:" - while read -r pkg; do - if (( verbose >= 3 )); then - [[ $pkg =~ $pkg_re ]] && name=${BASH_REMATCH[1]} arch=${BASH_REMATCH[2]} - if [[ -z $seen || $seenarch != "$arch" || $seen != "$name" ]]; then - seen=$name seenarch=$arch - printf '%s (%s):\n' "${name##*/}" "$arch" - fi - printf ' %s\n' "${pkg##*/}" - elif (( verbose >= 2 )); then - printf "%s$delim" "$pkg" - else - printf "%s$delim" "${pkg##*/}" - fi - done < <(printf '%s\n' "$@" | pacsort --files) - fi - printf -v output 'finished dry run: %d candidates' "$filecount" - fi - - echo - msg "$output (disk space saved: %s)" "$(size_to_human "$totalsaved")" -} - -usage() { - cat <<EOF -${myname} (pacman) v${myver} - -A flexible pacman cache cleaning utility. - -Usage: ${myname} <operation> [options] [targets...] - - Operations: - -d, --dryrun perform a dry run, only finding candidate packages. - -m, --move <dir> move candidate packages to "dir". - -r, --remove remove candidate packages. - - Options: - -a, --arch <arch> scan for "arch" (default: all architectures). - -c, --cachedir <dir> scan "dir" for packages. can be used more than once. - (default: read from @sysconfdir@/pacman.conf). - -f, --force apply force to mv(1) and rm(1) operations. - -h, --help display this help message and exit. - -i, --ignore <pkgs> ignore "pkgs", comma-separated. Alternatively, specify - "-" to read package names from stdin, newline- - delimited. - -k, --keep <num> keep "num" of each package in the cache (default: 3). - --nocolor remove color from output. - -q, --quiet minimize output - -u, --uninstalled target uninstalled packages. - -v, --verbose increase verbosity. specify up to 3 times. - -z, --null use null delimiters for candidate names (only with -v - and -vv). - -EOF -} - -version() { - printf "%s %s\n" "$myname" "$myver" - echo 'Copyright (C) 2011 Dave Reisner <dreisner@archlinux.org>' -} - -OPT_SHORT=':a:c:dfhi:k:m:qrsuVvz' -OPT_LONG=('arch:' 'cachedir:' 'dryrun' 'force' 'help' 'ignore:' 'keep:' 'move' - 'nocolor' 'quiet' 'remove' 'uninstalled' 'version' 'verbose' 'null') - -if ! parseopts "$OPT_SHORT" "${OPT_LONG[@]}" -- "$@"; then - exit 1 -fi -set -- "${OPTRET[@]}" -unset OPT_SHORT OPT_LONG OPTRET - -while :; do - case $1 in - -a|--arch) - scanarch=$2 - shift ;; - -c|--cachedir) - cachedirs+=("$2") - shift ;; - -d|--dryrun) - dryrun=1 ;; - -f|--force) - cmdopts=(-f) ;; - -h|--help) - usage - exit 0 ;; - -i|--ignore) - if [[ $2 = '-' ]]; then - [[ ! -t 0 ]] && IFS=$'\n' read -r -d '' -a ign - else - IFS=',' read -r -a ign <<< "$2" - fi - blacklist+=("${ign[@]}") - unset i ign - shift ;; - -k|--keep) - keep=$2 - if [[ -z $keep || -n ${keep//[0-9]/} ]]; then - die 'argument to option -k must be a non-negative integer' - else - keep=$(( 10#$keep )) - fi - shift ;; - -m|--move) - move=1 movedir=$2 - shift ;; - --nocolor) - USE_COLOR='n' ;; - -q|--quiet) - QUIET=1 ;; - -r|--remove) - delete=1 ;; - -u|--uninstalled) - IFS=$'\n' read -r -d '' -a ign < <(pacman -Qq) - # pacman -Qq may exit with an error, thus making ign an empty array - (( ${#ign[@]} )) || die 'failed to retrieve the list of installed packages' - blacklist+=("${ign[@]}") - unset ign ;; - -V|--version) - version - exit 0 ;; - -v|--verbose) - (( ++verbose )) ;; - -z|--null) - delim='\0' ;; - --) - shift - break 2 ;; - esac - shift -done - -m4_include(../scripts/library/term_colors.sh) - -# setting default cachedir -if [[ -z $cachedirs ]]; then - if cachedir=$(get_cachedir_from_config "@sysconfdir@/pacman.conf"); then - cachedirs=("$cachedir") - else - cachedirs=("${cachedirs[@]:-@localstatedir@/cache/pacman/pkg}") - fi -fi - -# remaining args are a whitelist -whitelist=("$@") - -# sanity checks -case $(( dryrun+delete+move )) in - 0) die "no operation specified (use -h for help)" ;; - [^1]) die "only one operation may be used at a time" ;; -esac - -[[ $movedir && ! -d $movedir ]] && - die "destination directory '%s' does not exist or is not a directory" "$movedir" - -if (( move || delete )); then - # make it an absolute path since we're about to chdir - [[ $movedir && ${movedir:0:1} != '/' ]] && movedir=$PWD/$movedir - [[ $movedir && ! -w $movedir ]] && needsroot=1 -fi - -for cachedir in "${cachedirs[@]}"; do - [[ -d $cachedir ]] || - die "cachedir '%s' does not exist or is not a directory" "$cachedir" - - if (( move || delete )); then - [[ ! -w $cachedir ]] && needsroot=1 - fi - - # unlikely that this will fail, but better make sure - pushd "$cachedir" &>/dev/null || die "failed to chdir to '%s'" "$cachedir" - - # note that these results are returned in an arbitrary order from awk, but - # they'll be resorted (in summarize) iff we have a verbosity level set. - IFS=$'\n' read -r -d '' -a cand < \ - <(printf '%s\n' "$PWD"/*.pkg.tar?(.+([^.])) | pacsort --files | - pkgfilter "$keep" "$scanarch" \ - "${#whitelist[*]}" "${whitelist[@]}" \ - "${#blacklist[*]}" "${blacklist[@]}") - - candidates+=("${cand[@]}") - unset cand - - popd &>/dev/null -done - -if (( ! ${#candidates[*]} )); then - msg 'no candidate packages found for pruning' - exit 0 -fi - -# grab this prior to signature scavenging -pkgcount=${#candidates[*]} - -# copy the list, merging in any found sigs -for cand in "${candidates[@]}"; do - candtemp+=("$cand") - [[ -f $cand.sig ]] && candtemp+=("$cand.sig") -done -candidates=("${candtemp[@]}") -unset candtemp - -# do this before we destroy anything -totalsaved=$(@SIZECMD@ "${candidates[@]}" | awk '{ sum += $1 } END { print sum }') - -# crush. kill. destroy. -(( verbose )) && cmdopts+=(-v) -if (( delete )); then - printf '%s\0' "${candidates[@]}" | runcmd xargs -0 rm "${cmdopts[@]}" -elif (( move )); then - printf '%s\0' "${candidates[@]}" | runcmd xargs -0 mv "${cmdopts[@]}" -t "$movedir" -fi - -summarize "$pkgcount" "${candidates[@]}" - -# vim: set noet: |