= Guix inside sourcehut builds.sr.ht CI
:updatedat: 2020-08-19

:nixos: https://man.sr.ht/builds.sr.ht/compatibility.md#nixos
:guix: https://guix.gnu.org/
:binary-inst: https://guix.gnu.org/manual/en/guix.html#Binary-Installation
:shell-inst: https://git.savannah.gnu.org/cgit/guix.git/plain/etc/guix-install.sh

After the release of the {nixos}[NixOS images in builds.sr.ht] and much usage of
it, I also started looking at {guix}[Guix] and wondered if I could get it on the
awesome builds.sr.ht service.

The Guix manual section on the {binary-inst}[binary installation] is very
thorough, and even a {shell-inst}[shell installer script] is provided, but it is
built towards someone installing Guix on their personal computer, and relies
heavily on interactive input.

I developed the following set of scripts that I have been using for some time to
run Guix tasks inside builds.sr.ht jobs.  First, `install-guix.sh`:

[source,sh]
----
#!/usr/bin/env bash
set -x
set -Eeuo pipefail

VERSION='1.0.1'
SYSTEM='x86_64-linux'
BINARY="guix-binary-${VERSION}.${SYSTEM}.tar.xz"

cd /tmp
wget "https://ftp.gnu.org/gnu/guix/${BINARY}"
tar -xf "${BINARY}"

sudo mv var/guix /var/
sudo mv gnu /
sudo mkdir -p ~root/.config/guix
sudo ln -fs /var/guix/profiles/per-user/root/current-guix ~root/.config/guix/current

GUIX_PROFILE="$(echo ~root)/.config/guix/current"
source "${GUIX_PROFILE}/etc/profile"

groupadd --system guixbuild
for i in $(seq -w 1 10);
do
  useradd -g guixbuild                       \
          -G guixbuild                       \
          -d /var/empty                      \
          -s "$(command -v nologin)"         \
          -c "Guix build user ${i}" --system \
          "guixbuilder${i}";
done

mkdir -p /usr/local/bin
cd /usr/local/bin
ln -s /var/guix/profiles/per-user/root/current-guix/bin/guix .
ln -s /var/guix/profiles/per-user/root/current-guix/bin/guix-daemon .

guix archive --authorize < ~root/.config/guix/current/share/guix/ci.guix.gnu.org.pub
----

Almost all of it is taken directly from the {binary-inst}[binary installation]
section from the manual, with the interactive bits stripped out: after
downloading and extracting the Guix tarball, we create some symlinks, add
guixbuild users and authorize the `ci.guix.gnu.org.pub` signing key.

After installing Guix, we perform a `guix pull` to update Guix inside
`start-guix.sh`:

[source,sh]
----
#!/usr/bin/env bash
set -x
set -Eeuo pipefail

sudo guix-daemon --build-users-group=guixbuild &
guix pull
guix package -u
guix --version
----

Then we can put it all together in a sample `.build.yml` configuration file I'm
using myself:

[source,yaml]
----
image: debian/stable
packages:
  - wget
sources:
  - https://git.sr.ht/~euandreh/songbooks
tasks:
  - install-guix: |
      cd ./songbooks/
      ./scripts/install-guix.sh
      ./scripts/start-guix.sh
      echo 'sudo guix-daemon --build-users-group=guixbuild &' >> ~/.buildenv
      echo 'export PATH="${HOME}/.config/guix/current/bin${PATH:+:}$PATH"' >> ~/.buildenv
  - tests: |
      cd ./songbooks/
      guix environment -m build-aux/guix.scm -- make check
  - docs: |
      cd ./songbooks/
      guix environment -m build-aux/guix.scm -- make publish-dist
----

We have to add the `guix-daemon` to `~/.buildenv` so it can be started on every
following task run.  Also, since we used `wget` inside `install-guix.sh`, we had
to add it to the images package list.

After the `install-guix` task, you can use Guix to build and test your project,
or run any `guix environment --ad-hoc my-package -- my script` :)

== Improvements

:repository: https://git.sr.ht/~sircmpwn/builds.sr.ht

When I originally created this code I had a reason why to have both a `sudo`
call for `sudo ./scripts/install-guix.sh` and `sudo` usages inside
`install-guix.sh` itself.  I couldn't figure out why (it feels like my past self
was a bit smarter 😬), but it feels ugly now.  If it is truly required I could
add an explanation for it, or remove this entirely in favor of a more elegant
solution.

I could also contribute the Guix image upstream to builds.sr.ht, but there
wasn't any build or smoke tests in the original {repository}[repository], so I
wasn't inclined to make something that just ``works on my machine'' or add a
maintainence burden to the author.  I didn't look at it again recently, though.
