mirror of
https://github.com/niess/python-appimage.git
synced 2026-03-14 04:10:15 +01:00
Relocate docs and update table
This commit is contained in:
214
docs/src/apps.md
Normal file
214
docs/src/apps.md
Normal file
@@ -0,0 +1,214 @@
|
||||
{# This document describes the usage of the python-appimage utility.
|
||||
|
||||
The intended audience is developers. In addition, this document also provides
|
||||
some tips for packaging Python based applications.
|
||||
#}
|
||||
|
||||
{{ importjs("highlight.min") }}
|
||||
{{ importjs("apps") }}
|
||||
|
||||
{% include "references.md" %}
|
||||
|
||||
|
||||
# Developers corner
|
||||
|
||||
Python [AppImages][APPIMAGE] are built with the `python-appimage` utility,
|
||||
available from [PyPI][PYPI]. This utility can also help packaging Python based
|
||||
applications as AppImages, using an existing Python AppImage and a recipe
|
||||
folder.
|
||||
|
||||
!!! Caution
|
||||
The `python-appimage` utility can only package applications that can be
|
||||
directly installed with `pip`. For more advanced usage, one needs to extract
|
||||
the Python AppImage and to edit it, e.g. as explained in the [Advanced
|
||||
installation](index.md#advanced-installation) section. Additional details
|
||||
on this use case are provided [below](#advanced-packaging).
|
||||
|
||||
|
||||
## Building a Python AppImage
|
||||
|
||||
The primary scope of `python-appimage` is to relocate an existing Python
|
||||
installation inside an AppDir, and to build the corresponding AppImage. For
|
||||
example, the following
|
||||
|
||||
```bash
|
||||
python-appimage build local -p $(which python2)
|
||||
```
|
||||
|
||||
should build an AppImage of your local Python 2 installation, provided that it
|
||||
exists.
|
||||
|
||||
!!! Tip
|
||||
Help on available arguments and options to `python-appimage` can be obtained
|
||||
with the `-h` flag. For example, `python-appimage build local -h` provides
|
||||
help on local builds.
|
||||
|
||||
|
||||
{{ begin(".capsule") }}
|
||||
### Auxiliary tools
|
||||
|
||||
The `python-appimage` utility relies on auxiliary tools that are downloaded and
|
||||
installed at runtime, on need. Those are [appimagetool][APPIMAGETOOL] for
|
||||
building AppImages, and [patchelf][PATCHELF] in order to edit ELFs runtime paths
|
||||
(`RPATH`). Auxiliary tools are installed to the the user space. One can get
|
||||
their location with the `which` command word. For example,
|
||||
|
||||
```bash
|
||||
python-appimage which appimagetool
|
||||
```
|
||||
|
||||
returns the location of `appimagetool`, if it has been installed. If not, the
|
||||
`install` command word can be used in order to trigger its installation.
|
||||
{{ end(".capsule") }}
|
||||
|
||||
|
||||
## 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
|
||||
across Linuses is the use of different versions of the `glibc` system library.
|
||||
Hopefully, `glibc` is highly backward compatible. Therefore, a simple
|
||||
work-around is to compile binaries using the oldest Linux distro you can afford
|
||||
to. This is the strategy used for creating portable AppImages, as well as for
|
||||
distributing Python site packages as ready-to-use binary [wheels][WHEELS].
|
||||
|
||||
The Python Packaging Authority (PyPA) has defined standard platform tags for
|
||||
building Python site packages, labelled [manylinux][MANYLINUX]. These build
|
||||
platforms are available as Docker images with various versions of Python already
|
||||
installed. The `python-appimage` utility can be used to package those installs
|
||||
as AppImages. For example, the following command
|
||||
|
||||
```bash
|
||||
python-appimage build manylinux 2014_x86_64 cp310-cp310
|
||||
```
|
||||
|
||||
should build an AppImage of Python 3.10 using the CPython (_cp310-cp310_)
|
||||
install found in the `manylinux2014_x86_64` Docker image.
|
||||
|
||||
!!! Note
|
||||
Docker needs to be already installed on your system in order to build
|
||||
Manylinux Python images. However, the command above can be run on the host.
|
||||
That is, you need **not** to explictly shell inside the manylinux Docker
|
||||
image.
|
||||
|
||||
!!! Tip
|
||||
A compilation of ready-to-use Manylinux Python AppImages is available from
|
||||
the [releases][RELEASES] area of the `python-appimage` [GitHub
|
||||
repository][GITHUB]. These AppImages are updated weekly, on every Sunday.
|
||||
|
||||
|
||||
## Simple packaging
|
||||
|
||||
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.
|
||||
|
||||
!!! Tip
|
||||
Some site packages are available only for specific Manylinux tags. This can
|
||||
be cross-checked by browsing the `Download files` section on the package's
|
||||
PyPI page.
|
||||
|
||||
{{ 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 %}
|
||||
|
||||
| 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(".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
|
||||
|
||||
In more complex cases, e.g. if your application relies on external C libraries
|
||||
not bundled with the Python runtime, then the simple packaging scheme described
|
||||
previously will fail. Indeed, this falls out of the scope of `python-appimage`,
|
||||
whose main purpose it to relocate an existing Python install. In this case, you
|
||||
might rather refer to the initial AppImage [Packaging
|
||||
Guide][APPIMAGE_PACKAGING], and use alternative tools like
|
||||
[linuxdeploy][LINUXDEPLOY].
|
||||
|
||||
Yet, `python-appimage` can still be of use in more complex cases by extracting
|
||||
its AppImages to an AppDir, as discussed in the [Advanced
|
||||
installation](index.md#advanced-installation) section. The extracted AppImages
|
||||
contain a relocatable Python runtime, that can be used as a starting base for
|
||||
building more complex AppImages.
|
||||
|
||||
!!! Tip
|
||||
In some cases, a simple workaround to missing external libraries can be to
|
||||
fetch portable versions of those from a Manylinux distro, and to bundle them
|
||||
under `AppDir/usr/lib`. You might also need to edit their dynamic section,
|
||||
e.g. using [`patchelf`][PATCHELF], which is installed by `python-appimage`.
|
||||
|
||||
|
||||
{{ begin(".capsule") }}
|
||||
### C extension modules
|
||||
|
||||
If your application relies on C extension modules, they need to be compiled on a
|
||||
Manylinux distro in order to be portable. In addition, their dependencies need
|
||||
to be bundled as well. In this case, you might better start by building a binary
|
||||
wheel of your package, using tools like [Auditwheel][AUDITWHEEL] which can
|
||||
automate some parts of the packaging process. Note that `auditwheel` is already
|
||||
installed on the Manylinux Docker images.
|
||||
|
||||
Once you have built a binary wheel of your package, it can be used with
|
||||
`python-appimage` in order to package your application as an AppImage.
|
||||
{{ end(".capsule") }}
|
||||
131
docs/src/css/extra.css
Normal file
131
docs/src/css/extra.css
Normal file
@@ -0,0 +1,131 @@
|
||||
/* Text justification */
|
||||
.justify, p {
|
||||
text-align: justify;
|
||||
text-justify: inter-word;
|
||||
}
|
||||
|
||||
/* Patch for code highlighting */
|
||||
.rst-content code,
|
||||
.rst-content .admonition code,
|
||||
.inline code {
|
||||
background: transparent;
|
||||
color: black;
|
||||
display: inline;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
pre code.hljs {
|
||||
background: #2e3440;
|
||||
color: #d8dee9;
|
||||
}
|
||||
|
||||
/* Wrap with a capsule */
|
||||
.capsule {
|
||||
margin-bottom: 10px;
|
||||
padding: 5px 20px 5px 20px;
|
||||
border: thin solid;
|
||||
-webkit-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
/* Appimages summary table */
|
||||
.appimages-summary-table {
|
||||
border-collapse: collapse;
|
||||
caption-side: bottom;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.appimages-summary-table caption {
|
||||
font-size: 1.2em;
|
||||
font-style: italic;
|
||||
padding: 12px 15px;
|
||||
}
|
||||
|
||||
.appimages-summary-table th,
|
||||
.appimages-summary-table td {
|
||||
font-weight: normal;
|
||||
padding: 12px 15px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.appimages-summary-table thead tr,
|
||||
.appimages-summary-table tbody td:first-child {
|
||||
background-color: #2e3440;
|
||||
color: #d8dee9;
|
||||
text-align: left;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.appimages-summary-table tbody tr {
|
||||
border-bottom: 1px solid #dddddd;
|
||||
}
|
||||
|
||||
.appimages-summary-table tbody tr:nth-of-type(even) {
|
||||
background-color: #f3f3f3;
|
||||
}
|
||||
|
||||
.appimages-summary-table tbody tr:last-of-type {
|
||||
border-bottom: 2px solid #2e3440;
|
||||
}
|
||||
|
||||
.appimages-summary-table-inner,
|
||||
.appimages-summary-table-inner tbody,
|
||||
.appimages-summary-table-inner tbody tr,
|
||||
.appimages-summary-table-inner tbody tr:last-of-type {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.appimages-summary-table-inner td
|
||||
{
|
||||
padding: 3px 4px;
|
||||
}
|
||||
|
||||
.appimages-summary-table-inner tbody tr:nth-of-type(even),
|
||||
.appimages-summary-table-inner tbody td:first-child {
|
||||
background-color: transparent;
|
||||
border: none !important;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* Resized badge */
|
||||
.smaller-appimage-badge img {
|
||||
height: 18px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/* Reshape tables */
|
||||
.rst-content .section .docutils {
|
||||
border-collapse: collapse;
|
||||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
|
||||
caption-side: bottom;
|
||||
display: table;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.rst-content table.docutils thead {
|
||||
background-color: #2e3440;
|
||||
color: #d8dee9;
|
||||
text-align: left;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.rst-content table.docutils tbody tr {
|
||||
border-bottom: 1px solid #dddddd;
|
||||
}
|
||||
|
||||
.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.rst-content table.docutils tbody tr:nth-of-type(even) {
|
||||
background-color: #f3f3f3;
|
||||
}
|
||||
|
||||
.rst-content table.docutils tbody tr:last-of-type {
|
||||
border-bottom: 2px solid #2e3440;
|
||||
}
|
||||
1
docs/src/css/nord.min.css
vendored
Normal file
1
docs/src/css/nord.min.css
vendored
Normal file
@@ -0,0 +1 @@
|
||||
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#2e3440}.hljs,.hljs-subst{color:#d8dee9}.hljs-selector-tag{color:#81a1c1}.hljs-selector-id{color:#8fbcbb;font-weight:700}.hljs-selector-attr,.hljs-selector-class{color:#8fbcbb}.hljs-property,.hljs-selector-pseudo{color:#88c0d0}.hljs-addition{background-color:rgba(163,190,140,.5)}.hljs-deletion{background-color:rgba(191,97,106,.5)}.hljs-built_in,.hljs-class,.hljs-type{color:#8fbcbb}.hljs-function,.hljs-function>.hljs-title,.hljs-title.hljs-function{color:#88c0d0}.hljs-keyword,.hljs-literal,.hljs-symbol{color:#81a1c1}.hljs-number{color:#b48ead}.hljs-regexp{color:#ebcb8b}.hljs-string{color:#a3be8c}.hljs-title{color:#8fbcbb}.hljs-params{color:#d8dee9}.hljs-bullet{color:#81a1c1}.hljs-code{color:#8fbcbb}.hljs-emphasis{font-style:italic}.hljs-formula{color:#8fbcbb}.hljs-strong{font-weight:700}.hljs-link:hover{text-decoration:underline}.hljs-comment,.hljs-quote{color:#4c566a}.hljs-doctag{color:#8fbcbb}.hljs-meta,.hljs-meta .hljs-keyword{color:#5e81ac}.hljs-meta .hljs-string{color:#a3be8c}.hljs-attr{color:#8fbcbb}.hljs-attribute{color:#d8dee9}.hljs-name{color:#81a1c1}.hljs-section{color:#88c0d0}.hljs-tag{color:#81a1c1}.hljs-template-variable,.hljs-variable{color:#d8dee9}.hljs-template-tag{color:#5e81ac}.language-abnf .hljs-attribute{color:#88c0d0}.language-abnf .hljs-symbol{color:#ebcb8b}.language-apache .hljs-attribute{color:#88c0d0}.language-apache .hljs-section{color:#81a1c1}.language-arduino .hljs-built_in{color:#88c0d0}.language-aspectj .hljs-meta{color:#d08770}.language-aspectj>.hljs-title{color:#88c0d0}.language-bnf .hljs-attribute{color:#8fbcbb}.language-clojure .hljs-name{color:#88c0d0}.language-clojure .hljs-symbol{color:#ebcb8b}.language-coq .hljs-built_in{color:#88c0d0}.language-cpp .hljs-meta .hljs-string{color:#8fbcbb}.language-css .hljs-built_in{color:#88c0d0}.language-css .hljs-keyword{color:#d08770}.language-diff .hljs-meta,.language-ebnf .hljs-attribute{color:#8fbcbb}.language-glsl .hljs-built_in{color:#88c0d0}.language-groovy .hljs-meta:not(:first-child),.language-haxe .hljs-meta,.language-java .hljs-meta{color:#d08770}.language-ldif .hljs-attribute{color:#8fbcbb}.language-lisp .hljs-name,.language-lua .hljs-built_in,.language-moonscript .hljs-built_in,.language-nginx .hljs-attribute{color:#88c0d0}.language-nginx .hljs-section{color:#5e81ac}.language-pf .hljs-built_in,.language-processing .hljs-built_in{color:#88c0d0}.language-scss .hljs-keyword,.language-stylus .hljs-keyword{color:#81a1c1}.language-swift .hljs-meta{color:#d08770}.language-vim .hljs-built_in{color:#88c0d0;font-style:italic}.language-yaml .hljs-meta{color:#d08770}
|
||||
242
docs/src/index.md
Normal file
242
docs/src/index.md
Normal file
@@ -0,0 +1,242 @@
|
||||
{# This document describes the usage of Python AppImages, as runtimes.
|
||||
|
||||
Note that some parts of this document are generated dynamically according to
|
||||
the reader's system configuration, and depending on released AppImages. The
|
||||
intent is to provide relevant examples to the reader, as well as a dynamic
|
||||
summary of available Python AppImages.
|
||||
#}
|
||||
|
||||
{{ importjs("highlight.min") }}
|
||||
{{ importjs("index") }}
|
||||
|
||||
{% include "references.md" %}
|
||||
|
||||
|
||||
# Python AppImages
|
||||
|
||||
We provide relocatable Python runtimes for _Linux_ systems, as
|
||||
[AppImages][APPIMAGE]. These runtimes have been extracted from
|
||||
[manylinux][MANYLINUX] Docker images.
|
||||
{{ "" | id("append-releases-list") }}
|
||||
|
||||
## Basic installation
|
||||
|
||||
Installing Python from an [AppImage][APPIMAGE] is as simple as downloading a
|
||||
single file and changing its mode to executable. For example, as
|
||||
|
||||
{{ begin("#basic-installation-example") }}
|
||||
```bash
|
||||
wget https://github.com/niess/python-appimage/releases/download\
|
||||
/python3.10/python3.10.2-cp310-cp310-manylinux2014_x86_64.AppImage
|
||||
|
||||
chmod +x python3.10.2-cp310-cp310-manylinux2014_x86_64.AppImage
|
||||
```
|
||||
{{ end("#basic-installation-example") }}
|
||||
|
||||
!!! Note
|
||||
As can be seen from the previous [example](#basic-installation-example), the
|
||||
AppImage name contains several informations. That are, the Python full
|
||||
version ({{ "3.10.2" | id("example-full-version") }}), the CPython tag
|
||||
({{ "cp310-cp310" | id("example-python-tag") }}), the Linux compatibility
|
||||
tag ({{ "manylinux2014" | id("example-linux-tag") }}) and the machine
|
||||
architecture ({{ "x86_64" | id("example-arch-tag") }}).
|
||||
|
||||
!!! Caution
|
||||
One needs to **select an AppImage** that matches **system requirements**. A
|
||||
summmary of available Python AppImages is provided at the
|
||||
[bottom](#available-python-appimages) of this page.
|
||||
|
||||
|
||||
{{ begin(".capsule") }}
|
||||
### Creating a symbolic link
|
||||
|
||||
Since AppImages native names are rather lengthy, one might create a symbolic
|
||||
link, e.g. as
|
||||
|
||||
{{ begin("#basic-installation-example-symlink") }}
|
||||
```bash
|
||||
ln -s python3.10.2-cp310-cp310-manylinux2014_x86_64.AppImage python3.10
|
||||
```
|
||||
{{ end("#basic-installation-example-symlink") }}
|
||||
|
||||
Then, executing the AppImage as
|
||||
{{ "`./python3.10`" | id("basic-installation-example-execution") }} should
|
||||
start a Python interactive session on _almost_ any Linux, provided that **fuse**
|
||||
is supported.
|
||||
{{ end(".capsule") }}
|
||||
|
||||
!!! Tip
|
||||
Fuse is not supported on Windows Subsytem for Linux v1 (WSL1), preventing
|
||||
AppImages direct execution. Yet, one can still extract the content of Python
|
||||
AppImages and use them, as explained in the [Advanced
|
||||
installation](#advanced-installation) section.
|
||||
|
||||
|
||||
## Installing site packages
|
||||
|
||||
Site packages can be installed using `pip`, distributed with the AppImage. For
|
||||
example, the following
|
||||
|
||||
{{ begin("#site-packages-example") }}
|
||||
```bash
|
||||
./python3.10 -m pip install numpy
|
||||
```
|
||||
{{ end("#site-packages-example") }}
|
||||
|
||||
installs the numpy package, where it is assumed that a symlink to the AppImage
|
||||
has been previously created. When using the **basic installation** scheme, by
|
||||
default Python packages are installed to your **user space**, i.e. under
|
||||
`~/.local` on Linux.
|
||||
|
||||
!!! Note
|
||||
AppImage are read-only. Therefore, site packages cannot be directly
|
||||
installed to the AppImage. However, the AppImage can be extracted, as
|
||||
explained in the [Advanced installation](#advanced-installation) section.
|
||||
|
||||
|
||||
{{ begin(".capsule") }}
|
||||
### Alternative site packages location
|
||||
|
||||
One can
|
||||
specify an alternative installation directory for site packages using the
|
||||
`--target` option of pip. For example, the following
|
||||
|
||||
{{ begin("#site-packages-example-target") }}
|
||||
```bash
|
||||
./python3.10 -m pip install --target=$(pwd)/packages numpy
|
||||
```
|
||||
{{ end("#site-packages-example-target") }}
|
||||
|
||||
installs the numpy package besides the AppImage, in a `packages` folder.
|
||||
{{ end(".capsule") }}
|
||||
|
||||
!!! Tip
|
||||
Packages installed in non standard locations are not automatically found by
|
||||
Python. Their location must be aded to `sys.path`, e.g. using the
|
||||
`PYTHONPATH` environment variable.
|
||||
|
||||
!!! Caution
|
||||
While Python AppImages are relocatable, site packages might not be. In
|
||||
particular, packages installing executable Python scripts assume a fix
|
||||
location of the Python runtime. If the Python AppImage is moved, then these
|
||||
scripts will fail. This can be patched by editing the script
|
||||
[shebang][SHEBANG], or be reinstalling the corresponding package.
|
||||
|
||||
|
||||
## Isolating from the user space
|
||||
|
||||
Python AppImages are not isolated from the user space. Therefore, by default
|
||||
site packages located under `~/.local` are loaded instead of system ones. Note
|
||||
that this is the usual Python runtime behaviour. However, it can be conflictual
|
||||
in some cases.
|
||||
|
||||
In order to disable user site packages, one can use the `-s` option of the
|
||||
Python runtime. For example, invoking the Python AppImage as {{ "`./python3.10
|
||||
-s`" | id("user-isolation-example") }} prevents user packages to be loaded.
|
||||
|
||||
|
||||
## Using a virtual environement
|
||||
|
||||
Isolation can also be achieved with a [virtual environment][VENV]. Python
|
||||
AppImages can create a `venv` using the standard syntax, e.g. as
|
||||
|
||||
{{ begin("#venv-example") }}
|
||||
```bash
|
||||
./python3.10 -m venv /path/to/new/virtual/environment
|
||||
```
|
||||
{{ end("#venv-example") }}
|
||||
|
||||
However, the virtual environment fails setting up `pip`, despite the latter is
|
||||
packaged with the AppImage. Yet, this can be patched by calling `ensurepip` from
|
||||
within the `venv`, after its creation. For example, as
|
||||
|
||||
```bash
|
||||
source /path/to/new/virtual/environment/bin/activate
|
||||
|
||||
python -m ensurepip
|
||||
```
|
||||
|
||||
|
||||
## Advanced installation
|
||||
|
||||
The [basic installation](#basic-installation) scheme described previously has
|
||||
some limitations when using Python AppImages as a runtime. For example, site
|
||||
packages need to be installed to a separate location. This can be solved by
|
||||
extracting a Python AppImage to an `*.AppDir` directory, e.g. as
|
||||
|
||||
|
||||
{{ begin("#advanced-installation-example") }}
|
||||
```bash
|
||||
./python3.10.2-cp310-cp310-manylinux2014_x86_64.AppImage --appimage-extract
|
||||
|
||||
mv squashfs-root python3.10.2-cp310-cp310-manylinux2014_x86_64.AppDir
|
||||
|
||||
ln -s python3.10.2-cp310-cp310-manylinux2014_x86_64.AppDir/AppRun python3.10
|
||||
```
|
||||
{{ end("#advanced-installation-example") }}
|
||||
|
||||
Then, by default **site packages** are installed to the extracted **AppDir**,
|
||||
when using `pip`. In addition, executable scripts installed by `pip` are patched
|
||||
in order to use relative [shebangs][SHEBANG]. Consequently, the AppDir can be
|
||||
freely moved around.
|
||||
|
||||
!!! Note
|
||||
Python AppDirs follow the [manylinux][MANYLINUX] installation scheme.
|
||||
Executable scripts are installed under `AppDir/opt/pythonX.Y/bin` where _X_
|
||||
and _Y_ in _pythonX.Y_ stand for the major and minor version numbers. Site
|
||||
packages are located under
|
||||
`AppDir/opt/pythonX.Y/lib/pythonX.Y/site-packages`.
|
||||
|
||||
!!! Tip
|
||||
As for Python AppImages, by default the extracted runtime is [not isolated
|
||||
from the user space](#isolating-from-the-user-space). This behaviour can be
|
||||
changed by editing the `AppDir/AppRun` wrapper script, and by adding the
|
||||
`-s` option at the very bottom, where Python is invoked.
|
||||
|
||||
|
||||
{{ begin(".capsule") }}
|
||||
### Repackaging the AppImage
|
||||
|
||||
An extracted AppDir can be re-packaged as an AppImage using
|
||||
[appimagetool][APPIMAGETOOL], e.g. as
|
||||
|
||||
|
||||
{{ begin("#repackaging-example") }}
|
||||
```bash
|
||||
wget https://github.com/AppImage/AppImageKit/releases/download/continuous/\
|
||||
appimagetool-x86_64.AppImage
|
||||
|
||||
chmod +x appimagetool-x86_64.AppImage
|
||||
|
||||
./appimagetool-x86_64.AppImage \
|
||||
python3.10.2-cp310-cp310-manylinux2014_x86_64.AppDir \
|
||||
python3.10.2-cp310-cp310-manylinux2014_x86_64.AppImage
|
||||
```
|
||||
{{ end("#repackaging-example") }}
|
||||
|
||||
This allows to customize your Python AppImage, for example by adding your
|
||||
preferred site packages.
|
||||
{{ end(".capsule") }}
|
||||
|
||||
!!! Note
|
||||
Python AppImages can also be used for packaging Python based applications,
|
||||
as AppImages. Additional details are provided in the [developers
|
||||
section](apps).
|
||||
|
||||
|
||||
## Available Python AppImages
|
||||
|
||||
A summary of available Python AppImages [releases][RELEASES] is provided in the
|
||||
[table](#appimages-download-links) below. Clicking on a badge should download
|
||||
the corresponding AppImage.
|
||||
|
||||
{{ begin("#suggest-appimage-download") }}
|
||||
!!! Caution
|
||||
According to your browser, your system would not be compatible with
|
||||
Python Appimages.
|
||||
{{ end("#suggest-appimage-download") }}
|
||||
|
||||
{{ begin("#appimages-download-links") }}
|
||||
!!! Danger
|
||||
Could not download releases metadata from {{ github_api.releases | url }}.
|
||||
{{ end("#appimages-download-links") }}
|
||||
2
docs/src/js/apps.js
Normal file
2
docs/src/js/apps.js
Normal file
@@ -0,0 +1,2 @@
|
||||
/* Perform the syntaxic highlighting */
|
||||
hljs.highlightAll();
|
||||
1160
docs/src/js/highlight.min.js
vendored
Normal file
1160
docs/src/js/highlight.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
263
docs/src/js/index.js
Normal file
263
docs/src/js/index.js
Normal file
@@ -0,0 +1,263 @@
|
||||
/*-Update content according to release metadata */
|
||||
$.getJSON("https://api.github.com/repos/niess/python-appimage/releases").done(function(data) {
|
||||
|
||||
/* Unpack release metadata */
|
||||
const releases = []
|
||||
for (const datum of data) {
|
||||
var full_version = undefined;
|
||||
const assets = [];
|
||||
for (const asset of datum.assets) {
|
||||
if (asset.name.endsWith(".AppImage")) {
|
||||
/* Parse AppImage metadata */
|
||||
const tmp0 = asset.name.split("manylinux")
|
||||
const tag = tmp0[1].slice(0,-9);
|
||||
const tmp1 = tag.split(/_(.+)/);
|
||||
const linux = tmp1[0]
|
||||
const arch = tmp1[1]
|
||||
const tmp2 = tmp0[0].split("-")
|
||||
const python = tmp2[1] + "-" + tmp2[2]
|
||||
assets.push({
|
||||
name: asset.name,
|
||||
url: asset.browser_download_url,
|
||||
python: python,
|
||||
linux: linux,
|
||||
arch: arch
|
||||
});
|
||||
|
||||
if (full_version === undefined) {
|
||||
const index = asset.name.indexOf("-")
|
||||
full_version = asset.name.slice(6, index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
releases.push({
|
||||
version: datum.name.slice(7),
|
||||
full_version: full_version,
|
||||
assets: assets,
|
||||
url: datum.html_url
|
||||
});
|
||||
}
|
||||
|
||||
/* Sort releases */
|
||||
releases.sort(function(a, b) {
|
||||
const tmpa = a.version.split(".")
|
||||
const tmpb = b.version.split(".")
|
||||
a0 = Number(tmpa[0])
|
||||
a1 = Number(tmpa[1])
|
||||
b0 = Number(tmpb[0])
|
||||
b1 = Number(tmpb[1])
|
||||
|
||||
if (a0 != b0) {
|
||||
return a0 - b0;
|
||||
} else {
|
||||
return a1 - b1;
|
||||
}
|
||||
});
|
||||
|
||||
/* Generate the releases list */
|
||||
{
|
||||
const elements = []
|
||||
for (const release of releases) {
|
||||
elements.push(`<a href="${release.url}">${release.version}</a>`)
|
||||
}
|
||||
$("#append-releases-list").append(
|
||||
" Available Python versions are " +
|
||||
elements.slice(0, -1).join(", ") +
|
||||
" and " +
|
||||
elements[elements.length - 1] +
|
||||
"."
|
||||
);
|
||||
}
|
||||
|
||||
/* Detect the host architecture */
|
||||
var host_arch = undefined;
|
||||
{
|
||||
var re = /Linux +(?<arch>[a-z0-9_]+)/g;
|
||||
const result = re.exec(navigator.userAgent);
|
||||
if (result) {
|
||||
host_arch = result.groups.arch;
|
||||
if (host_arch == "x64") {
|
||||
host_arch = "x86_64";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Strip blocks of whitespaces, e.g. at line start */
|
||||
function stripws (s) { return s.replace(/ +/g, ""); }
|
||||
|
||||
/* Utility function for setting an inline code */
|
||||
function set_inline (selector, code) {
|
||||
$(selector).children().html(stripws(code));
|
||||
}
|
||||
|
||||
/* Utility function for setting a code snippet */
|
||||
function set_snippet (selector, code) {
|
||||
$(selector).children().children().html(stripws(code));
|
||||
}
|
||||
|
||||
/* Generate the examples */
|
||||
var suggested_appimage = undefined;
|
||||
{
|
||||
const release = releases[releases.length - 1];
|
||||
const arch = (host_arch === undefined) ? "x86_64" : host_arch;
|
||||
var asset = undefined;
|
||||
for (const a of release.assets) {
|
||||
if (a.arch == arch) {
|
||||
if (asset == undefined) {
|
||||
asset = a;
|
||||
} else if (Number(a.linux) > Number(asset.linux)) {
|
||||
asset = a;
|
||||
}
|
||||
}
|
||||
}
|
||||
suggested_appimage = asset;
|
||||
|
||||
const pattern = "download";
|
||||
const i = asset.url.indexOf(pattern) + pattern.length;
|
||||
const url0 = asset.url.slice(0, i);
|
||||
const url1 = asset.url.slice(i + 1);
|
||||
set_snippet("#basic-installation-example", `\
|
||||
wget ${url0}\\
|
||||
/${url1}
|
||||
|
||||
chmod +x ${asset.name}</code></pre>
|
||||
`);
|
||||
|
||||
$("#example-full-version").text(release.full_version);
|
||||
$("#example-python-tag").text(asset.python);
|
||||
$("#example-linux-tag").text("manylinux" + asset.linux);
|
||||
$("#example-arch-tag").text(asset.arch);
|
||||
|
||||
set_snippet("#basic-installation-example-symlink", `\
|
||||
ln -s ${asset.name} python${release.version}
|
||||
`);
|
||||
|
||||
set_inline("#basic-installation-example-execution",
|
||||
`./python${release.version}`
|
||||
);
|
||||
|
||||
set_snippet("#site-packages-example", `\
|
||||
./python${release.version} -m pip install numpy
|
||||
`);
|
||||
|
||||
set_snippet("#site-packages-example-target", `\
|
||||
./python${release.version} -m pip install --target=$(pwd)/packages numpy
|
||||
`);
|
||||
|
||||
set_inline("#user-isolation-example",
|
||||
`./python${release.version} -s`
|
||||
);
|
||||
|
||||
set_snippet("#venv-example", `\
|
||||
./python${release.version} -m venv /path/to/new/virtual/environment
|
||||
`);
|
||||
|
||||
const appdir = asset.name.slice(0, -8) + "AppDir";
|
||||
|
||||
set_snippet("#advanced-installation-example", `\
|
||||
./${asset.name} --appimage-extract
|
||||
|
||||
mv squashfs-root ${appdir}
|
||||
|
||||
ln -s ${appdir}/AppRun python${release.version}
|
||||
`);
|
||||
}
|
||||
|
||||
|
||||
function badge (asset, pad) {
|
||||
const colors = {i686: "lightgrey", x86_64: "blue"};
|
||||
const python = asset.python.split("-")[1];
|
||||
const arch = asset.arch.replace("_", "__");
|
||||
var color = colors[asset.arch];
|
||||
if (color === undefined) {
|
||||
color = "red";
|
||||
}
|
||||
|
||||
const img = `<img src="https://img.shields.io/badge/${python}-${arch}-${color}" alt="${asset.arch}">`
|
||||
|
||||
if (pad) {
|
||||
return `<a href=${asset.url}>${img}</a>`;
|
||||
} else {
|
||||
return `<a href=${asset.url}><span class="smaller-appimage-badge">${img}</span></a>`;
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate the download links summary */
|
||||
{
|
||||
/* Find all Linux tags */
|
||||
function unique (arr) {
|
||||
var u = {}, a = [];
|
||||
for(var i = 0, l = arr.length; i < l; ++i){
|
||||
if(!u.hasOwnProperty(arr[i])) {
|
||||
a.push(arr[i]);
|
||||
u[arr[i]] = 1;
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
const all_linuses = [];
|
||||
for (const release of releases) {
|
||||
for (const asset of release.assets) {
|
||||
all_linuses.push(asset.linux);
|
||||
}
|
||||
}
|
||||
const linuses = unique(all_linuses);
|
||||
|
||||
/* Build the table header */
|
||||
const html = [];
|
||||
html.push("<table class=\"appimages-summary-table\"><thead><tr><th></th>");
|
||||
for (const linux of linuses) {
|
||||
html.push(`<th>Manylinux ${linux}</th>`);
|
||||
}
|
||||
html.push("</tr></thead>");
|
||||
|
||||
/* Build the table rows */
|
||||
html.push("<tbody>");
|
||||
for (const release of releases) {
|
||||
html.push(`<tr><td>Python ${release.version}</td>`)
|
||||
for (linux of linuses) {
|
||||
const candidates = [];
|
||||
for (asset of release.assets) {
|
||||
if (asset.linux == linux) {
|
||||
candidates.push(badge(asset, true));
|
||||
}
|
||||
}
|
||||
if (candidates.length > 0) {
|
||||
html.push(
|
||||
"<td><table class=\"appimages-summary-table-inner\"><tbody><tr><td>" +
|
||||
candidates.join("</td></tr><tr><td>") +
|
||||
"</td></tr></tbody></table></td>"
|
||||
);
|
||||
} else {
|
||||
html.push("<td>∅</td>");
|
||||
}
|
||||
}
|
||||
html.push(`</tr>`)
|
||||
}
|
||||
html.push("</tbody>");
|
||||
html.push("<caption>Summary of available Python AppImages.</caption>");
|
||||
html.push("</table>");
|
||||
|
||||
const element = $("#appimages-download-links");
|
||||
element.html(html.join("\n"));
|
||||
}
|
||||
|
||||
/* Suggest an AppImage */
|
||||
if (host_arch != undefined) {
|
||||
const main = $("#suggest-appimage-download").children().first();
|
||||
main.attr("class", "admonition tip");
|
||||
const children = main.children();
|
||||
children.first().text("Tip");
|
||||
children.eq(1).html(stripws(`\
|
||||
According to your browser, your system is an ${host_arch} Linux.
|
||||
Therefore, we recommend that you download an ${host_arch} AppImage
|
||||
with Manylinux ${suggested_appimage.linux} compatibility. For
|
||||
example, ${badge(suggested_appimage, false)}.
|
||||
`));
|
||||
}
|
||||
|
||||
/* Perform the syntaxic highlighting */
|
||||
hljs.highlightAll();
|
||||
});
|
||||
Reference in New Issue
Block a user