Adds container support to pymultic
Using the '-c' argument will - if possible - fetch and use a container for each version of Python specified in the arguments list.
This commit is contained in:
139
scripts/pymultic
139
scripts/pymultic
@@ -33,12 +33,17 @@ PYVERS = {
|
||||
'3.7': '3.7.10',
|
||||
'3.8': '3.8.9',
|
||||
'3.9': '3.9.4',
|
||||
'3.10': '3.10.0',
|
||||
}
|
||||
|
||||
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'
|
||||
|
||||
# Minimum version of Python with a pre-built container.
|
||||
PYVER_CONTAINER_MIN = '2.7'
|
||||
USE_CONTAINERS = False
|
||||
|
||||
|
||||
def fetch_python(snekdir, version):
|
||||
realver = PYVERS[version]
|
||||
@@ -122,58 +127,19 @@ def acquire_python(snekdir, version):
|
||||
return pyexe
|
||||
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
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.<version>.pyc for each version successfully compiled')
|
||||
print()
|
||||
print('Version is X.Y (e.g. 3.4), not including the patch version')
|
||||
sys.exit(1)
|
||||
|
||||
RE_PYVER = re.compile(r'\d\.\d')
|
||||
|
||||
pythons = []
|
||||
infile = None
|
||||
for arg in sys.argv[1:]:
|
||||
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
|
||||
|
||||
if infile is None:
|
||||
print('No input file specified')
|
||||
sys.exit(1)
|
||||
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__))
|
||||
result = 0
|
||||
for ver in pythons:
|
||||
def local_compile(snekdir, ver, infile):
|
||||
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(ver))
|
||||
result = 1
|
||||
continue
|
||||
return None
|
||||
|
||||
bcver = str(out, 'iso-8859-1').split(' ', 1)[0]
|
||||
if not bcver.startswith(ver):
|
||||
print('Python {} reported itself as version {}!'.format(ver, bcver))
|
||||
result = 1
|
||||
continue
|
||||
return None
|
||||
|
||||
if infile.endswith('.py'):
|
||||
outfile = os.path.basename(infile)[:-3]
|
||||
@@ -210,7 +176,94 @@ for ver in pythons:
|
||||
.format(infile, outfile)])
|
||||
proc.communicate()
|
||||
|
||||
if not os.path.exists(outfile):
|
||||
return outfile
|
||||
|
||||
|
||||
def container_compile(snekdir, ver, infile):
|
||||
if ver < PYVER_CONTAINER_MIN:
|
||||
print('Container compilation requires a Python version >= {}'.format(PYVER_CONTAINER_MIN))
|
||||
return None
|
||||
|
||||
if shutil.which('docker') is None:
|
||||
print('Cannot find docker in $PATH')
|
||||
return None
|
||||
|
||||
fullver = PYVERS[ver]
|
||||
|
||||
if infile.endswith('.py'):
|
||||
outfile = os.path.basename(infile)[:-3]
|
||||
else:
|
||||
outfile = os.path.basename(infile)
|
||||
outfile += '.{}.pyc'.format(ver)
|
||||
if os.path.exists(outfile):
|
||||
os.unlink(outfile)
|
||||
|
||||
print('*** Compiling for Python {}'.format(fullver))
|
||||
# The easy way
|
||||
proc = subprocess.Popen(['docker', 'run', '--privileged', '--rm', '--name', '{}-{}'.format(infile, ver),
|
||||
'-v', '{}:/src'.format(snekdir), '-w', '/src', 'python:{}'.format(fullver),
|
||||
'python', '-c', "import py_compile; py_compile.compile('{}', '{}')".format(infile, outfile)])
|
||||
proc.communicate()
|
||||
|
||||
return outfile
|
||||
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print('Usage: {} [-c] [versions] input.py'.format(sys.argv[0]))
|
||||
print('Compile input.py for one or more python versions')
|
||||
print()
|
||||
print('-c\tuse prebuilt containers for running different versions of Python (only available for versions >= {})'
|
||||
.format(PYVER_CONTAINER_MIN))
|
||||
print()
|
||||
print('Output is written to input.<version>.pyc for each version successfully compiled')
|
||||
print()
|
||||
print('Version is X.Y (e.g. 3.4), not including the patch version')
|
||||
sys.exit(1)
|
||||
|
||||
RE_PYVER = re.compile(r'\d\.\d')
|
||||
|
||||
pythons = []
|
||||
infile = None
|
||||
for arg in sys.argv[1:]:
|
||||
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 == '-c':
|
||||
USE_CONTAINERS = True
|
||||
elif arg.startswith('-'):
|
||||
print("WARNING: Unrecognized argument '{}'".format(arg))
|
||||
else:
|
||||
infile = arg
|
||||
|
||||
if infile is None:
|
||||
print('No input file specified')
|
||||
sys.exit(1)
|
||||
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__))
|
||||
result = 0
|
||||
for ver in pythons:
|
||||
compile_with_container = USE_CONTAINERS
|
||||
if USE_CONTAINERS and ver < PYVER_CONTAINER_MIN:
|
||||
print('Warning: No supported container for {} - using local build'.format(ver))
|
||||
compile_with_container = False
|
||||
|
||||
outfile = None
|
||||
if compile_with_container:
|
||||
outfile = container_compile(snekdir, ver, infile)
|
||||
else:
|
||||
outfile = local_compile(snekdir, ver, infile)
|
||||
|
||||
if outfile is None or not os.path.exists(outfile):
|
||||
result = 1
|
||||
|
||||
sys.exit(result)
|
||||
|
Reference in New Issue
Block a user