69 lines
2.8 KiB
Nix
69 lines
2.8 KiB
Nix
# modules/home-manager-bootstrap.nix
|
|
#
|
|
# Pre-create the directory tree that the home-manager activation
|
|
# script expects to exist on a fresh first boot. Without these
|
|
# rules, `home-manager-user.service` crashes in (at least) three
|
|
# different places — each one only visible after fixing the
|
|
# previous — making first-boot of any clean install fail with a
|
|
# misleading error.
|
|
#
|
|
# This module is imported by both:
|
|
# - lib/mksystem.nix (for normal hosts), and
|
|
# - iso.nix (for the live ISO),
|
|
# so the bootstrap is consistent across both code paths. It is
|
|
# intentionally a separate module rather than inlined in mksystem
|
|
# so the ISO — which bypasses mksystem — does not silently miss
|
|
# the fix.
|
|
#
|
|
# Reads `config.omni.user`, which is the canonical "main user"
|
|
# option set by modules/core.nix. Does nothing if that option is
|
|
# unset (e.g. during a flake check that does not set up users).
|
|
#
|
|
# The bugs this fixes:
|
|
#
|
|
# 1. The "find a profile dir" check in
|
|
# home-manager-generation/activate (around line 90 of the
|
|
# generated script) needs $HOME/.local/state/nix/profiles
|
|
# OR /nix/var/nix/profiles/per-user/$USER to exist. The
|
|
# nix-daemon only creates the per-user dir lazily on the
|
|
# user's first nix command, so on a fresh boot neither path
|
|
# exists. Symptom: "Could not find suitable profile
|
|
# directory" → service fails.
|
|
#
|
|
# 2. After (1) is fixed, `nix-store --realise ... --add-root
|
|
# $HOME/.local/state/home-manager/gcroots/new-home` fails
|
|
# because the activate script declares `hmGcrootsDir` but
|
|
# never `mkdir -p`s it. nix-store will not create parent
|
|
# dirs for --add-root. Symptom: silent exit, status 1, no
|
|
# error in journal.
|
|
#
|
|
# 3. After (2) is fixed, `linkGeneration` fails with
|
|
# "Permission denied" creating `~/.local/share/dev-env/...`.
|
|
# modules/lib.nix declares `d /home/$USER/.local/share/
|
|
# omni ...` and systemd-tmpfiles auto-creates the missing
|
|
# intermediate `.local/share` parent as root:root, which
|
|
# then blocks the user-running activation. Pinning the
|
|
# `.local/share` parent here keeps it user-owned regardless
|
|
# of declaration order.
|
|
#
|
|
# tmpfiles `d` rules do not recursively create parents, so each
|
|
# level of the tree is spelled out explicitly.
|
|
|
|
{ config, lib, ... }:
|
|
|
|
let
|
|
user = config.omni.user or null;
|
|
in
|
|
{
|
|
config = lib.mkIf (user != null) {
|
|
systemd.tmpfiles.rules = [
|
|
"d /nix/var/nix/profiles/per-user/${user} 0755 ${user} users -"
|
|
"d /nix/var/nix/gcroots/per-user/${user} 0755 ${user} users -"
|
|
"d /home/${user}/.local 0755 ${user} users -"
|
|
"d /home/${user}/.local/share 0755 ${user} users -"
|
|
"d /home/${user}/.local/state 0755 ${user} users -"
|
|
"d /home/${user}/.local/state/home-manager 0755 ${user} users -"
|
|
"d /home/${user}/.local/state/home-manager/gcroots 0755 ${user} users -"
|
|
];
|
|
};
|
|
}
|