Source

slp-installer / C4_linux-x86_64_2.7 / slpInstaller / __init__.py

Full commit
#
# Copyright 2013 Anselm Kruis
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.

"""
Installer for Stackless Python (Windows)

This distribution adds a Stackless Python executable to an existing
CPython installation.
"""

from __future__ import absolute_import

import argparse
import sysconfig
import sys
import atexit
from os.path import join, normpath, dirname, basename, abspath
from os import remove as os_remove, walk, chmod
from distutils.file_util import copy_file
from distutils.dir_util import copy_tree, mkpath, remove_tree
from distutils.util import get_platform, byte_compile
from distutils import log
from pkg_resources import (resource_filename, cleanup_resources)

# we need the correct lib directory. The os module works fine
from os import __file__ as os__file__

UCS=4
PLATFORM="linux-x86_64"
STACKLESS_VERSION = (2,7,4)
INSTALLER_VERSION = (0,2)

INSTALLER_VERSION_STR = ".".join(map(str,STACKLESS_VERSION + INSTALLER_VERSION))

       
# Build the shared library for Linux
EPREFIX="/EXEC_PREFIX-DOES-NOT-EXSIST"
PREFIX="/PREFIX-DOES-NOT-EXSIST"

def _setValueInBytes(bytes, marker, value):
    lMarker = len(marker)
    lValue  = len(value)
    if lMarker < lValue:
        marker += "-" * (lValue - lMarker)
        l = lValue
    else:
        value += "\x00" * (lMarker - lValue)
        l = lMarker
    assert len(marker) == len(value)
    assert len(marker) == l
        
    i = 0
    while True:
        i = bytes.find(marker, i)
        if -1 == i:
            break
        bytes[i:i+l] = value
        bytes[i+l] = 0

        
def build_pylib_linux(src, dstDir, stdArgs):
    with open(src, "rb") as s:
        lib = bytearray(s.read())
    _setValueInBytes(lib, PREFIX, sysconfig.get_config_var("prefix"))
    _setValueInBytes(lib, EPREFIX, sysconfig.get_config_var("exec_prefix"))
    
    target = join(dstDir, basename(src))
    mkpath(dstDir, **stdArgs)
    log.info("creating library %s", target)
    if not stdArgs['dry_run']:
        with open(target, "wb") as t:
            t.write(lib)

def remove_file(path, verbose=1, dry_run=0):
    if verbose >= 1:
        log.info("removing '%s'", path)
    if not dry_run:
        os_remove(path)


def main(args, default="install"):
    
    parser = argparse.ArgumentParser(description='Install or uninstall stackless python')
    parser.add_argument('--verbose', '-v', dest='verbose', action='append_const', const=True, help="run verbosely (default)")
    parser.add_argument('--quiet', '-q', dest='verbose', action='store_const', const=[], default=argparse.SUPPRESS, help="run quietly (turns verbosity off)")
    parser.add_argument('--dry-run', '-n', dest='dry_run', action='store_true', help="don't actually do anything")
    parser.add_argument('command', choices=['install', 'uninstall'], action='store', nargs='?', default=default)
    
    parsed = parser.parse_args(args=args)
    parsed.verbose = 1 if parsed.verbose is None else len(parsed.verbose)
    log.set_verbosity(parsed.verbose)
    
    if get_platform() != PLATFORM:
        raise RuntimeError("This package is for %s only. It does not work on %s" % (PLATFORM, get_platform()))
    currentUcs = 4 if sys.maxunicode >> 16 else 2
    if currentUcs != UCS:
        raise RuntimeError("This package requires ucs%d but your Python interpreter provides ucs%d" % (UCS, currentUcs))

    # standard arguments of various functions from distutils    
    stdArgs = dict(verbose=parsed.verbose, dry_run=parsed.dry_run)
    
    arch = PLATFORM
    assembly="lib.stackless"
    slPython = 'slpython%s.%s' % STACKLESS_VERSION[:2]
    pybindest = dirname(abspath(sys.executable))
    pylibdest = join(pybindest, assembly)
    pybindest = join(pybindest, slPython)
    stacklessPackages = join(dirname(abspath(os__file__)), "stackless-packages")

    if parsed.command == 'install':
        # get the binary resources
        atexit.register(cleanup_resources)
        src = resource_filename(__name__, arch)
        # copy the executable
        pyexe = join(src, slPython)
        copy_file(pyexe, pybindest, **stdArgs)
        chmod(pybindest, 0755)
        # copy and modify the lib
        pylib = join(src, assembly, "libpython%s.%s.so.1.0sl" % STACKLESS_VERSION[:2] )
        build_pylib_linux(pylib, pylibdest, stdArgs)
        
        # get the binary resources
        src = resource_filename(__name__, 'Lib')
        copy_tree(src, stacklessPackages, **stdArgs)
        
        # byte compile sources
        pyFiles = [] 
        for root, dirs, files in walk(stacklessPackages):
            pyFiles.extend(join(root, f) for f in files if f.endswith('.py'))
        byte_compile(pyFiles, optimize=False, prefix=stacklessPackages, force=1, **stdArgs)

    elif parsed.command == 'uninstall':
        # remove the executable and the shared library
        remove_file(pybindest, **stdArgs)
        remove_tree(pylibdest, **stdArgs)
        # remove the lib
        remove_tree(stacklessPackages, **stdArgs)
        
    else:
        raise ValueError("Unsupported command: " + parsed.command)


def main_install():
    return main(args=sys.argv[1:], default='install')
def main_uninstall():
    return main(args=sys.argv[1:], default='uninstall')

if __name__ == '__main__':
    sys.exit(main(args=sys.argv[1:]))