Merge remote-tracking branch 'origin/master' into non-blocking-gc

This commit is contained in:
Eelco Dolstra 2021-10-28 14:56:55 +02:00
commit a7d4f3411e
39 changed files with 266 additions and 91 deletions

View file

@ -11,7 +11,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v2.3.4 - uses: actions/checkout@v2.3.5
with: with:
fetch-depth: 0 fetch-depth: 0
- uses: cachix/install-nix-action@v14 - uses: cachix/install-nix-action@v14
@ -41,7 +41,7 @@ jobs:
outputs: outputs:
installerURL: ${{ steps.prepare-installer.outputs.installerURL }} installerURL: ${{ steps.prepare-installer.outputs.installerURL }}
steps: steps:
- uses: actions/checkout@v2.3.4 - uses: actions/checkout@v2.3.5
with: with:
fetch-depth: 0 fetch-depth: 0
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV - run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
@ -61,7 +61,7 @@ jobs:
os: [ubuntu-latest, macos-latest] os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v2.3.4 - uses: actions/checkout@v2.3.5
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV - run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
- uses: cachix/install-nix-action@v14 - uses: cachix/install-nix-action@v14
with: with:

View file

@ -70,7 +70,8 @@
- [Hacking](contributing/hacking.md) - [Hacking](contributing/hacking.md)
- [CLI guideline](contributing/cli-guideline.md) - [CLI guideline](contributing/cli-guideline.md)
- [Release Notes](release-notes/release-notes.md) - [Release Notes](release-notes/release-notes.md)
- [Release 2.4 (2021-XX-XX)](release-notes/rl-2.4.md) - [Release X.Y (202?-??-??)](release-notes/rl-next.md)
- [Release 2.4 (2021-11-01)](release-notes/rl-2.4.md)
- [Release 2.3 (2019-09-04)](release-notes/rl-2.3.md) - [Release 2.3 (2019-09-04)](release-notes/rl-2.3.md)
- [Release 2.2 (2019-01-11)](release-notes/rl-2.2.md) - [Release 2.2 (2019-01-11)](release-notes/rl-2.2.md)
- [Release 2.1 (2018-09-02)](release-notes/rl-2.1.md) - [Release 2.1 (2018-09-02)](release-notes/rl-2.1.md)

View file

@ -110,13 +110,19 @@ shell in which to build it:
```console ```console
$ nix-shell '<nixpkgs>' -A pan $ nix-shell '<nixpkgs>' -A pan
[nix-shell]$ unpackPhase [nix-shell]$ eval ${unpackPhase:-unpackPhase}
[nix-shell]$ cd pan-* [nix-shell]$ cd pan-*
[nix-shell]$ configurePhase [nix-shell]$ eval ${configurePhase:-configurePhase}
[nix-shell]$ buildPhase [nix-shell]$ eval ${buildPhase:-buildPhase}
[nix-shell]$ ./pan/gui/pan [nix-shell]$ ./pan/gui/pan
``` ```
The reason we use form `eval ${configurePhase:-configurePhase}` here is because
those packages that override these phases do so by exporting the overridden
values in the environment variable of the same name.
Here bash is being told to either evaluate the contents of 'configurePhase',
if it exists as a variable, otherwise evaluate the configurePhase function.
To clear the environment first, and do some additional automatic To clear the environment first, and do some additional automatic
initialisation of the interactive shell: initialisation of the interactive shell:

View file

@ -1,4 +1,4 @@
# Release 2.4 (2021-10-XX) # Release 2.4 (2021-11-01)
This is the first release in more than two years and is the result of This is the first release in more than two years and is the result of
more than 2800 commits from 195 contributors since release 2.3. more than 2800 commits from 195 contributors since release 2.3.
@ -286,8 +286,35 @@ more than 2800 commits from 195 contributors since release 2.3.
to your `nix.conf` if you want to use it, or pass to your `nix.conf` if you want to use it, or pass
`--extra-experimental-features nix-command` on the command line. `--extra-experimental-features nix-command` on the command line.
* The old `nix run` has been renamed to `nix shell` (and there is a * The `nix` command no longer has a syntax for referring to packages
new `nix run` that does something else, as described above). in a channel. This means that the following no longer works:
> nix build nixpkgs.hello # Nix 2.3
Instead, you can either use the `#` syntax to select a package from
a flake, e.g.
> nix build nixpkgs#hello
Or, if you want to use the `nixpkgs` channel in the `NIX_PATH`
environment variable:
> nix build -f '<nixpkgs>' hello
* The old `nix run` has been renamed to `nix shell`, while there is a
new `nix run` that runs a default command. So instead of
> nix run nixpkgs.hello -c hello # Nix 2.3
you should use
> nix shell nixpkgs#hello -c hello
or just
> nix run nixpkgs#hello
if the command you want to run has the same name as the package.
* It is now an error to modify the `plugin-files` setting via a * It is now an error to modify the `plugin-files` setting via a
command-line flag that appears after the first non-flag argument to command-line flag that appears after the first non-flag argument to

View file

@ -61,6 +61,7 @@
configureFlags = configureFlags =
lib.optionals stdenv.isLinux [ lib.optionals stdenv.isLinux [
"--with-boost=${boost}/lib"
"--with-sandbox-shell=${sh}/bin/busybox" "--with-sandbox-shell=${sh}/bin/busybox"
"LDFLAGS=-fuse-ld=gold" "LDFLAGS=-fuse-ld=gold"
]; ];

