summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'python-updater')
-rwxr-xr-xpython-updater414
1 files changed, 414 insertions, 0 deletions
diff --git a/python-updater b/python-updater
new file mode 100755
index 0000000..dff71fb
--- /dev/null
+++ b/python-updater
@@ -0,0 +1,414 @@
+#!/bin/bash
+# vim: set et sw=4 sts=4 tw=80:
+# Copyright 2007-2008 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# A bit of hackery to update everything that is humanly possible
+# that maybe related to an older version of python. This script can
+# be run as many times as you like.
+#
+# OLD_PY_VER = old python version we are upgrading from
+# NEW_PY_VER = new python 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 (eg. ones that have python compiled
+# statically)
+#
+# 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.
+#
+
+VERSION="0.6"
+NEW_PY_VER=$(python -V 2>&1 | sed 's:Python ::' | cut -d. -f1-2)
+
+PKGS_EXCEPTIONS="dev-lang/python sys-apps/portage"
+PKGS_MANUAL="app-office/gnumeric app-office/dia dev-libs/boost x11-libs/vte"
+
+PRETEND=0
+IGNORE_VERSIONS=0
+VERBOSE=0
+PKGS_TO_REMERGE=""
+PKGS_COUNT_REMERGE=0
+PORTAGE_PYTHON="/usr/bin/python"
+
+SUPPORTED_PMS="portage pkgcore paludis"
+PMS_COMMAND=( "emerge" "pmerge" "paludis" )
+PMS_OPTIONS=( "-vD1" "-Do" "-i1" )
+
+# Checks
+CHECK_ECLASS=0
+CHECK_MANUAL=1
+CHECK_PYLIBDIR=1
+CHECK_SONAME=1
+
+# load the gentoo-style info macros, but hack to get around
+# it thinking this is an rc script
+EBUILD="1"
+source /etc/init.d/functions.sh
+
+# portage variables
+PKG_DBDIR=/var/db/pkg
+
+# usage()
+# display usage
+usage() {
+ cat <<EOF_USAGE
+${0##*/} -- Find & rebuild packages broken due to a python upgrade
+
+Usage: python-updater [OPTION]
+
+Options:
+ -h, --help Print usage
+ -V, --version Print version
+ -p, --pretend Pretend (don't do anything)
+ -v, --verbose Increase verbosity (may be specified multiple times)
+ -o PYVER, --old-version PYVER
+ Set old python version to upgrade from to PYVER
+ -i, --ignore-versions
+ Ignore versions when remerging packages
+ (still respects SLOTs)
+ -P PM, --package-manager PM
+ Use package manager PM, where PM can be one of:
+$(for p in ${SUPPORTED_PMS} ; do
+echo -ne $'\t\t '\* ${p}
+if [[ ${p} == portage ]]; then
+ echo ' (Default)'
+else
+ echo
+fi
+done)
+ -c CMD, --command CMD
+ Pipe found packages to command CMD instead of invoking package
+ manager. Only for debug and script use.
+ -eCHECK --enable-CHECK
+ Enable CHECK where CHECK can be one of:
+ * eclass (Disabled by default)
+ * pylibdir (Enabled by default)
+ * soname (Enabled by default)
+ * manual (Enabled by default)
+ -dCHECK --disable-CHECK
+ Disable CHECK. See --enable option for a list of checks
+
+See CHECKS section in the manpage for explanations about checks and
+EXAMPLES section to learn how to use them.
+EOF_USAGE
+}
+
+# veinfo(verbosity, message)
+# einfo message if VERBOSE is bigger than verbosity
+veinfo() {
+ if [[ VERBOSE -ge $1 ]]; then
+ shift
+ einfo $@
+ fi
+}
+
+# get_old_pyver()
+# Find old python version, return non-zero if not found
+get_old_pyver() {
+ for old in 2.5 2.4 2.3 2.2 2.1; do
+ if [[ "${old}" != "${NEW_PY_VER}" && -e /usr/bin/python${old} ]]
+ then
+ echo -n "${old}"
+ return 0
+ fi
+ done
+ eerror "Couldn't determine any previous Python version(s)."
+ eerror "Use -o OLD_PYTHON_VERSION to specify your old python version."
+ return 1
+}
+
+# get_portage_python(oldpy=2.4,newpy=2.5)
+# Find where portage is, in python2.2 or somewhere else?
+get_portage_python() {
+ local oldpy newpy
+ if [[ ! -z "$1" ]]; then
+ oldpy="$1"
+ else
+ oldpy=2.4
+ fi
+
+ if [ ! -z "$2" ]; then
+ newpy="$2"
+ else
+ newpy=2.5
+ fi
+
+ pybin=/usr/bin/python
+ for py in ${pybin} ${pybin}${oldpy} ${pybin}${newpy}; do
+ if ${py} -c "import portage" > /dev/null 2>&1; then
+ echo -n "${py}"
+ return 0
+ fi
+ done
+ eerror "Couldn't determine portage python"
+ return 1
+}
+
+# get_portage_portdir()
+# Check if portage knows about PORTDIR and return it
+get_portage_portdir() {
+ local portdir="$(/usr/bin/portageq portdir)"
+
+ if [[ -z "${portdir}" ]]; then
+ eerror "Unable to proceed. Can not find PORTDIR. Make sure the command:"
+ eerror " "
+ eerror " portageq portdir"
+ 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/"
+ return 1
+ else
+ echo -n "${portdir}"
+ return 0
+ fi
+}
+
+# Respect PYUPDATER_OPTIONS
+if [[ -n "${PYUPDATER_OPTIONS}" ]]; then
+ set -- ${PYUPDATER_OPTIONS} $@
+fi
+
+# Command Line Parsing
+while [[ -n "$1" ]]; do
+ case "$1" in
+ -h|--help)
+ usage
+ exit 0
+ ;;
+ -V|--version)
+ echo "${VERSION}"
+ exit 0
+ ;;
+ -p|--pretend)
+ PRETEND=1
+ ;;
+ -v|--verbose)
+ VERBOSE=$(( $VERBOSE + 1 ))
+ ;;
+ -o|--old-version)
+ shift
+ OLD_PY_VER="$1"
+ ;;
+ -i|--ignore-versions)
+ IGNORE_VERSIONS=1
+ ;;
+ -P|--package-manager)
+ shift
+ PACKAGE_MANAGER="$1"
+ case "${PACKAGE_MANAGER}" in
+ portage|pkgcore|paludis)
+ ;;
+ *)
+ echo "unrecognised package manager selected. please select between ${SUPPORTED_PMS}"
+ exit
+ ;;
+ esac
+
+ # PMS_INDEX is used to select the right commands and options for the selected package manager
+ PMS_INDEX=0
+ for PM in ${SUPPORTED_PMS}; do
+ [[ ${PM} == ${PACKAGE_MANAGER} ]] && break
+ PMS_INDEX=$((${PMS_INDEX} + 1))
+ done
+ ;;
+ -c|--command)
+ shift
+ PIPE_COMMAND="$1"
+ ;;
+ -ee*|--enable-e*)
+ CHECK_ECLASS=1
+ ;;
+ -de*|--disable-e*)
+ CHECK_ECLASS=0
+ ;;
+ -em*|--enable-m*)
+ CHECK_MANUAL=1
+ ;;
+ -dm*|--disable-m*)
+ CHECK_MANUAL=0
+ ;;
+ -ep*|--enable-p*)
+ CHECK_PYLIBDIR=1
+ ;;
+ -dp*|--disable-p*)
+ CHECK_PYLIBDIR=0
+ ;;
+ -es*|--enable-s*)
+ CHECK_SONAME=1
+ ;;
+ -ds*|--disable-s*)
+ CHECK_SONAME=0
+ ;;
+ *)
+ usage
+ echo "unrecognised option: $1"
+ exit 0
+ ;;
+ esac
+ shift
+done
+
+# Sanity check
+PORTDIR="$(get_portage_portdir)"
+[[ $? != 0 ]] && exit 1
+
+# Determine old python version
+if [[ -z "${OLD_PY_VER}" ]]; then
+ OLD_PY_VER="$(get_old_pyver)"
+ if [[ $? != 0 ]]; then
+ exit 1
+ fi
+fi
+
+# Get portage python
+PORTAGE_PYTHON="$(get_portage_python ${OLD_PY_VER} ${NEW_PY_VER})"
+[[ $? != 0 ]] && exit 1
+
+
+einfo "Starting Python Updater from ${OLD_PY_VER} to ${NEW_PY_VER} :"
+if [[ CHECK_SONAME -ne 0 ]]; then
+ if ! type -P scanelf >/dev/null 2>&1; then
+ ewarn "scanelf not found!"
+ ewarn "check soname is disabled."
+ CHECK_SONAME=0
+ else
+ veinfo 1 'check "soname" enabled.'
+ OLD_SONAME="$(readlink -n /usr/lib/libpython${OLD_PY_VER}.so)"
+ if [[ -z "${OLD_SONAME}" ]]; then
+ ewarn "Couldn't find old libpython soname"
+ ewarn "Disabling soname check."
+ CHECK_SONAME=0
+ fi
+ fi
+else
+ veinfo 1 'check "soname" disabled.'
+fi
+[[ CHECK_PYLIBDIR -ne 0 ]] \
+ && veinfo 1 'check "pylibdir" enabled.' \
+ || veinfo 1 'check "pylibdir" disabled.'
+[[ CHECK_ECLASS -ne 0 ]] \
+ && veinfo 1 'check "eclass" enabled.' \
+ || veinfo 1 'check "eclass" disabled.'
+[[ CHECK_MANUAL -ne 0 ]] \
+ && veinfo 1 'check "manual" enabled.' \
+ || veinfo 1 'check "manual" disabled.'
+
+# 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:")
+ CATPKG="${CATPKGVER%%-[0-9]*}"
+ veinfo 2 "Checking ${CATPKGVER}"
+
+ # exclude packages that are an exception, like portage and python itself.
+ exception=0
+ for exp in ${PKGS_EXCEPTIONS}; do
+ if [[ -z "${CATPKG##${exp}}" ]]; then
+ veinfo 2 "Skipping ${CATPKG}, reason: exception"
+ exception=1
+ break;
+ fi
+ done
+
+ [[ ${exception} == 1 ]] && continue
+
+ # Check if package is in PKGS_MANUAL
+ if [[ CHECK_MANUAL -ne 0 ]]; then
+ for pkg in ${PKGS_MANUAL}; do
+ if [ -z "${CATPKG##${pkg}}" ]; then
+ exception=2
+ break;
+ fi
+ done
+ fi
+
+ # replace version number by SLOT if IGNORE_VERSIONS != 0
+ # Don't ignore versions when SLOT doesn't exist, bug 201848
+ if [[ IGNORE_VERSIONS -ne 0 && -f "${content/CONTENTS/SLOT}" ]]; then
+ SLOT=$(< ${content/CONTENTS/SLOT})
+ CATPKGVER="${CATPKG}:${SLOT}"
+ else
+ CATPKGVER="=${CATPKGVER}"
+ fi
+
+ if [[ ${exception} = 2 ]]; then
+ PKGS_TO_REMERGE="${PKGS_TO_REMERGE} ${CATPKGVER}"
+ eindent
+ einfo "Adding to list: ${CATPKGVER}"
+ eindent
+ einfo "check: manual [Added to list manually, see CHECKS in manpage for more information.]"
+ eoutdent && eoutdent
+ continue
+ fi
+
+ if [[ CHECK_PYLIBDIR -ne 0 ]]; then
+ # Search for possible old python dirs in CONTENTS
+ # /usr/include/python$old
+ # /usr/lib/python$old
+ # /usr/lib32/python$old
+ # /usr/lib64/python$old
+ if grep -qe "/usr/\(include\|lib\(32\|64\)\?\)/python${OLD_PY_VER}" ${content}; then
+ PKGS_TO_REMERGE="${PKGS_TO_REMERGE} ${CATPKGVER}"
+ eindent
+ einfo "Adding to list: ${CATPKGVER}"
+ eindent
+ veinfo 1 "check: pylibdir [ Installed file under old python library directory ]"
+ eoutdent && eoutdent
+ continue
+ fi
+ fi
+
+ if [[ CHECK_SONAME -ne 0 ]]; then
+ broken_libs="$(scanelf -qBN ${OLD_SONAME} < <(
+ grep -e '^obj' ${content} | cut -d' ' -f2))"
+ if [[ -n "${broken_libs}" ]]; then
+ PKGS_TO_REMERGE="${PKGS_TO_REMERGE} ${CATPKGVER}"
+ eindent
+ einfo "Adding to list: ${CATPKGVER}"
+ eindent
+ veinfo 1 "check: soname [ Libraries linked to old libpython found:"
+ veinfo 1 "${broken_libs}"
+ veinfo 1 "]"
+ eoutdent && eoutdent
+ fi
+ fi
+
+ if [[ CHECK_ECLASS -ne 0 ]]; then
+ ENVIRON="${content/CONTENTS/environment.bz2}"
+ if bzip2 -dc ${ENVIRON} | grep -qe "^\(export \)\?PYVER=${OLD_PY_VER}"; then
+ PKGS_TO_REMERGE="${PKGS_TO_REMERGE} ${CATPKGVER}"
+ eindent
+ einfo "Adding to list: ${CATPKGVER}"
+ eindent
+ veinfo 1 "check: eclass [ Ebuild set PYVER=${OLD_PY_VER} ]"
+ eoutdent && eoutdent
+ continue
+ fi
+ fi
+done
+
+# Pipe to command if we have one
+if [[ -n "${PIPE_COMMAND}" ]]; then
+ echo "${PKGS_TO_REMERGE}" | ${PIPE_COMMAND}
+ exit $?
+fi
+
+# only pretending?
+[[ PRETEND -eq 1 ]] && PMS_OPTIONS[${PMS_INDEX}]="${PMS_OPTIONS[${PMS_INDEX}]}p"
+
+# (Pretend to) remerge packages
+if [[ -n "${PKGS_TO_REMERGE}" ]]; then
+ cmd="${PMS_COMMAND[${PMS_INDEX}]} ${PMS_OPTIONS[${PMS_INDEX}]} ${PKGS_TO_REMERGE}"
+ einfo ${cmd}
+ ${cmd}
+else
+ einfo "No packages needs to be remerged."
+fi
+