From f6cd87b7544628f8947fb63907f6f5fee479c9cd Mon Sep 17 00:00:00 2001 From: Ben Sima Date: Fri, 14 Nov 2025 18:55:02 -0500 Subject: Tighten Nix source filtering to prevent spurious rebuilds Only include directories that are ancestors of source files in allSources. Previously accepted all directories, causing rebuilds when any new directory was added to the repo. Implementation: - Precompute normalized source paths and their ancestor directories - Filter directories against allowedDirs whitelist - Normalize paths in file filter for consistency - Keep existing skip list behavior for _ and .direnv This is optimization #2 from Phase 2 of the performance plan. --- Omni/Bild/Builder.nix | 49 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/Omni/Bild/Builder.nix b/Omni/Bild/Builder.nix index 6731185..2d311ff 100644 --- a/Omni/Bild/Builder.nix +++ b/Omni/Bild/Builder.nix @@ -32,20 +32,51 @@ with bild; let isEmpty = x: x == null || x == []; skip = ["_" ".direnv"]; + + # Normalize paths by removing leading "./" + normalize = p: lib.strings.removePrefix "./" p; + + # Given a list of path parts, produce all cumulative prefixes: + # ["a","b","c"] -> ["a","a/b","a/b/c"] + dirPrefixes = parts: + if parts == [] + then [] + else let + hd = lib.lists.head parts; + tl = lib.lists.tail parts; + rest = dirPrefixes tl; + in + [hd] ++ (lib.lists.map (r: "${hd}/${r}") rest); + + # Normalize all source file paths (relative to root) + allSourcesRel = lib.lists.map normalize allSources; + + # Allowed directories are the ancestors of all source files, plus the repo root "" + allowedDirs = lib.lists.unique ( + [""] + ++ lib.lists.concatMap + (p: let + parts = lib.strings.splitString "/" p; + in + dirPrefixes (lib.lists.init parts)) + allSourcesRel + ); + filter = file: type: if lib.lists.elem (builtins.baseNameOf file) skip then false - # TODO: this means any new directory will cause a rebuild. this bad. i - # should recurse into the directory and match against the srcs. for now I - # just use preBuild to delete empty dirs else if type == "directory" - then true + then let + rel = lib.strings.removePrefix "${root}/" file; + rel' = normalize rel; + in + lib.lists.elem rel' allowedDirs else if type == "regular" - then - lib.trivial.pipe file [ - (f: lib.strings.removePrefix "${root}/" f) - (f: lib.lists.elem f allSources) - ] + then let + rel = lib.strings.removePrefix "${root}/" file; + rel' = normalize rel; + in + lib.lists.elem rel' allSourcesRel else false; # remove empty directories, leftover from the src filter -- cgit v1.2.3