Craft Parts – Reusable code, Snapcraft style
by Igor Ljubuncic on 26 November 2021
Throughout the ages, humans have always used simpler tools and materials to create more complex ones. Wood and stone for smelting bronze and iron; iron to create steel; vacuum tubes to create logical gates; logical gates to create advanced arithmetic engines, and so on. Modern software is no different.
With Snapcraft in particular, the snap building process comprises a number of steps. Source artifacts are collected, there’s compilation and assembly of binary products, and then, these are packaged into a single final archive. This process is very similar to how various other Canonical solutions work, and applicable to many different use cases outside of the snap world. To that end, the Snapcraft team has created a portable, reusable mechanism called Craft Parts.
A cycle of life
Craft Parts can obtain data from different sources, process it in various ways, and prepare a filesystem subtree suitable for deployment. Similar to how it’s done with snaps, the components used in the project specification are called parts, and they can be independently downloaded, built and installed.
The heart of the craft_parts module is the Lifecycle Manager component, which coordinates and executes all the steps in the parts lifecycle. At first, the idea may look a bit abstract, but for those who have built snaps before, the general approach will look quite familiar. As an example:
import yaml
from craft_parts import LifecycleManager, Step
parts_yaml = """
parts:
hello:
plugin: autotools
source: https://ftp.gnu.org/gnu/hello/hello-2.10.tar.gz
prime:
- usr/local/bin/hello
- usr/local/share/man/*
"""
parts = yaml.safe_load(parts_yaml)
lcm = LifecycleManager(parts, application_name="example", cache_dir=".")
actions = lcm.plan(Step.PRIME)
with lcm.action_executor() as aex:
aex.execute(actions)
In the example above, the Lifecycle Manager will download the hello tarball, unpack it, run its configuration script, compile the source code, install the resulting artifacts, and extract only the files we want to deploy (as specified by the prime keyword).
The final result will be a subtree containing the following files:
prime
prime/usr
prime/usr/local
prime/usr/local/bin
prime/usr/local/bin/hello
prime/usr/local/share
prime/usr/local/share/man
prime/usr/local/share/man/man1
prime/usr/local/share/man/man1/hello.1
There are several practical software building advantages to this approach:
- The user does not need to manually compile the artifacts – in this example, the autotools plugin, contained in the module, will handle the default compilation. If required, users who require more flexibility can introduce overrides.
- The compilation is done relative to the project directory, allowing portability of the final code. Again, the command-line tool offers additional flexibility, which can help create applications for different use cases and scenarios, without relying on any strict host system layout.
Overall, you can use the Lifecycle Manager to create subtrees of binary code and libraries, test whether you can shorten and simplify your compilation effort in comparison to traditional methods and tooling, and if you can make your applications easier to deploy.
Summary
At the moment, Craft Parts is designed to run on Ubuntu and requires Python 3.7 or higher. The mechanism is still in (very) early stages, so this is a great opportunity for software enthusiasts and tinkerers to step in and try the tool. Your feedback and ideas could help make Craft Parts even more extensible and useful. So please, test the framework, join the Snapcraft forum, and let us know what you think.
Photo by Nicolas Hoizey on Unsplash.