Linux Maxxing dot com

Guix Part 2: Desktop Setup

Correction

One of the best features of any GNU project is the Reference Manual which typically ships in the texinfo format, commonly called info pages.

Prior to using Emacs I absolutely hated info pages. The terminal info viewer is basically a stripped-down version of emacs similar to mg and does not provide a great reading experience compared to man pages.

But within Emacs info pages are fantastic, especially when you leverage Emacs features like bookmarks. So as I cracked open the Guix Info Page I found this blurb:

(2) We used to refer to Guix System as “Guix System Distribution” or “GuixSD”. We now consider it makes more sense to group everything under the “Guix” banner since, after all, Guix System is readily available through the ‘guix system’ command, even if you’re using a different distro underneath!

This must have been a recent change, I did not realize Guix System and GuixSD just became Guix. I referred to Guix (the distro) as Guix System in my last post. There are other parts of the manual that still refer to Guix System when differentiating from Guix the package manager on "foreign distros," so perhaps the change has not propagated.



Default Programs

I failed to mention this in my first post, but Guix ships with a couple nice packages. The first is mg, also known as microemacs, as mentioned above. As an Emaxxer I am mildly hampered by the fact that your default out-of-the-box editor is almost always vi. Sometimes nano is installed as well.

mg is to Emacs what vi is to vim. It is an emacs-like environment with vanilla bindings and basic features (e.g. dired) maintained by the OpenBSD team.

It reminds me a ton of the default info page reader (which is why most do not like reading info pages). However the editing experience is much closer to emacs than vi is to vim and I have zero issues using it when on a server or container and don't want the full Emacs package, or when already in a terminal and don't want to fire up Emacs. It is not surprising that Guix ships with it considering guix is basically a convoluted way of Emaxxing an entire distro.

Guix ships with the findutils package which contains the locate and updatedb commands. On other distros this is usually found in the plocate package. I prefer plocate for speed reasons, but having the same functionality out of the box is nice since it is pretty much a must-have on guix unless you are a find command wizard.

In order to use plocate on guix it appears the plocate group is required. Additionally there is an updatedb cron/herd timer service, so with that in mind I will just stick with the default findutils version rather than bloating up my system with a single extra group and package


Dollar Path

Shebangs

I have followed Dave Eddy for a while and love his bash content. One thing he is adamant about is not calling bash with #!/bin/bash and instead using #!/usr/bin/env bash. This is because the bash executable is not located in /bin in macOS and it potentially renders the script unable to call locally-installed versions of bash depending on the installation path, so #!/usr/bin/env bash should be used instead as a catch-all that will always work. I basically said "whatever bro" to this advice as I will never use macOS. However in Guix and I presume Nix there is no /bin/bash symlink. So yeah, Dave was right, make your bash shebangs #!/usr/bin/env bash.

echo $PATH

All your system executable files are ultimately symlinked to /gnu/store. By default you should have the following directories or something similar in your PATH:

  • $HOME/.config/guix/current/bin
  • $HOME/.guix-profile/bin
  • /run/setuid-programs
  • $HOME/.config/guix/current/bin
  • $HOME/.guix-profile/bin
  • /run/current-system/profile/bin
  • /run/current-system/profile/sbin

If you use guix-home, you'll have the following added to your path from the ~/.profile symlinked file:

  • $HOME/.guix-home/profile/bin
  • $HOME/.guix-home/profile/sbin

If you follow the Nix service on Guix instructions, you'll end up adding:

  • $HOME/.nix-profile/bin

On most distros users typically add ~/.local/bin to PATH via .bash_profile (or similar) and stick custom executable files in that directory. You can still do this with Guix since your $HOME directory is still fair game. You cannot create /usr/local/bin however.


Dotfiles

Previously I used ~/.profile for most environmental variables and other stuff, but ~/.profile is a symlink used by guix-home to set the HOME_ENVIRONMENT variable. If you choose not to use guix-home, this won't be an issue, but guix-home is one of the biggest selling points of guix.

Instead I use the default profile file, ~/.bash_profile, as a launching point. All environmental variables are declared in ~/.config/shell/profile, which is the same directory all my aliases file. Then all Guix and Nix sourcing happens in ~/.bash_profile. I don't use zsh because I am a GNUTard.

Here's my ~/.bash_profile which has conditionals for Guix system, Guix package manager on a foreign distro, and Nix package manager. It works on any distro. The XDG_DATA_DIRS environment variable is also modified to include .desktop files provided by both nix and flatpak:

#!/bin/sh
[ -f "$HOME/.profile" ] && . "$HOME/.profile"
[ -f "$HOME/.config/shell/profile" ] && . "$HOME/.config/shell/profile"
[ -f "$HOME/.bashrc" ] && . "$HOME/.bashrc"

