rc icon indicating copy to clipboard operation
rc copied to clipboard

Structured system configuration (I moved from NixOS to GuixSD)

#+title: NixOS System Configuration #+author: bqv #+email: [email protected] #+options: toc:nil num:nil

#+BEGIN_SRC nix { description = "A highly structured configuration database.";

inputs = { priv.url = "hg+ssh://bao@delta/../../srv/hg/nixpriv";

master.url = "github:nixos/nixpkgs/master";               #|.
staged.url = "github:nixos/nixpkgs/staging";              #| |-- Nix
small.url  = "github:nixos/nixpkgs/nixos-unstable-small"; #| |--   pkgs
large.url  = "github:nixos/nixpkgs/nixos-unstable";       #|'

rel2009.url = "github:nixos/nixpkgs/nixos-20.09";         #| Stable
rel2003.url = "github:nixos/nixpkgs/nixos-20.03";         #| Old Stable
rel1909 = { url = "github:nixos/nixpkgs/nixos-19.09"; flake = false; };
rel1903 = { url = "github:nixos/nixpkgs/nixos-19.03"; flake = false; };
rel1809 = { url = "github:nixos/nixpkgs/nixos-18.09"; flake = false; };
rel1803 = { url = "github:nixos/nixpkgs/18.03"; flake = false; };
pr75800.url = "github:nixos/nixpkgs/517b290754f6a7cc487ce11932a8b750f868324d"; #|\ Pull
pr93659.url = "github:ju1m/nixpkgs/security.pass";                             #|/ Reqs

nix.url = "github:nixos/nix";                             #|- Nix
nix-ipfs.url = "github:obsidiansystems/nix/ipfs-develop"; #|  ^^^IPFS

dwarffs.url = "github:edolstra/dwarffs";         #|- Dwarffs
dwarffs.inputs.nix.follows = "/nix";             #|
dwarffs.inputs.nixpkgs.follows = "/nix/nixpkgs"; #|

home.url = "github:nix-community/home-manager"; #|- Home-manager
home.inputs.nixpkgs.follows = "/master";        #|

naersk.url = "github:nmattia/naersk";      #|- Naersk
naersk.inputs.nixpkgs.follows = "/master"; #|

guix.url = "github:emiller88/guix";      #|- Guix
guix.inputs.nixpkgs.follows = "/master"; #|

construct.url = "github:matrix-construct/construct"; #|- Construct
construct.inputs.nixpkgs.follows = "/large";         #|

hydra.url = "github:nixos/hydra/f64230b45edf07d1"; #|- Hydra

emacs.url = "github:nix-community/emacs-overlay"; # Emacs-overlay

lisp.url = "github:nix-lisp/lisp-overlay"; # Lisp-overlay

funkwhale.url = "github:mmai/funkwhale-flake"; # Funkwhale

devshell.url = "github:numtide/devshell"; # Devshell

wayland.url = "github:colemickens/nixpkgs-wayland"; #|- Nixpkgs-wayland
wayland.inputs.nixpkgs.follows = "/small";          #|

agenix.url = "github:ryantm/agenix";          #|- AgeNix
agenix.inputs.nixpkgs.follows = "/small";     #|
agenix.inputs.flake-utils.follows = "/utils"; #|

haskell.url = "github:input-output-hk/haskell.nix"; # Haskell.nix
utils.url = "github:numtide/flake-utils";           # Flake-utils
hardware.url = "github:nixos/nixos-hardware";       # Nixos-hardware
android.url = "github:tadfisher/android-nixpkgs";   # Android SDK

xontribs.url = "github:bqv/xontribs"; #|- Xontribs
xontribs.inputs = {
  nixpkgs.follows = "/master";
  prompt-bar = { url = "github:anki-code/xontrib-prompt-bar/68b3487e156ed3dce80578ebe552b6afa94c7eb8"; flake = false; };
  pipeliner = { url = "github:anki-code/xontrib-pipeliner/daccb6c8a67bbda799dfa2d6d8d829b5e9151c92"; flake = false; };
};

nyxt = { url = "github:atlas-engineer/nyxt"; flake = false; };                 # Nyxt
processmgmt = { url = "github:svanderburg/nix-processmgmt"; flake = false; };  # ProcessMgmt
hnix-overlay = { url = "github:haskell-nix/hnix"; flake = false; };            # Hnix
impermanence = { url = "github:nix-community/impermanence"; flake = false; };  # Impermanence
mozilla = { url = "github:mozilla/nixpkgs-mozilla"; flake = false; };          # Nixpkgs-mozilla
baduk = { url = "github:dustinlacewell/baduk.nix"; flake = false; };           # Baduk
snack = { url = "github:nmattia/snack"; flake = false; };                      # Snack
napalm = { url = "github:nmattia/napalm"; flake = false; };                    # Napalm
statichask = { url = "github:nh2/static-haskell-nix"; flake = false; };        # Static Haskell

#anki-sync = { url = "github:ankicommunity/anki-sync-server/125f7bb1"; flake = false; }; # Anki Server android-nix = { url = "github:tmcl/minimal-android-nix-example"; flake = false; }; conix = { url = "github:thenerd247/conix"; flake = false; }; matrix-nio = { url = "github:poljar/matrix-nio/98f0c244"; flake = false; }; weechat-matrix = { url = "github:poljar/weechat-matrix/d4158416"; flake = false; }; sqlcmdline = { url = "github:sebasmonia/sqlcmdline"; flake = false; }; fish-bass = { url = "github:edc/bass"; flake = false; }; spotify-adblock = { url = "github:x0uid/spotifyadblock"; flake = false; }; bottom = { url = "github:clementtsang/bottom/0.4.5"; flake = false; }; twitterpub = { url = "github:bqv/twitterpub"; flake = false; }; zsh-pure = { url = "github:sindresorhus/pure"; flake = false; }; fsnoop = { url = "github:jeffwalter/fsnoop"; flake = false; }; shflags = { url = "github:kward/shflags"; flake = false; }; git-remote-ipfs = { url = "github:bqv/git-remote-ipfs"; flake = false; }; git-get = { url = "github:grdl/git-get"; flake = false; }; git-pullrequest = { url = "github:google/git-pull-request-mirror"; flake = false; }; dgit = { url = "github:quorumcontrol/dgit/v0.0.14-alpha"; flake = false; }; wld = { url = "github:michaelforney/wld"; flake = false; }; swc = { url = "github:bqv/swc"; flake = false; }; velox = { url = "github:michaelforney/velox"; flake = false; }; st-wl = { url = "github:michaelforney/st"; flake = false; }; dmenu = { url = "github:michaelforney/dmenu"; flake = false; }; emacs-bitwarden = { url = "github:seanfarley/emacs-bitwarden"; flake = false; }; ivy-exwm = { url = "github:pjones/ivy-exwm"; flake = false; }; flycheck-purescript = { url = "github:bsermons/flycheck-purescript"; flake = false; }; eterm-256color = { url = "github:dieggsy/eterm-256color"; flake = false; }; emacsbridge = { url = "github:aardsoft/emacsbridge"; flake = false; }; font-lock-ext = { url = "github:sensorflo/font-lock-ext"; flake = false; }; sln-mode = { url = "github:sensorflo/sln-mode"; flake = false; }; emacs-ffi = { url = "github:tromey/emacs-ffi"; flake = false; }; explain-pause-mode = { url = "github:lastquestion/explain-pause-mode"; flake = false; }; gnome-network-displays = { url = "git+https://gitlab.gnome.org/gnome/gnome-network-displays"; flake = false; }; emacs-webkit = { url = "github:akirakyle/emacs-webkit"; flake = false; }; ini2json = { url = "github:anubisss/ini2json"; flake = false; }; mfs-replace-root = { url = "github:hsanjuan/mfs-replace-root"; flake = false; }; brig = { url = "github:sahib/brig/develop"; flake = false; }; emacs-straight = { url = "github:raxod502/straight.el"; flake = false; }; cloudflare-cli = { url = "github:danielpigott/cloudflare-cli"; flake = false; }; wgvanity = { url = "github:warner/wireguard-vanity-address"; flake = false; }; wold = { url = "github:pauliuszaleckas/wold"; flake = false; }; mactelnet = { url = "github:haakonnessjoen/mac-telnet"; flake = false; }; gh-notify = { url = "github:anticomputer/gh-notify"; flake = false; }; dendrite = { url = "github:matrix-org/dendrite"; flake = false; }; matrix-client = { url = "github:alphapapa/matrix-client.el"; flake = false; }; git-bug = { url = "github:michaelmure/git-bug"; flake = false; }; };

outputs = inputs: with builtins; let allSystems = [ "x86_64-linux" "i686-linux" "aarch64-linux" ];

# Nixos Config
config = {
  allowUnfree = true;
  android_sdk.accept_license = true;
};

patchNixpkgs = basePkgs: let
  pullReqs = map (meta: {
    url = meta.url or "https://github.com/nixos/nixpkgs/pull/${toString meta.id}.diff";
    name = "nixpkgs-pull-request-${toString meta.id}";
    inherit meta;
    sha256 = meta.hash;
  }) [
    {
      description = "nixos/anbox: use mainline drivers when available";
      id = 102341; hash = "rHKK1id+DHug+4drCfNuPBcGNT3bhQ/bvqYZxf+TVuI=";
    }
    {
      description = "nixos/nat: substitute iptables for compat under nftables";
      id = 085462; hash = "vU53uZUhhO6U2RGElAnZqAy3KForw/yyPiU5Rg1hL74=";
    } # see also #81172
   #{
   #  description = "matrix-dendrite: init at 0.3.9";
   #  id = 109561; hash = "+lTYEXjiMGh6hsYAWU+y5Cn0nFfzeW0yD84AZKsyHT4=";
   #} # broken, for now
  ];
  patches = [
   #(basePkgs.fetchurl {
   #  name = "grub-use-xkb-config";
   #  url = "https://github.com/NixOS/nixpkgs/compare/master...mdevlamynck:4a709715e3de83bfc34b880b8044af41a558316e.diff";
   #  sha256 = "1bkbr2znnwi5yc210vhnj638i1ls1w35sdhh3hfh6fnxlbjlmfbn";
   #})
  ] ++ map basePkgs.fetchpatch pullReqs;
  patchedTree = basePkgs.applyPatches {
    name = "nixpkgs-patched";
    src = basePkgs.path;
    inherit patches;
    postPatch = ''
      patch=$(printf '%s\n' ${builtins.concatStringsSep " " (map (p: p.outputHash or (builtins.baseNameOf p)) patches)} |
      sort | sha256sum | cut -c -7)
      echo "+patch-$patch" >.version-suffix
    '';
  };

  import_nixpkgs = args: import patchedTree ({ inherit (basePkgs) system config overlays; } // args);
in import_nixpkgs {} // patchedTree // {
  lib = (import_nixpkgs {}).lib;
  legacyPackages = basePkgs.lib.genAttrs allSystems (system: _: import_nixpkgs { inherit system; });
};

patchedPkgs = forAllSystems ({ system, ... }:
  patchNixpkgs (channels.modules.legacyPackages.${system})
);

channels = with inputs; {
  patched = lib.mapAttrs (_: nixpkgs: forAllSystems ({ system, ... }:
    patchNixpkgs nixpkgs.legacyPackages.${system}
  )) channels;

  pkgs = small;       # For packages
  modules = master;   # For nixos modules
  lib = master;       # For flake-wide lib
}; inherit (channels.lib) lib; # this ^

# Packages for nixos configs
pkgsForSystem = system: patchNixpkgs (import channels.pkgs rec {
  inherit system config;
  overlays = builtins.map (o: o // { value = lib.fix o.__functor; }) [{
    # Project each overlay through recursive subsets
    __functor = self: final: prev: let
      overlaySets = lib.mapAttrs' (ident: overlay: {
        name = "with" + (with lib.strings; let
          ch = stringToCharacters ident;
          ch' = [(toUpper (head ch))] ++ tail ch;
        in concatStringsSep "" ch');
        value = import prev.path {
          inherit (prev) system config;
          overlays = prev.overlays ++ [{
            value = _final: _prev: {
              inherit overlay;
              pkgsParent = final;
            } // overlay _final _prev;
            __functor = x: x.value;
            name = ident;
          }];
        };
      }) inputs.self.overlays;
    in overlaySets // {
      inherit overlaySets;
      overlay = self;
      overlaysBase = overlays;
      pkgsParent = prev // { overlays = []; };
      appendOverlays = extensions: prev.appendOverlays [{
        inherit extensions;
        value = lib.fold lib.composeExtensions (self: lib.id) extensions;
        __functor = x: _final: _prev: x.value _final _prev // {
          pkgsParent = final;
        };
        provides = builtins.listToAttrs (lib.imap0 (n: ext: {
          name = "_${toString n}";
          value = builtins.attrNames (ext {} {});
        }) extensions);
        name = "config";
      }];
      withPins = import prev.path {
        inherit (prev) system config;
        overlays = prev.overlays ++ [{
          # Flatten pkgs architecture superficially for convenient maintenance
          value = _final: _prev: let
            overlayPkgs = with final; {
              # hack to prioritize config overlays
              appendOverlays = exts: (final.appendOverlays exts).withPins;

              # this is one light breeze away from infrec
              inherit (withDevshellFlake) devshell;
              mkDevShell = configuration: (withDevshellFlake.devshell.eval { inherit configuration; }).shell;
              inherit (withGuixFlake) guix;
              inherit (withFunkwhaleFlake) funkwhale;
              inherit (withEmacsFlake.withSelfFlake.withEmacs) emacsPgtkGcc emacsPgtkGccClient emacsPgtkGccPackages;
              inherit (withCordless) cordless;
              inherit (withNix) nixFlakes nix-static nix-ipfs;
              inherit (withInsecureSSL) epsxe;
              inherit (withHydraFlake.withNix.withHydra) hydra hydra-unstable;
              inherit (withSelfFlake) velox electronmail;
              dotnetPackages = dotnetPackages // {
                inherit (withSelfFlake.dotnetPackages) azure-functions-core-tools;
              };
              haskellPackages = haskellPackages // {
                inherit (withRel2009.haskellPackages) pointfree-fancy;
              };
              inherit (withSelfFlake) dejavu_nerdfont;
              emacsPackagesFor = emacs: let
                inherit (withEmacsFlake) emacsPackagesFor;
                epkgs = withEmacsFlake.withSelfFlake.withEmacs.emacsPackagesFor emacs;
              in (emacsPackagesFor emacs).overrideScope' (_: _: {
                inherit (epkgs) bitwarden ivy-exwm emacs-webkit matrix-client;
                inherit (epkgs) flycheck-purescript eterm-256color gh-notify;
                inherit (epkgs) emacsbridge font-lock-ext sln-mode;
                inherit (epkgs) emacs-ffi explain-pause-mode weechat-patched;
              });
              inherit (withSelfFlake) git-pr-mirror git-remote-ipfs git-get ipfscat;
              inherit (import path { inherit system; }) notmuch; # ouch
              inherit (withSelfFlake) guix-ns twitterpub;
              inherit (withConstructFlake.withConstruct) matrix-construct;
              inherit (withSelfFlake) yacy;
              inherit (withRel2003.withSelfFlake) vervis;

              inherit (withSelfFlake) cfcli dgit fsnoop pure shflags taiwins;
              inherit (withIni2json) ini2json;
              inherit (withNix.withDwarffsFlake) dwarffs;
              inherit (withNaersk) naersk;
              inherit (withXonsh.withXontribsFlake) xonsh;

              inherit (withWeechat) weechatScripts;
              inherit (withRel2003) bcachefs-tools; # to match kernel ver
              inherit (withNaersk.withSelfFlake) wgvanity wold mactelnet;
              inherit (withNix.withSelfFlake) nix-bundle;
              inherit (withSelfFlake) matrix-dendrite;
              inherit (withGit-bug) git-bug;

              inherit (withMaster) discord;
             #inherit (withLarge.withHnix) hnix;
             #inherit (withLarge.withNyxt) nyxt;
              plasma5 = plasma5Packages;
              inherit (libsForQt5) kdeFrameworks;
            };
          in overlaySets // overlayPkgs // {
            inherit overlaySets overlayPkgs;
            pkgsParent = final;
          };
          __functor = x: x.value;
          name = "pins";
        }];
      };
    };
    name = "index";
  }];
});

