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/016455bfebeb85baa5c8639e9b611b96c077dcac.tar.gz;
    }))
  ];

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

  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()>>

  home.packages = with pkgs.lib; flatten(
    mapAttrsToList
      (name: value: value)
      lib.mypkgs
  );

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

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

  home.file.".emacs.d/init.el".source = /home/rrix/org/cce/init.el;

  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)

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 "Nixos Automatic Partitioning Installer"

in "Nixos Automatic Partitioning Installer"

in "NixGL"

in "NixGL"

in "Managing Firefox with Nix home-manager"

in "The Complete Computing Environment"

in "AxiDraw"

in "AxiDraw"

in "org-roam"

in "Creating Activation Scripts for Home Manager"

in "Shared CCE Helpers"

in "My NixOS configuration"

in "NixOps"