Skip to content

Instantly share code, notes, and snippets.

@Noah765
Last active July 26, 2024 11:12
Show Gist options
  • Select an option

  • Save Noah765/f03c3cb23ccdf70757ad2164a3a1b8e5 to your computer and use it in GitHub Desktop.

Select an option

Save Noah765/f03c3cb23ccdf70757ad2164a3a1b8e5 to your computer and use it in GitHub Desktop.
Debugging
{
prefix ? [],
specialArgs ? {},
modules ? [],
osModules ? [],
hmModules ? [],
}:
with specialArgs.inputs.nixpkgs.lib; let
inherit (specialArgs.inputs) nixpkgs home-manager;
inherit (nixpkgs) lib;
modifiedLib = import ./modified-lib.nix lib;
inherit (specialArgs) useHm;
inherit mkOption types;
osBaseModules = import "${nixpkgs}/nixos/modules/module-list.nix";
osExtraModules = let e = builtins.getEnv "NIXOS_EXTRA_MODULE_PATH"; in optional (e != "") (import e);
allOsModules = osBaseModules ++ osExtraModules ++ osModules;
osSpecialArgs =
{
modulesPath = "${nixpkgs}/nixos/modules";
baseModules = osBaseModules;
extraModules = osExtraModules;
modules = osModules;
}
// specialArgs;
evalOsModules = options:
evalModules {
class = "nixos";
specialArgs = osSpecialArgs;
modules =
allOsModules
++ [
(
let
osOptions =
(evalModules {
specialArgs = osSpecialArgs;
modules = allOsModules;
})
.options;
hmUsername = options.hmUsername.value;
# TODO Optional hm
hmOptions =
removeAttrs
(evalModules {
specialArgs.lib = import "${home-manager}/modules/lib/stdlib-extended.nix" lib;
modules =
osOptions.home-manager.users.type.getSubModules
++ [
{
_module.args.name = hmUsername;
home.stateVersion = options.os.value.home-manager.users.${hmUsername}.home.stateVersion;
}
];
})
.options ["_module" "nixpkgs"];
filtered =
osOptions
// {
nixpkgs = removeAttrs osOptions.nixpkgs ["pkgs"];
home-manager = osOptions.home-manager // {users.${hmUsername} = hmOptions;};
};
# Relying only on option.isDefined instead of also relying on the description doesn't work, because evaluating some defaults in the wrong circumstances will throw, e.g. networking.fqdn
filterOptions = options:
filterAttrsRecursive
(_: x: !isOption x || ((!hasPrefix "Alias of" x.description or "" || x.isDefined) && !x.readOnly or false))
(removeAttrs options ["_module"]);
mapOptions = options: config:
mapAttrsRecursiveCond (x: !isOption x) (path: option: let
currentConfig = getAttrFromPath path config;
in
if option.type.name == "submodule"
then mapOptions (filterOptions (option.type.getSubOptions [])) currentConfig
else if option.type.name == "attrsOf" && option.type.nestedTypes.elemType.name == "submodule"
then mapAttrs (name: mapOptions (filterOptions (evalModules {modules = option.type.getSubModules ++ [{_module.args.name = name;}];}).options)) currentConfig
else currentConfig)
options;
in
mapOptions (filterOptions filtered) options.os.value
)
];
};
evaluatedModules = modifiedLib.evalModules {
inherit prefix specialArgs;
class = "combinedManager";
modules =
[
(
{
options,
config,
...
}: {
options = {
inputs = mkOption {
type = with types; attrsOf raw;
default = {};
description = "Inputs";
};
hmUsername = mkOption {
type = types.str;
description = "Username used for Home Manager.";
};
osImports = mkOption {
type = with types; listOf raw;
default = [];
description = "NixOS modules.";
};
hmImports = mkOption {
type = with types; listOf raw;
default = [];
description = "Home Manager modules.";
};
os = mkOption {
# TODO Change type to deferredModule?
type = types.submoduleWith {
class = "nixos";
specialArgs = osSpecialArgs;
modules = allOsModules;
};
default = {};
visible = "shallow";
description = "NixOS configuration.";
};
hm = mkOption {
type = types.deferredModule;
default = {};
description = "Home Manager configuration.";
};
};
config = {
_module.args = {
pkgs =
(evalModules {
modules = [
"${nixpkgs}/nixos/modules/misc/nixpkgs.nix"
{nixpkgs = builtins.removeAttrs config.os.nixpkgs ["pkgs" "flake"];}
];
})
._module
.args
.pkgs;
osOptions = let
enhanceOption = _: option:
# TODO Support listOf, functionTo, and standalone submodules
if
(option.type.name == "attrsOf" || option.type.name == "lazyAttrsOf")
&& option.type.nestedTypes.elemType.name == "submodule"
then
option
// {
__functor = self: name:
mapAttrsRecursiveCond (x: !isOption x) enhanceOption
(evalModules {modules = [{_module.args.name = name;}] ++ self.type.getSubModules;}).options;
}
else option;
in
mapAttrsRecursiveCond (x: !isOption x) enhanceOption (evalOsModules options).options;
osConfig = config.os;
};
os = {
system.nixos.versionSuffix = ".${lib.substring 0 8 (nixpkgs.lastModifiedDate or nixpkgs.lastModified)}.${nixpkgs.shortRev or "dirty"}";
system.nixos.revision = lib.mkIf (nixpkgs ? rev) nixpkgs.rev;
};
};
}
)
"${nixpkgs}/nixos/modules/misc/assertions.nix"
(mkAliasOptionModule ["osModules"] ["osImports"])
]
++ optionals useHm [
(
{
osOptions,
config,
osConfig,
...
}: {
config = {
_module.args = {
hmOptions = osOptions.home-manager.users config.hmUsername;
hmConfig = osConfig.home-manager.users.${config.hmUsername};
};
os.home-manager = {
useGlobalPkgs = true;
useUserPackages = true;
extraSpecialArgs = specialArgs;
sharedModules = hmModules;
users.${config.hmUsername} = config.hm;
};
};
}
)
(mkAliasOptionModule ["hmModules"] ["hmImports"])
]
++ modules;
};
in {
combinedManager = evaluatedModules;
nixos = evalOsModules evaluatedModules.options;
}
{
useHomeManager ? true,
globalSpecialArgs ? {},
globalModules ? [],
globalOsModules ? [],
globalHmModules ? [],
configurations,
outputs ? (_: {}),
...
}: rawInputs:
with rawInputs.nixpkgs.lib; let
inherit (rawInputs.nixpkgs) lib;
modifiedLib = import ./modified-lib.nix lib;
evalModules = import ./eval-modules.nix;
evalModule = configs: config: let
inputs = rawInputs // config.inputOverrides or (_: {}) rawInputs;
modules = globalModules ++ config.modules or [];
configModules = modifiedLib.collectModules null "" modules {
inherit lib inputs;
options = null;
config = null;
};
findImports = name: alias: x:
if x ? ${name} || x ? ${alias}
then x.${name} or [] ++ x.${alias} or []
else if x ? content
then findImports name alias x.content
else if x ? contents
then lib.foldl (imports: x: imports ++ findImports name alias x) [] x.contents
else [];
configOsModules = lib.foldl (defs: module: defs ++ findImports "osImports" "osModules" module.config) [] configModules;
configHmModules = lib.foldl (defs: module: defs ++ findImports "hmImports" "hmModules" module.config) [] configModules;
useHm = config.useHomeManager or useHomeManager;
result = evalModules {
prefix = config.prefix or [];
specialArgs =
{
inherit inputs useHm configs;
combinedManager = import ../.;
combinedManagerPath = ../.;
}
// globalSpecialArgs
// config.specialArgs or {};
inherit modules;
osModules = globalOsModules ++ config.osModules or [] ++ configOsModules++ optional useHm inputs.home-manager.nixosModules.default;
hmModules = globalHmModules ++ config.hmModules or [] ++ configHmModules;
};
showWarnings = module:
foldl (
module: warning: builtins.trace "warning: ${warning}" module
)
module
module.config.warnings;
showErrors = module: let
failedAssertions = lists.map (x: x.message) (filter (x: !x.assertion) module.config.assertions);
in
if failedAssertions == []
then module
else
throw ''
Failed assertions:
${concatStringsSep "\n" (map (x: "- ${x}") failedAssertions)}'';
in {
combinedManager = showErrors (showWarnings result.combinedManager);
inherit (result) nixos; # TODO Errors and warnings?
};
explicitOutputs = outputs rawInputs;
combinedManagerConfigurations = let configs = mapAttrs (_: config: (evalModule configs config).combinedManager) configurations; in configs;
nixosConfigurations = let
withExtraAttrs = config:
config
// {
extraArgs = {};
inherit (config._module.args) pkgs;
inherit lib;
extendModules = args: withExtraAttrs (config.extendModules args);
};
configs = mapAttrs (_: config: withExtraAttrs (evalModule configs config).nixos) configurations;
in
configs;
in
explicitOutputs
// {
inherit combinedManagerConfigurations;
nixosConfigurations = nixosConfigurations // explicitOutputs.nixosConfigurations or {};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment