mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-29 17:16:15 +02:00
Merge pull request #7710 from obsidiansystems/context-not-path-set
Use `std::set<StringContextElem>` not `PathSet` for string contexts
This commit is contained in:
commit
7474a90db6
27 changed files with 219 additions and 204 deletions
|
@ -96,7 +96,7 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
|
||||||
auto v = attr->forceValue();
|
auto v = attr->forceValue();
|
||||||
|
|
||||||
if (v.type() == nPath) {
|
if (v.type() == nPath) {
|
||||||
PathSet context;
|
NixStringContext context;
|
||||||
auto storePath = state->copyPathToStore(context, Path(v.path));
|
auto storePath = state->copyPathToStore(context, Path(v.path));
|
||||||
return {{
|
return {{
|
||||||
.path = DerivedPath::Opaque {
|
.path = DerivedPath::Opaque {
|
||||||
|
@ -107,10 +107,10 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (v.type() == nString) {
|
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 s = state->forceString(v, context, noPos, fmt("while evaluating the flake output attribute '%s'", attrPath));
|
||||||
auto storePath = state->store->maybeParseStorePath(s);
|
auto storePath = state->store->maybeParseStorePath(s);
|
||||||
if (storePath && context.count(std::string(s))) {
|
if (storePath && context.count(NixStringContextElem::Opaque { .path = *storePath })) {
|
||||||
return {{
|
return {{
|
||||||
.path = DerivedPath::Opaque {
|
.path = DerivedPath::Opaque {
|
||||||
.path = std::move(*storePath),
|
.path = std::move(*storePath),
|
||||||
|
|
|
@ -596,7 +596,7 @@ bool NixRepl::processLine(std::string line)
|
||||||
|
|
||||||
const auto [path, line] = [&] () -> std::pair<Path, uint32_t> {
|
const auto [path, line] = [&] () -> std::pair<Path, uint32_t> {
|
||||||
if (v.type() == nPath || v.type() == nString) {
|
if (v.type() == nPath || v.type() == nString) {
|
||||||
PathSet context;
|
NixStringContext context;
|
||||||
auto path = state->coerceToPath(noPos, v, context, "while evaluating the filename to edit");
|
auto path = state->coerceToPath(noPos, v, context, "while evaluating the filename to edit");
|
||||||
return {path, 0};
|
return {path, 0};
|
||||||
} else if (v.isLambda()) {
|
} else if (v.isLambda()) {
|
||||||
|
@ -940,7 +940,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
|
||||||
if (isDrv) {
|
if (isDrv) {
|
||||||
str << "«derivation ";
|
str << "«derivation ";
|
||||||
Bindings::iterator i = v.attrs->find(state->sDrvPath);
|
Bindings::iterator i = v.attrs->find(state->sDrvPath);
|
||||||
PathSet context;
|
NixStringContext context;
|
||||||
if (i != v.attrs->end())
|
if (i != v.attrs->end())
|
||||||
str << state->store->printStorePath(state->coerceToStorePath(i->pos, *i->value, context, "while evaluating the drvPath of a derivation"));
|
str << state->store->printStorePath(state->coerceToStorePath(i->pos, *i->value, context, "while evaluating the drvPath of a derivation"));
|
||||||
else
|
else
|
||||||
|
|
|
@ -47,7 +47,7 @@ struct AttrDb
|
||||||
{
|
{
|
||||||
auto state(_state->lock());
|
auto state(_state->lock());
|
||||||
|
|
||||||
Path cacheDir = getCacheDir() + "/nix/eval-cache-v4";
|
Path cacheDir = getCacheDir() + "/nix/eval-cache-v5";
|
||||||
createDirs(cacheDir);
|
createDirs(cacheDir);
|
||||||
|
|
||||||
Path dbPath = cacheDir + "/" + fingerprint.to_string(Base16, false) + ".sqlite";
|
Path dbPath = cacheDir + "/" + fingerprint.to_string(Base16, false) + ".sqlite";
|
||||||
|
@ -300,7 +300,7 @@ struct AttrDb
|
||||||
NixStringContext context;
|
NixStringContext context;
|
||||||
if (!queryAttribute.isNull(3))
|
if (!queryAttribute.isNull(3))
|
||||||
for (auto & s : tokenizeString<std::vector<std::string>>(queryAttribute.getStr(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}}};
|
return {{rowId, string_t{queryAttribute.getStr(2), context}}};
|
||||||
}
|
}
|
||||||
case AttrType::Bool:
|
case AttrType::Bool:
|
||||||
|
@ -619,9 +619,11 @@ string_t AttrCursor::getStringWithContext()
|
||||||
|
|
||||||
auto & v = forceValue();
|
auto & v = forceValue();
|
||||||
|
|
||||||
if (v.type() == nString)
|
if (v.type() == nString) {
|
||||||
return {v.string.s, v.getContext(*root->state.store)};
|
NixStringContext context;
|
||||||
else if (v.type() == nPath)
|
copyContext(v, context);
|
||||||
|
return {v.string.s, std::move(context)};
|
||||||
|
} else if (v.type() == nPath)
|
||||||
return {v.path, {}};
|
return {v.path, {}};
|
||||||
else
|
else
|
||||||
root->state.error("'%s' is not a string but %s", getAttrPathStr()).debugThrow<TypeError>();
|
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);
|
allowPath(storePath);
|
||||||
|
|
||||||
auto path = store->printStorePath(storePath);
|
mkStorePathString(storePath, v);
|
||||||
v.mkString(path, PathSet({path}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Path EvalState::checkSourcePath(const Path & path_)
|
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'.
|
// FIXME: check whether 'path' is in 'context'.
|
||||||
return
|
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()) {
|
if (!context.empty()) {
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
v.string.context = (const char * *)
|
v.string.context = (const char * *)
|
||||||
allocBytes((context.size() + 1) * sizeof(char *));
|
allocBytes((context.size() + 1) * sizeof(char *));
|
||||||
for (auto & i : context)
|
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;
|
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);
|
mkString(s);
|
||||||
copyContextToValue(*this, context);
|
copyContextToValue(*this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::mkStringMove(const char * s, const PathSet & context)
|
void Value::mkStringMove(const char * s, const NixStringContext & context)
|
||||||
{
|
{
|
||||||
mkString(s);
|
mkString(s);
|
||||||
copyContextToValue(*this, context);
|
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
|
/* Create a thunk for the delayed computation of the given expression
|
||||||
in the given environment. But if the expression is a variable,
|
in the given environment. But if the expression is a variable,
|
||||||
then look it up right away. This significantly reduces the number
|
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)
|
void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
PathSet context;
|
NixStringContext context;
|
||||||
std::vector<BackedStringView> s;
|
std::vector<BackedStringView> s;
|
||||||
size_t sSize = 0;
|
size_t sSize = 0;
|
||||||
NixInt n = 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)
|
if (v.string.context)
|
||||||
for (const char * * p = v.string.context; *p; ++p)
|
for (const char * * p = v.string.context; *p; ++p)
|
||||||
context.insert(*p);
|
context.insert(NixStringContextElem::parse(*p));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NixStringContext Value::getContext(const Store & store)
|
std::string_view EvalState::forceString(Value & v, NixStringContext & context, const PosIdx pos, std::string_view errorCtx)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
auto s = forceString(v, pos, errorCtx);
|
auto s = forceString(v, pos, errorCtx);
|
||||||
copyContext(v, context);
|
copyContext(v, context);
|
||||||
|
@ -2158,7 +2156,7 @@ bool EvalState::isDerivation(Value & v)
|
||||||
|
|
||||||
|
|
||||||
std::optional<std::string> EvalState::tryAttrsToString(const PosIdx pos, 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);
|
auto i = v.attrs->find(sToString);
|
||||||
if (i != v.attrs->end()) {
|
if (i != v.attrs->end()) {
|
||||||
|
@ -2172,7 +2170,7 @@ std::optional<std::string> EvalState::tryAttrsToString(const PosIdx pos, Value &
|
||||||
return {};
|
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)
|
std::string_view errorCtx, bool coerceMore, bool copyToStore, bool canonicalizePath)
|
||||||
{
|
{
|
||||||
forceValue(v, pos);
|
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))
|
if (nix::isDerivation(path))
|
||||||
error("file names are not allowed to end in '%1%'", drvExtension).debugThrow<EvalError>();
|
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;
|
return dstPath;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
context.insert(store->printStorePath(dstPath));
|
context.insert(NixStringContextElem::Opaque {
|
||||||
|
.path = dstPath
|
||||||
|
});
|
||||||
return 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();
|
auto path = coerceToString(pos, v, context, errorCtx, false, false, true).toOwned();
|
||||||
if (path == "" || path[0] != '/')
|
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();
|
auto path = coerceToString(pos, v, context, errorCtx, false, false, true).toOwned();
|
||||||
if (auto storePath = store->maybeParseStorePath(path))
|
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({
|
throw TypeError({
|
||||||
.msg = hintfmt("cannot coerce %1% to a string", showType())
|
.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);
|
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
|
* intended to distinguish between import-from-derivation and
|
||||||
* sources stored in the actual /nix/store.
|
* 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.
|
* Parse a Nix expression from the specified file.
|
||||||
|
@ -423,7 +423,7 @@ public:
|
||||||
*/
|
*/
|
||||||
void forceFunction(Value & v, const PosIdx pos, std::string_view errorCtx);
|
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, 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);
|
std::string_view forceStringNoCtx(Value & v, const PosIdx pos, std::string_view errorCtx);
|
||||||
|
|
||||||
[[gnu::noinline]]
|
[[gnu::noinline]]
|
||||||
|
@ -439,7 +439,7 @@ public:
|
||||||
bool isDerivation(Value & v);
|
bool isDerivation(Value & v);
|
||||||
|
|
||||||
std::optional<std::string> tryAttrsToString(const PosIdx pos, 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.
|
* String coercion.
|
||||||
|
@ -449,12 +449,12 @@ public:
|
||||||
* booleans and lists to a string. If `copyToStore` is set,
|
* booleans and lists to a string. If `copyToStore` is set,
|
||||||
* referenced paths are copied to the Nix store as a side effect.
|
* 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,
|
std::string_view errorCtx,
|
||||||
bool coerceMore = false, bool copyToStore = true,
|
bool coerceMore = false, bool copyToStore = true,
|
||||||
bool canonicalizePath = true);
|
bool canonicalizePath = true);
|
||||||
|
|
||||||
StorePath copyPathToStore(PathSet & context, const Path & path);
|
StorePath copyPathToStore(NixStringContext & context, const Path & path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Path coercion.
|
* Path coercion.
|
||||||
|
@ -463,12 +463,12 @@ public:
|
||||||
* path. The result is guaranteed to be a canonicalised, absolute
|
* path. The result is guaranteed to be a canonicalised, absolute
|
||||||
* path. Nothing is copied to the store.
|
* 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.
|
* 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:
|
public:
|
||||||
|
|
||||||
|
@ -573,6 +573,12 @@ public:
|
||||||
void mkThunk_(Value & v, Expr * expr);
|
void mkThunk_(Value & v, Expr * expr);
|
||||||
void mkPos(Value & v, PosIdx pos);
|
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);
|
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
|
* Realise the given context, and return a mapping from the placeholders
|
||||||
* used to construct the associated value to their final store path
|
* used to construct the associated value to their final store path
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] StringMap realiseContext(const PathSet & context);
|
[[nodiscard]] StringMap realiseContext(const NixStringContext & context);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -265,7 +265,7 @@ static Flake getFlake(
|
||||||
state.symbols[setting.name],
|
state.symbols[setting.name],
|
||||||
std::string(state.forceStringNoCtx(*setting.value, setting.pos, "")));
|
std::string(state.forceStringNoCtx(*setting.value, setting.pos, "")));
|
||||||
else if (setting.value->type() == nPath) {
|
else if (setting.value->type() == nPath) {
|
||||||
PathSet emptyContext = {};
|
NixStringContext emptyContext = {};
|
||||||
flake.config.settings.emplace(
|
flake.config.settings.emplace(
|
||||||
state.symbols[setting.name],
|
state.symbols[setting.name],
|
||||||
state.coerceToString(setting.pos, *setting.value, emptyContext, "", false, true, true) .toOwned());
|
state.coerceToString(setting.pos, *setting.value, emptyContext, "", false, true, true) .toOwned());
|
||||||
|
|
|
@ -71,7 +71,7 @@ std::optional<StorePath> DrvInfo::queryDrvPath() const
|
||||||
{
|
{
|
||||||
if (!drvPath && attrs) {
|
if (!drvPath && attrs) {
|
||||||
Bindings::iterator i = attrs->find(state->sDrvPath);
|
Bindings::iterator i = attrs->find(state->sDrvPath);
|
||||||
PathSet context;
|
NixStringContext context;
|
||||||
if (i == attrs->end())
|
if (i == attrs->end())
|
||||||
drvPath = {std::nullopt};
|
drvPath = {std::nullopt};
|
||||||
else
|
else
|
||||||
|
@ -93,7 +93,7 @@ StorePath DrvInfo::queryOutPath() const
|
||||||
{
|
{
|
||||||
if (!outPath && attrs) {
|
if (!outPath && attrs) {
|
||||||
Bindings::iterator i = attrs->find(state->sOutPath);
|
Bindings::iterator i = attrs->find(state->sOutPath);
|
||||||
PathSet context;
|
NixStringContext context;
|
||||||
if (i != attrs->end())
|
if (i != attrs->end())
|
||||||
outPath = state->coerceToStorePath(i->pos, *i->value, context, "while evaluating the output path of a derivation");
|
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. */
|
/* And evaluate its ‘outPath’ attribute. */
|
||||||
Bindings::iterator outPath = out->value->attrs->find(state->sOutPath);
|
Bindings::iterator outPath = out->value->attrs->find(state->sOutPath);
|
||||||
if (outPath == out->value->attrs->end()) continue; // FIXME: throw error?
|
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"));
|
outputs.emplace(output, state->coerceToStorePath(outPath->pos, *outPath->value, context, "while evaluating an output path of a derivation"));
|
||||||
} else
|
} else
|
||||||
outputs.emplace(output, std::nullopt);
|
outputs.emplace(output, std::nullopt);
|
||||||
|
|
|
@ -38,17 +38,16 @@ namespace nix {
|
||||||
InvalidPathError::InvalidPathError(const Path & path) :
|
InvalidPathError::InvalidPathError(const Path & path) :
|
||||||
EvalError("path '%s' is not valid", path), 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;
|
std::vector<DerivedPath::Built> drvs;
|
||||||
StringMap res;
|
StringMap res;
|
||||||
|
|
||||||
for (auto & c_ : context) {
|
for (auto & c : context) {
|
||||||
auto ensureValid = [&](const StorePath & p) {
|
auto ensureValid = [&](const StorePath & p) {
|
||||||
if (!store->isValidPath(p))
|
if (!store->isValidPath(p))
|
||||||
debugThrowLastTrace(InvalidPathError(store->printStorePath(p)));
|
debugThrowLastTrace(InvalidPathError(store->printStorePath(p)));
|
||||||
};
|
};
|
||||||
auto c = NixStringContextElem::parse(*store, c_);
|
|
||||||
std::visit(overloaded {
|
std::visit(overloaded {
|
||||||
[&](const NixStringContextElem::Built & b) {
|
[&](const NixStringContextElem::Built & b) {
|
||||||
drvs.push_back(DerivedPath::Built {
|
drvs.push_back(DerivedPath::Built {
|
||||||
|
@ -112,7 +111,7 @@ struct RealisePathFlags {
|
||||||
|
|
||||||
static Path realisePath(EvalState & state, const PosIdx pos, Value & v, const RealisePathFlags flags = {})
|
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");
|
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
|
/* FIXME: we need to depend on the basic derivation, not
|
||||||
derivation */
|
derivation */
|
||||||
: downstreamPlaceholder(*state.store, drvPath, o.first),
|
: 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
|
/* 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;
|
auto storePath = *optStorePath;
|
||||||
Derivation drv = state.store->readDerivation(storePath);
|
Derivation drv = state.store->readDerivation(storePath);
|
||||||
auto attrs = state.buildBindings(3 + drv.outputs.size());
|
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"]);
|
attrs.alloc(state.sName).mkString(drv.env["name"]);
|
||||||
auto & outputsVal = attrs.alloc(state.sOutputs);
|
auto & outputsVal = attrs.alloc(state.sOutputs);
|
||||||
state.mkList(outputsVal, drv.outputs.size());
|
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();
|
auto count = args[0]->listSize();
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
state.error("at least one argument to 'exec' required").atPos(pos).debugThrow<EvalError>();
|
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,
|
auto program = state.coerceToString(pos, *elems[0], context,
|
||||||
"while evaluating the first element of the argument passed to builtins.exec",
|
"while evaluating the first element of the argument passed to builtins.exec",
|
||||||
false, false).toOwned();
|
false, false).toOwned();
|
||||||
|
@ -768,7 +774,7 @@ static RegisterPrimOp primop_abort({
|
||||||
)",
|
)",
|
||||||
.fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
.fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
PathSet context;
|
NixStringContext context;
|
||||||
auto s = state.coerceToString(pos, *args[0], context,
|
auto s = state.coerceToString(pos, *args[0], context,
|
||||||
"while evaluating the error message passed to builtins.abort").toOwned();
|
"while evaluating the error message passed to builtins.abort").toOwned();
|
||||||
state.debugThrowLastTrace(Abort("evaluation aborted with the following error message: '%1%'", s));
|
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)
|
.fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
PathSet context;
|
NixStringContext context;
|
||||||
auto s = state.coerceToString(pos, *args[0], context,
|
auto s = state.coerceToString(pos, *args[0], context,
|
||||||
"while evaluating the error message passed to builtin.throw").toOwned();
|
"while evaluating the error message passed to builtin.throw").toOwned();
|
||||||
state.debugThrowLastTrace(ThrownError(s));
|
state.debugThrowLastTrace(ThrownError(s));
|
||||||
|
@ -800,7 +806,7 @@ static void prim_addErrorContext(EvalState & state, const PosIdx pos, Value * *
|
||||||
state.forceValue(*args[1], pos);
|
state.forceValue(*args[1], pos);
|
||||||
v = *args[1];
|
v = *args[1];
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
PathSet context;
|
NixStringContext context;
|
||||||
auto message = state.coerceToString(pos, *args[0], context,
|
auto message = state.coerceToString(pos, *args[0], context,
|
||||||
"while evaluating the error message passed to builtins.addErrorContext",
|
"while evaluating the error message passed to builtins.addErrorContext",
|
||||||
false, false).toOwned();
|
false, false).toOwned();
|
||||||
|
@ -1086,7 +1092,7 @@ drvName, Bindings * attrs, Value & v)
|
||||||
Derivation drv;
|
Derivation drv;
|
||||||
drv.name = drvName;
|
drv.name = drvName;
|
||||||
|
|
||||||
PathSet context;
|
NixStringContext context;
|
||||||
|
|
||||||
bool contentAddressed = false;
|
bool contentAddressed = false;
|
||||||
bool isImpure = false;
|
bool isImpure = false;
|
||||||
|
@ -1232,8 +1238,7 @@ drvName, Bindings * attrs, Value & v)
|
||||||
/* Everything in the context of the strings in the derivation
|
/* Everything in the context of the strings in the derivation
|
||||||
attributes should be added as dependencies of the resulting
|
attributes should be added as dependencies of the resulting
|
||||||
derivation. */
|
derivation. */
|
||||||
for (auto & c_ : context) {
|
for (auto & c : context) {
|
||||||
auto c = NixStringContextElem::parse(*state.store, c_);
|
|
||||||
std::visit(overloaded {
|
std::visit(overloaded {
|
||||||
/* Since this allows the builder to gain access to every
|
/* Since this allows the builder to gain access to every
|
||||||
path in the dependency graph of the derivation (including
|
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());
|
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)
|
for (auto & i : drv.outputs)
|
||||||
mkOutputString(state, result, drvPath, drv, i);
|
mkOutputString(state, result, drvPath, drv, i);
|
||||||
|
|
||||||
|
@ -1437,7 +1444,7 @@ static RegisterPrimOp primop_placeholder({
|
||||||
/* Convert the argument to a path. !!! obsolete? */
|
/* Convert the argument to a path. !!! obsolete? */
|
||||||
static void prim_toPath(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
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");
|
Path path = state.coerceToPath(pos, *args[0], context, "while evaluating the first argument passed to builtins.toPath");
|
||||||
v.mkString(canonPath(path), context);
|
v.mkString(canonPath(path), context);
|
||||||
}
|
}
|
||||||
|
@ -1468,7 +1475,7 @@ static void prim_storePath(EvalState & state, const PosIdx pos, Value * * args,
|
||||||
.errPos = state.positions[pos]
|
.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"));
|
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
|
/* Resolve symlinks in ‘path’, unless ‘path’ itself is a symlink
|
||||||
directly in the store. The latter condition is necessary so
|
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;
|
auto path2 = state.store->toStorePath(path).first;
|
||||||
if (!settings.readOnlyMode)
|
if (!settings.readOnlyMode)
|
||||||
state.store->ensurePath(path2);
|
state.store->ensurePath(path2);
|
||||||
context.insert(state.store->printStorePath(path2));
|
context.insert(NixStringContextElem::Opaque { .path = path2 });
|
||||||
v.mkString(path, context);
|
v.mkString(path, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1538,7 +1545,7 @@ static RegisterPrimOp primop_pathExists({
|
||||||
following the last slash. */
|
following the last slash. */
|
||||||
static void prim_baseNameOf(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
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,
|
v.mkString(baseNameOf(*state.coerceToString(pos, *args[0], context,
|
||||||
"while evaluating the first argument passed to builtins.baseNameOf",
|
"while evaluating the first argument passed to builtins.baseNameOf",
|
||||||
false, false)), context);
|
false, false)), context);
|
||||||
|
@ -1560,7 +1567,7 @@ static RegisterPrimOp primop_baseNameOf({
|
||||||
of the argument. */
|
of the argument. */
|
||||||
static void prim_dirOf(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
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,
|
auto path = state.coerceToString(pos, *args[0], context,
|
||||||
"while evaluating the first argument passed to builtins.dirOf",
|
"while evaluating the first argument passed to builtins.dirOf",
|
||||||
false, false);
|
false, false);
|
||||||
|
@ -1597,7 +1604,12 @@ static void prim_readFile(EvalState & state, const PosIdx pos, Value * * args, V
|
||||||
refsSink << s;
|
refsSink << s;
|
||||||
refs = refsSink.getResultPaths();
|
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);
|
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");
|
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,
|
auto path = state.coerceToString(pos, *i->value, context,
|
||||||
"while evaluating the `path` attribute of an element of the list passed to builtins.findFile",
|
"while evaluating the `path` attribute of an element of the list passed to builtins.findFile",
|
||||||
false, false).toOwned();
|
false, false).toOwned();
|
||||||
|
@ -1787,7 +1799,7 @@ static RegisterPrimOp primop_readDir({
|
||||||
static void prim_toXML(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
static void prim_toXML(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
PathSet context;
|
NixStringContext context;
|
||||||
printValueAsXML(state, true, false, *args[0], out, context, pos);
|
printValueAsXML(state, true, false, *args[0], out, context, pos);
|
||||||
v.mkString(out.str(), context);
|
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)
|
static void prim_toJSON(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
PathSet context;
|
NixStringContext context;
|
||||||
printValueAsJSON(state, true, *args[0], pos, out, context);
|
printValueAsJSON(state, true, *args[0], pos, out, context);
|
||||||
v.mkString(out.str(), context);
|
v.mkString(out.str(), context);
|
||||||
}
|
}
|
||||||
|
@ -1945,22 +1957,23 @@ static RegisterPrimOp primop_fromJSON({
|
||||||
as an input by derivations. */
|
as an input by derivations. */
|
||||||
static void prim_toFile(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
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 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"));
|
std::string contents(state.forceString(*args[1], context, pos, "while evaluating the second argument passed to builtins.toFile"));
|
||||||
|
|
||||||
StorePathSet refs;
|
StorePathSet refs;
|
||||||
|
|
||||||
for (auto path : context) {
|
for (auto c : context) {
|
||||||
if (path.at(0) != '/')
|
if (auto p = std::get_if<NixStringContextElem::Opaque>(&c))
|
||||||
|
refs.insert(p->path);
|
||||||
|
else
|
||||||
state.debugThrowLastTrace(EvalError({
|
state.debugThrowLastTrace(EvalError({
|
||||||
.msg = hintfmt(
|
.msg = hintfmt(
|
||||||
"in 'toFile': the file named '%1%' must not contain a reference "
|
"in 'toFile': the file named '%1%' must not contain a reference "
|
||||||
"to a derivation but contains (%2%)",
|
"to a derivation but contains (%2%)",
|
||||||
name, path),
|
name, c.to_string()),
|
||||||
.errPos = state.positions[pos]
|
.errPos = state.positions[pos]
|
||||||
}));
|
}));
|
||||||
refs.insert(state.store->parseStorePath(path));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto storePath = settings.readOnlyMode
|
auto storePath = settings.readOnlyMode
|
||||||
|
@ -2061,7 +2074,7 @@ static void addPath(
|
||||||
FileIngestionMethod method,
|
FileIngestionMethod method,
|
||||||
const std::optional<Hash> expectedHash,
|
const std::optional<Hash> expectedHash,
|
||||||
Value & v,
|
Value & v,
|
||||||
const PathSet & context)
|
const NixStringContext & context)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
// FIXME: handle CA derivation outputs (where path needs to
|
// 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)
|
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");
|
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");
|
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);
|
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;
|
Value * filterFun = nullptr;
|
||||||
auto method = FileIngestionMethod::Recursive;
|
auto method = FileIngestionMethod::Recursive;
|
||||||
std::optional<Hash> expectedHash;
|
std::optional<Hash> expectedHash;
|
||||||
PathSet context;
|
NixStringContext context;
|
||||||
|
|
||||||
for (auto & attr : *args[0]->attrs) {
|
for (auto & attr : *args[0]->attrs) {
|
||||||
auto n = state.symbols[attr.name];
|
auto n = state.symbols[attr.name];
|
||||||
|
@ -3538,7 +3551,7 @@ static RegisterPrimOp primop_lessThan({
|
||||||
`"/nix/store/whatever..."'. */
|
`"/nix/store/whatever..."'. */
|
||||||
static void prim_toString(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
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,
|
auto s = state.coerceToString(pos, *args[0], context,
|
||||||
"while evaluating the first argument passed to builtins.toString",
|
"while evaluating the first argument passed to builtins.toString",
|
||||||
true, false);
|
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 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");
|
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");
|
auto s = state.coerceToString(pos, *args[2], context, "while evaluating the third argument (the string) passed to builtins.substring");
|
||||||
|
|
||||||
if (start < 0)
|
if (start < 0)
|
||||||
|
@ -3611,7 +3624,7 @@ static RegisterPrimOp primop_substring({
|
||||||
|
|
||||||
static void prim_stringLength(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
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");
|
auto s = state.coerceToString(pos, *args[0], context, "while evaluating the argument passed to builtins.stringLength");
|
||||||
v.mkInt(s->size());
|
v.mkInt(s->size());
|
||||||
}
|
}
|
||||||
|
@ -3637,7 +3650,7 @@ static void prim_hashString(EvalState & state, const PosIdx pos, Value * * args,
|
||||||
.errPos = state.positions[pos]
|
.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");
|
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));
|
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);
|
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");
|
const auto str = state.forceString(*args[1], context, pos, "while evaluating the second argument passed to builtins.match");
|
||||||
|
|
||||||
std::cmatch 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);
|
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");
|
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);
|
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)
|
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");
|
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");
|
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())
|
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"));
|
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());
|
to.reserve(args[1]->listSize());
|
||||||
for (auto elem : args[1]->listItems()) {
|
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");
|
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));
|
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");
|
auto s = state.forceString(*args[2], context, pos, "while evaluating the third argument passed to builtins.replaceStrings");
|
||||||
|
|
||||||
std::string res;
|
std::string res;
|
||||||
|
|
|
@ -7,7 +7,7 @@ namespace nix {
|
||||||
|
|
||||||
static void prim_unsafeDiscardStringContext(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
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");
|
auto s = state.coerceToString(pos, *args[0], context, "while evaluating the argument passed to builtins.unsafeDiscardStringContext");
|
||||||
v.mkString(*s);
|
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)
|
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");
|
state.forceString(*args[0], context, pos, "while evaluating the argument passed to builtins.hasContext");
|
||||||
v.mkBool(!context.empty());
|
v.mkBool(!context.empty());
|
||||||
}
|
}
|
||||||
|
@ -33,17 +33,18 @@ static RegisterPrimOp primop_hasContext("__hasContext", 1, prim_hasContext);
|
||||||
drv.inputDrvs. */
|
drv.inputDrvs. */
|
||||||
static void prim_unsafeDiscardOutputDependency(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
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");
|
auto s = state.coerceToString(pos, *args[0], context, "while evaluating the argument passed to builtins.unsafeDiscardOutputDependency");
|
||||||
|
|
||||||
PathSet context2;
|
NixStringContext context2;
|
||||||
for (auto && p : context) {
|
for (auto && c : context) {
|
||||||
auto c = NixStringContextElem::parse(*state.store, p);
|
|
||||||
if (auto * ptr = std::get_if<NixStringContextElem::DrvDeep>(&c)) {
|
if (auto * ptr = std::get_if<NixStringContextElem::DrvDeep>(&c)) {
|
||||||
context2.emplace(state.store->printStorePath(ptr->drvPath));
|
context2.emplace(NixStringContextElem::Opaque {
|
||||||
|
.path = ptr->drvPath
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
/* Can reuse original item */
|
/* 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;
|
bool allOutputs = false;
|
||||||
Strings outputs;
|
Strings outputs;
|
||||||
};
|
};
|
||||||
PathSet context;
|
NixStringContext context;
|
||||||
state.forceString(*args[0], context, pos, "while evaluating the argument passed to builtins.getContext");
|
state.forceString(*args[0], context, pos, "while evaluating the argument passed to builtins.getContext");
|
||||||
auto contextInfos = std::map<StorePath, ContextInfo>();
|
auto contextInfos = std::map<StorePath, ContextInfo>();
|
||||||
for (const auto & p : context) {
|
for (auto && i : context) {
|
||||||
NixStringContextElem ctx = NixStringContextElem::parse(*state.store, p);
|
|
||||||
std::visit(overloaded {
|
std::visit(overloaded {
|
||||||
[&](NixStringContextElem::DrvDeep & d) {
|
[&](NixStringContextElem::DrvDeep && d) {
|
||||||
contextInfos[d.drvPath].allOutputs = true;
|
contextInfos[std::move(d.drvPath)].allOutputs = true;
|
||||||
},
|
},
|
||||||
[&](NixStringContextElem::Built & b) {
|
[&](NixStringContextElem::Built && b) {
|
||||||
contextInfos[b.drvPath].outputs.emplace_back(std::move(b.output));
|
contextInfos[std::move(b.drvPath)].outputs.emplace_back(std::move(b.output));
|
||||||
},
|
},
|
||||||
[&](NixStringContextElem::Opaque & o) {
|
[&](NixStringContextElem::Opaque && o) {
|
||||||
contextInfos[o.path].path = true;
|
contextInfos[std::move(o.path)].path = true;
|
||||||
},
|
},
|
||||||
}, ctx.raw());
|
}, ((NixStringContextElem &&) i).raw());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto attrs = state.buildBindings(contextInfos.size());
|
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)
|
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");
|
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");
|
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),
|
.msg = hintfmt("context key '%s' is not a store path", name),
|
||||||
.errPos = state.positions[i.pos]
|
.errPos = state.positions[i.pos]
|
||||||
});
|
});
|
||||||
|
auto namePath = state.store->parseStorePath(name);
|
||||||
if (!settings.readOnlyMode)
|
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");
|
state.forceAttrs(*i.value, i.pos, "while evaluating the value of a string context");
|
||||||
auto iter = i.value->attrs->find(sPath);
|
auto iter = i.value->attrs->find(sPath);
|
||||||
if (iter != i.value->attrs->end()) {
|
if (iter != i.value->attrs->end()) {
|
||||||
if (state.forceBool(*iter->value, iter->pos, "while evaluating the `path` attribute of a string context"))
|
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);
|
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]
|
.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()) {
|
for (auto elem : iter->value->listItems()) {
|
||||||
auto outputName = state.forceStringNoCtx(*elem, iter->pos, "while evaluating an output name within a string context");
|
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];
|
const auto & attrName = state.symbols[attr.name];
|
||||||
|
|
||||||
if (attrName == "fromPath") {
|
if (attrName == "fromPath") {
|
||||||
PathSet context;
|
NixStringContext context;
|
||||||
fromPath = state.coerceToStorePath(attr.pos, *attr.value, context,
|
fromPath = state.coerceToStorePath(attr.pos, *attr.value, context,
|
||||||
"while evaluating the 'fromPath' attribute passed to builtins.fetchClosure");
|
"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);
|
state.forceValue(*attr.value, attr.pos);
|
||||||
toCA = true;
|
toCA = true;
|
||||||
if (attr.value->type() != nString || attr.value->string.s != std::string("")) {
|
if (attr.value->type() != nString || attr.value->string.s != std::string("")) {
|
||||||
PathSet context;
|
NixStringContext context;
|
||||||
toPath = state.coerceToStorePath(attr.pos, *attr.value, context,
|
toPath = state.coerceToStorePath(attr.pos, *attr.value, context,
|
||||||
"while evaluating the 'toPath' attribute passed to builtins.fetchClosure");
|
"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);
|
state.mkStorePathString(*toPath, v);
|
||||||
v.mkString(toPathS, {toPathS});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_fetchClosure({
|
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<Hash> rev;
|
||||||
std::optional<std::string> ref;
|
std::optional<std::string> ref;
|
||||||
std::string_view name = "source";
|
std::string_view name = "source";
|
||||||
PathSet context;
|
NixStringContext context;
|
||||||
|
|
||||||
state.forceValue(*args[0], pos);
|
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 [tree, input2] = input.fetch(state.store);
|
||||||
|
|
||||||
auto attrs2 = state.buildBindings(8);
|
auto attrs2 = state.buildBindings(8);
|
||||||
auto storePath = state.store->printStorePath(tree.storePath);
|
state.mkStorePathString(tree.storePath, attrs2.alloc(state.sOutPath));
|
||||||
attrs2.alloc(state.sOutPath).mkString(storePath, {storePath});
|
|
||||||
if (input2.getRef())
|
if (input2.getRef())
|
||||||
attrs2.alloc("branch").mkString(*input2.getRef());
|
attrs2.alloc("branch").mkString(*input2.getRef());
|
||||||
// Backward compatibility: set 'rev' to
|
// Backward compatibility: set 'rev' to
|
||||||
|
|
|
@ -24,9 +24,8 @@ void emitTreeAttrs(
|
||||||
|
|
||||||
auto attrs = state.buildBindings(8);
|
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.
|
// FIXME: support arbitrary input attributes.
|
||||||
|
|
||||||
|
@ -107,7 +106,7 @@ static void fetchTree(
|
||||||
const FetchTreeParams & params = FetchTreeParams{}
|
const FetchTreeParams & params = FetchTreeParams{}
|
||||||
) {
|
) {
|
||||||
fetchers::Input input;
|
fetchers::Input input;
|
||||||
PathSet context;
|
NixStringContext context;
|
||||||
|
|
||||||
state.forceValue(*args[0], pos);
|
state.forceValue(*args[0], pos);
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace nix {
|
||||||
protected:
|
protected:
|
||||||
std::string getJSONValue(Value& value) {
|
std::string getJSONValue(Value& value) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
PathSet ps;
|
NixStringContext ps;
|
||||||
printValueAsJSON(state, true, value, noPos, ss, ps);
|
printValueAsJSON(state, true, value, noPos, ss, ps);
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,69 +8,62 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
// Testing of trivial expressions
|
TEST(NixStringContextElemTest, empty_invalid) {
|
||||||
struct NixStringContextElemTest : public LibExprTest {
|
|
||||||
const Store & store() const {
|
|
||||||
return *LibExprTest::store;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(NixStringContextElemTest, empty_invalid) {
|
|
||||||
EXPECT_THROW(
|
EXPECT_THROW(
|
||||||
NixStringContextElem::parse(store(), ""),
|
NixStringContextElem::parse(""),
|
||||||
BadNixStringContextElem);
|
BadNixStringContextElem);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(NixStringContextElemTest, single_bang_invalid) {
|
TEST(NixStringContextElemTest, single_bang_invalid) {
|
||||||
EXPECT_THROW(
|
EXPECT_THROW(
|
||||||
NixStringContextElem::parse(store(), "!"),
|
NixStringContextElem::parse("!"),
|
||||||
BadNixStringContextElem);
|
BadNixStringContextElem);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(NixStringContextElemTest, double_bang_invalid) {
|
TEST(NixStringContextElemTest, double_bang_invalid) {
|
||||||
EXPECT_THROW(
|
EXPECT_THROW(
|
||||||
NixStringContextElem::parse(store(), "!!/"),
|
NixStringContextElem::parse("!!/"),
|
||||||
BadStorePath);
|
BadStorePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(NixStringContextElemTest, eq_slash_invalid) {
|
TEST(NixStringContextElemTest, eq_slash_invalid) {
|
||||||
EXPECT_THROW(
|
EXPECT_THROW(
|
||||||
NixStringContextElem::parse(store(), "=/"),
|
NixStringContextElem::parse("=/"),
|
||||||
BadStorePath);
|
BadStorePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(NixStringContextElemTest, slash_invalid) {
|
TEST(NixStringContextElemTest, slash_invalid) {
|
||||||
EXPECT_THROW(
|
EXPECT_THROW(
|
||||||
NixStringContextElem::parse(store(), "/"),
|
NixStringContextElem::parse("/"),
|
||||||
BadStorePath);
|
BadStorePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(NixStringContextElemTest, opaque) {
|
TEST(NixStringContextElemTest, opaque) {
|
||||||
std::string_view opaque = "/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x";
|
std::string_view opaque = "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x";
|
||||||
auto elem = NixStringContextElem::parse(store(), opaque);
|
auto elem = NixStringContextElem::parse(opaque);
|
||||||
auto * p = std::get_if<NixStringContextElem::Opaque>(&elem);
|
auto * p = std::get_if<NixStringContextElem::Opaque>(&elem);
|
||||||
ASSERT_TRUE(p);
|
ASSERT_TRUE(p);
|
||||||
ASSERT_EQ(p->path, store().parseStorePath(opaque));
|
ASSERT_EQ(p->path, StorePath { opaque });
|
||||||
ASSERT_EQ(elem.to_string(store()), opaque);
|
ASSERT_EQ(elem.to_string(), opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(NixStringContextElemTest, drvDeep) {
|
TEST(NixStringContextElemTest, drvDeep) {
|
||||||
std::string_view drvDeep = "=/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x.drv";
|
std::string_view drvDeep = "=g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x.drv";
|
||||||
auto elem = NixStringContextElem::parse(store(), drvDeep);
|
auto elem = NixStringContextElem::parse(drvDeep);
|
||||||
auto * p = std::get_if<NixStringContextElem::DrvDeep>(&elem);
|
auto * p = std::get_if<NixStringContextElem::DrvDeep>(&elem);
|
||||||
ASSERT_TRUE(p);
|
ASSERT_TRUE(p);
|
||||||
ASSERT_EQ(p->drvPath, store().parseStorePath(drvDeep.substr(1)));
|
ASSERT_EQ(p->drvPath, StorePath { drvDeep.substr(1) });
|
||||||
ASSERT_EQ(elem.to_string(store()), drvDeep);
|
ASSERT_EQ(elem.to_string(), drvDeep);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(NixStringContextElemTest, built) {
|
TEST(NixStringContextElemTest, built) {
|
||||||
std::string_view built = "!foo!/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x.drv";
|
std::string_view built = "!foo!g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x.drv";
|
||||||
auto elem = NixStringContextElem::parse(store(), built);
|
auto elem = NixStringContextElem::parse(built);
|
||||||
auto * p = std::get_if<NixStringContextElem::Built>(&elem);
|
auto * p = std::get_if<NixStringContextElem::Built>(&elem);
|
||||||
ASSERT_TRUE(p);
|
ASSERT_TRUE(p);
|
||||||
ASSERT_EQ(p->output, "foo");
|
ASSERT_EQ(p->output, "foo");
|
||||||
ASSERT_EQ(p->drvPath, store().parseStorePath(built.substr(5)));
|
ASSERT_EQ(p->drvPath, StorePath { built.substr(5) });
|
||||||
ASSERT_EQ(elem.to_string(store()), built);
|
ASSERT_EQ(elem.to_string(), built);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -116,12 +109,12 @@ Gen<NixStringContextElem> Arbitrary<NixStringContextElem>::arbitrary()
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
RC_GTEST_FIXTURE_PROP(
|
RC_GTEST_PROP(
|
||||||
NixStringContextElemTest,
|
NixStringContextElemTest,
|
||||||
prop_round_rip,
|
prop_round_rip,
|
||||||
(const NixStringContextElem & o))
|
(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 {
|
namespace nix {
|
||||||
using json = nlohmann::json;
|
using json = nlohmann::json;
|
||||||
json printValueAsJSON(EvalState & state, bool strict,
|
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();
|
checkInterrupt();
|
||||||
|
|
||||||
|
@ -94,13 +94,13 @@ json printValueAsJSON(EvalState & state, bool strict,
|
||||||
}
|
}
|
||||||
|
|
||||||
void 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);
|
str << printValueAsJSON(state, strict, v, pos, context, copyToStore);
|
||||||
}
|
}
|
||||||
|
|
||||||
json ExternalValueBase::printValueAsJSON(EvalState & state, bool strict,
|
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()));
|
state.debugThrowLastTrace(TypeError("cannot convert %1% to JSON", showType()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,9 @@
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
nlohmann::json printValueAsJSON(EvalState & state, bool strict,
|
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,
|
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,
|
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);
|
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,
|
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;
|
StringSet names;
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ static void showAttrs(EvalState & state, bool strict, bool location,
|
||||||
|
|
||||||
|
|
||||||
static void printValueAsXML(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)
|
const PosIdx pos)
|
||||||
{
|
{
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
|
@ -166,7 +166,7 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||||
|
|
||||||
|
|
||||||
void ExternalValueBase::printValueAsXML(EvalState & state, bool strict,
|
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
|
const PosIdx pos) const
|
||||||
{
|
{
|
||||||
doc.writeEmptyElement("unevaluated");
|
doc.writeEmptyElement("unevaluated");
|
||||||
|
@ -174,7 +174,7 @@ void ExternalValueBase::printValueAsXML(EvalState & state, bool strict,
|
||||||
|
|
||||||
|
|
||||||
void printValueAsXML(EvalState & state, bool strict, bool location,
|
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);
|
XMLWriter doc(true, out);
|
||||||
XMLOpenElement root(doc, "expr");
|
XMLOpenElement root(doc, "expr");
|
||||||
|
|
|
@ -10,6 +10,6 @@
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
void printValueAsXML(EvalState & state, bool strict, bool location,
|
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
|
* Coerce the value to a string. Defaults to uncoercable, i.e. throws an
|
||||||
* error.
|
* 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,
|
* 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
|
* Print the value as JSON. Defaults to unconvertable, i.e. throws an error
|
||||||
*/
|
*/
|
||||||
virtual nlohmann::json printValueAsJSON(EvalState & state, bool strict,
|
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
|
* Print the value as XML. Defaults to unevaluated
|
||||||
*/
|
*/
|
||||||
virtual void printValueAsXML(EvalState & state, bool strict, bool location,
|
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;
|
const PosIdx pos) const;
|
||||||
|
|
||||||
virtual ~ExternalValueBase()
|
virtual ~ExternalValueBase()
|
||||||
|
@ -268,9 +268,9 @@ public:
|
||||||
|
|
||||||
void mkString(std::string_view s);
|
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)
|
inline void mkPath(const char * s)
|
||||||
{
|
{
|
||||||
|
@ -394,8 +394,6 @@ public:
|
||||||
*/
|
*/
|
||||||
bool isTrivial() const;
|
bool isTrivial() const;
|
||||||
|
|
||||||
NixStringContext getContext(const Store &);
|
|
||||||
|
|
||||||
auto listItems()
|
auto listItems()
|
||||||
{
|
{
|
||||||
struct ListIterable
|
struct ListIterable
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
#include "value/context.hh"
|
#include "value/context.hh"
|
||||||
#include "store-api.hh"
|
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
NixStringContextElem NixStringContextElem::parse(const Store & store, std::string_view s0)
|
NixStringContextElem NixStringContextElem::parse(std::string_view s0)
|
||||||
{
|
{
|
||||||
std::string_view s = 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 '!'");
|
"String content element beginning with '!' should have a second '!'");
|
||||||
}
|
}
|
||||||
return NixStringContextElem::Built {
|
return NixStringContextElem::Built {
|
||||||
.drvPath = store.parseStorePath(s.substr(index + 1)),
|
.drvPath = StorePath { s.substr(index + 1) },
|
||||||
.output = std::string(s.substr(0, index)),
|
.output = std::string(s.substr(0, index)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case '=': {
|
case '=': {
|
||||||
return NixStringContextElem::DrvDeep {
|
return NixStringContextElem::DrvDeep {
|
||||||
.drvPath = store.parseStorePath(s.substr(1)),
|
.drvPath = StorePath { s.substr(1) },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
return NixStringContextElem::Opaque {
|
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 {
|
return std::visit(overloaded {
|
||||||
[&](const NixStringContextElem::Built & b) {
|
[&](const NixStringContextElem::Built & b) {
|
||||||
std::string res;
|
std::string res;
|
||||||
res += '!';
|
res += '!';
|
||||||
res += b.output;
|
res += b.output;
|
||||||
res += '!';
|
res += '!';
|
||||||
res += store.printStorePath(b.drvPath);
|
res += b.drvPath.to_string();
|
||||||
return res;
|
return res;
|
||||||
},
|
},
|
||||||
[&](const NixStringContextElem::DrvDeep & d) {
|
[&](const NixStringContextElem::DrvDeep & d) {
|
||||||
std::string res;
|
std::string res;
|
||||||
res += '=';
|
res += '=';
|
||||||
res += store.printStorePath(d.drvPath);
|
res += d.drvPath.to_string();
|
||||||
return res;
|
return res;
|
||||||
},
|
},
|
||||||
[&](const NixStringContextElem::Opaque & o) {
|
[&](const NixStringContextElem::Opaque & o) {
|
||||||
return store.printStorePath(o.path);
|
return std::string { o.path.to_string() };
|
||||||
},
|
},
|
||||||
}, raw());
|
}, raw());
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,6 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Store;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plain opaque path to some store object.
|
* Plain opaque path to some store object.
|
||||||
*
|
*
|
||||||
|
@ -80,12 +78,15 @@ struct NixStringContextElem : _NixStringContextElem_Raw {
|
||||||
using DrvDeep = NixStringContextElem_DrvDeep;
|
using DrvDeep = NixStringContextElem_DrvDeep;
|
||||||
using Built = NixStringContextElem_Built;
|
using Built = NixStringContextElem_Built;
|
||||||
|
|
||||||
inline const Raw & raw() const {
|
inline const Raw & raw() const & {
|
||||||
return static_cast<const Raw &>(*this);
|
return static_cast<const Raw &>(*this);
|
||||||
}
|
}
|
||||||
inline Raw & raw() {
|
inline Raw & raw() & {
|
||||||
return static_cast<Raw &>(*this);
|
return static_cast<Raw &>(*this);
|
||||||
}
|
}
|
||||||
|
inline Raw && raw() && {
|
||||||
|
return static_cast<Raw &&>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode a context string, one of:
|
* Decode a context string, one of:
|
||||||
|
@ -93,10 +94,10 @@ struct NixStringContextElem : _NixStringContextElem_Raw {
|
||||||
* - ‘=<path>’
|
* - ‘=<path>’
|
||||||
* - ‘!<name>!<path>’
|
* - ‘!<name>!<path>’
|
||||||
*/
|
*/
|
||||||
static NixStringContextElem parse(const Store & store, std::string_view s);
|
static NixStringContextElem parse(std::string_view s);
|
||||||
std::string to_string(const Store & store) const;
|
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);
|
printError("derivation '%s' has invalid meta attribute '%s'", i.queryName(), j);
|
||||||
metaObj[j] = nullptr;
|
metaObj[j] = nullptr;
|
||||||
} else {
|
} else {
|
||||||
PathSet context;
|
NixStringContext context;
|
||||||
metaObj[j] = printValueAsJSON(*globals.state, true, *v, noPos, 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
|
/* Construct a Nix expression that calls the user environment
|
||||||
builder with the manifest as argument. */
|
builder with the manifest as argument. */
|
||||||
auto attrs = state.buildBindings(3);
|
auto attrs = state.buildBindings(3);
|
||||||
attrs.alloc("manifest").mkString(
|
state.mkStorePathString(manifestFile, attrs.alloc("manifest"));
|
||||||
state.store->printStorePath(manifestFile),
|
|
||||||
{state.store->printStorePath(manifestFile)});
|
|
||||||
attrs.insert(state.symbols.create("derivations"), &manifest);
|
attrs.insert(state.symbols.create("derivations"), &manifest);
|
||||||
Value args;
|
Value args;
|
||||||
args.mkAttrs(attrs);
|
args.mkAttrs(attrs);
|
||||||
|
@ -132,7 +130,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
||||||
/* Evaluate it. */
|
/* Evaluate it. */
|
||||||
debug("evaluating user environment builder");
|
debug("evaluating user environment builder");
|
||||||
state.forceValue(topLevel, [&]() { return topLevel.determinePos(noPos); });
|
state.forceValue(topLevel, [&]() { return topLevel.determinePos(noPos); });
|
||||||
PathSet context;
|
NixStringContext context;
|
||||||
Attr & aDrvPath(*topLevel.attrs->find(state.sDrvPath));
|
Attr & aDrvPath(*topLevel.attrs->find(state.sDrvPath));
|
||||||
auto topLevelDrv = state.coerceToStorePath(aDrvPath.pos, *aDrvPath.value, context, "");
|
auto topLevelDrv = state.coerceToStorePath(aDrvPath.pos, *aDrvPath.value, context, "");
|
||||||
Attr & aOutPath(*topLevel.attrs->find(state.sOutPath));
|
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);
|
Value & v(*findAlongAttrPath(state, i, autoArgs, vRoot).first);
|
||||||
state.forceValue(v, [&]() { return v.determinePos(noPos); });
|
state.forceValue(v, [&]() { return v.determinePos(noPos); });
|
||||||
|
|
||||||
PathSet context;
|
NixStringContext context;
|
||||||
if (evalOnly) {
|
if (evalOnly) {
|
||||||
Value vRes;
|
Value vRes;
|
||||||
if (autoArgs.empty())
|
if (autoArgs.empty())
|
||||||
|
|
|
@ -98,7 +98,7 @@ struct CmdBundle : InstallableValueCommand
|
||||||
if (!attr1)
|
if (!attr1)
|
||||||
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
|
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 drvPath = evalState->coerceToStorePath(attr1->pos, *attr1->value, context2, "");
|
||||||
|
|
||||||
auto attr2 = vRes->attrs->get(evalState->sOutPath);
|
auto attr2 = vRes->attrs->get(evalState->sOutPath);
|
||||||
|
|
|
@ -62,7 +62,7 @@ struct CmdEval : MixJSON, InstallableValueCommand, MixReadOnlyOption
|
||||||
auto state = getEvalState();
|
auto state = getEvalState();
|
||||||
|
|
||||||
auto [v, pos] = installable->toValue(*state);
|
auto [v, pos] = installable->toValue(*state);
|
||||||
PathSet context;
|
NixStringContext context;
|
||||||
|
|
||||||
if (apply) {
|
if (apply) {
|
||||||
auto vApply = state->allocValue();
|
auto vApply = state->allocValue();
|
||||||
|
|
|
@ -438,7 +438,7 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
|
|
||||||
if (auto attr = v.attrs->get(state->symbols.create("path"))) {
|
if (auto attr = v.attrs->get(state->symbols.create("path"))) {
|
||||||
if (attr->name == state->symbols.create("path")) {
|
if (attr->name == state->symbols.create("path")) {
|
||||||
PathSet context;
|
NixStringContext context;
|
||||||
auto path = state->coerceToPath(attr->pos, *attr->value, context, "");
|
auto path = state->coerceToPath(attr->pos, *attr->value, context, "");
|
||||||
if (!store->isInStore(path))
|
if (!store->isInStore(path))
|
||||||
throw Error("template '%s' has a bad 'path' attribute");
|
throw Error("template '%s' has a bad 'path' attribute");
|
||||||
|
|
Loading…
Reference in a new issue