When a unit moves from ~/.config/systemd/user (e.g. home-manager) to
/etc/systemd/user, the first pass skips it because its FragmentPath
still points at the home directory. The per-user activation
(nixos-activation.service -> home-manager) then removes the home copy
and stops the unit, leaving the now-unmasked NixOS definition inactive
until the next login.
Record such units up front and run a second pass after
nixos-activation.service: daemon-reload, then find units that were
shadowed but now aren't anymore, start/restart them as needed, and
re-start active targets so any other newly-unmasked dependencies are
pulled in.
Units that remain shadowed by ~/.config are left alone.
The opposite direction (NixOS -> home-manager) already works: the first
pass stops the removed /etc unit and home-manager starts the new home copy.
Add a lingering test user plus specialisations covering stop-start,
stopIfChanged=false, reloadIfChanged, reloadTriggers, and removal for
systemd.user.services so the new user-scope diff/restart path in
switch-to-configuration-ng is exercised.
Previously the per-user child only reexecuted the user systemd instance
and restarted nixos-activation.service, leaving NixOS-managed user units
in /etc/systemd/user running stale binaries until the next login. Options
like systemd.user.services.<name>.restartTriggers were ineffective.
The user-scope child now:
1. collects changes by comparing the pre-switch old_toplevel (captured
before activation and passed via OLD_TOPLEVEL env) against the new
toplevel
2. stops obsolete units
3. reexecutes + reloads the user systemd
4. reloads/restarts/starts changed units
5. runs nixos-activation.service (home-manager etc.)
Units are filtered by FragmentPath so those shadowed by
~/.config/systemd/user are left to home-manager to handle.
Resume-after-interrupt persistence uses $XDG_RUNTIME_DIR/nixos for the
user scope, mirroring /run/nixos for system.
Fixes#246611
Introduce a UnitScope enum that abstracts the differences between
/etc/systemd/system and /etc/systemd/user (unit directory, persisted
action-list location) and thread it through handle_modified_unit() and
collect_unit_changes(). The system path is unchanged: all callers pass
UnitScope::System and the resulting unit directory and list-file paths
are identical to the previous constants.
Preparation to reuse the diff logic for user units.
Move the inline loop that diffs active units against the new toplevel
into a free-standing collect_unit_changes(). No functional change,
preparation to reuse the same logic for user units.