forAllSystems = f: lib.genAttrs allSystems (system: f {
  inherit system;
  pkgs = (pkgsForSystem system).withPins;
  inherit (pkgs) lib;
});

inputMap = let
  tryGetValue = res: if res.success then res.value else null;
in {
  n1 = lib.mapAttrsToList lib.nameValuePair inputs;

  n2 = let
    s0 = inputs // { self = {}; };
    s1 = lib.mapAttrs (k: v: v.inputs) (lib.filterAttrs (k: v: v ? inputs) s0);
    s2 = lib.mapAttrsRecursiveCond (s: !(s ? outPath)) (n: i: lib.nameValuePair (lib.concatStringsSep "." n) i) s1;
  in lib.concatMap lib.attrValues (lib.attrValues s2);

  n3 = lib.const [] (let # broken (but why?)
    s0 = inputs // { self = {}; };
    s1 = lib.mapAttrs (k: v: v.inputs) (lib.filterAttrs (k: v: v ? inputs) s0);
    s2 = lib.mapAttrsRecursiveCond (s: !(s ? outPath)) (n: i: lib.nameValuePair (lib.concatStringsSep "." n) i) s1;
    s3 = lib.concatMap lib.attrValues (lib.attrValues s2);
    s4 = lib.mapAttrs (k: v: v.inputs) (lib.filterAttrs (k: v: v ? inputs) (lib.listToAttrs s3));
    s5 = lib.mapAttrsRecursiveCond (s: !(s ? outPath)) (n: i: lib.nameValuePair (lib.concatStringsSep "." n) i) s4;
    s6 = lib.concatMap lib.attrValues (lib.attrValues s5);
  in tryGetValue (builtins.tryEval (lib.concatMap lib.attrValues (lib.attrValues s6))));
};

