Setting Up a Guix Channel

This post is a sort of “fresh in my mind” walkthrough of setting up a Guix channel. Most of the information I'll go over is from or alluded to in that section of the Guix manual, but I found the ordering and wording to be a bit confusing. Plus, none of the PGP signing or git steps are covered. This will instead be a step-by-step recap of what I did, both for myself and the broader community. Note that for unsigned repositories, the order doesn't actually matter; for signed repositories, this is the simplest order.

I plan to eventually write a series of blog posts on what Guix is and why it rocks, but if you're reading this you probably don't need it. Still, I wrote some preliminary thoughts a while back. While some things mentioned there have changed in the months since, including my understanding of Guix, it's still a decent overview.

Step 0 (optional): PGP Setup

You don't actually need to sign your Guix channel if you don't want to. I did it just because I thought it would be cool. If you expect other people to use your channel (I do not), it's the polite thing to do.

Note that the information in this section was learned from a friend. Thanks, friend! (Any incorrect terminology or inaccurate descriptions of what is going on are on me, not said friend.)

Step 1: Get GnuPG

If you're on GuixSD (which you should be if you're using Guix tbh in my imho opinion lon tawa mi), you should have the gpg commandline tool available already. But! It doesn't work. You need pinentry in the same profile. For whatever reason that I didn't want to debug at the time, sticking GnuPG and pinentry in my home profile didn't work, so I ultimately just did guix package -i gnupg pinentry and things worked. I also tried using Seahorse, but I couldn't use the generated key without gpg and pinentry anyway, and the CLI gives more power. I'll be covering the CLI approach here.

Step 2: Generate a Key

First, run gpg --full-gen-key --expert. You'll be presented with a dialog asking you to select your key type. I went with ECC on my friend's suggestion, but RSA with >=3072 bits should be equally strong. The rest of this description assumes you chose ECC. Make sure whatever you choose, you can both sign and encrypt with the key.

After choosing your key type, you'll be prompted to choose the elliptic curve. Curve25519 is what I went with, though Curve488 should be fine as well. Some others apparently have weaknesses known to at least the NSA and presumably others. (Edit: this wording is inaccurate; there is not known to be a backdoor in these algorithms, but it is provably possible that there is a backdoor. I have no idea what this means, but this Wikipedia article may help.)

Next you'll be prompted to choose an expiration for your key. I chose no expiration just because this channel should exist for an arbitrarily long period of time and I don't want to deal with updating keys, but setting an expiration period is probably a better idea and is what was advised to me.

Penultimately, you'll be prompted to fill in information associated with the key, like your name and email address. I was advised not to include a comment, but didn't realize that until just now and did it anyway. Oops! You probably want to make the name and email match whatever your git name and email are, just for consistency.

Finally, gpg will open a pinentry prompt asking you to fill in a password. If you want to copy this password, do it before pressing enter; the pinentry prompt blocks keyboard and mouse input. Fill in your password, press enter, and your key will be generated!

gpg will echo back the information you entered once it generates your key. Copy the string of random characters under the “pub” heading because you'll need it a few times going forward. This is the fingerprint of your public key.

This all sounds much more complicated than it is. Your shell history will basically look something like:

gpg --full-gen-key --expert
# following prompts...
<output>

Step 3: Setup Git Signing

Create the directory where you'll setup your Guix channel if you haven't already. Initialize a git repository, then turn on commit.gpgsign and set your key fingerprint for user.signingkey. That looks like so:

mkdir example
cd example
git init
git config [--local] commit.gpgsign true
git config [--local] user.signingkey <key fingerprint>

You can optionally enter your key fingerprint for each commit, but this is simpler and will throw errors if you try to commit without signing, so I advise this method.

And that's it! Your PGP setup is ready to go. We'll come back to the signatures again later, but everything else is directly related to Guix.

Step 1: Git Setup

Step 1: Create the Repository

Skip this step if you're following the signed channel instructions.

If you haven't already, make a git repository. That goes something like,

mkdir example
cd example
git init

Boom, done.

Step 1.1 (optional): Create Keyring Branch

Skip this step if you're not signing your channel.

This and the next two steps can be done in any order, but doing this in an empty repo saves some effort. All you need to do is create an orphan git branch named “keyring” and export your PGP key, either binary or “ASCII armored” (the -a switch), to a “<identifier>.key” file committed there. The Guix convention seems to be “<name of committer>-<first 8 characters of key fingerprint>.key” so that's what I did. You can name this branch anything you want, but for simplicity I advise using “keyring”; see the documentation if you want to do that. Here's what that looks like all together:

git checkout --orphan keyring
gpg --export [-a] > <identifier>.key
git add <identifier>.key
git commit [-m "Initial commit"]
git checkout <main branch>

Step 1.2 (optional): Create Guix Authorizations File

Skip this step if you're not signing your channel.

This part is covered fairly well by the official documentation, but here's a quick summary.

Create a file in the root of your git repository called “.guix-authorizations”. In that file, enter the following code:

(authorizations
  (version 0)      ; version for the file format, not your channel
  (("Paste Your Key Fingerprint Here"
    (name "Your Name"))))

The name entry is optional and does nothing at the moment.

Step 2: Create Channel File

