mirror of
https://github.com/NixOS/nix
synced 2025-06-29 14:53:16 +02:00
Merge remote-tracking branch 'origin/master' into lazy-trees
This commit is contained in:
commit
934f317250
35 changed files with 510 additions and 115 deletions
9
.github/stale.yml
vendored
9
.github/stale.yml
vendored
|
@ -1,10 +1,9 @@
|
||||||
# Configuration for probot-stale - https://github.com/probot/stale
|
# Configuration for probot-stale - https://github.com/probot/stale
|
||||||
daysUntilStale: 180
|
daysUntilStale: 180
|
||||||
daysUntilClose: 365
|
daysUntilClose: false
|
||||||
exemptLabels:
|
exemptLabels:
|
||||||
- "critical"
|
- "critical"
|
||||||
|
- "never-stale"
|
||||||
staleLabel: "stale"
|
staleLabel: "stale"
|
||||||
markComment: |
|
markComment: false
|
||||||
I marked this as stale due to inactivity. → [More info](https://github.com/NixOS/nix/blob/master/.github/STALE-BOT.md)
|
closeComment: false
|
||||||
closeComment: |
|
|
||||||
I closed this issue due to inactivity. → [More info](https://github.com/NixOS/nix/blob/master/.github/STALE-BOT.md)
|
|
||||||
|
|
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
|
@ -4,6 +4,8 @@ on:
|
||||||
pull_request:
|
pull_request:
|
||||||
push:
|
push:
|
||||||
|
|
||||||
|
permissions: read-all
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
|
@ -28,6 +30,8 @@ jobs:
|
||||||
- run: nix --experimental-features 'nix-command flakes' flake check -L
|
- run: nix --experimental-features 'nix-command flakes' flake check -L
|
||||||
|
|
||||||
check_cachix:
|
check_cachix:
|
||||||
|
permissions:
|
||||||
|
contents: none
|
||||||
name: Cachix secret present for installer tests
|
name: Cachix secret present for installer tests
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
outputs:
|
outputs:
|
||||||
|
|
4
.github/workflows/hydra_status.yml
vendored
4
.github/workflows/hydra_status.yml
vendored
|
@ -1,8 +1,12 @@
|
||||||
name: Hydra status
|
name: Hydra status
|
||||||
|
|
||||||
|
permissions: read-all
|
||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "12,42 * * * *"
|
- cron: "12,42 * * * *"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check_hydra_status:
|
check_hydra_status:
|
||||||
name: Check Hydra status
|
name: Check Hydra status
|
||||||
|
|
|
@ -72,6 +72,7 @@
|
||||||
- [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 X.Y (202?-??-??)](release-notes/rl-next.md)
|
- [Release X.Y (202?-??-??)](release-notes/rl-next.md)
|
||||||
|
- [Release 2.10 (2022-07-11)](release-notes/rl-2.10.md)
|
||||||
- [Release 2.9 (2022-05-30)](release-notes/rl-2.9.md)
|
- [Release 2.9 (2022-05-30)](release-notes/rl-2.9.md)
|
||||||
- [Release 2.8 (2022-04-19)](release-notes/rl-2.8.md)
|
- [Release 2.8 (2022-04-19)](release-notes/rl-2.8.md)
|
||||||
- [Release 2.7 (2022-03-07)](release-notes/rl-2.7.md)
|
- [Release 2.7 (2022-03-07)](release-notes/rl-2.7.md)
|
||||||
|
|
|
@ -31,7 +31,7 @@ subcommand to be performed. These are documented below.
|
||||||
Several commands, such as `nix-env -q` and `nix-env -i`, take a list of
|
Several commands, such as `nix-env -q` and `nix-env -i`, take a list of
|
||||||
arguments that specify the packages on which to operate. These are
|
arguments that specify the packages on which to operate. These are
|
||||||
extended regular expressions that must match the entire name of the
|
extended regular expressions that must match the entire name of the
|
||||||
package. (For details on regular expressions, see regex7.) The match is
|
package. (For details on regular expressions, see **regex**(7).) The match is
|
||||||
case-sensitive. The regular expression can optionally be followed by a
|
case-sensitive. The regular expression can optionally be followed by a
|
||||||
dash and a version number; if omitted, any version of the package will
|
dash and a version number; if omitted, any version of the package will
|
||||||
match. Here are some examples:
|
match. Here are some examples:
|
||||||
|
@ -412,7 +412,7 @@ The upgrade operation determines whether a derivation `y` is an upgrade
|
||||||
of a derivation `x` by looking at their respective `name` attributes.
|
of a derivation `x` by looking at their respective `name` attributes.
|
||||||
The names (e.g., `gcc-3.3.1` are split into two parts: the package name
|
The names (e.g., `gcc-3.3.1` are split into two parts: the package name
|
||||||
(`gcc`), and the version (`3.3.1`). The version part starts after the
|
(`gcc`), and the version (`3.3.1`). The version part starts after the
|
||||||
first dash not followed by a letter. `x` is considered an upgrade of `y`
|
first dash not followed by a letter. `y` is considered an upgrade of `x`
|
||||||
if their package names match, and the version of `y` is higher than that
|
if their package names match, and the version of `y` is higher than that
|
||||||
of `x`.
|
of `x`.
|
||||||
|
|
||||||
|
|
31
doc/manual/src/release-notes/rl-2.10.md
Normal file
31
doc/manual/src/release-notes/rl-2.10.md
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
# Release 2.10 (2022-07-11)
|
||||||
|
|
||||||
|
* `nix repl` now takes installables on the command line, unifying the usage
|
||||||
|
with other commands that use `--file` and `--expr`. Primary breaking change
|
||||||
|
is for the common usage of `nix repl '<nixpkgs>'` which can be recovered with
|
||||||
|
`nix repl --file '<nixpkgs>'` or `nix repl --expr 'import <nixpkgs>{}'`.
|
||||||
|
|
||||||
|
This is currently guarded by the `repl-flake` experimental feature.
|
||||||
|
|
||||||
|
* A new function `builtins.traceVerbose` is available. It is similar
|
||||||
|
to `builtins.trace` if the `trace-verbose` setting is set to true,
|
||||||
|
and it is a no-op otherwise.
|
||||||
|
|
||||||
|
* `nix search` has a new flag `--exclude` to filter out packages.
|
||||||
|
|
||||||
|
* On Linux, if `/nix` doesn't exist and cannot be created and you're
|
||||||
|
not running as root, Nix will automatically use
|
||||||
|
`~/.local/share/nix/root` as a chroot store. This enables non-root
|
||||||
|
users to download the statically linked Nix binary and have it work
|
||||||
|
out of the box, e.g.
|
||||||
|
|
||||||
|
```
|
||||||
|
# ~/nix run nixpkgs#hello
|
||||||
|
warning: '/nix' does not exists, so Nix will use '/home/ubuntu/.local/share/nix/root' as a chroot store
|
||||||
|
Hello, world!
|
||||||
|
```
|
||||||
|
|
||||||
|
* `flake-registry.json` is now fetched from `channels.nixos.org`.
|
||||||
|
|
||||||
|
* Nix can now be built with LTO by passing `--enable-lto` to `configure`.
|
||||||
|
LTO is currently only supported when building with GCC.
|
|
@ -1,4 +1,2 @@
|
||||||
# Release X.Y (202?-??-??)
|
# Release X.Y (202?-??-??)
|
||||||
|
|
||||||
* Nix can now be built with LTO by passing `--enable-lto` to `configure`.
|
|
||||||
LTO is currently only supported when building with GCC.
|
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
, tag ? "latest"
|
, tag ? "latest"
|
||||||
, channelName ? "nixpkgs"
|
, channelName ? "nixpkgs"
|
||||||
, channelURL ? "https://nixos.org/channels/nixpkgs-unstable"
|
, channelURL ? "https://nixos.org/channels/nixpkgs-unstable"
|
||||||
|
, extraPkgs ? []
|
||||||
|
, maxLayers ? 100
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
defaultPkgs = with pkgs; [
|
defaultPkgs = with pkgs; [
|
||||||
|
@ -23,7 +25,7 @@ let
|
||||||
iana-etc
|
iana-etc
|
||||||
git
|
git
|
||||||
openssh
|
openssh
|
||||||
];
|
] ++ extraPkgs;
|
||||||
|
|
||||||
users = {
|
users = {
|
||||||
|
|
||||||
|
@ -229,7 +231,7 @@ let
|
||||||
in
|
in
|
||||||
pkgs.dockerTools.buildLayeredImageWithNixDb {
|
pkgs.dockerTools.buildLayeredImageWithNixDb {
|
||||||
|
|
||||||
inherit name tag;
|
inherit name tag maxLayers;
|
||||||
|
|
||||||
contents = [ baseSystem ];
|
contents = [ baseSystem ];
|
||||||
|
|
||||||
|
|
16
flake.nix
16
flake.nix
|
@ -54,7 +54,7 @@
|
||||||
# we want most of the time and for backwards compatibility
|
# we want most of the time and for backwards compatibility
|
||||||
forAllSystems (system: stdenvsPackages.${system} // stdenvsPackages.${system}.stdenvPackages);
|
forAllSystems (system: stdenvsPackages.${system} // stdenvsPackages.${system}.stdenvPackages);
|
||||||
|
|
||||||
commonDeps = pkgs: with pkgs; rec {
|
commonDeps = { pkgs, isStatic ? false }: with pkgs; rec {
|
||||||
# Use "busybox-sandbox-shell" if present,
|
# Use "busybox-sandbox-shell" if present,
|
||||||
# if not (legacy) fallback and hope it's sufficient.
|
# if not (legacy) fallback and hope it's sufficient.
|
||||||
sh = pkgs.busybox-sandbox-shell or (busybox.override {
|
sh = pkgs.busybox-sandbox-shell or (busybox.override {
|
||||||
|
@ -85,6 +85,8 @@
|
||||||
lib.optionals stdenv.isLinux [
|
lib.optionals stdenv.isLinux [
|
||||||
"--with-boost=${boost}/lib"
|
"--with-boost=${boost}/lib"
|
||||||
"--with-sandbox-shell=${sh}/bin/busybox"
|
"--with-sandbox-shell=${sh}/bin/busybox"
|
||||||
|
]
|
||||||
|
++ lib.optionals (stdenv.isLinux && !(isStatic && stdenv.system == "aarch64-linux")) [
|
||||||
"LDFLAGS=-fuse-ld=gold"
|
"LDFLAGS=-fuse-ld=gold"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -174,7 +176,7 @@
|
||||||
echo "file installer $out/install" >> $out/nix-support/hydra-build-products
|
echo "file installer $out/install" >> $out/nix-support/hydra-build-products
|
||||||
'';
|
'';
|
||||||
|
|
||||||
testNixVersions = pkgs: client: daemon: with commonDeps pkgs; with pkgs.lib; pkgs.stdenv.mkDerivation {
|
testNixVersions = pkgs: client: daemon: with commonDeps { inherit pkgs; }; with pkgs.lib; pkgs.stdenv.mkDerivation {
|
||||||
NIX_DAEMON_PACKAGE = daemon;
|
NIX_DAEMON_PACKAGE = daemon;
|
||||||
NIX_CLIENT_PACKAGE = client;
|
NIX_CLIENT_PACKAGE = client;
|
||||||
name =
|
name =
|
||||||
|
@ -285,7 +287,7 @@
|
||||||
# Forward from the previous stage as we don’t want it to pick the lowdown override
|
# Forward from the previous stage as we don’t want it to pick the lowdown override
|
||||||
nixUnstable = prev.nixUnstable;
|
nixUnstable = prev.nixUnstable;
|
||||||
|
|
||||||
nix = with final; with commonDeps pkgs; currentStdenv.mkDerivation {
|
nix = with final; with commonDeps { inherit pkgs; }; currentStdenv.mkDerivation {
|
||||||
name = "nix-${version}";
|
name = "nix-${version}";
|
||||||
inherit version;
|
inherit version;
|
||||||
|
|
||||||
|
@ -452,7 +454,7 @@
|
||||||
# Line coverage analysis.
|
# Line coverage analysis.
|
||||||
coverage =
|
coverage =
|
||||||
with nixpkgsFor.x86_64-linux;
|
with nixpkgsFor.x86_64-linux;
|
||||||
with commonDeps pkgs;
|
with commonDeps { inherit pkgs; };
|
||||||
|
|
||||||
releaseTools.coverageAnalysis {
|
releaseTools.coverageAnalysis {
|
||||||
name = "nix-coverage-${version}";
|
name = "nix-coverage-${version}";
|
||||||
|
@ -563,7 +565,7 @@
|
||||||
} // (nixpkgs.lib.optionalAttrs (builtins.elem system linux64BitSystems) {
|
} // (nixpkgs.lib.optionalAttrs (builtins.elem system linux64BitSystems) {
|
||||||
nix-static = let
|
nix-static = let
|
||||||
nixpkgs = nixpkgsFor.${system}.pkgsStatic;
|
nixpkgs = nixpkgsFor.${system}.pkgsStatic;
|
||||||
in with commonDeps nixpkgs; nixpkgs.stdenv.mkDerivation {
|
in with commonDeps { pkgs = nixpkgs; isStatic = true; }; nixpkgs.stdenv.mkDerivation {
|
||||||
name = "nix-${version}";
|
name = "nix-${version}";
|
||||||
|
|
||||||
src = self;
|
src = self;
|
||||||
|
@ -634,7 +636,7 @@
|
||||||
inherit system crossSystem;
|
inherit system crossSystem;
|
||||||
overlays = [ self.overlays.default ];
|
overlays = [ self.overlays.default ];
|
||||||
};
|
};
|
||||||
in with commonDeps nixpkgsCross; nixpkgsCross.stdenv.mkDerivation {
|
in with commonDeps { pkgs = nixpkgsCross; }; nixpkgsCross.stdenv.mkDerivation {
|
||||||
name = "nix-${version}";
|
name = "nix-${version}";
|
||||||
|
|
||||||
src = self;
|
src = self;
|
||||||
|
@ -677,7 +679,7 @@
|
||||||
devShells = forAllSystems (system:
|
devShells = forAllSystems (system:
|
||||||
forAllStdenvs (stdenv:
|
forAllStdenvs (stdenv:
|
||||||
with nixpkgsFor.${system};
|
with nixpkgsFor.${system};
|
||||||
with commonDeps pkgs;
|
with commonDeps { inherit pkgs; };
|
||||||
nixpkgsFor.${system}.${stdenv}.mkDerivation {
|
nixpkgsFor.${system}.${stdenv}.mkDerivation {
|
||||||
name = "nix";
|
name = "nix";
|
||||||
|
|
||||||
|
|
|
@ -148,7 +148,9 @@ if ! [ -w "$dest" ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p "$dest/store"
|
# The auto-chroot code in openFromNonUri() checks for the
|
||||||
|
# non-existence of /nix/var/nix, so we need to create it here.
|
||||||
|
mkdir -p "$dest/store" "$dest/var/nix"
|
||||||
|
|
||||||
printf "copying Nix to %s..." "${dest}/store" >&2
|
printf "copying Nix to %s..." "${dest}/store" >&2
|
||||||
# Insert a newline if no progress is shown.
|
# Insert a newline if no progress is shown.
|
||||||
|
|
|
@ -120,7 +120,7 @@ ref<EvalState> EvalCommand::getEvalState()
|
||||||
;
|
;
|
||||||
|
|
||||||
if (startReplOnEvalErrors) {
|
if (startReplOnEvalErrors) {
|
||||||
evalState->debugRepl = &runRepl;
|
evalState->debugRepl = &runRepl;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return ref<EvalState>(evalState);
|
return ref<EvalState>(evalState);
|
||||||
|
|
|
@ -58,6 +58,7 @@ struct CopyCommand : virtual StoreCommand
|
||||||
struct EvalCommand : virtual StoreCommand, MixEvalArgs
|
struct EvalCommand : virtual StoreCommand, MixEvalArgs
|
||||||
{
|
{
|
||||||
bool startReplOnEvalErrors = false;
|
bool startReplOnEvalErrors = false;
|
||||||
|
bool ignoreExceptionsDuringTry = false;
|
||||||
|
|
||||||
EvalCommand();
|
EvalCommand();
|
||||||
|
|
||||||
|
@ -77,10 +78,16 @@ struct MixFlakeOptions : virtual Args, EvalCommand
|
||||||
{
|
{
|
||||||
flake::LockFlags lockFlags;
|
flake::LockFlags lockFlags;
|
||||||
|
|
||||||
|
std::optional<std::string> needsFlakeInputCompletion = {};
|
||||||
|
|
||||||
MixFlakeOptions();
|
MixFlakeOptions();
|
||||||
|
|
||||||
virtual std::optional<FlakeRef> getFlakeRefForCompletion()
|
virtual std::vector<std::string> getFlakesForCompletion()
|
||||||
{ return {}; }
|
{ return {}; }
|
||||||
|
|
||||||
|
void completeFlakeInput(std::string_view prefix);
|
||||||
|
|
||||||
|
void completionHook() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SourceExprCommand : virtual Args, MixFlakeOptions
|
struct SourceExprCommand : virtual Args, MixFlakeOptions
|
||||||
|
@ -116,12 +123,13 @@ struct InstallablesCommand : virtual Args, SourceExprCommand
|
||||||
InstallablesCommand();
|
InstallablesCommand();
|
||||||
|
|
||||||
void prepare() override;
|
void prepare() override;
|
||||||
|
Installables load();
|
||||||
|
|
||||||
virtual bool useDefaultInstallables() { return true; }
|
virtual bool useDefaultInstallables() { return true; }
|
||||||
|
|
||||||
std::optional<FlakeRef> getFlakeRefForCompletion() override;
|
std::vector<std::string> getFlakesForCompletion() override;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
|
|
||||||
std::vector<std::string> _installables;
|
std::vector<std::string> _installables;
|
||||||
};
|
};
|
||||||
|
@ -135,9 +143,9 @@ struct InstallableCommand : virtual Args, SourceExprCommand
|
||||||
|
|
||||||
void prepare() override;
|
void prepare() override;
|
||||||
|
|
||||||
std::optional<FlakeRef> getFlakeRefForCompletion() override
|
std::vector<std::string> getFlakesForCompletion() override
|
||||||
{
|
{
|
||||||
return parseFlakeRefWithFragment(_installable, absPath(".")).first;
|
return {_installable};
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -23,17 +23,6 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
void completeFlakeInputPath(
|
|
||||||
ref<EvalState> evalState,
|
|
||||||
const FlakeRef & flakeRef,
|
|
||||||
std::string_view prefix)
|
|
||||||
{
|
|
||||||
auto flake = flake::getFlake(*evalState, flakeRef, true);
|
|
||||||
for (auto & input : flake.inputs)
|
|
||||||
if (hasPrefix(input.first, prefix))
|
|
||||||
completions->add(input.first);
|
|
||||||
}
|
|
||||||
|
|
||||||
MixFlakeOptions::MixFlakeOptions()
|
MixFlakeOptions::MixFlakeOptions()
|
||||||
{
|
{
|
||||||
auto category = "Common flake-related options";
|
auto category = "Common flake-related options";
|
||||||
|
@ -86,8 +75,7 @@ MixFlakeOptions::MixFlakeOptions()
|
||||||
lockFlags.inputUpdates.insert(flake::parseInputPath(s));
|
lockFlags.inputUpdates.insert(flake::parseInputPath(s));
|
||||||
}},
|
}},
|
||||||
.completer = {[&](size_t, std::string_view prefix) {
|
.completer = {[&](size_t, std::string_view prefix) {
|
||||||
if (auto flakeRef = getFlakeRefForCompletion())
|
needsFlakeInputCompletion = {std::string(prefix)};
|
||||||
completeFlakeInputPath(getEvalState(), *flakeRef, prefix);
|
|
||||||
}}
|
}}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -103,12 +91,10 @@ MixFlakeOptions::MixFlakeOptions()
|
||||||
parseFlakeRef(flakeRef, absPath("."), true));
|
parseFlakeRef(flakeRef, absPath("."), true));
|
||||||
}},
|
}},
|
||||||
.completer = {[&](size_t n, std::string_view prefix) {
|
.completer = {[&](size_t n, std::string_view prefix) {
|
||||||
if (n == 0) {
|
if (n == 0)
|
||||||
if (auto flakeRef = getFlakeRefForCompletion())
|
needsFlakeInputCompletion = {std::string(prefix)};
|
||||||
completeFlakeInputPath(getEvalState(), *flakeRef, prefix);
|
else if (n == 1)
|
||||||
} else if (n == 1) {
|
|
||||||
completeFlakeRef(getEvalState()->store, prefix);
|
completeFlakeRef(getEvalState()->store, prefix);
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -139,6 +125,24 @@ MixFlakeOptions::MixFlakeOptions()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MixFlakeOptions::completeFlakeInput(std::string_view prefix)
|
||||||
|
{
|
||||||
|
auto evalState = getEvalState();
|
||||||
|
for (auto & flakeRefS : getFlakesForCompletion()) {
|
||||||
|
auto flakeRef = parseFlakeRefWithFragment(expandTilde(flakeRefS), absPath(".")).first;
|
||||||
|
auto flake = flake::getFlake(*evalState, flakeRef, true);
|
||||||
|
for (auto & input : flake.inputs)
|
||||||
|
if (hasPrefix(input.first, prefix))
|
||||||
|
completions->add(input.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MixFlakeOptions::completionHook()
|
||||||
|
{
|
||||||
|
if (auto & prefix = needsFlakeInputCompletion)
|
||||||
|
completeFlakeInput(*prefix);
|
||||||
|
}
|
||||||
|
|
||||||
SourceExprCommand::SourceExprCommand(bool supportReadOnlyMode)
|
SourceExprCommand::SourceExprCommand(bool supportReadOnlyMode)
|
||||||
{
|
{
|
||||||
addFlag({
|
addFlag({
|
||||||
|
@ -1041,21 +1045,26 @@ InstallablesCommand::InstallablesCommand()
|
||||||
|
|
||||||
void InstallablesCommand::prepare()
|
void InstallablesCommand::prepare()
|
||||||
{
|
{
|
||||||
|
installables = load();
|
||||||
|
}
|
||||||
|
|
||||||
|
Installables InstallablesCommand::load() {
|
||||||
|
Installables installables;
|
||||||
if (_installables.empty() && useDefaultInstallables())
|
if (_installables.empty() && useDefaultInstallables())
|
||||||
// FIXME: commands like "nix profile install" should not have a
|
// FIXME: commands like "nix profile install" should not have a
|
||||||
// default, probably.
|
// default, probably.
|
||||||
_installables.push_back(".");
|
_installables.push_back(".");
|
||||||
installables = parseInstallables(getStore(), _installables);
|
return parseInstallables(getStore(), _installables);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<FlakeRef> InstallablesCommand::getFlakeRefForCompletion()
|
std::vector<std::string> InstallablesCommand::getFlakesForCompletion()
|
||||||
{
|
{
|
||||||
if (_installables.empty()) {
|
if (_installables.empty()) {
|
||||||
if (useDefaultInstallables())
|
if (useDefaultInstallables())
|
||||||
return parseFlakeRefWithFragment(".", absPath(".")).first;
|
return {"."};
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return parseFlakeRefWithFragment(_installables.front(), absPath(".")).first;
|
return _installables;
|
||||||
}
|
}
|
||||||
|
|
||||||
InstallableCommand::InstallableCommand(bool supportReadOnlyMode)
|
InstallableCommand::InstallableCommand(bool supportReadOnlyMode)
|
||||||
|
|
|
@ -132,6 +132,8 @@ struct Installable
|
||||||
const std::vector<std::shared_ptr<Installable>> & installables);
|
const std::vector<std::shared_ptr<Installable>> & installables);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef std::vector<std::shared_ptr<Installable>> Installables;
|
||||||
|
|
||||||
struct InstallableValue : Installable
|
struct InstallableValue : Installable
|
||||||
{
|
{
|
||||||
ref<EvalState> state;
|
ref<EvalState> state;
|
||||||
|
|
|
@ -22,6 +22,7 @@ extern "C" {
|
||||||
#include "ansicolor.hh"
|
#include "ansicolor.hh"
|
||||||
#include "shared.hh"
|
#include "shared.hh"
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
|
#include "eval-cache.hh"
|
||||||
#include "eval-inline.hh"
|
#include "eval-inline.hh"
|
||||||
#include "attr-path.hh"
|
#include "attr-path.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
|
@ -54,6 +55,8 @@ struct NixRepl
|
||||||
size_t debugTraceIndex;
|
size_t debugTraceIndex;
|
||||||
|
|
||||||
Strings loadedFiles;
|
Strings loadedFiles;
|
||||||
|
typedef std::vector<std::pair<Value*,std::string>> AnnotatedValues;
|
||||||
|
std::function<AnnotatedValues()> getValues;
|
||||||
|
|
||||||
const static int envSize = 32768;
|
const static int envSize = 32768;
|
||||||
std::shared_ptr<StaticEnv> staticEnv;
|
std::shared_ptr<StaticEnv> staticEnv;
|
||||||
|
@ -63,13 +66,15 @@ struct NixRepl
|
||||||
|
|
||||||
const Path historyFile;
|
const Path historyFile;
|
||||||
|
|
||||||
NixRepl(ref<EvalState> state);
|
NixRepl(const Strings & searchPath, nix::ref<Store> store,ref<EvalState> state,
|
||||||
|
std::function<AnnotatedValues()> getValues);
|
||||||
~NixRepl();
|
~NixRepl();
|
||||||
void mainLoop(const std::vector<std::string> & files);
|
void mainLoop();
|
||||||
StringSet completePrefix(const std::string & prefix);
|
StringSet completePrefix(const std::string & prefix);
|
||||||
bool getLine(std::string & input, const std::string & prompt);
|
bool getLine(std::string & input, const std::string & prompt);
|
||||||
StorePath getDerivationPath(Value & v);
|
StorePath getDerivationPath(Value & v);
|
||||||
bool processLine(std::string line);
|
bool processLine(std::string line);
|
||||||
|
|
||||||
void loadFile(const Path & path);
|
void loadFile(const Path & path);
|
||||||
void loadFlake(const std::string & flakeRef);
|
void loadFlake(const std::string & flakeRef);
|
||||||
void initEnv();
|
void initEnv();
|
||||||
|
@ -96,9 +101,11 @@ std::string removeWhitespace(std::string s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NixRepl::NixRepl(ref<EvalState> state)
|
NixRepl::NixRepl(const Strings & searchPath, nix::ref<Store> store, ref<EvalState> state,
|
||||||
|
std::function<NixRepl::AnnotatedValues()> getValues)
|
||||||
: state(state)
|
: state(state)
|
||||||
, debugTraceIndex(0)
|
, debugTraceIndex(0)
|
||||||
|
, getValues(getValues)
|
||||||
, staticEnv(new StaticEnv(false, state->staticBaseEnv.get()))
|
, staticEnv(new StaticEnv(false, state->staticBaseEnv.get()))
|
||||||
, historyFile(getDataDir() + "/nix/repl-history")
|
, historyFile(getDataDir() + "/nix/repl-history")
|
||||||
{
|
{
|
||||||
|
@ -111,23 +118,20 @@ NixRepl::~NixRepl()
|
||||||
write_history(historyFile.c_str());
|
write_history(historyFile.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string runNix(Path program, const Strings & args,
|
void runNix(Path program, const Strings & args,
|
||||||
const std::optional<std::string> & input = {})
|
const std::optional<std::string> & input = {})
|
||||||
{
|
{
|
||||||
auto subprocessEnv = getEnv();
|
auto subprocessEnv = getEnv();
|
||||||
subprocessEnv["NIX_CONFIG"] = globalConfig.toKeyValue();
|
subprocessEnv["NIX_CONFIG"] = globalConfig.toKeyValue();
|
||||||
|
|
||||||
auto res = runProgram(RunOptions {
|
runProgram2(RunOptions {
|
||||||
.program = settings.nixBinDir+ "/" + program,
|
.program = settings.nixBinDir+ "/" + program,
|
||||||
.args = args,
|
.args = args,
|
||||||
.environment = subprocessEnv,
|
.environment = subprocessEnv,
|
||||||
.input = input,
|
.input = input,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!statusOk(res.first))
|
return;
|
||||||
throw ExecError(res.first, "program '%1%' %2%", program, statusToString(res.first));
|
|
||||||
|
|
||||||
return res.second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static NixRepl * curRepl; // ugly
|
static NixRepl * curRepl; // ugly
|
||||||
|
@ -226,18 +230,12 @@ static std::ostream & showDebugTrace(std::ostream & out, const PosTable & positi
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NixRepl::mainLoop(const std::vector<std::string> & files)
|
void NixRepl::mainLoop()
|
||||||
{
|
{
|
||||||
std::string error = ANSI_RED "error:" ANSI_NORMAL " ";
|
std::string error = ANSI_RED "error:" ANSI_NORMAL " ";
|
||||||
notice("Welcome to Nix " + nixVersion + ". Type :? for help.\n");
|
notice("Welcome to Nix " + nixVersion + ". Type :? for help.\n");
|
||||||
|
|
||||||
if (!files.empty()) {
|
|
||||||
for (auto & i : files)
|
|
||||||
loadedFiles.push_back(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
loadFiles();
|
loadFiles();
|
||||||
if (!loadedFiles.empty()) notice("");
|
|
||||||
|
|
||||||
// Allow nix-repl specific settings in .inputrc
|
// Allow nix-repl specific settings in .inputrc
|
||||||
rl_readline_name = "nix-repl";
|
rl_readline_name = "nix-repl";
|
||||||
|
@ -749,7 +747,6 @@ bool NixRepl::processLine(std::string line)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void NixRepl::loadFile(const Path & path)
|
void NixRepl::loadFile(const Path & path)
|
||||||
{
|
{
|
||||||
loadedFiles.remove(path);
|
loadedFiles.remove(path);
|
||||||
|
@ -809,13 +806,15 @@ void NixRepl::loadFiles()
|
||||||
Strings old = loadedFiles;
|
Strings old = loadedFiles;
|
||||||
loadedFiles.clear();
|
loadedFiles.clear();
|
||||||
|
|
||||||
bool first = true;
|
|
||||||
for (auto & i : old) {
|
for (auto & i : old) {
|
||||||
if (!first) notice("");
|
|
||||||
first = false;
|
|
||||||
notice("Loading '%1%'...", i);
|
notice("Loading '%1%'...", i);
|
||||||
loadFile(i);
|
loadFile(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto & [i, what] : getValues()) {
|
||||||
|
notice("Loading installable '%1%'...", what);
|
||||||
|
addAttrsToScope(*i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1015,7 +1014,17 @@ void runRepl(
|
||||||
ref<EvalState>evalState,
|
ref<EvalState>evalState,
|
||||||
const ValMap & extraEnv)
|
const ValMap & extraEnv)
|
||||||
{
|
{
|
||||||
auto repl = std::make_unique<NixRepl>(evalState);
|
auto getValues = [&]()->NixRepl::AnnotatedValues{
|
||||||
|
NixRepl::AnnotatedValues values;
|
||||||
|
return values;
|
||||||
|
};
|
||||||
|
const Strings & searchPath = {};
|
||||||
|
auto repl = std::make_unique<NixRepl>(
|
||||||
|
searchPath,
|
||||||
|
openStore(),
|
||||||
|
evalState,
|
||||||
|
getValues
|
||||||
|
);
|
||||||
|
|
||||||
repl->initEnv();
|
repl->initEnv();
|
||||||
|
|
||||||
|
@ -1023,20 +1032,35 @@ void runRepl(
|
||||||
for (auto & [name, value] : extraEnv)
|
for (auto & [name, value] : extraEnv)
|
||||||
repl->addVarToScope(repl->state->symbols.create(name), *value);
|
repl->addVarToScope(repl->state->symbols.create(name), *value);
|
||||||
|
|
||||||
repl->mainLoop({});
|
repl->mainLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CmdRepl : StoreCommand, MixEvalArgs
|
struct CmdRepl : InstallablesCommand
|
||||||
{
|
{
|
||||||
std::vector<std::string> files;
|
CmdRepl(){
|
||||||
|
evalSettings.pureEval = false;
|
||||||
CmdRepl()
|
}
|
||||||
|
void prepare()
|
||||||
{
|
{
|
||||||
expectArgs({
|
if (!settings.isExperimentalFeatureEnabled(Xp::ReplFlake) && !(file) && this->_installables.size() >= 1) {
|
||||||
.label = "files",
|
warn("future versions of Nix will require using `--file` to load a file");
|
||||||
.handler = {&files},
|
if (this->_installables.size() > 1)
|
||||||
.completer = completePath
|
warn("more than one input file is not currently supported");
|
||||||
});
|
auto filePath = this->_installables[0].data();
|
||||||
|
file = std::optional(filePath);
|
||||||
|
_installables.front() = _installables.back();
|
||||||
|
_installables.pop_back();
|
||||||
|
}
|
||||||
|
installables = InstallablesCommand::load();
|
||||||
|
}
|
||||||
|
std::vector<std::string> files;
|
||||||
|
Strings getDefaultFlakeAttrPaths() override
|
||||||
|
{
|
||||||
|
return {""};
|
||||||
|
}
|
||||||
|
virtual bool useDefaultInstallables() override
|
||||||
|
{
|
||||||
|
return file.has_value() or expr.has_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool forceImpureByDefault() override
|
bool forceImpureByDefault() override
|
||||||
|
@ -1058,12 +1082,37 @@ struct CmdRepl : StoreCommand, MixEvalArgs
|
||||||
|
|
||||||
void run(ref<Store> store) override
|
void run(ref<Store> store) override
|
||||||
{
|
{
|
||||||
auto evalState = make_ref<EvalState>(searchPath, store);
|
auto state = getEvalState();
|
||||||
|
auto getValues = [&]()->NixRepl::AnnotatedValues{
|
||||||
auto repl = std::make_unique<NixRepl>(evalState);
|
auto installables = load();
|
||||||
|
NixRepl::AnnotatedValues values;
|
||||||
|
for (auto & installable: installables){
|
||||||
|
auto what = installable->what();
|
||||||
|
if (file){
|
||||||
|
auto [val, pos] = installable->toValue(*state);
|
||||||
|
auto what = installable->what();
|
||||||
|
state->forceValue(*val, pos);
|
||||||
|
auto autoArgs = getAutoArgs(*state);
|
||||||
|
auto valPost = state->allocValue();
|
||||||
|
state->autoCallFunction(*autoArgs, *val, *valPost);
|
||||||
|
state->forceValue(*valPost, pos);
|
||||||
|
values.push_back( {valPost, what });
|
||||||
|
} else {
|
||||||
|
auto [val, pos] = installable->toValue(*state);
|
||||||
|
values.push_back( {val, what} );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
};
|
||||||
|
auto repl = std::make_unique<NixRepl>(
|
||||||
|
searchPath,
|
||||||
|
openStore(),
|
||||||
|
state,
|
||||||
|
getValues
|
||||||
|
);
|
||||||
repl->autoArgs = getAutoArgs(*repl->state);
|
repl->autoArgs = getAutoArgs(*repl->state);
|
||||||
repl->initEnv();
|
repl->initEnv();
|
||||||
repl->mainLoop(files);
|
repl->mainLoop();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -489,7 +489,7 @@ std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(Symbol name, bool forceErro
|
||||||
return nullptr;
|
return nullptr;
|
||||||
else if (std::get_if<failed_t>(&attr->second)) {
|
else if (std::get_if<failed_t>(&attr->second)) {
|
||||||
if (forceErrors)
|
if (forceErrors)
|
||||||
debug("reevaluating failed cached attribute '%s'");
|
debug("reevaluating failed cached attribute '%s'", getAttrPathStr(name));
|
||||||
else
|
else
|
||||||
throw CachedEvalError("cached failure of attribute '%s'", getAttrPathStr(name));
|
throw CachedEvalError("cached failure of attribute '%s'", getAttrPathStr(name));
|
||||||
} else
|
} else
|
||||||
|
|
|
@ -481,9 +481,10 @@ EvalState::EvalState(
|
||||||
)}
|
)}
|
||||||
, store(store)
|
, store(store)
|
||||||
, buildStore(buildStore ? buildStore : store)
|
, buildStore(buildStore ? buildStore : store)
|
||||||
, debugRepl(0)
|
, debugRepl(nullptr)
|
||||||
, debugStop(false)
|
, debugStop(false)
|
||||||
, debugQuit(false)
|
, debugQuit(false)
|
||||||
|
, trylevel(0)
|
||||||
, regexCache(makeRegexCache())
|
, regexCache(makeRegexCache())
|
||||||
#if HAVE_BOEHMGC
|
#if HAVE_BOEHMGC
|
||||||
, valueAllocCache(std::allocate_shared<void *>(traceable_allocator<void *>(), nullptr))
|
, valueAllocCache(std::allocate_shared<void *>(traceable_allocator<void *>(), nullptr))
|
||||||
|
@ -788,7 +789,14 @@ void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr &
|
||||||
: nullptr;
|
: nullptr;
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
printError("%s\n\n" ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error->what());
|
{
|
||||||
|
printError("%s\n\n", error->what());
|
||||||
|
|
||||||
|
if (trylevel > 0 && error->info().level != lvlInfo)
|
||||||
|
printError("This exception occurred in a 'tryEval' call. Use " ANSI_GREEN "--ignore-try" ANSI_NORMAL " to skip these.\n");
|
||||||
|
|
||||||
|
printError(ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
auto se = getStaticEnv(expr);
|
auto se = getStaticEnv(expr);
|
||||||
if (se) {
|
if (se) {
|
||||||
|
|
|
@ -128,6 +128,7 @@ public:
|
||||||
void (* debugRepl)(ref<EvalState> es, const ValMap & extraEnv);
|
void (* debugRepl)(ref<EvalState> es, const ValMap & extraEnv);
|
||||||
bool debugStop;
|
bool debugStop;
|
||||||
bool debugQuit;
|
bool debugQuit;
|
||||||
|
int trylevel;
|
||||||
std::list<DebugTrace> debugTraces;
|
std::list<DebugTrace> debugTraces;
|
||||||
std::map<const Expr*, const std::shared_ptr<const StaticEnv>> exprEnvs;
|
std::map<const Expr*, const std::shared_ptr<const StaticEnv>> exprEnvs;
|
||||||
const std::shared_ptr<const StaticEnv> getStaticEnv(const Expr & expr) const
|
const std::shared_ptr<const StaticEnv> getStaticEnv(const Expr & expr) const
|
||||||
|
@ -643,6 +644,15 @@ struct EvalSettings : Config
|
||||||
|
|
||||||
Setting<bool> useEvalCache{this, true, "eval-cache",
|
Setting<bool> useEvalCache{this, true, "eval-cache",
|
||||||
"Whether to use the flake evaluation cache."};
|
"Whether to use the flake evaluation cache."};
|
||||||
|
|
||||||
|
Setting<bool> ignoreExceptionsDuringTry{this, false, "ignore-try",
|
||||||
|
R"(
|
||||||
|
If set to true, ignore exceptions inside 'tryEval' calls when evaluating nix expressions in
|
||||||
|
debug mode (using the --debugger flag). By default the debugger will pause on all exceptions.
|
||||||
|
)"};
|
||||||
|
|
||||||
|
Setting<bool> traceVerbose{this, false, "trace-verbose",
|
||||||
|
"Whether `builtins.traceVerbose` should trace its first argument when evaluated."};
|
||||||
};
|
};
|
||||||
|
|
||||||
extern EvalSettings evalSettings;
|
extern EvalSettings evalSettings;
|
||||||
|
|
|
@ -324,6 +324,39 @@ LockedFlake lockFlake(
|
||||||
|
|
||||||
std::vector<FlakeRef> parents;
|
std::vector<FlakeRef> parents;
|
||||||
|
|
||||||
|
std::function<void(
|
||||||
|
const InputPath & inputPathPrefix,
|
||||||
|
const FlakeInputs & flakeInputs
|
||||||
|
)>
|
||||||
|
checkFollowsDeclarations;
|
||||||
|
|
||||||
|
checkFollowsDeclarations = [&](
|
||||||
|
const InputPath & inputPathPrefix,
|
||||||
|
const FlakeInputs & flakeInputs
|
||||||
|
) {
|
||||||
|
for (auto [inputPath, inputOverride] : overrides) {
|
||||||
|
auto inputPath2(inputPath);
|
||||||
|
auto follow = inputPath2.back();
|
||||||
|
inputPath2.pop_back();
|
||||||
|
if (inputPath2 == inputPathPrefix
|
||||||
|
&& flakeInputs.find(follow) == flakeInputs.end()
|
||||||
|
) {
|
||||||
|
std::string root;
|
||||||
|
for (auto & element : inputPath2) {
|
||||||
|
root.append(element);
|
||||||
|
if (element != inputPath2.back()) {
|
||||||
|
root.append(".inputs.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
warn(
|
||||||
|
"%s has a `follows'-declaration for a non-existent input %s!",
|
||||||
|
root,
|
||||||
|
follow
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
std::function<void(
|
std::function<void(
|
||||||
const FlakeInputs & flakeInputs,
|
const FlakeInputs & flakeInputs,
|
||||||
std::shared_ptr<Node> node,
|
std::shared_ptr<Node> node,
|
||||||
|
@ -356,6 +389,8 @@ LockedFlake lockFlake(
|
||||||
{
|
{
|
||||||
debug("computing lock file node '%s'", printInputPath(inputPathPrefix));
|
debug("computing lock file node '%s'", printInputPath(inputPathPrefix));
|
||||||
|
|
||||||
|
checkFollowsDeclarations(inputPathPrefix, flakeInputs);
|
||||||
|
|
||||||
/* Get the overrides (i.e. attributes of the form
|
/* Get the overrides (i.e. attributes of the form
|
||||||
'inputs.nixops.inputs.nixpkgs.url = ...'). */
|
'inputs.nixops.inputs.nixpkgs.url = ...'). */
|
||||||
for (auto & [id, input] : flakeInputs) {
|
for (auto & [id, input] : flakeInputs) {
|
||||||
|
|
|
@ -853,6 +853,18 @@ static RegisterPrimOp primop_floor({
|
||||||
static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
auto attrs = state.buildBindings(2);
|
auto attrs = state.buildBindings(2);
|
||||||
|
|
||||||
|
/* increment state.trylevel, and decrement it when this function returns. */
|
||||||
|
MaintainCount trylevel(state.trylevel);
|
||||||
|
|
||||||
|
void (* savedDebugRepl)(ref<EvalState> es, const ValMap & extraEnv) = nullptr;
|
||||||
|
if (state.debugRepl && evalSettings.ignoreExceptionsDuringTry)
|
||||||
|
{
|
||||||
|
/* to prevent starting the repl from exceptions withing a tryEval, null it. */
|
||||||
|
savedDebugRepl = state.debugRepl;
|
||||||
|
state.debugRepl = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
state.forceValue(*args[0], pos);
|
state.forceValue(*args[0], pos);
|
||||||
attrs.insert(state.sValue, args[0]);
|
attrs.insert(state.sValue, args[0]);
|
||||||
|
@ -861,6 +873,11 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va
|
||||||
attrs.alloc(state.sValue).mkBool(false);
|
attrs.alloc(state.sValue).mkBool(false);
|
||||||
attrs.alloc("success").mkBool(false);
|
attrs.alloc("success").mkBool(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// restore the debugRepl pointer if we saved it earlier.
|
||||||
|
if (savedDebugRepl)
|
||||||
|
state.debugRepl = savedDebugRepl;
|
||||||
|
|
||||||
v.mkAttrs(attrs);
|
v.mkAttrs(attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -972,6 +989,15 @@ static RegisterPrimOp primop_trace({
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* Takes two arguments and evaluates to the second one. Used as the
|
||||||
|
* builtins.traceVerbose implementation when --trace-verbose is not enabled
|
||||||
|
*/
|
||||||
|
static void prim_second(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||||
|
{
|
||||||
|
state.forceValue(*args[1], pos);
|
||||||
|
v = *args[1];
|
||||||
|
}
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
* Derivations
|
* Derivations
|
||||||
*************************************************************/
|
*************************************************************/
|
||||||
|
@ -3952,6 +3978,18 @@ void EvalState::createBaseEnv()
|
||||||
addPrimOp("__exec", 1, prim_exec);
|
addPrimOp("__exec", 1, prim_exec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addPrimOp({
|
||||||
|
.fun = evalSettings.traceVerbose ? prim_trace : prim_second,
|
||||||
|
.arity = 2,
|
||||||
|
.name = "__traceVerbose",
|
||||||
|
.args = { "e1", "e2" },
|
||||||
|
.doc = R"(
|
||||||
|
Evaluate *e1* and print its abstract syntax representation on standard
|
||||||
|
error if `--trace-verbose` is enabled. Then return *e2*. This function
|
||||||
|
is useful for debugging.
|
||||||
|
)",
|
||||||
|
});
|
||||||
|
|
||||||
/* Add a value containing the current Nix expression search path. */
|
/* Add a value containing the current Nix expression search path. */
|
||||||
mkList(v, searchPath.size());
|
mkList(v, searchPath.size());
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
|
|
@ -1330,9 +1330,14 @@ std::shared_ptr<Store> openFromNonUri(const std::string & uri, const Store::Para
|
||||||
we're not root, then automatically set up a chroot
|
we're not root, then automatically set up a chroot
|
||||||
store in ~/.local/share/nix/root. */
|
store in ~/.local/share/nix/root. */
|
||||||
auto chrootStore = getDataDir() + "/nix/root";
|
auto chrootStore = getDataDir() + "/nix/root";
|
||||||
if (!pathExists(chrootStore))
|
if (!pathExists(chrootStore)) {
|
||||||
|
try {
|
||||||
|
createDirs(chrootStore);
|
||||||
|
} catch (Error & e) {
|
||||||
|
return std::make_shared<LocalStore>(params);
|
||||||
|
}
|
||||||
warn("'/nix' does not exist, so Nix will use '%s' as a chroot store", chrootStore);
|
warn("'/nix' does not exist, so Nix will use '%s' as a chroot store", chrootStore);
|
||||||
else
|
} else
|
||||||
debug("'/nix' does not exist, so Nix will use '%s' as a chroot store", chrootStore);
|
debug("'/nix' does not exist, so Nix will use '%s' as a chroot store", chrootStore);
|
||||||
Store::Params params2;
|
Store::Params params2;
|
||||||
params2["root"] = chrootStore;
|
params2["root"] = chrootStore;
|
||||||
|
|
|
@ -124,7 +124,7 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
|
||||||
bool anyCompleted = false;
|
bool anyCompleted = false;
|
||||||
for (size_t n = 0 ; n < flag.handler.arity; ++n) {
|
for (size_t n = 0 ; n < flag.handler.arity; ++n) {
|
||||||
if (pos == end) {
|
if (pos == end) {
|
||||||
if (flag.handler.arity == ArityAny) break;
|
if (flag.handler.arity == ArityAny || anyCompleted) break;
|
||||||
throw UsageError("flag '%s' requires %d argument(s)", name, flag.handler.arity);
|
throw UsageError("flag '%s' requires %d argument(s)", name, flag.handler.arity);
|
||||||
}
|
}
|
||||||
if (auto prefix = needsCompletion(*pos)) {
|
if (auto prefix = needsCompletion(*pos)) {
|
||||||
|
@ -362,6 +362,14 @@ bool MultiCommand::processArgs(const Strings & args, bool finish)
|
||||||
return Args::processArgs(args, finish);
|
return Args::processArgs(args, finish);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MultiCommand::completionHook()
|
||||||
|
{
|
||||||
|
if (command)
|
||||||
|
return command->second->completionHook();
|
||||||
|
else
|
||||||
|
return Args::completionHook();
|
||||||
|
}
|
||||||
|
|
||||||
nlohmann::json MultiCommand::toJSON()
|
nlohmann::json MultiCommand::toJSON()
|
||||||
{
|
{
|
||||||
auto cmds = nlohmann::json::object();
|
auto cmds = nlohmann::json::object();
|
||||||
|
|
|
@ -148,6 +148,11 @@ protected:
|
||||||
argument (if any) have been processed. */
|
argument (if any) have been processed. */
|
||||||
virtual void initialFlagsProcessed() {}
|
virtual void initialFlagsProcessed() {}
|
||||||
|
|
||||||
|
/* Called after the command line has been processed if we need to generate
|
||||||
|
completions. Useful for commands that need to know the whole command line
|
||||||
|
in order to know what completions to generate. */
|
||||||
|
virtual void completionHook() { }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void addFlag(Flag && flag);
|
void addFlag(Flag && flag);
|
||||||
|
@ -223,6 +228,8 @@ public:
|
||||||
|
|
||||||
bool processArgs(const Strings & args, bool finish) override;
|
bool processArgs(const Strings & args, bool finish) override;
|
||||||
|
|
||||||
|
void completionHook() override;
|
||||||
|
|
||||||
nlohmann::json toJSON() override;
|
nlohmann::json toJSON() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ std::map<ExperimentalFeature, std::string> stringifiedXpFeatures = {
|
||||||
{ Xp::RecursiveNix, "recursive-nix" },
|
{ Xp::RecursiveNix, "recursive-nix" },
|
||||||
{ Xp::NoUrlLiterals, "no-url-literals" },
|
{ Xp::NoUrlLiterals, "no-url-literals" },
|
||||||
{ Xp::FetchClosure, "fetch-closure" },
|
{ Xp::FetchClosure, "fetch-closure" },
|
||||||
|
{ Xp::ReplFlake, "repl-flake" },
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::optional<ExperimentalFeature> parseExperimentalFeature(const std::string_view & name)
|
const std::optional<ExperimentalFeature> parseExperimentalFeature(const std::string_view & name)
|
||||||
|
|
|
@ -22,6 +22,7 @@ enum struct ExperimentalFeature
|
||||||
RecursiveNix,
|
RecursiveNix,
|
||||||
NoUrlLiterals,
|
NoUrlLiterals,
|
||||||
FetchClosure,
|
FetchClosure,
|
||||||
|
ReplFlake,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -257,11 +257,12 @@ static void main_nix_build(int argc, char * * argv)
|
||||||
|
|
||||||
auto autoArgs = myArgs.getAutoArgs(*state);
|
auto autoArgs = myArgs.getAutoArgs(*state);
|
||||||
|
|
||||||
|
auto autoArgsWithInNixShell = autoArgs;
|
||||||
if (runEnv) {
|
if (runEnv) {
|
||||||
auto newArgs = state->buildBindings(autoArgs->size() + 1);
|
auto newArgs = state->buildBindings(autoArgsWithInNixShell->size() + 1);
|
||||||
newArgs.alloc("inNixShell").mkBool(true);
|
newArgs.alloc("inNixShell").mkBool(true);
|
||||||
for (auto & i : *autoArgs) newArgs.insert(i);
|
for (auto & i : *autoArgs) newArgs.insert(i);
|
||||||
autoArgs = newArgs.finish();
|
autoArgsWithInNixShell = newArgs.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packages) {
|
if (packages) {
|
||||||
|
@ -319,10 +320,39 @@ static void main_nix_build(int argc, char * * argv)
|
||||||
Value vRoot;
|
Value vRoot;
|
||||||
state->eval(e, vRoot);
|
state->eval(e, vRoot);
|
||||||
|
|
||||||
|
std::function<bool(const Value & v)> takesNixShellAttr;
|
||||||
|
takesNixShellAttr = [&](const Value & v) {
|
||||||
|
if (!runEnv) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool add = false;
|
||||||
|
if (v.type() == nFunction && v.lambda.fun->hasFormals()) {
|
||||||
|
for (auto & i : v.lambda.fun->formals->formals) {
|
||||||
|
if (state->symbols[i.name] == "inNixShell") {
|
||||||
|
add = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return add;
|
||||||
|
};
|
||||||
|
|
||||||
for (auto & i : attrPaths) {
|
for (auto & i : attrPaths) {
|
||||||
Value & v(*findAlongAttrPath(*state, i, *autoArgs, vRoot).first);
|
Value & v(*findAlongAttrPath(
|
||||||
|
*state,
|
||||||
|
i,
|
||||||
|
takesNixShellAttr(vRoot) ? *autoArgsWithInNixShell : *autoArgs,
|
||||||
|
vRoot
|
||||||
|
).first);
|
||||||
state->forceValue(v, [&]() { return v.determinePos(noPos); });
|
state->forceValue(v, [&]() { return v.determinePos(noPos); });
|
||||||
getDerivations(*state, v, "", *autoArgs, drvs, false);
|
getDerivations(
|
||||||
|
*state,
|
||||||
|
v,
|
||||||
|
"",
|
||||||
|
takesNixShellAttr(v) ? *autoArgsWithInNixShell : *autoArgs,
|
||||||
|
drvs,
|
||||||
|
false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -276,15 +276,25 @@ struct Common : InstallableCommand, MixProfile
|
||||||
const BuildEnvironment & buildEnvironment,
|
const BuildEnvironment & buildEnvironment,
|
||||||
const Path & outputsDir = absPath(".") + "/outputs")
|
const Path & outputsDir = absPath(".") + "/outputs")
|
||||||
{
|
{
|
||||||
|
// A list of colon-separated environment variables that should be
|
||||||
|
// prepended to, rather than overwritten, in order to keep the shell usable.
|
||||||
|
// Please keep this list minimal in order to avoid impurities.
|
||||||
|
static const char * const savedVars[] = {
|
||||||
|
"PATH", // for commands
|
||||||
|
"XDG_DATA_DIRS", // for loadable completion
|
||||||
|
};
|
||||||
|
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
|
|
||||||
out << "unset shellHook\n";
|
out << "unset shellHook\n";
|
||||||
|
|
||||||
out << "nix_saved_PATH=\"$PATH\"\n";
|
for (auto & var : savedVars)
|
||||||
|
out << fmt("nix_saved_%s=\"$%s\"\n", var, var);
|
||||||
|
|
||||||
buildEnvironment.toBash(out, ignoreVars);
|
buildEnvironment.toBash(out, ignoreVars);
|
||||||
|
|
||||||
out << "PATH=\"$PATH:$nix_saved_PATH\"\n";
|
for (auto & var : savedVars)
|
||||||
|
out << fmt("%s=\"$%s:$nix_saved_%s\"\n", var, var, var);
|
||||||
|
|
||||||
out << "export NIX_BUILD_TOP=\"$(mktemp -d -t nix-shell.XXXXXX)\"\n";
|
out << "export NIX_BUILD_TOP=\"$(mktemp -d -t nix-shell.XXXXXX)\"\n";
|
||||||
for (auto & i : {"TMP", "TMPDIR", "TEMP", "TEMPDIR"})
|
for (auto & i : {"TMP", "TMPDIR", "TEMP", "TEMPDIR"})
|
||||||
|
|
|
@ -50,9 +50,9 @@ public:
|
||||||
return flake::lockFlake(*getEvalState(), getFlakeRef(), lockFlags);
|
return flake::lockFlake(*getEvalState(), getFlakeRef(), lockFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<FlakeRef> getFlakeRefForCompletion() override
|
std::vector<std::string> getFlakesForCompletion() override
|
||||||
{
|
{
|
||||||
return getFlakeRef();
|
return {flakeUrl};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -731,7 +731,8 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand
|
||||||
PathSet context;
|
PathSet context;
|
||||||
auto templateDir = evalState->coerceToPath(noPos, templateDirAttr, context);
|
auto templateDir = evalState->coerceToPath(noPos, templateDirAttr, context);
|
||||||
|
|
||||||
std::vector<CanonPath> files;
|
std::vector<CanonPath> changedFiles;
|
||||||
|
std::vector<CanonPath> conflictedFiles;
|
||||||
|
|
||||||
std::function<void(const SourcePath & from, const CanonPath & to)> copyDir;
|
std::function<void(const SourcePath & from, const CanonPath & to)> copyDir;
|
||||||
copyDir = [&](const SourcePath & from, const CanonPath & to)
|
copyDir = [&](const SourcePath & from, const CanonPath & to)
|
||||||
|
@ -748,31 +749,41 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand
|
||||||
auto contents = from2.readFile();
|
auto contents = from2.readFile();
|
||||||
if (pathExists(to2.abs())) {
|
if (pathExists(to2.abs())) {
|
||||||
auto contents2 = readFile(to2.abs());
|
auto contents2 = readFile(to2.abs());
|
||||||
if (contents != contents2)
|
if (contents != contents2) {
|
||||||
throw Error("refusing to overwrite existing file '%s'", to2);
|
printError("refusing to overwrite existing file '%s'\nplease merge it manually with '%s'", to2, from2);
|
||||||
|
conflictedFiles.push_back(to2);
|
||||||
|
} else {
|
||||||
|
notice("skipping identical file: %s", from2);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
} else
|
} else
|
||||||
writeFile(to2.abs(), contents);
|
writeFile(to2.abs(), contents);
|
||||||
}
|
}
|
||||||
else if (st.type == InputAccessor::tSymlink) {
|
else if (st.type == InputAccessor::tSymlink) {
|
||||||
auto target = from2.readLink();
|
auto target = from2.readLink();
|
||||||
if (pathExists(to2.abs())) {
|
if (pathExists(to2.abs())) {
|
||||||
if (readLink(to2.abs()) != target)
|
if (readLink(to2.abs()) != target) {
|
||||||
throw Error("refusing to overwrite existing symlink '%s'", to2);
|
printError("refusing to overwrite existing file '%s'\n please merge it manually with '%s'", to2, from2);
|
||||||
|
conflictedFiles.push_back(to2);
|
||||||
|
} else {
|
||||||
|
notice("skipping identical file: %s", from2);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
} else
|
} else
|
||||||
createSymlink(target, to2.abs());
|
createSymlink(target, to2.abs());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw Error("file '%s' has unsupported type", from2);
|
throw Error("file '%s' has unsupported type", from2);
|
||||||
files.push_back(to2);
|
changedFiles.push_back(to2);
|
||||||
notice("wrote: %s", to2);
|
notice("wrote: %s", to2);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
copyDir(templateDir, CanonPath(flakeDir));
|
copyDir(templateDir, CanonPath(flakeDir));
|
||||||
|
|
||||||
if (pathExists(flakeDir + "/.git")) {
|
if (!changedFiles.empty() && pathExists(flakeDir + "/.git")) {
|
||||||
Strings args = { "-C", flakeDir, "add", "--intent-to-add", "--force", "--" };
|
Strings args = { "-C", flakeDir, "add", "--intent-to-add", "--force", "--" };
|
||||||
for (auto & s : files) args.push_back(s.abs());
|
for (auto & s : changedFiles) args.push_back(s.abs());
|
||||||
runProgram("git", true, args);
|
runProgram("git", true, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -780,6 +791,9 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand
|
||||||
notice("\n");
|
notice("\n");
|
||||||
notice(renderMarkdownToTerminal(welcomeText->getString()));
|
notice(renderMarkdownToTerminal(welcomeText->getString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!conflictedFiles.empty())
|
||||||
|
throw Error("encountered %d conflicts - see above", conflictedFiles.size());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -344,7 +344,10 @@ void mainWrapped(int argc, char * * argv)
|
||||||
if (!completions) throw;
|
if (!completions) throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (completions) return;
|
if (completions) {
|
||||||
|
args.completionHook();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (args.showVersion) {
|
if (args.showVersion) {
|
||||||
printVersion(programName);
|
printVersion(programName);
|
||||||
|
|
|
@ -24,10 +24,34 @@ R""(
|
||||||
* Interact with Nixpkgs in the REPL:
|
* Interact with Nixpkgs in the REPL:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix repl '<nixpkgs>'
|
# nix repl --file example.nix
|
||||||
|
Loading Installable ''...
|
||||||
|
Added 3 variables.
|
||||||
|
|
||||||
Loading '<nixpkgs>'...
|
# nix repl --expr '{a={b=3;c=4;};}'
|
||||||
Added 12428 variables.
|
Loading Installable ''...
|
||||||
|
Added 1 variables.
|
||||||
|
|
||||||
|
# nix repl --expr '{a={b=3;c=4;};}' a
|
||||||
|
Loading Installable ''...
|
||||||
|
Added 1 variables.
|
||||||
|
|
||||||
|
# nix repl --extra_experimental_features 'flakes repl-flake' nixpkgs
|
||||||
|
Loading Installable 'flake:nixpkgs#'...
|
||||||
|
Added 5 variables.
|
||||||
|
|
||||||
|
nix-repl> legacyPackages.x86_64-linux.emacs.name
|
||||||
|
"emacs-27.1"
|
||||||
|
|
||||||
|
nix-repl> legacyPackages.x86_64-linux.emacs.name
|
||||||
|
"emacs-27.1"
|
||||||
|
|
||||||
|
nix-repl> :q
|
||||||
|
|
||||||
|
# nix repl --expr 'import <nixpkgs>{}'
|
||||||
|
|
||||||
|
Loading Installable ''...
|
||||||
|
Added 12439 variables.
|
||||||
|
|
||||||
nix-repl> emacs.name
|
nix-repl> emacs.name
|
||||||
"emacs-27.1"
|
"emacs-27.1"
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{ ... }@args: import ./shell.nix (args // { contentAddressed = true; })
|
{ inNixShell ? false, ... }@args: import ./shell.nix (args // { contentAddressed = true; })
|
||||||
|
|
|
@ -410,8 +410,10 @@ cat > $templatesDir/trivial/flake.nix <<EOF
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
echo a > $templatesDir/trivial/a
|
||||||
|
echo b > $templatesDir/trivial/b
|
||||||
|
|
||||||
git -C $templatesDir add flake.nix trivial/flake.nix
|
git -C $templatesDir add flake.nix trivial/
|
||||||
git -C $templatesDir commit -m 'Initial'
|
git -C $templatesDir commit -m 'Initial'
|
||||||
|
|
||||||
nix flake check templates
|
nix flake check templates
|
||||||
|
@ -426,6 +428,18 @@ nix flake show $flake7Dir
|
||||||
nix flake show $flake7Dir --json | jq
|
nix flake show $flake7Dir --json | jq
|
||||||
git -C $flake7Dir commit -a -m 'Initial'
|
git -C $flake7Dir commit -a -m 'Initial'
|
||||||
|
|
||||||
|
# Test 'nix flake init' with benign conflicts
|
||||||
|
rm -rf $flake7Dir && mkdir $flake7Dir && git -C $flake7Dir init
|
||||||
|
echo a > $flake7Dir/a
|
||||||
|
(cd $flake7Dir && nix flake init) # check idempotence
|
||||||
|
|
||||||
|
# Test 'nix flake init' with conflicts
|
||||||
|
rm -rf $flake7Dir && mkdir $flake7Dir && git -C $flake7Dir init
|
||||||
|
echo b > $flake7Dir/a
|
||||||
|
pushd $flake7Dir
|
||||||
|
(! nix flake init) |& grep "refusing to overwrite existing file '$flake7Dir/a'"
|
||||||
|
popd
|
||||||
|
|
||||||
# Test 'nix flake new'.
|
# Test 'nix flake new'.
|
||||||
rm -rf $flake6Dir
|
rm -rf $flake6Dir
|
||||||
nix flake new -t templates#trivial $flake6Dir
|
nix flake new -t templates#trivial $flake6Dir
|
||||||
|
@ -793,6 +807,8 @@ nix flake metadata $flakeFollowsA
|
||||||
|
|
||||||
nix flake update $flakeFollowsA
|
nix flake update $flakeFollowsA
|
||||||
|
|
||||||
|
nix flake lock $flakeFollowsA
|
||||||
|
|
||||||
oldLock="$(cat "$flakeFollowsA/flake.lock")"
|
oldLock="$(cat "$flakeFollowsA/flake.lock")"
|
||||||
|
|
||||||
# Ensure that locking twice doesn't change anything
|
# Ensure that locking twice doesn't change anything
|
||||||
|
@ -815,7 +831,6 @@ cat > $flakeFollowsA/flake.nix <<EOF
|
||||||
inputs = {
|
inputs = {
|
||||||
B = {
|
B = {
|
||||||
url = "path:./flakeB";
|
url = "path:./flakeB";
|
||||||
inputs.nonFlake.follows = "D";
|
|
||||||
};
|
};
|
||||||
D.url = "path:./flakeD";
|
D.url = "path:./flakeD";
|
||||||
};
|
};
|
||||||
|
@ -851,3 +866,21 @@ nix store delete $(nix store add-path $badFlakeDir)
|
||||||
|
|
||||||
[[ $(nix path-info $(nix store add-path $flake1Dir)) =~ flake1 ]]
|
[[ $(nix path-info $(nix store add-path $flake1Dir)) =~ flake1 ]]
|
||||||
[[ $(nix path-info path:$(nix store add-path $flake1Dir)) =~ simple ]]
|
[[ $(nix path-info path:$(nix store add-path $flake1Dir)) =~ simple ]]
|
||||||
|
|
||||||
|
# Non-existant follows causes an error
|
||||||
|
|
||||||
|
cat >$flakeFollowsA/flake.nix <<EOF
|
||||||
|
{
|
||||||
|
description = "Flake A";
|
||||||
|
inputs.B = {
|
||||||
|
url = "path:./flakeB";
|
||||||
|
inputs.invalid.follows = "D";
|
||||||
|
};
|
||||||
|
inputs.D.url = "path:./flakeD";
|
||||||
|
outputs = { ... }: {};
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
git -C $flakeFollowsA add flake.nix
|
||||||
|
|
||||||
|
nix flake lock $flakeFollowsA 2>&1 | grep "warning: B has a \`follows'-declaration for a non-existant input invalid!"
|
||||||
|
|
|
@ -5,6 +5,8 @@ export NIX_REMOTE=dummy://
|
||||||
|
|
||||||
nix-instantiate --eval -E 'builtins.trace "Hello" 123' 2>&1 | grep -q Hello
|
nix-instantiate --eval -E 'builtins.trace "Hello" 123' 2>&1 | grep -q Hello
|
||||||
nix-instantiate --eval -E 'builtins.addErrorContext "Hello" 123' 2>&1
|
nix-instantiate --eval -E 'builtins.addErrorContext "Hello" 123' 2>&1
|
||||||
|
nix-instantiate --trace-verbose --eval -E 'builtins.traceVerbose "Hello" 123' 2>&1 | grep -q Hello
|
||||||
|
(! nix-instantiate --eval -E 'builtins.traceVerbose "Hello" 123' 2>&1 | grep -q Hello)
|
||||||
(! nix-instantiate --show-trace --eval -E 'builtins.addErrorContext "Hello" 123' 2>&1 | grep -q Hello)
|
(! nix-instantiate --show-trace --eval -E 'builtins.addErrorContext "Hello" 123' 2>&1 | grep -q Hello)
|
||||||
nix-instantiate --show-trace --eval -E 'builtins.addErrorContext "Hello" (throw "Foo")' 2>&1 | grep -q Hello
|
nix-instantiate --show-trace --eval -E 'builtins.addErrorContext "Hello" (throw "Foo")' 2>&1 | grep -q Hello
|
||||||
|
|
||||||
|
|
|
@ -102,3 +102,11 @@ source <(nix print-dev-env -f "$shellDotNix" shellDrv)
|
||||||
[[ ${arr2[1]} = $'\n' ]]
|
[[ ${arr2[1]} = $'\n' ]]
|
||||||
[[ ${arr2[2]} = $'x\ny' ]]
|
[[ ${arr2[2]} = $'x\ny' ]]
|
||||||
[[ $(fun) = blabla ]]
|
[[ $(fun) = blabla ]]
|
||||||
|
|
||||||
|
# Test nix-shell with ellipsis and no `inNixShell` argument (for backwards compat with old nixpkgs)
|
||||||
|
cat >$TEST_ROOT/shell-ellipsis.nix <<EOF
|
||||||
|
{ system ? "x86_64-linux", ... }@args:
|
||||||
|
assert (!(args ? inNixShell));
|
||||||
|
(import $shellDotNix { }).shellDrv
|
||||||
|
EOF
|
||||||
|
nix-shell $TEST_ROOT/shell-ellipsis.nix --run "true"
|
||||||
|
|
|
@ -55,15 +55,17 @@ testRepl
|
||||||
testRepl --store "$TEST_ROOT/store?real=$NIX_STORE_DIR"
|
testRepl --store "$TEST_ROOT/store?real=$NIX_STORE_DIR"
|
||||||
|
|
||||||
testReplResponse () {
|
testReplResponse () {
|
||||||
local response="$(nix repl <<< "$1")"
|
local commands="$1"; shift
|
||||||
echo "$response" | grep -qs "$2" \
|
local expectedResponse="$1"; shift
|
||||||
|
local response="$(nix repl "$@" <<< "$commands")"
|
||||||
|
echo "$response" | grep -qs "$expectedResponse" \
|
||||||
|| fail "repl command set:
|
|| fail "repl command set:
|
||||||
|
|
||||||
$1
|
$commands
|
||||||
|
|
||||||
does not respond with:
|
does not respond with:
|
||||||
|
|
||||||
$2
|
$expectedResponse
|
||||||
|
|
||||||
but with:
|
but with:
|
||||||
|
|
||||||
|
@ -76,3 +78,48 @@ testReplResponse '
|
||||||
:a { a = "2"; }
|
:a { a = "2"; }
|
||||||
"result: ${a}"
|
"result: ${a}"
|
||||||
' "result: 2"
|
' "result: 2"
|
||||||
|
|
||||||
|
testReplResponse '
|
||||||
|
drvPath
|
||||||
|
' '".*-simple.drv"' \
|
||||||
|
$testDir/simple.nix
|
||||||
|
|
||||||
|
testReplResponse '
|
||||||
|
drvPath
|
||||||
|
' '".*-simple.drv"' \
|
||||||
|
--file $testDir/simple.nix --experimental-features 'ca-derivations'
|
||||||
|
|
||||||
|
testReplResponse '
|
||||||
|
drvPath
|
||||||
|
' '".*-simple.drv"' \
|
||||||
|
--file $testDir/simple.nix --extra-experimental-features 'repl-flake ca-derivations'
|
||||||
|
|
||||||
|
mkdir -p flake && cat <<EOF > flake/flake.nix
|
||||||
|
{
|
||||||
|
outputs = { self }: {
|
||||||
|
foo = 1;
|
||||||
|
bar.baz = 2;
|
||||||
|
|
||||||
|
changingThing = "beforeChange";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
testReplResponse '
|
||||||
|
foo + baz
|
||||||
|
' "3" \
|
||||||
|
./flake ./flake\#bar --experimental-features 'flakes repl-flake'
|
||||||
|
|
||||||
|
# Test the `:reload` mechansim with flakes:
|
||||||
|
# - Eval `./flake#changingThing`
|
||||||
|
# - Modify the flake
|
||||||
|
# - Re-eval it
|
||||||
|
# - Check that the result has changed
|
||||||
|
replResult=$( (
|
||||||
|
echo "changingThing"
|
||||||
|
sleep 1 # Leave the repl the time to eval 'foo'
|
||||||
|
sed -i 's/beforeChange/afterChange/' flake/flake.nix
|
||||||
|
echo ":reload"
|
||||||
|
echo "changingThing"
|
||||||
|
) | nix repl ./flake --experimental-features 'flakes repl-flake')
|
||||||
|
echo "$replResult" | grep -qs beforeChange
|
||||||
|
echo "$replResult" | grep -qs afterChange
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue