mirror of
https://github.com/niess/python-appimage.git
synced 2026-03-13 20:00:19 +01:00
Improve python selection when building apps
This commit is contained in:
@@ -62,7 +62,7 @@ returns the location of `appimagetool`, if it has been installed. If not, the
|
||||
{{ end(".capsule") }}
|
||||
|
||||
|
||||
## Manylinux Python AppImage
|
||||
## Manylinux Python AppImages
|
||||
|
||||
AppImages of your local `python` are unlikely to be portable, except if you run
|
||||
an ancient Linux distribution. Indeed, a core component preventing portability
|
||||
@@ -99,9 +99,78 @@ install found in the `manylinux2014_x86_64` Docker image.
|
||||
|
||||
## Simple packaging
|
||||
|
||||
The recipe folder contains
|
||||
the app metadata, a Python requirements file and an entry point script. Examples
|
||||
of recipes can be found on GitHub in the [applications][APPLICATIONS] folder.
|
||||
The `python-appimage` utility can also be used in order to build simple
|
||||
applications, that can be `pip` installed. The syntax is
|
||||
|
||||
```bash
|
||||
python-appimage build app -p 3.10 /path/to/recipe/folder
|
||||
```
|
||||
|
||||
in order to build a Python 3.10 based application from a recipe folder.
|
||||
Examples of recipes can be found on GitHub in the [applications][APPLICATIONS]
|
||||
folder. The recipe folder contains:
|
||||
|
||||
- the AppImage metadata (`application.xml` and `application.desktop`),
|
||||
- an application icon (e.g. `application.png`),
|
||||
- a Python requirements file (`requirements.txt`)
|
||||
- an entry point script (`entrypoint.sh`).
|
||||
|
||||
Additional information on metadata can be found in the AppImage documentation.
|
||||
That is, for [desktop][APPIMAGE_DESKTOP] and [AppStream XML][APPIMAGE_XML]
|
||||
files. The `requirements.txt` file allows to specify additional site packages
|
||||
to be bundled in the AppImage, using `pip`.
|
||||
|
||||
!!! Caution
|
||||
Site packages bundled in the AppImage, as well as their dependencies, must
|
||||
either be pure python packages, or they must be available as portable binary
|
||||
wheels.
|
||||
|
||||
If a **C extension** is bundled from **source**, then it will likely **not**
|
||||
be **portable**, as further discussed in the [Advanced
|
||||
packaging](#advanced-packaging) section.
|
||||
|
||||
{{ begin(".capsule") }}
|
||||
### Entry point script
|
||||
|
||||
{% raw %}
|
||||
The entry point script deserves some additional explanations. This script allows
|
||||
to customize the startup of your application. A typical `entrypoint.sh` script
|
||||
would look like
|
||||
|
||||
```bash
|
||||
{{ python-executable }} ${APPDIR}/opt/python{{ python-version }}/bin/my_app.py "$@"
|
||||
```
|
||||
|
||||
where `my_app.py` is the application startup script, installed by `pip`. As can
|
||||
be seen from the previous example, the `entrypoint.sh` script recognises some
|
||||
particular variables, nested between double curly braces, `{{ }}`. Those
|
||||
variables are listed in the table hereafter. In addition, usual [AppImage
|
||||
environement variables][APPIMAGE_ENV] can be used as well, if needed. For
|
||||
example, `$APPDIR` points to the AppImage mount point at runtime.
|
||||
{% endraw %}
|
||||
|
||||
{{ begin("#entrypoint-variables") }}
|
||||
| variable | Description |
|
||||
|----------------------|---------------------------------------------------------------|
|
||||
| `architecture` | The AppImage architecture, e.g. `x86_64`. |
|
||||
| `linux-tag` | The Manylinux compatibility tag, e.g. `manylinux2014_x86_64`. |
|
||||
| `python-executable` | Path to the AppImage Python runtime. |
|
||||
| `python-fullversion` | The Python full version string, e.g. `3.10.2`. |
|
||||
| `python-tag` | The Python compatibility tag, e.g. `cp310-cp310`. |
|
||||
| `python-version` | The Python short version string, e.g. `3.10`. |
|
||||
{{ end("#entrypoint-variables") }}
|
||||
{{ end(".capsule") }}
|
||||
|
||||
{% raw %}
|
||||
!!! Note
|
||||
By default, Python AppImages are not isolated from the user space, nor from
|
||||
Python specific environment variables, the like `PYTHONPATH`. Depending on
|
||||
your use case, this can be problematic.
|
||||
|
||||
The runtime isolation level can be changed by adding the `-s` and `-E`
|
||||
options, when invoking the runtime. For example,
|
||||
`{{ python-executable }} -sE` starts a fully isolated Python instance.
|
||||
{% endraw %}
|
||||
|
||||
|
||||
## Advanced packaging
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
{# References used in the documentation #}
|
||||
|
||||
[APPIMAGE]: https://appimage.org/
|
||||
[APPIMAGE_APPRUN]: https://docs.appimage.org/introduction/software-overview.html#apprun
|
||||
[APPIMAGE_DESKTOP]: https://docs.appimage.org/reference/desktop-integration.html#
|
||||
[APPIMAGE_ENV]: https://docs.appimage.org/packaging-guide/environment-variables.html
|
||||
[APPIMAGE_XML]: https://docs.appimage.org/packaging-guide/optional/appstream.html
|
||||
[APPIMAGETOOL]: https://appimage.github.io/appimagetool/
|
||||
[APPLICATIONS]: {{ config.repo_url }}tree/master/applications/
|
||||
[GITHUB]: {{ config.repo_url }}
|
||||
|
||||
@@ -16,6 +16,7 @@ from ...utils.system import system
|
||||
from ...utils.template import copy_template, load_template
|
||||
from ...utils.tmp import TemporaryDirectory
|
||||
from ...utils.url import urlopen, urlretrieve
|
||||
from ...utils.version import tonumbers
|
||||
|
||||
|
||||
__all__ = ['execute']
|
||||
@@ -29,6 +30,7 @@ def _unpack_args(args):
|
||||
|
||||
|
||||
_tag_pattern = re.compile('python([^-]+)[-]([^.]+)[.]AppImage')
|
||||
_linux_pattern = re.compile('manylinux([0-9]+)_' + platform.machine())
|
||||
|
||||
def execute(appdir, name=None, python_version=None, linux_tag=None,
|
||||
python_tag=None, base_image=None, in_tree_build=False):
|
||||
@@ -52,7 +54,7 @@ def execute(appdir, name=None, python_version=None, linux_tag=None,
|
||||
continue
|
||||
v = tag[6:]
|
||||
if python_version is None:
|
||||
if v > version:
|
||||
if tonumbers(v) > tonumbers(version):
|
||||
release, version = entry, v
|
||||
elif v == python_version:
|
||||
version = python_version
|
||||
@@ -66,18 +68,27 @@ def execute(appdir, name=None, python_version=None, linux_tag=None,
|
||||
|
||||
|
||||
# Check for a suitable image
|
||||
assets = release['assets']
|
||||
|
||||
if linux_tag is None:
|
||||
linux_tag = 'manylinux1_' + platform.machine()
|
||||
plat = None
|
||||
for asset in assets:
|
||||
match = _linux_pattern.search(asset['name'])
|
||||
if match:
|
||||
tmp = str(match.group(1))
|
||||
if (plat is None) or (tmp < plat):
|
||||
plat = tmp
|
||||
|
||||
linux_tag = 'manylinux' + plat + '_' + platform.machine()
|
||||
|
||||
if python_tag is None:
|
||||
v = ''.join(version.split('.'))
|
||||
python_tag = 'cp{0:}-cp{0:}'.format(v)
|
||||
if version < '3.8':
|
||||
if tonumbers(version) < tonumbers('3.8'):
|
||||
python_tag += 'm'
|
||||
|
||||
target_tag = '-'.join((python_tag, linux_tag))
|
||||
|
||||
assets = release['assets']
|
||||
for asset in assets:
|
||||
match = _tag_pattern.search(asset['name'])
|
||||
if str(match.group(2)) == target_tag:
|
||||
|
||||
7
python_appimage/utils/version.py
Normal file
7
python_appimage/utils/version.py
Normal file
@@ -0,0 +1,7 @@
|
||||
__all__ = ['tonumbers']
|
||||
|
||||
|
||||
def tonumbers(s):
|
||||
'''Convert a version string to a list of numbers, for comparison
|
||||
'''
|
||||
return [int(v) for v in s.split('.')]
|
||||
Reference in New Issue
Block a user