dotfiles/Guix.org

16 KiB

Guix

GNU Guix is (1) a transactional package manager and (2) a GNU/Linux distribution.

My personal selling points are declarative package configuration and transactional upgrades.

References:

Profiles

A profile is way to group Guix packages. Amongst many advantages, profiles can be defined by manifests, which in turn can be stored in VCS.

References:

Activate profiles

A script to activate guix profiles. Usage:

activate-profiles [profile1] [profile2] ...

Source: David Wilson's config

GREEN='\033[1;32m'
RED='\033[1;30m'
NC='\033[0m'
GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles

profiles=$*
if [[ $# -eq 0 ]]; then
    profiles="$HOME/.config/guix/manifests/*.scm";
fi

for profile in $profiles; do
  # Remove the path and file extension, if any
  profileName=$(basename $profile)
  profileName="${profileName%.*}"
  profilePath="$GUIX_EXTRA_PROFILES/$profileName"
  manifestPath=$HOME/.config/guix/manifests/$profileName.scm

  if [ -f $manifestPath ]; then
    echo
    echo -e "${GREEN}Activating profile:" $manifestPath "${NC}"
    echo

    mkdir -p $profilePath
    guix package --manifest=$manifestPath --profile="$profilePath/$profileName"

    # Source the new profile
    GUIX_PROFILE="$profilePath/$profileName"
    if [ -f $GUIX_PROFILE/etc/profile ]; then
        . "$GUIX_PROFILE"/etc/profile
    else
        echo -e "${RED}Couldn't find profile:" $GUIX_PROFILE/etc/profile "${NC}"
    fi
  else
    echo "No profile found at path" $profilePath
  fi
done

Update profiles

A script to update Guix profiles. Usage:

update-profiles [profile1] [profile2] ...

Source: once again, David Wilson's config.

GREEN='\033[1;32m'
NC='\033[0m'
GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles

profiles=$*
if [[ $# -eq 0 ]]; then
    profiles="$GUIX_EXTRA_PROFILES/*";
fi

for profile in $profiles; do
  profileName=$(basename $profile)
  profilePath=$GUIX_EXTRA_PROFILES/$profileName

  echo
  echo -e "${GREEN}Updating profile:" $profilePath "${NC}"
  echo

  guix package --profile="$profilePath/$profileName" --manifest="$HOME/.config/guix/manifests/$profileName.scm"
done

Channels

Specifying additional channels.

References:

Nonguix channel is pinned to a particular commit to avoid recompiling Linux kernel.

(cons*
 (channel
  (name 'channel-q)
  (url "https://github.com/SqrtMinusOne/channel-q.git"))
 (channel
  (name 'flat)
  (url "https://github.com/flatwhatson/guix-channel.git")
  (introduction
   (make-channel-introduction
    "33f86a4b48205c0dc19d7c036c85393f0766f806"
    (openpgp-fingerprint
     "736A C00E 1254 378B A982  7AF6 9DBE 8265 81B6 4490"))))
 (channel
  (name 'nonguix)
  (url "https://gitlab.com/nonguix/nonguix")
  (commit "46c1d8bcca674d3a71cd077c52dde9552a89873d")
  (introduction
   (make-channel-introduction
    "897c1a470da759236cc11798f4e0a5f7d4d59fbc"
    (openpgp-fingerprint
     "2A39 3FFF 68F4 EF7A 3D29  12AF 6F51 20A0 22FB B2D5"))))
 %default-channels)

Systems

Configuring systems with Guix.

Yes, all my machines are named after colors I like.

Base configuration

The base configuration is shared between all the machines.

While it's possible to make a single .scm file with base confguration and load it, I noticed that it produces more cryptic error messages whenever there is an error in the base file, so I opt in for noweb.

guix system invocation is as follows:

sudo -E guix system reconfigure ~/.config/guix/systems/[system].scm

Common modules:

(use-modules (gnu))
(use-modules (gnu system nss))
(use-modules (gnu packages certs))
(use-modules (gnu packages version-control))
(use-modules (gnu packages vim))
(use-modules (gnu packages gnome))
(use-modules (gnu packages xorg))
(use-modules (gnu packages wm))
(use-modules (gnu packages openbox))
(use-modules (nongnu packages linux))
(use-modules (nongnu system linux-initrd))

(use-service-modules desktop networking ssh xorg)
(use-package-modules ssh)

In principle, we could define a variable called base-operating-system and extend it in ancestors. However, then we would have to define mandatory fields like host-name, bootloader with dummy values. Since I'm already using noweb, there is little point.

The following code will be inserted in the top of the operating-system definition.

Use the fulll Linux kernel. I hope I'll be able to use Libre kernel somewhere later.

(kernel linux)
(initrd microcode-initrd)
(firmware (list linux-firmware))
(locale "en_US.utf8")
(timezone "Europe/Moscow")

US/RU keyboard layout, switch with Alt+Shift.

(keyboard-layout (keyboard-layout "us,ru" #:options '("grp:alt_shift_toggle")))

User accounts.

(users (cons* (user-account
               (name "pavel")
               (comment "Pavel")
               (group "users")
               (home-directory "/home/pavel")
               (supplementary-groups
                '("wheel"  ;; sudo
                  "netdev" ;; network devices
                  "audio"
                  "video"
                  "input"
                  "tty"
                  ;; "docker"
                  "lp")))
              %base-user-accounts))

Base packages, necessary right after the installation.

(packages
 (append
  (list nss-certs
	    git
        i3-gaps
        openbox
        xterm
	    vim)
  %base-packages))

Default services for each machine. Overrides the default %desktop-services to add OpenVPN support

(define %my-desktop-services
  (modify-services %desktop-services
                   (network-manager-service-type config =>
                                                 (network-manager-configuration (inherit config)
                                                                                (vpn-plugins (list network-manager-openvpn))))))

azure

azure is a Lenovo Ideapad 330 laptop.

%backlight-udev-rule should enable member of video group change the display backlight. See the relevant page at Arch Wiki.

<<system-common>>

(define %backlight-udev-rule
  (udev-rule
   "90-backlight.rules"
   (string-append "ACTION==\"add\", SUBSYSTEM==\"backlight\", "
                  "RUN+=\"/run/current-system/profile/bin/chgrp video /sys/class/backlight/%k/brightness\""
                  "\n"
                  "ACTION==\"add\", SUBSYSTEM==\"backlight\", "
                  "RUN+=\"/run/current-system/profile/bin/chmod g+w /sys/class/backlight/%k/brightness\"")))

(operating-system
 <<system-base>>

 (host-name "azure")
 (services (append
            (list (service openssh-service-type)
                  (set-xorg-configuration
                   (xorg-configuration
                    (keyboard-layout keyboard-layout))))
            (modify-services %my-desktop-services
                             (elogind-service-type config =>
                                                   (elogind-configuration (inherit config)
                                                                          (handle-lid-switch-external-power 'suspend)))
                             (udev-service-type config =>
                                                (udev-configuration (inherit config)
                                                                    (rules (cons %backlight-udev-rule
                                                                                 (udev-configuration-rules config))))))))

 (bootloader
  (bootloader-configuration
   (bootloader grub-efi-bootloader)
   (target "/boot/efi")
   (keyboard-layout keyboard-layout)))

 (swap-devices
  (list (uuid "4b2dedb3-b111-4e69-8c05-6daa2b072c76")))

 (file-systems
  (cons* (file-system
          (mount-point "/")
          (device (file-system-label "my-root"))
          (type "ext4"))
	     (file-system
	      (mount-point "/boot/efi")
	      (device "/dev/sda1")
	      (type "vfat"))
         %base-file-systems)))

blue

A VM on which I test Guix. Will probably be deleted sooner or later.

<<system-common>>

(operating-system
  <<system-base>>
 (host-name "blue")

 (bootloader
  (bootloader-configuration
   (bootloader grub-bootloader)
   (target "/dev/sda")
   (keyboard-layout keyboard-layout)))

 (swap-devices
  (list (uuid "d9ca4f8b-4bb1-420e-9371-3558731bada1")))

 (file-systems
  (cons* (file-system
          (mount-point "/")
          (device
           (uuid "179fbd75-3c7f-4de2-8c4f-4c30939b8a3f"
                 'ext4))
          (type "ext4"))
         %base-file-systems)))

System installation

Preparation

In my cases the provided ISO doesn't work because of Libre kernel.

Fortunately, David Wilson has made a repository with a toolchain to make an ISO with the full kernel. In case it won't be an option, the nonguix repo also has instructions on how to do that.

When an ISO is there, we have to write it on a USB stick. Run sudo fdisk -l to get a list of disks.

The approach in the official instruction is to create a bootable USB with dd:

sudo dd of=/dev/sdxX if=<path-to-iso> status=progress && sync

However, I couldn't make it work for some strange reason. Fortunately, gnome-disk-utility was able to produce a bootable USB.

Installation

Going further, the official instructions for installation & SystemCrafters wiki entry are pretty good, so it's not necessary to repeat them here.

After installation

After the installation, the strategy is as follows.

Set a password for the main user (pavel). Login with openbox to get a tolerable interface, because i3 default config is horrible.

Connect to the internet.

Clone the dotfiles repo:

mkdir Code
cd Code
git clone https://github.com/SqrtMinusOne/dotfiles.git

Copy the channels file and run guix pull:

cp ~/Code/dotfiles/.config/guix/channels.scm ~/.config/guix
guix pull

The first pull usually takes a while. After that install yadm and pull dotfiles:

guix install yadm
guix clone https://github.com/SqrtMinusOne/dotfiles.git

And activate the required profiles. Again, downloading & building Emacs, Starship and stuff will take a while.

Don't forget to install JetBrainsMono Nerd Font.

Various software

Browsers

Category Guix dependency
browsers ungoogled-chromium
browsers firefox

Office

Category Guix dependency
office libreoffice
office gimp

LaTeX

Category Guix dependency
latex texlive

System

Category Guix dependency
system openvpn
system python

Manifests

(my/format-guix-dependencies category)

Browsers

(specifications->manifest
 '(
   <<packages("browsers")>>))

System

(specifications->manifest
 '(
   <<packages("system")>>))

Office

(specifications->manifest
 '(
   <<packages("office")>>))

Notes on installing software

Category Guix dependency Description
system patchelf A program to modify existsing ELF executables
system glibc A lot of stuff, including ELF interpeter and ldd

flatpak

As for now, the easiest way to install most of proprietary software is via flatpak. See the relevant section in Desktop.org .

wakatime-cli

Note Description
TODO Package this for Guix

Before I figure out how to package this for Guix:

  • Clone the repo
  • Run go build
  • Copy the binary to the ~/bin folder

ActivityWatch

Note Description
TODO Package this for Guix

The official binaries work just fine after some patching, except for the aw-qt binary.

Properly building from source is more awkward (PyInstaller? Are you serious? xD), as there are multiple packages with lots of dependencies.

The patching is as follows:

  • Get ELF interpeter patch from guix build glibc, after which patch ELF interpeter path for the required binaries, e.g.:
patchelf --set-interpreter /gnu/store/fa6wj5bxkj5ll1d7292a70knmyl7a0cr-glibc-2.31/lib/ld-linux-x86-64.so.2 aw-qt
patchelf --set-interpreter /gnu/store/fa6wj5bxkj5ll1d7292a70knmyl7a0cr-glibc-2.31/lib/ld-linux-x86-64.so.2 aw-server/aw-server
patchelf --set-interpreter /gnu/store/fa6wj5bxkj5ll1d7292a70knmyl7a0cr-glibc-2.31/lib/ld-linux-x86-64.so.2 aw-server-rust/aw-server-rust
patchelf --set-interpreter /gnu/store/fa6wj5bxkj5ll1d7292a70knmyl7a0cr-glibc-2.31/lib/ld-linux-x86-64.so.2 aw-watcher-afk/aw-watcher-afk
patchelf --set-interpreter /gnu/store/fa6wj5bxkj5ll1d7292a70knmyl7a0cr-glibc-2.31/lib/ld-linux-x86-64.so.2 aw-watcher-window/aw-watcher-window

Add libz to RPATH

Category Guix dependency
misc zlib
patchelf --set-rpath /gnu/store/rykm237xkmq7rl1p0nwass01p090p88x-zlib-1.2.11/lib/ aw-qt
patchelf --set-rpath /gnu/store/rykm237xkmq7rl1p0nwass01p090p88x-zlib-1.2.11/lib/ aw-server/aw-server
patchelf --set-rpath /gnu/store/rykm237xkmq7rl1p0nwass01p090p88x-zlib-1.2.11/lib/ aw-server-rust/aw-server-rust
patchelf --set-rpath /gnu/store/rykm237xkmq7rl1p0nwass01p090p88x-zlib-1.2.11/lib/ aw-watcher-afk/aw-watcher-afk
patchelf --set-rpath /gnu/store/rykm237xkmq7rl1p0nwass01p090p88x-zlib-1.2.11/lib/ aw-watcher-window/aw-watcher-window

As aw-qt doesn't work properly, and the only thing it does is makes a tray icon anyhow, here is a script to launch the required components:

~/Programs/activitywatch/aw-server/aw-server &
~/Programs/activitywatch/aw-watcher-afk/aw-watcher-afk &
~/Programs/activitywatch/aw-watcher-window/aw-watcher-window &