diff --git a/src/libstore/meson.build b/src/libstore/meson.build index 5fde92dd0..125a19bc9 100644 --- a/src/libstore/meson.build +++ b/src/libstore/meson.build @@ -40,6 +40,7 @@ libstore_sources = files( 'derived-path.cc', 'downstream-placeholder.cc', 'dummy-store.cc', + 'testing-store.cc', 'export-import.cc', 'filetransfer.cc', 'gc.cc', diff --git a/src/libstore/testing-store.cc b/src/libstore/testing-store.cc new file mode 100644 index 000000000..64f1e3e8d --- /dev/null +++ b/src/libstore/testing-store.cc @@ -0,0 +1,217 @@ +#include +#include +#include +#include + +#include + +#include "content-address.hh" +#include "hash.hh" +#include "path-info.hh" +#include "store-api.hh" + +namespace nix +{ + +struct TestingStoreConfig : virtual StoreConfig +{ + using StoreConfig::StoreConfig; + + std::string const name() override + { + return "Testing Store"; + } + + std::string doc() override + { + return ""; + } +}; + +/** Like DummyStore, but keeps some track of what it's done and stubs rather than fails unsupported operations. + * + * Don't expect any operations on this to be at all fast lmao. + */ +struct TestingStore : public virtual TestingStoreConfig, public virtual Store +{ + struct AddedPath + { + StorePath storePath; + ValidPathInfo pathInfo; + }; + + struct AddedText + { + std::string name; + std::string text; + StorePath storePath; + }; + + static std::set uriSchemes() + { + return {"testing"}; + } + + std::vector addedPaths; + std::vector addedText; + + TestingStore(std::string const scheme, std::string const uri, Params const & params) + : TestingStore(params) + { } + + TestingStore(Params const & params) + : StoreConfig(params) + , TestingStoreConfig(params) + , Store(params) + { } + + virtual std::optional isTrustedClient() override + { + return Trusted; + } + + std::string getUri() override + { + return *this->uriSchemes().begin(); + } + + void addToStore( + ValidPathInfo const & info, + Source & source, + RepairFlag repair, + CheckSigsFlag checkSigs + ) override + { + notice("testing store: adding path '%s'", this->printStorePath(info.path)); + AddedPath added{ + .storePath = info.path, + .pathInfo = info, + }; + + this->addedPaths.push_back(added); + } + + virtual StorePath addToStoreFromDump( + Source & dump, + std::string_view name, + FileIngestionMethod method = FileIngestionMethod::Recursive, + HashType hashAlgo = htSHA256, + RepairFlag repair = NoRepair, + StorePathSet const & references = {} + ) override + { + notice("testing store: adding path from Source %s", boost::core::demangle(typeid(dump).name())); + HashSink hashSink(hashAlgo); + TeeSource tee(dump, hashSink); + + static constexpr uint64_t BUFSIZE = 32ULL * 1024ULL * 1024ULL; + + std::vector all; + char buffer[4096] = {0}; + size_t got = tee.read(buffer, BUFSIZE); + while (got > 0) { + for (size_t i = 0; i < got; i++) { + all.push_back(buffer[i]); + } + got = tee.read(buffer, 4096); + } + + auto const [hash, size] = hashSink.finish(); + + ContentAddressWithReferences caDesc(FixedOutputInfo{ + .method = method, + .hash = hash, + .references = { + .others = references, + .self = false, + }, + }); + + StorePath const dstPath = makeFixedOutputPathFromCA(name, caDesc); + + HashSink narSink(htSHA256); + + ValidPathInfo pathInfo{ + *this, + name, + std::move(caDesc), + Hash(htSHA256), + }; + + AddedPath added{ + .storePath = dstPath, + .pathInfo = pathInfo, + }; + + this->addedPaths.push_back(added); + + return dstPath; + } + + StorePath addTextToStore( + std::string_view name, + std::string_view text, + StorePathSet const & references, + [[maybe_unused]] RepairFlag repair + ) override + { + auto const hash = hashString(htSHA256, text); + StorePath const dstPath = makeTextPath(name, TextInfo { + .hash = hash, + .references = references, + }); + + AddedText added{ + .name = std::string(name), + .text = std::string(text), + .storePath = dstPath, + }; + + this->addedText.push_back(added); + + return dstPath; + } + + void narFromPath(StorePath const & path, Sink & sink) override + { + this->unsupported("narFromPath"); + } + + std::optional queryPathFromHashPart(std::string const & hashPart) override + { + for (auto const & addedPath : this->addedPaths) { + if (addedPath.storePath.hashPart() == hashPart) { + return std::make_optional(addedPath.storePath); + } + } + + return std::nullopt; + } + + std::shared_ptr queryPathInfoUncached(StorePath const & path) override + { + for (auto const & addedPath : this->addedPaths) { + if (addedPath.storePath == path) { + return std::shared_ptr(&addedPath.pathInfo); + } + } + + return nullptr; + } + + std::shared_ptr queryRealisationUncached(DrvOutput const &) override + { + this->unsupported("queryRealisationUncached"); + // return nullptr; + } + + virtual ref getFSAccessor() override + { + this->unsupported("getFSAccessor"); + } + +}; + +static RegisterStoreImplementation regTestingStore; + +}