View file

@ -18,6 +18,7 @@
#include "derivations.hh" #include "derivations.hh"
#include "local-store.hh" #include "local-store.hh"
#include "legacy.hh" #include "legacy.hh"
#include "experimental-features.hh"
using namespace nix; using namespace nix;
using std::cin; using std::cin;
@ -130,11 +131,14 @@ static int main_build_remote(int argc, char * * argv)
for (auto & m : machines) { for (auto & m : machines) {
debug("considering building on remote machine '%s'", m.storeUri); debug("considering building on remote machine '%s'", m.storeUri);
if (m.enabled && std::find(m.systemTypes.begin(), if (m.enabled
m.systemTypes.end(), && (neededSystem == "builtin"
neededSystem) != m.systemTypes.end() && || std::find(m.systemTypes.begin(),
m.systemTypes.end(),
neededSystem) != m.systemTypes.end()) &&
m.allSupported(requiredFeatures) && m.allSupported(requiredFeatures) &&
m.mandatoryMet(requiredFeatures)) { m.mandatoryMet(requiredFeatures))
{
rightType = true; rightType = true;
AutoCloseFD free; AutoCloseFD free;
uint64_t load = 0; uint64_t load = 0;
@ -295,7 +299,7 @@ connected:
std::set<Realisation> missingRealisations; std::set<Realisation> missingRealisations;
StorePathSet missingPaths; StorePathSet missingPaths;
if (settings.isExperimentalFeatureEnabled("ca-derivations") && !derivationHasKnownOutputPaths(drv.type())) { if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations) && !derivationHasKnownOutputPaths(drv.type())) {
for (auto & outputName : wantedOutputs) { for (auto & outputName : wantedOutputs) {
auto thisOutputHash = outputHashes.at(outputName); auto thisOutputHash = outputHashes.at(outputName);
auto thisOutputId = DrvOutput{ thisOutputHash, outputName }; auto thisOutputId = DrvOutput{ thisOutputHash, outputName };
@ -327,7 +331,7 @@ connected:
for (auto & realisation : missingRealisations) { for (auto & realisation : missingRealisations) {
// Should hold, because if the feature isn't enabled the set // Should hold, because if the feature isn't enabled the set
// of missing realisations should be empty // of missing realisations should be empty
settings.requireExperimentalFeature("ca-derivations"); settings.requireExperimentalFeature(Xp::CaDerivations);
store->registerDrvOutput(realisation); store->registerDrvOutput(realisation);
} }

View file

@ -714,7 +714,7 @@ BuiltPaths getBuiltPaths(ref<Store> evalStore, ref<Store> store, const DerivedPa
"the derivation '%s' doesn't have an output named '%s'", "the derivation '%s' doesn't have an output named '%s'",
store->printStorePath(bfd.drvPath), output); store->printStorePath(bfd.drvPath), output);
if (settings.isExperimentalFeatureEnabled( if (settings.isExperimentalFeatureEnabled(
"ca-derivations")) { Xp::CaDerivations)) {
auto outputId = auto outputId =
DrvOutput{outputHashes.at(output), output}; DrvOutput{outputHashes.at(output), output};
auto realisation = auto realisation =

View file

@ -466,7 +466,7 @@ EvalState::~EvalState()
void EvalState::requireExperimentalFeatureOnEvaluation( void EvalState::requireExperimentalFeatureOnEvaluation(
const std::string & feature, const ExperimentalFeature & feature,
const std::string_view fName, const std::string_view fName,
const Pos & pos) const Pos & pos)
{ {

View file

@ -5,6 +5,7 @@
#include "nixexpr.hh" #include "nixexpr.hh"
#include "symbol-table.hh" #include "symbol-table.hh"
#include "config.hh" #include "config.hh"
#include "experimental-features.hh"
#include <map> #include <map>
#include <optional> #include <optional>
@ -141,7 +142,7 @@ public:
~EvalState(); ~EvalState();
void requireExperimentalFeatureOnEvaluation( void requireExperimentalFeatureOnEvaluation(
const std::string & feature, const ExperimentalFeature &,
const std::string_view fName, const std::string_view fName,
const Pos & pos const Pos & pos
); );

View file

@ -297,7 +297,7 @@ LockedFlake lockFlake(
const FlakeRef & topRef, const FlakeRef & topRef,
const LockFlags & lockFlags) const LockFlags & lockFlags)
{ {
settings.requireExperimentalFeature("flakes"); settings.requireExperimentalFeature(Xp::Flakes);
FlakeCache flakeCache; FlakeCache flakeCache;
@ -687,7 +687,7 @@ void callFlake(EvalState & state,
static void prim_getFlake(EvalState & state, const Pos & pos, Value * * args, Value & v) static void prim_getFlake(EvalState & state, const Pos & pos, Value * * args, Value & v)
{ {
state.requireExperimentalFeatureOnEvaluation("flakes", "builtins.getFlake", pos); state.requireExperimentalFeatureOnEvaluation(Xp::Flakes, "builtins.getFlake", pos);
auto flakeRefS = state.forceStringNoCtx(*args[0], pos); auto flakeRefS = state.forceStringNoCtx(*args[0], pos);
auto flakeRef = parseFlakeRef(flakeRefS, {}, true); auto flakeRef = parseFlakeRef(flakeRefS, {}, true);

View file

@ -418,7 +418,7 @@ expr_simple
new ExprString(data->symbols.create(path))); new ExprString(data->symbols.create(path)));
} }
| URI { | URI {
static bool noURLLiterals = settings.isExperimentalFeatureEnabled("no-url-literals"); static bool noURLLiterals = settings.isExperimentalFeatureEnabled(Xp::NoUrlLiterals);
if (noURLLiterals) if (noURLLiterals)
throw ParseError({ throw ParseError({
.msg = hintfmt("URL literals are disabled"), .msg = hintfmt("URL literals are disabled"),
@ -752,7 +752,7 @@ std::pair<bool, std::string> EvalState::resolveSearchPathElem(const SearchPathEl
res = { true, path }; res = { true, path };
else { else {
logWarning({ logWarning({
.msg = hintfmt("warning: Nix search path entry '%1%' does not exist, ignoring", elem.second) .msg = hintfmt("Nix search path entry '%1%' does not exist, ignoring", elem.second)
}); });
res = { false, "" }; res = { false, "" };
} }

View file

@ -985,7 +985,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
} }
if (i->name == state.sContentAddressed) { if (i->name == state.sContentAddressed) {
settings.requireExperimentalFeature("ca-derivations"); settings.requireExperimentalFeature(Xp::CaDerivations);
contentAddressed = state.forceBool(*i->value, pos); contentAddressed = state.forceBool(*i->value, pos);
} }

View file

@ -15,7 +15,7 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar
std::string name = "source"; std::string name = "source";
PathSet context; PathSet context;
state.forceValue(*args[0]); state.forceValue(*args[0], pos);
if (args[0]->type() == nAttrs) { if (args[0]->type() == nAttrs) {

View file

@ -97,7 +97,7 @@ static void fetchTree(
fetchers::Input input; fetchers::Input input;
PathSet context; PathSet context;
state.forceValue(*args[0]); state.forceValue(*args[0], pos);
if (args[0]->type() == nAttrs) { if (args[0]->type() == nAttrs) {
state.forceAttrs(*args[0], pos); state.forceAttrs(*args[0], pos);
@ -121,7 +121,7 @@ static void fetchTree(
for (auto & attr : *args[0]->attrs) { for (auto & attr : *args[0]->attrs) {
if (attr.name == state.sType) continue; if (attr.name == state.sType) continue;
state.forceValue(*attr.value); state.forceValue(*attr.value, *attr.pos);
if (attr.value->type() == nPath || attr.value->type() == nString) { if (attr.value->type() == nPath || attr.value->type() == nString) {
auto s = state.coerceToString(*attr.pos, *attr.value, context, false, false); auto s = state.coerceToString(*attr.pos, *attr.value, context, false, false);
attrs.emplace(attr.name, attrs.emplace(attr.name,
@ -176,7 +176,7 @@ static void fetchTree(
static void prim_fetchTree(EvalState & state, const Pos & pos, Value * * args, Value & v) static void prim_fetchTree(EvalState & state, const Pos & pos, Value * * args, Value & v)
{ {
settings.requireExperimentalFeature("flakes"); settings.requireExperimentalFeature(Xp::Flakes);
fetchTree(state, pos, args, v, std::nullopt, FetchTreeParams { .allowNameArgument = false }); fetchTree(state, pos, args, v, std::nullopt, FetchTreeParams { .allowNameArgument = false });
} }
@ -189,7 +189,7 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
std::optional<std::string> url; std::optional<std::string> url;
std::optional<Hash> expectedHash; std::optional<Hash> expectedHash;
state.forceValue(*args[0]); state.forceValue(*args[0], pos);
if (args[0]->type() == nAttrs) { if (args[0]->type() == nAttrs) {
@ -287,13 +287,13 @@ static RegisterPrimOp primop_fetchTarball({
stdenv.mkDerivation { } stdenv.mkDerivation { }
``` ```
The fetched tarball is cached for a certain amount of time (1 hour The fetched tarball is cached for a certain amount of time (1
by default) in `~/.cache/nix/tarballs/`. You can change the cache hour by default) in `~/.cache/nix/tarballs/`. You can change the
timeout either on the command line with `--option tarball-ttl number cache timeout either on the command line with `--tarball-ttl`
of seconds` or in the Nix configuration file with this option: ` *number-of-seconds* or in the Nix configuration file by adding
number of seconds to cache `. the line `tarball-ttl = ` *number-of-seconds*.
Note that when obtaining the hash with ` nix-prefetch-url ` the Note that when obtaining the hash with `nix-prefetch-url` the
option `--unpack` is required. option `--unpack` is required.
This function can also verify the contents against a hash. In that This function can also verify the contents against a hash. In that
@ -393,7 +393,7 @@ static RegisterPrimOp primop_fetchGit({
``` ```
> **Note** > **Note**
> >
> It is nice to always specify the branch which a revision > It is nice to always specify the branch which a revision
> belongs to. Without the branch being specified, the fetcher > belongs to. Without the branch being specified, the fetcher
> might fail if the default branch changes. Additionally, it can > might fail if the default branch changes. Additionally, it can
@ -430,12 +430,12 @@ static RegisterPrimOp primop_fetchGit({
``` ```
> **Note** > **Note**
> >
> Nix will refetch the branch in accordance with > Nix will refetch the branch in accordance with
> the option `tarball-ttl`. > the option `tarball-ttl`.
> **Note** > **Note**
> >
> This behavior is disabled in *Pure evaluation mode*. > This behavior is disabled in *Pure evaluation mode*.
)", )",
.fun = prim_fetchGit, .fun = prim_fetchGit,

View file

@ -204,7 +204,7 @@ void DerivationGoal::haveDerivation()
trace("have derivation"); trace("have derivation");
if (drv->type() == DerivationType::CAFloating) if (drv->type() == DerivationType::CAFloating)
settings.requireExperimentalFeature("ca-derivations"); settings.requireExperimentalFeature(Xp::CaDerivations);
retrySubstitution = false; retrySubstitution = false;
@ -453,7 +453,7 @@ void DerivationGoal::inputsRealised()
if (useDerivation) { if (useDerivation) {
auto & fullDrv = *dynamic_cast<Derivation *>(drv.get()); auto & fullDrv = *dynamic_cast<Derivation *>(drv.get());
if (settings.isExperimentalFeatureEnabled("ca-derivations") && if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations) &&
((!fullDrv.inputDrvs.empty() && derivationIsCA(fullDrv.type())) ((!fullDrv.inputDrvs.empty() && derivationIsCA(fullDrv.type()))
|| fullDrv.type() == DerivationType::DeferredInputAddressed)) { || fullDrv.type() == DerivationType::DeferredInputAddressed)) {
/* We are be able to resolve this derivation based on the /* We are be able to resolve this derivation based on the
@ -616,7 +616,9 @@ void DerivationGoal::tryToBuild()
/* Don't do a remote build if the derivation has the attribute /* Don't do a remote build if the derivation has the attribute
`preferLocalBuild' set. Also, check and repair modes are only `preferLocalBuild' set. Also, check and repair modes are only
supported for local builds. */ supported for local builds. */
bool buildLocally = buildMode != bmNormal || parsedDrv->willBuildLocally(worker.store); bool buildLocally =
(buildMode != bmNormal || parsedDrv->willBuildLocally(worker.store))
&& settings.maxBuildJobs.get() != 0;
if (!buildLocally) { if (!buildLocally) {
switch (tryBuildHook()) { switch (tryBuildHook()) {
@ -1273,7 +1275,7 @@ void DerivationGoal::checkPathValidity()
: PathStatus::Corrupt, : PathStatus::Corrupt,
}; };
} }
if (settings.isExperimentalFeatureEnabled("ca-derivations")) { if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
auto drvOutput = DrvOutput{initialOutputs.at(i.first).outputHash, i.first}; auto drvOutput = DrvOutput{initialOutputs.at(i.first).outputHash, i.first};
if (auto real = worker.store.queryRealisation(drvOutput)) { if (auto real = worker.store.queryRealisation(drvOutput)) {
info.known = { info.known = {

View file

@ -74,7 +74,7 @@ BuildResult Store::buildDerivation(const StorePath & drvPath, const BasicDerivat
outputId, outputId,
Realisation{ outputId, *staticOutput.second} Realisation{ outputId, *staticOutput.second}
); );
if (settings.isExperimentalFeatureEnabled("ca-derivations") && !derivationHasKnownOutputPaths(drv.type())) { if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations) && !derivationHasKnownOutputPaths(drv.type())) {
auto realisation = this->queryRealisation(outputId); auto realisation = this->queryRealisation(outputId);
if (realisation) if (realisation)
result.builtOutputs.insert_or_assign( result.builtOutputs.insert_or_assign(

View file

@ -1259,7 +1259,7 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo
for (auto & [outputName, outputPath] : outputs) for (auto & [outputName, outputPath] : outputs)
if (wantOutput(outputName, bfd.outputs)) { if (wantOutput(outputName, bfd.outputs)) {
newPaths.insert(outputPath); newPaths.insert(outputPath);
if (settings.isExperimentalFeatureEnabled("ca-derivations")) { if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
auto thisRealisation = next->queryRealisation( auto thisRealisation = next->queryRealisation(
DrvOutput{drvHashes.at(outputName), outputName} DrvOutput{drvHashes.at(outputName), outputName}
); );
@ -1320,7 +1320,7 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo
void LocalDerivationGoal::startDaemon() void LocalDerivationGoal::startDaemon()
{ {
settings.requireExperimentalFeature("recursive-nix"); settings.requireExperimentalFeature(Xp::RecursiveNix);
Store::Params params; Store::Params params;
params["path-info-cache-size"] = "0"; params["path-info-cache-size"] = "0";
@ -2561,7 +2561,7 @@ void LocalDerivationGoal::registerOutputs()
that for floating CA derivations, which otherwise couldn't be cached, that for floating CA derivations, which otherwise couldn't be cached,
but it's fine to do in all cases. */ but it's fine to do in all cases. */
if (settings.isExperimentalFeatureEnabled("ca-derivations")) { if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
for (auto& [outputName, newInfo] : infos) { for (auto& [outputName, newInfo] : infos) {
auto thisRealisation = Realisation{ auto thisRealisation = Realisation{
.id = DrvOutput{initialOutputs.at(outputName).outputHash, .id = DrvOutput{initialOutputs.at(outputName).outputHash,

View file

@ -230,11 +230,12 @@ struct ClientSettings
else if (name == settings.experimentalFeatures.name) { else if (name == settings.experimentalFeatures.name) {
// We dont want to forward the experimental features to // We dont want to forward the experimental features to
// the daemon, as that could cause some pretty weird stuff // the daemon, as that could cause some pretty weird stuff
if (tokenizeString<Strings>(value) != settings.experimentalFeatures.get()) if (parseFeatures(tokenizeString<StringSet>(value)) != settings.experimentalFeatures.get())
debug("Ignoring the client-specified experimental features"); debug("Ignoring the client-specified experimental features");
} }
else if (trusted else if (trusted
|| name == settings.buildTimeout.name || name == settings.buildTimeout.name
|| name == settings.buildRepeat.name
|| name == "connect-timeout" || name == "connect-timeout"
|| (name == "builders" && value == "")) || (name == "builders" && value == ""))
settings.set(name, value); settings.set(name, value);

View file

@ -187,7 +187,7 @@ static DerivationOutput parseDerivationOutput(const Store & store,
}, },
}; };
} else { } else {
settings.requireExperimentalFeature("ca-derivations"); settings.requireExperimentalFeature(Xp::CaDerivations);
assert(pathS == ""); assert(pathS == "");
return DerivationOutput { return DerivationOutput {
.output = DerivationOutputCAFloating { .output = DerivationOutputCAFloating {

View file

@ -100,7 +100,7 @@ RealisedPath::Set BuiltPath::toRealisedPaths(Store & store) const
staticOutputHashes(store, store.readDerivation(p.drvPath)); staticOutputHashes(store, store.readDerivation(p.drvPath));
for (auto& [outputName, outputPath] : p.outputs) { for (auto& [outputName, outputPath] : p.outputs) {
if (settings.isExperimentalFeatureEnabled( if (settings.isExperimentalFeatureEnabled(
"ca-derivations")) { Xp::CaDerivations)) {
auto thisRealisation = store.queryRealisation( auto thisRealisation = store.queryRealisation(
DrvOutput{drvHashes.at(outputName), outputName}); DrvOutput{drvHashes.at(outputName), outputName});
assert(thisRealisation); // Weve built it, so we must h assert(thisRealisation); // Weve built it, so we must h

View file

@ -148,7 +148,8 @@ StringSet Settings::getDefaultExtraPlatforms()
// machines. Note that we cant force processes from executing // machines. Note that we cant force processes from executing
// x86_64 in aarch64 environments or vice versa since they can // x86_64 in aarch64 environments or vice versa since they can
// always exec with their own binary preferences. // always exec with their own binary preferences.
if (pathExists("/Library/Apple/System/Library/LaunchDaemons/com.apple.oahd.plist")) { if (pathExists("/Library/Apple/System/Library/LaunchDaemons/com.apple.oahd.plist") ||
pathExists("/System/Library/LaunchDaemons/com.apple.oahd.plist")) {
if (std::string{SYSTEM} == "x86_64-darwin") if (std::string{SYSTEM} == "x86_64-darwin")
extraPlatforms.insert("aarch64-darwin"); extraPlatforms.insert("aarch64-darwin");
else if (std::string{SYSTEM} == "aarch64-darwin") else if (std::string{SYSTEM} == "aarch64-darwin")
@ -159,21 +160,16 @@ StringSet Settings::getDefaultExtraPlatforms()
return extraPlatforms; return extraPlatforms;
} }
bool Settings::isExperimentalFeatureEnabled(const std::string & name) bool Settings::isExperimentalFeatureEnabled(const ExperimentalFeature & feature)
{ {
auto & f = experimentalFeatures.get(); auto & f = experimentalFeatures.get();
return std::find(f.begin(), f.end(), name) != f.end(); return std::find(f.begin(), f.end(), feature) != f.end();
} }
MissingExperimentalFeature::MissingExperimentalFeature(std::string feature) void Settings::requireExperimentalFeature(const ExperimentalFeature & feature)
: Error("experimental Nix feature '%1%' is disabled; use '--extra-experimental-features %1%' to override", feature)
, missingFeature(feature)
{}
void Settings::requireExperimentalFeature(const std::string & name)
{ {
if (!isExperimentalFeatureEnabled(name)) if (!isExperimentalFeatureEnabled(feature))
throw MissingExperimentalFeature(name); throw MissingExperimentalFeature(feature);
} }
bool Settings::isWSL1() bool Settings::isWSL1()

View file

@ -3,6 +3,7 @@
#include "types.hh" #include "types.hh"
#include "config.hh" #include "config.hh"
#include "util.hh" #include "util.hh"
#include "experimental-features.hh"
#include <map> #include <map>
#include <limits> #include <limits>
@ -45,15 +46,6 @@ struct PluginFilesSetting : public BaseSetting<Paths>
void set(const std::string & str, bool append = false) override; void set(const std::string & str, bool append = false) override;
}; };
class MissingExperimentalFeature: public Error
{
public:
std::string missingFeature;
MissingExperimentalFeature(std::string feature);
virtual const char* sname() const override { return "MissingExperimentalFeature"; }
};
class Settings : public Config { class Settings : public Config {
unsigned int getDefaultCores(); unsigned int getDefaultCores();
@ -925,12 +917,12 @@ public:
value. value.
)"}; )"};
Setting<Strings> experimentalFeatures{this, {}, "experimental-features", Setting<std::set<ExperimentalFeature>> experimentalFeatures{this, {}, "experimental-features",
"Experimental Nix features to enable."}; "Experimental Nix features to enable."};
bool isExperimentalFeatureEnabled(const std::string & name); bool isExperimentalFeatureEnabled(const ExperimentalFeature &);
void requireExperimentalFeature(const std::string & name); void requireExperimentalFeature(const ExperimentalFeature &);
Setting<bool> allowDirty{this, true, "allow-dirty", Setting<bool> allowDirty{this, true, "allow-dirty",
"Whether to allow dirty Git/Mercurial trees."}; "Whether to allow dirty Git/Mercurial trees."};

View file

@ -308,7 +308,7 @@ LocalStore::LocalStore(const Params & params)
else openDB(*state, false); else openDB(*state, false);
if (settings.isExperimentalFeatureEnabled("ca-derivations")) { if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
migrateCASchema(state->db, dbDir + "/ca-schema", globalLock); migrateCASchema(state->db, dbDir + "/ca-schema", globalLock);
} }
@ -338,7 +338,7 @@ LocalStore::LocalStore(const Params & params)
state->stmts->QueryPathFromHashPart.create(state->db, state->stmts->QueryPathFromHashPart.create(state->db,
"select path from ValidPaths where path >= ? limit 1;"); "select path from ValidPaths where path >= ? limit 1;");
state->stmts->QueryValidPaths.create(state->db, "select path from ValidPaths"); state->stmts->QueryValidPaths.create(state->db, "select path from ValidPaths");
if (settings.isExperimentalFeatureEnabled("ca-derivations")) { if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
state->stmts->RegisterRealisedOutput.create(state->db, state->stmts->RegisterRealisedOutput.create(state->db,
R"( R"(
insert into Realisations (drvPath, outputName, outputPath, signatures) insert into Realisations (drvPath, outputName, outputPath, signatures)
@ -717,7 +717,7 @@ void LocalStore::checkDerivationOutputs(const StorePath & drvPath, const Derivat
void LocalStore::registerDrvOutput(const Realisation & info, CheckSigsFlag checkSigs) void LocalStore::registerDrvOutput(const Realisation & info, CheckSigsFlag checkSigs)
{ {
settings.requireExperimentalFeature("ca-derivations"); settings.requireExperimentalFeature(Xp::CaDerivations);
if (checkSigs == NoCheckSigs || !realisationIsUntrusted(info)) if (checkSigs == NoCheckSigs || !realisationIsUntrusted(info))
registerDrvOutput(info); registerDrvOutput(info);
else else
@ -726,7 +726,7 @@ void LocalStore::registerDrvOutput(const Realisation & info, CheckSigsFlag check
void LocalStore::registerDrvOutput(const Realisation & info) void LocalStore::registerDrvOutput(const Realisation & info)
{ {
settings.requireExperimentalFeature("ca-derivations"); settings.requireExperimentalFeature(Xp::CaDerivations);
retrySQLite<void>([&]() { retrySQLite<void>([&]() {
auto state(_state.lock()); auto state(_state.lock());
if (auto oldR = queryRealisation_(*state, info.id)) { if (auto oldR = queryRealisation_(*state, info.id)) {
@ -1012,7 +1012,7 @@ LocalStore::queryPartialDerivationOutputMap(const StorePath & path_)
return outputs; return outputs;
}); });
if (!settings.isExperimentalFeatureEnabled("ca-derivations")) if (!settings.isExperimentalFeatureEnabled(Xp::CaDerivations))
return outputs; return outputs;
auto drv = readInvalidDerivation(path); auto drv = readInvalidDerivation(path);

View file

@ -355,7 +355,7 @@ ValidPathInfo Store::addToStoreSlow(std::string_view name, const Path & srcPath,
StringSet StoreConfig::getDefaultSystemFeatures() StringSet StoreConfig::getDefaultSystemFeatures()
{ {
auto res = settings.systemFeatures.get(); auto res = settings.systemFeatures.get();
if (settings.isExperimentalFeatureEnabled("ca-derivations")) if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations))
res.insert("ca-derivations"); res.insert("ca-derivations");
return res; return res;
} }
@ -854,7 +854,7 @@ std::map<StorePath, StorePath> copyPaths(
for (auto & path : paths) { for (auto & path : paths) {
storePaths.insert(path.path()); storePaths.insert(path.path());
if (auto realisation = std::get_if<Realisation>(&path.raw)) { if (auto realisation = std::get_if<Realisation>(&path.raw)) {
settings.requireExperimentalFeature("ca-derivations"); settings.requireExperimentalFeature(Xp::CaDerivations);
toplevelRealisations.insert(*realisation); toplevelRealisations.insert(*realisation);
} }
} }
@ -886,7 +886,7 @@ std::map<StorePath, StorePath> copyPaths(
// Don't fail if the remote doesn't support CA derivations is it might // Don't fail if the remote doesn't support CA derivations is it might
// not be within our control to change that, and we might still want // not be within our control to change that, and we might still want
// to at least copy the output paths. // to at least copy the output paths.
if (e.missingFeature == "ca-derivations") if (e.missingFeature == Xp::CaDerivations)
ignoreException(); ignoreException();
else else
throw; throw;

View file

@ -1,6 +1,7 @@
#include "config.hh" #include "config.hh"
#include "args.hh" #include "args.hh"
#include "abstract-setting-to-json.hh" #include "abstract-setting-to-json.hh"
#include "experimental-features.hh"
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
@ -313,6 +314,31 @@ template<> std::string BaseSetting<StringSet>::to_string() const
return concatStringsSep(" ", value); return concatStringsSep(" ", value);
} }
template<> void BaseSetting<std::set<ExperimentalFeature>>::set(const std::string & str, bool append)
{
if (!append) value.clear();
for (auto & s : tokenizeString<StringSet>(str)) {
auto thisXpFeature = parseExperimentalFeature(s);
if (thisXpFeature)
value.insert(thisXpFeature.value());
else
warn("unknown experimental feature '%s'", s);
}
}
template<> bool BaseSetting<std::set<ExperimentalFeature>>::isAppendable()
{
return true;
}
template<> std::string BaseSetting<std::set<ExperimentalFeature>>::to_string() const
{
StringSet stringifiedXpFeatures;
for (auto & feature : value)
stringifiedXpFeatures.insert(std::string(showExperimentalFeature(feature)));
return concatStringsSep(" ", stringifiedXpFeatures);
}
template<> void BaseSetting<StringMap>::set(const std::string & str, bool append) template<> void BaseSetting<StringMap>::set(const std::string & str, bool append)
{ {
if (!append) value.clear(); if (!append) value.clear();
@ -348,6 +374,7 @@ template class BaseSetting<std::string>;
template class BaseSetting<Strings>; template class BaseSetting<Strings>;
template class BaseSetting<StringSet>; template class BaseSetting<StringSet>;
template class BaseSetting<StringMap>; template class BaseSetting<StringMap>;
template class BaseSetting<std::set<ExperimentalFeature>>;
void PathSetting::set(const std::string & str, bool append) void PathSetting::set(const std::string & str, bool append)
{ {

View file

@ -0,0 +1,59 @@
#include "experimental-features.hh"
#include "util.hh"
#include "nlohmann/json.hpp"
namespace nix {
std::map<ExperimentalFeature, std::string> stringifiedXpFeatures = {
{ Xp::CaDerivations, "ca-derivations" },
{ Xp::Flakes, "flakes" },
{ Xp::NixCommand, "nix-command" },
{ Xp::RecursiveNix, "recursive-nix" },
{ Xp::NoUrlLiterals, "no-url-literals" },
};
const std::optional<ExperimentalFeature> parseExperimentalFeature(const std::string_view & name)
{
using ReverseXpMap = std::map<std::string_view, ExperimentalFeature>;
static auto reverseXpMap = []()
{
auto reverseXpMap = std::make_unique<ReverseXpMap>();
for (auto & [feature, name] : stringifiedXpFeatures)
(*reverseXpMap)[name] = feature;
return reverseXpMap;
}();
if (auto feature = get(*reverseXpMap, name))
return *feature;
else
return std::nullopt;
}
std::string_view showExperimentalFeature(const ExperimentalFeature feature)
{
return stringifiedXpFeatures.at(feature);
}
std::set<ExperimentalFeature> parseFeatures(const std::set<std::string> & rawFeatures)
{
std::set<ExperimentalFeature> res;
for (auto & rawFeature : rawFeatures) {
if (auto feature = parseExperimentalFeature(rawFeature))
res.insert(*feature);
}
return res;
}
MissingExperimentalFeature::MissingExperimentalFeature(ExperimentalFeature feature)
: Error("experimental Nix feature '%1%' is disabled; use '--extra-experimental-features %1%' to override", showExperimentalFeature(feature))
, missingFeature(feature)
{}
std::ostream & operator <<(std::ostream & str, const ExperimentalFeature & feature)
{
return str << showExperimentalFeature(feature);
}
}

View file

@ -0,0 +1,56 @@
#pragma once
#include "comparator.hh"
#include "error.hh"
#include "nlohmann/json_fwd.hpp"
#include "types.hh"
namespace nix {
/**
* The list of available experimental features.
*
* If you update this, dont forget to also change the map defining their
* string representation in the corresponding `.cc` file.
**/
enum struct ExperimentalFeature
{
CaDerivations,
Flakes,
NixCommand,
RecursiveNix,
NoUrlLiterals
};
/**
* Just because writing `ExperimentalFeature::CaDerivations` is way too long
*/
using Xp = ExperimentalFeature;
const std::optional<ExperimentalFeature> parseExperimentalFeature(
const std::string_view & name);
std::string_view showExperimentalFeature(const ExperimentalFeature);
std::ostream & operator<<(
std::ostream & str,
const ExperimentalFeature & feature);
/**
* Parse a set of strings to the corresponding set of experimental features,
* ignoring (but warning for) any unkwown feature.
*/
std::set<ExperimentalFeature> parseFeatures(const std::set<std::string> &);
class MissingExperimentalFeature : public Error
{
public:
ExperimentalFeature missingFeature;
MissingExperimentalFeature(ExperimentalFeature);
virtual const char * sname() const override
{
return "MissingExperimentalFeature";
}
};
}

View file

@ -17,7 +17,7 @@ private:
public: public:
ref<T>(const ref<T> & r) ref(const ref<T> & r)
: p(r.p) : p(r.p)
{ } { }

View file

@ -401,7 +401,7 @@ static void main_nix_build(int argc, char * * argv)
if (dryRun) return; if (dryRun) return;
if (settings.isExperimentalFeatureEnabled("ca-derivations")) { if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
auto resolvedDrv = drv.tryResolve(*store); auto resolvedDrv = drv.tryResolve(*store);
assert(resolvedDrv && "Successfully resolved the derivation"); assert(resolvedDrv && "Successfully resolved the derivation");
drv = *resolvedDrv; drv = *resolvedDrv;

View file

@ -195,7 +195,7 @@ static StorePath getDerivationEnvironment(ref<Store> store, ref<Store> evalStore
'buildDerivation', but that's privileged. */ 'buildDerivation', but that's privileged. */
drv.name += "-env"; drv.name += "-env";
drv.inputSrcs.insert(std::move(getEnvShPath)); drv.inputSrcs.insert(std::move(getEnvShPath));
if (settings.isExperimentalFeatureEnabled("ca-derivations")) { if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
for (auto & output : drv.outputs) { for (auto & output : drv.outputs) {
output.second = { output.second = {
.output = DerivationOutputDeferred{}, .output = DerivationOutputDeferred{},

View file

@ -1138,7 +1138,7 @@ struct CmdFlake : NixMultiCommand
{ {
if (!command) if (!command)
throw UsageError("'nix flake' requires a sub-command."); throw UsageError("'nix flake' requires a sub-command.");
settings.requireExperimentalFeature("flakes"); settings.requireExperimentalFeature(Xp::Flakes);
command->second->prepare(); command->second->prepare();
command->second->run(); command->second->run();
} }

View file

@ -337,7 +337,7 @@ void mainWrapped(int argc, char * * argv)
if (args.command->first != "repl" if (args.command->first != "repl"
&& args.command->first != "doctor" && args.command->first != "doctor"
&& args.command->first != "upgrade-nix") && args.command->first != "upgrade-nix")
settings.requireExperimentalFeature("nix-command"); settings.requireExperimentalFeature(Xp::NixCommand);
if (args.useNet && !haveInternet()) { if (args.useNet && !haveInternet()) {
warn("you don't have Internet access; disabling some network-dependent features"); warn("you don't have Internet access; disabling some network-dependent features");

View file

@ -46,7 +46,7 @@ struct CmdRealisationInfo : BuiltPathsCommand, MixJSON
void run(ref<Store> store, BuiltPaths && paths) override void run(ref<Store> store, BuiltPaths && paths) override
{ {
settings.requireExperimentalFeature("ca-derivations"); settings.requireExperimentalFeature(Xp::CaDerivations);
RealisedPath::Set realisations; RealisedPath::Set realisations;
for (auto & builtPath : paths) { for (auto & builtPath : paths) {

View file

@ -219,7 +219,7 @@ struct CmdKey : NixMultiCommand
{ {
if (!command) if (!command)
throw UsageError("'nix flake' requires a sub-command."); throw UsageError("'nix flake' requires a sub-command.");
settings.requireExperimentalFeature("flakes"); settings.requireExperimentalFeature(Xp::Flakes);
command->second->prepare(); command->second->prepare();
command->second->run(); command->second->run();
} }

View file

@ -126,7 +126,7 @@ isDaemonNewer () {
[[ -n "${NIX_DAEMON_PACKAGE:-}" ]] || return 0 [[ -n "${NIX_DAEMON_PACKAGE:-}" ]] || return 0
local requiredVersion="$1" local requiredVersion="$1"
local daemonVersion=$($NIX_DAEMON_PACKAGE/bin/nix-daemon --version | cut -d' ' -f3) local daemonVersion=$($NIX_DAEMON_PACKAGE/bin/nix-daemon --version | cut -d' ' -f3)
return [[ $(nix eval --expr "builtins.compareVersions ''$daemonVersion'' ''2.4''") -ge 0 ]] [[ $(nix eval --expr "builtins.compareVersions ''$daemonVersion'' ''$requiredVersion''") -ge 0 ]]
} }
requireDaemonNewerThan () { requireDaemonNewerThan () {

View file

@ -50,4 +50,4 @@ exp_cores=$(nix show-config | grep '^cores' | cut -d '=' -f 2 | xargs)
exp_features=$(nix show-config | grep '^experimental-features' | cut -d '=' -f 2 | xargs) exp_features=$(nix show-config | grep '^experimental-features' | cut -d '=' -f 2 | xargs)
[[ $prev != $exp_cores ]] [[ $prev != $exp_cores ]]
[[ $exp_cores == "4242" ]] [[ $exp_cores == "4242" ]]
[[ $exp_features == "nix-command flakes" ]] [[ $exp_features == "flakes nix-command" ]]

View file

@ -1,6 +1,8 @@
source common.sh source common.sh
requireDaemonNewerThan "2.4pre20210727" # Using `--eval-store` with the daemon will eventually copy everything
# to the build store, invalidating most of the tests here
needLocalStore
eval_store=$TEST_ROOT/eval-store eval_store=$TEST_ROOT/eval-store

View file

@ -2,7 +2,7 @@ source common.sh
# 27ce722638 required some incompatible changes to the nix file, so skip this # 27ce722638 required some incompatible changes to the nix file, so skip this
# tests for the older versions # tests for the older versions
requireDaemonNewerThan "2.4pre20210622" requireDaemonNewerThan "2.4pre20210712"
clearStore clearStore