Bläddra i källkod

Update the list command

Valentin Niess 8 månader sedan
förälder
incheckning
eb05b77a85

+ 6 - 15
python_appimage/commands/build/manylinux.py

@@ -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
         )

+ 16 - 26
python_appimage/commands/list.py

@@ -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]
-
-        for (abi, version) in pythons:
-            log('LIST', "{:7} ->  /opt/python/{:}".format(version, abi))
-
-        return pythons
+    image = ensure_image(tag)
+
+    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)
+
+    for (abi, version) in pythons:
+        log('LIST', "{:8} ->  /opt/python/{:}".format(version, abi))
+
+    return pythons

+ 23 - 1
python_appimage/manylinux/__init__.py

@@ -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(),
+    )

+ 1 - 4
python_appimage/manylinux/download.py

@@ -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)

+ 2 - 0
python_appimage/manylinux/extract.py

@@ -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']

+ 0 - 58
python_appimage/utils/docker.py

@@ -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])

+ 0 - 14
python_appimage/utils/manylinux.py

@@ -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

+ 1 - 1
scripts/test-appimage.py

@@ -162,7 +162,7 @@ assert_eq(expected, sys.prefix)
 
         # Test SSL (see issue #24).
         if version.major > 2:
-            Script(f'''
+            Script('''
 from http import HTTPStatus
 import urllib.request
 with urllib.request.urlopen('https://wikipedia.org') as r: