In the same spirit of my first PKGBUILD and Ebuild
, herein I will describe my first APKBUILD
.
At a glance
Alpine Linux package management is very similar to Arch Linux, with tiny differences:
PKGBUILD
→APKBUILD
: The filename is obviously different. Their format are very similar though, both of them are bash scripts with variables and functions. In particular, there’scheck
,patch
,build
andpackage
.cp /usr/share/pacman/PKGBUILD.proto
→newapkbuild
: Template versus scaffolding.pacman
→apk
: The package manager is different.makepkg -s
→abuild -r
:makepkg
drives all things package building forpacman
.abuild
drives package building forapk
.makepkg -i
→apk add <pkg>
:makepkg
can also drive package installations whereasabuild
cannot,apk
must be used.namcap
→apkbuild-lint
(fromatools
) +abuild sanitycheck
1: Linters are different.updpkgsums
→abuild checksum
: Generate hashes for package sources.
Other than that, the process of writing an APKBUILD
is very similar to writing a PKGBUILD
. In fact, the Arch repositories (especially the AUR) tend to be much more comprehensive than Alpine’s in terms of number of packages, so chances are if you want to write a new package for Alpine, check in Arch’s repos first, it’s a good starting point.
My first package: fpp
fpp
stands for ‘Facebook Path Picker’.
As of the time of this post, I maintain fpp-git
in the AUR. It looks like this:
pkgname=fpp-git
pkgver=0.9.2.r130.ge0d5cfc
pkgrel=1
pkgdesc='TUI that lets you pick paths out of its stdin and run arbitrary commands on them'
url='https://facebook.github.io/PathPicker'
license=('MIT')
source=("${pkgname%-git}::git+https://github.com/facebook/PathPicker.git")
sha256sums=('SKIP')
arch=('any')
makedepends=('git')
depends=('python')
conflicts=("${pkgname%-git}")
provides=("${pkgname%-git}")
prepare() {
cd "$srcdir/${pkgname%-git}"
rm -r "src/tests"
}
pkgver() {
cd "$srcdir/${pkgname%-git}"
git describe --long --tags | sed 's/\([^-]*-g\)/r\1/;s/-/./g'
}
package() {
cd "$srcdir/${pkgname%-git}"
# library
install -Dm755 "fpp" -t "$pkgdir/usr/share/fpp"
cp -a src "$pkgdir/usr/share/fpp"
# entrypoint
install -dm755 "$pkgdir/usr/bin"
ln -s "/usr/share/fpp/fpp" "$pkgdir/usr/bin"
# documentation
install -Dm644 LICENSE -t "$pkgdir/usr/share/licenses/$pkgname"
install -Dm644 "debian/usr/share/man/man1/fpp.1" -t "$pkgdir/usr/share/man/man1"
}
PKGBUILD
guidelines and instructions:
The equivalent APKBUILD
I wrote looks like this:
pkgname=fpp
pkgver=0.9.2
pkgrel=0
pkgdesc="TUI that lets you pick paths out of its stdin and run arbitrary commands on them"
url="https://facebook.github.io/PathPicker"
arch="noarch"
license="MIT"
depends="bash python3"
subpackages="$pkgname-doc"
source="$pkgname-$pkgver.tar.gz::https://github.com/facebook/PathPicker/archive/$pkgver.tar.gz"
builddir="$srcdir/PathPicker-$pkgver"
check() {
fpp --version
}
prepare() {
default_prepare
rm -r "src/__tests__"
}
package() {
# library
install -Dm755 "fpp" -t "$pkgdir/usr/share/fpp"
cp -a src "$pkgdir/usr/share/fpp"
# entrypoint
install -dm755 "$pkgdir/usr/bin"
ln -s "/usr/share/fpp/fpp" "$pkgdir/usr/bin"
# documentation
install -Dm644 LICENSE -t "$pkgdir/usr/share/licenses/$pkgname"
install -Dm644 "debian/usr/share/man/man1/fpp.1" -t "$pkgdir/usr/share/man/man1"
}
sha512sums="
65b6b077f437bd642ebf94c55be901aabc73f7b9c89e4522c4f51970c4d63d744ad8fa29cac06816851f63bcb81d0480e61d405231c582e9aca0f4e650949a97 fpp-0.9.2.tar.gz
"
APKBUILD
guidelines and instructions:
- https://wiki.alpinelinux.org/wiki/Creating_an_Alpine_package
- https://wiki.alpinelinux.org/wiki/APKBUILD_Reference
Build Comparison
Let’s highlight a few similarities and differences in them, excluding the fact that one is fetched from git and the other one fetches a point release directly2:
- package metadata, by the means of bash variables, are almost equivalent
one-to-one
- A notable difference is the architecture, Arch primarily supports
x86_64 whereas Alpine has support for multiple architectures. When
a package is architecture agnostic, Arch denotes it with
any
whereas alpine has bothnoarch
andall
, the latter is likeany
(=all architectures), theformer
means it’s agnostic (=e.g. a pure bash script or python package). APKBUILDs
use flat strings, whereasPKGBUILDs
use bash arrays- Alpine encourages splitting larger packages into subpackages, as such
APKBUILD
has first-class support and syntactic sugar for that.-dev
and-doc
subpackages are very common. On the other hand, Arch tends to have monolithic packages in order to keep it simple, although it also supports subpackages. - Alpine supports setting
$builddir
whereas Arch doesn’t. As a consequence, it’s often unneeded tocd
inbuild()
andpackage()
in Alpine, whereas in Arch one does need to manually change directories to$srcdir/$pkgname
before building. - Alpine lacks optional dependencies, whereas Arch has
optdepends
.
- A notable difference is the architecture, Arch primarily supports
x86_64 whereas Alpine has support for multiple architectures. When
a package is architecture agnostic, Arch denotes it with
- Alpine enforces the use of
check
in test packages, otherwise it needs to be explicitly disabled and documented with!check
inoptions=
. That’s not the case in Arch. check()
,build()
andpackage()
are pretty much similar in both formats.$srcdir
and$pkgdir
are provided in both.- The ArchWiki is way more documented in terms of packaging guidelines and examples than Alpine’s. If you use DuckDuckGo, you can query for
!aw <foo>
as a bang shortcut to search directly in the ArchWiki.
Last but not least, in Arch one can install package tarballs3 with makepkg -i
or pacman -U
. In Alpine that approach doesn’t seem to be directly supported. The workflow is to add a local repository diretory in /etc/apk/repositories
(notice the last two lines):
$ cat /etc/apk/repositories
# http://dl-cdn.alpinelinux.org/alpine/v3.15/main
# http://dl-cdn.alpinelinux.org/alpine/v3.15/community
# http://dl-cdn.alpinelinux.org/alpine/latest-stable/main
# http://dl-cdn.alpinelinux.org/alpine/latest-stable/community
http://dl-cdn.alpinelinux.org/alpine/edge/main
http://dl-cdn.alpinelinux.org/alpine/edge/community
http://dl-cdn.alpinelinux.org/alpine/edge/testing
/home/$USER/packages/community
/home/$USER/packages/testing
abuild
will place the resulting package tarball in ~/packages
, in this case:
$ ls ~/packages/testing/x86_64/fpp*
/home/$USER/packages/testing/x86_64/fpp-0.9.2-r0.apk
/home/$USER/packages/testing/x86_64/fpp-doc-0.9.2-r0.apk
…and then apk add fpp
will automagically recognize it’s in there and install it. The advantage of this approach is that it keeps a local package repository around and it’s well integrated with apk
, way differently from pacman
that has no integration with the AUR at all. One could also possibly set up a local repository in Arch, for example, with ccm
, but it takes extra steps and it’s not officially supported.
Upstream Contributions
On Arch, to contribute a PKGBUILD
upstream one just needs to create an account in the AUR. Armed with a git + ssh infrastructure, all you need to do is git push
. There are no ACLs involved, anyone can do that4.
On Alpine there’s a bit more of politics involved5: Anyone can send a patch(1)
, either via mailing list or via a Gitlab MR (merge request). Patch works well with git send-email -1
, being automatically cross-posted to a Gitlab MR. On the other hand the MR workflow is easier to be followed up on feedback from developers and other contributors (git push --force
), and it’s also cross-posted, to the mailing list. An Alpine developer with the appropriate permissions must approve your patch/MR before it becomes available to other Alpine users.
Sadly at the time of this writing my patch hasn’t yet been approved (2 weeks later), however we’re in holiday season. This wouldn’t have been a problem in the AUR, where I could have just pushed it immediately, without any review. On the other hand the Alpine approach at least gives me some hope that the submitted packages have slightly higher quality than the average ones in the AUR, since they need to be manually reviewed/approved/vetted by at least one Alpine developer.
Install
spdx-licenses-list
to lint the licenses, it’s used byabuild sanitycheck
as an optional dependency. ↩︎The AUR tends to have both non-vcs and vcs versions of a software, whereas Alpine is focused a bit more on stability and tends to have non-vcs only. This is not a hard rule though, exceptions may exist. ↩︎
.tar.xz
or, more recently,.tar.zstd
. ↩︎And this is one of the reasons why you should always inspect every
PKGBUILD
you install from the Arch User Repository, as it could have been tampered with and/or contain malicious code. ↩︎I’ll leave it open-ended whether that’s a bug or a feature. Depending on the lens you see through, it could be considered either gatekeeping (bureaucracy, control) or sanity (quality, stability). It has pros and cons, and even those are arguable. ↩︎