From f00d720d83ec4c8531c69013c1948d7a3fea7ee9 Mon Sep 17 00:00:00 2001 From: Qyriad Date: Thu, 6 Nov 2025 12:11:52 +0100 Subject: [PATCH] libutil: refactor trace types and functions into their own file Change-Id: I00fba6b382991322a083bedeaf169eb5a86f5aeb --- lix/libutil/error-trace.cc | 50 ++++++++++++++++++++++++++++++++ lix/libutil/error-trace.hh | 57 ++++++++++++++++++++++++++++++++++++ lix/libutil/error.cc | 59 +------------------------------------- lix/libutil/error.hh | 47 +----------------------------- lix/libutil/meson.build | 2 ++ 5 files changed, 111 insertions(+), 104 deletions(-) create mode 100644 lix/libutil/error-trace.cc create mode 100644 lix/libutil/error-trace.hh diff --git a/lix/libutil/error-trace.cc b/lix/libutil/error-trace.cc new file mode 100644 index 000000000..7362e425e --- /dev/null +++ b/lix/libutil/error-trace.cc @@ -0,0 +1,50 @@ +#include "lix/libutil/error-trace.hh" +#include "lix/libutil/error.hh" +#include "lix/libutil/position.hh" + +namespace nix { + +Trace Trace::fromDrv(std::shared_ptr pos, std::string drvName) +{ + DrvTrace dt(drvName); + + HintFmt h( + "while evaluating derivation '%s'\n" + " whose name attribute is located at %s", + dt.drvName, + *pos + ); + + return Trace{ + .pos = pos, + .hint = h, + .drvTrace = dt, + }; +} + +Trace Trace::fromDrvAttr(std::shared_ptr pos, std::string drvName, std::string attrOfDrv) +{ + DrvTrace dt(drvName); + + HintFmt h("while evaluating attribute '%s' of derivation '%s'", attrOfDrv, dt.drvName); + + return Trace{ + .pos = pos, + .hint = h, + .drvTrace = dt, + }; +} + +std::partial_ordering operator<=>(Trace const & lhs, Trace const & rhs) +{ + // If either's position is nullptr, then we compare without dereferencing either. + if (!lhs.pos || !rhs.pos) { + return std::forward_as_tuple(lhs.pos != nullptr, lhs.hint.str()) + <=> std::forward_as_tuple(rhs.pos != nullptr, rhs.hint.str()); + } + + return std::forward_as_tuple(*lhs.pos, lhs.hint.str()) + <=> std::forward_as_tuple(*rhs.pos, rhs.hint.str()); +} + +} diff --git a/lix/libutil/error-trace.hh b/lix/libutil/error-trace.hh new file mode 100644 index 000000000..de660b681 --- /dev/null +++ b/lix/libutil/error-trace.hh @@ -0,0 +1,57 @@ +#pragma once +/** + * @file + */ + +#include +#include +#include +#include + +#include "lix/libutil/fmt.hh" + +namespace nix { + +struct Pos; + +/** @brief Information for a @ref Trace that encountered a derivation. + * + * This is used for summarizing the derivations involved in an eval error + * at the end of a trace-print. + */ +struct DrvTrace +{ + std::string drvName; + // TODO: include more structured information like "element 6 of nativeBuildInputs". + + DrvTrace() = delete; + + explicit DrvTrace(std::string drvName) : drvName(drvName) {} + + friend std::strong_ordering + operator<=>(DrvTrace const & lhs, DrvTrace const & rhs) noexcept = default; +}; + +struct Trace; + +struct Trace +{ + std::shared_ptr pos; + HintFmt hint; + std::optional drvTrace; + + /** Construct a Trace and canned format message assuming a derivation's + * position and name. + */ + static Trace fromDrv(std::shared_ptr pos, std::string drvName); + + /** Construct a Trace and canned format message assuming a derivation's + * position, name, and the attribute of that derivation which caused the + * trace. + */ + static Trace fromDrvAttr(std::shared_ptr pos, std::string drvName, std::string attrOfDrv); + + friend std::partial_ordering operator<=>(Trace const & lhs, Trace const & rhs); +}; + +} diff --git a/lix/libutil/error.cc b/lix/libutil/error.cc index 3c1fc2e5a..b90573d74 100644 --- a/lix/libutil/error.cc +++ b/lix/libutil/error.cc @@ -1,6 +1,7 @@ #include "lix/libutil/concepts.hh" #include "lix/libutil/environment-variables.hh" #include "lix/libutil/error.hh" +#include "lix/libutil/error-trace.hh" #include "lix/libutil/logging.hh" #include "lix/libutil/position.hh" #include "lix/libutil/terminal.hh" @@ -41,64 +42,6 @@ std::ostream & operator <<(std::ostream & os, const HintFmt & hf) return os << hf.str(); } -Trace Trace::fromDrv(std::shared_ptr pos, std::string drvName) -{ - DrvTrace dt(drvName); - - HintFmt h( - "while evaluating derivation '%s'\n" - " whose name attribute is located at %s", - dt.drvName, - *pos - ); - - return Trace{ - .pos = pos, - .hint = h, - .drvTrace = dt, - }; - -} - -Trace Trace::fromDrvAttr(std::shared_ptr pos, std::string drvName, std::string attrOfDrv) -{ - DrvTrace dt(drvName); - - HintFmt h("while evaluating attribute '%s' of derivation '%s'", attrOfDrv, dt.drvName); - - return Trace{ - .pos = pos, - .hint = h, - .drvTrace = dt, - }; - -} - -/** - * An arbitrarily defined value comparison for the purpose of using traces in the key of a sorted container. - */ -inline bool operator<(const Trace& lhs, const Trace& rhs) -{ - // `std::shared_ptr` does not have value semantics for its comparison - // functions, so we need to check for nulls and compare the dereferenced - // values here. - if (lhs.pos != rhs.pos) { - if (!lhs.pos) - return true; - if (!rhs.pos) - return false; - if (*lhs.pos != *rhs.pos) - return *lhs.pos < *rhs.pos; - } - // This formats a freshly formatted hint string and then throws it away, which - // shouldn't be much of a problem because it only runs when pos is equal, and this function is - // used for trace printing, which is infrequent. - return lhs.hint.str() < rhs.hint.str(); -} -inline bool operator> (const Trace& lhs, const Trace& rhs) { return rhs < lhs; } -inline bool operator<=(const Trace& lhs, const Trace& rhs) { return !(lhs > rhs); } -inline bool operator>=(const Trace& lhs, const Trace& rhs) { return !(lhs < rhs); } - // print lines of code to the ostream, indicating the error column. void printCodeLines(std::ostream & out, const std::string & prefix, diff --git a/lix/libutil/error.hh b/lix/libutil/error.hh index 9c2ca5ba7..f1b9c29a2 100644 --- a/lix/libutil/error.hh +++ b/lix/libutil/error.hh @@ -15,6 +15,7 @@ * See libutil/tests/logging.cc for usage examples. */ +#include "lix/libutil/error-trace.hh" #include "lix/libutil/json-fwd.hh" #include "lix/libutil/suggestions.hh" #include "lix/libutil/fmt.hh" @@ -67,52 +68,6 @@ void printCodeLines(std::ostream & out, const Pos & errPos, const LinesOfCode & loc); -/** @brief Information for a @ref Trace that encountered a derivation. - * - * This is used for summarizing the derivations involved in an eval error - * at the end of a trace-print. - */ -struct DrvTrace -{ - std::string drvName; - // TODO: include more structured information like "element 6 of nativeBuildInputs". - - DrvTrace() = delete; - - explicit DrvTrace(std::string drvName) : drvName(drvName) {} - - friend std::strong_ordering operator<=>(DrvTrace const & lhs, DrvTrace const & rhs) noexcept = default; -}; - -struct Trace; - -// n.b.: std::shared_ptr can't be dereferenced in this header, -// because we can't include position.hh without circular includes. -// Yay. -Trace traceFromDrv(std::shared_ptr pos, std::string drvName); - -struct Trace { - std::shared_ptr pos; - HintFmt hint; - std::optional drvTrace; - - /** Construct a Trace and canned format message assuming a derivation's - * position and name. - */ - static Trace fromDrv(std::shared_ptr pos, std::string drvName); - - /** Construct a Trace and canned format message assuming a derivation's - * position, name, and the attribute of that derivation which caused the - * trace. - */ - static Trace fromDrvAttr(std::shared_ptr pos, std::string drvName, std::string attrOfDrv); -}; - -inline bool operator<(const Trace& lhs, const Trace& rhs); -inline bool operator> (const Trace& lhs, const Trace& rhs); -inline bool operator<=(const Trace& lhs, const Trace& rhs); -inline bool operator>=(const Trace& lhs, const Trace& rhs); - struct ErrorInfo { Verbosity level = Verbosity::lvlError; HintFmt msg; diff --git a/lix/libutil/meson.build b/lix/libutil/meson.build index 7b4b033bd..1783a6f2c 100644 --- a/lix/libutil/meson.build +++ b/lix/libutil/meson.build @@ -13,6 +13,7 @@ libutil_sources = files( 'deprecated-features.cc', 'english.cc', 'environment-variables.cc', + 'error-trace.cc', 'error.cc', 'escape-char.cc', 'escape-string.cc', @@ -85,6 +86,7 @@ libutil_headers = files( 'deprecated-features.hh', 'english.hh', 'environment-variables.hh', + 'error-trace.hh', 'error.hh', 'escape-char.hh', 'escape-string.hh',