From c6eac8a549fd9f55d5da908dbe49da9301e264f0 Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Thu, 31 Dec 2020 14:26:32 +0100 Subject: Set up template --- .gitignore | 2 ++ accounts/.keep | 0 flake.nix | 94 ++++++++++++++++++++++++++++++++++++++++++++++++ hosts/.keep | 0 modules/.keep | 0 overlays/.keep | 0 pkgs/default.nix | 3 ++ shell.nix | 16 +++++++++ system-profiles/.keep | 0 system-profiles/core.nix | 47 ++++++++++++++++++++++++ user-profiles/.keep | 0 users/.keep | 0 utils/default.nix | 57 +++++++++++++++++++++++++++++ 13 files changed, 219 insertions(+) create mode 100644 .gitignore create mode 100644 accounts/.keep create mode 100644 flake.nix create mode 100644 hosts/.keep create mode 100644 modules/.keep create mode 100644 overlays/.keep create mode 100644 pkgs/default.nix create mode 100644 shell.nix create mode 100644 system-profiles/.keep create mode 100644 system-profiles/core.nix create mode 100644 user-profiles/.keep create mode 100644 users/.keep create mode 100644 utils/default.nix diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..f295f429 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +result +result-* \ No newline at end of file diff --git a/accounts/.keep b/accounts/.keep new file mode 100644 index 00000000..e69de29b diff --git a/flake.nix b/flake.nix new file mode 100644 index 00000000..fa1e81d6 --- /dev/null +++ b/flake.nix @@ -0,0 +1,94 @@ +{ + description = "gkleen's machines"; + + inputs = { + nixpkgs = { + type = "github"; + owner = "NixOS"; + repo = "nixpkgs"; + ref = "master"; + }; + home-manager = { + type = "github"; + owner = "nix-community"; + repo = "home-manager"; + ref = "master"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = { self, nixpkgs, home-manager }@inputs: + let + inherit (builtins) attrNames attrValues elemAt; + inherit (nixpkgs) lib; + utils = import ./utils { inherit lib; }; + inherit (utils) recImport overrideModule; + inherit (lib) nixosSystem mkIf splitString filterAttrs listToAttrs mapAttrsToList nameValuePair concatMap composeManyExtensions mapAttrs mapAttrs' recursiveUpdate; + + mkNixosConfiguration = dir: path: hostName: nixosSystem rec { + specialArgs = { + flake = self; + flakeInputs = inputs; + path = toString ./.; + }; + modules = + let + defaultProfiles = with self.nixosModules.systemProfiles; [core]; + local = "${toString dir}/${path}"; + global._module.args = { + customUtils = utils; + inherit hostName; + }; + accountModules = attrValues (filterAttrs accountMatchesHost self.nixosModules.accounts); + accountMatchesHost = n: _v: + let + accountName' = splitString "@" n; + hostName' = elemAt accountName' 1; + in hostName' == hostName; + in [ home-manager.nixosModules.home-manager global ] ++ defaultProfiles ++ [ local ] ++ accountModules; + }; + + mkSystemProfile = dir: path: profileName: { + imports = [ "${toString dir}/${path}" ]; + config = { + system.profiles = [profileName]; + }; + }; + + mkUserModule = dir: path: userName: overrideModule (import "${toString dir}/${path}") (inputs: inputs // { inherit userName; }) (outputs: { _file = "${toString dir}/${path}"; } // outputs); + + mkAccountModule = dir: path: accountName: + let + accountName' = splitString "@" accountName; + userName = elemAt accountName' 0; + in overrideModule (import "${toString dir}/${path}") (inputs: inputs // { inherit userName; }) (outputs: { _file = "${toString dir}/${path}"; } // outputs // { imports = [self.nixosModules.users.${userName}] ++ (outputs.imports or []); }); + + forAllSystems = f: mapAttrs f nixpkgs.legacyPackages; + + activateHomeManagerConfigurations = forAllSystems (system: _pkgs: mapAttrs' (configName: hmConfig: nameValuePair "${configName}-activate" { type = "app"; program = "${hmConfig.activationPackage}/bin/activate"; }) self.homeManagerConfigurations); + activateNixosConfigurations = forAllSystems (system: _pkgs: mapAttrs' (hostName: nixosConfig: nameValuePair "${hostName}-activate" { type = "app"; program = "${nixosConfig.config.system.build.toplevel}/bin/switch-to-configuration"; }) self.nixosConfigurations); + in + { + nixosModules = + let modulesAttrs = recImport { dir = ./modules; }; + systemProfiles = recImport rec { dir = ./system-profiles; _import = mkSystemProfile dir; }; + userProfiles = recImport rec { dir = ./user-profiles; }; + users = recImport rec { dir = ./users; _import = mkUserModule dir; }; + accounts = recImport rec { dir = ./accounts; _import = mkAccountModule dir; }; + in modulesAttrs // { inherit systemProfiles userProfiles users accounts; }; + nixosConfigurations = recImport rec { dir = ./hosts; _import = mkNixosConfiguration dir; }; + + homeManagerConfigurations = listToAttrs (concatMap ({hostName, users}: mapAttrsToList (userName: homeConfig: nameValuePair "${userName}@${hostName}" homeConfig) users) (mapAttrsToList (hostName: nixosConfig: { inherit hostName; users = nixosConfig.config.home-manager.users; }) (self.nixosConfigurations))); + + overlay = import ./pkgs; + overlays = recImport { dir = ./overlays; } // { pkgs = self.overlay; }; + + packages = forAllSystems (system: systemPkgs: composeManyExtensions (attrValues self.overlays) (self.legacyPackages.${system}) systemPkgs); + + legacyPackages = forAllSystems (system: systemPkgs: recursiveUpdate systemPkgs self.packages.${system}); + + apps = recursiveUpdate activateNixosConfigurations activateHomeManagerConfigurations; + + devShell = forAllSystems (system: systemPkgs: import ./shell.nix { pkgs = self.legacyPackages.${system}; }); + }; +} diff --git a/hosts/.keep b/hosts/.keep new file mode 100644 index 00000000..e69de29b diff --git a/modules/.keep b/modules/.keep new file mode 100644 index 00000000..e69de29b diff --git a/overlays/.keep b/overlays/.keep new file mode 100644 index 00000000..e69de29b diff --git a/pkgs/default.nix b/pkgs/default.nix new file mode 100644 index 00000000..b5d83487 --- /dev/null +++ b/pkgs/default.nix @@ -0,0 +1,3 @@ +self: super: +{ +} diff --git a/shell.nix b/shell.nix new file mode 100644 index 00000000..2820eb1a --- /dev/null +++ b/shell.nix @@ -0,0 +1,16 @@ +{ pkgs ? import {} }: +let + nixWithFlakes = pkgs.symlinkJoin { + name = "nix-with-flakes"; + paths = [ pkgs.nixFlakes ]; + buildInputs = [ pkgs.makeWrapper ]; + postBuild = '' + wrapProgram $out/bin/nix --add-flags '--option experimental-features "nix-command flakes ca-references"' + ''; + }; +in pkgs.mkShell { + name = "nixos"; + nativeBuildInputs = with pkgs; [ + nixWithFlakes + ]; +} diff --git a/system-profiles/.keep b/system-profiles/.keep new file mode 100644 index 00000000..e69de29b diff --git a/system-profiles/core.nix b/system-profiles/core.nix new file mode 100644 index 00000000..2af82703 --- /dev/null +++ b/system-profiles/core.nix @@ -0,0 +1,47 @@ +{ flake, flakeInputs, path, hostName, config, lib, pkgs, customUtils, ... }: +let + profileSet = customUtils.types.attrNameSet flake.nixosModules.systemProfiles; +in { + options = { + # See mkSystemProfile in ../flake.nix + system.profiles = lib.mkOption { + type = profileSet; + default = []; + description = '' + Set (list without duplicates) of ‘systemProfiles’ enabled for this host + ''; + }; + }; + + config = { + networking.hostName = hostName; + system.configurationRevision = lib.mkIf (flake ? rev) flake.rev; + + nixpkgs.pkgs = flakeInputs.nixpkgs.legacyPackages.${config.nixpkgs.system}; + nixpkgs.overlays = lib.attrValues flake.overlays; + + nix = { + package = pkgs.nixUnstable; + useSandbox = true; + allowedUsers = [ "@wheel" ]; + trustedUsers = [ "root" "@wheel" ]; + extraOptions = '' + experimental-features = nix-command flakes ca-references + ''; + nixPath = [ + "nixpkgs=${path}" + ]; + registry = { + nixpkgs.flake = flakeInputs.nixpkgs; + home-manager.flake = flakeInputs.home-manager; + machines.flake = flake; + }; + }; + + users.mutableUsers = false; + + # documentation.nixos.includeAllModules = true; # incompatible with home-manager (build fails) + + home-manager.useGlobalPkgs = true; # Otherwise home-manager would only work impurely + }; +} diff --git a/user-profiles/.keep b/user-profiles/.keep new file mode 100644 index 00000000..e69de29b diff --git a/users/.keep b/users/.keep new file mode 100644 index 00000000..e69de29b diff --git a/utils/default.nix b/utils/default.nix new file mode 100644 index 00000000..d00357af --- /dev/null +++ b/utils/default.nix @@ -0,0 +1,57 @@ +{ lib }: +rec { + inherit (builtins) readDir; + inherit (lib) filterAttrs hasSuffix removeSuffix mapAttrs' nameValuePair isFunction functionArgs setFunctionArgs id; + mapFilterAttrs = seive: f: attrs: filterAttrs seive (mapAttrs' f attrs); + recImport = { dir, _import ? name: _base: import "${toString dir}/${name}" }: + mapFilterAttrs + (_: v: v != null) + (n: v: + if n != "default.nix" && hasSuffix ".nix" n && v == "regular" + then + let name = removeSuffix ".nix" n; in nameValuePair (name) (_import n name) + else + if v == "directory" + then + nameValuePair n (_import n n) + else + nameValuePair ("") (null)) + (readDir dir); + + types.attrNameSet = attr: + let + elemType = lib.types.enum (builtins.attrNames attr); + in lib.types.mkOptionType rec { + name = "attrNameSet"; + description = "set of names taken from an attribute set"; + check = lib.isList; + emptyValue = { value = {}; }; + getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["*"]); + getSubModules = elemType.getSubModules; + substSubModules = m: lib.types.listOf (elemType.substSubModules m); + functor = (lib.types.defaultFunctor name) // { wrapped = elemType; }; + merge = loc: defs: map (x: x.value) (lib.lists.filter (x: x ? value) (lib.lists.unique (lib.lists.concatLists (lib.lists.imap1 (n: def: + lib.lists.imap1 (m: def': + (lib.modules.mergeDefinitions + (loc ++ ["[definition ${toString n}-entry ${toString m}]"]) + elemType + [{ inherit (def) file; value = def'; }] + ).optionalValue + ) def.value + ) defs)))); + }; + + overrideModuleArgs = + let + overrideModuleArgs = module: appOverride: if isFunction module then overrideModuleArgs' module appOverride else module; + overrideModuleArgs' = module: appOverride: setFunctionArgs (inputs: overrideModuleArgs (module (appOverride inputs)) id) (functionArgs module); + in overrideModuleArgs; + + overrideModuleOutput = + let + overrideModuleOutput = module: appOverride: if isFunction module then overrideModuleOutput' module appOverride else appOverride module; + overrideModuleOutput' = module: appOverride: setFunctionArgs (inputs: overrideModuleOutput (module inputs) appOverride) (functionArgs module); + in overrideModuleOutput; + + overrideModule = module: appInput: appOutput: overrideModuleOutput (overrideModuleArgs module appInput) appOutput; +} -- cgit v1.2.3