From 04d13a96e33f18bc2d1c5606dbdda1d3331ec944 Mon Sep 17 00:00:00 2001 From: eveeifyeve <88671402+Eveeifyeve@users.noreply.github.com> Date: Wed, 11 Feb 2026 12:28:49 -0500 Subject: [PATCH] libstore: migrate `caFile`, `netrcFile`, and `downloadSpeed` to `FileTransferSettings` The `caFile`, `netrcFile`, and `downloadSpeed` settings are only used by the file transfer subsystem but lived in the global `Settings` class. This moves them to `FileTransferSettings` where they belong. Co-authored-by: Amaan Qureshi --- src/libfetchers/registry.cc | 2 +- src/libmain/shared.cc | 4 +- src/libstore-test-support/https-store.cc | 6 +- src/libstore/builtins/fetchurl.cc | 8 +- src/libstore/filetransfer.cc | 25 ++++- src/libstore/globals.cc | 70 ++++++------- .../include/nix/store/filetransfer.hh | 65 ++++++++++++ src/libstore/include/nix/store/globals.hh | 98 +++++-------------- src/libstore/unix/build/derivation-builder.cc | 5 +- .../unix/build/linux-derivation-builder.cc | 3 +- 10 files changed, 162 insertions(+), 124 deletions(-) diff --git a/src/libfetchers/registry.cc b/src/libfetchers/registry.cc index f96ef89b3..a19661f22 100644 --- a/src/libfetchers/registry.cc +++ b/src/libfetchers/registry.cc @@ -92,7 +92,7 @@ void Registry::remove(const Input & input) static std::filesystem::path getSystemRegistryPath() { - return settings.nixConfDir / "registry.json"; + return nixConfDir() / "registry.json"; } static std::shared_ptr getSystemRegistry(const Settings & settings) diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index 527a88c13..68a71e337 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -305,9 +305,9 @@ void printVersion(const std::string & programName) std::cout << "System type: " << settings.thisSystem << "\n"; std::cout << "Additional system types: " << concatStringsSep(", ", settings.extraPlatforms.get()) << "\n"; std::cout << "Features: " << concatStringsSep(", ", cfg) << "\n"; - std::cout << "System configuration file: " << (settings.nixConfDir / "nix.conf").string() << "\n"; + std::cout << "System configuration file: " << nixConfFile() << "\n"; std::cout << "User configuration files: " - << os_string_to_string(ExecutablePath{.directories = settings.nixUserConfFiles}.render()) << "\n"; + << os_string_to_string(ExecutablePath{.directories = nixUserConfFiles()}.render()) << "\n"; std::cout << "Store directory: " << settings.nixStore << "\n"; std::cout << "State directory: " << settings.nixStateDir << "\n"; } diff --git a/src/libstore-test-support/https-store.cc b/src/libstore-test-support/https-store.cc index bcf5ec177..e5a34eba1 100644 --- a/src/libstore-test-support/https-store.cc +++ b/src/libstore-test-support/https-store.cc @@ -80,13 +80,13 @@ void HttpsBinaryCacheStoreTest::SetUp() std::this_thread::sleep_for(std::chrono::milliseconds(50)); /* FIXME: Don't use global settings. Tests are not run concurrently, so this is fine for now. */ - oldCaCert = settings.caFile; - settings.caFile = caCert.string(); + oldCaCert = fileTransferSettings.caFile; + fileTransferSettings.caFile = caCert.string(); } void HttpsBinaryCacheStoreTest::TearDown() { - settings.caFile = oldCaCert; + fileTransferSettings.caFile = oldCaCert; serverPid.kill(); delTmpDir.reset(); } diff --git a/src/libstore/builtins/fetchurl.cc b/src/libstore/builtins/fetchurl.cc index 095260a17..cab11f7a1 100644 --- a/src/libstore/builtins/fetchurl.cc +++ b/src/libstore/builtins/fetchurl.cc @@ -14,12 +14,12 @@ static void builtinFetchurl(const BuiltinBuilderContext & ctx) this to be stored in a file. It would be nice if we could just pass a pointer to the data. */ if (ctx.netrcData != "") { - settings.netrcFile = "netrc"; - writeFile(settings.netrcFile, ctx.netrcData, 0600); + fileTransferSettings.netrcFile = "netrc"; + writeFile(fileTransferSettings.netrcFile, ctx.netrcData, 0600); } - settings.caFile = "ca-certificates.crt"; - writeFile(*settings.caFile.get(), ctx.caFileData, 0600); + fileTransferSettings.caFile = "ca-certificates.crt"; + writeFile(*fileTransferSettings.caFile.get(), ctx.caFileData, 0600); auto out = get(ctx.drv.outputs, "out"); if (!out) diff --git a/src/libstore/filetransfer.cc b/src/libstore/filetransfer.cc index 823d3a457..20433d642 100644 --- a/src/libstore/filetransfer.cc +++ b/src/libstore/filetransfer.cc @@ -35,6 +35,22 @@ namespace nix { const unsigned int RETRY_TIME_MS_DEFAULT = 250; const unsigned int RETRY_TIME_MS_TOO_MANY_REQUESTS = 60000; +std::filesystem::path FileTransferSettings::getDefaultSSLCertFile() +{ + for (auto & fn : + {"/etc/ssl/certs/ca-certificates.crt", "/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"}) + if (pathAccessible(fn)) + return fn; + return ""; +} + +FileTransferSettings::FileTransferSettings() +{ + auto sslOverride = getEnv("NIX_SSL_CERT_FILE").value_or(getEnv("SSL_CERT_FILE").value_or("")); + if (sslOverride != "") + caFile = sslOverride; +} + FileTransferSettings fileTransferSettings; static GlobalConfig::Register rFileTransferSettings(&fileTransferSettings); @@ -482,8 +498,9 @@ struct curlFileTransfer : public FileTransfer curl_easy_setopt(req, CURLOPT_HTTPHEADER, requestHeaders.get()); - if (settings.downloadSpeed.get() > 0) - curl_easy_setopt(req, CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t) (settings.downloadSpeed.get() * 1024)); + if (fileTransferSettings.downloadSpeed.get() > 0) + curl_easy_setopt( + req, CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t) (fileTransferSettings.downloadSpeed.get() * 1024)); if (request.method == HttpMethod::Head) curl_easy_setopt(req, CURLOPT_NOBODY, 1); @@ -512,7 +529,7 @@ struct curlFileTransfer : public FileTransfer curl_easy_setopt(req, CURLOPT_SEEKDATA, this); } - if (auto & caFile = settings.caFile.get()) + if (auto & caFile = fileTransferSettings.caFile.get()) curl_easy_setopt(req, CURLOPT_CAINFO, caFile->c_str()); #if !defined(_WIN32) @@ -525,7 +542,7 @@ struct curlFileTransfer : public FileTransfer /* If no file exist in the specified path, curl continues to work anyway as if netrc support was disabled. */ - curl_easy_setopt(req, CURLOPT_NETRC_FILE, settings.netrcFile.get().c_str()); + curl_easy_setopt(req, CURLOPT_NETRC_FILE, fileTransferSettings.netrcFile.get().c_str()); curl_easy_setopt(req, CURLOPT_NETRC, CURL_NETRC_OPTIONAL); if (writtenToSink) diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc index 695e512f6..3f9b3493d 100644 --- a/src/libstore/globals.cc +++ b/src/libstore/globals.cc @@ -1,12 +1,14 @@ #include "nix/store/globals.hh" #include "nix/util/config-global.hh" #include "nix/util/current-process.hh" +#include "nix/util/executable-path.hh" #include "nix/util/archive.hh" #include "nix/util/args.hh" #include "nix/util/abstract-setting-to-json.hh" #include "nix/util/compute-levels.hh" #include "nix/util/executable-path.hh" #include "nix/util/signals.hh" +#include "nix/store/filetransfer.hh" #include #include @@ -88,24 +90,6 @@ Settings::Settings() #endif (getEnvNonEmpty("NIX_STORE_DIR").value_or(getEnvNonEmpty("NIX_STORE").value_or(NIX_STORE_DIR)))) , nixStateDir(canonPath(getEnvNonEmpty("NIX_STATE_DIR").value_or(NIX_STATE_DIR))) - , nixConfDir(canonPath(getEnvOsNonEmpty(OS_STR("NIX_CONF_DIR")) - .transform([](auto && s) { return std::filesystem::path(s); }) - .value_or(resolveNixConfDir()))) - , nixUserConfFiles([] { - // Use the paths specified in NIX_USER_CONF_FILES if it has been defined - auto nixConfFiles = getEnvOs(OS_STR("NIX_USER_CONF_FILES")); - if (nixConfFiles.has_value()) { - return ExecutablePath::parse(*nixConfFiles).directories; - } - - // Use the paths specified by the XDG spec - std::vector files; - auto dirs = getConfigDirs(); - for (auto & dir : dirs) { - files.insert(files.end(), dir / "nix.conf"); - } - return files; - }()) , nixDaemonSocketFile(canonPath(getEnvOsNonEmpty(OS_STR("NIX_DAEMON_SOCKET_PATH")) .transform([](auto && s) { return std::filesystem::path(s); }) .value_or(nixStateDir / DEFAULT_SOCKET_PATH))) @@ -115,10 +99,6 @@ Settings::Settings() #endif allowSymlinkedStore = getEnv("NIX_IGNORE_SYMLINK_STORE") == "1"; - auto sslOverride = getEnv("NIX_SSL_CERT_FILE").value_or(getEnv("SSL_CERT_FILE").value_or("")); - if (sslOverride != "") - caFile = sslOverride; - /* Backwards compatibility. */ auto s = getEnv("NIX_REMOTE_SYSTEMS"); if (s) { @@ -151,21 +131,21 @@ Settings::Settings() void loadConfFile(AbstractConfig & config) { - auto applyConfigFile = [&](const Path & path) { + auto applyConfigFile = [&](const std::filesystem::path & path) { try { std::string contents = readFile(path); - config.applyConfig(contents, path); + config.applyConfig(contents, path.string()); } catch (SystemError &) { } }; - applyConfigFile((settings.nixConfDir / "nix.conf").string()); + applyConfigFile(nixConfFile()); /* We only want to send overrides to the daemon, i.e. stuff from ~/.nix/nix.conf or the command line. */ config.resetOverridden(); - auto files = settings.nixUserConfFiles; + auto files = nixUserConfFiles(); for (auto file = files.rbegin(); file != files.rend(); file++) { applyConfigFile(file->string()); } @@ -176,6 +156,35 @@ void loadConfFile(AbstractConfig & config) } } +const std::filesystem::path & nixConfDir() +{ + static const std::filesystem::path dir = + canonPath(getEnvOsNonEmpty(OS_STR("NIX_CONF_DIR")) + .transform([](auto && s) { return std::filesystem::path(s); }) + .value_or(resolveNixConfDir())); + return dir; +} + +const std::vector & nixUserConfFiles() +{ + static const std::vector files = [] { + // Use the paths specified in NIX_USER_CONF_FILES if it has been defined + auto nixConfFiles = getEnvOs(OS_STR("NIX_USER_CONF_FILES")); + if (nixConfFiles.has_value()) { + return ExecutablePath::parse(*nixConfFiles).directories; + } + + // Use the paths specified by the XDG spec + std::vector files; + auto dirs = getConfigDirs(); + for (auto & dir : dirs) { + files.insert(files.end(), dir / "nix.conf"); + } + return files; + }(); + return files; +} + unsigned int Settings::getDefaultCores() { const unsigned int concurrency = std::max(1U, std::thread::hardware_concurrency()); @@ -275,15 +284,6 @@ bool Settings::isWSL1() #endif } -std::filesystem::path Settings::getDefaultSSLCertFile() -{ - for (auto & fn : - {"/etc/ssl/certs/ca-certificates.crt", "/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"}) - if (pathAccessible(fn)) - return fn; - return ""; -} - const ExternalBuilder * Settings::findExternalDerivationBuilderIfSupported(const Derivation & drv) { if (auto it = std::ranges::find_if( diff --git a/src/libstore/include/nix/store/filetransfer.hh b/src/libstore/include/nix/store/filetransfer.hh index 500d9ebd7..9a509bb86 100644 --- a/src/libstore/include/nix/store/filetransfer.hh +++ b/src/libstore/include/nix/store/filetransfer.hh @@ -12,6 +12,7 @@ #include "nix/util/url.hh" #include "nix/store/config.hh" +#include "nix/store/globals.hh" #if NIX_WITH_AWS_AUTH # include "nix/store/aws-creds.hh" #endif @@ -21,6 +22,12 @@ namespace nix { struct FileTransferSettings : Config { +private: + static std::filesystem::path getDefaultSSLCertFile(); + +public: + FileTransferSettings(); + Setting enableHttp2{this, true, "http2", "Whether to enable HTTP/2 support."}; Setting userAgentSuffix{ @@ -77,6 +84,64 @@ struct FileTransferSettings : Config not processed quickly enough to exceed the size of this buffer, downloads may stall. The default is 1048576 (1 MiB). )"}; + + Setting downloadSpeed{ + this, + 0, + "download-speed", + R"( + Specify the maximum transfer rate in kilobytes per second you want + Nix to use for downloads. + )"}; + + Setting netrcFile{ + this, + nixConfDir() / "netrc", + "netrc-file", + R"( + If set to an absolute path to a `netrc` file, Nix uses the HTTP + authentication credentials in this file when trying to download from + a remote host through HTTP or HTTPS. Defaults to + `$NIX_CONF_DIR/netrc`. + + The `netrc` file consists of a list of accounts in the following + format: + + machine my-machine + login my-username + password my-password + + For the exact syntax, see [the `curl` + documentation](https://ec.haxx.se/usingcurl-netrc.html). + + > **Note** + > + > This must be an absolute path, and `~` is not resolved. For + > example, `~/.netrc` won't resolve to your home directory's + > `.netrc`. + )"}; + + Setting> caFile{ + this, + getDefaultSSLCertFile(), + "ssl-cert-file", + R"( + The path of a file containing CA certificates used to + authenticate `https://` downloads. Nix by default uses + the first of the following files that exists: + + 1. `/etc/ssl/certs/ca-certificates.crt` + 2. `/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt` + + The path can be overridden by the following environment + variables, in order of precedence: + + 1. `NIX_SSL_CERT_FILE` + 2. `SSL_CERT_FILE` + )", + {}, + // Don't document the machine-specific default value + false}; }; extern FileTransferSettings fileTransferSettings; diff --git a/src/libstore/include/nix/store/globals.hh b/src/libstore/include/nix/store/globals.hh index a011228ff..454522753 100644 --- a/src/libstore/include/nix/store/globals.hh +++ b/src/libstore/include/nix/store/globals.hh @@ -29,6 +29,30 @@ struct MaxBuildJobsSetting : public BaseSetting unsigned int parse(const std::string & str) const override; }; +/** + * The directory where system configuration files are stored. + * + * This is needed very early during initialization, before a main + * `Settings` object can be constructed. + */ +const std::filesystem::path & nixConfDir(); + +/** + * The path to the system configuration file (`nix.conf`). + */ +static inline std::filesystem::path nixConfFile() +{ + return nixConfDir() / "nix.conf"; +} + +/** + * A list of user configuration files to load. + * + * This is needed very early during initialization, before a main + * `Settings` object can be constructed. + */ +const std::vector & nixUserConfFiles(); + struct LogFileSettings : public virtual Config { /** @@ -72,8 +96,6 @@ class Settings : public virtual Config, private LocalSettings, private LogFileSe bool isWSL1(); - std::filesystem::path getDefaultSSLCertFile(); - public: Settings(); @@ -118,16 +140,6 @@ public: */ std::filesystem::path nixStateDir; - /** - * The directory where system configuration files are stored. - */ - std::filesystem::path nixConfDir; - - /** - * A list of user configuration files to load. - */ - std::vector nixUserConfFiles; - /** * File name of the socket the daemon listens to. */ @@ -314,7 +326,7 @@ public: Setting builders{ this, - "@" + nixConfDir.string() + "/machines", + "@" + (nixConfDir() / "machines").string(), "builders", R"( A semicolon- or newline-separated list of build machines. @@ -732,64 +744,6 @@ public: /nix/store/a724znygmd1cac856j3gfsyvih3lw07j-bash-4.4-p23`. )"}; - Setting downloadSpeed{ - this, - 0, - "download-speed", - R"( - Specify the maximum transfer rate in kilobytes per second you want - Nix to use for downloads. - )"}; - - Setting netrcFile{ - this, - (nixConfDir / "netrc").string(), - "netrc-file", - R"( - If set to an absolute path to a `netrc` file, Nix uses the HTTP - authentication credentials in this file when trying to download from - a remote host through HTTP or HTTPS. Defaults to - `$NIX_CONF_DIR/netrc`. - - The `netrc` file consists of a list of accounts in the following - format: - - machine my-machine - login my-username - password my-password - - For the exact syntax, see [the `curl` - documentation](https://ec.haxx.se/usingcurl-netrc.html). - - > **Note** - > - > This must be an absolute path, and `~` is not resolved. For - > example, `~/.netrc` won't resolve to your home directory's - > `.netrc`. - )"}; - - Setting> caFile{ - this, - getDefaultSSLCertFile(), - "ssl-cert-file", - R"( - The path of a file containing CA certificates used to - authenticate `https://` downloads. Nix by default uses - the first of the following files that exists: - - 1. `/etc/ssl/certs/ca-certificates.crt` - 2. `/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt` - - The path can be overridden by the following environment - variables, in order of precedence: - - 1. `NIX_SSL_CERT_FILE` - 2. `SSL_CERT_FILE` - )", - {}, - // Don't document the machine-specific default value - false}; - Setting useXDGBaseDirectories{ this, false, @@ -843,7 +797,7 @@ public: }; // FIXME: don't use a global variable. -extern Settings settings; +extern nix::Settings settings; /** * Load the configuration (from `nix.conf`, `NIX_CONFIG`, etc.) into the diff --git a/src/libstore/unix/build/derivation-builder.cc b/src/libstore/unix/build/derivation-builder.cc index d98fddcfc..d1038eba1 100644 --- a/src/libstore/unix/build/derivation-builder.cc +++ b/src/libstore/unix/build/derivation-builder.cc @@ -18,6 +18,7 @@ #include "nix/store/globals.hh" #include "nix/store/build/derivation-env-desugar.hh" #include "nix/util/terminal.hh" +#include "nix/store/filetransfer.hh" #include #include @@ -1261,11 +1262,11 @@ void DerivationBuilderImpl::runChild(RunChildArgs args) if (drv.isBuiltin() && drv.builder == "builtin:fetchurl") { try { - ctx.netrcData = readFile(settings.netrcFile); + ctx.netrcData = readFile(fileTransferSettings.netrcFile); } catch (SystemError &) { } - if (auto & caFile = settings.caFile.get()) + if (auto & caFile = fileTransferSettings.caFile.get()) try { ctx.caFileData = readFile(*caFile); } catch (SystemError &) { diff --git a/src/libstore/unix/build/linux-derivation-builder.cc b/src/libstore/unix/build/linux-derivation-builder.cc index 4af88bb15..04e9f2faa 100644 --- a/src/libstore/unix/build/linux-derivation-builder.cc +++ b/src/libstore/unix/build/linux-derivation-builder.cc @@ -2,6 +2,7 @@ # include "nix/store/globals.hh" # include "nix/store/personality.hh" +# include "nix/store/filetransfer.hh" # include "nix/util/cgroup.hh" # include "nix/util/linux-namespaces.hh" # include "nix/util/logging.hh" @@ -562,7 +563,7 @@ struct ChrootLinuxDerivationBuilder : ChrootDerivationBuilder, LinuxDerivationBu if (pathExists(path)) ss.push_back(path); - if (auto & caFile = settings.caFile.get()) { + if (auto & caFile = fileTransferSettings.caFile.get()) { if (pathExists(*caFile)) pathsInChroot.try_emplace( "/etc/ssl/certs/ca-certificates.crt", canonPath(caFile->native(), true), true);