#!/bin/bash

# Copyright 2007-2008 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Id: emacs-updater 1204 2008-12-30 17:05:24Z ulm $

# Authors:
# Christian Faulhammer <fauli@gentoo.org>
# Ulrich Mueller <ulm@gentoo.org>

VERSION=1.2
SITELISP=/usr/share/emacs/site-lisp

# Default actions
ACTIONS="sitedir rebuild"

# Default package manager
PM_COMMAND=pm_portage

# Other default variable settings
EXACT=
NOCOLOUR=
PRETEND=

cat <<-EOF

Emacs updater version ${VERSION}
Written by the Gentoo Emacs team http://www.gentoo.org/proj/en/lisp/emacs/
Find packages that are installed in the wrong location or rebuild all
GNU Emacs packages

EOF

usage() {
    sed -e 's/^X//' <<-EOF
	Usage: ${0##*/} [OPTION]...
	X  -a, --action <arg>[,<arg>]...
	X                         specify actions, comma-separated list of:
	X                         'sitedir': find site-init files not in the
	X                           new-style location
	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: sitedir,rebuild)
	X  -e, --exact            match exact versions when remerging packages
	X  -n, --nocolour         disable colour in output
	X  -p, --pretend          don't actually emerge packages
	X  -P, --package-manager <arg>
	X                         select a package manager. arg is one out of
	X                         'portage' (default), 'pkgcore', or 'paludis'
	X  -h, --help             display this help and exit
	EOF
    exit ${1}
}

# Read in all command-line options and force English output
OPTIONS=$(LC_ALL=C getopt -o a:ehnpP: \
    --long action:,exact,help,nocolour,pretend,package-manager: \
    -n 'emacs-updater' -- "$@")
[ $? -eq 0 ] || usage 1

eval set -- "${OPTIONS}"

while true
do
    case "${1}" in
	-h|--help)      usage 0 ;;
	-e|--exact)     EXACT="true"; shift 1 ;;
	-p|--pretend)   PRETEND="true"; shift 1 ;;
	-n|--nocolour)  NOCOLOUR="true"; shift 1 ;;
	-a|--action)
	    ACTIONS=
	    for action in ${2/,/ }; do
		case "${action}" in
		    sitedir|rebuild|all)
			ACTIONS="${ACTIONS}${ACTIONS:+ }${action}"
			;;
		    *)
			echo "Invalid action '$action' given!"
			exit 20
			;;
		esac
	    done
	    shift 2
	    ;;
	-P|--package-manager)
	    case "${2}" in
		portage|pkgcore|paludis)
		    PM_COMMAND=pm_${2}
		    ;;
		*)
		    echo "Package manager '${2}' not known!"
		    exit 21
		    ;;
	    esac
	    shift 2
	    ;;

	--) shift; break ;;
    esac
done

# Only set colours if output is not redirected or the --no-colour
# option is not set
if [ -t 1 ] && [ -z "${NOCOLOUR}" ] ; then
    RED=$(tput -S <<<$'setaf 1\nbold')
    GREEN=$(tput -S <<<$'setaf 2\nbold')
    YELLOW=$(tput -S <<<$'setaf 3\nbold')
    BLUE=$(tput -S <<<$'setaf 4\nbold')
    MAGENTA=$(tput -S <<<$'setaf 5\nbold')
    CYAN=$(tput -S <<<$'setaf 6\nbold')
    BOLD=$(tput bold)
    NORMAL=$(tput sgr0)
else
    RED=; GREEN=; YELLOW=; BLUE=; MAGENTA=; CYAN=; BOLD=; NORMAL=
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() {
    /usr/bin/emacs -batch -q --no-site-file --eval "(princ emacs-version)" \
	|| { failure "Cannot run Emacs"; exit 5; }
}

# Get Emacs version from byte-compiled file
bytecomp-version() {
    sed -n '/^[^;]/q;s/\.$//;s/.*emacs version \([0-9].*\)/\1/Ip' "${1}"
}

action_sitedir() {
    local sf

    message "Searching for site-init files in obsolete location ..."

    # Set nullglob option since there may be no matching files
    local old_shopts=$(shopt -p nullglob)
    shopt -s nullglob

    for sf in "${ROOT}${SITELISP}"/[0-9][0-9]*-gentoo.el
    do
	[ "${sf##*/}" = 00site-gentoo.el ] && continue
	echo "Found ${sf##*/}"
	echo "${sf}" >> "${TMPFILE}"
    done

    eval "${old_shopts}"
    echo
}

action_rebuild() {
    local active version elc

    message "Searching for byte-compiled elisp files ..."
    active=$(emacs-version)
    [ -n "${active}" ] || { failure "Cannot determine Emacs version"; exit 6; }
    message "Currently selected GNU Emacs version: ${active}"

    for elc in $(find "${ROOT}${SITELISP}" -name "*.elc")
    do
	version=$(bytecomp-version "${elc}")
	version=${version:-unknown}

	if [ "${version}" != "${active}" ] || [ "${1}" = all ]; then
	    echo "Found ${elc##*/} (compiled by Emacs version ${version})"
	    echo "${elc}" >> "${TMPFILE}"
	else
	    echo "Skipping ${elc##*/} (compiled by Emacs version ${version})"
	fi
    done
    echo
}

action_all() {
    action_rebuild all
}

# Wrapper for package manager commands
pm_portage() {
    emerge --oneshot --ask --verbose "$@"
}

pm_pkgcore() {
    pmerge --oneshot --ask "$@"
}

pm_paludis() {
    paludis --install --preserve-world "$@"
}

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 3
fi

NO_OF_FILES=$(sed -n '$=' "${TMPFILE}")
[ ${NO_OF_FILES} -eq 1 ] && s= || s=s
message "Assigning ${NO_OF_FILES} file${s} to packages ..."

if [ "${EXACT}" ]; then
    qfile -eqCR -f "${TMPFILE}" | sort -u | sed 's/^/=/' > "${PKGFILE}"
else
    qfile -qCR -f "${TMPFILE}" | sort -u > "${PKGFILE}"
    # Get package and slot number
    # qfile -eqCR -f "${TMPFILE}" | sort -u | xargs qlist -eqCILS
fi

if [ ! -s "${PKGFILE}" ]; then
    warning "No packages to update, quitting."
    exit 3
fi

NO_OF_PACKAGES=$(sed -n '$=' "${PKGFILE}")
[ ${NO_OF_PACKAGES} -eq 1 ] && s= || s=s
message "${NO_OF_PACKAGES} package${s} to remerge:"

cat "${PKGFILE}"

if [ "${PRETEND}" ]; then
    exit 4
fi

echo
echo -n "${BOLD}Remerge packages?${NORMAL} [${GREEN}Yes${NORMAL}/${RED}No${NORMAL}] "
read choice
echo
case "${choice}" in
    y*|Y*|"")
	;;
    *)
	warning "Quitting."
	exit 10 ;;
esac

${PM_COMMAND} $(<"${PKGFILE}")

warning "If a package is being rebuilt over and over again,"
warning "please report it on http://bugs.gentoo.org/"
