forked from lix-project/lix
Merge pull request #2951 from NixOS/app-improvements
App / check improvements
This commit is contained in:
commit
eb18aedccb
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
@ -102,6 +104,18 @@ struct SourceExprCommand : virtual Args, EvalCommand, MixFlakeOptions
|
||||||
{
|
{
|
||||||
return {"defaultPackage"};
|
return {"defaultPackage"};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual Strings getDefaultFlakeAttrPathPrefixes()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
// As a convenience, look for the attribute in
|
||||||
|
// 'outputs.packages'.
|
||||||
|
"packages.",
|
||||||
|
// As a temporary hack until Nixpkgs is properly converted
|
||||||
|
// to provide a clean 'packages' set, look in 'legacyPackages'.
|
||||||
|
"legacyPackages."
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RealiseMode { Build, NoBuild, DryRun };
|
enum RealiseMode { Build, NoBuild, DryRun };
|
||||||
|
|
|
@ -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>
|
||||||
|
@ -226,8 +227,8 @@ struct CmdFlakeInfo : FlakeCommand, MixJSON
|
||||||
if (json) {
|
if (json) {
|
||||||
auto json = flakeToJson(flake);
|
auto json = flakeToJson(flake);
|
||||||
|
|
||||||
#if 0
|
|
||||||
auto state = getEvalState();
|
auto state = getEvalState();
|
||||||
|
auto flake = resolveFlake();
|
||||||
|
|
||||||
auto vFlake = state->allocValue();
|
auto vFlake = state->allocValue();
|
||||||
flake::callFlake(*state, flake, *vFlake);
|
flake::callFlake(*state, flake, *vFlake);
|
||||||
|
@ -249,7 +250,6 @@ struct CmdFlakeInfo : FlakeCommand, MixJSON
|
||||||
});
|
});
|
||||||
|
|
||||||
json["outputs"] = std::move(outputs);
|
json["outputs"] = std::move(outputs);
|
||||||
#endif
|
|
||||||
|
|
||||||
std::cout << json.dump() << std::endl;
|
std::cout << json.dump() << std::endl;
|
||||||
} else
|
} else
|
||||||
|
@ -294,13 +294,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");
|
||||||
|
|
||||||
|
@ -330,9 +344,26 @@ 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);
|
||||||
|
|
||||||
|
else if (name == "legacyPackages")
|
||||||
|
// FIXME: do getDerivations?
|
||||||
|
;
|
||||||
|
|
||||||
|
else
|
||||||
|
warn("unknown flake output '%s'", name);
|
||||||
|
|
||||||
} 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;
|
||||||
|
@ -340,7 +371,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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
@ -257,14 +256,16 @@ struct InstallableFlake : InstallableValue
|
||||||
{
|
{
|
||||||
FlakeRef flakeRef;
|
FlakeRef flakeRef;
|
||||||
Strings attrPaths;
|
Strings attrPaths;
|
||||||
bool searchPackages = false;
|
Strings prefixes;
|
||||||
|
|
||||||
InstallableFlake(SourceExprCommand & cmd, FlakeRef && flakeRef, Strings attrPaths)
|
InstallableFlake(SourceExprCommand & cmd, FlakeRef && flakeRef, Strings attrPaths)
|
||||||
: InstallableValue(cmd), flakeRef(flakeRef), attrPaths(std::move(attrPaths))
|
: InstallableValue(cmd), flakeRef(flakeRef), attrPaths(std::move(attrPaths))
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
InstallableFlake(SourceExprCommand & cmd, FlakeRef && flakeRef, std::string attrPath)
|
InstallableFlake(SourceExprCommand & cmd, FlakeRef && flakeRef,
|
||||||
: InstallableValue(cmd), flakeRef(flakeRef), attrPaths{attrPath}, searchPackages(true)
|
std::string attrPath, Strings && prefixes)
|
||||||
|
: InstallableValue(cmd), flakeRef(flakeRef), attrPaths{attrPath},
|
||||||
|
prefixes(prefixes)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
std::string what() override { return flakeRef.to_string() + ":" + *attrPaths.begin(); }
|
std::string what() override { return flakeRef.to_string() + ":" + *attrPaths.begin(); }
|
||||||
|
@ -273,15 +274,8 @@ struct InstallableFlake : InstallableValue
|
||||||
{
|
{
|
||||||
std::vector<std::string> res;
|
std::vector<std::string> res;
|
||||||
|
|
||||||
if (searchPackages) {
|
for (auto & prefix : prefixes)
|
||||||
// As a convenience, look for the attribute in
|
res.push_back(prefix + *attrPaths.begin());
|
||||||
// 'outputs.packages'.
|
|
||||||
res.push_back("packages." + *attrPaths.begin());
|
|
||||||
|
|
||||||
// As a temporary hack until Nixpkgs is properly converted
|
|
||||||
// to provide a clean 'packages' set, look in 'legacyPackages'.
|
|
||||||
res.push_back("legacyPackages." + *attrPaths.begin());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto & s : attrPaths)
|
for (auto & s : attrPaths)
|
||||||
res.push_back(s);
|
res.push_back(s);
|
||||||
|
@ -421,7 +415,11 @@ std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
|
||||||
else if ((colon = s.rfind(':')) != std::string::npos) {
|
else if ((colon = s.rfind(':')) != std::string::npos) {
|
||||||
auto flakeRef = std::string(s, 0, colon);
|
auto flakeRef = std::string(s, 0, colon);
|
||||||
auto attrPath = std::string(s, colon + 1);
|
auto attrPath = std::string(s, colon + 1);
|
||||||
result.push_back(std::make_shared<InstallableFlake>(*this, FlakeRef(flakeRef, true), attrPath));
|
result.push_back(std::make_shared<InstallableFlake>(
|
||||||
|
*this,
|
||||||
|
FlakeRef(flakeRef, true),
|
||||||
|
attrPath,
|
||||||
|
getDefaultFlakeAttrPathPrefixes()));
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (s.find('/') != std::string::npos || s == ".") {
|
else if (s.find('/') != std::string::npos || s == ".") {
|
||||||
|
@ -437,7 +435,7 @@ std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
result.push_back(std::make_shared<InstallableFlake>(*this, FlakeRef("nixpkgs"), s));
|
throw Error("unsupported argument '%s'", s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -196,8 +196,11 @@ static RegisterCommand r1(make_ref<CmdRun>());
|
||||||
|
|
||||||
struct CmdApp : InstallableCommand, RunCommon
|
struct CmdApp : InstallableCommand, RunCommon
|
||||||
{
|
{
|
||||||
|
std::vector<std::string> args;
|
||||||
|
|
||||||
CmdApp()
|
CmdApp()
|
||||||
{
|
{
|
||||||
|
expectArgs("args", &args);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string name() override
|
std::string name() override
|
||||||
|
@ -225,6 +228,11 @@ struct CmdApp : InstallableCommand, RunCommon
|
||||||
return {"defaultApp"};
|
return {"defaultApp"};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Strings getDefaultFlakeAttrPathPrefixes() override
|
||||||
|
{
|
||||||
|
return {"apps."};
|
||||||
|
}
|
||||||
|
|
||||||
void run(ref<Store> store) override
|
void run(ref<Store> store) override
|
||||||
{
|
{
|
||||||
auto state = getEvalState();
|
auto state = getEvalState();
|
||||||
|
@ -233,7 +241,10 @@ struct CmdApp : InstallableCommand, RunCommon
|
||||||
|
|
||||||
state->realiseContext(app.context);
|
state->realiseContext(app.context);
|
||||||
|
|
||||||
runProgram(store, app.program, {app.program});
|
Strings allArgs{app.program};
|
||||||
|
for (auto & i : args) allArgs.push_back(i);
|
||||||
|
|
||||||
|
runProgram(store, app.program, allArgs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue