Compare commits

..

1 Commits

Author SHA1 Message Date
John Ericson
2933eb3684 WIP get rid of global Settings in libstore
This is analogous to 52bfccf8d8 for
`EvalSettings`, and 3fc77f281e for
`FlakeSettings` and `fetchers::Settings`.
2026-02-15 10:50:25 -05:00
190 changed files with 1755 additions and 2219 deletions

View File

@@ -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:

View File

@@ -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
View File

@@ -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",

View File

@@ -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}))

View File

@@ -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

View File

@@ -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.

View File

@@ -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);
}

View File

@@ -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);
}},
});

View File

@@ -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);

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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});

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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;
};

View File

@@ -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"}}); },
}
{
}
};

View File

@@ -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)

View File

@@ -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();

View File

@@ -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";
}

View File

@@ -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,

View File

@@ -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;

View File

@@ -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)
{
}
};

View File

@@ -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

View File

@@ -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();
}
/**

View File

@@ -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...);

View File

@@ -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',
]

View File

@@ -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)

View File

@@ -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");

View File

@@ -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);

View File

@@ -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,
};

View File

@@ -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");

View File

@@ -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");
}

View File

@@ -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();

View File

@@ -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);

View File

@@ -2,6 +2,9 @@
namespace nix::fetchers {
Settings::Settings() {}
Settings::Settings(const nix::Settings & storeSettings)
: storeSettings(storeSettings)
{
}
} // namespace nix::fetchers

View File

@@ -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,

View File

@@ -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);

View File

@@ -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,

View File

@@ -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

View File

@@ -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,

View File

@@ -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 {

View File

@@ -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.

View File

@@ -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();

View File

@@ -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};
}

View File

@@ -5,6 +5,8 @@
extern "C" {
extern nix::Settings cStoreSettings;
struct Store
{
nix::ref<nix::Store> ptr;

View File

@@ -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 =

View File

@@ -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);

View File

@@ -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://"); })
{
}

View File

@@ -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.

View File

@@ -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;
}

View File

@@ -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);
});
};

View File

@@ -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();
}())
})
{
}

View File

@@ -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",

View 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);
}

View File

@@ -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{

View File

@@ -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");
}

View File

@@ -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"});
}

View File

@@ -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");
}

View File

@@ -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());

View File

@@ -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"(",

View File

@@ -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"));
}

View File

@@ -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{

View File

@@ -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");

View File

@@ -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));

View File

@@ -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()

View File

@@ -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)
{
}

View File

@@ -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));
}

View File

@@ -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)
{
}

View File

@@ -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"

View File

@@ -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)
{
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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")))

View File

@@ -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)
{

View File

@@ -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))

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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("")
{
}

View File

@@ -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;

View File

@@ -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?

View File

@@ -10,7 +10,7 @@
namespace nix {
struct TimedOut final : CloneableError<TimedOut, BuildError>
struct TimedOut : BuildError
{
time_t maxDuration;

View File

@@ -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"

View File

@@ -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."};

View File

@@ -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

View File

@@ -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;

View File

@@ -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.

View File

@@ -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;

View File

@@ -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

View File

@@ -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.

View File

@@ -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;

View File

@@ -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."};

View File

@@ -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)
{
}

View File

@@ -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

View File

@@ -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";

View File

@@ -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.

View File

@@ -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 users
* Create and return the path to a directory suitable for storing the user's
* profiles.
*/
std::filesystem::path profilesDir(ProfileDirsOptions opts);

View File

@@ -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,

View File

@@ -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