diff --git a/local.mk b/local.mk index 0a2254237..5c80451bd 100644 --- a/local.mk +++ b/local.mk @@ -3,7 +3,7 @@ ifeq ($(MAKECMDGOALS), dist) dist-files += $(shell git --git-dir=.git ls-files || find * -type f) endif -dist-files += configure config.h.in nix.spec perl/configure +dist-files += configure config.h.in nix.spec perl/configure src/nlohmann/json.hpp clean-files += Makefile.config diff --git a/release.nix b/release.nix index 834269ff7..40df200fd 100644 --- a/release.nix +++ b/release.nix @@ -43,6 +43,8 @@ let (cd perl ; autoreconf --install --force --verbose) # TeX needs a writable font cache. export VARTEXFONTS=$TMPDIR/texfonts + + cp -rv ${nlohmann_json}/include/nlohmann src/nlohmann ''; distPhase = diff --git a/shell.nix b/shell.nix index 435399f0b..2b4d0dd20 100644 --- a/shell.nix +++ b/shell.nix @@ -18,6 +18,7 @@ with import ./release-common.nix { inherit pkgs; }; customMemoryManagement = false; }) autoreconfHook + nlohmann_json # For nix-perl perl diff --git a/src/libstore/build.cc b/src/libstore/build.cc index fc039a8e5..3663c33b0 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -55,6 +55,8 @@ #include #endif +#include + namespace nix { @@ -839,6 +841,8 @@ private: std::unique_ptr act; + std::map builderActivities; + public: DerivationGoal(const Path & drvPath, const StringSet & wantedOutputs, Worker & worker, BuildMode buildMode = bmNormal); @@ -2390,6 +2394,34 @@ void setupSeccomp() } +struct BuilderLogger : Logger +{ + Logger & prevLogger; + + BuilderLogger(Logger & prevLogger) : prevLogger(prevLogger) { } + + void log(Verbosity lvl, const FormatOrString & fs) override + { + prevLogger.log(lvl, fs); + } + + void startActivity(ActivityId act, ActivityType type, const std::string & s) override + { + log(lvlError, fmt("@nix {\"action\": \"start\", \"id\": %d, \"type\": %d, \"text\": \"%s\"}", act, type, s)); + } + + void stopActivity(ActivityId act) override + { + log(lvlError, fmt("@nix {\"action\": \"stop\", \"id\": %d}", act)); + } + + void progress(ActivityId act, uint64_t done = 0, uint64_t expected = 0, uint64_t running = 0, uint64_t failed = 0) override + { + log(lvlError, fmt("@nix {\"action\": \"progress\", \"id\": %d, \"done\": %d, \"expected\": %d, \"running\": %d, \"failed\": %d}", act, done, expected, running, failed)); + } +}; + + void DerivationGoal::runChild() { /* Warning: in the child we should absolutely not make any SQLite @@ -2796,6 +2828,7 @@ void DerivationGoal::runChild() /* Execute the program. This should not return. */ if (drv->isBuiltin()) { try { + logger = new BuilderLogger(*logger); if (drv->builder == "builtin:fetchurl") builtinFetchurl(*drv, netrcData); else @@ -3250,14 +3283,47 @@ void DerivationGoal::handleEOF(int fd) void DerivationGoal::flushLine() { - if (settings.verboseBuild && - (settings.printRepeatedBuilds || curRound == 1)) - printError(filterANSIEscapes(currentLogLine, true)); - else { - logTail.push_back(currentLogLine); - if (logTail.size() > settings.logLines) logTail.pop_front(); + if (hasPrefix(currentLogLine, "@nix ")) { + + try { + auto json = nlohmann::json::parse(std::string(currentLogLine, 5)); + + std::string action = json["action"]; + + if (action == "start") { + auto type = (ActivityType) json["type"]; + if (type == actDownload) + builderActivities.emplace(std::piecewise_construct, + std::forward_as_tuple(json["id"]), + std::forward_as_tuple(*logger, type, json["text"])); + } + + else if (action == "stop") + builderActivities.erase((ActivityId) json["id"]); + + else if (action == "progress") { + auto i = builderActivities.find((ActivityId) json["id"]); + if (i != builderActivities.end()) + i->second.progress(json.value("done", 0), json.value("expected", 0), json.value("running", 0), json.value("failed", 0)); + } + + } catch (std::exception & e) { + printError("bad log message from builder: %s", e.what()); + } } - act->result(resBuildLogLine, currentLogLine); + + else { + if (settings.verboseBuild && + (settings.printRepeatedBuilds || curRound == 1)) + printError(filterANSIEscapes(currentLogLine, true)); + else { + logTail.push_back(currentLogLine); + if (logTail.size() > settings.logLines) logTail.pop_front(); + } + + act->result(resBuildLogLine, currentLogLine); + } + currentLogLine = ""; currentLogLinePos = 0; }