From 4a57e917fd529ff940de2b217d7eaf39cec66fb8 Mon Sep 17 00:00:00 2001 From: Timothy DeHerrera Date: Tue, 27 Aug 2024 21:45:27 -0600 Subject: [PATCH 1/2] feat: trivial debug tracing information One of the best things about having a predictable module structure is that we can trivially construct error information. We can then use this to report unambiguously where we are in an Atom during evaluation. This makes debugging trivial, since if you fail anywhere in your code the debug trace (when enabled) will print the last location visited inside the module system before the error occurred. --- src/core/compose.nix | 39 +++++++++++++++++++++++++++------------ src/core/errors.nix | 20 ++++++++++++++++++++ 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/src/core/compose.nix b/src/core/compose.nix index b77ecda..a6d4e82 100644 --- a/src/core/compose.nix +++ b/src/core/compose.nix @@ -61,6 +61,7 @@ in config, extern ? { }, features ? [ ], + debug ? false, # internal features of the composer function stdFeatures ? src.stdToml.features.default or [ ], coreFeatures ? src.coreToml.features.default, @@ -70,7 +71,7 @@ in }: dir': let - dir = src.prepDir dir'; + par = src.prepDir dir'; std = src.readStd { features = stdFeatures; @@ -90,6 +91,12 @@ let }; }; + debugMsg = + path: + "in ${config.atom.name}${if config.atom ? version then "-${config.atom.version}" else ""}${ + if path == "" then "" else " at ${path}" + }"; + f = f: pre: dir: let @@ -153,13 +160,19 @@ let let path = src.path.make dir name; file = src.file.parse name; - member = l.path { inherit path name; }; + member = Import (l.path { inherit path name; }); module = src.path.make path "mod.nix"; in if type == "directory" && l.pathExists module then { ${name} = f ((src.lowerKeys self) // src.set.when preOpt) path; } else if type == "regular" && file.ext or null == "nix" && name != "mod.nix" then - { ${file.name} = Import member; } + { + ${file.name} = + let + trace = src.errors.modPath par dir; + in + src.errors.context debug (debugMsg "${trace}.${file.name}") member; + } else null # Ignore other file types ; @@ -169,14 +182,16 @@ let self = let path = src.path.make dir "mod.nix"; - module = l.path { - inherit path; - name = baseNameOf path; - }; - mod = Import module; + module = Import ( + l.path { + inherit path; + name = baseNameOf path; + } + ); + trace = src.errors.modPath par dir; in - assert src.modIsValid mod dir; - src.filterMap g contents // mod; + assert src.modIsValid module dir; + src.filterMap g contents // (src.errors.context debug (debugMsg trace) module); in if src.hasMod contents then @@ -187,12 +202,12 @@ let atom' = l.removeAttrs (extern // atom // { inherit extern; }) [ "atom" - (baseNameOf dir) + (baseNameOf par) ]; atom = let - fixed = src.fix f null dir; + fixed = src.fix f null par; in src.set.inject fixed [ ({ _if = __isStd__; } // src.pureBuiltinsForStd fixed) diff --git a/src/core/errors.nix b/src/core/errors.nix index a12b51d..b7d3062 100644 --- a/src/core/errors.nix +++ b/src/core/errors.nix @@ -18,6 +18,26 @@ let in { inherit warn; + + context = + debug: msg: value: + if debug then l.trace msg value else value; + modPath = + par: path: + let + + modFromDir = + path: l.concatStringsSep "." (l.tail (l.filter l.isString (l.split "/" (toString path)))); + stripParentDir = + p: p': + let + len = l.stringLength (toString p); + res = l.substring (len + 1) (-1) (toString p'); + in + /. + res; + + in + modFromDir (stripParentDir par path); import = abort "Importing arbitrary Nix files is forbidden. Declare your dependencies via the module system instead."; fetch = abort "Ad hoc fetching is illegal. Declare dependencies statically in the manifest instead."; system = abort "Accessing the current system is impure. Declare supported systems in the manifest."; From f94e53cbacf84960987a1e36f734ab38fc958474 Mon Sep 17 00:00:00 2001 From: Timothy DeHerrera Date: Thu, 26 Sep 2024 15:29:33 -0600 Subject: [PATCH 2/2] fix: use --trace-verbose Instead of having to keep track of a debug boolean, just use nix's builtin functionality to only show builtins.traceVerbose calls when --trace-verbose is passed on the nix cli. --- src/core/compose.nix | 11 +++-------- src/core/errors.nix | 10 +++++++--- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/core/compose.nix b/src/core/compose.nix index a6d4e82..f1e49bb 100644 --- a/src/core/compose.nix +++ b/src/core/compose.nix @@ -61,7 +61,6 @@ in config, extern ? { }, features ? [ ], - debug ? false, # internal features of the composer function stdFeatures ? src.stdToml.features.default or [ ], coreFeatures ? src.coreToml.features.default, @@ -91,11 +90,7 @@ let }; }; - debugMsg = - path: - "in ${config.atom.name}${if config.atom ? version then "-${config.atom.version}" else ""}${ - if path == "" then "" else " at ${path}" - }"; + msg = src.errors.debugMsg config; f = f: pre: dir: @@ -171,7 +166,7 @@ let let trace = src.errors.modPath par dir; in - src.errors.context debug (debugMsg "${trace}.${file.name}") member; + src.errors.context (msg "${trace}.${file.name}") member; } else null # Ignore other file types @@ -191,7 +186,7 @@ let trace = src.errors.modPath par dir; in assert src.modIsValid module dir; - src.filterMap g contents // (src.errors.context debug (debugMsg trace) module); + src.filterMap g contents // (src.errors.context (msg trace) module); in if src.hasMod contents then diff --git a/src/core/errors.nix b/src/core/errors.nix index b7d3062..ec5bd22 100644 --- a/src/core/errors.nix +++ b/src/core/errors.nix @@ -19,9 +19,13 @@ in { inherit warn; - context = - debug: msg: value: - if debug then l.trace msg value else value; + debugMsg = + config: path: + "in ${config.atom.name}${if config.atom ? version then "-${config.atom.version}" else ""}${ + if path == "" then "" else " at ${path}" + }"; + + context = msg: value: l.traceVerbose msg value; modPath = par: path: let