From 948ae3f80fddf8278ed6174afb46af064970ff61 Mon Sep 17 00:00:00 2001 From: Jack O'Sullivan Date: Tue, 15 Feb 2022 20:50:27 +0000 Subject: [PATCH] Add capability to choose home-manager branch --- flake.lock | 46 +++++++++-- flake.nix | 48 +++++++---- home-modules/common.nix | 174 +++++++++++++++++++++------------------ homes.nix | 33 ++++++-- modules/build.nix | 2 + modules/common.nix | 31 ++++--- modules/dynamic-motd.nix | 2 + modules/firewall.nix | 2 + modules/server.nix | 2 + modules/tmproot.nix | 2 + systems.nix | 87 ++++++++++++++++---- util.nix | 7 +- 12 files changed, 305 insertions(+), 131 deletions(-) diff --git a/flake.lock b/flake.lock index 676dd88..49e6bc1 100644 --- a/flake.lock +++ b/flake.lock @@ -109,7 +109,27 @@ "type": "github" } }, - "home-manager": { + "home-manager-stable": { + "inputs": { + "nixpkgs": [ + "nixpkgs-stable" + ] + }, + "locked": { + "lastModified": 1643933536, + "narHash": "sha256-yRmsWAG4DnLxLIUtlaZsl0kH7rN5xSoyNRlf0YZrcH4=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "2860d7e3bb350f18f7477858f3513f9798896831", + "type": "github" + }, + "original": { + "id": "home-manager", + "ref": "release-21.11", + "type": "indirect" + } + }, + "home-manager-unstable": { "inputs": { "nixpkgs": [ "nixpkgs-unstable" @@ -195,6 +215,20 @@ "type": "indirect" } }, + "nixpkgs-master": { + "locked": { + "lastModified": 1644486793, + "narHash": "sha256-EeijR4guVHgVv+JpOX3cQO+1XdrkJfGmiJ9XVsVU530=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "1882c6b7368fd284ad01b0a5b5601ef136321292", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "type": "indirect" + } + }, "nixpkgs-regression": { "locked": { "lastModified": 1643052045, @@ -227,11 +261,11 @@ }, "nixpkgs-unstable": { "locked": { - "lastModified": 1644420267, - "narHash": "sha256-rFJuctggkjM412OC6OGPdXogFp7czGDW05ueWqpJbj8=", + "lastModified": 1644525281, + "narHash": "sha256-D3VuWLdnLmAXIkooWAtbTGSQI9Fc1lkvAr94wTxhnTU=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "98bb5b77c8c6666824a4c13d23befa1e07210ef1", + "rev": "48d63e924a2666baf37f4f14a18f19347fbd54a2", "type": "github" }, "original": { @@ -246,9 +280,11 @@ "deploy-rs": "deploy-rs", "devshell": "devshell", "flake-utils": "flake-utils_2", - "home-manager": "home-manager", + "home-manager-stable": "home-manager-stable", + "home-manager-unstable": "home-manager-unstable", "impermanence": "impermanence", "nix": "nix", + "nixpkgs-master": "nixpkgs-master", "nixpkgs-stable": "nixpkgs-stable", "nixpkgs-unstable": "nixpkgs-unstable" } diff --git a/flake.nix b/flake.nix index 9998149..72027b6 100644 --- a/flake.nix +++ b/flake.nix @@ -5,18 +5,20 @@ flake-utils.url = "github:numtide/flake-utils"; devshell.url = "github:numtide/devshell"; devshell.inputs.nixpkgs.follows = "nixpkgs-unstable"; - # Used by most systems + + nixpkgs-master.url = "nixpkgs"; nixpkgs-unstable.url = "nixpkgs/nixos-unstable"; - # For extra-stable systems nixpkgs-stable.url = "nixpkgs/nixos-21.11"; + home-manager-unstable.url = "home-manager"; + home-manager-unstable.inputs.nixpkgs.follows = "nixpkgs-unstable"; + home-manager-stable.url = "home-manager/release-21.11"; + home-manager-stable.inputs.nixpkgs.follows = "nixpkgs-stable"; # Stuff used by the flake for build / deployment agenix.url = "github:ryantm/agenix"; agenix.inputs.nixpkgs.follows = "nixpkgs-unstable"; deploy-rs.url = "github:serokell/deploy-rs"; deploy-rs.inputs.nixpkgs.follows = "nixpkgs-unstable"; - home-manager.url = "home-manager"; - home-manager.inputs.nixpkgs.follows = "nixpkgs-unstable"; # Stuff used by systems nix.url = "nix/latest-release"; @@ -30,7 +32,8 @@ flake-utils, - nixpkgs-unstable, nixpkgs-stable, + nixpkgs-master, nixpkgs-unstable, nixpkgs-stable, + home-manager-unstable, home-manager-stable, ... }: @@ -39,37 +42,49 @@ inherit (lib.flake) eachDefaultSystem; inherit (lib.my) attrsToList mkApp mkShellApp mkShellApp' inlineModules mkDefaultSystemsPkgs flakePackageOverlay; - extendLib = lib: lib.extend (final: prev: { + # Extend a lib with extras that _must not_ internally reference private nixpkgs. flake-utils doesn't, but many + # other flakes (e.g. home-manager) probably do internally. + libOverlay = final: prev: { my = import ./util.nix { lib = final; }; flake = flake-utils.lib; - }); - libOverlay = final: prev: { lib = extendLib prev.lib; }; + }; + pkgsLibOverlay = final: prev: { lib = prev.lib.extend libOverlay; }; - pkgsFlakes = mapAttrs (_: pkgs: pkgs // { lib = extendLib pkgs.lib; }) { + # Override the flake-level lib since we're going to use it for non-config specific stuff + pkgsFlakes = mapAttrs (_: pkgsFlake: pkgsFlake // { lib = pkgsFlake.lib.extend libOverlay; }) { + master = nixpkgs-master; unstable = nixpkgs-unstable; stable = nixpkgs-stable; }; + hmFlakes = { + unstable = home-manager-unstable; + stable = home-manager-stable; + }; + # Should only be used for platform-independent flake stuff! This should never leak into a NixOS or home-manager + # config - they'll get their own. lib = pkgsFlakes.unstable.lib; + # pkgs for dev shell etc pkgs' = mapAttrs (_: path: mkDefaultSystemsPkgs path (system: { overlays = [ - libOverlay + pkgsLibOverlay inputs.devshell.overlay inputs.agenix.overlay inputs.deploy-rs.overlay + # TODO: This causes a compile from source which is pretty unnecessary inputs.nix.overlay - (flakePackageOverlay inputs.home-manager system) + (flakePackageOverlay inputs.home-manager-unstable system) ]; })) pkgsFlakes; # Easiest to build the basic pkgs here (with our lib overlay too) - homePkgs' = mapAttrs + configPkgs' = mapAttrs (_: path: mkDefaultSystemsPkgs path (_: { overlays = [ - libOverlay + pkgsLibOverlay ]; })) pkgsFlakes; @@ -96,7 +111,8 @@ homeModules = inlineModules homeModules; nixosConfigurations = import ./systems.nix { - inherit lib pkgsFlakes inputs; + inherit lib pkgsFlakes hmFlakes inputs; + pkgs' = configPkgs'; modules = attrValues modules; homeModules = attrValues homeModules; }; @@ -104,8 +120,8 @@ vms = mapAttrs (_: system: system.config.my.build.devVM) self.nixosConfigurations; homeConfigurations = import ./homes.nix { - inherit lib inputs; - pkgs' = homePkgs'; + inherit lib hmFlakes inputs; + pkgs' = configPkgs'; modules = attrValues homeModules; }; homes = mapAttrs(_: home: home.activationPackage) self.homeConfigurations; diff --git a/home-modules/common.nix b/home-modules/common.nix index 6b4d19a..b818f7d 100644 --- a/home-modules/common.nix +++ b/home-modules/common.nix @@ -1,91 +1,109 @@ -{ lib, pkgs, inputs, isStandalone, config, ... }: +{ lib, pkgs, pkgs', inputs, config, ... }@args: let - inherit (lib) mkMerge mkIf mkDefault mkForce; + inherit (lib) optionalAttrs versionAtLeast mkMerge mkIf mkDefault mkOption; + inherit (lib.my) mkOpt' dummyOption; in -mkMerge [ - { - nix.registry = { - pkgs = { - to = { - type = "path"; - path = toString pkgs.path; +{ + options = with lib.types; { + my = { + isStandalone = mkOption { + type = bool; + internal = true; + description = "Whether home-manager is running inside a NixOS system or not."; + }; + }; + + # Only present in >=22.05, so forward declare + nix.registry = dummyOption; + }; + config = mkMerge [ + (mkIf (versionAtLeast config.home.stateVersion "22.05") { + nix.registry = { + pkgs = { + to = { + type = "path"; + path = toString pkgs.path; + }; + exact = true; }; - exact = true; }; - }; + }) + { + my.isStandalone = !(args ? sysConfig); - programs = { - # Even when enabled this will only be actually installed in standalone mode - # Note: `home-manager.path` is for telling home-manager is installed and setting it in NIX_PATH, which we should - # never care about. - home-manager.enable = true; + programs = { + # Even when enabled this will only be actually installed in standalone mode + # Note: `home-manager.path` is for telling home-manager is installed and setting it in NIX_PATH, which we should + # never care about. + home-manager.enable = true; - bash = { - # This not only installs bash but has home-manager control .bashrc and friends - enable = mkDefault true; + bash = { + # This not only installs bash but has home-manager control .bashrc and friends + enable = mkDefault true; + }; + + direnv = { + enable = mkDefault true; + nix-direnv.enable = true; + stdlib = + '' + # addition to nix-direnv's use_nix that registers outputs as gc roots (as well as the .drv) + use_nix_outputs() { + local layout_dir drv deps + layout_dir="$(direnv_layout_dir)" + drv="$layout_dir/drv" + deps="$layout_dir/deps" + + if [ ! -e "$deps" ] || (( "$(stat --format=%Z "$drv")" > "$(stat --format=%Z "$deps")" )); then + rm -rf "$deps" + mkdir -p "$deps" + nix-store --indirect --add-root "$deps/out" --realise $(nix-store --query --references "$drv") > /dev/null + log_status renewed outputs gc roots + fi + } + ''; + }; + + htop = { + enable = true; + settings = {}; + }; }; - direnv = { - enable = mkDefault true; - nix-direnv.enable = true; - stdlib = - '' - # addition to nix-direnv's use_nix that registers outputs as gc roots (as well as the .drv) - use_nix_outputs() { - local layout_dir drv deps - layout_dir="$(direnv_layout_dir)" - drv="$layout_dir/drv" - deps="$layout_dir/deps" + home = { + packages = with pkgs; [ + tree + iperf3 + ]; - if [ ! -e "$deps" ] || (( "$(stat --format=%Z "$drv")" > "$(stat --format=%Z "$deps")" )); then - rm -rf "$deps" - mkdir -p "$deps" - nix-store --indirect --add-root "$deps/out" --realise $(nix-store --query --references "$drv") > /dev/null - log_status renewed outputs gc roots - fi - } - ''; + sessionVariables = { + EDITOR = "vim"; + }; + + language.base = mkDefault "en_IE.UTF-8"; }; - - htop = { - enable = true; - settings = {}; + } + (mkIf (config.my.isStandalone || !args.sysConfig.home-manager.useGlobalPkgs) { + # Note: If globalPkgs mode is on, then these will be overridden by the NixOS equivalents of these options + nixpkgs = { + overlays = [ + inputs.nix.overlay + # TODO: Wait for https://github.com/NixOS/nixpkgs/pull/159074 to arrive to nixos-unstable + (final: prev: { remarshal = pkgs'.master.remarshal; }) + ]; + config = { + allowUnfree = true; + }; }; - }; + }) + (mkIf config.my.isStandalone { + fonts.fontconfig.enable = true; - home = { - packages = with pkgs; [ - tree - iperf3 - ]; - - sessionVariables = { - EDITOR = "vim"; + home = { + packages = with pkgs; [ + nix + ]; }; - - language.base = mkDefault "en_IE.UTF-8"; - - # The flake passes a default setting, but we don't care about that - stateVersion = mkForce "22.05"; - }; - } - (mkIf isStandalone { - # Note: this only applies outside NixOS where home-manager imports nixpkgs internally - nixpkgs = { - overlays = [ - inputs.nix.overlay - ]; - config = { - allowUnfree = true; - }; - }; - - fonts.fontconfig.enable = true; - - home = { - packages = with pkgs; [ - nix - ]; - }; - }) -] + }) + ]; +} diff --git a/homes.nix b/homes.nix index 7dda0f0..4820405 100644 --- a/homes.nix +++ b/homes.nix @@ -1,23 +1,42 @@ -{ lib, inputs, pkgs', modules }: +{ lib, hmFlakes, inputs, pkgs', modules }: let inherit (builtins) removeAttrs mapAttrs; - inherit (lib) recursiveUpdate; + inherit (lib) flatten optional recursiveUpdate; + inherit (lib.my) homeStateVersion; mkHome = name: { system, nixpkgs ? "unstable", + home-manager ? nixpkgs, config, ... }@args: let - rest = removeAttrs args [ "nixpkgs" "config" ]; + rest = removeAttrs args [ "nixpkgs" "home-manager" "config" ]; in - inputs.home-manager.lib.homeManagerConfiguration (recursiveUpdate rest { + # homeManagerConfiguration doesn't allow us to set lib directly (inherits from passed pkgs) + hmFlakes.${home-manager}.lib.homeManagerConfiguration (recursiveUpdate rest { configuration = config; + # Passing pkgs here doesn't set the global pkgs, just where it'll be imported from (and where the global lib is + # derived from). We want home-manager to import pkgs itself so it'll apply config and overlays modularly. Any config + # and overlays previously applied will be passed on by `homeManagerConfiguration` though. pkgs = pkgs'.${nixpkgs}.${system}; - extraModules = modules ++ [{ - _module.args = { inherit inputs; isStandalone = true; }; - }]; + extraModules = modules ++ [ + { + warnings = flatten [ + (optional (nixpkgs != home-manager) + '' + Using nixpkgs ${nixpkgs} with home-manager ${home-manager} may cause issues. + '') + ]; + + _module.args = { + inherit inputs; + pkgs' = mapAttrs (_: p: p.${system}) pkgs'; + }; + } + (homeStateVersion home-manager) + ]; }); in mapAttrs mkHome { diff --git a/modules/build.nix b/modules/build.nix index e6c096f..6515100 100644 --- a/modules/build.nix +++ b/modules/build.nix @@ -44,4 +44,6 @@ in devVM = recursiveUpdate config.my.asDevVM.system.build.vm { meta.mainProgram = "run-${config.system.name}-vm"; }; }; }; + + meta.buildDocsInSandbox = false; } diff --git a/modules/common.nix b/modules/common.nix index 5eeb1a3..d43c75b 100644 --- a/modules/common.nix +++ b/modules/common.nix @@ -1,14 +1,19 @@ -{ lib, pkgs, inputs, homeModules, config, options, ... }: +{ lib, pkgs, inputs, options, config, ... }: let inherit (builtins) attrValues; inherit (lib) mkIf mkDefault mkAliasDefinitions; - inherit (lib.my) mkOpt'; + inherit (lib.my) mkOpt' dummyOption; in { - options.my = with lib.types; { - # Pretty hacky but too lazy to figure out if there's a better way to alias the options - user = mkOpt' (attrsOf anything) { } "User definition (as `users.users.*`)."; - homeConfig = mkOpt' anything {} "Home configuration (as `home-manager.users.*`)"; + options = with lib.types; { + my = { + # Pretty hacky but too lazy to figure out if there's a better way to alias the options + user = mkOpt' (attrsOf anything) { } "User definition (as `users.users.*`)."; + homeConfig = mkOpt' anything { } "Home configuration (as `home-manager.users.*`)"; + }; + + # Only present in >=22.05, so forward declare + documentation.nixos.options.warningsAreErrors = dummyOption; }; config = @@ -28,11 +33,8 @@ in }; home-manager = { - useGlobalPkgs = mkDefault true; + # Installs packages in the system config instead of in the local profile on activation useUserPackages = mkDefault true; - sharedModules = homeModules ++ [{ - _module.args = { inherit inputs; isStandalone = false; }; - }]; }; users = { @@ -67,6 +69,13 @@ in }; }; + documentation = { + nixos = { + enable = mkDefault true; + options.warningsAreErrors = mkDefault false; + }; + }; + time.timeZone = mkDefault "Europe/Dublin"; boot = { @@ -106,4 +115,6 @@ in configurationRevision = with inputs; mkIf (self ? rev) self.rev; }; }; + + meta.buildDocsInSandbox = false; } diff --git a/modules/dynamic-motd.nix b/modules/dynamic-motd.nix index 0de741e..04ed188 100644 --- a/modules/dynamic-motd.nix +++ b/modules/dynamic-motd.nix @@ -22,4 +22,6 @@ in ''; }); }; + + meta.buildDocsInSandbox = false; } diff --git a/modules/firewall.nix b/modules/firewall.nix index 9ab3e65..57b5ba8 100644 --- a/modules/firewall.nix +++ b/modules/firewall.nix @@ -164,4 +164,6 @@ in ''; }) ]); + + meta.buildDocsInSandbox = false; } diff --git a/modules/server.nix b/modules/server.nix index 3d489d7..24c8996 100644 --- a/modules/server.nix +++ b/modules/server.nix @@ -10,4 +10,6 @@ in config = mkIf cfg.enable { services.getty.autologinUser = config.my.user.name; }; + + meta.buildDocsInSandbox = false; } diff --git a/modules/tmproot.nix b/modules/tmproot.nix index a875132..acd1240 100644 --- a/modules/tmproot.nix +++ b/modules/tmproot.nix @@ -210,4 +210,6 @@ in }) ])) ]); + + meta.buildDocsInSandbox = false; } diff --git a/systems.nix b/systems.nix index 4dfc303..e92af59 100644 --- a/systems.nix +++ b/systems.nix @@ -1,18 +1,24 @@ -{ lib, pkgsFlakes, inputs, modules, homeModules }: +{ lib, pkgsFlakes, hmFlakes, inputs, pkgs', modules, homeModules }: let inherit (builtins) attrValues mapAttrs; - inherit (lib) optionals mkDefault; + inherit (lib) flatten optional optionals mkDefault mkForce; + inherit (lib.my) homeStateVersion; mkSystem = name: { system, + nixpkgs ? "unstable", + home-manager ? nixpkgs, + hmNixpkgs ? home-manager, + config, + # This causes a (very slow) docs rebuild on every change to a module's options it seems docCustom ? true, }: let + # The flake contains `nixosSystem`, so we do need it (if we didn't have the TODO hacked version anyway) pkgsFlake = pkgsFlakes.${nixpkgs}; - lib = pkgsFlake.lib; # TODO: This is mostly yoinked from nixpkgs/flake.nix master (as of 2022/02/11) since 21.11's version has hacky # vm build stuff that breaks our impl. REMOVE WHEN 22.05 IS OUT! nixosSystem' = args: @@ -23,22 +29,73 @@ let system.nixos.revision = pkgsFlake.rev; }]; }); - in - nixosSystem' { - inherit lib system; - baseModules = - (import "${pkgsFlake}/nixos/modules/module-list.nix") ++ [ + + modules' = [ # Importing modules from module args causes infinite recursion inputs.impermanence.nixosModule + hmFlake.nixosModule inputs.agenix.nixosModules.age - inputs.home-manager.nixosModule - ] ++ (optionals docCustom modules); - modules = (optionals (!docCustom) modules) ++ [ - { - _module.args = { inherit system inputs homeModules; }; + ] ++ modules; + pkgs = pkgs'.${nixpkgs}.${system}; + allPkgs = mapAttrs (_: p: p.${system}) pkgs'; + + hmFlake = hmFlakes.${home-manager}; + in + nixosSystem' { + # Gotta override lib here unforunately, eval-config.nix likes to import its own (unextended) lib. We explicitly + # don't pass pkgs so that it'll be imported with modularly applied config and overlays. + lib = pkgs.lib; + # `baseModules` informs the manual which modules to document + baseModules = + (import "${pkgsFlake}/nixos/modules/module-list.nix") ++ (optionals docCustom modules'); + modules = (optionals (!docCustom) modules') ++ [ + (modArgs: { + warnings = flatten [ + (optional (modArgs.config.home-manager.useGlobalPkgs && (nixpkgs != home-manager)) + '' + Using global nixpkgs ${nixpkgs} with home-manager ${home-manager} may cause problems. + '') + ]; + + _module.args = { + inherit inputs; + pkgs' = allPkgs; + }; + system.name = name; networking.hostName = mkDefault name; - } + nixpkgs = { + inherit system; + # Make sure any previously set config / overlays (e.g. lib which will be inherited by home-manager down the + # line) are passed on when nixpkgs is imported. + inherit (pkgs) config overlays; + }; + + # Unfortunately it seems there's no way to fully decouple home-manager's lib from NixOS's pkgs.lib. :( + # https://github.com/nix-community/home-manager/blob/7c2ae0bdd20ddcaafe41ef669226a1df67f8aa06/nixos/default.nix#L22 + home-manager = { + # Optimise if system and home-manager nixpkgs are the same + useGlobalPkgs = mkDefault (nixpkgs == home-manager); + sharedModules = homeModules ++ [ + { + warnings = flatten [ + (optional (!modArgs.config.home-manager.useGlobalPkgs && (hmNixpkgs != home-manager)) + '' + Using per-user nixpkgs ${hmNixpkgs} with home-manager ${home-manager} may cause issues. + '') + ]; + + # pkgsPath is used by home-manager's nixkpgs module to import nixpkgs (i.e. if !useGlobalPkgs) + _module.args = { + inherit inputs; + pkgsPath = toString pkgsFlakes.${hmNixpkgs}; + pkgs' = allPkgs; + }; + } + (homeStateVersion home-manager) + ]; + }; + }) config ]; }; @@ -47,6 +104,8 @@ mapAttrs mkSystem { colony = { system = "x86_64-linux"; nixpkgs = "stable"; + home-manager = "unstable"; config = boxes/colony.nix; + docCustom = false; }; } diff --git a/util.nix b/util.nix index acad7f4..500c7d0 100644 --- a/util.nix +++ b/util.nix @@ -1,7 +1,7 @@ { lib }: let inherit (builtins) replaceStrings elemAt mapAttrs; - inherit (lib) genAttrs mapAttrs' mapAttrsToList nameValuePair types mkOption mkOverride; + inherit (lib) genAttrs mapAttrs' mapAttrsToList nameValuePair types mkOption mkOverride mkForce; inherit (lib.flake) defaultSystems; in rec { @@ -61,4 +61,9 @@ rec { dummyOption = mkOption { }; mkVMOverride' = mkOverride 9; + + homeStateVersion = hmBranch: { + # The flake passes a default setting, but we don't care about that + home.stateVersion = mkForce (if hmBranch == "unstable" then "22.05" else "21.11"); + }; }