Snap Apps or Snaps are applications for the Linux platform. They are managed using the Snappy package management system. Applications implemented using the Snap format can be installed across a wide range of Linux distributions.
Snaps are currently supported by Arch Linux, CentOS, Debian, Fedora, Solus, Manjaro Linux, Linux Mint, OpenEmbedded, Raspbian, OpenWrt and openSUSE.
AppImage and Flatpack, which are similar to Snaps also allow portable distribution of software.
Snaps are not dependent on a specific apps store. They may be downloaded from any source. Ubuntu Snap Store is the main source for snaps. Many popular Linux applications such as Octave, Skype, Stellerium, GIMP, LibreOffice, Blender etc can be downloaded as Snaps from the Ubuntu Snap Store.
In this article I will describe how to package and distribute a PyQt5 application as a snap app. The PyQt5 application is first converted to executable format using the pyqtdeploy tool. See the article: Creating desktop applications with Python using PyQt5, on how to create executable files for PyQt5 applications.
It is possible to package a PyQt5 graphical application directly without converting to executable file format. However this requires knowledge of the package dependencies and desktop platforms. A self contained executable file that contains all the package dependencies such as Python interpreter, Qt5, PyQt5 etc can be deployed easily as a snap application.
Snaps can be installed and removed using the snap command. The snap command has several uses. For example:
Snaps are published to channels depending on their development status. Snaps may be published to the following channels: stable, candidate, beta and edge. When installing snaps, using the snap command or a Snap GUI front-end, the channel for the snap may be specified.
Snaps are managed using the snapd tool. Using snapd, we can install, remove, backup and restore snaps. Snaps are automatically updated. They can also be rolled back to previous versions. A snap app is deployed in deltas, meaning that only the parts of the application that have changed are updated.
A Snap app consists of a single .snap file. All applications dependencies are contained within this file. A snap file is based on the squashfs file system. Squashfs is a compressed read-only file system used by containers such as Docker. It allows several directories to be merged and mounted as a single directory. A squashfs file may consist of several directories mounted from different locations. The contents of the file can be viewed using the command:
unsquashfs -l file-name
When a Snap App is installed, it is mounted read only at the location: /snap/snap-name/revision/
Snaps are developed using the snapcraft tool. Snaps can be developed on LXC/LXD containers, Docker containers or the host system. The Snapcraft tool has useful documentation on creating Snaps.
The article Create your first Snap is an excellent starting point for getting started with Snap application development. First we need to install snapcraft using the command:
sudo snap install --classic snapcraft
This installs snapcraft as a snap app. The snap command requires the snapd tool. Snapd may be installed on Ubuntu using the command:
sudo apt-get install snapd
Once the snapcraft snap has been installed, we can create a snap using the command:
snapcraft init
This command creates a snap folder in the current directory. The snap folder has a single file called snapcraft.yaml. This is the main configuration file for the Snap App. It contains all information that is needed to build the Snap. The end result of building a snap is a .snap file. This file may be installed locally using the snap command or it may be published to a snap store.
The main parts of the snapcraft.yaml file are as follows:
snap-name.app-name
If the app name is same as the snap name, then it may be run using the command:
snap-name
After the snapcraft.yaml file has been updated, the command:
sudo snapcraft --debug
should be run from the directory containing the snap folder. This command creates a .snap file using the information given in the snapcraft.yaml file.
Snapcraft uses Multipass to build the snap file. Multipass is a virtual machine management system. It allows launching and managing Virtual Machines on Linux, Mac and Windows. The —debug options causes snapcraft to open the virtual machine command prompt in case of errors. This makes it easier to debug problems.
When using multipass, the first time the snap is built it takes between 15 to 20 minutes to download the virtual machine image and package dependencies. Future builds take much less time.
If the snap is being built from within a LXC/LXD container, then it makes sense to build the Snap on the current system, instead of within a virtual machine running within the container. The —destructive-mode option should be used when building snaps within LXC/LXD containers.
Once the snap has been created, we can install it using the command:
sudo snap install --devmode snap-file-name
A sample snapcraft.yaml file for executable files is as follows:
name: snap-name # you probably want to 'snapcraft register <name>'
base: core20 # the base snap is the execution environment for this snap
version: '1.2.0' # just for humans, typically '1.2+git' or '1.3.2'
summary: Package summary # 79 char long summary
description: |
Package description
grade: devel # must be 'stable' to release into candidate/stable channels
confinement: devmode # use 'strict' once you have the right plugs and slots
layout:
source-file-path:
bind-file: $SNAPtarget-file-path
parts:
# The application files
app-files:
plugin: dump
source: path-to-folder
filesets:
data-files:
- data-file-path-1
- data-file-path-2
binaries: ["bin/bin-file-name"]
desktop-files:
- usr/share/applications/app-name.desktop
icons:
- usr/share/applications/app-icon.svg
stage:
- $data-files
- $binaries
- $desktop-files
- $icons
prime:
- $data-files
- $binaries
- $desktop-files
- $icons
organize:
"data/*.db": "usr/local/share/"
"data/*.desktop": "usr/share/applications/"
"data/*.svg": "usr/share/applications/"
apps:
app-name:
extensions:
- kde-neon
command: bin/bin-file-name
plugs:
- desktop
- desktop-legacy
- wayland
- unity7
desktop: usr/share/applications/app.desktop
The above file contains all the information needed to create a snap file for a PyQt5 executable file. It may be used for any executable file that needs to run on Gnome or KDE.
A typical desktop executable application consists of an executable file, desktop launcher file, application icon and data files. All these files should be placed in a single folder. The source entry for the app-files part should point to this folder. In the above example this folder is path-to-folder.
All these files need to be copied to the correct location by the build process. This is done using the dump plugin. The dump plugin simply copies the contents of a file or folder from the location specified under source, to another location.
filesets entry allows us to group all project files. Each entry under filesets is for a specific category of files. This allows us to reference all files in a category using a single key name. For example data-files.
The stage and prime entries are used to specify the files that should be copied over from the build stage. In the above example, we specify that the data files, binary files, icons and desktop launcher files should be copied over.
The organize entry allows us to specify how the application files should be placed in the snap. In the above example, we specify that the data files in path-to-folder/data should appear in usr/local/share.
The layout entry allows us to specify refer to files from within our application code. In the above example source-file-path refers to the path that is used in the source code of our application. This should be an absolute path. The $SNAPtarget-file-path is the actual location of the file in the snap. $SNAP is an environment variable that refers to the base location within the snap.
The usr/share/applications/ folder is a standard location for desktop launcher files. The contents of a sample app.desktop file are:
[Desktop Entry]
Name=App Name
X-GNOME-FullName=App Name
Comment=short-description
Categories=GNOME;category-name (see: https://developer.gnome.org/menu-spec/);
Exec=snap-name.app-name
Icon=${SNAP}/usr/share/applications/app-icon.svg
Terminal=false
Type=Application
Version=1.0.0
The snapcraft.yaml file also needs to specify the desktop environments, in which the GUI app will run. This can be done by listing the plugs required by the app. In the above example, the plugs entry indicates that the app needs to be run on desktop, desktop-legacy, unity7 and wayland desktop environments.
Once the Snap has been created and tested, it can be pushed to the Ubuntu Snap Store. In order to publish the Snap to the store, we need to first register an account. Next we need to login to the snap store from the command line using:
snapcraft login
After that we need to register our snap using the command:
snapcraft register snap-name
After that we need to set the grade to stable in snapcraft.yaml. Next we need to rebuild the snap using command:
snapcraft
This will create a .snap file in the current directory. After that we can push our snap to the snap store using the command:
snapcraft push snap-file-name --release=candidate
This command publishes our snap on the candidate channel. We may specify the stable channel once the snap is ready. We should then be able to install our snap from the snap store using the command:
sudo snap install snap-name --channel=candidate
In this article I have described how to create a snap application for a PyQt5 executable file. Snaps are a popular application format. They allow portable distribution of applications. Snaps have several useful features such as interfaces, layouts, hooks and data snapshots. Applications deployed as snaps are secure, easy to maintain and can run on multiple platforms.