#!/bin/sh # # This script has been modified by kosmikus and is based on # python-updater by liquidx. # # It tries to update any package that provides a ghc library. # This script can be run as many times as you like. It will log the # results in /var/log/ghc-updater.log # # NEW_GHC_VER = new ghc version we are upgrading to # PKGS_EXCEPTIONS = packages that should NOT be re-emerged for any reason # PKGS_MANUAL = packages that should be re-emerged even if they don't # fit the criteria # # Runtime Variables: # # PKGS_TO_REMERGE = list of packages we deem to need re-emerging # PKGS_OK = list of packages that should be merged without any problems # PKGS_MISSING = list of packages that are installed, but cannot be merged # because they have been pruned from portage # PKGS_MASKED = list of packages that are installed, but masked. # shopt -s nullglob # fix the PATH to include the dirs where portage installs ghc PATH="/usr/bin:/opt/ghc/bin:${PATH}" NEW_GHC_VER=$(ghc --version | sed 's:^.*version ::') NEW_GHC_LIBDIR=$(ghc --print-libdir) PKGS_EXCEPTIONS="dev-lang/ghc dev-lang/ghc-bin" PKGS_MANUAL="" LOGFILE="/var/log/ghc-updater.log" # portage variables PKG_DBDIR=/var/db/pkg # moved the portageq checks into a function to make command # line parsing immediate setup_portdir() { PORTDIR=`portageq portdir` PORTDIR_OVERLAYS=`portageq portdir_overlay` } PRETEND=0 PKGS_TO_REMERGE="" PKGS_COUNT_REMERGE=0 PORTAGE_PYTHON="/usr/bin/python" usage() { echo "usage: ghc-updater [options]" echo " -h, -?, --help help" echo " -p, --pretend pretend (don't do anything)" } # # # Command Line Parsing # # while [ -n "$1" ]; do case "$1" in -h | -\? | --help) usage exit 0 ;; -p | --pretend) PRETEND=1 ;; *) usage echo "unrecognised option: $1" ;; esac shift done # load the gentoo-style info macros, but hack to get around # it thinking this is an rc script EBUILD="1" # /etc/init.d/functions.sh always points to the correct functions.sh no # matter which version of baselayout source /etc/init.d/functions.sh # misc helper functions eloginfo() { einfo $* DATESTRING=`date +"%Y/%m/%d %H:%M:%S"` (echo "${DATESTRING} - ${*}" >> ${LOGFILE}) 2>/dev/null } elogecho() { echo -n " " echo $* DATESTRING=`date +"%Y/%m/%d %H:%M:%S"` (echo "${DATESTRING} - ${*}" >> ${LOGFILE}) 2>/dev/null } elogerr() { eerror $* DATESTRING=`date +"%Y/%m/%d %H:%M:%S"` (echo "${DATESTRING} ! ${*}" >> ${LOGFILE}) 2>/dev/null } elog() { DATESTRING=`date +"%Y/%m/%d %H:%M:%S"` (echo "${DATESTRING} - ${*}" >> ${LOGFILE}) 2>/dev/null } # # Sanity check # setup_portdir find_in_portdir() { local f for f in ${PORTDIR} ${PORTDIR_OVERLAYS}; do if [[ -f "${f}/${1}" ]]; then echo "${f}/${1}" return 0 fi done return 1 } if [ -z "${PORTDIR}" ]; then eerror "Unable to proceed. Can not find PORTDIR. Make sure the command:" eerror " " eerror " portageq portdir" eerror " " eerror "returns a value. If it doesn't, make sure you have updated to" eerror "latest portage version." eerror " " eerror "Report bugs to http://bugs.gentoo.org/" exit 1 fi # # # Find all packages that have installed something in # directories of the form # /usr/lib/ghc- # or similar. # # /usr/lib/ghc-bin- # is included because an old ghc-bin ebuild was buggy and # installed to a wrong dir. # OLD_PACKAGES_DIR="" # Exclude new library dir and lib symlinks: for d in /{usr,opt/ghc}/lib{,64}/ghc{,-bin}-*; do [[ "${d}" == ${NEW_GHC_LIBDIR} ]] || [[ -L ${d%/*} ]] || OLD_PACKAGES_DIR="${OLD_PACKAGES_DIR}${d} " done eloginfo "Starting GHC Updater to $(which ghc), version ${NEW_GHC_VER} :" eloginfo "Searching for packages with files in the directories:" eloginfo "${OLD_PACKAGES_DIR}" # iterate thru all the installed package's contents for content in `find ${PKG_DBDIR} -name CONTENTS`; do # extract the category, package name and package version CATPKGVER=$(echo ${content} | sed "s:${PKG_DBDIR}/\(.*\)/CONTENTS:\1:") # exclude packages that are an exception, like portage and python itself. exception=0 for exp in ${PKGS_EXCEPTIONS}; do if [ -n "$(echo ${CATPKGVER} | grep ${exp})" ]; then exception=1 break; fi done if [ ${exception} = 1 ]; then continue; fi for d in ${OLD_PACKAGES_DIR}; do if fgrep "${d}/" ${content} > /dev/null; then PKGS_TO_REMERGE="${PKGS_TO_REMERGE} ${CATPKGVER}" elogecho "${CATPKGVER} has files in ${d}" fi done done # now we have to do each emerge seperately because if an installed version # does not have the corresponding ebuild in portage, then it will bail. eloginfo "Calculating Upgrade Package List .." PKGS_OK="" PKGS_MASKED="" PKGS_BLOCKED="" PKGS_MISSING="" MASKED_STRING="been masked" BLOCKED_STRING="is blocking" MISSING_STRING='there are no ebuilds to satisfy' for pkg in ${PKGS_TO_REMERGE}; do emerge_output="$(emerge -p '>='$pkg 2>&1)" if $(echo "${emerge_output}" | grep "${MASKED_STRING}" > /dev/null); then PKGS_MASKED="${PKGS_MASKED} $pkg" elogecho ">=$pkg is masked" elif $(echo "${emerge_output}" | grep "${BLOCKED_STRING}" > /dev/null); then PKGS_BLOCKED="${PKGS_BLOCKED} $pkg" elogecho ">=$pkg is blocked" elif $(echo "${emerge_output}" | grep "${MISSING_STRING}" > /dev/null); then PKGS_MISSING="${PKGS_MISSING} $pkg" elogecho ">=$pkg is missing from portage" else PKGS_OK="${PKGS_OK} $pkg" PKGS_COUNT_REMERGE=$((PKGS_COUNT_REMERGE + 1)) fi done # # Use my super dumb package reordering algorithm that works most of the time # eloginfo "Re-ordering packages to merge .." DEPSORT=$(find_in_portdir "dev-lang/ghc/files/depsort.py") if [[ -z ${DEPSORT} ]]; then eerror "Fatal error: File dev-lang/ghc/files/depsort.py not in portage tree." exit 1 fi PKGS_OK_SORTED="$(${PORTAGE_PYTHON} ${DEPSORT} ${PKGS_OK} | xargs)" if [[ -n ${PRETEND} ]]; then eloginfo "These are the packages that would be merged, in order:" else eloginfo "Preparing to merge these packages in this order:" fi for pkg in $PKGS_OK_SORTED; do elogecho ">=$pkg" done # we emerge each package seperately to ensure we know exactly which ones might # cause an error, and then report it at the end COUNT=1 PKGS_FAILED="" if [ "${PRETEND}" != "1" ]; then for pkg in ${PKGS_OK_SORTED}; do eloginfo "Starting to merge ($COUNT/$PKGS_COUNT_REMERGE) $pkg .." if ! emerge --oneshot --nodeps '>='$pkg; then PKGS_FAILED="${PKGS_FAILED} $pkg" elogerr "Failed merging $pkg ($COUNT/$PKGS_COUNT_REMERGE)!" fi COUNT=$((COUNT+1)) done fi # final output stuff OUTPUT_PKGS_MASKED="" for pkg in ${PKGS_MASKED}; do OUTPUT_PKGS_MASKED="${OUTPUT_PKGS_MASKED} '>='$pkg"; done OUTPUT_PKGS_BLOCKED="" for pkg in ${PKGS_BLOCKED}; do OUTPUT_PKGS_BLOCKED="${OUTPUT_PKGS_BLOCKED} $pkg"; done OUTPUT_PKGS_MISSING="" for pkg in ${PKGS_MISSING}; do OUTPUT_PKGS_MISSING="${OUTPUT_PKGS_MISSING} $pkg"; done OUTPUT_PKGS_FAILED="" for pkg in ${PKGS_FAILED}; do OUTPUT_PKGS_FAILED="${OUTPUT_PKGS_FAILED} '>='$pkg"; done if [ -n "${PKGS_FAILED}" -o -n "${PKGS_MISSING}" -o -n "${PKGS_MASKED}" ]; then echo ewarn "************************************************************" ewarn "* Packages that still need to be manually emerged : *" ewarn "************************************************************" if [ -n "${OUTPUT_PKGS_MASKED}" ]; then echo ewarn " Masked Packages:" ewarn " ----------------" ewarn " Unmask the following packages (at your own risk) and " ewarn " emerge them using this command after removing the '-p'" ewarn " parameter." echo ewarn " emerge -p ${OUTPUT_PKGS_MASKED}" echo fi if [ -n "${OUTPUT_PKGS_BLOCKED}" ]; then echo ewarn " Blocked Packages:" ewarn " -----------------" ewarn " These packages are currently blocked; they might not yet" ewarn " be compatible with the current ghc. You can run ghc-updater" ewarn " again at a later time." echo for x in ${OUTPUT_PKGS_BLOCKED}; do echo " ${x}" done fi if [ -n "${OUTPUT_PKGS_MISSING}" ]; then echo ewarn " Missing Packages:" ewarn " -----------------" ewarn " These packages cannot be updated because they do not exist" ewarn " in portage anymore." echo for x in ${OUTPUT_PKGS_MISSING}; do echo " ${x}" done fi if [ -n "${OUTPUT_PKGS_FAILED}" ]; then echo ewarn " Failed Packages:" ewarn " ----------------" ewarn " These packages have failed and need to be re-emerged again." ewarn " Alternatively, try re-running this script again to see if it" ewarn " can be fixed." echo ewarn " emerge -p ${OUTPUT_PKGS_FAILED}" echo fi elog "GHC update completed with errors." elog "Masked Packages:" for x in ${PKGS_MASKED}; do elog $x done elog "Missing Packages:" for x in ${PKGS_MISSING}; do elog $x done elog "Failed Packages:" for x in ${PKGS_FAILED}; do elog $x done elog "Update script completed." else eloginfo "GHC update completed successfully." fi