inherit (inputs.self.passthru) secrets;

in { nixosConfigurations = builtins.mapAttrs (host: node: { config = node.configuration; }) inputs.self.defaultPackage.x86_64-linux.config.nodes;

homeConfigurations = lib.genAttrs (builtins.attrNames inputs.self.nixosConfigurations)
  (host: inputs.self.nixosConfigurations.${host}.config.home-manager.users) //
{
  epsilon = forAllSystems ({ pkgs, system, ... }:
    let
      inherit (pkgs) pkgsStatic nix nix-static termonad-with-packages;
      flakeModules = import ./modules/home-manager.nix;
    in inputs.home.lib.homeManagerConfiguration rec {
      pkgs = pkgsStatic // {
        nixFlakes = nix;
        termonad = termonad-with-packages;
      };
      configuration = {
        _module.args = rec {
          pkgsPath = pkgs.path;
          inherit pkgs;
          nixosConfig = {
            services.aria2.rpcSecret = "";
            networking.hostName = "epsilon";
          };
          flake = inputs.self;
        };
        nixpkgs = {
          inherit config system;
        };
        home.packages = with pkgs; [ nixFlakes termonad ];
        imports = flakeModules ++ [ ./users/aion.nix ];
      };
      inherit system;
      homeDirectory = "/home/${username}";
      username = "aion";
    }
  );
};

legacyPackages = forAllSystems ({ pkgs, ... }: pkgs);

overlay = import ./pkgs;

