diff --git a/docs/architecture.md b/docs/architecture.md index 4a89620..54336e5 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -44,7 +44,7 @@ The script implements a sophisticated Nix installation strategy: 1. **Detection**: Checks if `/nix` directory exists 2. **First-time Setup**: If no Nix store is found: - Enables `nix-command` and `flakes` in `/etc/nix/nix.conf` - - Creates a bind mount from `$XDG_DATA_HOME/nix` to `/nix` + - Creates a bind mount from `$XDG_DATA_HOME/nix/root/nix/` to `/nix` - Installs Nix in single-user mode via the official installer 3. **Runtime Mount**: Ensures `/nix` is properly mounted on each container start 4. **Environment Sourcing**: Sources the Nix environment from `~/.nix-profile/etc/profile.d/nix.sh` @@ -53,12 +53,14 @@ The script implements a sophisticated Nix installation strategy: Nix-toolbox uses a bind mount approach for persistent storage: -- **Host Storage**: Nix store is persisted in `$XDG_DATA_HOME/nix` on the host +- **Host Storage**: Nix store is persisted in `$XDG_DATA_HOME/nix/root/nix/` on the host, matching the path used by upstream Nix's user namespace sandboxing. +Existing installs using the legacy `$XDG_DATA_HOME/nix` path are automatically detected and preserved. - **Container Mount**: Bind-mounted to `/nix` inside the container - **Benefits**: - Survives container recreation - Shares storage between multiple nix-toolbox containers - Keeps the Nix store outside the container filesystem + - Compatible with host Nix installations using user namespace sandboxing ### Home Manager Integration diff --git a/docs/host-config.md b/docs/host-config.md new file mode 100644 index 0000000..94845f5 --- /dev/null +++ b/docs/host-config.md @@ -0,0 +1,98 @@ +# Host Config Module + +When running Home Manager inside a nix-toolbox container on Fedora Atomic Desktops, config files managed by Home Manager are symlinks pointing to `/nix/store/...` paths. +The Nix store data lives on the host at `$XDG_DATA_HOME/nix/root/nix/` (or `$XDG_DATA_HOME/nix` for legacy installs), but the `/nix` bind mount only exists inside the container. +Host-side programs like sway, waybar, foot, or firefox cannot resolve these symlinks — the config files are effectively invisible to the host. + +The `hostConfig` Home Manager module solves this by materializing symlinks as real files after each `home-manager switch`. + +## How it works + +The module generates two Home Manager activation scripts: + +1. **`restoreNixLinks`** (runs before `checkLinkTargets`) — restores symlink backups (`.lnk` files) so Home Manager can replace them, and cleans up leftover `.new` temp files from any previous partial run. +2. **`createHostConfig`** (runs after `linkGeneration`) — copies each symlink to a real file using an atomic copy-before-move pattern, so a failed copy never leaves you without a config file. + +## Installation + +The module is available as a flake output from [thrix/nix-config](https://github.com/thrix/nix-config). + +Add it to your `flake.nix`: + +```nix +{ + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + + home-manager = { + url = "github:nix-community/home-manager"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + nix-config = { + url = "github:thrix/nix-config"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.home-manager.follows = "home-manager"; + }; + }; + + outputs = { nixpkgs, home-manager, nix-config, ... }: { + homeConfigurations."alice" = home-manager.lib.homeManagerConfiguration { + pkgs = nixpkgs.legacyPackages.x86_64-linux; + modules = [ + nix-config.homeManagerModules.hostConfig + ./home.nix + ]; + }; + }; +} +``` + +## Usage + +In your `home.nix`: + +```nix +hostConfig = { + enable = true; + + # Automatically materialize all xdg.desktopEntries as real files + xdgDesktopEntries = true; + + # Any other Home Manager-managed files the host needs to read + files = [ + ".config/sway/config" + ".config/waybar/config" + ".config/waybar/style.css" + ".config/foot/foot.ini" + ]; +}; +``` + +## Options + +### `hostConfig.enable` + +Whether to enable host config file materialization. + +**Type:** `boolean` +**Default:** `false` + +### `hostConfig.files` + +Home-relative paths to materialize as real files for host access. +Home Manager normally creates symlinks into the Nix store, which the host cannot follow from outside the toolbox container. +Files listed here are copied to real files after each switch. + +**Type:** `list of string` +**Default:** `[]` + +### `hostConfig.xdgDesktopEntries` + +When `true`, automatically materialize all desktop entries declared via `xdg.desktopEntries`. +Paths are derived directly from that option — adding a new entry in `xdg.desktopEntries` is sufficient, no need to list it in `files` too. + +This is useful for sharing Nix-installed desktop applications (such as 1Password, Discord, or Dropbox) with the host's application launcher. + +**Type:** `boolean` +**Default:** `false` diff --git a/nix.sh b/nix.sh index dc29135..0ac9953 100644 --- a/nix.sh +++ b/nix.sh @@ -40,8 +40,17 @@ export GUM_SPIN_SPINNER="points" export GUM_SPIN_SHOW_ERROR="yes" export GUM_SPIN_TITLE="Please wait, this might take a while" +# Determine persistent Nix root location (bind-mounted to /nix) +# New installs use upstream-compatible path: $XDG_DATA_HOME/nix/root/nix/ +# Existing installs with Nix root directly in $XDG_DATA_HOME/nix/ are preserved +if [ -d "$XDG_DATA_HOME/nix/store" ]; then + NIX_ROOT_DIR="$XDG_DATA_HOME/nix" +else + NIX_ROOT_DIR="$XDG_DATA_HOME/nix/root/nix" +fi + # Ensure /nix is bind-mounted from persistent storage -mkdir -p "$XDG_DATA_HOME/nix" +mkdir -p "$NIX_ROOT_DIR" if [ -e "/nix" ] && [ ! -d "/nix" ]; then echo "ERROR: /nix exists but is not a directory; cannot bind-mount persistent Nix store." >&2 exit 1 @@ -50,8 +59,8 @@ if [ ! -d "/nix" ]; then sudo mkdir -p /nix fi if ! mountpoint -q /nix; then - if ! sudo mount --bind "$XDG_DATA_HOME/nix" /nix; then - echo "ERROR: Failed to bind-mount $XDG_DATA_HOME/nix to /nix." >&2 + if ! sudo mount --bind "$NIX_ROOT_DIR" /nix; then + echo "ERROR: Failed to bind-mount $NIX_ROOT_DIR to /nix." >&2 exit 1 fi fi