Compare commits
107 Commits
nix-init-c
...
2.5.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a646dfcdd6 | ||
|
|
95bd5da341 | ||
|
|
ade870764a | ||
|
|
46d86e06ba | ||
|
|
9529de2eed | ||
|
|
18cb094aab | ||
|
|
6ae5f39ea0 | ||
|
|
e2e5f3a78f | ||
|
|
cc6406cc59 | ||
|
|
2567b74c66 | ||
|
|
775bdc0d9e | ||
|
|
d17d46cfc2 | ||
|
|
df1edd143f | ||
|
|
05fcc681ac | ||
|
|
6d30f9e6fe | ||
|
|
f133001dc8 | ||
|
|
3f417c8d1c | ||
|
|
853771b589 | ||
|
|
84497119ad | ||
|
|
ec33014e23 | ||
|
|
33e96820d5 | ||
|
|
f24ac3115f | ||
|
|
0e0de90b35 | ||
|
|
be1055f2cc | ||
|
|
20b1290103 | ||
|
|
f9437b4f18 | ||
|
|
4194b68250 | ||
|
|
5d64c33fa5 | ||
|
|
c7b66caaca | ||
|
|
4ce112406b | ||
|
|
0bd93ed747 | ||
|
|
55e3a1108c | ||
|
|
bc57b3854e | ||
|
|
75654bacc5 | ||
|
|
9b2ff20e3b | ||
|
|
b6d08a9e3f | ||
|
|
167e864697 | ||
|
|
92ff5b4254 | ||
|
|
21206caf13 | ||
|
|
853ef1304c | ||
|
|
8b5088b62f | ||
|
|
a5e9b5428f | ||
|
|
ae21aab456 | ||
|
|
33926ed1e7 | ||
|
|
0a2fa2d684 | ||
|
|
d1aaa7ef71 | ||
|
|
fa58bff1ab | ||
|
|
76af9375c1 | ||
|
|
8093456111 | ||
|
|
d9b3adca75 | ||
|
|
52f5fa948a | ||
|
|
2e606e87c4 | ||
|
|
6db9ca8ca4 | ||
|
|
69b9198875 | ||
|
|
90700736c7 | ||
|
|
2ff71b0213 | ||
|
|
77b3e4b4ee | ||
|
|
b42c1bea42 | ||
|
|
77141dded4 | ||
|
|
8cbf862e6f | ||
|
|
3bf7a868ee | ||
|
|
7489811736 | ||
|
|
c32a5f4d38 | ||
|
|
782837d934 | ||
|
|
fb662e0acf | ||
|
|
f3f32f0c30 | ||
|
|
2f5c913d4a | ||
|
|
95157b4e66 | ||
|
|
70a717f7a8 | ||
|
|
1f15441103 | ||
|
|
1a9bfdc4ca | ||
|
|
d22ce8b68d | ||
|
|
092c375cda | ||
|
|
5f64b69d23 | ||
|
|
a473e85c80 | ||
|
|
b96164f4af | ||
|
|
92bcd77a67 | ||
|
|
6e0cbc666b | ||
|
|
e1420c66a4 | ||
|
|
ddf4fb750d | ||
|
|
99804465af | ||
|
|
3d36f48acb | ||
|
|
5c9a1ef30c | ||
|
|
45abf0fa5f | ||
|
|
90d8178009 | ||
|
|
a9bd06d0ea | ||
|
|
b73a1c0638 | ||
|
|
33a227503a | ||
|
|
1d5a881da5 | ||
|
|
3a0277305a | ||
|
|
152e3cda0c | ||
|
|
55275fcc59 | ||
|
|
3ef66cd23a | ||
|
|
b653fb9ccf | ||
|
|
c18238d92a | ||
|
|
6d166d19a6 | ||
|
|
288c252570 | ||
|
|
e588f4c655 | ||
|
|
05081bedc1 | ||
|
|
d41af23a6c | ||
|
|
86b7962807 | ||
|
|
4b28798bfc | ||
|
|
69431edbc1 | ||
|
|
a2473823d7 | ||
|
|
9d67332e4b | ||
|
|
374fe49ff7 | ||
|
|
8438114399 |
7
.github/PULL_REQUEST_TEMPLATE/pull_request_template.md
vendored
Normal file
7
.github/PULL_REQUEST_TEMPLATE/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
**Release Notes**
|
||||
Please include relevant [release notes](https://github.com/NixOS/nix/blob/master/doc/manual/src/release-notes/rl-next.md) as needed.
|
||||
|
||||
|
||||
**Testing**
|
||||
|
||||
If this issue is a regression or something that should block release, please consider including a test either in the [testsuite](https://github.com/NixOS/nix/tree/master/tests) or as a [hydraJob]( https://github.com/NixOS/nix/blob/master/flake.nix#L396) so that it can be part of the [automatic checks](https://hydra.nixos.org/jobset/nix/master).
|
||||
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
|
||||
|
||||
15
configure.ac
15
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"])
|
||||
have_libcpuid=1
|
||||
AC_DEFINE([HAVE_LIBCPUID], [1], [Use libcpuid])
|
||||
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])]
|
||||
)
|
||||
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
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
- [Hacking](contributing/hacking.md)
|
||||
- [CLI guideline](contributing/cli-guideline.md)
|
||||
- [Release Notes](release-notes/release-notes.md)
|
||||
- [Release X.Y (202?-??-??)](release-notes/rl-next.md)
|
||||
- [Release 2.5 (2021-12-13)](release-notes/rl-2.5.md)
|
||||
- [Release 2.4 (2021-11-01)](release-notes/rl-2.4.md)
|
||||
- [Release 2.3 (2019-09-04)](release-notes/rl-2.3.md)
|
||||
- [Release 2.2 (2019-01-11)](release-notes/rl-2.2.md)
|
||||
|
||||
@@ -53,8 +53,8 @@ example, the following command allows you to build a derivation for
|
||||
$ uname
|
||||
Linux
|
||||
|
||||
$ nix build \
|
||||
'(with import <nixpkgs> { system = "x86_64-darwin"; }; runCommand "foo" {} "uname > $out")' \
|
||||
$ nix build --impure \
|
||||
--expr '(with import <nixpkgs> { system = "x86_64-darwin"; }; runCommand "foo" {} "uname > $out")' \
|
||||
--builders 'ssh://mac x86_64-darwin'
|
||||
[1/0/1 built, 0.0 MiB DL] building foo on ssh://mac
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
the store object at `P` contains the path `Q` somewhere. The
|
||||
*references* of a store path are the set of store paths to which it
|
||||
has a reference.
|
||||
|
||||
|
||||
A derivation can reference other derivations and sources (but not
|
||||
output paths), whereas an output path only references other output
|
||||
paths.
|
||||
@@ -66,7 +66,7 @@
|
||||
is necessary to deploy whole closures, since otherwise at runtime
|
||||
files could be missing. The command `nix-store -qR` prints out
|
||||
closures of store paths.
|
||||
|
||||
|
||||
As an example, if the store object at path `P` contains a reference
|
||||
to path `Q`, then `Q` is in the closure of `P`. Further, if `Q`
|
||||
references `R` then `R` is also in the closure of `P`.
|
||||
@@ -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.
|
||||
|
||||
@@ -40,7 +40,7 @@ $ nix-channel --update
|
||||
>
|
||||
> On NixOS, you’re automatically subscribed to a NixOS channel
|
||||
> corresponding to your NixOS major release (e.g.
|
||||
> <http://nixos.org/channels/nixos-14.12>). A NixOS channel is identical
|
||||
> <http://nixos.org/channels/nixos-21.11>). A NixOS channel is identical
|
||||
> to the Nixpkgs channel, except that it contains only Linux binaries
|
||||
> and is updated only if a set of regression tests succeed.
|
||||
|
||||
|
||||
16
doc/manual/src/release-notes/rl-2.5.md
Normal file
16
doc/manual/src/release-notes/rl-2.5.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# Release 2.5 (2021-12-13)
|
||||
|
||||
* The garbage collector no longer blocks new builds, so the message
|
||||
`waiting for the big garbage collector lock...` is a thing of the
|
||||
past.
|
||||
|
||||
* Binary cache stores now have a setting `compression-level`.
|
||||
|
||||
* `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.
|
||||
@@ -1,7 +1 @@
|
||||
# Release 2.5 (2021-XX-XX)
|
||||
|
||||
* Binary cache stores now have a setting `compression-level`.
|
||||
|
||||
* `nix develop` now has a flag `--unpack` to run `unpackPhase`.
|
||||
|
||||
* Lists can now be compared lexicographically using the `<` operator.
|
||||
# Release X.Y (202?-??-??)
|
||||
|
||||
82
flake.nix
82
flake.nix
@@ -14,7 +14,7 @@
|
||||
then ""
|
||||
else "pre${builtins.substring 0 8 (self.lastModifiedDate or self.lastModified or "19700101")}_${self.shortRev or "dirty"}";
|
||||
|
||||
officialRelease = false;
|
||||
officialRelease = true;
|
||||
|
||||
linux64BitSystems = [ "x86_64-linux" "aarch64-linux" ];
|
||||
linuxSystems = linux64BitSystems ++ [ "i686-linux" ];
|
||||
@@ -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:
|
||||
import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [ self.overlay ];
|
||||
}
|
||||
);
|
||||
nixpkgsFor =
|
||||
let stdenvsPackages = forAllSystemsAndStdenvs
|
||||
(system: stdenv:
|
||||
import nixpkgs {
|
||||
inherit system;
|
||||
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
|
||||
|
||||
|
||||
@@ -73,8 +73,13 @@ ref<Store> EvalCommand::getEvalStore()
|
||||
|
||||
ref<EvalState> EvalCommand::getEvalState()
|
||||
{
|
||||
if (!evalState)
|
||||
evalState = std::make_shared<EvalState>(searchPath, getEvalStore(), getStore());
|
||||
if (!evalState) evalState =
|
||||
#if HAVE_BOEHMGC
|
||||
std::allocate_shared<EvalState>(traceable_allocator<EvalState>(),
|
||||
#else
|
||||
std::make_shared<EvalState>(
|
||||
#endif
|
||||
searchPath, getEvalStore(), getStore());
|
||||
return ref<EvalState>(evalState);
|
||||
}
|
||||
|
||||
|
||||
@@ -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(".");
|
||||
|
||||
|
||||
@@ -1656,7 +1656,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||
bool first = !forceString;
|
||||
ValueType firstType = nString;
|
||||
|
||||
for (auto & i : *es) {
|
||||
for (auto & [i_pos, i] : *es) {
|
||||
Value vTmp;
|
||||
i->eval(state, env, vTmp);
|
||||
|
||||
@@ -1677,19 +1677,19 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||
nf = n;
|
||||
nf += vTmp.fpoint;
|
||||
} else
|
||||
throwEvalError(pos, "cannot add %1% to an integer", showType(vTmp));
|
||||
throwEvalError(i_pos, "cannot add %1% to an integer", showType(vTmp));
|
||||
} else if (firstType == nFloat) {
|
||||
if (vTmp.type() == nInt) {
|
||||
nf += vTmp.integer;
|
||||
} else if (vTmp.type() == nFloat) {
|
||||
nf += vTmp.fpoint;
|
||||
} else
|
||||
throwEvalError(pos, "cannot add %1% to a float", showType(vTmp));
|
||||
throwEvalError(i_pos, "cannot add %1% to a float", showType(vTmp));
|
||||
} else
|
||||
/* skip canonization of first path, which would only be not
|
||||
canonized in the first place if it's coming from a ./${foo} type
|
||||
path */
|
||||
s << state.coerceToString(pos, vTmp, context, false, firstType == nString, !first);
|
||||
s << state.coerceToString(i_pos, vTmp, context, false, firstType == nString, !first);
|
||||
|
||||
first = false;
|
||||
}
|
||||
|
||||
@@ -480,11 +480,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
|
||||
|
||||
@@ -191,7 +191,7 @@ void ExprConcatStrings::show(std::ostream & str) const
|
||||
str << "(";
|
||||
for (auto & i : *es) {
|
||||
if (first) first = false; else str << " + ";
|
||||
str << *i;
|
||||
str << i.second;
|
||||
}
|
||||
str << ")";
|
||||
}
|
||||
@@ -439,7 +439,7 @@ void ExprOpNot::bindVars(const StaticEnv & env)
|
||||
void ExprConcatStrings::bindVars(const StaticEnv & env)
|
||||
{
|
||||
for (auto & i : *es)
|
||||
i->bindVars(env);
|
||||
i.second->bindVars(env);
|
||||
}
|
||||
|
||||
void ExprPos::bindVars(const StaticEnv & env)
|
||||
|
||||
@@ -332,8 +332,8 @@ struct ExprConcatStrings : Expr
|
||||
{
|
||||
Pos pos;
|
||||
bool forceString;
|
||||
vector<Expr *> * es;
|
||||
ExprConcatStrings(const Pos & pos, bool forceString, vector<Expr *> * es)
|
||||
vector<std::pair<Pos, Expr *> > * es;
|
||||
ExprConcatStrings(const Pos & pos, bool forceString, vector<std::pair<Pos, Expr *> > * es)
|
||||
: pos(pos), forceString(forceString), es(es) { };
|
||||
COMMON_METHODS
|
||||
};
|
||||
|
||||
@@ -152,7 +152,7 @@ static void addFormal(const Pos & pos, Formals * formals, const Formal & formal)
|
||||
}
|
||||
|
||||
|
||||
static Expr * stripIndentation(const Pos & pos, SymbolTable & symbols, vector<Expr *> & es)
|
||||
static Expr * stripIndentation(const Pos & pos, SymbolTable & symbols, vector<std::pair<Pos, Expr *> > & es)
|
||||
{
|
||||
if (es.empty()) return new ExprString(symbols.create(""));
|
||||
|
||||
@@ -162,7 +162,7 @@ static Expr * stripIndentation(const Pos & pos, SymbolTable & symbols, vector<Ex
|
||||
bool atStartOfLine = true; /* = seen only whitespace in the current line */
|
||||
size_t minIndent = 1000000;
|
||||
size_t curIndent = 0;
|
||||
for (auto & i : es) {
|
||||
for (auto & [i_pos, i] : es) {
|
||||
ExprIndStr * e = dynamic_cast<ExprIndStr *>(i);
|
||||
if (!e) {
|
||||
/* Anti-quotations end the current start-of-line whitespace. */
|
||||
@@ -192,12 +192,12 @@ static Expr * stripIndentation(const Pos & pos, SymbolTable & symbols, vector<Ex
|
||||
}
|
||||
|
||||
/* Strip spaces from each line. */
|
||||
vector<Expr *> * es2 = new vector<Expr *>;
|
||||
vector<std::pair<Pos, Expr *> > * es2 = new vector<std::pair<Pos, Expr *> >;
|
||||
atStartOfLine = true;
|
||||
size_t curDropped = 0;
|
||||
size_t n = es.size();
|
||||
for (vector<Expr *>::iterator i = es.begin(); i != es.end(); ++i, --n) {
|
||||
ExprIndStr * e = dynamic_cast<ExprIndStr *>(*i);
|
||||
for (vector<std::pair<Pos, Expr *> >::iterator i = es.begin(); i != es.end(); ++i, --n) {
|
||||
ExprIndStr * e = dynamic_cast<ExprIndStr *>(i->second);
|
||||
if (!e) {
|
||||
atStartOfLine = false;
|
||||
curDropped = 0;
|
||||
@@ -234,11 +234,11 @@ static Expr * stripIndentation(const Pos & pos, SymbolTable & symbols, vector<Ex
|
||||
s2 = string(s2, 0, p + 1);
|
||||
}
|
||||
|
||||
es2->push_back(new ExprString(symbols.create(s2)));
|
||||
es2->emplace_back(i->first, new ExprString(symbols.create(s2)));
|
||||
}
|
||||
|
||||
/* If this is a single string, then don't do a concatenation. */
|
||||
return es2->size() == 1 && dynamic_cast<ExprString *>((*es2)[0]) ? (*es2)[0] : new ExprConcatStrings(pos, true, es2);
|
||||
return es2->size() == 1 && dynamic_cast<ExprString *>((*es2)[0].second) ? (*es2)[0].second : new ExprConcatStrings(pos, true, es2);
|
||||
}
|
||||
|
||||
|
||||
@@ -277,7 +277,7 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
|
||||
char * path;
|
||||
char * uri;
|
||||
std::vector<nix::AttrName> * attrNames;
|
||||
std::vector<nix::Expr *> * string_parts;
|
||||
std::vector<std::pair<nix::Pos, nix::Expr *> > * string_parts;
|
||||
}
|
||||
|
||||
%type <e> start expr expr_function expr_if expr_op
|
||||
@@ -364,7 +364,7 @@ expr_op
|
||||
| expr_op UPDATE expr_op { $$ = new ExprOpUpdate(CUR_POS, $1, $3); }
|
||||
| expr_op '?' attrpath { $$ = new ExprOpHasAttr($1, *$3); }
|
||||
| expr_op '+' expr_op
|
||||
{ $$ = new ExprConcatStrings(CUR_POS, false, new vector<Expr *>({$1, $3})); }
|
||||
{ $$ = new ExprConcatStrings(CUR_POS, false, new vector<std::pair<Pos, Expr *> >({{makeCurPos(@1, data), $1}, {makeCurPos(@3, data), $3}})); }
|
||||
| expr_op '-' expr_op { $$ = new ExprCall(CUR_POS, new ExprVar(data->symbols.create("__sub")), {$1, $3}); }
|
||||
| expr_op '*' expr_op { $$ = new ExprCall(CUR_POS, new ExprVar(data->symbols.create("__mul")), {$1, $3}); }
|
||||
| expr_op '/' expr_op { $$ = new ExprCall(CUR_POS, new ExprVar(data->symbols.create("__div")), {$1, $3}); }
|
||||
@@ -410,7 +410,7 @@ expr_simple
|
||||
}
|
||||
| path_start PATH_END { $$ = $1; }
|
||||
| path_start string_parts_interpolated PATH_END {
|
||||
$2->insert($2->begin(), $1);
|
||||
$2->insert($2->begin(), {makeCurPos(@1, data), $1});
|
||||
$$ = new ExprConcatStrings(CUR_POS, false, $2);
|
||||
}
|
||||
| SPATH {
|
||||
@@ -448,13 +448,13 @@ string_parts
|
||||
;
|
||||
|
||||
string_parts_interpolated
|
||||
: string_parts_interpolated STR { $$ = $1; $1->push_back($2); }
|
||||
| string_parts_interpolated DOLLAR_CURLY expr '}' { $$ = $1; $1->push_back($3); }
|
||||
| DOLLAR_CURLY expr '}' { $$ = new vector<Expr *>; $$->push_back($2); }
|
||||
: string_parts_interpolated STR { $$ = $1; $1->emplace_back(makeCurPos(@2, data), $2); }
|
||||
| string_parts_interpolated DOLLAR_CURLY expr '}' { $$ = $1; $1->emplace_back(makeCurPos(@2, data), $3); }
|
||||
| DOLLAR_CURLY expr '}' { $$ = new vector<std::pair<Pos, Expr *> >; $$->emplace_back(makeCurPos(@1, data), $2); }
|
||||
| STR DOLLAR_CURLY expr '}' {
|
||||
$$ = new vector<Expr *>;
|
||||
$$->push_back($1);
|
||||
$$->push_back($3);
|
||||
$$ = new vector<std::pair<Pos, Expr *> >;
|
||||
$$->emplace_back(makeCurPos(@1, data), $1);
|
||||
$$->emplace_back(makeCurPos(@2, data), $3);
|
||||
}
|
||||
;
|
||||
|
||||
@@ -473,9 +473,9 @@ path_start
|
||||
;
|
||||
|
||||
ind_string_parts
|
||||
: ind_string_parts IND_STR { $$ = $1; $1->push_back($2); }
|
||||
| ind_string_parts DOLLAR_CURLY expr '}' { $$ = $1; $1->push_back($3); }
|
||||
| { $$ = new vector<Expr *>; }
|
||||
: ind_string_parts IND_STR { $$ = $1; $1->emplace_back(makeCurPos(@2, data), $2); }
|
||||
| ind_string_parts DOLLAR_CURLY expr '}' { $$ = $1; $1->emplace_back(makeCurPos(@2, data), $3); }
|
||||
| { $$ = new vector<std::pair<Pos, Expr *> >; }
|
||||
;
|
||||
|
||||
binds
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -176,6 +176,7 @@ struct TarballInputScheme : InputScheme
|
||||
|
||||
if (!hasSuffix(url.path, ".zip")
|
||||
&& !hasSuffix(url.path, ".tar")
|
||||
&& !hasSuffix(url.path, ".tgz")
|
||||
&& !hasSuffix(url.path, ".tar.gz")
|
||||
&& !hasSuffix(url.path, ".tar.xz")
|
||||
&& !hasSuffix(url.path, ".tar.bz2")
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
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);
|
||||
|
||||
@@ -145,10 +145,10 @@ static void preloadNSS() {
|
||||
*
|
||||
* All other platforms are unaffected.
|
||||
*/
|
||||
if (dlopen (LIBNSS_DNS_SO, RTLD_NOW) == NULL) {
|
||||
printMsg(Verbosity::lvlWarn, fmt("Unable to load nss_dns backend"));
|
||||
}
|
||||
__nss_configure_lookup ("hosts", "dns");
|
||||
if (!dlopen(LIBNSS_DNS_SO, RTLD_NOW))
|
||||
warn("unable to load nss_dns backend");
|
||||
// FIXME: get hosts entry from nsswitch.conf.
|
||||
__nss_configure_lookup("hosts", "files dns");
|
||||
#endif
|
||||
});
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -655,7 +655,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");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1779,11 +1779,14 @@ void LocalDerivationGoal::runChild()
|
||||
i686-linux build on an x86_64-linux machine. */
|
||||
struct utsname utsbuf;
|
||||
uname(&utsbuf);
|
||||
if (drv->platform == "i686-linux" &&
|
||||
(settings.thisSystem == "x86_64-linux" ||
|
||||
(!strcmp(utsbuf.sysname, "Linux") && !strcmp(utsbuf.machine, "x86_64")))) {
|
||||
if ((drv->platform == "i686-linux"
|
||||
&& (settings.thisSystem == "x86_64-linux"
|
||||
|| (!strcmp(utsbuf.sysname, "Linux") && !strcmp(utsbuf.machine, "x86_64"))))
|
||||
|| drv->platform == "armv7l-linux"
|
||||
|| drv->platform == "armv6l-linux")
|
||||
{
|
||||
if (personality(PER_LINUX32) == -1)
|
||||
throw SysError("cannot set i686-linux personality");
|
||||
throw SysError("cannot set 32-bit personality");
|
||||
}
|
||||
|
||||
/* Impersonate a Linux 2.6 machine to get some determinism in
|
||||
|
||||
@@ -281,11 +281,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 };
|
||||
|
||||
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(). */
|
||||
ParseSink sink; /* null sink; just parse the NAR */
|
||||
parseDump(sink, savedNARSource);
|
||||
} else
|
||||
parseDump(savedRegular, from);
|
||||
|
||||
auto dumpSource = sinkToSource([&](Sink & saved) {
|
||||
if (method == FileIngestionMethod::Recursive) {
|
||||
/* 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 {
|
||||
/* Incrementally parse the NAR file, stripping the
|
||||
metadata, and streaming the sole file we expect into
|
||||
`saved`. */
|
||||
RetrieveRegularNARSink savedRegular { saved };
|
||||
parseDump(savedRegular, from);
|
||||
if (!savedRegular.regular) throw Error("regular file expected");
|
||||
}
|
||||
});
|
||||
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);
|
||||
auto path = store->addToStoreFromDump(*dumpSource, baseName, method, hashAlgo);
|
||||
logger->stopWork();
|
||||
|
||||
to << store->printStorePath(path);
|
||||
@@ -951,7 +956,7 @@ void processConnection(
|
||||
|
||||
Finally finally([&]() {
|
||||
_isInterrupted = false;
|
||||
prevLogger->log(lvlDebug, fmt("%d operations", opCount));
|
||||
printMsgUsing(prevLogger, lvlDebug, "%d operations", opCount);
|
||||
});
|
||||
|
||||
if (GET_PROTOCOL_MINOR(clientVersion) >= 14 && readInt(from)) {
|
||||
@@ -984,6 +989,8 @@ void processConnection(
|
||||
break;
|
||||
}
|
||||
|
||||
printMsgUsing(prevLogger, lvlDebug, "received daemon op %d", op);
|
||||
|
||||
opCount++;
|
||||
|
||||
try {
|
||||
|
||||
@@ -126,7 +126,17 @@ void LocalStore::addTempRoot(const StorePath & path)
|
||||
auto socketPath = stateDir.get() + gcSocketPath;
|
||||
debug("connecting to '%s'", socketPath);
|
||||
state->fdRootsSocket = createUnixDomainSocket();
|
||||
nix::connect(state->fdRootsSocket.get(), socketPath);
|
||||
try {
|
||||
nix::connect(state->fdRootsSocket.get(), socketPath);
|
||||
} catch (SysError & e) {
|
||||
/* The garbage collector may have exited, so we need to
|
||||
restart. */
|
||||
if (e.errNo == ECONNREFUSED) {
|
||||
debug("GC socket connection refused");
|
||||
state->fdRootsSocket.close();
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -523,6 +533,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
||||
AutoCloseFD fdClient = accept(fdServer.get(), nullptr, nullptr);
|
||||
if (!fdClient) continue;
|
||||
|
||||
debug("GC roots server accepted new client");
|
||||
|
||||
/* Process the connection in a separate thread. */
|
||||
auto fdClient_ = fdClient.get();
|
||||
std::thread clientThread([&, fdClient = std::move(fdClient)]() {
|
||||
@@ -535,6 +547,12 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
||||
}
|
||||
});
|
||||
|
||||
/* On macOS, accepted sockets inherit the
|
||||
non-blocking flag from the server socket, so
|
||||
explicitly make it blocking. */
|
||||
if (fcntl(fdServer.get(), F_SETFL, fcntl(fdServer.get(), F_GETFL) & ~O_NONBLOCK) == -1)
|
||||
abort();
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
auto path = readLine(fdClient.get());
|
||||
@@ -559,7 +577,10 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
||||
} else
|
||||
printError("received garbage instead of a root from client");
|
||||
writeFull(fdClient.get(), "1", false);
|
||||
} catch (Error &) { break; }
|
||||
} catch (Error & e) {
|
||||
debug("reading GC root from client: %s", e.msg());
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -797,6 +797,15 @@ public:
|
||||
may be useful in certain scenarios (e.g. to spin up containers or
|
||||
set up userspace network interfaces in tests).
|
||||
)"};
|
||||
|
||||
Setting<StringSet> ignoredAcls{
|
||||
this, {"security.selinux", "system.nfs4_acl"}, "ignored-acls",
|
||||
R"(
|
||||
A list of ACLs that should be ignored, normally Nix attempts to
|
||||
remove all ACLs from files and directories in the Nix store, but
|
||||
some ACLs like `security.selinux` or `system.nfs4_acl` can't be
|
||||
removed even by root. Therefore it's best to just ignore them.
|
||||
)"};
|
||||
#endif
|
||||
|
||||
Setting<Strings> hashedMirrors{
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "references.hh"
|
||||
#include "callback.hh"
|
||||
#include "topo-sort.hh"
|
||||
#include "finally.hh"
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
@@ -589,9 +590,7 @@ static void canonicalisePathMetaData_(const Path & path, uid_t fromUid, InodesSe
|
||||
throw SysError("querying extended attributes of '%s'", path);
|
||||
|
||||
for (auto & eaName: tokenizeString<Strings>(std::string(eaBuf.data(), eaSize), std::string("\000", 1))) {
|
||||
/* Ignore SELinux security labels since these cannot be
|
||||
removed even by root. */
|
||||
if (eaName == "security.selinux") continue;
|
||||
if (settings.ignoredAcls.get().count(eaName)) continue;
|
||||
if (lremovexattr(path.c_str(), eaName.c_str()) == -1)
|
||||
throw SysError("removing extended attribute '%s' from '%s'", eaName, path);
|
||||
}
|
||||
@@ -1333,13 +1332,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;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "topo-sort.hh"
|
||||
#include "callback.hh"
|
||||
#include "closure.hh"
|
||||
#include "filetransfer.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -100,7 +101,8 @@ void Store::queryMissing(const std::vector<DerivedPath> & targets,
|
||||
|
||||
downloadSize_ = narSize_ = 0;
|
||||
|
||||
ThreadPool pool;
|
||||
// FIXME: make async.
|
||||
ThreadPool pool(fileTransferSettings.httpConnections);
|
||||
|
||||
struct State
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -1079,7 +1079,7 @@ std::map<StorePath, StorePath> copyPaths(
|
||||
nrFailed++;
|
||||
if (!settings.keepGoing)
|
||||
throw e;
|
||||
logger->log(lvlError, fmt("could not copy %s: %s", dstStore.printStorePath(storePath), e.what()));
|
||||
printMsg(lvlError, "could not copy %s: %s", dstStore.printStorePath(storePath), e.what());
|
||||
showProgress();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -189,13 +189,14 @@ extern Verbosity verbosity; /* suppress msgs > this */
|
||||
/* Print a string message if the current log level is at least the specified
|
||||
level. Note that this has to be implemented as a macro to ensure that the
|
||||
arguments are evaluated lazily. */
|
||||
#define printMsg(level, args...) \
|
||||
#define printMsgUsing(loggerParam, level, args...) \
|
||||
do { \
|
||||
auto __lvl = level; \
|
||||
if (__lvl <= nix::verbosity) { \
|
||||
logger->log(__lvl, fmt(args)); \
|
||||
loggerParam->log(__lvl, fmt(args)); \
|
||||
} \
|
||||
} while (0)
|
||||
#define printMsg(level, args...) printMsgUsing(logger, level, args)
|
||||
|
||||
#define printError(args...) printMsg(lvlError, args)
|
||||
#define notice(args...) printMsg(lvlNotice, args)
|
||||
|
||||
@@ -93,9 +93,16 @@ static void extract_archive(TarArchive & archive, const Path & destDir)
|
||||
else
|
||||
archive.check(r);
|
||||
|
||||
archive_entry_set_pathname(entry,
|
||||
archive_entry_copy_pathname(entry,
|
||||
(destDir + "/" + name).c_str());
|
||||
|
||||
// Patch hardlink path
|
||||
const char *original_hardlink = archive_entry_hardlink(entry);
|
||||
if (original_hardlink) {
|
||||
archive_entry_copy_hardlink(entry,
|
||||
(destDir + "/" + original_hardlink).c_str());
|
||||
}
|
||||
|
||||
archive.check(archive_read_extract(archive.archive, entry, flags));
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -83,11 +83,14 @@ UnresolvedApp Installable::toApp(EvalState & state)
|
||||
auto outPath = cursor->getAttr(state.sOutPath)->getString();
|
||||
auto outputName = cursor->getAttr(state.sOutputName)->getString();
|
||||
auto name = cursor->getAttr(state.sName)->getString();
|
||||
auto aPname = cursor->maybeGetAttr("pname");
|
||||
auto aMeta = cursor->maybeGetAttr("meta");
|
||||
auto aMainProgram = aMeta ? aMeta->maybeGetAttr("mainProgram") : nullptr;
|
||||
auto mainProgram =
|
||||
aMainProgram
|
||||
? aMainProgram->getString()
|
||||
: aPname
|
||||
? aPname->getString()
|
||||
: DrvName(name).name;
|
||||
auto program = outPath + "/bin/" + mainProgram;
|
||||
return UnresolvedApp { App {
|
||||
|
||||
@@ -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});
|
||||
}
|
||||
@@ -647,6 +672,8 @@ void NixRepl::addVarToScope(const Symbol & name, Value & v)
|
||||
{
|
||||
if (displ >= envSize)
|
||||
throw Error("environment full; cannot add more variables");
|
||||
if (auto oldVar = staticEnv.find(name); oldVar != staticEnv.vars.end())
|
||||
staticEnv.vars.erase(oldVar);
|
||||
staticEnv.vars.emplace_back(name, displ);
|
||||
staticEnv.sort();
|
||||
env->values[displ++] = &v;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -43,10 +43,15 @@ program specified by the app definition.
|
||||
|
||||
If *installable* evaluates to a derivation, it will try to execute the
|
||||
program `<out>/bin/<name>`, where *out* is the primary output store
|
||||
path of the derivation and *name* is the `meta.mainProgram` attribute
|
||||
of the derivation if it exists, and otherwise the name part of the
|
||||
value of the `name` attribute of the derivation (e.g. if `name` is set
|
||||
to `hello-1.10`, it will run `$out/bin/hello`).
|
||||
path of the derivation, and *name* is the first of the following that
|
||||
exists:
|
||||
|
||||
* The `meta.mainProgram` attribute of the derivation.
|
||||
* The `pname` attribute of the derivation.
|
||||
* The name part of the value of the `name` attribute of the derivation.
|
||||
|
||||
For instance, if `name` is set to `hello-1.10`, `nix run` will run
|
||||
`$out/bin/hello`.
|
||||
|
||||
# Flake output attributes
|
||||
|
||||
|
||||
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"]' ]]
|
||||
|
||||
@@ -19,7 +19,7 @@ pid=$!
|
||||
|
||||
sleep 2
|
||||
|
||||
outPath=$(nix-build -o "$TEST_ROOT/result" -E "
|
||||
outPath=$(nix-build --max-silent-time 60 -o "$TEST_ROOT/result" -E "
|
||||
with import ./config.nix;
|
||||
mkDerivation {
|
||||
name = \"non-blocking\";
|
||||
|
||||
@@ -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' ]]
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
source common.sh
|
||||
|
||||
replCmds="
|
||||
simple = 1
|
||||
simple = import ./simple.nix
|
||||
:b simple
|
||||
:log simple
|
||||
"
|
||||
|
||||
replFailingCmds="
|
||||
failing = import ./simple-failing.nix
|
||||
:b failing
|
||||
:log failing
|
||||
"
|
||||
|
||||
testRepl () {
|
||||
@@ -12,6 +20,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;
|
||||
}
|
||||
Reference in New Issue
Block a user