From 613de9d9cceb25e7eaf29f08fb20c64b0a5bcfbf Mon Sep 17 00:00:00 2001 From: John Ericson Date: Wed, 17 Sep 2025 15:21:08 -0400 Subject: [PATCH 1/3] Add missing `#pragma once` --- src/libutil/include/nix/util/memory-source-accessor.hh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libutil/include/nix/util/memory-source-accessor.hh b/src/libutil/include/nix/util/memory-source-accessor.hh index a04d1d347..98c193800 100644 --- a/src/libutil/include/nix/util/memory-source-accessor.hh +++ b/src/libutil/include/nix/util/memory-source-accessor.hh @@ -1,3 +1,6 @@ +#pragma once +///@file + #include "nix/util/source-path.hh" #include "nix/util/fs-sink.hh" #include "nix/util/variant-wrapper.hh" From 168c24b605f7124fedb0a957659d2c76e979573f Mon Sep 17 00:00:00 2001 From: John Ericson Date: Wed, 17 Sep 2025 15:20:42 -0400 Subject: [PATCH 2/3] Declare `DummyStoreConfig` in a header This will useful for unit tests. --- src/libstore/dummy-store.cc | 43 +++---------------- src/libstore/include/nix/store/dummy-store.hh | 41 ++++++++++++++++++ src/libstore/include/nix/store/meson.build | 1 + 3 files changed, 47 insertions(+), 38 deletions(-) create mode 100644 src/libstore/include/nix/store/dummy-store.hh diff --git a/src/libstore/dummy-store.cc b/src/libstore/dummy-store.cc index d0e298968..defee4a98 100644 --- a/src/libstore/dummy-store.cc +++ b/src/libstore/dummy-store.cc @@ -1,48 +1,15 @@ #include "nix/store/store-registration.hh" #include "nix/util/callback.hh" +#include "nix/store/dummy-store.hh" namespace nix { -struct DummyStoreConfig : public std::enable_shared_from_this, virtual StoreConfig +std::string DummyStoreConfig::doc() { - using StoreConfig::StoreConfig; - - DummyStoreConfig(std::string_view scheme, std::string_view authority, const Params & params) - : StoreConfig(params) - { - if (!authority.empty()) - throw UsageError("`%s` store URIs must not contain an authority part %s", scheme, authority); - } - - static const std::string name() - { - return "Dummy Store"; - } - - static std::string doc() - { - return + return #include "dummy-store.md" - ; - } - - static StringSet uriSchemes() - { - return {"dummy"}; - } - - ref openStore() const override; - - StoreReference getReference() const override - { - return { - .variant = - StoreReference::Specified{ - .scheme = *uriSchemes().begin(), - }, - }; - } -}; + ; +} struct DummyStore : virtual Store { diff --git a/src/libstore/include/nix/store/dummy-store.hh b/src/libstore/include/nix/store/dummy-store.hh new file mode 100644 index 000000000..9cb26d8d4 --- /dev/null +++ b/src/libstore/include/nix/store/dummy-store.hh @@ -0,0 +1,41 @@ +#include "nix/store/store-api.hh" + +namespace nix { + +struct DummyStoreConfig : public std::enable_shared_from_this, virtual StoreConfig +{ + using StoreConfig::StoreConfig; + + DummyStoreConfig(std::string_view scheme, std::string_view authority, const Params & params) + : StoreConfig(params) + { + if (!authority.empty()) + throw UsageError("`%s` store URIs must not contain an authority part %s", scheme, authority); + } + + static const std::string name() + { + return "Dummy Store"; + } + + static std::string doc(); + + static StringSet uriSchemes() + { + return {"dummy"}; + } + + ref openStore() const override; + + StoreReference getReference() const override + { + return { + .variant = + StoreReference::Specified{ + .scheme = *uriSchemes().begin(), + }, + }; + } +}; + +} // namespace nix diff --git a/src/libstore/include/nix/store/meson.build b/src/libstore/include/nix/store/meson.build index 60af5ff53..428ef00f3 100644 --- a/src/libstore/include/nix/store/meson.build +++ b/src/libstore/include/nix/store/meson.build @@ -34,6 +34,7 @@ headers = [ config_pub_h ] + files( 'derived-path-map.hh', 'derived-path.hh', 'downstream-placeholder.hh', + 'dummy-store.hh', 'export-import.hh', 'filetransfer.hh', 'gc-store.hh', From d5ce8c3caacd189a4a6e6f8aef0f688cd4264515 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Fri, 14 Jun 2024 10:54:34 -0400 Subject: [PATCH 3/3] Use `MemorySourceAccessor` in `DummyStore` Add `read-only` setting to `dummy://` store for back compat. Test by changing an existing test to use this instead, fixing a TODO. Co-Authored-By: HaeNoe Co-authored-by: Eelco Dolstra --- src/libfetchers-tests/git.cc | 10 ++-- src/libstore/dummy-store.cc | 51 +++++++++++++++++-- src/libstore/dummy-store.md | 8 +-- src/libstore/include/nix/store/dummy-store.hh | 9 ++++ 4 files changed, 67 insertions(+), 11 deletions(-) diff --git a/src/libfetchers-tests/git.cc b/src/libfetchers-tests/git.cc index af987e260..4f0e0d974 100644 --- a/src/libfetchers-tests/git.cc +++ b/src/libfetchers-tests/git.cc @@ -1,5 +1,6 @@ #include "nix/store/store-open.hh" #include "nix/store/globals.hh" +#include "nix/store/dummy-store.hh" #include "nix/fetchers/fetch-settings.hh" #include "nix/fetchers/fetchers.hh" #include "nix/fetchers/git-utils.hh" @@ -179,10 +180,11 @@ TEST_F(GitTest, submodulePeriodSupport) // 6) Commit the addition in super commitAll(super.get(), "Add submodule with branch='.'"); - // TODO: Use dummy:// store with MemorySourceAccessor. - Path storeTmpDir = createTempDir(); - auto storeTmpDirAutoDelete = AutoDelete(storeTmpDir, true); - ref store = openStore(storeTmpDir); + auto store = [] { + auto cfg = make_ref(StoreReference::Params{}); + cfg->readOnly = false; + return cfg->openStore(); + }(); auto settings = fetchers::Settings{}; auto input = fetchers::Input::fromAttrs( diff --git a/src/libstore/dummy-store.cc b/src/libstore/dummy-store.cc index defee4a98..2909d20e0 100644 --- a/src/libstore/dummy-store.cc +++ b/src/libstore/dummy-store.cc @@ -1,5 +1,7 @@ #include "nix/store/store-registration.hh" +#include "nix/util/archive.hh" #include "nix/util/callback.hh" +#include "nix/util/memory-source-accessor.hh" #include "nix/store/dummy-store.hh" namespace nix { @@ -17,9 +19,12 @@ struct DummyStore : virtual Store ref config; + ref contents; + DummyStore(ref config) : Store{*config} , config(config) + , contents(make_ref()) { } @@ -47,8 +52,8 @@ struct DummyStore : virtual Store unsupported("addToStore"); } - virtual StorePath addToStoreFromDump( - Source & dump, + StorePath addToStoreFromDump( + Source & source, std::string_view name, FileSerialisationMethod dumpMethod = FileSerialisationMethod::NixArchive, ContentAddressMethod hashMethod = FileIngestionMethod::NixArchive, @@ -56,7 +61,45 @@ struct DummyStore : virtual Store const StorePathSet & references = StorePathSet(), RepairFlag repair = NoRepair) override { - unsupported("addToStore"); + if (config->readOnly) + unsupported("addToStoreFromDump"); + + auto temp = make_ref(); + + { + MemorySink tempSink{*temp}; + + // TODO factor this out into `restorePath`, same todo on it. + switch (dumpMethod) { + case FileSerialisationMethod::NixArchive: + parseDump(tempSink, source); + break; + case FileSerialisationMethod::Flat: { + // Replace root dir with file so next part succeeds. + temp->root = MemorySourceAccessor::File::Regular{}; + tempSink.createRegularFile(CanonPath::root, [&](auto & sink) { source.drainInto(sink); }); + break; + } + } + } + + auto hash = hashPath({temp, CanonPath::root}, hashMethod.getFileIngestionMethod(), hashAlgo).first; + + auto desc = ContentAddressWithReferences::fromParts( + hashMethod, + hash, + { + .others = references, + // caller is not capable of creating a self-reference, because + // this is content-addressed without modulus + .self = false, + }); + + auto dstPath = makeFixedOutputPathFromCA(name, desc); + + contents->open(CanonPath(printStorePath(dstPath)), std::move(temp->root)); + + return dstPath; } void narFromPath(const StorePath & path, Sink & sink) override @@ -72,7 +115,7 @@ struct DummyStore : virtual Store virtual ref getFSAccessor(bool requireValidPath) override { - return makeEmptySourceAccessor(); + return this->contents; } }; diff --git a/src/libstore/dummy-store.md b/src/libstore/dummy-store.md index eb7b4ba0d..3cbec3b3a 100644 --- a/src/libstore/dummy-store.md +++ b/src/libstore/dummy-store.md @@ -2,9 +2,11 @@ R"( **Store URL format**: `dummy://` -This store type represents a store that contains no store paths and -cannot be written to. It's useful when you want to use the Nix -evaluator when no actual Nix store exists, e.g. +This store type represents a store in memory. +Store objects can be read and written, but only so long as the store is open. +Once the store is closed, all data will be forgoton. + +It's useful when you want to use the Nix evaluator when no actual Nix store exists, e.g. ```console # nix eval --store dummy:// --expr '1 + 2' diff --git a/src/libstore/include/nix/store/dummy-store.hh b/src/libstore/include/nix/store/dummy-store.hh index 9cb26d8d4..0a15667b6 100644 --- a/src/libstore/include/nix/store/dummy-store.hh +++ b/src/libstore/include/nix/store/dummy-store.hh @@ -13,6 +13,15 @@ struct DummyStoreConfig : public std::enable_shared_from_this, throw UsageError("`%s` store URIs must not contain an authority part %s", scheme, authority); } + Setting readOnly{ + this, + true, + "read-only", + R"( + Make any sort of write fail instead of succeeding. + No additional memory will be used, because no information needs to be stored. + )"}; + static const std::string name() { return "Dummy Store";