[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: The Python Registrar



On Sat, Feb 23, 2002 at 10:38:17AM +1100, Donovan Baarda wrote:
> On Tue, Feb 12, 2002 at 12:05:22AM +0100, Bastian Kleineidam wrote:
> > Hello.
> > 
> > The first version of the python-central package is online at
> > http://people.debian.org/~calvin/python-central/
> > 
> > It provides support for installing pure Python modules independent
> > of the Python version (see Python Policy 2.2.3).
[...]
> Did you see my analysis and modified "register-python-package" script? I
> posted it under a misleading subject by mistake (responded to another thread
> that migrated onto it).

OK, I got creative and figured out a way the python-central could work
without using an emac's style registry, instead just using the existing dpkg
"Depends:" information.

This new version of register-python-package has shrunk to under 180 lines,
and is much simplified over the original. The usage has been reduced to;

usage: ./register-python-package {configure|remove} <package name>

It will determine if it is configure/removing a python version or python
module from the package name. Any package that contains *.py files in
/usr/lib/python/site-packages is assumed to be multi-version python module.
The versions of python that a multi-version python module supports is
determined by the  "pythonX.Y" entries in the package's "Depends:". 

An example for a python-foo module that works for python version 1.5->2.1
would have the following dependancies;

  Depends: python1.5 | python1.6 | python2.0 | python2.1, python-central

Any python package with python-central support, including pythonX.Y
packages, would call in it's postinst;

  register-python-package configure <package-name>
  
and in its prerm would call;

  register-python-package remove <package-name>

For a pythonX.Y package, installing will symlink and compile all modules
with files in /usr/lib/python/site-packages that have compable dependancies.
For a python-foo package, installing will symlink and compile the module for
all installed and compatible python versions. Removing will do the correct
inverse.

Comments welcome. This one is a bit more tested than the last.

-- 
----------------------------------------------------------------------
ABO: finger abo@minkirri.apana.org.au for more info, including pgp key
----------------------------------------------------------------------
#!/bin/sh
# the python registrar

# directory with registered packages
CENTRAL=/var/lib/python-central
# python command to byte-compile a file
BYTECOMP="import sys,py_compile;py_compile.compile(sys.argv[1],sys.argv[2])"
# directory for installed .py files
IN=/usr/lib/python/site-packages


# get_modules <pythonX.Y package>
# return installed multi-version python packages that work for the 
# specified python package
get_modules() {
    PYTHONXY=$1
    RET=""
    for p in `dpkg -S /usr/lib/python/site-packages 2>/dev/null | sed 's#,\|:.*$##g'`; do
        if dpkg -s $p | egrep "^Depends:.* $PYTHONXY([ ,]|$)" >/dev/null 2>&1; then
	    RET="$RET $p"
	fi
    done
}


# get_versions <package name>
# return installed versions of python supported by the python package
get_versions () {
    DEPENDS=`dpkg -s $1 | grep "^Depends:" | cut -d: -f2`
    RET=""
    for PYTHONXY in `ls /usr/bin/python?.? | cut -c 10-`; do
	if echo "$DEPENDS" | egrep " $PYTHONXY([ ,]|$)" >/dev/null 2>&1; then
            RET="$RET $PYTHONXY"
        fi
    done
}


# module_compile <package name> <pythonX.Y package>
# symlinks and compiles a package for the specified python version 
module_compile () {
    PACKAGE=$1
    PYTHONXY=$2
    PYTHON=/usr/bin/$PYTHONXY
    OUT=/usr/lib/$PYTHONXY/site-packages
    # look for .py files in the package
    for i in `dpkg --listfiles $PACKAGE | grep "^$IN/.*\.py$" | sed "s#^$IN/##"`; do
        # install potentially missing (sub)directories
        DIRNAME=`dirname $OUT/$i`
        install -d -o root -g root -m 0755 $DIRNAME
        # make relative link
        REL="../.."
        while [ $DIRNAME != $OUT ]; do
            REL=../$REL
            DIRNAME=`dirname $DIRNAME`
            # prevent infinite loops
            if [ "$DIRNAME" = "/" -o "$DIRNAME" = "." ]; then
                exit 1
            fi
        done
        # REL points to /usr/lib now
        ln -sf $REL/python/site-packages/$i $OUT/$i
        # byte-compile package .py files
        $PYTHON -O -c "$BYTECOMP" $OUT/$i $OUT/${i}o
        $PYTHON -c "$BYTECOMP" $OUT/$i $OUT/${i}c
        # fix output file mode
        chmod 0644 $OUT/${i}[co] || true
    done
}


# module_clean <package name> <pythonX.Y package>
# removes symlinks and bytecode of a package for the specified python version
module_clean() {
    # remove symlink and byte-compiled files
    PACKAGE=$1
    PYTHONXY=$2
    OUT=/usr/lib/$PYTHONXY/site-packages
    for i in `dpkg --listfiles $PACKAGE | grep "^$IN/.*\.py$" | sed "s#^$IN/##"`; do
        rm -f $OUT/$i $OUT/${i}c $OUT/${i}o
    done
    # remove directories
    for i in `dpkg --listfiles $PACKAGE | grep "^$IN/" | sort -r | sed "s#^$IN/##"`; do
        if [ -d $OUT/$i ]; then
            rmdir $OUT/$i || true
        fi
    done
}


# module_configure <package name>
# configure a module for all supported installed python versions
module_configure () {
    PACKAGE=$1
    get_versions $PACKAGE
    versions=$RET
    for pyver in $versions; do
        module_compile $PACKAGE $pyver
    done
}


# module_remove <package name>
# remove a configured module for all supported installed python versions
module_remove () {
    PACKAGE=$1
    get_versions $PACKAGE
    versions=$RET
    for pyver in $versions; do
        module_clean $PACKAGE $pyver
    done
}


# python_configure <pythonX.Y package>
# byte-compile this python version plus all supported packages
python_configure () {
    PYTHONXY=$1
    PYTHON=/usr/bin/$PYTHONXY
    PYLIBS=/usr/lib/$PYTHONXY
    # byte-compile all python files
    $PYTHON -O $PYLIBS/compileall.py -q $PYLIBS
    $PYTHON $PYLIBS/compileall.py -q $PYLIBS
    # byte-compile registered packages
    get_modules $PYTHONXY
    modules=$RET
    for p in $modules; do
        module_compile $p $PYTHONXY
    done
}


# python_remove <pythonX.Y package>
# remove byte-compiled files for this python version and for all
# supported python packages
python_remove () {
    PYTHONXY=$1
    PYTHON=/usr/bin/$PYTHONXY
    # remove byte-compiled files for this python version
    dpkg --listfiles $PYTHONXY |
        awk '$0~/\.py$/ {print $0"c\n" $0"o"}' |
        xargs rm -f >&2
    # remove registered packages
    get_modules $PYTHONXY
    modules=$RET
    for p in $modules; do
        module_clean $p $PYTHONXY
    done
}


usage () {
    echo "usage: $0 {configure|remove} <package name>"
    exit 1
}


###############################################################
################         main        ##########################
###############################################################
action=$1
if echo $2 | egrep '^python[0-9]\.[0-9]$' >/dev/null 2>&1; then
     mode="python"
else
     mode="module"
fi
if [ "$action" = "configure" ]; then
    ${mode}_configure $2
elif [ "$action" = "remove" ]; then
    ${mode}_remove $2
else
    usage
fi

Reply to: