Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
292 changes: 137 additions & 155 deletions src/libstore/dummy-store.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ std::string DummyStoreConfig::doc()
;
}

namespace {

// Note: This class is used by DummyStoreImpl and needs to be visible
class WholeStoreViewAccessor : public SourceAccessor
{
using BaseName = std::string;
Expand Down Expand Up @@ -106,184 +105,167 @@ class WholeStoreViewAccessor : public SourceAccessor
}
};

} // namespace

ref<Store> DummyStoreConfig::openStore() const
{
return openDummyStore();
}

struct DummyStoreImpl : DummyStore
{
using Config = DummyStoreConfig;
// DummyStoreImpl method implementations

/**
* This view conceptually just borrows the file systems objects of
* each store object from `contents`, and combines them together
* into one store-wide source accessor.
*
* This is needed just in order to implement `Store::getFSAccessor`.
*/
ref<WholeStoreViewAccessor> wholeStoreView = make_ref<WholeStoreViewAccessor>();
DummyStoreImpl::DummyStoreImpl(ref<const Config> config)
: Store{*config}
, DummyStore{config}
, wholeStoreView(make_ref<WholeStoreViewAccessor>())
{
wholeStoreView->setPathDisplay(config->storeDir);
}

DummyStoreImpl(ref<const Config> config)
: Store{*config}
, DummyStore{config}
{
wholeStoreView->setPathDisplay(config->storeDir);
}
void DummyStoreImpl::queryPathInfoUncached(
const StorePath & path, Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept
{
bool visited = contents.cvisit(
path, [&](const auto & kv) { callback(std::make_shared<ValidPathInfo>(StorePath{kv.first}, kv.second.info)); });

void queryPathInfoUncached(
const StorePath & path, Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept override
{
bool visited = contents.cvisit(path, [&](const auto & kv) {
callback(std::make_shared<ValidPathInfo>(StorePath{kv.first}, kv.second.info));
});
if (!visited)
callback(nullptr);
}

if (!visited)
callback(nullptr);
}
std::optional<TrustedFlag> DummyStoreImpl::isTrustedClient()
{
return Trusted;
}

/**
* The dummy store is incapable of *not* trusting! :)
*/
virtual std::optional<TrustedFlag> isTrustedClient() override
{
return Trusted;
}
std::optional<StorePath> DummyStoreImpl::queryPathFromHashPart(const std::string & hashPart)
{
unsupported("queryPathFromHashPart");
}

std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override
{
unsupported("queryPathFromHashPart");
}
void DummyStoreImpl::addToStore(const ValidPathInfo & info, Source & source, RepairFlag repair, CheckSigsFlag checkSigs)
{
if (config->readOnly)
unsupported("addToStore");

if (repair)
throw Error("repairing is not supported for '%s' store", config->getHumanReadableURI());

if (checkSigs)
throw Error("checking signatures is not supported for '%s' store", config->getHumanReadableURI());

auto temp = make_ref<MemorySourceAccessor>();
MemorySink tempSink{*temp};
parseDump(tempSink, source);
auto path = info.path;

auto accessor = make_ref<MemorySourceAccessor>(std::move(*temp));
contents.insert(
{path,
PathInfoAndContents{
std::move(info),
accessor,
}});
wholeStoreView->addObject(path.to_string(), accessor);
}

void addToStore(const ValidPathInfo & info, Source & source, RepairFlag repair, CheckSigsFlag checkSigs) override
{
if (config->readOnly)
unsupported("addToStore");
StorePath DummyStoreImpl::addToStoreFromDump(
Source & source,
std::string_view name,
FileSerialisationMethod dumpMethod,
ContentAddressMethod hashMethod,
HashAlgorithm hashAlgo,
const StorePathSet & references,
RepairFlag repair)
{
if (config->readOnly)
unsupported("addToStoreFromDump");

if (repair)
throw Error("repairing is not supported for '%s' store", config->getHumanReadableURI());
if (repair)
throw Error("repairing is not supported for '%s' store", config->getHumanReadableURI());

if (checkSigs)
throw Error("checking signatures is not supported for '%s' store", config->getHumanReadableURI());
auto temp = make_ref<MemorySourceAccessor>();

auto temp = make_ref<MemorySourceAccessor>();
{
MemorySink tempSink{*temp};
parseDump(tempSink, source);
auto path = info.path;

auto accessor = make_ref<MemorySourceAccessor>(std::move(*temp));
contents.insert(
{path,
PathInfoAndContents{
std::move(info),
accessor,
}});
wholeStoreView->addObject(path.to_string(), accessor);
}

StorePath addToStoreFromDump(
Source & source,
std::string_view name,
FileSerialisationMethod dumpMethod = FileSerialisationMethod::NixArchive,
ContentAddressMethod hashMethod = FileIngestionMethod::NixArchive,
HashAlgorithm hashAlgo = HashAlgorithm::SHA256,
const StorePathSet & references = StorePathSet(),
RepairFlag repair = NoRepair) override
{
if (config->readOnly)
unsupported("addToStoreFromDump");

if (repair)
throw Error("repairing is not supported for '%s' store", config->getHumanReadableURI());

auto temp = make_ref<MemorySourceAccessor>();

{
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;
}
}
// 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 narHash = hashPath({temp, CanonPath::root}, FileIngestionMethod::NixArchive, HashAlgorithm::SHA256);

auto info = ValidPathInfo::makeFromCA(
*this,
name,
ContentAddressWithReferences::fromParts(
hashMethod,
std::move(hash),
{
.others = references,
// caller is not capable of creating a self-reference, because
// this is content-addressed without modulus
.self = false,
}),
std::move(narHash.first));

info.narSize = narHash.second.value();

auto path = info.path;
auto accessor = make_ref<MemorySourceAccessor>(std::move(*temp));
contents.insert(
{path,
PathInfoAndContents{
std::move(info),
accessor,
}});
wholeStoreView->addObject(path.to_string(), accessor);

return path;
}

void registerDrvOutput(const Realisation & output) override
{
unsupported("registerDrvOutput");
}
auto hash = hashPath({temp, CanonPath::root}, hashMethod.getFileIngestionMethod(), hashAlgo).first;
auto narHash = hashPath({temp, CanonPath::root}, FileIngestionMethod::NixArchive, HashAlgorithm::SHA256);

auto info = ValidPathInfo::makeFromCA(
*this,
name,
ContentAddressWithReferences::fromParts(
hashMethod,
std::move(hash),
{
.others = references,
// caller is not capable of creating a self-reference, because
// this is content-addressed without modulus
.self = false,
}),
std::move(narHash.first));

info.narSize = narHash.second.value();

auto path = info.path;
auto accessor = make_ref<MemorySourceAccessor>(std::move(*temp));
contents.insert(
{path,
PathInfoAndContents{
std::move(info),
accessor,
}});
wholeStoreView->addObject(path.to_string(), accessor);

return path;
}

void narFromPath(const StorePath & path, Sink & sink) override
{
bool visited = contents.cvisit(path, [&](const auto & kv) {
const auto & [info, accessor] = kv.second;
SourcePath sourcePath(accessor);
dumpPath(sourcePath, sink, FileSerialisationMethod::NixArchive);
});
void DummyStoreImpl::registerDrvOutput(const Realisation & output)
{
unsupported("registerDrvOutput");
}

if (!visited)
throw Error("path '%s' is not valid", printStorePath(path));
}
void DummyStoreImpl::narFromPath(const StorePath & path, Sink & sink)
{
bool visited = contents.cvisit(path, [&](const auto & kv) {
const auto & [info, accessor] = kv.second;
SourcePath sourcePath(accessor);
dumpPath(sourcePath, sink, FileSerialisationMethod::NixArchive);
});

if (!visited)
throw Error("path '%s' is not valid", printStorePath(path));
}

void
queryRealisationUncached(const DrvOutput &, Callback<std::shared_ptr<const Realisation>> callback) noexcept override
{
callback(nullptr);
}
void DummyStoreImpl::queryRealisationUncached(
const DrvOutput &, Callback<std::shared_ptr<const Realisation>> callback) noexcept
{
callback(nullptr);
}

std::shared_ptr<SourceAccessor> getFSAccessor(const StorePath & path, bool requireValidPath) override
{
std::shared_ptr<SourceAccessor> res;
contents.cvisit(path, [&](const auto & kv) { res = kv.second.contents.get_ptr(); });
return res;
}
std::shared_ptr<SourceAccessor> DummyStoreImpl::getFSAccessor(const StorePath & path, bool requireValidPath)
{
std::shared_ptr<SourceAccessor> res;
contents.cvisit(path, [&](const auto & kv) { res = kv.second.contents.get_ptr(); });
return res;
}

ref<SourceAccessor> getFSAccessor(bool requireValidPath) override
{
return wholeStoreView;
}
};
ref<SourceAccessor> DummyStoreImpl::getFSAccessor(bool requireValidPath)
{
return wholeStoreView;
}

ref<DummyStore> DummyStore::Config::openDummyStore() const
{
Expand Down
55 changes: 55 additions & 0 deletions src/libstore/include/nix/store/dummy-store-impl.hh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
namespace nix {

struct MemorySourceAccessor;
class WholeStoreViewAccessor;

/**
* Enough of the Dummy Store exposed for sake of writing unit tests
Expand Down Expand Up @@ -37,4 +38,58 @@ struct DummyStore : virtual Store
}
};

/**
* Full implementation of DummyStore.
* Exposed in the header so it can be inherited from in tests.
*/
class DummyStoreImpl : public DummyStore
{
protected:
/**
* This view conceptually just borrows the file systems objects of
* each store object from `contents`, and combines them together
* into one store-wide source accessor.
*
* This is needed just in order to implement `Store::getFSAccessor`.
*/
ref<WholeStoreViewAccessor> wholeStoreView;

public:
using Config = DummyStoreConfig;

DummyStoreImpl(ref<const Config> config);

void queryPathInfoUncached(
const StorePath & path, Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept override;

/**
* The dummy store is incapable of *not* trusting! :)
*/
virtual std::optional<TrustedFlag> isTrustedClient() override;

std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override;

void addToStore(const ValidPathInfo & info, Source & source, RepairFlag repair, CheckSigsFlag checkSigs) override;

virtual StorePath addToStoreFromDump(
Source & source,
std::string_view name,
FileSerialisationMethod dumpMethod = FileSerialisationMethod::NixArchive,
ContentAddressMethod hashMethod = FileIngestionMethod::NixArchive,
HashAlgorithm hashAlgo = HashAlgorithm::SHA256,
const StorePathSet & references = StorePathSet(),
RepairFlag repair = NoRepair) override;

void registerDrvOutput(const Realisation & output) override;

void narFromPath(const StorePath & path, Sink & sink) override;

void queryRealisationUncached(
const DrvOutput &, Callback<std::shared_ptr<const Realisation>> callback) noexcept override;

std::shared_ptr<SourceAccessor> getFSAccessor(const StorePath & path, bool requireValidPath) override;

ref<SourceAccessor> getFSAccessor(bool requireValidPath) override;
};

} // namespace nix
Loading