####### GUIX SYSTEM
# Merge search-paths from multiple profiles. Order matters.
if [ -e /run/current-system/configuration.scm ]; then
    eval "$(guix package --search-paths \
-p $HOME/.config/guix/current \
-p $HOME/.guix-home/profile \
-p $HOME/.guix-profile \
-p /run/current-system/profile)"

    # Prepend setuid programs.
    export PATH=/run/setuid-programs:$PATH
fi

####### GUIX PACKAGE MANAGER
GUIX_PROFILE="$HOME/.guix-profile"
if [ -f "$GUIX_PROFILE/etc/profile" ]; then
    . "$GUIX_PROFILE/etc/profile"
    unset GUIX_PROFILE
fi

GUIX_PROFILE="$HOME/.config/guix/current"
if [ -f "$GUIX_PROFILE/etc/profile" ]; then
    . "$GUIX_PROFILE/etc/profile"
    unset GUIX_PROFILE
fi

####### GUIX HOME
[ -f "$HOME/.guix-home/setup-environment" ] && . "$HOME/.guix-home/setup-environment"

####### NIX PACKAGE MANAGER
[ -d "$HOME/.nix-profile/bin" ] && export PATH="$HOME/.nix-profile/bin:$PATH"
[ -d "/nix/var/nix/profiles/default/bin" ] && export PATH="/nix/var/nix/profiles/default/bin:$PATH"

[ -e "$HOME/.nix-profile/etc/profile.d/nix.sh" ] &&
    . "$HOME/.nix-profile/etc/profile.d/nix.sh"

[ -e "/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh" ] &&
    . "/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh"

####### Nix desktop files
[ -d "$HOME/.nix-profile/share" ] && \
    export XDG_DATA_DIRS="$HOME/.nix-profile/share${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}"

####### flatpak desktop files
[ -d "$HOME/.local/share/flatpak/exports/share" ] && \
    export XDG_DATA_DIRS="$HOME/.local/share:$HOME/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}"

####### Reset ~/.local/bin on guix
export PATH="$HOME/.local/bin:$PATH"

Guix Home for Managing Dotfiles

I do not plan to declaratively define my dotfiles using guix-home using home-files-service-type, it just doesn't make sense since I use them on other linux distros. I will continue to use GNU Stow as I like the flexibility it provides. I keep all personal git repos in one root directory and symlink files out as needed.

In fact I actually have 2 dotfiles repos: one minimal containing just the things needed for a headless environment, and another containing just the desktop related stuff. That way I can keep the files lean on servers/containers and bloated on desktops. Plus a scripts repo which I symlink to ~/.local/bin. This is an easy task to accomplish with GNU Stow since it is just a symlink manager, but would not be possible using the git bare repo method for managing dotfiles. Continuing to use GNU Stow also seems right in-line with the Emacs/Guix/GNUTard pipeline.

However, guix also has home-dotfiles-service-type which effectively functions as a hybrid between GNU Stow and home-files-service-type. You declare your dotfiles repos in your guix home config, and guix home will create symlinks to a created copy in /gnu/store. This is a best of both world's approach. It gives you the stability and roll-back features of home-files-service-type and the flexibility of an independent dotfiles repo. It also prevents you from having to run something like stow -R -t $HOME --no-folding . every time you add a file to your dotfiles repo, but it does require re-configuring guix home for every edit. For now I'm holding off on using this as your dotfiles become managed in the gnu store, which means on-the-fly edits are not possible without running guix home reconfigure afterward.


Desktop Mods

Surprising to me, though I suppose not surprising when you consider GNU's history, Guix defaults to Gnome and retains Gnome tools by default. The default login manager is gdm, though they support a somewhat limited number of other login managers. Having tried a number of them, I would just stick to the default gdm. It Just WerksTM on Guix. LXDM and ly are my favorite, but those are not included in the Guix repos.

Gnome Keyring, ssh/gpg-agent Woes:

Without getting in the configuration weeds, all alternatives to gdm (lightdm, tty+startx, etc) required typing your keyring password in after every login out of the box. Since your gpg and ssh keys are also stored in your keyring, you'll need to enter those passwords as well depending on your setup. In my case emacs sources ~/.authinfo.gpg immediately on startup, and I launch emacs automatically on login This results in a race condition where I needed to enter my keyring password before emacs could read ~/.authinfo.gpg, else I had to additionally type in my gpg passphrase.

Additionally your ssh-agent will be affected by how you log in. When using the default gcr (gnome) gpg agent, logging in from gdm works fine. Launching X from the tty resulted in dbus-related errors so that ssh refused using gcr as an ssh-agent. I managed to get gpg-agent to work as an ssh agent, but that involved adding a couple of lines to my ~/.xinitrc to export the GPG_TTY environmental variable among other things. The keyring unlock race condition still existed when launching X from tty.

I had all kinds of bugs using slim which is otherwise a good but underused login manager. When logging out of any DE or WM, slim would pop up from within the DE/WM and lock up.

