Improve error message for self reference with text hashing

The `ContentAddressWithReferences` method is made total, with error
handling now squarely the caller's job. This is better.
This commit is contained in:
John Ericson 2023-05-09 14:44:08 -04:00
parent e514b3939a
commit 6a3a87a714
3 changed files with 34 additions and 21 deletions

View file

@ -2456,13 +2456,21 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
},
}, outputHash.method.raw);
auto got = caSink.finish().first;
auto optCA = ContentAddressWithReferences::fromPartsOpt(
outputHash.method,
std::move(got),
rewriteRefs());
if (!optCA) {
// TODO track distinct failure modes separately (at the time of
// writing there is just one but `nullopt` is unclear) so this
// message can't get out of sync.
throw BuildError("output path '%s' has illegal content address, probably a spurious self-reference with text hashing");
}
ValidPathInfo newInfo0 {
worker.store,
outputPathName(drv->name, outputName),
ContentAddressWithReferences::fromParts(
outputHash.method,
std::move(got),
rewriteRefs()),
*std::move(optCA),
Hash::dummy,
};
if (*scratchPath != newInfo0.path) {

View file

@ -232,25 +232,29 @@ ContentAddressWithReferences ContentAddressWithReferences::withoutRefs(const Con
}, ca.raw);
}
ContentAddressWithReferences ContentAddressWithReferences::fromParts(
ContentAddressMethod method, Hash hash, StoreReferences refs)
std::optional<ContentAddressWithReferences> ContentAddressWithReferences::fromPartsOpt(
ContentAddressMethod method, Hash hash, StoreReferences refs) noexcept
{
return std::visit(overloaded {
[&](TextIngestionMethod _) -> ContentAddressWithReferences {
[&](TextIngestionMethod _) -> std::optional<ContentAddressWithReferences> {
if (refs.self)
throw UsageError("Cannot have a self reference with text hashing scheme");
return TextInfo {
.hash = { .hash = std::move(hash) },
.references = std::move(refs.others),
return std::nullopt;
return ContentAddressWithReferences {
TextInfo {
.hash = { .hash = std::move(hash) },
.references = std::move(refs.others),
}
};
},
[&](FileIngestionMethod m2) -> ContentAddressWithReferences {
return FixedOutputInfo {
.hash = {
.method = m2,
.hash = std::move(hash),
},
.references = std::move(refs),
[&](FileIngestionMethod m2) -> std::optional<ContentAddressWithReferences> {
return ContentAddressWithReferences {
FixedOutputInfo {
.hash = {
.method = m2,
.hash = std::move(hash),
},
.references = std::move(refs),
}
};
},
}, method.raw);

View file

@ -303,10 +303,11 @@ struct ContentAddressWithReferences
*
* @param refs References to other store objects or oneself.
*
* Do note that not all combinations are supported.
* Do note that not all combinations are supported; `nullopt` is
* returns for invalid combinations.
*/
static ContentAddressWithReferences fromParts(
ContentAddressMethod method, Hash hash, StoreReferences refs);
static std::optional<ContentAddressWithReferences> fromPartsOpt(
ContentAddressMethod method, Hash hash, StoreReferences refs) noexcept;
ContentAddressMethod getMethod() const;