Remove InputScheme::fetchToStore()

InputSchemes now only have a getAccessor(). They could be implemented
internally by fetching the input to the store, but in that case they
will just return a FSInputAccessor.
This commit is contained in:
Eelco Dolstra 2022-08-01 15:44:40 +02:00
parent 360a1284db
commit 55c63c9b89
13 changed files with 168 additions and 162 deletions

View file

@ -94,7 +94,7 @@ SourcePath lookupFileArg(EvalState & state, std::string_view s)
if (isUri(s)) {
auto storePath = fetchers::downloadTarball(
state.store, resolveUri(s), "source", false).first;
auto accessor = makeFSInputAccessor(CanonPath(state.store->toRealPath(storePath)));
auto accessor = makeStorePathAccessor(state.store, storePath);
state.registerAccessor(accessor);
return {accessor, CanonPath::root};
} else if (s.size() > 2 && s.at(0) == '<' && s.at(s.size() - 1) == '>') {

View file

@ -791,7 +791,7 @@ SourcePath EvalState::findFile(SearchPath & searchPath, const std::string_view p
try {
auto storePath = fetchers::downloadTarball(
store, resolveUri(elem.second), "source", false).first;
auto accessor = makeFSInputAccessor(CanonPath(store->toRealPath(storePath)));
auto accessor = makeStorePathAccessor(store, storePath);
registerAccessor(accessor);
res.emplace(SourcePath {accessor, CanonPath::root});
} catch (FileTransferError & e) {

View file

@ -115,32 +115,40 @@ bool Input::contains(const Input & other) const
std::pair<StorePath, Input> Input::fetchToStore(ref<Store> store) const
{
if (!scheme)
throw Error("cannot fetch unsupported input '%s'", attrsToJSON(toAttrs()));
auto [storePath, input] = [&]() -> std::pair<StorePath, Input> {
try {
return scheme->fetchToStore(store, *this);
auto [accessor, input2] = getAccessor(store);
// FIXME: add an optimisation for the case where the
// accessor is an FSInputAccessor pointing to a store
// path.
auto source = sinkToSource([&, accessor{accessor}](Sink & sink) {
accessor->dumpPath(CanonPath::root, sink);
});
auto storePath = store->addToStoreFromDump(*source, input2.getName());
return {storePath, input2};
} catch (Error & e) {
e.addTrace({}, "while fetching the input '%s'", to_string());
throw;
}
}();
checkLocked(*store, storePath, input);
return {std::move(storePath), input};
}
void Input::checkLocked(Store & store, const StorePath & storePath, Input & input) const
void Input::checkLocks(Input & input) const
{
#if 0
auto narHash = store.queryPathInfo(storePath)->narHash;
input.attrs.insert_or_assign("narHash", narHash.to_string(SRI, true));
#endif
if (auto prevNarHash = getNarHash()) {
if (narHash != *prevNarHash)
throw Error((unsigned int) 102, "NAR hash mismatch in input '%s' (%s), expected '%s', got '%s'",
to_string(), store.printStorePath(storePath), prevNarHash->to_string(SRI, true), narHash.to_string(SRI, true));
if (input.getNarHash() != prevNarHash)
throw Error((unsigned int) 102, "NAR hash mismatch in input '%s', expected '%s'",
to_string(), prevNarHash->to_string(SRI, true));
}
if (auto prevLastModified = getLastModified()) {
@ -155,9 +163,12 @@ void Input::checkLocked(Store & store, const StorePath & storePath, Input & inpu
input.to_string(), *prevRevCount);
}
// FIXME
#if 0
input.locked = true;
assert(input.hasAllInfo());
#endif
}
std::pair<ref<InputAccessor>, Input> Input::getAccessor(ref<Store> store) const
@ -166,7 +177,9 @@ std::pair<ref<InputAccessor>, Input> Input::getAccessor(ref<Store> store) const
throw Error("cannot fetch unsupported input '%s'", attrsToJSON(toAttrs()));
try {
return scheme->getAccessor(store, *this);
auto [accessor, final] = scheme->getAccessor(store, *this);
checkLocks(final);
return {accessor, std::move(final)};
} catch (Error & e) {
e.addTrace({}, "while fetching the input '%s'", to_string());
throw;
@ -262,7 +275,7 @@ std::optional<std::string> Input::getFingerprint(ref<Store> store) const
return scheme->getFingerprint(store, *this);
}
ParsedURL InputScheme::toURL(const Input & input)
ParsedURL InputScheme::toURL(const Input & input) const
{
throw Error("don't know how to convert input '%s' to a URL", attrsToJSON(input.attrs));
}
@ -270,7 +283,7 @@ ParsedURL InputScheme::toURL(const Input & input)
Input InputScheme::applyOverrides(
const Input & input,
std::optional<std::string> ref,
std::optional<Hash> rev)
std::optional<Hash> rev) const
{
if (ref)
throw Error("don't know how to set branch/tag name of input '%s' to '%s'", input.to_string(), *ref);
@ -288,31 +301,9 @@ void InputScheme::putFile(
throw Error("input '%s' does not support modifying file '%s'", input.to_string(), path);
}
void InputScheme::clone(const Input & input, const Path & destDir)
void InputScheme::clone(const Input & input, const Path & destDir) const
{
throw Error("do not know how to clone input '%s'", input.to_string());
}
std::pair<StorePath, Input> InputScheme::fetchToStore(ref<Store> store, const Input & input)
{
auto [accessor, input2] = getAccessor(store, input);
auto source = sinkToSource([&, accessor{accessor}](Sink & sink) {
accessor->dumpPath(CanonPath::root, sink);
});
auto storePath = store->addToStoreFromDump(*source, "source");
return {storePath, input2};
}
std::pair<ref<InputAccessor>, Input> InputScheme::getAccessor(ref<Store> store, const Input & input)
{
auto [storePath, input2] = fetchToStore(store, input);
input.checkLocked(*store, storePath, input2);
return {makeFSInputAccessor(CanonPath(store->toRealPath(storePath))), input2};
}
}

View file

@ -100,7 +100,7 @@ public:
private:
void checkLocked(Store & store, const StorePath & storePath, Input & input) const;
void checkLocks(Input & input) const;
};
/* The InputScheme represents a type of fetcher. Each fetcher
@ -116,20 +116,20 @@ struct InputScheme
virtual ~InputScheme()
{ }
virtual std::optional<Input> inputFromURL(const ParsedURL & url) = 0;
virtual std::optional<Input> inputFromURL(const ParsedURL & url) const = 0;
virtual std::optional<Input> inputFromAttrs(const Attrs & attrs) = 0;
virtual std::optional<Input> inputFromAttrs(const Attrs & attrs) const = 0;
virtual ParsedURL toURL(const Input & input);
virtual ParsedURL toURL(const Input & input) const;
virtual bool hasAllInfo(const Input & input) = 0;
virtual bool hasAllInfo(const Input & input) const = 0;
virtual Input applyOverrides(
const Input & input,
std::optional<std::string> ref,
std::optional<Hash> rev);
std::optional<Hash> rev) const;
virtual void clone(const Input & input, const Path & destDir);
virtual void clone(const Input & input, const Path & destDir) const;
virtual void putFile(
const Input & input,
@ -137,13 +137,7 @@ struct InputScheme
std::string_view contents,
std::optional<std::string> commitMsg) const;
/* Note: the default implementations of fetchToStore() and
getAccessor() are defined using the other, so implementations
have to override at least one. */
virtual std::pair<StorePath, Input> fetchToStore(ref<Store> store, const Input & input);
virtual std::pair<ref<InputAccessor>, Input> getAccessor(ref<Store> store, const Input & input);
virtual std::pair<ref<InputAccessor>, Input> getAccessor(ref<Store> store, const Input & input) const = 0;
virtual std::optional<CanonPath> isRelative(const Input & input) const
{ return std::nullopt; }

View file

@ -140,7 +140,7 @@ bool isNotDotGitDirectory(const Path & path)
struct GitInputScheme : InputScheme
{
std::optional<Input> inputFromURL(const ParsedURL & url) override
std::optional<Input> inputFromURL(const ParsedURL & url) const override
{
if (url.scheme != "git" &&
url.scheme != "git+http" &&
@ -169,7 +169,7 @@ struct GitInputScheme : InputScheme
return inputFromAttrs(attrs);
}
std::optional<Input> inputFromAttrs(const Attrs & attrs) override
std::optional<Input> inputFromAttrs(const Attrs & attrs) const override
{
if (maybeGetStrAttr(attrs, "type") != "git") return {};
@ -192,7 +192,7 @@ struct GitInputScheme : InputScheme
return input;
}
ParsedURL toURL(const Input & input) override
ParsedURL toURL(const Input & input) const override
{
auto url = parseURL(getStrAttr(input.attrs, "url"));
if (url.scheme != "git") url.scheme = "git+" + url.scheme;
@ -203,7 +203,7 @@ struct GitInputScheme : InputScheme
return url;
}
bool hasAllInfo(const Input & input) override
bool hasAllInfo(const Input & input) const override
{
bool maybeDirty = !input.getRef();
bool shallow = maybeGetBoolAttr(input.attrs, "shallow").value_or(false);
@ -215,7 +215,7 @@ struct GitInputScheme : InputScheme
Input applyOverrides(
const Input & input,
std::optional<std::string> ref,
std::optional<Hash> rev) override
std::optional<Hash> rev) const override
{
auto res(input);
if (rev) res.attrs.insert_or_assign("rev", rev->gitRev());
@ -225,7 +225,7 @@ struct GitInputScheme : InputScheme
return res;
}
void clone(const Input & input, const Path & destDir) override
void clone(const Input & input, const Path & destDir) const override
{
auto repoInfo = getRepoInfo(input);
@ -394,7 +394,7 @@ struct GitInputScheme : InputScheme
return repoInfo;
}
std::set<CanonPath> listFiles(const RepoInfo & repoInfo)
std::set<CanonPath> listFiles(const RepoInfo & repoInfo) const
{
auto gitOpts = Strings({ "-C", repoInfo.url, "--git-dir", repoInfo.gitDir, "ls-files", "-z" });
if (repoInfo.submodules)
@ -409,14 +409,14 @@ struct GitInputScheme : InputScheme
return res;
}
void updateRev(Input & input, const RepoInfo & repoInfo, const std::string & ref)
void updateRev(Input & input, const RepoInfo & repoInfo, const std::string & ref) const
{
if (!input.getRev())
input.attrs.insert_or_assign("rev",
Hash::parseAny(chomp(runProgram("git", true, { "-C", repoInfo.url, "--git-dir", repoInfo.gitDir, "rev-parse", ref })), htSHA1).gitRev());
}
uint64_t getLastModified(const RepoInfo & repoInfo, const std::string & repoDir, const std::string & ref)
uint64_t getLastModified(const RepoInfo & repoInfo, const std::string & repoDir, const std::string & ref) const
{
return
repoInfo.hasHead
@ -426,7 +426,7 @@ struct GitInputScheme : InputScheme
: 0;
}
uint64_t getRevCount(const RepoInfo & repoInfo, const std::string & repoDir, const Hash & rev)
uint64_t getRevCount(const RepoInfo & repoInfo, const std::string & repoDir, const Hash & rev) const
{
// FIXME: cache this.
return
@ -437,7 +437,7 @@ struct GitInputScheme : InputScheme
: 0;
}
std::string getDefaultRef(const RepoInfo & repoInfo)
std::string getDefaultRef(const RepoInfo & repoInfo) const
{
auto head = repoInfo.isLocal
? readHead(repoInfo.url)
@ -449,11 +449,14 @@ struct GitInputScheme : InputScheme
return *head;
}
std::pair<StorePath, Input> fetchToStore(ref<Store> store, const Input & _input) override
StorePath fetchToStore(
ref<Store> store,
RepoInfo & repoInfo,
Input & input) const
{
Input input(_input);
assert(!repoInfo.isDirty);
auto repoInfo = getRepoInfo(input);
auto origRev = input.getRev();
std::string name = input.getName();
@ -466,15 +469,21 @@ struct GitInputScheme : InputScheme
});
};
auto makeResult = [&](const Attrs & infoAttrs, StorePath && storePath)
-> std::pair<StorePath, Input>
auto makeResult = [&](const Attrs & infoAttrs, const StorePath & storePath) -> StorePath
{
assert(input.getRev());
assert(!_input.getRev() || _input.getRev() == input.getRev());
assert(!origRev || origRev == input.getRev());
if (!repoInfo.shallow)
input.attrs.insert_or_assign("revCount", getIntAttr(infoAttrs, "revCount"));
input.attrs.insert_or_assign("lastModified", getIntAttr(infoAttrs, "lastModified"));
return {std::move(storePath), input};
// FIXME: remove?
//input.attrs.erase("narHash");
auto narHash = store->queryPathInfo(storePath)->narHash;
input.attrs.insert_or_assign("narHash", narHash.to_string(SRI, true));
input.locked = true;
return storePath;
};
if (input.getRev()) {
@ -482,9 +491,6 @@ struct GitInputScheme : InputScheme
return makeResult(res->first, std::move(res->second));
}
if (repoInfo.isDirty)
return fetchFromWorkdir(store, repoInfo, std::move(input));
auto originalRef = input.getRef();
auto ref = originalRef ? *originalRef : getDefaultRef(repoInfo);
input.attrs.insert_or_assign("ref", ref);
@ -674,7 +680,7 @@ struct GitInputScheme : InputScheme
infoAttrs.insert_or_assign("revCount",
getRevCount(repoInfo, repoDir, rev));
if (!_input.getRev())
if (!origRev)
getCache()->add(
store,
unlockedAttrs,
@ -692,45 +698,27 @@ struct GitInputScheme : InputScheme
return makeResult(infoAttrs, std::move(storePath));
}
std::pair<StorePath, Input> fetchFromWorkdir(
ref<Store> store,
const RepoInfo & repoInfo,
Input input)
{
/* This is an unclean working tree. So copy all tracked
files. */
repoInfo.checkDirty();
auto files = listFiles(repoInfo);
CanonPath repoDir(repoInfo.url);
PathFilter filter = [&](const Path & p) -> bool {
return CanonPath(p).removePrefix(repoDir).isAllowed(files);
};
auto storePath = store->addToStore(input.getName(), repoInfo.url, FileIngestionMethod::Recursive, htSHA256, filter);
// FIXME: maybe we should use the timestamp of the last
// modified dirty file?
input.attrs.insert_or_assign(
"lastModified",
getLastModified(repoInfo, repoInfo.url, "HEAD"));
return {std::move(storePath), input};
}
std::pair<ref<InputAccessor>, Input> getAccessor(ref<Store> store, const Input & _input) override
std::pair<ref<InputAccessor>, Input> getAccessor(ref<Store> store, const Input & _input) const override
{
Input input(_input);
auto repoInfo = getRepoInfo(input);
auto makeNotAllowedError = [url{repoInfo.url}](const CanonPath & path) -> RestrictedPathError
{
if (nix::pathExists(path.abs()))
return RestrictedPathError("access to path '%s' is forbidden because it is not under Git control; maybe you should 'git add' it to the repository '%s'?", path, url);
else
return RestrictedPathError("path '%s' does not exist in Git repository '%s'", path, url);
};
/* Unless we're using the working tree, copy the tree into the
Nix store. TODO: We could have an accessor for fetching
files from the Git repository directly. */
if (input.getRef() || input.getRev() || !repoInfo.isLocal)
return InputScheme::getAccessor(store, input);
if (input.getRef() || input.getRev() || !repoInfo.isLocal) {
auto storePath = fetchToStore(store, repoInfo, input);
return {makeStorePathAccessor(store, storePath, std::move(makeNotAllowedError)), input};
}
repoInfo.checkDirty();
@ -753,14 +741,6 @@ struct GitInputScheme : InputScheme
"lastModified",
getLastModified(repoInfo, repoInfo.url, ref));
auto makeNotAllowedError = [url{repoInfo.url}](const CanonPath & path) -> RestrictedPathError
{
if (nix::pathExists(path.abs()))
return RestrictedPathError("access to path '%s' is forbidden because it is not under Git control; maybe you should 'git add' it to the repository '%s'?", path, url);
else
return RestrictedPathError("path '%s' does not exist in Git repository '%s'", path, url);
};
return {makeFSInputAccessor(CanonPath(repoInfo.url), listFiles(repoInfo), std::move(makeNotAllowedError)), input};
}
};