overlays = let
  diffTrace = left: right: string: value: if left != right then trace string value else value;
  silentKeys = [ "config" "system" "path" "stdenv" "lib" ];

  channelOverlay = { flake, branch }: { ${flake} = final: prev: let
    mapWarn = mapAttrs (k: v: if lib.elem k silentKeys then v
      else if lib.elem k ([ "overlaySets" ] ++ builtins.attrNames prev.overlaySets) then mapWarn v
      else diffTrace (baseNameOf inputs.${flake}) (baseNameOf prev.path) "pkgs.${k} pinned to nixpkgs/${branch}" v);
  in
    mapWarn (import inputs.${flake} { inherit (prev) config system; overlays = [(builtins.head prev.overlays)]; });
  };
  flakeOverlay = { flake, name }: { ${flake} = final: prev: let
    mapWarn = mapAttrs (k: v: if lib.elem k silentKeys then v
      else if lib.elem k ([ "overlaySets" ] ++ builtins.attrNames prev.overlaySets) then mapWarn v
      else diffTrace (baseNameOf inputs.${flake}) (baseNameOf prev.path) "pkgs.${k} pinned to ${name}" v);
  in
    mapWarn inputs.${flake}.legacyPackages.${prev.system};
  };
  inputsOverlay = builtins.listToAttrs (builtins.filter (v: v != null)
    (builtins.map (name: if inputs.${name} ? overlay then {
      name = "${name}Flake";
      value = inputs.${name}.overlay;
    } else null) (builtins.attrNames inputs)));
  configOverlay = config: final: prev: import prev.path {
    inherit (prev) system;
    overlays = [(builtins.head prev.overlays)];
    config = prev.config // config;
  };
in lib.fold (lib.mergeAttrsNoOverride {}) {} [
  {
    broken = configOverlay { allowBroken = true; };
    insecureSSL = configOverlay { permittedInsecurePackages = [ "openssl-1.0.2u" ]; };
    sources = final: prev: inputs;
    lib = final: prev: { inherit lib; };
  }
  {
    mozilla = final: prev: import inputs.mozilla final prev;
    naersk = final: prev: { naersk = inputs.naersk.lib.${prev.system}; };
    snack = final: prev: { snack = final.callPackage "${inputs.snack}/snack-lib"; };
    napalm = final: prev: { napalm = final.callPackage inputs.napalm; };
    nix = final: prev: let inherit (prev) system; in rec {
      nixFlakes = nix;
      nixUnstable = nix;
      nix = inputs.nix.packages.${system}.nix.overrideAttrs (drv: {
        patches = (drv.patches or []) ++ [
         #(final.fetchpatch {
         #  name = "libfetcher-file.patch";
         #  url = "https://github.com/nixos/nix/pull/4153.diff";
         #  sha256 = "JfcswqOG0V5qlolxxYFOpqXJgENC4Adfk4J8r//tgfA=";
         #})
          (final.fetchpatch {
            name = "log-all-ifd.patch";
            url = "https://github.com/NixOS/nix/pull/3494.diff";
            sha256 = "OMDCAc3GalFZwdDsaOfcM07e08334yPE+e8KiyVUWYo=";
          })
        ];
        passthru = {
          inherit (inputs.nix.packages.${system}.nix) perl-bindings;
        };
      });
      nix-static = inputs.nix.packages.${system}.nix-static or null;
      nix-ipfs = inputs.nix-ipfs.packages.${system}.nix;
     #nix-ipfs-static = inputs.nix-ipfs.packages.${system}.nix-static;
    };
    hydra = final: prev: {
      hydra-unstable = final.hydra;
    };
    construct = final: prev: {
      riot-web = final.element-web;
      matrix-construct = (final.callPackage "${inputs.construct}/default.nix" { pkgs = final; }).overrideAttrs (_: {
        EXTRA_CXXFLAGS = "-mabm -mbmi";
        patchPhase = '' sed '/RB_INC_EXECUTION/d' -i ./include/ircd/stdinc.h '';
        preAutoreconf = let
          VERSION_COMMIT_CMD = "git rev-parse --short HEAD";
          VERSION_BRANCH_CMD = "git rev-parse --abbrev-ref HEAD";
          VERSION_TAG_CMD = "git describe --tags --abbrev=0 --dirty --always --broken";
          VERSION_CMD = "git describe --tags --always";
        in ''
          substituteInPlace configure.ac --replace "${VERSION_COMMIT_CMD}" "echo ${inputs.construct.rev}"
          substituteInPlace configure.ac --replace "${VERSION_BRANCH_CMD}" "echo master"
          substituteInPlace configure.ac --replace "${VERSION_TAG_CMD}" "echo ${inputs.construct.rev}"
          substituteInPlace configure.ac --replace "${VERSION_CMD}" "echo ${inputs.construct.rev}"
        '';
        src = builtins.toPath "${inputs.construct}/.";
      });
    };
  }
 #(flakeOverlay { flake = "lg400"; name = "delta/system-400-link"; })
  (channelOverlay { flake = "master"; branch = "master"; })
  (channelOverlay { flake = "staged"; branch = "staging"; })
  (channelOverlay { flake = "small"; branch = "nixos-unstable-small"; })
  (channelOverlay { flake = "large"; branch = "nixos-unstable"; })
  (channelOverlay { flake = "rel2009"; branch = "nixos-20.09"; })
  (channelOverlay { flake = "rel2003"; branch = "nixos-20.03"; })
  (channelOverlay { flake = "rel1909"; branch = "nixos-19.09"; })
  (channelOverlay { flake = "rel1903"; branch = "nixos-19.03"; })
  (channelOverlay { flake = "rel1809"; branch = "nixos-18.09"; })
  (channelOverlay { flake = "rel1803"; branch = "nixos-18.03"; })
  (listToAttrs (map
    (name: {
      name = lib.removeSuffix ".nix" name;
      value = import (./overlays + "/${name}") inputs;
    })
    (builtins.filter
      (file: lib.hasSuffix ".nix" file || file == "default.nix")
      (attrNames (readDir ./overlays)))))
  inputsOverlay
];

packages = forAllSystems ({ pkgs, ... }: lib.filterAttrs (_: p:
  (lib.isDerivation p) && (p.meta.broken or null) != true
) pkgs.overlayPkgs);

