Skip to content

Plugin system

TheAssassin edited this page Jul 6, 2023 · 15 revisions

Plugin system

linuxdeploy is using a subprocess-based plugin system. It communicates with the plugin processes via stdin and stdout with simple text-based protocols described below.

Like linuxdeploy, the plugins work with AppDirs. They expect an AppDir on which linuxdeploy has been run to be provided as a CLI parameter. Input plugins can add, modify or delete files inside the AppDir. Output plugins shall turn the AppDir into application bundles like e.g., AppImages.

Plugin types

There are two plugin types: input and output plugins.

Input plugins are also known as bundling plugins. These plugins bundle resources like libraries, frameworks, translations, media, etc. for different frameworks, libraries etc.

Output plugins create actual application bundles. As the AppDir contains all sufficient data to be able to run an application on Linux systems, it is relatively easy for the plugins to create e.g., AppImages from them.

Warning

warning

The following text is a work in progress. It will be subject to major changes until the initial stable version 1 is released.

Plugin specification

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.

Version history

Versions are named using integer numbers. The number is monotonically increased for every new release.

The current version of this document is 0, which implies that the document is still work in progress. The initial release will be version 1.

Introduction

Plugins MUST be standalone applications. They MUST work with AppDirs. It is RECOMMENDED to write them in C++ for performance reasons, but they can OPTIONALLY also be written in other languages. They MUST ship with all their dependencies. Therefore, authors SHOULD ship them as application bundles (e.g., as AppImages).

Plugin naming

Plugins MUST be named as follows:

Regular expression, Perl style (uses [Boost.Regex] internally to match the filenames):

^linuxdeploy-plugin-([^\s\.-]+)(?:-[^\.]+)?(?:\..+)?$

. represents only characters that may be used to name files on common Linux filesystems of course.

Plugin names consist of the prefix linuxdeploy-plugin-, the actual plugin name and optionally a version identifier (can be used for architectures, actual versions etc.) which must be separated from the plugin name with another dash, and an optional file extension.

Example names:

  • linuxdeploy-plugin-TEST: valid
  • linuxdeploy-plugin-TEST-1.0: valid
  • linuxdeploy-plugin-TEST-x86_64: valid
  • linuxdeploy-plugin-TEST-1.0-x86_64: valid
  • linuxdeploy-plugin-TEST.AppImage: valid
  • linuxdeploy-plugin-TEST-x86_64.AppImage: valid

Plugin discovery

The following locations are searched for plugins by linuxdeploy on startup:

  • in case the linuxdeploy AppImage is used: next to the AppImage (read: same directory)
  • next to the linuxdeploy binary (read: same directory)
  • in any of the directories in $PATH
  • in the current working directory

linuxdeploy's --list-plugins can be used to verify that single plugins have been found. The plugin discovery follows the first-come-first-served principle, i.e., the first plugin found by the search algorithm will be used. If multiple plugin files are available, it is recommended to use --list-plugins to verify the right plugin is used.

Common CLI parameters

Mandatory parameters

All plugins MUST implement the following parameters:

  • --appdir: The most important parameter. Relative (to current working directory) or absolute path to an AppDir which should be processed by the plugin application.
  • --plugin-api-version: Plugins MUST return the version of the specification they implement in textual form in a single line. As of 2018, this is always version 0, as the plugin system is still under development.

If one of these arguments is missing, the plugin MUST exit with a non-zero code without modifying the AppDir.

Optional parameters

The plugins MAY provide the following parameters:

  • --plugin-type: Specifies the plugin type. If supported, the plugin MUST write a single line to stdout, containing either the words input or output. By default, plugins are assumed to be input plugins.

Input plugin specification

Input plugins SHOULD expect AppDirs that have been processed by linuxdeploy already (for instance, all shared libraries linked to the executables should be in place already). Therefore it is sufficient for them to scan the libraries directory to get a list of all shared dependencies. They MAY re-deploy shared dependencies again, though.

CLI parameters

The plugin MAY implement the following parameters:

  • --plugin-patterns: a list of filename patterns, each in a separate line. linuxdeploy will search for them in the AppDir, and will automatically run the plugin if one of the patterns matches. This is our form of auto discovery.
    • The output MUST start with this preamble in the first line: -//- plugin patterns -//-. This makes sure that when the flag is not implemented, any kind of other output is ignored.
    • Plugins SHOULD exit with an error state when the flag is not implemented which makes it easier for linuxdeploy to recognize this situation.
    • Patterns MUST be paths relative to the AppDir root. For instance: usr/lib/libQt5Core.so.5.
    • Patterns MAY contain wildcard characters. If they do, the pattern MUST start with the following prefix: fnmatch:. The filenames will be matched using fnmatch(). Example: usr/lib/libQt5*.so*.

Environment variables

linuxdeploy input plugins can make use of $LINUXDEPLOY. This environment variable is set by linuxdeploy when the plugin is run through it, and could be set manually for debugging. This is especially useful to plugins which set up e.g., portable environments for scripting languages, as they can then easily use linuxdeploy to bundle additional dependencies.

Output plugins

CLI parameters

Output plugins MUST implement the following CLI parameters:

  • --plugin-type: unlike input plugins, output plugins MUST implement this parameter. See the section above for details.

Environment variables

Output plugins SHOULD implement support for the following environment variables:

  • LINUXDEPLOY_OUTPUT_APP_NAME: SHOULD be used as an identifier for the resulting package. SHOULD be used as a filename component, ideally as a prefix. SHOULD be used in the package's metadata, if available.
  • LINUXDEPLOY_OUTPUT_VERSION: SHOULD be used in a way for users to be able to distinguish between different versions of the same application. MAY be included in the filename, too.

This example illustrates how these variables may be used by an output plugin:

# generate an AppImage called myApp-1.2.3-x86_64.AppImage
> env LINUXDEPLOY_OUTPUT_PREFIX=myApp LINUXDEPLOY_OUTPUT_VERSION=1.2.3 ./linuxdeploy-x86_64.AppImage --appdir AppDir --output appimage
# alternatively, one could have set the AppImage output plugin specific OUTPUT variable
> env OUTPUT=myApp-1.2.3-x86_64.AppImage ./linuxdeploy-x86_64.AppImage --appdir AppDir --output appimage

Controlling plugin behavior

There is no way to have linuxdeploy forward parameters to plugins. This design decision has been made to keep this specification simple, and reduce the potential for issues due to parameter naming issues (e.g., if --plugin-<name>-<parameter> would have to be passed to the plugin as --<parameter>).

Instead, plugin behavior may be controlled by environment variables the user can set before running linuxdeploy. Plugins may evaluate any environment variable they want to, but plugin developers are encouraged to prefix their variable names with <plugin_name_upper>_.

// TODO: specify optional --plugin-env-vars allowing plugins to provide some sort of "help text" for environment variables
// linuxdeploy could make use of that and show them to the user in some way, e.g., in the --help text

AppRun hooks

Input plugins may create shell scripts in the directory <AppDir root>/apprun-hooks/. If linuxdeploy finds files in there, it will automatically create an AppRun script that sources all the scripts in this directory.

Files placed in this directory MUST be idempotent (i.e., they must be able to deal with previous executions) and MUST NOT rely on any special order (i.e., if a plugin relies on environment variables that might also be set by another plugin, it should set those variables nevertheless or try to recognize on runtime whether the variables have been amended already; they SHOULD NOT just check for other files' existence, as their name may change at any time).