#!/bin/bash # Copyright 2007-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 or later # Authors: # Christian Faulhammer # Ulrich Müller VERSION=1.14 EMACS=/usr/bin/emacs GETOPT=/usr/bin/getopt SITELISP=/usr/share/emacs/site-lisp # Default actions ACTIONS="rebuild" # Default package manager PM_COMMAND=pm_auto PM_EXTRAOPTS=( ) # Other default variable settings BATCH= COLOUR= EXACT= MAJOR= ORPHANS= PRETEND= usage() { sed -e 's/^X//' <<-EOF Usage: ${0##*/} [OPTION]... Rebuild Emacs packages that were compiled by a different GNU Emacs version, or all Emacs packages. X X -a, --action=ACTION[,ACTION]... X specify actions, comma-separated list of: X rebuild: rebuild packages with elisp files X byte-compiled by a different Emacs version X all: rebuild all packages that have X byte-compiled elisp files X (default: rebuild) X -b, --batch batch mode, don't ask any questions X --color[=MODE], --colour[=MODE] X control colour output. MODE is yes, no, X or auto. For 'auto', colour is enabled if X standard output is to a terminal X (default: auto) X -e, --exact match exact versions when remerging packages X -m, --major use only the major version when comparing X Emacs version numbers X -o, --orphans list orphan files (implies '--action all') X -p, --pretend don't actually emerge packages X -P, --package-manager=PM X select a package manager. PM is one out of X portage, pkgcore, or paludis X (default: automatically determined) X --package-manager-command=CMD X call CMD instead of the default package X manager command. If CMD includes options, X the whole command string must be quoted X -h, --help display this help and exit X --version output version information and exit X X -- OPTION... pass additional options to package manager EOF exit $1 } version() { cat <<-EOF Emacs updater version ${VERSION} Copyright 2007-2014 Gentoo Foundation. Distributed under the terms of the GNU GPL version 2 or later. Gentoo Emacs project: EOF exit } # Wrapper for package manager commands have_portage() { type -P emerge >/dev/null; } pm_portage() { emerge --oneshot "$@"; } have_pkgcore() { type -P pmerge >/dev/null; } pm_pkgcore() { pmerge --oneshot "$@"; } have_paludis() { type -P cave >/dev/null; } pm_paludis() { cave resolve --execute --preserve-world "$@"; } pm_auto() { local pm # Try environment variable first case ${PACKAGE_MANAGER} in portage|pkgcore|paludis) pm=${PACKAGE_MANAGER} ;; esac for pm in ${pm} portage pkgcore paludis; do if have_${pm}; then PM_COMMAND=pm_${pm} ${PM_COMMAND} "$@" return fi done failure "No package manager found" return 1 } # Read in all command-line options and force English output OPTIONS=$(LC_ALL=C "${GETOPT}" -o a:behmnopP: \ --long action:,batch,color::,colour::,nocolor,nocolour,exact,help,major \ --long orphans,pretend,package-manager:,package-manager-command:,version \ -n 'emacs-updater' -- "$@") \ || usage $? eval set -- "${OPTIONS}" while true do case $1 in -h|--help) usage 0 ;; --version) version ;; -b|--batch) BATCH="true"; shift ;; -e|--exact) EXACT="true"; shift ;; -m|--major) MAJOR="true"; shift ;; -o|--orphans) ORPHANS="true"; ACTIONS="all"; shift ;; -p|--pretend) PRETEND="true"; shift ;; --color|--colour) case $2 in yes|y|always|force|"") COLOUR="yes" ;; no|n|never|none) COLOUR="no" ;; auto|tty|if-tty) COLOUR="" ;; *) echo "Invalid argument for '$1' option" usage 1 ;; esac shift 2 ;; -n|--nocolor|--nocolour) COLOUR="no"; shift ;; # legacy option -a|--action) ACTIONS= for action in ${2/,/ }; do case ${action} in rebuild|all) ACTIONS="${ACTIONS}${ACTIONS:+ }${action}" ;; sitedir) echo "Obsolete action '$action' ignored." ;; *) echo "Invalid action '$action' given!" usage 1 ;; esac done shift 2 ;; -P|--package-manager) case $2 in auto|automatic) PM_COMMAND=pm_auto ;; portage|pkgcore|paludis) if ! have_$2; then echo "Package manager '$2' not found!" exit 1 fi PM_COMMAND=pm_$2 ;; *) echo "Package manager '$2' not known!" usage 1 ;; esac shift 2 ;; --package-manager-command) PM_COMMAND=$2; shift 2 ;; --) shift if [[ $# -gt 0 && ${1#-} = "$1" ]]; then # first parameter after -- should be an option echo "Non-option parameter '$1' for package manager specified!" usage 1 fi PM_EXTRAOPTS=( "$@" ) break ;; *) # this should not happen; getopt should return bad status echo "Invalid option '$1' given!" usage 1 ;; esac done # Set colours based on the --colour option and output redirection status if [[ -z ${COLOUR} && -t 1 ]] || [[ ${COLOUR} = yes ]]; then BOLD=$(tput bold) NORMAL=$(tput sgr0) RED=$(tput setaf 1)${BOLD} GREEN=$(tput setaf 2)${BOLD} YELLOW=$(tput setaf 3)${BOLD} BLUE=$(tput setaf 4)${BOLD} MAGENTA=$(tput setaf 5)${BOLD} CYAN=$(tput setaf 6)${BOLD} else BOLD=; NORMAL=; RED=; GREEN=; YELLOW=; BLUE=; MAGENTA=; CYAN= fi # Some type of output can be prettified and capsulated in functions message() { local OUTPUT="$@" echo "${GREEN}*${NORMAL}${BOLD} ${OUTPUT}${NORMAL}" } warning() { local OUTPUT="$@" echo "${YELLOW}*${NORMAL}${BOLD} ${OUTPUT}${NORMAL}" } failure() { local OUTPUT="$@" echo "${RED}*${NORMAL}${BOLD} ${OUTPUT}${NORMAL}" } emacs_version() { "${EMACS}" -batch -q --no-site-file --eval "(princ emacs-version)" } # Get Emacs version from byte-compiled file bytecomp_version() { sed -n '/^[^;]/q;s/\.$//;s/.*[Ee]macs version \([0-9].*\)/\1/p' "$1" } action_rebuild() { local active version elc ret message "Searching for byte-compiled elisp files ..." active=$(emacs_version) ret=$? [[ ${ret} -eq 0 ]] || { failure "Error running Emacs"; exit ${ret}; } [[ ${active} ]] || { failure "Cannot determine Emacs version"; exit 1; } message "Currently selected GNU Emacs version: ${active}" for elc in $(find "${ROOT}${SITELISP}" -name "*.elc") do version=$(bytecomp_version "${elc}") ret=$? [[ ${ret} -eq 0 ]] || { failure "Error running sed"; exit ${ret}; } version=${version:-unknown} if [[ -z ${MAJOR} && ${version%.*} != "${active%.*}" ]] \ || [[ ${version%%.*} != "${active%%.*}" ]] \ || [[ $1 = all ]] then echo "Found ${elc##*/} (compiled by Emacs ${version})" echo "${elc}" >> "${TMPFILE}" else echo "Skipping ${elc##*/} (compiled by Emacs ${version})" fi done echo } action_all() { action_rebuild all } cleanup() { rm -f "${TMPFILE}" "${PKGFILE}" } trap cleanup EXIT TMPFILE="$(mktemp ${TMPDIR:-/tmp}/emacs-updater.files.XXXXXX)" PKGFILE="$(mktemp ${TMPDIR:-/tmp}/emacs-updater.pkgs.XXXXXX)" for action in ${ACTIONS}; do action_${action} done if [[ ! -s ${TMPFILE} ]]; then warning "No files to update, quitting." exit 0 fi NO_OF_FILES=$(wc -l <"${TMPFILE}") [[ ${NO_OF_FILES} -eq 1 ]] && s= || s=s message "Assigning ${NO_OF_FILES} file${s} to packages ..." if [[ ${ORPHANS} ]]; then qfile -oCR -f "${TMPFILE}" | sort -u > "${PKGFILE}" elif [[ ${EXACT} ]]; then qfile -eqCR -f "${TMPFILE}" | sort -u | sed 's/^/=/' > "${PKGFILE}" else # Get package and slot number, requires >=portage-utils-0.3 qfile -SqCR -f "${TMPFILE}" | sort -u > "${PKGFILE}" fi NO_OF_PACKAGES=$(wc -l <"${PKGFILE}") [[ ${NO_OF_PACKAGES} -eq 1 ]] && s= || s=s if [[ ${ORPHANS} ]]; then message "${NO_OF_PACKAGES} orphan file${s} found:" else message "${NO_OF_PACKAGES} package${s} to remerge:" fi cat "${PKGFILE}" if [[ ${PRETEND} || ${ORPHANS} ]]; then exit 0 fi echo if [[ ${NO_OF_PACKAGES} -eq 0 ]]; then warning "No packages to update, quitting." exit 0 fi if [[ ${BATCH} ]]; then message "Remerging packages ..." else echo -n "${BOLD}Remerge packages?${NORMAL} [${GREEN}Yes${NORMAL}/${RED}No${NORMAL}] " read choice echo case ${choice} in y*|Y*|"") ;; *) warning "Quitting."; exit 0 ;; esac fi ${PM_COMMAND} "${PM_EXTRAOPTS[@]}" $(<"${PKGFILE}") ret=$? warning "If a package is being rebuilt over and over again," warning "please report it on http://bugs.gentoo.org/" exit ${ret}