diff options
author | Robert Helgesson <robert@rycee.net> | 2017-10-14 20:56:02 +0200 |
---|---|---|
committer | Robert Helgesson <robert@rycee.net> | 2018-02-07 20:50:01 +0100 |
commit | 1bc59f729047886b845ffd9162d40593fad5c7f0 (patch) | |
tree | d2c09ded840697e7b885ddaaeaadbc6f7e9ec9ae /modules | |
parent | 563a20fc82124abebd75a1fbaa6b6ead835d2553 (diff) |
allow Home Manager to be used as a NixOS module
This is a NixOS module that is intended to be imported into a NixOS
system configuration. It allows the system users to be set up directly
from the system configuration.
The actual profile switch is performed by a oneshot systemd unit per
configured user that acts much like the regular `home-manager switch`
command.
With this implementation, the NixOS module does not work properly with
the `nixos-rebuild build-vm` command. This can be solved by using the
`users.users.<name?>.packages` option to install packages but this
does not work flawlessly with certain Nixpkgs packages. In particular,
for programs using the Qt libraries.
Diffstat (limited to 'modules')
-rw-r--r-- | modules/home-environment.nix | 1 | ||||
-rw-r--r-- | modules/misc/news.nix | 46 | ||||
-rw-r--r-- | modules/modules.nix | 10 | ||||
-rw-r--r-- | modules/programs/home-manager.nix | 2 | ||||
-rw-r--r-- | modules/systemd-activate.sh (renamed from modules/systemd-activate.nix) | 44 | ||||
-rw-r--r-- | modules/systemd.nix | 26 |
6 files changed, 102 insertions, 27 deletions
diff --git a/modules/home-environment.nix b/modules/home-environment.nix index 197e9dc57f3..6c98343d792 100644 --- a/modules/home-environment.nix +++ b/modules/home-environment.nix @@ -291,6 +291,7 @@ in # script's "check" and the "write" phases. home.activation.writeBoundary = dag.entryAnywhere ""; + # Install packages to the user environment. home.activation.installPackages = dag.entryAfter ["writeBoundary"] '' $DRY_RUN_CMD nix-env -i ${cfg.path} ''; diff --git a/modules/misc/news.nix b/modules/misc/news.nix index 47efef6a146..0fffe2ea8c9 100644 --- a/modules/misc/news.nix +++ b/modules/misc/news.nix @@ -568,6 +568,52 @@ in GTK configurations. ''; } + + { + time = "2018-02-06T20:23:34+00:00"; + message = '' + It is now possible to use Home Manager as a NixOS module. + This allows you to prepare user environments from the system + configuration file, which often is more convenient than + using the 'home-manager' tool. It also opens up additional + possibilities, for example, to automatically configure user + environments in NixOS declarative containers or on systems + deployed through NixOps. + + This feature should be considered experimental for now and + some critial limitations apply. For example, it is currently + not possible to use 'nixos-rebuild build-vm' when using the + Home Manager NixOS module. That said, it should be + reasonably robust and stable for simpler use cases. + + To make Home Manager available in your NixOS system + configuration you can add + + imports = [ + "''${builtins.fetchTarball https://github.com/rycee/home-manager/archive/master.tar.gz}/nixos" + ]; + + to your 'configuration.nix' file. This will introduce a new + NixOS option called 'home-manager.users' whose type is an + attribute set mapping user names to Home Manager + configurations. + + For example, a NixOS configuration may include the lines + + users.users.eve.isNormalUser = true; + home-manager.users.eve = { + home.packages = [ pkgs.atool pkgs.httpie ]; + programs.bash.enable = true; + }; + + and after a 'nixos-rebuild switch' the user eve's + environment should include a basic Bash configuration and + the packages atool and httpie. + + More detailed documentation on the intricacies of this new + feature is slowly forthcoming. + ''; + } ]; }; } diff --git a/modules/modules.nix b/modules/modules.nix index c179c732536..7e9e6dae7e4 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -3,6 +3,9 @@ # Whether to enable module type checking. , check ? true + + # Whether these modules are inside a NixOS submodule. +, nixosSubmodule ? false }: with lib; @@ -75,10 +78,17 @@ let ]; pkgsModule = { + options.nixosSubmodule = mkOption { + type = types.bool; + internal = true; + readOnly = true; + }; + config._module.args.baseModules = modules; config._module.args.pkgs = lib.mkDefault pkgs; config._module.check = check; config.lib = import ./lib { inherit lib; }; + config.nixosSubmodule = nixosSubmodule; config.nixpkgs.system = mkDefault pkgs.system; }; diff --git a/modules/programs/home-manager.nix b/modules/programs/home-manager.nix index 306b14a2198..e9d48117da0 100644 --- a/modules/programs/home-manager.nix +++ b/modules/programs/home-manager.nix @@ -32,7 +32,7 @@ in }; }; - config = mkIf cfg.enable { + config = mkIf (cfg.enable && !config.nixosSubmodule) { home.packages = [ (import ../../home-manager { inherit pkgs; diff --git a/modules/systemd-activate.nix b/modules/systemd-activate.sh index 5e3b5773df7..1c464693cfc 100644 --- a/modules/systemd-activate.nix +++ b/modules/systemd-activate.sh @@ -1,14 +1,14 @@ -systemctlPath: -'' +#!/usr/bin/env bash + function isStartable() { local service="$1" - [[ $(${systemctlPath} --user show -p RefuseManualStart "$service") == *=no ]] + [[ $(systemctl --user show -p RefuseManualStart "$service") == *=no ]] } function isStoppable() { if [[ -v oldGenPath ]] ; then local service="$1" - [[ $(${systemctlPath} --user show -p RefuseManualStop "$service") == *=no ]] + [[ $(systemctl --user show -p RefuseManualStop "$service") == *=no ]] fi } @@ -53,19 +53,19 @@ function systemdPostReload() { --old-line-format='-%L' \ --unchanged-line-format=' %L' \ "$oldServiceFiles" "$newServiceFiles" \ - > $servicesDiffFile || true + > "$servicesDiffFile" || true - local -a maybeRestart=( $(grep '^ ' $servicesDiffFile | cut -c2-) ) - local -a maybeStop=( $(grep '^-' $servicesDiffFile | cut -c2-) ) - local -a maybeStart=( $(grep '^+' $servicesDiffFile | cut -c2-) ) + local -a maybeRestart=( $(grep '^ ' "$servicesDiffFile" | cut -c2-) ) + local -a maybeStop=( $(grep '^-' "$servicesDiffFile" | cut -c2-) ) + local -a maybeStart=( $(grep '^+' "$servicesDiffFile" | cut -c2-) ) local -a toRestart=( ) local -a toStop=( ) local -a toStart=( ) - for f in ''${maybeRestart[@]} ; do + for f in "${maybeRestart[@]}" ; do if isStoppable "$f" \ && isStartable "$f" \ - && ${systemctlPath} --quiet --user is-active "$f" \ + && systemctl --quiet --user is-active "$f" \ && ! cmp --quiet \ "$oldUserServicePath/$f" \ "$newUserServicePath/$f" ; then @@ -73,32 +73,32 @@ function systemdPostReload() { fi done - for f in ''${maybeStop[@]} ; do + for f in "${maybeStop[@]}" ; do if isStoppable "$f" ; then toStop+=("$f") fi done - for f in ''${maybeStart[@]} ; do + for f in "${maybeStart[@]}" ; do if isStartable "$f" ; then toStart+=("$f") fi done - rm -r $workDir + rm -r "$workDir" local sugg="" - if [[ -n "''${toRestart[@]}" ]] ; then - sugg="''${sugg}systemctl --user restart ''${toRestart[@]}\n" + if [[ -n "${toRestart[@]}" ]] ; then + sugg="${sugg}systemctl --user restart ${toRestart[@]}\n" fi - if [[ -n "''${toStop[@]}" ]] ; then - sugg="''${sugg}systemctl --user stop ''${toStop[@]}\n" + if [[ -n "${toStop[@]}" ]] ; then + sugg="${sugg}systemctl --user stop ${toStop[@]}\n" fi - if [[ -n "''${toStart[@]}" ]] ; then - sugg="''${sugg}systemctl --user start ''${toStart[@]}\n" + if [[ -n "${toStart[@]}" ]] ; then + sugg="${sugg}systemctl --user start ${toStart[@]}\n" fi if [[ -n "$sugg" ]] ; then @@ -107,6 +107,8 @@ function systemdPostReload() { fi } -$DRY_RUN_CMD ${systemctlPath} --user daemon-reload +oldGenPath="$1" +newGenPath="$2" + +$DRY_RUN_CMD systemctl --user daemon-reload systemdPostReload -'' diff --git a/modules/systemd.nix b/modules/systemd.nix index 3ee5ccc8ef9..9eaba7c22b1 100644 --- a/modules/systemd.nix +++ b/modules/systemd.nix @@ -145,14 +145,30 @@ in (buildServices "timer" cfg.timers) ); + # Run systemd service reload if user is logged in. If we're + # running this from the NixOS module then XDG_RUNTIME_DIR is not + # set and systemd commands will fail. We'll therefore have to + # set it ourselves in that case. home.activation.reloadSystemD = dag.entryAfter ["linkGeneration"] ( - if cfg.startServices then + let + autoReloadCmd = '' + ${pkgs.ruby}/bin/ruby ${./systemd-activate.rb} \ + "''${oldGenPath=}" "$newGenPath" "${servicesStartTimeoutMs}" + ''; + + legacyReloadCmd = '' + bash ${./systemd-activate.sh} "''${oldGenPath=}" "$newGenPath" + ''; + in '' - PATH=${dirOf cfg.systemctlPath} \ - ${pkgs.ruby}/bin/ruby ${./systemd-activate.rb} \ - "''${oldGenPath=}" "$newGenPath" "${servicesStartTimeoutMs}" + if who | grep -q '^${config.home.username} '; then + XDG_RUNTIME_DIR=''${XDG_RUNTIME_DIR:-/run/user/$(id -u)} \ + PATH=${dirOf cfg.systemctlPath}:$PATH \ + ${if cfg.startServices then autoReloadCmd else legacyReloadCmd} + else + echo "User ${config.home.username} not logged in. Skipping." + fi '' - else import ./systemd-activate.nix cfg.systemctlPath ); }) ]; |