nix flake check: Check apps

This commit is contained in:
Eelco Dolstra 2019-06-17 17:59:57 +02:00
parent 3b2ebd029c
commit 9d1207c02c
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
4 changed files with 47 additions and 21 deletions

View file

@ -51,21 +51,20 @@ void EvalState::realiseContext(const PathSet & context)
PathSet drvs; PathSet drvs;
for (auto & i : context) { for (auto & i : context) {
std::pair<string, string> decoded = decodeContext(i); auto [ctx, outputName] = decodeContext(i);
Path ctx = decoded.first;
assert(store->isStorePath(ctx)); assert(store->isStorePath(ctx));
if (!store->isValidPath(ctx)) if (!store->isValidPath(ctx))
throw InvalidPathError(ctx); throw InvalidPathError(ctx);
if (!decoded.second.empty() && nix::isDerivation(ctx)) { if (!outputName.empty() && nix::isDerivation(ctx)) {
drvs.insert(decoded.first + "!" + decoded.second); drvs.insert(ctx + "!" + outputName);
/* Add the output of this derivation to the allowed /* Add the output of this derivation to the allowed
paths. */ paths. */
if (allowedPaths) { if (allowedPaths) {
auto drv = store->derivationFromPath(decoded.first); auto drv = store->derivationFromPath(ctx);
DerivationOutputs::iterator i = drv.outputs.find(decoded.second); DerivationOutputs::iterator i = drv.outputs.find(outputName);
if (i == drv.outputs.end()) if (i == drv.outputs.end())
throw Error("derivation '%s' does not have an output named '%s'", decoded.first, decoded.second); throw Error("derivation '%s' does not have an output named '%s'", ctx, outputName);
allowedPaths->insert(i->second.path); allowedPaths->insert(i->second.path);
} }
} }
@ -80,6 +79,7 @@ void EvalState::realiseContext(const PathSet & context)
PathSet willBuild, willSubstitute, unknown; PathSet willBuild, willSubstitute, unknown;
unsigned long long downloadSize, narSize; unsigned long long downloadSize, narSize;
store->queryMissing(drvs, willBuild, willSubstitute, unknown, downloadSize, narSize); store->queryMissing(drvs, willBuild, willSubstitute, unknown, downloadSize, narSize);
store->buildPaths(drvs); store->buildPaths(drvs);
} }

View file

@ -43,6 +43,8 @@ struct App
PathSet context; PathSet context;
Path program; Path program;
// FIXME: add args, sandbox settings, metadata, ... // FIXME: add args, sandbox settings, metadata, ...
App(EvalState & state, Value & vApp);
}; };
struct Installable struct Installable

View file

@ -7,6 +7,7 @@
#include "flake/flake.hh" #include "flake/flake.hh"
#include "get-drvs.hh" #include "get-drvs.hh"
#include "store-api.hh" #include "store-api.hh"
#include "derivations.hh"
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <queue> #include <queue>
@ -301,13 +302,27 @@ struct CmdFlakeCheck : FlakeCommand, MixJSON
// FIXME: check meta attributes // FIXME: check meta attributes
return drvInfo->queryDrvPath(); return drvInfo->queryDrvPath();
} catch (Error & e) { } catch (Error & e) {
e.addPrefix(fmt("while checking flake output attribute '" ANSI_BOLD "%s" ANSI_NORMAL "':\n", attrPath)); e.addPrefix(fmt("while checking the derivation '" ANSI_BOLD "%s" ANSI_NORMAL "':\n", attrPath));
throw; throw;
} }
}; };
PathSet drvPaths; PathSet drvPaths;
auto checkApp = [&](const std::string & attrPath, Value & v) {
try {
auto app = App(*state, v);
for (auto & i : app.context) {
auto [drvPath, outputName] = decodeContext(i);
if (!outputName.empty() && nix::isDerivation(drvPath))
drvPaths.insert(drvPath + "!" + outputName);
}
} catch (Error & e) {
e.addPrefix(fmt("while checking the app definition '" ANSI_BOLD "%s" ANSI_NORMAL "':\n", attrPath));
throw;
}
};
{ {
Activity act(*logger, lvlInfo, actUnknown, "evaluating flake"); Activity act(*logger, lvlInfo, actUnknown, "evaluating flake");
@ -337,9 +352,19 @@ struct CmdFlakeCheck : FlakeCommand, MixJSON
name + "." + (std::string) aCheck.name, *aCheck.value); name + "." + (std::string) aCheck.name, *aCheck.value);
} }
else if (name == "apps") {
state->forceAttrs(vProvide);
for (auto & aCheck : *vProvide.attrs)
checkApp(
name + "." + (std::string) aCheck.name, *aCheck.value);
}
else if (name == "defaultPackage" || name == "devShell") else if (name == "defaultPackage" || name == "devShell")
checkDerivation(name, vProvide); checkDerivation(name, vProvide);
else if (name == "defaultApp")
checkApp(name, vProvide);
} catch (Error & e) { } catch (Error & e) {
e.addPrefix(fmt("while checking flake output '" ANSI_BOLD "%s" ANSI_NORMAL "':\n", name)); e.addPrefix(fmt("while checking flake output '" ANSI_BOLD "%s" ANSI_NORMAL "':\n", name));
throw; throw;
@ -347,7 +372,7 @@ struct CmdFlakeCheck : FlakeCommand, MixJSON
}); });
} }
if (build) { if (build && !drvPaths.empty()) {
Activity act(*logger, lvlInfo, actUnknown, "running flake checks"); Activity act(*logger, lvlInfo, actUnknown, "running flake checks");
store->buildPaths(drvPaths); store->buildPaths(drvPaths);
} }

View file

@ -69,26 +69,25 @@ Buildable Installable::toBuildable()
return std::move(buildables[0]); return std::move(buildables[0]);
} }
App Installable::toApp(EvalState & state) App::App(EvalState & state, Value & vApp)
{ {
auto v = toValue(state); state.forceAttrs(vApp);
state.forceAttrs(*v); auto aType = vApp.attrs->need(state.sType);
auto aType = v->attrs->need(state.sType);
if (state.forceStringNoCtx(*aType.value, *aType.pos) != "app") if (state.forceStringNoCtx(*aType.value, *aType.pos) != "app")
throw Error("value does not have type 'app', at %s", *aType.pos); throw Error("value does not have type 'app', at %s", *aType.pos);
App app; auto aProgram = vApp.attrs->need(state.symbols.create("program"));
program = state.forceString(*aProgram.value, context, *aProgram.pos);
auto aProgram = v->attrs->need(state.symbols.create("program"));
app.program = state.forceString(*aProgram.value, app.context, *aProgram.pos);
// FIXME: check that 'program' is in the closure of 'context'. // FIXME: check that 'program' is in the closure of 'context'.
if (!state.store->isInStore(app.program)) if (!state.store->isInStore(program))
throw Error("app program '%s' is not in the Nix store", app.program); throw Error("app program '%s' is not in the Nix store", program);
}
return app; App Installable::toApp(EvalState & state)
{
return App(state, *toValue(state));
} }
struct InstallableStorePath : Installable struct InstallableStorePath : Installable