Compare commits
1 Commits
cloneable-
...
settings-g
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2933eb3684 |
11
.github/workflows/upload-release.yml
vendored
11
.github/workflows/upload-release.yml
vendored
@@ -39,17 +39,6 @@ jobs:
|
||||
role-to-assume: "arn:aws:iam::080433136561:role/nix-release"
|
||||
role-session-name: nix-release-oidc-${{ github.run_id }}
|
||||
aws-region: eu-west-1
|
||||
- name: Disable containerd image store
|
||||
run: |
|
||||
# Docker 28+ defaults to the containerd image store, which
|
||||
# pushes layers uncompressed instead of gzip. OCI clients
|
||||
# that only support gzip (e.g. go-containerregistry) fail
|
||||
# with "gzip: invalid header". Disabling the containerd
|
||||
# snapshotter restores the classic storage driver, which
|
||||
# preserves gzip-compressed layers through the
|
||||
# `docker load` / `docker push` pipeline.
|
||||
echo '{"features":{"containerd-snapshotter":false}}' | sudo tee /etc/docker/daemon.json > /dev/null
|
||||
sudo systemctl restart docker
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
|
||||
with:
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
---
|
||||
synopsis: New command `nix store roots-daemon` for serving GC roots
|
||||
prs: [15143]
|
||||
---
|
||||
|
||||
New command [`nix store roots-daemon`](@docroot@/command-ref/new-cli/nix3-store-roots-daemon.md) runs a daemon that serves garbage collector roots over a Unix domain socket.
|
||||
It enables the garbage collector to discover runtime roots when the main Nix daemon doesn't have `CAP_SYS_PTRACE` capability and therefore cannot scan `/proc`.
|
||||
|
||||
The garbage collector can be configured to use this daemon via the [`use-roots-daemon`](@docroot@/store/types/local-store.md#store-experimental-option-use-roots-daemon) store setting.
|
||||
|
||||
This feature requires the [`local-overlay-store` experimental feature](@docroot@/development/experimental-features.md#xp-feature-local-overlay-store).
|
||||
8
flake.lock
generated
8
flake.lock
generated
@@ -63,11 +63,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1771043024,
|
||||
"narHash": "sha256-WoiezqWJQ3OHILah+p6rzNXdJceEAmAhyDFZFZ6pZzY=",
|
||||
"rev": "3aadb7ca9eac2891d52a9dec199d9580a6e2bf44",
|
||||
"lastModified": 1769089682,
|
||||
"narHash": "sha256-Xu+7iYcAuOvsI2wdkUcIEmkqEJbvvE6n7qR9QNjJyP4=",
|
||||
"rev": "078d69f03934859a181e81ba987c2bb033eebfc5",
|
||||
"type": "tarball",
|
||||
"url": "https://releases.nixos.org/nixos/25.11/nixos-25.11.5960.3aadb7ca9eac/nixexprs.tar.xz"
|
||||
"url": "https://releases.nixos.org/nixos/25.11/nixos-25.11.4506.078d69f03934/nixexprs.tar.xz"
|
||||
},
|
||||
"original": {
|
||||
"type": "tarball",
|
||||
|
||||
@@ -115,9 +115,6 @@
|
||||
}
|
||||
// lib.optionalAttrs (crossSystem == "x86_64-unknown-freebsd13") {
|
||||
useLLVM = true;
|
||||
}
|
||||
// lib.optionalAttrs (crossSystem == "x86_64-w64-mingw32") {
|
||||
emulator = pkgs: "${pkgs.buildPackages.wineWow64Packages.stable_11}/bin/wine";
|
||||
};
|
||||
overlays = [
|
||||
(overlayFor (pkgs: pkgs.${stdenv}))
|
||||
|
||||
@@ -9,9 +9,3 @@ endif
|
||||
if 'address' in get_option('b_sanitize')
|
||||
deps_other += declare_dependency(sources : 'asan-options.cc')
|
||||
endif
|
||||
|
||||
if 'undefined' in get_option('b_sanitize')
|
||||
add_project_arguments('-DNIX_UBSAN_ENABLED=1', language : 'cpp')
|
||||
else
|
||||
add_project_arguments('-DNIX_UBSAN_ENABLED=0', language : 'cpp')
|
||||
endif
|
||||
|
||||
@@ -27,19 +27,13 @@ add_project_arguments(
|
||||
'-Wignored-qualifiers',
|
||||
'-Wimplicit-fallthrough',
|
||||
'-Wno-deprecated-declarations',
|
||||
'-Wno-interference-size', # Used for C++ ABI only. We don't provide any guarantees about different march tunings.
|
||||
language : 'cpp',
|
||||
)
|
||||
|
||||
# GCC doesn't benefit much from precompiled headers.
|
||||
do_pch = cxx.get_id() == 'clang'
|
||||
|
||||
if cxx.get_id() == 'gcc'
|
||||
add_project_arguments(
|
||||
'-Wno-interference-size', # Used for C++ ABI only. We don't provide any guarantees about different march tunings.
|
||||
language : 'cpp',
|
||||
)
|
||||
endif
|
||||
|
||||
# This is a clang-only option for improving build times.
|
||||
# It forces the instantiation of templates in the PCH itself and
|
||||
# not every translation unit it's included in.
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "nix/cmd/command.hh"
|
||||
#include "nix/cmd/legacy.hh"
|
||||
#include "nix/cmd/markdown.hh"
|
||||
#include "nix/main/shared.hh"
|
||||
#include "nix/store/globals.hh"
|
||||
#include "nix/store/store-open.hh"
|
||||
#include "nix/store/local-fs-store.hh"
|
||||
@@ -75,7 +76,7 @@ ref<StoreConfig> StoreConfigCommand::getStoreConfig()
|
||||
|
||||
ref<StoreConfig> StoreConfigCommand::createStoreConfig()
|
||||
{
|
||||
return resolveStoreConfig(StoreReference{settings.storeUri.get()});
|
||||
return resolveStoreConfig(settings, StoreReference{settings.storeUri.get()});
|
||||
}
|
||||
|
||||
void StoreConfigCommand::run()
|
||||
@@ -129,7 +130,7 @@ CopyCommand::CopyCommand()
|
||||
|
||||
ref<StoreConfig> CopyCommand::createStoreConfig()
|
||||
{
|
||||
return !srcUri ? StoreCommand::createStoreConfig() : resolveStoreConfig(StoreReference{*srcUri});
|
||||
return !srcUri ? StoreCommand::createStoreConfig() : resolveStoreConfig(settings, StoreReference{*srcUri});
|
||||
}
|
||||
|
||||
ref<Store> CopyCommand::getDstStore()
|
||||
@@ -137,7 +138,7 @@ ref<Store> CopyCommand::getDstStore()
|
||||
if (!srcUri && !dstUri)
|
||||
throw UsageError("you must pass '--from' and/or '--to'");
|
||||
|
||||
return !dstUri ? openStore() : openStore(StoreReference{*dstUri});
|
||||
return !dstUri ? openStore(settings) : openStore(settings, StoreReference{*dstUri});
|
||||
}
|
||||
|
||||
EvalCommand::EvalCommand()
|
||||
@@ -159,7 +160,7 @@ EvalCommand::~EvalCommand()
|
||||
ref<Store> EvalCommand::getEvalStore()
|
||||
{
|
||||
if (!evalStore)
|
||||
evalStore = evalStoreUrl ? openStore(StoreReference{*evalStoreUrl}) : getStore();
|
||||
evalStore = evalStoreUrl ? openStore(settings, StoreReference{*evalStoreUrl}) : getStore();
|
||||
return ref<Store>(evalStore);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,12 +19,12 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
fetchers::Settings fetchSettings;
|
||||
fetchers::Settings fetchSettings{settings};
|
||||
|
||||
static GlobalConfig::Register rFetchSettings(&fetchSettings);
|
||||
|
||||
EvalSettings evalSettings{
|
||||
settings.readOnlyMode,
|
||||
settings,
|
||||
{
|
||||
{
|
||||
"flake",
|
||||
@@ -135,7 +135,7 @@ MixEvalArgs::MixEvalArgs()
|
||||
fetchers::overrideRegistry(from.input, to.input, extraAttrs);
|
||||
}},
|
||||
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
|
||||
completeFlakeRef(completions, openStore(), prefix);
|
||||
completeFlakeRef(completions, openStore(settings), prefix);
|
||||
}},
|
||||
});
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
std::string fetchBuildLog(ref<Store> store, const StorePath & path, std::string_view what)
|
||||
std::string fetchBuildLog(Settings & settings, ref<Store> store, const StorePath & path, std::string_view what)
|
||||
{
|
||||
auto subs = getDefaultSubstituters();
|
||||
auto subs = getDefaultSubstituters(settings);
|
||||
|
||||
subs.push_front(store);
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
class Settings;
|
||||
|
||||
/**
|
||||
* Fetch the build log for a store path, searching the store and its
|
||||
* substituters.
|
||||
@@ -18,6 +20,6 @@ namespace nix {
|
||||
* @return The build log content.
|
||||
* @throws Error if the build log is not available.
|
||||
*/
|
||||
std::string fetchBuildLog(ref<Store> store, const StorePath & path, std::string_view what);
|
||||
std::string fetchBuildLog(Settings & settings, ref<Store> store, const StorePath & path, std::string_view what);
|
||||
|
||||
} // namespace nix
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "nix/store/globals.hh"
|
||||
#include "nix/cmd/installable-value.hh"
|
||||
#include "nix/store/outputs-spec.hh"
|
||||
#include "nix/cmd/command.hh"
|
||||
|
||||
@@ -40,8 +40,8 @@ void sigintHandler(int signo)
|
||||
static detail::ReplCompleterMixin * curRepl; // ugly
|
||||
|
||||
#if !USE_READLINE
|
||||
static char * completionCallback(char * s, int * match) noexcept
|
||||
try {
|
||||
static char * completionCallback(char * s, int * match)
|
||||
{
|
||||
auto possible = curRepl->completePrefix(s);
|
||||
if (possible.size() == 1) {
|
||||
*match = 1;
|
||||
@@ -73,12 +73,10 @@ try {
|
||||
|
||||
*match = 0;
|
||||
return nullptr;
|
||||
} catch (...) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static int listPossibleCallback(char * s, char *** avp) noexcept
|
||||
try {
|
||||
static int listPossibleCallback(char * s, char *** avp)
|
||||
{
|
||||
auto possible = curRepl->completePrefix(s);
|
||||
|
||||
if (possible.size() > (std::numeric_limits<int>::max() / sizeof(char *)))
|
||||
@@ -107,9 +105,6 @@ try {
|
||||
*avp = vp;
|
||||
|
||||
return ac;
|
||||
} catch (...) {
|
||||
*avp = nullptr;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -564,7 +564,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
||||
settings.readOnlyMode = true;
|
||||
Finally roModeReset([&]() { settings.readOnlyMode = false; });
|
||||
RunPager pager;
|
||||
auto log = fetchBuildLog(state->store, drvPath, drvPathRaw);
|
||||
auto log = fetchBuildLog(settings, state->store, drvPath, drvPathRaw);
|
||||
logger->writeToStdout(log);
|
||||
} else {
|
||||
runNix("nix-shell", {drvPathRaw});
|
||||
|
||||
@@ -132,9 +132,8 @@ nix_eval_state_builder * nix_eval_state_builder_new(nix_c_context * context, Sto
|
||||
return unsafe_new_with_self<nix_eval_state_builder>([&](auto * self) {
|
||||
return nix_eval_state_builder{
|
||||
.store = nix::ref<nix::Store>(store->ptr),
|
||||
.settings = nix::EvalSettings{/* &bool */ self->readOnlyMode},
|
||||
.fetchSettings = nix::fetchers::Settings{},
|
||||
.readOnlyMode = true,
|
||||
.settings = nix::EvalSettings{cStoreSettings},
|
||||
.fetchSettings = nix::fetchers::Settings{cStoreSettings},
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -153,8 +152,7 @@ nix_err nix_eval_state_builder_load(nix_c_context * context, nix_eval_state_buil
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
// TODO: load in one go?
|
||||
builder->settings.readOnlyMode = nix::settings.readOnlyMode;
|
||||
loadConfFile(cStoreSettings);
|
||||
loadConfFile(builder->settings);
|
||||
loadConfFile(builder->fetchSettings);
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@ struct nix_eval_state_builder
|
||||
nix::EvalSettings settings;
|
||||
nix::fetchers::Settings fetchSettings;
|
||||
nix::LookupPath lookupPath;
|
||||
// TODO: make an EvalSettings setting own this instead?
|
||||
bool readOnlyMode;
|
||||
};
|
||||
|
||||
struct EvalState
|
||||
|
||||
@@ -26,18 +26,18 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
LibExprTest(ref<Store> store, auto && makeEvalSettings)
|
||||
: LibStoreTest()
|
||||
, evalSettings(makeEvalSettings(readOnlyMode))
|
||||
LibExprTest(auto && makeEvalSettings, auto &&... args)
|
||||
: LibStoreTest(args...)
|
||||
, evalSettings(makeEvalSettings(settings))
|
||||
, state({}, store, fetchSettings, evalSettings, nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
LibExprTest()
|
||||
: LibExprTest(openStore("dummy://"), [](bool & readOnlyMode) {
|
||||
EvalSettings settings{readOnlyMode};
|
||||
settings.nixPath = {};
|
||||
return settings;
|
||||
: LibExprTest([](Settings & settings) {
|
||||
EvalSettings evalSettings{settings};
|
||||
evalSettings.nixPath = {};
|
||||
return evalSettings;
|
||||
})
|
||||
{
|
||||
}
|
||||
@@ -66,8 +66,8 @@ protected:
|
||||
}
|
||||
|
||||
bool readOnlyMode = true;
|
||||
fetchers::Settings fetchSettings{};
|
||||
EvalSettings evalSettings{readOnlyMode};
|
||||
fetchers::Settings fetchSettings{settings};
|
||||
EvalSettings evalSettings{settings};
|
||||
EvalState state;
|
||||
};
|
||||
|
||||
|
||||
@@ -179,12 +179,15 @@ class PureEvalTest : public LibExprTest
|
||||
{
|
||||
public:
|
||||
PureEvalTest()
|
||||
: LibExprTest(openStore("dummy://", {{"read-only", "false"}}), [](bool & readOnlyMode) {
|
||||
EvalSettings settings{readOnlyMode};
|
||||
settings.pureEval = true;
|
||||
settings.restrictEval = true;
|
||||
return settings;
|
||||
})
|
||||
: LibExprTest{
|
||||
[](auto & settings) {
|
||||
EvalSettings evalSettings{settings};
|
||||
evalSettings.pureEval = true;
|
||||
evalSettings.restrictEval = true;
|
||||
return evalSettings;
|
||||
},
|
||||
[](auto & settings) { return openStore(settings, "dummy://", {{"read-only", "false"}}); },
|
||||
}
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -13,7 +13,8 @@ TEST_F(ValueTest, unsetValue)
|
||||
{
|
||||
Value unsetValue;
|
||||
ASSERT_EQ(false, unsetValue.isValid());
|
||||
ASSERT_EQ(nThunk, unsetValue.type</*invalidIsThunk=*/true>());
|
||||
ASSERT_EQ(nThunk, unsetValue.type(true));
|
||||
ASSERT_DEATH(unsetValue.type(), "");
|
||||
}
|
||||
|
||||
TEST_F(ValueTest, vInt)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
namespace nix::eval_cache {
|
||||
|
||||
CachedEvalError::CachedEvalError(ref<AttrCursor> cursor, Symbol attr)
|
||||
: CloneableError(cursor->root->state, "cached failure of attribute '%s'", cursor->getAttrPathStr(attr))
|
||||
: EvalError(cursor->root->state, "cached failure of attribute '%s'", cursor->getAttrPathStr(attr))
|
||||
, cursor(cursor)
|
||||
, attr(attr)
|
||||
{
|
||||
@@ -63,7 +63,7 @@ struct AttrDb
|
||||
|
||||
SymbolTable & symbols;
|
||||
|
||||
AttrDb(const StoreDirConfig & cfg, const Hash & fingerprint, SymbolTable & symbols)
|
||||
AttrDb(bool useSQLiteWAL, const StoreDirConfig & cfg, const Hash & fingerprint, SymbolTable & symbols)
|
||||
: cfg(cfg)
|
||||
, _state(std::make_unique<Sync<State>>())
|
||||
, symbols(symbols)
|
||||
@@ -75,7 +75,7 @@ struct AttrDb
|
||||
|
||||
auto dbPath = cacheDir / (fingerprint.to_string(HashFormat::Base16, false) + ".sqlite");
|
||||
|
||||
state->db = SQLite(dbPath, {.useWAL = settings.useSQLiteWAL});
|
||||
state->db = SQLite(dbPath, {.useWAL = useSQLiteWAL});
|
||||
state->db.isCache();
|
||||
state->db.exec(schema);
|
||||
|
||||
@@ -287,10 +287,11 @@ struct AttrDb
|
||||
}
|
||||
};
|
||||
|
||||
static std::shared_ptr<AttrDb> makeAttrDb(const StoreDirConfig & cfg, const Hash & fingerprint, SymbolTable & symbols)
|
||||
static std::shared_ptr<AttrDb>
|
||||
makeAttrDb(bool useSQLiteWAL, const StoreDirConfig & cfg, const Hash & fingerprint, SymbolTable & symbols)
|
||||
{
|
||||
try {
|
||||
return std::make_shared<AttrDb>(cfg, fingerprint, symbols);
|
||||
return std::make_shared<AttrDb>(useSQLiteWAL, cfg, fingerprint, symbols);
|
||||
} catch (SQLiteError &) {
|
||||
ignoreExceptionExceptInterrupt();
|
||||
return nullptr;
|
||||
@@ -299,7 +300,8 @@ static std::shared_ptr<AttrDb> makeAttrDb(const StoreDirConfig & cfg, const Hash
|
||||
|
||||
EvalCache::EvalCache(
|
||||
std::optional<std::reference_wrapper<const Hash>> useCache, EvalState & state, RootLoader rootLoader)
|
||||
: db(useCache ? makeAttrDb(*state.store, *useCache, state.symbols) : nullptr)
|
||||
: db(useCache ? makeAttrDb(state.store->config.settings.useSQLiteWAL, *state.store, *useCache, state.symbols)
|
||||
: nullptr)
|
||||
, state(state)
|
||||
, rootLoader(rootLoader)
|
||||
{
|
||||
@@ -707,7 +709,7 @@ StorePath AttrCursor::forceDerivation()
|
||||
auto aDrvPath = getAttr(root->state.s.drvPath);
|
||||
auto drvPath = root->state.store->parseStorePath(aDrvPath->getString());
|
||||
drvPath.requireDerivation();
|
||||
if (!root->state.store->isValidPath(drvPath) && !settings.readOnlyMode) {
|
||||
if (!root->state.store->isValidPath(drvPath) && !root->state.store->config.settings.readOnlyMode) {
|
||||
/* The eval cache contains 'drvPath', but the actual path has
|
||||
been garbage-collected. So force it to be regenerated. */
|
||||
aDrvPath->forceValue();
|
||||
|
||||
@@ -48,8 +48,8 @@ Strings EvalSettings::parseNixPath(const std::string & s)
|
||||
return res;
|
||||
}
|
||||
|
||||
EvalSettings::EvalSettings(bool & readOnlyMode, EvalSettings::LookupPathHooks lookupPathHooks)
|
||||
: readOnlyMode{readOnlyMode}
|
||||
EvalSettings::EvalSettings(nix::Settings & storeSettings, EvalSettings::LookupPathHooks lookupPathHooks)
|
||||
: storeSettings{storeSettings}
|
||||
, lookupPathHooks{lookupPathHooks}
|
||||
{
|
||||
auto var = getEnv("NIX_ABORT_ON_WARN");
|
||||
@@ -57,7 +57,7 @@ EvalSettings::EvalSettings(bool & readOnlyMode, EvalSettings::LookupPathHooks lo
|
||||
builtinsAbortOnWarn = true;
|
||||
}
|
||||
|
||||
Strings EvalSettings::getDefaultNixPath()
|
||||
Strings EvalSettings::getDefaultNixPath(nix::Settings & settings)
|
||||
{
|
||||
Strings res;
|
||||
auto add = [&](const std::filesystem::path & p, const std::string & s = std::string()) {
|
||||
@@ -70,7 +70,7 @@ Strings EvalSettings::getDefaultNixPath()
|
||||
}
|
||||
};
|
||||
|
||||
add(std::filesystem::path{getNixDefExpr()} / "channels");
|
||||
add(std::filesystem::path{getNixDefExpr(settings)} / "channels");
|
||||
auto profilesDirOpts = settings.getProfileDirsOptions();
|
||||
add(rootChannelsDir(profilesDirOpts) / "nixpkgs", "nixpkgs");
|
||||
add(rootChannelsDir(profilesDirOpts));
|
||||
@@ -101,10 +101,10 @@ std::string EvalSettings::resolvePseudoUrl(std::string_view url)
|
||||
const std::string & EvalSettings::getCurrentSystem() const
|
||||
{
|
||||
const auto & evalSystem = currentSystem.get();
|
||||
return evalSystem != "" ? evalSystem : settings.thisSystem.get();
|
||||
return evalSystem != "" ? evalSystem : storeSettings.thisSystem.get();
|
||||
}
|
||||
|
||||
std::filesystem::path getNixDefExpr()
|
||||
std::filesystem::path getNixDefExpr(const Settings & settings)
|
||||
{
|
||||
return settings.useXDGBaseDirectories ? getStateDir() / "defexpr" : getHome() / ".nix-defexpr";
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "nix/store/filetransfer.hh"
|
||||
#include "nix/expr/function-trace.hh"
|
||||
#include "nix/store/profiles.hh"
|
||||
#include "nix/store/globals.hh"
|
||||
#include "nix/expr/print.hh"
|
||||
#include "nix/fetchers/filtering-source-accessor.hh"
|
||||
#include "nix/util/memory-source-accessor.hh"
|
||||
@@ -330,7 +331,7 @@ EvalState::EvalState(
|
||||
lookupPath.elements.emplace_back(LookupPath::Elem::parse(i));
|
||||
}
|
||||
if (!settings.restrictEval) {
|
||||
for (auto & i : EvalSettings::getDefaultNixPath()) {
|
||||
for (auto & i : EvalSettings::getDefaultNixPath(store->config.settings)) {
|
||||
lookupPath.elements.emplace_back(LookupPath::Elem::parse(i));
|
||||
}
|
||||
}
|
||||
@@ -466,7 +467,7 @@ void EvalState::addConstant(const std::string & name, Value * v, Constant info)
|
||||
|
||||
We might know the type of a thunk in advance, so be allowed
|
||||
to just write it down in that case. */
|
||||
if (auto gotType = v->type</*invalidIsThunk=*/true>(); gotType != nThunk)
|
||||
if (auto gotType = v->type(true); gotType != nThunk)
|
||||
assert(info.type == gotType);
|
||||
|
||||
/* Install value the base environment. */
|
||||
@@ -885,7 +886,7 @@ void Value::mkPath(const SourcePath & path, EvalMemory & mem)
|
||||
mkPath(&*path.accessor, StringData::make(mem, path.path.abs()));
|
||||
}
|
||||
|
||||
[[gnu::always_inline]] inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
|
||||
inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
|
||||
{
|
||||
for (auto l = var.level; l; --l, env = env->up)
|
||||
;
|
||||
@@ -903,11 +904,11 @@ void Value::mkPath(const SourcePath & path, EvalMemory & mem)
|
||||
while (1) {
|
||||
forceAttrs(*env->values[0], fromWith->pos, "while evaluating the first subexpression of a with expression");
|
||||
if (auto j = env->values[0]->attrs()->get(var.name)) {
|
||||
if (countCalls) [[unlikely]]
|
||||
if (countCalls)
|
||||
attrSelects[j->pos]++;
|
||||
return j->value;
|
||||
}
|
||||
if (!fromWith->parentWith) [[unlikely]]
|
||||
if (!fromWith->parentWith)
|
||||
error<UndefinedVarError>("undefined variable '%1%'", symbols[var.name])
|
||||
.atPos(var.pos)
|
||||
.withFrame(*env, var)
|
||||
@@ -2508,7 +2509,7 @@ StorePath EvalState::copyPathToStore(NixStringContext & context, const SourcePat
|
||||
fetchSettings,
|
||||
*store,
|
||||
path.resolveSymlinks(SymlinkResolution::Ancestors),
|
||||
settings.readOnlyMode ? FetchMode::DryRun : FetchMode::Copy,
|
||||
settings.storeSettings.readOnlyMode ? FetchMode::DryRun : FetchMode::Copy,
|
||||
path.baseName(),
|
||||
ContentAddressMethod::Raw::NixArchive,
|
||||
nullptr,
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace nix::eval_cache {
|
||||
struct AttrDb;
|
||||
class AttrCursor;
|
||||
|
||||
struct CachedEvalError : CloneableError<CachedEvalError, EvalError>
|
||||
struct CachedEvalError : EvalError
|
||||
{
|
||||
const ref<AttrCursor> cursor;
|
||||
const Symbol attr;
|
||||
|
||||
@@ -18,7 +18,7 @@ class EvalErrorBuilder;
|
||||
*
|
||||
* Most subclasses should inherit from `EvalError` instead of this class.
|
||||
*/
|
||||
class EvalBaseError : public CloneableError<EvalBaseError, Error>
|
||||
class EvalBaseError : public Error
|
||||
{
|
||||
template<class T>
|
||||
friend class EvalErrorBuilder;
|
||||
@@ -26,14 +26,14 @@ public:
|
||||
EvalState & state;
|
||||
|
||||
EvalBaseError(EvalState & state, ErrorInfo && errorInfo)
|
||||
: CloneableError(errorInfo)
|
||||
: Error(errorInfo)
|
||||
, state(state)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
explicit EvalBaseError(EvalState & state, const std::string & formatString, const Args &... formatArgs)
|
||||
: CloneableError(formatString, formatArgs...)
|
||||
: Error(formatString, formatArgs...)
|
||||
, state(state)
|
||||
{
|
||||
}
|
||||
@@ -60,23 +60,23 @@ MakeError(InfiniteRecursionError, EvalError);
|
||||
* Inherits from EvalBaseError (not EvalError) because resource exhaustion
|
||||
* should not be cached.
|
||||
*/
|
||||
struct StackOverflowError : public CloneableError<StackOverflowError, EvalBaseError>
|
||||
struct StackOverflowError : public EvalBaseError
|
||||
{
|
||||
StackOverflowError(EvalState & state)
|
||||
: CloneableError(state, "stack overflow; max-call-depth exceeded")
|
||||
: EvalBaseError(state, "stack overflow; max-call-depth exceeded")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
MakeError(IFDError, EvalBaseError);
|
||||
|
||||
struct InvalidPathError : public CloneableError<InvalidPathError, EvalError>
|
||||
struct InvalidPathError : public EvalError
|
||||
{
|
||||
public:
|
||||
Path path;
|
||||
|
||||
InvalidPathError(EvalState & state, const Path & path)
|
||||
: CloneableError(state, "path '%s' is not valid", path)
|
||||
: EvalError(state, "path '%s' is not valid", path)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -9,9 +9,15 @@ namespace nix {
|
||||
|
||||
class EvalState;
|
||||
struct PrimOp;
|
||||
class Settings;
|
||||
|
||||
struct EvalSettings : Config
|
||||
{
|
||||
/**
|
||||
* Reference to the "parent" store-layer settings.
|
||||
*/
|
||||
nix::Settings & storeSettings;
|
||||
|
||||
/**
|
||||
* Function used to interpret look path entries of a given scheme.
|
||||
*
|
||||
@@ -38,11 +44,9 @@ struct EvalSettings : Config
|
||||
*/
|
||||
using LookupPathHooks = std::map<std::string, std::function<LookupPathHook>>;
|
||||
|
||||
EvalSettings(bool & readOnlyMode, LookupPathHooks lookupPathHooks = {});
|
||||
EvalSettings(nix::Settings & settings, LookupPathHooks lookupPathHooks = {});
|
||||
|
||||
bool & readOnlyMode;
|
||||
|
||||
static Strings getDefaultNixPath();
|
||||
static Strings getDefaultNixPath(nix::Settings & settings);
|
||||
|
||||
static bool isPseudoUrl(std::string_view s);
|
||||
|
||||
@@ -366,6 +370,6 @@ struct EvalSettings : Config
|
||||
/**
|
||||
* Conventionally part of the default nix path in impure mode.
|
||||
*/
|
||||
std::filesystem::path getNixDefExpr();
|
||||
std::filesystem::path getNixDefExpr(const Settings & settings);
|
||||
|
||||
} // namespace nix
|
||||
|
||||
@@ -35,7 +35,7 @@ class BindingsBuilder;
|
||||
* about how this is mapped into the alignment bits to save significant memory.
|
||||
* This also restricts the number of internal types represented with distinct memory layouts.
|
||||
*/
|
||||
enum InternalType {
|
||||
typedef enum {
|
||||
tUninitialized = 0,
|
||||
/* layout: Single/zero field payload */
|
||||
tInt = 1,
|
||||
@@ -46,20 +46,16 @@ enum InternalType {
|
||||
tPrimOp,
|
||||
tAttrs,
|
||||
/* layout: Pair of pointers payload */
|
||||
tFirstPairOfPointers,
|
||||
tListSmall = tFirstPairOfPointers,
|
||||
tListSmall,
|
||||
tPrimOpApp,
|
||||
tApp,
|
||||
tThunk,
|
||||
tLambda,
|
||||
tLastPairOfPointers = tLambda,
|
||||
/* layout: Single untaggable field */
|
||||
tFirstSingleUntaggable,
|
||||
tListN = tFirstSingleUntaggable,
|
||||
tListN,
|
||||
tString,
|
||||
tPath,
|
||||
tNumberOfInternalTypes, // Must be last
|
||||
};
|
||||
} InternalType;
|
||||
|
||||
/**
|
||||
* This type abstracts over all actual value types in the language,
|
||||
@@ -637,7 +633,7 @@ class alignas(16)
|
||||
template<InternalType type, typename T, typename U>
|
||||
void setPairOfPointersPayload(T * firstPtrField, U * secondPtrField) noexcept
|
||||
{
|
||||
static_assert(type >= tFirstPairOfPointers && type <= tLastPairOfPointers);
|
||||
static_assert(type >= tListSmall && type <= tLambda);
|
||||
{
|
||||
auto firstFieldPayload = std::bit_cast<PackedPointer>(firstPtrField);
|
||||
assertAligned(firstFieldPayload);
|
||||
@@ -646,7 +642,7 @@ class alignas(16)
|
||||
{
|
||||
auto secondFieldPayload = std::bit_cast<PackedPointer>(secondPtrField);
|
||||
assertAligned(secondFieldPayload);
|
||||
payload[1] = (type - tFirstPairOfPointers) | secondFieldPayload;
|
||||
payload[1] = (type - tListSmall) | secondFieldPayload;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -674,11 +670,11 @@ protected:
|
||||
case pdListN:
|
||||
case pdString:
|
||||
case pdPath:
|
||||
return static_cast<InternalType>(tFirstSingleUntaggable + (pd - pdListN));
|
||||
return static_cast<InternalType>(tListN + (pd - pdListN));
|
||||
case pdPairOfPointers:
|
||||
return static_cast<InternalType>(tFirstPairOfPointers + (payload[1] & discriminatorMask));
|
||||
return static_cast<InternalType>(tListSmall + (payload[1] & discriminatorMask));
|
||||
[[unlikely]] default:
|
||||
nixUnreachableWhenHardened();
|
||||
unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1031,7 +1027,7 @@ private:
|
||||
T getStorage() const noexcept
|
||||
{
|
||||
if (getInternalType() != detail::payloadTypeToInternalType<T>) [[unlikely]]
|
||||
nixUnreachableWhenHardened();
|
||||
unreachable();
|
||||
T out;
|
||||
ValueStorage::getStorage(out);
|
||||
return out;
|
||||
@@ -1083,44 +1079,45 @@ public:
|
||||
* Returns the normal type of a Value. This only returns nThunk if
|
||||
* the Value hasn't been forceValue'd
|
||||
*
|
||||
* @param invalidIsThunk Instead of UB an an invalid (probably
|
||||
* @param invalidIsThunk Instead of aborting an an invalid (probably
|
||||
* 0, so uninitialized) internal type, return `nThunk`.
|
||||
*/
|
||||
template<bool invalidIsThunk = false>
|
||||
inline ValueType type() const
|
||||
inline ValueType type(bool invalidIsThunk = false) const
|
||||
{
|
||||
/* Explicit lookup table. switch() might compile down (and it does at least with GCC 14)
|
||||
to a jump table. Let's help the compiler a bit here. */
|
||||
static constexpr auto table = [] {
|
||||
std::array<ValueType, tNumberOfInternalTypes> t{};
|
||||
t[tUninitialized] = nThunk;
|
||||
t[tInt] = nInt;
|
||||
t[tBool] = nBool;
|
||||
t[tNull] = nNull;
|
||||
t[tFloat] = nFloat;
|
||||
t[tExternal] = nExternal;
|
||||
t[tAttrs] = nAttrs;
|
||||
t[tPrimOp] = nFunction;
|
||||
t[tLambda] = nFunction;
|
||||
t[tPrimOpApp] = nFunction;
|
||||
t[tApp] = nThunk;
|
||||
t[tThunk] = nThunk;
|
||||
t[tListSmall] = nList;
|
||||
t[tListN] = nList;
|
||||
t[tString] = nString;
|
||||
t[tPath] = nPath;
|
||||
return t;
|
||||
}();
|
||||
|
||||
auto it = getInternalType();
|
||||
if (it == tUninitialized || it >= tNumberOfInternalTypes) [[unlikely]] {
|
||||
if constexpr (invalidIsThunk)
|
||||
return nThunk;
|
||||
else
|
||||
nixUnreachableWhenHardened();
|
||||
switch (getInternalType()) {
|
||||
case tUninitialized:
|
||||
break;
|
||||
case tInt:
|
||||
return nInt;
|
||||
case tBool:
|
||||
return nBool;
|
||||
case tString:
|
||||
return nString;
|
||||
case tPath:
|
||||
return nPath;
|
||||
case tNull:
|
||||
return nNull;
|
||||
case tAttrs:
|
||||
return nAttrs;
|
||||
case tListSmall:
|
||||
case tListN:
|
||||
return nList;
|
||||
case tLambda:
|
||||
case tPrimOp:
|
||||
case tPrimOpApp:
|
||||
return nFunction;
|
||||
case tExternal:
|
||||
return nExternal;
|
||||
case tFloat:
|
||||
return nFloat;
|
||||
case tThunk:
|
||||
case tApp:
|
||||
return nThunk;
|
||||
}
|
||||
|
||||
return table[it];
|
||||
if (invalidIsThunk)
|
||||
return nThunk;
|
||||
else
|
||||
unreachable();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
class BadNixStringContextElem final : public CloneableError<BadNixStringContextElem, Error>
|
||||
class BadNixStringContextElem : public Error
|
||||
{
|
||||
public:
|
||||
std::string_view raw;
|
||||
|
||||
template<typename... Args>
|
||||
BadNixStringContextElem(std::string_view raw_, const Args &... args)
|
||||
: CloneableError("")
|
||||
: Error("")
|
||||
{
|
||||
raw = raw_;
|
||||
auto hf = HintFmt(args...);
|
||||
|
||||
@@ -28,7 +28,7 @@ deps_public_maybe_subproject = [
|
||||
subdir('nix-meson-build-support/subprojects')
|
||||
subdir('nix-meson-build-support/big-objs')
|
||||
|
||||
# Check for each of these functions, and create a define like `#define HAVE_SYSCONF 1`.
|
||||
# Check for each of these functions, and create a define like `#define HAVE_LCHOWN 1`.
|
||||
check_funcs = [
|
||||
'sysconf',
|
||||
]
|
||||
|
||||
@@ -1312,12 +1312,11 @@ static void prim_warn(EvalState & state, const PosIdx pos, Value ** args, Value
|
||||
state.forceString(*args[0], pos, "while evaluating the first argument; the message passed to builtins.warn");
|
||||
|
||||
{
|
||||
ErrorInfo info{
|
||||
.level = lvlWarn,
|
||||
.msg = HintFmt(std::string(msgStr)),
|
||||
.pos = state.positions[pos],
|
||||
.isFromExpr = true,
|
||||
};
|
||||
BaseError msg(std::string{msgStr});
|
||||
msg.atPos(state.positions[pos]);
|
||||
auto info = msg.info();
|
||||
info.level = lvlWarn;
|
||||
info.isFromExpr = true;
|
||||
logWarning(info);
|
||||
}
|
||||
|
||||
@@ -1820,8 +1819,8 @@ static void derivationStrictInternal(EvalState & state, std::string_view drvName
|
||||
Unless we are in read-only mode, that is, in which case we do not
|
||||
write anything. Users commonly do this to speed up evaluation in
|
||||
contexts where they don't actually want to build anything. */
|
||||
auto drvPath =
|
||||
settings.readOnlyMode ? computeStorePath(*state.store, drv) : state.store->writeDerivation(drv, state.repair);
|
||||
auto drvPath = state.settings.storeSettings.readOnlyMode ? computeStorePath(*state.store, drv)
|
||||
: state.store->writeDerivation(drv, state.repair);
|
||||
auto drvPathS = state.store->printStorePath(drvPath);
|
||||
|
||||
printMsg(lvlChatty, "instantiated '%1%' -> '%2%'", drvName, drvPathS);
|
||||
@@ -1936,7 +1935,7 @@ static void prim_storePath(EvalState & state, const PosIdx pos, Value ** args, V
|
||||
if (!state.store->isInStore(path.abs()))
|
||||
state.error<EvalError>("path '%1%' is not in the Nix store", path).atPos(pos).debugThrow();
|
||||
auto path2 = state.store->toStorePath(path.abs()).first;
|
||||
if (!settings.readOnlyMode)
|
||||
if (!state.settings.storeSettings.readOnlyMode)
|
||||
state.store->ensurePath(path2);
|
||||
context.insert(NixStringContextElem::Opaque{.path = path2});
|
||||
v.mkString(path.abs(), context, state.mem);
|
||||
@@ -2677,23 +2676,24 @@ static void prim_toFile(EvalState & state, const PosIdx pos, Value ** args, Valu
|
||||
.debugThrow();
|
||||
}
|
||||
|
||||
auto storePath = settings.readOnlyMode ? state.store->makeFixedOutputPathFromCA(
|
||||
name,
|
||||
TextInfo{
|
||||
.hash = hashString(HashAlgorithm::SHA256, contents),
|
||||
.references = std::move(refs),
|
||||
})
|
||||
: ({
|
||||
StringSource s{contents};
|
||||
state.store->addToStoreFromDump(
|
||||
s,
|
||||
name,
|
||||
FileSerialisationMethod::Flat,
|
||||
ContentAddressMethod::Raw::Text,
|
||||
HashAlgorithm::SHA256,
|
||||
refs,
|
||||
state.repair);
|
||||
});
|
||||
auto storePath = state.settings.storeSettings.readOnlyMode
|
||||
? state.store->makeFixedOutputPathFromCA(
|
||||
name,
|
||||
TextInfo{
|
||||
.hash = hashString(HashAlgorithm::SHA256, contents),
|
||||
.references = std::move(refs),
|
||||
})
|
||||
: ({
|
||||
StringSource s{contents};
|
||||
state.store->addToStoreFromDump(
|
||||
s,
|
||||
name,
|
||||
FileSerialisationMethod::Flat,
|
||||
ContentAddressMethod::Raw::Text,
|
||||
HashAlgorithm::SHA256,
|
||||
refs,
|
||||
state.repair);
|
||||
});
|
||||
|
||||
/* Note: we don't need to add `context' to the context of the
|
||||
result, since `storePath' itself has references to the paths
|
||||
@@ -2837,23 +2837,24 @@ static void addPath(
|
||||
|
||||
if (!expectedHash || !state.store->isValidPath(*expectedStorePath)) {
|
||||
// FIXME: support refs in fetchToStore()?
|
||||
auto dstPath = refs.empty() ? fetchToStore(
|
||||
state.fetchSettings,
|
||||
*state.store,
|
||||
path.resolveSymlinks(),
|
||||
settings.readOnlyMode ? FetchMode::DryRun : FetchMode::Copy,
|
||||
name,
|
||||
method,
|
||||
filter.get(),
|
||||
state.repair)
|
||||
: state.store->addToStore(
|
||||
name,
|
||||
path.resolveSymlinks(),
|
||||
method,
|
||||
HashAlgorithm::SHA256,
|
||||
refs,
|
||||
filter ? *filter.get() : defaultPathFilter,
|
||||
state.repair);
|
||||
auto dstPath = refs.empty()
|
||||
? fetchToStore(
|
||||
state.fetchSettings,
|
||||
*state.store,
|
||||
path.resolveSymlinks(),
|
||||
state.settings.storeSettings.readOnlyMode ? FetchMode::DryRun : FetchMode::Copy,
|
||||
name,
|
||||
method,
|
||||
filter.get(),
|
||||
state.repair)
|
||||
: state.store->addToStore(
|
||||
name,
|
||||
path.resolveSymlinks(),
|
||||
method,
|
||||
HashAlgorithm::SHA256,
|
||||
refs,
|
||||
filter ? *filter.get() : defaultPathFilter,
|
||||
state.repair);
|
||||
if (expectedHash && expectedStorePath != dstPath)
|
||||
state.error<EvalError>("store path mismatch in (possibly filtered) path added from '%s'", path)
|
||||
.atPos(pos)
|
||||
|
||||
@@ -271,7 +271,7 @@ static void prim_appendContext(EvalState & state, const PosIdx pos, Value ** arg
|
||||
if (!state.store->isStorePath(name))
|
||||
state.error<EvalError>("context key '%s' is not a store path", name).atPos(i.pos).debugThrow();
|
||||
auto namePath = state.store->parseStorePath(name);
|
||||
if (!settings.readOnlyMode)
|
||||
if (!state.settings.storeSettings.readOnlyMode)
|
||||
state.store->ensurePath(namePath);
|
||||
state.forceAttrs(*i.value, i.pos, "while evaluating the value of a string context");
|
||||
|
||||
|
||||
@@ -209,7 +209,7 @@ static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value ** args
|
||||
{.msg = HintFmt("'fetchClosure' does not support URL query parameters (in '%s')", *fromStoreUrl),
|
||||
.pos = state.positions[pos]});
|
||||
|
||||
auto fromStore = openStore(std::move(storeRef));
|
||||
auto fromStore = openStore(state.settings.storeSettings, std::move(storeRef));
|
||||
|
||||
if (toPath)
|
||||
runFetchClosureWithRewrite(state, pos, *fromStore, *fromPath, *toPath, v);
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
#include "nix_api_fetchers.h"
|
||||
#include "nix_api_fetchers_internal.hh"
|
||||
#include "nix_api_util_internal.h"
|
||||
#include "nix_api_store_internal.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
nix_fetchers_settings * nix_fetchers_settings_new(nix_c_context * context)
|
||||
{
|
||||
try {
|
||||
auto fetchersSettings = nix::make_ref<nix::fetchers::Settings>(nix::fetchers::Settings{});
|
||||
auto fetchersSettings = nix::make_ref<nix::fetchers::Settings>(nix::fetchers::Settings{cStoreSettings});
|
||||
return new nix_fetchers_settings{
|
||||
.settings = fetchersSettings,
|
||||
};
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "nix/util/json-utils.hh"
|
||||
#include "nix/store/globals.hh"
|
||||
#include "nix/fetchers/fetchers.hh"
|
||||
#include "nix/fetchers/fetch-settings.hh"
|
||||
#include "nix/util/json-utils.hh"
|
||||
|
||||
#include "nix/store/tests/test-main.hh"
|
||||
#include "nix/util/tests/characterization.hh"
|
||||
|
||||
namespace nix::fetchers {
|
||||
@@ -25,7 +28,8 @@ public:
|
||||
|
||||
TEST_F(AccessKeysTest, singleOrgGitHub)
|
||||
{
|
||||
fetchers::Settings fetchSettings = fetchers::Settings{};
|
||||
auto settings = getTestSettings();
|
||||
fetchers::Settings fetchSettings = fetchers::Settings{settings};
|
||||
fetchSettings.accessTokens.get().insert({"github.com/a", "token"});
|
||||
auto i = Input::fromURL(fetchSettings, "github:a/b");
|
||||
|
||||
@@ -35,7 +39,8 @@ TEST_F(AccessKeysTest, singleOrgGitHub)
|
||||
|
||||
TEST_F(AccessKeysTest, nonMatches)
|
||||
{
|
||||
fetchers::Settings fetchSettings = fetchers::Settings{};
|
||||
auto settings = getTestSettings();
|
||||
fetchers::Settings fetchSettings = fetchers::Settings{settings};
|
||||
fetchSettings.accessTokens.get().insert({"github.com", "token"});
|
||||
auto i = Input::fromURL(fetchSettings, "gitlab:github.com/evil");
|
||||
|
||||
@@ -45,7 +50,8 @@ TEST_F(AccessKeysTest, nonMatches)
|
||||
|
||||
TEST_F(AccessKeysTest, noPartialMatches)
|
||||
{
|
||||
fetchers::Settings fetchSettings = fetchers::Settings{};
|
||||
auto settings = getTestSettings();
|
||||
fetchers::Settings fetchSettings = fetchers::Settings{settings};
|
||||
fetchSettings.accessTokens.get().insert({"github.com/partial", "token"});
|
||||
auto i = Input::fromURL(fetchSettings, "github:partial-match/repo");
|
||||
|
||||
@@ -55,7 +61,8 @@ TEST_F(AccessKeysTest, noPartialMatches)
|
||||
|
||||
TEST_F(AccessKeysTest, repoGitHub)
|
||||
{
|
||||
fetchers::Settings fetchSettings = fetchers::Settings{};
|
||||
auto settings = getTestSettings();
|
||||
fetchers::Settings fetchSettings = fetchers::Settings{settings};
|
||||
fetchSettings.accessTokens.get().insert({"github.com", "token"});
|
||||
fetchSettings.accessTokens.get().insert({"github.com/a/b", "another_token"});
|
||||
fetchSettings.accessTokens.get().insert({"github.com/a/c", "yet_another_token"});
|
||||
@@ -73,7 +80,8 @@ TEST_F(AccessKeysTest, repoGitHub)
|
||||
|
||||
TEST_F(AccessKeysTest, multipleGitLab)
|
||||
{
|
||||
fetchers::Settings fetchSettings = fetchers::Settings{};
|
||||
auto settings = getTestSettings();
|
||||
fetchers::Settings fetchSettings = fetchers::Settings{settings};
|
||||
fetchSettings.accessTokens.get().insert({"gitlab.com", "token"});
|
||||
fetchSettings.accessTokens.get().insert({"gitlab.com/a/b", "another_token"});
|
||||
auto i = Input::fromURL(fetchSettings, "gitlab:a/b");
|
||||
@@ -87,7 +95,8 @@ TEST_F(AccessKeysTest, multipleGitLab)
|
||||
|
||||
TEST_F(AccessKeysTest, multipleSourceHut)
|
||||
{
|
||||
fetchers::Settings fetchSettings = fetchers::Settings{};
|
||||
auto settings = getTestSettings();
|
||||
fetchers::Settings fetchSettings = fetchers::Settings{settings};
|
||||
fetchSettings.accessTokens.get().insert({"git.sr.ht", "token"});
|
||||
fetchSettings.accessTokens.get().insert({"git.sr.ht/~a/b", "another_token"});
|
||||
auto i = Input::fromURL(fetchSettings, "sourcehut:a/b");
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "nix/fetchers/fetchers.hh"
|
||||
#include "nix/fetchers/git-utils.hh"
|
||||
|
||||
#include "nix/store/tests/test-main.hh"
|
||||
|
||||
#include <git2.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
@@ -180,13 +182,15 @@ TEST_F(GitTest, submodulePeriodSupport)
|
||||
// 6) Commit the addition in super
|
||||
commitAll(super.get(), "Add submodule with branch='.'");
|
||||
|
||||
auto store = [] {
|
||||
auto cfg = make_ref<DummyStoreConfig>(StoreReference::Params{});
|
||||
auto settings = getTestSettings();
|
||||
|
||||
auto store = [&] {
|
||||
auto cfg = make_ref<DummyStoreConfig>(settings, StoreReference::Params{});
|
||||
cfg->readOnly = false;
|
||||
return cfg->openStore();
|
||||
}();
|
||||
|
||||
auto settings = fetchers::Settings{};
|
||||
auto fetchSettings = fetchers::Settings{settings};
|
||||
auto input = fetchers::Input::fromAttrs(
|
||||
settings,
|
||||
{
|
||||
@@ -196,7 +200,7 @@ TEST_F(GitTest, submodulePeriodSupport)
|
||||
{"ref", "main"},
|
||||
});
|
||||
|
||||
auto [accessor, i] = input.getAccessor(settings, *store);
|
||||
auto [accessor, i] = input.getAccessor(fetchSettings, *store);
|
||||
|
||||
ASSERT_EQ(accessor->readFile(CanonPath("deps/sub/lib.txt")), "hello from submodule\n");
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
#include "nix/store/globals.hh"
|
||||
|
||||
#include "nix/fetchers/fetch-settings.hh"
|
||||
#include "nix/fetchers/attrs.hh"
|
||||
#include "nix/fetchers/fetchers.hh"
|
||||
|
||||
#include "nix/store/tests/test-main.hh"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <string>
|
||||
@@ -23,7 +27,8 @@ class InputFromAttrsTest : public ::testing::WithParamInterface<InputFromAttrsTe
|
||||
|
||||
TEST_P(InputFromAttrsTest, attrsAreCorrectAndRoundTrips)
|
||||
{
|
||||
fetchers::Settings fetchSettings;
|
||||
auto settings = getTestSettings();
|
||||
fetchers::Settings fetchSettings{settings};
|
||||
|
||||
const auto & testCase = GetParam();
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ struct CacheImpl : Cache
|
||||
auto dbPath = (getCacheDir() / "fetcher-cache-v4.sqlite").string();
|
||||
createDirs(dirOf(dbPath));
|
||||
|
||||
state->db = SQLite(dbPath, {.useWAL = nix::settings.useSQLiteWAL});
|
||||
state->db = SQLite(dbPath, {.useWAL = settings.storeSettings.useSQLiteWAL});
|
||||
state->db.isCache();
|
||||
state->db.exec(schema);
|
||||
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
namespace nix::fetchers {
|
||||
|
||||
Settings::Settings() {}
|
||||
Settings::Settings(const nix::Settings & storeSettings)
|
||||
: storeSettings(storeSettings)
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace nix::fetchers
|
||||
|
||||
@@ -47,12 +47,6 @@ std::pair<StorePath, Hash> fetchToStore2(
|
||||
auto hash = Hash::parseSRI(fetchers::getStrAttr(*res, "hash"));
|
||||
auto storePath =
|
||||
store.makeFixedOutputPathFromCA(name, ContentAddressWithReferences::fromParts(method, hash, {}));
|
||||
|
||||
/* Add a temproot before the call to isValidPath to prevent accidental GC in case the
|
||||
input is cached. Note that this must be done before to avoid races. */
|
||||
if (mode != FetchMode::DryRun)
|
||||
store.addTempRoot(storePath);
|
||||
|
||||
if (mode == FetchMode::DryRun || store.isValidPath(storePath)) {
|
||||
debug(
|
||||
"source path '%s' cache hit in '%s' (hash '%s')",
|
||||
@@ -82,8 +76,8 @@ std::pair<StorePath, Hash> fetchToStore2(
|
||||
auto [storePath, hash] =
|
||||
mode == FetchMode::DryRun
|
||||
? [&]() {
|
||||
auto [storePath, hash] =
|
||||
store.computeStorePath(name, path, method, HashAlgorithm::SHA256, {}, filter2);
|
||||
auto [storePath, hash] = store.computeStorePath(
|
||||
store.config.settings, name, path, method, HashAlgorithm::SHA256, {}, filter2);
|
||||
debug(
|
||||
"hashed '%s' to '%s' (hash '%s')",
|
||||
path,
|
||||
|
||||
@@ -74,29 +74,6 @@ namespace nix {
|
||||
|
||||
struct GitSourceAccessor;
|
||||
|
||||
struct GitError final : public CloneableError<GitError, Error>
|
||||
{
|
||||
template<typename... Ts>
|
||||
GitError(const git_error & error, Ts &&... args)
|
||||
: CloneableError("")
|
||||
{
|
||||
auto hf = HintFmt(std::forward<Ts>(args)...);
|
||||
err.msg = HintFmt("%1%: %2% (libgit2 error code = %3%)", Uncolored(hf.str()), error.message, error.klass);
|
||||
}
|
||||
|
||||
template<typename... Ts>
|
||||
GitError(Ts &&... args)
|
||||
: GitError(
|
||||
[]() -> const git_error & {
|
||||
const git_error * p = git_error_last();
|
||||
assert(p && "git_error_last() is unexpectedly null");
|
||||
return *p;
|
||||
}(),
|
||||
std::forward<Ts>(args)...)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::unique_ptr<git_repository, Deleter<git_repository_free>> Repository;
|
||||
typedef std::unique_ptr<git_tree_entry, Deleter<git_tree_entry_free>> TreeEntry;
|
||||
typedef std::unique_ptr<git_tree, Deleter<git_tree_free>> Tree;
|
||||
@@ -129,7 +106,7 @@ static void initLibGit2()
|
||||
static std::once_flag initialized;
|
||||
std::call_once(initialized, []() {
|
||||
if (git_libgit2_init() < 0)
|
||||
throw GitError("initialising libgit2");
|
||||
throw Error("initialising libgit2: %s", git_error_last()->message);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -137,7 +114,7 @@ static git_oid hashToOID(const Hash & hash)
|
||||
{
|
||||
git_oid oid;
|
||||
if (git_oid_fromstr(&oid, hash.gitRev().c_str()))
|
||||
throw GitError("cannot convert '%s' to a Git OID", hash.gitRev());
|
||||
throw Error("cannot convert '%s' to a Git OID", hash.gitRev());
|
||||
return oid;
|
||||
}
|
||||
|
||||
@@ -145,7 +122,8 @@ static Object lookupObject(git_repository * repo, const git_oid & oid, git_objec
|
||||
{
|
||||
Object obj;
|
||||
if (git_object_lookup(Setter(obj), repo, &oid, type)) {
|
||||
throw GitError("getting Git object '%s'", oid);
|
||||
auto err = git_error_last();
|
||||
throw Error("getting Git object '%s': %s", oid, err->message);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
@@ -155,7 +133,8 @@ static T peelObject(git_object * obj, git_object_t type)
|
||||
{
|
||||
T obj2;
|
||||
if (git_object_peel((git_object **) (typename T::pointer *) Setter(obj2), obj, type)) {
|
||||
throw Error("peeling Git object '%s'", *git_object_id(obj));
|
||||
auto err = git_error_last();
|
||||
throw Error("peeling Git object '%s': %s", *git_object_id(obj), err->message);
|
||||
}
|
||||
return obj2;
|
||||
}
|
||||
@@ -165,7 +144,7 @@ static T dupObject(typename T::pointer obj)
|
||||
{
|
||||
T obj2;
|
||||
if (git_object_dup((git_object **) (typename T::pointer *) Setter(obj2), (git_object *) obj))
|
||||
throw GitError("duplicating object '%s'", *git_object_id((git_object *) obj));
|
||||
throw Error("duplicating object '%s': %s", *git_object_id((git_object *) obj), git_error_last()->message);
|
||||
return obj2;
|
||||
}
|
||||
|
||||
@@ -237,7 +216,7 @@ static void initRepoAtomically(std::filesystem::path & path, GitRepo::Options op
|
||||
Repository tmpRepo;
|
||||
|
||||
if (git_repository_init(Setter(tmpRepo), tmpDir.string().c_str(), options.bare))
|
||||
throw GitError("creating Git repository %s", PathFmt(path));
|
||||
throw Error("creating Git repository %s: %s", PathFmt(path), git_error_last()->message);
|
||||
try {
|
||||
std::filesystem::rename(tmpDir, path);
|
||||
} catch (std::filesystem::filesystem_error & e) {
|
||||
@@ -287,7 +266,7 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
|
||||
|
||||
initRepoAtomically(path, options);
|
||||
if (git_repository_open(Setter(repo), path.string().c_str()))
|
||||
throw GitError("opening Git repository %s", PathFmt(path));
|
||||
throw Error("opening Git repository %s: %s", PathFmt(path), git_error_last()->message);
|
||||
|
||||
ObjectDb odb;
|
||||
if (options.packfilesOnly) {
|
||||
@@ -300,28 +279,28 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
|
||||
*/
|
||||
|
||||
if (git_odb_new(Setter(odb)))
|
||||
throw GitError("creating Git object database");
|
||||
throw Error("creating Git object database: %s", git_error_last()->message);
|
||||
|
||||
if (git_odb_backend_pack(&packBackend, (path / "objects").string().c_str()))
|
||||
throw GitError("creating pack backend");
|
||||
throw Error("creating pack backend: %s", git_error_last()->message);
|
||||
|
||||
if (git_odb_add_backend(odb.get(), packBackend, 1))
|
||||
throw GitError("adding pack backend to Git object database");
|
||||
throw Error("adding pack backend to Git object database: %s", git_error_last()->message);
|
||||
} else {
|
||||
if (git_repository_odb(Setter(odb), repo.get()))
|
||||
throw GitError("getting Git object database");
|
||||
throw Error("getting Git object database: %s", git_error_last()->message);
|
||||
}
|
||||
|
||||
// mempack_backend will be owned by the repository, so we are not expected to free it ourselves.
|
||||
if (git_mempack_new(&mempackBackend))
|
||||
throw GitError("creating mempack backend");
|
||||
throw Error("creating mempack backend: %s", git_error_last()->message);
|
||||
|
||||
if (git_odb_add_backend(odb.get(), mempackBackend, 999))
|
||||
throw GitError("adding mempack backend to Git object database");
|
||||
throw Error("adding mempack backend to Git object database: %s", git_error_last()->message);
|
||||
|
||||
if (options.packfilesOnly) {
|
||||
if (git_repository_set_odb(repo.get(), odb.get()))
|
||||
throw GitError("setting Git object database");
|
||||
throw Error("setting Git object database: %s", git_error_last()->message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,7 +340,7 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
|
||||
Indexer indexer;
|
||||
git_indexer_progress stats;
|
||||
if (git_indexer_new(Setter(indexer), pack_dir_path.c_str(), 0, nullptr, nullptr))
|
||||
throw GitError("creating git packfile indexer");
|
||||
throw Error("creating git packfile indexer: %s", git_error_last()->message);
|
||||
|
||||
// TODO: provide index callback for checkInterrupt() termination
|
||||
// though this is about an order of magnitude faster than the packbuilder
|
||||
@@ -369,15 +348,15 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
|
||||
constexpr size_t chunkSize = 128 * 1024;
|
||||
for (size_t offset = 0; offset < buf.size; offset += chunkSize) {
|
||||
if (git_indexer_append(indexer.get(), buf.ptr + offset, std::min(chunkSize, buf.size - offset), &stats))
|
||||
throw GitError("appending to git packfile index");
|
||||
throw Error("appending to git packfile index: %s", git_error_last()->message);
|
||||
checkInterrupt();
|
||||
}
|
||||
|
||||
if (git_indexer_commit(indexer.get(), &stats))
|
||||
throw GitError("committing git packfile index");
|
||||
throw Error("committing git packfile index: %s", git_error_last()->message);
|
||||
|
||||
if (git_mempack_reset(mempackBackend))
|
||||
throw GitError("resetting git mempack backend");
|
||||
throw Error("resetting git mempack backend: %s", git_error_last()->message);
|
||||
|
||||
checkInterrupt();
|
||||
}
|
||||
@@ -470,7 +449,7 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
|
||||
void setRemote(const std::string & name, const std::string & url) override
|
||||
{
|
||||
if (git_remote_set_url(*this, name.c_str(), url.c_str()))
|
||||
throw GitError("setting remote '%s' URL to '%s'", name, url);
|
||||
throw Error("setting remote '%s' URL to '%s': %s", name, url, git_error_last()->message);
|
||||
}
|
||||
|
||||
Hash resolveRef(std::string ref) override
|
||||
@@ -483,7 +462,7 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
|
||||
// an object_id.
|
||||
std::string peeledRef = ref + "^{commit}";
|
||||
if (git_revparse_single(Setter(object), *this, peeledRef.c_str()))
|
||||
throw GitError("resolving Git reference '%s'", ref);
|
||||
throw Error("resolving Git reference '%s': %s", ref, git_error_last()->message);
|
||||
auto oid = git_object_id(object.get());
|
||||
return toHash(*oid);
|
||||
}
|
||||
@@ -492,11 +471,11 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
|
||||
{
|
||||
GitConfig config;
|
||||
if (git_config_open_ondisk(Setter(config), configFile.string().c_str()))
|
||||
throw GitError("parsing .gitmodules file");
|
||||
throw Error("parsing .gitmodules file: %s", git_error_last()->message);
|
||||
|
||||
ConfigIterator it;
|
||||
if (git_config_iterator_glob_new(Setter(it), config.get(), "^submodule\\..*\\.(path|url|branch)$"))
|
||||
throw GitError("iterating over .gitmodules");
|
||||
throw Error("iterating over .gitmodules: %s", git_error_last()->message);
|
||||
|
||||
StringMap entries;
|
||||
|
||||
@@ -505,7 +484,7 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
|
||||
if (auto err = git_config_next(&entry, it.get())) {
|
||||
if (err == GIT_ITEROVER)
|
||||
break;
|
||||
throw GitError("iterating over .gitmodules");
|
||||
throw Error("iterating over .gitmodules: %s", git_error_last()->message);
|
||||
}
|
||||
entries.emplace(entry->name + 10, entry->value);
|
||||
}
|
||||
@@ -542,7 +521,7 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
|
||||
git_oid headRev;
|
||||
if (auto err = git_reference_name_to_id(&headRev, *this, "HEAD")) {
|
||||
if (err != GIT_ENOTFOUND)
|
||||
throw GitError("resolving HEAD");
|
||||
throw Error("resolving HEAD: %s", git_error_last()->message);
|
||||
} else
|
||||
info.headRev = toHash(headRev);
|
||||
|
||||
@@ -565,7 +544,7 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
|
||||
options.flags |= GIT_STATUS_OPT_INCLUDE_UNMODIFIED;
|
||||
options.flags |= GIT_STATUS_OPT_EXCLUDE_SUBMODULES;
|
||||
if (git_status_foreach_ext(*this, &options, &statusCallbackTrampoline, &statusCallback))
|
||||
throw GitError("getting working directory status");
|
||||
throw Error("getting working directory status: %s", git_error_last()->message);
|
||||
|
||||
/* Get submodule info. */
|
||||
auto modulesFile = path / ".gitmodules";
|
||||
@@ -608,7 +587,8 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
|
||||
if (auto errCode = git_object_lookup(Setter(obj), *this, &oid, GIT_OBJECT_ANY)) {
|
||||
if (errCode == GIT_ENOTFOUND)
|
||||
return false;
|
||||
throw GitError("getting Git object '%s'", oid);
|
||||
auto err = git_error_last();
|
||||
throw Error("getting Git object '%s': %s", oid, err->message);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -938,7 +918,7 @@ struct GitSourceAccessor : SourceAccessor
|
||||
|
||||
TreeEntry copy;
|
||||
if (git_tree_entry_dup(Setter(copy), entry))
|
||||
throw GitError("dupping tree entry");
|
||||
throw Error("dupping tree entry: %s", git_error_last()->message);
|
||||
|
||||
auto entryName = std::string_view(git_tree_entry_name(entry));
|
||||
|
||||
@@ -968,7 +948,7 @@ struct GitSourceAccessor : SourceAccessor
|
||||
|
||||
Tree tree;
|
||||
if (git_tree_entry_to_object((git_object **) (git_tree **) Setter(tree), *state.repo, entry))
|
||||
throw GitError("looking up directory '%s'", showPath(path));
|
||||
throw Error("looking up directory '%s': %s", showPath(path), git_error_last()->message);
|
||||
|
||||
return tree;
|
||||
}
|
||||
@@ -1003,7 +983,7 @@ struct GitSourceAccessor : SourceAccessor
|
||||
|
||||
Tree tree;
|
||||
if (git_tree_entry_to_object((git_object **) (git_tree **) Setter(tree), *state.repo, entry))
|
||||
throw GitError("looking up directory '%s'", showPath(path));
|
||||
throw Error("looking up directory '%s': %s", showPath(path), git_error_last()->message);
|
||||
|
||||
return tree;
|
||||
}
|
||||
@@ -1036,7 +1016,7 @@ struct GitSourceAccessor : SourceAccessor
|
||||
|
||||
Blob blob;
|
||||
if (git_tree_entry_to_object((git_object **) (git_blob **) Setter(blob), *state.repo, entry))
|
||||
throw GitError("looking up file '%s'", showPath(path));
|
||||
throw Error("looking up file '%s': %s", showPath(path), git_error_last()->message);
|
||||
|
||||
return blob;
|
||||
}
|
||||
@@ -1088,7 +1068,7 @@ struct GitExportIgnoreSourceAccessor : CachingFilteringSourceAccessor
|
||||
if (git_error_last()->klass == GIT_ENOTFOUND)
|
||||
return false;
|
||||
else
|
||||
throw GitError("looking up '%s'", showPath(path));
|
||||
throw Error("looking up '%s': %s", showPath(path), git_error_last()->message);
|
||||
} else {
|
||||
// Official git will silently reject export-ignore lines that have
|
||||
// values. We do the same.
|
||||
@@ -1244,17 +1224,17 @@ struct GitFileSystemObjectSinkImpl : GitFileSystemObjectSink
|
||||
repo.emplace(parent.repoPool.get());
|
||||
|
||||
if (git_blob_create_from_stream(Setter(stream), **repo, nullptr))
|
||||
throw GitError("creating a blob stream object");
|
||||
throw Error("creating a blob stream object: %s", git_error_last()->message);
|
||||
|
||||
if (stream->write(stream.get(), contents.data(), contents.size()))
|
||||
throw GitError("writing a blob for tarball member '%s'", path);
|
||||
throw Error("writing a blob for tarball member '%s': %s", path, git_error_last()->message);
|
||||
|
||||
parent.totalBufSize -= contents.size();
|
||||
contents.clear();
|
||||
}
|
||||
} else {
|
||||
if (stream->write(stream.get(), data.data(), data.size()))
|
||||
throw GitError("writing a blob for tarball member '%s'", path);
|
||||
throw Error("writing a blob for tarball member '%s': %s", path, git_error_last()->message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1276,7 +1256,7 @@ struct GitFileSystemObjectSinkImpl : GitFileSystemObjectSink
|
||||
acquires ownership and frees the stream. */
|
||||
git_oid oid;
|
||||
if (git_blob_create_from_stream_commit(&oid, crf->stream.release()))
|
||||
throw GitError("creating a blob object for '%s'", path);
|
||||
throw Error("creating a blob object for '%s': %s", path, git_error_last()->message);
|
||||
addNode(
|
||||
*_state.lock(),
|
||||
crf->path,
|
||||
@@ -1290,7 +1270,8 @@ struct GitFileSystemObjectSinkImpl : GitFileSystemObjectSink
|
||||
|
||||
git_oid oid;
|
||||
if (git_blob_create_from_buffer(&oid, *repo, crf->contents.data(), crf->contents.size()))
|
||||
throw GitError("creating a blob object for '%s' from in-memory buffer", crf->path);
|
||||
throw Error(
|
||||
"creating a blob object for '%s' from in-memory buffer: %s", crf->path, git_error_last()->message);
|
||||
|
||||
addNode(
|
||||
*_state.lock(),
|
||||
@@ -1314,7 +1295,8 @@ struct GitFileSystemObjectSinkImpl : GitFileSystemObjectSink
|
||||
|
||||
git_oid oid;
|
||||
if (git_blob_create_from_buffer(&oid, *repo, target.c_str(), target.size()))
|
||||
throw GitError("creating a blob object for tarball symlink member '%s'", path);
|
||||
throw Error(
|
||||
"creating a blob object for tarball symlink member '%s': %s", path, git_error_last()->message);
|
||||
|
||||
auto state(_state.lock());
|
||||
addNode(*state, path, Child{GIT_FILEMODE_LINK, oid});
|
||||
@@ -1375,19 +1357,19 @@ struct GitFileSystemObjectSinkImpl : GitFileSystemObjectSink
|
||||
// Write this directory.
|
||||
git_treebuilder * b;
|
||||
if (git_treebuilder_new(&b, *repo, nullptr))
|
||||
throw GitError("creating a tree builder");
|
||||
throw Error("creating a tree builder: %s", git_error_last()->message);
|
||||
TreeBuilder builder(b);
|
||||
|
||||
for (auto & [name, child] : node.children) {
|
||||
auto oid_p = std::get_if<git_oid>(&child.file);
|
||||
auto oid = oid_p ? *oid_p : std::get<Directory>(child.file).oid.value();
|
||||
if (git_treebuilder_insert(nullptr, builder.get(), name.c_str(), &oid, child.mode))
|
||||
throw GitError("adding a file to a tree builder");
|
||||
throw Error("adding a file to a tree builder: %s", git_error_last()->message);
|
||||
}
|
||||
|
||||
git_oid oid;
|
||||
if (git_treebuilder_write(&oid, builder.get()))
|
||||
throw GitError("creating a tree object");
|
||||
throw Error("creating a tree object: %s", git_error_last()->message);
|
||||
node.oid = oid;
|
||||
}(_state.lock()->root);
|
||||
|
||||
|
||||
@@ -13,9 +13,10 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
class Settings;
|
||||
struct GitRepo;
|
||||
|
||||
}
|
||||
} // namespace nix
|
||||
|
||||
namespace nix::fetchers {
|
||||
|
||||
@@ -23,7 +24,12 @@ struct Cache;
|
||||
|
||||
struct Settings : public Config
|
||||
{
|
||||
Settings();
|
||||
/**
|
||||
* Reference to the "parent" store-layer settings.
|
||||
*/
|
||||
const nix::Settings & storeSettings;
|
||||
|
||||
Settings(const nix::Settings & storeSettings);
|
||||
|
||||
Setting<StringMap> accessTokens{
|
||||
this,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "nix/store/globals.hh"
|
||||
#include "nix/fetchers/fetch-settings.hh"
|
||||
#include "nix/flake/flakeref.hh"
|
||||
#include "nix/fetchers/attrs.hh"
|
||||
@@ -19,7 +20,8 @@ TEST(parseFlakeRef, path)
|
||||
{
|
||||
experimentalFeatureSettings.experimentalFeatures.get().insert(Xp::Flakes);
|
||||
|
||||
fetchers::Settings fetchSettings;
|
||||
Settings settings;
|
||||
fetchers::Settings fetchSettings{settings};
|
||||
|
||||
{
|
||||
auto s = "/foo/bar";
|
||||
@@ -69,7 +71,8 @@ TEST(parseFlakeRef, GitArchiveInput)
|
||||
{
|
||||
experimentalFeatureSettings.experimentalFeatures.get().insert(Xp::Flakes);
|
||||
|
||||
fetchers::Settings fetchSettings;
|
||||
Settings settings;
|
||||
fetchers::Settings fetchSettings{settings};
|
||||
|
||||
{
|
||||
auto s = "github:foo/bar/branch%23"; // branch name with `#`
|
||||
@@ -112,7 +115,8 @@ class InputFromURLTest : public ::testing::WithParamInterface<InputFromURLTestCa
|
||||
TEST_P(InputFromURLTest, attrsAreCorrectAndRoundTrips)
|
||||
{
|
||||
experimentalFeatureSettings.experimentalFeatures.get().insert(Xp::Flakes);
|
||||
fetchers::Settings fetchSettings;
|
||||
Settings settings;
|
||||
fetchers::Settings fetchSettings{settings};
|
||||
|
||||
const auto & testCase = GetParam();
|
||||
|
||||
@@ -274,7 +278,8 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
|
||||
TEST(to_string, doesntReencodeUrl)
|
||||
{
|
||||
fetchers::Settings fetchSettings;
|
||||
Settings settings;
|
||||
fetchers::Settings fetchSettings{settings};
|
||||
auto s = "http://localhost:8181/test/+3d.tar.gz";
|
||||
auto flakeref = parseFlakeRef(fetchSettings, s);
|
||||
auto unparsed = flakeref.to_string();
|
||||
@@ -283,18 +288,4 @@ TEST(to_string, doesntReencodeUrl)
|
||||
ASSERT_EQ(unparsed, expected);
|
||||
}
|
||||
|
||||
TEST(parseFlakeRef, malformedGithubUrlDoesNotCrash)
|
||||
{
|
||||
experimentalFeatureSettings.experimentalFeatures.get().insert(Xp::Flakes);
|
||||
|
||||
fetchers::Settings fetchSettings;
|
||||
|
||||
// Using ref= instead of rev= with a github: URL should produce an
|
||||
// error, not an assertion failure in renderAuthorityAndPath
|
||||
// (https://github.com/NixOS/nix/issues/15196).
|
||||
EXPECT_THROW(
|
||||
parseFlakeRef(fetchSettings, "github:nixos/nixpkgs/nixpkgs.git?ref=aead170c1a49253ebfa5027010dfd89a77b73ca4"),
|
||||
Error);
|
||||
}
|
||||
|
||||
} // namespace nix
|
||||
|
||||
@@ -205,7 +205,7 @@ std::pair<FlakeRef, std::string> parsePathFlakeRefWithFragment(
|
||||
fetchSettings,
|
||||
{
|
||||
.scheme = "path",
|
||||
.authority = isAbsolute(path) ? std::optional{ParsedURL::Authority{}} : std::nullopt,
|
||||
.authority = ParsedURL::Authority{},
|
||||
.path = splitString<std::vector<std::string>>(path, "/"),
|
||||
.query = query,
|
||||
.fragment = fragment,
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "nix/main/loggers.hh"
|
||||
#include "nix/util/util.hh"
|
||||
#include "nix/main/plugin.hh"
|
||||
#include "nix/main/shared.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
||||
@@ -13,6 +13,13 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
class Settings;
|
||||
|
||||
// FIXME: don't use a global variable.
|
||||
extern Settings settings;
|
||||
|
||||
int handleExceptions(const std::string & programName, std::function<void()> fun);
|
||||
|
||||
/**
|
||||
* Don't forget to call initPlugins() after settings are initialized!
|
||||
* @param loadConfig Whether to load configuration from `nix.conf`, `NIX_CONFIG`, etc. May be disabled for unit tests.
|
||||
|
||||
@@ -31,12 +31,17 @@
|
||||
|
||||
#include "nix/util/exit.hh"
|
||||
#include "nix/util/strings.hh"
|
||||
#include "nix/util/config-global.hh"
|
||||
|
||||
#include "main-config-private.hh"
|
||||
#include "nix/expr/config.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
Settings settings;
|
||||
|
||||
static GlobalConfig::Register rSettings(&settings);
|
||||
|
||||
char ** savedArgv;
|
||||
|
||||
static bool gcWarning = true;
|
||||
@@ -335,8 +340,8 @@ void printVersion(const std::string & programName)
|
||||
std::cout << "System configuration file: " << nixConfFile() << "\n";
|
||||
std::cout << "User configuration files: "
|
||||
<< os_string_to_string(ExecutablePath{.directories = nixUserConfFiles()}.render()) << "\n";
|
||||
std::cout << "Store directory: " << resolveStoreConfig(StoreReference{settings.storeUri.get()})->storeDir
|
||||
<< "\n";
|
||||
std::cout << "Store directory: "
|
||||
<< resolveStoreConfig(settings, StoreReference{settings.storeUri.get()})->storeDir << "\n";
|
||||
std::cout << "State directory: " << settings.nixStateDir << "\n";
|
||||
}
|
||||
throw Exit();
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
|
||||
extern "C" {
|
||||
|
||||
// FIXME: This is going to conflict with the one in libmain.
|
||||
nix::Settings cStoreSettings;
|
||||
|
||||
nix_err nix_libstore_init(nix_c_context * context)
|
||||
{
|
||||
if (context)
|
||||
@@ -46,7 +49,7 @@ Store * nix_store_open(nix_c_context * context, const char * uri, const char ***
|
||||
std::string uri_str = uri ? uri : "";
|
||||
|
||||
if (uri_str.empty())
|
||||
return new Store{nix::openStore()};
|
||||
return new Store{nix::openStore(cStoreSettings)};
|
||||
|
||||
auto storeRef = nix::StoreReference::parse(uri_str);
|
||||
|
||||
@@ -55,7 +58,7 @@ Store * nix_store_open(nix_c_context * context, const char * uri, const char ***
|
||||
storeRef.params[params[i][0]] = params[i][1];
|
||||
}
|
||||
}
|
||||
return new Store{nix::openStore(std::move(storeRef))};
|
||||
return new Store{nix::openStore(cStoreSettings, std::move(storeRef))};
|
||||
}
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
@@ -312,8 +315,8 @@ StorePath * nix_add_derivation(nix_c_context * context, Store * store, nix_deriv
|
||||
without actually writing the derivation if this setting is
|
||||
set, but it was that way already, so we are doing this for
|
||||
back-compat for now. */
|
||||
auto ret = nix::settings.readOnlyMode ? nix::computeStorePath(*store->ptr, derivation->drv)
|
||||
: store->ptr->writeDerivation(derivation->drv, nix::NoRepair);
|
||||
auto ret = cStoreSettings.readOnlyMode ? nix::computeStorePath(*store->ptr, derivation->drv)
|
||||
: store->ptr->writeDerivation(derivation->drv, nix::NoRepair);
|
||||
|
||||
return new StorePath{ret};
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
extern "C" {
|
||||
|
||||
extern nix::Settings cStoreSettings;
|
||||
|
||||
struct Store
|
||||
{
|
||||
nix::ref<nix::Store> ptr;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "nix/store/tests/https-store.hh"
|
||||
#include "nix/store/tests/test-main.hh"
|
||||
|
||||
#include <thread>
|
||||
|
||||
@@ -36,9 +37,9 @@ void HttpsBinaryCacheStoreTest::SetUp()
|
||||
cacheDir = tmpDir / "cache";
|
||||
delTmpDir = std::make_unique<AutoDelete>(tmpDir);
|
||||
|
||||
localCacheStore =
|
||||
make_ref<LocalBinaryCacheStoreConfig>("file", cacheDir.string(), LocalBinaryCacheStoreConfig::Params{})
|
||||
->openStore();
|
||||
localCacheStore = make_ref<LocalBinaryCacheStoreConfig>(
|
||||
settings, "file", cacheDir.string(), LocalBinaryCacheStoreConfig::Params{})
|
||||
->openStore();
|
||||
|
||||
caCert = tmpDir / "ca.crt";
|
||||
caKey = tmpDir / "ca.key";
|
||||
@@ -50,11 +51,9 @@ void HttpsBinaryCacheStoreTest::SetUp()
|
||||
// clang-format off
|
||||
openssl({"ecparam", "-genkey", "-name", "prime256v1", "-out", caKey.string()});
|
||||
openssl({"req", "-new", "-x509", "-days", "1", "-key", caKey.string(), "-out", caCert.string(), "-subj", "/CN=TestCA"});
|
||||
auto serverExtFile = tmpDir / "server.ext";
|
||||
writeFile(serverExtFile, "subjectAltName=DNS:localhost,IP:127.0.0.1");
|
||||
openssl({"ecparam", "-genkey", "-name", "prime256v1", "-out", serverKey.string()});
|
||||
openssl({"req", "-new", "-key", serverKey.string(), "-out", (tmpDir / "server.csr").string(), "-subj", "/CN=localhost", "-addext", "subjectAltName=DNS:localhost,IP:127.0.0.1"});
|
||||
openssl({"x509", "-req", "-in", (tmpDir / "server.csr").string(), "-CA", caCert.string(), "-CAkey", caKey.string(), "-CAcreateserial", "-out", serverCert.string(), "-days", "1", "-extfile", serverExtFile.string()});
|
||||
openssl({"req", "-new", "-key", serverKey.string(), "-out", (tmpDir / "server.csr").string(), "-subj", "/CN=localhost"});
|
||||
openssl({"x509", "-req", "-in", (tmpDir / "server.csr").string(), "-CA", caCert.string(), "-CAkey", caKey.string(), "-CAcreateserial", "-out", serverCert.string(), "-days", "1"});
|
||||
openssl({"ecparam", "-genkey", "-name", "prime256v1", "-out", clientKey.string()});
|
||||
openssl({"req", "-new", "-key", clientKey.string(), "-out", (tmpDir / "client.csr").string(), "-subj", "/CN=TestClient"});
|
||||
openssl({"x509", "-req", "-in", (tmpDir / "client.csr").string(), "-CA", caCert.string(), "-CAkey", caKey.string(), "-CAcreateserial", "-out", clientCert.string(), "-days", "1"});
|
||||
@@ -123,6 +122,7 @@ std::vector<std::string> HttpsBinaryCacheStoreMtlsTest::serverArgs()
|
||||
ref<TestHttpBinaryCacheStoreConfig> HttpsBinaryCacheStoreTest::makeConfig()
|
||||
{
|
||||
auto res = make_ref<TestHttpBinaryCacheStoreConfig>(
|
||||
settings,
|
||||
ParsedURL{
|
||||
.scheme = "https",
|
||||
.authority =
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include "nix/util/file-system.hh"
|
||||
#include "nix/util/processes.hh"
|
||||
|
||||
#include "nix/store/tests/test-main.hh"
|
||||
|
||||
namespace nix::testing {
|
||||
|
||||
class TestHttpBinaryCacheStoreConfig;
|
||||
@@ -42,9 +44,9 @@ public:
|
||||
class TestHttpBinaryCacheStoreConfig : public HttpBinaryCacheStoreConfig
|
||||
{
|
||||
public:
|
||||
TestHttpBinaryCacheStoreConfig(ParsedURL url, const Store::Config::Params & params)
|
||||
: StoreConfig(params)
|
||||
, HttpBinaryCacheStoreConfig(url, params)
|
||||
TestHttpBinaryCacheStoreConfig(nix::Settings & settings, ParsedURL url, const Store::Config::Params & params)
|
||||
: StoreConfig(settings, params)
|
||||
, HttpBinaryCacheStoreConfig(settings, url, params)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -56,6 +58,8 @@ class HttpsBinaryCacheStoreTest : public virtual LibStoreNetworkTest
|
||||
std::unique_ptr<AutoDelete> delTmpDir;
|
||||
|
||||
public:
|
||||
Settings settings = getTestSettings();
|
||||
|
||||
static void SetUpTestSuite()
|
||||
{
|
||||
initLibStore(/*loadConfig=*/false);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "nix/store/store-api.hh"
|
||||
#include "nix/store/store-open.hh"
|
||||
#include "nix/store/globals.hh"
|
||||
#include "nix/store/tests/test-main.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -18,14 +19,16 @@ public:
|
||||
initLibStore(false);
|
||||
}
|
||||
|
||||
Settings settings = getTestSettings();
|
||||
|
||||
protected:
|
||||
LibStoreTest(ref<Store> store)
|
||||
: store(std::move(store))
|
||||
LibStoreTest(auto && makeStore)
|
||||
: store(makeStore(settings))
|
||||
{
|
||||
}
|
||||
|
||||
LibStoreTest()
|
||||
: LibStoreTest(openStore("dummy://"))
|
||||
: LibStoreTest([](auto & settings) { return openStore(settings, "dummy://"); })
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,13 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
class Settings;
|
||||
|
||||
/**
|
||||
* Get a Settings object configured appropriately for unit testing.
|
||||
*/
|
||||
Settings getTestSettings();
|
||||
|
||||
/**
|
||||
* Call this for a GTest test suite that will including performing Nix
|
||||
* builds, before running tests.
|
||||
|
||||
@@ -7,12 +7,9 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
int testMainForBuidingPre(int argc, char ** argv)
|
||||
Settings getTestSettings()
|
||||
{
|
||||
if (argc > 1 && std::string_view(argv[1]) == "__build-remote") {
|
||||
printError("test-build-remote: not supported in libexpr unit tests");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
Settings settings;
|
||||
|
||||
// Disable build hook. We won't be testing remote builds in these unit tests. If we do, fix the above build hook.
|
||||
settings.getWorkerSettings().buildHook = {};
|
||||
@@ -41,6 +38,16 @@ int testMainForBuidingPre(int argc, char ** argv)
|
||||
setEnv("_NIX_TEST_NO_SANDBOX", "1");
|
||||
#endif
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
int testMainForBuidingPre(int argc, char ** argv)
|
||||
{
|
||||
if (argc > 1 && std::string_view(argv[1]) == "__build-remote") {
|
||||
printError("test-build-remote: not supported in libexpr unit tests");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_defaults)
|
||||
|
||||
EXPECT_EQ(options, advancedAttributes_defaults);
|
||||
|
||||
EXPECT_EQ(options.substitutesAllowed(settings.getWorkerSettings()), true);
|
||||
EXPECT_EQ(options.substitutesAllowed(this->settings.getWorkerSettings()), true);
|
||||
EXPECT_EQ(options.useUidRange(got), false);
|
||||
});
|
||||
};
|
||||
@@ -241,7 +241,7 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes)
|
||||
|
||||
EXPECT_EQ(options, expected);
|
||||
|
||||
EXPECT_EQ(options.substitutesAllowed(settings.getWorkerSettings()), false);
|
||||
EXPECT_EQ(options.substitutesAllowed(this->settings.getWorkerSettings()), false);
|
||||
EXPECT_EQ(options.useUidRange(got), true);
|
||||
});
|
||||
};
|
||||
@@ -333,7 +333,7 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_structuredAttrs_d
|
||||
|
||||
EXPECT_EQ(options, advancedAttributes_structuredAttrs_defaults);
|
||||
|
||||
EXPECT_EQ(options.substitutesAllowed(settings.getWorkerSettings()), true);
|
||||
EXPECT_EQ(options.substitutesAllowed(this->settings.getWorkerSettings()), true);
|
||||
EXPECT_EQ(options.useUidRange(got), false);
|
||||
});
|
||||
};
|
||||
@@ -398,7 +398,7 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_structuredAttrs)
|
||||
|
||||
EXPECT_EQ(options, expected);
|
||||
|
||||
EXPECT_EQ(options.substitutesAllowed(settings.getWorkerSettings()), false);
|
||||
EXPECT_EQ(options.substitutesAllowed(this->settings.getWorkerSettings()), false);
|
||||
EXPECT_EQ(options.useUidRange(got), true);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -16,11 +16,11 @@ class FillInOutputPathsTest : public LibStoreTest, public JsonCharacterizationTe
|
||||
|
||||
protected:
|
||||
FillInOutputPathsTest()
|
||||
: LibStoreTest([]() {
|
||||
auto config = make_ref<DummyStoreConfig>(DummyStoreConfig::Params{});
|
||||
: LibStoreTest([](auto & settings) {
|
||||
auto config = make_ref<DummyStoreConfig>(settings, DummyStoreConfig::Params{});
|
||||
config->readOnly = false;
|
||||
return config->openDummyStore();
|
||||
}())
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "nix/store/realisation.hh"
|
||||
|
||||
#include "nix/util/tests/json-characterization.hh"
|
||||
#include "nix/store/tests/test-main.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -31,8 +32,10 @@ TEST(DummyStore, realisation_read)
|
||||
{
|
||||
initLibStore(/*loadConfig=*/false);
|
||||
|
||||
auto store = [] {
|
||||
auto cfg = make_ref<DummyStoreConfig>(StoreReference::Params{});
|
||||
auto settings = getTestSettings();
|
||||
|
||||
auto store = [&] {
|
||||
auto cfg = make_ref<DummyStoreConfig>(settings, StoreReference::Params{});
|
||||
cfg->readOnly = false;
|
||||
return cfg->openDummyStore();
|
||||
}();
|
||||
@@ -73,9 +76,10 @@ TEST_P(DummyStoreJsonTest, from_json)
|
||||
using namespace nlohmann;
|
||||
/* Cannot use `readJsonTest` because need to dereference the stores
|
||||
for equality. */
|
||||
auto settings = getTestSettings();
|
||||
readTest(Path{name} + ".json", [&](const auto & encodedRaw) {
|
||||
auto encoded = json::parse(encodedRaw);
|
||||
ref<DummyStore> decoded = adl_serializer<ref<DummyStore>>::from_json(encoded);
|
||||
ref<DummyStore> decoded = adl_serializer<ref<DummyStore>>::from_json(settings, encoded);
|
||||
ASSERT_EQ(*decoded, *expected);
|
||||
});
|
||||
}
|
||||
@@ -88,12 +92,13 @@ TEST_P(DummyStoreJsonTest, to_json)
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DummyStoreJSON, DummyStoreJsonTest, [] {
|
||||
initLibStore(false);
|
||||
auto writeCfg = make_ref<DummyStore::Config>(DummyStore::Config::Params{});
|
||||
auto settings = getTestSettings();
|
||||
auto writeCfg = make_ref<DummyStore::Config>(settings, DummyStore::Config::Params{});
|
||||
writeCfg->readOnly = false;
|
||||
return ::testing::Values(
|
||||
std::pair{
|
||||
"empty",
|
||||
make_ref<DummyStore::Config>(DummyStore::Config::Params{})->openDummyStore(),
|
||||
make_ref<DummyStore::Config>(settings, DummyStore::Config::Params{})->openDummyStore(),
|
||||
},
|
||||
std::pair{
|
||||
"one-flat-file",
|
||||
|
||||
@@ -1,38 +1,44 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <regex>
|
||||
|
||||
#include "nix/store/globals.hh"
|
||||
#include "nix/store/http-binary-cache-store.hh"
|
||||
#include "nix/store/tests/https-store.hh"
|
||||
#include "nix/util/fs-sink.hh"
|
||||
#include "nix/store/tests/test-main.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
TEST(HttpBinaryCacheStore, constructConfig)
|
||||
{
|
||||
HttpBinaryCacheStoreConfig config{"http", "foo.bar.baz", {}};
|
||||
auto settings = getTestSettings();
|
||||
HttpBinaryCacheStoreConfig config{settings, "http", "foo.bar.baz", {}};
|
||||
|
||||
EXPECT_EQ(config.cacheUri.to_string(), "http://foo.bar.baz");
|
||||
}
|
||||
|
||||
TEST(HttpBinaryCacheStore, constructConfigNoTrailingSlash)
|
||||
{
|
||||
HttpBinaryCacheStoreConfig config{"https", "foo.bar.baz/a/b/", {}};
|
||||
auto settings = getTestSettings();
|
||||
HttpBinaryCacheStoreConfig config{settings, "https", "foo.bar.baz/a/b/", {}};
|
||||
|
||||
EXPECT_EQ(config.cacheUri.to_string(), "https://foo.bar.baz/a/b");
|
||||
}
|
||||
|
||||
TEST(HttpBinaryCacheStore, constructConfigWithParams)
|
||||
{
|
||||
auto settings = getTestSettings();
|
||||
StoreConfig::Params params{{"compression", "xz"}};
|
||||
HttpBinaryCacheStoreConfig config{"https", "foo.bar.baz/a/b/", params};
|
||||
HttpBinaryCacheStoreConfig config{settings, "https", "foo.bar.baz/a/b/", params};
|
||||
EXPECT_EQ(config.cacheUri.to_string(), "https://foo.bar.baz/a/b");
|
||||
EXPECT_EQ(config.getReference().params, params);
|
||||
}
|
||||
|
||||
TEST(HttpBinaryCacheStore, constructConfigWithParamsAndUrlWithParams)
|
||||
{
|
||||
auto settings = getTestSettings();
|
||||
StoreConfig::Params params{{"compression", "xz"}};
|
||||
HttpBinaryCacheStoreConfig config{"https", "foo.bar.baz/a/b?some-param=some-value", params};
|
||||
HttpBinaryCacheStoreConfig config{settings, "https", "foo.bar.baz/a/b?some-param=some-value", params};
|
||||
EXPECT_EQ(config.cacheUri.to_string(), "https://foo.bar.baz/a/b?some-param=some-value");
|
||||
EXPECT_EQ(config.getReference().params, params);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "nix/store/globals.hh"
|
||||
#include "nix/store/legacy-ssh-store.hh"
|
||||
#include "nix/store/tests/test-main.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
TEST(LegacySSHStore, constructConfig)
|
||||
{
|
||||
auto settings = getTestSettings();
|
||||
LegacySSHStoreConfig config(
|
||||
settings,
|
||||
"ssh",
|
||||
"me@localhost:2222",
|
||||
StoreConfig::Params{
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "nix/store/globals.hh"
|
||||
#include "nix/store/local-binary-cache-store.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
TEST(LocalBinaryCacheStore, constructConfig)
|
||||
{
|
||||
LocalBinaryCacheStoreConfig config{"local", "/foo/bar/baz", {}};
|
||||
Settings settings;
|
||||
LocalBinaryCacheStoreConfig config{settings, "local", "/foo/bar/baz", {}};
|
||||
|
||||
EXPECT_EQ(config.binaryCacheDir, "/foo/bar/baz");
|
||||
}
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "nix/store/globals.hh"
|
||||
#include "nix/store/local-overlay-store.hh"
|
||||
#include "nix/store/tests/test-main.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
TEST(LocalOverlayStore, constructConfig_rootQueryParam)
|
||||
{
|
||||
auto settings = getTestSettings();
|
||||
LocalOverlayStoreConfig config{
|
||||
settings,
|
||||
"local-overlay",
|
||||
"",
|
||||
{
|
||||
@@ -22,7 +26,8 @@ TEST(LocalOverlayStore, constructConfig_rootQueryParam)
|
||||
|
||||
TEST(LocalOverlayStore, constructConfig_rootPath)
|
||||
{
|
||||
LocalOverlayStoreConfig config{"local-overlay", "/foo/bar", {}};
|
||||
auto settings = getTestSettings();
|
||||
LocalOverlayStoreConfig config{settings, "local-overlay", "/foo/bar", {}};
|
||||
|
||||
EXPECT_EQ(config.rootDir.get(), std::optional{"/foo/bar"});
|
||||
}
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "nix/store/globals.hh"
|
||||
#include "nix/store/local-store.hh"
|
||||
|
||||
// Needed for template specialisations. This is not good! When we
|
||||
// overhaul how store configs work, this should be fixed.
|
||||
#include "nix/util/args.hh"
|
||||
#include "nix/util/config-impl.hh"
|
||||
#include "nix/util/abstract-setting-to-json.hh"
|
||||
#include "nix/store/tests/test-main.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
TEST(LocalStore, constructConfig_rootQueryParam)
|
||||
{
|
||||
auto settings = getTestSettings();
|
||||
LocalStoreConfig config{
|
||||
settings,
|
||||
"local",
|
||||
"",
|
||||
{
|
||||
@@ -28,14 +26,16 @@ TEST(LocalStore, constructConfig_rootQueryParam)
|
||||
|
||||
TEST(LocalStore, constructConfig_rootPath)
|
||||
{
|
||||
LocalStoreConfig config{"local", "/foo/bar", {}};
|
||||
auto settings = getTestSettings();
|
||||
LocalStoreConfig config{settings, "local", "/foo/bar", {}};
|
||||
|
||||
EXPECT_EQ(config.rootDir.get(), std::optional{"/foo/bar"});
|
||||
}
|
||||
|
||||
TEST(LocalStore, constructConfig_to_string)
|
||||
{
|
||||
LocalStoreConfig config{"local", "", {}};
|
||||
auto settings = getTestSettings();
|
||||
LocalStoreConfig config{settings, "local", "", {}};
|
||||
EXPECT_EQ(config.getReference().to_string(), "local");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
#include "nix/store/nar-info-disk-cache.hh"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <rapidcheck/gtest.h>
|
||||
#include "nix/store/globals.hh"
|
||||
#include "nix/store/sqlite.hh"
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include "nix/store/globals.hh"
|
||||
#include "nix/store/sqlite.hh"
|
||||
#include "nix/store/nar-info-disk-cache.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
TEST(NarInfoDiskCacheImpl, create_and_read)
|
||||
@@ -24,6 +26,8 @@ TEST(NarInfoDiskCacheImpl, create_and_read)
|
||||
SQLite db;
|
||||
SQLiteStmt getIds;
|
||||
|
||||
Settings settings;
|
||||
|
||||
{
|
||||
auto cache = NarInfoDiskCache::getTest(
|
||||
settings.getNarInfoDiskCacheSettings(), {.useWAL = settings.useSQLiteWAL}, dbPath.string());
|
||||
|
||||
@@ -299,7 +299,7 @@ public:
|
||||
nix_api_store_test_base::SetUp();
|
||||
|
||||
nix::experimentalFeatureSettings.set("extra-experimental-features", "ca-derivations");
|
||||
nix::settings.getWorkerSettings().substituters = {};
|
||||
cStoreSettings.getWorkerSettings().substituters = {};
|
||||
|
||||
store = open_local_store();
|
||||
|
||||
@@ -309,7 +309,7 @@ public:
|
||||
buffer << t.rdbuf();
|
||||
|
||||
// Replace the hardcoded system with the current system
|
||||
std::string jsonStr = nix::replaceStrings(buffer.str(), "x86_64-linux", nix::settings.thisSystem.get());
|
||||
std::string jsonStr = nix::replaceStrings(buffer.str(), "x86_64-linux", cStoreSettings.thisSystem.get());
|
||||
|
||||
drv = nix_derivation_from_json(ctx, store, jsonStr.c_str());
|
||||
assert_ctx_ok();
|
||||
@@ -354,7 +354,7 @@ TEST_F(nix_api_store_test_base, build_from_json)
|
||||
{
|
||||
// FIXME get rid of these
|
||||
nix::experimentalFeatureSettings.set("extra-experimental-features", "ca-derivations");
|
||||
nix::settings.getWorkerSettings().substituters = {};
|
||||
cStoreSettings.getWorkerSettings().substituters = {};
|
||||
|
||||
auto * store = open_local_store();
|
||||
|
||||
@@ -365,7 +365,7 @@ TEST_F(nix_api_store_test_base, build_from_json)
|
||||
buffer << t.rdbuf();
|
||||
|
||||
// Replace the hardcoded system with the current system
|
||||
std::string jsonStr = nix::replaceStrings(buffer.str(), "x86_64-linux", nix::settings.thisSystem.get());
|
||||
std::string jsonStr = nix::replaceStrings(buffer.str(), "x86_64-linux", cStoreSettings.thisSystem.get());
|
||||
|
||||
auto * drv = nix_derivation_from_json(ctx, store, jsonStr.c_str());
|
||||
assert_ctx_ok();
|
||||
@@ -401,7 +401,7 @@ TEST_F(nix_api_store_test_base, nix_store_realise_invalid_system)
|
||||
{
|
||||
// Test that nix_store_realise properly reports errors when the system is invalid
|
||||
nix::experimentalFeatureSettings.set("extra-experimental-features", "ca-derivations");
|
||||
nix::settings.getWorkerSettings().substituters = {};
|
||||
cStoreSettings.getWorkerSettings().substituters = {};
|
||||
|
||||
auto * store = open_local_store();
|
||||
|
||||
@@ -446,7 +446,7 @@ TEST_F(nix_api_store_test_base, nix_store_realise_builder_fails)
|
||||
{
|
||||
// Test that nix_store_realise properly reports errors when the builder fails
|
||||
nix::experimentalFeatureSettings.set("extra-experimental-features", "ca-derivations");
|
||||
nix::settings.getWorkerSettings().substituters = {};
|
||||
cStoreSettings.getWorkerSettings().substituters = {};
|
||||
|
||||
auto * store = open_local_store();
|
||||
|
||||
@@ -456,7 +456,7 @@ TEST_F(nix_api_store_test_base, nix_store_realise_builder_fails)
|
||||
buffer << t.rdbuf();
|
||||
|
||||
// Replace with current system and make builder command fail
|
||||
std::string jsonStr = nix::replaceStrings(buffer.str(), "x86_64-linux", nix::settings.thisSystem.get());
|
||||
std::string jsonStr = nix::replaceStrings(buffer.str(), "x86_64-linux", cStoreSettings.thisSystem.get());
|
||||
jsonStr = nix::replaceStrings(jsonStr, "echo $name foo > $out", "exit 1");
|
||||
|
||||
auto * drv = nix_derivation_from_json(ctx, store, jsonStr.c_str());
|
||||
@@ -491,7 +491,7 @@ TEST_F(nix_api_store_test_base, nix_store_realise_builder_no_output)
|
||||
{
|
||||
// Test that nix_store_realise properly reports errors when builder succeeds but produces no output
|
||||
nix::experimentalFeatureSettings.set("extra-experimental-features", "ca-derivations");
|
||||
nix::settings.getWorkerSettings().substituters = {};
|
||||
cStoreSettings.getWorkerSettings().substituters = {};
|
||||
|
||||
auto * store = open_local_store();
|
||||
|
||||
@@ -501,7 +501,7 @@ TEST_F(nix_api_store_test_base, nix_store_realise_builder_no_output)
|
||||
buffer << t.rdbuf();
|
||||
|
||||
// Replace with current system and make builder succeed but not produce output
|
||||
std::string jsonStr = nix::replaceStrings(buffer.str(), "x86_64-linux", nix::settings.thisSystem.get());
|
||||
std::string jsonStr = nix::replaceStrings(buffer.str(), "x86_64-linux", cStoreSettings.thisSystem.get());
|
||||
jsonStr = nix::replaceStrings(jsonStr, "echo $name foo > $out", "true");
|
||||
|
||||
auto * drv = nix_derivation_from_json(ctx, store, jsonStr.c_str());
|
||||
@@ -687,7 +687,7 @@ TEST_F(NixApiStoreTestWithRealisedPath, nix_store_realise_output_ordering)
|
||||
// This test uses a CA derivation with 10 outputs in randomized input order
|
||||
// to verify that the callback order is deterministic and alphabetical.
|
||||
nix::experimentalFeatureSettings.set("extra-experimental-features", "ca-derivations");
|
||||
nix::settings.getWorkerSettings().substituters = {};
|
||||
cStoreSettings.getWorkerSettings().substituters = {};
|
||||
|
||||
auto * store = open_local_store();
|
||||
|
||||
@@ -706,14 +706,14 @@ TEST_F(NixApiStoreTestWithRealisedPath, nix_store_realise_output_ordering)
|
||||
std::string drvJson = R"({
|
||||
"version": 4,
|
||||
"name": "multi-output-test",
|
||||
"system": ")" + nix::settings.thisSystem.get()
|
||||
"system": ")" + cStoreSettings.thisSystem.get()
|
||||
+ R"(",
|
||||
"builder": "/bin/sh",
|
||||
"args": ["-c", "echo a > $outa; echo b > $outb; echo c > $outc; echo d > $outd; echo e > $oute; echo f > $outf; echo g > $outg; echo h > $outh; echo i > $outi; echo j > $outj"],
|
||||
"env": {
|
||||
"builder": "/bin/sh",
|
||||
"name": "multi-output-test",
|
||||
"system": ")" + nix::settings.thisSystem.get()
|
||||
"system": ")" + cStoreSettings.thisSystem.get()
|
||||
+ R"(",
|
||||
"outf": ")" + outf_ph
|
||||
+ R"(",
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#include "nix/store/globals.hh"
|
||||
#include "nix/store/s3-binary-cache-store.hh"
|
||||
#include "nix/store/http-binary-cache-store.hh"
|
||||
#include "nix/store/filetransfer.hh"
|
||||
#include "nix/store/s3-url.hh"
|
||||
#include "nix/store/tests/test-main.hh"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
@@ -9,7 +11,8 @@ namespace nix {
|
||||
|
||||
TEST(S3BinaryCacheStore, constructConfig)
|
||||
{
|
||||
S3BinaryCacheStoreConfig config{"s3", "foobar", {}};
|
||||
auto settings = getTestSettings();
|
||||
S3BinaryCacheStoreConfig config{settings, "s3", "foobar", {}};
|
||||
|
||||
// The bucket name is stored as the host part of the authority in cacheUri
|
||||
EXPECT_EQ(
|
||||
@@ -22,8 +25,9 @@ TEST(S3BinaryCacheStore, constructConfig)
|
||||
|
||||
TEST(S3BinaryCacheStore, constructConfigWithRegion)
|
||||
{
|
||||
auto settings = getTestSettings();
|
||||
Store::Config::Params params{{"region", "eu-west-1"}};
|
||||
S3BinaryCacheStoreConfig config{"s3", "my-bucket", params};
|
||||
S3BinaryCacheStoreConfig config{settings, "s3", "my-bucket", params};
|
||||
|
||||
EXPECT_EQ(
|
||||
config.cacheUri,
|
||||
@@ -37,7 +41,8 @@ TEST(S3BinaryCacheStore, constructConfigWithRegion)
|
||||
|
||||
TEST(S3BinaryCacheStore, defaultSettings)
|
||||
{
|
||||
S3BinaryCacheStoreConfig config{"s3", "test-bucket", {}};
|
||||
auto settings = getTestSettings();
|
||||
S3BinaryCacheStoreConfig config{settings, "s3", "test-bucket", {}};
|
||||
|
||||
EXPECT_EQ(
|
||||
config.cacheUri,
|
||||
@@ -58,11 +63,13 @@ TEST(S3BinaryCacheStore, defaultSettings)
|
||||
*/
|
||||
TEST(S3BinaryCacheStore, s3StoreConfigPreservesParameters)
|
||||
{
|
||||
auto settings = getTestSettings();
|
||||
|
||||
StringMap params;
|
||||
params["region"] = "eu-west-1";
|
||||
params["endpoint"] = "custom.s3.com";
|
||||
|
||||
S3BinaryCacheStoreConfig config("s3", "test-bucket", params);
|
||||
S3BinaryCacheStoreConfig config(settings, "s3", "test-bucket", params);
|
||||
|
||||
// The config should preserve S3-specific parameters
|
||||
EXPECT_EQ(
|
||||
@@ -93,13 +100,15 @@ TEST(S3BinaryCacheStore, s3SchemeRegistration)
|
||||
*/
|
||||
TEST(S3BinaryCacheStore, parameterFiltering)
|
||||
{
|
||||
auto settings = getTestSettings();
|
||||
|
||||
StringMap params;
|
||||
params["region"] = "eu-west-1";
|
||||
params["endpoint"] = "minio.local";
|
||||
params["want-mass-query"] = "true"; // Non-S3 store parameter
|
||||
params["priority"] = "10"; // Non-S3 store parameter
|
||||
|
||||
S3BinaryCacheStoreConfig config("s3", "test-bucket", params);
|
||||
S3BinaryCacheStoreConfig config(settings, "s3", "test-bucket", params);
|
||||
|
||||
// Only S3-specific params should be in cacheUri.query
|
||||
EXPECT_EQ(
|
||||
@@ -127,16 +136,19 @@ TEST(S3BinaryCacheStore, parameterFiltering)
|
||||
*/
|
||||
TEST(S3BinaryCacheStore, storageClassDefault)
|
||||
{
|
||||
S3BinaryCacheStoreConfig config{"s3", "test-bucket", {}};
|
||||
auto settings = getTestSettings();
|
||||
S3BinaryCacheStoreConfig config{settings, "s3", "test-bucket", {}};
|
||||
EXPECT_EQ(config.storageClass.get(), std::nullopt);
|
||||
}
|
||||
|
||||
TEST(S3BinaryCacheStore, storageClassConfiguration)
|
||||
{
|
||||
auto settings = getTestSettings();
|
||||
|
||||
StringMap params;
|
||||
params["storage-class"] = "GLACIER";
|
||||
|
||||
S3BinaryCacheStoreConfig config("s3", "test-bucket", params);
|
||||
S3BinaryCacheStoreConfig config(settings, "s3", "test-bucket", params);
|
||||
EXPECT_EQ(config.storageClass.get(), std::optional<std::string>("GLACIER"));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "nix/store/globals.hh"
|
||||
#include "nix/store/ssh-store.hh"
|
||||
#include "nix/util/config-impl.hh"
|
||||
#include "nix/util/abstract-setting-to-json.hh"
|
||||
#include "nix/store/tests/test-main.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
TEST(SSHStore, constructConfig)
|
||||
{
|
||||
auto settings = getTestSettings();
|
||||
SSHStoreConfig config{
|
||||
settings,
|
||||
"ssh-ng",
|
||||
"me@localhost:2222",
|
||||
StoreConfig::Params{
|
||||
@@ -34,7 +36,9 @@ TEST(SSHStore, constructConfig)
|
||||
|
||||
TEST(MountedSSHStore, constructConfig)
|
||||
{
|
||||
auto settings = getTestSettings();
|
||||
MountedSSHStoreConfig config{
|
||||
settings,
|
||||
"mounted-ssh",
|
||||
"localhost",
|
||||
StoreConfig::Params{
|
||||
|
||||
@@ -1,31 +1,38 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "nix/store/globals.hh"
|
||||
#include "nix/store/uds-remote-store.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
TEST(UDSRemoteStore, constructConfig)
|
||||
{
|
||||
UDSRemoteStoreConfig config{"unix", "/tmp/socket", {}};
|
||||
Settings settings;
|
||||
UDSRemoteStoreConfig config{settings, "unix", "/tmp/socket", {}};
|
||||
|
||||
EXPECT_EQ(config.path, "/tmp/socket");
|
||||
}
|
||||
|
||||
TEST(UDSRemoteStore, constructConfigWrongScheme)
|
||||
{
|
||||
EXPECT_THROW(UDSRemoteStoreConfig("http", "/tmp/socket", {}), UsageError);
|
||||
Settings settings;
|
||||
EXPECT_THROW(UDSRemoteStoreConfig(settings, "http", "/tmp/socket", {}), UsageError);
|
||||
}
|
||||
|
||||
TEST(UDSRemoteStore, constructConfig_to_string)
|
||||
{
|
||||
UDSRemoteStoreConfig config{"unix", "", {}};
|
||||
Settings settings;
|
||||
UDSRemoteStoreConfig config{settings, "unix", "", {}};
|
||||
EXPECT_EQ(config.getReference().to_string(), "daemon");
|
||||
}
|
||||
|
||||
TEST(UDSRemoteStore, constructConfigWithParams)
|
||||
{
|
||||
Settings settings;
|
||||
|
||||
StoreConfig::Params params{{"max-connections", "1"}};
|
||||
UDSRemoteStoreConfig config{"unix", "/tmp/socket", params};
|
||||
UDSRemoteStoreConfig config{settings, "unix", "/tmp/socket", params};
|
||||
|
||||
auto storeReference = config.getReference();
|
||||
EXPECT_EQ(storeReference.to_string(), "unix:///tmp/socket?max-connections=1");
|
||||
EXPECT_EQ(storeReference.render(/*withParams=*/false), "unix:///tmp/socket");
|
||||
@@ -34,8 +41,11 @@ TEST(UDSRemoteStore, constructConfigWithParams)
|
||||
|
||||
TEST(UDSRemoteStore, constructConfigWithParamsNoPath)
|
||||
{
|
||||
Settings settings;
|
||||
|
||||
StoreConfig::Params params{{"max-connections", "1"}};
|
||||
UDSRemoteStoreConfig config{"unix", "", params};
|
||||
UDSRemoteStoreConfig config{settings, "unix", "", params};
|
||||
|
||||
auto storeReference = config.getReference();
|
||||
EXPECT_EQ(storeReference.to_string(), "daemon?max-connections=1");
|
||||
EXPECT_EQ(storeReference.render(/*withParams=*/false), "daemon");
|
||||
|
||||
@@ -21,14 +21,14 @@ protected:
|
||||
ref<DummyStore> substituter;
|
||||
|
||||
WorkerSubstitutionTest()
|
||||
: LibStoreTest([] {
|
||||
auto config = make_ref<DummyStoreConfig>(DummyStoreConfig::Params{});
|
||||
: LibStoreTest([](auto & settings) {
|
||||
auto config = make_ref<DummyStoreConfig>(settings, DummyStoreConfig::Params{});
|
||||
config->readOnly = false;
|
||||
return config->openDummyStore();
|
||||
}())
|
||||
})
|
||||
, dummyStore(store.dynamic_pointer_cast<DummyStore>())
|
||||
, substituter([] {
|
||||
auto config = make_ref<DummyStoreConfig>(DummyStoreConfig::Params{});
|
||||
, substituter([this] {
|
||||
auto config = make_ref<DummyStoreConfig>(settings, DummyStoreConfig::Params{});
|
||||
config->readOnly = false;
|
||||
config->isTrusted = true;
|
||||
return config->openDummyStore();
|
||||
@@ -67,10 +67,10 @@ TEST_F(WorkerSubstitutionTest, singleStoreObject)
|
||||
HashAlgorithm::SHA256);
|
||||
|
||||
// Snapshot the substituter (has one store object)
|
||||
checkpointJson("single/substituter", substituter);
|
||||
checkpointJson("single/substituter", substituter, settings);
|
||||
|
||||
// Snapshot the destination store before (should be empty)
|
||||
checkpointJson("../dummy-store/empty", dummyStore);
|
||||
checkpointJson("../dummy-store/empty", dummyStore, settings);
|
||||
|
||||
// The path should not exist in the destination store yet
|
||||
ASSERT_FALSE(dummyStore->isValidPath(pathInSubstituter));
|
||||
@@ -92,7 +92,7 @@ TEST_F(WorkerSubstitutionTest, singleStoreObject)
|
||||
worker.run(goals);
|
||||
|
||||
// Snapshot the destination store after (should match the substituter)
|
||||
checkpointJson("single/substituter", dummyStore);
|
||||
checkpointJson("single/substituter", dummyStore, settings);
|
||||
|
||||
// The path should now exist in the destination store
|
||||
ASSERT_TRUE(dummyStore->isValidPath(pathInSubstituter));
|
||||
@@ -138,10 +138,10 @@ TEST_F(WorkerSubstitutionTest, singleRootStoreObjectWithSingleDepStoreObject)
|
||||
StorePathSet{dependencyPath});
|
||||
|
||||
// Snapshot the substituter (has two store objects)
|
||||
checkpointJson("with-dep/substituter", substituter);
|
||||
checkpointJson("with-dep/substituter", substituter, settings);
|
||||
|
||||
// Snapshot the destination store before (should be empty)
|
||||
checkpointJson("../dummy-store/empty", dummyStore);
|
||||
checkpointJson("../dummy-store/empty", dummyStore, settings);
|
||||
|
||||
// Neither path should exist in the destination store yet
|
||||
ASSERT_FALSE(dummyStore->isValidPath(dependencyPath));
|
||||
@@ -164,7 +164,7 @@ TEST_F(WorkerSubstitutionTest, singleRootStoreObjectWithSingleDepStoreObject)
|
||||
worker.run(goals);
|
||||
|
||||
// Snapshot the destination store after (should match the substituter)
|
||||
checkpointJson("with-dep/substituter", dummyStore);
|
||||
checkpointJson("with-dep/substituter", dummyStore, settings);
|
||||
|
||||
// Both paths should now exist in the destination store
|
||||
ASSERT_TRUE(dummyStore->isValidPath(dependencyPath));
|
||||
@@ -196,7 +196,7 @@ TEST_F(WorkerSubstitutionTest, floatingDerivationOutput)
|
||||
auto drvPath = dummyStore->writeDerivation(drv);
|
||||
|
||||
// Snapshot the destination store before
|
||||
checkpointJson("ca-drv/store-before", dummyStore);
|
||||
checkpointJson("ca-drv/store-before", dummyStore, settings);
|
||||
|
||||
// Compute the hash modulo of the derivation
|
||||
// For CA floating derivations, the kind is Deferred since outputs aren't known until build
|
||||
@@ -233,7 +233,7 @@ TEST_F(WorkerSubstitutionTest, floatingDerivationOutput)
|
||||
});
|
||||
|
||||
// Snapshot the substituter
|
||||
checkpointJson("ca-drv/substituter", substituter);
|
||||
checkpointJson("ca-drv/substituter", substituter, settings);
|
||||
|
||||
// The realisation should not exist in the destination store yet
|
||||
DrvOutput drvOutput{drvHash, "out"};
|
||||
@@ -256,7 +256,7 @@ TEST_F(WorkerSubstitutionTest, floatingDerivationOutput)
|
||||
worker.run(goals);
|
||||
|
||||
// Snapshot the destination store after
|
||||
checkpointJson("ca-drv/store-after", dummyStore);
|
||||
checkpointJson("ca-drv/store-after", dummyStore, settings);
|
||||
|
||||
// The output path should now exist in the destination store
|
||||
ASSERT_TRUE(dummyStore->isValidPath(outputPath));
|
||||
@@ -351,7 +351,7 @@ TEST_F(WorkerSubstitutionTest, floatingDerivationOutputWithDepDrv)
|
||||
auto rootDrvPath = dummyStore->writeDerivation(rootDrv);
|
||||
|
||||
// Snapshot the destination store before
|
||||
checkpointJson("issue-11928/store-before", dummyStore);
|
||||
checkpointJson("issue-11928/store-before", dummyStore, settings);
|
||||
|
||||
// Compute the hash modulo for the root derivation
|
||||
auto rootHashModulo = hashDerivationModulo(*dummyStore, rootDrv, true);
|
||||
@@ -395,7 +395,7 @@ TEST_F(WorkerSubstitutionTest, floatingDerivationOutputWithDepDrv)
|
||||
|
||||
// Snapshot the substituter
|
||||
// Note: it has realisations for both drvs, but only the root's output store object
|
||||
checkpointJson("issue-11928/substituter", substituter);
|
||||
checkpointJson("issue-11928/substituter", substituter, settings);
|
||||
|
||||
// The realisations should not exist in the destination store yet
|
||||
ASSERT_FALSE(dummyStore->queryRealisation(depDrvOutput));
|
||||
@@ -418,7 +418,7 @@ TEST_F(WorkerSubstitutionTest, floatingDerivationOutputWithDepDrv)
|
||||
worker.run(goals);
|
||||
|
||||
// Snapshot the destination store after
|
||||
checkpointJson("issue-11928/store-after", dummyStore);
|
||||
checkpointJson("issue-11928/store-after", dummyStore, settings);
|
||||
|
||||
// The root output path should now exist in the destination store
|
||||
ASSERT_TRUE(dummyStore->isValidPath(rootOutputPath));
|
||||
|
||||
@@ -12,19 +12,22 @@ namespace {
|
||||
class WriteDerivationTest : public LibStoreTest
|
||||
{
|
||||
protected:
|
||||
WriteDerivationTest(ref<DummyStoreConfig> config_)
|
||||
: LibStoreTest(config_->openDummyStore())
|
||||
, config(std::move(config_))
|
||||
WriteDerivationTest(auto && makeConfig)
|
||||
: LibStoreTest([&](auto & settings) {
|
||||
this->config = makeConfig(settings);
|
||||
return config->openDummyStore();
|
||||
})
|
||||
{
|
||||
config->readOnly = false;
|
||||
}
|
||||
|
||||
WriteDerivationTest()
|
||||
: WriteDerivationTest(make_ref<DummyStoreConfig>(DummyStoreConfig::Params{}))
|
||||
: WriteDerivationTest(
|
||||
[](auto & settings) { return make_ref<DummyStoreConfig>(settings, DummyStoreConfig::Params{}); })
|
||||
{
|
||||
}
|
||||
|
||||
ref<DummyStoreConfig> config;
|
||||
std::shared_ptr<DummyStoreConfig> config;
|
||||
};
|
||||
|
||||
static Derivation makeSimpleDrv()
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
namespace nix {
|
||||
|
||||
AwsAuthError::AwsAuthError(int errorCode)
|
||||
: CloneableError("AWS authentication error: '%s' (%d)", aws_error_str(errorCode), errorCode)
|
||||
: Error("AWS authentication error: '%s' (%d)", aws_error_str(errorCode), errorCode)
|
||||
, errorCode(errorCode)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "nix/store/local-store.hh" // TODO remove, along with remaining downcasts
|
||||
#include "nix/store/globals.hh"
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
@@ -185,82 +184,6 @@ struct LogFile
|
||||
~LogFile();
|
||||
};
|
||||
|
||||
struct LocalBuildRejection
|
||||
{
|
||||
bool maxJobsZero = false;
|
||||
|
||||
struct NoLocalStore
|
||||
{};
|
||||
|
||||
/**
|
||||
* We have a local store, but we don't have an external derivation builder (which is fine), if we did, it'd be
|
||||
* fine because we would not care about platforms and features then. Since we don't, we either have the wrong
|
||||
* platform, or we are missing some system features.
|
||||
*/
|
||||
struct WrongLocalStore
|
||||
{
|
||||
template<typename T>
|
||||
struct Pair
|
||||
{
|
||||
T derivation;
|
||||
T localStore;
|
||||
};
|
||||
|
||||
std::optional<Pair<std::string>> badPlatform;
|
||||
std::optional<Pair<StringSet>> missingFeatures;
|
||||
};
|
||||
|
||||
std::variant<NoLocalStore, WrongLocalStore> rejection;
|
||||
};
|
||||
|
||||
static BuildError reject(const LocalBuildRejection & rejection, std::string_view thingCannotBuild)
|
||||
{
|
||||
if (std::get_if<LocalBuildRejection::NoLocalStore>(&rejection.rejection))
|
||||
return BuildError(
|
||||
BuildResult::Failure::InputRejected,
|
||||
"Unable to build with a primary store that isn't a local store; "
|
||||
"either pass a different '--store' or enable remote builds.\n\n"
|
||||
"For more information check 'man nix.conf' and search for '/machines'.");
|
||||
|
||||
auto & wrongStore = std::get<LocalBuildRejection::WrongLocalStore>(rejection.rejection);
|
||||
|
||||
std::string msg = fmt("Cannot build '%s'.", Magenta(thingCannotBuild));
|
||||
|
||||
if (rejection.maxJobsZero)
|
||||
msg += "\nReason: " ANSI_RED "local builds are disabled" ANSI_NORMAL
|
||||
" (max-jobs = 0)"
|
||||
"\nHint: set 'max-jobs' to a non-zero value to enable local builds, "
|
||||
"or configure remote builders via 'builders'";
|
||||
|
||||
if (wrongStore.badPlatform)
|
||||
msg +=
|
||||
fmt("\nReason: " ANSI_RED "platform mismatch" ANSI_NORMAL
|
||||
"\nRequired system: '%s'"
|
||||
"\nCurrent system: '%s'",
|
||||
Magenta(wrongStore.badPlatform->derivation),
|
||||
Magenta(wrongStore.badPlatform->localStore));
|
||||
|
||||
if (wrongStore.missingFeatures)
|
||||
msg +=
|
||||
fmt("\nReason: " ANSI_RED "missing system features" ANSI_NORMAL
|
||||
"\nRequired features: {%s}"
|
||||
"\nAvailable features: {%s}",
|
||||
concatStringsSep(", ", wrongStore.missingFeatures->derivation),
|
||||
concatStringsSep<StringSet>(", ", wrongStore.missingFeatures->localStore));
|
||||
|
||||
if (wrongStore.badPlatform || wrongStore.missingFeatures) {
|
||||
// since aarch64-darwin has Rosetta 2, this user can actually run x86_64-darwin on their
|
||||
// hardware - we should tell them to run the command to install Rosetta
|
||||
if (wrongStore.badPlatform && wrongStore.badPlatform->derivation == "x86_64-darwin"
|
||||
&& wrongStore.badPlatform->localStore == "aarch64-darwin")
|
||||
msg +=
|
||||
fmt("\nNote: run `%s` to run programs for x86_64-darwin",
|
||||
Magenta("/usr/sbin/softwareupdate --install-rosetta && launchctl stop org.nixos.nix-daemon"));
|
||||
}
|
||||
|
||||
return BuildError(BuildResult::Failure::InputRejected, std::move(msg));
|
||||
}
|
||||
|
||||
Goal::Co DerivationBuildingGoal::tryToBuild(StorePathSet inputPaths)
|
||||
{
|
||||
auto drvOptions = [&] {
|
||||
@@ -322,57 +245,29 @@ Goal::Co DerivationBuildingGoal::tryToBuild(StorePathSet inputPaths)
|
||||
}
|
||||
checkPathValidity(initialOutputs);
|
||||
|
||||
auto localBuildResult = [&]() -> std::variant<LocalBuildCapability, LocalBuildRejection> {
|
||||
bool maxJobsZero = worker.settings.maxBuildJobs.get() == 0;
|
||||
/**
|
||||
* Activity that denotes waiting for a lock.
|
||||
*/
|
||||
std::unique_ptr<Activity> actLock;
|
||||
|
||||
auto * localStoreP = dynamic_cast<LocalStore *>(&worker.store);
|
||||
if (!localStoreP)
|
||||
return LocalBuildRejection{.maxJobsZero = maxJobsZero, .rejection = LocalBuildRejection::NoLocalStore{}};
|
||||
/**
|
||||
* Locks on (fixed) output paths.
|
||||
*/
|
||||
PathLocks outputLocks;
|
||||
|
||||
/**
|
||||
* Now that we've decided we can't / won't do a remote build, check
|
||||
* that we can in fact build locally. First see if there is an
|
||||
* external builder for a "semi-local build". If there is, prefer to
|
||||
* use that. If there is not, then check if we can do a "true" local
|
||||
* build.
|
||||
*/
|
||||
auto * ext = settings.getLocalSettings().findExternalDerivationBuilderIfSupported(*drv);
|
||||
bool useHook;
|
||||
|
||||
if (ext)
|
||||
return LocalBuildCapability{*localStoreP, ext};
|
||||
const ExternalBuilder * externalBuilder = nullptr;
|
||||
|
||||
using WrongLocalStore = LocalBuildRejection::WrongLocalStore;
|
||||
|
||||
WrongLocalStore wrongStore;
|
||||
|
||||
if (drv->platform != settings.thisSystem.get() && !settings.extraPlatforms.get().count(drv->platform)
|
||||
&& !drv->isBuiltin())
|
||||
wrongStore.badPlatform = WrongLocalStore::Pair<std::string>{drv->platform, settings.thisSystem.get()};
|
||||
|
||||
{
|
||||
auto required = drvOptions.getRequiredSystemFeatures(*drv);
|
||||
auto & available = worker.store.config.systemFeatures.get();
|
||||
if (std::ranges::any_of(required, [&](const std::string & f) { return !available.count(f); }))
|
||||
wrongStore.missingFeatures = WrongLocalStore::Pair<StringSet>{required, available};
|
||||
}
|
||||
|
||||
if (maxJobsZero || wrongStore.badPlatform || wrongStore.missingFeatures)
|
||||
return LocalBuildRejection{.maxJobsZero = maxJobsZero, .rejection = std::move(wrongStore)};
|
||||
|
||||
return LocalBuildCapability{*localStoreP, ext};
|
||||
}();
|
||||
|
||||
auto acquireResources = [&](bool & done, PathLocks & outputLocks) -> Goal::Co {
|
||||
while (true) {
|
||||
trace("trying to build");
|
||||
|
||||
/**
|
||||
* Output paths to acquire locks on, if known a priori.
|
||||
*
|
||||
* The locks are automatically released when the caller's `PathLocks` goes
|
||||
* out of scope, including on exception unwinding. If we can't acquire the lock, then
|
||||
* continue; hopefully some other goal can start a build, and if not, the
|
||||
* main loop will sleep a few seconds and then retry this goal.
|
||||
*/
|
||||
/* Obtain locks on all output paths, if the paths are known a priori.
|
||||
|
||||
The locks are automatically released when we exit this function or Nix
|
||||
crashes. If we can't acquire the lock, then continue; hopefully some
|
||||
other goal can start a build, and if not, the main loop will sleep a few
|
||||
seconds and then retry this goal. */
|
||||
std::set<std::filesystem::path> lockFiles;
|
||||
/* FIXME: Should lock something like the drv itself so we don't build same
|
||||
CA drv concurrently */
|
||||
@@ -416,8 +311,7 @@ Goal::Co DerivationBuildingGoal::tryToBuild(StorePathSet inputPaths)
|
||||
debug("skipping build of derivation '%s', someone beat us to it", worker.store.printStorePath(drvPath));
|
||||
outputLocks.setDeletion(true);
|
||||
outputLocks.unlock();
|
||||
done = true;
|
||||
co_return Return{};
|
||||
co_return doneSuccess(BuildResult::Success::AlreadyValid, std::move(validOutputs));
|
||||
}
|
||||
|
||||
/* If any of the outputs already exist but are not valid, delete
|
||||
@@ -432,133 +326,112 @@ Goal::Co DerivationBuildingGoal::tryToBuild(StorePathSet inputPaths)
|
||||
}
|
||||
}
|
||||
|
||||
co_return Return{};
|
||||
};
|
||||
bool canBuildLocally = [&] {
|
||||
if (drv->platform != worker.store.config.settings.thisSystem.get()
|
||||
&& !worker.store.config.settings.extraPlatforms.get().count(drv->platform) && !drv->isBuiltin())
|
||||
return false;
|
||||
|
||||
auto tryHookLoop = [&](bool & valid) -> Goal::Co {
|
||||
{
|
||||
PathLocks outputLocks;
|
||||
co_await acquireResources(valid, outputLocks);
|
||||
if (valid)
|
||||
co_return doneSuccess(BuildResult::Success::AlreadyValid, checkPathValidity(initialOutputs).second);
|
||||
if (worker.settings.maxBuildJobs.get() == 0 && !drv->isBuiltin())
|
||||
return false;
|
||||
|
||||
for (auto & feature : drvOptions.getRequiredSystemFeatures(*drv))
|
||||
if (!worker.store.config.systemFeatures.get().count(feature))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}();
|
||||
|
||||
/* Don't do a remote build if the derivation has the attribute
|
||||
`preferLocalBuild' set. Also, check and repair modes are only
|
||||
supported for local builds. */
|
||||
bool buildLocally = (buildMode != bmNormal || (drvOptions.preferLocalBuild && canBuildLocally))
|
||||
&& worker.settings.maxBuildJobs.get() != 0;
|
||||
|
||||
if (buildLocally) {
|
||||
useHook = false;
|
||||
} else {
|
||||
switch (tryBuildHook(drvOptions)) {
|
||||
case rpAccept:
|
||||
/* Yes, it has started doing so. Wait until we get
|
||||
EOF from the hook. */
|
||||
valid = true;
|
||||
co_return buildWithHook(
|
||||
std::move(inputPaths), std::move(initialOutputs), std::move(drvOptions), std::move(outputLocks));
|
||||
case rpDecline:
|
||||
// We should do it ourselves.
|
||||
co_return Return{};
|
||||
useHook = true;
|
||||
break;
|
||||
case rpPostpone:
|
||||
/* Not now; wait until at least one child finishes or
|
||||
the wake-up timeout expires. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PathLocks outputLocks;
|
||||
{
|
||||
// First attempt was postponed. Retry in a loop with an activity
|
||||
// that lives until accept or decline.
|
||||
Activity act(
|
||||
*logger,
|
||||
lvlWarn,
|
||||
actBuildWaiting,
|
||||
fmt("waiting for a machine to build '%s'", Magenta(worker.store.printStorePath(drvPath))));
|
||||
|
||||
while (true) {
|
||||
if (!actLock)
|
||||
actLock = std::make_unique<Activity>(
|
||||
*logger,
|
||||
lvlWarn,
|
||||
actBuildWaiting,
|
||||
fmt("waiting for a machine to build '%s'", Magenta(worker.store.printStorePath(drvPath))));
|
||||
outputLocks.unlock();
|
||||
co_await waitForAWhile();
|
||||
co_await acquireResources(valid, outputLocks);
|
||||
if (valid)
|
||||
break;
|
||||
continue;
|
||||
case rpDecline:
|
||||
/* We should do it ourselves.
|
||||
|
||||
Now that we've decided we can't / won't do a remote build, check
|
||||
that we can in fact build locally. First see if there is an
|
||||
external builder for a "semi-local build". If there is, prefer to
|
||||
use that. If there is not, then check if we can do a "true" local
|
||||
build. */
|
||||
|
||||
externalBuilder = worker.store.config.settings.findExternalDerivationBuilderIfSupported(*drv);
|
||||
|
||||
if (!externalBuilder && !canBuildLocally) {
|
||||
auto msg =
|
||||
fmt("Cannot build '%s'.\n"
|
||||
"Reason: " ANSI_RED "required system or feature not available" ANSI_NORMAL
|
||||
"\n"
|
||||
"Required system: '%s' with features {%s}\n"
|
||||
"Current system: '%s' with features {%s}",
|
||||
Magenta(worker.store.printStorePath(drvPath)),
|
||||
Magenta(drv->platform),
|
||||
concatStringsSep(", ", drvOptions.getRequiredSystemFeatures(*drv)),
|
||||
Magenta(worker.store.config.settings.thisSystem),
|
||||
concatStringsSep<StringSet>(", ", worker.store.Store::config.systemFeatures));
|
||||
|
||||
// since aarch64-darwin has Rosetta 2, this user can actually run x86_64-darwin on their hardware -
|
||||
// we should tell them to run the command to install Darwin 2
|
||||
if (drv->platform == "x86_64-darwin" && worker.store.config.settings.thisSystem == "aarch64-darwin")
|
||||
msg += fmt(
|
||||
"\nNote: run `%s` to run programs for x86_64-darwin",
|
||||
Magenta(
|
||||
"/usr/sbin/softwareupdate --install-rosetta && launchctl stop org.nixos.nix-daemon"));
|
||||
|
||||
switch (tryBuildHook(drvOptions)) {
|
||||
case rpAccept:
|
||||
/* Yes, it has started doing so. Wait until we get
|
||||
EOF from the hook. */
|
||||
break;
|
||||
case rpPostpone:
|
||||
/* Not now; wait until at least one child finishes or
|
||||
the wake-up timeout expires. */
|
||||
outputLocks.unlock();
|
||||
continue;
|
||||
case rpDecline:
|
||||
// We should do it ourselves.
|
||||
co_return Return{};
|
||||
co_return doneFailure({BuildResult::Failure::InputRejected, std::move(msg)});
|
||||
}
|
||||
|
||||
useHook = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
co_return doneSuccess(BuildResult::Success::AlreadyValid, checkPathValidity(initialOutputs).second);
|
||||
} else {
|
||||
co_return buildWithHook(
|
||||
std::move(inputPaths), std::move(initialOutputs), std::move(drvOptions), std::move(outputLocks));
|
||||
}
|
||||
};
|
||||
|
||||
auto tryBuildLocally = [&](bool & valid) -> Goal::Co {
|
||||
if (auto * cap = std::get_if<LocalBuildCapability>(&localBuildResult)) {
|
||||
PathLocks outputLocks;
|
||||
co_await acquireResources(valid, outputLocks);
|
||||
if (valid)
|
||||
co_return doneSuccess(BuildResult::Success::AlreadyValid, checkPathValidity(initialOutputs).second);
|
||||
|
||||
valid = true;
|
||||
co_return buildLocally(
|
||||
*cap, std::move(inputPaths), std::move(initialOutputs), std::move(drvOptions), std::move(outputLocks));
|
||||
}
|
||||
|
||||
co_return Return{};
|
||||
};
|
||||
|
||||
if (buildMode != bmNormal) {
|
||||
// Check and repair modes operate on the state of this store specifically,
|
||||
// so they must always build locally.
|
||||
bool valid = false;
|
||||
co_await tryBuildLocally(valid);
|
||||
if (valid)
|
||||
co_return Return{};
|
||||
} else if (drvOptions.preferLocalBuild) {
|
||||
// Local is preferred, so try it first. If it's not available, fall back to the hook.
|
||||
{
|
||||
bool valid = false;
|
||||
co_await tryBuildLocally(valid);
|
||||
if (valid)
|
||||
co_return Return{};
|
||||
}
|
||||
{
|
||||
bool valid = false;
|
||||
co_await tryHookLoop(valid);
|
||||
if (valid)
|
||||
co_return Return{};
|
||||
}
|
||||
} else {
|
||||
// Default preference is a remote build: they tend to be faster and preserve local
|
||||
// resources for other tasks. Fall back to local if no remote is available.
|
||||
{
|
||||
bool valid = false;
|
||||
co_await tryHookLoop(valid);
|
||||
if (valid)
|
||||
co_return Return{};
|
||||
}
|
||||
{
|
||||
bool valid = false;
|
||||
co_await tryBuildLocally(valid);
|
||||
if (valid)
|
||||
co_return Return{};
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
std::string storePath = worker.store.printStorePath(drvPath);
|
||||
auto * rejection = std::get_if<LocalBuildRejection>(&localBuildResult);
|
||||
assert(rejection);
|
||||
co_return doneFailure(reject(*rejection, storePath));
|
||||
actLock.reset();
|
||||
|
||||
if (useHook) {
|
||||
co_return buildWithHook(
|
||||
std::move(inputPaths), std::move(initialOutputs), std::move(drvOptions), std::move(outputLocks));
|
||||
} else if (auto * localStoreP = dynamic_cast<LocalStore *>(&worker.store)) {
|
||||
co_return buildLocally(
|
||||
*localStoreP,
|
||||
std::move(inputPaths),
|
||||
std::move(initialOutputs),
|
||||
std::move(drvOptions),
|
||||
std::move(outputLocks),
|
||||
externalBuilder);
|
||||
} else {
|
||||
throw Error(
|
||||
R"(
|
||||
Unable to build with a primary store that isn't a local store;
|
||||
either pass a different '--store' or enable remote builds.
|
||||
|
||||
For more information check 'man nix.conf' and search for '/machines'.
|
||||
)");
|
||||
}
|
||||
}
|
||||
|
||||
Goal::Co DerivationBuildingGoal::buildWithHook(
|
||||
@@ -606,7 +479,8 @@ Goal::Co DerivationBuildingGoal::buildWithHook(
|
||||
hook->toHook.writeSide.close();
|
||||
|
||||
/* Create the log file and pipe. */
|
||||
std::unique_ptr<LogFile> logFile = std::make_unique<LogFile>(worker.store, drvPath, settings.getLogFileSettings());
|
||||
std::unique_ptr<LogFile> logFile =
|
||||
std::make_unique<LogFile>(worker.store, drvPath, worker.store.config.settings.getLogFileSettings());
|
||||
|
||||
std::set<MuxablePipePollState::CommChannel> fds;
|
||||
fds.insert(hook->fromHook.readSide.get());
|
||||
@@ -766,11 +640,12 @@ Goal::Co DerivationBuildingGoal::buildWithHook(
|
||||
}
|
||||
|
||||
Goal::Co DerivationBuildingGoal::buildLocally(
|
||||
LocalBuildCapability localBuildCap,
|
||||
LocalStore & localStore,
|
||||
StorePathSet inputPaths,
|
||||
std::map<std::string, InitialOutput> initialOutputs,
|
||||
DerivationOptions<StorePath> drvOptions,
|
||||
PathLocks outputLocks)
|
||||
PathLocks outputLocks,
|
||||
const ExternalBuilder * externalBuilder)
|
||||
{
|
||||
co_await yield();
|
||||
|
||||
@@ -781,7 +656,7 @@ Goal::Co DerivationBuildingGoal::buildLocally(
|
||||
std::unique_ptr<LogFile> logFile;
|
||||
|
||||
auto openLogFile = [&]() {
|
||||
logFile = std::make_unique<LogFile>(worker.store, drvPath, settings.getLogFileSettings());
|
||||
logFile = std::make_unique<LogFile>(worker.store, drvPath, worker.store.config.settings.getLogFileSettings());
|
||||
};
|
||||
|
||||
auto closeLogFile = [&]() { logFile.reset(); };
|
||||
@@ -854,7 +729,7 @@ Goal::Co DerivationBuildingGoal::buildLocally(
|
||||
};
|
||||
|
||||
decltype(DerivationBuilderParams::defaultPathsInChroot) defaultPathsInChroot =
|
||||
localBuildCap.localStore.config->getLocalSettings().sandboxPaths.get();
|
||||
localStore.config->getLocalSettings().sandboxPaths.get();
|
||||
DesugaredEnv desugaredEnv;
|
||||
|
||||
/* Add the closure of store paths to the chroot. */
|
||||
@@ -882,6 +757,7 @@ Goal::Co DerivationBuildingGoal::buildLocally(
|
||||
}
|
||||
|
||||
DerivationBuilderParams params{
|
||||
.settings = worker.store.config.settings,
|
||||
.drvPath = drvPath,
|
||||
.buildResult = buildResult,
|
||||
.drv = *drv,
|
||||
@@ -896,14 +772,14 @@ Goal::Co DerivationBuildingGoal::buildLocally(
|
||||
|
||||
/* If we have to wait and retry (see below), then `builder` will
|
||||
already be created, so we don't need to create it again. */
|
||||
builder = localBuildCap.externalBuilder
|
||||
builder = externalBuilder
|
||||
? makeExternalDerivationBuilder(
|
||||
localBuildCap.localStore,
|
||||
localStore,
|
||||
std::make_unique<DerivationBuildingGoalCallbacks>(*this, openLogFile, closeLogFile),
|
||||
std::move(params),
|
||||
*localBuildCap.externalBuilder)
|
||||
*externalBuilder)
|
||||
: makeDerivationBuilder(
|
||||
localBuildCap.localStore,
|
||||
localStore,
|
||||
std::make_unique<DerivationBuildingGoalCallbacks>(*this, openLogFile, closeLogFile),
|
||||
std::move(params));
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "nix/store/build/goal.hh"
|
||||
#include "nix/store/build/worker.hh"
|
||||
#include "nix/store/worker-settings.hh"
|
||||
#include "nix/store/globals.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
TimedOut::TimedOut(time_t maxDuration)
|
||||
: CloneableError(BuildResult::Failure::TimedOut, "timed out after %1% seconds", maxDuration)
|
||||
: BuildError(BuildResult::Failure::TimedOut, "timed out after %1% seconds", maxDuration)
|
||||
, maxDuration(maxDuration)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -22,9 +22,9 @@ Worker::Worker(Store & store, Store & evalStore)
|
||||
, actSubstitutions(*logger, actCopyPaths)
|
||||
, store(store)
|
||||
, evalStore(evalStore)
|
||||
, settings(nix::settings.getWorkerSettings())
|
||||
, getSubstituters{[] {
|
||||
return nix::settings.getWorkerSettings().useSubstitutes ? getDefaultSubstituters() : std::list<ref<Store>>{};
|
||||
, settings(store.config.settings.getWorkerSettings())
|
||||
, getSubstituters{[&] {
|
||||
return settings.useSubstitutes ? getDefaultSubstituters(store.config.settings) : std::list<ref<Store>>{};
|
||||
}}
|
||||
{
|
||||
nrLocalBuilds = 0;
|
||||
@@ -367,7 +367,9 @@ void Worker::run(const Goals & _topGoals)
|
||||
if (!children.empty() || !waitingForAWhile.empty())
|
||||
waitForInput();
|
||||
else if (awake.empty() && 0U == settings.maxBuildJobs) {
|
||||
if (Machine::parseConfig({nix::settings.thisSystem}, nix::settings.getWorkerSettings().builders).empty())
|
||||
if (Machine::parseConfig(
|
||||
{store.config.settings.thisSystem}, store.config.settings.getWorkerSettings().builders)
|
||||
.empty())
|
||||
throw Error(
|
||||
"Unable to start any build; either increase '--max-jobs' or enable remote builds.\n"
|
||||
"\n"
|
||||
|
||||
@@ -5,14 +5,15 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
CommonSSHStoreConfig::CommonSSHStoreConfig(std::string_view scheme, std::string_view authority, const Params & params)
|
||||
: CommonSSHStoreConfig(scheme, ParsedURL::Authority::parse(authority), params)
|
||||
CommonSSHStoreConfig::CommonSSHStoreConfig(
|
||||
nix::Settings & settings, std::string_view scheme, std::string_view authority, const Params & params)
|
||||
: CommonSSHStoreConfig(settings, scheme, ParsedURL::Authority::parse(authority), params)
|
||||
{
|
||||
}
|
||||
|
||||
CommonSSHStoreConfig::CommonSSHStoreConfig(
|
||||
std::string_view scheme, const ParsedURL::Authority & authority, const Params & params)
|
||||
: StoreConfig(params)
|
||||
nix::Settings & settings, std::string_view scheme, const ParsedURL::Authority & authority, const Params & params)
|
||||
: StoreConfig(settings, params)
|
||||
, authority(authority)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -230,7 +230,7 @@ struct ClientSettings
|
||||
bool useSubstitutes;
|
||||
StringMap overrides;
|
||||
|
||||
void apply(TrustedFlag trusted)
|
||||
void apply(Settings & settings, TrustedFlag trusted)
|
||||
{
|
||||
settings.keepFailed = keepFailed;
|
||||
settings.getWorkerSettings().keepGoing = keepGoing;
|
||||
@@ -783,7 +783,7 @@ static void performOp(
|
||||
// FIXME: use some setting in recursive mode. Will need to use
|
||||
// non-global variables.
|
||||
if (!recursive)
|
||||
clientSettings.apply(trusted);
|
||||
clientSettings.apply(store->config.settings, trusted);
|
||||
|
||||
logger->stopWork();
|
||||
break;
|
||||
|
||||
@@ -136,12 +136,6 @@ StorePath Store::writeDerivation(const Derivation & drv, RepairFlag repair)
|
||||
{
|
||||
auto [suffix, contents, references, path] = infoForDerivation(*this, drv);
|
||||
|
||||
/* In case the derivation is already valid, we bail out early since that's
|
||||
faster. But we need to make sure that the derivation has a corresponding
|
||||
temproot. It is added by the remote in addToStoreFromDump, but we'd like
|
||||
to avoid sending a lot of drv contents to the daemon. */
|
||||
addTempRoot(path);
|
||||
|
||||
if (isValidPath(path) && !repair)
|
||||
return path;
|
||||
|
||||
|
||||
@@ -408,10 +408,10 @@ void adl_serializer<DummyStore::PathInfoAndContents>::to_json(json & json, const
|
||||
};
|
||||
}
|
||||
|
||||
ref<DummyStoreConfig> adl_serializer<ref<DummyStore::Config>>::from_json(const json & json)
|
||||
ref<DummyStoreConfig> adl_serializer<ref<DummyStore::Config>>::from_json(Settings & settings, const json & json)
|
||||
{
|
||||
auto & obj = getObject(json);
|
||||
auto cfg = make_ref<DummyStore::Config>(DummyStore::Config::Params{});
|
||||
auto cfg = make_ref<DummyStore::Config>(settings, DummyStore::Config::Params{});
|
||||
const_cast<PathSetting &>(cfg->storeDir_).set(getString(valueAt(obj, "store")));
|
||||
cfg->readOnly = true;
|
||||
return cfg;
|
||||
@@ -424,10 +424,11 @@ void adl_serializer<DummyStoreConfig>::to_json(json & json, const DummyStoreConf
|
||||
};
|
||||
}
|
||||
|
||||
ref<DummyStore> adl_serializer<ref<DummyStore>>::from_json(const json & json)
|
||||
ref<DummyStore> adl_serializer<ref<DummyStore>>::from_json(Settings & settings, const json & json)
|
||||
{
|
||||
auto & obj = getObject(json);
|
||||
ref<DummyStore> res = adl_serializer<ref<DummyStoreConfig>>::from_json(valueAt(obj, "config"))->openDummyStore();
|
||||
ref<DummyStore> res =
|
||||
adl_serializer<ref<DummyStoreConfig>>::from_json(settings, valueAt(obj, "config"))->openDummyStore();
|
||||
for (auto & [k, v] : getObject(valueAt(obj, "contents")))
|
||||
res->contents.insert({StorePath{k}, v});
|
||||
for (auto & [k, v] : getObject(valueAt(obj, "derivations")))
|
||||
|
||||
@@ -60,12 +60,12 @@ namespace {
|
||||
using curlSList = std::unique_ptr<::curl_slist, decltype([](::curl_slist * list) { ::curl_slist_free_all(list); })>;
|
||||
using curlMulti = std::unique_ptr<::CURLM, decltype([](::CURLM * multi) { ::curl_multi_cleanup(multi); })>;
|
||||
|
||||
struct curlMultiError final : CloneableError<curlMultiError, Error>
|
||||
struct curlMultiError : Error
|
||||
{
|
||||
::CURLMcode code;
|
||||
|
||||
curlMultiError(::CURLMcode code)
|
||||
: CloneableError{"unexpected curl multi error: %s", ::curl_multi_strerror(code)}
|
||||
: Error{"unexpected curl multi error: %s", ::curl_multi_strerror(code)}
|
||||
{
|
||||
assert(code != CURLM_OK);
|
||||
}
|
||||
@@ -737,7 +737,7 @@ struct curlFileTransfer : public FileTransfer
|
||||
download after a while. If we're writing to a
|
||||
sink, we can only retry if the server supports
|
||||
ranged requests. */
|
||||
if (err == Transient && attempt < fileTransfer.settings.tries
|
||||
if (err == Transient && attempt < request.tries
|
||||
&& (!this->request.dataCallback || writtenToSink == 0 || (acceptRanges && encoding.empty()))) {
|
||||
int ms = retryTimeMs
|
||||
* std::pow(
|
||||
@@ -1212,7 +1212,7 @@ void FileTransfer::download(
|
||||
template<typename... Args>
|
||||
FileTransferError::FileTransferError(
|
||||
FileTransfer::Error error, std::optional<std::string> response, const Args &... args)
|
||||
: CloneableError(args...)
|
||||
: Error(args...)
|
||||
, error(error)
|
||||
, response(response)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "nix/store/local-gc.hh"
|
||||
#include "nix/store/local-store.hh"
|
||||
#include "nix/store/path.hh"
|
||||
#include "nix/util/configuration.hh"
|
||||
#include "nix/util/finally.hh"
|
||||
#include "nix/util/unix-domain-socket.hh"
|
||||
#include "nix/util/signals.hh"
|
||||
@@ -307,33 +306,9 @@ Roots LocalStore::findRoots(bool censor)
|
||||
return roots;
|
||||
}
|
||||
|
||||
static Roots requestRuntimeRoots(const LocalStoreConfig & config, const std::filesystem::path & socketPath)
|
||||
{
|
||||
Roots roots;
|
||||
|
||||
auto socket = connect(socketPath);
|
||||
auto socketSource = FdSource(socket.get());
|
||||
|
||||
while (1) {
|
||||
auto line = socketSource.readLine(true, '\0');
|
||||
if (line == "")
|
||||
break;
|
||||
roots[config.parseStorePath(line)].insert(censored);
|
||||
};
|
||||
|
||||
return roots;
|
||||
}
|
||||
|
||||
void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
|
||||
{
|
||||
Roots unchecked;
|
||||
|
||||
if (config->useRootsDaemon) {
|
||||
experimentalFeatureSettings.require(Xp::LocalOverlayStore);
|
||||
unchecked = requestRuntimeRoots(*config, config->getRootsSocketPath());
|
||||
} else {
|
||||
unchecked = findRuntimeRootsUnchecked(*config);
|
||||
}
|
||||
auto unchecked = findRuntimeRootsUnchecked(*config);
|
||||
|
||||
for (auto & [path, links] : unchecked) {
|
||||
if (!isValidPath(path))
|
||||
|
||||
@@ -79,10 +79,6 @@ LogFileSettings::LogFileSettings()
|
||||
{
|
||||
}
|
||||
|
||||
Settings settings;
|
||||
|
||||
static GlobalConfig::Register rSettings(&settings);
|
||||
|
||||
Settings::Settings()
|
||||
: nixStateDir(canonPath(getEnvNonEmpty("NIX_STATE_DIR").value_or(NIX_STATE_DIR)))
|
||||
, nixDaemonSocketFile(canonPath(getEnvOsNonEmpty(OS_STR("NIX_DAEMON_SOCKET_PATH"))
|
||||
@@ -279,7 +275,7 @@ bool Settings::isWSL1()
|
||||
#endif
|
||||
}
|
||||
|
||||
const ExternalBuilder * LocalSettings::findExternalDerivationBuilderIfSupported(const Derivation & drv)
|
||||
const ExternalBuilder * Settings::findExternalDerivationBuilderIfSupported(const Derivation & drv)
|
||||
{
|
||||
if (auto it = std::ranges::find_if(
|
||||
externalBuilders.get(), [&](const auto & handler) { return handler.systems.contains(drv.platform); });
|
||||
@@ -429,17 +425,17 @@ unsigned int MaxBuildJobsSetting::parse(const std::string & str) const
|
||||
}
|
||||
|
||||
template<>
|
||||
LocalSettings::ExternalBuilders BaseSetting<LocalSettings::ExternalBuilders>::parse(const std::string & str) const
|
||||
Settings::ExternalBuilders BaseSetting<Settings::ExternalBuilders>::parse(const std::string & str) const
|
||||
{
|
||||
try {
|
||||
return nlohmann::json::parse(str).template get<LocalSettings::ExternalBuilders>();
|
||||
return nlohmann::json::parse(str).template get<Settings::ExternalBuilders>();
|
||||
} catch (std::exception & e) {
|
||||
throw UsageError("parsing setting '%s': %s", name, e.what());
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string BaseSetting<LocalSettings::ExternalBuilders>::to_string() const
|
||||
std::string BaseSetting<Settings::ExternalBuilders>::to_string() const
|
||||
{
|
||||
return nlohmann::json(value).dump();
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "nix/store/sqlite.hh"
|
||||
#include "nix/util/callback.hh"
|
||||
#include "nix/store/store-registration.hh"
|
||||
#include "nix/store/globals.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -21,8 +20,9 @@ StringSet HttpBinaryCacheStoreConfig::uriSchemes()
|
||||
}
|
||||
|
||||
HttpBinaryCacheStoreConfig::HttpBinaryCacheStoreConfig(
|
||||
std::string_view scheme, std::string_view _cacheUri, const Params & params)
|
||||
nix::Settings & settings, std::string_view scheme, std::string_view _cacheUri, const Params & params)
|
||||
: HttpBinaryCacheStoreConfig(
|
||||
settings,
|
||||
parseURL(
|
||||
std::string{scheme} + "://"
|
||||
+ (!_cacheUri.empty()
|
||||
@@ -32,9 +32,10 @@ HttpBinaryCacheStoreConfig::HttpBinaryCacheStoreConfig(
|
||||
{
|
||||
}
|
||||
|
||||
HttpBinaryCacheStoreConfig::HttpBinaryCacheStoreConfig(ParsedURL _cacheUri, const Params & params)
|
||||
: StoreConfig(params)
|
||||
, BinaryCacheStoreConfig(params)
|
||||
HttpBinaryCacheStoreConfig::HttpBinaryCacheStoreConfig(
|
||||
nix::Settings & settings, ParsedURL _cacheUri, const Params & params)
|
||||
: StoreConfig(settings, params)
|
||||
, BinaryCacheStoreConfig(settings, params)
|
||||
, cacheUri(std::move(_cacheUri))
|
||||
{
|
||||
while (!cacheUri.path.empty() && cacheUri.path.back() == "")
|
||||
@@ -66,7 +67,8 @@ HttpBinaryCacheStore::HttpBinaryCacheStore(ref<Config> config, ref<FileTransfer>
|
||||
, fileTransfer{fileTransfer}
|
||||
, config{config}
|
||||
{
|
||||
diskCache = NarInfoDiskCache::get(settings.getNarInfoDiskCacheSettings(), {.useWAL = settings.useSQLiteWAL});
|
||||
diskCache = NarInfoDiskCache::get(
|
||||
config->settings.getNarInfoDiskCacheSettings(), {.useWAL = config->settings.useSQLiteWAL});
|
||||
}
|
||||
|
||||
void HttpBinaryCacheStore::init()
|
||||
@@ -104,7 +106,7 @@ std::optional<CompressionAlgo> HttpBinaryCacheStore::getCompressionMethod(const
|
||||
void HttpBinaryCacheStore::maybeDisable()
|
||||
{
|
||||
auto state(_state.lock());
|
||||
if (state->enabled && settings.getWorkerSettings().tryFallback) {
|
||||
if (state->enabled && config->settings.getWorkerSettings().tryFallback) {
|
||||
int t = 60;
|
||||
printError("disabling binary cache '%s' for %s seconds", config->getHumanReadableURI(), t);
|
||||
state->enabled = false;
|
||||
|
||||
@@ -34,13 +34,12 @@ struct AwsCredentials
|
||||
}
|
||||
};
|
||||
|
||||
class AwsAuthError final : public CloneableError<AwsAuthError, Error>
|
||||
class AwsAuthError : public Error
|
||||
{
|
||||
std::optional<int> errorCode;
|
||||
|
||||
public:
|
||||
using CloneableError::CloneableError;
|
||||
|
||||
using Error::Error;
|
||||
AwsAuthError(int errorCode);
|
||||
|
||||
std::optional<int> getErrorCode() const
|
||||
|
||||
@@ -58,7 +58,7 @@ enum struct BuildResultFailureStatus : uint8_t {
|
||||
* This is both an exception type (inherits from Error) and serves as
|
||||
* the failure variant in BuildResult::inner.
|
||||
*/
|
||||
struct BuildError : public CloneableError<BuildError, Error>
|
||||
struct BuildError : public Error
|
||||
{
|
||||
using Status = BuildResultFailureStatus;
|
||||
using enum Status;
|
||||
@@ -80,7 +80,7 @@ public:
|
||||
*/
|
||||
template<typename... Args>
|
||||
BuildError(Status status, const Args &... args)
|
||||
: CloneableError(args...)
|
||||
: Error(args...)
|
||||
, status{status}
|
||||
{
|
||||
}
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
* Also used for deserialization.
|
||||
*/
|
||||
BuildError(Args args)
|
||||
: CloneableError(std::move(args.msg))
|
||||
: Error(std::move(args.msg))
|
||||
, status{args.status}
|
||||
, isNonDeterministic{args.isNonDeterministic}
|
||||
|
||||
@@ -108,7 +108,7 @@ public:
|
||||
* Default constructor for deserialization.
|
||||
*/
|
||||
BuildError()
|
||||
: CloneableError("")
|
||||
: Error("")
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -16,18 +16,20 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
class Settings;
|
||||
|
||||
/**
|
||||
* Denotes a build failure that stemmed from the builder exiting with a
|
||||
* failing exist status.
|
||||
*/
|
||||
struct BuilderFailureError final : CloneableError<BuilderFailureError, BuildError>
|
||||
struct BuilderFailureError : BuildError
|
||||
{
|
||||
int builderStatus;
|
||||
|
||||
std::string extraMsgAfter;
|
||||
|
||||
BuilderFailureError(BuildResult::Failure::Status status, int builderStatus, std::string extraMsgAfter)
|
||||
: CloneableError{
|
||||
: BuildError{
|
||||
status,
|
||||
/* No message for now, because the caller will make for
|
||||
us, with extra context */
|
||||
@@ -55,6 +57,8 @@ typedef std::map<std::filesystem::path, ChrootPath> PathsInChroot; // maps targe
|
||||
*/
|
||||
struct DerivationBuilderParams
|
||||
{
|
||||
Settings & settings;
|
||||
|
||||
/** The path of the derivation. */
|
||||
const StorePath & drvPath;
|
||||
|
||||
|
||||
@@ -64,12 +64,6 @@ private:
|
||||
|
||||
std::string key() override;
|
||||
|
||||
struct LocalBuildCapability
|
||||
{
|
||||
LocalStore & localStore;
|
||||
const ExternalBuilder * externalBuilder;
|
||||
};
|
||||
|
||||
/**
|
||||
* The states.
|
||||
*/
|
||||
@@ -81,11 +75,12 @@ private:
|
||||
DerivationOptions<StorePath> drvOptions,
|
||||
PathLocks outputLocks);
|
||||
Co buildLocally(
|
||||
LocalBuildCapability localBuildCap,
|
||||
LocalStore & localStore,
|
||||
StorePathSet inputPaths,
|
||||
std::map<std::string, InitialOutput> initialOutputs,
|
||||
DerivationOptions<StorePath> drvOptions,
|
||||
PathLocks outputLocks);
|
||||
PathLocks outputLocks,
|
||||
const ExternalBuilder * externalBuilder);
|
||||
|
||||
/**
|
||||
* Is the build hook willing to perform the build?
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
struct TimedOut final : CloneableError<TimedOut, BuildError>
|
||||
struct TimedOut : BuildError
|
||||
{
|
||||
time_t maxDuration;
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ struct Package
|
||||
}
|
||||
};
|
||||
|
||||
class BuildEnvFileConflictError final : public CloneableError<BuildEnvFileConflictError, Error>
|
||||
class BuildEnvFileConflictError : public Error
|
||||
{
|
||||
public:
|
||||
const Path fileA;
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
int priority;
|
||||
|
||||
BuildEnvFileConflictError(const Path fileA, const Path fileB, int priority)
|
||||
: CloneableError(
|
||||
: Error(
|
||||
"Unable to build profile. There is a conflict for the following files:\n"
|
||||
"\n"
|
||||
" %1%\n"
|
||||
|
||||
@@ -12,8 +12,13 @@ struct CommonSSHStoreConfig : virtual StoreConfig
|
||||
{
|
||||
using StoreConfig::StoreConfig;
|
||||
|
||||
CommonSSHStoreConfig(std::string_view scheme, const ParsedURL::Authority & authority, const Params & params);
|
||||
CommonSSHStoreConfig(std::string_view scheme, std::string_view authority, const Params & params);
|
||||
CommonSSHStoreConfig(
|
||||
nix::Settings & settings,
|
||||
std::string_view scheme,
|
||||
const ParsedURL::Authority & authority,
|
||||
const Params & params);
|
||||
CommonSSHStoreConfig(
|
||||
nix::Settings & settings, std::string_view scheme, std::string_view authority, const Params & params);
|
||||
|
||||
Setting<Path> sshKey{
|
||||
this, "", "ssh-key", "Path to the SSH private key used to authenticate to the remote machine."};
|
||||
|
||||
@@ -12,15 +12,16 @@ struct DummyStore;
|
||||
|
||||
struct DummyStoreConfig : public std::enable_shared_from_this<DummyStoreConfig>, virtual StoreConfig
|
||||
{
|
||||
DummyStoreConfig(const Params & params)
|
||||
: StoreConfig(params)
|
||||
DummyStoreConfig(nix::Settings & settings, const Params & params)
|
||||
: StoreConfig(settings, params)
|
||||
{
|
||||
// Disable caching since this a temporary in-memory store.
|
||||
pathInfoCacheSize = 0;
|
||||
}
|
||||
|
||||
DummyStoreConfig(std::string_view scheme, std::string_view authority, const Params & params)
|
||||
: DummyStoreConfig(params)
|
||||
DummyStoreConfig(
|
||||
nix::Settings & settings, std::string_view scheme, std::string_view authority, const Params & params)
|
||||
: DummyStoreConfig(settings, params)
|
||||
{
|
||||
if (!authority.empty())
|
||||
throw UsageError("`%s` store URIs must not contain an authority part %s", scheme, authority);
|
||||
@@ -90,11 +91,20 @@ namespace nlohmann {
|
||||
|
||||
template<>
|
||||
JSON_IMPL_INNER_TO(nix::DummyStoreConfig);
|
||||
|
||||
template<>
|
||||
JSON_IMPL_INNER_FROM(nix::ref<nix::DummyStoreConfig>);
|
||||
struct adl_serializer<nix::ref<nix::DummyStoreConfig>>
|
||||
{
|
||||
static nix::ref<nix::DummyStoreConfig> from_json(nix::Settings & settings, const json & json);
|
||||
};
|
||||
|
||||
template<>
|
||||
JSON_IMPL_INNER_TO(nix::DummyStore);
|
||||
|
||||
template<>
|
||||
JSON_IMPL_INNER_FROM(nix::ref<nix::DummyStore>);
|
||||
struct adl_serializer<nix::ref<nix::DummyStore>>
|
||||
{
|
||||
static nix::ref<nix::DummyStore> from_json(nix::Settings & settings, const json & json);
|
||||
};
|
||||
|
||||
} // namespace nlohmann
|
||||
|
||||
@@ -182,6 +182,7 @@ struct FileTransferRequest
|
||||
Headers headers;
|
||||
std::string expectedETag;
|
||||
HttpMethod method = HttpMethod::Get;
|
||||
size_t tries = fileTransferSettings.tries;
|
||||
unsigned int baseRetryTimeMs = RETRY_TIME_MS_DEFAULT;
|
||||
ActivityId parentAct;
|
||||
bool decompress = true;
|
||||
@@ -403,7 +404,7 @@ ref<FileTransfer> getFileTransfer();
|
||||
*/
|
||||
ref<FileTransfer> makeFileTransfer(const FileTransferSettings & settings = fileTransferSettings);
|
||||
|
||||
class FileTransferError final : public CloneableError<FileTransferError, Error>
|
||||
class FileTransferError : public Error
|
||||
{
|
||||
public:
|
||||
FileTransfer::Error error;
|
||||
|
||||
@@ -104,6 +104,8 @@ public:
|
||||
|
||||
Settings();
|
||||
|
||||
using ExternalBuilders = std::vector<ExternalBuilder>;
|
||||
|
||||
/**
|
||||
* Get the local store settings.
|
||||
*/
|
||||
@@ -408,15 +410,18 @@ public:
|
||||
Set it to 1 to warn on all paths.
|
||||
)"};
|
||||
|
||||
/**
|
||||
* Finds the first external derivation builder that supports this
|
||||
* derivation, or else returns a null pointer.
|
||||
*/
|
||||
const ExternalBuilder * findExternalDerivationBuilderIfSupported(const Derivation & drv);
|
||||
|
||||
/**
|
||||
* Get the options needed for profile directory functions.
|
||||
*/
|
||||
ProfileDirsOptions getProfileDirsOptions() const;
|
||||
};
|
||||
|
||||
// FIXME: don't use a global variable.
|
||||
extern nix::Settings settings;
|
||||
|
||||
/**
|
||||
* Load the configuration (from `nix.conf`, `NIX_CONFIG`, etc.) into the
|
||||
* given configuration object.
|
||||
|
||||
@@ -17,9 +17,12 @@ struct HttpBinaryCacheStoreConfig : std::enable_shared_from_this<HttpBinaryCache
|
||||
using BinaryCacheStoreConfig::BinaryCacheStoreConfig;
|
||||
|
||||
HttpBinaryCacheStoreConfig(
|
||||
std::string_view scheme, std::string_view cacheUri, const Store::Config::Params & params);
|
||||
nix::Settings & settings,
|
||||
std::string_view scheme,
|
||||
std::string_view cacheUri,
|
||||
const Store::Config::Params & params);
|
||||
|
||||
HttpBinaryCacheStoreConfig(ParsedURL cacheUri, const Store::Config::Params & params);
|
||||
HttpBinaryCacheStoreConfig(nix::Settings & settings, ParsedURL cacheUri, const Store::Config::Params & params);
|
||||
|
||||
ParsedURL cacheUri;
|
||||
|
||||
|
||||
@@ -5,6 +5,12 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
PublicKeys getDefaultPublicKeys();
|
||||
class Settings;
|
||||
|
||||
}
|
||||
/**
|
||||
* @todo use more narrow settings, or rethink whether this is a good
|
||||
* idea at all, vs always associating keys with stores.
|
||||
*/
|
||||
PublicKeys getDefaultPublicKeys(const Settings & settings);
|
||||
|
||||
} // namespace nix
|
||||
|
||||
@@ -14,7 +14,8 @@ struct LegacySSHStoreConfig : std::enable_shared_from_this<LegacySSHStoreConfig>
|
||||
{
|
||||
using CommonSSHStoreConfig::CommonSSHStoreConfig;
|
||||
|
||||
LegacySSHStoreConfig(std::string_view scheme, std::string_view authority, const Params & params);
|
||||
LegacySSHStoreConfig(
|
||||
nix::Settings & settings, std::string_view scheme, std::string_view authority, const Params & params);
|
||||
|
||||
#ifndef _WIN32
|
||||
// Hack for getting remote build log output.
|
||||
|
||||
@@ -12,7 +12,8 @@ struct LocalBinaryCacheStoreConfig : std::enable_shared_from_this<LocalBinaryCac
|
||||
* @param binaryCacheDir `file://` is a short-hand for `file:///`
|
||||
* for now.
|
||||
*/
|
||||
LocalBinaryCacheStoreConfig(std::string_view scheme, PathView binaryCacheDir, const Params & params);
|
||||
LocalBinaryCacheStoreConfig(
|
||||
nix::Settings & settings, std::string_view scheme, PathView binaryCacheDir, const Params & params);
|
||||
|
||||
Path binaryCacheDir;
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
*
|
||||
* @todo Make this less error-prone with new store settings system.
|
||||
*/
|
||||
LocalFSStoreConfig(PathView path, const Params & params);
|
||||
LocalFSStoreConfig(nix::Settings & settings, PathView path, const Params & params);
|
||||
|
||||
OptionalPathSetting rootDir = makeRootDirSetting(*this, std::nullopt);
|
||||
|
||||
@@ -40,25 +40,25 @@ private:
|
||||
* An indirection so that we don't need to refer to global settings
|
||||
* in headers.
|
||||
*/
|
||||
static Path getDefaultStateDir();
|
||||
static Path getDefaultStateDir(const nix::Settings & settings);
|
||||
|
||||
/**
|
||||
* An indirection so that we don't need to refer to global settings
|
||||
* in headers.
|
||||
*/
|
||||
static Path getDefaultLogDir();
|
||||
static Path getDefaultLogDir(const nix::Settings & settings);
|
||||
|
||||
public:
|
||||
|
||||
PathSetting stateDir{
|
||||
this,
|
||||
rootDir.get() ? *rootDir.get() + "/nix/var/nix" : getDefaultStateDir(),
|
||||
rootDir.get() ? *rootDir.get() + "/nix/var/nix" : getDefaultStateDir(settings),
|
||||
"state",
|
||||
"Directory where Nix stores state."};
|
||||
|
||||
PathSetting logDir{
|
||||
this,
|
||||
rootDir.get() ? *rootDir.get() + "/nix/var/log/nix" : getDefaultLogDir(),
|
||||
rootDir.get() ? *rootDir.get() + "/nix/var/log/nix" : getDefaultLogDir(settings),
|
||||
"log",
|
||||
"directory where Nix stores log files."};
|
||||
|
||||
|
||||
@@ -7,15 +7,15 @@ namespace nix {
|
||||
*/
|
||||
struct LocalOverlayStoreConfig : virtual LocalStoreConfig
|
||||
{
|
||||
LocalOverlayStoreConfig(const StringMap & params)
|
||||
: LocalOverlayStoreConfig("local-overlay", "", params)
|
||||
LocalOverlayStoreConfig(nix::Settings & settings, const StringMap & params)
|
||||
: LocalOverlayStoreConfig(settings, "local-overlay", "", params)
|
||||
{
|
||||
}
|
||||
|
||||
LocalOverlayStoreConfig(std::string_view scheme, PathView path, const Params & params)
|
||||
: StoreConfig(params)
|
||||
, LocalFSStoreConfig(path, params)
|
||||
, LocalStoreConfig(scheme, path, params)
|
||||
LocalOverlayStoreConfig(nix::Settings & settings, std::string_view scheme, PathView path, const Params & params)
|
||||
: StoreConfig(settings, params)
|
||||
, LocalFSStoreConfig(settings, path, params)
|
||||
, LocalStoreConfig(settings, scheme, path, params)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -707,12 +707,6 @@ public:
|
||||
// Current system: 'aarch64-darwin' with features {apple-virt, benchmark, big-parallel, nixos-test}
|
||||
// Xp::ExternalBuilders
|
||||
};
|
||||
|
||||
/**
|
||||
* Finds the first external derivation builder that supports this
|
||||
* derivation, or else returns a null pointer.
|
||||
*/
|
||||
const ExternalBuilder * findExternalDerivationBuilderIfSupported(const Derivation & drv);
|
||||
};
|
||||
|
||||
} // namespace nix
|
||||
|
||||
@@ -82,7 +82,8 @@ struct LocalStoreConfig : std::enable_shared_from_this<LocalStoreConfig>,
|
||||
{
|
||||
using LocalFSStoreConfig::LocalFSStoreConfig;
|
||||
|
||||
LocalStoreConfig(std::string_view scheme, std::string_view authority, const Params & params);
|
||||
LocalStoreConfig(
|
||||
nix::Settings & settings, std::string_view scheme, std::string_view authority, const Params & params);
|
||||
|
||||
private:
|
||||
|
||||
@@ -133,27 +134,6 @@ public:
|
||||
Xp::LocalOverlayStore,
|
||||
};
|
||||
|
||||
Setting<bool> useRootsDaemon{
|
||||
this,
|
||||
false,
|
||||
"use-roots-daemon",
|
||||
R"(
|
||||
Whether to request garbage collector roots from an external daemon.
|
||||
|
||||
When enabled, the garbage collector connects to a Unix domain socket
|
||||
at [`<state-dir>`](@docroot@/store/types/local-store.md#store-option-state)`/gc-roots-socket/socket` to discover additional roots
|
||||
that should not be collected. This is useful when the Nix daemon runs
|
||||
without root privileges and cannot scan `/proc` for runtime roots.
|
||||
|
||||
The daemon can be started with [`nix store roots-daemon`](@docroot@/command-ref/new-cli/nix3-store-roots-daemon.md).
|
||||
)",
|
||||
{},
|
||||
true,
|
||||
Xp::LocalOverlayStore,
|
||||
};
|
||||
|
||||
std::filesystem::path getRootsSocketPath() const;
|
||||
|
||||
static const std::string name()
|
||||
{
|
||||
return "Local Store";
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
class Settings;
|
||||
class Store;
|
||||
|
||||
struct Machine;
|
||||
@@ -67,7 +68,7 @@ struct Machine
|
||||
* nix::openStore(completeStoreReference())
|
||||
* ```
|
||||
*/
|
||||
ref<Store> openStore() const;
|
||||
ref<Store> openStore(Settings & settings) const;
|
||||
|
||||
/**
|
||||
* Parse a machine configuration.
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
class Settings;
|
||||
class StorePath;
|
||||
|
||||
/**
|
||||
@@ -216,7 +217,7 @@ struct ProfileDirsOptions
|
||||
};
|
||||
|
||||
/**
|
||||
* Create and return the path to a directory suitable for storing the user’s
|
||||
* Create and return the path to a directory suitable for storing the user's
|
||||
* profiles.
|
||||
*/
|
||||
std::filesystem::path profilesDir(ProfileDirsOptions opts);
|
||||
|
||||
@@ -146,7 +146,7 @@ struct RealisedPath
|
||||
auto operator<=>(const RealisedPath &) const = default;
|
||||
};
|
||||
|
||||
class MissingRealisation final : public CloneableError<MissingRealisation, Error>
|
||||
class MissingRealisation : public Error
|
||||
{
|
||||
public:
|
||||
MissingRealisation(DrvOutput & outputId)
|
||||
@@ -155,7 +155,7 @@ public:
|
||||
}
|
||||
|
||||
MissingRealisation(std::string_view drv, OutputName outputName)
|
||||
: CloneableError(
|
||||
: Error(
|
||||
"cannot operate on output '%s' of the "
|
||||
"unbuilt derivation '%s'",
|
||||
outputName,
|
||||
|
||||
@@ -11,7 +11,8 @@ struct S3BinaryCacheStoreConfig : HttpBinaryCacheStoreConfig
|
||||
{
|
||||
using HttpBinaryCacheStoreConfig::HttpBinaryCacheStoreConfig;
|
||||
|
||||
S3BinaryCacheStoreConfig(std::string_view uriScheme, std::string_view bucketName, const Params & params);
|
||||
S3BinaryCacheStoreConfig(
|
||||
nix::Settings & settings, std::string_view uriScheme, std::string_view bucketName, const Params & params);
|
||||
|
||||
Setting<std::string> profile{
|
||||
this,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user