1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-12-20 16:01:07 +01:00

Improve wrong format message with nix hash convert

We have the machinery to make a more informative error, telling the
user what format was actually encountered, and not just that it is not
the format that was requested.
This commit is contained in:
John Ericson 2025-12-05 11:21:47 -05:00
parent 5f42e5ebb7
commit b61885786d
5 changed files with 43 additions and 22 deletions

View file

@ -182,8 +182,10 @@ Hash Hash::parseSRI(std::string_view original)
*
* @param resolveAlgo resolves the parsed type (or throws an error when it is not
* possible.)
*
* @return the parsed hash and the format it was parsed from
*/
static Hash parseAnyHelper(std::string_view rest, auto resolveAlgo)
static std::pair<Hash, HashFormat> parseAnyHelper(std::string_view rest, auto resolveAlgo)
{
bool isSRI = false;
@ -203,34 +205,45 @@ static Hash parseAnyHelper(std::string_view rest, auto resolveAlgo)
HashAlgorithm algo = resolveAlgo(std::move(optParsedAlgo));
auto [decode, formatName] = [&]() -> DecodeNamePair {
auto [decode, formatName, format] = [&]() -> std::tuple<decltype(base16::decode) *, std::string_view, HashFormat> {
if (isSRI) {
/* In the SRI case, we always are using Base64. If the
length is wrong, get an error later. */
return {base64::decode, "SRI"};
return {base64::decode, "SRI", HashFormat::SRI};
} else {
/* Otherwise, decide via the length of the hash (for the
given algorithm) what base encoding it is. */
return baseExplicit(baseFromSize(rest, algo));
auto format = baseFromSize(rest, algo);
auto [decode, formatName] = baseExplicit(format);
return {decode, formatName, format};
}
}();
return parseLowLevel(rest, algo, {decode, formatName});
return {parseLowLevel(rest, algo, {decode, formatName}), format};
}
Hash Hash::parseAnyPrefixed(std::string_view original)
{
return parseAnyHelper(original, [&](std::optional<HashAlgorithm> optParsedAlgo) {
// Either the string or user must provide the type, if they both do they
// must agree.
if (!optParsedAlgo)
throw BadHash("hash '%s' does not include a type", original);
return parseAnyHelper(
original,
[&](std::optional<HashAlgorithm> optParsedAlgo) {
// Either the string or user must provide the type, if they both do they
// must agree.
if (!optParsedAlgo)
throw BadHash("hash '%s' does not include a type", original);
return *optParsedAlgo;
});
return *optParsedAlgo;
})
.first;
}
Hash Hash::parseAny(std::string_view original, std::optional<HashAlgorithm> optAlgo)
{
return parseAnyReturningFormat(original, optAlgo).first;
}
std::pair<Hash, HashFormat>
Hash::parseAnyReturningFormat(std::string_view original, std::optional<HashAlgorithm> optAlgo)
{
return parseAnyHelper(original, [&](std::optional<HashAlgorithm> optParsedAlgo) {
// Either the string or user must provide the type, if they both do they

View file

@ -79,6 +79,12 @@ struct Hash
*/
static Hash parseAny(std::string_view s, std::optional<HashAlgorithm> optAlgo);
/**
* Like `parseAny`, but also returns the format the hash was parsed from.
*/
static std::pair<Hash, HashFormat>
parseAnyReturningFormat(std::string_view s, std::optional<HashAlgorithm> optAlgo);
/**
* Parse a hash from a string representation like the above, except the
* type prefix is mandatory is there is no separate argument.