mirror of
https://github.com/niess/python-appimage.git
synced 2026-03-14 04:10:15 +01:00
Update the list command
This commit is contained in:
@@ -3,8 +3,7 @@ from pathlib import Path
|
||||
import shutil
|
||||
|
||||
from ...appimage import build_appimage
|
||||
from ...manylinux import Arch, Downloader, ImageExtractor, LinuxTag, \
|
||||
PythonExtractor
|
||||
from ...manylinux import ensure_image, PythonExtractor
|
||||
from ...utils.tmp import TemporaryDirectory
|
||||
|
||||
|
||||
@@ -21,21 +20,13 @@ def execute(tag, abi):
|
||||
'''Build a Python AppImage using a Manylinux image
|
||||
'''
|
||||
|
||||
tag, arch = tag.split('_', 1)
|
||||
tag = LinuxTag.from_brief(tag)
|
||||
arch = Arch.from_str(arch)
|
||||
|
||||
downloader = Downloader(tag=tag, arch=arch)
|
||||
downloader.download()
|
||||
|
||||
image_extractor = ImageExtractor(downloader.default_destination())
|
||||
image_extractor.extract()
|
||||
image = ensure_image(tag)
|
||||
|
||||
pwd = os.getcwd()
|
||||
with TemporaryDirectory() as tmpdir:
|
||||
python_extractor = PythonExtractor(
|
||||
arch = arch,
|
||||
prefix = image_extractor.default_destination(),
|
||||
arch = image.arch,
|
||||
prefix = image.path,
|
||||
tag = abi
|
||||
)
|
||||
appdir = Path(tmpdir) / 'AppDir'
|
||||
@@ -44,7 +35,7 @@ def execute(tag, abi):
|
||||
fullname = '-'.join((
|
||||
f'{python_extractor.impl}{python_extractor.version.long()}',
|
||||
abi,
|
||||
f'{tag}_{arch}'
|
||||
f'{image.tag}_{image.arch}'
|
||||
))
|
||||
|
||||
destination = f'{fullname}.AppImage'
|
||||
@@ -52,7 +43,7 @@ def execute(tag, abi):
|
||||
appdir = str(appdir),
|
||||
destination = destination
|
||||
)
|
||||
shutil.move(
|
||||
shutil.copy(
|
||||
Path(tmpdir) / destination,
|
||||
Path(pwd) / destination
|
||||
)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import os
|
||||
import glob
|
||||
from pathlib import Path
|
||||
|
||||
from ..utils.docker import docker_run
|
||||
from ..manylinux import ensure_image, PythonVersion
|
||||
from ..utils.log import log
|
||||
from ..utils.tmp import TemporaryDirectory
|
||||
|
||||
|
||||
__all__ = ['execute']
|
||||
@@ -18,26 +18,16 @@ def execute(tag):
|
||||
'''List python versions installed in a manylinux image
|
||||
'''
|
||||
|
||||
with TemporaryDirectory() as tmpdir:
|
||||
script = (
|
||||
'for dir in $(ls /opt/python | grep "^cp[0-9]"); do',
|
||||
' version=$(/opt/python/$dir/bin/python -c "import sys; ' \
|
||||
'sys.stdout.write(sys.version.split()[0])")',
|
||||
' echo "$dir $version"',
|
||||
'done',
|
||||
)
|
||||
if tag.startswith('2_'):
|
||||
image = 'manylinux_' + tag
|
||||
else:
|
||||
image = 'manylinux' + tag
|
||||
result = docker_run(
|
||||
'quay.io/pypa/' + image,
|
||||
script,
|
||||
capture = True
|
||||
)
|
||||
pythons = [line.split() for line in result.split(os.linesep) if line]
|
||||
image = ensure_image(tag)
|
||||
|
||||
for (abi, version) in pythons:
|
||||
log('LIST', "{:7} -> /opt/python/{:}".format(version, abi))
|
||||
pythons = []
|
||||
for path in glob.glob(str(image.path / 'opt/python/cp*')):
|
||||
path = Path(path)
|
||||
version = PythonVersion.from_str(path.readlink().name[8:]).long()
|
||||
pythons.append((path.name, version))
|
||||
pythons = sorted(pythons)
|
||||
|
||||
return pythons
|
||||
for (abi, version) in pythons:
|
||||
log('LIST', "{:8} -> /opt/python/{:}".format(version, abi))
|
||||
|
||||
return pythons
|
||||
|
||||
@@ -1,7 +1,29 @@
|
||||
from types import SimpleNamespace
|
||||
|
||||
from .config import Arch, LinuxTag, PythonImpl, PythonVersion
|
||||
from .download import Downloader
|
||||
from .extract import ImageExtractor, PythonExtractor
|
||||
|
||||
|
||||
__all__ = ['Arch', 'Downloader', 'ImageExtractor', 'LinuxTag',
|
||||
__all__ = ['Arch', 'Downloader', 'ensure_image', 'ImageExtractor', 'LinuxTag',
|
||||
'PythonExtractor', 'PythonImpl', 'PythonVersion']
|
||||
|
||||
|
||||
def ensure_image(tag):
|
||||
'''Extract a manylinux image to the cache'''
|
||||
|
||||
tag, arch = tag.split('_', 1)
|
||||
tag = LinuxTag.from_brief(tag)
|
||||
arch = Arch.from_str(arch)
|
||||
|
||||
downloader = Downloader(tag=tag, arch=arch)
|
||||
downloader.download()
|
||||
|
||||
image_extractor = ImageExtractor(downloader.default_destination())
|
||||
image_extractor.extract()
|
||||
|
||||
return SimpleNamespace(
|
||||
arch = arch,
|
||||
tag = tag,
|
||||
path = image_extractor.default_destination(),
|
||||
)
|
||||
|
||||
@@ -22,10 +22,6 @@ class DownloadError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class TarError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Downloader:
|
||||
|
||||
@@ -68,6 +64,7 @@ class Downloader:
|
||||
|
||||
# Authenticate to quay.io.
|
||||
repository = f'pypa/{self.image}'
|
||||
log('PULL', f'{self.image}:{tag}')
|
||||
url = 'https://quay.io/v2/auth'
|
||||
url = f'{url}?service=quay.io&scope=repository:{repository}:pull'
|
||||
debug('GET', url)
|
||||
|
||||
@@ -346,6 +346,8 @@ class ImageExtractor:
|
||||
shutil.rmtree(destination, ignore_errors=True)
|
||||
atexit.register(cleanup, destination)
|
||||
|
||||
log('EXTRACT', f'{self.prefix.name}:{self.tag}')
|
||||
|
||||
with open(self.prefix / f'tags/{self.tag}.json') as f:
|
||||
meta = json.load(f)
|
||||
layers = meta['layers']
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
import os
|
||||
import platform
|
||||
import stat
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from .compat import decode
|
||||
from .log import log
|
||||
from .system import system
|
||||
|
||||
|
||||
def docker_run(image, extra_cmds, capture=False):
|
||||
'''Execute commands within a docker container
|
||||
'''
|
||||
|
||||
ARCH = platform.machine()
|
||||
if image.endswith(ARCH):
|
||||
bash_arg = '/pwd/run.sh'
|
||||
elif image.endswith('i686') and ARCH == 'x86_64':
|
||||
bash_arg = '-c "linux32 /pwd/run.sh"'
|
||||
elif image.endswith('x86_64') and ARCH == 'i686':
|
||||
bash_arg = '-c "linux64 /pwd/run.sh"'
|
||||
else:
|
||||
raise ValueError('Unsupported Docker image: ' + image)
|
||||
|
||||
log('PULL', image)
|
||||
system(('docker', 'pull', image))
|
||||
|
||||
script = [
|
||||
'set -e',
|
||||
'trap "chown -R {:}:{:} *" EXIT'.format(os.getuid(),
|
||||
os.getgid()),
|
||||
'cd /pwd'
|
||||
]
|
||||
|
||||
script += extra_cmds
|
||||
|
||||
with open('run.sh', 'w') as f:
|
||||
f.write(os.linesep.join(script))
|
||||
os.chmod('run.sh', stat.S_IRWXU)
|
||||
|
||||
cmd = ' '.join(('docker', 'run', '--mount',
|
||||
'type=bind,source={:},target=/pwd'.format(os.getcwd()),
|
||||
image, '/bin/bash', bash_arg))
|
||||
|
||||
if capture:
|
||||
opts = {'stderr': subprocess.PIPE, 'stdout': subprocess.PIPE}
|
||||
else:
|
||||
opts = {}
|
||||
log('RUN', image)
|
||||
p = subprocess.Popen(cmd, shell=True, **opts)
|
||||
r = p.communicate()
|
||||
if p.returncode != 0:
|
||||
if p.returncode == 139:
|
||||
sys.stderr.write("segmentation fault when running Docker (139)\n")
|
||||
sys.exit(p.returncode)
|
||||
if capture:
|
||||
return decode(r[0])
|
||||
@@ -1,14 +0,0 @@
|
||||
def format_appimage_name(abi, version, tag):
|
||||
'''Format the Python AppImage name using the ABI, python version and OS tags
|
||||
'''
|
||||
return 'python{:}-{:}-{:}.AppImage'.format(
|
||||
version, abi, format_tag(tag))
|
||||
|
||||
|
||||
def format_tag(tag):
|
||||
'''Format Manylinux tag
|
||||
'''
|
||||
if tag.startswith('2_'):
|
||||
return 'manylinux_' + tag
|
||||
else:
|
||||
return 'manylinux' + tag
|
||||
Reference in New Issue
Block a user