Published

Notes on building Arch packages on openSUSE Build Service

I use openSUSE Build Service (OBS) to build most of my packages for Archlinux, sourced from AUR or written by myself, except for a few proprietary packages which OBS does not permit to be built on its infrastructure. There are some caveats, tho, and this post keeps a few notes to work around these.

Set PACKAGER

OBS uses a generated PACKAGER value which effectively identifies the build worker, for instance, i04-ch1b <abuild@i04-ch1b>. There are no direct means to change this, but there's a workaround, albeit a slightly hacky one:

  1. Create a package (say, makepkg-packager) which installs a profile snippet containing export PACKAGER="Jane Doe (OBS) <jdoe@example.com>" at /etc/profile.d/obs-packager.sh (example).
  2. Add the package to Requires: makepkg-packager in the project configuration, via the web interface or osc meta prjconf -e (example).

This effectively sets the $PACKAGER environment variable for the build process of every package in the project, and luckily the Arch build recipe explicitly sources the whole /etc/profile before invoking makepkg. A makepkg drop-in for /etc/makepkg.conf.d won't work, because the Arch OBS build recipe explicitly assembles a custom makepkg file.

The package can be moved to a separate subproject (e.g. "supplemental" or "internal") linked to the main project; this will enable builds from the main project to use the package, but the package won't appear in the repository of the main project.

Disable automated rebuilds

OBS automatically rebuilds packages if dependencies change, but this doesn't work well for Archlinux packages:

Automatic rebuilds can be disabled by adding the attribute rebuild="local" to the repository element in the project metadata, via the web interface or osc meta prj -e (example):

   <title>Internal dependencies</title>
   <description></description>
   <person userid="swsnr" role="maintainer"/>
-  <repository name="Arch">
+  <repository name="Arch" rebuild="local">
     <path project="Arch:Extra" repository="standard"/>
     <arch>x86_64</arch>
   </repository>

Resolve multiple providers for dependencies

OBS does not resolve multiple provides automatically. This affects e.g. Rust, which is provided both by rust and rustup; OBS fails to resolve this and needs to be told explicitly which package to prefer via the Prefer setting in the project configuration (example).

Dealing with offline builds

OBS builds packages without network access, so all sources must be available upfront in the package repository. For standard packages with archive sources (i.e. source tarballs) the download_files source service makes OBS automatically download and commit the source archives on every commit. It can be enabled with the following content in the _service file (example):

<services>
  <service name="download_files"/>
</services>

For packages which fetch extra dependencies during build (e.g. NPM, Rust, Go, Maven, etc.) these dependencies need to be vendored upfront and added as an explicit source. The details depend on the package manager being used; for Cargo for instance I usually use cargo vendor, then tar the resulting vendor/ directory and commit it as separate source (example). For go it's similar (example). Generally, it's easy for anything with first-class support for vendoring (e.g. Rust, Go) or which just puts dependencies into a directory in the source tree (e.g. npm). For stuff which doesn't support vendoring and puts dependency artifacts in some other location, it can be quite some work (e.g. Maven, Haskell).

In any case, any PKGBUILD from the AUR which expects to be able to download dependencies during build won't work on OBS; it needs to be adapted, or in some cases entirely rewritten, to account for offline builds.