defaultPackage = forAllSystems ({ pkgs, system, ... }: let
  deployment = import ./deploy {
    nixpkgs = channels.patched.modules.${system};
    deploySystem = system; # By habit, system is deployer, platform is target
  } ({ config, lib, ... }: let
    inherit (config) nodes;
  in {
    defaults = { name, config, ... }: let
      evalConfig = import "${patchNixpkgs pkgs}/nixos/lib/eval-config.nix";

      getPlatform = with lib.modules; { modules, specialArgs, ... }: let
        args = { config = null; options = null; inherit lib; } // specialArgs;
      in (mergeModules [] (collectModules "" modules args)).matchedOptions.platform.value;

      nixos = with inputs.self.nixosModules; let
        base = hosts.${system}.${name} or null;
        platform = getPlatform base;
      in if base == null then hosts.${system}.image else hosts.${platform}.${name};

      vmsystem = { modules, pkgs, specialArgs, ... }: {
        system.build.vm = (evalConfig {
          inherit specialArgs;
          inherit (pkgs) system;
          modules = modules ++ [
            (import "${channels.modules}/nixos/modules/virtualisation/qemu-vm.nix")
          ];
        }).config.system.build.toplevel;
      };

      linkage = { config, pkgs, ... }: let
        systems = builtins.mapAttrs (host: _: with inputs.self;
          let platform = getPlatform nixosModules.hosts.${system}.${host};
          in defaultPackage.${platform}.config.nodes.${host}.configuration
        ) nodes;
      in {
        options.system.linkOtherSystems = lib.mkOption {
          type = lib.types.bool;
          default = true;
          description = "Whether to link other flake nodes to the system derivation.";
        };

        # Link raw hosts on each host (non-recursively)
        config.system = {
          extraSystemBuilderCmds = lib.mkIf config.system.linkOtherSystems (''
            mkdir -p $out/flake/hosts

            # Link other hosts (nonrecursively)
            ${lib.concatMapStringsSep "\n" ({ name, value }: ''
              ln -s '${value.system.build.toplevel}' "$out/flake/hosts/${name}"
            '') (lib.mapAttrsToList lib.nameValuePair systems)}

            # Link host containers
            ${lib.concatMapStringsSep "\n" (host@{ name, value }: ''
              mkdir -p $out/flake/container/${name}
              ${lib.concatMapStringsSep "\n" (container@{ name, value }: ''
                ln -s '${value.config.system.build.toplevel}' "$out/flake/container/${host.name}/${name}"
              '') (lib.mapAttrsToList lib.nameValuePair value.containers)}
            '') (lib.mapAttrsToList lib.nameValuePair systems)}
          '');
        };
      };

     ifdroots = { config, pkgs, ... }: {
        config.system.extraDependencies = [
          channels.patched.modules.${system}
        ];
      };
    in {
      options = {
        configuration = lib.mkOption {
          type = lib.types.submoduleWith {
            inherit (nixos) modules;
          };
        };
      };

      config = {
        host = "root@${nixos.specialArgs.hosts.wireguard.ipv4.${name}}";

        configuration = {
          imports = [
            ifdroots
           #linkage # TODO: figure out how to make this work
            vmsystem
          ];
          config = {
            secrets.baseDirectory = "/var/lib/secrets";
            _module.args = nixos.specialArgs;
          };
        };

        # Filter out "added to list of known hosts" spam from output
        deployScriptPhases.filter-known-hosts = lib.dag.entryBefore ["copy-closure"] ''
          # Remove known hosts spam
          pipeline -w { ${pkgs.gnugrep}/bin/grep --line-buffered -v "list of known hosts" }
          fdswap 1 2
          pipeline -w { ${pkgs.gnugrep}/bin/grep --line-buffered -v "list of known hosts" }
          fdswap 2 1
        '';

        # Git tag all systems and deployments
        deployScriptPhases.git-tag = let
          inherit (config.configuration) system;
        in lib.dag.entryAfter ["trigger-switch"] ''
          foreground {
            backtick -i -n systemstorepath { basename "${system.build.toplevel.outPath}" }
            importas -i systemstorepath systemstorepath
            define systempath "nix/store/''${systemstorepath}"
            importas -i id ID
            define systemnum "${name}/system-''${id}"
            fdswap 1 2
            foreground { echo Tagging $systempath }
            foreground { ${pkgs.git}/bin/git tag $systempath "${system.configurationRevision}" }
            foreground { echo Tagging $systemnum }
            foreground { ${pkgs.git}/bin/git tag $systemnum "${system.configurationRevision}" }
            exit 0
          }
        '';

        privilegeEscalationCommand = []; # already root

        successTimeout = lib.mkDefault 120;
        switchTimeout = lib.mkDefault 120;

        ignoreFailingSystemdUnits = true;
        systemSwitcherDir = "/nix/node/";

        dirty = ! (inputs.self ? rev);
      };
    };

    nodes = let
      hosts = builtins.attrNames inputs.self.nixosModules.hosts.${system};
    in (lib.genAttrs hosts (_: {})) // {
      delta.hasFastConnection = true; # it's local!
      delta.rollbackOnFailure = false; # accidentally rebooting this gets annoying
      image.enabled = false;
      zeta.panicAction = "false"; # we shouldn't reboot this carelessly
      zeta.hasFastConnection = true;
      zeta.successTimeout = 240; # Zeta seems very slow...
      zeta.switchTimeout = 240; # maybe due to wireguard reloading?
    };

    ssh.access = let
      collapse = attrs: lib.fold (a: b: a // b) {}
        (builtins.concatMap builtins.attrValues (builtins.attrValues
          (lib.mapAttrs (u: lib.mapAttrs (t: v: {
            "${u}-${t}" = v;
          })) attrs)));
    in lib.mkIf false {
      delta = {
        hostKeys = lib.genAttrs [ "rsa" "ecdsa" "ed25519" "dsa" ] (type:
          lib.removeSuffix "\n" (builtins.readFile "${secrets.keyDir}/deltassh/ssh_host_${type}_key.pub")
        );
        keys = collapse {
          bao = {
            rsa = {
              publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAEAQC/Ca5MUwmHMZt4sH/xLAq20X12xDj2bSqg88thxWLvpqnLpLEJmpasaHKRRh9O6E/NE0Zsn45dsTuvB9/otoDGdstYX2VZyi3UBIWp3BjxdbvmMrbhvpihiZl6rAFXU45/LM/4PvraLic2ZXuOGFqoLcnKDAvCATJsQfUGcEnM0YJVcFLjA4sSPHarSoSHFxZ90RXVmW8m5sfNCsMMo3jCMgE49zlWhcrKfp/FfpIlKMytTDdb+JE0JIsR+28oxJtL63wTbO9p2zFS8geNPVMfj8+Ge4bb0YWroBNGaMo3cHcdtquWWvTzZxWJu+AiSlZIWcP6aOhOoRiFrCWIYBP91dtARm2+OXIpUNAT+yPR+YQ4BAUNxYyBZO3hTH47cq2dC4NAQVcjuUb5VLoRAOAl+DzHSj7FNFGo49CxE/eDlhoXzmgP28N5tDktZYYstrr4j/KAZPYzGW8tB6s/VhhiCGFgZQXq2irH2UtU3Amr7cw0Wiiuyoe4x67dUB+sy3yT5jle/dLe0U9qgAiFTptix1QpjDaT8dFYQsi0kzXlSUEB05pmnCjM2n9eksdtF5kggLDNQ3VKH+LRN/rd5JKJsMJn9Lxr9nO3x+x+fhBurthumrDB2S3oqEOWQDxJ+JaZi5mshzZ2bB4lSXGB5aYjaBSk49EmlrNo8dUUXpZFT9mePx8BIC73XtoEsFgH9kpvHqHxOaBBO3wsxWekbS5bzi2KkBWxMAHq/fVV37iNaDHnldEn9DGDIQb6fQnjLkWbwNRBsdZxqfJGBqVpUNVbsS4BOFoa7yxnCZ6OgxzXpScoyeTxgM1nDALRnwee2d+3GrKHzE23Db6tIwUUeHEkcNwY2L6MW6Z2Onv2T9+V0IITe16EV+TcTc04DQ2XtnVEqUfqK5NZX0wpDuO0Bw0cJrbxJy3lk1PbnUnP/slfRgB4yOvkA0zRrer27EiyRsQe9QSfcmcpIK66+UncYqTFZ/qJFBdupn2ruYaDfCq/G8HyNsm7fXJLgsnGrAfEqUlBabbmLBdSvPqWpkMCjmmX7tMvTTWV5/IdFo0NVPQ7VBdZrRoPbYOQetZqr6S1tkKvpISrBKMRXXgaCcegnqWKqomZsFWcTnhyV0vCJM16IaNp++2rqw426hvpm2F+hhUzDa7CP/+HKvo0ucwC1u24CX75eT/pEP7WuINNMEx1y+/VxyeWscAK89NYa2YGBzqBEJ9+0QVFNYye/baaNn1dNEuPk49bkM7g3LTp8ae+J+5dAb3QsKMxL/bssFzAc+7M5+LFQDFpWtxkzkB5+X9HzMtVbsgDk9CDgn56OfkpzjFR7PeDUcKeFWeccWHRMOyXVX1daoUTeDIpESID2FnR bao@delta";
              hasAccessTo.zeta.bao = true;
            };
            ecdsa = {
              publicKey = "ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAEY1DRzmt77NPp64/DEkuPwdOd5yzchRBDmZJBvu+ip42tV3c1FdDNs/7ictpROqfm/Nkh6D/mmbQV+MI2Aa1H66AC+8/wMJl/fkfSEeX6Z6thVM7oC6a2kXuJjlZNF5wQngTP5AWydEFacuZduW+Ir2++IVFyjtIVOR/lumtdzuvi5/A== bao@delta";
              hasAccessTo.zeta.bao = true;
            };
            ed25519 = {
              publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOvcvk1nLYImKqjhL8HdAb1sM2vXcEGu+rMZJ8XIG4H7 bao@delta";
              hasAccessTo.zeta.bao = true;
            };
            gpg = {
              publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDX40Dm37dDdxreqQxQ+bd9c9mNXfSqC5k3Rrf4iQHy7OdzsQD0qngHFdcq2dG0d4sYeHeyJGYHPbtwNYb0AED/zDVgfuiW6+xYSW+apg5Hc2EfktxxmVbRXqq8SoWUP9CtwJLIw0Q4vBiWBKT367VlXnWJ5ob8bwhfRlK7Sk4595Mm2Wp98sgMXdcQbFc+nQ+TYyYnkIYv63g3Lyxi8NQKWGwh2zspGl2rbDVJrtr196bSd3leZhD/v+YquqO2Saf9DZCmDMJmw4rUWZ84rkUZ0lB5eSICfQZAl5UxpnorWutLDxjuFOc/7H6iSGFRNjQ/fM8Jh2dxDm3XWxWp+E+F9q5Q9bsziL+zwxkAL2SvWULhmAALbLMqEC2qkPU9ccqRRBteGIRt/ix+J87lImz6Zp2UqSYFe2GpwP+NtMB8TyMaDUOni+L/NGw7o/EvAm7K7tH6OJW5vSC7e8P5lLc825SHlJdfn5L2aAfD+vr8rZv4L9uy1isJTMvVDRp4CLHwsw+xn4XfnfvsNtWNyVoAfi7NN3+jtCGlpNckj+5ylaQcgGuFbQUJ7jhsUGDYRSvX3wWaRBD94Pi+XS1jUTLyRmIbgcbiSeyzx2fZm1saQAb3MSF9yf0ibCJlTJ3JMLfqlDYP6Yl64bQ67T8QcYvDSUurqh+T6AN83SF6aHT3HQ== gpg";
              hasAccessTo.zeta.bao = true;
            };
          };
        };
      };
      zeta = {
        hostKeys = lib.genAttrs [ "rsa" "ecdsa" "ed25519" "dsa" ] (type:
          lib.removeSuffix "\n" (builtins.readFile "${secrets.keyDir}/zetassh/ssh_host_${type}_key.pub")
        );
        keys = collapse {
        };
      };
    };

    vpn.networks = {
      # TBC
    };
  });
in pkgs.runCommandLocal "deployment" {
  outputs = [ "out" "systems" ] ++ builtins.attrNames (
    lib.filterAttrs (_: n: n.enabled) deployment.config.nodes
  );
  passthru = deployment;
} ''
  mkdir -p $(dirname $out)
  ln -s ${deployment.config.deployScript} $out
  ${lib.concatStringsSep "" (lib.mapAttrsToList (host: node: if node.enabled then ''
    ln -s ${node.nodeDeployScript} ''$${host}
    mkdir -p $systems
    ln -s ${node.configuration.system.build.toplevel} $systems/${host}
  '' else "") deployment.config.nodes)}
'');

apps = forAllSystems ({ pkgs, system, ... }: {
  epsilon = rec {
    type = "app";
    inherit (inputs.self.homeConfigurations.epsilon.${system}) activationPackage;
    program = (pkgs.writeShellScript "reconfigure-epsilon" ''
      echo Deploying ${activationPackage}
      export HOST=epsilon
      export NIX_SSHOPTS="-o StrictHostKeyChecking=no"
      nix copy --to ssh://$HOST '${activationPackage}' \
        && ssh $NIX_SSHOPTS $HOST -t \
          sh -c ". $HOME/.nix-profile/etc/profile.d/nix.sh && \
            exec ${activationPackage}/activate $@"
    '').outPath;
  };
  zeta = rec {
    type = "app";
    inherit (inputs.self.nixosConfigurations.zeta.config.system.build) toplevel;
    program = (pkgs.writeShellScript "test-zeta" ''
      echo Deploying ${toplevel}
      export HOST=${inputs.self.passthru.secrets.hosts.wireguard.ipv4.zeta}
      export NIX_SSHOPTS="-o StrictHostKeyChecking=no"
      nix copy --to ssh://root@$HOST '${toplevel}' \
        && ssh $NIX_SSHOPTS root@$HOST -t \
          exec ${toplevel}/bin/switch-to-configuration test $@
    '').outPath;
  };
  delta = rec {
    type = "app";
    inherit (inputs.self.nixosConfigurations.delta.config.system.build) toplevel;
    program = (pkgs.writeShellScript "test-delta" ''
      echo Deploying ${toplevel}
      exec doas ${toplevel}/bin/switch-to-configuration test $@
    '').outPath;
    bao = rec {
      type = "app";
      inherit (inputs.self.homeConfigurations.delta.bao.home) activationPackage;
      program = (pkgs.writeShellScript "test-delta-bao" ''
        echo Deploying ${activationPackage}
        exec ${activationPackage}/activate $@
      '').outPath;
    };
  };
});

