mirror of
https://github.com/NixOS/nix.git
synced 2025-11-24 03:09:35 +01:00
Merge commit '971382cab0' into progress-bar
This commit is contained in:
commit
c70a6c81bb
48 changed files with 547 additions and 168 deletions
16
.github/workflows/hydra_status.yml
vendored
Normal file
16
.github/workflows/hydra_status.yml
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
name: Hydra status
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: "12,42 * * * *"
|
||||||
|
workflow_dispatch:
|
||||||
|
jobs:
|
||||||
|
check_hydra_status:
|
||||||
|
name: Check Hydra status
|
||||||
|
if: github.repository_owner == 'NixOS'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2.4.0
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- run: bash scripts/check-hydra-status.sh
|
||||||
|
|
||||||
2
.version
2
.version
|
|
@ -1 +1 @@
|
||||||
2.5
|
2.5.0
|
||||||
13
configure.ac
13
configure.ac
|
|
@ -188,17 +188,24 @@ PKG_CHECK_MODULES([EDITLINE], [libeditline], [CXXFLAGS="$EDITLINE_CFLAGS $CXXFLA
|
||||||
[AC_MSG_ERROR([Nix requires libeditline; it was not found via pkg-config, but via its header, but required functions do not work. Maybe it is too old? >= 1.14 is required.])])
|
[AC_MSG_ERROR([Nix requires libeditline; it was not found via pkg-config, but via its header, but required functions do not work. Maybe it is too old? >= 1.14 is required.])])
|
||||||
])
|
])
|
||||||
|
|
||||||
# Look for libsodium, an optional dependency.
|
# Look for libsodium.
|
||||||
PKG_CHECK_MODULES([SODIUM], [libsodium], [CXXFLAGS="$SODIUM_CFLAGS $CXXFLAGS"])
|
PKG_CHECK_MODULES([SODIUM], [libsodium], [CXXFLAGS="$SODIUM_CFLAGS $CXXFLAGS"])
|
||||||
|
|
||||||
# Look for libbrotli{enc,dec}.
|
# Look for libbrotli{enc,dec}.
|
||||||
PKG_CHECK_MODULES([LIBBROTLI], [libbrotlienc libbrotlidec], [CXXFLAGS="$LIBBROTLI_CFLAGS $CXXFLAGS"])
|
PKG_CHECK_MODULES([LIBBROTLI], [libbrotlienc libbrotlidec], [CXXFLAGS="$LIBBROTLI_CFLAGS $CXXFLAGS"])
|
||||||
|
|
||||||
# Look for libcpuid.
|
# Look for libcpuid.
|
||||||
|
have_libcpuid=
|
||||||
if test "$machine_name" = "x86_64"; then
|
if test "$machine_name" = "x86_64"; then
|
||||||
PKG_CHECK_MODULES([LIBCPUID], [libcpuid], [CXXFLAGS="$LIBCPUID_CFLAGS $CXXFLAGS"])
|
AC_ARG_ENABLE([cpuid],
|
||||||
|
AS_HELP_STRING([--disable-cpuid], [Do not determine microarchitecture levels with libcpuid (relevant to x86_64 only)]))
|
||||||
|
if test "x$enable_cpuid" != "xno"; then
|
||||||
|
PKG_CHECK_MODULES([LIBCPUID], [libcpuid],
|
||||||
|
[CXXFLAGS="$LIBCPUID_CFLAGS $CXXFLAGS"
|
||||||
have_libcpuid=1
|
have_libcpuid=1
|
||||||
AC_DEFINE([HAVE_LIBCPUID], [1], [Use libcpuid])
|
AC_DEFINE([HAVE_LIBCPUID], [1], [Use libcpuid])]
|
||||||
|
)
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
AC_SUBST(HAVE_LIBCPUID, [$have_libcpuid])
|
AC_SUBST(HAVE_LIBCPUID, [$have_libcpuid])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,13 @@ man-pages := $(foreach n, \
|
||||||
clean-files += $(d)/*.1 $(d)/*.5 $(d)/*.8
|
clean-files += $(d)/*.1 $(d)/*.5 $(d)/*.8
|
||||||
|
|
||||||
# Provide a dummy environment for nix, so that it will not access files outside the macOS sandbox.
|
# Provide a dummy environment for nix, so that it will not access files outside the macOS sandbox.
|
||||||
|
# Set cores to 0 because otherwise nix show-config resolves the cores based on the current machine
|
||||||
dummy-env = env -i \
|
dummy-env = env -i \
|
||||||
HOME=/dummy \
|
HOME=/dummy \
|
||||||
NIX_CONF_DIR=/dummy \
|
NIX_CONF_DIR=/dummy \
|
||||||
NIX_SSL_CERT_FILE=/dummy/no-ca-bundle.crt \
|
NIX_SSL_CERT_FILE=/dummy/no-ca-bundle.crt \
|
||||||
NIX_STATE_DIR=/dummy
|
NIX_STATE_DIR=/dummy \
|
||||||
|
NIX_CONFIG='cores = 0'
|
||||||
|
|
||||||
nix-eval = $(dummy-env) $(bindir)/nix eval --experimental-features nix-command -I nix/corepkgs=corepkgs --store dummy:// --impure --raw
|
nix-eval = $(dummy-env) $(bindir)/nix eval --experimental-features nix-command -I nix/corepkgs=corepkgs --store dummy:// --impure --raw
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,25 @@ variables are set up so that those dependencies can be found:
|
||||||
$ nix-shell
|
$ nix-shell
|
||||||
```
|
```
|
||||||
|
|
||||||
|
or if you have a flake-enabled nix:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ nix develop
|
||||||
|
```
|
||||||
|
|
||||||
|
To get a shell with a different compilation environment (e.g. stdenv,
|
||||||
|
gccStdenv, clangStdenv, clang11Stdenv):
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ nix-shell -A devShells.x86_64-linux.clang11StdenvPackages
|
||||||
|
```
|
||||||
|
|
||||||
|
or if you have a flake-enabled nix:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ nix develop .#clang11StdenvPackages
|
||||||
|
```
|
||||||
|
|
||||||
To build Nix itself in this shell:
|
To build Nix itself in this shell:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
|
|
|
||||||
|
|
@ -98,3 +98,7 @@
|
||||||
store. It can contain regular files, directories and symbolic
|
store. It can contain regular files, directories and symbolic
|
||||||
links. NARs are generated and unpacked using `nix-store --dump`
|
links. NARs are generated and unpacked using `nix-store --dump`
|
||||||
and `nix-store --restore`.
|
and `nix-store --restore`.
|
||||||
|
- `∅` \
|
||||||
|
The empty set symbol. In the context of profile history, this denotes a package is not present in a particular version of the profile.
|
||||||
|
- `ε` \
|
||||||
|
The epsilon symbol. In the context of a package, this means the version is empty. More precisely, the derivation does not have a version attribute.
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,30 @@ this to run the installer, but it may help if you run into trouble:
|
||||||
- update `/etc/synthetic.conf` to direct macOS to create a "synthetic"
|
- update `/etc/synthetic.conf` to direct macOS to create a "synthetic"
|
||||||
empty root directory to mount your volume
|
empty root directory to mount your volume
|
||||||
- specify mount options for the volume in `/etc/fstab`
|
- specify mount options for the volume in `/etc/fstab`
|
||||||
|
- `rw`: read-write
|
||||||
|
- `noauto`: prevent the system from auto-mounting the volume (so the
|
||||||
|
LaunchDaemon mentioned below can control mounting it, and to avoid
|
||||||
|
masking problems with that mounting service).
|
||||||
|
- `nobrowse`: prevent the Nix Store volume from showing up on your
|
||||||
|
desktop; also keeps Spotlight from spending resources to index
|
||||||
|
this volume
|
||||||
|
<!-- TODO:
|
||||||
|
- `suid`: honor setuid? surely not? ...
|
||||||
|
- `owners`: honor file ownership on the volume
|
||||||
|
|
||||||
|
For now I'll avoid pretending to understand suid/owners more
|
||||||
|
than I do. There've been some vague reports of file-ownership
|
||||||
|
and permission issues, particularly in cloud/VM/headless setups.
|
||||||
|
My pet theory is that this has something to do with these setups
|
||||||
|
not having a token that gets delegated to initial/admin accounts
|
||||||
|
on macOS. See scripts/create-darwin-volume.sh for a little more.
|
||||||
|
|
||||||
|
In any case, by Dec 4 2021, it _seems_ like some combination of
|
||||||
|
suid, owners, and calling diskutil enableOwnership have stopped
|
||||||
|
new reports from coming in. But I hesitate to celebrate because we
|
||||||
|
haven't really named and catalogued the behavior, understood what
|
||||||
|
we're fixing, and validated that all 3 components are essential.
|
||||||
|
-->
|
||||||
- if you have FileVault enabled
|
- if you have FileVault enabled
|
||||||
- generate an encryption password
|
- generate an encryption password
|
||||||
- put it in your system Keychain
|
- put it in your system Keychain
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
To run the latest stable release of Nix with Docker run the following command:
|
To run the latest stable release of Nix with Docker run the following command:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ docker -ti run nixos/nix
|
$ docker run -ti nixos/nix
|
||||||
Unable to find image 'nixos/nix:latest' locally
|
Unable to find image 'nixos/nix:latest' locally
|
||||||
latest: Pulling from nixos/nix
|
latest: Pulling from nixos/nix
|
||||||
5843afab3874: Pull complete
|
5843afab3874: Pull complete
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,11 @@
|
||||||
obtained from the its repository
|
obtained from the its repository
|
||||||
<https://github.com/troglobit/editline>.
|
<https://github.com/troglobit/editline>.
|
||||||
|
|
||||||
|
- The `libsodium` library for verifying cryptographic signatures
|
||||||
|
of contents fetched from binary caches.
|
||||||
|
It can be obtained from the official web site
|
||||||
|
<https://libsodium.org>.
|
||||||
|
|
||||||
- Recent versions of Bison and Flex to build the parser. (This is
|
- Recent versions of Bison and Flex to build the parser. (This is
|
||||||
because Nix needs GLR support in Bison and reentrancy support in
|
because Nix needs GLR support in Bison and reentrancy support in
|
||||||
Flex.) For Bison, you need version 2.6, which can be obtained from
|
Flex.) For Bison, you need version 2.6, which can be obtained from
|
||||||
|
|
@ -58,3 +63,11 @@
|
||||||
`--disable-seccomp-sandboxing` option to the `configure` script (Not
|
`--disable-seccomp-sandboxing` option to the `configure` script (Not
|
||||||
recommended unless your system doesn't support `libseccomp`). To get
|
recommended unless your system doesn't support `libseccomp`). To get
|
||||||
the library, visit <https://github.com/seccomp/libseccomp>.
|
the library, visit <https://github.com/seccomp/libseccomp>.
|
||||||
|
|
||||||
|
- On 64-bit x86 machines only, `libcpuid` library
|
||||||
|
is used to determine which microarchitecture levels are supported
|
||||||
|
(e.g., as whether to have `x86_64-v2-linux` among additional system types).
|
||||||
|
The library is available from its homepage
|
||||||
|
<http://libcpuid.sourceforge.net>.
|
||||||
|
This is an optional dependency and can be disabled
|
||||||
|
by providing a `--disable-cpuid` to the `configure` script.
|
||||||
|
|
|
||||||
|
|
@ -5,3 +5,8 @@
|
||||||
* `nix develop` now has a flag `--unpack` to run `unpackPhase`.
|
* `nix develop` now has a flag `--unpack` to run `unpackPhase`.
|
||||||
|
|
||||||
* Lists can now be compared lexicographically using the `<` operator.
|
* Lists can now be compared lexicographically using the `<` operator.
|
||||||
|
|
||||||
|
* New built-in function: `builtins.groupBy`, with the same functionality as
|
||||||
|
Nixpkgs' `lib.groupBy`, but faster.
|
||||||
|
|
||||||
|
* `nix repl` now has a `:log` command.
|
||||||
|
|
|
||||||
70
flake.nix
70
flake.nix
|
|
@ -22,15 +22,36 @@
|
||||||
|
|
||||||
crossSystems = [ "armv6l-linux" "armv7l-linux" ];
|
crossSystems = [ "armv6l-linux" "armv7l-linux" ];
|
||||||
|
|
||||||
|
stdenvs = [ "gccStdenv" "clangStdenv" "clang11Stdenv" "stdenv" ];
|
||||||
|
|
||||||
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f system);
|
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f system);
|
||||||
|
forAllSystemsAndStdenvs = f: forAllSystems (system:
|
||||||
|
nixpkgs.lib.listToAttrs
|
||||||
|
(map
|
||||||
|
(n:
|
||||||
|
nixpkgs.lib.nameValuePair "${n}Packages" (
|
||||||
|
f system n
|
||||||
|
)) stdenvs
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
forAllStdenvs = stdenvs: f: nixpkgs.lib.genAttrs stdenvs (stdenv: f stdenv);
|
||||||
|
|
||||||
# Memoize nixpkgs for different platforms for efficiency.
|
# Memoize nixpkgs for different platforms for efficiency.
|
||||||
nixpkgsFor = forAllSystems (system:
|
nixpkgsFor =
|
||||||
|
let stdenvsPackages = forAllSystemsAndStdenvs
|
||||||
|
(system: stdenv:
|
||||||
import nixpkgs {
|
import nixpkgs {
|
||||||
inherit system;
|
inherit system;
|
||||||
overlays = [ self.overlay ];
|
overlays = [
|
||||||
|
(overlayFor (p: p.${stdenv}))
|
||||||
|
];
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
in
|
||||||
|
# Add the `stdenvPackages` at toplevel, both because these are the ones
|
||||||
|
# we want most of the time and for backwards compatibility
|
||||||
|
forAllSystems (system: stdenvsPackages.${system} // stdenvsPackages.${system}.stdenvPackages);
|
||||||
|
|
||||||
commonDeps = pkgs: with pkgs; rec {
|
commonDeps = pkgs: with pkgs; rec {
|
||||||
# Use "busybox-sandbox-shell" if present,
|
# Use "busybox-sandbox-shell" if present,
|
||||||
|
|
@ -255,18 +276,15 @@
|
||||||
$(cat ${installerClosureInfo}/store-paths)
|
$(cat ${installerClosureInfo}/store-paths)
|
||||||
'';
|
'';
|
||||||
|
|
||||||
in {
|
overlayFor = getStdenv: final: prev:
|
||||||
|
let currentStdenv = getStdenv final; in
|
||||||
# A Nixpkgs overlay that overrides the 'nix' and
|
{
|
||||||
# 'nix.perl-bindings' packages.
|
|
||||||
overlay = final: prev: {
|
|
||||||
|
|
||||||
nixStable = prev.nix;
|
nixStable = prev.nix;
|
||||||
|
|
||||||
# Forward from the previous stage as we don’t want it to pick the lowdown override
|
# Forward from the previous stage as we don’t want it to pick the lowdown override
|
||||||
nixUnstable = prev.nixUnstable;
|
nixUnstable = prev.nixUnstable;
|
||||||
|
|
||||||
nix = with final; with commonDeps pkgs; stdenv.mkDerivation {
|
nix = with final; with commonDeps pkgs; currentStdenv.mkDerivation {
|
||||||
name = "nix-${version}";
|
name = "nix-${version}";
|
||||||
inherit version;
|
inherit version;
|
||||||
|
|
||||||
|
|
@ -288,9 +306,9 @@
|
||||||
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 stdenv.isLinux ''
|
${lib.optionalString currentStdenv.isLinux ''
|
||||||
chmod u+w $out/lib/*.so.*
|
chmod u+w $out/lib/*.so.*
|
||||||
patchelf --set-rpath $out/lib:${stdenv.cc.cc.lib}/lib $out/lib/libboost_thread.so.*
|
patchelf --set-rpath $out/lib:${currentStdenv.cc.cc.lib}/lib $out/lib/libboost_thread.so.*
|
||||||
''}
|
''}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
|
@ -317,7 +335,7 @@
|
||||||
|
|
||||||
strictDeps = true;
|
strictDeps = true;
|
||||||
|
|
||||||
passthru.perl-bindings = with final; stdenv.mkDerivation {
|
passthru.perl-bindings = with final; currentStdenv.mkDerivation {
|
||||||
name = "nix-perl-${version}";
|
name = "nix-perl-${version}";
|
||||||
|
|
||||||
src = self;
|
src = self;
|
||||||
|
|
@ -336,8 +354,8 @@
|
||||||
pkgs.perl
|
pkgs.perl
|
||||||
boost
|
boost
|
||||||
]
|
]
|
||||||
++ lib.optional (stdenv.isLinux || stdenv.isDarwin) libsodium
|
++ lib.optional (currentStdenv.isLinux || currentStdenv.isDarwin) libsodium
|
||||||
++ lib.optional stdenv.isDarwin darwin.apple_sdk.frameworks.Security;
|
++ lib.optional currentStdenv.isDarwin darwin.apple_sdk.frameworks.Security;
|
||||||
|
|
||||||
configureFlags = ''
|
configureFlags = ''
|
||||||
--with-dbi=${perlPackages.DBI}/${pkgs.perl.libPrefix}
|
--with-dbi=${perlPackages.DBI}/${pkgs.perl.libPrefix}
|
||||||
|
|
@ -351,7 +369,7 @@
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
lowdown-nix = with final; stdenv.mkDerivation rec {
|
lowdown-nix = with final; currentStdenv.mkDerivation rec {
|
||||||
name = "lowdown-0.9.0";
|
name = "lowdown-0.9.0";
|
||||||
|
|
||||||
src = lowdown-src;
|
src = lowdown-src;
|
||||||
|
|
@ -361,15 +379,20 @@
|
||||||
nativeBuildInputs = [ buildPackages.which ];
|
nativeBuildInputs = [ buildPackages.which ];
|
||||||
|
|
||||||
configurePhase = ''
|
configurePhase = ''
|
||||||
${if (stdenv.isDarwin && stdenv.isAarch64) then "echo \"HAVE_SANDBOX_INIT=false\" > configure.local" else ""}
|
${if (currentStdenv.isDarwin && currentStdenv.isAarch64) then "echo \"HAVE_SANDBOX_INIT=false\" > configure.local" else ""}
|
||||||
./configure \
|
./configure \
|
||||||
PREFIX=${placeholder "dev"} \
|
PREFIX=${placeholder "dev"} \
|
||||||
BINDIR=${placeholder "bin"}/bin
|
BINDIR=${placeholder "bin"}/bin
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
in {
|
||||||
|
|
||||||
|
# A Nixpkgs overlay that overrides the 'nix' and
|
||||||
|
# 'nix.perl-bindings' packages.
|
||||||
|
overlay = overlayFor (p: p.stdenv);
|
||||||
|
|
||||||
hydraJobs = {
|
hydraJobs = {
|
||||||
|
|
||||||
# Binary package for various platforms.
|
# Binary package for various platforms.
|
||||||
|
|
@ -610,15 +633,22 @@
|
||||||
doInstallCheck = true;
|
doInstallCheck = true;
|
||||||
installCheckFlags = "sysconfdir=$(out)/etc";
|
installCheckFlags = "sysconfdir=$(out)/etc";
|
||||||
};
|
};
|
||||||
}) crossSystems)));
|
}) crossSystems)) // (builtins.listToAttrs (map (stdenvName:
|
||||||
|
nixpkgsFor.${system}.lib.nameValuePair
|
||||||
|
"nix-${stdenvName}"
|
||||||
|
nixpkgsFor.${system}."${stdenvName}Packages".nix
|
||||||
|
) stdenvs))
|
||||||
|
);
|
||||||
|
|
||||||
defaultPackage = forAllSystems (system: self.packages.${system}.nix);
|
defaultPackage = forAllSystems (system: self.packages.${system}.nix);
|
||||||
|
|
||||||
devShell = forAllSystems (system:
|
devShell = forAllSystems (system: self.devShells.${system}.stdenvPackages);
|
||||||
|
|
||||||
|
devShells = forAllSystemsAndStdenvs (system: stdenv:
|
||||||
with nixpkgsFor.${system};
|
with nixpkgsFor.${system};
|
||||||
with commonDeps pkgs;
|
with commonDeps pkgs;
|
||||||
|
|
||||||
stdenv.mkDerivation {
|
nixpkgsFor.${system}.${stdenv}.mkDerivation {
|
||||||
name = "nix";
|
name = "nix";
|
||||||
|
|
||||||
outputs = [ "out" "dev" "doc" ];
|
outputs = [ "out" "dev" "doc" ];
|
||||||
|
|
|
||||||
|
|
@ -25,5 +25,10 @@
|
||||||
<string>/var/log/nix-daemon.log</string>
|
<string>/var/log/nix-daemon.log</string>
|
||||||
<key>StandardOutPath</key>
|
<key>StandardOutPath</key>
|
||||||
<string>/dev/null</string>
|
<string>/dev/null</string>
|
||||||
|
<key>SoftResourceLimits</key>
|
||||||
|
<dict>
|
||||||
|
<key>NumberOfFiles</key>
|
||||||
|
<integer>4096</integer>
|
||||||
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ perlarchname=$($perl -e 'use Config; print $Config{archname};')
|
||||||
AC_SUBST(perllibdir, [${libdir}/perl5/site_perl/$perlversion/$perlarchname])
|
AC_SUBST(perllibdir, [${libdir}/perl5/site_perl/$perlversion/$perlarchname])
|
||||||
AC_MSG_RESULT($perllibdir)
|
AC_MSG_RESULT($perllibdir)
|
||||||
|
|
||||||
# Look for libsodium, an optional dependency.
|
# Look for libsodium.
|
||||||
PKG_CHECK_MODULES([SODIUM], [libsodium], [CXXFLAGS="$SODIUM_CFLAGS $CXXFLAGS"])
|
PKG_CHECK_MODULES([SODIUM], [libsodium], [CXXFLAGS="$SODIUM_CFLAGS $CXXFLAGS"])
|
||||||
|
|
||||||
# Check for the required Perl dependencies (DBI and DBD::SQLite).
|
# Check for the required Perl dependencies (DBI and DBD::SQLite).
|
||||||
|
|
|
||||||
28
scripts/check-hydra-status.sh
Normal file
28
scripts/check-hydra-status.sh
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
# set -x
|
||||||
|
|
||||||
|
|
||||||
|
# mapfile BUILDS_FOR_LATEST_EVAL < <(
|
||||||
|
# curl -H 'Accept: application/json' https://hydra.nixos.org/jobset/nix/master/evals | \
|
||||||
|
# jq -r '.evals[0].builds[] | @sh')
|
||||||
|
BUILDS_FOR_LATEST_EVAL=$(
|
||||||
|
curl -sS -H 'Accept: application/json' https://hydra.nixos.org/jobset/nix/master/evals | \
|
||||||
|
jq -r '.evals[0].builds[]')
|
||||||
|
|
||||||
|
someBuildFailed=0
|
||||||
|
|
||||||
|
for buildId in $BUILDS_FOR_LATEST_EVAL; do
|
||||||
|
buildInfo=$(curl -sS -H 'Accept: application/json' "https://hydra.nixos.org/build/$buildId")
|
||||||
|
|
||||||
|
buildStatus=$(echo "$buildInfo" | \
|
||||||
|
jq -r '.buildstatus')
|
||||||
|
|
||||||
|
if [[ "$buildStatus" -ne 0 ]]; then
|
||||||
|
someBuildFailed=1
|
||||||
|
echo "Job “$(echo "$buildInfo" | jq -r '.job')” failed on hydra"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
exit "$someBuildFailed"
|
||||||
|
|
@ -440,7 +440,22 @@ add_nix_vol_fstab_line() {
|
||||||
# shellcheck disable=SC1003,SC2026
|
# shellcheck disable=SC1003,SC2026
|
||||||
local escaped_mountpoint="${NIX_ROOT/ /'\\\'040}"
|
local escaped_mountpoint="${NIX_ROOT/ /'\\\'040}"
|
||||||
shift
|
shift
|
||||||
EDITOR="/usr/bin/ex" _sudo "to add nix to fstab" "$@" <<EOF
|
|
||||||
|
# wrap `ex` to work around a problem with vim plugins breaking exit codes;
|
||||||
|
# (see https://github.com/NixOS/nix/issues/5468)
|
||||||
|
# we'd prefer EDITOR="/usr/bin/ex --noplugin" but vifs doesn't word-split
|
||||||
|
# the EDITOR env.
|
||||||
|
#
|
||||||
|
# TODO: at some point we should switch to `--clean`, but it wasn't added
|
||||||
|
# until https://github.com/vim/vim/releases/tag/v8.0.1554 while the macOS
|
||||||
|
# minver 10.12.6 seems to have released with vim 7.4
|
||||||
|
cat > "$SCRATCH/ex_cleanroom_wrapper" <<EOF
|
||||||
|
#!/bin/sh
|
||||||
|
/usr/bin/ex --noplugin "\$@"
|
||||||
|
EOF
|
||||||
|
chmod 755 "$SCRATCH/ex_cleanroom_wrapper"
|
||||||
|
|
||||||
|
EDITOR="$SCRATCH/ex_cleanroom_wrapper" _sudo "to add nix to fstab" "$@" <<EOF
|
||||||
:a
|
:a
|
||||||
UUID=$uuid $escaped_mountpoint apfs rw,noauto,nobrowse,suid,owners
|
UUID=$uuid $escaped_mountpoint apfs rw,noauto,nobrowse,suid,owners
|
||||||
.
|
.
|
||||||
|
|
@ -631,7 +646,7 @@ EOF
|
||||||
# technically /etc/synthetic.d/nix is supported in Big Sur+
|
# technically /etc/synthetic.d/nix is supported in Big Sur+
|
||||||
# but handling both takes even more code...
|
# but handling both takes even more code...
|
||||||
_sudo "to add Nix to /etc/synthetic.conf" \
|
_sudo "to add Nix to /etc/synthetic.conf" \
|
||||||
/usr/bin/ex /etc/synthetic.conf <<EOF
|
/usr/bin/ex --noplugin /etc/synthetic.conf <<EOF
|
||||||
:a
|
:a
|
||||||
${NIX_ROOT:1}
|
${NIX_ROOT:1}
|
||||||
.
|
.
|
||||||
|
|
@ -794,7 +809,7 @@ setup_volume_daemon() {
|
||||||
local volume_uuid="$2"
|
local volume_uuid="$2"
|
||||||
if ! test_voldaemon; then
|
if ! test_voldaemon; then
|
||||||
task "Configuring LaunchDaemon to mount '$NIX_VOLUME_LABEL'" >&2
|
task "Configuring LaunchDaemon to mount '$NIX_VOLUME_LABEL'" >&2
|
||||||
_sudo "to install the Nix volume mounter" /usr/bin/ex "$NIX_VOLUME_MOUNTD_DEST" <<EOF
|
_sudo "to install the Nix volume mounter" /usr/bin/ex --noplugin "$NIX_VOLUME_MOUNTD_DEST" <<EOF
|
||||||
:a
|
:a
|
||||||
$(generate_mount_daemon "$cmd_type" "$volume_uuid")
|
$(generate_mount_daemon "$cmd_type" "$volume_uuid")
|
||||||
.
|
.
|
||||||
|
|
|
||||||
|
|
@ -218,7 +218,7 @@ EOF
|
||||||
setup_darwin_volume
|
setup_darwin_volume
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$(diskutil info -plist /nix | xmllint --xpath "(/plist/dict/key[text()='GlobalPermissionsEnabled'])/following-sibling::*[1]" -)" = "<false/>" ]; then
|
if [ "$(/usr/sbin/diskutil info -plist /nix | xmllint --xpath "(/plist/dict/key[text()='GlobalPermissionsEnabled'])/following-sibling::*[1]" -)" = "<false/>" ]; then
|
||||||
failure "This script needs a /nix volume with global permissions! This may require running sudo diskutil enableOwnership /nix."
|
failure "This script needs a /nix volume with global permissions! This may require running sudo /usr/sbin/diskutil enableOwnership /nix."
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -377,6 +377,11 @@ cure_artifacts() {
|
||||||
}
|
}
|
||||||
|
|
||||||
validate_starting_assumptions() {
|
validate_starting_assumptions() {
|
||||||
|
task "Checking for artifacts of previous installs"
|
||||||
|
cat <<EOF
|
||||||
|
Before I try to install, I'll check for signs Nix already is or has
|
||||||
|
been installed on this system.
|
||||||
|
EOF
|
||||||
if type nix-env 2> /dev/null >&2; then
|
if type nix-env 2> /dev/null >&2; then
|
||||||
warning <<EOF
|
warning <<EOF
|
||||||
Nix already appears to be installed. This installer may run into issues.
|
Nix already appears to be installed. This installer may run into issues.
|
||||||
|
|
@ -386,6 +391,11 @@ $(uninstall_directions)
|
||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# TODO: I think it would be good for this step to accumulate more
|
||||||
|
# knowledge of older obsolete artifacts, if there are any.
|
||||||
|
# We could issue a "reminder" here that the user might want
|
||||||
|
# to clean them up?
|
||||||
|
|
||||||
for profile_target in "${PROFILE_TARGETS[@]}"; do
|
for profile_target in "${PROFILE_TARGETS[@]}"; do
|
||||||
# TODO: I think it would be good to accumulate a list of all
|
# TODO: I think it would be good to accumulate a list of all
|
||||||
# of the copies so that people don't hit this 2 or 3x in
|
# of the copies so that people don't hit this 2 or 3x in
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ fi
|
||||||
|
|
||||||
# Determine if we could use the multi-user installer or not
|
# Determine if we could use the multi-user installer or not
|
||||||
if [ "$(uname -s)" = "Linux" ]; then
|
if [ "$(uname -s)" = "Linux" ]; then
|
||||||
echo "Note: a multi-user installation is possible. See https://nixos.org/nix/manual/#sect-multi-user-installation" >&2
|
echo "Note: a multi-user installation is possible. See https://nixos.org/manual/nix/stable/installation/installing-binary.html#multi-user-installation" >&2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
case "$(uname -s)" in
|
case "$(uname -s)" in
|
||||||
|
|
@ -98,7 +98,7 @@ while [ $# -gt 0 ]; do
|
||||||
echo " providing multi-user support and better isolation for local builds."
|
echo " providing multi-user support and better isolation for local builds."
|
||||||
echo " Both for security and reproducibility, this method is recommended if"
|
echo " Both for security and reproducibility, this method is recommended if"
|
||||||
echo " supported on your platform."
|
echo " supported on your platform."
|
||||||
echo " See https://nixos.org/nix/manual/#sect-multi-user-installation"
|
echo " See https://nixos.org/manual/nix/stable/installation/installing-binary.html#multi-user-installation"
|
||||||
echo ""
|
echo ""
|
||||||
echo " --no-daemon: Simple, single-user installation that does not require root and is"
|
echo " --no-daemon: Simple, single-user installation that does not require root and is"
|
||||||
echo " trivial to uninstall."
|
echo " trivial to uninstall."
|
||||||
|
|
@ -144,7 +144,7 @@ if ! [ -e "$dest" ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! [ -w "$dest" ]; then
|
if ! [ -w "$dest" ]; then
|
||||||
echo "$0: directory $dest exists, but is not writable by you. This could indicate that another user has already performed a single-user installation of Nix on this system. If you wish to enable multi-user support see https://nixos.org/nix/manual/#ssec-multi-user. If you wish to continue with a single-user install for $USER please run 'chown -R $USER $dest' as root." >&2
|
echo "$0: directory $dest exists, but is not writable by you. This could indicate that another user has already performed a single-user installation of Nix on this system. If you wish to enable multi-user support see https://nixos.org/manual/nix/stable/installation/multi-user.html. If you wish to continue with a single-user install for $USER please run 'chown -R $USER $dest' as root." >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -291,6 +291,9 @@ void completeFlakeRefWithFragment(
|
||||||
|
|
||||||
void completeFlakeRef(ref<Store> store, std::string_view prefix)
|
void completeFlakeRef(ref<Store> store, std::string_view prefix)
|
||||||
{
|
{
|
||||||
|
if (!settings.isExperimentalFeatureEnabled(Xp::Flakes))
|
||||||
|
return;
|
||||||
|
|
||||||
if (prefix == "")
|
if (prefix == "")
|
||||||
completions->add(".");
|
completions->add(".");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -482,11 +482,16 @@ LockedFlake lockFlake(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LockParent newParent {
|
||||||
|
.path = inputPath,
|
||||||
|
.absolute = false
|
||||||
|
};
|
||||||
|
|
||||||
computeLocks(
|
computeLocks(
|
||||||
mustRefetch
|
mustRefetch
|
||||||
? getFlake(state, oldLock->lockedRef, false, flakeCache).inputs
|
? getFlake(state, oldLock->lockedRef, false, flakeCache).inputs
|
||||||
: fakeInputs,
|
: fakeInputs,
|
||||||
childNode, inputPath, oldLock, parent, parentPath);
|
childNode, inputPath, oldLock, newParent, parentPath);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* We need to create a new lock file entry. So fetch
|
/* We need to create a new lock file entry. So fetch
|
||||||
|
|
|
||||||
|
|
@ -2928,6 +2928,56 @@ static RegisterPrimOp primop_partition({
|
||||||
.fun = prim_partition,
|
.fun = prim_partition,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
static void prim_groupBy(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
|
{
|
||||||
|
state.forceFunction(*args[0], pos);
|
||||||
|
state.forceList(*args[1], pos);
|
||||||
|
|
||||||
|
ValueVectorMap attrs;
|
||||||
|
|
||||||
|
for (auto vElem : args[1]->listItems()) {
|
||||||
|
Value res;
|
||||||
|
state.callFunction(*args[0], *vElem, res, pos);
|
||||||
|
string name = state.forceStringNoCtx(res, pos);
|
||||||
|
Symbol sym = state.symbols.create(name);
|
||||||
|
auto vector = attrs.try_emplace(sym, ValueVector()).first;
|
||||||
|
vector->second.push_back(vElem);
|
||||||
|
}
|
||||||
|
|
||||||
|
state.mkAttrs(v, attrs.size());
|
||||||
|
|
||||||
|
for (auto & i : attrs) {
|
||||||
|
Value * list = state.allocAttr(v, i.first);
|
||||||
|
auto size = i.second.size();
|
||||||
|
state.mkList(*list, size);
|
||||||
|
memcpy(list->listElems(), i.second.data(), sizeof(Value *) * size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static RegisterPrimOp primop_groupBy({
|
||||||
|
.name = "__groupBy",
|
||||||
|
.args = {"f", "list"},
|
||||||
|
.doc = R"(
|
||||||
|
Groups elements of *list* together by the string returned from the
|
||||||
|
function *f* called on each element. It returns an attribute set
|
||||||
|
where each attribute value contains the elements of *list* that are
|
||||||
|
mapped to the same corresponding attribute name returned by *f*.
|
||||||
|
|
||||||
|
For example,
|
||||||
|
|
||||||
|
```nix
|
||||||
|
builtins.groupBy (builtins.substring 0 1) ["foo" "bar" "baz"]
|
||||||
|
```
|
||||||
|
|
||||||
|
evaluates to
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ b = [ "bar" "baz" ]; f = [ "foo" ]; }
|
||||||
|
```
|
||||||
|
)",
|
||||||
|
.fun = prim_groupBy,
|
||||||
|
});
|
||||||
|
|
||||||
static void prim_concatMap(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_concatMap(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
state.forceFunction(*args[0], pos);
|
state.forceFunction(*args[0], pos);
|
||||||
|
|
@ -3732,7 +3782,7 @@ void EvalState::createBaseEnv()
|
||||||
.fun = primOp.fun,
|
.fun = primOp.fun,
|
||||||
.arity = std::max(primOp.args.size(), primOp.arity),
|
.arity = std::max(primOp.args.size(), primOp.arity),
|
||||||
.name = symbols.create(primOp.name),
|
.name = symbols.create(primOp.name),
|
||||||
.args = std::move(primOp.args),
|
.args = primOp.args,
|
||||||
.doc = primOp.doc,
|
.doc = primOp.doc,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -425,9 +425,11 @@ void mkPath(Value & v, const char * s);
|
||||||
#if HAVE_BOEHMGC
|
#if HAVE_BOEHMGC
|
||||||
typedef std::vector<Value *, traceable_allocator<Value *> > ValueVector;
|
typedef std::vector<Value *, traceable_allocator<Value *> > ValueVector;
|
||||||
typedef std::map<Symbol, Value *, std::less<Symbol>, traceable_allocator<std::pair<const Symbol, Value *> > > ValueMap;
|
typedef std::map<Symbol, Value *, std::less<Symbol>, traceable_allocator<std::pair<const Symbol, Value *> > > ValueMap;
|
||||||
|
typedef std::map<Symbol, ValueVector, std::less<Symbol>, traceable_allocator<std::pair<const Symbol, ValueVector> > > ValueVectorMap;
|
||||||
#else
|
#else
|
||||||
typedef std::vector<Value *> ValueVector;
|
typedef std::vector<Value *> ValueVector;
|
||||||
typedef std::map<Symbol, Value *> ValueMap;
|
typedef std::map<Symbol, Value *> ValueMap;
|
||||||
|
typedef std::map<Symbol, ValueVector> ValueVectorMap;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ struct PathInputScheme : InputScheme
|
||||||
// for security, ensure that if the parent is a store path, it's inside it
|
// for security, ensure that if the parent is a store path, it's inside it
|
||||||
if (store->isInStore(parent)) {
|
if (store->isInStore(parent)) {
|
||||||
auto storePath = store->printStorePath(store->toStorePath(parent).first);
|
auto storePath = store->printStorePath(store->toStorePath(parent).first);
|
||||||
if (!isInDir(absPath, storePath))
|
if (!isDirOrInDir(absPath, storePath))
|
||||||
throw BadStorePath("relative path '%s' points outside of its parent's store path '%s'", path, storePath);
|
throw BadStorePath("relative path '%s' points outside of its parent's store path '%s'", path, storePath);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ ProgressBarSettings progressBarSettings;
|
||||||
|
|
||||||
static GlobalConfig::Register rProgressBarSettings(&progressBarSettings);
|
static GlobalConfig::Register rProgressBarSettings(&progressBarSettings);
|
||||||
|
|
||||||
static std::string getS(const std::vector<Logger::Field> & fields, size_t n)
|
static std::string_view getS(const std::vector<Logger::Field> & fields, size_t n)
|
||||||
{
|
{
|
||||||
assert(n < fields.size());
|
assert(n < fields.size());
|
||||||
assert(fields[n].type == Logger::Field::tString);
|
assert(fields[n].type == Logger::Field::tString);
|
||||||
|
|
|
||||||
|
|
@ -427,7 +427,7 @@ RunPager::RunPager()
|
||||||
});
|
});
|
||||||
|
|
||||||
pid.setKillSignal(SIGINT);
|
pid.setKillSignal(SIGINT);
|
||||||
|
stdout = fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 0);
|
||||||
if (dup2(toPager.writeSide.get(), STDOUT_FILENO) == -1)
|
if (dup2(toPager.writeSide.get(), STDOUT_FILENO) == -1)
|
||||||
throw SysError("dupping stdout");
|
throw SysError("dupping stdout");
|
||||||
}
|
}
|
||||||
|
|
@ -438,7 +438,7 @@ RunPager::~RunPager()
|
||||||
try {
|
try {
|
||||||
if (pid != -1) {
|
if (pid != -1) {
|
||||||
std::cout.flush();
|
std::cout.flush();
|
||||||
close(STDOUT_FILENO);
|
dup2(stdout, STDOUT_FILENO);
|
||||||
pid.wait();
|
pid.wait();
|
||||||
}
|
}
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Pid pid;
|
Pid pid;
|
||||||
|
int stdout;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern volatile ::sig_atomic_t blockInt;
|
extern volatile ::sig_atomic_t blockInt;
|
||||||
|
|
|
||||||
|
|
@ -656,7 +656,7 @@ void DerivationGoal::tryLocalBuild() {
|
||||||
throw Error(
|
throw Error(
|
||||||
"unable to build with a primary store that isn't a local store; "
|
"unable to build with a primary store that isn't a local store; "
|
||||||
"either pass a different '--store' or enable remote builds."
|
"either pass a different '--store' or enable remote builds."
|
||||||
"\nhttps://nixos.org/nix/manual/#chap-distributed-builds");
|
"\nhttps://nixos.org/manual/nix/stable/advanced-topics/distributed-builds.html");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,8 @@ void PathSubstitutionGoal::tryNext()
|
||||||
{
|
{
|
||||||
warn("substituter '%s' does not have a valid signature for path '%s'",
|
warn("substituter '%s' does not have a valid signature for path '%s'",
|
||||||
sub->getUri(), worker.store.printStorePath(storePath));
|
sub->getUri(), worker.store.printStorePath(storePath));
|
||||||
|
warn("verify that your nix.conf contains a correct signature in 'trusted-public-keys' for %s",
|
||||||
|
sub->getUri());
|
||||||
tryNext();
|
tryNext();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -291,11 +291,11 @@ void Worker::run(const Goals & _topGoals)
|
||||||
if (getMachines().empty())
|
if (getMachines().empty())
|
||||||
throw Error("unable to start any build; either increase '--max-jobs' "
|
throw Error("unable to start any build; either increase '--max-jobs' "
|
||||||
"or enable remote builds."
|
"or enable remote builds."
|
||||||
"\nhttps://nixos.org/nix/manual/#chap-distributed-builds");
|
"\nhttps://nixos.org/manual/nix/stable/advanced-topics/distributed-builds.html");
|
||||||
else
|
else
|
||||||
throw Error("unable to start any build; remote machines may not have "
|
throw Error("unable to start any build; remote machines may not have "
|
||||||
"all required system features."
|
"all required system features."
|
||||||
"\nhttps://nixos.org/nix/manual/#chap-distributed-builds");
|
"\nhttps://nixos.org/manual/nix/stable/advanced-topics/distributed-builds.html");
|
||||||
|
|
||||||
}
|
}
|
||||||
assert(!awake.empty());
|
assert(!awake.empty());
|
||||||
|
|
|
||||||
|
|
@ -431,25 +431,30 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
hashAlgo = parseHashType(hashAlgoRaw);
|
hashAlgo = parseHashType(hashAlgoRaw);
|
||||||
}
|
}
|
||||||
|
|
||||||
StringSink saved;
|
auto dumpSource = sinkToSource([&](Sink & saved) {
|
||||||
TeeSource savedNARSource(from, saved);
|
|
||||||
RetrieveRegularNARSink savedRegular { saved };
|
|
||||||
|
|
||||||
if (method == FileIngestionMethod::Recursive) {
|
if (method == FileIngestionMethod::Recursive) {
|
||||||
/* Get the entire NAR dump from the client and save it to
|
/* We parse the NAR dump through into `saved` unmodified,
|
||||||
a string so that we can pass it to
|
so why all this extra work? We still parse the NAR so
|
||||||
addToStoreFromDump(). */
|
that we aren't sending arbitrary data to `saved`
|
||||||
|
unwittingly`, and we know when the NAR ends so we don't
|
||||||
|
consume the rest of `from` and can't parse another
|
||||||
|
command. (We don't trust `addToStoreFromDump` to not
|
||||||
|
eagerly consume the entire stream it's given, past the
|
||||||
|
length of the Nar. */
|
||||||
|
TeeSource savedNARSource(from, saved);
|
||||||
ParseSink sink; /* null sink; just parse the NAR */
|
ParseSink sink; /* null sink; just parse the NAR */
|
||||||
parseDump(sink, savedNARSource);
|
parseDump(sink, savedNARSource);
|
||||||
} else
|
} else {
|
||||||
|
/* Incrementally parse the NAR file, stripping the
|
||||||
|
metadata, and streaming the sole file we expect into
|
||||||
|
`saved`. */
|
||||||
|
RetrieveRegularNARSink savedRegular { saved };
|
||||||
parseDump(savedRegular, from);
|
parseDump(savedRegular, from);
|
||||||
|
|
||||||
logger->startWork();
|
|
||||||
if (!savedRegular.regular) throw Error("regular file expected");
|
if (!savedRegular.regular) throw Error("regular file expected");
|
||||||
|
}
|
||||||
// FIXME: try to stream directly from `from`.
|
});
|
||||||
StringSource dumpSource { *saved.s };
|
logger->startWork();
|
||||||
auto path = store->addToStoreFromDump(dumpSource, baseName, method, hashAlgo);
|
auto path = store->addToStoreFromDump(*dumpSource, baseName, method, hashAlgo);
|
||||||
logger->stopWork();
|
logger->stopWork();
|
||||||
|
|
||||||
to << store->printStorePath(path);
|
to << store->printStorePath(path);
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#include "references.hh"
|
#include "references.hh"
|
||||||
#include "callback.hh"
|
#include "callback.hh"
|
||||||
#include "topo-sort.hh"
|
#include "topo-sort.hh"
|
||||||
|
#include "finally.hh"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
@ -1333,13 +1334,15 @@ StorePath LocalStore::addToStoreFromDump(Source & source0, const string & name,
|
||||||
auto want = std::min(chunkSize, settings.narBufferSize - oldSize);
|
auto want = std::min(chunkSize, settings.narBufferSize - oldSize);
|
||||||
dump.resize(oldSize + want);
|
dump.resize(oldSize + want);
|
||||||
auto got = 0;
|
auto got = 0;
|
||||||
|
Finally cleanup([&]() {
|
||||||
|
dump.resize(oldSize + got);
|
||||||
|
});
|
||||||
try {
|
try {
|
||||||
got = source.read(dump.data() + oldSize, want);
|
got = source.read(dump.data() + oldSize, want);
|
||||||
} catch (EndOfFile &) {
|
} catch (EndOfFile &) {
|
||||||
inMemory = true;
|
inMemory = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
dump.resize(oldSize + got);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<AutoDelete> delTempDir;
|
std::unique_ptr<AutoDelete> delTempDir;
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ DrvName::~DrvName()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
||||||
bool DrvName::matches(DrvName & n)
|
bool DrvName::matches(const DrvName & n)
|
||||||
{
|
{
|
||||||
if (name != "*") {
|
if (name != "*") {
|
||||||
if (!regex) {
|
if (!regex) {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ struct DrvName
|
||||||
DrvName(std::string_view s);
|
DrvName(std::string_view s);
|
||||||
~DrvName();
|
~DrvName();
|
||||||
|
|
||||||
bool matches(DrvName & n);
|
bool matches(const DrvName & n);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Regex> regex;
|
std::unique_ptr<Regex> regex;
|
||||||
|
|
|
||||||
|
|
@ -684,6 +684,14 @@ void RemoteStore::queryRealisationUncached(const DrvOutput & id,
|
||||||
Callback<std::shared_ptr<const Realisation>> callback) noexcept
|
Callback<std::shared_ptr<const Realisation>> callback) noexcept
|
||||||
{
|
{
|
||||||
auto conn(getConnection());
|
auto conn(getConnection());
|
||||||
|
|
||||||
|
if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 27) {
|
||||||
|
warn("the daemon is too old to support content-addressed derivations, please upgrade it to 2.4");
|
||||||
|
try {
|
||||||
|
callback(nullptr);
|
||||||
|
} catch (...) { return callback.rethrow(); }
|
||||||
|
}
|
||||||
|
|
||||||
conn->to << wopQueryRealisation;
|
conn->to << wopQueryRealisation;
|
||||||
conn->to << id.to_string();
|
conn->to << id.to_string();
|
||||||
conn.processStderr();
|
conn.processStderr();
|
||||||
|
|
|
||||||
|
|
@ -512,6 +512,7 @@ std::pair<AutoCloseFD, Path> createTempFile(const Path & prefix)
|
||||||
AutoCloseFD fd(mkstemp((char *) tmpl.c_str()));
|
AutoCloseFD fd(mkstemp((char *) tmpl.c_str()));
|
||||||
if (!fd)
|
if (!fd)
|
||||||
throw SysError("creating temporary file '%s'", tmpl);
|
throw SysError("creating temporary file '%s'", tmpl);
|
||||||
|
closeOnExec(fd.get());
|
||||||
return {std::move(fd), tmpl};
|
return {std::move(fd), tmpl};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
|
||||||
|
|
@ -359,6 +359,7 @@ static void main_nix_build(int argc, char * * argv)
|
||||||
is not set, then build bashInteractive from
|
is not set, then build bashInteractive from
|
||||||
<nixpkgs>. */
|
<nixpkgs>. */
|
||||||
auto shell = getEnv("NIX_BUILD_SHELL");
|
auto shell = getEnv("NIX_BUILD_SHELL");
|
||||||
|
std::optional<StorePath> shellDrv;
|
||||||
|
|
||||||
if (!shell) {
|
if (!shell) {
|
||||||
|
|
||||||
|
|
@ -375,8 +376,7 @@ static void main_nix_build(int argc, char * * argv)
|
||||||
auto bashDrv = store->parseStorePath(drv->queryDrvPath());
|
auto bashDrv = store->parseStorePath(drv->queryDrvPath());
|
||||||
pathsToBuild.push_back({bashDrv});
|
pathsToBuild.push_back({bashDrv});
|
||||||
pathsToCopy.insert(bashDrv);
|
pathsToCopy.insert(bashDrv);
|
||||||
|
shellDrv = bashDrv;
|
||||||
shell = drv->queryOutPath() + "/bin/bash";
|
|
||||||
|
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
logError(e.info());
|
logError(e.info());
|
||||||
|
|
@ -402,6 +402,11 @@ static void main_nix_build(int argc, char * * argv)
|
||||||
|
|
||||||
if (dryRun) return;
|
if (dryRun) return;
|
||||||
|
|
||||||
|
if (shellDrv) {
|
||||||
|
auto shellDrvOutputs = store->queryPartialDerivationOutputMap(shellDrv.value());
|
||||||
|
shell = store->printStorePath(shellDrvOutputs.at("out").value()) + "/bin/bash";
|
||||||
|
}
|
||||||
|
|
||||||
if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
|
if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
|
||||||
auto resolvedDrv = drv.tryResolve(*store);
|
auto resolvedDrv = drv.tryResolve(*store);
|
||||||
assert(resolvedDrv && "Successfully resolved the derivation");
|
assert(resolvedDrv && "Successfully resolved the derivation");
|
||||||
|
|
|
||||||
|
|
@ -224,6 +224,91 @@ static void checkSelectorUse(DrvNames & selectors)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
std::set<std::string> searchByPrefix(const DrvInfos & allElems, std::string_view prefix) {
|
||||||
|
constexpr std::size_t maxResults = 3;
|
||||||
|
std::set<std::string> result;
|
||||||
|
for (const auto & drvInfo : allElems) {
|
||||||
|
const auto drvName = DrvName { drvInfo.queryName() };
|
||||||
|
if (hasPrefix(drvName.name, prefix)) {
|
||||||
|
result.emplace(drvName.name);
|
||||||
|
|
||||||
|
if (result.size() >= maxResults) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Match
|
||||||
|
{
|
||||||
|
DrvInfo drvInfo;
|
||||||
|
std::size_t index;
|
||||||
|
|
||||||
|
Match(DrvInfo drvInfo_, std::size_t index_)
|
||||||
|
: drvInfo{std::move(drvInfo_)}
|
||||||
|
, index{index_}
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* If a selector matches multiple derivations
|
||||||
|
with the same name, pick the one matching the current
|
||||||
|
system. If there are still multiple derivations, pick the
|
||||||
|
one with the highest priority. If there are still multiple
|
||||||
|
derivations, pick the one with the highest version.
|
||||||
|
Finally, if there are still multiple derivations,
|
||||||
|
arbitrarily pick the first one. */
|
||||||
|
std::vector<Match> pickNewestOnly(EvalState & state, std::vector<Match> matches) {
|
||||||
|
/* Map from package names to derivations. */
|
||||||
|
std::map<std::string, Match> newest;
|
||||||
|
StringSet multiple;
|
||||||
|
|
||||||
|
for (auto & match : matches) {
|
||||||
|
auto & oneDrv = match.drvInfo;
|
||||||
|
|
||||||
|
const auto drvName = DrvName { oneDrv.queryName() };
|
||||||
|
long comparison = 1;
|
||||||
|
|
||||||
|
const auto itOther = newest.find(drvName.name);
|
||||||
|
|
||||||
|
if (itOther != newest.end()) {
|
||||||
|
auto & newestDrv = itOther->second.drvInfo;
|
||||||
|
|
||||||
|
comparison =
|
||||||
|
oneDrv.querySystem() == newestDrv.querySystem() ? 0 :
|
||||||
|
oneDrv.querySystem() == settings.thisSystem ? 1 :
|
||||||
|
newestDrv.querySystem() == settings.thisSystem ? -1 : 0;
|
||||||
|
if (comparison == 0)
|
||||||
|
comparison = comparePriorities(state, oneDrv, newestDrv);
|
||||||
|
if (comparison == 0)
|
||||||
|
comparison = compareVersions(drvName.version, DrvName { newestDrv.queryName() }.version);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (comparison > 0) {
|
||||||
|
newest.erase(drvName.name);
|
||||||
|
newest.emplace(drvName.name, match);
|
||||||
|
multiple.erase(drvName.fullName);
|
||||||
|
} else if (comparison == 0) {
|
||||||
|
multiple.insert(drvName.fullName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
matches.clear();
|
||||||
|
for (auto & [name, match] : newest) {
|
||||||
|
if (multiple.find(name) != multiple.end())
|
||||||
|
warn(
|
||||||
|
"there are multiple derivations named '%1%'; using the first one",
|
||||||
|
name);
|
||||||
|
matches.push_back(match);
|
||||||
|
}
|
||||||
|
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end namespace
|
||||||
|
|
||||||
static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems,
|
static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems,
|
||||||
const Strings & args, bool newestOnly)
|
const Strings & args, bool newestOnly)
|
||||||
{
|
{
|
||||||
|
|
@ -232,79 +317,42 @@ static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems,
|
||||||
selectors.emplace_back("*");
|
selectors.emplace_back("*");
|
||||||
|
|
||||||
DrvInfos elems;
|
DrvInfos elems;
|
||||||
set<unsigned int> done;
|
std::set<std::size_t> done;
|
||||||
|
|
||||||
for (auto & i : selectors) {
|
for (auto & selector : selectors) {
|
||||||
typedef list<std::pair<DrvInfo, unsigned int> > Matches;
|
std::vector<Match> matches;
|
||||||
Matches matches;
|
for (const auto & [index, drvInfo] : enumerate(allElems)) {
|
||||||
unsigned int n = 0;
|
const auto drvName = DrvName { drvInfo.queryName() };
|
||||||
for (DrvInfos::const_iterator j = allElems.begin();
|
if (selector.matches(drvName)) {
|
||||||
j != allElems.end(); ++j, ++n)
|
++selector.hits;
|
||||||
{
|
matches.emplace_back(drvInfo, index);
|
||||||
DrvName drvName(j->queryName());
|
|
||||||
if (i.matches(drvName)) {
|
|
||||||
i.hits++;
|
|
||||||
matches.push_back(std::pair<DrvInfo, unsigned int>(*j, n));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If `newestOnly', if a selector matches multiple derivations
|
|
||||||
with the same name, pick the one matching the current
|
|
||||||
system. If there are still multiple derivations, pick the
|
|
||||||
one with the highest priority. If there are still multiple
|
|
||||||
derivations, pick the one with the highest version.
|
|
||||||
Finally, if there are still multiple derivations,
|
|
||||||
arbitrarily pick the first one. */
|
|
||||||
if (newestOnly) {
|
if (newestOnly) {
|
||||||
|
matches = pickNewestOnly(state, std::move(matches));
|
||||||
/* Map from package names to derivations. */
|
|
||||||
typedef map<string, std::pair<DrvInfo, unsigned int> > Newest;
|
|
||||||
Newest newest;
|
|
||||||
StringSet multiple;
|
|
||||||
|
|
||||||
for (auto & j : matches) {
|
|
||||||
DrvName drvName(j.first.queryName());
|
|
||||||
long d = 1;
|
|
||||||
|
|
||||||
Newest::iterator k = newest.find(drvName.name);
|
|
||||||
|
|
||||||
if (k != newest.end()) {
|
|
||||||
d = j.first.querySystem() == k->second.first.querySystem() ? 0 :
|
|
||||||
j.first.querySystem() == settings.thisSystem ? 1 :
|
|
||||||
k->second.first.querySystem() == settings.thisSystem ? -1 : 0;
|
|
||||||
if (d == 0)
|
|
||||||
d = comparePriorities(state, j.first, k->second.first);
|
|
||||||
if (d == 0)
|
|
||||||
d = compareVersions(drvName.version, DrvName(k->second.first.queryName()).version);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d > 0) {
|
|
||||||
newest.erase(drvName.name);
|
|
||||||
newest.insert(Newest::value_type(drvName.name, j));
|
|
||||||
multiple.erase(j.first.queryName());
|
|
||||||
} else if (d == 0) {
|
|
||||||
multiple.insert(j.first.queryName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
matches.clear();
|
|
||||||
for (auto & j : newest) {
|
|
||||||
if (multiple.find(j.second.first.queryName()) != multiple.end())
|
|
||||||
printInfo(
|
|
||||||
"warning: there are multiple derivations named '%1%'; using the first one",
|
|
||||||
j.second.first.queryName());
|
|
||||||
matches.push_back(j.second);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Insert only those elements in the final list that we
|
/* Insert only those elements in the final list that we
|
||||||
haven't inserted before. */
|
haven't inserted before. */
|
||||||
for (auto & j : matches)
|
for (auto & match : matches)
|
||||||
if (done.insert(j.second).second)
|
if (done.insert(match.index).second)
|
||||||
elems.push_back(j.first);
|
elems.push_back(match.drvInfo);
|
||||||
}
|
|
||||||
|
|
||||||
checkSelectorUse(selectors);
|
if (selector.hits == 0 && selector.fullName != "*") {
|
||||||
|
const auto prefixHits = searchByPrefix(allElems, selector.name);
|
||||||
|
|
||||||
|
if (prefixHits.empty()) {
|
||||||
|
throw Error("selector '%1%' matches no derivations", selector.fullName);
|
||||||
|
} else {
|
||||||
|
std::string suggestionMessage = ", maybe you meant:";
|
||||||
|
for (const auto & drvName : prefixHits) {
|
||||||
|
suggestionMessage += fmt("\n%s", drvName);
|
||||||
|
}
|
||||||
|
throw Error("selector '%1%' matches no derivations" + suggestionMessage, selector.fullName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return elems;
|
return elems;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ R""(
|
||||||
|
|
||||||
# Description
|
# Description
|
||||||
|
|
||||||
`nix flake` provides subcommands for managing *flake
|
`nix registry` provides subcommands for managing *flake
|
||||||
registries*. Flake registries are a convenience feature that allows
|
registries*. Flake registries are a convenience feature that allows
|
||||||
you to refer to flakes using symbolic identifiers such as `nixpkgs`,
|
you to refer to flakes using symbolic identifiers such as `nixpkgs`,
|
||||||
rather than full URLs such as `git://github.com/NixOS/nixpkgs`. You
|
rather than full URLs such as `git://github.com/NixOS/nixpkgs`. You
|
||||||
|
|
|
||||||
|
|
@ -279,6 +279,7 @@ bool NixRepl::getLine(string & input, const std::string &prompt)
|
||||||
};
|
};
|
||||||
|
|
||||||
setupSignals();
|
setupSignals();
|
||||||
|
Finally resetTerminal([&]() { rl_deprep_terminal(); });
|
||||||
char * s = readline(prompt.c_str());
|
char * s = readline(prompt.c_str());
|
||||||
Finally doFree([&]() { free(s); });
|
Finally doFree([&]() { free(s); });
|
||||||
restoreSignals();
|
restoreSignals();
|
||||||
|
|
@ -356,6 +357,8 @@ StringSet NixRepl::completePrefix(string prefix)
|
||||||
// Quietly ignore evaluation errors.
|
// Quietly ignore evaluation errors.
|
||||||
} catch (UndefinedVarError & e) {
|
} catch (UndefinedVarError & e) {
|
||||||
// Quietly ignore undefined variable errors.
|
// Quietly ignore undefined variable errors.
|
||||||
|
} catch (BadURL & e) {
|
||||||
|
// Quietly ignore BadURL flake-related errors.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -427,7 +430,8 @@ bool NixRepl::processLine(string line)
|
||||||
<< " :s <expr> Build dependencies of derivation, then start nix-shell\n"
|
<< " :s <expr> Build dependencies of derivation, then start nix-shell\n"
|
||||||
<< " :t <expr> Describe result of evaluation\n"
|
<< " :t <expr> Describe result of evaluation\n"
|
||||||
<< " :u <expr> Build derivation, then start nix-shell\n"
|
<< " :u <expr> Build derivation, then start nix-shell\n"
|
||||||
<< " :doc <expr> Show documentation of a builtin function\n";
|
<< " :doc <expr> Show documentation of a builtin function\n"
|
||||||
|
<< " :log <expr> Show logs for a derivation\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (command == ":a" || command == ":add") {
|
else if (command == ":a" || command == ":add") {
|
||||||
|
|
@ -497,7 +501,7 @@ bool NixRepl::processLine(string line)
|
||||||
runNix("nix-shell", {state->store->printStorePath(drvPath)});
|
runNix("nix-shell", {state->store->printStorePath(drvPath)});
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (command == ":b" || command == ":i" || command == ":s") {
|
else if (command == ":b" || command == ":i" || command == ":s" || command == ":log") {
|
||||||
Value v;
|
Value v;
|
||||||
evalString(arg, v);
|
evalString(arg, v);
|
||||||
StorePath drvPath = getDerivationPath(v);
|
StorePath drvPath = getDerivationPath(v);
|
||||||
|
|
@ -511,6 +515,27 @@ bool NixRepl::processLine(string line)
|
||||||
logger->cout(" %s -> %s", outputName, state->store->printStorePath(outputPath));
|
logger->cout(" %s -> %s", outputName, state->store->printStorePath(outputPath));
|
||||||
} else if (command == ":i") {
|
} else if (command == ":i") {
|
||||||
runNix("nix-env", {"-i", drvPathRaw});
|
runNix("nix-env", {"-i", drvPathRaw});
|
||||||
|
} else if (command == ":log") {
|
||||||
|
settings.readOnlyMode = true;
|
||||||
|
Finally roModeReset([&]() {
|
||||||
|
settings.readOnlyMode = false;
|
||||||
|
});
|
||||||
|
auto subs = getDefaultSubstituters();
|
||||||
|
|
||||||
|
subs.push_front(state->store);
|
||||||
|
|
||||||
|
bool foundLog = false;
|
||||||
|
RunPager pager;
|
||||||
|
for (auto & sub : subs) {
|
||||||
|
auto log = sub->getBuildLog(drvPath);
|
||||||
|
if (log) {
|
||||||
|
printInfo("got build log for '%s' from '%s'", drvPathRaw, sub->getUri());
|
||||||
|
logger->writeToStdout(*log);
|
||||||
|
foundLog = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!foundLog) throw Error("build log of '%s' is not available", drvPathRaw);
|
||||||
} else {
|
} else {
|
||||||
runNix("nix-shell", {drvPathRaw});
|
runNix("nix-shell", {drvPathRaw});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,14 +35,17 @@ R""(
|
||||||
nix-repl> emacs.drvPath
|
nix-repl> emacs.drvPath
|
||||||
"/nix/store/lp0sjrhgg03y2n0l10n70rg0k7hhyz0l-emacs-27.1.drv"
|
"/nix/store/lp0sjrhgg03y2n0l10n70rg0k7hhyz0l-emacs-27.1.drv"
|
||||||
|
|
||||||
nix-repl> drv = runCommand "hello" { buildInputs = [ hello ]; } "hello > $out"
|
nix-repl> drv = runCommand "hello" { buildInputs = [ hello ]; } "hello; hello > $out"
|
||||||
|
|
||||||
nix-repl> :b x
|
nix-repl> :b drv
|
||||||
this derivation produced the following outputs:
|
this derivation produced the following outputs:
|
||||||
out -> /nix/store/0njwbgwmkwls0w5dv9mpc1pq5fj39q0l-hello
|
out -> /nix/store/0njwbgwmkwls0w5dv9mpc1pq5fj39q0l-hello
|
||||||
|
|
||||||
nix-repl> builtins.readFile drv
|
nix-repl> builtins.readFile drv
|
||||||
"Hello, world!\n"
|
"Hello, world!\n"
|
||||||
|
|
||||||
|
nix-repl> :log drv
|
||||||
|
Hello, world!
|
||||||
```
|
```
|
||||||
|
|
||||||
# Description
|
# Description
|
||||||
|
|
|
||||||
1
tests/ca-shell.nix
Normal file
1
tests/ca-shell.nix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
{ ... }@args: import ./shell.nix (args // { contentAddressed = true; })
|
||||||
|
|
@ -722,6 +722,7 @@ cat > $flakeFollowsB/flake.nix <<EOF
|
||||||
inputs = {
|
inputs = {
|
||||||
foobar.url = "path:$flakeFollowsA/flakeE";
|
foobar.url = "path:$flakeFollowsA/flakeE";
|
||||||
nonFlake.url = "path:$nonFlakeDir";
|
nonFlake.url = "path:$nonFlakeDir";
|
||||||
|
goodoo.follows = "C/goodoo";
|
||||||
C = {
|
C = {
|
||||||
url = "path:./flakeC";
|
url = "path:./flakeC";
|
||||||
inputs.foobar.follows = "foobar";
|
inputs.foobar.follows = "foobar";
|
||||||
|
|
@ -736,6 +737,7 @@ cat > $flakeFollowsC/flake.nix <<EOF
|
||||||
description = "Flake C";
|
description = "Flake C";
|
||||||
inputs = {
|
inputs = {
|
||||||
foobar.url = "path:$flakeFollowsA/flakeE";
|
foobar.url = "path:$flakeFollowsA/flakeE";
|
||||||
|
goodoo.follows = "foobar";
|
||||||
};
|
};
|
||||||
outputs = { ... }: {};
|
outputs = { ... }: {};
|
||||||
}
|
}
|
||||||
|
|
@ -760,8 +762,18 @@ EOF
|
||||||
git -C $flakeFollowsA add flake.nix flakeB/flake.nix \
|
git -C $flakeFollowsA add flake.nix flakeB/flake.nix \
|
||||||
flakeB/flakeC/flake.nix flakeD/flake.nix flakeE/flake.nix
|
flakeB/flakeC/flake.nix flakeD/flake.nix flakeE/flake.nix
|
||||||
|
|
||||||
|
nix flake update $flakeFollowsA
|
||||||
|
|
||||||
|
oldLock="$(cat "$flakeFollowsA/flake.lock")"
|
||||||
|
|
||||||
|
# Ensure that locking twice doesn't change anything
|
||||||
|
|
||||||
nix flake lock $flakeFollowsA
|
nix flake lock $flakeFollowsA
|
||||||
|
|
||||||
|
newLock="$(cat "$flakeFollowsA/flake.lock")"
|
||||||
|
|
||||||
|
diff <(echo "$newLock") <(echo "$oldLock")
|
||||||
|
|
||||||
[[ $(jq -c .nodes.B.inputs.C $flakeFollowsA/flake.lock) = '"C"' ]]
|
[[ $(jq -c .nodes.B.inputs.C $flakeFollowsA/flake.lock) = '"C"' ]]
|
||||||
[[ $(jq -c .nodes.B.inputs.foobar $flakeFollowsA/flake.lock) = '["D"]' ]]
|
[[ $(jq -c .nodes.B.inputs.foobar $flakeFollowsA/flake.lock) = '["D"]' ]]
|
||||||
[[ $(jq -c .nodes.C.inputs.foobar $flakeFollowsA/flake.lock) = '["B","foobar"]' ]]
|
[[ $(jq -c .nodes.C.inputs.foobar $flakeFollowsA/flake.lock) = '["B","foobar"]' ]]
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,6 @@ nix_tests = \
|
||||||
flakes.sh \
|
flakes.sh \
|
||||||
flake-local-settings.sh \
|
flake-local-settings.sh \
|
||||||
build.sh \
|
build.sh \
|
||||||
compute-levels.sh \
|
|
||||||
repl.sh ca/repl.sh \
|
repl.sh ca/repl.sh \
|
||||||
ca/build.sh \
|
ca/build.sh \
|
||||||
ca/build-with-garbage-path.sh \
|
ca/build-with-garbage-path.sh \
|
||||||
|
|
@ -63,6 +62,10 @@ nix_tests = \
|
||||||
eval-store.sh
|
eval-store.sh
|
||||||
# parallel.sh
|
# parallel.sh
|
||||||
|
|
||||||
|
ifeq ($(HAVE_LIBCPUID), 1)
|
||||||
|
nix_tests += compute-levels.sh
|
||||||
|
endif
|
||||||
|
|
||||||
install-tests += $(foreach x, $(nix_tests), tests/$(x))
|
install-tests += $(foreach x, $(nix_tests), tests/$(x))
|
||||||
|
|
||||||
tests-environment = NIX_REMOTE= $(bash) -e
|
tests-environment = NIX_REMOTE= $(bash) -e
|
||||||
|
|
|
||||||
|
|
@ -3,59 +3,53 @@ source common.sh
|
||||||
clearStore
|
clearStore
|
||||||
|
|
||||||
if [[ -n ${CONTENT_ADDRESSED:-} ]]; then
|
if [[ -n ${CONTENT_ADDRESSED:-} ]]; then
|
||||||
nix-shell () {
|
shellDotNix="$PWD/ca-shell.nix"
|
||||||
command nix-shell --arg contentAddressed true "$@"
|
|
||||||
}
|
|
||||||
|
|
||||||
nix_develop() {
|
|
||||||
nix develop --arg contentAddressed true "$@"
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
nix_develop() {
|
shellDotNix="$PWD/shell.nix"
|
||||||
nix develop "$@"
|
|
||||||
}
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
export NIX_PATH=nixpkgs="$shellDotNix"
|
||||||
|
|
||||||
# Test nix-shell -A
|
# Test nix-shell -A
|
||||||
export IMPURE_VAR=foo
|
export IMPURE_VAR=foo
|
||||||
export SELECTED_IMPURE_VAR=baz
|
export SELECTED_IMPURE_VAR=baz
|
||||||
export NIX_BUILD_SHELL=$SHELL
|
|
||||||
output=$(nix-shell --pure shell.nix -A shellDrv --run \
|
output=$(nix-shell --pure "$shellDotNix" -A shellDrv --run \
|
||||||
'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX - $TEST_inNixShell"')
|
'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX - $TEST_inNixShell"')
|
||||||
|
|
||||||
[ "$output" = " - foo - bar - true" ]
|
[ "$output" = " - foo - bar - true" ]
|
||||||
|
|
||||||
# Test --keep
|
# Test --keep
|
||||||
output=$(nix-shell --pure --keep SELECTED_IMPURE_VAR shell.nix -A shellDrv --run \
|
output=$(nix-shell --pure --keep SELECTED_IMPURE_VAR "$shellDotNix" -A shellDrv --run \
|
||||||
'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX - $SELECTED_IMPURE_VAR"')
|
'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX - $SELECTED_IMPURE_VAR"')
|
||||||
|
|
||||||
[ "$output" = " - foo - bar - baz" ]
|
[ "$output" = " - foo - bar - baz" ]
|
||||||
|
|
||||||
# Test nix-shell on a .drv
|
# Test nix-shell on a .drv
|
||||||
[[ $(nix-shell --pure $(nix-instantiate shell.nix -A shellDrv) --run \
|
[[ $(nix-shell --pure $(nix-instantiate "$shellDotNix" -A shellDrv) --run \
|
||||||
'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX - $TEST_inNixShell"') = " - foo - bar - false" ]]
|
'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX - $TEST_inNixShell"') = " - foo - bar - false" ]]
|
||||||
|
|
||||||
[[ $(nix-shell --pure $(nix-instantiate shell.nix -A shellDrv) --run \
|
[[ $(nix-shell --pure $(nix-instantiate "$shellDotNix" -A shellDrv) --run \
|
||||||
'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX - $TEST_inNixShell"') = " - foo - bar - false" ]]
|
'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX - $TEST_inNixShell"') = " - foo - bar - false" ]]
|
||||||
|
|
||||||
# Test nix-shell on a .drv symlink
|
# Test nix-shell on a .drv symlink
|
||||||
|
|
||||||
# Legacy: absolute path and .drv extension required
|
# Legacy: absolute path and .drv extension required
|
||||||
nix-instantiate shell.nix -A shellDrv --add-root $TEST_ROOT/shell.drv
|
nix-instantiate "$shellDotNix" -A shellDrv --add-root $TEST_ROOT/shell.drv
|
||||||
[[ $(nix-shell --pure $TEST_ROOT/shell.drv --run \
|
[[ $(nix-shell --pure $TEST_ROOT/shell.drv --run \
|
||||||
'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX"') = " - foo - bar" ]]
|
'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX"') = " - foo - bar" ]]
|
||||||
|
|
||||||
# New behaviour: just needs to resolve to a derivation in the store
|
# New behaviour: just needs to resolve to a derivation in the store
|
||||||
nix-instantiate shell.nix -A shellDrv --add-root $TEST_ROOT/shell
|
nix-instantiate "$shellDotNix" -A shellDrv --add-root $TEST_ROOT/shell
|
||||||
[[ $(nix-shell --pure $TEST_ROOT/shell --run \
|
[[ $(nix-shell --pure $TEST_ROOT/shell --run \
|
||||||
'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX"') = " - foo - bar" ]]
|
'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX"') = " - foo - bar" ]]
|
||||||
|
|
||||||
# Test nix-shell -p
|
# Test nix-shell -p
|
||||||
output=$(NIX_PATH=nixpkgs=shell.nix nix-shell --pure -p foo bar --run 'echo "$(foo) $(bar)"')
|
output=$(NIX_PATH=nixpkgs="$shellDotNix" nix-shell --pure -p foo bar --run 'echo "$(foo) $(bar)"')
|
||||||
[ "$output" = "foo bar" ]
|
[ "$output" = "foo bar" ]
|
||||||
|
|
||||||
# Test nix-shell -p --arg x y
|
# Test nix-shell -p --arg x y
|
||||||
output=$(NIX_PATH=nixpkgs=shell.nix nix-shell --pure -p foo --argstr fooContents baz --run 'echo "$(foo)"')
|
output=$(NIX_PATH=nixpkgs="$shellDotNix" nix-shell --pure -p foo --argstr fooContents baz --run 'echo "$(foo)"')
|
||||||
[ "$output" = "baz" ]
|
[ "$output" = "baz" ]
|
||||||
|
|
||||||
# Test nix-shell shebang mode
|
# Test nix-shell shebang mode
|
||||||
|
|
@ -91,18 +85,18 @@ output=$($TEST_ROOT/spaced\ \\\'\"shell.shebang.rb abc ruby)
|
||||||
[ "$output" = '-e load(ARGV.shift) -- '"$TEST_ROOT"'/spaced \'\''"shell.shebang.rb abc ruby' ]
|
[ "$output" = '-e load(ARGV.shift) -- '"$TEST_ROOT"'/spaced \'\''"shell.shebang.rb abc ruby' ]
|
||||||
|
|
||||||
# Test 'nix develop'.
|
# Test 'nix develop'.
|
||||||
nix_develop -f shell.nix shellDrv -c bash -c '[[ -n $stdenv ]]'
|
nix develop -f "$shellDotNix" shellDrv -c bash -c '[[ -n $stdenv ]]'
|
||||||
|
|
||||||
# Ensure `nix develop -c` preserves stdin
|
# Ensure `nix develop -c` preserves stdin
|
||||||
echo foo | nix develop -f shell.nix shellDrv -c cat | grep -q foo
|
echo foo | nix develop -f "$shellDotNix" shellDrv -c cat | grep -q foo
|
||||||
|
|
||||||
# Ensure `nix develop -c` actually executes the command if stdout isn't a terminal
|
# Ensure `nix develop -c` actually executes the command if stdout isn't a terminal
|
||||||
nix_develop -f shell.nix shellDrv -c echo foo |& grep -q foo
|
nix develop -f "$shellDotNix" shellDrv -c echo foo |& grep -q foo
|
||||||
|
|
||||||
# Test 'nix print-dev-env'.
|
# Test 'nix print-dev-env'.
|
||||||
[[ $(nix print-dev-env -f shell.nix shellDrv --json | jq -r .variables.arr1.value[2]) = '3 4' ]]
|
[[ $(nix print-dev-env -f "$shellDotNix" shellDrv --json | jq -r .variables.arr1.value[2]) = '3 4' ]]
|
||||||
|
|
||||||
source <(nix print-dev-env -f shell.nix shellDrv)
|
source <(nix print-dev-env -f "$shellDotNix" shellDrv)
|
||||||
[[ -n $stdenv ]]
|
[[ -n $stdenv ]]
|
||||||
[[ ${arr1[2]} = "3 4" ]]
|
[[ ${arr1[2]} = "3 4" ]]
|
||||||
[[ ${arr2[1]} = $'\n' ]]
|
[[ ${arr2[1]} = $'\n' ]]
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,13 @@ source common.sh
|
||||||
replCmds="
|
replCmds="
|
||||||
simple = import ./simple.nix
|
simple = import ./simple.nix
|
||||||
:b simple
|
:b simple
|
||||||
|
:log simple
|
||||||
|
"
|
||||||
|
|
||||||
|
replFailingCmds="
|
||||||
|
failing = import ./simple-failing.nix
|
||||||
|
:b failing
|
||||||
|
:log failing
|
||||||
"
|
"
|
||||||
|
|
||||||
testRepl () {
|
testRepl () {
|
||||||
|
|
@ -12,6 +19,12 @@ testRepl () {
|
||||||
local outPath=$(echo "$replOutput" |&
|
local outPath=$(echo "$replOutput" |&
|
||||||
grep -o -E "$NIX_STORE_DIR/\w*-simple")
|
grep -o -E "$NIX_STORE_DIR/\w*-simple")
|
||||||
nix path-info "${nixArgs[@]}" "$outPath"
|
nix path-info "${nixArgs[@]}" "$outPath"
|
||||||
|
# simple.nix prints a PATH during build
|
||||||
|
echo "$replOutput" | grep -qs 'PATH=' || fail "nix repl :log doesn't output logs"
|
||||||
|
local replOutput="$(nix repl "${nixArgs[@]}" <<< "$replFailingCmds")"
|
||||||
|
echo "$replOutput"
|
||||||
|
echo "$replOutput" | grep -qs 'This should fail' \
|
||||||
|
|| fail "nix repl :log doesn't output logs for a failed derivation"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Simple test, try building a drv
|
# Simple test, try building a drv
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,10 @@ let pkgs = rec {
|
||||||
'';
|
'';
|
||||||
|
|
||||||
bash = shell;
|
bash = shell;
|
||||||
|
bashInteractive = runCommand "bash" {} ''
|
||||||
|
mkdir -p $out/bin
|
||||||
|
ln -s ${shell} $out/bin/bash
|
||||||
|
'';
|
||||||
|
|
||||||
# ruby "interpreter" that outputs "$@"
|
# ruby "interpreter" that outputs "$@"
|
||||||
ruby = runCommand "ruby" {} ''
|
ruby = runCommand "ruby" {} ''
|
||||||
|
|
|
||||||
12
tests/simple-failing.nix
Normal file
12
tests/simple-failing.nix
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
with import ./config.nix;
|
||||||
|
|
||||||
|
mkDerivation {
|
||||||
|
name = "simple-failing";
|
||||||
|
builder = builtins.toFile "builder.sh"
|
||||||
|
''
|
||||||
|
echo "This should fail"
|
||||||
|
exit 1
|
||||||
|
'';
|
||||||
|
PATH = "";
|
||||||
|
goodPath = path;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue