mirror of
https://github.com/NixOS/nix.git
synced 2024-11-22 14:52:55 +00:00
Use std::set<StringContextElem>
not PathSet
for string contexts
Motivation `PathSet` is not correct because string contexts have other forms (`Built` and `DrvDeep`) that are not rendered as plain store paths. Instead of wrongly using `PathSet`, or "stringly typed" using `StringSet`, use `std::std<StringContextElem>`. ----- In support of this change, `NixStringContext` is now defined as `std::std<StringContextElem>` not `std:vector<StringContextElem>`. The old definition was just used by a `getContext` method which was only used by the eval cache. It can be deleted altogether since the types are now unified and the preexisting `copyContext` function already suffices. Summarizing the previous paragraph: Old: - `value/context.hh`: `NixStringContext = std::vector<StringContextElem>` - `value.hh`: `NixStringContext Value::getContext(...)` - `value.hh`: `copyContext(...)` New: - `value/context.hh`: `NixStringContext = std::set<StringContextElem>` - `value.hh`: `copyContext(...)` ---- The string representation of string context elements no longer contains the store dir. The diff of `src/libexpr/tests/value/context.cc` should make clear what the new representation is, so we recommend reviewing that file first. This was done for two reasons: Less API churn: `Value::mkString` and friends did not take a `Store` before. But if `NixStringContextElem::{parse, to_string}` *do* take a store (as they did before), then we cannot have the `Value` functions use them (in order to work with the fully-structured `NixStringContext`) without adding that argument. That would have been a lot of churn of threading the store, and this diff is already large enough, so the easier and less invasive thing to do was simply make the element `parse` and `to_string` functions not take the `Store` reference, and the easiest way to do that was to simply drop the store dir. Space usage: Dropping the `/nix/store/` (or similar) from the internal representation will safe space in the heap of the Nix programming being interpreted. If the heap contains many strings with non-trivial contexts, the saving could add up to something significant. ---- The eval cache version is bumped. The eval cache serialization uses `NixStringContextElem::{parse, to_string}`, and since those functions are changed per the above, that means the on-disk representation is also changed. This is simply done by changing the name of the used for the eval cache from `eval-cache-v4` to eval-cache-v5`. ---- To avoid some duplication `EvalCache::mkPathString` is added to abstract over the simple case of turning a store path to a string with just that string in the context. Context This PR picks up where #7543 left off. That one introduced the fully structured `NixStringContextElem` data type, but kept `PathSet context` as an awkward middle ground between internal `char[][]` interpreter heap string contexts and `NixStringContext` fully parsed string contexts. The infelicity of `PathSet context` was specifically called out during Nix team group review, but it was agreeing that fixing it could be left as future work. This is that future work. A possible follow-up step would be to get rid of the `char[][]` evaluator heap representation, too, but it is not yet clear how to do that. To use `NixStringContextElem` there we would need to get the STL containers to GC pointers in the GC build, and I am not sure how to do that. ---- PR #7543 effectively is writing the inverse of a `mkPathString`, `mkOutputString`, and one more such function for the `DrvDeep` case. I would like that PR to have property tests ensuring it is actually the inverse as expected. This PR sets things up nicely so that reworking that PR to be in that more elegant and better tested way is possible. Co-authored-by: Théophane Hufschmitt <7226587+thufschmitt@users.noreply.github.com>
This commit is contained in:
parent
ef432b2b15
commit
85f0cdc370
@ -96,7 +96,7 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
|
||||
auto v = attr->forceValue();
|
||||
|
||||
if (v.type() == nPath) {
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
auto storePath = state->copyPathToStore(context, Path(v.path));
|
||||
return {{
|
||||
.path = DerivedPath::Opaque {
|
||||
@ -107,10 +107,10 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
|
||||
}
|
||||
|
||||
else if (v.type() == nString) {
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
auto s = state->forceString(v, context, noPos, fmt("while evaluating the flake output attribute '%s'", attrPath));
|
||||
auto storePath = state->store->maybeParseStorePath(s);
|
||||
if (storePath && context.count(std::string(s))) {
|
||||
if (storePath && context.count(NixStringContextElem::Opaque { .path = *storePath })) {
|
||||
return {{
|
||||
.path = DerivedPath::Opaque {
|
||||
.path = std::move(*storePath),
|
||||
|
@ -596,7 +596,7 @@ bool NixRepl::processLine(std::string line)
|
||||
|
||||
const auto [path, line] = [&] () -> std::pair<Path, uint32_t> {
|
||||
if (v.type() == nPath || v.type() == nString) {
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
auto path = state->coerceToPath(noPos, v, context, "while evaluating the filename to edit");
|
||||
return {path, 0};
|
||||
} else if (v.isLambda()) {
|
||||
@ -940,7 +940,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
|
||||
if (isDrv) {
|
||||
str << "«derivation ";
|
||||
Bindings::iterator i = v.attrs->find(state->sDrvPath);
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
if (i != v.attrs->end())
|
||||
str << state->store->printStorePath(state->coerceToStorePath(i->pos, *i->value, context, "while evaluating the drvPath of a derivation"));
|
||||
else
|
||||
|
@ -47,7 +47,7 @@ struct AttrDb
|
||||
{
|
||||
auto state(_state->lock());
|
||||
|
||||
Path cacheDir = getCacheDir() + "/nix/eval-cache-v4";
|
||||
Path cacheDir = getCacheDir() + "/nix/eval-cache-v5";
|
||||
createDirs(cacheDir);
|
||||
|
||||
Path dbPath = cacheDir + "/" + fingerprint.to_string(Base16, false) + ".sqlite";
|
||||
@ -300,7 +300,7 @@ struct AttrDb
|
||||
NixStringContext context;
|
||||
if (!queryAttribute.isNull(3))
|
||||
for (auto & s : tokenizeString<std::vector<std::string>>(queryAttribute.getStr(3), ";"))
|
||||
context.push_back(NixStringContextElem::parse(cfg, s));
|
||||
context.insert(NixStringContextElem::parse(s));
|
||||
return {{rowId, string_t{queryAttribute.getStr(2), context}}};
|
||||
}
|
||||
case AttrType::Bool:
|
||||
@ -619,9 +619,11 @@ string_t AttrCursor::getStringWithContext()
|
||||
|
||||
auto & v = forceValue();
|
||||
|
||||
if (v.type() == nString)
|
||||
return {v.string.s, v.getContext(*root->state.store)};
|
||||
else if (v.type() == nPath)
|
||||
if (v.type() == nString) {
|
||||
NixStringContext context;
|
||||
copyContext(v, context);
|
||||
return {v.string.s, std::move(context)};
|
||||
} else if (v.type() == nPath)
|
||||
return {v.path, {}};
|
||||
else
|
||||
root->state.error("'%s' is not a string but %s", getAttrPathStr()).debugThrow<TypeError>();
|
||||
|
@ -609,8 +609,7 @@ void EvalState::allowAndSetStorePathString(const StorePath & storePath, Value &
|
||||
{
|
||||
allowPath(storePath);
|
||||
|
||||
auto path = store->printStorePath(storePath);
|
||||
v.mkString(path, PathSet({path}));
|
||||
mkStorePathString(storePath, v);
|
||||
}
|
||||
|
||||
Path EvalState::checkSourcePath(const Path & path_)
|
||||
@ -692,7 +691,7 @@ void EvalState::checkURI(const std::string & uri)
|
||||
}
|
||||
|
||||
|
||||
Path EvalState::toRealPath(const Path & path, const PathSet & context)
|
||||
Path EvalState::toRealPath(const Path & path, const NixStringContext & context)
|
||||
{
|
||||
// FIXME: check whether 'path' is in 'context'.
|
||||
return
|
||||
@ -944,25 +943,25 @@ void Value::mkString(std::string_view s)
|
||||
}
|
||||
|
||||
|
||||
static void copyContextToValue(Value & v, const PathSet & context)
|
||||
static void copyContextToValue(Value & v, const NixStringContext & context)
|
||||
{
|
||||
if (!context.empty()) {
|
||||
size_t n = 0;
|
||||
v.string.context = (const char * *)
|
||||
allocBytes((context.size() + 1) * sizeof(char *));
|
||||
for (auto & i : context)
|
||||
v.string.context[n++] = dupString(i.c_str());
|
||||
v.string.context[n++] = dupString(i.to_string().c_str());
|
||||
v.string.context[n] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Value::mkString(std::string_view s, const PathSet & context)
|
||||
void Value::mkString(std::string_view s, const NixStringContext & context)
|
||||
{
|
||||
mkString(s);
|
||||
copyContextToValue(*this, context);
|
||||
}
|
||||
|
||||
void Value::mkStringMove(const char * s, const PathSet & context)
|
||||
void Value::mkStringMove(const char * s, const NixStringContext & context)
|
||||
{
|
||||
mkString(s);
|
||||
copyContextToValue(*this, context);
|
||||
@ -1038,6 +1037,16 @@ void EvalState::mkPos(Value & v, PosIdx p)
|
||||
}
|
||||
|
||||
|
||||
void EvalState::mkStorePathString(const StorePath & p, Value & v)
|
||||
{
|
||||
v.mkString(
|
||||
store->printStorePath(p),
|
||||
NixStringContext {
|
||||
NixStringContextElem::Opaque { .path = p },
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/* Create a thunk for the delayed computation of the given expression
|
||||
in the given environment. But if the expression is a variable,
|
||||
then look it up right away. This significantly reduces the number
|
||||
@ -1900,7 +1909,7 @@ void EvalState::concatLists(Value & v, size_t nrLists, Value * * lists, const Po
|
||||
|
||||
void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||
{
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
std::vector<BackedStringView> s;
|
||||
size_t sSize = 0;
|
||||
NixInt n = 0;
|
||||
@ -2109,26 +2118,15 @@ std::string_view EvalState::forceString(Value & v, const PosIdx pos, std::string
|
||||
}
|
||||
|
||||
|
||||
void copyContext(const Value & v, PathSet & context)
|
||||
void copyContext(const Value & v, NixStringContext & context)
|
||||
{
|
||||
if (v.string.context)
|
||||
for (const char * * p = v.string.context; *p; ++p)
|
||||
context.insert(*p);
|
||||
context.insert(NixStringContextElem::parse(*p));
|
||||
}
|
||||
|
||||
|
||||
NixStringContext Value::getContext(const Store & store)
|
||||
{
|
||||
NixStringContext res;
|
||||
assert(internalType == tString);
|
||||
if (string.context)
|
||||
for (const char * * p = string.context; *p; ++p)
|
||||
res.push_back(NixStringContextElem::parse(store, *p));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
std::string_view EvalState::forceString(Value & v, PathSet & context, const PosIdx pos, std::string_view errorCtx)
|
||||
std::string_view EvalState::forceString(Value & v, NixStringContext & context, const PosIdx pos, std::string_view errorCtx)
|
||||
{
|
||||
auto s = forceString(v, pos, errorCtx);
|
||||
copyContext(v, context);
|
||||
@ -2158,7 +2156,7 @@ bool EvalState::isDerivation(Value & v)
|
||||
|
||||
|
||||
std::optional<std::string> EvalState::tryAttrsToString(const PosIdx pos, Value & v,
|
||||
PathSet & context, bool coerceMore, bool copyToStore)
|
||||
NixStringContext & context, bool coerceMore, bool copyToStore)
|
||||
{
|
||||
auto i = v.attrs->find(sToString);
|
||||
if (i != v.attrs->end()) {
|
||||
@ -2172,7 +2170,7 @@ std::optional<std::string> EvalState::tryAttrsToString(const PosIdx pos, Value &
|
||||
return {};
|
||||
}
|
||||
|
||||
BackedStringView EvalState::coerceToString(const PosIdx pos, Value &v, PathSet &context,
|
||||
BackedStringView EvalState::coerceToString(const PosIdx pos, Value &v, NixStringContext &context,
|
||||
std::string_view errorCtx, bool coerceMore, bool copyToStore, bool canonicalizePath)
|
||||
{
|
||||
forceValue(v, pos);
|
||||
@ -2249,7 +2247,7 @@ BackedStringView EvalState::coerceToString(const PosIdx pos, Value &v, PathSet &
|
||||
}
|
||||
|
||||
|
||||
StorePath EvalState::copyPathToStore(PathSet & context, const Path & path)
|
||||
StorePath EvalState::copyPathToStore(NixStringContext & context, const Path & path)
|
||||
{
|
||||
if (nix::isDerivation(path))
|
||||
error("file names are not allowed to end in '%1%'", drvExtension).debugThrow<EvalError>();
|
||||
@ -2268,12 +2266,14 @@ StorePath EvalState::copyPathToStore(PathSet & context, const Path & path)
|
||||
return dstPath;
|
||||
}();
|
||||
|
||||
context.insert(store->printStorePath(dstPath));
|
||||
context.insert(NixStringContextElem::Opaque {
|
||||
.path = dstPath
|
||||
});
|
||||
return dstPath;
|
||||
}
|
||||
|
||||
|
||||
Path EvalState::coerceToPath(const PosIdx pos, Value & v, PathSet & context, std::string_view errorCtx)
|
||||
Path EvalState::coerceToPath(const PosIdx pos, Value & v, NixStringContext & context, std::string_view errorCtx)
|
||||
{
|
||||
auto path = coerceToString(pos, v, context, errorCtx, false, false, true).toOwned();
|
||||
if (path == "" || path[0] != '/')
|
||||
@ -2282,7 +2282,7 @@ Path EvalState::coerceToPath(const PosIdx pos, Value & v, PathSet & context, std
|
||||
}
|
||||
|
||||
|
||||
StorePath EvalState::coerceToStorePath(const PosIdx pos, Value & v, PathSet & context, std::string_view errorCtx)
|
||||
StorePath EvalState::coerceToStorePath(const PosIdx pos, Value & v, NixStringContext & context, std::string_view errorCtx)
|
||||
{
|
||||
auto path = coerceToString(pos, v, context, errorCtx, false, false, true).toOwned();
|
||||
if (auto storePath = store->maybeParseStorePath(path))
|
||||
@ -2489,7 +2489,7 @@ void EvalState::printStats()
|
||||
}
|
||||
|
||||
|
||||
std::string ExternalValueBase::coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore) const
|
||||
std::string ExternalValueBase::coerceToString(const Pos & pos, NixStringContext & context, bool copyMore, bool copyToStore) const
|
||||
{
|
||||
throw TypeError({
|
||||
.msg = hintfmt("cannot coerce %1% to a string", showType())
|
||||
|
@ -56,7 +56,7 @@ void printEnvBindings(const SymbolTable & st, const StaticEnv & se, const Env &
|
||||
|
||||
std::unique_ptr<ValMap> mapStaticEnvBindings(const SymbolTable & st, const StaticEnv & se, const Env & env);
|
||||
|
||||
void copyContext(const Value & v, PathSet & context);
|
||||
void copyContext(const Value & v, NixStringContext & context);
|
||||
|
||||
|
||||
/**
|
||||
@ -327,7 +327,7 @@ public:
|
||||
* intended to distinguish between import-from-derivation and
|
||||
* sources stored in the actual /nix/store.
|
||||
*/
|
||||
Path toRealPath(const Path & path, const PathSet & context);
|
||||
Path toRealPath(const Path & path, const NixStringContext & context);
|
||||
|
||||
/**
|
||||
* Parse a Nix expression from the specified file.
|
||||
@ -423,7 +423,7 @@ public:
|
||||
*/
|
||||
void forceFunction(Value & v, const PosIdx pos, std::string_view errorCtx);
|
||||
std::string_view forceString(Value & v, const PosIdx pos, std::string_view errorCtx);
|
||||
std::string_view forceString(Value & v, PathSet & context, const PosIdx pos, std::string_view errorCtx);
|
||||
std::string_view forceString(Value & v, NixStringContext & context, const PosIdx pos, std::string_view errorCtx);
|
||||
std::string_view forceStringNoCtx(Value & v, const PosIdx pos, std::string_view errorCtx);
|
||||
|
||||
[[gnu::noinline]]
|
||||
@ -439,7 +439,7 @@ public:
|
||||
bool isDerivation(Value & v);
|
||||
|
||||
std::optional<std::string> tryAttrsToString(const PosIdx pos, Value & v,
|
||||
PathSet & context, bool coerceMore = false, bool copyToStore = true);
|
||||
NixStringContext & context, bool coerceMore = false, bool copyToStore = true);
|
||||
|
||||
/**
|
||||
* String coercion.
|
||||
@ -449,12 +449,12 @@ public:
|
||||
* booleans and lists to a string. If `copyToStore` is set,
|
||||
* referenced paths are copied to the Nix store as a side effect.
|
||||
*/
|
||||
BackedStringView coerceToString(const PosIdx pos, Value & v, PathSet & context,
|
||||
BackedStringView coerceToString(const PosIdx pos, Value & v, NixStringContext & context,
|
||||
std::string_view errorCtx,
|
||||
bool coerceMore = false, bool copyToStore = true,
|
||||
bool canonicalizePath = true);
|
||||
|
||||
StorePath copyPathToStore(PathSet & context, const Path & path);
|
||||
StorePath copyPathToStore(NixStringContext & context, const Path & path);
|
||||
|
||||
/**
|
||||
* Path coercion.
|
||||
@ -463,12 +463,12 @@ public:
|
||||
* path. The result is guaranteed to be a canonicalised, absolute
|
||||
* path. Nothing is copied to the store.
|
||||
*/
|
||||
Path coerceToPath(const PosIdx pos, Value & v, PathSet & context, std::string_view errorCtx);
|
||||
Path coerceToPath(const PosIdx pos, Value & v, NixStringContext & context, std::string_view errorCtx);
|
||||
|
||||
/**
|
||||
* Like coerceToPath, but the result must be a store path.
|
||||
*/
|
||||
StorePath coerceToStorePath(const PosIdx pos, Value & v, PathSet & context, std::string_view errorCtx);
|
||||
StorePath coerceToStorePath(const PosIdx pos, Value & v, NixStringContext & context, std::string_view errorCtx);
|
||||
|
||||
public:
|
||||
|
||||
@ -573,6 +573,12 @@ public:
|
||||
void mkThunk_(Value & v, Expr * expr);
|
||||
void mkPos(Value & v, PosIdx pos);
|
||||
|
||||
/* Create a string representing a store path.
|
||||
|
||||
The string is the printed store path with a context containing a single
|
||||
`Opaque` element of that store path. */
|
||||
void mkStorePathString(const StorePath & storePath, Value & v);
|
||||
|
||||
void concatLists(Value & v, size_t nrLists, Value * * lists, const PosIdx pos, std::string_view errorCtx);
|
||||
|
||||
/**
|
||||
@ -584,7 +590,7 @@ public:
|
||||
* Realise the given context, and return a mapping from the placeholders
|
||||
* used to construct the associated value to their final store path
|
||||
*/
|
||||
[[nodiscard]] StringMap realiseContext(const PathSet & context);
|
||||
[[nodiscard]] StringMap realiseContext(const NixStringContext & context);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -265,7 +265,7 @@ static Flake getFlake(
|
||||
state.symbols[setting.name],
|
||||
std::string(state.forceStringNoCtx(*setting.value, setting.pos, "")));
|
||||
else if (setting.value->type() == nPath) {
|
||||
PathSet emptyContext = {};
|
||||
NixStringContext emptyContext = {};
|
||||
flake.config.settings.emplace(
|
||||
state.symbols[setting.name],
|
||||
state.coerceToString(setting.pos, *setting.value, emptyContext, "", false, true, true) .toOwned());
|
||||
|
@ -71,7 +71,7 @@ std::optional<StorePath> DrvInfo::queryDrvPath() const
|
||||
{
|
||||
if (!drvPath && attrs) {
|
||||
Bindings::iterator i = attrs->find(state->sDrvPath);
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
if (i == attrs->end())
|
||||
drvPath = {std::nullopt};
|
||||
else
|
||||
@ -93,7 +93,7 @@ StorePath DrvInfo::queryOutPath() const
|
||||
{
|
||||
if (!outPath && attrs) {
|
||||
Bindings::iterator i = attrs->find(state->sOutPath);
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
if (i != attrs->end())
|
||||
outPath = state->coerceToStorePath(i->pos, *i->value, context, "while evaluating the output path of a derivation");
|
||||
}
|
||||
@ -124,7 +124,7 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool withPaths, bool onlyOutputsToInstall
|
||||
/* And evaluate its ‘outPath’ attribute. */
|
||||
Bindings::iterator outPath = out->value->attrs->find(state->sOutPath);
|
||||
if (outPath == out->value->attrs->end()) continue; // FIXME: throw error?
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
outputs.emplace(output, state->coerceToStorePath(outPath->pos, *outPath->value, context, "while evaluating an output path of a derivation"));
|
||||
} else
|
||||
outputs.emplace(output, std::nullopt);
|
||||
|
@ -38,17 +38,16 @@ namespace nix {
|
||||
InvalidPathError::InvalidPathError(const Path & path) :
|
||||
EvalError("path '%s' is not valid", path), path(path) {}
|
||||
|
||||
StringMap EvalState::realiseContext(const PathSet & context)
|
||||
StringMap EvalState::realiseContext(const NixStringContext & context)
|
||||
{
|
||||
std::vector<DerivedPath::Built> drvs;
|
||||
StringMap res;
|
||||
|
||||
for (auto & c_ : context) {
|
||||
for (auto & c : context) {
|
||||
auto ensureValid = [&](const StorePath & p) {
|
||||
if (!store->isValidPath(p))
|
||||
debugThrowLastTrace(InvalidPathError(store->printStorePath(p)));
|
||||
};
|
||||
auto c = NixStringContextElem::parse(*store, c_);
|
||||
std::visit(overloaded {
|
||||
[&](const NixStringContextElem::Built & b) {
|
||||
drvs.push_back(DerivedPath::Built {
|
||||
@ -112,7 +111,7 @@ struct RealisePathFlags {
|
||||
|
||||
static Path realisePath(EvalState & state, const PosIdx pos, Value & v, const RealisePathFlags flags = {})
|
||||
{
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
|
||||
auto path = state.coerceToPath(noPos, v, context, "while realising the context of a path");
|
||||
|
||||
@ -158,7 +157,12 @@ static void mkOutputString(
|
||||
/* FIXME: we need to depend on the basic derivation, not
|
||||
derivation */
|
||||
: downstreamPlaceholder(*state.store, drvPath, o.first),
|
||||
{"!" + o.first + "!" + state.store->printStorePath(drvPath)});
|
||||
NixStringContext {
|
||||
NixStringContextElem::Built {
|
||||
.drvPath = drvPath,
|
||||
.output = o.first,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* Load and evaluate an expression from path specified by the
|
||||
@ -181,7 +185,9 @@ static void import(EvalState & state, const PosIdx pos, Value & vPath, Value * v
|
||||
auto storePath = *optStorePath;
|
||||
Derivation drv = state.store->readDerivation(storePath);
|
||||
auto attrs = state.buildBindings(3 + drv.outputs.size());
|
||||
attrs.alloc(state.sDrvPath).mkString(path, {"=" + path});
|
||||
attrs.alloc(state.sDrvPath).mkString(path, {
|
||||
NixStringContextElem::DrvDeep { .drvPath = storePath },
|
||||
});
|
||||
attrs.alloc(state.sName).mkString(drv.env["name"]);
|
||||
auto & outputsVal = attrs.alloc(state.sOutputs);
|
||||
state.mkList(outputsVal, drv.outputs.size());
|
||||
@ -358,7 +364,7 @@ void prim_exec(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
auto count = args[0]->listSize();
|
||||
if (count == 0)
|
||||
state.error("at least one argument to 'exec' required").atPos(pos).debugThrow<EvalError>();
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
auto program = state.coerceToString(pos, *elems[0], context,
|
||||
"while evaluating the first element of the argument passed to builtins.exec",
|
||||
false, false).toOwned();
|
||||
@ -768,7 +774,7 @@ static RegisterPrimOp primop_abort({
|
||||
)",
|
||||
.fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
auto s = state.coerceToString(pos, *args[0], context,
|
||||
"while evaluating the error message passed to builtins.abort").toOwned();
|
||||
state.debugThrowLastTrace(Abort("evaluation aborted with the following error message: '%1%'", s));
|
||||
@ -787,7 +793,7 @@ static RegisterPrimOp primop_throw({
|
||||
)",
|
||||
.fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
auto s = state.coerceToString(pos, *args[0], context,
|
||||
"while evaluating the error message passed to builtin.throw").toOwned();
|
||||
state.debugThrowLastTrace(ThrownError(s));
|
||||
@ -800,7 +806,7 @@ static void prim_addErrorContext(EvalState & state, const PosIdx pos, Value * *
|
||||
state.forceValue(*args[1], pos);
|
||||
v = *args[1];
|
||||
} catch (Error & e) {
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
auto message = state.coerceToString(pos, *args[0], context,
|
||||
"while evaluating the error message passed to builtins.addErrorContext",
|
||||
false, false).toOwned();
|
||||
@ -1086,7 +1092,7 @@ drvName, Bindings * attrs, Value & v)
|
||||
Derivation drv;
|
||||
drv.name = drvName;
|
||||
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
|
||||
bool contentAddressed = false;
|
||||
bool isImpure = false;
|
||||
@ -1232,8 +1238,7 @@ drvName, Bindings * attrs, Value & v)
|
||||
/* Everything in the context of the strings in the derivation
|
||||
attributes should be added as dependencies of the resulting
|
||||
derivation. */
|
||||
for (auto & c_ : context) {
|
||||
auto c = NixStringContextElem::parse(*state.store, c_);
|
||||
for (auto & c : context) {
|
||||
std::visit(overloaded {
|
||||
/* Since this allows the builder to gain access to every
|
||||
path in the dependency graph of the derivation (including
|
||||
@ -1392,7 +1397,9 @@ drvName, Bindings * attrs, Value & v)
|
||||
}
|
||||
|
||||
auto result = state.buildBindings(1 + drv.outputs.size());
|
||||
result.alloc(state.sDrvPath).mkString(drvPathS, {"=" + drvPathS});
|
||||
result.alloc(state.sDrvPath).mkString(drvPathS, {
|
||||
NixStringContextElem::DrvDeep { .drvPath = drvPath },
|
||||
});
|
||||
for (auto & i : drv.outputs)
|
||||
mkOutputString(state, result, drvPath, drv, i);
|
||||
|
||||
@ -1437,7 +1444,7 @@ static RegisterPrimOp primop_placeholder({
|
||||
/* Convert the argument to a path. !!! obsolete? */
|
||||
static void prim_toPath(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
Path path = state.coerceToPath(pos, *args[0], context, "while evaluating the first argument passed to builtins.toPath");
|
||||
v.mkString(canonPath(path), context);
|
||||
}
|
||||
@ -1468,7 +1475,7 @@ static void prim_storePath(EvalState & state, const PosIdx pos, Value * * args,
|
||||
.errPos = state.positions[pos]
|
||||
}));
|
||||
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
Path path = state.checkSourcePath(state.coerceToPath(pos, *args[0], context, "while evaluating the first argument passed to builtins.storePath"));
|
||||
/* Resolve symlinks in ‘path’, unless ‘path’ itself is a symlink
|
||||
directly in the store. The latter condition is necessary so
|
||||
@ -1482,7 +1489,7 @@ static void prim_storePath(EvalState & state, const PosIdx pos, Value * * args,
|
||||
auto path2 = state.store->toStorePath(path).first;
|
||||
if (!settings.readOnlyMode)
|
||||
state.store->ensurePath(path2);
|
||||
context.insert(state.store->printStorePath(path2));
|
||||
context.insert(NixStringContextElem::Opaque { .path = path2 });
|
||||
v.mkString(path, context);
|
||||
}
|
||||
|
||||
@ -1538,7 +1545,7 @@ static RegisterPrimOp primop_pathExists({
|
||||
following the last slash. */
|
||||
static void prim_baseNameOf(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
v.mkString(baseNameOf(*state.coerceToString(pos, *args[0], context,
|
||||
"while evaluating the first argument passed to builtins.baseNameOf",
|
||||
false, false)), context);
|
||||
@ -1560,7 +1567,7 @@ static RegisterPrimOp primop_baseNameOf({
|
||||
of the argument. */
|
||||
static void prim_dirOf(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
auto path = state.coerceToString(pos, *args[0], context,
|
||||
"while evaluating the first argument passed to builtins.dirOf",
|
||||
false, false);
|
||||
@ -1597,7 +1604,12 @@ static void prim_readFile(EvalState & state, const PosIdx pos, Value * * args, V
|
||||
refsSink << s;
|
||||
refs = refsSink.getResultPaths();
|
||||
}
|
||||
auto context = state.store->printStorePathSet(refs);
|
||||
NixStringContext context;
|
||||
for (auto && p : std::move(refs)) {
|
||||
context.insert(NixStringContextElem::Opaque {
|
||||
.path = std::move((StorePath &&)p),
|
||||
});
|
||||
}
|
||||
v.mkString(s, context);
|
||||
}
|
||||
|
||||
@ -1628,7 +1640,7 @@ static void prim_findFile(EvalState & state, const PosIdx pos, Value * * args, V
|
||||
|
||||
i = getAttr(state, state.sPath, v2->attrs, "in an element of the __nixPath");
|
||||
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
auto path = state.coerceToString(pos, *i->value, context,
|
||||
"while evaluating the `path` attribute of an element of the list passed to builtins.findFile",
|
||||
false, false).toOwned();
|
||||
@ -1787,7 +1799,7 @@ static RegisterPrimOp primop_readDir({
|
||||
static void prim_toXML(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
std::ostringstream out;
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
printValueAsXML(state, true, false, *args[0], out, context, pos);
|
||||
v.mkString(out.str(), context);
|
||||
}
|
||||
@ -1895,7 +1907,7 @@ static RegisterPrimOp primop_toXML({
|
||||
static void prim_toJSON(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
std::ostringstream out;
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
printValueAsJSON(state, true, *args[0], pos, out, context);
|
||||
v.mkString(out.str(), context);
|
||||
}
|
||||
@ -1945,22 +1957,23 @@ static RegisterPrimOp primop_fromJSON({
|
||||
as an input by derivations. */
|
||||
static void prim_toFile(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
std::string name(state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.toFile"));
|
||||
std::string contents(state.forceString(*args[1], context, pos, "while evaluating the second argument passed to builtins.toFile"));
|
||||
|
||||
StorePathSet refs;
|
||||
|
||||
for (auto path : context) {
|
||||
if (path.at(0) != '/')
|
||||
for (auto c : context) {
|
||||
if (auto p = std::get_if<NixStringContextElem::Opaque>(&c))
|
||||
refs.insert(p->path);
|
||||
else
|
||||
state.debugThrowLastTrace(EvalError({
|
||||
.msg = hintfmt(
|
||||
"in 'toFile': the file named '%1%' must not contain a reference "
|
||||
"to a derivation but contains (%2%)",
|
||||
name, path),
|
||||
name, c.to_string()),
|
||||
.errPos = state.positions[pos]
|
||||
}));
|
||||
refs.insert(state.store->parseStorePath(path));
|
||||
}
|
||||
|
||||
auto storePath = settings.readOnlyMode
|
||||
@ -2061,7 +2074,7 @@ static void addPath(
|
||||
FileIngestionMethod method,
|
||||
const std::optional<Hash> expectedHash,
|
||||
Value & v,
|
||||
const PathSet & context)
|
||||
const NixStringContext & context)
|
||||
{
|
||||
try {
|
||||
// FIXME: handle CA derivation outputs (where path needs to
|
||||
@ -2135,7 +2148,7 @@ static void addPath(
|
||||
|
||||
static void prim_filterSource(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
Path path = state.coerceToPath(pos, *args[1], context, "while evaluating the second argument (the path to filter) passed to builtins.filterSource");
|
||||
state.forceFunction(*args[0], pos, "while evaluating the first argument passed to builtins.filterSource");
|
||||
addPath(state, pos, std::string(baseNameOf(path)), path, args[0], FileIngestionMethod::Recursive, std::nullopt, v, context);
|
||||
@ -2204,7 +2217,7 @@ static void prim_path(EvalState & state, const PosIdx pos, Value * * args, Value
|
||||
Value * filterFun = nullptr;
|
||||
auto method = FileIngestionMethod::Recursive;
|
||||
std::optional<Hash> expectedHash;
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
|
||||
for (auto & attr : *args[0]->attrs) {
|
||||
auto n = state.symbols[attr.name];
|
||||
@ -3538,7 +3551,7 @@ static RegisterPrimOp primop_lessThan({
|
||||
`"/nix/store/whatever..."'. */
|
||||
static void prim_toString(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
auto s = state.coerceToString(pos, *args[0], context,
|
||||
"while evaluating the first argument passed to builtins.toString",
|
||||
true, false);
|
||||
@ -3577,7 +3590,7 @@ static void prim_substring(EvalState & state, const PosIdx pos, Value * * args,
|
||||
{
|
||||
int start = state.forceInt(*args[0], pos, "while evaluating the first argument (the start offset) passed to builtins.substring");
|
||||
int len = state.forceInt(*args[1], pos, "while evaluating the second argument (the substring length) passed to builtins.substring");
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
auto s = state.coerceToString(pos, *args[2], context, "while evaluating the third argument (the string) passed to builtins.substring");
|
||||
|
||||
if (start < 0)
|
||||
@ -3611,7 +3624,7 @@ static RegisterPrimOp primop_substring({
|
||||
|
||||
static void prim_stringLength(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
auto s = state.coerceToString(pos, *args[0], context, "while evaluating the argument passed to builtins.stringLength");
|
||||
v.mkInt(s->size());
|
||||
}
|
||||
@ -3637,7 +3650,7 @@ static void prim_hashString(EvalState & state, const PosIdx pos, Value * * args,
|
||||
.errPos = state.positions[pos]
|
||||
}));
|
||||
|
||||
PathSet context; // discarded
|
||||
NixStringContext context; // discarded
|
||||
auto s = state.forceString(*args[1], context, pos, "while evaluating the second argument passed to builtins.hashString");
|
||||
|
||||
v.mkString(hashString(*ht, s).to_string(Base16, false));
|
||||
@ -3683,7 +3696,7 @@ void prim_match(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
|
||||
auto regex = state.regexCache->get(re);
|
||||
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
const auto str = state.forceString(*args[1], context, pos, "while evaluating the second argument passed to builtins.match");
|
||||
|
||||
std::cmatch match;
|
||||
@ -3763,7 +3776,7 @@ void prim_split(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
|
||||
auto regex = state.regexCache->get(re);
|
||||
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
const auto str = state.forceString(*args[1], context, pos, "while evaluating the second argument passed to builtins.split");
|
||||
|
||||
auto begin = std::cregex_iterator(str.begin(), str.end(), regex);
|
||||
@ -3860,7 +3873,7 @@ static RegisterPrimOp primop_split({
|
||||
|
||||
static void prim_concatStringsSep(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
|
||||
auto sep = state.forceString(*args[0], context, pos, "while evaluating the first argument (the separator string) passed to builtins.concatStringsSep");
|
||||
state.forceList(*args[1], pos, "while evaluating the second argument (the list of strings to concat) passed to builtins.concatStringsSep");
|
||||
@ -3900,15 +3913,15 @@ static void prim_replaceStrings(EvalState & state, const PosIdx pos, Value * * a
|
||||
for (auto elem : args[0]->listItems())
|
||||
from.emplace_back(state.forceString(*elem, pos, "while evaluating one of the strings to replace passed to builtins.replaceStrings"));
|
||||
|
||||
std::vector<std::pair<std::string, PathSet>> to;
|
||||
std::vector<std::pair<std::string, NixStringContext>> to;
|
||||
to.reserve(args[1]->listSize());
|
||||
for (auto elem : args[1]->listItems()) {
|
||||
PathSet ctx;
|
||||
NixStringContext ctx;
|
||||
auto s = state.forceString(*elem, ctx, pos, "while evaluating one of the replacement strings passed to builtins.replaceStrings");
|
||||
to.emplace_back(s, std::move(ctx));
|
||||
}
|
||||
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
auto s = state.forceString(*args[2], context, pos, "while evaluating the third argument passed to builtins.replaceStrings");
|
||||
|
||||
std::string res;
|
||||
|
@ -7,7 +7,7 @@ namespace nix {
|
||||
|
||||
static void prim_unsafeDiscardStringContext(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
auto s = state.coerceToString(pos, *args[0], context, "while evaluating the argument passed to builtins.unsafeDiscardStringContext");
|
||||
v.mkString(*s);
|
||||
}
|
||||
@ -17,7 +17,7 @@ static RegisterPrimOp primop_unsafeDiscardStringContext("__unsafeDiscardStringCo
|
||||
|
||||
static void prim_hasContext(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
state.forceString(*args[0], context, pos, "while evaluating the argument passed to builtins.hasContext");
|
||||
v.mkBool(!context.empty());
|
||||
}
|
||||
@ -33,17 +33,18 @@ static RegisterPrimOp primop_hasContext("__hasContext", 1, prim_hasContext);
|
||||
drv.inputDrvs. */
|
||||
static void prim_unsafeDiscardOutputDependency(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
auto s = state.coerceToString(pos, *args[0], context, "while evaluating the argument passed to builtins.unsafeDiscardOutputDependency");
|
||||
|
||||
PathSet context2;
|
||||
for (auto && p : context) {
|
||||
auto c = NixStringContextElem::parse(*state.store, p);
|
||||
NixStringContext context2;
|
||||
for (auto && c : context) {
|
||||
if (auto * ptr = std::get_if<NixStringContextElem::DrvDeep>(&c)) {
|
||||
context2.emplace(state.store->printStorePath(ptr->drvPath));
|
||||
context2.emplace(NixStringContextElem::Opaque {
|
||||
.path = ptr->drvPath
|
||||
});
|
||||
} else {
|
||||
/* Can reuse original item */
|
||||
context2.emplace(std::move(p));
|
||||
context2.emplace(std::move(c));
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,22 +80,21 @@ static void prim_getContext(EvalState & state, const PosIdx pos, Value * * args,
|
||||
bool allOutputs = false;
|
||||
Strings outputs;
|
||||
};
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
state.forceString(*args[0], context, pos, "while evaluating the argument passed to builtins.getContext");
|
||||
auto contextInfos = std::map<StorePath, ContextInfo>();
|
||||
for (const auto & p : context) {
|
||||
NixStringContextElem ctx = NixStringContextElem::parse(*state.store, p);
|
||||
for (auto && i : context) {
|
||||
std::visit(overloaded {
|
||||
[&](NixStringContextElem::DrvDeep & d) {
|
||||
contextInfos[d.drvPath].allOutputs = true;
|
||||
[&](NixStringContextElem::DrvDeep && d) {
|
||||
contextInfos[std::move(d.drvPath)].allOutputs = true;
|
||||
},
|
||||
[&](NixStringContextElem::Built & b) {
|
||||
contextInfos[b.drvPath].outputs.emplace_back(std::move(b.output));
|
||||
[&](NixStringContextElem::Built && b) {
|
||||
contextInfos[std::move(b.drvPath)].outputs.emplace_back(std::move(b.output));
|
||||
},
|
||||
[&](NixStringContextElem::Opaque & o) {
|
||||
contextInfos[o.path].path = true;
|
||||
[&](NixStringContextElem::Opaque && o) {
|
||||
contextInfos[std::move(o.path)].path = true;
|
||||
},
|
||||
}, ctx.raw());
|
||||
}, ((NixStringContextElem &&) i).raw());
|
||||
}
|
||||
|
||||
auto attrs = state.buildBindings(contextInfos.size());
|
||||
@ -129,7 +129,7 @@ static RegisterPrimOp primop_getContext("__getContext", 1, prim_getContext);
|
||||
*/
|
||||
static void prim_appendContext(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
auto orig = state.forceString(*args[0], context, noPos, "while evaluating the first argument passed to builtins.appendContext");
|
||||
|
||||
state.forceAttrs(*args[1], pos, "while evaluating the second argument passed to builtins.appendContext");
|
||||
@ -143,13 +143,16 @@ static void prim_appendContext(EvalState & state, const PosIdx pos, Value * * ar
|
||||
.msg = hintfmt("context key '%s' is not a store path", name),
|
||||
.errPos = state.positions[i.pos]
|
||||
});
|
||||
auto namePath = state.store->parseStorePath(name);
|
||||
if (!settings.readOnlyMode)
|
||||
state.store->ensurePath(state.store->parseStorePath(name));
|
||||
state.store->ensurePath(namePath);
|
||||
state.forceAttrs(*i.value, i.pos, "while evaluating the value of a string context");
|
||||
auto iter = i.value->attrs->find(sPath);
|
||||
if (iter != i.value->attrs->end()) {
|
||||
if (state.forceBool(*iter->value, iter->pos, "while evaluating the `path` attribute of a string context"))
|
||||
context.emplace(name);
|
||||
context.emplace(NixStringContextElem::Opaque {
|
||||
.path = namePath,
|
||||
});
|
||||
}
|
||||
|
||||
iter = i.value->attrs->find(sAllOutputs);
|
||||
@ -161,7 +164,9 @@ static void prim_appendContext(EvalState & state, const PosIdx pos, Value * * ar
|
||||
.errPos = state.positions[i.pos]
|
||||
});
|
||||
}
|
||||
context.insert(concatStrings("=", name));
|
||||
context.emplace(NixStringContextElem::DrvDeep {
|
||||
.drvPath = namePath,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -176,7 +181,10 @@ static void prim_appendContext(EvalState & state, const PosIdx pos, Value * * ar
|
||||
}
|
||||
for (auto elem : iter->value->listItems()) {
|
||||
auto outputName = state.forceStringNoCtx(*elem, iter->pos, "while evaluating an output name within a string context");
|
||||
context.insert(concatStrings("!", outputName, "!", name));
|
||||
context.emplace(NixStringContextElem::Built {
|
||||
.drvPath = namePath,
|
||||
.output = std::string { outputName },
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value * * arg
|
||||
const auto & attrName = state.symbols[attr.name];
|
||||
|
||||
if (attrName == "fromPath") {
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
fromPath = state.coerceToStorePath(attr.pos, *attr.value, context,
|
||||
"while evaluating the 'fromPath' attribute passed to builtins.fetchClosure");
|
||||
}
|
||||
@ -27,7 +27,7 @@ static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value * * arg
|
||||
state.forceValue(*attr.value, attr.pos);
|
||||
toCA = true;
|
||||
if (attr.value->type() != nString || attr.value->string.s != std::string("")) {
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
toPath = state.coerceToStorePath(attr.pos, *attr.value, context,
|
||||
"while evaluating the 'toPath' attribute passed to builtins.fetchClosure");
|
||||
}
|
||||
@ -114,8 +114,7 @@ static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value * * arg
|
||||
});
|
||||
}
|
||||
|
||||
auto toPathS = state.store->printStorePath(*toPath);
|
||||
v.mkString(toPathS, {toPathS});
|
||||
state.mkStorePathString(*toPath, v);
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_fetchClosure({
|
||||
|
@ -13,7 +13,7 @@ static void prim_fetchMercurial(EvalState & state, const PosIdx pos, Value * * a
|
||||
std::optional<Hash> rev;
|
||||
std::optional<std::string> ref;
|
||||
std::string_view name = "source";
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
|
||||
state.forceValue(*args[0], pos);
|
||||
|
||||
@ -73,8 +73,7 @@ static void prim_fetchMercurial(EvalState & state, const PosIdx pos, Value * * a
|
||||
auto [tree, input2] = input.fetch(state.store);
|
||||
|
||||
auto attrs2 = state.buildBindings(8);
|
||||
auto storePath = state.store->printStorePath(tree.storePath);
|
||||
attrs2.alloc(state.sOutPath).mkString(storePath, {storePath});
|
||||
state.mkStorePathString(tree.storePath, attrs2.alloc(state.sOutPath));
|
||||
if (input2.getRef())
|
||||
attrs2.alloc("branch").mkString(*input2.getRef());
|
||||
// Backward compatibility: set 'rev' to
|
||||
|
@ -24,9 +24,8 @@ void emitTreeAttrs(
|
||||
|
||||
auto attrs = state.buildBindings(8);
|
||||
|
||||
auto storePath = state.store->printStorePath(tree.storePath);
|
||||
|
||||
attrs.alloc(state.sOutPath).mkString(storePath, {storePath});
|
||||
state.mkStorePathString(tree.storePath, attrs.alloc(state.sOutPath));
|
||||
|
||||
// FIXME: support arbitrary input attributes.
|
||||
|
||||
@ -107,7 +106,7 @@ static void fetchTree(
|
||||
const FetchTreeParams & params = FetchTreeParams{}
|
||||
) {
|
||||
fetchers::Input input;
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
|
||||
state.forceValue(*args[0], pos);
|
||||
|
||||
|
@ -8,7 +8,7 @@ namespace nix {
|
||||
protected:
|
||||
std::string getJSONValue(Value& value) {
|
||||
std::stringstream ss;
|
||||
PathSet ps;
|
||||
NixStringContext ps;
|
||||
printValueAsJSON(state, true, value, noPos, ss, ps);
|
||||
return ss.str();
|
||||
}
|
||||
|
@ -8,69 +8,62 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
// Testing of trivial expressions
|
||||
struct NixStringContextElemTest : public LibExprTest {
|
||||
const Store & store() const {
|
||||
return *LibExprTest::store;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(NixStringContextElemTest, empty_invalid) {
|
||||
TEST(NixStringContextElemTest, empty_invalid) {
|
||||
EXPECT_THROW(
|
||||
NixStringContextElem::parse(store(), ""),
|
||||
NixStringContextElem::parse(""),
|
||||
BadNixStringContextElem);
|
||||
}
|
||||
|
||||
TEST_F(NixStringContextElemTest, single_bang_invalid) {
|
||||
TEST(NixStringContextElemTest, single_bang_invalid) {
|
||||
EXPECT_THROW(
|
||||
NixStringContextElem::parse(store(), "!"),
|
||||
NixStringContextElem::parse("!"),
|
||||
BadNixStringContextElem);
|
||||
}
|
||||
|
||||
TEST_F(NixStringContextElemTest, double_bang_invalid) {
|
||||
TEST(NixStringContextElemTest, double_bang_invalid) {
|
||||
EXPECT_THROW(
|
||||
NixStringContextElem::parse(store(), "!!/"),
|
||||
NixStringContextElem::parse("!!/"),
|
||||
BadStorePath);
|
||||
}
|
||||
|
||||
TEST_F(NixStringContextElemTest, eq_slash_invalid) {
|
||||
TEST(NixStringContextElemTest, eq_slash_invalid) {
|
||||
EXPECT_THROW(
|
||||
NixStringContextElem::parse(store(), "=/"),
|
||||
NixStringContextElem::parse("=/"),
|
||||
BadStorePath);
|
||||
}
|
||||
|
||||
TEST_F(NixStringContextElemTest, slash_invalid) {
|
||||
TEST(NixStringContextElemTest, slash_invalid) {
|
||||
EXPECT_THROW(
|
||||
NixStringContextElem::parse(store(), "/"),
|
||||
NixStringContextElem::parse("/"),
|
||||
BadStorePath);
|
||||
}
|
||||
|
||||
TEST_F(NixStringContextElemTest, opaque) {
|
||||
std::string_view opaque = "/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x";
|
||||
auto elem = NixStringContextElem::parse(store(), opaque);
|
||||
TEST(NixStringContextElemTest, opaque) {
|
||||
std::string_view opaque = "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x";
|
||||
auto elem = NixStringContextElem::parse(opaque);
|
||||
auto * p = std::get_if<NixStringContextElem::Opaque>(&elem);
|
||||
ASSERT_TRUE(p);
|
||||
ASSERT_EQ(p->path, store().parseStorePath(opaque));
|
||||
ASSERT_EQ(elem.to_string(store()), opaque);
|
||||
ASSERT_EQ(p->path, StorePath { opaque });
|
||||
ASSERT_EQ(elem.to_string(), opaque);
|
||||
}
|
||||
|
||||
TEST_F(NixStringContextElemTest, drvDeep) {
|
||||
std::string_view drvDeep = "=/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x.drv";
|
||||
auto elem = NixStringContextElem::parse(store(), drvDeep);
|
||||
TEST(NixStringContextElemTest, drvDeep) {
|
||||
std::string_view drvDeep = "=g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x.drv";
|
||||
auto elem = NixStringContextElem::parse(drvDeep);
|
||||
auto * p = std::get_if<NixStringContextElem::DrvDeep>(&elem);
|
||||
ASSERT_TRUE(p);
|
||||
ASSERT_EQ(p->drvPath, store().parseStorePath(drvDeep.substr(1)));
|
||||
ASSERT_EQ(elem.to_string(store()), drvDeep);
|
||||
ASSERT_EQ(p->drvPath, StorePath { drvDeep.substr(1) });
|
||||
ASSERT_EQ(elem.to_string(), drvDeep);
|
||||
}
|
||||
|
||||
TEST_F(NixStringContextElemTest, built) {
|
||||
std::string_view built = "!foo!/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x.drv";
|
||||
auto elem = NixStringContextElem::parse(store(), built);
|
||||
TEST(NixStringContextElemTest, built) {
|
||||
std::string_view built = "!foo!g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x.drv";
|
||||
auto elem = NixStringContextElem::parse(built);
|
||||
auto * p = std::get_if<NixStringContextElem::Built>(&elem);
|
||||
ASSERT_TRUE(p);
|
||||
ASSERT_EQ(p->output, "foo");
|
||||
ASSERT_EQ(p->drvPath, store().parseStorePath(built.substr(5)));
|
||||
ASSERT_EQ(elem.to_string(store()), built);
|
||||
ASSERT_EQ(p->drvPath, StorePath { built.substr(5) });
|
||||
ASSERT_EQ(elem.to_string(), built);
|
||||
}
|
||||
|
||||
}
|
||||
@ -116,12 +109,12 @@ Gen<NixStringContextElem> Arbitrary<NixStringContextElem>::arbitrary()
|
||||
|
||||
namespace nix {
|
||||
|
||||
RC_GTEST_FIXTURE_PROP(
|
||||
RC_GTEST_PROP(
|
||||
NixStringContextElemTest,
|
||||
prop_round_rip,
|
||||
(const NixStringContextElem & o))
|
||||
{
|
||||
RC_ASSERT(o == NixStringContextElem::parse(store(), o.to_string(store())));
|
||||
RC_ASSERT(o == NixStringContextElem::parse(o.to_string()));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
namespace nix {
|
||||
using json = nlohmann::json;
|
||||
json printValueAsJSON(EvalState & state, bool strict,
|
||||
Value & v, const PosIdx pos, PathSet & context, bool copyToStore)
|
||||
Value & v, const PosIdx pos, NixStringContext & context, bool copyToStore)
|
||||
{
|
||||
checkInterrupt();
|
||||
|
||||
@ -94,13 +94,13 @@ json printValueAsJSON(EvalState & state, bool strict,
|
||||
}
|
||||
|
||||
void printValueAsJSON(EvalState & state, bool strict,
|
||||
Value & v, const PosIdx pos, std::ostream & str, PathSet & context, bool copyToStore)
|
||||
Value & v, const PosIdx pos, std::ostream & str, NixStringContext & context, bool copyToStore)
|
||||
{
|
||||
str << printValueAsJSON(state, strict, v, pos, context, copyToStore);
|
||||
}
|
||||
|
||||
json ExternalValueBase::printValueAsJSON(EvalState & state, bool strict,
|
||||
PathSet & context, bool copyToStore) const
|
||||
NixStringContext & context, bool copyToStore) const
|
||||
{
|
||||
state.debugThrowLastTrace(TypeError("cannot convert %1% to JSON", showType()));
|
||||
}
|
||||
|
@ -11,9 +11,9 @@
|
||||
namespace nix {
|
||||
|
||||
nlohmann::json printValueAsJSON(EvalState & state, bool strict,
|
||||
Value & v, const PosIdx pos, PathSet & context, bool copyToStore = true);
|
||||
Value & v, const PosIdx pos, NixStringContext & context, bool copyToStore = true);
|
||||
|
||||
void printValueAsJSON(EvalState & state, bool strict,
|
||||
Value & v, const PosIdx pos, std::ostream & str, PathSet & context, bool copyToStore = true);
|
||||
Value & v, const PosIdx pos, std::ostream & str, NixStringContext & context, bool copyToStore = true);
|
||||
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ static XMLAttrs singletonAttrs(const std::string & name, const std::string & val
|
||||
|
||||
|
||||
static void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||
Value & v, XMLWriter & doc, PathSet & context, PathSet & drvsSeen,
|
||||
Value & v, XMLWriter & doc, NixStringContext & context, PathSet & drvsSeen,
|
||||
const PosIdx pos);
|
||||
|
||||
|
||||
@ -32,7 +32,7 @@ static void posToXML(EvalState & state, XMLAttrs & xmlAttrs, const Pos & pos)
|
||||
|
||||
|
||||
static void showAttrs(EvalState & state, bool strict, bool location,
|
||||
Bindings & attrs, XMLWriter & doc, PathSet & context, PathSet & drvsSeen)
|
||||
Bindings & attrs, XMLWriter & doc, NixStringContext & context, PathSet & drvsSeen)
|
||||
{
|
||||
StringSet names;
|
||||
|
||||
@ -54,7 +54,7 @@ static void showAttrs(EvalState & state, bool strict, bool location,
|
||||
|
||||
|
||||
static void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||
Value & v, XMLWriter & doc, PathSet & context, PathSet & drvsSeen,
|
||||
Value & v, XMLWriter & doc, NixStringContext & context, PathSet & drvsSeen,
|
||||
const PosIdx pos)
|
||||
{
|
||||
checkInterrupt();
|
||||
@ -166,7 +166,7 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||
|
||||
|
||||
void ExternalValueBase::printValueAsXML(EvalState & state, bool strict,
|
||||
bool location, XMLWriter & doc, PathSet & context, PathSet & drvsSeen,
|
||||
bool location, XMLWriter & doc, NixStringContext & context, PathSet & drvsSeen,
|
||||
const PosIdx pos) const
|
||||
{
|
||||
doc.writeEmptyElement("unevaluated");
|
||||
@ -174,7 +174,7 @@ void ExternalValueBase::printValueAsXML(EvalState & state, bool strict,
|
||||
|
||||
|
||||
void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||
Value & v, std::ostream & out, PathSet & context, const PosIdx pos)
|
||||
Value & v, std::ostream & out, NixStringContext & context, const PosIdx pos)
|
||||
{
|
||||
XMLWriter doc(true, out);
|
||||
XMLOpenElement root(doc, "expr");
|
||||
|
@ -10,6 +10,6 @@
|
||||
namespace nix {
|
||||
|
||||
void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||
Value & v, std::ostream & out, PathSet & context, const PosIdx pos);
|
||||
Value & v, std::ostream & out, NixStringContext & context, const PosIdx pos);
|
||||
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ class ExternalValueBase
|
||||
* Coerce the value to a string. Defaults to uncoercable, i.e. throws an
|
||||
* error.
|
||||
*/
|
||||
virtual std::string coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore) const;
|
||||
virtual std::string coerceToString(const Pos & pos, NixStringContext & context, bool copyMore, bool copyToStore) const;
|
||||
|
||||
/**
|
||||
* Compare to another value of the same type. Defaults to uncomparable,
|
||||
@ -112,13 +112,13 @@ class ExternalValueBase
|
||||
* Print the value as JSON. Defaults to unconvertable, i.e. throws an error
|
||||
*/
|
||||
virtual nlohmann::json printValueAsJSON(EvalState & state, bool strict,
|
||||
PathSet & context, bool copyToStore = true) const;
|
||||
NixStringContext & context, bool copyToStore = true) const;
|
||||
|
||||
/**
|
||||
* Print the value as XML. Defaults to unevaluated
|
||||
*/
|
||||
virtual void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||
XMLWriter & doc, PathSet & context, PathSet & drvsSeen,
|
||||
XMLWriter & doc, NixStringContext & context, PathSet & drvsSeen,
|
||||
const PosIdx pos) const;
|
||||
|
||||
virtual ~ExternalValueBase()
|
||||
@ -268,9 +268,9 @@ public:
|
||||
|
||||
void mkString(std::string_view s);
|
||||
|
||||
void mkString(std::string_view s, const PathSet & context);
|
||||
void mkString(std::string_view s, const NixStringContext & context);
|
||||
|
||||
void mkStringMove(const char * s, const PathSet & context);
|
||||
void mkStringMove(const char * s, const NixStringContext & context);
|
||||
|
||||
inline void mkPath(const char * s)
|
||||
{
|
||||
@ -394,8 +394,6 @@ public:
|
||||
*/
|
||||
bool isTrivial() const;
|
||||
|
||||
NixStringContext getContext(const Store &);
|
||||
|
||||
auto listItems()
|
||||
{
|
||||
struct ListIterable
|
||||
|
@ -1,11 +1,10 @@
|
||||
#include "value/context.hh"
|
||||
#include "store-api.hh"
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace nix {
|
||||
|
||||
NixStringContextElem NixStringContextElem::parse(const Store & store, std::string_view s0)
|
||||
NixStringContextElem NixStringContextElem::parse(std::string_view s0)
|
||||
{
|
||||
std::string_view s = s0;
|
||||
|
||||
@ -25,41 +24,41 @@ NixStringContextElem NixStringContextElem::parse(const Store & store, std::strin
|
||||
"String content element beginning with '!' should have a second '!'");
|
||||
}
|
||||
return NixStringContextElem::Built {
|
||||
.drvPath = store.parseStorePath(s.substr(index + 1)),
|
||||
.drvPath = StorePath { s.substr(index + 1) },
|
||||
.output = std::string(s.substr(0, index)),
|
||||
};
|
||||
}
|
||||
case '=': {
|
||||
return NixStringContextElem::DrvDeep {
|
||||
.drvPath = store.parseStorePath(s.substr(1)),
|
||||
.drvPath = StorePath { s.substr(1) },
|
||||
};
|
||||
}
|
||||
default: {
|
||||
return NixStringContextElem::Opaque {
|
||||
.path = store.parseStorePath(s),
|
||||
.path = StorePath { s },
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string NixStringContextElem::to_string(const Store & store) const {
|
||||
std::string NixStringContextElem::to_string() const {
|
||||
return std::visit(overloaded {
|
||||
[&](const NixStringContextElem::Built & b) {
|
||||
std::string res;
|
||||
res += '!';
|
||||
res += b.output;
|
||||
res += '!';
|
||||
res += store.printStorePath(b.drvPath);
|
||||
res += b.drvPath.to_string();
|
||||
return res;
|
||||
},
|
||||
[&](const NixStringContextElem::DrvDeep & d) {
|
||||
std::string res;
|
||||
res += '=';
|
||||
res += store.printStorePath(d.drvPath);
|
||||
res += d.drvPath.to_string();
|
||||
return res;
|
||||
},
|
||||
[&](const NixStringContextElem::Opaque & o) {
|
||||
return store.printStorePath(o.path);
|
||||
return std::string { o.path.to_string() };
|
||||
},
|
||||
}, raw());
|
||||
}
|
||||
|
@ -26,8 +26,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class Store;
|
||||
|
||||
/**
|
||||
* Plain opaque path to some store object.
|
||||
*
|
||||
@ -80,12 +78,15 @@ struct NixStringContextElem : _NixStringContextElem_Raw {
|
||||
using DrvDeep = NixStringContextElem_DrvDeep;
|
||||
using Built = NixStringContextElem_Built;
|
||||
|
||||
inline const Raw & raw() const {
|
||||
inline const Raw & raw() const & {
|
||||
return static_cast<const Raw &>(*this);
|
||||
}
|
||||
inline Raw & raw() {
|
||||
inline Raw & raw() & {
|
||||
return static_cast<Raw &>(*this);
|
||||
}
|
||||
inline Raw && raw() && {
|
||||
return static_cast<Raw &&>(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a context string, one of:
|
||||
@ -93,10 +94,10 @@ struct NixStringContextElem : _NixStringContextElem_Raw {
|
||||
* - ‘=<path>’
|
||||
* - ‘!<name>!<path>’
|
||||
*/
|
||||
static NixStringContextElem parse(const Store & store, std::string_view s);
|
||||
std::string to_string(const Store & store) const;
|
||||
static NixStringContextElem parse(std::string_view s);
|
||||
std::string to_string() const;
|
||||
};
|
||||
|
||||
typedef std::vector<NixStringContextElem> NixStringContext;
|
||||
typedef std::set<NixStringContextElem> NixStringContext;
|
||||
|
||||
}
|
||||
|
@ -960,7 +960,7 @@ static void queryJSON(Globals & globals, std::vector<DrvInfo> & elems, bool prin
|
||||
printError("derivation '%s' has invalid meta attribute '%s'", i.queryName(), j);
|
||||
metaObj[j] = nullptr;
|
||||
} else {
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
metaObj[j] = printValueAsJSON(*globals.state, true, *v, noPos, context);
|
||||
}
|
||||
}
|
||||
|
@ -119,9 +119,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
||||
/* Construct a Nix expression that calls the user environment
|
||||
builder with the manifest as argument. */
|
||||
auto attrs = state.buildBindings(3);
|
||||
attrs.alloc("manifest").mkString(
|
||||
state.store->printStorePath(manifestFile),
|
||||
{state.store->printStorePath(manifestFile)});
|
||||
state.mkStorePathString(manifestFile, attrs.alloc("manifest"));
|
||||
attrs.insert(state.symbols.create("derivations"), &manifest);
|
||||
Value args;
|
||||
args.mkAttrs(attrs);
|
||||
@ -132,7 +130,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
||||
/* Evaluate it. */
|
||||
debug("evaluating user environment builder");
|
||||
state.forceValue(topLevel, [&]() { return topLevel.determinePos(noPos); });
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
Attr & aDrvPath(*topLevel.attrs->find(state.sDrvPath));
|
||||
auto topLevelDrv = state.coerceToStorePath(aDrvPath.pos, *aDrvPath.value, context, "");
|
||||
Attr & aOutPath(*topLevel.attrs->find(state.sOutPath));
|
||||
|
@ -43,7 +43,7 @@ void processExpr(EvalState & state, const Strings & attrPaths,
|
||||
Value & v(*findAlongAttrPath(state, i, autoArgs, vRoot).first);
|
||||
state.forceValue(v, [&]() { return v.determinePos(noPos); });
|
||||
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
if (evalOnly) {
|
||||
Value vRes;
|
||||
if (autoArgs.empty())
|
||||
|
@ -98,7 +98,7 @@ struct CmdBundle : InstallableValueCommand
|
||||
if (!attr1)
|
||||
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
|
||||
|
||||
PathSet context2;
|
||||
NixStringContext context2;
|
||||
auto drvPath = evalState->coerceToStorePath(attr1->pos, *attr1->value, context2, "");
|
||||
|
||||
auto attr2 = vRes->attrs->get(evalState->sOutPath);
|
||||
|
@ -62,7 +62,7 @@ struct CmdEval : MixJSON, InstallableValueCommand, MixReadOnlyOption
|
||||
auto state = getEvalState();
|
||||
|
||||
auto [v, pos] = installable->toValue(*state);
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
|
||||
if (apply) {
|
||||
auto vApply = state->allocValue();
|
||||
|
@ -438,7 +438,7 @@ struct CmdFlakeCheck : FlakeCommand
|
||||
|
||||
if (auto attr = v.attrs->get(state->symbols.create("path"))) {
|
||||
if (attr->name == state->symbols.create("path")) {
|
||||
PathSet context;
|
||||
NixStringContext context;
|
||||
auto path = state->coerceToPath(attr->pos, *attr->value, context, "");
|
||||
if (!store->isInStore(path))
|
||||
throw Error("template '%s' has a bad 'path' attribute");
|
||||
|
Loading…
Reference in New Issue
Block a user