defaultApp = forAllSystems ({ system, ... }: inputs.self.apps.${system}.delta);

nixosModules = let
  mergeAll = lib.fold lib.recursiveUpdate {};
  pathsToAttrs = map (file:
    let cleanFile = lib.removeSuffix ".nix" (lib.removePrefix "${toString ./.}/" (toString file));
    in lib.setAttrByPath (lib.splitString "/" cleanFile) (import file)
  );
  nixFilesOf = builtins.filter (lib.hasSuffix ".nix");

  moduleList = (import ./modules/nixos.nix)
    ++ (import ./modules/home-manager.nix);

  profilesList = (lib.filesystem.listFilesRecursive ./profiles)
    ++ (builtins.filter (f: ! builtins.hasAttr (builtins.baseNameOf f) (builtins.readDir ./users))
                        (lib.filesystem.listFilesRecursive ./users));
in (mergeAll (pathsToAttrs (nixFilesOf moduleList)))
// (mergeAll (pathsToAttrs (nixFilesOf profilesList)))
// {
  hosts = forAllSystems ({ pkgs, system, ... }: (let
    usr = {
      tools = import ./lib/utils.nix {
        inherit lib;
      };
      elisp = import ./lib/elisp.nix {
        inherit lib;
        pkgs = channels.lib.legacyPackages.${system};
      };
      dag = let dagLib = import ./lib/dag.nix lib lib;
      in dagLib.dag // { inherit (dagLib) types; };
      units = {
        kilobytes = b: b * 1024;
        megabytes = k: k * 1024;
        gigabytes = m: m * 1024;
      };
      inherit (inputs.self.passthru) secrets;
    };

    modulesFor = hostName: appendModules: let
      specialArgs = {
        inherit usr;
        flake = inputs.self;

        inherit (secrets) hosts domains;

        modules = modules ++ [
          { _module.args = specialArgs; }
        ];
        inherit extraModules;
      };

      # External modules
      inherit (inputs.home.nixosModules) home-manager;
      inherit (inputs.dwarffs.nixosModules) dwarffs;
      inherit (inputs.guix.nixosModules) guix;
      inherit (inputs.construct.nixosModules) matrix-construct;
      inherit (inputs.agenix.nixosModules) age;
      hydra = "${inputs.hydra}/hydra-module.nix";
      funkwhale = inputs.funkwhale.nixosModule;

      # Some common basic stuff
      core = ./profiles/core.nix;

      # The flake-ier common basic stuff
      global = {
        environment.pathsToLink = [ "/share/bios" ];

        documentation.nixos.extraModuleSources = [./.]
          ++ lib.mapAttrsToList (_: x: x.outPath) inputs;

        nix.package = lib.mkDefault pkgs.nixFlakes;
        nix.registry = lib.mapAttrs (id: flake: {
          inherit flake;
          from = { inherit id; type = "indirect"; };
        }) (inputs // { nixpkgs = inputs.master; });
        nix.nixPath = lib.mapAttrsToList (k: v: "${k}=${toString v}") {
          nixpkgs = "${channels.pkgs}/";
          nixos = "${inputs.self}/";
          home-manager = "${inputs.home}/";
          self = "/run/current-system/flake/input/self/";
          flake = "/srv/git/github.com/bqv/nixrc";
        };

        system.configurationRevision = inputs.self.rev or "dirty";
        system.nixos.versionSuffix = let inherit (inputs) self;
          date = lib.substring 0 8 (self.lastModifiedDate or "19700101");
          rev = self.shortRev or "dirty";
        in lib.mkForce ".${date}.${rev}";

        system.extraSystemBuilderCmds = (''

          mkdir -p $out/flake/input

          # Link first-class inputs
          ${lib.concatMapStringsSep "\n" ({ name, value }: ''
            ln -s '${value}' "$out/flake/input/${name}"
          '') inputMap.n1}

          # Link second-class inputs
          ${(lib.concatMapStringsSep "\n" ({ name, value }: ''
            ln -s '${value}' "$out/flake/input/${name}"
          '') inputMap.n2)}

          # Link third-class inputs (skipped)
          ${lib.concatMapStringsSep "\n" ({ name, value }: ''
            ln -s '${value}' "$out/flake/input/${name}"
          '') inputMap.n3}

        '');

        system.activationScripts.etcnixos = ''
          rm -f /etc/nixos && \
          ln -sfn /run/current-system/flake/input/self /etc/nixos || \
          true
        '';
      };

      # Host-specific basic stuff
      host = {
        environment.etc."machine-id".text = builtins.hashString "md5" hostName;

        networking = { inherit hostName; };
      };

      # Nixos eval settings
      nixpkgs = { config, ... }: {
        config.nixpkgs = {
          inherit pkgs;
          system = config.platform;
        };
      };

      # Amend home-manager (inject modules, set common stuff)
      home = { config, ... }: {
        options.home-manager.users = lib.mkOption {
          type = with lib.types; attrsOf (submoduleWith {
            inherit specialArgs;
            modules = let
              flakeModules = import ./modules/home-manager.nix;
              nixProfile = { lib, ... }: {
                home.activation.disableNixEnv = lib.hm.dag.entryBefore ["installPackages"] ''
                  alias nix-env=true
                '';
                home.activation.installPackages = lib.mapAttrs (k: v: lib.mkForce v) (lib.hm.dag.entryAnywhere "true");
              };
              baduk = {
                imports = [ (import inputs.baduk) ];
               #baduk.sabaki.enable = false; # needs flake-ification patches
                baduk.sabaki.engines = lib.mkDefault [];
               #baduk.gnugo.enable = false;
               #baduk.katago.enable = false;
               #baduk.leela-zero.enable = false;
              };
              impermanence = import "${inputs.impermanence}/home-manager.nix";
            in flakeModules ++ [
              nixProfile
              baduk
            ];
          });
        };

        config.home-manager = {
          useUserPackages = true;
          useGlobalPkgs = true;
          verbose = true;
        };
      };

      # Hack in the gnupg secrets module (fix docbook)
      gnupg = import "${inputs.pr93659}/nixos/modules/security/gnupg.nix";

      # Plug in the impermanence module (not a flake :<)
      impermanence = import "${inputs.impermanence}/nixos.nix";

      # Set up any other pull request modules
      iwd = { config, ... }: let
        iwdModule = "services/networking/iwd.nix";
      in {
        disabledModules = [ iwdModule ];
        imports = [
          (import "${inputs.pr75800}/nixos/modules/${iwdModule}" {
            inherit config pkgs;
            lib = let
              iwdLib = import "${inputs.pr75800}/lib/default.nix";
            in lib // {
              types = {
                inherit (iwdLib.types) fixedLengthString lengthCheckedString;
              } // lib.types;
            };
          })
        ];
      };

      # Our modules
      flakeModules = import ./modules/nixos.nix;

      # Actual host config
      configuration = import "${toString ./hosts}/${hostName}";

      # Modules to propagate to containers
      extraModules = [
        core global
      ];

      # Final modules set
      modules = flakeModules ++ extraModules ++ [
        home nixpkgs iwd gnupg
        home-manager dwarffs matrix-construct hydra
        impermanence age guix funkwhale
      ];
    in {
      inherit system specialArgs;
      modules = modules ++ [
        host configuration
      ] ++ appendModules;
    };

    forEachHost = do: usr.tools.recImport {
      # Build a nixos system for each dir in ./hosts using modulesFor
      dir = ./hosts;
      _import = do;
    };
  in forEachHost (host: let
    pkgs = channels.modules.legacyPackages.${system};
  in modulesFor host [])));
};

