Software development is what happens in between users and bug reports.
In an ideal world, developers would be able to create new applications without any errors, and live happily ever after. Unfortunately, errors, warnings and bugs are an inseparable part of the process. Sometimes, these problems are caused or magnified by the very development framework, making the coding that much harder.
Snapcraft comes with its own basket of mysteries, side by side with the benefits and advantages that it brings. We want to make snapcraft as streamlined and elegant as possible, so that developers can focus on productivity, translating their ideas to creation, and not having to fight the environment and the tools they are using. To that end, we’d like to share several practical, useful tips and tricks that can make your snap journey as a developer more pleasant and effective.
One of the most trivial checks to run before building a snap is to make sure the snapcraft.yaml file has a correct, valid syntax. There could be minor typos in your file, and running the code against a validator can save time. Snapcraft has some built-in checks, but you can make the process even more robust.
You can use tools like JS-YAML or YAML Lint online. This is not a perfect solution, and some errors may slip under the radar, but you can at least detect and fix the obvious ones before you start your application build. Various linting tools for YAML are also available in most Linux distribution repositories, so you can also use those, and maybe even integrate them into your development build environment.
It is best to build snaps in a clean environment. There are several ways you can do this. The ideal solution is to use the base keyword in your snapcraft.yaml, e.g.:
The base keyword specifies a special kind of snap that provides a minimal set of libraries common to most applications. It will be mounted as the root filesystem for your application. Using core18 as the base is the recommended option.
In the background, snapcraft will instantiate virtual machines and build snaps in a pristine, isolated and consistent environment. If you encounter errors or problems, you can then run snapcraft clean <part> to delete created artifacts and re-run your builds.
Alternatively, if you are not using the base keyword, you can use the snapcraft cleanbuild command. This command will span a new container with the necessary build tools inside, parse the snapcraft.yaml file and try to build your snap.
Review Tools snap
Once you have built your snap successfully, the next step is to upload it to the store for a review. After it’s been approved, it will be published and made available to users. Sometimes, your snap may be rejected, and it is frustrating to have to wait and then start over again.
You can save time by reviewing your own snaps – using the same tools normally involved in the vetting process. The review-tools snap is a set of scripts that can analyze your newly built snap before you upload it, allowing you to remedy any errors and warnings you encounter. First, start by installing the tools:
snap install review-tools --beta
After the snap is installed, run it against your snap:
snap-review <snap file>
The review-tools snap also comes with several options, so you can tweak your testing. It allows for overrides, classic confinement, and other flags. You can check the full list by running the tool without a target and only the –help argument.
After the tool finishes running, it will print output, which you can then use to better understand the nature of your non-compliant code and rebuild the snap. You should publish the snap once you get a clean run.
desktop interfaces (unity7,x11) specified without a corresponding meta/gui/*.desktop file. If using snapcraft, please see https://snapcraft.io/docs/build-snaps/metadata#fixed-assets. Otherwise, please provide a desktop file in meta/gui/*.desktop (it should reference one of the 'apps' from your snapcraft/snap.yaml).
The output above shows a typical error a developer may see after running the review-tools snap. Some of the explanations are self-explanatory, and you will also usually get a reference to the online documentation.
Finally, like the linting tools, you can add snap-review into your Continuous Integration (CI) environment or your software release process, so you get an automated report of your builds before uploads. This can be helpful if you develop applications as part of a team, and allow you to detect possible breakages before the software lands in the Snap Store.
Home directory contents and configurations
If you’re testing the behavior of your snaps, you may discover that it is not using the configuration normally found in your home directory. For example, if you have GIMP 2.8 installed from the repositories and GIMP 2.10 as a snap, the scripts, brushes, themes, and templates you may have stored in the program’s hidden folder in your home will not be available in the snap, which could hamper your experience. The reason for the separation stems from security considerations, to prevent confined snaps from accessing configuration files and potentially sensitive data.
You can move content – either for testing or actual use – into the snap environment. This is a seemingly trivial action, but it can save a lot of time and effort, especially if you need to troubleshoot specific behavior in your snap.
For each snap, go to ~/snap/<application name>. In this folder, there may be several versions of the program available, with current being a symbolic link pointing to the relevant version. Inside, you will find the expected hierarchy of files and folders as you’d normally find in your home directory. You can now manually copy the files from outside the snap environment into it, so your applications will use the content on next launch. For instance:
Snaps are designed to be confined and restricted in what they can do. In some cases, the snap may be packaged in a way that do not use folders inside the home directory, so you won’t be able to move or copy content into the snap environment using the method shown above. Specifically, the home interface will be auto-connected on classic systems, but it will not be on Ubuntu Core. Instead, you can connect to the home interface manually to perform necessary tasks. For instance:
We briefly touched on the interfaces, but there’s more we can do to troubleshoot our applications. Specifically, when an interface is omitted in snapcraft.yaml (or not auto-connected), but your software expects it to be available, this may result in the application misbehaving.
The snap security team have provided a tool to debug these situations, and it’s called snappy-debug. Like the review-tools, it is available as a snap. Once it’s installed, you can use it to help identify missing interfaces by reporting on application security failures. It will also make suggestions on how to improve the snap, perhaps by adding interfaces.
snap install snappy-debug
After the snappy-debug tool is installed, run it in a separate shell:
snappy-debug.security scanlog INFO: following '/var/log/syslog'. If have dropped messages, use: INFO: $ sudo journalctl --output=short --follow --all | sudo snappy-debug.security scanlog
Then, in another window, run your application and go through the expected behavior steps until you encounter an error. You can then consult the log for more details, which should highlight any issues with your snap. For instance, if you use a Firefox snap with the removable-media that isn’t auto-connected, and you try to save a file to a USB drive, you will see something like this:
= AppArmor = Time: Oct 24 13:39:04 Log: apparmor="DENIED" operation="open" profile="snap.firefox.firefox" name="/etc/fstab" pid=25299 comm="firefox" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0 File: /etc/fstab (read) Suggestions: * adjust program to read necessary files from $SNAP, $SNAP_DATA, $SNAP_COMMON, $SNAP_USER_DATA or $SNAP_USER_COMMON * add 'mount-observe' to 'plugs'
= AppArmor = Time: Oct 24 13:39:07 Log: apparmor="DENIED" operation="open" profile="snap.firefox.firefox" name="/media/alan/9098a06f-f509-452a-b2b8-3f00aee808a2/" pid=25299 comm="pool" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0 File: /media/alan/9098a06f-f509-452a-b2b8-3f00aee808a2/ (read) Suggestion: * adjust program to read necessary files from $SNAP, $SNAP_DATA, $SNAP_COMMON, $SNAP_USER_DATA or $SNAP_USER_COMMON
Sometimes, you have be interested in profiling the behavior of your application in detail. You might want to compare the initial startup between your application as a snap and the version distributed through the repository channels. Or you might want to examine the performance, or resolve an issue with a missing theme.
The snap binary comes with a built-in strace functionality. The invocation is slightly different from the standard usage, but the tool works exactly like the strace program normally would, including the different flags. For example, -c for a summary run, or -s512 to get the log printed with 512 characters per line (often useful if you need to debug long file name paths). To use strace, you need to use the equal sign to pass the arguments to strace and enclose the options in double quotation marks:
snap run --strace=”-s512 -f”
We believe that software tools should work with the developers – not against them. If the development framework is not transparent, then it can hurt the productivity and creativity of the developer. Snapcraft has many useful, practical features, and we’re working on making the experience even more streamlined.
If you are developing snaps, we’d like to see you spend as little time debugging errors and warnings and focus on making your software as robust as possible. To that end, the tips and tricks presented in this article, from linting to review and configurations, ought to help you enjoy snapcraft.
If you have any questions or perhaps useful tips of your own own you’d like to share, please join the discussion forum.
P.S. No Star Trek fans were harmed in the production of this blog post.