From 69bd805cc6eb7e000927a9ac3b6f3494bbddf418 Mon Sep 17 00:00:00 2001 From: Michael Raitza Date: Thu, 18 Feb 2021 21:06:02 +0100 Subject: [PATCH] Implement the getSrc combinator Allows the use of ${l.src ./foo ./bar} to generate a sparse source tree, used for the do script. This disects the source tree into those piece actually needed to build the target. - boosts clarity as all sources have to be explicitly specified - targets that don't use eachothers sources should be independent now --- builder.nix | 11 ++++---- lib.nix | 77 +++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 75 insertions(+), 13 deletions(-) diff --git a/builder.nix b/builder.nix index efb296f..f21961b 100644 --- a/builder.nix +++ b/builder.nix @@ -1,6 +1,6 @@ buildArgs@{ lib ? import ./lib.nix {}, nixpkgs ? , pkgs ? import nixpkgs {}, root, cwd, filter ? [] }: let - inherit (lib) searchPath whichdo d1 d2; + inherit (lib) searchPath whichdo d1 d2 getSrc; resolve = path: let builder = (whichdo path); @@ -11,15 +11,16 @@ let with pkgs.lib; with builtins; let - # Funktionalise pkgs; our main entry point to resolve default*nix build scripts. - getSrc = filterSource - (path: type: baseNameOf path != ".git" && baseNameOf path != ".envrc" && (all (x: path != x) filter)); + # CWD relative to source root rcwd = dirOf (removePrefix (root + "/") builder); + # Funktionalise pkgs; our main entry point to resolve default*nix build + # scripts. funcPkgs = { __functor = self: arg: resolve arg; - inherit pkgs getSrc cwd rcwd; + src = getSrc root rcwd filter; + inherit pkgs cwd rcwd; }; _builder = let diff --git a/lib.nix b/lib.nix index 6ac2697..c32aef8 100644 --- a/lib.nix +++ b/lib.nix @@ -1,8 +1,10 @@ { lib ? import }: let - inherit (builtins) baseNameOf dirOf length genList pathExists; - inherit (lib) take splitString concatStringsSep last foldl foldr head - tail singleton removePrefix hasSuffix removeSuffix flatten crossLists reverseList; + inherit (builtins) baseNameOf dirOf length genList pathExists filterSource + isString match replaceStrings; + inherit (lib) take splitString concatStringsSep last foldl foldr head tail + singleton removePrefix hasSuffix removeSuffix flatten crossLists reverseList + all any unique; butlast = list: take (length list - 1) list; doFileSuffix = "do"; @@ -14,16 +16,21 @@ let [ doFileSuffix ] (tail (splitString "." fn)))); + genPathlist = path: let + pathlist = (splitString "/" path); + foldedpaths = foldr (a: b: + let + h = if length b == 0 then "" else head b; + in [ (h + a + "/") ] ++ b) [] (tail (reverseList pathlist)); + in foldedpaths; + searchPath = path: let pathlist = (splitString "/" path); pat = (last pathlist); doFile = path + "." + doFileSuffix; patlist = genPatterns pat; - foldedpaths = foldr (a: b: - let - h = if length b == 0 then "" else head b; - in [ (h + a + "/") ] ++ b) [] (tail (reverseList pathlist)); + foldedpaths = genPathlist path; pths = crossLists (p: pat: p + pat) [ foldedpaths patlist ]; in [ doFile ] ++ pths; @@ -31,10 +38,13 @@ let pathlist = searchPath path; in foldl (res: p: if res == "" then if pathExists p then p else res else res) "" pathlist; + # Redo's $1, the full name of the target d1 = path: pat: let dir = (dirOf pat) + "/"; in removePrefix dir path; + # Redo's $2, the full name of the target or the name stripped by a suffix for + # a default.* target. d2 = path: pat: let dir = (dirOf pat) + "/"; _path = removePrefix dir path; @@ -42,8 +52,59 @@ let _out = removeSuffix _pat _path; in if _out == "" then _path else _out; + # The varargs capture combinator used by getSrc. + # Fuctions calling this are expected to supply a function treating one + # argument to the final function and a second function that operates on the + # whole list of arguments. Call the final function with literal null to + # trigger evaluation. + captureFunc = argFun: f: { + args = []; + __functor = self: a: let + _a = argFun a; + in if a == null + then f self.args + else self // { args = self.args ++ [ _a ]; }; + __toString = self: f self.args; + }; + + # Resolve a src given as string relative to cwd and root. + resolveSrc = root: rcwd: a: let + sanitize = s: let _s = replaceStrings [ "/./" ] ["/"] s; in if s != _s then sanitize _s else s; + _a = toString (/. + (root + "/" + rcwd + "/" + (sanitize a))); + in + if isString a then _a else toString a; + + # Add all preceding paths to a src down to the root. Otherwise + # builtins.filterSource will reject it. + augmentedSrcs = root: srcs: let + aug = map (s: singleton s ++ (map (p: root + (removeSuffix "/" p)) (genPathlist (removePrefix root s)))) srcs; + in unique (flatten aug); + + # The source tree resolver combinator. + # Takes the source root and cwd of the current builder and a list of paths + # that shall always be rejected. + # + # Returns a filter that accepts zero to n paths relative to cwd. Captures the + # whole source tree when called with zero arguments. + getSrc = root: rcwd: rejected: + captureFunc (resolveSrc root rcwd) (srcs: let + + rejector = path: (all (x: path != x) rejected); + _srcs = (augmentedSrcs root srcs); + srcFilter = path: if srcs == [] + then true # No explicit srcs means: Take the whole source tree! + else (any (x: path == x) _srcs); + filter = (path: type: + (baseNameOf path != ".git") && + (baseNameOf path != ".envrc") && + (rejector path) && + (srcFilter path)); + in (builtins.filterSource filter root)); + self = { - inherit searchPath doFileSuffix whichdo d1 d2; + inherit doFileSuffix whichdo d1 d2 getSrc; + # For testing. To be removed. + inherit searchPath augmentedSrcs genPathlist captureFunc; }; in self