This is it! This is the big moment! This is where your git repository becomes a Guix channel! All you do is create a file called “.guix-channel” that is potentially as simple as:

(channel
  (version 0))

And you're done!

If you are signing your repo and didn't use “keyring” as your keyring branch name, you'll need another entry in addition to version called keyring-reference with a string for the name of your branch, like so:

(channel
  (version 0)
  (keyring-reference "your-keyring-branch"))

Step 3: Commit!

You're ready to commit to your main branch! git add your “.guix-channel” file and, if you're signing, your “.guix-authorizations” file. Here's what that looks like:

git add .guix-channel [.guix-authorizations]
git commit [-m "Initial commit"]

Step 4: Advertise Your Channel

Now that you have an initial commit, you can setup a signed or unsigned channel advertisement equally easily. If you aren't signing, you can add the advertisement in the initial commit. Basically, all “advertising your channel” means is putting the channel definition a user needs somewhere public. I stuck mine in my README since git forges display this by default. Here's what a basic channel definition looks like:

(channel
  (name 'your-channel-name)
  (url "https://example.com/channel-git-repo.git"))

If your main branch is not called “master” (and it really shouldn't be), you'll need to specify that in a branch entry, shown below:

(channel
  (name 'your-channel-name)
  (branch "main-branch-name")
  (url "https://example.com/channel-git-repo.git"))

If you are signing your repo, you'll also need an introduction entry with your first signed commit; this is whatever commit you added “.guix-authorizations” with. You can get that by eg git log and copying the commit hash. You'll also need the key fingerprint in a openpgp-fingerprint entry. It'll look like this:

(channel
  (name 'your-channel-name)
  (branch "main-branch-name")
  (url "https://example.com/channel-git-repo.git")
  (introduction
   (make-channel-introduction
    "commit-hash"
    (openpgp-fingerprint
     "pgp-key-fingerprint"))))

If you need to get your gpg key fingerprint again, that's done with gpg --list-keys and copying the random characters under the “pub” heading.

Step 5: Push!

All that's left is to add your advertisement and push to your remote git repository! Create a skeleton repo in your git software of choice (I use gitea, which is like a lightweight, self-hosted GitHub) then add the url as a remote origin and push your branches. Here's that procedure for completeness:

git add README.md
git commit [-m "Add README"]
git remote add origin "https://example.com/channel-git-repo.git"
git push -u origin <main branch>
[git checkout keyring]
[git push -u origin keyring]
[git checkout <main branch>]

Congratulations! You now have a Guix channel of your very own!

Wait! Fuck! We didn't add any packages! I guess that means we need to...

Step 3: Add Packages

Adding Guix packages is “as simple as” creating a Guile module with them in it. I didn't use Guile before switching to Guix, so the procedure was non-obvious to me. It is fairly simple once you know how it works, but many of the overlaps of Guix and Guile are fuzzy. For absolute clarity, I'll break it down into steps.

Step 1: Create Directory Structure

On the main branch of your git repository, make a directory with whatever name you chose for your channel; that is, the name entry you used in your channel declaration. Under that, you'll probably also want a “packages” directory or similar. That's as simple as mkdir -p your-channel-name/packages.

Step 2: Create Guile Files Declaring a Module

This is simple. Just make a file ending in “.scm” and, at the top, declare a normal Guile module. Here's what that looks like with the standin names we've discussed: (define-module (your-channel-name packages filename)). Note that filename is the name of the file without the “.scm” bit. If you need other modules (and you probably do), you'll use standard #:use-module declarations. A more robust example:

(define-module (your-channel-name packages filename)
  #:use-module (guix packages)
  #:use-module (...))

You can find more information about Guile modules and how to use them in the official documentation.

Step 3: Define Packages!

If you're going to the effort of setting up a Guix channel, I'm going to assume you're already at least vaguely familiar with package definitions; if not, get intimately familiar with your new best friend, the Guix programming interface. You also probably want to check out some official Guix package definitions, either via guix edit <package> or by looking through the Guix git repo (they're defined under “gnu/packages”).

One non-obvious aspect of package definition is, again, modules, namely their names. To get access to a package name, you can use guix show <package> and modify the “location” value to use as the module value by replacing slashes with spaces and dropping the “.scm”. So for the package “hello”, the location value is “gnu/packages/base.scm” and the module import would be (gnu packages base). Here's one last module example showing what using that would be like:

(define-module (your-channel-name packages filename)
  #:use-module (guix packages) ; or whatever
  #:use-module (gnu packages base))

Now you can refer to “hello” in your package definition. Some packages have different in-code names than their commandline names; you can find the exact name of a package with guix edit <package> which will open an editor at the beginning of the package definition. Just copy the value after the define-public bit and use that in your inputs.

There's a lot more gotchas and intricacies to package definition, but this should be enough to get you started. Hopefully my series on Guix will include some discussion of packaging (that could be a whole series on its own...) and I'll link to that here if and when I write it.

Conclusion

Fuck, my eyes burn.

If you want to see what this actually looks like in a git repository, you can check out my new Guix channel or the more mature (and actually useful) flatwhatson Guix channel.

Well, that's it! Go forth, newly empowered, and happy hacking!

I'm a Red Eyed Tree Frog!