Request for Comments: Transitioning to APK
RFC — Turris OS APK
This document proposes options in transition of Turris OS package management Updater infrastructure to Alpine Package Keeper (hereinafter APK).
Rationale
As OpenWrt transitioned to APK from opkg, we should move to it as well. We currently have a very extensive Updater project, but as APK is more advanced (and reliable) package manager than opkg is, many of its features can be left to from big parts or fully for APK.
Document Notes
This document uses examples of packages. It is written as a Python script for awesome Chimera Linux's cbuild. Most of the code will be left out for brevity.
I also include example package definitions for cports and also a pre-built repository.
Specific APK features
APK does not have some features common for other package managers, like weak dependencies or groups. But it still does include some intriguing features, like:
Virtual Packages
APK can create virtual packages on the fly, allowing specifying their dependencies1.
We can create one just like this:
> apk add --virtual my-devtools rust clang mold
Uninstalling package my-devtools will, unless rust, clang and mold are requested by something else,
trigger their removal.
These can be used, for example, to ad-hoc group packages together or as, as you can see later, as nodes for
world solver. So packages can have e.g. install_if constraints on virtual packages or even their negations.
Install If
Although APK does not support weak dependencies or recommendations, it does support something like it in reverse.
A package can specify install_if, which, in case of fulfilling these constraints will install the package.
pkgname = "sway"
# … removed for brevity …
@subpackage("sway-backgrounds")
def _(self):
self.subdesc = "backgrounds"
self.install_if = [self.parent]
return ["usr/share/backgrounds"]
— Example from https://github.com/chimera-linux/cports/blob/5fe0b75dfe9ca7741204c8fc4995f43b26f10f2f/main/sway/template.py
Negations
We can also specify a negative constraint. APK's solver is pretty simple, with no support for priorities, so negation of a dependency will create a conflict.
If we take a look on the install_if example for sway-backgrounds, it's condition is, that it gets installed
when sway is installed, but it is not (in our example, at least) a dependency of anything, therefore we can
specify a negative dependency !sway-backgrounds which will prevent it from being installed.
Package Lists
One of Updater's features is package lists. Currently these are configured using UCI configuration document.
These can be (likely) implemented using just packages which provide nothing, just specify dependencies for the APK solver.
pkgname = "turris-pkglist-tor"
pkgver = "2026.03.08"
pkgrel = 0
build_style = "meta"
depends = ["tor", "tor-hs"]
pkgdesc = "The Onion Router"
license = "custom:none"
url = "https://turris.cz"
Updater then can just add turris-pkglist-tor to the world file.
Device-dependent packages
This is a job for Turris OS updater, reacting on available devices and managing world file accordingly.
if Devices.is_class_available DVB then
APK.add "turris-device-dvb"
else
APK.del "turris-device-dvb"
end
Executing of the package turris-device-dvb can vary. One option would be creating such package
with dependency on TVH.
pkgname = "turris-device-dvb"
depends = ["tvheadend", "turris-webapps-tvheadend"]
This introduces an issue, when user does not want to have tvheadend installed despite having
DVB tuner, for example, if they wish to use different software. For such cases alternative solution
could be:
pkgname = "tvheadend"
install_if = ["turris-device-dvb=0.1.0-r0"]
# …
pkgname = "turris-webapps-tvheadend"
install_if = ["turris-device-dvb=0.1.0-r0", "tvheadend"]
# …
In this case, user could just specifcy !tvheadend constraint in the world file.
As we build packages ourselves anyways, adding install_if to packages is a non-issue.
Priorities
APK does not have priority on constraints in the world file. The only priority available is for providers, serving as tie-breaker when two packages provide the same virtual package and the constraints can be fulfilled by both.
So our current solution of having basically our own implementation of opkg with our own solver would require keeping doing exactly this but for APK. As APK is more capable than opkg, this, in my opinion, seems to be a case of doing 80% of the work for solving 5% of edge cases.
Providers
Another example of updaters feature which can be done only using APK is current (as of 2026-03-08) case of Knot Resolver.
The default Knot Resolver is v5 but v6 is available at user's request.
If we include Knot Resolver v5 as, let's say part of a base system metapackage, installing v6 would be basically impossible.
Adding Knot Resolver v6 to the world file would then require the updater to have higher reasoning over the world file, which introduces additional complexity to the updater itself and the rest of the system.
This is a good use case for provider priorities, as we could define packages in this way:
pkgname = "knot-resolver-v5"
provides = ["turris-meta-dns-resolver"]
provider_priority = 20
# …
pkgname = "knot-resolver-v6"
provides = ["turris-meta-dns-resolver"]
provider_priority = 10
# …
pkgname = "turris-meta-base"
depends = ["virtual:turris-meta-dns-resolver!knot-resolver-v5", …]
# …
Drawbacks
- Transitioning from updater scripts to APK may require additional work to reinterpret them in APK context
- Unless we reimplement basically the package manager (or at least the solver part) ourselves, priorities are not much a thing to do
- Would require extensive work on updater and probably package building infrastructure, but as opkg is getting officially dead, it is a thing that would have to be done anyways (unless we want to continue supporting
opkgcompletely on our own which may get more difficult and complex as time goes and opkg is kinda crappy…)
Further reads
- https://docs.postmarketos.org/pmaports/main/packaging-guidelines.html
- https://gitlab.com/postmarketOS/pmbootstrap/-/work_items/1933
- https://github.com/chimera-linux/cports/blob/master/Packaging.md
- https://wiki.alpinelinux.org/wiki/APKBUILD_Reference
Attachments
-
Not completely sure about how it works internally, maybe programmatic API allows more? ↩