mirror of
https://github.com/NixOS/nix
synced 2025-06-29 06:21:14 +02:00
Merge remote-tracking branch 'origin/master' into lazy-trees
This commit is contained in:
commit
5d1e5a09d1
36 changed files with 1150 additions and 740 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -103,6 +103,7 @@ outputs/
|
||||||
|
|
||||||
*.a
|
*.a
|
||||||
*.o
|
*.o
|
||||||
|
*.o.tmp
|
||||||
*.so
|
*.so
|
||||||
*.dylib
|
*.dylib
|
||||||
*.dll
|
*.dll
|
||||||
|
|
|
@ -20,8 +20,8 @@ Information on additional installation methods is available on the [Nix download
|
||||||
|
|
||||||
## Building And Developing
|
## Building And Developing
|
||||||
|
|
||||||
See our [Hacking guide](https://nixos.org/manual/nix/stable/contributing/hacking.html) in our manual for instruction on how to
|
See our [Hacking guide](https://nixos.org/manual/nix/unstable/contributing/hacking.html) in our manual for instruction on how to
|
||||||
build nix from source with nix-build or how to get a development environment.
|
to set up a development environment and build Nix from source.
|
||||||
|
|
||||||
## Additional Resources
|
## Additional Resources
|
||||||
|
|
||||||
|
|
|
@ -8,25 +8,64 @@ $ git clone https://github.com/NixOS/nix.git
|
||||||
$ cd nix
|
$ cd nix
|
||||||
```
|
```
|
||||||
|
|
||||||
To build Nix for the current operating system/architecture use
|
The following instructions assume you already have some version of Nix installed locally, so that you can use it to set up the development environment. If you don't have it installed, follow the [installation instructions].
|
||||||
|
|
||||||
|
[installation instructions]: ../installation/installation.md
|
||||||
|
|
||||||
|
## Nix with flakes
|
||||||
|
|
||||||
|
This section assumes you are using Nix with [flakes] enabled. See the [next section](#classic-nix) for equivalent instructions which don't require flakes.
|
||||||
|
|
||||||
|
[flakes]: ../command-ref/new-cli/nix3-flake.md#description
|
||||||
|
|
||||||
|
To build all dependencies and start a shell in which all environment
|
||||||
|
variables are set up so that those dependencies can be found:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build
|
$ nix develop
|
||||||
```
|
```
|
||||||
|
|
||||||
or if you have a flake-enabled nix:
|
This shell also adds `./outputs/bin/nix` to your `$PATH` so you can run `nix` immediately after building it.
|
||||||
|
|
||||||
|
To get a shell with one of the other [supported compilation environments](#compilation-environments):
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ nix develop .#native-clang11StdenvPackages
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Note**
|
||||||
|
>
|
||||||
|
> Use `ccacheStdenv` to drastically improve rebuild time.
|
||||||
|
> By default, [ccache](https://ccache.dev) keeps artifacts in `~/.cache/ccache/`.
|
||||||
|
|
||||||
|
To build Nix itself in this shell:
|
||||||
|
|
||||||
|
```console
|
||||||
|
[nix-shell]$ ./bootstrap.sh
|
||||||
|
[nix-shell]$ ./configure $configureFlags --prefix=$(pwd)/outputs/out
|
||||||
|
[nix-shell]$ make -j $NIX_BUILD_CORES
|
||||||
|
```
|
||||||
|
|
||||||
|
To install it in `$(pwd)/outputs` and test it:
|
||||||
|
|
||||||
|
```console
|
||||||
|
[nix-shell]$ make install
|
||||||
|
[nix-shell]$ make installcheck -j $NIX_BUILD_CORES
|
||||||
|
[nix-shell]$ nix --version
|
||||||
|
nix (Nix) 2.12
|
||||||
|
```
|
||||||
|
|
||||||
|
To build a release version of Nix:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix build
|
$ nix build
|
||||||
```
|
```
|
||||||
|
|
||||||
This will build `defaultPackage` attribute defined in the `flake.nix`
|
You can also build Nix for one of the [supported target platforms](#target-platforms).
|
||||||
file. To build for other platforms add one of the following suffixes to
|
|
||||||
it: aarch64-linux, i686-linux, x86\_64-darwin, x86\_64-linux. i.e.
|
|
||||||
|
|
||||||
```console
|
## Classic Nix
|
||||||
$ nix-build -A defaultPackage.x86_64-linux
|
|
||||||
```
|
This section is for Nix without [flakes].
|
||||||
|
|
||||||
To build all dependencies and start a shell in which all environment
|
To build all dependencies and start a shell in which all environment
|
||||||
variables are set up so that those dependencies can be found:
|
variables are set up so that those dependencies can be found:
|
||||||
|
@ -35,27 +74,16 @@ variables are set up so that those dependencies can be found:
|
||||||
$ nix-shell
|
$ nix-shell
|
||||||
```
|
```
|
||||||
|
|
||||||
or if you have a flake-enabled nix:
|
To get a shell with one of the other [supported compilation environments](#compilation-environments):
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix develop
|
$ nix-shell -A devShells.x86_64-linux.native-clang11StdenvPackages
|
||||||
```
|
```
|
||||||
|
|
||||||
To get a shell with a different compilation environment (e.g. stdenv,
|
> **Note**
|
||||||
gccStdenv, clangStdenv, clang11Stdenv, ccacheStdenv):
|
>
|
||||||
|
> You can use `native-ccacheStdenvPackages` to drastically improve rebuild time.
|
||||||
```console
|
> By default, [ccache](https://ccache.dev) keeps artifacts in `~/.cache/ccache/`.
|
||||||
$ nix-shell -A devShells.x86_64-linux.clang11Stdenv
|
|
||||||
```
|
|
||||||
|
|
||||||
or if you have a flake-enabled nix:
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ nix develop .#clang11Stdenv
|
|
||||||
```
|
|
||||||
|
|
||||||
Note: you can use `ccacheStdenv` to drastically improve rebuild
|
|
||||||
time. By default, ccache keeps artifacts in `~/.cache/ccache/`.
|
|
||||||
|
|
||||||
To build Nix itself in this shell:
|
To build Nix itself in this shell:
|
||||||
|
|
||||||
|
@ -71,21 +99,99 @@ To install it in `$(pwd)/outputs` and test it:
|
||||||
[nix-shell]$ make install
|
[nix-shell]$ make install
|
||||||
[nix-shell]$ make installcheck -j $NIX_BUILD_CORES
|
[nix-shell]$ make installcheck -j $NIX_BUILD_CORES
|
||||||
[nix-shell]$ ./outputs/out/bin/nix --version
|
[nix-shell]$ ./outputs/out/bin/nix --version
|
||||||
nix (Nix) 3.0
|
nix (Nix) 2.12
|
||||||
```
|
```
|
||||||
|
|
||||||
If you have a flakes-enabled Nix you can replace:
|
To build Nix for the current operating system and CPU architecture use
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-shell
|
$ nix-build
|
||||||
```
|
```
|
||||||
|
|
||||||
by:
|
You can also build Nix for one of the [supported target platforms](#target-platforms).
|
||||||
|
|
||||||
|
## Platforms
|
||||||
|
|
||||||
|
As specified in [`flake.nix`], Nix can be built for various platforms:
|
||||||
|
|
||||||
|
- `aarch64-linux`
|
||||||
|
- `i686-linux`
|
||||||
|
- `x86_64-darwin`
|
||||||
|
- `x86_64-linux`
|
||||||
|
|
||||||
|
[`flake.nix`]: https://github.com/nixos/nix/blob/master/flake.nix
|
||||||
|
|
||||||
|
In order to build Nix for a different platform than the one you're currently
|
||||||
|
on, you need to have some way for your system Nix to build code for that
|
||||||
|
platform. Common solutions include [remote builders] and [binfmt emulation]
|
||||||
|
(only supported on NixOS).
|
||||||
|
|
||||||
|
[remote builders]: ../advanced-topics/distributed-builds.md
|
||||||
|
[binfmt emulation]: https://nixos.org/manual/nixos/stable/options.html#opt-boot.binfmt.emulatedSystems
|
||||||
|
|
||||||
|
These solutions let Nix perform builds as if you're on the native platform, so
|
||||||
|
executing the build is as simple as
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix develop
|
$ nix build .#packages.aarch64-linux.default
|
||||||
```
|
```
|
||||||
|
|
||||||
|
for flake-enabled Nix, or
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ nix-build -A packages.aarch64-linux.default
|
||||||
|
```
|
||||||
|
|
||||||
|
for classic Nix.
|
||||||
|
|
||||||
|
You can use any of the other supported platforms in place of `aarch64-linux`.
|
||||||
|
|
||||||
|
Cross-compiled builds are available for ARMv6 and ARMv7, and Nix on unsupported platforms can be bootstrapped by adding more `crossSystems` in `flake.nix`.
|
||||||
|
|
||||||
|
## Compilation environments
|
||||||
|
|
||||||
|
Nix can be compiled using multiple environments:
|
||||||
|
|
||||||
|
- `stdenv`: default;
|
||||||
|
- `gccStdenv`: force the use of `gcc` compiler;
|
||||||
|
- `clangStdenv`: force the use of `clang` compiler;
|
||||||
|
- `ccacheStdenv`: enable [ccache], a compiler cache to speed up compilation.
|
||||||
|
|
||||||
|
To build with one of those environments, you can use
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ nix build .#nix-ccacheStdenv
|
||||||
|
```
|
||||||
|
|
||||||
|
for flake-enabled Nix, or
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ nix-build -A nix-ccacheStdenv
|
||||||
|
```
|
||||||
|
|
||||||
|
for classic Nix.
|
||||||
|
|
||||||
|
You can use any of the other supported environments in place of `nix-ccacheStdenv`.
|
||||||
|
|
||||||
|
## Editor integration
|
||||||
|
|
||||||
|
The `clangd` LSP server is installed by default on the `clang`-based `devShell`s.
|
||||||
|
See [supported compilation environments](#compilation-environments) and instructions how to set up a shell [with flakes](#nix-with-flakes) or in [classic Nix](#classic-nix).
|
||||||
|
|
||||||
|
To use the LSP with your editor, you first need to [set up `clangd`](https://clangd.llvm.org/installation#project-setup) by running:
|
||||||
|
|
||||||
|
```console
|
||||||
|
make clean && bear -- make -j$NIX_BUILD_CORES install
|
||||||
|
```
|
||||||
|
|
||||||
|
Configure your editor to use the `clangd` from the shell, either by running it inside the development shell, or by using [nix-direnv](https://github.com/nix-community/nix-direnv) and [the appropriate editor plugin](https://github.com/direnv/direnv/wiki#editor-integration).
|
||||||
|
|
||||||
|
> **Note**
|
||||||
|
>
|
||||||
|
> For some editors (e.g. Visual Studio Code), you may need to install a [special extension](https://open-vsx.org/extension/llvm-vs-code-extensions/vscode-clangd) for the editor to interact with `clangd`.
|
||||||
|
> Some other editors (e.g. Emacs, Vim) need a plugin to support LSP servers in general (e.g. [lsp-mode](https://github.com/emacs-lsp/lsp-mode) for Emacs and [vim-lsp](https://github.com/prabirshrestha/vim-lsp) for vim).
|
||||||
|
> Editor-specific setup is typically opinionated, so we will not cover it here in more detail.
|
||||||
|
|
||||||
## Running tests
|
## Running tests
|
||||||
|
|
||||||
### Unit-tests
|
### Unit-tests
|
||||||
|
|
287
flake.nix
287
flake.nix
|
@ -8,10 +8,11 @@
|
||||||
outputs = { self, nixpkgs, nixpkgs-regression, lowdown-src }:
|
outputs = { self, nixpkgs, nixpkgs-regression, lowdown-src }:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
inherit (nixpkgs) lib;
|
||||||
|
|
||||||
officialRelease = false;
|
officialRelease = false;
|
||||||
|
|
||||||
version = nixpkgs.lib.fileContents ./.version + versionSuffix;
|
version = lib.fileContents ./.version + versionSuffix;
|
||||||
versionSuffix =
|
versionSuffix =
|
||||||
if officialRelease
|
if officialRelease
|
||||||
then ""
|
then ""
|
||||||
|
@ -25,34 +26,36 @@
|
||||||
|
|
||||||
stdenvs = [ "gccStdenv" "clangStdenv" "clang11Stdenv" "stdenv" "libcxxStdenv" "ccacheStdenv" ];
|
stdenvs = [ "gccStdenv" "clangStdenv" "clang11Stdenv" "stdenv" "libcxxStdenv" "ccacheStdenv" ];
|
||||||
|
|
||||||
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f system);
|
forAllSystems = lib.genAttrs systems;
|
||||||
forAllSystemsAndStdenvs = f: forAllSystems (system:
|
|
||||||
nixpkgs.lib.listToAttrs
|
forAllCrossSystems = lib.genAttrs crossSystems;
|
||||||
(map
|
|
||||||
(n:
|
forAllStdenvs = f:
|
||||||
nixpkgs.lib.nameValuePair "${n}Packages" (
|
lib.listToAttrs
|
||||||
f system n
|
(map
|
||||||
)) stdenvs
|
(stdenvName: {
|
||||||
)
|
name = "${stdenvName}Packages";
|
||||||
);
|
value = f stdenvName;
|
||||||
|
})
|
||||||
|
stdenvs);
|
||||||
|
|
||||||
forAllStdenvs = f: nixpkgs.lib.genAttrs stdenvs (stdenv: f stdenv);
|
|
||||||
|
|
||||||
# Memoize nixpkgs for different platforms for efficiency.
|
# Memoize nixpkgs for different platforms for efficiency.
|
||||||
nixpkgsFor =
|
nixpkgsFor = forAllSystems
|
||||||
let stdenvsPackages = forAllSystemsAndStdenvs
|
(system: let
|
||||||
(system: stdenv:
|
make-pkgs = crossSystem: stdenv: import nixpkgs {
|
||||||
import nixpkgs {
|
inherit system crossSystem;
|
||||||
inherit system;
|
overlays = [
|
||||||
overlays = [
|
(overlayFor (p: p.${stdenv}))
|
||||||
(overlayFor (p: p.${stdenv}))
|
];
|
||||||
];
|
};
|
||||||
}
|
stdenvs = forAllStdenvs (make-pkgs null);
|
||||||
);
|
native = stdenvs.stdenvPackages;
|
||||||
in
|
in {
|
||||||
# Add the `stdenvPackages` at toplevel, both because these are the ones
|
inherit stdenvs native;
|
||||||
# we want most of the time and for backwards compatibility
|
static = native.pkgsStatic;
|
||||||
forAllSystems (system: stdenvsPackages.${system} // stdenvsPackages.${system}.stdenvPackages);
|
cross = forAllCrossSystems (crossSystem: make-pkgs crossSystem "stdenv");
|
||||||
|
});
|
||||||
|
|
||||||
commonDeps = { pkgs, isStatic ? false }: with pkgs; rec {
|
commonDeps = { pkgs, isStatic ? false }: with pkgs; rec {
|
||||||
# Use "busybox-sandbox-shell" if present,
|
# Use "busybox-sandbox-shell" if present,
|
||||||
|
@ -145,7 +148,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
installScriptFor = systems:
|
installScriptFor = systems:
|
||||||
with nixpkgsFor.x86_64-linux;
|
with nixpkgsFor.x86_64-linux.native;
|
||||||
runCommand "installer-script"
|
runCommand "installer-script"
|
||||||
{ buildInputs = [ nix ];
|
{ buildInputs = [ nix ];
|
||||||
}
|
}
|
||||||
|
@ -209,8 +212,9 @@
|
||||||
installCheckPhase = "make installcheck -j$NIX_BUILD_CORES -l$NIX_BUILD_CORES";
|
installCheckPhase = "make installcheck -j$NIX_BUILD_CORES -l$NIX_BUILD_CORES";
|
||||||
};
|
};
|
||||||
|
|
||||||
binaryTarball = buildPackages: nix: pkgs:
|
binaryTarball = nix: pkgs:
|
||||||
let
|
let
|
||||||
|
inherit (pkgs) buildPackages;
|
||||||
inherit (pkgs) cacert;
|
inherit (pkgs) cacert;
|
||||||
installerClosureInfo = buildPackages.closureInfo { rootPaths = [ nix cacert ]; };
|
installerClosureInfo = buildPackages.closureInfo { rootPaths = [ nix cacert ]; };
|
||||||
in
|
in
|
||||||
|
@ -290,7 +294,9 @@
|
||||||
# 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 { inherit pkgs; }; currentStdenv.mkDerivation {
|
nix = with final; with commonDeps { inherit pkgs; }; let
|
||||||
|
canRunInstalled = currentStdenv.buildPlatform.canExecute currentStdenv.hostPlatform;
|
||||||
|
in currentStdenv.mkDerivation {
|
||||||
name = "nix-${version}";
|
name = "nix-${version}";
|
||||||
inherit version;
|
inherit version;
|
||||||
|
|
||||||
|
@ -301,24 +307,26 @@
|
||||||
outputs = [ "out" "dev" "doc" ];
|
outputs = [ "out" "dev" "doc" ];
|
||||||
|
|
||||||
nativeBuildInputs = nativeBuildDeps;
|
nativeBuildInputs = nativeBuildDeps;
|
||||||
buildInputs = buildDeps ++ awsDeps;
|
buildInputs = buildDeps
|
||||||
|
# There have been issues building these dependencies
|
||||||
|
++ lib.optionals (currentStdenv.hostPlatform == currentStdenv.buildPlatform) awsDeps;
|
||||||
|
|
||||||
propagatedBuildInputs = propagatedDeps;
|
propagatedBuildInputs = propagatedDeps;
|
||||||
|
|
||||||
disallowedReferences = [ boost ];
|
disallowedReferences = [ boost ];
|
||||||
|
|
||||||
preConfigure =
|
preConfigure = lib.optionalString (! currentStdenv.hostPlatform.isStatic)
|
||||||
''
|
''
|
||||||
# Copy libboost_context so we don't get all of Boost in our closure.
|
# Copy libboost_context so we don't get all of Boost in our closure.
|
||||||
# https://github.com/NixOS/nixpkgs/issues/45462
|
# https://github.com/NixOS/nixpkgs/issues/45462
|
||||||
mkdir -p $out/lib
|
mkdir -p $out/lib
|
||||||
cp -pd ${boost}/lib/{libboost_context*,libboost_thread*,libboost_system*} $out/lib
|
cp -pd ${boost}/lib/{libboost_context*,libboost_thread*,libboost_system*} $out/lib
|
||||||
rm -f $out/lib/*.a
|
rm -f $out/lib/*.a
|
||||||
${lib.optionalString currentStdenv.isLinux ''
|
${lib.optionalString currentStdenv.hostPlatform.isLinux ''
|
||||||
chmod u+w $out/lib/*.so.*
|
chmod u+w $out/lib/*.so.*
|
||||||
patchelf --set-rpath $out/lib:${currentStdenv.cc.cc.lib}/lib $out/lib/libboost_thread.so.*
|
patchelf --set-rpath $out/lib:${currentStdenv.cc.cc.lib}/lib $out/lib/libboost_thread.so.*
|
||||||
''}
|
''}
|
||||||
${lib.optionalString currentStdenv.isDarwin ''
|
${lib.optionalString currentStdenv.hostPlatform.isDarwin ''
|
||||||
for LIB in $out/lib/*.dylib; do
|
for LIB in $out/lib/*.dylib; do
|
||||||
chmod u+w $LIB
|
chmod u+w $LIB
|
||||||
install_name_tool -id $LIB $LIB
|
install_name_tool -id $LIB $LIB
|
||||||
|
@ -329,7 +337,9 @@
|
||||||
'';
|
'';
|
||||||
|
|
||||||
configureFlags = configureFlags ++
|
configureFlags = configureFlags ++
|
||||||
[ "--sysconfdir=/etc" ];
|
[ "--sysconfdir=/etc" ] ++
|
||||||
|
lib.optional stdenv.hostPlatform.isStatic "--enable-embedded-sandbox-shell" ++
|
||||||
|
lib.optional (!canRunInstalled) "--disable-doc-gen";
|
||||||
|
|
||||||
enableParallelBuilding = true;
|
enableParallelBuilding = true;
|
||||||
|
|
||||||
|
@ -357,6 +367,8 @@
|
||||||
|
|
||||||
strictDeps = true;
|
strictDeps = true;
|
||||||
|
|
||||||
|
hardeningDisable = lib.optional stdenv.hostPlatform.isStatic "pie";
|
||||||
|
|
||||||
passthru.perl-bindings = with final; perl.pkgs.toPerlModule (currentStdenv.mkDerivation {
|
passthru.perl-bindings = with final; perl.pkgs.toPerlModule (currentStdenv.mkDerivation {
|
||||||
name = "nix-perl-${version}";
|
name = "nix-perl-${version}";
|
||||||
|
|
||||||
|
@ -389,7 +401,7 @@
|
||||||
postUnpack = "sourceRoot=$sourceRoot/perl";
|
postUnpack = "sourceRoot=$sourceRoot/perl";
|
||||||
});
|
});
|
||||||
|
|
||||||
meta.platforms = systems;
|
meta.platforms = lib.platforms.unix;
|
||||||
};
|
};
|
||||||
|
|
||||||
lowdown-nix = with final; currentStdenv.mkDerivation rec {
|
lowdown-nix = with final; currentStdenv.mkDerivation rec {
|
||||||
|
@ -415,14 +427,15 @@
|
||||||
# https://nixos.org/manual/nixos/unstable/index.html#sec-calling-nixos-tests
|
# https://nixos.org/manual/nixos/unstable/index.html#sec-calling-nixos-tests
|
||||||
runNixOSTestFor = system: test: nixos-lib.runTest {
|
runNixOSTestFor = system: test: nixos-lib.runTest {
|
||||||
imports = [ test ];
|
imports = [ test ];
|
||||||
hostPkgs = nixpkgsFor.${system};
|
hostPkgs = nixpkgsFor.${system}.native;
|
||||||
defaults = {
|
defaults = {
|
||||||
nixpkgs.pkgs = nixpkgsFor.${system};
|
nixpkgs.pkgs = nixpkgsFor.${system}.native;
|
||||||
};
|
};
|
||||||
_module.args.nixpkgs = nixpkgs;
|
_module.args.nixpkgs = nixpkgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
in {
|
in {
|
||||||
|
inherit nixpkgsFor;
|
||||||
|
|
||||||
# A Nixpkgs overlay that overrides the 'nix' and
|
# A Nixpkgs overlay that overrides the 'nix' and
|
||||||
# 'nix.perl-bindings' packages.
|
# 'nix.perl-bindings' packages.
|
||||||
|
@ -431,32 +444,28 @@
|
||||||
hydraJobs = {
|
hydraJobs = {
|
||||||
|
|
||||||
# Binary package for various platforms.
|
# Binary package for various platforms.
|
||||||
build = nixpkgs.lib.genAttrs systems (system: self.packages.${system}.nix);
|
build = forAllSystems (system: self.packages.${system}.nix);
|
||||||
|
|
||||||
buildStatic = nixpkgs.lib.genAttrs linux64BitSystems (system: self.packages.${system}.nix-static);
|
buildStatic = lib.genAttrs linux64BitSystems (system: self.packages.${system}.nix-static);
|
||||||
|
|
||||||
buildCross = nixpkgs.lib.genAttrs crossSystems (crossSystem:
|
buildCross = forAllCrossSystems (crossSystem:
|
||||||
nixpkgs.lib.genAttrs ["x86_64-linux"] (system: self.packages.${system}."nix-${crossSystem}"));
|
lib.genAttrs ["x86_64-linux"] (system: self.packages.${system}."nix-${crossSystem}"));
|
||||||
|
|
||||||
buildNoGc = nixpkgs.lib.genAttrs systems (system: self.packages.${system}.nix.overrideAttrs (a: { configureFlags = (a.configureFlags or []) ++ ["--enable-gc=no"];}));
|
buildNoGc = forAllSystems (system: self.packages.${system}.nix.overrideAttrs (a: { configureFlags = (a.configureFlags or []) ++ ["--enable-gc=no"];}));
|
||||||
|
|
||||||
# Perl bindings for various platforms.
|
# Perl bindings for various platforms.
|
||||||
perlBindings = nixpkgs.lib.genAttrs systems (system: self.packages.${system}.nix.perl-bindings);
|
perlBindings = forAllSystems (system: nixpkgsFor.${system}.native.nix.perl-bindings);
|
||||||
|
|
||||||
# Binary tarball for various platforms, containing a Nix store
|
# Binary tarball for various platforms, containing a Nix store
|
||||||
# with the closure of 'nix' package, and the second half of
|
# with the closure of 'nix' package, and the second half of
|
||||||
# the installation script.
|
# the installation script.
|
||||||
binaryTarball = nixpkgs.lib.genAttrs systems (system: binaryTarball nixpkgsFor.${system} nixpkgsFor.${system}.nix nixpkgsFor.${system});
|
binaryTarball = forAllSystems (system: binaryTarball nixpkgsFor.${system}.native.nix nixpkgsFor.${system}.native);
|
||||||
|
|
||||||
binaryTarballCross = nixpkgs.lib.genAttrs ["x86_64-linux"] (system: builtins.listToAttrs (map (crossSystem: {
|
binaryTarballCross = lib.genAttrs ["x86_64-linux"] (system:
|
||||||
name = crossSystem;
|
forAllCrossSystems (crossSystem:
|
||||||
value = let
|
binaryTarball
|
||||||
nixpkgsCross = import nixpkgs {
|
self.packages.${system}."nix-${crossSystem}"
|
||||||
inherit system crossSystem;
|
nixpkgsFor.${system}.cross.${crossSystem}));
|
||||||
overlays = [ self.overlays.default ];
|
|
||||||
};
|
|
||||||
in binaryTarball nixpkgsFor.${system} self.packages.${system}."nix-${crossSystem}" nixpkgsCross;
|
|
||||||
}) crossSystems));
|
|
||||||
|
|
||||||
# The first half of the installation script. This is uploaded
|
# The first half of the installation script. This is uploaded
|
||||||
# to https://nixos.org/nix/install. It downloads the binary
|
# to https://nixos.org/nix/install. It downloads the binary
|
||||||
|
@ -466,11 +475,11 @@
|
||||||
installerScriptForGHA = installScriptFor [ "x86_64-linux" "x86_64-darwin" "armv6l-linux" "armv7l-linux"];
|
installerScriptForGHA = installScriptFor [ "x86_64-linux" "x86_64-darwin" "armv6l-linux" "armv7l-linux"];
|
||||||
|
|
||||||
# docker image with Nix inside
|
# docker image with Nix inside
|
||||||
dockerImage = nixpkgs.lib.genAttrs linux64BitSystems (system: self.packages.${system}.dockerImage);
|
dockerImage = lib.genAttrs linux64BitSystems (system: self.packages.${system}.dockerImage);
|
||||||
|
|
||||||
# Line coverage analysis.
|
# Line coverage analysis.
|
||||||
coverage =
|
coverage =
|
||||||
with nixpkgsFor.x86_64-linux;
|
with nixpkgsFor.x86_64-linux.native;
|
||||||
with commonDeps { inherit pkgs; };
|
with commonDeps { inherit pkgs; };
|
||||||
|
|
||||||
releaseTools.coverageAnalysis {
|
releaseTools.coverageAnalysis {
|
||||||
|
@ -514,7 +523,7 @@
|
||||||
|
|
||||||
tests.containers = runNixOSTestFor "x86_64-linux" ./tests/nixos/containers/containers.nix;
|
tests.containers = runNixOSTestFor "x86_64-linux" ./tests/nixos/containers/containers.nix;
|
||||||
|
|
||||||
tests.setuid = nixpkgs.lib.genAttrs
|
tests.setuid = lib.genAttrs
|
||||||
["i686-linux" "x86_64-linux"]
|
["i686-linux" "x86_64-linux"]
|
||||||
(system: runNixOSTestFor system ./tests/nixos/setuid.nix);
|
(system: runNixOSTestFor system ./tests/nixos/setuid.nix);
|
||||||
|
|
||||||
|
@ -522,7 +531,7 @@
|
||||||
# Make sure that nix-env still produces the exact same result
|
# Make sure that nix-env still produces the exact same result
|
||||||
# on a particular version of Nixpkgs.
|
# on a particular version of Nixpkgs.
|
||||||
tests.evalNixpkgs =
|
tests.evalNixpkgs =
|
||||||
with nixpkgsFor.x86_64-linux;
|
with nixpkgsFor.x86_64-linux.native;
|
||||||
runCommand "eval-nixos" { buildInputs = [ nix ]; }
|
runCommand "eval-nixos" { buildInputs = [ nix ]; }
|
||||||
''
|
''
|
||||||
type -p nix-env
|
type -p nix-env
|
||||||
|
@ -533,18 +542,18 @@
|
||||||
'';
|
'';
|
||||||
|
|
||||||
tests.nixpkgsLibTests =
|
tests.nixpkgsLibTests =
|
||||||
nixpkgs.lib.genAttrs systems (system:
|
forAllSystems (system:
|
||||||
import (nixpkgs + "/lib/tests/release.nix")
|
import (nixpkgs + "/lib/tests/release.nix")
|
||||||
{ pkgs = nixpkgsFor.${system}; }
|
{ pkgs = nixpkgsFor.${system}.native; }
|
||||||
);
|
);
|
||||||
|
|
||||||
metrics.nixpkgs = import "${nixpkgs-regression}/pkgs/top-level/metrics.nix" {
|
metrics.nixpkgs = import "${nixpkgs-regression}/pkgs/top-level/metrics.nix" {
|
||||||
pkgs = nixpkgsFor.x86_64-linux;
|
pkgs = nixpkgsFor.x86_64-linux.native;
|
||||||
nixpkgs = nixpkgs-regression;
|
nixpkgs = nixpkgs-regression;
|
||||||
};
|
};
|
||||||
|
|
||||||
installTests = forAllSystems (system:
|
installTests = forAllSystems (system:
|
||||||
let pkgs = nixpkgsFor.${system}; in
|
let pkgs = nixpkgsFor.${system}.native; in
|
||||||
pkgs.runCommand "install-tests" {
|
pkgs.runCommand "install-tests" {
|
||||||
againstSelf = testNixVersions pkgs pkgs.nix pkgs.pkgs.nix;
|
againstSelf = testNixVersions pkgs pkgs.nix pkgs.pkgs.nix;
|
||||||
againstCurrentUnstable =
|
againstCurrentUnstable =
|
||||||
|
@ -569,67 +578,18 @@
|
||||||
perlBindings = self.hydraJobs.perlBindings.${system};
|
perlBindings = self.hydraJobs.perlBindings.${system};
|
||||||
installTests = self.hydraJobs.installTests.${system};
|
installTests = self.hydraJobs.installTests.${system};
|
||||||
nixpkgsLibTests = self.hydraJobs.tests.nixpkgsLibTests.${system};
|
nixpkgsLibTests = self.hydraJobs.tests.nixpkgsLibTests.${system};
|
||||||
} // (nixpkgs.lib.optionalAttrs (builtins.elem system linux64BitSystems)) {
|
} // (lib.optionalAttrs (builtins.elem system linux64BitSystems)) {
|
||||||
dockerImage = self.hydraJobs.dockerImage.${system};
|
dockerImage = self.hydraJobs.dockerImage.${system};
|
||||||
});
|
});
|
||||||
|
|
||||||
packages = forAllSystems (system: rec {
|
packages = forAllSystems (system: rec {
|
||||||
inherit (nixpkgsFor.${system}) nix;
|
inherit (nixpkgsFor.${system}.native) nix;
|
||||||
default = nix;
|
default = nix;
|
||||||
} // (nixpkgs.lib.optionalAttrs (builtins.elem system linux64BitSystems) {
|
} // (lib.optionalAttrs (builtins.elem system linux64BitSystems) {
|
||||||
nix-static = let
|
nix-static = nixpkgsFor.${system}.static.nix;
|
||||||
nixpkgs = nixpkgsFor.${system}.pkgsStatic;
|
|
||||||
in with commonDeps { pkgs = nixpkgs; isStatic = true; }; nixpkgs.stdenv.mkDerivation {
|
|
||||||
name = "nix-${version}";
|
|
||||||
|
|
||||||
src = self;
|
|
||||||
|
|
||||||
VERSION_SUFFIX = versionSuffix;
|
|
||||||
|
|
||||||
outputs = [ "out" "dev" "doc" ];
|
|
||||||
|
|
||||||
nativeBuildInputs = nativeBuildDeps;
|
|
||||||
buildInputs = buildDeps ++ propagatedDeps;
|
|
||||||
|
|
||||||
# Work around pkgsStatic disabling all tests.
|
|
||||||
# Remove in NixOS 22.11, see https://github.com/NixOS/nixpkgs/pull/140271.
|
|
||||||
preHook =
|
|
||||||
''
|
|
||||||
doCheck=1
|
|
||||||
doInstallCheck=1
|
|
||||||
'';
|
|
||||||
|
|
||||||
configureFlags =
|
|
||||||
configureFlags ++
|
|
||||||
[ "--sysconfdir=/etc"
|
|
||||||
"--enable-embedded-sandbox-shell"
|
|
||||||
];
|
|
||||||
|
|
||||||
enableParallelBuilding = true;
|
|
||||||
|
|
||||||
makeFlags = "profiledir=$(out)/etc/profile.d";
|
|
||||||
|
|
||||||
installFlags = "sysconfdir=$(out)/etc";
|
|
||||||
|
|
||||||
postInstall = ''
|
|
||||||
mkdir -p $doc/nix-support
|
|
||||||
echo "doc manual $doc/share/doc/nix/manual" >> $doc/nix-support/hydra-build-products
|
|
||||||
mkdir -p $out/nix-support
|
|
||||||
echo "file binary-dist $out/bin/nix" >> $out/nix-support/hydra-build-products
|
|
||||||
'';
|
|
||||||
|
|
||||||
installCheckFlags = "sysconfdir=$(out)/etc";
|
|
||||||
|
|
||||||
stripAllList = ["bin"];
|
|
||||||
|
|
||||||
strictDeps = true;
|
|
||||||
|
|
||||||
hardeningDisable = [ "pie" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
dockerImage =
|
dockerImage =
|
||||||
let
|
let
|
||||||
pkgs = nixpkgsFor.${system};
|
pkgs = nixpkgsFor.${system}.native;
|
||||||
image = import ./docker.nix { inherit pkgs; tag = version; };
|
image = import ./docker.nix { inherit pkgs; tag = version; };
|
||||||
in
|
in
|
||||||
pkgs.runCommand
|
pkgs.runCommand
|
||||||
|
@ -641,70 +601,30 @@
|
||||||
ln -s ${image} $image
|
ln -s ${image} $image
|
||||||
echo "file binary-dist $image" >> $out/nix-support/hydra-build-products
|
echo "file binary-dist $image" >> $out/nix-support/hydra-build-products
|
||||||
'';
|
'';
|
||||||
}
|
} // builtins.listToAttrs (map
|
||||||
|
(crossSystem: {
|
||||||
|
name = "nix-${crossSystem}";
|
||||||
|
value = nixpkgsFor.${system}.cross.${crossSystem}.nix;
|
||||||
|
})
|
||||||
|
crossSystems)
|
||||||
|
// builtins.listToAttrs (map
|
||||||
|
(stdenvName: {
|
||||||
|
name = "nix-${stdenvName}";
|
||||||
|
value = nixpkgsFor.${system}.stdenvs."${stdenvName}Packages".nix;
|
||||||
|
})
|
||||||
|
stdenvs)));
|
||||||
|
|
||||||
// builtins.listToAttrs (map (crossSystem: {
|
devShells = let
|
||||||
name = "nix-${crossSystem}";
|
makeShell = pkgs: stdenv:
|
||||||
value = let
|
|
||||||
nixpkgsCross = import nixpkgs {
|
|
||||||
inherit system crossSystem;
|
|
||||||
overlays = [ self.overlays.default ];
|
|
||||||
};
|
|
||||||
inherit (nixpkgsCross) lib;
|
|
||||||
in with commonDeps { pkgs = nixpkgsCross; }; nixpkgsCross.stdenv.mkDerivation {
|
|
||||||
name = "nix-${version}";
|
|
||||||
|
|
||||||
src = self;
|
|
||||||
|
|
||||||
VERSION_SUFFIX = versionSuffix;
|
|
||||||
|
|
||||||
outputs = [ "out" "dev" "doc" ];
|
|
||||||
|
|
||||||
nativeBuildInputs = nativeBuildDeps;
|
|
||||||
buildInputs = buildDeps ++ propagatedDeps;
|
|
||||||
|
|
||||||
configureFlags = [
|
|
||||||
"CXXFLAGS=-I${lib.getDev nixpkgsCross.rapidcheck}/extras/gtest/include"
|
|
||||||
"--sysconfdir=/etc"
|
|
||||||
"--disable-doc-gen"
|
|
||||||
];
|
|
||||||
|
|
||||||
enableParallelBuilding = true;
|
|
||||||
|
|
||||||
makeFlags = "profiledir=$(out)/etc/profile.d";
|
|
||||||
|
|
||||||
doCheck = true;
|
|
||||||
|
|
||||||
installFlags = "sysconfdir=$(out)/etc";
|
|
||||||
|
|
||||||
postInstall = ''
|
|
||||||
mkdir -p $doc/nix-support
|
|
||||||
echo "doc manual $doc/share/doc/nix/manual" >> $doc/nix-support/hydra-build-products
|
|
||||||
mkdir -p $out/nix-support
|
|
||||||
echo "file binary-dist $out/bin/nix" >> $out/nix-support/hydra-build-products
|
|
||||||
'';
|
|
||||||
|
|
||||||
doInstallCheck = true;
|
|
||||||
installCheckFlags = "sysconfdir=$(out)/etc";
|
|
||||||
};
|
|
||||||
}) (if system == "x86_64-linux" then crossSystems else [])))
|
|
||||||
|
|
||||||
// (builtins.listToAttrs (map (stdenvName:
|
|
||||||
nixpkgsFor.${system}.lib.nameValuePair
|
|
||||||
"nix-${stdenvName}"
|
|
||||||
nixpkgsFor.${system}."${stdenvName}Packages".nix
|
|
||||||
) stdenvs)));
|
|
||||||
|
|
||||||
devShells = forAllSystems (system:
|
|
||||||
forAllStdenvs (stdenv:
|
|
||||||
with nixpkgsFor.${system};
|
|
||||||
with commonDeps { inherit pkgs; };
|
with commonDeps { inherit pkgs; };
|
||||||
nixpkgsFor.${system}.${stdenv}.mkDerivation {
|
stdenv.mkDerivation {
|
||||||
name = "nix";
|
name = "nix";
|
||||||
|
|
||||||
outputs = [ "out" "dev" "doc" ];
|
outputs = [ "out" "dev" "doc" ];
|
||||||
|
|
||||||
nativeBuildInputs = nativeBuildDeps;
|
nativeBuildInputs = nativeBuildDeps
|
||||||
|
++ (lib.optionals stdenv.cc.isClang [ pkgs.bear pkgs.clang-tools ]);
|
||||||
|
|
||||||
buildInputs = buildDeps ++ propagatedDeps ++ awsDeps;
|
buildInputs = buildDeps ++ propagatedDeps ++ awsDeps;
|
||||||
|
|
||||||
inherit configureFlags;
|
inherit configureFlags;
|
||||||
|
@ -722,10 +642,21 @@
|
||||||
# Make bash completion work.
|
# Make bash completion work.
|
||||||
XDG_DATA_DIRS+=:$out/share
|
XDG_DATA_DIRS+=:$out/share
|
||||||
'';
|
'';
|
||||||
}
|
};
|
||||||
)
|
in
|
||||||
// { default = self.devShells.${system}.stdenv; }
|
forAllSystems (system:
|
||||||
);
|
let
|
||||||
|
makeShells = prefix: pkgs:
|
||||||
|
lib.mapAttrs'
|
||||||
|
(k: v: lib.nameValuePair "${prefix}-${k}" v)
|
||||||
|
(forAllStdenvs (stdenvName: makeShell pkgs pkgs.${stdenvName}));
|
||||||
|
in
|
||||||
|
(makeShells "native" nixpkgsFor.${system}.native) //
|
||||||
|
(makeShells "static" nixpkgsFor.${system}.static) //
|
||||||
|
(forAllCrossSystems (crossSystem: let pkgs = nixpkgsFor.${system}.cross.${crossSystem}; in makeShell pkgs pkgs.stdenv)) //
|
||||||
|
{
|
||||||
|
default = self.devShells.${system}.native-stdenvPackages;
|
||||||
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "derivations.hh"
|
#include "derivations.hh"
|
||||||
#include "nixexpr.hh"
|
#include "nixexpr.hh"
|
||||||
#include "profiles.hh"
|
#include "profiles.hh"
|
||||||
|
#include "repl.hh"
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
@ -121,7 +122,7 @@ ref<EvalState> EvalCommand::getEvalState()
|
||||||
;
|
;
|
||||||
|
|
||||||
if (startReplOnEvalErrors) {
|
if (startReplOnEvalErrors) {
|
||||||
evalState->debugRepl = &runRepl;
|
evalState->debugRepl = &AbstractNixRepl::runSimple;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return ref<EvalState>(evalState);
|
return ref<EvalState>(evalState);
|
||||||
|
@ -218,23 +219,6 @@ void StorePathCommand::run(ref<Store> store, std::vector<StorePath> && storePath
|
||||||
run(store, *storePaths.begin());
|
run(store, *storePaths.begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
Strings editorFor(const SourcePath & file, uint32_t line)
|
|
||||||
{
|
|
||||||
auto path = file.getPhysicalPath();
|
|
||||||
if (!path)
|
|
||||||
throw Error("cannot open '%s' in an editor because it has no physical path", file);
|
|
||||||
auto editor = getEnv("EDITOR").value_or("cat");
|
|
||||||
auto args = tokenizeString<Strings>(editor);
|
|
||||||
if (line > 0 && (
|
|
||||||
editor.find("emacs") != std::string::npos ||
|
|
||||||
editor.find("nano") != std::string::npos ||
|
|
||||||
editor.find("vim") != std::string::npos ||
|
|
||||||
editor.find("kak") != std::string::npos))
|
|
||||||
args.push_back(fmt("+%d", line));
|
|
||||||
args.push_back(path->abs());
|
|
||||||
return args;
|
|
||||||
}
|
|
||||||
|
|
||||||
MixProfile::MixProfile()
|
MixProfile::MixProfile()
|
||||||
{
|
{
|
||||||
addFlag({
|
addFlag({
|
||||||
|
|
|
@ -231,10 +231,6 @@ static RegisterCommand registerCommand2(std::vector<std::string> && name)
|
||||||
return RegisterCommand(std::move(name), [](){ return make_ref<T>(); });
|
return RegisterCommand(std::move(name), [](){ return make_ref<T>(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper function to generate args that invoke $EDITOR on
|
|
||||||
filename:lineno. */
|
|
||||||
Strings editorFor(const SourcePath & file, uint32_t line);
|
|
||||||
|
|
||||||
struct MixProfile : virtual StoreCommand
|
struct MixProfile : virtual StoreCommand
|
||||||
{
|
{
|
||||||
std::optional<Path> profile;
|
std::optional<Path> profile;
|
||||||
|
@ -284,8 +280,4 @@ void printClosureDiff(
|
||||||
const StorePath & afterPath,
|
const StorePath & afterPath,
|
||||||
std::string_view indent);
|
std::string_view indent);
|
||||||
|
|
||||||
|
|
||||||
void runRepl(
|
|
||||||
ref<EvalState> evalState,
|
|
||||||
const ValMap & extraEnv);
|
|
||||||
}
|
}
|
||||||
|
|
23
src/libcmd/editor-for.cc
Normal file
23
src/libcmd/editor-for.cc
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#include "util.hh"
|
||||||
|
#include "editor-for.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
Strings editorFor(const SourcePath & file, uint32_t line)
|
||||||
|
{
|
||||||
|
auto path = file.getPhysicalPath();
|
||||||
|
if (!path)
|
||||||
|
throw Error("cannot open '%s' in an editor because it has no physical path", file);
|
||||||
|
auto editor = getEnv("EDITOR").value_or("cat");
|
||||||
|
auto args = tokenizeString<Strings>(editor);
|
||||||
|
if (line > 0 && (
|
||||||
|
editor.find("emacs") != std::string::npos ||
|
||||||
|
editor.find("nano") != std::string::npos ||
|
||||||
|
editor.find("vim") != std::string::npos ||
|
||||||
|
editor.find("kak") != std::string::npos))
|
||||||
|
args.push_back(fmt("+%d", line));
|
||||||
|
args.push_back(path->abs());
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
12
src/libcmd/editor-for.hh
Normal file
12
src/libcmd/editor-for.hh
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "types.hh"
|
||||||
|
#include "input-accessor.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
/* Helper function to generate args that invoke $EDITOR on
|
||||||
|
filename:lineno. */
|
||||||
|
Strings editorFor(const SourcePath & file, uint32_t line);
|
||||||
|
|
||||||
|
}
|
109
src/libcmd/installable-attr-path.cc
Normal file
109
src/libcmd/installable-attr-path.cc
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
#include "globals.hh"
|
||||||
|
#include "installable-attr-path.hh"
|
||||||
|
#include "outputs-spec.hh"
|
||||||
|
#include "util.hh"
|
||||||
|
#include "command.hh"
|
||||||
|
#include "attr-path.hh"
|
||||||
|
#include "common-eval-args.hh"
|
||||||
|
#include "derivations.hh"
|
||||||
|
#include "eval-inline.hh"
|
||||||
|
#include "eval.hh"
|
||||||
|
#include "get-drvs.hh"
|
||||||
|
#include "store-api.hh"
|
||||||
|
#include "shared.hh"
|
||||||
|
#include "flake/flake.hh"
|
||||||
|
#include "eval-cache.hh"
|
||||||
|
#include "url.hh"
|
||||||
|
#include "registry.hh"
|
||||||
|
#include "build-result.hh"
|
||||||
|
|
||||||
|
#include <regex>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
InstallableAttrPath::InstallableAttrPath(
|
||||||
|
ref<EvalState> state,
|
||||||
|
SourceExprCommand & cmd,
|
||||||
|
Value * v,
|
||||||
|
const std::string & attrPath,
|
||||||
|
ExtendedOutputsSpec extendedOutputsSpec)
|
||||||
|
: InstallableValue(state)
|
||||||
|
, cmd(cmd)
|
||||||
|
, v(allocRootValue(v))
|
||||||
|
, attrPath(attrPath)
|
||||||
|
, extendedOutputsSpec(std::move(extendedOutputsSpec))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
std::pair<Value *, PosIdx> InstallableAttrPath::toValue(EvalState & state)
|
||||||
|
{
|
||||||
|
auto [vRes, pos] = findAlongAttrPath(state, attrPath, *cmd.getAutoArgs(state), **v);
|
||||||
|
state.forceValue(*vRes, pos);
|
||||||
|
return {vRes, pos};
|
||||||
|
}
|
||||||
|
|
||||||
|
DerivedPathsWithInfo InstallableAttrPath::toDerivedPaths()
|
||||||
|
{
|
||||||
|
auto v = toValue(*state).first;
|
||||||
|
|
||||||
|
Bindings & autoArgs = *cmd.getAutoArgs(*state);
|
||||||
|
|
||||||
|
DrvInfos drvInfos;
|
||||||
|
getDerivations(*state, *v, "", autoArgs, drvInfos, false);
|
||||||
|
|
||||||
|
// Backward compatibility hack: group results by drvPath. This
|
||||||
|
// helps keep .all output together.
|
||||||
|
std::map<StorePath, OutputsSpec> byDrvPath;
|
||||||
|
|
||||||
|
for (auto & drvInfo : drvInfos) {
|
||||||
|
auto drvPath = drvInfo.queryDrvPath();
|
||||||
|
if (!drvPath)
|
||||||
|
throw Error("'%s' is not a derivation", what());
|
||||||
|
|
||||||
|
auto newOutputs = std::visit(overloaded {
|
||||||
|
[&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
|
||||||
|
std::set<std::string> outputsToInstall;
|
||||||
|
for (auto & output : drvInfo.queryOutputs(false, true))
|
||||||
|
outputsToInstall.insert(output.first);
|
||||||
|
return OutputsSpec::Names { std::move(outputsToInstall) };
|
||||||
|
},
|
||||||
|
[&](const ExtendedOutputsSpec::Explicit & e) -> OutputsSpec {
|
||||||
|
return e;
|
||||||
|
},
|
||||||
|
}, extendedOutputsSpec.raw());
|
||||||
|
|
||||||
|
auto [iter, didInsert] = byDrvPath.emplace(*drvPath, newOutputs);
|
||||||
|
|
||||||
|
if (!didInsert)
|
||||||
|
iter->second = iter->second.union_(newOutputs);
|
||||||
|
}
|
||||||
|
|
||||||
|
DerivedPathsWithInfo res;
|
||||||
|
for (auto & [drvPath, outputs] : byDrvPath)
|
||||||
|
res.push_back({
|
||||||
|
.path = DerivedPath::Built {
|
||||||
|
.drvPath = drvPath,
|
||||||
|
.outputs = outputs,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
InstallableAttrPath InstallableAttrPath::parse(
|
||||||
|
ref<EvalState> state,
|
||||||
|
SourceExprCommand & cmd,
|
||||||
|
Value * v,
|
||||||
|
std::string_view prefix,
|
||||||
|
ExtendedOutputsSpec extendedOutputsSpec)
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
state, cmd, v,
|
||||||
|
prefix == "." ? "" : std::string { prefix },
|
||||||
|
extendedOutputsSpec
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
56
src/libcmd/installable-attr-path.hh
Normal file
56
src/libcmd/installable-attr-path.hh
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
#include "globals.hh"
|
||||||
|
#include "installable-value.hh"
|
||||||
|
#include "outputs-spec.hh"
|
||||||
|
#include "util.hh"
|
||||||
|
#include "command.hh"
|
||||||
|
#include "attr-path.hh"
|
||||||
|
#include "common-eval-args.hh"
|
||||||
|
#include "derivations.hh"
|
||||||
|
#include "eval-inline.hh"
|
||||||
|
#include "eval.hh"
|
||||||
|
#include "get-drvs.hh"
|
||||||
|
#include "store-api.hh"
|
||||||
|
#include "shared.hh"
|
||||||
|
#include "eval-cache.hh"
|
||||||
|
#include "url.hh"
|
||||||
|
#include "registry.hh"
|
||||||
|
#include "build-result.hh"
|
||||||
|
|
||||||
|
#include <regex>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
class InstallableAttrPath : public InstallableValue
|
||||||
|
{
|
||||||
|
SourceExprCommand & cmd;
|
||||||
|
RootValue v;
|
||||||
|
std::string attrPath;
|
||||||
|
ExtendedOutputsSpec extendedOutputsSpec;
|
||||||
|
|
||||||
|
InstallableAttrPath(
|
||||||
|
ref<EvalState> state,
|
||||||
|
SourceExprCommand & cmd,
|
||||||
|
Value * v,
|
||||||
|
const std::string & attrPath,
|
||||||
|
ExtendedOutputsSpec extendedOutputsSpec);
|
||||||
|
|
||||||
|
std::string what() const override { return attrPath; };
|
||||||
|
|
||||||
|
std::pair<Value *, PosIdx> toValue(EvalState & state) override;
|
||||||
|
|
||||||
|
DerivedPathsWithInfo toDerivedPaths() override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
static InstallableAttrPath parse(
|
||||||
|
ref<EvalState> state,
|
||||||
|
SourceExprCommand & cmd,
|
||||||
|
Value * v,
|
||||||
|
std::string_view prefix,
|
||||||
|
ExtendedOutputsSpec extendedOutputsSpec);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
235
src/libcmd/installable-flake.cc
Normal file
235
src/libcmd/installable-flake.cc
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
#include "globals.hh"
|
||||||
|
#include "installable-flake.hh"
|
||||||
|
#include "installable-derived-path.hh"
|
||||||
|
#include "outputs-spec.hh"
|
||||||
|
#include "util.hh"
|
||||||
|
#include "command.hh"
|
||||||
|
#include "attr-path.hh"
|
||||||
|
#include "common-eval-args.hh"
|
||||||
|
#include "derivations.hh"
|
||||||
|
#include "eval-inline.hh"
|
||||||
|
#include "eval.hh"
|
||||||
|
#include "get-drvs.hh"
|
||||||
|
#include "store-api.hh"
|
||||||
|
#include "shared.hh"
|
||||||
|
#include "flake/flake.hh"
|
||||||
|
#include "eval-cache.hh"
|
||||||
|
#include "url.hh"
|
||||||
|
#include "registry.hh"
|
||||||
|
#include "build-result.hh"
|
||||||
|
|
||||||
|
#include <regex>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
std::vector<std::string> InstallableFlake::getActualAttrPaths()
|
||||||
|
{
|
||||||
|
std::vector<std::string> res;
|
||||||
|
|
||||||
|
for (auto & prefix : prefixes)
|
||||||
|
res.push_back(prefix + *attrPaths.begin());
|
||||||
|
|
||||||
|
for (auto & s : attrPaths)
|
||||||
|
res.push_back(s);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value * InstallableFlake::getFlakeOutputs(EvalState & state, const flake::LockedFlake & lockedFlake)
|
||||||
|
{
|
||||||
|
auto vFlake = state.allocValue();
|
||||||
|
|
||||||
|
callFlake(state, lockedFlake, *vFlake);
|
||||||
|
|
||||||
|
auto aOutputs = vFlake->attrs->get(state.symbols.create("outputs"));
|
||||||
|
assert(aOutputs);
|
||||||
|
|
||||||
|
state.forceValue(*aOutputs->value, [&]() { return aOutputs->value->determinePos(noPos); });
|
||||||
|
|
||||||
|
return aOutputs->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string showAttrPaths(const std::vector<std::string> & paths)
|
||||||
|
{
|
||||||
|
std::string s;
|
||||||
|
for (const auto & [n, i] : enumerate(paths)) {
|
||||||
|
if (n > 0) s += n + 1 == paths.size() ? " or " : ", ";
|
||||||
|
s += '\''; s += i; s += '\'';
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
InstallableFlake::InstallableFlake(
|
||||||
|
SourceExprCommand * cmd,
|
||||||
|
ref<EvalState> state,
|
||||||
|
FlakeRef && flakeRef,
|
||||||
|
std::string_view fragment,
|
||||||
|
ExtendedOutputsSpec extendedOutputsSpec,
|
||||||
|
Strings attrPaths,
|
||||||
|
Strings prefixes,
|
||||||
|
const flake::LockFlags & lockFlags)
|
||||||
|
: InstallableValue(state),
|
||||||
|
flakeRef(flakeRef),
|
||||||
|
attrPaths(fragment == "" ? attrPaths : Strings{(std::string) fragment}),
|
||||||
|
prefixes(fragment == "" ? Strings{} : prefixes),
|
||||||
|
extendedOutputsSpec(std::move(extendedOutputsSpec)),
|
||||||
|
lockFlags(lockFlags)
|
||||||
|
{
|
||||||
|
if (cmd && cmd->getAutoArgs(*state)->size())
|
||||||
|
throw UsageError("'--arg' and '--argstr' are incompatible with flakes");
|
||||||
|
}
|
||||||
|
|
||||||
|
DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
|
||||||
|
{
|
||||||
|
Activity act(*logger, lvlTalkative, actUnknown, fmt("evaluating derivation '%s'", what()));
|
||||||
|
|
||||||
|
auto attr = getCursor(*state);
|
||||||
|
|
||||||
|
auto attrPath = attr->getAttrPathStr();
|
||||||
|
|
||||||
|
if (!attr->isDerivation()) {
|
||||||
|
|
||||||
|
// FIXME: use eval cache?
|
||||||
|
auto v = attr->forceValue();
|
||||||
|
|
||||||
|
if (v.type() == nPath) {
|
||||||
|
auto storePath = v.path().fetchToStore(state->store);
|
||||||
|
return {{
|
||||||
|
.path = DerivedPath::Opaque {
|
||||||
|
.path = std::move(storePath),
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (v.type() == nString) {
|
||||||
|
PathSet context;
|
||||||
|
auto s = state->forceString(v, context, noPos, fmt("while evaluating the flake output attribute '%s'", attrPath));
|
||||||
|
auto storePath = state->store->maybeParseStorePath(s);
|
||||||
|
if (storePath && context.count(std::string(s))) {
|
||||||
|
return {{
|
||||||
|
.path = DerivedPath::Opaque {
|
||||||
|
.path = std::move(*storePath),
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
} else
|
||||||
|
throw Error("flake output attribute '%s' evaluates to the string '%s' which is not a store path", attrPath, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
throw Error("flake output attribute '%s' is not a derivation or path", attrPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto drvPath = attr->forceDerivation();
|
||||||
|
|
||||||
|
std::optional<NixInt> priority;
|
||||||
|
|
||||||
|
if (attr->maybeGetAttr(state->sOutputSpecified)) {
|
||||||
|
} else if (auto aMeta = attr->maybeGetAttr(state->sMeta)) {
|
||||||
|
if (auto aPriority = aMeta->maybeGetAttr("priority"))
|
||||||
|
priority = aPriority->getInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {{
|
||||||
|
.path = DerivedPath::Built {
|
||||||
|
.drvPath = std::move(drvPath),
|
||||||
|
.outputs = std::visit(overloaded {
|
||||||
|
[&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
|
||||||
|
std::set<std::string> outputsToInstall;
|
||||||
|
if (auto aOutputSpecified = attr->maybeGetAttr(state->sOutputSpecified)) {
|
||||||
|
if (aOutputSpecified->getBool()) {
|
||||||
|
if (auto aOutputName = attr->maybeGetAttr("outputName"))
|
||||||
|
outputsToInstall = { aOutputName->getString() };
|
||||||
|
}
|
||||||
|
} else if (auto aMeta = attr->maybeGetAttr(state->sMeta)) {
|
||||||
|
if (auto aOutputsToInstall = aMeta->maybeGetAttr("outputsToInstall"))
|
||||||
|
for (auto & s : aOutputsToInstall->getListOfStrings())
|
||||||
|
outputsToInstall.insert(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outputsToInstall.empty())
|
||||||
|
outputsToInstall.insert("out");
|
||||||
|
|
||||||
|
return OutputsSpec::Names { std::move(outputsToInstall) };
|
||||||
|
},
|
||||||
|
[&](const ExtendedOutputsSpec::Explicit & e) -> OutputsSpec {
|
||||||
|
return e;
|
||||||
|
},
|
||||||
|
}, extendedOutputsSpec.raw()),
|
||||||
|
},
|
||||||
|
.info = {
|
||||||
|
.priority = priority,
|
||||||
|
.originalRef = flakeRef,
|
||||||
|
.resolvedRef = getLockedFlake()->flake.lockedRef,
|
||||||
|
.attrPath = attrPath,
|
||||||
|
.extendedOutputsSpec = extendedOutputsSpec,
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<Value *, PosIdx> InstallableFlake::toValue(EvalState & state)
|
||||||
|
{
|
||||||
|
return {&getCursor(state)->forceValue(), noPos};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ref<eval_cache::AttrCursor>>
|
||||||
|
InstallableFlake::getCursors(EvalState & state)
|
||||||
|
{
|
||||||
|
auto evalCache = openEvalCache(state,
|
||||||
|
std::make_shared<flake::LockedFlake>(lockFlake(state, flakeRef, lockFlags)));
|
||||||
|
|
||||||
|
auto root = evalCache->getRoot();
|
||||||
|
|
||||||
|
std::vector<ref<eval_cache::AttrCursor>> res;
|
||||||
|
|
||||||
|
Suggestions suggestions;
|
||||||
|
auto attrPaths = getActualAttrPaths();
|
||||||
|
|
||||||
|
for (auto & attrPath : attrPaths) {
|
||||||
|
debug("trying flake output attribute '%s'", attrPath);
|
||||||
|
|
||||||
|
auto attr = root->findAlongAttrPath(parseAttrPath(state, attrPath));
|
||||||
|
if (attr) {
|
||||||
|
res.push_back(ref(*attr));
|
||||||
|
} else {
|
||||||
|
suggestions += attr.getSuggestions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.size() == 0)
|
||||||
|
throw Error(
|
||||||
|
suggestions,
|
||||||
|
"flake '%s' does not provide attribute %s",
|
||||||
|
flakeRef,
|
||||||
|
showAttrPaths(attrPaths));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<flake::LockedFlake> InstallableFlake::getLockedFlake() const
|
||||||
|
{
|
||||||
|
if (!_lockedFlake) {
|
||||||
|
flake::LockFlags lockFlagsApplyConfig = lockFlags;
|
||||||
|
lockFlagsApplyConfig.applyNixConfig = true;
|
||||||
|
_lockedFlake = std::make_shared<flake::LockedFlake>(lockFlake(*state, flakeRef, lockFlagsApplyConfig));
|
||||||
|
}
|
||||||
|
return _lockedFlake;
|
||||||
|
}
|
||||||
|
|
||||||
|
FlakeRef InstallableFlake::nixpkgsFlakeRef() const
|
||||||
|
{
|
||||||
|
auto lockedFlake = getLockedFlake();
|
||||||
|
|
||||||
|
if (auto nixpkgsInput = lockedFlake->lockFile.findInput({"nixpkgs"})) {
|
||||||
|
if (auto lockedNode = std::dynamic_pointer_cast<const flake::LockedNode>(nixpkgsInput)) {
|
||||||
|
debug("using nixpkgs flake '%s'", lockedNode->lockedRef);
|
||||||
|
return std::move(lockedNode->lockedRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Installable::nixpkgsFlakeRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
50
src/libcmd/installable-flake.hh
Normal file
50
src/libcmd/installable-flake.hh
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "installable-value.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
struct InstallableFlake : InstallableValue
|
||||||
|
{
|
||||||
|
FlakeRef flakeRef;
|
||||||
|
Strings attrPaths;
|
||||||
|
Strings prefixes;
|
||||||
|
ExtendedOutputsSpec extendedOutputsSpec;
|
||||||
|
const flake::LockFlags & lockFlags;
|
||||||
|
mutable std::shared_ptr<flake::LockedFlake> _lockedFlake;
|
||||||
|
|
||||||
|
InstallableFlake(
|
||||||
|
SourceExprCommand * cmd,
|
||||||
|
ref<EvalState> state,
|
||||||
|
FlakeRef && flakeRef,
|
||||||
|
std::string_view fragment,
|
||||||
|
ExtendedOutputsSpec extendedOutputsSpec,
|
||||||
|
Strings attrPaths,
|
||||||
|
Strings prefixes,
|
||||||
|
const flake::LockFlags & lockFlags);
|
||||||
|
|
||||||
|
std::string what() const override { return flakeRef.to_string() + "#" + *attrPaths.begin(); }
|
||||||
|
|
||||||
|
std::vector<std::string> getActualAttrPaths();
|
||||||
|
|
||||||
|
Value * getFlakeOutputs(EvalState & state, const flake::LockedFlake & lockedFlake);
|
||||||
|
|
||||||
|
DerivedPathsWithInfo toDerivedPaths() override;
|
||||||
|
|
||||||
|
std::pair<Value *, PosIdx> toValue(EvalState & state) override;
|
||||||
|
|
||||||
|
/* Get a cursor to every attrpath in getActualAttrPaths()
|
||||||
|
that exists. However if none exists, throw an exception. */
|
||||||
|
std::vector<ref<eval_cache::AttrCursor>>
|
||||||
|
getCursors(EvalState & state) override;
|
||||||
|
|
||||||
|
std::shared_ptr<flake::LockedFlake> getLockedFlake() const;
|
||||||
|
|
||||||
|
FlakeRef nixpkgsFlakeRef() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
ref<eval_cache::EvalCache> openEvalCache(
|
||||||
|
EvalState & state,
|
||||||
|
std::shared_ptr<flake::LockedFlake> lockedFlake);
|
||||||
|
|
||||||
|
}
|
14
src/libcmd/installable-value.hh
Normal file
14
src/libcmd/installable-value.hh
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "installables.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
struct InstallableValue : Installable
|
||||||
|
{
|
||||||
|
ref<EvalState> state;
|
||||||
|
|
||||||
|
InstallableValue(ref<EvalState> state) : state(state) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "installables.hh"
|
#include "installables.hh"
|
||||||
#include "installable-derived-path.hh"
|
#include "installable-derived-path.hh"
|
||||||
|
#include "installable-attr-path.hh"
|
||||||
|
#include "installable-flake.hh"
|
||||||
#include "outputs-spec.hh"
|
#include "outputs-spec.hh"
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
#include "command.hh"
|
#include "command.hh"
|
||||||
|
@ -391,111 +393,6 @@ static StorePath getDeriver(
|
||||||
return *derivers.begin();
|
return *derivers.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct InstallableAttrPath : InstallableValue
|
|
||||||
{
|
|
||||||
SourceExprCommand & cmd;
|
|
||||||
RootValue v;
|
|
||||||
std::string attrPath;
|
|
||||||
ExtendedOutputsSpec extendedOutputsSpec;
|
|
||||||
|
|
||||||
InstallableAttrPath(
|
|
||||||
ref<EvalState> state,
|
|
||||||
SourceExprCommand & cmd,
|
|
||||||
Value * v,
|
|
||||||
const std::string & attrPath,
|
|
||||||
ExtendedOutputsSpec extendedOutputsSpec)
|
|
||||||
: InstallableValue(state)
|
|
||||||
, cmd(cmd)
|
|
||||||
, v(allocRootValue(v))
|
|
||||||
, attrPath(attrPath)
|
|
||||||
, extendedOutputsSpec(std::move(extendedOutputsSpec))
|
|
||||||
{ }
|
|
||||||
|
|
||||||
std::string what() const override { return attrPath; }
|
|
||||||
|
|
||||||
std::pair<Value *, PosIdx> toValue(EvalState & state) override
|
|
||||||
{
|
|
||||||
auto [vRes, pos] = findAlongAttrPath(state, attrPath, *cmd.getAutoArgs(state), **v);
|
|
||||||
state.forceValue(*vRes, pos);
|
|
||||||
return {vRes, pos};
|
|
||||||
}
|
|
||||||
|
|
||||||
DerivedPathsWithInfo toDerivedPaths() override
|
|
||||||
{
|
|
||||||
auto v = toValue(*state).first;
|
|
||||||
|
|
||||||
Bindings & autoArgs = *cmd.getAutoArgs(*state);
|
|
||||||
|
|
||||||
DrvInfos drvInfos;
|
|
||||||
getDerivations(*state, *v, "", autoArgs, drvInfos, false);
|
|
||||||
|
|
||||||
// Backward compatibility hack: group results by drvPath. This
|
|
||||||
// helps keep .all output together.
|
|
||||||
std::map<StorePath, OutputsSpec> byDrvPath;
|
|
||||||
|
|
||||||
for (auto & drvInfo : drvInfos) {
|
|
||||||
auto drvPath = drvInfo.queryDrvPath();
|
|
||||||
if (!drvPath)
|
|
||||||
throw Error("'%s' is not a derivation", what());
|
|
||||||
|
|
||||||
auto newOutputs = std::visit(overloaded {
|
|
||||||
[&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
|
|
||||||
std::set<std::string> outputsToInstall;
|
|
||||||
for (auto & output : drvInfo.queryOutputs(false, true))
|
|
||||||
outputsToInstall.insert(output.first);
|
|
||||||
return OutputsSpec::Names { std::move(outputsToInstall) };
|
|
||||||
},
|
|
||||||
[&](const ExtendedOutputsSpec::Explicit & e) -> OutputsSpec {
|
|
||||||
return e;
|
|
||||||
},
|
|
||||||
}, extendedOutputsSpec.raw());
|
|
||||||
|
|
||||||
auto [iter, didInsert] = byDrvPath.emplace(*drvPath, newOutputs);
|
|
||||||
|
|
||||||
if (!didInsert)
|
|
||||||
iter->second = iter->second.union_(newOutputs);
|
|
||||||
}
|
|
||||||
|
|
||||||
DerivedPathsWithInfo res;
|
|
||||||
for (auto & [drvPath, outputs] : byDrvPath)
|
|
||||||
res.push_back({
|
|
||||||
.path = DerivedPath::Built {
|
|
||||||
.drvPath = drvPath,
|
|
||||||
.outputs = outputs,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<std::string> InstallableFlake::getActualAttrPaths()
|
|
||||||
{
|
|
||||||
std::vector<std::string> res;
|
|
||||||
|
|
||||||
for (auto & prefix : prefixes)
|
|
||||||
res.push_back(prefix + *attrPaths.begin());
|
|
||||||
|
|
||||||
for (auto & s : attrPaths)
|
|
||||||
res.push_back(s);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
Value * InstallableFlake::getFlakeOutputs(EvalState & state, const flake::LockedFlake & lockedFlake)
|
|
||||||
{
|
|
||||||
auto vFlake = state.allocValue();
|
|
||||||
|
|
||||||
callFlake(state, lockedFlake, *vFlake);
|
|
||||||
|
|
||||||
auto aOutputs = vFlake->attrs->get(state.symbols.create("outputs"));
|
|
||||||
assert(aOutputs);
|
|
||||||
|
|
||||||
state.forceValue(*aOutputs->value, [&]() { return aOutputs->value->determinePos(noPos); });
|
|
||||||
|
|
||||||
return aOutputs->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
ref<eval_cache::EvalCache> openEvalCache(
|
ref<eval_cache::EvalCache> openEvalCache(
|
||||||
EvalState & state,
|
EvalState & state,
|
||||||
std::shared_ptr<flake::LockedFlake> lockedFlake)
|
std::shared_ptr<flake::LockedFlake> lockedFlake)
|
||||||
|
@ -525,186 +422,6 @@ ref<eval_cache::EvalCache> openEvalCache(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string showAttrPaths(const std::vector<std::string> & paths)
|
|
||||||
{
|
|
||||||
std::string s;
|
|
||||||
for (const auto & [n, i] : enumerate(paths)) {
|
|
||||||
if (n > 0) s += n + 1 == paths.size() ? " or " : ", ";
|
|
||||||
s += '\''; s += i; s += '\'';
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
InstallableFlake::InstallableFlake(
|
|
||||||
SourceExprCommand * cmd,
|
|
||||||
ref<EvalState> state,
|
|
||||||
FlakeRef && flakeRef,
|
|
||||||
std::string_view fragment,
|
|
||||||
ExtendedOutputsSpec extendedOutputsSpec,
|
|
||||||
Strings attrPaths,
|
|
||||||
Strings prefixes,
|
|
||||||
const flake::LockFlags & lockFlags)
|
|
||||||
: InstallableValue(state),
|
|
||||||
flakeRef(flakeRef),
|
|
||||||
attrPaths(fragment == "" ? attrPaths : Strings{(std::string) fragment}),
|
|
||||||
prefixes(fragment == "" ? Strings{} : prefixes),
|
|
||||||
extendedOutputsSpec(std::move(extendedOutputsSpec)),
|
|
||||||
lockFlags(lockFlags)
|
|
||||||
{
|
|
||||||
if (cmd && cmd->getAutoArgs(*state)->size())
|
|
||||||
throw UsageError("'--arg' and '--argstr' are incompatible with flakes");
|
|
||||||
}
|
|
||||||
|
|
||||||
DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
|
|
||||||
{
|
|
||||||
Activity act(*logger, lvlTalkative, actUnknown, fmt("evaluating derivation '%s'", what()));
|
|
||||||
|
|
||||||
auto attr = getCursor(*state);
|
|
||||||
|
|
||||||
auto attrPath = attr->getAttrPathStr();
|
|
||||||
|
|
||||||
if (!attr->isDerivation()) {
|
|
||||||
|
|
||||||
// FIXME: use eval cache?
|
|
||||||
auto v = attr->forceValue();
|
|
||||||
|
|
||||||
if (v.type() == nPath) {
|
|
||||||
auto storePath = v.path().fetchToStore(state->store);
|
|
||||||
return {{
|
|
||||||
.path = DerivedPath::Opaque {
|
|
||||||
.path = std::move(storePath),
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (v.type() == nString) {
|
|
||||||
PathSet context;
|
|
||||||
auto s = state->forceString(v, context, noPos, fmt("while evaluating the flake output attribute '%s'", attrPath));
|
|
||||||
auto storePath = state->store->maybeParseStorePath(s);
|
|
||||||
if (storePath && context.count(std::string(s))) {
|
|
||||||
return {{
|
|
||||||
.path = DerivedPath::Opaque {
|
|
||||||
.path = std::move(*storePath),
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
} else
|
|
||||||
throw Error("flake output attribute '%s' evaluates to the string '%s' which is not a store path", attrPath, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
throw Error("flake output attribute '%s' is not a derivation or path", attrPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto drvPath = attr->forceDerivation();
|
|
||||||
|
|
||||||
std::optional<NixInt> priority;
|
|
||||||
|
|
||||||
if (attr->maybeGetAttr(state->sOutputSpecified)) {
|
|
||||||
} else if (auto aMeta = attr->maybeGetAttr(state->sMeta)) {
|
|
||||||
if (auto aPriority = aMeta->maybeGetAttr("priority"))
|
|
||||||
priority = aPriority->getInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
return {{
|
|
||||||
.path = DerivedPath::Built {
|
|
||||||
.drvPath = std::move(drvPath),
|
|
||||||
.outputs = std::visit(overloaded {
|
|
||||||
[&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
|
|
||||||
std::set<std::string> outputsToInstall;
|
|
||||||
if (auto aOutputSpecified = attr->maybeGetAttr(state->sOutputSpecified)) {
|
|
||||||
if (aOutputSpecified->getBool()) {
|
|
||||||
if (auto aOutputName = attr->maybeGetAttr("outputName"))
|
|
||||||
outputsToInstall = { aOutputName->getString() };
|
|
||||||
}
|
|
||||||
} else if (auto aMeta = attr->maybeGetAttr(state->sMeta)) {
|
|
||||||
if (auto aOutputsToInstall = aMeta->maybeGetAttr("outputsToInstall"))
|
|
||||||
for (auto & s : aOutputsToInstall->getListOfStrings())
|
|
||||||
outputsToInstall.insert(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outputsToInstall.empty())
|
|
||||||
outputsToInstall.insert("out");
|
|
||||||
|
|
||||||
return OutputsSpec::Names { std::move(outputsToInstall) };
|
|
||||||
},
|
|
||||||
[&](const ExtendedOutputsSpec::Explicit & e) -> OutputsSpec {
|
|
||||||
return e;
|
|
||||||
},
|
|
||||||
}, extendedOutputsSpec.raw()),
|
|
||||||
},
|
|
||||||
.info = {
|
|
||||||
.priority = priority,
|
|
||||||
.originalRef = flakeRef,
|
|
||||||
.resolvedRef = getLockedFlake()->flake.lockedRef,
|
|
||||||
.attrPath = attrPath,
|
|
||||||
.extendedOutputsSpec = extendedOutputsSpec,
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<Value *, PosIdx> InstallableFlake::toValue(EvalState & state)
|
|
||||||
{
|
|
||||||
return {&getCursor(state)->forceValue(), noPos};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<ref<eval_cache::AttrCursor>>
|
|
||||||
InstallableFlake::getCursors(EvalState & state)
|
|
||||||
{
|
|
||||||
auto evalCache = openEvalCache(state,
|
|
||||||
std::make_shared<flake::LockedFlake>(lockFlake(state, flakeRef, lockFlags)));
|
|
||||||
|
|
||||||
auto root = evalCache->getRoot();
|
|
||||||
|
|
||||||
std::vector<ref<eval_cache::AttrCursor>> res;
|
|
||||||
|
|
||||||
Suggestions suggestions;
|
|
||||||
auto attrPaths = getActualAttrPaths();
|
|
||||||
|
|
||||||
for (auto & attrPath : attrPaths) {
|
|
||||||
debug("trying flake output attribute '%s'", attrPath);
|
|
||||||
|
|
||||||
auto attr = root->findAlongAttrPath(parseAttrPath(state, attrPath));
|
|
||||||
if (attr) {
|
|
||||||
res.push_back(ref(*attr));
|
|
||||||
} else {
|
|
||||||
suggestions += attr.getSuggestions();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res.size() == 0)
|
|
||||||
throw Error(
|
|
||||||
suggestions,
|
|
||||||
"flake '%s' does not provide attribute %s",
|
|
||||||
flakeRef,
|
|
||||||
showAttrPaths(attrPaths));
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<flake::LockedFlake> InstallableFlake::getLockedFlake() const
|
|
||||||
{
|
|
||||||
if (!_lockedFlake) {
|
|
||||||
flake::LockFlags lockFlagsApplyConfig = lockFlags;
|
|
||||||
lockFlagsApplyConfig.applyNixConfig = true;
|
|
||||||
_lockedFlake = std::make_shared<flake::LockedFlake>(lockFlake(*state, flakeRef, lockFlagsApplyConfig));
|
|
||||||
}
|
|
||||||
return _lockedFlake;
|
|
||||||
}
|
|
||||||
|
|
||||||
FlakeRef InstallableFlake::nixpkgsFlakeRef() const
|
|
||||||
{
|
|
||||||
auto lockedFlake = getLockedFlake();
|
|
||||||
|
|
||||||
if (auto nixpkgsInput = lockedFlake->lockFile.findInput({"nixpkgs"})) {
|
|
||||||
if (auto lockedNode = std::dynamic_pointer_cast<const flake::LockedNode>(nixpkgsInput)) {
|
|
||||||
debug("using nixpkgs flake '%s'", lockedNode->lockedRef);
|
|
||||||
return std::move(lockedNode->lockedRef);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Installable::nixpkgsFlakeRef();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
|
std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
|
||||||
ref<Store> store, std::vector<std::string> ss)
|
ref<Store> store, std::vector<std::string> ss)
|
||||||
{
|
{
|
||||||
|
@ -739,9 +456,8 @@ std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
|
||||||
auto [prefix, extendedOutputsSpec] = ExtendedOutputsSpec::parse(s);
|
auto [prefix, extendedOutputsSpec] = ExtendedOutputsSpec::parse(s);
|
||||||
result.push_back(
|
result.push_back(
|
||||||
std::make_shared<InstallableAttrPath>(
|
std::make_shared<InstallableAttrPath>(
|
||||||
state, *this, vFile,
|
InstallableAttrPath::parse(
|
||||||
prefix == "." ? "" : std::string { prefix },
|
state, *this, vFile, prefix, extendedOutputsSpec)));
|
||||||
extendedOutputsSpec));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -993,8 +709,8 @@ void InstallablesCommand::prepare()
|
||||||
installables = load();
|
installables = load();
|
||||||
}
|
}
|
||||||
|
|
||||||
Installables InstallablesCommand::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.
|
||||||
|
@ -1004,11 +720,8 @@ Installables InstallablesCommand::load() {
|
||||||
|
|
||||||
std::vector<std::string> InstallablesCommand::getFlakesForCompletion()
|
std::vector<std::string> InstallablesCommand::getFlakesForCompletion()
|
||||||
{
|
{
|
||||||
if (_installables.empty()) {
|
if (_installables.empty() && useDefaultInstallables())
|
||||||
if (useDefaultInstallables())
|
return {"."};
|
||||||
return {"."};
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return _installables;
|
return _installables;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -161,54 +161,4 @@ struct Installable
|
||||||
|
|
||||||
typedef std::vector<std::shared_ptr<Installable>> Installables;
|
typedef std::vector<std::shared_ptr<Installable>> Installables;
|
||||||
|
|
||||||
struct InstallableValue : Installable
|
|
||||||
{
|
|
||||||
ref<EvalState> state;
|
|
||||||
|
|
||||||
InstallableValue(ref<EvalState> state) : state(state) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct InstallableFlake : InstallableValue
|
|
||||||
{
|
|
||||||
FlakeRef flakeRef;
|
|
||||||
Strings attrPaths;
|
|
||||||
Strings prefixes;
|
|
||||||
ExtendedOutputsSpec extendedOutputsSpec;
|
|
||||||
const flake::LockFlags & lockFlags;
|
|
||||||
mutable std::shared_ptr<flake::LockedFlake> _lockedFlake;
|
|
||||||
|
|
||||||
InstallableFlake(
|
|
||||||
SourceExprCommand * cmd,
|
|
||||||
ref<EvalState> state,
|
|
||||||
FlakeRef && flakeRef,
|
|
||||||
std::string_view fragment,
|
|
||||||
ExtendedOutputsSpec extendedOutputsSpec,
|
|
||||||
Strings attrPaths,
|
|
||||||
Strings prefixes,
|
|
||||||
const flake::LockFlags & lockFlags);
|
|
||||||
|
|
||||||
std::string what() const override { return flakeRef.to_string() + "#" + *attrPaths.begin(); }
|
|
||||||
|
|
||||||
std::vector<std::string> getActualAttrPaths();
|
|
||||||
|
|
||||||
Value * getFlakeOutputs(EvalState & state, const flake::LockedFlake & lockedFlake);
|
|
||||||
|
|
||||||
DerivedPathsWithInfo toDerivedPaths() override;
|
|
||||||
|
|
||||||
std::pair<Value *, PosIdx> toValue(EvalState & state) override;
|
|
||||||
|
|
||||||
/* Get a cursor to every attrpath in getActualAttrPaths()
|
|
||||||
that exists. However if none exists, throw an exception. */
|
|
||||||
std::vector<ref<eval_cache::AttrCursor>>
|
|
||||||
getCursors(EvalState & state) override;
|
|
||||||
|
|
||||||
std::shared_ptr<flake::LockedFlake> getLockedFlake() const;
|
|
||||||
|
|
||||||
FlakeRef nixpkgsFlakeRef() const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
ref<eval_cache::EvalCache> openEvalCache(
|
|
||||||
EvalState & state,
|
|
||||||
std::shared_ptr<flake::LockedFlake> lockedFlake);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ libcmd_DIR := $(d)
|
||||||
|
|
||||||
libcmd_SOURCES := $(wildcard $(d)/*.cc)
|
libcmd_SOURCES := $(wildcard $(d)/*.cc)
|
||||||
|
|
||||||
libcmd_CXXFLAGS += -I src/libutil -I src/libstore -I src/libexpr -I src/libmain -I src/libfetchers -I src/nix
|
libcmd_CXXFLAGS += -I src/libutil -I src/libstore -I src/libexpr -I src/libmain -I src/libfetchers
|
||||||
|
|
||||||
libcmd_LDFLAGS = $(EDITLINE_LIBS) $(LOWDOWN_LIBS) -pthread
|
libcmd_LDFLAGS = $(EDITLINE_LIBS) $(LOWDOWN_LIBS) -pthread
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@ extern "C" {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "repl.hh"
|
||||||
|
|
||||||
#include "ansicolor.hh"
|
#include "ansicolor.hh"
|
||||||
#include "shared.hh"
|
#include "shared.hh"
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
|
@ -31,7 +33,9 @@ extern "C" {
|
||||||
#include "get-drvs.hh"
|
#include "get-drvs.hh"
|
||||||
#include "derivations.hh"
|
#include "derivations.hh"
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "command.hh"
|
#include "flake/flake.hh"
|
||||||
|
#include "flake/lockfile.hh"
|
||||||
|
#include "editor-for.hh"
|
||||||
#include "finally.hh"
|
#include "finally.hh"
|
||||||
#include "markdown.hh"
|
#include "markdown.hh"
|
||||||
#include "local-fs-store.hh"
|
#include "local-fs-store.hh"
|
||||||
|
@ -45,18 +49,16 @@ extern "C" {
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
struct NixRepl
|
struct NixRepl
|
||||||
|
: AbstractNixRepl,
|
||||||
#if HAVE_BOEHMGC
|
#if HAVE_BOEHMGC
|
||||||
: gc
|
gc
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
std::string curDir;
|
std::string curDir;
|
||||||
ref<EvalState> state;
|
|
||||||
Bindings * autoArgs;
|
|
||||||
|
|
||||||
size_t debugTraceIndex;
|
size_t debugTraceIndex;
|
||||||
|
|
||||||
Strings loadedFiles;
|
Strings loadedFiles;
|
||||||
typedef std::vector<std::pair<Value*,std::string>> AnnotatedValues;
|
|
||||||
std::function<AnnotatedValues()> getValues;
|
std::function<AnnotatedValues()> getValues;
|
||||||
|
|
||||||
const static int envSize = 32768;
|
const static int envSize = 32768;
|
||||||
|
@ -69,8 +71,11 @@ struct NixRepl
|
||||||
|
|
||||||
NixRepl(const Strings & searchPath, nix::ref<Store> store,ref<EvalState> state,
|
NixRepl(const Strings & searchPath, nix::ref<Store> store,ref<EvalState> state,
|
||||||
std::function<AnnotatedValues()> getValues);
|
std::function<AnnotatedValues()> getValues);
|
||||||
~NixRepl();
|
virtual ~NixRepl();
|
||||||
void mainLoop();
|
|
||||||
|
void mainLoop() override;
|
||||||
|
void initEnv() override;
|
||||||
|
|
||||||
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);
|
||||||
|
@ -78,7 +83,6 @@ struct NixRepl
|
||||||
|
|
||||||
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 loadFiles();
|
void loadFiles();
|
||||||
void reloadFiles();
|
void reloadFiles();
|
||||||
void addAttrsToScope(Value & attrs);
|
void addAttrsToScope(Value & attrs);
|
||||||
|
@ -92,7 +96,6 @@ struct NixRepl
|
||||||
std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth, ValuesSeen & seen);
|
std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth, ValuesSeen & seen);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
std::string removeWhitespace(std::string s)
|
std::string removeWhitespace(std::string s)
|
||||||
{
|
{
|
||||||
s = chomp(s);
|
s = chomp(s);
|
||||||
|
@ -104,7 +107,7 @@ std::string removeWhitespace(std::string s)
|
||||||
|
|
||||||
NixRepl::NixRepl(const Strings & searchPath, nix::ref<Store> store, ref<EvalState> state,
|
NixRepl::NixRepl(const Strings & searchPath, nix::ref<Store> store, ref<EvalState> state,
|
||||||
std::function<NixRepl::AnnotatedValues()> getValues)
|
std::function<NixRepl::AnnotatedValues()> getValues)
|
||||||
: state(state)
|
: AbstractNixRepl(state)
|
||||||
, debugTraceIndex(0)
|
, debugTraceIndex(0)
|
||||||
, getValues(getValues)
|
, getValues(getValues)
|
||||||
, staticEnv(new StaticEnv(false, state->staticBaseEnv.get()))
|
, staticEnv(new StaticEnv(false, state->staticBaseEnv.get()))
|
||||||
|
@ -1029,8 +1032,22 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
void runRepl(
|
|
||||||
ref<EvalState>evalState,
|
std::unique_ptr<AbstractNixRepl> AbstractNixRepl::create(
|
||||||
|
const Strings & searchPath, nix::ref<Store> store, ref<EvalState> state,
|
||||||
|
std::function<AnnotatedValues()> getValues)
|
||||||
|
{
|
||||||
|
return std::make_unique<NixRepl>(
|
||||||
|
searchPath,
|
||||||
|
openStore(),
|
||||||
|
state,
|
||||||
|
getValues
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AbstractNixRepl::runSimple(
|
||||||
|
ref<EvalState> evalState,
|
||||||
const ValMap & extraEnv)
|
const ValMap & extraEnv)
|
||||||
{
|
{
|
||||||
auto getValues = [&]()->NixRepl::AnnotatedValues{
|
auto getValues = [&]()->NixRepl::AnnotatedValues{
|
||||||
|
@ -1054,91 +1071,4 @@ void runRepl(
|
||||||
repl->mainLoop();
|
repl->mainLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CmdRepl : InstallablesCommand
|
|
||||||
{
|
|
||||||
CmdRepl() {
|
|
||||||
evalSettings.pureEval = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void prepare() override
|
|
||||||
{
|
|
||||||
if (!settings.isExperimentalFeatureEnabled(Xp::ReplFlake) && !(file) && this->_installables.size() >= 1) {
|
|
||||||
warn("future versions of Nix will require using `--file` to load a file");
|
|
||||||
if (this->_installables.size() > 1)
|
|
||||||
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 {""};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool useDefaultInstallables() override
|
|
||||||
{
|
|
||||||
return file.has_value() or expr.has_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool forceImpureByDefault() override
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string description() override
|
|
||||||
{
|
|
||||||
return "start an interactive environment for evaluating Nix expressions";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string doc() override
|
|
||||||
{
|
|
||||||
return
|
|
||||||
#include "repl.md"
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
void run(ref<Store> store) override
|
|
||||||
{
|
|
||||||
auto state = getEvalState();
|
|
||||||
auto getValues = [&]()->NixRepl::AnnotatedValues{
|
|
||||||
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->initEnv();
|
|
||||||
repl->mainLoop();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static auto rCmdRepl = registerCommand<CmdRepl>("repl");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
39
src/libcmd/repl.hh
Normal file
39
src/libcmd/repl.hh
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "eval.hh"
|
||||||
|
|
||||||
|
#if HAVE_BOEHMGC
|
||||||
|
#define GC_INCLUDE_NEW
|
||||||
|
#include <gc/gc_cpp.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
struct AbstractNixRepl
|
||||||
|
{
|
||||||
|
ref<EvalState> state;
|
||||||
|
Bindings * autoArgs;
|
||||||
|
|
||||||
|
AbstractNixRepl(ref<EvalState> state)
|
||||||
|
: state(state)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
virtual ~AbstractNixRepl()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
typedef std::vector<std::pair<Value*,std::string>> AnnotatedValues;
|
||||||
|
|
||||||
|
static std::unique_ptr<AbstractNixRepl> create(
|
||||||
|
const Strings & searchPath, nix::ref<Store> store, ref<EvalState> state,
|
||||||
|
std::function<AnnotatedValues()> getValues);
|
||||||
|
|
||||||
|
static void runSimple(
|
||||||
|
ref<EvalState> evalState,
|
||||||
|
const ValMap & extraEnv);
|
||||||
|
|
||||||
|
virtual void initEnv() = 0;
|
||||||
|
|
||||||
|
virtual void mainLoop() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -3057,9 +3057,9 @@ static RegisterPrimOp primop_foldlStrict({
|
||||||
.doc = R"(
|
.doc = R"(
|
||||||
Reduce a list by applying a binary operator, from left to right,
|
Reduce a list by applying a binary operator, from left to right,
|
||||||
e.g. `foldl' op nul [x0 x1 x2 ...] = op (op (op nul x0) x1) x2)
|
e.g. `foldl' op nul [x0 x1 x2 ...] = op (op (op nul x0) x1) x2)
|
||||||
...`. The operator is applied strictly, i.e., its arguments are
|
...`. For example, `foldl' (x: y: x + y) 0 [1 2 3]` evaluates to 6.
|
||||||
evaluated first. For example, `foldl' (x: y: x + y) 0 [1 2 3]`
|
The return value of each application of `op` is evaluated immediately,
|
||||||
evaluates to 6.
|
even for intermediate values.
|
||||||
)",
|
)",
|
||||||
.fun = prim_foldlStrict,
|
.fun = prim_foldlStrict,
|
||||||
});
|
});
|
||||||
|
|
|
@ -971,10 +971,6 @@ void LocalDerivationGoal::startBuilder()
|
||||||
"nobody:x:65534:65534:Nobody:/:/noshell\n",
|
"nobody:x:65534:65534:Nobody:/:/noshell\n",
|
||||||
sandboxUid(), sandboxGid(), settings.sandboxBuildDir));
|
sandboxUid(), sandboxGid(), settings.sandboxBuildDir));
|
||||||
|
|
||||||
/* Make /etc unwritable */
|
|
||||||
if (!parsedDrv->useUidRange())
|
|
||||||
chmod_(chrootRootDir + "/etc", 0555);
|
|
||||||
|
|
||||||
/* Save the mount- and user namespace of the child. We have to do this
|
/* Save the mount- and user namespace of the child. We have to do this
|
||||||
*before* the child does a chroot. */
|
*before* the child does a chroot. */
|
||||||
sandboxMountNamespace = open(fmt("/proc/%d/ns/mnt", (pid_t) pid).c_str(), O_RDONLY);
|
sandboxMountNamespace = open(fmt("/proc/%d/ns/mnt", (pid_t) pid).c_str(), O_RDONLY);
|
||||||
|
@ -1855,6 +1851,10 @@ void LocalDerivationGoal::runChild()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Make /etc unwritable */
|
||||||
|
if (!parsedDrv->useUidRange())
|
||||||
|
chmod_(chrootRootDir + "/etc", 0555);
|
||||||
|
|
||||||
/* Unshare this mount namespace. This is necessary because
|
/* Unshare this mount namespace. This is necessary because
|
||||||
pivot_root() below changes the root of the mount
|
pivot_root() below changes the root of the mount
|
||||||
namespace. This means that the call to setns() in
|
namespace. This means that the call to setns() in
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "worker-protocol.hh"
|
#include "worker-protocol.hh"
|
||||||
#include "fs-accessor.hh"
|
#include "fs-accessor.hh"
|
||||||
#include <boost/container/small_vector.hpp>
|
#include <boost/container/small_vector.hpp>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
@ -890,4 +891,63 @@ std::optional<BasicDerivation> Derivation::tryResolve(
|
||||||
|
|
||||||
const Hash impureOutputHash = hashString(htSHA256, "impure");
|
const Hash impureOutputHash = hashString(htSHA256, "impure");
|
||||||
|
|
||||||
|
nlohmann::json DerivationOutput::toJSON(
|
||||||
|
const Store & store, std::string_view drvName, std::string_view outputName) const
|
||||||
|
{
|
||||||
|
nlohmann::json res = nlohmann::json::object();
|
||||||
|
std::visit(overloaded {
|
||||||
|
[&](const DerivationOutput::InputAddressed & doi) {
|
||||||
|
res["path"] = store.printStorePath(doi.path);
|
||||||
|
},
|
||||||
|
[&](const DerivationOutput::CAFixed & dof) {
|
||||||
|
res["path"] = store.printStorePath(dof.path(store, drvName, outputName));
|
||||||
|
res["hashAlgo"] = dof.hash.printMethodAlgo();
|
||||||
|
res["hash"] = dof.hash.hash.to_string(Base16, false);
|
||||||
|
},
|
||||||
|
[&](const DerivationOutput::CAFloating & dof) {
|
||||||
|
res["hashAlgo"] = makeFileIngestionPrefix(dof.method) + printHashType(dof.hashType);
|
||||||
|
},
|
||||||
|
[&](const DerivationOutput::Deferred &) {},
|
||||||
|
[&](const DerivationOutput::Impure & doi) {
|
||||||
|
res["hashAlgo"] = makeFileIngestionPrefix(doi.method) + printHashType(doi.hashType);
|
||||||
|
res["impure"] = true;
|
||||||
|
},
|
||||||
|
}, raw());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlohmann::json Derivation::toJSON(const Store & store) const
|
||||||
|
{
|
||||||
|
nlohmann::json res = nlohmann::json::object();
|
||||||
|
|
||||||
|
{
|
||||||
|
nlohmann::json & outputsObj = res["outputs"];
|
||||||
|
outputsObj = nlohmann::json::object();
|
||||||
|
for (auto & [outputName, output] : outputs) {
|
||||||
|
outputsObj[outputName] = output.toJSON(store, name, outputName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto& inputsList = res["inputSrcs"];
|
||||||
|
inputsList = nlohmann::json ::array();
|
||||||
|
for (auto & input : inputSrcs)
|
||||||
|
inputsList.emplace_back(store.printStorePath(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto& inputDrvsObj = res["inputDrvs"];
|
||||||
|
inputDrvsObj = nlohmann::json ::object();
|
||||||
|
for (auto & input : inputDrvs)
|
||||||
|
inputDrvsObj[store.printStorePath(input.first)] = input.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
res["system"] = platform;
|
||||||
|
res["builder"] = builder;
|
||||||
|
res["args"] = args;
|
||||||
|
res["env"] = env;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,11 @@ struct DerivationOutput : _DerivationOutputRaw
|
||||||
inline const Raw & raw() const {
|
inline const Raw & raw() const {
|
||||||
return static_cast<const Raw &>(*this);
|
return static_cast<const Raw &>(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nlohmann::json toJSON(
|
||||||
|
const Store & store,
|
||||||
|
std::string_view drvName,
|
||||||
|
std::string_view outputName) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<std::string, DerivationOutput> DerivationOutputs;
|
typedef std::map<std::string, DerivationOutput> DerivationOutputs;
|
||||||
|
@ -210,6 +215,8 @@ struct Derivation : BasicDerivation
|
||||||
Derivation() = default;
|
Derivation() = default;
|
||||||
Derivation(const BasicDerivation & bd) : BasicDerivation(bd) { }
|
Derivation(const BasicDerivation & bd) : BasicDerivation(bd) { }
|
||||||
Derivation(BasicDerivation && bd) : BasicDerivation(std::move(bd)) { }
|
Derivation(BasicDerivation && bd) : BasicDerivation(std::move(bd)) { }
|
||||||
|
|
||||||
|
nlohmann::json toJSON(const Store & store) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
124
src/libstore/tests/derivation.cc
Normal file
124
src/libstore/tests/derivation.cc
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "derivations.hh"
|
||||||
|
|
||||||
|
#include "tests/libstore.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
class DerivationTest : public LibStoreTest
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
#define TEST_JSON(TYPE, NAME, STR, VAL, ...) \
|
||||||
|
TEST_F(DerivationTest, TYPE ## _ ## NAME ## _to_json) { \
|
||||||
|
using nlohmann::literals::operator "" _json; \
|
||||||
|
ASSERT_EQ( \
|
||||||
|
STR ## _json, \
|
||||||
|
(TYPE { VAL }).toJSON(*store __VA_OPT__(,) __VA_ARGS__)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_JSON(DerivationOutput, inputAddressed,
|
||||||
|
R"({
|
||||||
|
"path": "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"
|
||||||
|
})",
|
||||||
|
(DerivationOutput::InputAddressed {
|
||||||
|
.path = store->parseStorePath("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"),
|
||||||
|
}),
|
||||||
|
"drv-name", "output-name")
|
||||||
|
|
||||||
|
TEST_JSON(DerivationOutput, caFixed,
|
||||||
|
R"({
|
||||||
|
"hashAlgo": "r:sha256",
|
||||||
|
"hash": "894517c9163c896ec31a2adbd33c0681fd5f45b2c0ef08a64c92a03fb97f390f",
|
||||||
|
"path": "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"
|
||||||
|
})",
|
||||||
|
(DerivationOutput::CAFixed {
|
||||||
|
.hash = {
|
||||||
|
.method = FileIngestionMethod::Recursive,
|
||||||
|
.hash = Hash::parseAnyPrefixed("sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
"drv-name", "output-name")
|
||||||
|
|
||||||
|
TEST_JSON(DerivationOutput, caFloating,
|
||||||
|
R"({
|
||||||
|
"hashAlgo": "r:sha256"
|
||||||
|
})",
|
||||||
|
(DerivationOutput::CAFloating {
|
||||||
|
.method = FileIngestionMethod::Recursive,
|
||||||
|
.hashType = htSHA256,
|
||||||
|
}),
|
||||||
|
"drv-name", "output-name")
|
||||||
|
|
||||||
|
TEST_JSON(DerivationOutput, deferred,
|
||||||
|
R"({ })",
|
||||||
|
DerivationOutput::Deferred { },
|
||||||
|
"drv-name", "output-name")
|
||||||
|
|
||||||
|
TEST_JSON(DerivationOutput, impure,
|
||||||
|
R"({
|
||||||
|
"hashAlgo": "r:sha256",
|
||||||
|
"impure": true
|
||||||
|
})",
|
||||||
|
(DerivationOutput::Impure {
|
||||||
|
.method = FileIngestionMethod::Recursive,
|
||||||
|
.hashType = htSHA256,
|
||||||
|
}),
|
||||||
|
"drv-name", "output-name")
|
||||||
|
|
||||||
|
TEST_JSON(Derivation, impure,
|
||||||
|
R"({
|
||||||
|
"inputSrcs": [
|
||||||
|
"/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"
|
||||||
|
],
|
||||||
|
"inputDrvs": {
|
||||||
|
"/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv": [
|
||||||
|
"cat",
|
||||||
|
"dog"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"system": "wasm-sel4",
|
||||||
|
"builder": "foo",
|
||||||
|
"args": [
|
||||||
|
"bar",
|
||||||
|
"baz"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"BIG_BAD": "WOLF"
|
||||||
|
},
|
||||||
|
"outputs": {}
|
||||||
|
})",
|
||||||
|
({
|
||||||
|
Derivation drv;
|
||||||
|
drv.inputSrcs = {
|
||||||
|
store->parseStorePath("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"),
|
||||||
|
};
|
||||||
|
drv.inputDrvs = {
|
||||||
|
{
|
||||||
|
store->parseStorePath("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv"),
|
||||||
|
{
|
||||||
|
"cat",
|
||||||
|
"dog",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
drv.platform = "wasm-sel4";
|
||||||
|
drv.builder = "foo";
|
||||||
|
drv.args = {
|
||||||
|
"bar",
|
||||||
|
"baz",
|
||||||
|
};
|
||||||
|
drv.env = {
|
||||||
|
{
|
||||||
|
"BIG_BAD",
|
||||||
|
"WOLF",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
drv;
|
||||||
|
}))
|
||||||
|
|
||||||
|
#undef TEST_JSON
|
||||||
|
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
#include "command.hh"
|
#include "command.hh"
|
||||||
|
#include "installable-flake.hh"
|
||||||
#include "common-args.hh"
|
#include "common-args.hh"
|
||||||
#include "shared.hh"
|
#include "shared.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
#include "command.hh"
|
#include "command.hh"
|
||||||
|
#include "installable-flake.hh"
|
||||||
#include "common-args.hh"
|
#include "common-args.hh"
|
||||||
#include "shared.hh"
|
#include "shared.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
#include "attr-path.hh"
|
#include "attr-path.hh"
|
||||||
#include "progress-bar.hh"
|
#include "progress-bar.hh"
|
||||||
|
#include "editor-for.hh"
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "command.hh"
|
#include "command.hh"
|
||||||
|
#include "installable-flake.hh"
|
||||||
#include "common-args.hh"
|
#include "common-args.hh"
|
||||||
#include "shared.hh"
|
#include "shared.hh"
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "command.hh"
|
#include "command.hh"
|
||||||
|
#include "installable-flake.hh"
|
||||||
#include "common-args.hh"
|
#include "common-args.hh"
|
||||||
#include "shared.hh"
|
#include "shared.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
|
|
95
src/nix/repl.cc
Normal file
95
src/nix/repl.cc
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
#include "eval.hh"
|
||||||
|
#include "globals.hh"
|
||||||
|
#include "command.hh"
|
||||||
|
#include "repl.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
struct CmdRepl : InstallablesCommand
|
||||||
|
{
|
||||||
|
CmdRepl() {
|
||||||
|
evalSettings.pureEval = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void prepare() override
|
||||||
|
{
|
||||||
|
if (!settings.isExperimentalFeatureEnabled(Xp::ReplFlake) && !(file) && this->_installables.size() >= 1) {
|
||||||
|
warn("future versions of Nix will require using `--file` to load a file");
|
||||||
|
if (this->_installables.size() > 1)
|
||||||
|
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 {""};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool useDefaultInstallables() override
|
||||||
|
{
|
||||||
|
return file.has_value() or expr.has_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool forceImpureByDefault() override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string description() override
|
||||||
|
{
|
||||||
|
return "start an interactive environment for evaluating Nix expressions";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string doc() override
|
||||||
|
{
|
||||||
|
return
|
||||||
|
#include "repl.md"
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
void run(ref<Store> store) override
|
||||||
|
{
|
||||||
|
auto state = getEvalState();
|
||||||
|
auto getValues = [&]()->AbstractNixRepl::AnnotatedValues{
|
||||||
|
auto installables = load();
|
||||||
|
AbstractNixRepl::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 = AbstractNixRepl::create(
|
||||||
|
searchPath,
|
||||||
|
openStore(),
|
||||||
|
state,
|
||||||
|
getValues
|
||||||
|
);
|
||||||
|
repl->autoArgs = getAutoArgs(*repl->state);
|
||||||
|
repl->initEnv();
|
||||||
|
repl->mainLoop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static auto rCmdRepl = registerCommand<CmdRepl>("repl");
|
||||||
|
|
||||||
|
}
|
|
@ -54,56 +54,8 @@ struct CmdShowDerivation : InstallablesCommand
|
||||||
for (auto & drvPath : drvPaths) {
|
for (auto & drvPath : drvPaths) {
|
||||||
if (!drvPath.isDerivation()) continue;
|
if (!drvPath.isDerivation()) continue;
|
||||||
|
|
||||||
json& drvObj = jsonRoot[store->printStorePath(drvPath)];
|
jsonRoot[store->printStorePath(drvPath)] =
|
||||||
|
store->readDerivation(drvPath).toJSON(*store);
|
||||||
auto drv = store->readDerivation(drvPath);
|
|
||||||
|
|
||||||
{
|
|
||||||
json& outputsObj = drvObj["outputs"];
|
|
||||||
outputsObj = json::object();
|
|
||||||
for (auto & [_outputName, output] : drv.outputs) {
|
|
||||||
auto & outputName = _outputName; // work around clang bug
|
|
||||||
auto& outputObj = outputsObj[outputName];
|
|
||||||
outputObj = json::object();
|
|
||||||
std::visit(overloaded {
|
|
||||||
[&](const DerivationOutput::InputAddressed & doi) {
|
|
||||||
outputObj["path"] = store->printStorePath(doi.path);
|
|
||||||
},
|
|
||||||
[&](const DerivationOutput::CAFixed & dof) {
|
|
||||||
outputObj["path"] = store->printStorePath(dof.path(*store, drv.name, outputName));
|
|
||||||
outputObj["hashAlgo"] = dof.hash.printMethodAlgo();
|
|
||||||
outputObj["hash"] = dof.hash.hash.to_string(Base16, false);
|
|
||||||
},
|
|
||||||
[&](const DerivationOutput::CAFloating & dof) {
|
|
||||||
outputObj["hashAlgo"] = makeFileIngestionPrefix(dof.method) + printHashType(dof.hashType);
|
|
||||||
},
|
|
||||||
[&](const DerivationOutput::Deferred &) {},
|
|
||||||
[&](const DerivationOutput::Impure & doi) {
|
|
||||||
outputObj["hashAlgo"] = makeFileIngestionPrefix(doi.method) + printHashType(doi.hashType);
|
|
||||||
outputObj["impure"] = true;
|
|
||||||
},
|
|
||||||
}, output.raw());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
auto& inputsList = drvObj["inputSrcs"];
|
|
||||||
inputsList = json::array();
|
|
||||||
for (auto & input : drv.inputSrcs)
|
|
||||||
inputsList.emplace_back(store->printStorePath(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
auto& inputDrvsObj = drvObj["inputDrvs"];
|
|
||||||
inputDrvsObj = json::object();
|
|
||||||
for (auto & input : drv.inputDrvs)
|
|
||||||
inputDrvsObj[store->printStorePath(input.first)] = input.second;
|
|
||||||
}
|
|
||||||
|
|
||||||
drvObj["system"] = drv.platform;
|
|
||||||
drvObj["builder"] = drv.builder;
|
|
||||||
drvObj["args"] = drv.args;
|
|
||||||
drvObj["env"] = drv.env;
|
|
||||||
}
|
}
|
||||||
std::cout << jsonRoot.dump(2) << std::endl;
|
std::cout << jsonRoot.dump(2) << std::endl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,7 +120,7 @@ let
|
||||||
|
|
||||||
makeTest = imageName: testName:
|
makeTest = imageName: testName:
|
||||||
let image = images.${imageName}; in
|
let image = images.${imageName}; in
|
||||||
with nixpkgsFor.${image.system};
|
with nixpkgsFor.${image.system}.native;
|
||||||
runCommand
|
runCommand
|
||||||
"installer-test-${imageName}-${testName}"
|
"installer-test-${imageName}-${testName}"
|
||||||
{ buildInputs = [ qemu_kvm openssh ];
|
{ buildInputs = [ qemu_kvm openssh ];
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Tests that the result of applying op is forced even if the value is never used
|
||||||
|
builtins.foldl'
|
||||||
|
(_: f: f null)
|
||||||
|
null
|
||||||
|
[ (_: throw "Not the final value, but is still forced!") (_: 23) ]
|
1
tests/lang/eval-okay-foldlStrict-lazy-elements.exp
Normal file
1
tests/lang/eval-okay-foldlStrict-lazy-elements.exp
Normal file
|
@ -0,0 +1 @@
|
||||||
|
42
|
9
tests/lang/eval-okay-foldlStrict-lazy-elements.nix
Normal file
9
tests/lang/eval-okay-foldlStrict-lazy-elements.nix
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# Tests that the rhs argument of op is not forced unconditionally
|
||||||
|
let
|
||||||
|
lst = builtins.foldl'
|
||||||
|
(acc: x: acc ++ [ x ])
|
||||||
|
[ ]
|
||||||
|
[ 42 (throw "this shouldn't be evaluated") ];
|
||||||
|
in
|
||||||
|
|
||||||
|
builtins.head lst
|
|
@ -0,0 +1 @@
|
||||||
|
42
|
|
@ -0,0 +1,6 @@
|
||||||
|
# Checks that the nul value for the accumulator is not forced unconditionally.
|
||||||
|
# Some languages provide a foldl' that is strict in this argument, but Nix does not.
|
||||||
|
builtins.foldl'
|
||||||
|
(_: x: x)
|
||||||
|
(throw "This is never forced")
|
||||||
|
[ "but the results of applying op are" 42 ]
|
Loading…
Add table
Add a link
Reference in a new issue