mirror of
https://github.com/NixOS/nix.git
synced 2025-11-23 18:59: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.])])
|
||||
])
|
||||
|
||||
# Look for libsodium, an optional dependency.
|
||||
# Look for libsodium.
|
||||
PKG_CHECK_MODULES([SODIUM], [libsodium], [CXXFLAGS="$SODIUM_CFLAGS $CXXFLAGS"])
|
||||
|
||||
# Look for libbrotli{enc,dec}.
|
||||
PKG_CHECK_MODULES([LIBBROTLI], [libbrotlienc libbrotlidec], [CXXFLAGS="$LIBBROTLI_CFLAGS $CXXFLAGS"])
|
||||
|
||||
# Look for libcpuid.
|
||||
have_libcpuid=
|
||||
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
|
||||
AC_DEFINE([HAVE_LIBCPUID], [1], [Use libcpuid])
|
||||
AC_DEFINE([HAVE_LIBCPUID], [1], [Use libcpuid])]
|
||||
)
|
||||
fi
|
||||
fi
|
||||
AC_SUBST(HAVE_LIBCPUID, [$have_libcpuid])
|
||||
|
||||
|
|
|
|||
|
|
@ -12,11 +12,13 @@ man-pages := $(foreach n, \
|
|||
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.
|
||||
# Set cores to 0 because otherwise nix show-config resolves the cores based on the current machine
|
||||
dummy-env = env -i \
|
||||
HOME=/dummy \
|
||||
NIX_CONF_DIR=/dummy \
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,25 @@ variables are set up so that those dependencies can be found:
|
|||
$ 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:
|
||||
|
||||
```console
|
||||
|
|
|
|||
|
|
@ -98,3 +98,7 @@
|
|||
store. It can contain regular files, directories and symbolic
|
||||
links. NARs are generated and unpacked using `nix-store --dump`
|
||||
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"
|
||||
empty root directory to mount your volume
|
||||
- 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
|
||||
- generate an encryption password
|
||||
- put it in your system Keychain
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
To run the latest stable release of Nix with Docker run the following command:
|
||||
|
||||
```console
|
||||
$ docker -ti run nixos/nix
|
||||
$ docker run -ti nixos/nix
|
||||
Unable to find image 'nixos/nix:latest' locally
|
||||
latest: Pulling from nixos/nix
|
||||
5843afab3874: Pull complete
|
||||
|
|
|
|||
|
|
@ -44,6 +44,11 @@
|
|||
obtained from the its repository
|
||||
<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
|
||||
because Nix needs GLR support in Bison and reentrancy support in
|
||||
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
|
||||
recommended unless your system doesn't support `libseccomp`). To get
|
||||
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`.
|
||||
|
||||
* 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" ];
|
||||
|
||||
stdenvs = [ "gccStdenv" "clangStdenv" "clang11Stdenv" "stdenv" ];
|
||||
|
||||
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.
|
||||
nixpkgsFor = forAllSystems (system:
|
||||
nixpkgsFor =
|
||||
let stdenvsPackages = forAllSystemsAndStdenvs
|
||||
(system: stdenv:
|
||||
import nixpkgs {
|
||||
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 {
|
||||
# Use "busybox-sandbox-shell" if present,
|
||||
|
|
@ -255,18 +276,15 @@
|
|||
$(cat ${installerClosureInfo}/store-paths)
|
||||
'';
|
||||
|
||||
in {
|
||||
|
||||
# A Nixpkgs overlay that overrides the 'nix' and
|
||||
# 'nix.perl-bindings' packages.
|
||||
overlay = final: prev: {
|
||||
|
||||
overlayFor = getStdenv: final: prev:
|
||||
let currentStdenv = getStdenv final; in
|
||||
{
|
||||
nixStable = prev.nix;
|
||||
|
||||
# Forward from the previous stage as we don’t want it to pick the lowdown override
|
||||
nixUnstable = prev.nixUnstable;
|
||||
|
||||
nix = with final; with commonDeps pkgs; stdenv.mkDerivation {
|
||||
nix = with final; with commonDeps pkgs; currentStdenv.mkDerivation {
|
||||
name = "nix-${version}";
|
||||
inherit version;
|
||||
|
||||
|
|
@ -288,9 +306,9 @@
|
|||
mkdir -p $out/lib
|
||||
cp -pd ${boost}/lib/{libboost_context*,libboost_thread*,libboost_system*} $out/lib
|
||||
rm -f $out/lib/*.a
|
||||
${lib.optionalString stdenv.isLinux ''
|
||||
${lib.optionalString currentStdenv.isLinux ''
|
||||
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;
|
||||
|
||||
passthru.perl-bindings = with final; stdenv.mkDerivation {
|
||||
passthru.perl-bindings = with final; currentStdenv.mkDerivation {
|
||||
name = "nix-perl-${version}";
|
||||
|
||||
src = self;
|
||||
|
|
@ -336,8 +354,8 @@
|
|||
pkgs.perl
|
||||
boost
|
||||
]
|
||||
++ lib.optional (stdenv.isLinux || stdenv.isDarwin) libsodium
|
||||
++ lib.optional stdenv.isDarwin darwin.apple_sdk.frameworks.Security;
|
||||
++ lib.optional (currentStdenv.isLinux || currentStdenv.isDarwin) libsodium
|
||||
++ lib.optional currentStdenv.isDarwin darwin.apple_sdk.frameworks.Security;
|
||||
|
||||
configureFlags = ''
|
||||
--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";
|
||||
|
||||
src = lowdown-src;
|
||||
|
|
@ -361,15 +379,20 @@
|
|||
nativeBuildInputs = [ buildPackages.which ];
|
||||
|
||||
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 \
|
||||
PREFIX=${placeholder "dev"} \
|
||||
BINDIR=${placeholder "bin"}/bin
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
in {
|
||||
|
||||
# A Nixpkgs overlay that overrides the 'nix' and
|
||||
# 'nix.perl-bindings' packages.
|
||||
overlay = overlayFor (p: p.stdenv);
|
||||
|
||||
hydraJobs = {
|
||||
|
||||
# Binary package for various platforms.
|
||||
|
|
@ -610,15 +633,22 @@
|
|||
doInstallCheck = true;
|
||||
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);
|
||||
|
||||
devShell = forAllSystems (system:
|
||||
devShell = forAllSystems (system: self.devShells.${system}.stdenvPackages);
|
||||
|
||||
devShells = forAllSystemsAndStdenvs (system: stdenv:
|
||||
with nixpkgsFor.${system};
|
||||
with commonDeps pkgs;
|
||||
|
||||
stdenv.mkDerivation {
|
||||
nixpkgsFor.${system}.${stdenv}.mkDerivation {
|
||||
name = "nix";
|
||||
|
||||
outputs = [ "out" "dev" "doc" ];
|
||||
|
|
|
|||
|
|
@ -25,5 +25,10 @@
|
|||
<string>/var/log/nix-daemon.log</string>
|
||||
<key>StandardOutPath</key>
|
||||
<string>/dev/null</string>
|
||||
<key>SoftResourceLimits</key>
|
||||
<dict>
|
||||
<key>NumberOfFiles</key>
|
||||
<integer>4096</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ perlarchname=$($perl -e 'use Config; print $Config{archname};')
|
|||
AC_SUBST(perllibdir, [${libdir}/perl5/site_perl/$perlversion/$perlarchname])
|
||||
AC_MSG_RESULT($perllibdir)
|
||||
|
||||
# Look for libsodium, an optional dependency.
|
||||
# Look for libsodium.
|
||||
PKG_CHECK_MODULES([SODIUM], [libsodium], [CXXFLAGS="$SODIUM_CFLAGS $CXXFLAGS"])
|
||||
|
||||
# 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
|
||||
local escaped_mountpoint="${NIX_ROOT/ /'\\\'040}"
|
||||
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
|
||||
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+
|
||||
# but handling both takes even more code...
|
||||
_sudo "to add Nix to /etc/synthetic.conf" \
|
||||
/usr/bin/ex /etc/synthetic.conf <<EOF
|
||||
/usr/bin/ex --noplugin /etc/synthetic.conf <<EOF
|
||||
:a
|
||||
${NIX_ROOT:1}
|
||||
.
|
||||
|
|
@ -794,7 +809,7 @@ setup_volume_daemon() {
|
|||
local volume_uuid="$2"
|
||||
if ! test_voldaemon; then
|
||||
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
|
||||
$(generate_mount_daemon "$cmd_type" "$volume_uuid")
|
||||
.
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ EOF
|
|||
setup_darwin_volume
|
||||
fi
|
||||
|
||||
if [ "$(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."
|
||||
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 /usr/sbin/diskutil enableOwnership /nix."
|
||||
fi
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,6 +377,11 @@ cure_artifacts() {
|
|||
}
|
||||
|
||||
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
|
||||
warning <<EOF
|
||||
Nix already appears to be installed. This installer may run into issues.
|
||||
|
|
@ -386,6 +391,11 @@ $(uninstall_directions)
|
|||
EOF
|
||||
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
|
||||
# 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
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ fi
|
|||
|
||||
# Determine if we could use the multi-user installer or not
|
||||
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
|
||||
|
||||
case "$(uname -s)" in
|
||||
|
|
@ -98,7 +98,7 @@ while [ $# -gt 0 ]; do
|
|||
echo " providing multi-user support and better isolation for local builds."
|
||||
echo " Both for security and reproducibility, this method is recommended if"
|
||||
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 " --no-daemon: Simple, single-user installation that does not require root and is"
|
||||
echo " trivial to uninstall."
|
||||
|
|
@ -144,7 +144,7 @@ if ! [ -e "$dest" ]; then
|
|||
fi
|
||||
|
||||
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
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -291,6 +291,9 @@ void completeFlakeRefWithFragment(
|
|||
|
||||
void completeFlakeRef(ref<Store> store, std::string_view prefix)
|
||||
{
|
||||
if (!settings.isExperimentalFeatureEnabled(Xp::Flakes))
|
||||
return;
|
||||
|
||||
if (prefix == "")
|
||||
completions->add(".");
|
||||
|
||||
|
|
|
|||
|
|
@ -482,11 +482,16 @@ LockedFlake lockFlake(
|
|||
}
|
||||
}
|
||||
|
||||
LockParent newParent {
|
||||
.path = inputPath,
|
||||
.absolute = false
|
||||
};
|
||||
|
||||
computeLocks(
|
||||
mustRefetch
|
||||
? getFlake(state, oldLock->lockedRef, false, flakeCache).inputs
|
||||
: fakeInputs,
|
||||
childNode, inputPath, oldLock, parent, parentPath);
|
||||
childNode, inputPath, oldLock, newParent, parentPath);
|
||||
|
||||
} else {
|
||||
/* We need to create a new lock file entry. So fetch
|
||||
|
|
|
|||
|
|
@ -2928,6 +2928,56 @@ static RegisterPrimOp primop_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)
|
||||
{
|
||||
state.forceFunction(*args[0], pos);
|
||||
|
|
@ -3732,7 +3782,7 @@ void EvalState::createBaseEnv()
|
|||
.fun = primOp.fun,
|
||||
.arity = std::max(primOp.args.size(), primOp.arity),
|
||||
.name = symbols.create(primOp.name),
|
||||
.args = std::move(primOp.args),
|
||||
.args = primOp.args,
|
||||
.doc = primOp.doc,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -425,9 +425,11 @@ void mkPath(Value & v, const char * s);
|
|||
#if HAVE_BOEHMGC
|
||||
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, ValueVector, std::less<Symbol>, traceable_allocator<std::pair<const Symbol, ValueVector> > > ValueVectorMap;
|
||||
#else
|
||||
typedef std::vector<Value *> ValueVector;
|
||||
typedef std::map<Symbol, Value *> ValueMap;
|
||||
typedef std::map<Symbol, ValueVector> ValueVectorMap;
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ struct PathInputScheme : InputScheme
|
|||
// for security, ensure that if the parent is a store path, it's inside it
|
||||
if (store->isInStore(parent)) {
|
||||
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);
|
||||
}
|
||||
} else
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ ProgressBarSettings 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(fields[n].type == Logger::Field::tString);
|
||||
|
|
|
|||
|
|
@ -427,7 +427,7 @@ RunPager::RunPager()
|
|||
});
|
||||
|
||||
pid.setKillSignal(SIGINT);
|
||||
|
||||
stdout = fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 0);
|
||||
if (dup2(toPager.writeSide.get(), STDOUT_FILENO) == -1)
|
||||
throw SysError("dupping stdout");
|
||||
}
|
||||
|
|
@ -438,7 +438,7 @@ RunPager::~RunPager()
|
|||
try {
|
||||
if (pid != -1) {
|
||||
std::cout.flush();
|
||||
close(STDOUT_FILENO);
|
||||
dup2(stdout, STDOUT_FILENO);
|
||||
pid.wait();
|
||||
}
|
||||
} catch (...) {
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ public:
|
|||
|
||||
private:
|
||||
Pid pid;
|
||||
int stdout;
|
||||
};
|
||||
|
||||
extern volatile ::sig_atomic_t blockInt;
|
||||
|
|
|
|||
|
|
@ -656,7 +656,7 @@ void DerivationGoal::tryLocalBuild() {
|
|||
throw Error(
|
||||
"unable to build with a primary store that isn't a local store; "
|
||||
"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'",
|
||||
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();
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -291,11 +291,11 @@ void Worker::run(const Goals & _topGoals)
|
|||
if (getMachines().empty())
|
||||
throw Error("unable to start any build; either increase '--max-jobs' "
|
||||
"or enable remote builds."
|
||||
"\nhttps://nixos.org/nix/manual/#chap-distributed-builds");
|
||||
"\nhttps://nixos.org/manual/nix/stable/advanced-topics/distributed-builds.html");
|
||||
else
|
||||
throw Error("unable to start any build; remote machines may not have "
|
||||
"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());
|
||||
|
|
|
|||
|
|
@ -431,25 +431,30 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
|||
hashAlgo = parseHashType(hashAlgoRaw);
|
||||
}
|
||||
|
||||
StringSink saved;
|
||||
TeeSource savedNARSource(from, saved);
|
||||
RetrieveRegularNARSink savedRegular { saved };
|
||||
|
||||
auto dumpSource = sinkToSource([&](Sink & saved) {
|
||||
if (method == FileIngestionMethod::Recursive) {
|
||||
/* Get the entire NAR dump from the client and save it to
|
||||
a string so that we can pass it to
|
||||
addToStoreFromDump(). */
|
||||
/* We parse the NAR dump through into `saved` unmodified,
|
||||
so why all this extra work? We still parse the NAR so
|
||||
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 */
|
||||
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);
|
||||
|
||||
logger->startWork();
|
||||
if (!savedRegular.regular) throw Error("regular file expected");
|
||||
|
||||
// FIXME: try to stream directly from `from`.
|
||||
StringSource dumpSource { *saved.s };
|
||||
auto path = store->addToStoreFromDump(dumpSource, baseName, method, hashAlgo);
|
||||
}
|
||||
});
|
||||
logger->startWork();
|
||||
auto path = store->addToStoreFromDump(*dumpSource, baseName, method, hashAlgo);
|
||||
logger->stopWork();
|
||||
|
||||
to << store->printStorePath(path);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include "references.hh"
|
||||
#include "callback.hh"
|
||||
#include "topo-sort.hh"
|
||||
#include "finally.hh"
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
|
@ -1333,13 +1334,15 @@ StorePath LocalStore::addToStoreFromDump(Source & source0, const string & name,
|
|||
auto want = std::min(chunkSize, settings.narBufferSize - oldSize);
|
||||
dump.resize(oldSize + want);
|
||||
auto got = 0;
|
||||
Finally cleanup([&]() {
|
||||
dump.resize(oldSize + got);
|
||||
});
|
||||
try {
|
||||
got = source.read(dump.data() + oldSize, want);
|
||||
} catch (EndOfFile &) {
|
||||
inMemory = true;
|
||||
break;
|
||||
}
|
||||
dump.resize(oldSize + got);
|
||||
}
|
||||
|
||||
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 (!regex) {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ struct DrvName
|
|||
DrvName(std::string_view s);
|
||||
~DrvName();
|
||||
|
||||
bool matches(DrvName & n);
|
||||
bool matches(const DrvName & n);
|
||||
|
||||
private:
|
||||
std::unique_ptr<Regex> regex;
|
||||
|
|
|
|||
|
|
@ -684,6 +684,14 @@ void RemoteStore::queryRealisationUncached(const DrvOutput & id,
|
|||
Callback<std::shared_ptr<const Realisation>> callback) noexcept
|
||||
{
|
||||
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 << id.to_string();
|
||||
conn.processStderr();
|
||||
|
|
|
|||
|
|
@ -512,6 +512,7 @@ std::pair<AutoCloseFD, Path> createTempFile(const Path & prefix)
|
|||
AutoCloseFD fd(mkstemp((char *) tmpl.c_str()));
|
||||
if (!fd)
|
||||
throw SysError("creating temporary file '%s'", tmpl);
|
||||
closeOnExec(fd.get());
|
||||
return {std::move(fd), tmpl};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
|
|
|
|||
|
|
@ -359,6 +359,7 @@ static void main_nix_build(int argc, char * * argv)
|
|||
is not set, then build bashInteractive from
|
||||
<nixpkgs>. */
|
||||
auto shell = getEnv("NIX_BUILD_SHELL");
|
||||
std::optional<StorePath> shellDrv;
|
||||
|
||||
if (!shell) {
|
||||
|
||||
|
|
@ -375,8 +376,7 @@ static void main_nix_build(int argc, char * * argv)
|
|||
auto bashDrv = store->parseStorePath(drv->queryDrvPath());
|
||||
pathsToBuild.push_back({bashDrv});
|
||||
pathsToCopy.insert(bashDrv);
|
||||
|
||||
shell = drv->queryOutPath() + "/bin/bash";
|
||||
shellDrv = bashDrv;
|
||||
|
||||
} catch (Error & e) {
|
||||
logError(e.info());
|
||||
|
|
@ -402,6 +402,11 @@ static void main_nix_build(int argc, char * * argv)
|
|||
|
||||
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)) {
|
||||
auto resolvedDrv = drv.tryResolve(*store);
|
||||
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,
|
||||
const Strings & args, bool newestOnly)
|
||||
{
|
||||
|
|
@ -232,79 +317,42 @@ static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems,
|
|||
selectors.emplace_back("*");
|
||||
|
||||
DrvInfos elems;
|
||||
set<unsigned int> done;
|
||||
std::set<std::size_t> done;
|
||||
|
||||
for (auto & i : selectors) {
|
||||
typedef list<std::pair<DrvInfo, unsigned int> > Matches;
|
||||
Matches matches;
|
||||
unsigned int n = 0;
|
||||
for (DrvInfos::const_iterator j = allElems.begin();
|
||||
j != allElems.end(); ++j, ++n)
|
||||
{
|
||||
DrvName drvName(j->queryName());
|
||||
if (i.matches(drvName)) {
|
||||
i.hits++;
|
||||
matches.push_back(std::pair<DrvInfo, unsigned int>(*j, n));
|
||||
for (auto & selector : selectors) {
|
||||
std::vector<Match> matches;
|
||||
for (const auto & [index, drvInfo] : enumerate(allElems)) {
|
||||
const auto drvName = DrvName { drvInfo.queryName() };
|
||||
if (selector.matches(drvName)) {
|
||||
++selector.hits;
|
||||
matches.emplace_back(drvInfo, index);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
|
||||
/* 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);
|
||||
}
|
||||
matches = pickNewestOnly(state, std::move(matches));
|
||||
}
|
||||
|
||||
/* Insert only those elements in the final list that we
|
||||
haven't inserted before. */
|
||||
for (auto & j : matches)
|
||||
if (done.insert(j.second).second)
|
||||
elems.push_back(j.first);
|
||||
}
|
||||
for (auto & match : matches)
|
||||
if (done.insert(match.index).second)
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ R""(
|
|||
|
||||
# Description
|
||||
|
||||
`nix flake` provides subcommands for managing *flake
|
||||
`nix registry` provides subcommands for managing *flake
|
||||
registries*. Flake registries are a convenience feature that allows
|
||||
you to refer to flakes using symbolic identifiers such as `nixpkgs`,
|
||||
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();
|
||||
Finally resetTerminal([&]() { rl_deprep_terminal(); });
|
||||
char * s = readline(prompt.c_str());
|
||||
Finally doFree([&]() { free(s); });
|
||||
restoreSignals();
|
||||
|
|
@ -356,6 +357,8 @@ StringSet NixRepl::completePrefix(string prefix)
|
|||
// Quietly ignore evaluation errors.
|
||||
} catch (UndefinedVarError & e) {
|
||||
// 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"
|
||||
<< " :t <expr> Describe result of evaluation\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") {
|
||||
|
|
@ -497,7 +501,7 @@ bool NixRepl::processLine(string line)
|
|||
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;
|
||||
evalString(arg, v);
|
||||
StorePath drvPath = getDerivationPath(v);
|
||||
|
|
@ -511,6 +515,27 @@ bool NixRepl::processLine(string line)
|
|||
logger->cout(" %s -> %s", outputName, state->store->printStorePath(outputPath));
|
||||
} else if (command == ":i") {
|
||||
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 {
|
||||
runNix("nix-shell", {drvPathRaw});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,14 +35,17 @@ R""(
|
|||
nix-repl> emacs.drvPath
|
||||
"/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:
|
||||
out -> /nix/store/0njwbgwmkwls0w5dv9mpc1pq5fj39q0l-hello
|
||||
|
||||
nix-repl> builtins.readFile drv
|
||||
"Hello, world!\n"
|
||||
|
||||
nix-repl> :log drv
|
||||
Hello, world!
|
||||
```
|
||||
|
||||
# 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 = {
|
||||
foobar.url = "path:$flakeFollowsA/flakeE";
|
||||
nonFlake.url = "path:$nonFlakeDir";
|
||||
goodoo.follows = "C/goodoo";
|
||||
C = {
|
||||
url = "path:./flakeC";
|
||||
inputs.foobar.follows = "foobar";
|
||||
|
|
@ -736,6 +737,7 @@ cat > $flakeFollowsC/flake.nix <<EOF
|
|||
description = "Flake C";
|
||||
inputs = {
|
||||
foobar.url = "path:$flakeFollowsA/flakeE";
|
||||
goodoo.follows = "foobar";
|
||||
};
|
||||
outputs = { ... }: {};
|
||||
}
|
||||
|
|
@ -760,8 +762,18 @@ EOF
|
|||
git -C $flakeFollowsA add flake.nix flakeB/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
|
||||
|
||||
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.foobar $flakeFollowsA/flake.lock) = '["D"]' ]]
|
||||
[[ $(jq -c .nodes.C.inputs.foobar $flakeFollowsA/flake.lock) = '["B","foobar"]' ]]
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ nix_tests = \
|
|||
flakes.sh \
|
||||
flake-local-settings.sh \
|
||||
build.sh \
|
||||
compute-levels.sh \
|
||||
repl.sh ca/repl.sh \
|
||||
ca/build.sh \
|
||||
ca/build-with-garbage-path.sh \
|
||||
|
|
@ -63,6 +62,10 @@ nix_tests = \
|
|||
eval-store.sh
|
||||
# parallel.sh
|
||||
|
||||
ifeq ($(HAVE_LIBCPUID), 1)
|
||||
nix_tests += compute-levels.sh
|
||||
endif
|
||||
|
||||
install-tests += $(foreach x, $(nix_tests), tests/$(x))
|
||||
|
||||
tests-environment = NIX_REMOTE= $(bash) -e
|
||||
|
|
|
|||
|
|
@ -3,59 +3,53 @@ source common.sh
|
|||
clearStore
|
||||
|
||||
if [[ -n ${CONTENT_ADDRESSED:-} ]]; then
|
||||
nix-shell () {
|
||||
command nix-shell --arg contentAddressed true "$@"
|
||||
}
|
||||
|
||||
nix_develop() {
|
||||
nix develop --arg contentAddressed true "$@"
|
||||
}
|
||||
shellDotNix="$PWD/ca-shell.nix"
|
||||
else
|
||||
nix_develop() {
|
||||
nix develop "$@"
|
||||
}
|
||||
shellDotNix="$PWD/shell.nix"
|
||||
fi
|
||||
|
||||
export NIX_PATH=nixpkgs="$shellDotNix"
|
||||
|
||||
# Test nix-shell -A
|
||||
export IMPURE_VAR=foo
|
||||
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"')
|
||||
|
||||
[ "$output" = " - foo - bar - true" ]
|
||||
|
||||
# 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"')
|
||||
|
||||
[ "$output" = " - foo - bar - baz" ]
|
||||
|
||||
# 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" ]]
|
||||
|
||||
[[ $(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" ]]
|
||||
|
||||
# Test nix-shell on a .drv symlink
|
||||
|
||||
# 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 \
|
||||
'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX"') = " - foo - bar" ]]
|
||||
|
||||
# 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 \
|
||||
'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX"') = " - foo - bar" ]]
|
||||
|
||||
# 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" ]
|
||||
|
||||
# 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" ]
|
||||
|
||||
# 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' ]
|
||||
|
||||
# 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
|
||||
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
|
||||
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'.
|
||||
[[ $(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 ]]
|
||||
[[ ${arr1[2]} = "3 4" ]]
|
||||
[[ ${arr2[1]} = $'\n' ]]
|
||||
|
|
|
|||
|
|
@ -3,6 +3,13 @@ source common.sh
|
|||
replCmds="
|
||||
simple = import ./simple.nix
|
||||
:b simple
|
||||
:log simple
|
||||
"
|
||||
|
||||
replFailingCmds="
|
||||
failing = import ./simple-failing.nix
|
||||
:b failing
|
||||
:log failing
|
||||
"
|
||||
|
||||
testRepl () {
|
||||
|
|
@ -12,6 +19,12 @@ testRepl () {
|
|||
local outPath=$(echo "$replOutput" |&
|
||||
grep -o -E "$NIX_STORE_DIR/\w*-simple")
|
||||
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
|
||||
|
|
|
|||
|
|
@ -74,6 +74,10 @@ let pkgs = rec {
|
|||
'';
|
||||
|
||||
bash = shell;
|
||||
bashInteractive = runCommand "bash" {} ''
|
||||
mkdir -p $out/bin
|
||||
ln -s ${shell} $out/bin/bash
|
||||
'';
|
||||
|
||||
# ruby "interpreter" that outputs "$@"
|
||||
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