From cc1eaf53ae5e9f2c900437af941da8bd627354fc Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Fri, 6 Dec 2024 19:53:34 +0100 Subject: [PATCH] lib/values: fix submodule definition merging --- lib/values/default.nix | 42 +++++++++------- lib/values/test.nix | 50 +++++++++++++++++++ .../app/src/components/MachineListItem.tsx | 8 +-- .../app/src/routes/machines/details.tsx | 12 ++--- 4 files changed, 84 insertions(+), 28 deletions(-) diff --git a/lib/values/default.nix b/lib/values/default.nix index 05dcdebe1..8754d685c 100644 --- a/lib/values/default.nix +++ b/lib/values/default.nix @@ -23,11 +23,9 @@ let prio = { __prio = opt.highestPrio; }; - subOptions = opt.type.getSubOptions opt.loc; + filteredSubOptions = filterOptions (opt.type.getSubOptions opt.loc); - attrDefinitions = (lib.modules.mergeAttrDefinitionsWithPrio opt); - zipDefs = builtins.zipAttrsWith (_ns: vs: vs); - defs = zipDefs opt.definitions; + zipDefs = builtins.zipAttrsWith (_: vs: vs); prioPerValue = { type, defs }: @@ -35,7 +33,7 @@ let attrName: prioSet: let # Evaluate the submodule - options = filterOptions subOptions; + options = filteredSubOptions; modules = ( [ { inherit options; } @@ -48,7 +46,6 @@ let in (lib.optionalAttrs (prioSet ? highestPrio) { __prio = prioSet.highestPrio; - # inherit defs options; }) // ( if type.nestedTypes.elemType.name == "submodule" then @@ -64,21 +61,30 @@ let ) ); - attributePrios = prioPerValue { - type = opt.type; - inherit defs; - } attrDefinitions; + submodulePrios = + let + options = filteredSubOptions; + modules = ( + [ + { inherit options; } + ] + ++ opt.definitions + ); + submoduleEval = lib.evalModules { + inherit modules; + }; + in + getPrios { options = filterOptions submoduleEval.options; }; + in if opt ? type && opt.type.name == "submodule" then - prio // (getPrios { options = subOptions; }) + (prio) // submodulePrios else if opt ? type && opt.type.name == "attrsOf" then - # prio // attributePrios - # else if - # opt ? type && opt.type.name == "attrsOf" && opt.type.nestedTypes.elemType.name == "attrsOf" - # then - # prio // attributePrios - # else if opt ? type && opt.type.name == "attrsOf" then - prio // attributePrios + prio // ( + prioPerValue { + type = opt.type; + defs = zipDefs opt.definitions; + } (lib.modules.mergeAttrDefinitionsWithPrio opt)) else if opt ? type && opt._type == "option" then prio else diff --git a/lib/values/test.nix b/lib/values/test.nix index b18c85179..fd519fcc7 100644 --- a/lib/values/test.nix +++ b/lib/values/test.nix @@ -80,6 +80,56 @@ in }; }; + test_submodule_with_merging = + let + evaluated = ( + eval [ + { + options.foo = lib.mkOption { + type = lib.types.submodule { + options = { + normal = lib.mkOption { + type = lib.types.bool; + }; + default = lib.mkOption { + type = lib.types.bool; + }; + optionDefault = lib.mkOption { + type = lib.types.bool; + default = true; + }; + unset = lib.mkOption { + type = lib.types.bool; + }; + }; + }; + }; + } + { + foo.default = lib.mkDefault true; + } + { + foo.normal = false; + } + ] + ); + in + { + inherit evaluated; + expr = slib.getPrios { + options = evaluated.options; + }; + expected = { + foo = { + __prio = 100; + normal.__prio = 100; # Set via other module + default.__prio = 1000; + optionDefault.__prio = 1500; + unset.__prio = 9999; + }; + }; + }; + # TODO(@hsjobeki): Cover this edge case # test_freeform = # let diff --git a/pkgs/webview-ui/app/src/components/MachineListItem.tsx b/pkgs/webview-ui/app/src/components/MachineListItem.tsx index 2ebd2ba76..3d00ea0e2 100644 --- a/pkgs/webview-ui/app/src/components/MachineListItem.tsx +++ b/pkgs/webview-ui/app/src/components/MachineListItem.tsx @@ -40,7 +40,7 @@ export const MachineListItem = (props: MachineListItemProps) => { } if (!info?.deploy?.targetHost) { toast.error( - "Machine does not have a target host. Specify where the machine should be deployed." + "Machine does not have a target host. Specify where the machine should be deployed.", ); return; } @@ -63,7 +63,7 @@ export const MachineListItem = (props: MachineListItemProps) => { loading: "Installing...", success: "Installed", error: "Failed to install", - } + }, ); setInstalling(false); }; @@ -80,7 +80,7 @@ export const MachineListItem = (props: MachineListItemProps) => { } if (!info?.deploy.targetHost) { toast.error( - "Machine does not have a target host. Specify where the machine should be deployed." + "Machine does not have a target host. Specify where the machine should be deployed.", ); return; } @@ -101,7 +101,7 @@ export const MachineListItem = (props: MachineListItemProps) => { loading: "Updating...", success: "Updated", error: "Failed to update", - } + }, ); setUpdating(false); }; diff --git a/pkgs/webview-ui/app/src/routes/machines/details.tsx b/pkgs/webview-ui/app/src/routes/machines/details.tsx index 11c1298dd..edfa3d7c6 100644 --- a/pkgs/webview-ui/app/src/routes/machines/details.tsx +++ b/pkgs/webview-ui/app/src/routes/machines/details.tsx @@ -65,7 +65,7 @@ const InstallMachine = (props: InstallMachineProps) => { } const loading_toast = toast.loading( - "Installing machine. Grab coffee (15min)..." + "Installing machine. Grab coffee (15min)...", ); const r = await callApi("install_machine", { opts: { @@ -248,13 +248,13 @@ const MachineForm = (props: MachineDetailsProps) => { ...values.machine, // TODO: Remove this workaround tags: Array.from( - values.machine.tags || props.initialData.machine.tags || [] + values.machine.tags || props.initialData.machine.tags || [], ), }, }); if (machine_response.status === "error") { toast.error( - `Failed to set machine: ${machine_response.errors[0].message}` + `Failed to set machine: ${machine_response.errors[0].message}`, ); } if (machine_response.status === "success") { @@ -455,7 +455,7 @@ const MachineForm = (props: MachineDetailsProps) => { // disabled={!online()} onClick={() => { const modal = document.getElementById( - "install_modal" + "install_modal", ) as HTMLDialogElement | null; modal?.showModal(); }} @@ -561,7 +561,7 @@ function WifiModule(props: MachineWifiProps) { }); const [nets, setNets] = createSignal<1[]>( - new Array(props.initialData.length || 1).fill(1) + new Array(props.initialData.length || 1).fill(1), ); const handleSubmit = async (values: WifiForm) => { @@ -572,7 +572,7 @@ function WifiModule(props: MachineWifiProps) { ...acc, [curr.ssid || ""]: { ssid: curr.ssid, password: curr.password }, }), - {} + {}, ); console.log("submitting", values, networks);