Simplify ContentAddress

Whereas `ContentAddressWithReferences` is a sum type complex because different
varieties support different notions of reference, and
`ContentAddressMethod` is a nested enum to support that,
`ContentAddress` can be a simple pair of a method and hash.

`ContentAddress` does not need to be a sum type on the outside because
the choice of method doesn't effect what type of hashes we can use.

Co-Authored-By: Cale Gibbard <cgibbard@gmail.com>
This commit is contained in:
John Ericson 2023-07-05 18:53:44 -04:00
parent 6db66ebfc5
commit 903700c5e1
20 changed files with 182 additions and 293 deletions

View file

@ -294,10 +294,8 @@ SV * makeFixedOutputPath(int recursive, char * algo, char * hash, char * name)
auto h = Hash::parseAny(hash, parseHashType(algo)); auto h = Hash::parseAny(hash, parseHashType(algo));
auto method = recursive ? FileIngestionMethod::Recursive : FileIngestionMethod::Flat; auto method = recursive ? FileIngestionMethod::Recursive : FileIngestionMethod::Flat;
auto path = store()->makeFixedOutputPath(name, FixedOutputInfo { auto path = store()->makeFixedOutputPath(name, FixedOutputInfo {
.hash = {
.method = method, .method = method,
.hash = h, .hash = h,
},
.references = {}, .references = {},
}); });
XPUSHs(sv_2mortal(newSVpv(store()->printStorePath(path).c_str(), 0))); XPUSHs(sv_2mortal(newSVpv(store()->printStorePath(path).c_str(), 0)));

View file

@ -1300,9 +1300,10 @@ drvName, Bindings * attrs, Value & v)
auto method = ingestionMethod.value_or(FileIngestionMethod::Flat); auto method = ingestionMethod.value_or(FileIngestionMethod::Flat);
DerivationOutput::CAFixed dof { DerivationOutput::CAFixed dof {
.ca = ContentAddress::fromParts( .ca = ContentAddress {
std::move(method), .method = std::move(method),
std::move(h)), .hash = std::move(h),
},
}; };
drv.env["out"] = state.store->printStorePath(dof.path(*state.store, drvName, "out")); drv.env["out"] = state.store->printStorePath(dof.path(*state.store, drvName, "out"));
@ -2162,10 +2163,8 @@ static void addPath(
std::optional<StorePath> expectedStorePath; std::optional<StorePath> expectedStorePath;
if (expectedHash) if (expectedHash)
expectedStorePath = state.store->makeFixedOutputPath(name, FixedOutputInfo { expectedStorePath = state.store->makeFixedOutputPath(name, FixedOutputInfo {
.hash = {
.method = method, .method = method,
.hash = *expectedHash, .hash = *expectedHash,
},
.references = {}, .references = {},
}); });

View file

@ -254,10 +254,8 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v
auto expectedPath = state.store->makeFixedOutputPath( auto expectedPath = state.store->makeFixedOutputPath(
name, name,
FixedOutputInfo { FixedOutputInfo {
.hash = {
.method = unpack ? FileIngestionMethod::Recursive : FileIngestionMethod::Flat, .method = unpack ? FileIngestionMethod::Recursive : FileIngestionMethod::Flat,
.hash = *expectedHash, .hash = *expectedHash,
},
.references = {} .references = {}
}); });

View file

@ -217,10 +217,8 @@ StorePath Input::computeStorePath(Store & store) const
if (!narHash) if (!narHash)
throw Error("cannot compute store path for unlocked input '%s'", to_string()); throw Error("cannot compute store path for unlocked input '%s'", to_string());
return store.makeFixedOutputPath(getName(), FixedOutputInfo { return store.makeFixedOutputPath(getName(), FixedOutputInfo {
.hash = {
.method = FileIngestionMethod::Recursive, .method = FileIngestionMethod::Recursive,
.hash = *narHash, .hash = *narHash,
},
.references = {}, .references = {},
}); });
} }

View file

