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:
parent
6db66ebfc5
commit
903700c5e1
20 changed files with 182 additions and 293 deletions
|
@ -294,10 +294,8 @@ SV * makeFixedOutputPath(int recursive, char * algo, char * hash, char * name)
|
|||
auto h = Hash::parseAny(hash, parseHashType(algo));
|
||||
auto method = recursive ? FileIngestionMethod::Recursive : FileIngestionMethod::Flat;
|
||||
auto path = store()->makeFixedOutputPath(name, FixedOutputInfo {
|
||||
.hash = {
|
||||
.method = method,
|
||||
.hash = h,
|
||||
},
|
||||
.method = method,
|
||||
.hash = h,
|
||||
.references = {},
|
||||
});
|
||||
XPUSHs(sv_2mortal(newSVpv(store()->printStorePath(path).c_str(), 0)));
|
||||
|
|
|
@ -1300,9 +1300,10 @@ drvName, Bindings * attrs, Value & v)
|
|||
auto method = ingestionMethod.value_or(FileIngestionMethod::Flat);
|
||||
|
||||
DerivationOutput::CAFixed dof {
|
||||
.ca = ContentAddress::fromParts(
|
||||
std::move(method),
|
||||
std::move(h)),
|
||||
.ca = ContentAddress {
|
||||
.method = std::move(method),
|
||||
.hash = std::move(h),
|
||||
},
|
||||
};
|
||||
|
||||
drv.env["out"] = state.store->printStorePath(dof.path(*state.store, drvName, "out"));
|
||||
|
@ -2162,10 +2163,8 @@ static void addPath(
|
|||
std::optional<StorePath> expectedStorePath;
|
||||
if (expectedHash)
|
||||
expectedStorePath = state.store->makeFixedOutputPath(name, FixedOutputInfo {
|
||||
.hash = {
|
||||
.method = method,
|
||||
.hash = *expectedHash,
|
||||
},
|
||||
.method = method,
|
||||
.hash = *expectedHash,
|
||||
.references = {},
|
||||
});
|
||||
|
||||
|
|
|
@ -254,10 +254,8 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v
|
|||
auto expectedPath = state.store->makeFixedOutputPath(
|
||||
name,
|
||||
FixedOutputInfo {
|
||||
.hash = {
|
||||
.method = unpack ? FileIngestionMethod::Recursive : FileIngestionMethod::Flat,
|
||||
.hash = *expectedHash,
|
||||
},
|
||||
.method = unpack ? FileIngestionMethod::Recursive : FileIngestionMethod::Flat,
|
||||
.hash = *expectedHash,
|
||||
.references = {}
|
||||
});
|
||||
|
||||
|
|
|
@ -217,10 +217,8 @@ StorePath Input::computeStorePath(Store & store) const
|
|||
if (!narHash)
|
||||
throw Error("cannot compute store path for unlocked input '%s'", to_string());
|
||||
return store.makeFixedOutputPath(getName(), FixedOutputInfo {
|
||||
.hash = {
|
||||
.method = FileIngestionMethod::Recursive,
|
||||
.hash = *narHash,
|
||||
},
|
||||
.method = FileIngestionMethod::Recursive,
|
||||
.hash = *narHash,
|
||||
.references = {},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -77,10 +77,8 @@ DownloadFileResult downloadFile(
|
|||
*store,
|
||||
name,
|
||||
FixedOutputInfo {
|
||||
.hash = {
|
||||
.method = FileIngestionMethod::Flat,
|
||||
.hash = hash,
|
||||
},
|
||||
.method = FileIngestionMethod::Flat,
|
||||
.hash = hash,
|
||||
.references = {},
|
||||
},
|
||||
hashString(htSHA256, sink.s),
|
||||
|
|
|
@ -309,10 +309,8 @@ StorePath BinaryCacheStore::addToStoreFromDump(Source & dump, std::string_view n
|
|||
*this,
|
||||
name,
|
||||
FixedOutputInfo {
|
||||
.hash = {
|
||||
.method = method,
|
||||
.hash = nar.first,
|
||||
},
|
||||
.method = method,
|
||||
.hash = nar.first,
|
||||
.references = {
|
||||
.others = references,
|
||||
// caller is not capable of creating a self-reference, because this is content-addressed without modulus
|
||||
|
@ -428,10 +426,8 @@ StorePath BinaryCacheStore::addToStore(
|
|||
*this,
|
||||
name,
|
||||
FixedOutputInfo {
|
||||
.hash = {
|
||||
.method = method,
|
||||
.hash = h,
|
||||
},
|
||||
.method = method,
|
||||
.hash = h,
|
||||
.references = {
|
||||
.others = references,
|
||||
// caller is not capable of creating a self-reference, because this is content-addressed without modulus
|
||||
|
@ -465,8 +461,8 @@ StorePath BinaryCacheStore::addTextToStore(
|
|||
*this,
|
||||
std::string { name },
|
||||
TextInfo {
|
||||
{ .hash = textHash },
|
||||
references,
|
||||
.hash = textHash,
|
||||
.references = references,
|
||||
},
|
||||
nar.first,
|
||||
};
|
||||
|
|
|
@ -2538,16 +2538,16 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
|
|||
},
|
||||
|
||||
[&](const DerivationOutput::CAFixed & dof) {
|
||||
auto wanted = dof.ca.getHash();
|
||||
auto & wanted = dof.ca.hash;
|
||||
|
||||
auto newInfo0 = newInfoFromCA(DerivationOutput::CAFloating {
|
||||
.method = dof.ca.getMethod(),
|
||||
.method = dof.ca.method,
|
||||
.hashType = wanted.type,
|
||||
});
|
||||
|
||||
/* Check wanted hash */
|
||||
assert(newInfo0.ca);
|
||||
auto got = newInfo0.ca->getHash();
|
||||
auto & got = newInfo0.ca->hash;
|
||||
if (wanted != got) {
|
||||
/* Throw an error after registering the path as
|
||||
valid. */
|
||||
|
|
|
@ -4,11 +4,6 @@
|
|||
|
||||
namespace nix {
|
||||
|
||||
std::string FixedOutputHash::printMethodAlgo() const
|
||||
{
|
||||
return makeFileIngestionPrefix(method) + printHashType(hash.type);
|
||||
}
|
||||
|
||||
std::string makeFileIngestionPrefix(FileIngestionMethod m)
|
||||
{
|
||||
switch (m) {
|
||||
|
@ -42,21 +37,6 @@ ContentAddressMethod ContentAddressMethod::parsePrefix(std::string_view & m)
|
|||
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
|
||||
{
|
||||
return std::visit(overloaded {
|
||||
|
@ -69,6 +49,20 @@ std::string ContentAddressMethod::render(HashType ht) const
|
|||
}, 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.
|
||||
*/
|
||||
|
@ -118,22 +112,12 @@ ContentAddress ContentAddress::parse(std::string_view rawCa)
|
|||
{
|
||||
auto rest = rawCa;
|
||||
|
||||
auto [caMethod, hashType_] = parseContentAddressMethodPrefix(rest);
|
||||
auto hashType = hashType_; // work around clang bug
|
||||
auto [caMethod, hashType] = parseContentAddressMethodPrefix(rest);
|
||||
|
||||
return std::visit(overloaded {
|
||||
[&](TextIngestionMethod &) {
|
||||
return ContentAddress(TextHash {
|
||||
.hash = Hash::parseNonSRIUnprefixed(rest, hashType)
|
||||
});
|
||||
},
|
||||
[&](FileIngestionMethod & fim) {
|
||||
return ContentAddress(FixedOutputHash {
|
||||
.method = fim,
|
||||
.hash = Hash::parseNonSRIUnprefixed(rest, hashType),
|
||||
});
|
||||
},
|
||||
}, caMethod.raw);
|
||||
return ContentAddress {
|
||||
.method = std::move(caMethod).raw,
|
||||
.hash = Hash::parseNonSRIUnprefixed(rest, hashType),
|
||||
};
|
||||
}
|
||||
|
||||
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() : "";
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
return getMethod().renderPrefix()
|
||||
+ printHashType(getHash().type);
|
||||
return method.renderPrefix()
|
||||
+ printHashType(hash.type);
|
||||
}
|
||||
|
||||
bool StoreReferences::empty() const
|
||||
|
@ -217,19 +159,20 @@ size_t StoreReferences::size() const
|
|||
ContentAddressWithReferences ContentAddressWithReferences::withoutRefs(const ContentAddress & ca) noexcept
|
||||
{
|
||||
return std::visit(overloaded {
|
||||
[&](const TextHash & h) -> ContentAddressWithReferences {
|
||||
[&](const TextIngestionMethod &) -> ContentAddressWithReferences {
|
||||
return TextInfo {
|
||||
.hash = h,
|
||||
.hash = ca.hash,
|
||||
.references = {},
|
||||
};
|
||||
},
|
||||
[&](const FixedOutputHash & h) -> ContentAddressWithReferences {
|
||||
[&](const FileIngestionMethod & method) -> ContentAddressWithReferences {
|
||||
return FixedOutputInfo {
|
||||
.hash = h,
|
||||
.method = method,
|
||||
.hash = ca.hash,
|
||||
.references = {},
|
||||
};
|
||||
},
|
||||
}, ca.raw);
|
||||
}, ca.method.raw);
|
||||
}
|
||||
|
||||
std::optional<ContentAddressWithReferences> ContentAddressWithReferences::fromPartsOpt(
|
||||
|
@ -241,7 +184,7 @@ std::optional<ContentAddressWithReferences> ContentAddressWithReferences::fromPa
|
|||
return std::nullopt;
|
||||
return ContentAddressWithReferences {
|
||||
TextInfo {
|
||||
.hash = { .hash = std::move(hash) },
|
||||
.hash = std::move(hash),
|
||||
.references = std::move(refs.others),
|
||||
}
|
||||
};
|
||||
|
@ -249,10 +192,8 @@ std::optional<ContentAddressWithReferences> ContentAddressWithReferences::fromPa
|
|||
[&](FileIngestionMethod m2) -> std::optional<ContentAddressWithReferences> {
|
||||
return ContentAddressWithReferences {
|
||||
FixedOutputInfo {
|
||||
.hash = {
|
||||
.method = m2,
|
||||
.hash = std::move(hash),
|
||||
},
|
||||
.method = m2,
|
||||
.hash = std::move(hash),
|
||||
.references = std::move(refs),
|
||||
}
|
||||
};
|
||||
|
@ -267,7 +208,7 @@ ContentAddressMethod ContentAddressWithReferences::getMethod() const
|
|||
return TextIngestionMethod {};
|
||||
},
|
||||
[](const FixedOutputInfo & fsh) -> ContentAddressMethod {
|
||||
return fsh.hash.method;
|
||||
return fsh.method;
|
||||
},
|
||||
}, raw);
|
||||
}
|
||||
|
@ -276,10 +217,10 @@ Hash ContentAddressWithReferences::getHash() const
|
|||
{
|
||||
return std::visit(overloaded {
|
||||
[](const TextInfo & th) {
|
||||
return th.hash.hash;
|
||||
return th.hash;
|
||||
},
|
||||
[](const FixedOutputInfo & fsh) {
|
||||
return fsh.hash.hash;
|
||||
return fsh.hash;
|
||||
},
|
||||
}, raw);
|
||||
}
|
||||
|
|
|
@ -113,37 +113,6 @@ struct ContentAddressMethod
|
|||
* 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
|
||||
* years; fixed-output derivations support multiple hash algorithms and
|
||||
|
@ -158,19 +127,17 @@ struct FixedOutputHash {
|
|||
*/
|
||||
struct ContentAddress
|
||||
{
|
||||
typedef std::variant<
|
||||
TextHash,
|
||||
FixedOutputHash
|
||||
> Raw;
|
||||
/**
|
||||
* How the file system objects are serialized
|
||||
*/
|
||||
ContentAddressMethod method;
|
||||
|
||||
Raw raw;
|
||||
/**
|
||||
* Hash of that serialization
|
||||
*/
|
||||
Hash hash;
|
||||
|
||||
GENERATE_CMP(ContentAddress, me->raw);
|
||||
|
||||
/* The moral equivalent of `using Raw::Raw;` */
|
||||
ContentAddress(auto &&... arg)
|
||||
: raw(std::forward<decltype(arg)>(arg)...)
|
||||
{ }
|
||||
GENERATE_CMP(ContentAddress, me->method, me->hash);
|
||||
|
||||
/**
|
||||
* Compute the content-addressability assertion
|
||||
|
@ -183,20 +150,6 @@ struct ContentAddress
|
|||
|
||||
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;
|
||||
};
|
||||
|
||||
|
@ -219,7 +172,8 @@ std::string renderContentAddress(std::optional<ContentAddress> ca);
|
|||
* References to other store objects are tracked with store paths, self
|
||||
* references however are tracked with a boolean.
|
||||
*/
|
||||
struct StoreReferences {
|
||||
struct StoreReferences
|
||||
{
|
||||
/**
|
||||
* References to other store objects
|
||||
*/
|
||||
|
@ -246,8 +200,13 @@ struct StoreReferences {
|
|||
};
|
||||
|
||||
// This matches the additional info that we need for makeTextPath
|
||||
struct TextInfo {
|
||||
TextHash hash;
|
||||
struct TextInfo
|
||||
{
|
||||
/**
|
||||
* Hash of the contents of the text/file.
|
||||
*/
|
||||
Hash hash;
|
||||
|
||||
/**
|
||||
* References to other store objects only; self references
|
||||
* disallowed
|
||||
|
@ -257,8 +216,18 @@ struct TextInfo {
|
|||
GENERATE_CMP(TextInfo, me->hash, me->references);
|
||||
};
|
||||
|
||||
struct FixedOutputInfo {
|
||||
FixedOutputHash hash;
|
||||
struct FixedOutputInfo
|
||||
{
|
||||
/**
|
||||
* How the file system objects are serialized
|
||||
*/
|
||||
FileIngestionMethod method;
|
||||
|
||||
/**
|
||||
* Hash of that serialization
|
||||
*/
|
||||
Hash hash;
|
||||
|
||||
/**
|
||||
* References to other store objects or this one.
|
||||
*/
|
||||
|
|
|
@ -232,9 +232,10 @@ static DerivationOutput parseDerivationOutput(const Store & store,
|
|||
validatePath(pathS);
|
||||
auto hash = Hash::parseNonSRIUnprefixed(hashS, hashType);
|
||||
return DerivationOutput::CAFixed {
|
||||
.ca = ContentAddress::fromParts(
|
||||
std::move(method),
|
||||
std::move(hash)),
|
||||
.ca = ContentAddress {
|
||||
.method = std::move(method),
|
||||
.hash = std::move(hash),
|
||||
},
|
||||
};
|
||||
} else {
|
||||
experimentalFeatureSettings.require(Xp::CaDerivations);
|
||||
|
@ -395,7 +396,7 @@ std::string Derivation::unparse(const Store & store, bool maskOutputs,
|
|||
[&](const DerivationOutput::CAFixed & dof) {
|
||||
s += ','; printUnquotedString(s, maskOutputs ? "" : store.printStorePath(dof.path(store, name, i.first)));
|
||||
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) {
|
||||
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 hash = hashString(htSHA256, "fixed:out:"
|
||||
+ 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)));
|
||||
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) {
|
||||
out << store.printStorePath(dof.path(store, drv.name, i.first))
|
||||
<< dof.ca.printMethodAlgo()
|
||||
<< dof.ca.getHash().to_string(Base16, false);
|
||||
<< dof.ca.hash.to_string(Base16, false);
|
||||
},
|
||||
[&](const DerivationOutput::CAFloating & dof) {
|
||||
out << ""
|
||||
|
@ -970,7 +971,7 @@ nlohmann::json DerivationOutput::toJSON(
|
|||
[&](const DerivationOutput::CAFixed & dof) {
|
||||
res["path"] = store.printStorePath(dof.path(store, drvName, outputName));
|
||||
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?
|
||||
},
|
||||
[&](const DerivationOutput::CAFloating & dof) {
|
||||
|
@ -1017,9 +1018,10 @@ DerivationOutput DerivationOutput::fromJSON(
|
|||
else if (keys == (std::set<std::string_view> { "path", "hashAlgo", "hash" })) {
|
||||
auto [method, hashType] = methodAlgo();
|
||||
auto dof = DerivationOutput::CAFixed {
|
||||
.ca = ContentAddress::fromParts(
|
||||
std::move(method),
|
||||
Hash::parseNonSRIUnprefixed((std::string) json["hash"], hashType)),
|
||||
.ca = ContentAddress {
|
||||
.method = std::move(method),
|
||||
.hash = Hash::parseNonSRIUnprefixed((std::string) json["hash"], hashType),
|
||||
},
|
||||
};
|
||||
if (dof.path(store, drvName, outputName) != store.parseStorePath((std::string) json["path"]))
|
||||
throw Error("Path doesn't match derivation output");
|
||||
|
|
|
@ -1249,27 +1249,17 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
|
|||
printStorePath(info.path), info.narSize, hashResult.second);
|
||||
|
||||
if (info.ca) {
|
||||
if (auto foHash = std::get_if<FixedOutputHash>(&info.ca->raw)) {
|
||||
auto actualFoHash = hashCAPath(
|
||||
foHash->method,
|
||||
foHash->hash.type,
|
||||
info.path
|
||||
);
|
||||
if (foHash->hash != actualFoHash.hash) {
|
||||
throw Error("ca hash mismatch importing path '%s';\n specified: %s\n got: %s",
|
||||
printStorePath(info.path),
|
||||
foHash->hash.to_string(Base32, true),
|
||||
actualFoHash.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));
|
||||
}
|
||||
auto & specified = *info.ca;
|
||||
auto actualHash = hashCAPath(
|
||||
specified.method,
|
||||
specified.hash.type,
|
||||
info.path
|
||||
);
|
||||
if (specified.hash != actualHash.hash) {
|
||||
throw Error("ca hash mismatch importing path '%s';\n specified: %s\n got: %s",
|
||||
printStorePath(info.path),
|
||||
specified.hash.to_string(Base32, true),
|
||||
actualHash.hash.to_string(Base32, true));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1349,10 +1339,8 @@ StorePath LocalStore::addToStoreFromDump(Source & source0, std::string_view name
|
|||
auto [hash, size] = hashSink->finish();
|
||||
|
||||
ContentAddressWithReferences desc = FixedOutputInfo {
|
||||
.hash = {
|
||||
.method = method,
|
||||
.hash = hash,
|
||||
},
|
||||
.method = method,
|
||||
.hash = hash,
|
||||
.references = {
|
||||
.others = references,
|
||||
// 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 dstPath = makeTextPath(name, TextInfo {
|
||||
{ .hash = hash },
|
||||
references,
|
||||
.hash = hash,
|
||||
.references = references,
|
||||
});
|
||||
|
||||
addTempRoot(dstPath);
|
||||
|
@ -1459,7 +1447,10 @@ StorePath LocalStore::addTextToStore(
|
|||
ValidPathInfo info { dstPath, narHash };
|
||||
info.narSize = sink.s.size();
|
||||
info.references = references;
|
||||
info.ca = TextHash { .hash = hash };
|
||||
info.ca = {
|
||||
.method = TextIngestionMethod {},
|
||||
.hash = hash,
|
||||
};
|
||||
registerValidPath(info);
|
||||
}
|
||||
|
||||
|
@ -1856,33 +1847,39 @@ void LocalStore::queryRealisationUncached(const DrvOutput & id,
|
|||
}
|
||||
}
|
||||
|
||||
FixedOutputHash LocalStore::hashCAPath(
|
||||
const FileIngestionMethod & method, const HashType & hashType,
|
||||
ContentAddress LocalStore::hashCAPath(
|
||||
const ContentAddressMethod & method, const HashType & hashType,
|
||||
const StorePath & path)
|
||||
{
|
||||
return hashCAPath(method, hashType, Store::toRealPath(path), path.hashPart());
|
||||
}
|
||||
|
||||
FixedOutputHash LocalStore::hashCAPath(
|
||||
const FileIngestionMethod & method,
|
||||
ContentAddress LocalStore::hashCAPath(
|
||||
const ContentAddressMethod & method,
|
||||
const HashType & hashType,
|
||||
const Path & path,
|
||||
const std::string_view pathHash
|
||||
)
|
||||
{
|
||||
HashModuloSink caSink ( hashType, std::string(pathHash) );
|
||||
switch (method) {
|
||||
case FileIngestionMethod::Recursive:
|
||||
dumpPath(path, caSink);
|
||||
break;
|
||||
case FileIngestionMethod::Flat:
|
||||
readFile(path, caSink);
|
||||
break;
|
||||
}
|
||||
auto hash = caSink.finish().first;
|
||||
return FixedOutputHash{
|
||||
std::visit(overloaded {
|
||||
[&](const TextIngestionMethod &) {
|
||||
readFile(path, caSink);
|
||||
},
|
||||
[&](const FileIngestionMethod & m2) {
|
||||
switch (m2) {
|
||||
case FileIngestionMethod::Recursive:
|
||||
dumpPath(path, caSink);
|
||||
break;
|
||||
case FileIngestionMethod::Flat:
|
||||
readFile(path, caSink);
|
||||
break;
|
||||
}
|
||||
},
|
||||
}, method.raw);
|
||||
return ContentAddress {
|
||||
.method = method,
|
||||
.hash = hash,
|
||||
.hash = caSink.finish().first,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -345,13 +345,13 @@ private:
|
|||
void signRealisation(Realisation &);
|
||||
|
||||
// XXX: Make a generic `Store` method
|
||||
FixedOutputHash hashCAPath(
|
||||
const FileIngestionMethod & method,
|
||||
ContentAddress hashCAPath(
|
||||
const ContentAddressMethod & method,
|
||||
const HashType & hashType,
|
||||
const StorePath & path);
|
||||
|
||||
FixedOutputHash hashCAPath(
|
||||
const FileIngestionMethod & method,
|
||||
ContentAddress hashCAPath(
|
||||
const ContentAddressMethod & method,
|
||||
const HashType & hashType,
|
||||
const Path & path,
|
||||
const std::string_view pathHash
|
||||
|
|
|
@ -52,10 +52,8 @@ std::map<StorePath, StorePath> makeContentAddressed(
|
|||
dstStore,
|
||||
path.name(),
|
||||
FixedOutputInfo {
|
||||
.hash = {
|
||||
.method = FileIngestionMethod::Recursive,
|
||||
.hash = narModuloHash,
|
||||
},
|
||||
.method = FileIngestionMethod::Recursive,
|
||||
.hash = narModuloHash,
|
||||
.references = std::move(refs),
|
||||
},
|
||||
Hash::dummy,
|
||||
|
|
|
@ -29,14 +29,14 @@ std::optional<ContentAddressWithReferences> ValidPathInfo::contentAddressWithRef
|
|||
return std::nullopt;
|
||||
|
||||
return std::visit(overloaded {
|
||||
[&](const TextHash & th) -> ContentAddressWithReferences {
|
||||
[&](const TextIngestionMethod &) -> ContentAddressWithReferences {
|
||||
assert(references.count(path) == 0);
|
||||
return TextInfo {
|
||||
.hash = th,
|
||||
.hash = ca->hash,
|
||||
.references = references,
|
||||
};
|
||||
},
|
||||
[&](const FixedOutputHash & foh) -> ContentAddressWithReferences {
|
||||
[&](const FileIngestionMethod & m2) -> ContentAddressWithReferences {
|
||||
auto refs = references;
|
||||
bool hasSelfReference = false;
|
||||
if (refs.count(path)) {
|
||||
|
@ -44,14 +44,15 @@ std::optional<ContentAddressWithReferences> ValidPathInfo::contentAddressWithRef
|
|||
refs.erase(path);
|
||||
}
|
||||
return FixedOutputInfo {
|
||||
.hash = foh,
|
||||
.method = m2,
|
||||
.hash = ca->hash,
|
||||
.references = {
|
||||
.others = std::move(refs),
|
||||
.self = hasSelfReference,
|
||||
},
|
||||
};
|
||||
},
|
||||
}, ca->raw);
|
||||
}, ca->method.raw);
|
||||
}
|
||||
|
||||
bool ValidPathInfo::isContentAddressed(const Store & store) const
|
||||
|
@ -110,13 +111,19 @@ ValidPathInfo::ValidPathInfo(
|
|||
std::visit(overloaded {
|
||||
[this](TextInfo && ti) {
|
||||
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->references = std::move(foi.references.others);
|
||||
if (foi.references.self)
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -184,15 +184,15 @@ static std::string makeType(
|
|||
|
||||
StorePath Store::makeFixedOutputPath(std::string_view name, const FixedOutputInfo & info) const
|
||||
{
|
||||
if (info.hash.hash.type == htSHA256 && info.hash.method == FileIngestionMethod::Recursive) {
|
||||
return makeStorePath(makeType(*this, "source", info.references), info.hash.hash, name);
|
||||
if (info.hash.type == htSHA256 && info.method == FileIngestionMethod::Recursive) {
|
||||
return makeStorePath(makeType(*this, "source", info.references), info.hash, name);
|
||||
} else {
|
||||
assert(info.references.size() == 0);
|
||||
return makeStorePath("output:out",
|
||||
hashString(htSHA256,
|
||||
"fixed:out:"
|
||||
+ makeFileIngestionPrefix(info.hash.method)
|
||||
+ info.hash.hash.to_string(Base16, true) + ":"),
|
||||
+ makeFileIngestionPrefix(info.method)
|
||||
+ info.hash.to_string(Base16, true) + ":"),
|
||||
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
|
||||
{
|
||||
assert(info.hash.hash.type == htSHA256);
|
||||
assert(info.hash.type == htSHA256);
|
||||
return makeStorePath(
|
||||
makeType(*this, "text", StoreReferences {
|
||||
.others = info.references,
|
||||
.self = false,
|
||||
}),
|
||||
info.hash.hash,
|
||||
info.hash,
|
||||
name);
|
||||
}
|
||||
|
||||
|
@ -232,10 +232,8 @@ std::pair<StorePath, Hash> Store::computeStorePathForPath(std::string_view name,
|
|||
? hashPath(hashAlgo, srcPath, filter).first
|
||||
: hashFile(hashAlgo, srcPath);
|
||||
FixedOutputInfo caInfo {
|
||||
.hash = {
|
||||
.method = method,
|
||||
.hash = h,
|
||||
},
|
||||
.method = method,
|
||||
.hash = h,
|
||||
.references = {},
|
||||
};
|
||||
return std::make_pair(makeFixedOutputPath(name, caInfo), h);
|
||||
|
@ -248,8 +246,8 @@ StorePath Store::computeStorePathForText(
|
|||
const StorePathSet & references) const
|
||||
{
|
||||
return makeTextPath(name, TextInfo {
|
||||
{ .hash = hashString(htSHA256, s) },
|
||||
references,
|
||||
.hash = hashString(htSHA256, s),
|
||||
.references = references,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -441,10 +439,8 @@ ValidPathInfo Store::addToStoreSlow(std::string_view name, const Path & srcPath,
|
|||
*this,
|
||||
name,
|
||||
FixedOutputInfo {
|
||||
.hash = {
|
||||
.method = method,
|
||||
.hash = hash,
|
||||
},
|
||||
.method = method,
|
||||
.hash = hash,
|
||||
.references = {},
|
||||
},
|
||||
narHash,
|
||||
|
|
|
@ -81,7 +81,7 @@ TEST_JSON(DerivationTest, caFixedFlat,
|
|||
"path": "/nix/store/rhcg9h16sqvlbpsa6dqm57sbr2al6nzg-drv-name-output-name"
|
||||
})",
|
||||
(DerivationOutput::CAFixed {
|
||||
.ca = FixedOutputHash {
|
||||
.ca = {
|
||||
.method = FileIngestionMethod::Flat,
|
||||
.hash = Hash::parseAnyPrefixed("sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="),
|
||||
},
|
||||
|
@ -95,7 +95,7 @@ TEST_JSON(DerivationTest, caFixedNAR,
|
|||
"path": "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"
|
||||
})",
|
||||
(DerivationOutput::CAFixed {
|
||||
.ca = FixedOutputHash {
|
||||
.ca = {
|
||||
.method = FileIngestionMethod::Recursive,
|
||||
.hash = Hash::parseAnyPrefixed("sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="),
|
||||
},
|
||||
|
@ -109,7 +109,7 @@ TEST_JSON(DynDerivationTest, caFixedText,
|
|||
"path": "/nix/store/6s1zwabh956jvhv4w9xcdb5jiyanyxg1-drv-name-output-name"
|
||||
})",
|
||||
(DerivationOutput::CAFixed {
|
||||
.ca = TextHash {
|
||||
.ca = {
|
||||
.hash = Hash::parseAnyPrefixed("sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="),
|
||||
},
|
||||
}),
|
||||
|
|
|
@ -220,10 +220,8 @@ static void opPrintFixedPath(Strings opFlags, Strings opArgs)
|
|||
std::string name = *i++;
|
||||
|
||||
cout << fmt("%s\n", store->printStorePath(store->makeFixedOutputPath(name, FixedOutputInfo {
|
||||
.hash = {
|
||||
.method = method,
|
||||
.hash = Hash::parseAny(hash, hashAlgo),
|
||||
},
|
||||
.method = method,
|
||||
.hash = Hash::parseAny(hash, hashAlgo),
|
||||
.references = {},
|
||||
})));
|
||||
}
|
||||
|
|
|
@ -45,10 +45,8 @@ struct CmdAddToStore : MixDryRun, StoreCommand
|
|||
*store,
|
||||
std::move(*namePart),
|
||||
FixedOutputInfo {
|
||||
.hash = {
|
||||
.method = std::move(ingestionMethod),
|
||||
.hash = std::move(hash),
|
||||
},
|
||||
.method = std::move(ingestionMethod),
|
||||
.hash = std::move(hash),
|
||||
.references = {},
|
||||
},
|
||||
narHash,
|
||||
|
|
|
@ -71,10 +71,8 @@ std::tuple<StorePath, Hash> prefetchFile(
|
|||
if (expectedHash) {
|
||||
hashType = expectedHash->type;
|
||||
storePath = store->makeFixedOutputPath(*name, FixedOutputInfo {
|
||||
.hash = {
|
||||
.method = ingestionMethod,
|
||||
.hash = *expectedHash,
|
||||
},
|
||||
.method = ingestionMethod,
|
||||
.hash = *expectedHash,
|
||||
.references = {},
|
||||
});
|
||||
if (store->isValidPath(*storePath))
|
||||
|
@ -127,7 +125,7 @@ std::tuple<StorePath, Hash> prefetchFile(
|
|||
auto info = store->addToStoreSlow(*name, tmpFile, ingestionMethod, hashType, expectedHash);
|
||||
storePath = info.path;
|
||||
assert(info.ca);
|
||||
hash = info.ca->getHash();
|
||||
hash = info.ca->hash;
|
||||
}
|
||||
|
||||
return {storePath.value(), hash.value()};
|
||||
|
|
|
@ -222,10 +222,8 @@ struct ProfileManifest
|
|||
*store,
|
||||
"profile",
|
||||
FixedOutputInfo {
|
||||
.hash = {
|
||||
.method = FileIngestionMethod::Recursive,
|
||||
.hash = narHash,
|
||||
},
|
||||
.method = FileIngestionMethod::Recursive,
|
||||
.hash = narHash,
|
||||
.references = {
|
||||
.others = std::move(references),
|
||||
// profiles never refer to themselves
|
||||
|
|
Loading…
Reference in a new issue