Generate a Dynamic Home Manager Configuration

Tags:  CCE Project

Home Manager is a basic system for managing a user environment using the Nix package manager together with the Nix libraries found in nixpkgs.

readmeWikiManual

Home Manager works anywhere that Nix does and populates a ~/.nix-profile which is added to various environment PATHs to expose a bunch of Nix packaged programs to the rest of my system. I plan to slowly fork all of my Ansible automation in to this system and when the bulk of it is moved I can evaluate building fully idempotent systems with NixOS and NixOps. oh what fun! See below a cool method to generate some foot-gun shaped code!

Emacs scaffolding via CCE

This document relies on some org-roam keyword caching:

(with-eval-after-load "org-roam-keywords"
  (dolist (kw '("CCE_HOME_MODULE" "CCE_HOME_PACKAGES" "CCE_HOME_DERIVATIONS" "CCE_HOME_EPKGS"))
    (add-to-list 'org-roam-cached-keywords kw nil #'equal)))
(provide 'cce/home-manager)

CCE Modules Which Use This

Here are files which will be included by home-manager:

(->>
 (org-roam-db-query [:select [file title]
                     :from keywords
                     :join titles :using [[file]]
                     :where (= keyword "CCE_HOME_MODULE")
                     :group-by file])
 (seq-map (lambda (item) (format "- [[file:%s][%s]]\n" (file-relative-name (first item) cce-directory) (second item))))
 (apply #'concat))

Quickly Install it

With a working Nix installation run this to install home-manager:

nix-channel --add https://github.com/nix-community/home-manager/archive/master.tar.gz home-manager
nix-channel --update
nix-shell '<home-manager>' -A install

Additionally, Cachix can be used to skip compiling the Emacs GCC branch on NixOS systems. Here it's not so helpful

nix-env -iA cachix -f https://cachix.org/api/v1/install
cachix use nix-community

Generating home.nix dynamically with noweb Literate Programming

This uses my org-roam keyword caching patch and the Shared CCE Helpers to dynamically generate a home.nix. some neat and tidy ELisp is nice to see. Every page with home manager code in it will carry a CCE_HOME_MODULE keyword with the location of the .nix file for that CCE module which will be inserted in to the home.nix template.

It's complicated because I need to define home.packages only in one place and I can't figure out a better way to compose this file. This relies on some implied code standards to work: home.packages will be populated with things hidden under lib.mypkgs.FOO, a list of packages concatenated with all the other lib.mypkgs but reliant on very particular shape and naming. Inherent limitation to the craft, I guess.

I also should define program modules for a lot of these over the long term so that they're more simple to harness and my configurations can become more stable. This references a lot of code in the Shared CCE Helpers, consider reading that if you're interested in understanding this.

for now, this is going to be kind of awkward. I have a Fedora Linux that is reliant on this home.nix, but i want nodes managed with NixOps to have access to this during a bootstrap.

{ config, pkgs, lib, ... }:

with builtins;
let
  <<generate_custom_derivations()>>
  mkNixGLWrapper = pkgs.callPackage /home/rrix/org/cce/nixlib/nixgl.nix {};
in rec {
  nixpkgs.overlays = [
    (import (builtins.fetchTarball {
      url = https://github.com/nix-community/emacs-overlay/archive/master.tar.gz;
    }))
  ];

  programs.home-manager.enable = true;
  home.stateVersion = "21.05";

  # let's play with fire!
  # home.file.".config/nixpkgs/home.nix".source = ./home-manager.nix; # this file

  manual.html.enable = true;
  manual.json.enable = true;
  news.display = "silent";

  <<transclude_nix_files()>>

  <<generate_dotpackages()>>

  home.username = "rrix";
  home.homeDirectory = "/home/rrix";

  home.language.base = "en_US";
  home.language.time = "en_GB";

  programs.emacs = {
    enable = true;
    package = (pkgs.emacsWithPackagesFromUsePackage {
      package = pkgs.emacsGcc;
      config = /home/rrix/org/cce/init.el;
      alwaysEnsure = true;

      override = epkgs: epkgs // {
        <<generate_epkg_overrides()>>
      };
    });
  };
}

Regenerating on command: M-x cce/dynamic-home-manager

To apply this quickly, I have a small helper function which will make it all the way in to my CCE init file. With elisp:(cce/dynamic-home-manager), available in M-x slash execute-extended-command, which will tangle and apply the home.nix file.

(defun cce/tangle-home-manager-inputs ()
  (dolist (path (org-roam-db-query
                 [:select file
                  :from keywords
                  :where (= keyword "CCE_HOME_MODULE")
                  :or (= keyword "CCE_HOME_EPKGS")
                  :or (= keyword "CCE_HOME_DERIVATIONS")
                  :group-by file]))
    (org-babel-tangle-file (car path))))
(cce/tangle-home-manager-inputs)
(setq cce/home-manager-org-name "~/org/cce/home-manager.org")
(setq cce/home-manager-nix-name "~/org/cce/nixlib/home-manager.nix")
(defun cce/dynamic-home-manager (&optional prefix)
  (interactive "p")
  (when (eq major-mode 'org-mode)
    (org-babel-tangle-file (buffer-file-name)))
  (when (org-babel-tangle-file cce/home-manager-org-name)
    (async-shell-command (concat "home-manager switch -f "
                                 cce/home-manager-nix-name
                                 (unless (eq 1 prefix) " --show-trace"))
                         "*home-manager*")))

Literate Programming helpers

transclude_nix_files by looking at the first word in CCE_HOME_MODULE keyword on each file, and then running insert-file-contents on it, basically.

(cce/home-manager-transclude-nix-files)

generate_custom_derivations will transclude one-off derivations by referencing a file containing the derviation snippet in the CCE_HOME_DERVIATIONS keyword, and then these can be referenced in the transcluded snippets or other places since this will always be in scope. I probably want to use overlays for this, but, oh well.

(cce/home-manager-custom-derivations)

home.packages is generated with generate_dotpackages by concatenating together files referenced in CCE_HOME_PACKAGES keyword (or in the second word of CCE_HOME_MODULE keyword!). It's a little weird. Each module sets CCE_HOME_PACKAGES to a value (like, say, MY_PACKAGE) and then it sets a lib.myapp.MY_PACKAGE in its transcluded Nix files. Each of these are concatenated together in to home.packages:

(cce/home-manager-collect-packages)

Right now the only epkg override is in org-roam with my custom keyword caching, but home-manager-collect-epkg-overrides can be used to insert any overridden elisp package in to the registry for use-package to install, including things with patches or personal forks. yummy.

(cce/home-manager-collect-epkg-overrides)

Task list to port CCE_ANSIBLE to CCE_HOME_MODULE

Now This Is Podracing!

(apply #'concat
       (seq-map (lambda (row)
                  (message "%s" row)
                  (format "** NEXT port [[%s][%s]] to home-manager  :CCE:Dev:Nix:\n" (first row) (second row)))
                (org-roam-db-query [:select [file value]
                                    :from keywords
                                    :where (= keyword $s1)]
                                   "CCE_ANSIBLE")))

DONE port pass to home-manager CCE Dev Nix

  • State "DONE" from "NEXT" [2021-03-12 Fri 20:09]

DONE port applications to home-manager CCE Dev Nix

  • State "DONE" from "INPROGRESS" [2021-04-03 Sat 17:34]
  • State "INPROGRESS" from "NEXT" [2021-03-13 Sat 18:07]

DONE port gnupg to home-manager CCE Dev Nix

  • State "DONE" from "NEXT" [2021-03-20 Sat 00:39]

DONE port deadgrep to home-manager CCE Dev Nix

  • State "DONE" from "NEXT" [2021-03-20 Sat 00:42]

DONE port picom to home-manager CCE Dev Nix

  • State "DONE" from "NEXT" [2021-03-20 Sat 01:06]

DONE port git to home-manager CCE Dev Nix

  • State "DONE" from "NEXT" [2021-03-20 Sat 01:22]

DONE port axidraw to home-manager CCE Dev Nix

  • Note taken on [2021-03-21 Sun 01:19]
    axicli is basically uninstallable in NixOS lol
  • State "DONE" from "INPROGRESS" [2021-03-21 Sun 01:19]
  • State "INPROGRESS" from "NEXT" [2021-03-21 Sun 01:18]

DONE port code-base to home-manager CCE Dev Nix

  • Note taken on [2021-03-21 Sun 01:34]
    this only had git which i installed in Magit. probably could stand to include more later on.
  • State "DONE" from "NEXT" [2021-03-21 Sun 01:34]

DONE port org-roam to home-manager CCE Dev Nix

  • State "DONE" from "NEXT" [2021-03-26 Fri 00:26]

DONE port syncthing to home-manager CCE Dev Nix

  • State "DONE" from "INPROGRESS" [2021-03-26 Fri 00:56]
  • State "INPROGRESS" from "NEXT" [2021-03-21 Sun 01:27]

DONE port msmtp to home-manager CCE Dev Nix

  • State "DONE" from "NEXT" [2021-03-26 Fri 00:57]

CANCELLED port emacs-sqlite3 to home-manager CCE Dev Nix

  • State "CANCELLED" from "NEXT" [2021-03-26 Fri 00:57]

NEXT port ansible-bender to home-manager CCE Dev Nix

NEXT port shell-loader to home-manager CCE Dev Nix

NEXT port yubikeys to home-manager CCE Dev Nix

NEXT port ruby to home-manager CCE Dev Nix

NEXT port firefox-cust to home-manager CCE Dev Nix

NEXT port org-protocol to home-manager CCE Dev Nix

NEXT port vulfpeck to home-manager CCE Dev Nix

NEXT port gnus to home-manager CCE Dev Nix

NEXT port hpi-kobo to home-manager CCE Dev Nix

NEXT port code-modes to home-manager CCE Dev Nix

NEXT port weechat to home-manager CCE Dev Nix

NEXT port pam-u2f to home-manager CCE Dev Nix

NEXT port common-lisp to home-manager CCE Dev Nix

NEXT port redshift to home-manager CCE Dev Nix

NEXT port packaging to home-manager CCE Dev Nix

NEXT port obs-v4l2sink to home-manager CCE Dev Nix

NEXT port yubikey-otp to home-manager CCE Dev Nix

NEXT port python to home-manager CCE Dev Nix

NEXT port emacs-pager to home-manager CCE Dev Nix

NEXT port universal-aggregator to home-manager CCE Dev Nix

NEXT port elixir to home-manager CCE Dev Nix

NEXT port podman to home-manager CCE Dev Nix

NEXT port atreus to home-manager CCE Dev Nix

NEXT port rpmfusion to home-manager CCE Dev Nix

NEXT port kde-desktop to home-manager CCE Dev Nix

NEXT port firefox-portal to home-manager CCE Dev Nix

NEXT port sitelen-pona-pona to home-manager CCE Dev Nix

NEXT port mbsync to home-manager CCE Dev Nix

NEXT port firefox to home-manager CCE Dev Nix

NEXT port hpi to home-manager CCE Dev Nix

NEXT port nixos to home-manager CCE Dev Nix


This is Referenced

''

in "Picom on EXWM startup"

in "Nearly Stateless Computing Using Syncthing"

in "Deadgrep is a Great Grep Interface"

in "GnuPG Configuration"

in "PrintrBot Simple Metal"

in "AxiDraw"

in "AxiDraw"

in "Shared CCE Helpers"

in "Nixos Automatic Partitioning Installer"

in "Nixos Automatic Partitioning Installer"

in "NixGL"

in "NixGL"

in "The Complete Computing Environment"

in "My NixOS configuration"

in "My NixOS configuration"

in "Managing Firefox with Nix"

in "NixOps"