diff options
Diffstat (limited to 'src/libfetchers')
-rw-r--r-- | src/libfetchers/cache.cc | 8 | ||||
-rw-r--r-- | src/libfetchers/cache.hh | 2 | ||||
-rw-r--r-- | src/libfetchers/fetch-settings.cc | 13 | ||||
-rw-r--r-- | src/libfetchers/fetch-settings.hh | 93 | ||||
-rw-r--r-- | src/libfetchers/fetchers.cc | 20 | ||||
-rw-r--r-- | src/libfetchers/fetchers.hh | 15 | ||||
-rw-r--r-- | src/libfetchers/git.cc | 44 | ||||
-rw-r--r-- | src/libfetchers/github.cc | 114 | ||||
-rw-r--r-- | src/libfetchers/indirect.cc | 2 | ||||
-rw-r--r-- | src/libfetchers/mercurial.cc | 38 | ||||
-rw-r--r-- | src/libfetchers/path.cc | 9 | ||||
-rw-r--r-- | src/libfetchers/registry.cc | 4 | ||||
-rw-r--r-- | src/libfetchers/tarball.cc | 33 |
13 files changed, 290 insertions, 105 deletions
diff --git a/src/libfetchers/cache.cc b/src/libfetchers/cache.cc index 34ff6f85b..0c8ecac9d 100644 --- a/src/libfetchers/cache.cc +++ b/src/libfetchers/cache.cc @@ -52,13 +52,13 @@ struct CacheImpl : Cache const Attrs & inAttrs, const Attrs & infoAttrs, const StorePath & storePath, - bool immutable) override + bool locked) override { _state.lock()->add.use() (attrsToJSON(inAttrs).dump()) (attrsToJSON(infoAttrs).dump()) (store->printStorePath(storePath)) - (immutable) + (locked) (time(0)).exec(); } @@ -91,7 +91,7 @@ struct CacheImpl : Cache auto infoJSON = stmt.getStr(0); auto storePath = store->parseStorePath(stmt.getStr(1)); - auto immutable = stmt.getInt(2) != 0; + auto locked = stmt.getInt(2) != 0; auto timestamp = stmt.getInt(3); store->addTempRoot(storePath); @@ -105,7 +105,7 @@ struct CacheImpl : Cache inAttrsJSON, infoJSON, store->printStorePath(storePath)); return Result { - .expired = !immutable && (settings.tarballTtl.get() == 0 || timestamp + settings.tarballTtl < time(0)), + .expired = !locked && (settings.tarballTtl.get() == 0 || timestamp + settings.tarballTtl < time(0)), .infoAttrs = jsonToAttrs(nlohmann::json::parse(infoJSON)), .storePath = std::move(storePath) }; diff --git a/src/libfetchers/cache.hh b/src/libfetchers/cache.hh index 3db4f081c..3763ee2a6 100644 --- a/src/libfetchers/cache.hh +++ b/src/libfetchers/cache.hh @@ -13,7 +13,7 @@ struct Cache const Attrs & inAttrs, const Attrs & infoAttrs, const StorePath & storePath, - bool immutable) = 0; + bool locked) = 0; virtual std::optional<std::pair<Attrs, StorePath>> lookup( ref<Store> store, diff --git a/src/libfetchers/fetch-settings.cc b/src/libfetchers/fetch-settings.cc new file mode 100644 index 000000000..e7d5244dc --- /dev/null +++ b/src/libfetchers/fetch-settings.cc @@ -0,0 +1,13 @@ +#include "fetch-settings.hh" + +namespace nix { + +FetchSettings::FetchSettings() +{ +} + +FetchSettings fetchSettings; + +static GlobalConfig::Register rFetchSettings(&fetchSettings); + +} diff --git a/src/libfetchers/fetch-settings.hh b/src/libfetchers/fetch-settings.hh new file mode 100644 index 000000000..04c9feda0 --- /dev/null +++ b/src/libfetchers/fetch-settings.hh @@ -0,0 +1,93 @@ +#pragma once + +#include "types.hh" +#include "config.hh" +#include "util.hh" + +#include <map> +#include <limits> + +#include <sys/types.h> + +namespace nix { + +struct FetchSettings : public Config +{ + FetchSettings(); + + Setting<StringMap> accessTokens{this, {}, "access-tokens", + R"( + Access tokens used to access protected GitHub, GitLab, or + other locations requiring token-based authentication. + + Access tokens are specified as a string made up of + space-separated `host=token` values. The specific token + used is selected by matching the `host` portion against the + "host" specification of the input. The actual use of the + `token` value is determined by the type of resource being + accessed: + + * Github: the token value is the OAUTH-TOKEN string obtained + as the Personal Access Token from the Github server (see + https://docs.github.com/en/developers/apps/building-oauth-apps/authorizing-oauth-apps). + + * Gitlab: the token value is either the OAuth2 token or the + Personal Access Token (these are different types tokens + for gitlab, see + https://docs.gitlab.com/12.10/ee/api/README.html#authentication). + The `token` value should be `type:tokenstring` where + `type` is either `OAuth2` or `PAT` to indicate which type + of token is being specified. + + Example `~/.config/nix/nix.conf`: + + ``` + access-tokens = github.com=23ac...b289 gitlab.mycompany.com=PAT:A123Bp_Cd..EfG gitlab.com=OAuth2:1jklw3jk + ``` + + Example `~/code/flake.nix`: + + ```nix + input.foo = { + type = "gitlab"; + host = "gitlab.mycompany.com"; + owner = "mycompany"; + repo = "pro"; + }; + ``` + + This example specifies three tokens, one each for accessing + github.com, gitlab.mycompany.com, and sourceforge.net. + + The `input.foo` uses the "gitlab" fetcher, which might + requires specifying the token type along with the token + value. + )"}; + + Setting<bool> allowDirty{this, true, "allow-dirty", + "Whether to allow dirty Git/Mercurial trees."}; + + Setting<bool> warnDirty{this, true, "warn-dirty", + "Whether to warn about dirty Git/Mercurial trees."}; + + Setting<std::string> flakeRegistry{this, "https://github.com/NixOS/flake-registry/raw/master/flake-registry.json", "flake-registry", + "Path or URI of the global flake registry."}; + + Setting<bool> useRegistries{this, true, "use-registries", + "Whether to use flake registries to resolve flake references."}; + + Setting<bool> acceptFlakeConfig{this, false, "accept-flake-config", + "Whether to accept nix configuration from a flake without prompting."}; + + Setting<std::string> commitLockFileSummary{ + this, "", "commit-lockfile-summary", + R"( + The commit summary to use when committing changed flake lock files. If + empty, the summary is generated based on the action performed. + )"}; +}; + +// FIXME: don't use a global variable. +extern FetchSettings fetchSettings; + +} diff --git a/src/libfetchers/fetchers.cc b/src/libfetchers/fetchers.cc index 7a88b4acc..4c457966d 100644 --- a/src/libfetchers/fetchers.cc +++ b/src/libfetchers/fetchers.cc @@ -24,11 +24,11 @@ static void fixupInput(Input & input) input.getType(); input.getRef(); if (input.getRev()) - input.immutable = true; + input.locked = true; input.getRevCount(); input.getLastModified(); if (input.getNarHash()) - input.immutable = true; + input.locked = true; } Input Input::fromURL(const ParsedURL & url) @@ -124,15 +124,13 @@ std::pair<Tree, Input> Input::fetch(ref<Store> store) const debug("using substituted/cached input '%s' in '%s'", to_string(), store->printStorePath(storePath)); - auto actualPath = store->toRealPath(storePath); - - return {fetchers::Tree(std::move(actualPath), std::move(storePath)), *this}; + return {Tree { .actualPath = store->toRealPath(storePath), .storePath = std::move(storePath) }, *this}; } catch (Error & e) { debug("substitution of input '%s' failed: %s", to_string(), e.what()); } } - auto [tree, input] = [&]() -> std::pair<Tree, Input> { + auto [storePath, input] = [&]() -> std::pair<StorePath, Input> { try { return scheme->fetch(store, *this); } catch (Error & e) { @@ -141,8 +139,10 @@ std::pair<Tree, Input> Input::fetch(ref<Store> store) const } }(); - if (tree.actualPath == "") - tree.actualPath = store->toRealPath(tree.storePath); + Tree tree { + .actualPath = store->toRealPath(storePath), + .storePath = storePath, + }; auto narHash = store->queryPathInfo(tree.storePath)->narHash; input.attrs.insert_or_assign("narHash", narHash.to_string(SRI, true)); @@ -165,7 +165,7 @@ std::pair<Tree, Input> Input::fetch(ref<Store> store) const input.to_string(), *prevRevCount); } - input.immutable = true; + input.locked = true; assert(input.hasAllInfo()); @@ -209,7 +209,7 @@ StorePath Input::computeStorePath(Store & store) const { auto narHash = getNarHash(); if (!narHash) - throw Error("cannot compute store path for mutable input '%s'", to_string()); + throw Error("cannot compute store path for unlocked input '%s'", to_string()); return store.makeFixedOutputPath(getName(), FixedOutputInfo { { .method = FileIngestionMethod::Recursive, diff --git a/src/libfetchers/fetchers.hh b/src/libfetchers/fetchers.hh index c43b047a7..bc9a76b0b 100644 --- a/src/libfetchers/fetchers.hh +++ b/src/libfetchers/fetchers.hh @@ -16,7 +16,6 @@ struct Tree { Path actualPath; StorePath storePath; - Tree(Path && actualPath, StorePath && storePath) : actualPath(actualPath), storePath(std::move(storePath)) {} }; struct InputScheme; @@ -35,7 +34,7 @@ struct Input std::shared_ptr<InputScheme> scheme; // note: can be null Attrs attrs; - bool immutable = false; + bool locked = false; bool direct = true; /* path of the parent of this input, used for relative path resolution */ @@ -60,9 +59,9 @@ public: one that goes through a registry. */ bool isDirect() const { return direct; } - /* Check whether this is an "immutable" input, that is, + /* Check whether this is a "locked" input, that is, one that contains a commit hash or content hash. */ - bool isImmutable() const { return immutable; } + bool isLocked() const { return locked; } bool hasAllInfo() const; @@ -70,6 +69,8 @@ public: bool contains(const Input & other) const; + /* Fetch the input into the Nix store, returning the location in + the Nix store and the locked input. */ std::pair<Tree, Input> fetch(ref<Store> store) const; Input applyOverrides( @@ -131,7 +132,7 @@ struct InputScheme virtual void markChangedFile(const Input & input, std::string_view file, std::optional<std::string> commitMsg); - virtual std::pair<Tree, Input> fetch(ref<Store> store, const Input & input) = 0; + virtual std::pair<StorePath, Input> fetch(ref<Store> store, const Input & input) = 0; }; void registerInputScheme(std::shared_ptr<InputScheme> && fetcher); @@ -147,14 +148,14 @@ DownloadFileResult downloadFile( ref<Store> store, const std::string & url, const std::string & name, - bool immutable, + bool locked, const Headers & headers = {}); std::pair<Tree, time_t> downloadTarball( ref<Store> store, const std::string & url, const std::string & name, - bool immutable, + bool locked, const Headers & headers = {}); } diff --git a/src/libfetchers/git.cc b/src/libfetchers/git.cc index 8468d2afc..c0beca2f2 100644 --- a/src/libfetchers/git.cc +++ b/src/libfetchers/git.cc @@ -6,6 +6,8 @@ #include "url-parts.hh" #include "pathlocks.hh" +#include "fetch-settings.hh" + #include <sys/time.h> #include <sys/wait.h> @@ -51,7 +53,7 @@ struct GitInputScheme : InputScheme for (auto &[name, value] : url.query) { if (name == "rev" || name == "ref") attrs.emplace(name, value); - else if (name == "shallow") + else if (name == "shallow" || name == "submodules") attrs.emplace(name, Explicit<bool> { value == "1" }); else url2.query.emplace(name, value); @@ -172,7 +174,7 @@ struct GitInputScheme : InputScheme return {isLocal, isLocal ? url.path : url.base}; } - std::pair<Tree, Input> fetch(ref<Store> store, const Input & _input) override + std::pair<StorePath, Input> fetch(ref<Store> store, const Input & _input) override { Input input(_input); @@ -187,7 +189,7 @@ struct GitInputScheme : InputScheme if (submodules) cacheType += "-submodules"; if (allRefs) cacheType += "-all-refs"; - auto getImmutableAttrs = [&]() + auto getLockedAttrs = [&]() { return Attrs({ {"type", cacheType}, @@ -197,21 +199,18 @@ struct GitInputScheme : InputScheme }; auto makeResult = [&](const Attrs & infoAttrs, StorePath && storePath) - -> std::pair<Tree, Input> + -> std::pair<StorePath, Input> { assert(input.getRev()); assert(!_input.getRev() || _input.getRev() == input.getRev()); if (!shallow) input.attrs.insert_or_assign("revCount", getIntAttr(infoAttrs, "revCount")); input.attrs.insert_or_assign("lastModified", getIntAttr(infoAttrs, "lastModified")); - return { - Tree(store->toRealPath(storePath), std::move(storePath)), - input - }; + return {std::move(storePath), input}; }; if (input.getRev()) { - if (auto res = getCache()->lookup(store, getImmutableAttrs())) + if (auto res = getCache()->lookup(store, getLockedAttrs())) return makeResult(res->first, std::move(res->second)); } @@ -249,10 +248,10 @@ struct GitInputScheme : InputScheme /* This is an unclean working tree. So copy all tracked files. */ - if (!settings.allowDirty) + if (!fetchSettings.allowDirty) throw Error("Git tree '%s' is dirty", actualUrl); - if (settings.warnDirty) + if (fetchSettings.warnDirty) warn("Git tree '%s' is dirty", actualUrl); auto gitOpts = Strings({ "-C", actualUrl, "ls-files", "-z" }); @@ -285,16 +284,13 @@ struct GitInputScheme : InputScheme "lastModified", haveCommits ? std::stoull(runProgram("git", true, { "-C", actualUrl, "log", "-1", "--format=%ct", "--no-show-signature", "HEAD" })) : 0); - return { - Tree(store->toRealPath(storePath), std::move(storePath)), - input - }; + return {std::move(storePath), input}; } } if (!input.getRef()) input.attrs.insert_or_assign("ref", isLocal ? readHead(actualUrl) : "master"); - Attrs mutableAttrs({ + Attrs unlockedAttrs({ {"type", cacheType}, {"name", name}, {"url", actualUrl}, @@ -313,7 +309,7 @@ struct GitInputScheme : InputScheme } else { - if (auto res = getCache()->lookup(store, mutableAttrs)) { + if (auto res = getCache()->lookup(store, unlockedAttrs)) { auto rev2 = Hash::parseAny(getStrAttr(res->first, "rev"), htSHA1); if (!input.getRev() || input.getRev() == rev2) { input.attrs.insert_or_assign("rev", rev2.gitRev()); @@ -324,17 +320,13 @@ struct GitInputScheme : InputScheme Path cacheDir = getCacheDir() + "/nix/gitv3/" + hashString(htSHA256, actualUrl).to_string(Base32, false); repoDir = cacheDir; - Path cacheDirLock = cacheDir + ".lock"; createDirs(dirOf(cacheDir)); - AutoCloseFD lock = openLockFile(cacheDirLock, true); - lockFile(lock.get(), ltWrite, true); + PathLocks cacheDirLock({cacheDir + ".lock"}); if (!pathExists(cacheDir)) { runProgram("git", true, { "-c", "init.defaultBranch=" + gitInitialBranch, "init", "--bare", repoDir }); } - deleteLockFile(cacheDirLock, lock.get()); - Path localRefFile = input.getRef()->compare(0, 5, "refs/") == 0 ? cacheDir + "/" + *input.getRef() @@ -399,6 +391,8 @@ struct GitInputScheme : InputScheme if (!input.getRev()) input.attrs.insert_or_assign("rev", Hash::parseAny(chomp(readFile(localRefFile)), htSHA1).gitRev()); + + // cache dir lock is removed at scope end; we will only use read-only operations on specific revisions in the remainder } bool isShallow = chomp(runProgram("git", true, { "-C", repoDir, "rev-parse", "--is-shallow-repository" })) == "true"; @@ -412,7 +406,7 @@ struct GitInputScheme : InputScheme /* Now that we know the ref, check again whether we have it in the store. */ - if (auto res = getCache()->lookup(store, getImmutableAttrs())) + if (auto res = getCache()->lookup(store, getLockedAttrs())) return makeResult(res->first, std::move(res->second)); Path tmpDir = createTempDir(); @@ -484,14 +478,14 @@ struct GitInputScheme : InputScheme if (!_input.getRev()) getCache()->add( store, - mutableAttrs, + unlockedAttrs, infoAttrs, storePath, false); getCache()->add( store, - getImmutableAttrs(), + getLockedAttrs(), infoAttrs, storePath, true); diff --git a/src/libfetchers/github.cc b/src/libfetchers/github.cc index ffc44e9e2..a1430f087 100644 --- a/src/libfetchers/github.cc +++ b/src/libfetchers/github.cc @@ -1,13 +1,16 @@ #include "filetransfer.hh" #include "cache.hh" -#include "fetchers.hh" #include "globals.hh" #include "store-api.hh" #include "types.hh" #include "url-parts.hh" +#include "fetchers.hh" +#include "fetch-settings.hh" + #include <optional> #include <nlohmann/json.hpp> +#include <fstream> namespace nix::fetchers { @@ -17,7 +20,7 @@ struct DownloadUrl Headers headers; }; -// A github or gitlab host +// A github, gitlab, or sourcehut host const static std::string hostRegexS = "[a-zA-Z0-9.]*"; // FIXME: check std::regex hostRegex(hostRegexS, std::regex::ECMAScript); @@ -156,7 +159,7 @@ struct GitArchiveInputScheme : InputScheme std::optional<std::string> getAccessToken(const std::string & host) const { - auto tokens = settings.accessTokens.get(); + auto tokens = fetchSettings.accessTokens.get(); if (auto token = get(tokens, host)) return *token; return {}; @@ -180,7 +183,7 @@ struct GitArchiveInputScheme : InputScheme virtual DownloadUrl getDownloadUrl(const Input & input) const = 0; - std::pair<Tree, Input> fetch(ref<Store> store, const Input & _input) override + std::pair<StorePath, Input> fetch(ref<Store> store, const Input & _input) override { Input input(_input); @@ -192,17 +195,14 @@ struct GitArchiveInputScheme : InputScheme input.attrs.erase("ref"); input.attrs.insert_or_assign("rev", rev->gitRev()); - Attrs immutableAttrs({ + Attrs lockedAttrs({ {"type", "git-tarball"}, {"rev", rev->gitRev()}, }); - if (auto res = getCache()->lookup(store, immutableAttrs)) { + if (auto res = getCache()->lookup(store, lockedAttrs)) { input.attrs.insert_or_assign("lastModified", getIntAttr(res->first, "lastModified")); - return { - Tree(store->toRealPath(res->second), std::move(res->second)), - input - }; + return {std::move(res->second), input}; } auto url = getDownloadUrl(input); @@ -213,7 +213,7 @@ struct GitArchiveInputScheme : InputScheme getCache()->add( store, - immutableAttrs, + lockedAttrs, { {"rev", rev->gitRev()}, {"lastModified", uint64_t(lastModified)} @@ -221,7 +221,7 @@ struct GitArchiveInputScheme : InputScheme tree.storePath, true); - return {std::move(tree), input}; + return {std::move(tree.storePath), input}; } }; @@ -300,7 +300,7 @@ struct GitLabInputScheme : GitArchiveInputScheme if ("PAT" == token.substr(0, fldsplit)) return std::make_pair("Private-token", token.substr(fldsplit+1)); warn("Unrecognized GitLab token type %s", token.substr(0, fldsplit)); - return std::nullopt; + return std::make_pair(token.substr(0,fldsplit), token.substr(fldsplit+1)); } Hash getRevFromRef(nix::ref<Store> store, const Input & input) const override @@ -348,7 +348,95 @@ struct GitLabInputScheme : GitArchiveInputScheme } }; +struct SourceHutInputScheme : GitArchiveInputScheme +{ + std::string type() override { return "sourcehut"; } + + std::optional<std::pair<std::string, std::string>> accessHeaderFromToken(const std::string & token) const override + { + // SourceHut supports both PAT and OAuth2. See + // https://man.sr.ht/meta.sr.ht/oauth.md + return std::pair<std::string, std::string>("Authorization", fmt("Bearer %s", token)); + // Note: This currently serves no purpose, as this kind of authorization + // does not allow for downloading tarballs on sourcehut private repos. + // Once it is implemented, however, should work as expected. + } + + Hash getRevFromRef(nix::ref<Store> store, const Input & input) const override + { + // TODO: In the future, when the sourcehut graphql API is implemented for mercurial + // and with anonymous access, this method should use it instead. + + auto ref = *input.getRef(); + + auto host = maybeGetStrAttr(input.attrs, "host").value_or("git.sr.ht"); + auto base_url = fmt("https://%s/%s/%s", + host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo")); + + Headers headers = makeHeadersWithAuthTokens(host); + + std::string ref_uri; + if (ref == "HEAD") { + auto file = store->toRealPath( + downloadFile(store, fmt("%s/HEAD", base_url), "source", false, headers).storePath); + std::ifstream is(file); + std::string line; + getline(is, line); + + auto ref_index = line.find("ref: "); + if (ref_index == std::string::npos) { + throw BadURL("in '%d', couldn't resolve HEAD ref '%d'", input.to_string(), ref); + } + + ref_uri = line.substr(ref_index+5, line.length()-1); + } else + ref_uri = fmt("refs/heads/%s", ref); + + auto file = store->toRealPath( + downloadFile(store, fmt("%s/info/refs", base_url), "source", false, headers).storePath); + std::ifstream is(file); + + std::string line; + std::string id; + while(getline(is, line)) { + auto index = line.find(ref_uri); + if (index != std::string::npos) { + id = line.substr(0, index-1); + break; + } + } + + if(id.empty()) + throw BadURL("in '%d', couldn't find ref '%d'", input.to_string(), ref); + + auto rev = Hash::parseAny(id, htSHA1); + debug("HEAD revision for '%s' is %s", fmt("%s/%s", base_url, ref), rev.gitRev()); + return rev; + } + + DownloadUrl getDownloadUrl(const Input & input) const override + { + auto host = maybeGetStrAttr(input.attrs, "host").value_or("git.sr.ht"); + auto url = fmt("https://%s/%s/%s/archive/%s.tar.gz", + host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"), + input.getRev()->to_string(Base16, false)); + + Headers headers = makeHeadersWithAuthTokens(host); + return DownloadUrl { url, headers }; + } + + void clone(const Input & input, const Path & destDir) override + { + auto host = maybeGetStrAttr(input.attrs, "host").value_or("git.sr.ht"); + Input::fromURL(fmt("git+https://%s/%s/%s", + host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"))) + .applyOverrides(input.getRef(), input.getRev()) + .clone(destDir); + } +}; + static auto rGitHubInputScheme = OnStartup([] { registerInputScheme(std::make_unique<GitHubInputScheme>()); }); static auto rGitLabInputScheme = OnStartup([] { registerInputScheme(std::make_unique<GitLabInputScheme>()); }); +static auto rSourceHutInputScheme = OnStartup([] { registerInputScheme(std::make_unique<SourceHutInputScheme>()); }); } diff --git a/src/libfetchers/indirect.cc b/src/libfetchers/indirect.cc index 10e59919a..9288fc6cf 100644 --- a/src/libfetchers/indirect.cc +++ b/src/libfetchers/indirect.cc @@ -94,7 +94,7 @@ struct IndirectInputScheme : InputScheme return input; } - std::pair<Tree, Input> fetch(ref<Store> store, const Input & input) override + std::pair<StorePath, Input> fetch(ref<Store> store, const Input & input) override { throw Error("indirect input '%s' cannot be fetched directly", input.to_string()); } diff --git a/src/libfetchers/mercurial.cc b/src/libfetchers/mercurial.cc index d52d4641b..8b82e9daa 100644 --- a/src/libfetchers/mercurial.cc +++ b/src/libfetchers/mercurial.cc @@ -5,6 +5,8 @@ #include "store-api.hh" #include "url-parts.hh" +#include "fetch-settings.hh" + #include <sys/time.h> using namespace std::string_literals; @@ -26,7 +28,7 @@ static RunOptions hgOptions(const Strings & args) } // runProgram wrapper that uses hgOptions instead of stock RunOptions. -static string runHg(const Strings & args, const std::optional<std::string> & input = {}) +static std::string runHg(const Strings & args, const std::optional<std::string> & input = {}) { RunOptions opts = hgOptions(args); opts.input = input; @@ -143,7 +145,7 @@ struct MercurialInputScheme : InputScheme return {isLocal, isLocal ? url.path : url.base}; } - std::pair<Tree, Input> fetch(ref<Store> store, const Input & _input) override + std::pair<StorePath, Input> fetch(ref<Store> store, const Input & _input) override { Input input(_input); @@ -165,10 +167,10 @@ struct MercurialInputScheme : InputScheme /* This is an unclean working tree. So copy all tracked files. */ - if (!settings.allowDirty) + if (!fetchSettings.allowDirty) throw Error("Mercurial tree '%s' is unclean", actualUrl); - if (settings.warnDirty) + if (fetchSettings.warnDirty) warn("Mercurial tree '%s' is unclean", actualUrl); input.attrs.insert_or_assign("ref", chomp(runHg({ "branch", "-R", actualUrl }))); @@ -193,16 +195,13 @@ struct MercurialInputScheme : InputScheme auto storePath = store->addToStore(input.getName(), actualUrl, FileIngestionMethod::Recursive, htSHA256, filter); - return { - Tree(store->toRealPath(storePath), std::move(storePath)), - input - }; + return {std::move(storePath), input}; } } if (!input.getRef()) input.attrs.insert_or_assign("ref", "default"); - auto getImmutableAttrs = [&]() + auto getLockedAttrs = [&]() { return Attrs({ {"type", "hg"}, @@ -212,32 +211,29 @@ struct MercurialInputScheme : InputScheme }; auto makeResult = [&](const Attrs & infoAttrs, StorePath && storePath) - -> std::pair<Tree, Input> + -> std::pair<StorePath, Input> { assert(input.getRev()); assert(!_input.getRev() || _input.getRev() == input.getRev()); input.attrs.insert_or_assign("revCount", getIntAttr(infoAttrs, "revCount")); - return { - Tree(store->toRealPath(storePath), std::move(storePath)), - input - }; + return {std::move(storePath), input}; }; if (input.getRev()) { - if (auto res = getCache()->lookup(store, getImmutableAttrs())) + if (auto res = getCache()->lookup(store, getLockedAttrs())) return makeResult(res->first, std::move(res->second)); } auto revOrRef = input.getRev() ? input.getRev()->gitRev() : *input.getRef(); - Attrs mutableAttrs({ + Attrs unlockedAttrs({ {"type", "hg"}, {"name", name}, {"url", actualUrl}, {"ref", *input.getRef()}, }); - if (auto res = getCache()->lookup(store, mutableAttrs)) { + if (auto res = getCache()->lookup(store, unlockedAttrs)) { auto rev2 = Hash::parseAny(getStrAttr(res->first, "rev"), htSHA1); if (!input.getRev() || input.getRev() == rev2) { input.attrs.insert_or_assign("rev", rev2.gitRev()); @@ -260,7 +256,7 @@ struct MercurialInputScheme : InputScheme runHg({ "pull", "-R", cacheDir, "--", actualUrl }); } catch (ExecError & e) { - string transJournal = cacheDir + "/.hg/store/journal"; + auto transJournal = cacheDir + "/.hg/store/journal"; /* hg throws "abandoned transaction" error only if this file exists */ if (pathExists(transJournal)) { runHg({ "recover", "-R", cacheDir }); @@ -283,7 +279,7 @@ struct MercurialInputScheme : InputScheme auto revCount = std::stoull(tokens[1]); input.attrs.insert_or_assign("ref", tokens[2]); - if (auto res = getCache()->lookup(store, getImmutableAttrs())) + if (auto res = getCache()->lookup(store, getLockedAttrs())) return makeResult(res->first, std::move(res->second)); Path tmpDir = createTempDir(); @@ -303,14 +299,14 @@ struct MercurialInputScheme : InputScheme if (!_input.getRev()) getCache()->add( store, - mutableAttrs, + unlockedAttrs, infoAttrs, storePath, false); getCache()->add( store, - getImmutableAttrs(), + getLockedAttrs(), infoAttrs, storePath, true); diff --git a/src/libfetchers/path.cc b/src/libfetchers/path.cc index fb5702c4c..59e228e97 100644 --- a/src/libfetchers/path.cc +++ b/src/libfetchers/path.cc @@ -80,7 +80,7 @@ struct PathInputScheme : InputScheme // nothing to do } - std::pair<Tree, Input> fetch(ref<Store> store, const Input & input) override + std::pair<StorePath, Input> fetch(ref<Store> store, const Input & input) override { std::string absPath; auto path = getStrAttr(input.attrs, "path"); @@ -97,7 +97,7 @@ struct PathInputScheme : InputScheme // for security, ensure that if the parent is a store path, it's inside it if (store->isInStore(parent)) { auto storePath = store->printStorePath(store->toStorePath(parent).first); - if (!isInDir(absPath, storePath)) + if (!isDirOrInDir(absPath, storePath)) throw BadStorePath("relative path '%s' points outside of its parent's store path '%s'", path, storePath); } } else @@ -115,10 +115,7 @@ struct PathInputScheme : InputScheme // FIXME: try to substitute storePath. storePath = store->addToStore("source", absPath); - return { - Tree(store->toRealPath(*storePath), std::move(*storePath)), - input - }; + return {std::move(*storePath), input}; } }; diff --git a/src/libfetchers/registry.cc b/src/libfetchers/registry.cc index f35359d4b..acd1ff866 100644 --- a/src/libfetchers/registry.cc +++ b/src/libfetchers/registry.cc @@ -5,6 +5,8 @@ #include "store-api.hh" #include "local-fs-store.hh" +#include "fetch-settings.hh" + #include <nlohmann/json.hpp> namespace nix::fetchers { @@ -150,7 +152,7 @@ void overrideRegistry( static std::shared_ptr<Registry> getGlobalRegistry(ref<Store> store) { static auto reg = [&]() { - auto path = settings.flakeRegistry.get(); + auto path = fetchSettings.flakeRegistry.get(); if (!hasPrefix(path, "/")) { auto storePath = downloadFile(store, path, "flake-registry.json", false).storePath; diff --git a/src/libfetchers/tarball.cc b/src/libfetchers/tarball.cc index efd34932c..4be923148 100644 --- a/src/libfetchers/tarball.cc +++ b/src/libfetchers/tarball.cc @@ -13,7 +13,7 @@ DownloadFileResult downloadFile( ref<Store> store, const std::string & url, const std::string & name, - bool immutable, + bool locked, const Headers & headers) { // FIXME: check store @@ -67,8 +67,8 @@ DownloadFileResult downloadFile( storePath = std::move(cached->storePath); } else { StringSink sink; - dumpString(*res.data, sink); - auto hash = hashString(htSHA256, *res.data); + dumpString(res.data, sink); + auto hash = hashString(htSHA256, res.data); ValidPathInfo info { *store, { @@ -81,10 +81,10 @@ DownloadFileResult downloadFile( {}, }, }, - hashString(htSHA256, *sink.s), + hashString(htSHA256, sink.s), }; - info.narSize = sink.s->size(); - auto source = StringSource { *sink.s }; + info.narSize = sink.s.size(); + auto source = StringSource { sink.s }; store->addToStore(info, source, NoRepair, NoCheckSigs); storePath = std::move(info.path); } @@ -94,7 +94,7 @@ DownloadFileResult downloadFile( inAttrs, infoAttrs, *storePath, - immutable); + locked); if (url != res.effectiveUri) getCache()->add( @@ -106,7 +106,7 @@ DownloadFileResult downloadFile( }, infoAttrs, *storePath, - immutable); + locked); return { .storePath = std::move(*storePath), @@ -119,7 +119,7 @@ std::pair<Tree, time_t> downloadTarball( ref<Store> store, const std::string & url, const std::string & name, - bool immutable, + bool locked, const Headers & headers) { Attrs inAttrs({ @@ -132,11 +132,11 @@ std::pair<Tree, time_t> downloadTarball( if (cached && !cached->expired) return { - Tree(store->toRealPath(cached->storePath), std::move(cached->storePath)), + Tree { .actualPath = store->toRealPath(cached->storePath), .storePath = std::move(cached->storePath) }, getIntAttr(cached->infoAttrs, "lastModified") }; - auto res = downloadFile(store, url, name, immutable, headers); + auto res = downloadFile(store, url, name, locked, headers); std::optional<StorePath> unpackedStorePath; time_t lastModified; @@ -166,10 +166,10 @@ std::pair<Tree, time_t> downloadTarball( inAttrs, infoAttrs, *unpackedStorePath, - immutable); + locked); return { - Tree(store->toRealPath(*unpackedStorePath), std::move(*unpackedStorePath)), + Tree { .actualPath = store->toRealPath(*unpackedStorePath), .storePath = std::move(*unpackedStorePath) }, lastModified, }; } @@ -182,6 +182,7 @@ struct TarballInputScheme : InputScheme if (!hasSuffix(url.path, ".zip") && !hasSuffix(url.path, ".tar") + && !hasSuffix(url.path, ".tgz") && !hasSuffix(url.path, ".tar.gz") && !hasSuffix(url.path, ".tar.xz") && !hasSuffix(url.path, ".tar.bz2") @@ -207,7 +208,7 @@ struct TarballInputScheme : InputScheme Input input; input.attrs = attrs; - //input.immutable = (bool) maybeGetStrAttr(input.attrs, "hash"); + //input.locked = (bool) maybeGetStrAttr(input.attrs, "hash"); return input; } @@ -230,10 +231,10 @@ struct TarballInputScheme : InputScheme return true; } - std::pair<Tree, Input> fetch(ref<Store> store, const Input & input) override + std::pair<StorePath, Input> fetch(ref<Store> store, const Input & input) override { auto tree = downloadTarball(store, getStrAttr(input.attrs, "url"), input.getName(), false).first; - return {std::move(tree), input}; + return {std::move(tree.storePath), input}; } }; |