Add 'nix flake check' command

This evaluates all the 'provides' of a flake and builds the 'check'
attributes.
This commit is contained in:
Eelco Dolstra 2019-05-29 17:25:41 +02:00
parent de00ed15d3
commit e0aaf05f4f
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
2 changed files with 97 additions and 4 deletions

View file

@ -14,13 +14,17 @@
nixpkgs = deps.nixpkgs; nixpkgs = deps.nixpkgs;
}; };
packages.nix = hydraJobs.build.x86_64-linux; checks.binaryTarball = hydraJobs.binaryTarball.x86_64-linux;
packages = {
nix = hydraJobs.build.x86_64-linux;
nix-perl-bindings = hydraJobs.perlBindings.x86_64-linux;
};
defaultPackage = packages.nix; defaultPackage = packages.nix;
devShell = import ./shell.nix { devShell = import ./shell.nix {
nixpkgs = deps.nixpkgs; nixpkgs = deps.nixpkgs;
}; };
}; };
} }

View file

@ -3,7 +3,10 @@
#include "shared.hh" #include "shared.hh"
#include "progress-bar.hh" #include "progress-bar.hh"
#include "eval.hh" #include "eval.hh"
#include "eval-inline.hh"
#include "primops/flake.hh" #include "primops/flake.hh"
#include "get-drvs.hh"
#include "store-api.hh"
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <queue> #include <queue>
@ -208,8 +211,6 @@ struct CmdFlakeInfo : FlakeCommand, MixJSON
return "list info about a given flake"; return "list info about a given flake";
} }
CmdFlakeInfo () { }
void run(nix::ref<nix::Store> store) override void run(nix::ref<nix::Store> store) override
{ {
auto flake = getFlake(); auto flake = getFlake();
@ -221,6 +222,93 @@ struct CmdFlakeInfo : FlakeCommand, MixJSON
} }
}; };
static void enumerateProvides(EvalState & state, Value & vFlake,
std::function<void(const std::string & name, Value & vProvide)> callback)
{
state.forceAttrs(vFlake);
auto vProvides = (*vFlake.attrs->get(state.symbols.create("provides")))->value;
state.forceAttrs(*vProvides);
for (auto & attr : *vProvides->attrs)
callback(attr.name, *attr.value);
}
struct CmdFlakeCheck : FlakeCommand, MixJSON
{
bool build = true;
CmdFlakeCheck()
{
mkFlag()
.longName("no-build")
.description("do not build checks")
.set(&build, false);
}
std::string name() override
{
return "check";
}
std::string description() override
{
return "check whether the flake evaluates and run its tests";
}
void run(nix::ref<nix::Store> store) override
{
auto state = getEvalState();
auto flake = resolveFlake();
PathSet drvPaths;
{
Activity act(*logger, lvlInfo, actUnknown, "evaluating flake");
auto vFlake = state->allocValue();
flake::callFlake(*state, flake, *vFlake);
enumerateProvides(*state,
*vFlake,
[&](const std::string & name, Value & vProvide) {
Activity act(*logger, lvlChatty, actUnknown,
fmt("checking flake output '%s'", name));
try {
state->forceValue(vProvide);
if (name == "checks") {
state->forceAttrs(vProvide);
for (auto & aCheck : *vProvide.attrs) {
try {
auto drvInfo = getDerivation(*state, *aCheck.value, false);
if (!drvInfo)
throw Error("flake output 'check.%s' is not a derivation", aCheck.name);
drvPaths.insert(drvInfo->queryDrvPath());
// FIXME: check meta attributes?
} catch (Error & e) {
e.addPrefix(fmt("while checking flake check '" ANSI_BOLD "%s" ANSI_NORMAL "':\n", aCheck.name));
throw;
}
}
}
} catch (Error & e) {
e.addPrefix(fmt("while checking flake output '" ANSI_BOLD "%s" ANSI_NORMAL "':\n", name));
throw;
}
});
}
if (build) {
Activity act(*logger, lvlInfo, actUnknown, "running flake checks");
store->buildPaths(drvPaths);
}
}
};
struct CmdFlakeAdd : MixEvalArgs, Command struct CmdFlakeAdd : MixEvalArgs, Command
{ {
FlakeUri alias; FlakeUri alias;
@ -387,6 +475,7 @@ struct CmdFlake : virtual MultiCommand, virtual Command
: MultiCommand({make_ref<CmdFlakeList>() : MultiCommand({make_ref<CmdFlakeList>()
, make_ref<CmdFlakeUpdate>() , make_ref<CmdFlakeUpdate>()
, make_ref<CmdFlakeInfo>() , make_ref<CmdFlakeInfo>()
, make_ref<CmdFlakeCheck>()
, make_ref<CmdFlakeDeps>() , make_ref<CmdFlakeDeps>()
, make_ref<CmdFlakeAdd>() , make_ref<CmdFlakeAdd>()
, make_ref<CmdFlakeRemove>() , make_ref<CmdFlakeRemove>()