@ -77,10 +77,8 @@ DownloadFileResult downloadFile(
*store, *store,
name, name,
FixedOutputInfo { FixedOutputInfo {
.hash = {
.method = FileIngestionMethod::Flat, .method = FileIngestionMethod::Flat,
.hash = hash, .hash = hash,
},
.references = {}, .references = {},
}, },
hashString(htSHA256, sink.s), hashString(htSHA256, sink.s),

View file

@ -309,10 +309,8 @@ StorePath BinaryCacheStore::addToStoreFromDump(Source & dump, std::string_view n
*this, *this,
name, name,
FixedOutputInfo { FixedOutputInfo {
.hash = {
.method = method, .method = method,
.hash = nar.first, .hash = nar.first,
},
.references = { .references = {
.others = references, .others = references,
// caller is not capable of creating a self-reference, because this is content-addressed without modulus // caller is not capable of creating a self-reference, because this is content-addressed without modulus
@ -428,10 +426,8 @@ StorePath BinaryCacheStore::addToStore(
*this, *this,
name, name,
FixedOutputInfo { FixedOutputInfo {
.hash = {
.method = method, .method = method,
.hash = h, .hash = h,
},
.references = { .references = {
.others = references, .others = references,
// caller is not capable of creating a self-reference, because this is content-addressed without modulus // caller is not capable of creating a self-reference, because this is content-addressed without modulus
@ -465,8 +461,8 @@ StorePath BinaryCacheStore::addTextToStore(
*this, *this,
std::string { name }, std::string { name },
TextInfo { TextInfo {
{ .hash = textHash }, .hash = textHash,
references, .references = references,
}, },
nar.first, nar.first,
}; };

View file

@ -2538,16 +2538,16 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
}, },
[&](const DerivationOutput::CAFixed & dof) { [&](const DerivationOutput::CAFixed & dof) {
auto wanted = dof.ca.getHash(); auto & wanted = dof.ca.hash;
auto newInfo0 = newInfoFromCA(DerivationOutput::CAFloating { auto newInfo0 = newInfoFromCA(DerivationOutput::CAFloating {
.method = dof.ca.getMethod(), .method = dof.ca.method,
.hashType = wanted.type, .hashType = wanted.type,
}); });
/* Check wanted hash */ /* Check wanted hash */
assert(newInfo0.ca); assert(newInfo0.ca);
auto got = newInfo0.ca->getHash(); auto & got = newInfo0.ca->hash;
if (wanted != got) { if (wanted != got) {
/* Throw an error after registering the path as /* Throw an error after registering the path as
valid. */ valid. */

View file

@ -4,11 +4,6 @@
namespace nix { namespace nix {
std::string FixedOutputHash::printMethodAlgo() const
{
return makeFileIngestionPrefix(method) + printHashType(hash.type);
}
std::string makeFileIngestionPrefix(FileIngestionMethod m) std::string makeFileIngestionPrefix(FileIngestionMethod m)
{ {
switch (m) { switch (m) {
@ -42,21 +37,6 @@ ContentAddressMethod ContentAddressMethod::parsePrefix(std::string_view & m)
return method; return method;
} }
std::string ContentAddress::render() const
{
return std::visit(overloaded {
[](const TextHash & th) {
return "text:"
+ th.hash.to_string(Base32, true);
},
[](const FixedOutputHash & fsh) {
return "fixed:"
+ makeFileIngestionPrefix(fsh.method)
+ fsh.hash.to_string(Base32, true);
}
}, raw);
}
std::string ContentAddressMethod::render(HashType ht) const std::string ContentAddressMethod::render(HashType ht) const
{ {
return std::visit(overloaded { return std::visit(overloaded {
@ -69,6 +49,20 @@ std::string ContentAddressMethod::render(HashType ht) const
}, raw); }, raw);
} }
std::string ContentAddress::render() const
{
return std::visit(overloaded {
[](const TextIngestionMethod &) -> std::string {
return "text:";
},
[](const FileIngestionMethod & method) {
return "fixed:"
+ makeFileIngestionPrefix(method);
},
}, method.raw)
+ this->hash.to_string(Base32, true);
}
/** /**
* Parses content address strings up to the hash. * Parses content address strings up to the hash.
*/ */
@ -118,22 +112,12 @@ ContentAddress ContentAddress::parse(std::string_view rawCa)
{ {
auto rest = rawCa; auto rest = rawCa;
auto [caMethod, hashType_] = parseContentAddressMethodPrefix(rest); auto [caMethod, hashType] = parseContentAddressMethodPrefix(rest);
auto hashType = hashType_; // work around clang bug
return std::visit(overloaded { return ContentAddress {
[&](TextIngestionMethod &) { .method = std::move(caMethod).raw,
return ContentAddress(TextHash {
.hash = Hash::parseNonSRIUnprefixed(rest, hashType)
});
},
[&](FileIngestionMethod & fim) {
return ContentAddress(FixedOutputHash {
.method = fim,
.hash = Hash::parseNonSRIUnprefixed(rest, hashType), .hash = Hash::parseNonSRIUnprefixed(rest, hashType),
}); };
},
}, caMethod.raw);
} }
std::pair<ContentAddressMethod, HashType> ContentAddressMethod::parse(std::string_view caMethod) std::pair<ContentAddressMethod, HashType> ContentAddressMethod::parse(std::string_view caMethod)
@ -156,52 +140,10 @@ std::string renderContentAddress(std::optional<ContentAddress> ca)
return ca ? ca->render() : ""; return ca ? ca->render() : "";
} }
ContentAddress ContentAddress::fromParts(
ContentAddressMethod method, Hash hash) noexcept
{
return std::visit(overloaded {
[&](TextIngestionMethod _) -> ContentAddress {
return TextHash {
.hash = std::move(hash),
};
},
[&](FileIngestionMethod m2) -> ContentAddress {
return FixedOutputHash {
.method = std::move(m2),
.hash = std::move(hash),
};
},
}, method.raw);
}
ContentAddressMethod ContentAddress::getMethod() const
{
return std::visit(overloaded {
[](const TextHash & th) -> ContentAddressMethod {
return TextIngestionMethod {};
},
[](const FixedOutputHash & fsh) -> ContentAddressMethod {
return fsh.method;
},
}, raw);
}
const Hash & ContentAddress::getHash() const
{
return std::visit(overloaded {
[](const TextHash & th) -> auto & {
return th.hash;
},
[](const FixedOutputHash & fsh) -> auto & {
return fsh.hash;
},
}, raw);
}
std::string ContentAddress::printMethodAlgo() const std::string ContentAddress::printMethodAlgo() const
{ {
return getMethod().renderPrefix() return method.renderPrefix()
+ printHashType(getHash().type); + printHashType(hash.type);
} }
bool StoreReferences::empty() const bool StoreReferences::empty() const
@ -217,19 +159,20 @@ size_t StoreReferences::size() const
ContentAddressWithReferences ContentAddressWithReferences::withoutRefs(const ContentAddress & ca) noexcept ContentAddressWithReferences ContentAddressWithReferences::withoutRefs(const ContentAddress & ca) noexcept
{ {
return std::visit(overloaded { return std::visit(overloaded {
[&](const TextHash & h) -> ContentAddressWithReferences { [&](const TextIngestionMethod &) -> ContentAddressWithReferences {
return TextInfo { return TextInfo {
.hash = h, .hash = ca.hash,
.references = {}, .references = {},
}; };
}, },
[&](const FixedOutputHash & h) -> ContentAddressWithReferences { [&](const FileIngestionMethod & method) -> ContentAddressWithReferences {
return FixedOutputInfo { return FixedOutputInfo {
.hash = h, .method = method,
.hash = ca.hash,
.references = {}, .references = {},
}; };
}, },
}, ca.raw); }, ca.method.raw);
} }
std::optional<ContentAddressWithReferences> ContentAddressWithReferences::fromPartsOpt( std::optional<ContentAddressWithReferences> ContentAddressWithReferences::fromPartsOpt(
@ -241,7 +184,7 @@ std::optional<ContentAddressWithReferences> ContentAddressWithReferences::fromPa
return std::nullopt; return std::nullopt;
return ContentAddressWithReferences { return ContentAddressWithReferences {
TextInfo { TextInfo {
.hash = { .hash = std::move(hash) }, .hash = std::move(hash),
.references = std::move(refs.others), .references = std::move(refs.others),
} }
}; };
@ -249,10 +192,8 @@ std::optional<ContentAddressWithReferences> ContentAddressWithReferences::fromPa
[&](FileIngestionMethod m2) -> std::optional<ContentAddressWithReferences> { [&](FileIngestionMethod m2) -> std::optional<ContentAddressWithReferences> {
return ContentAddressWithReferences { return ContentAddressWithReferences {
FixedOutputInfo { FixedOutputInfo {
.hash = {
.method = m2, .method = m2,
.hash = std::move(hash), .hash = std::move(hash),
},
.references = std::move(refs), .references = std::move(refs),
} }
}; };
@ -267,7 +208,7 @@ ContentAddressMethod ContentAddressWithReferences::getMethod() const
return TextIngestionMethod {}; return TextIngestionMethod {};
}, },
[](const FixedOutputInfo & fsh) -> ContentAddressMethod { [](const FixedOutputInfo & fsh) -> ContentAddressMethod {
return fsh.hash.method; return fsh.method;
}, },
}, raw); }, raw);
} }
@ -276,10 +217,10 @@ Hash ContentAddressWithReferences::getHash() const
{ {
return std::visit(overloaded { return std::visit(overloaded {
[](const TextInfo & th) { [](const TextInfo & th) {
return th.hash.hash; return th.hash;
}, },
[](const FixedOutputInfo & fsh) { [](const FixedOutputInfo & fsh) {
return fsh.hash.hash; return fsh.hash;
}, },
}, raw); }, raw);
} }

View file

@ -113,37 +113,6 @@ struct ContentAddressMethod
* Mini content address * Mini content address
*/ */
/**
* Somewhat obscure, used by \ref Derivation derivations and
* `builtins.toFile` currently.
*/
struct TextHash {
/**
* Hash of the contents of the text/file.
*/
Hash hash;
GENERATE_CMP(TextHash, me->hash);
};
/**
* Used by most store objects that are content-addressed.
*/
struct FixedOutputHash {
/**
* How the file system objects are serialized
*/
FileIngestionMethod method;
/**
* Hash of that serialization
*/
Hash hash;
std::string printMethodAlgo() const;
GENERATE_CMP(FixedOutputHash, me->method, me->hash);
};
/** /**
* We've accumulated several types of content-addressed paths over the * We've accumulated several types of content-addressed paths over the
* years; fixed-output derivations support multiple hash algorithms and * years; fixed-output derivations support multiple hash algorithms and
@ -158,19 +127,17 @@ struct FixedOutputHash {
*/ */
struct ContentAddress struct ContentAddress
{ {
typedef std::variant< /**
TextHash, * How the file system objects are serialized
FixedOutputHash */
> Raw; ContentAddressMethod method;
Raw raw; /**
* Hash of that serialization
*/
Hash hash;
GENERATE_CMP(ContentAddress, me->raw); GENERATE_CMP(ContentAddress, me->method, me->hash);
/* The moral equivalent of `using Raw::Raw;` */
ContentAddress(auto &&... arg)
: raw(std::forward<decltype(arg)>(arg)...)
{ }
/** /**
* Compute the content-addressability assertion * Compute the content-addressability assertion
@ -183,20 +150,6 @@ struct ContentAddress
static std::optional<ContentAddress> parseOpt(std::string_view rawCaOpt); static std::optional<ContentAddress> parseOpt(std::string_view rawCaOpt);
/**
* Create a `ContentAddress` from 2 parts:
*
* @param method Way ingesting the file system data.
*
* @param hash Hash of ingested file system data.
*/
static ContentAddress fromParts(
ContentAddressMethod method, Hash hash) noexcept;
ContentAddressMethod getMethod() const;
const Hash & getHash() const;
std::string printMethodAlgo() const; std::string printMethodAlgo() const;
}; };
@ -219,7 +172,8 @@ std::string renderContentAddress(std::optional<ContentAddress> ca);
* References to other store objects are tracked with store paths, self * References to other store objects are tracked with store paths, self
* references however are tracked with a boolean. * references however are tracked with a boolean.
*/ */
struct StoreReferences { struct StoreReferences
{
/** /**
* References to other store objects * References to other store objects
*/ */
@ -246,8 +200,13 @@ struct StoreReferences {
}; };
// This matches the additional info that we need for makeTextPath // This matches the additional info that we need for makeTextPath
struct TextInfo { struct TextInfo
TextHash hash; {
/**
* Hash of the contents of the text/file.
*/
Hash hash;
/** /**
* References to other store objects only; self references * References to other store objects only; self references
* disallowed * disallowed
@ -257,8 +216,18 @@ struct TextInfo {
GENERATE_CMP(TextInfo, me->hash, me->references); GENERATE_CMP(TextInfo, me->hash, me->references);
}; };
struct FixedOutputInfo { struct FixedOutputInfo
FixedOutputHash hash; {
/**
* How the file system objects are serialized
*/
FileIngestionMethod method;
/**
* Hash of that serialization
*/
Hash hash;
/** /**
* References to other store objects or this one. * References to other store objects or this one.
*/ */

View file

@ -232,9 +232,10 @@ static DerivationOutput parseDerivationOutput(const Store & store,
validatePath(pathS); validatePath(pathS);
auto hash = Hash::parseNonSRIUnprefixed(hashS, hashType); auto hash = Hash::parseNonSRIUnprefixed(hashS, hashType);
return DerivationOutput::CAFixed { return DerivationOutput::CAFixed {
.ca = ContentAddress::fromParts( .ca = ContentAddress {
std::move(method), .method = std::move(method),
std::move(hash)), .hash = std::move(hash),
},
}; };
} else { } else {
experimentalFeatureSettings.require(Xp::CaDerivations); experimentalFeatureSettings.require(Xp::CaDerivations);
@ -395,7 +396,7 @@ std::string Derivation::unparse(const Store & store, bool maskOutputs,
[&](const DerivationOutput::CAFixed & dof) { [&](const DerivationOutput::CAFixed & dof) {
s += ','; printUnquotedString(s, maskOutputs ? "" : store.printStorePath(dof.path(store, name, i.first))); s += ','; printUnquotedString(s, maskOutputs ? "" : store.printStorePath(dof.path(store, name, i.first)));
s += ','; printUnquotedString(s, dof.ca.printMethodAlgo()); s += ','; printUnquotedString(s, dof.ca.printMethodAlgo());
s += ','; printUnquotedString(s, dof.ca.getHash().to_string(Base16, false)); s += ','; printUnquotedString(s, dof.ca.hash.to_string(Base16, false));
}, },
[&](const DerivationOutput::CAFloating & dof) { [&](const DerivationOutput::CAFloating & dof) {
s += ','; printUnquotedString(s, ""); s += ','; printUnquotedString(s, "");
@ -628,7 +629,7 @@ DrvHash hashDerivationModulo(Store & store, const Derivation & drv, bool maskOut
auto & dof = std::get<DerivationOutput::CAFixed>(i.second.raw()); auto & dof = std::get<DerivationOutput::CAFixed>(i.second.raw());
auto hash = hashString(htSHA256, "fixed:out:" auto hash = hashString(htSHA256, "fixed:out:"
+ dof.ca.printMethodAlgo() + ":" + dof.ca.printMethodAlgo() + ":"
+ dof.ca.getHash().to_string(Base16, false) + ":" + dof.ca.hash.to_string(Base16, false) + ":"
+ store.printStorePath(dof.path(store, drv.name, i.first))); + store.printStorePath(dof.path(store, drv.name, i.first)));
outputHashes.insert_or_assign(i.first, std::move(hash)); outputHashes.insert_or_assign(i.first, std::move(hash));
} }
@ -780,7 +781,7 @@ void writeDerivation(Sink & out, const Store & store, const BasicDerivation & dr
[&](const DerivationOutput::CAFixed & dof) { [&](const DerivationOutput::CAFixed & dof) {
out << store.printStorePath(dof.path(store, drv.name, i.first)) out << store.printStorePath(dof.path(store, drv.name, i.first))
<< dof.ca.printMethodAlgo() << dof.ca.printMethodAlgo()
<< dof.ca.getHash().to_string(Base16, false); << dof.ca.hash.to_string(Base16, false);
}, },
[&](const DerivationOutput::CAFloating & dof) { [&](const DerivationOutput::CAFloating & dof) {
out << "" out << ""
@ -970,7 +971,7 @@ nlohmann::json DerivationOutput::toJSON(
[&](const DerivationOutput::CAFixed & dof) { [&](const DerivationOutput::CAFixed & dof) {
res["path"] = store.printStorePath(dof.path(store, drvName, outputName)); res["path"] = store.printStorePath(dof.path(store, drvName, outputName));
res["hashAlgo"] = dof.ca.printMethodAlgo(); res["hashAlgo"] = dof.ca.printMethodAlgo();
res["hash"] = dof.ca.getHash().to_string(Base16, false); res["hash"] = dof.ca.hash.to_string(Base16, false);
// FIXME print refs? // FIXME print refs?
}, },
[&](const DerivationOutput::CAFloating & dof) { [&](const DerivationOutput::CAFloating & dof) {
@ -1017,9 +1018,10 @@ DerivationOutput DerivationOutput::fromJSON(
else if (keys == (std::set<std::string_view> { "path", "hashAlgo", "hash" })) { else if (keys == (std::set<std::string_view> { "path", "hashAlgo", "hash" })) {
auto [method, hashType] = methodAlgo(); auto [method, hashType] = methodAlgo();
auto dof = DerivationOutput::CAFixed { auto dof = DerivationOutput::CAFixed {
.ca = ContentAddress::fromParts( .ca = ContentAddress {
std::move(method), .method = std::move(method),
Hash::parseNonSRIUnprefixed((std::string) json["hash"], hashType)), .hash = Hash::parseNonSRIUnprefixed((std::string) json["hash"], hashType),
},
}; };
if (dof.path(store, drvName, outputName) != store.parseStorePath((std::string) json["path"])) if (dof.path(store, drvName, outputName) != store.parseStorePath((std::string) json["path"]))
throw Error("Path doesn't match derivation output"); throw Error("Path doesn't match derivation output");

View file

@ -1249,27 +1249,17 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
printStorePath(info.path), info.narSize, hashResult.second); printStorePath(info.path), info.narSize, hashResult.second);
if (info.ca) { if (info.ca) {
if (auto foHash = std::get_if<FixedOutputHash>(&info.ca->raw)) { auto & specified = *info.ca;
auto actualFoHash = hashCAPath( auto actualHash = hashCAPath(
foHash->method, specified.method,
foHash->hash.type, specified.hash.type,
info.path info.path
); );
if (foHash->hash != actualFoHash.hash) { if (specified.hash != actualHash.hash) {
throw Error("ca hash mismatch importing path '%s';\n specified: %s\n got: %s", throw Error("ca hash mismatch importing path '%s';\n specified: %s\n got: %s",
printStorePath(info.path), printStorePath(info.path),
foHash->hash.to_string(Base32, true), specified.hash.to_string(Base32, true),
actualFoHash.hash.to_string(Base32, true)); actualHash.hash.to_string(Base32, true));
}
}
if (auto textHash = std::get_if<TextHash>(&info.ca->raw)) {
auto actualTextHash = hashString(htSHA256, readFile(realPath));
if (textHash->hash != actualTextHash) {
throw Error("ca hash mismatch importing path '%s';\n specified: %s\n got: %s",
printStorePath(info.path),
textHash->hash.to_string(Base32, true),
actualTextHash.to_string(Base32, true));
}
} }
} }
@ -1349,10 +1339,8 @@ StorePath LocalStore::addToStoreFromDump(Source & source0, std::string_view name
auto [hash, size] = hashSink->finish(); auto [hash, size] = hashSink->finish();
ContentAddressWithReferences desc = FixedOutputInfo { ContentAddressWithReferences desc = FixedOutputInfo {
.hash = {
.method = method, .method = method,
.hash = hash, .hash = hash,
},
.references = { .references = {
.others = references, .others = references,
// caller is not capable of creating a self-reference, because this is content-addressed without modulus // caller is not capable of creating a self-reference, because this is content-addressed without modulus
@ -1428,8 +1416,8 @@ StorePath LocalStore::addTextToStore(
{ {
auto hash = hashString(htSHA256, s); auto hash = hashString(htSHA256, s);
auto dstPath = makeTextPath(name, TextInfo { auto dstPath = makeTextPath(name, TextInfo {
{ .hash = hash }, .hash = hash,
references, .references = references,
}); });
addTempRoot(dstPath); addTempRoot(dstPath);
@ -1459,7 +1447,10 @@ StorePath LocalStore::addTextToStore(
ValidPathInfo info { dstPath, narHash }; ValidPathInfo info { dstPath, narHash };
info.narSize = sink.s.size(); info.narSize = sink.s.size();
info.references = references; info.references = references;
info.ca = TextHash { .hash = hash }; info.ca = {
.method = TextIngestionMethod {},
.hash = hash,
};
registerValidPath(info); registerValidPath(info);
} }
@ -1856,22 +1847,27 @@ void LocalStore::queryRealisationUncached(const DrvOutput & id,
} }
} }
FixedOutputHash LocalStore::hashCAPath( ContentAddress LocalStore::hashCAPath(
const FileIngestionMethod & method, const HashType & hashType, const ContentAddressMethod & method, const HashType & hashType,
const StorePath & path) const StorePath & path)
{ {
return hashCAPath(method, hashType, Store::toRealPath(path), path.hashPart()); return hashCAPath(method, hashType, Store::toRealPath(path), path.hashPart());
} }
FixedOutputHash LocalStore::hashCAPath( ContentAddress LocalStore::hashCAPath(
const FileIngestionMethod & method, const ContentAddressMethod & method,
const HashType & hashType, const HashType & hashType,
const Path & path, const Path & path,
const std::string_view pathHash const std::string_view pathHash
) )
{ {
HashModuloSink caSink ( hashType, std::string(pathHash) ); HashModuloSink caSink ( hashType, std::string(pathHash) );
switch (method) { std::visit(overloaded {
[&](const TextIngestionMethod &) {
readFile(path, caSink);
},
[&](const FileIngestionMethod & m2) {
switch (m2) {
case FileIngestionMethod::Recursive: case FileIngestionMethod::Recursive:
dumpPath(path, caSink); dumpPath(path, caSink);
break; break;
@ -1879,10 +1875,11 @@ FixedOutputHash LocalStore::hashCAPath(
readFile(path, caSink); readFile(path, caSink);
break; break;
} }
auto hash = caSink.finish().first; },
return FixedOutputHash{ }, method.raw);
return ContentAddress {
.method = method, .method = method,
.hash = hash, .hash = caSink.finish().first,
}; };
} }

View file

@ -345,13 +345,13 @@ private:
void signRealisation(Realisation &); void signRealisation(Realisation &);
// XXX: Make a generic `Store` method // XXX: Make a generic `Store` method
FixedOutputHash hashCAPath( ContentAddress hashCAPath(
const FileIngestionMethod & method, const ContentAddressMethod & method,
const HashType & hashType, const HashType & hashType,
const StorePath & path); const StorePath & path);
FixedOutputHash hashCAPath( ContentAddress hashCAPath(
const FileIngestionMethod & method, const ContentAddressMethod & method,
const HashType & hashType, const HashType & hashType,
const Path & path, const Path & path,
const std::string_view pathHash const std::string_view pathHash

View file

@ -52,10 +52,8 @@ std::map<StorePath, StorePath> makeContentAddressed(
dstStore, dstStore,
path.name(), path.name(),
FixedOutputInfo { FixedOutputInfo {
.hash = {
.method = FileIngestionMethod::Recursive, .method = FileIngestionMethod::Recursive,
.hash = narModuloHash, .hash = narModuloHash,
},
.references = std::move(refs), .references = std::move(refs),
}, },
Hash::dummy, Hash::dummy,

View file

@ -29,14 +29,14 @@ std::optional<ContentAddressWithReferences> ValidPathInfo::contentAddressWithRef
return std::nullopt; return std::nullopt;
return std::visit(overloaded { return std::visit(overloaded {
[&](const TextHash & th) -> ContentAddressWithReferences { [&](const TextIngestionMethod &) -> ContentAddressWithReferences {
assert(references.count(path) == 0); assert(references.count(path) == 0);
return TextInfo { return TextInfo {
.hash = th, .hash = ca->hash,
.references = references, .references = references,
}; };
}, },
[&](const FixedOutputHash & foh) -> ContentAddressWithReferences { [&](const FileIngestionMethod & m2) -> ContentAddressWithReferences {
auto refs = references; auto refs = references;
bool hasSelfReference = false; bool hasSelfReference = false;
if (refs.count(path)) { if (refs.count(path)) {
@ -44,14 +44,15 @@ std::optional<ContentAddressWithReferences> ValidPathInfo::contentAddressWithRef
refs.erase(path); refs.erase(path);
} }
return FixedOutputInfo { return FixedOutputInfo {
.hash = foh, .method = m2,
.hash = ca->hash,
.references = { .references = {
.others = std::move(refs), .others = std::move(refs),
.self = hasSelfReference, .self = hasSelfReference,
}, },
}; };
}, },
}, ca->raw); }, ca->method.raw);
} }
bool ValidPathInfo::isContentAddressed(const Store & store) const bool ValidPathInfo::isContentAddressed(const Store & store) const
@ -110,13 +111,19 @@ ValidPathInfo::ValidPathInfo(
std::visit(overloaded { std::visit(overloaded {
[this](TextInfo && ti) { [this](TextInfo && ti) {
this->references = std::move(ti.references); this->references = std::move(ti.references);
this->ca = std::move((TextHash &&) ti); this->ca = ContentAddress {
.method = TextIngestionMethod {},
.hash = std::move(ti.hash),
};
}, },
[this](FixedOutputInfo && foi) { [this](FixedOutputInfo && foi) {
this->references = std::move(foi.references.others); this->references = std::move(foi.references.others);
if (foi.references.self) if (foi.references.self)
this->references.insert(path); this->references.insert(path);
this->ca = std::move((FixedOutputHash &&) foi); this->ca = ContentAddress {
.method = std::move(foi.method),
.hash = std::move(foi.hash),
};
}, },
}, std::move(ca).raw); }, std::move(ca).raw);
} }

View file

@ -184,15 +184,15 @@ static std::string makeType(
StorePath Store::makeFixedOutputPath(std::string_view name, const FixedOutputInfo & info) const StorePath Store::makeFixedOutputPath(std::string_view name, const FixedOutputInfo & info) const
{ {
if (info.hash.hash.type == htSHA256 && info.hash.method == FileIngestionMethod::Recursive) { if (info.hash.type == htSHA256 && info.method == FileIngestionMethod::Recursive) {
return makeStorePath(makeType(*this, "source", info.references), info.hash.hash, name); return makeStorePath(makeType(*this, "source", info.references), info.hash, name);
} else { } else {
assert(info.references.size() == 0); assert(info.references.size() == 0);
return makeStorePath("output:out", return makeStorePath("output:out",
hashString(htSHA256, hashString(htSHA256,
"fixed:out:" "fixed:out:"
+ makeFileIngestionPrefix(info.hash.method) + makeFileIngestionPrefix(info.method)
+ info.hash.hash.to_string(Base16, true) + ":"), + info.hash.to_string(Base16, true) + ":"),
name); name);
} }
} }
@ -200,13 +200,13 @@ StorePath Store::makeFixedOutputPath(std::string_view name, const FixedOutputInf
StorePath Store::makeTextPath(std::string_view name, const TextInfo & info) const StorePath Store::makeTextPath(std::string_view name, const TextInfo & info) const
{ {
assert(info.hash.hash.type == htSHA256); assert(info.hash.type == htSHA256);
return makeStorePath( return makeStorePath(
makeType(*this, "text", StoreReferences { makeType(*this, "text", StoreReferences {
.others = info.references, .others = info.references,
.self = false, .self = false,
}), }),
info.hash.hash, info.hash,
name); name);
} }
@ -232,10 +232,8 @@ std::pair<StorePath, Hash> Store::computeStorePathForPath(std::string_view name,
? hashPath(hashAlgo, srcPath, filter).first ? hashPath(hashAlgo, srcPath, filter).first
: hashFile(hashAlgo, srcPath); : hashFile(hashAlgo, srcPath);
FixedOutputInfo caInfo { FixedOutputInfo caInfo {
.hash = {
.method = method, .method = method,
.hash = h, .hash = h,
},
.references = {}, .references = {},
}; };
return std::make_pair(makeFixedOutputPath(name, caInfo), h); return std::make_pair(makeFixedOutputPath(name, caInfo), h);
@ -248,8 +246,8 @@ StorePath Store::computeStorePathForText(
const StorePathSet & references) const const StorePathSet & references) const
{ {
return makeTextPath(name, TextInfo { return makeTextPath(name, TextInfo {
{ .hash = hashString(htSHA256, s) }, .hash = hashString(htSHA256, s),
references, .references = references,
}); });
} }
@ -441,10 +439,8 @@ ValidPathInfo Store::addToStoreSlow(std::string_view name, const Path & srcPath,
*this, *this,
name, name,
FixedOutputInfo { FixedOutputInfo {
.hash = {
.method = method, .method = method,
.hash = hash, .hash = hash,
},
.references = {}, .references = {},
}, },
narHash, narHash,

View file

@ -81,7 +81,7 @@ TEST_JSON(DerivationTest, caFixedFlat,
"path": "/nix/store/rhcg9h16sqvlbpsa6dqm57sbr2al6nzg-drv-name-output-name" "path": "/nix/store/rhcg9h16sqvlbpsa6dqm57sbr2al6nzg-drv-name-output-name"
})", })",
(DerivationOutput::CAFixed { (DerivationOutput::CAFixed {
.ca = FixedOutputHash { .ca = {
.method = FileIngestionMethod::Flat, .method = FileIngestionMethod::Flat,
.hash = Hash::parseAnyPrefixed("sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="), .hash = Hash::parseAnyPrefixed("sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="),
}, },
@ -95,7 +95,7 @@ TEST_JSON(DerivationTest, caFixedNAR,
"path": "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name" "path": "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"
})", })",
(DerivationOutput::CAFixed { (DerivationOutput::CAFixed {
.ca = FixedOutputHash { .ca = {
.method = FileIngestionMethod::Recursive, .method = FileIngestionMethod::Recursive,
.hash = Hash::parseAnyPrefixed("sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="), .hash = Hash::parseAnyPrefixed("sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="),
}, },
@ -109,7 +109,7 @@ TEST_JSON(DynDerivationTest, caFixedText,
"path": "/nix/store/6s1zwabh956jvhv4w9xcdb5jiyanyxg1-drv-name-output-name" "path": "/nix/store/6s1zwabh956jvhv4w9xcdb5jiyanyxg1-drv-name-output-name"
})", })",
(DerivationOutput::CAFixed { (DerivationOutput::CAFixed {
.ca = TextHash { .ca = {
.hash = Hash::parseAnyPrefixed("sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="), .hash = Hash::parseAnyPrefixed("sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="),
}, },
}), }),

View file

@ -220,10 +220,8 @@ static void opPrintFixedPath(Strings opFlags, Strings opArgs)
std::string name = *i++; std::string name = *i++;
cout << fmt("%s\n", store->printStorePath(store->makeFixedOutputPath(name, FixedOutputInfo { cout << fmt("%s\n", store->printStorePath(store->makeFixedOutputPath(name, FixedOutputInfo {
.hash = {
.method = method, .method = method,
.hash = Hash::parseAny(hash, hashAlgo), .hash = Hash::parseAny(hash, hashAlgo),
},
.references = {}, .references = {},
}))); })));
} }

View file

@ -45,10 +45,8 @@ struct CmdAddToStore : MixDryRun, StoreCommand
*store, *store,
std::move(*namePart), std::move(*namePart),
FixedOutputInfo { FixedOutputInfo {
.hash = {
.method = std::move(ingestionMethod), .method = std::move(ingestionMethod),
.hash = std::move(hash), .hash = std::move(hash),
},
.references = {}, .references = {},
}, },
narHash, narHash,

View file

@ -71,10 +71,8 @@ std::tuple<StorePath, Hash> prefetchFile(
if (expectedHash) { if (expectedHash) {
hashType = expectedHash->type; hashType = expectedHash->type;
storePath = store->makeFixedOutputPath(*name, FixedOutputInfo { storePath = store->makeFixedOutputPath(*name, FixedOutputInfo {
.hash = {
.method = ingestionMethod, .method = ingestionMethod,
.hash = *expectedHash, .hash = *expectedHash,
},
.references = {}, .references = {},
}); });
if (store->isValidPath(*storePath)) if (store->isValidPath(*storePath))
@ -127,7 +125,7 @@ std::tuple<StorePath, Hash> prefetchFile(
auto info = store->addToStoreSlow(*name, tmpFile, ingestionMethod, hashType, expectedHash); auto info = store->addToStoreSlow(*name, tmpFile, ingestionMethod, hashType, expectedHash);
storePath = info.path; storePath = info.path;
assert(info.ca); assert(info.ca);
hash = info.ca->getHash(); hash = info.ca->hash;
} }
return {storePath.value(), hash.value()}; return {storePath.value(), hash.value()};

View file

@ -222,10 +222,8 @@ struct ProfileManifest
*store, *store,
"profile", "profile",
FixedOutputInfo { FixedOutputInfo {
.hash = {
.method = FileIngestionMethod::Recursive, .method = FileIngestionMethod::Recursive,
.hash = narHash, .hash = narHash,
},
.references = { .references = {
.others = std::move(references), .others = std::move(references),
// profiles never refer to themselves // profiles never refer to themselves