From e534a5e7affbe7f4e7714d2f72db36203fdf4217 Mon Sep 17 00:00:00 2001 From: Birdee <85372418+BirdeeHub@users.noreply.github.com> Date: Mon, 30 Mar 2026 01:52:46 -0700 Subject: [PATCH] feat(modules.constructFiles): auto-sanitize .key value to always be valid should make it easier to map multiple things to generated files --- lib/lib.nix | 38 +++++++++++++++++++++++++++++++ modules/constructFiles/module.nix | 35 ++++++++++++++++++++++------ 2 files changed, 66 insertions(+), 7 deletions(-) diff --git a/lib/lib.nix b/lib/lib.nix index 34c137f0..0291b0d0 100644 --- a/lib/lib.nix +++ b/lib/lib.nix @@ -682,6 +682,44 @@ in */ toKdl = import ./toKdl.nix { inherit lib wlib; }; + /** + Sanitize a string into a valid environment variable name. + + This function sanitizes all characters that are not allowed in typical + POSIX environment variable names (`[A-Za-z0-9_]`), and ensures the + resulting string starts with a valid leading character (`[A-Za-z_]`). + + Behavior: + - All invalid characters are replaced with underscore characters (`_`) + + Examples: + ``` + sanitizeEnvVarName "FOO-BAR" => "FOO_BAR" + sanitizeEnvVarName "123.abc" => "_23_abc" + sanitizeEnvVarName "!@#" => "___" + sanitizeEnvVarName "hello, world!" => "hello__world_" + ``` + + Notes: + - Only ASCII characters are considered; all other characters are removed + - This does not guarantee uniqueness across multiple inputs + */ + sanitizeEnvVarName = + s: + let + isUpper = c: c >= "A" && c <= "Z"; + isLower = c: c >= "a" && c <= "z"; + isDigit = c: c >= "0" && c <= "9"; + + valid = + i: c: + if i == 0 then + isUpper c || isLower c || c == "_" + else + isUpper c || isLower c || isDigit c || c == "_"; + in + lib.concatStrings (lib.imap0 (i: c: if valid i c then c else "_") (lib.stringToCharacters s)); + /** Placeholder value used when overriding a non-main field of a spec type. diff --git a/modules/constructFiles/module.nix b/modules/constructFiles/module.nix index 3518a961..4f598a2b 100644 --- a/modules/constructFiles/module.nix +++ b/modules/constructFiles/module.nix @@ -36,6 +36,7 @@ then that means you should set this value to something which is a valid shell variable name. ''; + apply = wlib.sanitizeEnvVarName; }; content = lib.mkOption { type = lib.types.lines; @@ -85,16 +86,36 @@ config.drv = lib.mkIf (config.constructFiles != { }) ( let files = builtins.attrValues config.constructFiles; + mkUnique = + attrs: base: + let + try = + i: + let + candidate = if i == null then base else "${base}_${toString i}"; + in + if attrs ? ${candidate} then try (if i == null then 0 else i + 1) else candidate; + in + try null; result = builtins.foldl' - (acc: v: { - attrs = acc.attrs // { - ${v.key} = v.content; - }; - passAsFile = acc.passAsFile ++ [ v.key ]; - }) + ( + acc: v: + let + key = mkUnique acc.attrs v.key; + in + { + attrs = acc.attrs // { + ${key} = v.content; + }; + passAsFile = acc.passAsFile ++ [ key ]; + } + ) { - attrs = { }; + attrs = { + # prevents something from being named this + passAsFile = [ ]; + }; passAsFile = [ ]; } files;