ソースを参照

_initappimage in site.py

Valentin Niess 3 年 前
コミット
cd5df332f1

+ 33 - 1
python_appimage/appimage/relocate.py

@@ -106,6 +106,32 @@ def patch_binary(path, libdir, recursive=True):
                 patch_binary(target, libdir, recursive=True)
 
 
+def patch_site(path, patch):
+    '''Patch the site.py module for running Python from an AppImage
+    '''
+
+    with open(path) as f:
+        source = f.read()
+
+    if '_initappimage' in source: return
+
+    lines = source.split(os.linesep)
+    for i, line in enumerate(lines):
+        if line.startswith('def main('): break
+    else:
+        return
+
+    with open(patch) as f:
+        patch = f.read()
+
+    lines.insert(i, patch)
+    lines.insert(i + 1, '')
+
+    source = os.linesep.join(lines)
+    with open(path, 'w') as f:
+        f.write(source)
+
+
 def relocate_python(python=None, appdir=None):
     '''Bundle a Python install inside an AppDir
     '''
@@ -258,8 +284,14 @@ def relocate_python(python=None, appdir=None):
             os.symlink('pip3', pip)
 
 
+    # Patch the site.py module
+    log('PATCH', '%s site.py', PYTHON_X_Y)
+
+    sitepath = PYTHON_PKG + '/site.py'
+    patch_site(sitepath, PREFIX + '/data/site-patch.py')
+
     # Set a hook in Python for cleaning the path detection
-    log('HOOK', '%s site packages', PYTHON_X_Y)
+    log('HOOK', '%s site-packages', PYTHON_X_Y)
 
     sitepkgs = PYTHON_PKG + '/site-packages'
     make_tree(sitepkgs)

+ 11 - 4
python_appimage/data/apprun.sh

@@ -1,9 +1,16 @@
 {{ shebang }}
 
-# Export APPRUN if running from an extracted image
-self="$(readlink -f -- $0)"
-here="${self%/*}"
-APPDIR="${APPDIR:-${here}}"
+# If running from an extracted image, then export ARGV0 and APPDIR
+if [ -z "${APPIMAGE}" ]; then
+    export ARGV0=$0
+
+    self="$(readlink -f -- $0)"
+    here="${self%/*}"
+    export APPDIR="${APPDIR:-${here}}"
+fi
+
+# Resolve the calling command (preserving symbolic links).
+export APPIMAGE_COMMAND="$(command -v -- $ARGV0)"
 {{ tcltk-env }}
 {{ cert-file }}
 

+ 1 - 25
python_appimage/data/entrypoint.sh

@@ -1,25 +1 @@
-for opt in "$@"
-do
-    [ "${opt:0:1}" != "-" ] && break
-    if [[ "${opt}" =~ "I" ]] || [[ "${opt}" =~ "E" ]]; then
-        # Environment variables are disabled ($PYTHONHOME). Let's run in a safe
-        # mode from the raw Python binary inside the AppImage
-        "$APPDIR/opt/{{ python }}/bin/{{ python }}" "$@"
-        exit "$?"
-    fi
-done
-
-# Get the executable name, i.e. the AppImage or the python binary if running from an
-# extracted image
-executable="${APPDIR}/opt/{{ python }}/bin/{{ python }}"
-if [[ "${ARGV0}" =~ "/" ]]; then
-    executable="$(cd $(dirname ${ARGV0}) && pwd)/$(basename ${ARGV0})"
-elif [[ "${ARGV0}" != "" ]]; then
-    executable=$(which "${ARGV0}")
-fi
-
-# Wrap the call to Python in order to mimic a call from the source
-# executable ($ARGV0), but potentially located outside of the Python
-# install ($PYTHONHOME)
-(PYTHONHOME="${APPDIR}/opt/{{ python }}" exec -a "${executable}" "$APPDIR/opt/{{ python }}/bin/{{ python }}" "$@")
-exit "$?"
+"$APPDIR/opt/{{ python }}/bin/{{ python }}" "$@"

+ 16 - 0
python_appimage/data/site-patch.py

@@ -0,0 +1,16 @@
+# This is a site.py patch when calling Python from an AppImage.
+def _initappimage():
+    """Initialise executable name for running from an AppImage."""
+    env = os.environ
+    try:
+        command = env["APPIMAGE_COMMAND"]
+    except KeyError:
+        return
+
+    if command and ("APPDIR" in env):
+        command = os.path.abspath(command)
+        sys.executable = command
+        sys._base_executable = command
+
+_initappimage()
+del _initappimage

+ 6 - 26
python_appimage/data/sitecustomize.py

@@ -1,34 +1,10 @@
-'''Hooks for isloating the AppImage Python and making it relocatable
+'''Python AppImage hooks
 '''
 import atexit
 import os
 import sys
 
 
-def clean_path():
-    '''Remove system locations from the packages search path
-    '''
-    site_packages = '/usr/local/lib/python{:}.{:}/site-packages'.format(
-        *sys.version_info[:2])
-    binaries_path = '/usr/local/bin'
-    env_path = os.getenv("PYTHONPATH")
-    if env_path is None:
-        env_path = []
-    else:
-        env_path = [os.path.realpath(path) for path in env_path.split(':')]
-
-    if ((os.path.dirname(sys.executable) != binaries_path) and
-        (site_packages not in env_path)):
-        # Remove the builtin site-packages from the path
-        try:
-            sys.path.remove(site_packages)
-        except ValueError:
-            pass
-
-
-clean_path()
-
-
 _bin_at_start = os.listdir(sys.prefix + '/bin')
 '''Initial content of the bin/ directory
 '''
@@ -108,4 +84,8 @@ def patch_pip_install():
             os.remove(path)
 
 
-atexit.register(patch_pip_install)
+if os.getenv('VIRTUAL_ENV') is None:
+    atexit.register(patch_pip_install)
+else:
+    del _bin_at_start
+    del patch_pip_install

+ 2 - 0
python_appimage/utils/docker.py

@@ -46,4 +46,6 @@ def docker_run(image, extra_cmds):
     p = subprocess.Popen(cmd, shell=True)
     p.communicate()
     if p.returncode != 0:
+        if p.returncode == 139:
+            sys.stderr.write("segmentation fault when running Docker (139)\n")
         sys.exit(p.returncode)