Merge pull request #2628 from shlevy/context-introspection
Context introspection
This commit is contained in:
		
						commit
						7a7ec22298
					
				
					 6 changed files with 220 additions and 54 deletions
				
			
		
							
								
								
									
										3
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -81,6 +81,9 @@ perl/Makefile.config
 | 
				
			||||||
/tests/common.sh
 | 
					/tests/common.sh
 | 
				
			||||||
/tests/dummy
 | 
					/tests/dummy
 | 
				
			||||||
/tests/result*
 | 
					/tests/result*
 | 
				
			||||||
 | 
					/tests/restricted-innocent
 | 
				
			||||||
 | 
					/tests/shell
 | 
				
			||||||
 | 
					/tests/shell.drv
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# /tests/lang/
 | 
					# /tests/lang/
 | 
				
			||||||
/tests/lang/*.out
 | 
					/tests/lang/*.out
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -316,6 +316,9 @@ private:
 | 
				
			||||||
/* Return a string representing the type of the value `v'. */
 | 
					/* Return a string representing the type of the value `v'. */
 | 
				
			||||||
string showType(const Value & v);
 | 
					string showType(const Value & v);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Decode a context string ‘!<name>!<path>’ into a pair <path,
 | 
				
			||||||
 | 
					   name>. */
 | 
				
			||||||
 | 
					std::pair<string, string> decodeContext(const string & s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* If `path' refers to a directory, then append "/default.nix". */
 | 
					/* If `path' refers to a directory, then append "/default.nix". */
 | 
				
			||||||
Path resolveExprPath(Path path);
 | 
					Path resolveExprPath(Path path);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -687,21 +687,12 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* See prim_unsafeDiscardOutputDependency. */
 | 
					 | 
				
			||||||
        else if (path.at(0) == '~')
 | 
					 | 
				
			||||||
            drv.inputSrcs.insert(string(path, 1));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* Handle derivation outputs of the form ‘!<name>!<path>’. */
 | 
					        /* Handle derivation outputs of the form ‘!<name>!<path>’. */
 | 
				
			||||||
        else if (path.at(0) == '!') {
 | 
					        else if (path.at(0) == '!') {
 | 
				
			||||||
            std::pair<string, string> ctx = decodeContext(path);
 | 
					            std::pair<string, string> ctx = decodeContext(path);
 | 
				
			||||||
            drv.inputDrvs[ctx.first].insert(ctx.second);
 | 
					            drv.inputDrvs[ctx.first].insert(ctx.second);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* Handle derivation contexts returned by
 | 
					 | 
				
			||||||
           ‘builtins.storePath’. */
 | 
					 | 
				
			||||||
        else if (isDerivation(path))
 | 
					 | 
				
			||||||
            drv.inputDrvs[path] = state.store->queryDerivationOutputNames(path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* Otherwise it's a source file. */
 | 
					        /* Otherwise it's a source file. */
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
            drv.inputSrcs.insert(path);
 | 
					            drv.inputSrcs.insert(path);
 | 
				
			||||||
| 
						 | 
					@ -1004,13 +995,8 @@ static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Valu
 | 
				
			||||||
    PathSet refs;
 | 
					    PathSet refs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (auto path : context) {
 | 
					    for (auto path : context) {
 | 
				
			||||||
        if (path.at(0) == '=') path = string(path, 1);
 | 
					        if (path.at(0) != '/')
 | 
				
			||||||
        if (isDerivation(path)) {
 | 
					 | 
				
			||||||
            /* See prim_unsafeDiscardOutputDependency. */
 | 
					 | 
				
			||||||
            if (path.at(0) != '~')
 | 
					 | 
				
			||||||
            throw EvalError(format("in 'toFile': the file '%1%' cannot refer to derivation outputs, at %2%") % name % pos);
 | 
					            throw EvalError(format("in 'toFile': the file '%1%' cannot refer to derivation outputs, at %2%") % name % pos);
 | 
				
			||||||
            path = string(path, 1);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        refs.insert(path);
 | 
					        refs.insert(path);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1794,41 +1780,6 @@ static void prim_stringLength(EvalState & state, const Pos & pos, Value * * args
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void prim_unsafeDiscardStringContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    PathSet context;
 | 
					 | 
				
			||||||
    string s = state.coerceToString(pos, *args[0], context);
 | 
					 | 
				
			||||||
    mkString(v, s, PathSet());
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void prim_hasContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    PathSet context;
 | 
					 | 
				
			||||||
    state.forceString(*args[0], context, pos);
 | 
					 | 
				
			||||||
    mkBool(v, !context.empty());
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Sometimes we want to pass a derivation path (i.e. pkg.drvPath) to a
 | 
					 | 
				
			||||||
   builder without causing the derivation to be built (for instance,
 | 
					 | 
				
			||||||
   in the derivation that builds NARs in nix-push, when doing
 | 
					 | 
				
			||||||
   source-only deployment).  This primop marks the string context so
 | 
					 | 
				
			||||||
   that builtins.derivation adds the path to drv.inputSrcs rather than
 | 
					 | 
				
			||||||
   drv.inputDrvs. */
 | 
					 | 
				
			||||||
static void prim_unsafeDiscardOutputDependency(EvalState & state, const Pos & pos, Value * * args, Value & v)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    PathSet context;
 | 
					 | 
				
			||||||
    string s = state.coerceToString(pos, *args[0], context);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    PathSet context2;
 | 
					 | 
				
			||||||
    for (auto & p : context)
 | 
					 | 
				
			||||||
        context2.insert(p.at(0) == '=' ? "~" + string(p, 1) : p);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    mkString(v, s, context2);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Return the cryptographic hash of a string in base-16. */
 | 
					/* Return the cryptographic hash of a string in base-16. */
 | 
				
			||||||
static void prim_hashString(EvalState & state, const Pos & pos, Value * * args, Value & v)
 | 
					static void prim_hashString(EvalState & state, const Pos & pos, Value * * args, Value & v)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -2299,9 +2250,6 @@ void EvalState::createBaseEnv()
 | 
				
			||||||
    addPrimOp("toString", 1, prim_toString);
 | 
					    addPrimOp("toString", 1, prim_toString);
 | 
				
			||||||
    addPrimOp("__substring", 3, prim_substring);
 | 
					    addPrimOp("__substring", 3, prim_substring);
 | 
				
			||||||
    addPrimOp("__stringLength", 1, prim_stringLength);
 | 
					    addPrimOp("__stringLength", 1, prim_stringLength);
 | 
				
			||||||
    addPrimOp("__hasContext", 1, prim_hasContext);
 | 
					 | 
				
			||||||
    addPrimOp("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext);
 | 
					 | 
				
			||||||
    addPrimOp("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency);
 | 
					 | 
				
			||||||
    addPrimOp("__hashString", 2, prim_hashString);
 | 
					    addPrimOp("__hashString", 2, prim_hashString);
 | 
				
			||||||
    addPrimOp("__match", 2, prim_match);
 | 
					    addPrimOp("__match", 2, prim_match);
 | 
				
			||||||
    addPrimOp("__split", 2, prim_split);
 | 
					    addPrimOp("__split", 2, prim_split);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										187
									
								
								src/libexpr/primops/context.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								src/libexpr/primops/context.cc
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,187 @@
 | 
				
			||||||
 | 
					#include "primops.hh"
 | 
				
			||||||
 | 
					#include "eval-inline.hh"
 | 
				
			||||||
 | 
					#include "derivations.hh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace nix {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void prim_unsafeDiscardStringContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    PathSet context;
 | 
				
			||||||
 | 
					    string s = state.coerceToString(pos, *args[0], context);
 | 
				
			||||||
 | 
					    mkString(v, s, PathSet());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static RegisterPrimOp r1("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void prim_hasContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    PathSet context;
 | 
				
			||||||
 | 
					    state.forceString(*args[0], context, pos);
 | 
				
			||||||
 | 
					    mkBool(v, !context.empty());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static RegisterPrimOp r2("__hasContext", 1, prim_hasContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Sometimes we want to pass a derivation path (i.e. pkg.drvPath) to a
 | 
				
			||||||
 | 
					   builder without causing the derivation to be built (for instance,
 | 
				
			||||||
 | 
					   in the derivation that builds NARs in nix-push, when doing
 | 
				
			||||||
 | 
					   source-only deployment).  This primop marks the string context so
 | 
				
			||||||
 | 
					   that builtins.derivation adds the path to drv.inputSrcs rather than
 | 
				
			||||||
 | 
					   drv.inputDrvs. */
 | 
				
			||||||
 | 
					static void prim_unsafeDiscardOutputDependency(EvalState & state, const Pos & pos, Value * * args, Value & v)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    PathSet context;
 | 
				
			||||||
 | 
					    string s = state.coerceToString(pos, *args[0], context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PathSet context2;
 | 
				
			||||||
 | 
					    for (auto & p : context)
 | 
				
			||||||
 | 
					        context2.insert(p.at(0) == '=' ? string(p, 1) : p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mkString(v, s, context2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static RegisterPrimOp r3("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Extract the context of a string as a structured Nix value.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   The context is represented as an attribute set whose keys are the
 | 
				
			||||||
 | 
					   paths in the context set and whose values are attribute sets with
 | 
				
			||||||
 | 
					   the following keys:
 | 
				
			||||||
 | 
					     path: True if the relevant path is in the context as a plain store
 | 
				
			||||||
 | 
					           path (i.e. the kind of context you get when interpolating
 | 
				
			||||||
 | 
					           a Nix path (e.g. ./.) into a string). False if missing.
 | 
				
			||||||
 | 
					     allOutputs: True if the relevant path is a derivation and it is
 | 
				
			||||||
 | 
					                  in the context as a drv file with all of its outputs
 | 
				
			||||||
 | 
					                  (i.e. the kind of context you get when referencing
 | 
				
			||||||
 | 
					                  .drvPath of some derivation). False if missing.
 | 
				
			||||||
 | 
					     outputs: If a non-empty list, the relevant path is a derivation
 | 
				
			||||||
 | 
					              and the provided outputs are referenced in the context
 | 
				
			||||||
 | 
					              (i.e. the kind of context you get when referencing
 | 
				
			||||||
 | 
					              .outPath of some derivation). Empty list if missing.
 | 
				
			||||||
 | 
					   Note that for a given path any combination of the above attributes
 | 
				
			||||||
 | 
					   may be present.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					static void prim_getContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct ContextInfo {
 | 
				
			||||||
 | 
					        bool path = false;
 | 
				
			||||||
 | 
					        bool allOutputs = false;
 | 
				
			||||||
 | 
					        Strings outputs;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    PathSet context;
 | 
				
			||||||
 | 
					    state.forceString(*args[0], context, pos);
 | 
				
			||||||
 | 
					    auto contextInfos = std::map<Path, ContextInfo>();
 | 
				
			||||||
 | 
					    for (const auto & p : context) {
 | 
				
			||||||
 | 
					        Path drv;
 | 
				
			||||||
 | 
					        string output;
 | 
				
			||||||
 | 
					        const Path * path = &p;
 | 
				
			||||||
 | 
					        if (p.at(0) == '=') {
 | 
				
			||||||
 | 
					            drv = string(p, 1);
 | 
				
			||||||
 | 
					            path = &drv;
 | 
				
			||||||
 | 
					        } else if (p.at(0) == '!') {
 | 
				
			||||||
 | 
					            std::pair<string, string> ctx = decodeContext(p);
 | 
				
			||||||
 | 
					            drv = ctx.first;
 | 
				
			||||||
 | 
					            output = ctx.second;
 | 
				
			||||||
 | 
					            path = &drv;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        auto isPath = drv.empty();
 | 
				
			||||||
 | 
					        auto isAllOutputs = (!drv.empty()) && output.empty();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto iter = contextInfos.find(*path);
 | 
				
			||||||
 | 
					        if (iter == contextInfos.end()) {
 | 
				
			||||||
 | 
					            contextInfos.emplace(*path, ContextInfo{isPath, isAllOutputs, output.empty() ? Strings{} : Strings{std::move(output)}});
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            if (isPath)
 | 
				
			||||||
 | 
					                iter->second.path = true;
 | 
				
			||||||
 | 
					            else if (isAllOutputs)
 | 
				
			||||||
 | 
					                iter->second.allOutputs = true;
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                iter->second.outputs.emplace_back(std::move(output));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    state.mkAttrs(v, contextInfos.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto sPath = state.symbols.create("path");
 | 
				
			||||||
 | 
					    auto sAllOutputs = state.symbols.create("allOutputs");
 | 
				
			||||||
 | 
					    for (const auto & info : contextInfos) {
 | 
				
			||||||
 | 
					        auto & infoVal = *state.allocAttr(v, state.symbols.create(info.first));
 | 
				
			||||||
 | 
					        state.mkAttrs(infoVal, 3);
 | 
				
			||||||
 | 
					        if (info.second.path)
 | 
				
			||||||
 | 
					            mkBool(*state.allocAttr(infoVal, sPath), true);
 | 
				
			||||||
 | 
					        if (info.second.allOutputs)
 | 
				
			||||||
 | 
					            mkBool(*state.allocAttr(infoVal, sAllOutputs), true);
 | 
				
			||||||
 | 
					        if (!info.second.outputs.empty()) {
 | 
				
			||||||
 | 
					            auto & outputsVal = *state.allocAttr(infoVal, state.sOutputs);
 | 
				
			||||||
 | 
					            state.mkList(outputsVal, info.second.outputs.size());
 | 
				
			||||||
 | 
					            size_t i = 0;
 | 
				
			||||||
 | 
					            for (const auto & output : info.second.outputs) {
 | 
				
			||||||
 | 
					                mkString(*(outputsVal.listElems()[i++] = state.allocValue()), output);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        infoVal.attrs->sort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    v.attrs->sort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static RegisterPrimOp r4("__getContext", 1, prim_getContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Append the given context to a given string.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   See the commentary above unsafeGetContext for details of the
 | 
				
			||||||
 | 
					   context representation.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					static void prim_appendContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    PathSet context;
 | 
				
			||||||
 | 
					    auto orig = state.forceString(*args[0], context, pos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    state.forceAttrs(*args[1], pos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto sPath = state.symbols.create("path");
 | 
				
			||||||
 | 
					    auto sAllOutputs = state.symbols.create("allOutputs");
 | 
				
			||||||
 | 
					    for (auto & i : *args[1]->attrs) {
 | 
				
			||||||
 | 
					        if (!state.store->isStorePath(i.name))
 | 
				
			||||||
 | 
					            throw EvalError("Context key '%s' is not a store path, at %s", i.name, i.pos);
 | 
				
			||||||
 | 
					        if (!settings.readOnlyMode)
 | 
				
			||||||
 | 
					            state.store->ensurePath(i.name);
 | 
				
			||||||
 | 
					        state.forceAttrs(*i.value, *i.pos);
 | 
				
			||||||
 | 
					        auto iter = i.value->attrs->find(sPath);
 | 
				
			||||||
 | 
					        if (iter != i.value->attrs->end()) {
 | 
				
			||||||
 | 
					            if (state.forceBool(*iter->value, *iter->pos))
 | 
				
			||||||
 | 
					                context.insert(i.name);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        iter = i.value->attrs->find(sAllOutputs);
 | 
				
			||||||
 | 
					        if (iter != i.value->attrs->end()) {
 | 
				
			||||||
 | 
					            if (state.forceBool(*iter->value, *iter->pos)) {
 | 
				
			||||||
 | 
					                if (!isDerivation(i.name)) {
 | 
				
			||||||
 | 
					                    throw EvalError("Tried to add all-outputs context of %s, which is not a derivation, to a string, at %s", i.name, i.pos);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                context.insert("=" + string(i.name));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        iter = i.value->attrs->find(state.sOutputs);
 | 
				
			||||||
 | 
					        if (iter != i.value->attrs->end()) {
 | 
				
			||||||
 | 
					            state.forceList(*iter->value, *iter->pos);
 | 
				
			||||||
 | 
					            if (iter->value->listSize() && !isDerivation(i.name)) {
 | 
				
			||||||
 | 
					                throw EvalError("Tried to add derivation output context of %s, which is not a derivation, to a string, at %s", i.name, i.pos);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            for (unsigned int n = 0; n < iter->value->listSize(); ++n) {
 | 
				
			||||||
 | 
					                auto name = state.forceStringNoCtx(*iter->value->listElems()[n], *iter->pos);
 | 
				
			||||||
 | 
					                context.insert("!" + name + "!" + string(i.name));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mkString(v, orig, context);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static RegisterPrimOp r5("__appendContext", 2, prim_appendContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								tests/lang/eval-okay-context-introspection.exp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/lang/eval-okay-context-introspection.exp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					true
 | 
				
			||||||
							
								
								
									
										24
									
								
								tests/lang/eval-okay-context-introspection.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								tests/lang/eval-okay-context-introspection.nix
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,24 @@
 | 
				
			||||||
 | 
					let
 | 
				
			||||||
 | 
					  drv = derivation {
 | 
				
			||||||
 | 
					    name = "fail";
 | 
				
			||||||
 | 
					    builder = "/bin/false";
 | 
				
			||||||
 | 
					    system = "x86_64-linux";
 | 
				
			||||||
 | 
					    outputs = [ "out" "foo" ];
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  path = "${./eval-okay-context-introspection.nix}";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  desired-context = {
 | 
				
			||||||
 | 
					    "${builtins.unsafeDiscardStringContext path}" = {
 | 
				
			||||||
 | 
					      path = true;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    "${builtins.unsafeDiscardStringContext drv.drvPath}" = {
 | 
				
			||||||
 | 
					      outputs = [ "foo" "out" ];
 | 
				
			||||||
 | 
					      allOutputs = true;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  legit-context = builtins.getContext "${path}${drv.outPath}${drv.foo.outPath}${drv.drvPath}";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  constructed-context = builtins.getContext (builtins.appendContext "" desired-context);
 | 
				
			||||||
 | 
					in legit-context == constructed-context
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue