From 07adf65f99c6afb44c68252a38767f896b4cc31c Mon Sep 17 00:00:00 2001 From: Valentin Niess Date: Wed, 6 May 2020 13:49:16 +0200 Subject: [PATCH 1/2] Patch TCl/Tk exports for apps --- python_appimage/appimage/__init__.py | 5 ++- python_appimage/appimage/relocate.py | 56 ++++++++++++++++----------- python_appimage/commands/build/app.py | 8 +++- 3 files changed, 43 insertions(+), 26 deletions(-) diff --git a/python_appimage/appimage/__init__.py b/python_appimage/appimage/__init__.py index 2846400..eeeee14 100644 --- a/python_appimage/appimage/__init__.py +++ b/python_appimage/appimage/__init__.py @@ -1,5 +1,6 @@ from .build import build_appimage -from .relocate import patch_binary, relocate_python +from .relocate import patch_binary, relocate_python, tcltk_env_string -__all__ = ['build_appimage', 'patch_binary', 'relocate_python'] +__all__ = ['build_appimage', 'patch_binary', 'relocate_python', + 'tcltk_env_string'] diff --git a/python_appimage/appimage/relocate.py b/python_appimage/appimage/relocate.py index 9460b45..26e74cd 100644 --- a/python_appimage/appimage/relocate.py +++ b/python_appimage/appimage/relocate.py @@ -12,7 +12,7 @@ from ..utils.system import ldd, system from ..utils.template import copy_template, load_template -__all__ = ["patch_binary", "relocate_python"] +__all__ = ["patch_binary", "relocate_python", "tcltk_env_string"] def _copy_template(name, destination, **kwargs): @@ -20,6 +20,35 @@ def _copy_template(name, destination, **kwargs): copy_template(path, destination, **kwargs) +def _get_tk_version(python_pkg): + tkinter = glob.glob(python_pkg + '/lib-dynload/_tkinter*.so') + if tkinter: + tkinter = tkinter[0] + for dep in ldd(tkinter): + name = os.path.basename(dep) + if name.startswith('libtk'): + match = re.search('libtk([0-9]+[.][0-9]+)', name) + return match.group(1) + else: + raise RuntimeError('could not guess Tcl/Tk version') + + +def tcltk_env_string(python_pkg): + '''Environment for using AppImage's TCl/Tk + ''' + tk_version = _get_tk_version(python_pkg) + + if tk_version: + return ''' +# Export TCl/Tk +export TCL_LIBRARY="${{APPDIR}}/usr/share/tcltk/tcl{tk_version:}" +export TK_LIBRARY="${{APPDIR}}/usr/share/tcltk/tk{tk_version:}" +export TKPATH="${{TK_LIBRARY}}" +'''.format(tk_version=tk_version) + else: + return '' + + _excluded_libs = None '''Appimage excluded libraries, i.e. assumed to be installed on the host ''' @@ -238,18 +267,8 @@ def relocate_python(python=None, appdir=None): # Copy shared data for TCl/Tk - tkinter = glob.glob(PYTHON_PKG + '/lib-dynload/_tkinter*.so') - if tkinter: - tkinter = tkinter[0] - for dep in ldd(tkinter): - name = os.path.basename(dep) - if name.startswith('libtk'): - match = re.search('libtk([0-9]+[.][0-9]+)', name) - tk_version = match.group(1) - break - else: - raise RuntimeError('could not guess Tcl/Tk version') - + tk_version = _get_tk_version(PYTHON_PKG) + if tk_version is not None: tcltkdir = APPDIR_SHARE + '/tcltk' if (not os.path.exists(tcltkdir + '/tcl' + tk_version)) or \ (not os.path.exists(tcltkdir + '/tk' + tk_version)): @@ -268,14 +287,6 @@ def relocate_python(python=None, appdir=None): if not tkpath: raise ValueError('could not find ' + tkpath) copy_tree(tkpath, tcltkdir + '/tk' + tk_version) - tcltk_env = ''' -# Export TCl/Tk -export TCL_LIBRARY="${{APPDIR}}/usr/share/tcltk/tcl{tk_version:}" -export TK_LIBRARY="${{APPDIR}}/usr/share/tcltk/tk{tk_version:}" -export TKPATH="${{TK_LIBRARY}}" -'''.format(tk_version=tk_version) - else: - tcltk_env = '' # Bundle the entry point @@ -284,7 +295,8 @@ export TKPATH="${{TK_LIBRARY}}" log('INSTALL', 'AppRun') entrypoint_path = PREFIX + '/data/entrypoint.sh' entrypoint = load_template(entrypoint_path, python=PYTHON_X_Y) - dictionary = {'entrypoint': entrypoint, 'tcltk-env': tcltk_env} + dictionary = {'entrypoint': entrypoint, + 'tcltk-env': tcltk_env_string(PYTHON_PKG)} _copy_template('apprun.sh', apprun, **dictionary) diff --git a/python_appimage/commands/build/app.py b/python_appimage/commands/build/app.py index 8f38a80..c98e1cb 100644 --- a/python_appimage/commands/build/app.py +++ b/python_appimage/commands/build/app.py @@ -7,7 +7,7 @@ import shutil import stat import struct -from ...appimage import build_appimage +from ...appimage import build_appimage, tcltk_env_string from ...utils.compat import decode from ...utils.deps import PREFIX from ...utils.fs import copy_file, make_tree, remove_file, remove_tree @@ -248,8 +248,12 @@ def execute(appdir, name=None, python_version=None, linux_tag=None, entrypoint_path = entrypoint_path[0] log('BUNDLE', os.path.basename(entrypoint_path)) entrypoint = load_template(entrypoint_path, **dictionary) + python_pkg = 'AppDir/opt/python{0:}/lib/python{0:}'.format( + python_version) + dictionary = {'entrypoint': entrypoint, + 'tcltk-env': tcltk_env_string(python_pkg)} copy_template(PREFIX + '/data/apprun.sh', 'AppDir/AppRun', - entrypoint=entrypoint) + **dictionary) # Build the new AppImage From 70aaa05f4e1941f717465d9d97ec90738856a7ff Mon Sep 17 00:00:00 2001 From: Valentin Niess Date: Wed, 6 May 2020 13:58:15 +0200 Subject: [PATCH 2/2] Custom shebangs for applications entrypoint --- applications/xonsh/entrypoint.sh | 1 + python_appimage/appimage/relocate.py | 1 + python_appimage/commands/build/app.py | 7 +++++++ python_appimage/data/apprun.sh | 2 +- 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/applications/xonsh/entrypoint.sh b/applications/xonsh/entrypoint.sh index 91ee2ec..a89b9a0 100644 --- a/applications/xonsh/entrypoint.sh +++ b/applications/xonsh/entrypoint.sh @@ -1 +1,2 @@ +#! /bin/bash -i {{ python-executable }} -u "${APPDIR}/opt/python{{ python-version }}/bin/xonsh" "$@" diff --git a/python_appimage/appimage/relocate.py b/python_appimage/appimage/relocate.py index 26e74cd..2925ea6 100644 --- a/python_appimage/appimage/relocate.py +++ b/python_appimage/appimage/relocate.py @@ -296,6 +296,7 @@ def relocate_python(python=None, appdir=None): entrypoint_path = PREFIX + '/data/entrypoint.sh' entrypoint = load_template(entrypoint_path, python=PYTHON_X_Y) dictionary = {'entrypoint': entrypoint, + 'shebang': '#! /bin/bash', 'tcltk-env': tcltk_env_string(PYTHON_PKG)} _copy_template('apprun.sh', apprun, **dictionary) diff --git a/python_appimage/commands/build/app.py b/python_appimage/commands/build/app.py index c98e1cb..8c9add9 100644 --- a/python_appimage/commands/build/app.py +++ b/python_appimage/commands/build/app.py @@ -247,10 +247,17 @@ def execute(appdir, name=None, python_version=None, linux_tag=None, if entrypoint_path: entrypoint_path = entrypoint_path[0] log('BUNDLE', os.path.basename(entrypoint_path)) + + with open(entrypoint_path) as f: + shebang = f.readline().strip() + if not shebang.startswith('#!'): + shebang = '#! /bin/bash' + entrypoint = load_template(entrypoint_path, **dictionary) python_pkg = 'AppDir/opt/python{0:}/lib/python{0:}'.format( python_version) dictionary = {'entrypoint': entrypoint, + 'shebang': shebang, 'tcltk-env': tcltk_env_string(python_pkg)} copy_template(PREFIX + '/data/apprun.sh', 'AppDir/AppRun', **dictionary) diff --git a/python_appimage/data/apprun.sh b/python_appimage/data/apprun.sh index af416de..a0315d2 100755 --- a/python_appimage/data/apprun.sh +++ b/python_appimage/data/apprun.sh @@ -1,4 +1,4 @@ -#! /bin/bash +{{ shebang }} # Export APPRUN if running from an extracted image self="$(readlink -f -- $0)"