Merge pull request #204 from dotjrich/pymultic-container

Adds container support to pymultic
This commit is contained in:
Michael Hansen
2021-10-21 20:54:11 -07:00
committed by GitHub

View File

@@ -33,12 +33,32 @@ 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'
# Not all versions of Python have an official container.
PYVER_CONTAINERS = {
'2.7',
'3.2',
'3.3',
'3.4',
'3.5',
'3.6',
'3.7',
'3.8',
'3.9',
'3.10',
}
CONTAINER_EXES = ['podman', 'docker']
CONTAINER_EXE_EXTRA_ARGS = {
'podman': [],
'docker': ['-u', '{}:{}'.format(os.getuid(), os.getgid())], # Docker requires extra magic for permissions.
}
def fetch_python(snekdir, version):
realver = PYVERS[version]
@@ -122,58 +142,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 +191,107 @@ for ver in pythons:
.format(infile, outfile)])
proc.communicate()
if not os.path.exists(outfile):
return outfile
def container_compile(ver, infile):
if ver not in PYVER_CONTAINERS:
print('Container compilation not supported for version {}'.format(ver))
return None
container_exe = None
for ce in CONTAINER_EXES:
if shutil.which(ce) is not None:
container_exe = ce
break
if container_exe is None:
print('Cannot find {} in $PATH'.format(' or '.join(CONTAINER_EXES)))
return None
fullver = PYVERS[ver]
indir = os.path.dirname(os.path.abspath(infile))
infile = os.path.basename(infile)
if infile.endswith('.py'):
outfile = infile[:-3]
else:
outfile = infile
outfile += '.{}.pyc'.format(ver)
if os.path.exists(outfile):
os.unlink(outfile)
print('*** Compiling for Python {}'.format(fullver))
proc = subprocess.Popen([container_exe, 'run'] + CONTAINER_EXE_EXTRA_ARGS[container_exe] +
['--rm', '--name', '{}'.format(outfile),
'-v', '{}:/indir:Z'.format(indir),
'-v', '{}:/outdir:Z'.format(os.getcwd()), '-w', '/outdir',
'python:{}'.format(fullver),
'python', '-c',
"import py_compile; py_compile.compile('/indir/{}', '{}')".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')
print('\t(not available for all versions)')
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
use_containers = False
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 not in PYVER_CONTAINERS:
print('Warning: No supported container for {} - using local build'.format(ver))
compile_with_container = False
outfile = None
if compile_with_container:
outfile = container_compile(ver, infile)
else:
outfile = local_compile(snekdir, ver, infile)
if outfile is None or not os.path.exists(outfile):
result = 1
sys.exit(result)