Organize content addressing, use SourceAccessor with Store::addToStore

Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
This commit is contained in:
John Ericson 2023-11-04 16:25:41 -04:00
parent d19a667528
commit dfc876531f
38 changed files with 515 additions and 390 deletions

View file

@ -13,6 +13,7 @@
#include "globals.hh" #include "globals.hh"
#include "store-api.hh" #include "store-api.hh"
#include "crypto.hh" #include "crypto.hh"
#include "posix-source-accessor.hh"
#include <sodium.h> #include <sodium.h>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
@ -205,7 +206,10 @@ void importPaths(int fd, int dontCheckSigs)
SV * hashPath(char * algo, int base32, char * path) SV * hashPath(char * algo, int base32, char * path)
PPCODE: PPCODE:
try { try {
Hash h = hashPath(parseHashAlgo(algo), path).first; PosixSourceAccessor accessor;
Hash h = hashPath(
accessor, CanonPath::fromCwd(path),
FileIngestionMethod::Recursive, parseHashAlgo(algo)).first;
auto s = h.to_string(base32 ? HashFormat::Nix32 : HashFormat::Base16, false); auto s = h.to_string(base32 ? HashFormat::Nix32 : HashFormat::Base16, false);
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0))); XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
} catch (Error & e) { } catch (Error & e) {
@ -281,7 +285,11 @@ SV * addToStore(char * srcPath, int recursive, char * algo)
PPCODE: PPCODE:
try { try {
auto method = recursive ? FileIngestionMethod::Recursive : FileIngestionMethod::Flat; auto method = recursive ? FileIngestionMethod::Recursive : FileIngestionMethod::Flat;
auto path = store()->addToStore(std::string(baseNameOf(srcPath)), srcPath, method, parseHashAlgo(algo)); PosixSourceAccessor accessor;
auto path = store()->addToStore(
std::string(baseNameOf(srcPath)),
accessor, CanonPath::fromCwd(srcPath),
method, parseHashAlgo(algo));
XPUSHs(sv_2mortal(newSVpv(store()->printStorePath(path).c_str(), 0))); XPUSHs(sv_2mortal(newSVpv(store()->printStorePath(path).c_str(), 0)));
} catch (Error & e) { } catch (Error & e) {
croak("%s", e.what()); croak("%s", e.what());

View file

@ -44,7 +44,7 @@ ref<InstallableValue> InstallableValue::require(ref<Installable> installable)
std::optional<DerivedPathWithInfo> InstallableValue::trySinglePathToDerivedPaths(Value & v, const PosIdx pos, std::string_view errorCtx) std::optional<DerivedPathWithInfo> InstallableValue::trySinglePathToDerivedPaths(Value & v, const PosIdx pos, std::string_view errorCtx)
{ {
if (v.type() == nPath) { if (v.type() == nPath) {
auto storePath = v.path().fetchToStore(state->store); auto storePath = v.path().fetchToStore(*state->store);
return {{ return {{
.path = DerivedPath::Opaque { .path = DerivedPath::Opaque {
.path = std::move(storePath), .path = std::move(storePath),

View file

@ -2317,7 +2317,7 @@ StorePath EvalState::copyPathToStore(NixStringContext & context, const SourcePat
auto dstPath = i != srcToStore.end() auto dstPath = i != srcToStore.end()
? i->second ? i->second
: [&]() { : [&]() {
auto dstPath = path.fetchToStore(store, path.baseName(), FileIngestionMethod::Recursive, nullptr, repair); auto dstPath = path.fetchToStore(*store, path.baseName(), FileIngestionMethod::Recursive, nullptr, repair);
allowPath(dstPath); allowPath(dstPath);
srcToStore.insert_or_assign(path, dstPath); srcToStore.insert_or_assign(path, dstPath);
printMsg(lvlChatty, "copied source '%1%' -> '%2%'", path, store->printStorePath(dstPath)); printMsg(lvlChatty, "copied source '%1%' -> '%2%'", path, store->printStorePath(dstPath));

View file

@ -2229,7 +2229,7 @@ static void addPath(
}); });
if (!expectedHash || !state.store->isValidPath(*expectedStorePath)) { if (!expectedHash || !state.store->isValidPath(*expectedStorePath)) {
auto dstPath = path.fetchToStore(state.store, name, method, filter.get(), state.repair); auto dstPath = path.fetchToStore(*state.store, name, method, filter.get(), state.repair);
if (expectedHash && expectedStorePath != dstPath) if (expectedHash && expectedStorePath != dstPath)
state.debugThrowLastTrace(Error("store path mismatch in (possibly filtered) path added from '%s'", path)); state.debugThrowLastTrace(Error("store path mismatch in (possibly filtered) path added from '%s'", path));
state.allowAndSetStorePathString(dstPath, v); state.allowAndSetStorePathString(dstPath, v);

View file

@ -106,7 +106,7 @@ struct CacheImpl : Cache
} }
void add( void add(
ref<Store> store, Store & store,
const Attrs & inAttrs, const Attrs & inAttrs,
const Attrs & infoAttrs, const Attrs & infoAttrs,
const StorePath & storePath, const StorePath & storePath,
@ -115,13 +115,13 @@ struct CacheImpl : Cache
_state.lock()->add.use() _state.lock()->add.use()
(attrsToJSON(inAttrs).dump()) (attrsToJSON(inAttrs).dump())
(attrsToJSON(infoAttrs).dump()) (attrsToJSON(infoAttrs).dump())
(store->printStorePath(storePath)) (store.printStorePath(storePath))
(locked) (locked)
(time(0)).exec(); (time(0)).exec();
} }
std::optional<std::pair<Attrs, StorePath>> lookup( std::optional<std::pair<Attrs, StorePath>> lookup(
ref<Store> store, Store & store,
const Attrs & inAttrs) override const Attrs & inAttrs) override
{ {
if (auto res = lookupExpired(store, inAttrs)) { if (auto res = lookupExpired(store, inAttrs)) {
@ -134,7 +134,7 @@ struct CacheImpl : Cache
} }
std::optional<Result> lookupExpired( std::optional<Result> lookupExpired(
ref<Store> store, Store & store,
const Attrs & inAttrs) override const Attrs & inAttrs) override
{ {
auto state(_state.lock()); auto state(_state.lock());
@ -148,19 +148,19 @@ struct CacheImpl : Cache
} }
auto infoJSON = stmt.getStr(0); auto infoJSON = stmt.getStr(0);
auto storePath = store->parseStorePath(stmt.getStr(1)); auto storePath = store.parseStorePath(stmt.getStr(1));
auto locked = stmt.getInt(2) != 0; auto locked = stmt.getInt(2) != 0;
auto timestamp = stmt.getInt(3); auto timestamp = stmt.getInt(3);
store->addTempRoot(storePath); store.addTempRoot(storePath);
if (!store->isValidPath(storePath)) { if (!store.isValidPath(storePath)) {
// FIXME: we could try to substitute 'storePath'. // FIXME: we could try to substitute 'storePath'.
debug("ignoring disappeared cache entry '%s'", inAttrsJSON); debug("ignoring disappeared cache entry '%s'", inAttrsJSON);
return {}; return {};
} }
debug("using cache entry '%s' -> '%s', '%s'", debug("using cache entry '%s' -> '%s', '%s'",
inAttrsJSON, infoJSON, store->printStorePath(storePath)); inAttrsJSON, infoJSON, store.printStorePath(storePath));
return Result { return Result {
.expired = !locked && (settings.tarballTtl.get() == 0 || timestamp + settings.tarballTtl < time(0)), .expired = !locked && (settings.tarballTtl.get() == 0 || timestamp + settings.tarballTtl < time(0)),

View file

@ -50,14 +50,14 @@ struct Cache
/* Old cache for things that have a store path. */ /* Old cache for things that have a store path. */
virtual void add( virtual void add(
ref<Store> store, Store & store,
const Attrs & inAttrs, const Attrs & inAttrs,
const Attrs & infoAttrs, const Attrs & infoAttrs,
const StorePath & storePath, const StorePath & storePath,
bool locked) = 0; bool locked) = 0;
virtual std::optional<std::pair<Attrs, StorePath>> lookup( virtual std::optional<std::pair<Attrs, StorePath>> lookup(
ref<Store> store, Store & store,
const Attrs & inAttrs) = 0; const Attrs & inAttrs) = 0;
struct Result struct Result
@ -68,7 +68,7 @@ struct Cache
}; };
virtual std::optional<Result> lookupExpired( virtual std::optional<Result> lookupExpired(
ref<Store> store, Store & store,
const Attrs & inAttrs) = 0; const Attrs & inAttrs) = 0;
}; };

View file

@ -374,7 +374,7 @@ void InputScheme::clone(const Input & input, const Path & destDir) const
std::pair<StorePath, Input> InputScheme::fetch(ref<Store> store, const Input & input) std::pair<StorePath, Input> InputScheme::fetch(ref<Store> store, const Input & input)
{ {
auto [accessor, input2] = getAccessor(store, input); auto [accessor, input2] = getAccessor(store, input);
auto storePath = SourcePath(accessor).fetchToStore(store, input2.getName()); auto storePath = SourcePath(accessor).fetchToStore(*store, input2.getName());
return {storePath, input2}; return {storePath, input2};
} }

View file

@ -368,14 +368,14 @@ struct GitInputScheme : InputScheme
RepoInfo getRepoInfo(const Input & input) const RepoInfo getRepoInfo(const Input & input) const
{ {
auto checkHashType = [&](const std::optional<Hash> & hash) auto checkHashAlgorithm = [&](const std::optional<Hash> & hash)
{ {
if (hash.has_value() && !(hash->algo == HashAlgorithm::SHA1 || hash->algo == HashAlgorithm::SHA256)) if (hash.has_value() && !(hash->algo == HashAlgorithm::SHA1 || hash->algo == HashAlgorithm::SHA256))
throw Error("Hash '%s' is not supported by Git. Supported types are sha1 and sha256.", hash->to_string(HashFormat::Base16, true)); throw Error("Hash '%s' is not supported by Git. Supported types are sha1 and sha256.", hash->to_string(HashFormat::Base16, true));
}; };
if (auto rev = input.getRev()) if (auto rev = input.getRev())
checkHashType(rev); checkHashAlgorithm(rev);
RepoInfo repoInfo; RepoInfo repoInfo;

View file

@ -201,7 +201,7 @@ struct GitArchiveInputScheme : InputScheme
{"rev", rev->gitRev()}, {"rev", rev->gitRev()},
}); });
if (auto res = getCache()->lookup(store, lockedAttrs)) { if (auto res = getCache()->lookup(*store, lockedAttrs)) {
input.attrs.insert_or_assign("lastModified", getIntAttr(res->first, "lastModified")); input.attrs.insert_or_assign("lastModified", getIntAttr(res->first, "lastModified"));
return {std::move(res->second), input}; return {std::move(res->second), input};
} }
@ -213,7 +213,7 @@ struct GitArchiveInputScheme : InputScheme
input.attrs.insert_or_assign("lastModified", uint64_t(result.lastModified)); input.attrs.insert_or_assign("lastModified", uint64_t(result.lastModified));
getCache()->add( getCache()->add(
store, *store,
lockedAttrs, lockedAttrs,
{ {
{"rev", rev->gitRev()}, {"rev", rev->gitRev()},

View file

@ -5,10 +5,10 @@
namespace nix { namespace nix {
StorePath InputAccessor::fetchToStore( StorePath InputAccessor::fetchToStore(
ref<Store> store, Store & store,
const CanonPath & path, const CanonPath & path,
std::string_view name, std::string_view name,
FileIngestionMethod method, ContentAddressMethod method,
PathFilter * filter, PathFilter * filter,
RepairFlag repair) RepairFlag repair)
{ {
@ -20,10 +20,24 @@ StorePath InputAccessor::fetchToStore(
if (!filter && fingerprint) { if (!filter && fingerprint) {
cacheKey = fetchers::Attrs{ cacheKey = fetchers::Attrs{
{"_what", "fetchToStore"}, {"_what", "fetchToStore"},
{"store", store->storeDir}, {"store", store.storeDir},
{"name", std::string(name)}, {"name", std::string(name)},
{"fingerprint", *fingerprint}, {"fingerprint", *fingerprint},
{"method", (uint8_t) method}, {
"method",
std::visit(overloaded {
[](const TextIngestionMethod &) {
return "text";
},
[](const FileIngestionMethod & fim) {
switch (fim) {
case FileIngestionMethod::Flat: return "flat";
case FileIngestionMethod::Recursive: return "nar";
default: assert(false);
}
},
}, method.raw),
},
{"path", path.abs()} {"path", path.abs()}
}; };
if (auto res = fetchers::getCache()->lookup(store, *cacheKey)) { if (auto res = fetchers::getCache()->lookup(store, *cacheKey)) {
@ -35,17 +49,14 @@ StorePath InputAccessor::fetchToStore(
Activity act(*logger, lvlChatty, actUnknown, fmt("copying '%s' to the store", showPath(path))); Activity act(*logger, lvlChatty, actUnknown, fmt("copying '%s' to the store", showPath(path)));
auto source = sinkToSource([&](Sink & sink) { auto filter2 = filter ? *filter : defaultPathFilter;
if (method == FileIngestionMethod::Recursive)
dumpPath(path, sink, filter ? *filter : defaultPathFilter);
else
readFile(path, sink);
});
auto storePath = auto storePath =
settings.readOnlyMode settings.readOnlyMode
? store->computeStorePathFromDump(*source, name, method, HashAlgorithm::SHA256).first ? store.computeStorePath(
: store->addToStoreFromDump(*source, name, method, HashAlgorithm::SHA256, repair); name, *this, path, method, HashAlgorithm::SHA256, {}, filter2).first
: store.addToStore(
name, *this, path, method, HashAlgorithm::SHA256, {}, filter2, repair);
if (cacheKey) if (cacheKey)
fetchers::getCache()->add(store, *cacheKey, {}, storePath, true); fetchers::getCache()->add(store, *cacheKey, {}, storePath, true);
@ -60,9 +71,9 @@ std::ostream & operator << (std::ostream & str, const SourcePath & path)
} }
StorePath SourcePath::fetchToStore( StorePath SourcePath::fetchToStore(
ref<Store> store, Store & store,
std::string_view name, std::string_view name,
FileIngestionMethod method, ContentAddressMethod method,
PathFilter * filter, PathFilter * filter,
RepairFlag repair) const RepairFlag repair) const
{ {

View file

@ -30,10 +30,10 @@ struct InputAccessor : virtual SourceAccessor, std::enable_shared_from_this<Inpu
} }
StorePath fetchToStore( StorePath fetchToStore(
ref<Store> store, Store & store,
const CanonPath & path, const CanonPath & path,
std::string_view name = "source", std::string_view name = "source",
FileIngestionMethod method = FileIngestionMethod::Recursive, ContentAddressMethod method = FileIngestionMethod::Recursive,
PathFilter * filter = nullptr, PathFilter * filter = nullptr,
RepairFlag repair = NoRepair); RepairFlag repair = NoRepair);
}; };
@ -116,9 +116,9 @@ struct SourcePath
* Copy this `SourcePath` to the Nix store. * Copy this `SourcePath` to the Nix store.
*/ */
StorePath fetchToStore( StorePath fetchToStore(
ref<Store> store, Store & store,
std::string_view name = "source", std::string_view name = "source",
FileIngestionMethod method = FileIngestionMethod::Recursive, ContentAddressMethod method = FileIngestionMethod::Recursive,
PathFilter * filter = nullptr, PathFilter * filter = nullptr,
RepairFlag repair = NoRepair) const; RepairFlag repair = NoRepair) const;

View file

@ -6,6 +6,7 @@
#include "tarfile.hh" #include "tarfile.hh"
#include "store-api.hh" #include "store-api.hh"
#include "url-parts.hh" #include "url-parts.hh"
#include "posix-source-accessor.hh"
#include "fetch-settings.hh" #include "fetch-settings.hh"
@ -210,7 +211,12 @@ struct MercurialInputScheme : InputScheme
return files.count(file); return files.count(file);
}; };
auto storePath = store->addToStore(input.getName(), actualPath, FileIngestionMethod::Recursive, HashAlgorithm::SHA256, filter); PosixSourceAccessor accessor;
auto storePath = store->addToStore(
input.getName(),
accessor, CanonPath { actualPath },
FileIngestionMethod::Recursive, HashAlgorithm::SHA256, {},
filter);
return {std::move(storePath), input}; return {std::move(storePath), input};
} }
@ -218,7 +224,7 @@ struct MercurialInputScheme : InputScheme
if (!input.getRef()) input.attrs.insert_or_assign("ref", "default"); if (!input.getRef()) input.attrs.insert_or_assign("ref", "default");
auto checkHashType = [&](const std::optional<Hash> & hash) auto checkHashAlgorithm = [&](const std::optional<Hash> & hash)
{ {
if (hash.has_value() && hash->algo != HashAlgorithm::SHA1) if (hash.has_value() && hash->algo != HashAlgorithm::SHA1)
throw Error("Hash '%s' is not supported by Mercurial. Only sha1 is supported.", hash->to_string(HashFormat::Base16, true)); throw Error("Hash '%s' is not supported by Mercurial. Only sha1 is supported.", hash->to_string(HashFormat::Base16, true));
@ -227,7 +233,7 @@ struct MercurialInputScheme : InputScheme
auto getLockedAttrs = [&]() auto getLockedAttrs = [&]()
{ {
checkHashType(input.getRev()); checkHashAlgorithm(input.getRev());
return Attrs({ return Attrs({
{"type", "hg"}, {"type", "hg"},
@ -246,7 +252,7 @@ struct MercurialInputScheme : InputScheme
}; };
if (input.getRev()) { if (input.getRev()) {
if (auto res = getCache()->lookup(store, getLockedAttrs())) if (auto res = getCache()->lookup(*store, getLockedAttrs()))
return makeResult(res->first, std::move(res->second)); return makeResult(res->first, std::move(res->second));
} }
@ -259,7 +265,7 @@ struct MercurialInputScheme : InputScheme
{"ref", *input.getRef()}, {"ref", *input.getRef()},
}); });
if (auto res = getCache()->lookup(store, unlockedAttrs)) { if (auto res = getCache()->lookup(*store, unlockedAttrs)) {
auto rev2 = Hash::parseAny(getStrAttr(res->first, "rev"), HashAlgorithm::SHA1); auto rev2 = Hash::parseAny(getStrAttr(res->first, "rev"), HashAlgorithm::SHA1);
if (!input.getRev() || input.getRev() == rev2) { if (!input.getRev() || input.getRev() == rev2) {
input.attrs.insert_or_assign("rev", rev2.gitRev()); input.attrs.insert_or_assign("rev", rev2.gitRev());
@ -305,7 +311,7 @@ struct MercurialInputScheme : InputScheme
auto revCount = std::stoull(tokens[1]); auto revCount = std::stoull(tokens[1]);
input.attrs.insert_or_assign("ref", tokens[2]); input.attrs.insert_or_assign("ref", tokens[2]);
if (auto res = getCache()->lookup(store, getLockedAttrs())) if (auto res = getCache()->lookup(*store, getLockedAttrs()))
return makeResult(res->first, std::move(res->second)); return makeResult(res->first, std::move(res->second));
Path tmpDir = createTempDir(); Path tmpDir = createTempDir();
@ -315,7 +321,8 @@ struct MercurialInputScheme : InputScheme
deletePath(tmpDir + "/.hg_archival.txt"); deletePath(tmpDir + "/.hg_archival.txt");
auto storePath = store->addToStore(name, tmpDir); PosixSourceAccessor accessor;
auto storePath = store->addToStore(name, accessor, CanonPath { tmpDir });
Attrs infoAttrs({ Attrs infoAttrs({
{"rev", input.getRev()->gitRev()}, {"rev", input.getRev()->gitRev()},
@ -324,14 +331,14 @@ struct MercurialInputScheme : InputScheme
if (!_input.getRev()) if (!_input.getRev())
getCache()->add( getCache()->add(
store, *store,
unlockedAttrs, unlockedAttrs,
infoAttrs, infoAttrs,
storePath, storePath,
false); false);
getCache()->add( getCache()->add(
store, *store,
getLockedAttrs(), getLockedAttrs(),
infoAttrs, infoAttrs,
storePath, storePath,

View file

@ -8,6 +8,7 @@
#include "tarfile.hh" #include "tarfile.hh"
#include "types.hh" #include "types.hh"
#include "split.hh" #include "split.hh"
#include "posix-source-accessor.hh"
namespace nix::fetchers { namespace nix::fetchers {
@ -26,7 +27,7 @@ DownloadFileResult downloadFile(
{"name", name}, {"name", name},
}); });
auto cached = getCache()->lookupExpired(store, inAttrs); auto cached = getCache()->lookupExpired(*store, inAttrs);
auto useCached = [&]() -> DownloadFileResult auto useCached = [&]() -> DownloadFileResult
{ {
@ -91,7 +92,7 @@ DownloadFileResult downloadFile(
} }
getCache()->add( getCache()->add(
store, *store,
inAttrs, inAttrs,
infoAttrs, infoAttrs,
*storePath, *storePath,
@ -99,7 +100,7 @@ DownloadFileResult downloadFile(
if (url != res.effectiveUri) if (url != res.effectiveUri)
getCache()->add( getCache()->add(
store, *store,
{ {
{"type", "file"}, {"type", "file"},
{"url", res.effectiveUri}, {"url", res.effectiveUri},
@ -130,7 +131,7 @@ DownloadTarballResult downloadTarball(
{"name", name}, {"name", name},
}); });
auto cached = getCache()->lookupExpired(store, inAttrs); auto cached = getCache()->lookupExpired(*store, inAttrs);
if (cached && !cached->expired) if (cached && !cached->expired)
return { return {
@ -156,7 +157,8 @@ DownloadTarballResult downloadTarball(
throw nix::Error("tarball '%s' contains an unexpected number of top-level files", url); throw nix::Error("tarball '%s' contains an unexpected number of top-level files", url);
auto topDir = tmpDir + "/" + members.begin()->name; auto topDir = tmpDir + "/" + members.begin()->name;
lastModified = lstat(topDir).st_mtime; lastModified = lstat(topDir).st_mtime;
unpackedStorePath = store->addToStore(name, topDir, FileIngestionMethod::Recursive, HashAlgorithm::SHA256, defaultPathFilter, NoRepair); PosixSourceAccessor accessor;
unpackedStorePath = store->addToStore(name, accessor, CanonPath { topDir }, FileIngestionMethod::Recursive, HashAlgorithm::SHA256, {}, defaultPathFilter, NoRepair);
} }
Attrs infoAttrs({ Attrs infoAttrs({
@ -168,7 +170,7 @@ DownloadTarballResult downloadTarball(
infoAttrs.emplace("immutableUrl", *res.immutableUrl); infoAttrs.emplace("immutableUrl", *res.immutableUrl);
getCache()->add( getCache()->add(
store, *store,
inAttrs, inAttrs,
infoAttrs, infoAttrs,
*unpackedStorePath, *unpackedStorePath,

View file

@ -300,8 +300,13 @@ void BinaryCacheStore::addToStore(const ValidPathInfo & info, Source & narSource
}}); }});
} }
StorePath BinaryCacheStore::addToStoreFromDump(Source & dump, std::string_view name, StorePath BinaryCacheStore::addToStoreFromDump(
FileIngestionMethod method, HashAlgorithm hashAlgo, RepairFlag repair, const StorePathSet & references) Source & dump,
std::string_view name,
ContentAddressMethod method,
HashAlgorithm hashAlgo,
const StorePathSet & references,
RepairFlag repair)
{ {
if (method != FileIngestionMethod::Recursive || hashAlgo != HashAlgorithm::SHA256) if (method != FileIngestionMethod::Recursive || hashAlgo != HashAlgorithm::SHA256)
unsupported("addToStoreFromDump"); unsupported("addToStoreFromDump");
@ -309,15 +314,14 @@ StorePath BinaryCacheStore::addToStoreFromDump(Source & dump, std::string_view n
ValidPathInfo info { ValidPathInfo info {
*this, *this,
name, name,
FixedOutputInfo { ContentAddressWithReferences::fromParts(
.method = method, method,
.hash = nar.first, nar.first,
.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
.self = false, .self = false,
}, }),
},
nar.first, nar.first,
}; };
info.narSize = nar.second; info.narSize = nar.second;
@ -400,41 +404,35 @@ void BinaryCacheStore::queryPathInfoUncached(const StorePath & storePath,
StorePath BinaryCacheStore::addToStore( StorePath BinaryCacheStore::addToStore(
std::string_view name, std::string_view name,
const Path & srcPath, SourceAccessor & accessor,
FileIngestionMethod method, const CanonPath & path,
ContentAddressMethod method,
HashAlgorithm hashAlgo, HashAlgorithm hashAlgo,
const StorePathSet & references,
PathFilter & filter, PathFilter & filter,
RepairFlag repair, RepairFlag repair)
const StorePathSet & references)
{ {
/* FIXME: Make BinaryCacheStore::addToStoreCommon support /* FIXME: Make BinaryCacheStore::addToStoreCommon support
non-recursive+sha256 so we can just use the default non-recursive+sha256 so we can just use the default
implementation of this method in terms of addToStoreFromDump. */ implementation of this method in terms of addToStoreFromDump. */
HashSink sink { hashAlgo }; auto h = hashPath(accessor, path, method.getFileIngestionMethod(), hashAlgo, filter).first;
if (method == FileIngestionMethod::Recursive) {
dumpPath(srcPath, sink, filter);
} else {
readFile(srcPath, sink);
}
auto h = sink.finish().first;
auto source = sinkToSource([&](Sink & sink) { auto source = sinkToSource([&](Sink & sink) {
dumpPath(srcPath, sink, filter); accessor.dumpPath(path, sink, filter);
}); });
return addToStoreCommon(*source, repair, CheckSigs, [&](HashResult nar) { return addToStoreCommon(*source, repair, CheckSigs, [&](HashResult nar) {
ValidPathInfo info { ValidPathInfo info {
*this, *this,
name, name,
FixedOutputInfo { ContentAddressWithReferences::fromParts(
.method = method, method,
.hash = h, h,
.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
.self = false, .self = false,
}, }),
},
nar.first, nar.first,
}; };
info.narSize = nar.second; info.narSize = nar.second;

View file

@ -123,17 +123,23 @@ public:
void addToStore(const ValidPathInfo & info, Source & narSource, void addToStore(const ValidPathInfo & info, Source & narSource,
RepairFlag repair, CheckSigsFlag checkSigs) override; RepairFlag repair, CheckSigsFlag checkSigs) override;
StorePath addToStoreFromDump(Source & dump, std::string_view name, StorePath addToStoreFromDump(
FileIngestionMethod method, HashAlgorithm hashAlgo, RepairFlag repair, const StorePathSet & references) override; Source & dump,
std::string_view name,
ContentAddressMethod method,
HashAlgorithm hashAlgo,
const StorePathSet & references,
RepairFlag repair) override;
StorePath addToStore( StorePath addToStore(
std::string_view name, std::string_view name,
const Path & srcPath, SourceAccessor & accessor,
FileIngestionMethod method, const CanonPath & srcPath,
ContentAddressMethod method,
HashAlgorithm hashAlgo, HashAlgorithm hashAlgo,
const StorePathSet & references,
PathFilter & filter, PathFilter & filter,
RepairFlag repair, RepairFlag repair) override;
const StorePathSet & references) override;
StorePath addTextToStore( StorePath addTextToStore(
std::string_view name, std::string_view name,

View file

@ -20,6 +20,7 @@
#include "child.hh" #include "child.hh"
#include "unix-domain-socket.hh" #include "unix-domain-socket.hh"
#include "posix-fs-canonicalise.hh" #include "posix-fs-canonicalise.hh"
#include "posix-source-accessor.hh"
#include <regex> #include <regex>
#include <queue> #include <queue>
@ -1291,12 +1292,13 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual In
StorePath addToStore( StorePath addToStore(
std::string_view name, std::string_view name,
const Path & srcPath, SourceAccessor & accessor,
FileIngestionMethod method, const CanonPath & srcPath,
ContentAddressMethod method,
HashAlgorithm hashAlgo, HashAlgorithm hashAlgo,
const StorePathSet & references,
PathFilter & filter, PathFilter & filter,
RepairFlag repair, RepairFlag repair) override
const StorePathSet & references) override
{ throw Error("addToStore"); } { throw Error("addToStore"); }
void addToStore(const ValidPathInfo & info, Source & narSource, void addToStore(const ValidPathInfo & info, Source & narSource,
@ -1320,12 +1322,12 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual In
StorePath addToStoreFromDump( StorePath addToStoreFromDump(
Source & dump, Source & dump,
std::string_view name, std::string_view name,
FileIngestionMethod method, ContentAddressMethod method,
HashAlgorithm hashAlgo, HashAlgorithm hashAlgo,
RepairFlag repair, const StorePathSet & references,
const StorePathSet & references) override RepairFlag repair) override
{ {
auto path = next->addToStoreFromDump(dump, name, method, hashAlgo, repair, references); auto path = next->addToStoreFromDump(dump, name, method, hashAlgo, references, repair);
goal.addDependency(path); goal.addDependency(path);
return path; return path;
} }
@ -2453,8 +2455,7 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
throw BuildError( throw BuildError(
"output path %1% without valid stats info", "output path %1% without valid stats info",
actualPath); actualPath);
if (outputHash.method == ContentAddressMethod { FileIngestionMethod::Flat } || if (outputHash.method.getFileIngestionMethod() == FileIngestionMethod::Flat)
outputHash.method == ContentAddressMethod { TextIngestionMethod {} })
{ {
/* The output path should be a regular file without execute permission. */ /* The output path should be a regular file without execute permission. */
if (!S_ISREG(st->st_mode) || (st->st_mode & S_IXUSR) != 0) if (!S_ISREG(st->st_mode) || (st->st_mode & S_IXUSR) != 0)
@ -2466,38 +2467,23 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
rewriteOutput(outputRewrites); rewriteOutput(outputRewrites);
/* FIXME optimize and deduplicate with addToStore */ /* FIXME optimize and deduplicate with addToStore */
std::string oldHashPart { scratchPath->hashPart() }; std::string oldHashPart { scratchPath->hashPart() };
auto got = ({
HashModuloSink caSink { outputHash.hashAlgo, oldHashPart }; HashModuloSink caSink { outputHash.hashAlgo, oldHashPart };
std::visit(overloaded { PosixSourceAccessor accessor;
[&](const TextIngestionMethod &) { dumpPath(
readFile(actualPath, caSink); accessor, CanonPath { actualPath },
}, caSink,
[&](const FileIngestionMethod & m2) { outputHash.method.getFileIngestionMethod());
switch (m2) { caSink.finish().first;
case FileIngestionMethod::Recursive: });
dumpPath(actualPath, caSink);
break;
case FileIngestionMethod::Flat:
readFile(actualPath, caSink);
break;
}
},
}, outputHash.method.raw);
auto got = caSink.finish().first;
auto optCA = ContentAddressWithReferences::fromPartsOpt(
outputHash.method,
std::move(got),
rewriteRefs());
if (!optCA) {
// TODO track distinct failure modes separately (at the time of
// writing there is just one but `nullopt` is unclear) so this
// message can't get out of sync.
throw BuildError("output path '%s' has illegal content address, probably a spurious self-reference with text hashing");
}
ValidPathInfo newInfo0 { ValidPathInfo newInfo0 {
worker.store, worker.store,
outputPathName(drv->name, outputName), outputPathName(drv->name, outputName),
std::move(*optCA), ContentAddressWithReferences::fromParts(
outputHash.method,
std::move(got),
rewriteRefs()),
Hash::dummy, Hash::dummy,
}; };
if (*scratchPath != newInfo0.path) { if (*scratchPath != newInfo0.path) {
@ -2511,9 +2497,14 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
std::string(newInfo0.path.hashPart())}}); std::string(newInfo0.path.hashPart())}});
} }
HashResult narHashAndSize = hashPath(HashAlgorithm::SHA256, actualPath); {
PosixSourceAccessor accessor;
HashResult narHashAndSize = hashPath(
accessor, CanonPath { actualPath },
FileIngestionMethod::Recursive, HashAlgorithm::SHA256);
newInfo0.narHash = narHashAndSize.first; newInfo0.narHash = narHashAndSize.first;
newInfo0.narSize = narHashAndSize.second; newInfo0.narSize = narHashAndSize.second;
}
assert(newInfo0.ca); assert(newInfo0.ca);
return newInfo0; return newInfo0;
@ -2531,7 +2522,10 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
std::string { scratchPath->hashPart() }, std::string { scratchPath->hashPart() },
std::string { requiredFinalPath.hashPart() }); std::string { requiredFinalPath.hashPart() });
rewriteOutput(outputRewrites); rewriteOutput(outputRewrites);
auto narHashAndSize = hashPath(HashAlgorithm::SHA256, actualPath); PosixSourceAccessor accessor;
HashResult narHashAndSize = hashPath(
accessor, CanonPath { actualPath },
FileIngestionMethod::Recursive, HashAlgorithm::SHA256);
ValidPathInfo newInfo0 { requiredFinalPath, narHashAndSize.first }; ValidPathInfo newInfo0 { requiredFinalPath, narHashAndSize.first };
newInfo0.narSize = narHashAndSize.second; newInfo0.narSize = narHashAndSize.second;
auto refs = rewriteRefs(); auto refs = rewriteRefs();

View file

@ -519,7 +519,9 @@ bool Worker::pathContentsGood(const StorePath & path)
if (!pathExists(store.printStorePath(path))) if (!pathExists(store.printStorePath(path)))
res = false; res = false;
else { else {
HashResult current = hashPath(info->narHash.algo, store.printStorePath(path)); HashResult current = hashPath(
*store.getFSAccessor(), CanonPath { store.printStorePath(path) },
FileIngestionMethod::Recursive, info->narHash.algo);
Hash nullHash(HashAlgorithm::SHA256); Hash nullHash(HashAlgorithm::SHA256);
res = info->narHash == nullHash || info->narHash == current.first; res = info->narHash == nullHash || info->narHash == current.first;
} }

View file

@ -50,6 +50,18 @@ std::string ContentAddressMethod::render(HashAlgorithm ha) const
}, raw); }, raw);
} }
FileIngestionMethod ContentAddressMethod::getFileIngestionMethod() const
{
return std::visit(overloaded {
[&](const TextIngestionMethod & th) {
return FileIngestionMethod::Flat;
},
[&](const FileIngestionMethod & fim) {
return fim;
}
}, raw);
}
std::string ContentAddress::render() const std::string ContentAddress::render() const
{ {
return std::visit(overloaded { return std::visit(overloaded {
@ -79,7 +91,7 @@ static std::pair<ContentAddressMethod, HashAlgorithm> parseContentAddressMethodP
prefix = *optPrefix; prefix = *optPrefix;
} }
auto parseHashType_ = [&](){ auto parseHashAlgorithm_ = [&](){
auto hashTypeRaw = splitPrefixTo(rest, ':'); auto hashTypeRaw = splitPrefixTo(rest, ':');
if (!hashTypeRaw) if (!hashTypeRaw)
throw UsageError("content address hash must be in form '<algo>:<hash>', but found: %s", wholeInput); throw UsageError("content address hash must be in form '<algo>:<hash>', but found: %s", wholeInput);
@ -90,7 +102,7 @@ static std::pair<ContentAddressMethod, HashAlgorithm> parseContentAddressMethodP
// Switch on prefix // Switch on prefix
if (prefix == "text") { if (prefix == "text") {
// No parsing of the ingestion method, "text" only support flat. // No parsing of the ingestion method, "text" only support flat.
HashAlgorithm hashAlgo = parseHashType_(); HashAlgorithm hashAlgo = parseHashAlgorithm_();
return { return {
TextIngestionMethod {}, TextIngestionMethod {},
std::move(hashAlgo), std::move(hashAlgo),
@ -100,7 +112,7 @@ static std::pair<ContentAddressMethod, HashAlgorithm> parseContentAddressMethodP
auto method = FileIngestionMethod::Flat; auto method = FileIngestionMethod::Flat;
if (splitPrefix(rest, "r:")) if (splitPrefix(rest, "r:"))
method = FileIngestionMethod::Recursive; method = FileIngestionMethod::Recursive;
HashAlgorithm hashAlgo = parseHashType_(); HashAlgorithm hashAlgo = parseHashAlgorithm_();
return { return {
std::move(method), std::move(method),
std::move(hashAlgo), std::move(hashAlgo),
@ -176,13 +188,13 @@ ContentAddressWithReferences ContentAddressWithReferences::withoutRefs(const Con
}, ca.method.raw); }, ca.method.raw);
} }
std::optional<ContentAddressWithReferences> ContentAddressWithReferences::fromPartsOpt( ContentAddressWithReferences ContentAddressWithReferences::fromParts(
ContentAddressMethod method, Hash hash, StoreReferences refs) noexcept ContentAddressMethod method, Hash hash, StoreReferences refs)
{ {
return std::visit(overloaded { return std::visit(overloaded {
[&](TextIngestionMethod _) -> std::optional<ContentAddressWithReferences> { [&](TextIngestionMethod _) -> ContentAddressWithReferences {
if (refs.self) if (refs.self)
return std::nullopt; throw Error("self-reference not allowed with text hashing");
return ContentAddressWithReferences { return ContentAddressWithReferences {
TextInfo { TextInfo {
.hash = std::move(hash), .hash = std::move(hash),
@ -190,7 +202,7 @@ std::optional<ContentAddressWithReferences> ContentAddressWithReferences::fromPa
} }
}; };
}, },
[&](FileIngestionMethod m2) -> std::optional<ContentAddressWithReferences> { [&](FileIngestionMethod m2) -> ContentAddressWithReferences {
return ContentAddressWithReferences { return ContentAddressWithReferences {
FixedOutputInfo { FixedOutputInfo {
.method = m2, .method = m2,

View file

@ -4,6 +4,7 @@
#include <variant> #include <variant>
#include "hash.hh" #include "hash.hh"
#include "path.hh" #include "path.hh"
#include "file-content-address.hh"
#include "comparator.hh" #include "comparator.hh"
#include "variant-wrapper.hh" #include "variant-wrapper.hh"
@ -31,22 +32,6 @@ namespace nix {
*/ */
struct TextIngestionMethod : std::monostate { }; struct TextIngestionMethod : std::monostate { };
/**
* An enumeration of the main ways we can serialize file system
* objects.
*/
enum struct FileIngestionMethod : uint8_t {
/**
* Flat-file hashing. Directly ingest the contents of a single file
*/
Flat = 0,
/**
* Recursive (or NAR) hashing. Serializes the file-system object in Nix
* Archive format and ingest that
*/
Recursive = 1
};
/** /**
* Compute the prefix to the hash algorithm which indicates how the * Compute the prefix to the hash algorithm which indicates how the
* files were ingested. * files were ingested.
@ -54,7 +39,7 @@ enum struct FileIngestionMethod : uint8_t {
std::string makeFileIngestionPrefix(FileIngestionMethod m); std::string makeFileIngestionPrefix(FileIngestionMethod m);
/** /**
* An enumeration of all the ways we can serialize file system objects. * An enumeration of all the ways we can content-address store objects.
* *
* Just the type of a content address. Combine with the hash itself, and * Just the type of a content address. Combine with the hash itself, and
* we have a `ContentAddress` as defined below. Combine that, in turn, * we have a `ContentAddress` as defined below. Combine that, in turn,
@ -102,7 +87,15 @@ struct ContentAddressMethod
* *
* The rough inverse of `parse()`. * The rough inverse of `parse()`.
*/ */
std::string render(HashAlgorithm ha) const; std::string render(HashAlgorithm ht) const;
/**
* Get the underlying way to content-address file system objects.
*
* Different ways of hashing store objects may use the same method
* for hashing file systeme objects.
*/
FileIngestionMethod getFileIngestionMethod() const;
}; };
@ -266,11 +259,12 @@ struct ContentAddressWithReferences
* *
* @param refs References to other store objects or oneself. * @param refs References to other store objects or oneself.
* *
* Do note that not all combinations are supported; `nullopt` is * @note note that all combinations are supported. This is a
* returns for invalid combinations. * *partial function* and exceptions will be thrown for invalid
* combinations.
*/ */
static std::optional<ContentAddressWithReferences> fromPartsOpt( static ContentAddressWithReferences fromParts(
ContentAddressMethod method, Hash hash, StoreReferences refs) noexcept; ContentAddressMethod method, Hash hash, StoreReferences refs);
ContentAddressMethod getMethod() const; ContentAddressMethod getMethod() const;

View file

@ -403,22 +403,9 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
auto [contentAddressMethod, hashAlgo_] = ContentAddressMethod::parse(camStr); auto [contentAddressMethod, hashAlgo_] = ContentAddressMethod::parse(camStr);
auto hashAlgo = hashAlgo_; // work around clang bug auto hashAlgo = hashAlgo_; // work around clang bug
FramedSource source(from); FramedSource source(from);
// TODO this is essentially RemoteStore::addCAToStore. Move it up to Store. // TODO these two steps are essentially RemoteStore::addCAToStore. Move it up to Store.
return std::visit(overloaded { auto path = store->addToStoreFromDump(source, name, contentAddressMethod, hashAlgo, refs, repair);
[&](const TextIngestionMethod &) {
if (hashAlgo != HashAlgorithm::SHA256)
throw UnimplementedError("When adding text-hashed data called '%s', only SHA-256 is supported but '%s' was given",
name, printHashAlgo(hashAlgo));
// We could stream this by changing Store
std::string contents = source.drain();
auto path = store->addTextToStore(name, contents, refs, repair);
return store->queryPathInfo(path); return store->queryPathInfo(path);
},
[&](const FileIngestionMethod & fim) {
auto path = store->addToStoreFromDump(source, name, fim, hashAlgo, repair, refs);
return store->queryPathInfo(path);
},
}, contentAddressMethod.raw);
}(); }();
logger->stopWork(); logger->stopWork();

View file

@ -60,12 +60,13 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor
StorePath addToStore( StorePath addToStore(
std::string_view name, std::string_view name,
const Path & srcPath, SourceAccessor & accessor,
FileIngestionMethod method, const CanonPath & srcPath,
ContentAddressMethod method,
HashAlgorithm hashAlgo, HashAlgorithm hashAlgo,
const StorePathSet & references,
PathFilter & filter, PathFilter & filter,
RepairFlag repair, RepairFlag repair) override
const StorePathSet & references) override
{ unsupported("addToStore"); } { unsupported("addToStore"); }
StorePath addTextToStore( StorePath addTextToStore(

View file

@ -13,6 +13,7 @@
#include "compression.hh" #include "compression.hh"
#include "signals.hh" #include "signals.hh"
#include "posix-fs-canonicalise.hh" #include "posix-fs-canonicalise.hh"
#include "posix-source-accessor.hh"
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
@ -1088,11 +1089,22 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
if (info.ca) { if (info.ca) {
auto & specified = *info.ca; auto & specified = *info.ca;
auto actualHash = hashCAPath( auto actualHash = ({
specified.method, HashModuloSink caSink {
specified.hash.algo, specified.hash.algo,
info.path std::string { info.path.hashPart() },
); };
PosixSourceAccessor accessor;
dumpPath(
*getFSAccessor(false),
CanonPath { printStorePath(info.path) },
caSink,
specified.method.getFileIngestionMethod());
ContentAddress {
.method = specified.method,
.hash = caSink.finish().first,
};
});
if (specified.hash != actualHash.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),
@ -1115,8 +1127,13 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
} }
StorePath LocalStore::addToStoreFromDump(Source & source0, std::string_view name, StorePath LocalStore::addToStoreFromDump(
FileIngestionMethod method, HashAlgorithm hashAlgo, RepairFlag repair, const StorePathSet & references) Source & source0,
std::string_view name,
ContentAddressMethod method,
HashAlgorithm hashAlgo,
const StorePathSet & references,
RepairFlag repair)
{ {
/* For computing the store path. */ /* For computing the store path. */
auto hashSink = std::make_unique<HashSink>(hashAlgo); auto hashSink = std::make_unique<HashSink>(hashAlgo);
@ -1166,25 +1183,21 @@ StorePath LocalStore::addToStoreFromDump(Source & source0, std::string_view name
delTempDir = std::make_unique<AutoDelete>(tempDir); delTempDir = std::make_unique<AutoDelete>(tempDir);
tempPath = tempDir + "/x"; tempPath = tempDir + "/x";
if (method == FileIngestionMethod::Recursive) restorePath(tempPath, bothSource, method.getFileIngestionMethod());
restorePath(tempPath, bothSource);
else
writeFile(tempPath, bothSource);
dump.clear(); dump.clear();
} }
auto [hash, size] = hashSink->finish(); auto [hash, size] = hashSink->finish();
ContentAddressWithReferences desc = FixedOutputInfo { auto desc = ContentAddressWithReferences::fromParts(
.method = method, method,
.hash = hash, hash,
.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
.self = false, .self = false,
}, });
};
auto dstPath = makeFixedOutputPathFromCA(name, desc); auto dstPath = makeFixedOutputPathFromCA(name, desc);
@ -1207,11 +1220,8 @@ StorePath LocalStore::addToStoreFromDump(Source & source0, std::string_view name
if (inMemory) { if (inMemory) {
StringSource dumpSource { dump }; StringSource dumpSource { dump };
/* Restore from the NAR in memory. */ /* Restore from the buffer in memory. */
if (method == FileIngestionMethod::Recursive) restorePath(realPath, dumpSource, method.getFileIngestionMethod());
restorePath(realPath, dumpSource);
else
writeFile(realPath, dumpSource);
} else { } else {
/* Move the temporary path we restored above. */ /* Move the temporary path we restored above. */
moveFile(tempPath, realPath); moveFile(tempPath, realPath);
@ -1389,7 +1399,10 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
for (auto & link : readDirectory(linksDir)) { for (auto & link : readDirectory(linksDir)) {
printMsg(lvlTalkative, "checking contents of '%s'", link.name); printMsg(lvlTalkative, "checking contents of '%s'", link.name);
Path linkPath = linksDir + "/" + link.name; Path linkPath = linksDir + "/" + link.name;
std::string hash = hashPath(HashAlgorithm::SHA256, linkPath).first.to_string(HashFormat::Nix32, false); PosixSourceAccessor accessor;
std::string hash = hashPath(
accessor, CanonPath { linkPath },
FileIngestionMethod::Recursive, HashAlgorithm::SHA256).first.to_string(HashFormat::Nix32, false);
if (hash != link.name) { if (hash != link.name) {
printError("link '%s' was modified! expected hash '%s', got '%s'", printError("link '%s' was modified! expected hash '%s', got '%s'",
linkPath, link.name, hash); linkPath, link.name, hash);
@ -1696,42 +1709,6 @@ void LocalStore::queryRealisationUncached(const DrvOutput & id,
} }
} }
ContentAddress LocalStore::hashCAPath(
const ContentAddressMethod & method, const HashAlgorithm & hashAlgo,
const StorePath & path)
{
return hashCAPath(method, hashAlgo, Store::toRealPath(path), path.hashPart());
}
ContentAddress LocalStore::hashCAPath(
const ContentAddressMethod & method,
const HashAlgorithm & hashAlgo,
const Path & path,
const std::string_view pathHash
)
{
HashModuloSink caSink ( hashAlgo, std::string(pathHash) );
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 = caSink.finish().first,
};
}
void LocalStore::addBuildLog(const StorePath & drvPath, std::string_view log) void LocalStore::addBuildLog(const StorePath & drvPath, std::string_view log)
{ {
assert(drvPath.isDerivation()); assert(drvPath.isDerivation());

View file

@ -177,8 +177,13 @@ public:
void addToStore(const ValidPathInfo & info, Source & source, void addToStore(const ValidPathInfo & info, Source & source,
RepairFlag repair, CheckSigsFlag checkSigs) override; RepairFlag repair, CheckSigsFlag checkSigs) override;
StorePath addToStoreFromDump(Source & dump, std::string_view name, StorePath addToStoreFromDump(
FileIngestionMethod method, HashAlgorithm hashAlgo, RepairFlag repair, const StorePathSet & references) override; Source & dump,
std::string_view name,
ContentAddressMethod method,
HashAlgorithm hashAlgo,
const StorePathSet & references,
RepairFlag repair) override;
StorePath addTextToStore( StorePath addTextToStore(
std::string_view name, std::string_view name,
@ -350,19 +355,6 @@ private:
void signPathInfo(ValidPathInfo & info); void signPathInfo(ValidPathInfo & info);
void signRealisation(Realisation &); void signRealisation(Realisation &);
// XXX: Make a generic `Store` method
ContentAddress hashCAPath(
const ContentAddressMethod & method,
const HashAlgorithm & hashAlgo,
const StorePath & path);
ContentAddress hashCAPath(
const ContentAddressMethod & method,
const HashAlgorithm & hashAlgo,
const Path & path,
const std::string_view pathHash
);
void addBuildLog(const StorePath & drvPath, std::string_view log) override; void addBuildLog(const StorePath & drvPath, std::string_view log) override;
friend struct LocalDerivationGoal; friend struct LocalDerivationGoal;

View file

@ -2,6 +2,7 @@
#include "globals.hh" #include "globals.hh"
#include "signals.hh" #include "signals.hh"
#include "posix-fs-canonicalise.hh" #include "posix-fs-canonicalise.hh"
#include "posix-source-accessor.hh"
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
@ -146,7 +147,12 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
Also note that if `path' is a symlink, then we're hashing the Also note that if `path' is a symlink, then we're hashing the
contents of the symlink (i.e. the result of readlink()), not contents of the symlink (i.e. the result of readlink()), not
the contents of the target (which may not even exist). */ the contents of the target (which may not even exist). */
Hash hash = hashPath(HashAlgorithm::SHA256, path).first; Hash hash = ({
PosixSourceAccessor accessor;
hashPath(
accessor, CanonPath { path },
FileIngestionMethod::Recursive, HashAlgorithm::SHA256).first;
});
debug("'%1%' has hash '%2%'", path, hash.to_string(HashFormat::Nix32, true)); debug("'%1%' has hash '%2%'", path, hash.to_string(HashFormat::Nix32, true));
/* Check if this is a known hash. */ /* Check if this is a known hash. */
@ -156,7 +162,12 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
if (pathExists(linkPath)) { if (pathExists(linkPath)) {
auto stLink = lstat(linkPath); auto stLink = lstat(linkPath);
if (st.st_size != stLink.st_size if (st.st_size != stLink.st_size
|| (repair && hash != hashPath(HashAlgorithm::SHA256, linkPath).first)) || (repair && hash != ({
PosixSourceAccessor accessor;
hashPath(
accessor, CanonPath { linkPath },
FileIngestionMethod::Recursive, HashAlgorithm::SHA256).first;
})))
{ {
// XXX: Consider overwriting linkPath with our valid version. // XXX: Consider overwriting linkPath with our valid version.
warn("removing corrupted link '%s'", linkPath); warn("removing corrupted link '%s'", linkPath);

View file

@ -502,8 +502,13 @@ ref<const ValidPathInfo> RemoteStore::addCAToStore(
} }
StorePath RemoteStore::addToStoreFromDump(Source & dump, std::string_view name, StorePath RemoteStore::addToStoreFromDump(
FileIngestionMethod method, HashAlgorithm hashAlgo, RepairFlag repair, const StorePathSet & references) Source & dump,
std::string_view name,
ContentAddressMethod method,
HashAlgorithm hashAlgo,
const StorePathSet & references,
RepairFlag repair)
{ {
return addCAToStore(dump, name, method, hashAlgo, references, repair)->path; return addCAToStore(dump, name, method, hashAlgo, references, repair)->path;
} }

View file

@ -82,10 +82,15 @@ public:
RepairFlag repair); RepairFlag repair);
/** /**
* Add a content-addressable store path. Does not support references. `dump` will be drained. * Add a content-addressable store path. `dump` will be drained.
*/ */
StorePath addToStoreFromDump(Source & dump, std::string_view name, StorePath addToStoreFromDump(
FileIngestionMethod method = FileIngestionMethod::Recursive, HashAlgorithm hashAlgo = HashAlgorithm::SHA256, RepairFlag repair = NoRepair, const StorePathSet & references = StorePathSet()) override; Source & dump,
std::string_view name,
ContentAddressMethod method = FileIngestionMethod::Recursive,
HashAlgorithm hashAlgo = HashAlgorithm::SHA256,
const StorePathSet & references = StorePathSet(),
RepairFlag repair = NoRepair) override;
void addToStore(const ValidPathInfo & info, Source & nar, void addToStore(const ValidPathInfo & info, Source & nar,
RepairFlag repair, CheckSigsFlag checkSigs) override; RepairFlag repair, CheckSigsFlag checkSigs) override;

View file

@ -232,22 +232,28 @@ StorePath StoreDirConfig::makeFixedOutputPathFromCA(std::string_view name, const
} }
std::pair<StorePath, Hash> StoreDirConfig::computeStorePathFromDump( std::pair<StorePath, Hash> StoreDirConfig::computeStorePath(
Source & dump,
std::string_view name, std::string_view name,
FileIngestionMethod method, SourceAccessor & accessor,
const CanonPath & path,
ContentAddressMethod method,
HashAlgorithm hashAlgo, HashAlgorithm hashAlgo,
const StorePathSet & references) const const StorePathSet & references,
PathFilter & filter) const
{ {
HashSink sink(hashAlgo); auto h = hashPath(accessor, path, method.getFileIngestionMethod(), hashAlgo, filter).first;
dump.drainInto(sink); return {
auto h = sink.finish().first; makeFixedOutputPathFromCA(
FixedOutputInfo caInfo { name,
.method = method, ContentAddressWithReferences::fromParts(
.hash = h, method,
.references = {}, h,
{
.others = references,
.self = false,
})),
h,
}; };
return std::make_pair(makeFixedOutputPath(name, caInfo), h);
} }
@ -265,21 +271,18 @@ StorePath StoreDirConfig::computeStorePathForText(
StorePath Store::addToStore( StorePath Store::addToStore(
std::string_view name, std::string_view name,
const Path & _srcPath, SourceAccessor & accessor,
FileIngestionMethod method, const CanonPath & path,
ContentAddressMethod method,
HashAlgorithm hashAlgo, HashAlgorithm hashAlgo,
const StorePathSet & references,
PathFilter & filter, PathFilter & filter,
RepairFlag repair, RepairFlag repair)
const StorePathSet & references)
{ {
Path srcPath(absPath(_srcPath));
auto source = sinkToSource([&](Sink & sink) { auto source = sinkToSource([&](Sink & sink) {
if (method == FileIngestionMethod::Recursive) dumpPath(accessor, path, sink, method.getFileIngestionMethod(), filter);
dumpPath(srcPath, sink, filter);
else
readFile(srcPath, sink);
}); });
return addToStoreFromDump(*source, name, method, hashAlgo, repair, references); return addToStoreFromDump(*source, name, method, hashAlgo, references, repair);
} }
void Store::addMultipleToStore( void Store::addMultipleToStore(
@ -404,8 +407,12 @@ digraph graphname {
fileSink -> caHashSink fileSink -> caHashSink
} }
*/ */
ValidPathInfo Store::addToStoreSlow(std::string_view name, const Path & srcPath, ValidPathInfo Store::addToStoreSlow(
FileIngestionMethod method, HashAlgorithm hashAlgo, std::string_view name,
SourceAccessor & accessor,
const CanonPath & srcPath,
ContentAddressMethod method, HashAlgorithm hashAlgo,
const StorePathSet & references,
std::optional<Hash> expectedCAHash) std::optional<Hash> expectedCAHash)
{ {
HashSink narHashSink { HashAlgorithm::SHA256 }; HashSink narHashSink { HashAlgorithm::SHA256 };
@ -425,7 +432,7 @@ ValidPathInfo Store::addToStoreSlow(std::string_view name, const Path & srcPath,
srcPath. The fact that we use scratchpadSink as a temporary buffer here srcPath. The fact that we use scratchpadSink as a temporary buffer here
is an implementation detail. */ is an implementation detail. */
auto fileSource = sinkToSource([&](Sink & scratchpadSink) { auto fileSource = sinkToSource([&](Sink & scratchpadSink) {
dumpPath(srcPath, scratchpadSink); accessor.dumpPath(srcPath, scratchpadSink);
}); });
/* tapped provides the same data as fileSource, but we also write all the /* tapped provides the same data as fileSource, but we also write all the
@ -433,9 +440,11 @@ ValidPathInfo Store::addToStoreSlow(std::string_view name, const Path & srcPath,
TeeSource tapped { *fileSource, narSink }; TeeSource tapped { *fileSource, narSink };
NullParseSink blank; NullParseSink blank;
auto & parseSink = method == FileIngestionMethod::Flat auto & parseSink = method.getFileIngestionMethod() == FileIngestionMethod::Flat
? (ParseSink &) fileSink ? (ParseSink &) fileSink
: (ParseSink &) blank; : method.getFileIngestionMethod() == FileIngestionMethod::Recursive
? (ParseSink &) blank
: (abort(), (ParseSink &)*(ParseSink *)nullptr); // handled both cases
/* The information that flows from tapped (besides being replicated in /* The information that flows from tapped (besides being replicated in
narSink), is now put in parseSink. */ narSink), is now put in parseSink. */
@ -452,21 +461,24 @@ ValidPathInfo Store::addToStoreSlow(std::string_view name, const Path & srcPath,
if (expectedCAHash && expectedCAHash != hash) if (expectedCAHash && expectedCAHash != hash)
throw Error("hash mismatch for '%s'", srcPath); throw Error("hash mismatch for '%s'", srcPath);
ValidPathInfo info { ValidPathInfo info {
*this, *this,
name, name,
FixedOutputInfo { ContentAddressWithReferences::fromParts(
.method = method, method,
.hash = hash, hash,
.references = {}, {
}, .others = references,
.self = false,
}),
narHash, narHash,
}; };
info.narSize = narSize; info.narSize = narSize;
if (!isValidPath(info.path)) { if (!isValidPath(info.path)) {
auto source = sinkToSource([&](Sink & scratchpadSink) { auto source = sinkToSource([&](Sink & scratchpadSink) {
dumpPath(srcPath, scratchpadSink); accessor.dumpPath(srcPath, scratchpadSink);
}); });
addToStore(info, *source); addToStore(info, *source);
} }

View file

@ -428,20 +428,26 @@ public:
*/ */
virtual StorePath addToStore( virtual StorePath addToStore(
std::string_view name, std::string_view name,
const Path & srcPath, SourceAccessor & accessor,
FileIngestionMethod method = FileIngestionMethod::Recursive, const CanonPath & path,
ContentAddressMethod method = FileIngestionMethod::Recursive,
HashAlgorithm hashAlgo = HashAlgorithm::SHA256, HashAlgorithm hashAlgo = HashAlgorithm::SHA256,
const StorePathSet & references = StorePathSet(),
PathFilter & filter = defaultPathFilter, PathFilter & filter = defaultPathFilter,
RepairFlag repair = NoRepair, RepairFlag repair = NoRepair);
const StorePathSet & references = StorePathSet());
/** /**
* Copy the contents of a path to the store and register the * Copy the contents of a path to the store and register the
* validity the resulting path, using a constant amount of * validity the resulting path, using a constant amount of
* memory. * memory.
*/ */
ValidPathInfo addToStoreSlow(std::string_view name, const Path & srcPath, ValidPathInfo addToStoreSlow(
FileIngestionMethod method = FileIngestionMethod::Recursive, HashAlgorithm hashAlgo = HashAlgorithm::SHA256, std::string_view name,
SourceAccessor & accessor,
const CanonPath & path,
ContentAddressMethod method = FileIngestionMethod::Recursive,
HashAlgorithm hashAlgo = HashAlgorithm::SHA256,
const StorePathSet & references = StorePathSet(),
std::optional<Hash> expectedCAHash = {}); std::optional<Hash> expectedCAHash = {});
/** /**
@ -453,9 +459,13 @@ public:
* *
* \todo remove? * \todo remove?
*/ */
virtual StorePath addToStoreFromDump(Source & dump, std::string_view name, virtual StorePath addToStoreFromDump(
FileIngestionMethod method = FileIngestionMethod::Recursive, HashAlgorithm hashAlgo = HashAlgorithm::SHA256, RepairFlag repair = NoRepair, Source & dump,
const StorePathSet & references = StorePathSet()) std::string_view name,
ContentAddressMethod method = FileIngestionMethod::Recursive,
HashAlgorithm hashAlgo = HashAlgorithm::SHA256,
const StorePathSet & references = StorePathSet(),
RepairFlag repair = NoRepair)
{ unsupported("addToStoreFromDump"); } { unsupported("addToStoreFromDump"); }
/** /**

View file

@ -91,15 +91,17 @@ struct StoreDirConfig : public Config
StorePath makeFixedOutputPathFromCA(std::string_view name, const ContentAddressWithReferences & ca) const; StorePath makeFixedOutputPathFromCA(std::string_view name, const ContentAddressWithReferences & ca) const;
/** /**
* Read-only variant of addToStoreFromDump(). It returns the store * Read-only variant of addToStore(). It returns the store
* path to which a NAR or flat file would be written. * path for the given file sytem object.
*/ */
std::pair<StorePath, Hash> computeStorePathFromDump( std::pair<StorePath, Hash> computeStorePath(
Source & dump,
std::string_view name, std::string_view name,
FileIngestionMethod method = FileIngestionMethod::Recursive, SourceAccessor & accessor,
const CanonPath & path,
ContentAddressMethod method = FileIngestionMethod::Recursive,
HashAlgorithm hashAlgo = HashAlgorithm::SHA256, HashAlgorithm hashAlgo = HashAlgorithm::SHA256,
const StorePathSet & references = {}) const; const StorePathSet & references = {},
PathFilter & filter = defaultPathFilter) const;
/** /**
* Preparatory part of addTextToStore(). * Preparatory part of addTextToStore().

View file

@ -0,0 +1,49 @@
#include "file-content-address.hh"
#include "archive.hh"
namespace nix {
void dumpPath(
SourceAccessor & accessor, const CanonPath & path,
Sink & sink,
FileIngestionMethod method,
PathFilter & filter)
{
switch (method) {
case FileIngestionMethod::Flat:
accessor.readFile(path, sink);
break;
case FileIngestionMethod::Recursive:
accessor.dumpPath(path, sink, filter);
break;
}
}
void restorePath(
const Path & path,
Source & source,
FileIngestionMethod method)
{
switch (method) {
case FileIngestionMethod::Flat:
writeFile(path, source);
break;
case FileIngestionMethod::Recursive:
restorePath(path, source);
break;
}
}
HashResult hashPath(
SourceAccessor & accessor, const CanonPath & path,
FileIngestionMethod method, HashAlgorithm ht,
PathFilter & filter)
{
HashSink sink { ht };
dumpPath(accessor, path, sink, method, filter);
return sink.finish();
}
}

View file

@ -0,0 +1,56 @@
#pragma once
///@file
#include "source-accessor.hh"
#include "fs-sink.hh"
#include "util.hh"
namespace nix {
/**
* An enumeration of the main ways we can serialize file system
* objects.
*/
enum struct FileIngestionMethod : uint8_t {
/**
* Flat-file hashing. Directly ingest the contents of a single file
*/
Flat = 0,
/**
* Recursive (or NAR) hashing. Serializes the file-system object in
* Nix Archive format and ingest that.
*/
Recursive = 1,
};
/**
* Dump a serialization of the given file system object.
*/
void dumpPath(
SourceAccessor & accessor, const CanonPath & path,
Sink & sink,
FileIngestionMethod method,
PathFilter & filter = defaultPathFilter);
/**
* Restore a serialization of the given file system object.
*
* @TODO use an arbitrary `ParseSink`.
*/
void restorePath(
const Path & path,
Source & source,
FileIngestionMethod method);
/**
* Compute the hash of the given file system object according to the
* given method.
*
* The hash is defined as (essentially) hashString(ht, dumpPath(path)).
*/
HashResult hashPath(
SourceAccessor & accessor, const CanonPath & path,
FileIngestionMethod method, HashAlgorithm ht,
PathFilter & filter = defaultPathFilter);
}

View file

@ -367,15 +367,6 @@ HashResult HashSink::currentHash()
} }
HashResult hashPath(
HashAlgorithm ha, const Path & path, PathFilter & filter)
{
HashSink sink(ha);
dumpPath(path, sink, filter);
return sink.finish();
}
Hash compressHash(const Hash & hash, unsigned int newSize) Hash compressHash(const Hash & hash, unsigned int newSize)
{ {
Hash h(hash.algo); Hash h(hash.algo);

View file

@ -168,14 +168,11 @@ Hash hashString(HashAlgorithm ha, std::string_view s);
Hash hashFile(HashAlgorithm ha, const Path & path); Hash hashFile(HashAlgorithm ha, const Path & path);
/** /**
* Compute the hash of the given path, serializing as a Nix Archive and * The final hash and the number of bytes digested.
* then hashing that.
* *
* The hash is defined as (essentially) hashString(ht, dumpPath(path)). * @todo Convert to proper struct
*/ */
typedef std::pair<Hash, uint64_t> HashResult; typedef std::pair<Hash, uint64_t> HashResult;
HashResult hashPath(HashAlgorithm ha, const Path & path,
PathFilter & filter = defaultPathFilter);
/** /**
* Compress a hash to the specified number of bytes by cyclically * Compress a hash to the specified number of bytes by cyclically

View file

@ -13,6 +13,7 @@
#include "shared.hh" #include "shared.hh"
#include "graphml.hh" #include "graphml.hh"
#include "legacy.hh" #include "legacy.hh"
#include "posix-source-accessor.hh"
#include "path-with-outputs.hh" #include "path-with-outputs.hh"
#include "posix-fs-canonicalise.hh" #include "posix-fs-canonicalise.hh"
@ -175,8 +176,12 @@ static void opAdd(Strings opFlags, Strings opArgs)
{ {
if (!opFlags.empty()) throw UsageError("unknown flag"); if (!opFlags.empty()) throw UsageError("unknown flag");
PosixSourceAccessor accessor;
for (auto & i : opArgs) for (auto & i : opArgs)
cout << fmt("%s\n", store->printStorePath(store->addToStore(std::string(baseNameOf(i)), i))); cout << fmt("%s\n", store->printStorePath(store->addToStore(
std::string(baseNameOf(i)),
accessor,
CanonPath::fromCwd(i))));
} }
@ -196,8 +201,14 @@ static void opAddFixed(Strings opFlags, Strings opArgs)
HashAlgorithm hashAlgo = parseHashAlgo(opArgs.front()); HashAlgorithm hashAlgo = parseHashAlgo(opArgs.front());
opArgs.pop_front(); opArgs.pop_front();
PosixSourceAccessor accessor;
for (auto & i : opArgs) for (auto & i : opArgs)
std::cout << fmt("%s\n", store->printStorePath(store->addToStoreSlow(baseNameOf(i), i, method, hashAlgo).path)); std::cout << fmt("%s\n", store->printStorePath(store->addToStoreSlow(
baseNameOf(i),
accessor,
CanonPath::fromCwd(i),
method,
hashAlgo).path));
} }
@ -541,7 +552,10 @@ static void registerValidity(bool reregister, bool hashGiven, bool canonicalise)
if (canonicalise) if (canonicalise)
canonicalisePathMetaData(store->printStorePath(info->path), {}); canonicalisePathMetaData(store->printStorePath(info->path), {});
if (!hashGiven) { if (!hashGiven) {
HashResult hash = hashPath(HashAlgorithm::SHA256, store->printStorePath(info->path)); HashResult hash = hashPath(
*store->getFSAccessor(false), CanonPath { store->printStorePath(info->path) },
FileIngestionMethod::Recursive, HashAlgorithm::SHA256);
info->narHash = hash.first; info->narHash = hash.first;
info->narSize = hash.second; info->narSize = hash.second;
} }

View file

@ -2,6 +2,7 @@
#include "common-args.hh" #include "common-args.hh"
#include "store-api.hh" #include "store-api.hh"
#include "archive.hh" #include "archive.hh"
#include "posix-source-accessor.hh"
using namespace nix; using namespace nix;
@ -20,7 +21,7 @@ struct CmdAddToStore : MixDryRun, StoreCommand
{ {
Path path; Path path;
std::optional<std::string> namePart; std::optional<std::string> namePart;
FileIngestionMethod ingestionMethod = FileIngestionMethod::Recursive; ContentAddressMethod caMethod = FileIngestionMethod::Recursive;
CmdAddToStore() CmdAddToStore()
{ {
@ -48,7 +49,7 @@ struct CmdAddToStore : MixDryRun, StoreCommand
)", )",
.labels = {"hash-mode"}, .labels = {"hash-mode"},
.handler = {[this](std::string s) { .handler = {[this](std::string s) {
this->ingestionMethod = parseIngestionMethod(s); this->caMethod = parseIngestionMethod(s);
}}, }},
}); });
} }
@ -57,36 +58,17 @@ struct CmdAddToStore : MixDryRun, StoreCommand
{ {
if (!namePart) namePart = baseNameOf(path); if (!namePart) namePart = baseNameOf(path);
StringSink sink; PosixSourceAccessor accessor;
dumpPath(path, sink);
auto narHash = hashString(HashAlgorithm::SHA256, sink.s); auto path2 = CanonPath::fromCwd(path);
Hash hash = narHash; auto storePath = dryRun
if (ingestionMethod == FileIngestionMethod::Flat) { ? store->computeStorePath(
HashSink hsink(HashAlgorithm::SHA256); *namePart, accessor, path2, caMethod, HashAlgorithm::SHA256, {}).first
readFile(path, hsink); : store->addToStoreSlow(
hash = hsink.finish().first; *namePart, accessor, path2, caMethod, HashAlgorithm::SHA256, {}).path;
}
ValidPathInfo info { logger->cout("%s", store->printStorePath(storePath));
*store,
std::move(*namePart),
FixedOutputInfo {
.method = std::move(ingestionMethod),
.hash = std::move(hash),
.references = {},
},
narHash,
};
info.narSize = sink.s.size();
if (!dryRun) {
auto source = StringSource(sink.s);
store->addToStore(info, source);
}
logger->cout("%s", store->printStorePath(info.path));
} }
}; };
@ -110,7 +92,7 @@ struct CmdAddFile : CmdAddToStore
{ {
CmdAddFile() CmdAddFile()
{ {
ingestionMethod = FileIngestionMethod::Flat; caMethod = FileIngestionMethod::Flat;
} }
std::string description() override std::string description() override

View file

@ -5,6 +5,7 @@
#include "shared.hh" #include "shared.hh"
#include "references.hh" #include "references.hh"
#include "archive.hh" #include "archive.hh"
#include "posix-source-accessor.hh"
using namespace nix; using namespace nix;
@ -88,14 +89,8 @@ struct CmdHashBase : Command
else else
hashSink = std::make_unique<HashSink>(ha); hashSink = std::make_unique<HashSink>(ha);
switch (mode) { PosixSourceAccessor accessor;
case FileIngestionMethod::Flat: dumpPath(accessor, CanonPath::fromCwd(path), *hashSink, mode);
readFile(path, *hashSink);
break;
case FileIngestionMethod::Recursive:
dumpPath(path, *hashSink);
break;
}
Hash h = hashSink->finish().first; Hash h = hashSink->finish().first;
if (truncate && h.hashSize > 20) h = compressHash(h, 20); if (truncate && h.hashSize > 20) h = compressHash(h, 20);

View file

@ -9,6 +9,7 @@
#include "attr-path.hh" #include "attr-path.hh"
#include "eval-inline.hh" #include "eval-inline.hh"
#include "legacy.hh" #include "legacy.hh"
#include "posix-source-accessor.hh"
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
@ -122,7 +123,11 @@ std::tuple<StorePath, Hash> prefetchFile(
Activity act(*logger, lvlChatty, actUnknown, Activity act(*logger, lvlChatty, actUnknown,
fmt("adding '%s' to the store", url)); fmt("adding '%s' to the store", url));
auto info = store->addToStoreSlow(*name, tmpFile, ingestionMethod, hashAlgo, expectedHash); PosixSourceAccessor accessor;
auto info = store->addToStoreSlow(
*name,
accessor, CanonPath::fromCwd(tmpFile),
ingestionMethod, hashAlgo, {}, expectedHash);
storePath = info.path; storePath = info.path;
assert(info.ca); assert(info.ca);
hash = info.ca->hash; hash = info.ca->hash;

View file

@ -604,7 +604,7 @@ namespace nix {
ASSERT_THAT(v, IsStringEq("401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429080fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1")); ASSERT_THAT(v, IsStringEq("401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429080fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1"));
} }
TEST_F(PrimOpTest, hashStringInvalidHashType) { TEST_F(PrimOpTest, hashStringInvalidHashAlgorithm) {
ASSERT_THROW(eval("builtins.hashString \"foobar\" \"asdf\""), Error); ASSERT_THROW(eval("builtins.hashString \"foobar\" \"asdf\""), Error);
} }