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); }, outputHash.method.raw);
auto got = caSink.finish().first; 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 { ValidPathInfo newInfo0 {
worker.store, worker.store,
outputPathName(drv->name, outputName), outputPathName(drv->name, outputName),
ContentAddressWithReferences::fromParts( *std::move(optCA),
outputHash.method,
std::move(got),
rewriteRefs()),
Hash::dummy, Hash::dummy,
}; };
if (*scratchPath != newInfo0.path) { if (*scratchPath != newInfo0.path) {

View file

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

View file

@ -303,10 +303,11 @@ struct ContentAddressWithReferences
* *
* @param refs References to other store objects or oneself. * @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( static std::optional<ContentAddressWithReferences> fromPartsOpt(
ContentAddressMethod method, Hash hash, StoreReferences refs); ContentAddressMethod method, Hash hash, StoreReferences refs) noexcept;
ContentAddressMethod getMethod() const; ContentAddressMethod getMethod() const;