forked from lix-project/lix
Merge pull request #5807 from NixOS/5805-ca-ifd
Fix IFD with CA derivations
This commit is contained in:
commit
89faff93e2
|
@ -353,7 +353,10 @@ public:
|
||||||
/* Print statistics. */
|
/* Print statistics. */
|
||||||
void printStats();
|
void printStats();
|
||||||
|
|
||||||
void realiseContext(const PathSet & context);
|
/* Realise the given context, and return a mapping from the placeholders
|
||||||
|
* used to construct the associated value to their final store path
|
||||||
|
*/
|
||||||
|
[[nodiscard]] StringMap realiseContext(const PathSet & context);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -35,9 +35,10 @@ 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) {}
|
||||||
|
|
||||||
void EvalState::realiseContext(const PathSet & context)
|
StringMap EvalState::realiseContext(const PathSet & context)
|
||||||
{
|
{
|
||||||
std::vector<DerivedPath::Built> drvs;
|
std::vector<DerivedPath::Built> drvs;
|
||||||
|
StringMap res;
|
||||||
|
|
||||||
for (auto & i : context) {
|
for (auto & i : context) {
|
||||||
auto [ctxS, outputName] = decodeContext(i);
|
auto [ctxS, outputName] = decodeContext(i);
|
||||||
|
@ -46,10 +47,12 @@ void EvalState::realiseContext(const PathSet & context)
|
||||||
throw InvalidPathError(store->printStorePath(ctx));
|
throw InvalidPathError(store->printStorePath(ctx));
|
||||||
if (!outputName.empty() && ctx.isDerivation()) {
|
if (!outputName.empty() && ctx.isDerivation()) {
|
||||||
drvs.push_back({ctx, {outputName}});
|
drvs.push_back({ctx, {outputName}});
|
||||||
|
} else {
|
||||||
|
res.insert_or_assign(ctxS, ctxS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drvs.empty()) return;
|
if (drvs.empty()) return {};
|
||||||
|
|
||||||
if (!evalSettings.enableImportFromDerivation)
|
if (!evalSettings.enableImportFromDerivation)
|
||||||
throw Error(
|
throw Error(
|
||||||
|
@ -61,21 +64,45 @@ void EvalState::realiseContext(const PathSet & context)
|
||||||
for (auto & d : drvs) buildReqs.emplace_back(DerivedPath { d });
|
for (auto & d : drvs) buildReqs.emplace_back(DerivedPath { d });
|
||||||
store->buildPaths(buildReqs);
|
store->buildPaths(buildReqs);
|
||||||
|
|
||||||
/* Add the output of this derivations to the allowed
|
/* Get all the output paths corresponding to the placeholders we had */
|
||||||
paths. */
|
|
||||||
if (allowedPaths) {
|
|
||||||
for (auto & [drvPath, outputs] : drvs) {
|
for (auto & [drvPath, outputs] : drvs) {
|
||||||
auto outputPaths = store->queryDerivationOutputMap(drvPath);
|
auto outputPaths = store->queryDerivationOutputMap(drvPath);
|
||||||
for (auto & outputName : outputs) {
|
for (auto & outputName : outputs) {
|
||||||
if (outputPaths.count(outputName) == 0)
|
if (outputPaths.count(outputName) == 0)
|
||||||
throw Error("derivation '%s' does not have an output named '%s'",
|
throw Error("derivation '%s' does not have an output named '%s'",
|
||||||
store->printStorePath(drvPath), outputName);
|
store->printStorePath(drvPath), outputName);
|
||||||
allowPath(outputPaths.at(outputName));
|
res.insert_or_assign(
|
||||||
|
downstreamPlaceholder(*store, drvPath, outputName),
|
||||||
|
store->printStorePath(outputPaths.at(outputName))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add the output of this derivations to the allowed
|
||||||
|
paths. */
|
||||||
|
if (allowedPaths) {
|
||||||
|
for (auto & [_placeholder, outputPath] : res) {
|
||||||
|
allowPath(outputPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Path realisePath(EvalState & state, const Pos & pos, Value & v, bool requireAbsolutePath = true)
|
||||||
|
{
|
||||||
|
PathSet context;
|
||||||
|
|
||||||
|
Path path = requireAbsolutePath
|
||||||
|
? state.coerceToPath(pos, v, context)
|
||||||
|
: state.coerceToString(pos, v, context, false, false);
|
||||||
|
|
||||||
|
StringMap rewrites = state.realiseContext(context);
|
||||||
|
|
||||||
|
return state.checkSourcePath(
|
||||||
|
state.toRealPath(rewriteStrings(path, rewrites), context));
|
||||||
|
}
|
||||||
|
|
||||||
/* Add and attribute to the given attribute map from the output name to
|
/* Add and attribute to the given attribute map from the output name to
|
||||||
the output path, or a placeholder.
|
the output path, or a placeholder.
|
||||||
|
|
||||||
|
@ -109,11 +136,9 @@ static void mkOutputString(EvalState & state, Value & v,
|
||||||
argument. */
|
argument. */
|
||||||
static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vScope, Value & v)
|
static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vScope, Value & v)
|
||||||
{
|
{
|
||||||
PathSet context;
|
Path path;
|
||||||
Path path = state.coerceToPath(pos, vPath, context);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
state.realiseContext(context);
|
path = realisePath(state, pos, vPath);
|
||||||
} catch (InvalidPathError & e) {
|
} catch (InvalidPathError & e) {
|
||||||
throw EvalError({
|
throw EvalError({
|
||||||
.msg = hintfmt("cannot import '%1%', since path '%2%' is not valid", path, e.path),
|
.msg = hintfmt("cannot import '%1%', since path '%2%' is not valid", path, e.path),
|
||||||
|
@ -124,8 +149,6 @@ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vS
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
Path realPath = state.checkSourcePath(state.toRealPath(path, context));
|
|
||||||
|
|
||||||
// FIXME
|
// FIXME
|
||||||
auto isValidDerivationInStore = [&]() -> std::optional<StorePath> {
|
auto isValidDerivationInStore = [&]() -> std::optional<StorePath> {
|
||||||
if (!state.store->isStorePath(path))
|
if (!state.store->isStorePath(path))
|
||||||
|
@ -177,7 +200,7 @@ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vS
|
||||||
|
|
||||||
else {
|
else {
|
||||||
if (!vScope)
|
if (!vScope)
|
||||||
state.evalFile(realPath, v);
|
state.evalFile(path, v);
|
||||||
else {
|
else {
|
||||||
state.forceAttrs(*vScope);
|
state.forceAttrs(*vScope);
|
||||||
|
|
||||||
|
@ -195,8 +218,8 @@ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vS
|
||||||
// No need to call staticEnv.sort(), because
|
// No need to call staticEnv.sort(), because
|
||||||
// args[0]->attrs is already sorted.
|
// args[0]->attrs is already sorted.
|
||||||
|
|
||||||
printTalkative("evaluating file '%1%'", realPath);
|
printTalkative("evaluating file '%1%'", path);
|
||||||
Expr * e = state.parseExprFromFile(resolveExprPath(realPath), staticEnv);
|
Expr * e = state.parseExprFromFile(resolveExprPath(path), staticEnv);
|
||||||
|
|
||||||
e->eval(state, *env, v);
|
e->eval(state, *env, v);
|
||||||
}
|
}
|
||||||
|
@ -281,22 +304,19 @@ extern "C" typedef void (*ValueInitializer)(EvalState & state, Value & v);
|
||||||
/* Load a ValueInitializer from a DSO and return whatever it initializes */
|
/* Load a ValueInitializer from a DSO and return whatever it initializes */
|
||||||
void prim_importNative(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
void prim_importNative(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
PathSet context;
|
Path path;
|
||||||
Path path = state.coerceToPath(pos, *args[0], context);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
state.realiseContext(context);
|
path = realisePath(state, pos, *args[0]);
|
||||||
} catch (InvalidPathError & e) {
|
} catch (InvalidPathError & e) {
|
||||||
throw EvalError({
|
throw EvalError({
|
||||||
.msg = hintfmt(
|
.msg = hintfmt("cannot import '%1%', since path '%2%' is not valid", path, e.path),
|
||||||
"cannot import '%1%', since path '%2%' is not valid",
|
|
||||||
path, e.path),
|
|
||||||
.errPos = pos
|
.errPos = pos
|
||||||
});
|
});
|
||||||
|
} catch (Error & e) {
|
||||||
|
e.addTrace(pos, "while importing '%s'", path);
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
path = state.checkSourcePath(path);
|
|
||||||
|
|
||||||
string sym = state.forceStringNoCtx(*args[1], pos);
|
string sym = state.forceStringNoCtx(*args[1], pos);
|
||||||
|
|
||||||
void *handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
|
void *handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
|
||||||
|
@ -338,7 +358,7 @@ void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
for (unsigned int i = 1; i < args[0]->listSize(); ++i)
|
for (unsigned int i = 1; i < args[0]->listSize(); ++i)
|
||||||
commandArgs.emplace_back(state.coerceToString(pos, *elems[i], context, false, false));
|
commandArgs.emplace_back(state.coerceToString(pos, *elems[i], context, false, false));
|
||||||
try {
|
try {
|
||||||
state.realiseContext(context);
|
auto _ = state.realiseContext(context); // FIXME: Handle CA derivations
|
||||||
} catch (InvalidPathError & e) {
|
} catch (InvalidPathError & e) {
|
||||||
throw EvalError({
|
throw EvalError({
|
||||||
.msg = hintfmt("cannot execute '%1%', since path '%2%' is not valid",
|
.msg = hintfmt("cannot execute '%1%', since path '%2%' is not valid",
|
||||||
|
@ -1349,10 +1369,9 @@ static RegisterPrimOp primop_storePath({
|
||||||
|
|
||||||
static void prim_pathExists(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_pathExists(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
PathSet context;
|
Path path;
|
||||||
Path path = state.coerceToPath(pos, *args[0], context);
|
|
||||||
try {
|
try {
|
||||||
state.realiseContext(context);
|
path = realisePath(state, pos, *args[0]);
|
||||||
} catch (InvalidPathError & e) {
|
} catch (InvalidPathError & e) {
|
||||||
throw EvalError({
|
throw EvalError({
|
||||||
.msg = hintfmt(
|
.msg = hintfmt(
|
||||||
|
@ -1363,7 +1382,7 @@ static void prim_pathExists(EvalState & state, const Pos & pos, Value * * args,
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mkBool(v, pathExists(state.checkSourcePath(path)));
|
mkBool(v, pathExists(path));
|
||||||
} catch (SysError & e) {
|
} catch (SysError & e) {
|
||||||
/* Don't give away info from errors while canonicalising
|
/* Don't give away info from errors while canonicalising
|
||||||
‘path’ in restricted mode. */
|
‘path’ in restricted mode. */
|
||||||
|
@ -1426,17 +1445,16 @@ static RegisterPrimOp primop_dirOf({
|
||||||
/* Return the contents of a file as a string. */
|
/* Return the contents of a file as a string. */
|
||||||
static void prim_readFile(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_readFile(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
PathSet context;
|
Path path;
|
||||||
Path path = state.coerceToPath(pos, *args[0], context);
|
|
||||||
try {
|
try {
|
||||||
state.realiseContext(context);
|
path = realisePath(state, pos, *args[0]);
|
||||||
} catch (InvalidPathError & e) {
|
} catch (InvalidPathError & e) {
|
||||||
throw EvalError({
|
throw EvalError({
|
||||||
.msg = hintfmt("cannot read '%1%', since path '%2%' is not valid", path, e.path),
|
.msg = hintfmt("cannot read '%1%', since path '%2%' is not valid", path, e.path),
|
||||||
.errPos = pos
|
.errPos = pos
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
string s = readFile(state.checkSourcePath(state.toRealPath(path, context)));
|
string s = readFile(path);
|
||||||
if (s.find((char) 0) != string::npos)
|
if (s.find((char) 0) != string::npos)
|
||||||
throw Error("the contents of the file '%1%' cannot be represented as a Nix string", path);
|
throw Error("the contents of the file '%1%' cannot be represented as a Nix string", path);
|
||||||
mkString(v, s.c_str());
|
mkString(v, s.c_str());
|
||||||
|
@ -1475,11 +1493,10 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
|
||||||
pos
|
pos
|
||||||
);
|
);
|
||||||
|
|
||||||
PathSet context;
|
Path path;
|
||||||
string path = state.coerceToString(pos, *i->value, context, false, false);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
state.realiseContext(context);
|
path = realisePath(state, pos, *i->value, false);
|
||||||
} catch (InvalidPathError & e) {
|
} catch (InvalidPathError & e) {
|
||||||
throw EvalError({
|
throw EvalError({
|
||||||
.msg = hintfmt("cannot find '%1%', since path '%2%' is not valid", path, e.path),
|
.msg = hintfmt("cannot find '%1%', since path '%2%' is not valid", path, e.path),
|
||||||
|
@ -1512,15 +1529,14 @@ static void prim_hashFile(EvalState & state, const Pos & pos, Value * * args, Va
|
||||||
.errPos = pos
|
.errPos = pos
|
||||||
});
|
});
|
||||||
|
|
||||||
PathSet context;
|
Path path;
|
||||||
Path path = state.coerceToPath(pos, *args[1], context);
|
|
||||||
try {
|
try {
|
||||||
state.realiseContext(context);
|
path = realisePath(state, pos, *args[1]);
|
||||||
} catch (InvalidPathError & e) {
|
} catch (InvalidPathError & e) {
|
||||||
throw EvalError("cannot read '%s' since path '%s' is not valid, at %s", path, e.path, pos);
|
throw EvalError("cannot read '%s' since path '%s' is not valid, at %s", path, e.path, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
mkString(v, hashFile(*ht, state.checkSourcePath(state.toRealPath(path, context))).to_string(Base16, false));
|
mkString(v, hashFile(*ht, path).to_string(Base16, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_hashFile({
|
static RegisterPrimOp primop_hashFile({
|
||||||
|
@ -1537,10 +1553,9 @@ static RegisterPrimOp primop_hashFile({
|
||||||
/* Read a directory (without . or ..) */
|
/* Read a directory (without . or ..) */
|
||||||
static void prim_readDir(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_readDir(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
PathSet ctx;
|
Path path;
|
||||||
Path path = state.coerceToPath(pos, *args[0], ctx);
|
|
||||||
try {
|
try {
|
||||||
state.realiseContext(ctx);
|
path = realisePath(state, pos, *args[0]);
|
||||||
} catch (InvalidPathError & e) {
|
} catch (InvalidPathError & e) {
|
||||||
throw EvalError({
|
throw EvalError({
|
||||||
.msg = hintfmt("cannot read '%1%', since path '%2%' is not valid", path, e.path),
|
.msg = hintfmt("cannot read '%1%', since path '%2%' is not valid", path, e.path),
|
||||||
|
@ -1548,7 +1563,7 @@ static void prim_readDir(EvalState & state, const Pos & pos, Value * * args, Val
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
DirEntries entries = readDirectory(state.checkSourcePath(path));
|
DirEntries entries = readDirectory(path);
|
||||||
state.mkAttrs(v, entries.size());
|
state.mkAttrs(v, entries.size());
|
||||||
|
|
||||||
for (auto & ent : entries) {
|
for (auto & ent : entries) {
|
||||||
|
@ -1875,7 +1890,8 @@ static void addPath(
|
||||||
try {
|
try {
|
||||||
// FIXME: handle CA derivation outputs (where path needs to
|
// FIXME: handle CA derivation outputs (where path needs to
|
||||||
// be rewritten to the actual output).
|
// be rewritten to the actual output).
|
||||||
state.realiseContext(context);
|
auto rewrites = state.realiseContext(context);
|
||||||
|
path = state.toRealPath(rewriteStrings(path, rewrites), context);
|
||||||
|
|
||||||
StorePathSet refs;
|
StorePathSet refs;
|
||||||
|
|
||||||
|
|
6
tests/ca/import-derivation.sh
Normal file
6
tests/ca/import-derivation.sh
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
source common.sh
|
||||||
|
|
||||||
|
export NIX_TESTS_CA_BY_DEFAULT=1
|
||||||
|
|
||||||
|
cd .. && source import-derivation.sh
|
||||||
|
|
|
@ -11,7 +11,7 @@ nix_tests = \
|
||||||
local-store.sh remote-store.sh export.sh export-graph.sh \
|
local-store.sh remote-store.sh export.sh export-graph.sh \
|
||||||
db-migration.sh \
|
db-migration.sh \
|
||||||
timeout.sh secure-drv-outputs.sh nix-channel.sh \
|
timeout.sh secure-drv-outputs.sh nix-channel.sh \
|
||||||
multiple-outputs.sh import-derivation.sh fetchurl.sh optimise-store.sh \
|
multiple-outputs.sh import-derivation.sh ca/import-derivation.sh fetchurl.sh optimise-store.sh \
|
||||||
binary-cache.sh \
|
binary-cache.sh \
|
||||||
substitute-with-invalid-ca.sh \
|
substitute-with-invalid-ca.sh \
|
||||||
binary-cache-build-remote.sh \
|
binary-cache-build-remote.sh \
|
||||||
|
|
Loading…
Reference in a new issue