From e29263b638d86378b78f10a246f05ee743b117b2 Mon Sep 17 00:00:00 2001 From: Tom Hubrecht Date: Tue, 6 Jan 2026 09:47:43 +0100 Subject: [PATCH] libutil/hash: Add default values for Hash::to_string The sane default is to print in SRI format, and include the hash type Change-Id: I7efcb5dcfbe56c82dbf1928e2bb35cdd3ff089c6 --- lix/legacy/nix-store.cc | 6 +++--- lix/libexpr/primops/fetchTree.cc | 6 +++--- lix/libfetchers/fetchers.cc | 6 +++--- lix/libfetchers/git.cc | 2 +- lix/libfetchers/mercurial.cc | 2 +- lix/libfetchers/tarball.cc | 2 +- lix/libstore/build/local-derivation-goal.cc | 4 ++-- lix/libstore/content-address.cc | 2 +- lix/libstore/export-import.cc | 4 ++-- lix/libstore/local-store.cc | 16 ++++++++-------- lix/libstore/nar-info-disk-cache.cc | 4 ++-- lix/libstore/nar-info.cc | 4 ++-- lix/libstore/optimise-store.cc | 2 +- lix/libstore/path-info.cc | 2 +- lix/libstore/realisation.hh | 2 +- lix/libstore/serve-protocol.cc | 2 +- lix/libstore/store-api.cc | 6 +++--- lix/libutil/hash.hh | 9 +-------- lix/nix/flake.cc | 4 ++-- lix/nix/prefetch.cc | 4 ++-- lix/nix/verify.cc | 4 ++-- perl/lib/Nix/Store.xs | 2 +- tests/unit/libutil/hash.cc | 16 ++++++++-------- 23 files changed, 52 insertions(+), 59 deletions(-) diff --git a/lix/legacy/nix-store.cc b/lix/legacy/nix-store.cc index 9d9c3549e..d1998f3da 100644 --- a/lix/legacy/nix-store.cc +++ b/lix/legacy/nix-store.cc @@ -467,7 +467,7 @@ opQuery(std::shared_ptr store, AsyncIoRoot & aio, Strings opFlags, String auto info = aio.blockOn(store->queryPathInfo(j)); if (query == qHash) { assert(info->narHash.type == HashType::SHA256); - cout << fmt("%s\n", info->narHash.to_string(HashFormat::Base32, true)); + cout << fmt("%s\n", info->narHash.to_string(HashFormat::Base32)); } else if (query == qSize) cout << fmt("%d\n", info->narSize); } @@ -859,8 +859,8 @@ opVerifyPath(std::shared_ptr store, AsyncIoRoot & aio, Strings opFlags, S printError( "path '%s' was modified! expected hash '%s', got '%s'", store->printStorePath(path), - info->narHash.to_string(HashFormat::SRI, true), - current.first.to_string(HashFormat::SRI, true) + info->narHash.to_string(), + current.first.to_string() ); status = 1; } diff --git a/lix/libexpr/primops/fetchTree.cc b/lix/libexpr/primops/fetchTree.cc index 55935fba8..21c75cec3 100644 --- a/lix/libexpr/primops/fetchTree.cc +++ b/lix/libexpr/primops/fetchTree.cc @@ -32,7 +32,7 @@ void emitTreeAttrs( auto narHash = input.getNarHash(); assert(narHash); - attrs.alloc("narHash").mkString(narHash->to_string(HashFormat::SRI, true)); + attrs.alloc("narHash").mkString(narHash->to_string()); if (input.getType() == "git") attrs.alloc("submodules").mkBool( @@ -318,8 +318,8 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v .make( "hash mismatch in file downloaded from '%s':\n specified: %s\n got: %s", *url, - expectedHash->to_string(HashFormat::SRI, true), - hash.to_string(HashFormat::SRI, true) + expectedHash->to_string(), + hash.to_string() ) .withExitStatus(102) .debugThrow(); diff --git a/lix/libfetchers/fetchers.cc b/lix/libfetchers/fetchers.cc index 3ccde2bba..22683d76d 100644 --- a/lix/libfetchers/fetchers.cc +++ b/lix/libfetchers/fetchers.cc @@ -178,7 +178,7 @@ try { }; auto narHash = TRY_AWAIT(store->queryPathInfo(tree.storePath))->narHash; - input.attrs.insert_or_assign("narHash", narHash.to_string(HashFormat::SRI, true)); + input.attrs.insert_or_assign("narHash", narHash.to_string()); if (auto prevNarHash = getNarHash()) { if (narHash != *prevNarHash) @@ -187,8 +187,8 @@ try { "NAR hash mismatch in input '%s' (%s), expected '%s', got '%s'", to_string(), tree.actualPath, - prevNarHash->to_string(HashFormat::SRI, true), - narHash.to_string(HashFormat::SRI, true) + prevNarHash->to_string(), + narHash.to_string() ); } diff --git a/lix/libfetchers/git.cc b/lix/libfetchers/git.cc index e40e2e4f0..d4f8dc285 100644 --- a/lix/libfetchers/git.cc +++ b/lix/libfetchers/git.cc @@ -579,7 +579,7 @@ struct GitInputScheme : InputScheme if (hash.has_value() && !(hash->type == HashType::SHA1 || hash->type == HashType::SHA256)) throw Error( "Hash '%s' is not supported by Git. Supported types are sha1 and sha256.", - hash->to_string(HashFormat::Base16, true) + hash->to_string(HashFormat::Base16) ); }; diff --git a/lix/libfetchers/mercurial.cc b/lix/libfetchers/mercurial.cc index 9b5769261..9962e282d 100644 --- a/lix/libfetchers/mercurial.cc +++ b/lix/libfetchers/mercurial.cc @@ -252,7 +252,7 @@ struct MercurialInputScheme : InputScheme if (hash.has_value() && hash->type != HashType::SHA1) throw Error( "Hash '%s' is not supported by Mercurial. Only sha1 is supported.", - hash->to_string(HashFormat::Base16, true) + hash->to_string(HashFormat::Base16) ); }; diff --git a/lix/libfetchers/tarball.cc b/lix/libfetchers/tarball.cc index 2436ba8f0..d19dbebef 100644 --- a/lix/libfetchers/tarball.cc +++ b/lix/libfetchers/tarball.cc @@ -293,7 +293,7 @@ struct CurlInputScheme : InputScheme // NAR hashes are preferred over file hashes since tar/zip // files don't have a canonical representation. if (auto narHash = input.getNarHash()) - url.query.insert_or_assign("narHash", narHash->to_string(HashFormat::SRI, true)); + url.query.insert_or_assign("narHash", narHash->to_string()); return url; } diff --git a/lix/libstore/build/local-derivation-goal.cc b/lix/libstore/build/local-derivation-goal.cc index f84071a4f..34a0f2da4 100644 --- a/lix/libstore/build/local-derivation-goal.cc +++ b/lix/libstore/build/local-derivation-goal.cc @@ -2105,8 +2105,8 @@ try { "specified: %s\n got: %s\n expected path: %s\n got path: %s", worker.store.printStorePath(drvPath), guessedUrl, - wanted.to_string(HashFormat::SRI, true), - got.to_string(HashFormat::SRI, true), + wanted.to_string(), + got.to_string(), worker.store.printStorePath(dof.path(worker.store, drv->name, outputName)), worker.store.printStorePath(newInfo0.path) )); diff --git a/lix/libstore/content-address.cc b/lix/libstore/content-address.cc index b58a554b2..809147593 100644 --- a/lix/libstore/content-address.cc +++ b/lix/libstore/content-address.cc @@ -62,7 +62,7 @@ std::string ContentAddress::render() const }, method.raw ) - + this->hash.to_string(HashFormat::Base32, true); + + this->hash.to_string(HashFormat::Base32); } /** diff --git a/lix/libstore/export-import.cc b/lix/libstore/export-import.cc index 2ea3c1638..e5ae2487c 100644 --- a/lix/libstore/export-import.cc +++ b/lix/libstore/export-import.cc @@ -42,8 +42,8 @@ try { throw Error( "hash of path '%s' has changed from '%s' to '%s'!", printStorePath(path), - info->narHash.to_string(HashFormat::SRI, true), - hash.to_string(HashFormat::SRI, true) + info->narHash.to_string(), + hash.to_string() ); teeSink diff --git a/lix/libstore/local-store.cc b/lix/libstore/local-store.cc index 1c3b72088..8e854111a 100644 --- a/lix/libstore/local-store.cc +++ b/lix/libstore/local-store.cc @@ -655,7 +655,7 @@ try { state.stmts->RegisterValidPath.use() (printStorePath(info.path)) - (info.narHash.to_string(HashFormat::Base16, true)) + (info.narHash.to_string(HashFormat::Base16)) (info.registrationTime == 0 ? time(0) : info.registrationTime) (info.deriver ? printStorePath(*info.deriver) : "", (bool) info.deriver) (info.narSize, info.narSize != 0) @@ -768,7 +768,7 @@ void LocalStore::updatePathInfo(DBState & state, const ValidPathInfo & info) { state.stmts->UpdatePathInfo.use() (info.narSize, info.narSize != 0) - (info.narHash.to_string(HashFormat::Base16, true)) + (info.narHash.to_string(HashFormat::Base16)) (info.ultimate ? 1 : 0, info.ultimate) (concatStringsSep(" ", info.sigs), !info.sigs.empty()) (renderContentAddress(info.ca), (bool) info.ca) @@ -1143,8 +1143,8 @@ try { throw Error( "hash mismatch importing path '%s';\n specified: %s\n got: %s", printStorePath(info.path), - info.narHash.to_string(HashFormat::SRI, true), - hashResult.first.to_string(HashFormat::SRI, true) + info.narHash.to_string(), + hashResult.first.to_string() ); if (hashResult.second != info.narSize) @@ -1162,8 +1162,8 @@ try { throw Error( "ca hash mismatch importing path '%s';\n specified: %s\n got: %s", printStorePath(info.path), - specified.hash.to_string(HashFormat::SRI, true), - actualHash.hash.to_string(HashFormat::SRI, true) + specified.hash.to_string(), + actualHash.hash.to_string() ); } } @@ -1551,8 +1551,8 @@ try { printError( "path '%s' was modified! expected hash '%s', got '%s'", toRealPath(printStorePath(i)), - info->narHash.to_string(HashFormat::SRI, true), - current.first.to_string(HashFormat::SRI, true) + info->narHash.to_string(), + current.first.to_string() ); if (repair) TRY_AWAIT(repairPath(i)); else errors = true; } else { diff --git a/lix/libstore/nar-info-disk-cache.cc b/lix/libstore/nar-info-disk-cache.cc index ee5a4f138..e16762d33 100644 --- a/lix/libstore/nar-info-disk-cache.cc +++ b/lix/libstore/nar-info-disk-cache.cc @@ -288,9 +288,9 @@ public: (std::string(info->path.name())) (narInfo ? narInfo->url : "", narInfo != 0) (narInfo ? narInfo->compression : "", narInfo != 0) - (narInfo && narInfo->fileHash ? narInfo->fileHash->to_string(HashFormat::Base32, true) : "", narInfo && narInfo->fileHash) + (narInfo && narInfo->fileHash ? narInfo->fileHash->to_string(HashFormat::Base32) : "", narInfo && narInfo->fileHash) (narInfo ? narInfo->fileSize : 0, narInfo != 0 && narInfo->fileSize) - (info->narHash.to_string(HashFormat::Base32, true)) + (info->narHash.to_string(HashFormat::Base32)) (info->narSize) (concatStringsSep(" ", info->shortRefs())) (info->deriver ? std::string(info->deriver->to_string()) : "", (bool) info->deriver) diff --git a/lix/libstore/nar-info.cc b/lix/libstore/nar-info.cc index 5524ffce4..8c1dea1b3 100644 --- a/lix/libstore/nar-info.cc +++ b/lix/libstore/nar-info.cc @@ -105,10 +105,10 @@ std::string NarInfo::to_string(const Store & store) const assert(compression != ""); res += "Compression: " + compression + "\n"; assert(fileHash && fileHash->type == HashType::SHA256); - res += "FileHash: " + fileHash->to_string(HashFormat::Base32, true) + "\n"; + res += "FileHash: " + fileHash->to_string(HashFormat::Base32) + "\n"; res += "FileSize: " + std::to_string(fileSize) + "\n"; assert(narHash.type == HashType::SHA256); - res += "NarHash: " + narHash.to_string(HashFormat::Base32, true) + "\n"; + res += "NarHash: " + narHash.to_string(HashFormat::Base32) + "\n"; res += "NarSize: " + std::to_string(narSize) + "\n"; res += "References: " + concatStringsSep(" ", shortRefs()) + "\n"; diff --git a/lix/libstore/optimise-store.cc b/lix/libstore/optimise-store.cc index 66c6e0cd8..d59e4f510 100644 --- a/lix/libstore/optimise-store.cc +++ b/lix/libstore/optimise-store.cc @@ -156,7 +156,7 @@ std::optional LocalStore::optimisePath_( contents of the symlink (i.e. the result of readlink()), not the contents of the target (which may not even exist). */ Hash hash = hashPath(HashType::SHA256, path).first; - debug("'%1%' has hash '%2%'", path, hash.to_string(HashFormat::Base32, true)); + debug("'%1%' has hash '%2%'", path, hash.to_string(HashFormat::Base32)); /* Check if this is a known hash. */ Path linkPath = linksDir + "/" + hash.to_string(HashFormat::Base32, false); diff --git a/lix/libstore/path-info.cc b/lix/libstore/path-info.cc index c39733fe3..6d8a825b6 100644 --- a/lix/libstore/path-info.cc +++ b/lix/libstore/path-info.cc @@ -28,7 +28,7 @@ std::string ValidPathInfo::fingerprint(const Store & store) const if (narSize == 0) throw Error("cannot calculate fingerprint of path '%s' because its size is not known", store.printStorePath(path)); - return "1;" + store.printStorePath(path) + ";" + narHash.to_string(HashFormat::Base32, true) + ";" + return "1;" + store.printStorePath(path) + ";" + narHash.to_string(HashFormat::Base32) + ";" + std::to_string(narSize) + ";" + concatStringsSep(",", store.printStorePathSet(references)); } diff --git a/lix/libstore/realisation.hh b/lix/libstore/realisation.hh index 1a8cc9097..6359e4e90 100644 --- a/lix/libstore/realisation.hh +++ b/lix/libstore/realisation.hh @@ -40,7 +40,7 @@ struct DrvOutput { std::string strHash() const { - return drvHash.to_string(HashFormat::Base16, true); + return drvHash.to_string(HashFormat::Base16); } static DrvOutput parse(const std::string &); diff --git a/lix/libstore/serve-protocol.cc b/lix/libstore/serve-protocol.cc index 3f8d962ce..750ede4fd 100644 --- a/lix/libstore/serve-protocol.cc +++ b/lix/libstore/serve-protocol.cc @@ -87,7 +87,7 @@ WireFormatGenerator ServeProto::Serialise::write(WriteConn co_yield info.narSize; // downloadSize, lie a little co_yield info.narSize; if (GET_PROTOCOL_MINOR(conn.version) >= 4) { - co_yield info.narHash.to_string(HashFormat::Base32, true); + co_yield info.narHash.to_string(HashFormat::Base32); co_yield renderContentAddress(info.ca); co_yield info.sigs; } diff --git a/lix/libstore/store-api.cc b/lix/libstore/store-api.cc index 652a14a99..2b23a7b9c 100644 --- a/lix/libstore/store-api.cc +++ b/lix/libstore/store-api.cc @@ -178,7 +178,7 @@ StorePath Store::makeStorePath(std::string_view type, StorePath Store::makeStorePath(std::string_view type, const Hash & hash, std::string_view name) const { - return makeStorePath(type, hash.to_string(HashFormat::Base16, true), name); + return makeStorePath(type, hash.to_string(HashFormat::Base16), name); } @@ -219,8 +219,8 @@ StorePath Store::makeFixedOutputPath(std::string_view name, const FixedOutputInf "output:out", hashString( HashType::SHA256, - "fixed:out:" + makeFileIngestionPrefix(info.method) - + info.hash.to_string(HashFormat::Base16, true) + ":" + "fixed:out:" + makeFileIngestionPrefix(info.method) + info.hash.to_string(HashFormat::Base16) + + ":" ), name ); diff --git a/lix/libutil/hash.hh b/lix/libutil/hash.hh index 67cdb998a..c71044bee 100644 --- a/lix/libutil/hash.hh +++ b/lix/libutil/hash.hh @@ -8,20 +8,16 @@ #include "lix/libutil/serialise.hh" #include "lix/libutil/file-system.hh" - namespace nix { - namespace detail { using EvpMdCtxPtr = std::unique_ptr; } - MakeError(BadHash, Error); - enum class HashType : char { MD5 = 42, SHA1, SHA256, SHA512 }; @@ -136,7 +132,7 @@ public: * or base-64. By default, this is prefixed by the hash type * (e.g. "sha256:"). */ - std::string to_string(HashFormat format, bool includeType) const; + std::string to_string(HashFormat format = HashFormat::SRI, bool includeType = true) const; std::string gitRev() const { @@ -198,7 +194,6 @@ std::optional parseHashTypeOpt(std::string_view s); */ std::string_view printHashType(HashType ht); - struct AbstractHashSink : virtual Sink { virtual HashResult finish() = 0; @@ -225,6 +220,4 @@ inline HashResult hashSource(HashType ht, Source & source) source.drainInto(h); return h.finish(); } - - } diff --git a/lix/nix/flake.cc b/lix/nix/flake.cc index c299516f8..9a441a40c 100644 --- a/lix/nix/flake.cc +++ b/lix/nix/flake.cc @@ -1532,14 +1532,14 @@ struct CmdFlakePrefetch : FlakeCommand, MixJSON if (json) { auto res = JSON::object(); res["storePath"] = store->printStorePath(tree.storePath); - res["hash"] = hash.to_string(HashFormat::SRI, true); + res["hash"] = hash.to_string(); logger->cout(res.dump()); } else { notice( "Downloaded '%s' to '%s' (hash '%s').", lockedRef.to_string(), store->printStorePath(tree.storePath), - hash.to_string(HashFormat::SRI, true) + hash.to_string() ); } } diff --git a/lix/nix/prefetch.cc b/lix/nix/prefetch.cc index bcb16fa6a..5cad445a3 100644 --- a/lix/nix/prefetch.cc +++ b/lix/nix/prefetch.cc @@ -345,14 +345,14 @@ struct CmdStorePrefetchFile : StoreCommand, MixJSON if (json) { auto res = JSON::object(); res["storePath"] = store->printStorePath(storePath); - res["hash"] = hash.to_string(HashFormat::SRI, true); + res["hash"] = hash.to_string(); logger->cout(res.dump()); } else { notice( "Downloaded '%s' to '%s' (hash '%s').", url, store->printStorePath(storePath), - hash.to_string(HashFormat::SRI, true) + hash.to_string() ); } } diff --git a/lix/nix/verify.cc b/lix/nix/verify.cc index 24c6c6b8b..1dac05d12 100644 --- a/lix/nix/verify.cc +++ b/lix/nix/verify.cc @@ -117,8 +117,8 @@ struct CmdVerify : StorePathsCommand printError( "path '%s' was modified! expected hash '%s', got '%s'", store->printStorePath(info->path), - info->narHash.to_string(HashFormat::SRI, true), - hash.first.to_string(HashFormat::SRI, true) + info->narHash.to_string(), + hash.first.to_string() ); } } diff --git a/perl/lib/Nix/Store.xs b/perl/lib/Nix/Store.xs index 6f85e5972..fb32c3124 100644 --- a/perl/lib/Nix/Store.xs +++ b/perl/lib/Nix/Store.xs @@ -92,7 +92,7 @@ SV * queryReferences(char * path) SV * queryPathHash(char * path) PPCODE: try { - auto s = aio().blockOn(store()->queryPathInfo(store()->parseStorePath(path)))->narHash.to_string(HashFormat::Base32, true); + auto s = aio().blockOn(store()->queryPathInfo(store()->parseStorePath(path)))->narHash.to_string(HashFormat::Base32); XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0))); } catch (Error & e) { croak("%s", e.what()); diff --git a/tests/unit/libutil/hash.cc b/tests/unit/libutil/hash.cc index f1bf4e3a4..4a134d178 100644 --- a/tests/unit/libutil/hash.cc +++ b/tests/unit/libutil/hash.cc @@ -14,28 +14,28 @@ namespace nix { // values taken from: https://tools.ietf.org/html/rfc1321 auto s1 = ""; auto hash = hashString(HashType::MD5, s1); - ASSERT_EQ(hash.to_string(HashFormat::Base16, true), "md5:d41d8cd98f00b204e9800998ecf8427e"); + ASSERT_EQ(hash.to_string(HashFormat::Base16), "md5:d41d8cd98f00b204e9800998ecf8427e"); } TEST(hashString, testKnownMD5Hashes2) { // values taken from: https://tools.ietf.org/html/rfc1321 auto s2 = "abc"; auto hash = hashString(HashType::MD5, s2); - ASSERT_EQ(hash.to_string(HashFormat::Base16, true), "md5:900150983cd24fb0d6963f7d28e17f72"); + ASSERT_EQ(hash.to_string(HashFormat::Base16), "md5:900150983cd24fb0d6963f7d28e17f72"); } TEST(hashString, testKnownSHA1Hashes1) { // values taken from: https://tools.ietf.org/html/rfc3174 auto s = "abc"; auto hash = hashString(HashType::SHA1, s); - ASSERT_EQ(hash.to_string(HashFormat::Base16, true), "sha1:a9993e364706816aba3e25717850c26c9cd0d89d"); + ASSERT_EQ(hash.to_string(HashFormat::Base16), "sha1:a9993e364706816aba3e25717850c26c9cd0d89d"); } TEST(hashString, testKnownSHA1Hashes2) { // values taken from: https://tools.ietf.org/html/rfc3174 auto s = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; auto hash = hashString(HashType::SHA1, s); - ASSERT_EQ(hash.to_string(HashFormat::Base16, true), "sha1:84983e441c3bd26ebaae4aa1f95129e5e54670f1"); + ASSERT_EQ(hash.to_string(HashFormat::Base16), "sha1:84983e441c3bd26ebaae4aa1f95129e5e54670f1"); } TEST(hashString, testKnownSHA256Hashes1) { @@ -44,7 +44,7 @@ namespace nix { auto hash = hashString(HashType::SHA256, s); ASSERT_EQ( - hash.to_string(HashFormat::Base16, true), + hash.to_string(HashFormat::Base16), "sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" ); } @@ -54,7 +54,7 @@ namespace nix { auto s = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; auto hash = hashString(HashType::SHA256, s); ASSERT_EQ( - hash.to_string(HashFormat::Base16, true), + hash.to_string(HashFormat::Base16), "sha256:248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" ); } @@ -64,7 +64,7 @@ namespace nix { auto s = "abc"; auto hash = hashString(HashType::SHA512, s); ASSERT_EQ( - hash.to_string(HashFormat::Base16, true), + hash.to_string(HashFormat::Base16), "sha512:ddaf35a193617abacc417349ae20413112e6fa4e89a9" "7ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd" "454d4423643ce80e2a9ac94fa54ca49f" @@ -76,7 +76,7 @@ namespace nix { auto hash = hashString(HashType::SHA512, s); ASSERT_EQ( - hash.to_string(HashFormat::Base16, true), + hash.to_string(HashFormat::Base16), "sha512:8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa1" "7299aeadb6889018501d289e4900f7e4331b99dec4b5433a" "c7d329eeb6dd26545e96e55b874be909"