mirror of
https://github.com/NixOS/nix
synced 2025-06-28 05:21:16 +02:00
Merge remote-tracking branch 'upstream/master' into upstream-merge
This commit is contained in:
commit
1a93ac8133
262 changed files with 5827 additions and 2852 deletions
|
@ -209,7 +209,7 @@ void BuiltPathsCommand::run(ref<Store> store)
|
|||
for (auto & p : store->queryAllValidPaths())
|
||||
paths.push_back(BuiltPath::Opaque{p});
|
||||
} else {
|
||||
paths = toBuiltPaths(getEvalStore(), store, realiseMode, operateOn, installables);
|
||||
paths = Installable::toBuiltPaths(getEvalStore(), store, realiseMode, operateOn, installables);
|
||||
if (recursive) {
|
||||
// XXX: This only computes the store path closure, ignoring
|
||||
// intermediate realisations
|
||||
|
@ -260,7 +260,8 @@ Strings editorFor(const Pos & pos)
|
|||
if (pos.line > 0 && (
|
||||
editor.find("emacs") != std::string::npos ||
|
||||
editor.find("nano") != std::string::npos ||
|
||||
editor.find("vim") != std::string::npos))
|
||||
editor.find("vim") != std::string::npos ||
|
||||
editor.find("kak") != std::string::npos))
|
||||
args.push_back(fmt("+%d", pos.line));
|
||||
args.push_back(pos.file);
|
||||
return args;
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#include "common-eval-args.hh"
|
||||
#include "path.hh"
|
||||
#include "flake/lockfile.hh"
|
||||
#include "store-api.hh"
|
||||
|
||||
#include <optional>
|
||||
|
||||
|
@ -84,14 +83,6 @@ struct MixFlakeOptions : virtual Args, EvalCommand
|
|||
{ return {}; }
|
||||
};
|
||||
|
||||
/* How to handle derivations in commands that operate on store paths. */
|
||||
enum class OperateOn {
|
||||
/* Operate on the output path. */
|
||||
Output,
|
||||
/* Operate on the .drv path. */
|
||||
Derivation
|
||||
};
|
||||
|
||||
struct SourceExprCommand : virtual Args, MixFlakeOptions
|
||||
{
|
||||
std::optional<Path> file;
|
||||
|
@ -115,19 +106,6 @@ struct SourceExprCommand : virtual Args, MixFlakeOptions
|
|||
void completeInstallable(std::string_view prefix);
|
||||
};
|
||||
|
||||
enum class Realise {
|
||||
/* Build the derivation. Postcondition: the
|
||||
derivation outputs exist. */
|
||||
Outputs,
|
||||
/* Don't build the derivation. Postcondition: the store derivation
|
||||
exists. */
|
||||
Derivation,
|
||||
/* Evaluate in dry-run mode. Postcondition: nothing. */
|
||||
// FIXME: currently unused, but could be revived if we can
|
||||
// evaluate derivations in-memory.
|
||||
Nothing
|
||||
};
|
||||
|
||||
/* A command that operates on a list of "installables", which can be
|
||||
store paths, attribute paths, Nix expressions, etc. */
|
||||
struct InstallablesCommand : virtual Args, SourceExprCommand
|
||||
|
@ -240,38 +218,6 @@ static RegisterCommand registerCommand2(std::vector<std::string> && name)
|
|||
return RegisterCommand(std::move(name), [](){ return make_ref<T>(); });
|
||||
}
|
||||
|
||||
BuiltPaths build(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store, Realise mode,
|
||||
const std::vector<std::shared_ptr<Installable>> & installables,
|
||||
BuildMode bMode = bmNormal);
|
||||
|
||||
std::set<StorePath> toStorePaths(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
OperateOn operateOn,
|
||||
const std::vector<std::shared_ptr<Installable>> & installables);
|
||||
|
||||
StorePath toStorePath(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
OperateOn operateOn,
|
||||
std::shared_ptr<Installable> installable);
|
||||
|
||||
std::set<StorePath> toDerivations(
|
||||
ref<Store> store,
|
||||
const std::vector<std::shared_ptr<Installable>> & installables,
|
||||
bool useDeriver = false);
|
||||
|
||||
BuiltPaths toBuiltPaths(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
OperateOn operateOn,
|
||||
const std::vector<std::shared_ptr<Installable>> & installables);
|
||||
|
||||
/* Helper function to generate args that invoke $EDITOR on
|
||||
filename:lineno. */
|
||||
Strings editorFor(const Pos & pos);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "eval-cache.hh"
|
||||
#include "url.hh"
|
||||
#include "registry.hh"
|
||||
#include "build-result.hh"
|
||||
|
||||
#include <regex>
|
||||
#include <queue>
|
||||
|
@ -97,7 +98,7 @@ MixFlakeOptions::MixFlakeOptions()
|
|||
lockFlags.writeLockFile = false;
|
||||
lockFlags.inputOverrides.insert_or_assign(
|
||||
flake::parseInputPath(inputPath),
|
||||
parseFlakeRef(flakeRef, absPath(".")));
|
||||
parseFlakeRef(flakeRef, absPath("."), true));
|
||||
}}
|
||||
});
|
||||
|
||||
|
@ -133,7 +134,9 @@ SourceExprCommand::SourceExprCommand()
|
|||
addFlag({
|
||||
.longName = "file",
|
||||
.shortName = 'f',
|
||||
.description = "Interpret installables as attribute paths relative to the Nix expression stored in *file*.",
|
||||
.description =
|
||||
"Interpret installables as attribute paths relative to the Nix expression stored in *file*. "
|
||||
"If *file* is the character -, then a Nix expression will be read from standard input.",
|
||||
.category = installablesCategory,
|
||||
.labels = {"file"},
|
||||
.handler = {&file},
|
||||
|
@ -158,7 +161,10 @@ SourceExprCommand::SourceExprCommand()
|
|||
|
||||
Strings SourceExprCommand::getDefaultFlakeAttrPaths()
|
||||
{
|
||||
return {"defaultPackage." + settings.thisSystem.get()};
|
||||
return {
|
||||
"packages." + settings.thisSystem.get() + ".default",
|
||||
"defaultPackage." + settings.thisSystem.get()
|
||||
};
|
||||
}
|
||||
|
||||
Strings SourceExprCommand::getDefaultFlakeAttrPathPrefixes()
|
||||
|
@ -269,9 +275,9 @@ void completeFlakeRefWithFragment(
|
|||
auto attr = root->findAlongAttrPath(attrPath);
|
||||
if (!attr) continue;
|
||||
|
||||
for (auto & attr2 : attr->getAttrs()) {
|
||||
for (auto & attr2 : (*attr)->getAttrs()) {
|
||||
if (hasPrefix(attr2, lastAttr)) {
|
||||
auto attrPath2 = attr->getAttrPath(attr2);
|
||||
auto attrPath2 = (*attr)->getAttrPath(attr2);
|
||||
/* Strip the attrpath prefix. */
|
||||
attrPath2.erase(attrPath2.begin(), attrPath2.begin() + attrPathPrefix.size());
|
||||
completions->add(flakeRefS + "#" + concatStringsSep(".", attrPath2));
|
||||
|
@ -465,11 +471,10 @@ std::vector<InstallableValue::DerivationInfo> InstallableAttrPath::toDerivations
|
|||
|
||||
std::vector<DerivationInfo> res;
|
||||
for (auto & drvInfo : drvInfos) {
|
||||
res.push_back({
|
||||
state->store->parseStorePath(drvInfo.queryDrvPath()),
|
||||
state->store->maybeParseStorePath(drvInfo.queryOutPath()),
|
||||
drvInfo.queryOutputName()
|
||||
});
|
||||
auto drvPath = drvInfo.queryDrvPath();
|
||||
if (!drvPath)
|
||||
throw Error("'%s' is not a derivation", what());
|
||||
res.push_back({ *drvPath, drvInfo.queryOutputName() });
|
||||
}
|
||||
|
||||
return res;
|
||||
|
@ -545,13 +550,14 @@ InstallableFlake::InstallableFlake(
|
|||
SourceExprCommand * cmd,
|
||||
ref<EvalState> state,
|
||||
FlakeRef && flakeRef,
|
||||
Strings && attrPaths,
|
||||
Strings && prefixes,
|
||||
std::string_view fragment,
|
||||
Strings attrPaths,
|
||||
Strings prefixes,
|
||||
const flake::LockFlags & lockFlags)
|
||||
: InstallableValue(state),
|
||||
flakeRef(flakeRef),
|
||||
attrPaths(attrPaths),
|
||||
prefixes(prefixes),
|
||||
attrPaths(fragment == "" ? attrPaths : Strings{(std::string) fragment}),
|
||||
prefixes(fragment == "" ? Strings{} : prefixes),
|
||||
lockFlags(lockFlags)
|
||||
{
|
||||
if (cmd && cmd->getAutoArgs(*state)->size())
|
||||
|
@ -565,29 +571,37 @@ std::tuple<std::string, FlakeRef, InstallableValue::DerivationInfo> InstallableF
|
|||
auto cache = openEvalCache(*state, lockedFlake);
|
||||
auto root = cache->getRoot();
|
||||
|
||||
Suggestions suggestions;
|
||||
|
||||
for (auto & attrPath : getActualAttrPaths()) {
|
||||
auto attr = root->findAlongAttrPath(
|
||||
debug("trying flake output attribute '%s'", attrPath);
|
||||
|
||||
auto attrOrSuggestions = root->findAlongAttrPath(
|
||||
parseAttrPath(*state, attrPath),
|
||||
true
|
||||
);
|
||||
|
||||
if (!attr) continue;
|
||||
if (!attrOrSuggestions) {
|
||||
suggestions += attrOrSuggestions.getSuggestions();
|
||||
continue;
|
||||
}
|
||||
|
||||
auto attr = *attrOrSuggestions;
|
||||
|
||||
if (!attr->isDerivation())
|
||||
throw Error("flake output attribute '%s' is not a derivation", attrPath);
|
||||
|
||||
auto drvPath = attr->forceDerivation();
|
||||
|
||||
auto drvInfo = DerivationInfo{
|
||||
auto drvInfo = DerivationInfo {
|
||||
std::move(drvPath),
|
||||
state->store->maybeParseStorePath(attr->getAttr(state->sOutPath)->getString()),
|
||||
attr->getAttr(state->sOutputName)->getString()
|
||||
};
|
||||
|
||||
return {attrPath, lockedFlake->flake.lockedRef, std::move(drvInfo)};
|
||||
}
|
||||
|
||||
throw Error("flake '%s' does not provide attribute %s",
|
||||
throw Error(suggestions, "flake '%s' does not provide attribute %s",
|
||||
flakeRef, showAttrPaths(getActualAttrPaths()));
|
||||
}
|
||||
|
||||
|
@ -606,17 +620,24 @@ std::pair<Value *, Pos> InstallableFlake::toValue(EvalState & state)
|
|||
|
||||
auto emptyArgs = state.allocBindings(0);
|
||||
|
||||
Suggestions suggestions;
|
||||
|
||||
for (auto & attrPath : getActualAttrPaths()) {
|
||||
try {
|
||||
auto [v, pos] = findAlongAttrPath(state, attrPath, *emptyArgs, *vOutputs);
|
||||
state.forceValue(*v, pos);
|
||||
return {v, pos};
|
||||
} catch (AttrPathNotFound & e) {
|
||||
suggestions += e.info().suggestions;
|
||||
}
|
||||
}
|
||||
|
||||
throw Error("flake '%s' does not provide attribute %s",
|
||||
flakeRef, showAttrPaths(getActualAttrPaths()));
|
||||
throw Error(
|
||||
suggestions,
|
||||
"flake '%s' does not provide attribute %s",
|
||||
flakeRef,
|
||||
showAttrPaths(getActualAttrPaths())
|
||||
);
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string>>
|
||||
|
@ -631,7 +652,7 @@ InstallableFlake::getCursors(EvalState & state)
|
|||
|
||||
for (auto & attrPath : getActualAttrPaths()) {
|
||||
auto attr = root->findAlongAttrPath(parseAttrPath(state, attrPath));
|
||||
if (attr) res.push_back({attr, attrPath});
|
||||
if (attr) res.push_back({*attr, attrPath});
|
||||
}
|
||||
|
||||
return res;
|
||||
|
@ -676,7 +697,10 @@ std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
|
|||
auto state = getEvalState();
|
||||
auto vFile = state->allocValue();
|
||||
|
||||
if (file)
|
||||
if (file == "-") {
|
||||
auto e = state->parseStdin();
|
||||
state->eval(e, *vFile);
|
||||
} else if (file)
|
||||
state->evalFile(lookupFileArg(*state, *file), *vFile);
|
||||
else {
|
||||
auto e = state->parseExprFromString(*expr, absPath("."));
|
||||
|
@ -708,7 +732,8 @@ std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
|
|||
this,
|
||||
getEvalState(),
|
||||
std::move(flakeRef),
|
||||
fragment == "" ? getDefaultFlakeAttrPaths() : Strings{fragment},
|
||||
fragment,
|
||||
getDefaultFlakeAttrPaths(),
|
||||
getDefaultFlakeAttrPathPrefixes(),
|
||||
lockFlags));
|
||||
continue;
|
||||
|
@ -731,56 +756,20 @@ std::shared_ptr<Installable> SourceExprCommand::parseInstallable(
|
|||
return installables.front();
|
||||
}
|
||||
|
||||
BuiltPaths getBuiltPaths(ref<Store> evalStore, ref<Store> store, const DerivedPaths & hopefullyBuiltPaths)
|
||||
BuiltPaths Installable::build(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
const std::vector<std::shared_ptr<Installable>> & installables,
|
||||
BuildMode bMode)
|
||||
{
|
||||
BuiltPaths res;
|
||||
for (const auto & b : hopefullyBuiltPaths)
|
||||
std::visit(
|
||||
overloaded{
|
||||
[&](const DerivedPath::Opaque & bo) {
|
||||
res.push_back(BuiltPath::Opaque{bo.path});
|
||||
},
|
||||
[&](const DerivedPath::Built & bfd) {
|
||||
OutputPathMap outputs;
|
||||
auto drv = evalStore->readDerivation(bfd.drvPath);
|
||||
auto outputHashes = staticOutputHashes(*evalStore, drv); // FIXME: expensive
|
||||
auto drvOutputs = drv.outputsAndOptPaths(*store);
|
||||
for (auto & output : bfd.outputs) {
|
||||
if (!outputHashes.count(output))
|
||||
throw Error(
|
||||
"the derivation '%s' doesn't have an output named '%s'",
|
||||
store->printStorePath(bfd.drvPath), output);
|
||||
if (settings.isExperimentalFeatureEnabled(
|
||||
Xp::CaDerivations)) {
|
||||
auto outputId =
|
||||
DrvOutput{outputHashes.at(output), output};
|
||||
auto realisation =
|
||||
store->queryRealisation(outputId);
|
||||
if (!realisation)
|
||||
throw Error(
|
||||
"cannot operate on an output of unbuilt "
|
||||
"content-addressed derivation '%s'",
|
||||
outputId.to_string());
|
||||
outputs.insert_or_assign(
|
||||
output, realisation->outPath);
|
||||
} else {
|
||||
// If ca-derivations isn't enabled, assume that
|
||||
// the output path is statically known.
|
||||
assert(drvOutputs.count(output));
|
||||
assert(drvOutputs.at(output).second);
|
||||
outputs.insert_or_assign(
|
||||
output, *drvOutputs.at(output).second);
|
||||
}
|
||||
}
|
||||
res.push_back(BuiltPath::Built{bfd.drvPath, outputs});
|
||||
},
|
||||
},
|
||||
b.raw());
|
||||
|
||||
for (auto & [_, builtPath] : build2(evalStore, store, mode, installables, bMode))
|
||||
res.push_back(builtPath);
|
||||
return res;
|
||||
}
|
||||
|
||||
BuiltPaths build(
|
||||
std::vector<std::pair<std::shared_ptr<Installable>, BuiltPath>> Installable::build2(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
|
@ -791,21 +780,96 @@ BuiltPaths build(
|
|||
settings.readOnlyMode = true;
|
||||
|
||||
std::vector<DerivedPath> pathsToBuild;
|
||||
std::map<DerivedPath, std::vector<std::shared_ptr<Installable>>> backmap;
|
||||
|
||||
for (auto & i : installables) {
|
||||
auto b = i->toDerivedPaths();
|
||||
pathsToBuild.insert(pathsToBuild.end(), b.begin(), b.end());
|
||||
for (auto b : i->toDerivedPaths()) {
|
||||
pathsToBuild.push_back(b);
|
||||
backmap[b].push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (mode == Realise::Nothing || mode == Realise::Derivation)
|
||||
printMissing(store, pathsToBuild, lvlError);
|
||||
else if (mode == Realise::Outputs)
|
||||
store->buildPaths(pathsToBuild, bMode, evalStore);
|
||||
std::vector<std::pair<std::shared_ptr<Installable>, BuiltPath>> res;
|
||||
|
||||
return getBuiltPaths(evalStore, store, pathsToBuild);
|
||||
switch (mode) {
|
||||
|
||||
case Realise::Nothing:
|
||||
case Realise::Derivation:
|
||||
printMissing(store, pathsToBuild, lvlError);
|
||||
|
||||
for (auto & path : pathsToBuild) {
|
||||
for (auto & installable : backmap[path]) {
|
||||
std::visit(overloaded {
|
||||
[&](const DerivedPath::Built & bfd) {
|
||||
OutputPathMap outputs;
|
||||
auto drv = evalStore->readDerivation(bfd.drvPath);
|
||||
auto outputHashes = staticOutputHashes(*evalStore, drv); // FIXME: expensive
|
||||
auto drvOutputs = drv.outputsAndOptPaths(*store);
|
||||
for (auto & output : bfd.outputs) {
|
||||
if (!outputHashes.count(output))
|
||||
throw Error(
|
||||
"the derivation '%s' doesn't have an output named '%s'",
|
||||
store->printStorePath(bfd.drvPath), output);
|
||||
if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
|
||||
DrvOutput outputId { outputHashes.at(output), output };
|
||||
auto realisation = store->queryRealisation(outputId);
|
||||
if (!realisation)
|
||||
throw Error(
|
||||
"cannot operate on an output of unbuilt "
|
||||
"content-addressed derivation '%s'",
|
||||
outputId.to_string());
|
||||
outputs.insert_or_assign(output, realisation->outPath);
|
||||
} else {
|
||||
// If ca-derivations isn't enabled, assume that
|
||||
// the output path is statically known.
|
||||
assert(drvOutputs.count(output));
|
||||
assert(drvOutputs.at(output).second);
|
||||
outputs.insert_or_assign(
|
||||
output, *drvOutputs.at(output).second);
|
||||
}
|
||||
}
|
||||
res.push_back({installable, BuiltPath::Built { bfd.drvPath, outputs }});
|
||||
},
|
||||
[&](const DerivedPath::Opaque & bo) {
|
||||
res.push_back({installable, BuiltPath::Opaque { bo.path }});
|
||||
},
|
||||
}, path.raw());
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Realise::Outputs: {
|
||||
for (auto & buildResult : store->buildPathsWithResults(pathsToBuild, bMode, evalStore)) {
|
||||
if (!buildResult.success())
|
||||
buildResult.rethrow();
|
||||
|
||||
for (auto & installable : backmap[buildResult.path]) {
|
||||
std::visit(overloaded {
|
||||
[&](const DerivedPath::Built & bfd) {
|
||||
std::map<std::string, StorePath> outputs;
|
||||
for (auto & path : buildResult.builtOutputs)
|
||||
outputs.emplace(path.first.outputName, path.second.outPath);
|
||||
res.push_back({installable, BuiltPath::Built { bfd.drvPath, outputs }});
|
||||
},
|
||||
[&](const DerivedPath::Opaque & bo) {
|
||||
res.push_back({installable, BuiltPath::Opaque { bo.path }});
|
||||
},
|
||||
}, buildResult.path.raw());
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
BuiltPaths toBuiltPaths(
|
||||
BuiltPaths Installable::toBuiltPaths(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
|
@ -813,19 +877,19 @@ BuiltPaths toBuiltPaths(
|
|||
const std::vector<std::shared_ptr<Installable>> & installables)
|
||||
{
|
||||
if (operateOn == OperateOn::Output)
|
||||
return build(evalStore, store, mode, installables);
|
||||
return Installable::build(evalStore, store, mode, installables);
|
||||
else {
|
||||
if (mode == Realise::Nothing)
|
||||
settings.readOnlyMode = true;
|
||||
|
||||
BuiltPaths res;
|
||||
for (auto & drvPath : toDerivations(store, installables, true))
|
||||
for (auto & drvPath : Installable::toDerivations(store, installables, true))
|
||||
res.push_back(BuiltPath::Opaque{drvPath});
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
StorePathSet toStorePaths(
|
||||
StorePathSet Installable::toStorePaths(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode, OperateOn operateOn,
|
||||
|
@ -839,7 +903,7 @@ StorePathSet toStorePaths(
|
|||
return outPaths;
|
||||
}
|
||||
|
||||
StorePath toStorePath(
|
||||
StorePath Installable::toStorePath(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode, OperateOn operateOn,
|
||||
|
@ -853,7 +917,7 @@ StorePath toStorePath(
|
|||
return *paths.begin();
|
||||
}
|
||||
|
||||
StorePathSet toDerivations(
|
||||
StorePathSet Installable::toDerivations(
|
||||
ref<Store> store,
|
||||
const std::vector<std::shared_ptr<Installable>> & installables,
|
||||
bool useDeriver)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "path-with-outputs.hh"
|
||||
#include "derived-path.hh"
|
||||
#include "eval.hh"
|
||||
#include "store-api.hh"
|
||||
#include "flake/flake.hh"
|
||||
|
||||
#include <optional>
|
||||
|
@ -29,6 +30,27 @@ struct UnresolvedApp
|
|||
App resolve(ref<Store> evalStore, ref<Store> store);
|
||||
};
|
||||
|
||||
enum class Realise {
|
||||
/* Build the derivation. Postcondition: the
|
||||
derivation outputs exist. */
|
||||
Outputs,
|
||||
/* Don't build the derivation. Postcondition: the store derivation
|
||||
exists. */
|
||||
Derivation,
|
||||
/* Evaluate in dry-run mode. Postcondition: nothing. */
|
||||
// FIXME: currently unused, but could be revived if we can
|
||||
// evaluate derivations in-memory.
|
||||
Nothing
|
||||
};
|
||||
|
||||
/* How to handle derivations in commands that operate on store paths. */
|
||||
enum class OperateOn {
|
||||
/* Operate on the output path. */
|
||||
Output,
|
||||
/* Operate on the .drv path. */
|
||||
Derivation
|
||||
};
|
||||
|
||||
struct Installable
|
||||
{
|
||||
virtual ~Installable() { }
|
||||
|
@ -68,6 +90,46 @@ struct Installable
|
|||
{
|
||||
return FlakeRef::fromAttrs({{"type","indirect"}, {"id", "nixpkgs"}});
|
||||
}
|
||||
|
||||
static BuiltPaths build(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
const std::vector<std::shared_ptr<Installable>> & installables,
|
||||
BuildMode bMode = bmNormal);
|
||||
|
||||
static std::vector<std::pair<std::shared_ptr<Installable>, BuiltPath>> build2(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
const std::vector<std::shared_ptr<Installable>> & installables,
|
||||
BuildMode bMode = bmNormal);
|
||||
|
||||
static std::set<StorePath> toStorePaths(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
OperateOn operateOn,
|
||||
const std::vector<std::shared_ptr<Installable>> & installables);
|
||||
|
||||
static StorePath toStorePath(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
OperateOn operateOn,
|
||||
std::shared_ptr<Installable> installable);
|
||||
|
||||
static std::set<StorePath> toDerivations(
|
||||
ref<Store> store,
|
||||
const std::vector<std::shared_ptr<Installable>> & installables,
|
||||
bool useDeriver = false);
|
||||
|
||||
static BuiltPaths toBuiltPaths(
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
OperateOn operateOn,
|
||||
const std::vector<std::shared_ptr<Installable>> & installables);
|
||||
};
|
||||
|
||||
struct InstallableValue : Installable
|
||||
|
@ -79,7 +141,6 @@ struct InstallableValue : Installable
|
|||
struct DerivationInfo
|
||||
{
|
||||
StorePath drvPath;
|
||||
std::optional<StorePath> outPath;
|
||||
std::string outputName;
|
||||
};
|
||||
|
||||
|
@ -102,8 +163,9 @@ struct InstallableFlake : InstallableValue
|
|||
SourceExprCommand * cmd,
|
||||
ref<EvalState> state,
|
||||
FlakeRef && flakeRef,
|
||||
Strings && attrPaths,
|
||||
Strings && prefixes,
|
||||
std::string_view fragment,
|
||||
Strings attrPaths,
|
||||
Strings prefixes,
|
||||
const flake::LockFlags & lockFlags);
|
||||
|
||||
std::string what() const override { return flakeRef.to_string() + "#" + *attrPaths.begin(); }
|
||||
|
|
|
@ -25,6 +25,7 @@ extern "C" {
|
|||
#include "eval-inline.hh"
|
||||
#include "attr-path.hh"
|
||||
#include "store-api.hh"
|
||||
#include "log-store.hh"
|
||||
#include "common-eval-args.hh"
|
||||
#include "get-drvs.hh"
|
||||
#include "derivations.hh"
|
||||
|
@ -45,7 +46,7 @@ struct NixRepl
|
|||
: gc
|
||||
#endif
|
||||
{
|
||||
string curDir;
|
||||
std::string curDir;
|
||||
ref<EvalState> state;
|
||||
Bindings * autoArgs;
|
||||
|
||||
|
@ -65,10 +66,10 @@ struct NixRepl
|
|||
NixRepl(ref<EvalState> state);
|
||||
~NixRepl();
|
||||
void mainLoop(const std::vector<std::string> & files);
|
||||
StringSet completePrefix(string prefix);
|
||||
bool getLine(string & input, const std::string &prompt);
|
||||
StringSet completePrefix(const std::string & prefix);
|
||||
bool getLine(std::string & input, const std::string &prompt);
|
||||
StorePath getDerivationPath(Value & v);
|
||||
bool processLine(string line);
|
||||
bool processLine(std::string line);
|
||||
void loadFile(const Path & path);
|
||||
void loadFlake(const std::string & flakeRef);
|
||||
void initEnv();
|
||||
|
@ -76,22 +77,21 @@ struct NixRepl
|
|||
void reloadFiles();
|
||||
void addAttrsToScope(Value & attrs);
|
||||
void addVarToScope(const Symbol & name, Value & v);
|
||||
Expr * parseString(string s);
|
||||
void evalString(string s, Value & v);
|
||||
Expr * parseString(std::string s);
|
||||
void evalString(std::string s, Value & v);
|
||||
void loadDebugTraceEnv(DebugTrace &dt);
|
||||
|
||||
typedef set<Value *> ValuesSeen;
|
||||
typedef std::set<Value *> ValuesSeen;
|
||||
std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth);
|
||||
std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth, ValuesSeen & seen);
|
||||
};
|
||||
|
||||
|
||||
string removeWhitespace(string s)
|
||||
std::string removeWhitespace(std::string s)
|
||||
{
|
||||
s = chomp(s);
|
||||
size_t n = s.find_first_not_of(" \n\r\t");
|
||||
if (n != string::npos) s = string(s, n);
|
||||
|
||||
if (n != std::string::npos) s = std::string(s, n);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -111,7 +111,7 @@ NixRepl::~NixRepl()
|
|||
write_history(historyFile.c_str());
|
||||
}
|
||||
|
||||
string runNix(Path program, const Strings & args,
|
||||
std::string runNix(Path program, const Strings & args,
|
||||
const std::optional<std::string> & input = {})
|
||||
{
|
||||
auto subprocessEnv = getEnv();
|
||||
|
@ -229,7 +229,7 @@ std::ostream& showDebugTrace(std::ostream &out, const DebugTrace &dt)
|
|||
|
||||
void NixRepl::mainLoop(const std::vector<std::string> & files)
|
||||
{
|
||||
string error = ANSI_RED "error:" ANSI_NORMAL " ";
|
||||
std::string error = ANSI_RED "error:" ANSI_NORMAL " ";
|
||||
notice("Welcome to Nix " + nixVersion + ". Type :? for help.\n");
|
||||
|
||||
if (!files.empty()) {
|
||||
|
@ -297,7 +297,7 @@ void NixRepl::mainLoop(const std::vector<std::string> & files)
|
|||
}
|
||||
|
||||
|
||||
bool NixRepl::getLine(string & input, const std::string &prompt)
|
||||
bool NixRepl::getLine(std::string & input, const std::string & prompt)
|
||||
{
|
||||
struct sigaction act, old;
|
||||
sigset_t savedSignalMask, set;
|
||||
|
@ -342,7 +342,7 @@ bool NixRepl::getLine(string & input, const std::string &prompt)
|
|||
}
|
||||
|
||||
|
||||
StringSet NixRepl::completePrefix(string prefix)
|
||||
StringSet NixRepl::completePrefix(const std::string & prefix)
|
||||
{
|
||||
StringSet completions;
|
||||
|
||||
|
@ -358,7 +358,7 @@ StringSet NixRepl::completePrefix(string prefix)
|
|||
|
||||
size_t slash, dot;
|
||||
|
||||
if ((slash = cur.rfind('/')) != string::npos) {
|
||||
if ((slash = cur.rfind('/')) != std::string::npos) {
|
||||
try {
|
||||
auto dir = std::string(cur, 0, slash);
|
||||
auto prefix2 = std::string(cur, slash + 1);
|
||||
|
@ -368,11 +368,11 @@ StringSet NixRepl::completePrefix(string prefix)
|
|||
}
|
||||
} catch (Error &) {
|
||||
}
|
||||
} else if ((dot = cur.rfind('.')) == string::npos) {
|
||||
} else if ((dot = cur.rfind('.')) == std::string::npos) {
|
||||
/* This is a variable name; look it up in the current scope. */
|
||||
StringSet::iterator i = varNames.lower_bound(cur);
|
||||
while (i != varNames.end()) {
|
||||
if (string(*i, 0, cur.size()) != cur) break;
|
||||
if (i->substr(0, cur.size()) != cur) break;
|
||||
completions.insert(prev + *i);
|
||||
i++;
|
||||
}
|
||||
|
@ -381,8 +381,8 @@ StringSet NixRepl::completePrefix(string prefix)
|
|||
/* This is an expression that should evaluate to an
|
||||
attribute set. Evaluate it to get the names of the
|
||||
attributes. */
|
||||
string expr(cur, 0, dot);
|
||||
string cur2 = string(cur, dot + 1);
|
||||
auto expr = cur.substr(0, dot);
|
||||
auto cur2 = cur.substr(dot + 1);
|
||||
|
||||
Expr * e = parseString(expr);
|
||||
Value v;
|
||||
|
@ -390,8 +390,8 @@ StringSet NixRepl::completePrefix(string prefix)
|
|||
state->forceAttrs(v, noPos);
|
||||
|
||||
for (auto & i : *v.attrs) {
|
||||
string name = i.name;
|
||||
if (string(name, 0, cur2.size()) != cur2) continue;
|
||||
std::string name = i.name;
|
||||
if (name.substr(0, cur2.size()) != cur2) continue;
|
||||
completions.insert(prev + expr + "." + name);
|
||||
}
|
||||
|
||||
|
@ -410,7 +410,7 @@ StringSet NixRepl::completePrefix(string prefix)
|
|||
}
|
||||
|
||||
|
||||
bool isVarName(const string & s)
|
||||
static bool isVarName(std::string_view s)
|
||||
{
|
||||
if (s.size() == 0) return false;
|
||||
char c = s[0];
|
||||
|
@ -429,13 +429,12 @@ StorePath NixRepl::getDerivationPath(Value & v) {
|
|||
auto drvInfo = getDerivation(*state, v, false);
|
||||
if (!drvInfo)
|
||||
throw Error("expression does not evaluate to a derivation, so I can't build it");
|
||||
Path drvPathRaw = drvInfo->queryDrvPath();
|
||||
if (drvPathRaw == "")
|
||||
throw Error("expression did not evaluate to a valid derivation (no drv path)");
|
||||
StorePath drvPath = state->store->parseStorePath(drvPathRaw);
|
||||
if (!state->store->isValidPath(drvPath))
|
||||
throw Error("expression did not evaluate to a valid derivation (invalid drv path)");
|
||||
return drvPath;
|
||||
auto drvPath = drvInfo->queryDrvPath();
|
||||
if (!drvPath)
|
||||
throw Error("expression did not evaluate to a valid derivation (no 'drvPath' attribute)");
|
||||
if (!state->store->isValidPath(*drvPath))
|
||||
throw Error("expression evaluated to invalid derivation '%s'", state->store->printStorePath(*drvPath));
|
||||
return *drvPath;
|
||||
}
|
||||
|
||||
void NixRepl::loadDebugTraceEnv(DebugTrace &dt)
|
||||
|
@ -457,18 +456,19 @@ void NixRepl::loadDebugTraceEnv(DebugTrace &dt)
|
|||
}
|
||||
}
|
||||
|
||||
bool NixRepl::processLine(string line)
|
||||
bool NixRepl::processLine(std::string line)
|
||||
{
|
||||
line = trim(line);
|
||||
if (line == "") return true;
|
||||
|
||||
_isInterrupted = false;
|
||||
|
||||
string command, arg;
|
||||
std::string command, arg;
|
||||
|
||||
if (line[0] == ':') {
|
||||
size_t p = line.find_first_of(" \n\r\t");
|
||||
command = string(line, 0, p);
|
||||
if (p != string::npos) arg = removeWhitespace(string(line, p));
|
||||
command = line.substr(0, p);
|
||||
if (p != std::string::npos) arg = removeWhitespace(line.substr(p));
|
||||
} else {
|
||||
arg = line;
|
||||
}
|
||||
|
@ -667,9 +667,16 @@ bool NixRepl::processLine(string line)
|
|||
bool foundLog = false;
|
||||
RunPager pager;
|
||||
for (auto & sub : subs) {
|
||||
auto log = sub->getBuildLog(drvPath);
|
||||
auto * logSubP = dynamic_cast<LogStore *>(&*sub);
|
||||
if (!logSubP) {
|
||||
printInfo("Skipped '%s' which does not support retrieving build logs", sub->getUri());
|
||||
continue;
|
||||
}
|
||||
auto & logSub = *logSubP;
|
||||
|
||||
auto log = logSub.getBuildLog(drvPath);
|
||||
if (log) {
|
||||
printInfo("got build log for '%s' from '%s'", drvPathRaw, sub->getUri());
|
||||
printInfo("got build log for '%s' from '%s'", drvPathRaw, logSub.getUri());
|
||||
logger->writeToStdout(*log);
|
||||
foundLog = true;
|
||||
break;
|
||||
|
@ -733,13 +740,13 @@ bool NixRepl::processLine(string line)
|
|||
|
||||
else {
|
||||
size_t p = line.find('=');
|
||||
string name;
|
||||
if (p != string::npos &&
|
||||
std::string name;
|
||||
if (p != std::string::npos &&
|
||||
p < line.size() &&
|
||||
line[p + 1] != '=' &&
|
||||
isVarName(name = removeWhitespace(string(line, 0, p))))
|
||||
isVarName(name = removeWhitespace(line.substr(0, p))))
|
||||
{
|
||||
Expr * e = parseString(string(line, p + 1));
|
||||
Expr * e = parseString(line.substr(p + 1));
|
||||
Value & v(*state->allocValue());
|
||||
v.mkThunk(env, e);
|
||||
addVarToScope(state->symbols.create(name), v);
|
||||
|
@ -766,9 +773,12 @@ void NixRepl::loadFile(const Path & path)
|
|||
|
||||
void NixRepl::loadFlake(const std::string & flakeRefS)
|
||||
{
|
||||
if (flakeRefS.empty())
|
||||
throw Error("cannot use ':load-flake' without a path specified. (Use '.' for the current working directory.)");
|
||||
|
||||
auto flakeRef = parseFlakeRef(flakeRefS, absPath("."), true);
|
||||
if (evalSettings.pureEval && !flakeRef.input.isImmutable())
|
||||
throw Error("cannot use ':load-flake' on mutable flake reference '%s' (use --impure to override)", flakeRefS);
|
||||
if (evalSettings.pureEval && !flakeRef.input.isLocked())
|
||||
throw Error("cannot use ':load-flake' on locked flake reference '%s' (use --impure to override)", flakeRefS);
|
||||
|
||||
Value v;
|
||||
|
||||
|
@ -829,7 +839,7 @@ void NixRepl::addAttrsToScope(Value & attrs)
|
|||
for (auto & i : *attrs.attrs) {
|
||||
staticEnv->vars.emplace_back(i.name, displ);
|
||||
env->values[displ++] = i.value;
|
||||
varNames.insert((string) i.name);
|
||||
varNames.insert((std::string) i.name);
|
||||
}
|
||||
staticEnv->sort();
|
||||
staticEnv->deduplicate();
|
||||
|
@ -846,17 +856,18 @@ void NixRepl::addVarToScope(const Symbol & name, Value & v)
|
|||
staticEnv->vars.emplace_back(name, displ);
|
||||
staticEnv->sort();
|
||||
env->values[displ++] = &v;
|
||||
varNames.insert((string) name);
|
||||
varNames.insert((std::string) name);
|
||||
}
|
||||
|
||||
Expr * NixRepl::parseString(string s)
|
||||
|
||||
Expr * NixRepl::parseString(std::string s)
|
||||
{
|
||||
Expr * e = state->parseExprFromString(std::move(s), curDir, staticEnv);
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
void NixRepl::evalString(string s, Value & v)
|
||||
void NixRepl::evalString(std::string s, Value & v)
|
||||
{
|
||||
Expr * e = parseString(s);
|
||||
e->eval(*state, *env, v);
|
||||
|
@ -925,14 +936,17 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
|
|||
str << "«derivation ";
|
||||
Bindings::iterator i = v.attrs->find(state->sDrvPath);
|
||||
PathSet context;
|
||||
Path drvPath = i != v.attrs->end() ? state->coerceToPath(*i->pos, *i->value, context) : "???";
|
||||
str << drvPath << "»";
|
||||
if (i != v.attrs->end())
|
||||
str << state->store->printStorePath(state->coerceToStorePath(*i->pos, *i->value, context));
|
||||
else
|
||||
str << "???";
|
||||
str << "»";
|
||||
}
|
||||
|
||||
else if (maxDepth > 0) {
|
||||
str << "{ ";
|
||||
|
||||
typedef std::map<string, Value *> Sorted;
|
||||
typedef std::map<std::string, Value *> Sorted;
|
||||
Sorted sorted;
|
||||
for (auto & i : *v.attrs)
|
||||
sorted[i.name] = i.value;
|
||||
|
@ -943,7 +957,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
|
|||
else
|
||||
printStringValue(str, i.first.c_str());
|
||||
str << " = ";
|
||||
if (seen.find(i.second) != seen.end())
|
||||
if (seen.count(i.second))
|
||||
str << "«repeated»";
|
||||
else
|
||||
try {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue