Skip to content

Commit

Permalink
fetchClosure: Always check that inputAddressed matches the result
Browse files Browse the repository at this point in the history
  • Loading branch information
roberth committed May 19, 2023
1 parent 41ed7e1 commit 6542be8
Showing 1 changed file with 35 additions and 9 deletions.
44 changes: 35 additions & 9 deletions src/libexpr/primops/fetchClosure.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value * * arg
std::optional<StorePath> fromPath;
bool enableRewriting = false;
std::optional<StorePath> toPath;
bool inputAddressed = false;
std::optional<bool> inputAddressedMaybe;

for (auto & attr : *args[0]->attrs) {
const auto & attrName = state.symbols[attr.name];
Expand All @@ -40,7 +40,7 @@ static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value * * arg
attrHint());

else if (attrName == "inputAddressed")
inputAddressed = state.forceBool(*attr.value, attr.pos, attrHint());
inputAddressedMaybe = state.forceBool(*attr.value, attr.pos, attrHint());

else
throw Error({
Expand All @@ -55,6 +55,8 @@ static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value * * arg
.errPos = state.positions[pos]
});

bool inputAddressed = inputAddressedMaybe.value_or(false);

if (inputAddressed) {
if (toPath && toPath != fromPath)
throw Error({
Expand Down Expand Up @@ -121,16 +123,40 @@ static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value * * arg
toPath = fromPath;
}

/* We want input addressing to be explicit, to inform readers and to give
expression authors an opportunity to improve their user experience. */
if (!inputAddressed) {
auto info = state.store->queryPathInfo(*toPath);
auto info = state.store->queryPathInfo(*toPath);

/* If inputAddressed is set, make sure the result is as expected. */
if (inputAddressedMaybe) {
bool expectCA = !inputAddressed;
if (info->isContentAddressed(*state.store) != expectCA) {
if (inputAddressed)
throw Error({
.msg = hintfmt("The 'fetchClosure' result, '%s' is not input addressed, despite 'inputAddressed' being set to true. It is ok or even preferable to return a content addressed path, so you probably want to remove the 'inputAddressed' attribute",
state.store->printStorePath(*toPath)),
.errPos = state.positions[pos]
});
else
throw Error({
.msg = hintfmt("The 'fetchClosure' result, '%s' is input addressed, despite 'inputAddressed' being set to false. Please make sure you passed the correct path(s) or set 'inputAddressed' to true if you intended to return an input addressed path",
state.store->printStorePath(*toPath)),
.errPos = state.positions[pos]
});
}
} else {
/*
While it's fine to omit the inputAddressed attribute for CA paths,
we want input addressing to be explicit, to inform readers and to give
expression authors an opportunity to improve their user experience;
see message below.
*/
if (!info->isContentAddressed(*state.store)) {
if (enableRewriting) {
// We don't perform the rewriting when outPath already exists, as an optimisation.
// However, we can quickly detect a mistake if the toPath is input addressed.
// Ideally we'd compute the path for them here, but this error message is unlikely to occur in practice, so we keep it simple.
throw Error({
// Ideally we'd compute the path for them, but this error message is unlikely to occur in practice, so we keep it simple.
.msg = hintfmt("Rewriting was requested, but 'toPath' is not content addressed. This is impossible. Please change 'toPath' to the correct path, or to a non-existing path, and try again",
state.store->printStorePath(*toPath)),
.msg = hintfmt("The 'toPath' value '%s' is input addressed, so it can't possibly be the result of rewriting. You may set 'toPath' to an empty string to figure out the correct path.",
state.store->printStorePath(*fromPath)),
.errPos = state.positions[pos]
});
} else {
Expand Down

0 comments on commit 6542be8

Please sign in to comment.