diff --git a/scripts/acquire_pythons b/scripts/acquire_pythons deleted file mode 100755 index 7965371..0000000 --- a/scripts/acquire_pythons +++ /dev/null @@ -1,93 +0,0 @@ -#!/bin/bash - -# NOTE: This script has only been tested on a Debian 9 x86_64 system -- it -# is probably not as robust as it should be... - -old_pythons=('1.0.1' '1.1' '1.2' '1.3' '1.4' '1.5.2') -old_pyurl='https://legacy.python.org/download/releases/src' - -pythons=('2.0.1' '2.1.3' '2.2.3' '2.3.7' '2.4.6' '2.5.6' '2.6.9' '2.7.15' - '3.0.1' '3.1.5' '3.2.6' '3.3.7' '3.4.8' '3.5.5' '3.6.5') -py_url='https://www.python.org/ftp/python' - - -set -e - -srcdir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -startdir="$(pwd)" - -fetch_python() { - local url="$1" - local tarball="${url##*/}" - local version="$2" - - if [[ ! -d "Python-${version}" ]]; then - local tarfile="${srcdir}/tarballs/${tarball}" - if [[ ! -f "$tarfile" ]]; then - if [[ "$version" == "1.6.1" ]]; then - echo "Python 1.6.1 cannot be downloaded automatically due to a license agreement" - echo "which must be manually accepted." - echo "Please download it from https://www.python.org/download/releases/1.6.1/download/" - echo "and place the tarball in ${srcdir}/tarballs" - exit 1 - fi - echo "Downloading Python-${version}..." - ( cd "${srcdir}/tarballs" && curl -LfO# "$url" ) - fi - echo "Extracting Python-${version}..." - tar xaf "${srcdir}/tarballs/${tarball}" - [[ -d "python-${version}" ]] && mv "python-${version}" "Python-${version}" - if [[ -f "${srcdir}/python-builds/Python-${version}.patch" ]]; then - ( - cd "Python-${version}" && - patch -p1 -i "${srcdir}/python-builds/Python-${version}.patch" - ) - fi - fi -} - -build_python() { - local version="$1" - - if [[ ! -x "Python-${version}/python" ]]; then - echo "Configuring Python-${version}..." - rm -f "${startdir}/Python-${version}.conf.log" - ( - cd "Python-${version}" - if ! ./configure > "${startdir}/Python-${version}.conf.log" 2>&1; then - echo "... Configuration failed. See Python-${version}.conf.log for details" - exit 1 - fi - ) - - echo "Building Python-${version}..." - rm -f "${startdir}/Python-${version}.build.log" - ( - cd "Python-${version}" - if ! make > "${startdir}/Python-${version}.build.log" 2>&1; then - echo "... Configuration failed. See Python-${version}.build.log for details" - exit 1 - fi - ) - fi -} - -mkdir -p "${startdir}/tarballs" - -for ver in ${old_pythons[@]:0:2}; do - fetch_python "${old_pyurl}/python${ver}.tar.gz" "$ver" - build_python "$ver" -done -for ver in ${old_pythons[@]:2}; do - fetch_python "${old_pyurl}/python-${ver}.tar.gz" "$ver" - build_python "$ver" -done - -# 1.6.1 must be downloaded manually -fetch_python "https://INVALID_URL_FOR/Python-1.6.1.tar.gz" "1.6.1" -build_python "1.6.1" - -for ver in ${pythons[@]}; do - fetch_python "${py_url}/${ver}/Python-${ver}.tgz" "$ver" - build_python "$ver" -done diff --git a/scripts/pymultic b/scripts/pymultic index e15b5d0..3722a2f 100755 --- a/scripts/pymultic +++ b/scripts/pymultic @@ -5,67 +5,140 @@ import os import sys import subprocess import shutil +import re -pythons1 = [ - 'Python-1.0.1', - 'Python-1.1', - 'Python-1.2', - 'Python-1.3', - 'Python-1.4', - 'Python-1.5.2', - 'Python-1.6.1', -] +PYVERS = { + '1.0': '1.0.1', + '1.1': '1.1', + '1.2': '1.2', + '1.3': '1.3', + '1.4': '1.4', + '1.5': '1.5.2', + '1.6': '1.6.1', + '2.0': '2.0.1', + '2.1': '2.1.3', + '2.2': '2.2.3', + '2.3': '2.3.7', + '2.4': '2.4.6', + '2.5': '2.5.6', + '2.6': '2.6.9', + '2.7': '2.7.16', + '3.0': '3.0.1', + '3.1': '3.1.5', + '3.2': '3.2.6', + '3.3': '3.3.7', + '3.4': '3.4.10', + '3.5': '3.5.7', + '3.6': '3.6.9', + '3.7': '3.7.4', +} -pythons2 = [ - 'Python-2.0.1', - 'Python-2.1.3', - 'Python-2.2.3', - 'Python-2.3.7', - 'Python-2.4.6', - 'Python-2.5.6', - 'Python-2.6.9', - 'Python-2.7.15', -] +OLD_PYTHONS = ('1.0', '1.1', '1.2', '1.3', '1.4', '1.5') +OLD_PYURL = 'https://legacy.python.org/download/releases/src' +PYURL = 'https://www.python.org/ftp/python' + + +def fetch_python(snekdir, version): + realver = PYVERS[version] + if version in ('1.0', '1.1'): + tarball = 'python{}.tar.gz'.format(realver) + url = '{}/{}'.format(OLD_PYURL, tarball) + elif version in ('1.2', '1.3', '1.4', '1.5'): + tarball = 'python-{}.tar.gz'.format(realver) + url = '{}/{}'.format(OLD_PYURL, tarball) + elif version == '1.6': + tarball = 'Python-{}.tar.gz'.format(realver) + url = None + else: + tarball = 'Python-{}.tgz'.format(realver) + url = '{}/{}/{}'.format(PYURL, realver, tarball) + + pyver_dir = 'Python-{}'.format(realver) + if os.path.exists(pyver_dir): + return + + tb_dir = os.path.join(snekdir, 'tarballs') + tarfile = os.path.join(tb_dir, tarball) + if not os.path.exists(tarfile): + if version == '1.6': + print('Python 1.6.1 cannot be downloaded automatically due to a license agreement') + print('which must be manually accepted.') + print('Please download it from https://www.python.org/download/releases/1.6.1/download/') + print('and place the tarball in {}'.format(tb_dir)) + sys.exit(1) + + print('Downloading Python {}...'.format(realver)) + if subprocess.call(['curl', '-LfO#', url], cwd=tb_dir) != 0: + sys.exit(1) + + print('Extracting Python {}...'.format(realver)) + if subprocess.call(['tar', 'xaf', tarfile]) != 0: + sys.exit(1) + + if os.path.exists('python-{}'.format(realver)) \ + and not os.path.exists(pyver_dir): + # The dual check prevents useless renames on case-insensitive + # file systems + os.rename('python-{}'.format(realver), pyver_dir) + + patch_file = '{}/python-builds/Python-{}.patch'.format(snekdir, realver) + if os.path.exists(patch_file): + if subprocess.call(['patch', '-p1', '-i', patch_file], cwd=pyver_dir) != 0: + sys.exit(1) + + +def build_python(snekdir, version): + realver = PYVERS[version] + snek = 'Python-{}'.format(realver) + builddir = os.path.join(snekdir, snek) + + # NOTE: This has only been tested on a Debian 10 x86_64 system -- it is + # probably not as robust as it should be... + print('Configuring Python {}...'.format(realver)) + logfile = os.path.join(snekdir, '{}.conf.log'.format(snek)) + with open(logfile, 'wb') as log: + if subprocess.call(['./configure'], stdout=log, stderr=log, cwd=builddir) != 0: + print('... Configuration failed. See {} for details'.format(logfile)) + sys.exit(1) + + print('Building Python {}...'.format(realver)) + logfile = os.path.join(snekdir, '{}.build.log'.format(snek)) + with open(logfile, 'wb') as log: + if subprocess.call(['make'], stdout=log, stderr=log, cwd=builddir) != 0: + print('... Build failed. See {} for details'.format(logfile)) + sys.exit(1) + + +def acquire_python(snekdir, version): + snek = 'Python-{}'.format(PYVERS[version]) + pyexe = os.path.join(snekdir, snek, 'python') + if not os.path.exists(pyexe): + fetch_python(snekdir, version) + build_python(snekdir, version) + return pyexe -pythons3 = [ - 'Python-3.0.1', - 'Python-3.1.5', - 'Python-3.2.6', - 'Python-3.3.7', - 'Python-3.4.8', - 'Python-3.5.5', - 'Python-3.6.5', -] if len(sys.argv) < 2: - print('Usage: {} [options] input.py'.format(sys.argv[0])) - print('Compile input.py for many pythons') + print('Usage: {} [versions] input.py'.format(sys.argv[0])) + print('Compile input.py for one or more python versions') print('Output is written to input..pyc for each version successfully compiled') print() - print('Options:') - print(' -1 Compile for Python 1.x only') - print(' -2 Compile for Python 2.x only') - print(' -12 Compile for Python 1.x and 2.x versions (default)') - print(' -3 Compile for Python 3.x only') - print(' -23 Compile for Python 2.x and 3.x versions') - print(' -A Attempt to compile for all known python versions') + print('Version is X.Y (e.g. 3.4), not including the patch version') sys.exit(1) -pythons = pythons1 + pythons2 +RE_PYVER = re.compile(r'\d\.\d') + +pythons = [] infile = None for arg in sys.argv[1:]: - if arg == '-1': - pythons = pythons1 - elif arg == '-2': - pythons = pythons2 - elif arg == '-12': - pythons = pythons1 + pythons2 - elif arg == '-3': - pythons = pythons3 - elif arg == '-23': - pythons = pythons2 + pythons3 - elif arg == '-A': - pythons = pythons1 + pythons2 + pythons3 + if RE_PYVER.match(arg): + if arg in PYVERS.keys(): + pythons.append(arg) + else: + print('Unknown Python version: {}'.format(arg)) + sys.exit(1) + elif arg.startswith('-'): + print("WARNING: Unrecognized argument '{}'".format(arg)) else: infile = arg @@ -76,26 +149,34 @@ elif not os.path.exists(infile): print('Error: Input file {} does not exist'.format(infile)) sys.exit(1) +if len(pythons) == 0: + print('At least one Python version is required') + sys.exit(1) + snekdir = os.path.dirname(os.path.realpath(__file__)) -for snek in pythons: - pyexe = os.path.join(snekdir, snek, 'python') +for ver in pythons: + pyexe = acquire_python(snekdir, ver) proc = subprocess.Popen([pyexe, '-c', 'import sys; print(sys.version)'], stdout=subprocess.PIPE) out, _ = proc.communicate() if proc.returncode != 0: - print('Could not determine Python version for {}'.format(snek)) + print('Could not determine Python version for {}'.format(ver)) + continue + + bcver = str(out, 'iso-8859-1').split(' ', 1)[0] + if not bcver.startswith(ver): + print('Python {} reported itself as version {}!'.format(ver, bcver)) continue - bcver = str(out[:3], 'iso-8859-1') if '.py' in infile: - outfile = infile.replace('.py', '.{}.pyc'.format(bcver)) + outfile = infile.replace('.py', '.{}.pyc'.format(ver)) else: - outfile = infile + '.{}.pyc'.format(bcver) + outfile = infile + '.{}.pyc'.format(ver) if os.path.exists(outfile): os.unlink(outfile) - print('*** Compiling for {}'.format(snek)) - if bcver in {'1.0', '1.1', '1.2', '1.3', '1.4'}: + print('*** Compiling for Python {}'.format(bcver)) + if ver in {'1.0', '1.1', '1.2', '1.3', '1.4'}: # The hard way -- hope your code is safe... srcdir = os.path.dirname(os.path.realpath(infile)) comptmp = os.path.join(srcdir, 'pymc_temp.py')