nix flake check: Check hydraJobs

This commit is contained in:
Eelco Dolstra 2019-09-10 17:39:55 +02:00
parent 1f631ac85b
commit 55e55b34e6
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE

View file

@ -211,7 +211,7 @@ struct CmdFlakeInfo : FlakeCommand, MixJSON
auto provide = nlohmann::json::object(); auto provide = nlohmann::json::object();
if (name == "checks" || name == "packages") { if (name == "checks" || name == "packages") {
state->forceAttrs(vProvide); state->forceAttrs(vProvide, pos);
for (auto & aCheck : *vProvide.attrs) for (auto & aCheck : *vProvide.attrs)
provide[aCheck.name] = nlohmann::json::object(); provide[aCheck.name] = nlohmann::json::object();
} }
@ -282,7 +282,7 @@ struct CmdFlakeCheck : FlakeCommand, MixJSON
auto checkOverlay = [&](const std::string & attrPath, Value & v, const Pos & pos) { auto checkOverlay = [&](const std::string & attrPath, Value & v, const Pos & pos) {
try { try {
state->forceValue(v); state->forceValue(v, pos);
if (v.type != tLambda || v.lambda.fun->matchAttrs || std::string(v.lambda.fun->arg) != "final") if (v.type != tLambda || v.lambda.fun->matchAttrs || std::string(v.lambda.fun->arg) != "final")
throw Error("overlay does not take an argument named 'final'"); throw Error("overlay does not take an argument named 'final'");
auto body = dynamic_cast<ExprLambda *>(v.lambda.fun->body); auto body = dynamic_cast<ExprLambda *>(v.lambda.fun->body);
@ -298,14 +298,14 @@ struct CmdFlakeCheck : FlakeCommand, MixJSON
auto checkModule = [&](const std::string & attrPath, Value & v, const Pos & pos) { auto checkModule = [&](const std::string & attrPath, Value & v, const Pos & pos) {
try { try {
state->forceValue(v); state->forceValue(v, pos);
if (v.type == tLambda) { if (v.type == tLambda) {
if (!v.lambda.fun->matchAttrs || !v.lambda.fun->formals->ellipsis) if (!v.lambda.fun->matchAttrs || !v.lambda.fun->formals->ellipsis)
throw Error("module must match an open attribute set ('{ config, ... }')"); throw Error("module must match an open attribute set ('{ config, ... }')");
} else if (v.type == tAttrs) { } else if (v.type == tAttrs) {
for (auto & attr : *v.attrs) for (auto & attr : *v.attrs)
try { try {
state->forceValue(*attr.value); state->forceValue(*attr.value, *attr.pos);
} catch (Error & e) { } catch (Error & e) {
e.addPrefix(fmt("while evaluating the option '" ANSI_BOLD "%s" ANSI_NORMAL "' at %s:\n", attr.name, *attr.pos)); e.addPrefix(fmt("while evaluating the option '" ANSI_BOLD "%s" ANSI_NORMAL "' at %s:\n", attr.name, *attr.pos));
throw; throw;
@ -320,6 +320,28 @@ struct CmdFlakeCheck : FlakeCommand, MixJSON
} }
}; };
std::function<void(const std::string & attrPath, Value & v, const Pos & pos)> checkHydraJobs;
checkHydraJobs = [&](const std::string & attrPath, Value & v, const Pos & pos) {
try {
state->forceAttrs(v, pos);
if (state->isDerivation(v))
throw Error("jobset should not be a derivation at top-level");
for (auto & attr : *v.attrs) {
state->forceAttrs(*attr.value, *attr.pos);
if (!state->isDerivation(*attr.value))
checkHydraJobs(attrPath + "." + (std::string) attr.name,
*attr.value, *attr.pos);
}
} catch (Error & e) {
e.addPrefix(fmt("while checking the Hydra jobset '" ANSI_BOLD "%s" ANSI_NORMAL "' at %s:\n", attrPath, pos));
throw;
}
};
{ {
Activity act(*logger, lvlInfo, actUnknown, "evaluating flake"); Activity act(*logger, lvlInfo, actUnknown, "evaluating flake");
@ -333,24 +355,24 @@ struct CmdFlakeCheck : FlakeCommand, MixJSON
fmt("checking flake output '%s'", name)); fmt("checking flake output '%s'", name));
try { try {
state->forceValue(vOutput); state->forceValue(vOutput, pos);
if (name == "checks") { if (name == "checks") {
state->forceAttrs(vOutput); state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs) for (auto & attr : *vOutput.attrs)
drvPaths.insert(checkDerivation( drvPaths.insert(checkDerivation(
name + "." + (std::string) attr.name, *attr.value, *attr.pos)); name + "." + (std::string) attr.name, *attr.value, *attr.pos));
} }
else if (name == "packages") { else if (name == "packages") {
state->forceAttrs(vOutput); state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs) for (auto & attr : *vOutput.attrs)
checkDerivation( checkDerivation(
name + "." + (std::string) attr.name, *attr.value, *attr.pos); name + "." + (std::string) attr.name, *attr.value, *attr.pos);
} }
else if (name == "apps") { else if (name == "apps") {
state->forceAttrs(vOutput); state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs) for (auto & attr : *vOutput.attrs)
checkApp( checkApp(
name + "." + (std::string) attr.name, *attr.value, *attr.pos); name + "." + (std::string) attr.name, *attr.value, *attr.pos);
@ -370,7 +392,7 @@ struct CmdFlakeCheck : FlakeCommand, MixJSON
checkOverlay(name, vOutput, pos); checkOverlay(name, vOutput, pos);
else if (name == "overlays") { else if (name == "overlays") {
state->forceAttrs(vOutput); state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs) for (auto & attr : *vOutput.attrs)
checkOverlay(name + "." + (std::string) attr.name, checkOverlay(name + "." + (std::string) attr.name,
*attr.value, *attr.pos); *attr.value, *attr.pos);
@ -380,12 +402,15 @@ struct CmdFlakeCheck : FlakeCommand, MixJSON
checkModule(name, vOutput, pos); checkModule(name, vOutput, pos);
else if (name == "nixosModules") { else if (name == "nixosModules") {
state->forceAttrs(vOutput); state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs) for (auto & attr : *vOutput.attrs)
checkModule(name + "." + (std::string) attr.name, checkModule(name + "." + (std::string) attr.name,
*attr.value, *attr.pos); *attr.value, *attr.pos);
} }
else if (name == "hydraJobs")
checkHydraJobs(name, vOutput, pos);
else else
warn("unknown flake output '%s'", name); warn("unknown flake output '%s'", name);