If you are really particular about your login manager, Guix is probably not the system for you unless you're ready to create your own packages and services. This isn't so much a guix problem, more of a dubs/keyring/secret-service problem that nobody enjoys troubleshooting. This is also why it is a not-uncommon practice to have password-less gpg and ssh keys, something I will not do because schizo.

I could go down the path of troubleshooting all this stuff and trying to get a perfect solution, but it's something I really don't care much about. If I can get a consistently working solution with all little mucking as possible, I'm going to take that every time.

I haven't even addressed the fact that some programs also have hard-coded requirements for gnome-keyring even though pass and keepassxc can both function as secret-service alternatives.

Window Managers

Openbox worked fine out of the box, though I haven't touched my openbox config in years. There is not a menu-generation package in Guix/Nix which is expected as most of those are no longer maintained, so you'll just have to edit the xml directly.

Before using dwm I used spectrwm (formerly called scrotwm). It is a very nice dwm-clone which uses a plain-text config file. Think of it as dwm with sane defaults, a few useful patches, and an extremely minimal bar that is just a shell script.

This spectrwm package manager is included in guix, however I could not get it to launch from gdm. It ends up logging out to a locked gdm screen that won't accept password input. Side note: I had similar errors with gdm when using an ~/.xsession file. I have yet to troubleshoot this spectrwm launching issue, though I found a reddit dot com post from 4 years describing the same behavior.

Suckless Software

In guix you cannot just git clone <repo> && cd <repo> && sudo make clean install like you'll see in tutorials. For starters you generally never have a need to blanket make install as root, your makefile should be set to a local directory (~/.local) unless a root directory is explicitly needed.

In guix the ideal solution is to package your own builds of suckless software (or anything else you'd otherwise compile). I'll go down this route eventually, but in the short-term I just needed something to build to the suckless starter-pack: dmenu, dwm, slstatus, and st.

I ended up just cloning my repos as normal, changing to the repo directory, and then launching guix shell with the required compilation dependencies. Then I ran make and make install with a environmental variables to get gcc and function properly and to install to ~/.local/bin. Ideally you create a manifest.scm file for repeatable guix shell environments, but in my case I just wrote a shell script which I could use on each of the 4 suckless packages I use:

#!/bin/sh
set -e

cd "$(dirname "$0")"

guix shell \
     gcc-toolchain pkg-config make \
     libx11 libxft libxinerama fontconfig freetype \
     -- make \
     CC=gcc \
     X11INC=$(guix build libx11)/include \
     X11LIB=$(guix build libx11)/lib \
     FREETYPEINC=$(guix build freetype)/include/freetype2

guix shell \
     gcc-toolchain pkg-config make libx11 libxft libxinerama fontconfig freetype \
     -- make \
     CC=gcc \
     X11INC=$(guix build libx11)/include \
     X11LIB=$(guix build libx11)/lib \
     FREETYPEINC=$(guix build freetype)/include/freetype2 \
     PREFIX=~/.local \
     install clean

Not strictly necessary, but I just lumped in every dependency I needed for all 4 programs in one shell. Those dependencies will depend on which features are patched in your builds.

Launching X from tty

Getting startx/xinit to work took some tinkering. Startx my not directly run from the tty (from what I can tell, see mailing list thread from 2018).

HOWEVER guix has a "package" which actually originates from the AUR called xinitrc-xsession. This build script creates a symbolically-linked xinitrc.desktop file which launches whatever is in your ~/.xinitrc. This desktop file can then be read by your login manager so you have an easy way to effectively run startx ~/.xinitrc from gdm. With this you retain all the benefits/conveniences of your login manager without the PATH/environment issues that can arise from something like lightdm which can prevent execution of stuff called out in ~/.xinitrc.

There are ways you can set this up from config.scm, but you might as well hit the easy-button and use a provided solution.

In time I would like to have my own dwm package to set up both the executable and .desktop file, which I figure will be an easy intro to guix packaging. For now this will suffice, I can launch dwm without issue from gdm and all muh keys TM unlock at login.


What Comes Next?

My laptop is functionally riced out exactly as I have it in Artix, Devuan, and in the future Alpine and perhaps even Gentoo via ansible. I won't come to any conclusions regarding continuing to use Guix for the long-term until I've given it at least 6 months. So far it is very promising, and after configuration Guix to no surprise runs like any other GNU/Linux distro if you can accept the few defaults I've mentioned here.

At first I was a bit bothered by not being able to edit files in /etc, /usr/local/bin, or /usr/share, but I'm not sure that will be a long-term concern.

I will continue to read the Guix reference manual over the coming days and after that will probably shift gears to properly learning Guile scheme. Fortunately knowing emacs-lisp goes a long way in Guix.

I probably won't bother trying to get off gdm, I've done enough dbus/secret-service troubleshooting to know that the juice is usually not worth the squeeze, and is only a distraction from learning more useful things like guix packaging. In addition to that I'd also like to explore guix containers, guix deployment, running or replacing podman, and other features that might make me want to migrate some of my servers to guix.

#gnu #guix #linux