From 1dc5dff82f609bd3074d99b5308c0a2df0d1b077 Mon Sep 17 00:00:00 2001
From: Gregor Kleen <gkleen@yggdrasil.li>
Date: Thu, 31 Dec 2020 14:26:32 +0100
Subject: Set up template

---
 .gitignore               |  2 ++
 accounts/.keep           |  0
 flake.lock               | 49 +++++++++++++++++++++++++
 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 +++++++++++++++++++++++++++++
 14 files changed, 268 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 accounts/.keep
 create mode 100644 flake.lock
 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.lock b/flake.lock
new file mode 100644
index 00000000..89225a55
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,49 @@
+{
+  "nodes": {
+    "home-manager": {
+      "inputs": {
+        "nixpkgs": [
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1609269962,
+        "narHash": "sha256-YvkJhcBBls39JFZzh/S3oRKyDFAgy2KoW5AzJ+MvNgQ=",
+        "owner": "nix-community",
+        "repo": "home-manager",
+        "rev": "8e0c1c55fbb7f16f9fd313275ddf63c97b34394c",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-community",
+        "ref": "master",
+        "repo": "home-manager",
+        "type": "github"
+      }
+    },
+    "nixpkgs": {
+      "locked": {
+        "lastModified": 1609337906,
+        "narHash": "sha256-xj027twGqdK/xRzxlnM8icyUUF4GANlBevHqLYhqb7w=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "58f3c19b78594e1839abf702fa73ddf9d7a96437",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "master",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "root": {
+      "inputs": {
+        "home-manager": "home-manager",
+        "nixpkgs": "nixpkgs"
+      }
+    }
+  },
+  "root": "root",
+  "version": 7
+}
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 <nixpkgs> {} }:
+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