devShell = forAllSystems ({ system, ... }:
  let
    pkgs = import channels.pkgs { inherit system; overlays = [ inputs.devshell.overlay ]; };
    mkDevShell = configuration: (pkgs.devshell.eval { inherit configuration; }).shell;
  in mkDevShell {
    packages = with pkgs; let
      git-crypt = pkgs.git-crypt.overrideAttrs (attrs: rec {
        worktreePatch = fetchurl {
          name = "support-worktree-simple-version.patch";
          url = "https://github.com/AGWA/git-crypt/files/2771938/git-crypt-support-worktree-simple-version-patch.txt";
          sha256 = "1k477m6g3zjdarjr38lndh0kpgkp0yi8lg2iqdispfd4c85krrax";
          # date = 2021-01-29T23:45:21+0000;
        };
        patches = [ worktreePatch ];
      });
    in [
      git git-crypt git-secrets nixfmt
    ];

    env = with pkgs; let
      nixConf = ''
        ${lib.optionalString (builtins.pathExists /etc/nix/nix.conf)
          (builtins.readFile /etc/nix/nix.conf)}
        experimental-features = nix-command flakes ca-references
        print-build-logs = true
        access-tokens = "github.com=${secrets.git.github.oauth-token}"
      '';
    in [{
      name = "NIX_CONF_DIR";
      value = "${linkFarm "nix-conf-dir" ( [
        { name = "nix.conf"; path = writeText "flakes-nix.conf" nixConf; }
        { name = "registry.json"; path = /etc/nix/registry.json; }
        { name = "machines"; path = /etc/nix/machines; }
      ] )}";
    }];

    commands = [{
      name = "forecast";
      category = "automation";
      command = ''
        export ARGS="$*"
        REPO=$(
          nix build --impure --json --no-link '.#lib.forecast' \
          | jq '.[] | .outputs.out' -r \
        )
        git fetch $REPO substrate:substrate
        git branch -f substrate FETCH_HEAD
      '';
    }];

    motd = "";
  }
);

passthru = rec {
  inherit inputs channels config allSystems inputMap patchNixpkgs;
  patchedPkgs = forAllSystems ({ system, ... }:
    patchNixpkgs (channels.modules.legacyPackages.${system})
  );

  #$ git config secrets.providers "nix eval --raw .#passthru.textFilter"
  textFilter = with inputs.priv.lib.textFilter { inherit lib; }; lines;
  inherit (inputs.priv.lib) secrets;

  forecast = let
    inherit (channels.pkgs.legacyPackages.${builtins.currentSystem}) pkgs;
    date = builtins.readFile (pkgs.runCommandLocal "forecast-name" {
      nonce = builtins.currentTime;
    } "date -Iminutes | tr 'T\\-:' '---' | cut -d+ -f1 | tr -d '\n' > $out");
  in pkgs.runCommandLocal "forecast-${date}" rec {
    repo = builtins.getEnv "PWD";
    inputs = builtins.getEnv "ARGS";
    buildInputs = [ pkgs.git pkgs.nixUnstable pkgs.cacert ];
    PAGER = "cat";
    GIT_AUTHOR_NAME = "ci";
    GIT_AUTHOR_EMAIL = "nix@system";
    GIT_COMMITTER_NAME = "systemd";
    GIT_COMMITTER_EMAIL = "timer@service";
    __noChroot = true;
  } ''
    git clone $repo $out
    export NIX_REMOTE=local?real=$PWD/nix/store\&store=/nix/store
    export NIX_STATE_DIR=$PWD/nix/var NIX_LOG_DIR=$PWD/nix/var/log
    export HOME=$PWD
    cd $out
    git switch -c substrate live
    git commit-tree -m "merge: live" -p HEAD -p origin/live origin/live:
    git reset --hard origin/live
    for INPUT in $inputs; do
      nix flake update --update-input $INPUT \
        --experimental-features "nix-command flakes ca-references"
      git commit -m "flake(lock): autoupdate $INPUT" flake.lock
    done
  '';
};

hydraJobs = rec {
  deployment = forAllSystems ({ system, ... }:
    inputs.self.defaultPackage.${system}
  );
};

}; } #+END_SRC