From e21c7895ebec83db0ae39231fba9b35b080b6b1e Mon Sep 17 00:00:00 2001 From: Philipp Otterbein Date: Mon, 7 Oct 2024 02:05:53 +0200 Subject: [PATCH] MacOS built: add workaround for missing view() member of std::ostringstream --- src/libcmd/repl.cc | 4 ++-- src/libexpr/eval.cc | 6 +++--- src/libexpr/primops.cc | 4 ++-- src/libexpr/primops/fromTOML.cc | 2 +- src/libexpr/print.cc | 2 +- src/libstore/daemon.cc | 2 +- src/libutil/strings.cc | 15 +++++++++++++++ src/libutil/strings.hh | 5 +++++ src/nix-build/nix-build.cc | 4 ++-- src/nix-env/user-env.cc | 2 +- src/nix/config-check.cc | 12 ++++++------ 11 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 1ae126e1e..018171889 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -645,7 +645,7 @@ ProcessLineResult NixRepl::processLine(std::string line) logger->cout(trim(renderMarkdownToTerminal(markdown))); } else if (fallbackPos) { - std::stringstream ss; + std::ostringstream ss; ss << "Attribute `" << fallbackName << "`\n\n"; ss << " … defined at " << state->positions[fallbackPos] << "\n\n"; if (fallbackDoc) { @@ -654,7 +654,7 @@ ProcessLineResult NixRepl::processLine(std::string line) ss << "No documentation found.\n\n"; } - auto markdown = ss.view(); + auto markdown = toView(ss); logger->cout(trim(renderMarkdownToTerminal(markdown))); } else diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 64516fd98..8fbba7c14 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -539,7 +539,7 @@ std::optional EvalState::getDoc(Value & v) if (v.isLambda()) { auto exprLambda = v.payload.lambda.fun; - std::stringstream s(std::ios_base::out); + std::ostringstream s(std::ios_base::out); std::string name; auto pos = positions[exprLambda->getPos()]; std::string docStr; @@ -578,7 +578,7 @@ std::optional EvalState::getDoc(Value & v) .name = name, .arity = 0, // FIXME: figure out how deep by syntax only? It's not semantically useful though... .args = {}, - .doc = makeImmutableString(s.view()), // NOTE: memory leak when compiled without GC + .doc = makeImmutableString(toView(s)), // NOTE: memory leak when compiled without GC }; } if (isFunctor(v)) { @@ -1804,7 +1804,7 @@ void ExprAssert::eval(EvalState & state, Env & env, Value & v) if (!state.evalBool(env, cond, pos, "in the condition of the assert statement")) { std::ostringstream out; cond->show(state.symbols, out); - auto exprStr = out.view(); + auto exprStr = toView(out); if (auto eq = dynamic_cast(cond)) { try { diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 29121bb81..a3c8a0c9c 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -2136,7 +2136,7 @@ static void prim_toXML(EvalState & state, const PosIdx pos, Value * * args, Valu std::ostringstream out; NixStringContext context; printValueAsXML(state, true, false, *args[0], out, context, pos); - v.mkString(out.view(), context); + v.mkString(toView(out), context); } static RegisterPrimOp primop_toXML({ @@ -2244,7 +2244,7 @@ static void prim_toJSON(EvalState & state, const PosIdx pos, Value * * args, Val std::ostringstream out; NixStringContext context; printValueAsJSON(state, true, *args[0], pos, out, context); - v.mkString(out.view(), context); + v.mkString(toView(out), context); } static RegisterPrimOp primop_toJSON({ diff --git a/src/libexpr/primops/fromTOML.cc b/src/libexpr/primops/fromTOML.cc index 15568e529..264046711 100644 --- a/src/libexpr/primops/fromTOML.cc +++ b/src/libexpr/primops/fromTOML.cc @@ -66,7 +66,7 @@ static void prim_fromTOML(EvalState & state, const PosIdx pos, Value * * args, V attrs.alloc("_type").mkString("timestamp"); std::ostringstream s; s << t; - attrs.alloc("value").mkString(s.view()); + attrs.alloc("value").mkString(toView(s)); v.mkAttrs(attrs); } else { throw std::runtime_error("Dates and times are not supported"); diff --git a/src/libexpr/print.cc b/src/libexpr/print.cc index 11a6c9161..d62aaf25f 100644 --- a/src/libexpr/print.cc +++ b/src/libexpr/print.cc @@ -460,7 +460,7 @@ private: std::ostringstream s; s << state.positions[v.payload.lambda.fun->pos]; - output << " @ " << filterANSIEscapes(s.view()); + output << " @ " << filterANSIEscapes(toView(s)); } } else if (v.isPrimOp()) { if (v.primOp()) diff --git a/src/libstore/daemon.cc b/src/libstore/daemon.cc index f0c3c866e..b921dbe2d 100644 --- a/src/libstore/daemon.cc +++ b/src/libstore/daemon.cc @@ -94,7 +94,7 @@ struct TunnelLogger : public Logger showErrorInfo(oss, ei, false); StringSink buf; - buf << STDERR_NEXT << oss.view(); + buf << STDERR_NEXT << toView(oss); enqueueMsg(buf.s); } diff --git a/src/libutil/strings.cc b/src/libutil/strings.cc index 5cad95758..d1c9f700c 100644 --- a/src/libutil/strings.cc +++ b/src/libutil/strings.cc @@ -6,6 +6,21 @@ namespace nix { +struct view_stringbuf : public std::stringbuf +{ + inline std::string_view toView() + { + auto begin = pbase(); + return {begin, begin + pubseekoff(0, std::ios_base::cur, std::ios_base::out)}; + } +}; + +std::string_view toView(const std::ostringstream & os) +{ + auto buf = static_cast(os.rdbuf()); + return buf->toView(); +} + template std::list tokenizeString(std::string_view s, std::string_view separators); template std::set tokenizeString(std::string_view s, std::string_view separators); template std::vector tokenizeString(std::string_view s, std::string_view separators); diff --git a/src/libutil/strings.hh b/src/libutil/strings.hh index 88b48d770..533126be1 100644 --- a/src/libutil/strings.hh +++ b/src/libutil/strings.hh @@ -8,6 +8,11 @@ namespace nix { +/* + * workaround for unavailable view() method (C++20) of std::ostringstream under MacOS with clang-16 + */ +std::string_view toView(const std::ostringstream & os); + /** * String tokenizer. * diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc index 8c52979f6..7d32a6f97 100644 --- a/src/nix-build/nix-build.cc +++ b/src/nix-build/nix-build.cc @@ -260,9 +260,9 @@ static void main_nix_build(int argc, char * * argv) // read the shebang to understand which packages to read from. Since // this is handled via nix-shell -p, we wrap our ruby script execution // in ruby -e 'load' which ignores the shebangs. - envCommand = fmt("exec %1% %2% -e 'load(ARGV.shift)' -- %3% %4%", execArgs, interpreter, shellEscape(script), joined.view()); + envCommand = fmt("exec %1% %2% -e 'load(ARGV.shift)' -- %3% %4%", execArgs, interpreter, shellEscape(script), toView(joined)); } else { - envCommand = fmt("exec %1% %2% %3% %4%", execArgs, interpreter, shellEscape(script), joined.view()); + envCommand = fmt("exec %1% %2% %3% %4%", execArgs, interpreter, shellEscape(script), toView(joined)); } } diff --git a/src/nix-env/user-env.cc b/src/nix-env/user-env.cc index ebd8ef42b..ee62077c0 100644 --- a/src/nix-env/user-env.cc +++ b/src/nix-env/user-env.cc @@ -111,7 +111,7 @@ bool createUserEnv(EvalState & state, PackageInfos & elems, auto manifestFile = ({ std::ostringstream str; printAmbiguous(manifest, state.symbols, str, nullptr, std::numeric_limits::max()); - StringSource source { str.view() }; + StringSource source { toView(str) }; state.store->addToStoreFromDump( source, "env-manifest.nix", FileSerialisationMethod::Flat, ContentAddressMethod::Raw::Text, HashAlgorithm::SHA256, references); }); diff --git a/src/nix/config-check.cc b/src/nix/config-check.cc index be252c3f1..a72b06542 100644 --- a/src/nix/config-check.cc +++ b/src/nix/config-check.cc @@ -87,11 +87,11 @@ struct CmdConfigCheck : StoreCommand } if (dirs.size() != 1) { - std::stringstream ss; + std::ostringstream ss; ss << "Multiple versions of nix found in PATH:\n"; for (auto & dir : dirs) ss << " " << dir << "\n"; - return checkFail(ss.view()); + return checkFail(toView(ss)); } return checkPass("PATH contains only one nix version."); @@ -125,14 +125,14 @@ struct CmdConfigCheck : StoreCommand } if (!dirs.empty()) { - std::stringstream ss; + std::ostringstream ss; ss << "Found profiles outside of " << settings.nixStateDir << "/profiles.\n" << "The generation this profile points to might not have a gcroot and could be\n" << "garbage collected, resulting in broken symlinks.\n\n"; for (auto & dir : dirs) ss << " " << dir << "\n"; ss << "\n"; - return checkFail(ss.view()); + return checkFail(toView(ss)); } return checkPass("All profiles are gcroots."); @@ -145,13 +145,13 @@ struct CmdConfigCheck : StoreCommand : PROTOCOL_VERSION; if (clientProto != storeProto) { - std::stringstream ss; + std::ostringstream ss; ss << "Warning: protocol version of this client does not match the store.\n" << "While this is not necessarily a problem it's recommended to keep the client in\n" << "sync with the daemon.\n\n" << "Client protocol: " << formatProtocol(clientProto) << "\n" << "Store protocol: " << formatProtocol(storeProto) << "\n\n"; - return checkFail(ss.view()); + return checkFail(toView(ss)); } return checkPass("Client protocol matches store protocol.");