View file

@ -26,11 +26,11 @@ std::regex hostRegex(hostRegexS, std::regex::ECMAScript);
struct GitArchiveInputScheme : InputScheme
{
virtual std::string type() = 0;
virtual std::string type() const = 0;
virtual std::optional<std::pair<std::string, std::string>> accessHeaderFromToken(const std::string & token) const = 0;
std::optional<Input> inputFromURL(const ParsedURL & url) override
std::optional<Input> inputFromURL(const ParsedURL & url) const override
{
if (url.scheme != type()) return {};
@ -100,7 +100,7 @@ struct GitArchiveInputScheme : InputScheme
return input;
}
std::optional<Input> inputFromAttrs(const Attrs & attrs) override
std::optional<Input> inputFromAttrs(const Attrs & attrs) const override
{
if (maybeGetStrAttr(attrs, "type") != type()) return {};
@ -116,7 +116,7 @@ struct GitArchiveInputScheme : InputScheme
return input;
}
ParsedURL toURL(const Input & input) override
ParsedURL toURL(const Input & input) const override
{
auto owner = getStrAttr(input.attrs, "owner");
auto repo = getStrAttr(input.attrs, "repo");
@ -132,7 +132,7 @@ struct GitArchiveInputScheme : InputScheme
};
}
bool hasAllInfo(const Input & input) override
bool hasAllInfo(const Input & input) const override
{
return input.getRev() &&
true; // FIXME
@ -142,7 +142,7 @@ struct GitArchiveInputScheme : InputScheme
Input applyOverrides(
const Input & _input,
std::optional<std::string> ref,
std::optional<Hash> rev) override
std::optional<Hash> rev) const override
{
auto input(_input);
if (rev && ref)
@ -185,7 +185,7 @@ struct GitArchiveInputScheme : InputScheme
virtual DownloadUrl getDownloadUrl(const Input & input) const = 0;
std::pair<StorePath, Input> downloadArchive(ref<Store> store, Input input)
std::pair<StorePath, Input> downloadArchive(ref<Store> store, Input input) const
{
if (!maybeGetStrAttr(input.attrs, "ref")) input.attrs.insert_or_assign("ref", "HEAD");
@ -228,7 +228,7 @@ struct GitArchiveInputScheme : InputScheme
return {res.storePath, input};
}
std::pair<ref<InputAccessor>, Input> getAccessor(ref<Store> store, const Input & input) override
std::pair<ref<InputAccessor>, Input> getAccessor(ref<Store> store, const Input & input) const override
{
auto [storePath, input2] = downloadArchive(store, input);
@ -242,7 +242,7 @@ struct GitArchiveInputScheme : InputScheme
struct GitHubInputScheme : GitArchiveInputScheme
{
std::string type() override { return "github"; }
std::string type() const override { return "github"; }
std::optional<std::pair<std::string, std::string>> accessHeaderFromToken(const std::string & token) const override
{
@ -291,7 +291,7 @@ struct GitHubInputScheme : GitArchiveInputScheme
return DownloadUrl { url, headers };
}
void clone(const Input & input, const Path & destDir) override
void clone(const Input & input, const Path & destDir) const override
{
auto host = maybeGetStrAttr(input.attrs, "host").value_or("github.com");
Input::fromURL(fmt("git+https://%s/%s/%s.git",
@ -303,7 +303,7 @@ struct GitHubInputScheme : GitArchiveInputScheme
struct GitLabInputScheme : GitArchiveInputScheme
{
std::string type() override { return "gitlab"; }
std::string type() const override { return "gitlab"; }
std::optional<std::pair<std::string, std::string>> accessHeaderFromToken(const std::string & token) const override
{
@ -358,7 +358,7 @@ struct GitLabInputScheme : GitArchiveInputScheme
return DownloadUrl { url, headers };
}
void clone(const Input & input, const Path & destDir) override
void clone(const Input & input, const Path & destDir) const override
{
auto host = maybeGetStrAttr(input.attrs, "host").value_or("gitlab.com");
// FIXME: get username somewhere
@ -371,7 +371,7 @@ struct GitLabInputScheme : GitArchiveInputScheme
struct SourceHutInputScheme : GitArchiveInputScheme
{
std::string type() override { return "sourcehut"; }
std::string type() const override { return "sourcehut"; }
std::optional<std::pair<std::string, std::string>> accessHeaderFromToken(const std::string & token) const override
{
@ -445,7 +445,7 @@ struct SourceHutInputScheme : GitArchiveInputScheme
return DownloadUrl { url, headers };
}
void clone(const Input & input, const Path & destDir) override
void clone(const Input & input, const Path & destDir) const override
{
auto host = maybeGetStrAttr(input.attrs, "host").value_or("git.sr.ht");
Input::fromURL(fmt("git+https://%s/%s/%s",

View file

@ -7,7 +7,7 @@ std::regex flakeRegex("[a-zA-Z][a-zA-Z0-9_-]*", std::regex::ECMAScript);
struct IndirectInputScheme : InputScheme
{
std::optional<Input> inputFromURL(const ParsedURL & url) override
std::optional<Input> inputFromURL(const ParsedURL & url) const override
{
if (url.scheme != "flake") return {};
@ -50,7 +50,7 @@ struct IndirectInputScheme : InputScheme
return input;
}
std::optional<Input> inputFromAttrs(const Attrs & attrs) override
std::optional<Input> inputFromAttrs(const Attrs & attrs) const override
{
if (maybeGetStrAttr(attrs, "type") != "indirect") return {};
@ -68,7 +68,7 @@ struct IndirectInputScheme : InputScheme
return input;
}
ParsedURL toURL(const Input & input) override
ParsedURL toURL(const Input & input) const override
{
ParsedURL url;
url.scheme = "flake";
@ -78,7 +78,7 @@ struct IndirectInputScheme : InputScheme
return url;
}
bool hasAllInfo(const Input & input) override
bool hasAllInfo(const Input & input) const override
{
return false;
}
@ -86,7 +86,7 @@ struct IndirectInputScheme : InputScheme
Input applyOverrides(
const Input & _input,
std::optional<std::string> ref,
std::optional<Hash> rev) override
std::optional<Hash> rev) const override
{
auto input(_input);
if (rev) input.attrs.insert_or_assign("rev", rev->gitRev());
@ -94,7 +94,7 @@ struct IndirectInputScheme : InputScheme
return input;
}
std::pair<StorePath, Input> fetchToStore(ref<Store> store, const Input & input) override
std::pair<ref<InputAccessor>, Input> getAccessor(ref<Store> store, const Input & input) const override
{
throw Error("indirect input '%s' cannot be fetched directly", input.to_string());
}

View file

@ -1,5 +1,6 @@
#include "input-accessor.hh"
#include "util.hh"
#include "store-api.hh"
#include <atomic>
@ -235,6 +236,14 @@ ref<FSInputAccessor> makeFSInputAccessor(
return make_ref<FSInputAccessorImpl>(root, std::move(allowedPaths), std::move(makeNotAllowedError));
}
ref<FSInputAccessor> makeStorePathAccessor(
ref<Store> store,
const StorePath & storePath,
MakeNotAllowedError && makeNotAllowedError)
{
return makeFSInputAccessor(CanonPath(store->toRealPath(storePath)), {}, std::move(makeNotAllowedError));
}
std::ostream & operator << (std::ostream & str, const SourcePath & path)
{
str << path.to_string();

View file

@ -10,6 +10,8 @@ namespace nix {
MakeError(RestrictedPathError, Error);
struct SourcePath;
class StorePath;
class Store;
struct InputAccessor : public std::enable_shared_from_this<InputAccessor>
{
@ -91,6 +93,11 @@ ref<FSInputAccessor> makeFSInputAccessor(
std::optional<std::set<CanonPath>> && allowedPaths = {},
MakeNotAllowedError && makeNotAllowedError = {});
ref<FSInputAccessor> makeStorePathAccessor(
ref<Store> store,
const StorePath & storePath,
MakeNotAllowedError && makeNotAllowedError = {});
struct SourcePath;
struct MemoryInputAccessor : InputAccessor

View file

@ -43,7 +43,7 @@ static std::string runHg(const Strings & args, const std::optional<std::string>
struct MercurialInputScheme : InputScheme
{
std::optional<Input> inputFromURL(const ParsedURL & url) override
std::optional<Input> inputFromURL(const ParsedURL & url) const override
{
if (url.scheme != "hg+http" &&
url.scheme != "hg+https" &&
@ -69,7 +69,7 @@ struct MercurialInputScheme : InputScheme
return inputFromAttrs(attrs);
}
std::optional<Input> inputFromAttrs(const Attrs & attrs) override
std::optional<Input> inputFromAttrs(const Attrs & attrs) const override
{
if (maybeGetStrAttr(attrs, "type") != "hg") return {};
@ -89,7 +89,7 @@ struct MercurialInputScheme : InputScheme
return input;
}
ParsedURL toURL(const Input & input) override
ParsedURL toURL(const Input & input) const override
{
auto url = parseURL(getStrAttr(input.attrs, "url"));
url.scheme = "hg+" + url.scheme;
@ -98,7 +98,7 @@ struct MercurialInputScheme : InputScheme
return url;
}
bool hasAllInfo(const Input & input) override
bool hasAllInfo(const Input & input) const override
{
// FIXME: ugly, need to distinguish between dirty and clean
// default trees.
@ -108,7 +108,7 @@ struct MercurialInputScheme : InputScheme
Input applyOverrides(
const Input & input,
std::optional<std::string> ref,
std::optional<Hash> rev) override
std::optional<Hash> rev) const override
{
auto res(input);
if (rev) res.attrs.insert_or_assign("rev", rev->gitRev());
@ -148,9 +148,9 @@ struct MercurialInputScheme : InputScheme
return {isLocal, isLocal ? url.path : url.base};
}
std::pair<StorePath, Input> fetchToStore(ref<Store> store, const Input & _input) override
StorePath fetchToStore(ref<Store> store, Input & input) const
{
Input input(_input);
auto origRev = input.getRev();
auto name = input.getName();
@ -200,7 +200,7 @@ struct MercurialInputScheme : InputScheme
auto storePath = store->addToStore(input.getName(), actualPath, FileIngestionMethod::Recursive, htSHA256, filter);
return {std::move(storePath), input};
return storePath;
}
}
@ -224,13 +224,13 @@ struct MercurialInputScheme : InputScheme
});
};
auto makeResult = [&](const Attrs & infoAttrs, StorePath && storePath)
-> std::pair<StorePath, Input>
auto makeResult = [&](const Attrs & infoAttrs, const StorePath & storePath) -> StorePath
{
assert(input.getRev());
assert(!_input.getRev() || _input.getRev() == input.getRev());
assert(!origRev || origRev == input.getRev());
input.attrs.insert_or_assign("revCount", getIntAttr(infoAttrs, "revCount"));
return {std::move(storePath), input};
input.locked = true;
return storePath;
};
if (input.getRev()) {
@ -310,7 +310,7 @@ struct MercurialInputScheme : InputScheme
{"revCount", (uint64_t) revCount},
});
if (!_input.getRev())
if (!origRev)
getCache()->add(
store,
unlockedAttrs,
@ -327,6 +327,15 @@ struct MercurialInputScheme : InputScheme
return makeResult(infoAttrs, std::move(storePath));
}
std::pair<ref<InputAccessor>, Input> getAccessor(ref<Store> store, const Input & _input) const override
{
Input input(_input);
auto storePath = fetchToStore(store, input);
return {makeStorePathAccessor(store, storePath), input};
}
};
static auto rMercurialInputScheme = OnStartup([] { registerInputScheme(std::make_unique<MercurialInputScheme>()); });

View file

@ -6,7 +6,7 @@ namespace nix::fetchers {
struct PathInputScheme : InputScheme
{
std::optional<Input> inputFromURL(const ParsedURL & url) override
std::optional<Input> inputFromURL(const ParsedURL & url) const override
{
if (url.scheme != "path") return {};
@ -32,7 +32,7 @@ struct PathInputScheme : InputScheme
return input;
}
std::optional<Input> inputFromAttrs(const Attrs & attrs) override
std::optional<Input> inputFromAttrs(const Attrs & attrs) const override
{
if (maybeGetStrAttr(attrs, "type") != "path") return {};
@ -54,7 +54,7 @@ struct PathInputScheme : InputScheme
return input;
}
ParsedURL toURL(const Input & input) override
ParsedURL toURL(const Input & input) const override
{
auto query = attrsToQuery(input.attrs);
query.erase("path");
@ -75,7 +75,7 @@ struct PathInputScheme : InputScheme
return CanonPath(path);
}
bool hasAllInfo(const Input & input) override
bool hasAllInfo(const Input & input) const override
{
return true;
}
@ -103,7 +103,7 @@ struct PathInputScheme : InputScheme
throw Error("cannot fetch input '%s' because it uses a relative path", input.to_string());
}
std::pair<ref<InputAccessor>, Input> getAccessor(ref<Store> store, const Input & input) override
std::pair<ref<InputAccessor>, Input> getAccessor(ref<Store> store, const Input & input) const override
{
auto absPath = getAbsPath(input);
auto input2(input);

View file

@ -185,7 +185,7 @@ struct CurlInputScheme : InputScheme
virtual bool isValidURL(const ParsedURL & url) const = 0;
std::optional<Input> inputFromURL(const ParsedURL & url) override
std::optional<Input> inputFromURL(const ParsedURL & url) const override
{
if (!isValidURL(url))
return std::nullopt;
@ -203,7 +203,7 @@ struct CurlInputScheme : InputScheme
return input;
}
std::optional<Input> inputFromAttrs(const Attrs & attrs) override
std::optional<Input> inputFromAttrs(const Attrs & attrs) const override
{
auto type = maybeGetStrAttr(attrs, "type");
if (type != inputType()) return {};
@ -220,7 +220,7 @@ struct CurlInputScheme : InputScheme
return input;
}
ParsedURL toURL(const Input & input) override
ParsedURL toURL(const Input & input) const override
{
auto url = parseURL(getStrAttr(input.attrs, "url"));
// NAR hashes are preferred over file hashes since tar/zip
@ -230,7 +230,7 @@ struct CurlInputScheme : InputScheme
return url;
}
bool hasAllInfo(const Input & input) override
bool hasAllInfo(const Input & input) const override
{
return true;
}
@ -250,10 +250,18 @@ struct FileInputScheme : CurlInputScheme
: !hasTarballExtension(url.path));
}
std::pair<StorePath, Input> fetchToStore(ref<Store> store, const Input & input) override
std::pair<ref<InputAccessor>, Input> getAccessor(ref<Store> store, const Input & _input) const override
{
auto input(_input);
auto file = downloadFile(store, getStrAttr(input.attrs, "url"), input.getName(), false);
return {std::move(file.storePath), input};
// FIXME: remove?
auto narHash = store->queryPathInfo(file.storePath)->narHash;
input.attrs.insert_or_assign("narHash", narHash.to_string(SRI, true));
input.locked = true;
return {makeStorePathAccessor(store, file.storePath), input};
}
};
@ -271,12 +279,18 @@ struct TarballInputScheme : CurlInputScheme
: hasTarballExtension(url.path));
}
std::pair<StorePath, Input> fetchToStore(ref<Store> store, const Input & input) override
std::pair<ref<InputAccessor>, Input> getAccessor(ref<Store> store, const Input & _input) const override
{
return {
downloadTarball(store, getStrAttr(input.attrs, "url"), input.getName(), false).first,
input
};
auto input(_input);
auto storePath = downloadTarball(store, getStrAttr(input.attrs, "url"), input.getName(), false).first;
// FIXME: remove?
auto narHash = store->queryPathInfo(storePath)->narHash;
input.attrs.insert_or_assign("narHash", narHash.to_string(SRI, true));
input.locked = true;
return {makeStorePathAccessor(store, storePath), input};
}
};

View file

@ -120,6 +120,7 @@ git -C $repo commit -m 'Bla3' -a
path4=$(nix eval --impure --refresh --raw --expr "(builtins.fetchGit file://$repo).outPath")
[[ $path2 = $path4 ]]
status=0
nix eval --impure --raw --expr "(builtins.fetchGit { url = $repo; rev = \"$rev2\"; narHash = \"sha256-B5yIPHhEm0eysJKEsO7nqxprh9vcblFxpJG11gXJus1=\"; }).outPath" || status=$?
[[ "$status" = "102" ]]
@ -223,4 +224,5 @@ rm -rf $repo/.git
# should succeed for a repo without commits
git init $repo
git -C $repo add hello # need to add at least one file to cause the root of the repo to be visible
path10=$(nix eval --impure --raw --expr "(builtins.fetchGit \"file://$repo\").outPath")