forked from lix-project/nix-eval-jobs
split nix-eval-jobs further into smaller files
This commit is contained in:
parent
880c66a7d1
commit
a03f039a56
52
src/buffered-io.cc
Normal file
52
src/buffered-io.cc
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
#include "buffered-io.hh"
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <nix/signals.hh>
|
||||||
|
|
||||||
|
[[nodiscard]] int tryWriteLine(int fd, std::string s) {
|
||||||
|
s += "\n";
|
||||||
|
std::string_view sv{s};
|
||||||
|
while (!sv.empty()) {
|
||||||
|
nix::checkInterrupt();
|
||||||
|
ssize_t res = write(fd, sv.data(), sv.size());
|
||||||
|
if (res == -1 && errno != EINTR) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
if (res > 0) {
|
||||||
|
sv.remove_prefix(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LineReader::LineReader(int fd) {
|
||||||
|
stream = fdopen(fd, "r");
|
||||||
|
if (!stream) {
|
||||||
|
throw nix::Error("fdopen failed: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LineReader::~LineReader() {
|
||||||
|
fclose(stream);
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
LineReader::LineReader(LineReader &&other) {
|
||||||
|
stream = other.stream;
|
||||||
|
other.stream = nullptr;
|
||||||
|
buffer = other.buffer;
|
||||||
|
other.buffer = nullptr;
|
||||||
|
len = other.len;
|
||||||
|
other.len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::string_view LineReader::readLine() {
|
||||||
|
ssize_t read = getline(&buffer, &len, stream);
|
||||||
|
|
||||||
|
if (read == -1) {
|
||||||
|
return {}; // Return an empty string_view in case of error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove trailing newline
|
||||||
|
return std::string_view(buffer, read - 1);
|
||||||
|
}
|
20
src/buffered-io.hh
Normal file
20
src/buffered-io.hh
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#pragma once
|
||||||
|
#include <cstdio>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
[[nodiscard]] int tryWriteLine(int fd, std::string s);
|
||||||
|
|
||||||
|
class LineReader {
|
||||||
|
public:
|
||||||
|
LineReader(int fd);
|
||||||
|
~LineReader();
|
||||||
|
|
||||||
|
LineReader(LineReader &&other);
|
||||||
|
[[nodiscard]] std::string_view readLine();
|
||||||
|
|
||||||
|
private:
|
||||||
|
FILE *stream = nullptr;
|
||||||
|
char *buffer = nullptr;
|
||||||
|
size_t len = 0;
|
||||||
|
};
|
|
@ -1,4 +1,4 @@
|
||||||
#include "drvs.hh"
|
#include "drv.hh"
|
||||||
#include <nix/config.h>
|
#include <nix/config.h>
|
||||||
#include <nix/path-with-outputs.hh>
|
#include <nix/path-with-outputs.hh>
|
||||||
#include <nix/store-api.hh>
|
#include <nix/store-api.hh>
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
src = [
|
src = [
|
||||||
'nix-eval-jobs.cc',
|
'nix-eval-jobs.cc',
|
||||||
'eval-args.cc',
|
'eval-args.cc',
|
||||||
'drv.cc'
|
'drv.cc',
|
||||||
|
'buffered-io.cc',
|
||||||
|
'worker.cc'
|
||||||
]
|
]
|
||||||
|
|
||||||
executable('nix-eval-jobs', src,
|
executable('nix-eval-jobs', src,
|
||||||
|
|
|
@ -9,19 +9,18 @@
|
||||||
|
|
||||||
#include <nix/shared.hh>
|
#include <nix/shared.hh>
|
||||||
#include <nix/sync.hh>
|
#include <nix/sync.hh>
|
||||||
#include <nix/terminal.hh>
|
|
||||||
#include <nix/eval.hh>
|
#include <nix/eval.hh>
|
||||||
#include <nix/local-fs-store.hh>
|
|
||||||
#include <nix/installable-flake.hh>
|
|
||||||
#include <nix/get-drvs.hh>
|
#include <nix/get-drvs.hh>
|
||||||
#include <nix/attr-path.hh>
|
|
||||||
#include <nix/value-to-json.hh>
|
#include <nix/value-to-json.hh>
|
||||||
|
#include <nix/local-fs-store.hh>
|
||||||
#include <nix/signals.hh>
|
#include <nix/signals.hh>
|
||||||
|
#include <nix/terminal.hh>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/resource.h>
|
|
||||||
|
|
||||||
#include "eval-args.hh"
|
#include "eval-args.hh"
|
||||||
#include "drv.hh"
|
#include "drv.hh"
|
||||||
|
#include "buffered-io.hh"
|
||||||
|
#include "worker.hh"
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
@ -36,224 +35,8 @@ using namespace nlohmann;
|
||||||
#endif
|
#endif
|
||||||
static MyArgs myArgs;
|
static MyArgs myArgs;
|
||||||
|
|
||||||
static Value *releaseExprTopLevelValue(EvalState &state, Bindings &autoArgs) {
|
|
||||||
Value vTop;
|
|
||||||
|
|
||||||
if (myArgs.fromArgs) {
|
|
||||||
Expr *e = state.parseExprFromString(
|
|
||||||
myArgs.releaseExpr, state.rootPath(CanonPath::fromCwd()));
|
|
||||||
state.eval(e, vTop);
|
|
||||||
} else {
|
|
||||||
state.evalFile(lookupFileArg(state, myArgs.releaseExpr), vTop);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto vRoot = state.allocValue();
|
|
||||||
|
|
||||||
state.autoCallFunction(autoArgs, vTop, *vRoot);
|
|
||||||
|
|
||||||
return vRoot;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::string attrPathJoin(json input) {
|
|
||||||
return std::accumulate(input.begin(), input.end(), std::string(),
|
|
||||||
[](std::string ss, std::string s) {
|
|
||||||
// Escape token if containing dots
|
|
||||||
if (s.find(".") != std::string::npos) {
|
|
||||||
s = "\"" + s + "\"";
|
|
||||||
}
|
|
||||||
return ss.empty() ? s : ss + "." + s;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] static int tryWriteLine(int fd, std::string s) {
|
|
||||||
s += "\n";
|
|
||||||
std::string_view sv{s};
|
|
||||||
while (!sv.empty()) {
|
|
||||||
checkInterrupt();
|
|
||||||
ssize_t res = write(fd, sv.data(), sv.size());
|
|
||||||
if (res == -1 && errno != EINTR) {
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
if (res > 0) {
|
|
||||||
sv.remove_prefix(res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
class LineReader {
|
|
||||||
public:
|
|
||||||
LineReader(int fd) {
|
|
||||||
stream = fdopen(fd, "r");
|
|
||||||
if (!stream) {
|
|
||||||
throw Error("fdopen failed: %s", strerror(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~LineReader() {
|
|
||||||
fclose(stream);
|
|
||||||
free(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
LineReader(LineReader &&other) {
|
|
||||||
stream = other.stream;
|
|
||||||
other.stream = nullptr;
|
|
||||||
buffer = other.buffer;
|
|
||||||
other.buffer = nullptr;
|
|
||||||
len = other.len;
|
|
||||||
other.len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] std::string_view readLine() {
|
|
||||||
ssize_t read = getline(&buffer, &len, stream);
|
|
||||||
|
|
||||||
if (read == -1) {
|
|
||||||
return {}; // Return an empty string_view in case of error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove trailing newline
|
|
||||||
return std::string_view(buffer, read - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
FILE *stream = nullptr;
|
|
||||||
char *buffer = nullptr;
|
|
||||||
size_t len = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void worker(ref<EvalState> state, Bindings &autoArgs, AutoCloseFD &to,
|
|
||||||
AutoCloseFD &from) {
|
|
||||||
|
|
||||||
nix::Value *vRoot = [&]() {
|
|
||||||
if (myArgs.flake) {
|
|
||||||
auto [flakeRef, fragment, outputSpec] =
|
|
||||||
parseFlakeRefWithFragmentAndExtendedOutputsSpec(
|
|
||||||
myArgs.releaseExpr, absPath("."));
|
|
||||||
InstallableFlake flake{
|
|
||||||
{}, state, std::move(flakeRef), fragment, outputSpec,
|
|
||||||
{}, {}, myArgs.lockFlags};
|
|
||||||
|
|
||||||
return flake.toValue(*state).first;
|
|
||||||
} else {
|
|
||||||
return releaseExprTopLevelValue(*state, autoArgs);
|
|
||||||
}
|
|
||||||
}();
|
|
||||||
|
|
||||||
LineReader fromReader(from.release());
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
/* Wait for the collector to send us a job name. */
|
|
||||||
if (tryWriteLine(to.get(), "next") < 0) {
|
|
||||||
return; // main process died
|
|
||||||
}
|
|
||||||
|
|
||||||
auto s = fromReader.readLine();
|
|
||||||
if (s == "exit") {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!hasPrefix(s, "do ")) {
|
|
||||||
fprintf(stderr, "worker error: received invalid command '%s'\n",
|
|
||||||
s.data());
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
auto path = json::parse(s.substr(3));
|
|
||||||
auto attrPathS = attrPathJoin(path);
|
|
||||||
|
|
||||||
debug("worker process %d at '%s'", getpid(), path);
|
|
||||||
|
|
||||||
/* Evaluate it and send info back to the collector. */
|
|
||||||
json reply = json{{"attr", attrPathS}, {"attrPath", path}};
|
|
||||||
try {
|
|
||||||
auto vTmp =
|
|
||||||
findAlongAttrPath(*state, attrPathS, autoArgs, *vRoot).first;
|
|
||||||
|
|
||||||
auto v = state->allocValue();
|
|
||||||
state->autoCallFunction(autoArgs, *vTmp, *v);
|
|
||||||
|
|
||||||
if (v->type() == nAttrs) {
|
|
||||||
if (auto drvInfo = getDerivation(*state, *v, false)) {
|
|
||||||
auto drv = Drv(attrPathS, *state, *drvInfo, myArgs);
|
|
||||||
reply.update(drv);
|
|
||||||
|
|
||||||
/* Register the derivation as a GC root. !!! This
|
|
||||||
registers roots for jobs that we may have already
|
|
||||||
done. */
|
|
||||||
if (myArgs.gcRootsDir != "") {
|
|
||||||
Path root = myArgs.gcRootsDir + "/" +
|
|
||||||
std::string(baseNameOf(drv.drvPath));
|
|
||||||
if (!pathExists(root)) {
|
|
||||||
auto localStore =
|
|
||||||
state->store
|
|
||||||
.dynamic_pointer_cast<LocalFSStore>();
|
|
||||||
auto storePath =
|
|
||||||
localStore->parseStorePath(drv.drvPath);
|
|
||||||
localStore->addPermRoot(storePath, root);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
auto attrs = nlohmann::json::array();
|
|
||||||
bool recurse =
|
|
||||||
myArgs.forceRecurse ||
|
|
||||||
path.size() == 0; // Dont require `recurseForDerivations
|
|
||||||
// = true;` for top-level attrset
|
|
||||||
|
|
||||||
for (auto &i :
|
|
||||||
v->attrs->lexicographicOrder(state->symbols)) {
|
|
||||||
const std::string &name = state->symbols[i->name];
|
|
||||||
attrs.push_back(name);
|
|
||||||
|
|
||||||
if (name == "recurseForDerivations" &&
|
|
||||||
!myArgs.forceRecurse) {
|
|
||||||
auto attrv =
|
|
||||||
v->attrs->get(state->sRecurseForDerivations);
|
|
||||||
recurse = state->forceBool(
|
|
||||||
*attrv->value, attrv->pos,
|
|
||||||
"while evaluating recurseForDerivations");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (recurse)
|
|
||||||
reply["attrs"] = std::move(attrs);
|
|
||||||
else
|
|
||||||
reply["attrs"] = nlohmann::json::array();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// We ignore everything that cannot be build
|
|
||||||
reply["attrs"] = nlohmann::json::array();
|
|
||||||
}
|
|
||||||
} catch (EvalError &e) {
|
|
||||||
auto err = e.info();
|
|
||||||
std::ostringstream oss;
|
|
||||||
showErrorInfo(oss, err, loggerSettings.showTrace.get());
|
|
||||||
auto msg = oss.str();
|
|
||||||
|
|
||||||
// Transmits the error we got from the previous evaluation
|
|
||||||
// in the JSON output.
|
|
||||||
reply["error"] = filterANSIEscapes(msg, true);
|
|
||||||
// Don't forget to print it into the STDERR log, this is
|
|
||||||
// what's shown in the Hydra UI.
|
|
||||||
printError(e.msg());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tryWriteLine(to.get(), reply.dump()) < 0) {
|
|
||||||
return; // main process died
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If our RSS exceeds the maximum, exit. The collector will
|
|
||||||
start a new process. */
|
|
||||||
struct rusage r;
|
|
||||||
getrusage(RUSAGE_SELF, &r);
|
|
||||||
if ((size_t)r.ru_maxrss > myArgs.maxMemorySize * 1024)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tryWriteLine(to.get(), "restart") < 0) {
|
|
||||||
return; // main process died
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef std::function<void(ref<EvalState> state, Bindings &autoArgs,
|
typedef std::function<void(ref<EvalState> state, Bindings &autoArgs,
|
||||||
AutoCloseFD &to, AutoCloseFD &from)>
|
AutoCloseFD &to, AutoCloseFD &from, MyArgs &args)>
|
||||||
Processor;
|
Processor;
|
||||||
|
|
||||||
/* Auto-cleanup of fork's process and fds. */
|
/* Auto-cleanup of fork's process and fds. */
|
||||||
|
@ -275,11 +58,11 @@ struct Proc {
|
||||||
auto state = std::make_shared<EvalState>(
|
auto state = std::make_shared<EvalState>(
|
||||||
myArgs.searchPath, openStore(*myArgs.evalStoreUrl));
|
myArgs.searchPath, openStore(*myArgs.evalStoreUrl));
|
||||||
Bindings &autoArgs = *myArgs.getAutoArgs(*state);
|
Bindings &autoArgs = *myArgs.getAutoArgs(*state);
|
||||||
proc(ref<EvalState>(state), autoArgs, *to, *from);
|
proc(ref<EvalState>(state), autoArgs, *to, *from, myArgs);
|
||||||
} catch (Error &e) {
|
} catch (Error &e) {
|
||||||
nlohmann::json err;
|
nlohmann::json err;
|
||||||
auto msg = e.msg();
|
auto msg = e.msg();
|
||||||
err["error"] = filterANSIEscapes(msg, true);
|
err["error"] = nix::filterANSIEscapes(msg, true);
|
||||||
printError(msg);
|
printError(msg);
|
||||||
if (tryWriteLine(to->get(), err.dump()) < 0) {
|
if (tryWriteLine(to->get(), err.dump()) < 0) {
|
||||||
return; // main process died
|
return; // main process died
|
||||||
|
|
173
src/worker.cc
Normal file
173
src/worker.cc
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
#include "worker.hh"
|
||||||
|
#include "drv.hh"
|
||||||
|
#include "buffered-io.hh"
|
||||||
|
|
||||||
|
#include <nix/terminal.hh>
|
||||||
|
#include <nix/attr-path.hh>
|
||||||
|
#include <nix/local-fs-store.hh>
|
||||||
|
#include <nix/installable-flake.hh>
|
||||||
|
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
static nix::Value *releaseExprTopLevelValue(nix::EvalState &state,
|
||||||
|
nix::Bindings &autoArgs,
|
||||||
|
MyArgs &args) {
|
||||||
|
nix::Value vTop;
|
||||||
|
|
||||||
|
if (args.fromArgs) {
|
||||||
|
nix::Expr *e = state.parseExprFromString(
|
||||||
|
args.releaseExpr, state.rootPath(nix::CanonPath::fromCwd()));
|
||||||
|
state.eval(e, vTop);
|
||||||
|
} else {
|
||||||
|
state.evalFile(lookupFileArg(state, args.releaseExpr), vTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto vRoot = state.allocValue();
|
||||||
|
|
||||||
|
state.autoCallFunction(autoArgs, vTop, *vRoot);
|
||||||
|
|
||||||
|
return vRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string attrPathJoin(nlohmann::json input) {
|
||||||
|
return std::accumulate(input.begin(), input.end(), std::string(),
|
||||||
|
[](std::string ss, std::string s) {
|
||||||
|
// Escape token if containing dots
|
||||||
|
if (s.find(".") != std::string::npos) {
|
||||||
|
s = "\"" + s + "\"";
|
||||||
|
}
|
||||||
|
return ss.empty() ? s : ss + "." + s;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void worker(nix::ref<nix::EvalState> state, nix::Bindings &autoArgs,
|
||||||
|
nix::AutoCloseFD &to, nix::AutoCloseFD &from, MyArgs &args) {
|
||||||
|
|
||||||
|
nix::Value *vRoot = [&]() {
|
||||||
|
if (args.flake) {
|
||||||
|
auto [flakeRef, fragment, outputSpec] =
|
||||||
|
nix::parseFlakeRefWithFragmentAndExtendedOutputsSpec(
|
||||||
|
args.releaseExpr, nix::absPath("."));
|
||||||
|
nix::InstallableFlake flake{
|
||||||
|
{}, state, std::move(flakeRef), fragment, outputSpec,
|
||||||
|
{}, {}, args.lockFlags};
|
||||||
|
|
||||||
|
return flake.toValue(*state).first;
|
||||||
|
} else {
|
||||||
|
return releaseExprTopLevelValue(*state, autoArgs, args);
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
LineReader fromReader(from.release());
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
/* Wait for the collector to send us a job name. */
|
||||||
|
if (tryWriteLine(to.get(), "next") < 0) {
|
||||||
|
return; // main process died
|
||||||
|
}
|
||||||
|
|
||||||
|
auto s = fromReader.readLine();
|
||||||
|
if (s == "exit") {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!nix::hasPrefix(s, "do ")) {
|
||||||
|
fprintf(stderr, "worker error: received invalid command '%s'\n",
|
||||||
|
s.data());
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
auto path = nlohmann::json::parse(s.substr(3));
|
||||||
|
auto attrPathS = attrPathJoin(path);
|
||||||
|
|
||||||
|
/* Evaluate it and send info back to the collector. */
|
||||||
|
nlohmann::json reply =
|
||||||
|
nlohmann::json{{"attr", attrPathS}, {"attrPath", path}};
|
||||||
|
try {
|
||||||
|
auto vTmp =
|
||||||
|
nix::findAlongAttrPath(*state, attrPathS, autoArgs, *vRoot)
|
||||||
|
.first;
|
||||||
|
|
||||||
|
auto v = state->allocValue();
|
||||||
|
state->autoCallFunction(autoArgs, *vTmp, *v);
|
||||||
|
|
||||||
|
if (v->type() == nix::nAttrs) {
|
||||||
|
if (auto drvInfo = nix::getDerivation(*state, *v, false)) {
|
||||||
|
auto drv = Drv(attrPathS, *state, *drvInfo, args);
|
||||||
|
reply.update(drv);
|
||||||
|
|
||||||
|
/* Register the derivation as a GC root. !!! This
|
||||||
|
registers roots for jobs that we may have already
|
||||||
|
done. */
|
||||||
|
if (args.gcRootsDir != "") {
|
||||||
|
nix::Path root =
|
||||||
|
args.gcRootsDir + "/" +
|
||||||
|
std::string(nix::baseNameOf(drv.drvPath));
|
||||||
|
if (!nix::pathExists(root)) {
|
||||||
|
auto localStore =
|
||||||
|
state->store
|
||||||
|
.dynamic_pointer_cast<nix::LocalFSStore>();
|
||||||
|
auto storePath =
|
||||||
|
localStore->parseStorePath(drv.drvPath);
|
||||||
|
localStore->addPermRoot(storePath, root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto attrs = nlohmann::json::array();
|
||||||
|
bool recurse =
|
||||||
|
args.forceRecurse ||
|
||||||
|
path.size() == 0; // Dont require `recurseForDerivations
|
||||||
|
// = true;` for top-level attrset
|
||||||
|
|
||||||
|
for (auto &i :
|
||||||
|
v->attrs->lexicographicOrder(state->symbols)) {
|
||||||
|
const std::string &name = state->symbols[i->name];
|
||||||
|
attrs.push_back(name);
|
||||||
|
|
||||||
|
if (name == "recurseForDerivations" &&
|
||||||
|
!args.forceRecurse) {
|
||||||
|
auto attrv =
|
||||||
|
v->attrs->get(state->sRecurseForDerivations);
|
||||||
|
recurse = state->forceBool(
|
||||||
|
*attrv->value, attrv->pos,
|
||||||
|
"while evaluating recurseForDerivations");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (recurse)
|
||||||
|
reply["attrs"] = std::move(attrs);
|
||||||
|
else
|
||||||
|
reply["attrs"] = nlohmann::json::array();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// We ignore everything that cannot be build
|
||||||
|
reply["attrs"] = nlohmann::json::array();
|
||||||
|
}
|
||||||
|
} catch (nix::EvalError &e) {
|
||||||
|
auto err = e.info();
|
||||||
|
std::ostringstream oss;
|
||||||
|
nix::showErrorInfo(oss, err, nix::loggerSettings.showTrace.get());
|
||||||
|
auto msg = oss.str();
|
||||||
|
|
||||||
|
// Transmits the error we got from the previous evaluation
|
||||||
|
// in the JSON output.
|
||||||
|
reply["error"] = nix::filterANSIEscapes(msg, true);
|
||||||
|
// Don't forget to print it into the STDERR log, this is
|
||||||
|
// what's shown in the Hydra UI.
|
||||||
|
fprintf(stderr, "%s\n", msg.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tryWriteLine(to.get(), reply.dump()) < 0) {
|
||||||
|
return; // main process died
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If our RSS exceeds the maximum, exit. The collector will
|
||||||
|
start a new process. */
|
||||||
|
struct rusage r;
|
||||||
|
getrusage(RUSAGE_SELF, &r);
|
||||||
|
if ((size_t)r.ru_maxrss > args.maxMemorySize * 1024)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tryWriteLine(to.get(), "restart") < 0) {
|
||||||
|
return; // main process died
|
||||||
|
};
|
||||||
|
}
|
9
src/worker.hh
Normal file
9
src/worker.hh
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#pragma once
|
||||||
|
#include <nix/config.h>
|
||||||
|
#include <nix/shared.hh>
|
||||||
|
#include <nix/eval.hh>
|
||||||
|
|
||||||
|
#include "eval-args.hh"
|
||||||
|
|
||||||
|
void worker(nix::ref<nix::EvalState> state, nix::Bindings &autoArgs,
|
||||||
|
nix::AutoCloseFD &to, nix::AutoCloseFD &from, MyArgs &args);
|
Loading…
Reference in a new issue