Merge remote-tracking branch 'upstream/master' into rm-createdirs

This commit is contained in:
John Ericson 2024-06-17 12:57:54 -04:00
commit a1bb668ccb
112 changed files with 2290 additions and 893 deletions

2
.gitignore vendored
View file

@ -11,6 +11,8 @@ perl/Makefile.config
/svn-revision /svn-revision
/libtool /libtool
/config/config.* /config/config.*
# Default meson build dir
/build
# /doc/manual/ # /doc/manual/
/doc/manual/*.1 /doc/manual/*.1

View file

@ -1,2 +1,4 @@
external-sources=true external-sources=true
source-path=SCRIPTDIR source-path=SCRIPTDIR
# Hack for scripts in e.g. tests/functional/ca
source-path=SCRIPTDIR/..

View file

@ -1 +1 @@
2.23.0 2.24.0

View file

@ -13,7 +13,7 @@ Visit [nix.dev](https://nix.dev) for [installation instructions](https://nix.dev
Full reference documentation can be found in the [Nix manual](https://nixos.org/nix/manual). Full reference documentation can be found in the [Nix manual](https://nixos.org/nix/manual).
## Building And Developing ## Building and developing
See our [Hacking guide](https://nixos.org/manual/nix/unstable/contributing/hacking.html) in our manual for instruction on how to See our [Hacking guide](https://nixos.org/manual/nix/unstable/contributing/hacking.html) in our manual for instruction on how to
set up a development environment and build Nix from source. set up a development environment and build Nix from source.
@ -22,12 +22,17 @@ See our [Hacking guide](https://nixos.org/manual/nix/unstable/contributing/hacki
Check the [contributing guide](./CONTRIBUTING.md) if you want to get involved with developing Nix. Check the [contributing guide](./CONTRIBUTING.md) if you want to get involved with developing Nix.
## Additional Resources ## Additional resources
- [Nix manual](https://nixos.org/nix/manual) Nix was created by Eelco Dolstra and developed as the subject of his PhD thesis [The Purely Functional Software Deployment Model](https://edolstra.github.io/pubs/phd-thesis.pdf), published 2006.
- [Nix jobsets on hydra.nixos.org](https://hydra.nixos.org/project/nix) Today, a world-wide developer community contributes to Nix and the ecosystem that has grown around it.
- [NixOS Discourse](https://discourse.nixos.org/)
- [Matrix - #nix:nixos.org](https://matrix.to/#/#nix:nixos.org) - [The Nix, Nixpkgs, NixOS Community on nixos.org](https://nixos.org/)
- [Official documentation on nix.dev](https://nix.dev)
- [Nixpkgs](https://github.com/NixOS/nixpkgs) is [the largest, most up-to-date free software repository in the world](https://repology.org/repositories/graphs)
- [NixOS](https://github.com/NixOS/nixpkgs/tree/master/nixos) is a Linux distribution that can be configured fully declaratively
- [Discourse](https://discourse.nixos.org/)
- [Matrix](https://matrix.to/#/#nix:nixos.org)
## License ## License

View file

@ -369,6 +369,14 @@ if test "$gc" = yes; then
PKG_CHECK_MODULES([BDW_GC], [bdw-gc]) PKG_CHECK_MODULES([BDW_GC], [bdw-gc])
CXXFLAGS="$BDW_GC_CFLAGS $CXXFLAGS" CXXFLAGS="$BDW_GC_CFLAGS $CXXFLAGS"
AC_DEFINE(HAVE_BOEHMGC, 1, [Whether to use the Boehm garbage collector.]) AC_DEFINE(HAVE_BOEHMGC, 1, [Whether to use the Boehm garbage collector.])
# See `fixupBoehmStackPointer`, for the integration between Boehm GC
# and Boost coroutines.
old_CFLAGS="$CFLAGS"
# Temporary set `-pthread` just for the next check
CFLAGS="$CFLAGS -pthread"
AC_CHECK_FUNCS([pthread_attr_get_np pthread_getattr_np])
CFLAGS="$old_CFLAGS"
fi fi
AS_IF([test "$ENABLE_UNIT_TESTS" == "yes"],[ AS_IF([test "$ENABLE_UNIT_TESTS" == "yes"],[

View file

@ -71,10 +71,9 @@
[`__contentAddressed`](./language/advanced-attributes.md#adv-attr-__contentAddressed) [`__contentAddressed`](./language/advanced-attributes.md#adv-attr-__contentAddressed)
attribute set to `true`. attribute set to `true`.
- [fixed-output derivation]{#gloss-fixed-output-derivation} - [fixed-output derivation]{#gloss-fixed-output-derivation} (FOD)
A derivation which includes the A [derivation] where a cryptographic hash of the [output] is determined in advance using the [`outputHash`](./language/advanced-attributes.md#adv-attr-outputHash) attribute, and where the [`builder`](@docroot@/language/derivations.md#attr-builder) executable has access to the network.
[`outputHash`](./language/advanced-attributes.md#adv-attr-outputHash) attribute.
- [store]{#gloss-store} - [store]{#gloss-store}

View file

@ -120,12 +120,11 @@ Derivations can declare some infrequently used optional attributes.
configuration setting. configuration setting.
- [`outputHash`]{#adv-attr-outputHash}; [`outputHashAlgo`]{#adv-attr-outputHashAlgo}; [`outputHashMode`]{#adv-attr-outputHashMode}\ - [`outputHash`]{#adv-attr-outputHash}; [`outputHashAlgo`]{#adv-attr-outputHashAlgo}; [`outputHashMode`]{#adv-attr-outputHashMode}\
These attributes declare that the derivation is a so-called These attributes declare that the derivation is a so-called *fixed-output derivation* (FOD), which means that a cryptographic hash of the output is already known in advance.
*fixed-output derivation*, which means that a cryptographic hash of
the output is already known in advance. When the build of a As opposed to regular derivations, the [`builder`] executable of a fixed-output derivation has access to the network.
fixed-output derivation finishes, Nix computes the cryptographic Nix computes a cryptographic hash of its output and compares that to the hash declared with these attributes.
hash of the output and compares it to the hash declared with these If there is a mismatch, the derivation fails.
attributes. If there is a mismatch, the build fails.
The rationale for fixed-output derivations is derivations such as The rationale for fixed-output derivations is derivations such as
those produced by the `fetchurl` function. This function downloads a those produced by the `fetchurl` function. This function downloads a
@ -279,7 +278,9 @@ Derivations can declare some infrequently used optional attributes.
> **Note** > **Note**
> >
> If set to `false`, the [`builder`](./derivations.md#attr-builder) should be able to run on the system type specified in the [`system` attribute](./derivations.md#attr-system), since the derivation cannot be substituted. > If set to `false`, the [`builder`] should be able to run on the system type specified in the [`system` attribute](./derivations.md#attr-system), since the derivation cannot be substituted.
[`builder`]: ./derivations.md#attr-builder
- [`__structuredAttrs`]{#adv-attr-structuredAttrs}\ - [`__structuredAttrs`]{#adv-attr-structuredAttrs}\
If the special attribute `__structuredAttrs` is set to `true`, the other derivation If the special attribute `__structuredAttrs` is set to `true`, the other derivation

View file

@ -160,21 +160,34 @@
}; };
}); });
nix = nix-util = final.callPackage ./src/libutil/package.nix {
let
officialRelease = false;
versionSuffix =
if officialRelease
then ""
else "pre${builtins.substring 0 8 (self.lastModifiedDate or self.lastModified or "19700101")}_${self.shortRev or "dirty"}";
in final.callPackage ./package.nix {
inherit inherit
fileset fileset
stdenv stdenv
officialRelease
versionSuffix
;
};
nix-store = final.callPackage ./src/libstore/package.nix {
inherit
fileset
stdenv
officialRelease
versionSuffix
;
libseccomp = final.libseccomp-nix;
busybox-sandbox-shell = final.busybox-sandbox-shell or final.default-busybox-sandbox-shell;
};
nix =
final.callPackage ./package.nix {
inherit
fileset
stdenv
officialRelease
versionSuffix versionSuffix
; ;
officialRelease = false;
boehmgc = final.boehmgc-nix; boehmgc = final.boehmgc-nix;
libgit2 = final.libgit2-nix; libgit2 = final.libgit2-nix;
libseccomp = final.libseccomp-nix; libseccomp = final.libseccomp-nix;
@ -203,7 +216,7 @@
# 'nix.perl-bindings' packages. # 'nix.perl-bindings' packages.
overlays.default = overlayFor (p: p.stdenv); overlays.default = overlayFor (p: p.stdenv);
hydraJobs = import ./build/hydra.nix { hydraJobs = import ./maintainers/hydra.nix {
inherit inherit
inputs inputs
binaryTarball binaryTarball
@ -236,11 +249,34 @@
} // devFlake.checks.${system} or {} } // devFlake.checks.${system} or {}
); );
packages = forAllSystems (system: rec { packages = forAllSystems (system: {
inherit (nixpkgsFor.${system}.native) nix changelog-d; inherit (nixpkgsFor.${system}.native)
default = nix; changelog-d;
} // (lib.optionalAttrs (builtins.elem system linux64BitSystems) { default = self.packages.${system}.nix;
nix-static = nixpkgsFor.${system}.static.nix; } // lib.concatMapAttrs
# We need to flatten recursive attribute sets of derivations to pass `flake check`.
(pkgName: {}: {
"${pkgName}" = nixpkgsFor.${system}.native.${pkgName};
"${pkgName}-static" = nixpkgsFor.${system}.static.${pkgName};
} // lib.concatMapAttrs
(crossSystem: {}: {
"${pkgName}-${crossSystem}" = nixpkgsFor.${system}.cross.${crossSystem}.${pkgName};
})
(lib.genAttrs crossSystems (_: { }))
// lib.concatMapAttrs
(stdenvName: {}: {
"${pkgName}-${stdenvName}" = nixpkgsFor.${system}.stdenvs."${stdenvName}Packages".${pkgName};
})
(lib.genAttrs stdenvs (_: { })))
{
"nix" = { };
# Temporarily disabled because GitHub Actions OOM issues. Once
# the old build system is gone and we are back to one build
# system, we should reenable these.
#"nix-util" = { };
#"nix-store" = { };
}
// lib.optionalAttrs (builtins.elem system linux64BitSystems) {
dockerImage = dockerImage =
let let
pkgs = nixpkgsFor.${system}.native; pkgs = nixpkgsFor.${system}.native;
@ -255,18 +291,7 @@
ln -s ${image} $image ln -s ${image} $image
echo "file binary-dist $image" >> $out/nix-support/hydra-build-products echo "file binary-dist $image" >> $out/nix-support/hydra-build-products
''; '';
} // builtins.listToAttrs (map });
(crossSystem: {
name = "nix-${crossSystem}";
value = nixpkgsFor.${system}.cross.${crossSystem}.nix;
})
crossSystems)
// builtins.listToAttrs (map
(stdenvName: {
name = "nix-${stdenvName}";
value = nixpkgsFor.${system}.stdenvs."${stdenvName}Packages".nix;
})
stdenvs)));
devShells = let devShells = let
makeShell = pkgs: stdenv: (pkgs.nix.override { inherit stdenv; forDevShell = true; }).overrideAttrs (attrs: makeShell = pkgs: stdenv: (pkgs.nix.override { inherit stdenv; forDevShell = true; }).overrideAttrs (attrs:
@ -274,6 +299,11 @@
modular = devFlake.getSystem stdenv.buildPlatform.system; modular = devFlake.getSystem stdenv.buildPlatform.system;
in { in {
pname = "shell-for-" + attrs.pname; pname = "shell-for-" + attrs.pname;
# Remove the version suffix to avoid unnecessary attempts to substitute in nix develop
version = lib.fileContents ./.version;
name = attrs.pname;
installFlags = "sysconfdir=$(out)/etc"; installFlags = "sysconfdir=$(out)/etc";
shellHook = '' shellHook = ''
PATH=$prefix/bin:$PATH PATH=$prefix/bin:$PATH
@ -288,12 +318,20 @@
src = null; src = null;
env = { env = {
# Needed for Meson to find Boost.
# https://github.com/NixOS/nixpkgs/issues/86131.
BOOST_INCLUDEDIR = "${lib.getDev pkgs.boost}/include";
BOOST_LIBRARYDIR = "${lib.getLib pkgs.boost}/lib";
# For `make format`, to work without installing pre-commit # For `make format`, to work without installing pre-commit
_NIX_PRE_COMMIT_HOOKS_CONFIG = _NIX_PRE_COMMIT_HOOKS_CONFIG =
"${(pkgs.formats.yaml { }).generate "pre-commit-config.yaml" modular.pre-commit.settings.rawConfig}"; "${(pkgs.formats.yaml { }).generate "pre-commit-config.yaml" modular.pre-commit.settings.rawConfig}";
}; };
mesonFlags = pkgs.nix-util.mesonFlags ++ pkgs.nix-store.mesonFlags;
nativeBuildInputs = attrs.nativeBuildInputs or [] nativeBuildInputs = attrs.nativeBuildInputs or []
++ pkgs.nix-util.nativeBuildInputs
++ pkgs.nix-store.nativeBuildInputs
++ [ ++ [
modular.pre-commit.settings.package modular.pre-commit.settings.package
(pkgs.writeScriptBin "pre-commit-hooks-install" (pkgs.writeScriptBin "pre-commit-hooks-install"

View file

@ -507,50 +507,30 @@
''^scripts/install-nix-from-closure\.sh$'' ''^scripts/install-nix-from-closure\.sh$''
''^scripts/install-systemd-multi-user\.sh$'' ''^scripts/install-systemd-multi-user\.sh$''
''^src/nix/get-env\.sh$'' ''^src/nix/get-env\.sh$''
''^tests/functional/bash-profile\.sh$''
''^tests/functional/binary-cache-build-remote\.sh$''
''^tests/functional/binary-cache\.sh$''
''^tests/functional/brotli\.sh$''
''^tests/functional/build-delete\.sh$''
''^tests/functional/build-dry\.sh$''
''^tests/functional/build\.sh$'' ''^tests/functional/build\.sh$''
''^tests/functional/ca/build-cache\.sh$''
''^tests/functional/ca/build-dry\.sh$'' ''^tests/functional/ca/build-dry\.sh$''
''^tests/functional/ca/build-with-garbage-path\.sh$'' ''^tests/functional/ca/build-with-garbage-path\.sh$''
''^tests/functional/ca/build\.sh$''
''^tests/functional/ca/common\.sh$'' ''^tests/functional/ca/common\.sh$''
''^tests/functional/ca/concurrent-builds\.sh$'' ''^tests/functional/ca/concurrent-builds\.sh$''
''^tests/functional/ca/derivation-json\.sh$''
''^tests/functional/ca/duplicate-realisation-in-closure\.sh$''
''^tests/functional/ca/eval-store\.sh$'' ''^tests/functional/ca/eval-store\.sh$''
''^tests/functional/ca/gc\.sh$'' ''^tests/functional/ca/gc\.sh$''
''^tests/functional/ca/import-derivation\.sh$'' ''^tests/functional/ca/import-derivation\.sh$''
''^tests/functional/ca/new-build-cmd\.sh$'' ''^tests/functional/ca/new-build-cmd\.sh$''
''^tests/functional/ca/nix-copy\.sh$''
''^tests/functional/ca/nix-run\.sh$''
''^tests/functional/ca/nix-shell\.sh$'' ''^tests/functional/ca/nix-shell\.sh$''
''^tests/functional/ca/post-hook\.sh$'' ''^tests/functional/ca/post-hook\.sh$''
''^tests/functional/ca/recursive\.sh$'' ''^tests/functional/ca/recursive\.sh$''
''^tests/functional/ca/repl\.sh$'' ''^tests/functional/ca/repl\.sh$''
''^tests/functional/ca/selfref-gc\.sh$'' ''^tests/functional/ca/selfref-gc\.sh$''
''^tests/functional/ca/signatures\.sh$''
''^tests/functional/ca/substitute\.sh$''
''^tests/functional/ca/why-depends\.sh$'' ''^tests/functional/ca/why-depends\.sh$''
''^tests/functional/case-hack\.sh$''
''^tests/functional/check-refs\.sh$''
''^tests/functional/check-reqs\.sh$''
''^tests/functional/check\.sh$'' ''^tests/functional/check\.sh$''
''^tests/functional/chroot-store\.sh$''
''^tests/functional/common/vars-and-functions\.sh$'' ''^tests/functional/common/vars-and-functions\.sh$''
''^tests/functional/completions\.sh$'' ''^tests/functional/completions\.sh$''
''^tests/functional/compression-levels\.sh$''
''^tests/functional/compute-levels\.sh$'' ''^tests/functional/compute-levels\.sh$''
''^tests/functional/config\.sh$'' ''^tests/functional/config\.sh$''
''^tests/functional/db-migration\.sh$'' ''^tests/functional/db-migration\.sh$''
''^tests/functional/debugger\.sh$'' ''^tests/functional/debugger\.sh$''
''^tests/functional/dependencies\.builder0\.sh$'' ''^tests/functional/dependencies\.builder0\.sh$''
''^tests/functional/dependencies\.sh$'' ''^tests/functional/dependencies\.sh$''
''^tests/functional/derivation-json\.sh$''
''^tests/functional/dump-db\.sh$'' ''^tests/functional/dump-db\.sh$''
''^tests/functional/dyn-drv/build-built-drv\.sh$'' ''^tests/functional/dyn-drv/build-built-drv\.sh$''
''^tests/functional/dyn-drv/common\.sh$'' ''^tests/functional/dyn-drv/common\.sh$''
@ -558,10 +538,8 @@
''^tests/functional/dyn-drv/eval-outputOf\.sh$'' ''^tests/functional/dyn-drv/eval-outputOf\.sh$''
''^tests/functional/dyn-drv/old-daemon-error-hack\.sh$'' ''^tests/functional/dyn-drv/old-daemon-error-hack\.sh$''
''^tests/functional/dyn-drv/recursive-mod-json\.sh$'' ''^tests/functional/dyn-drv/recursive-mod-json\.sh$''
''^tests/functional/dyn-drv/text-hashed-output\.sh$''
''^tests/functional/eval-store\.sh$'' ''^tests/functional/eval-store\.sh$''
''^tests/functional/eval\.sh$'' ''^tests/functional/eval\.sh$''
''^tests/functional/experimental-features\.sh$''
''^tests/functional/export-graph\.sh$'' ''^tests/functional/export-graph\.sh$''
''^tests/functional/export\.sh$'' ''^tests/functional/export\.sh$''
''^tests/functional/extra-sandbox-profile\.sh$'' ''^tests/functional/extra-sandbox-profile\.sh$''
@ -571,49 +549,32 @@
''^tests/functional/fetchGitSubmodules\.sh$'' ''^tests/functional/fetchGitSubmodules\.sh$''
''^tests/functional/fetchGitVerification\.sh$'' ''^tests/functional/fetchGitVerification\.sh$''
''^tests/functional/fetchMercurial\.sh$'' ''^tests/functional/fetchMercurial\.sh$''
''^tests/functional/fetchPath\.sh$''
''^tests/functional/fetchTree-file\.sh$''
''^tests/functional/fetchurl\.sh$'' ''^tests/functional/fetchurl\.sh$''
''^tests/functional/filter-source\.sh$''
''^tests/functional/fixed\.builder1\.sh$'' ''^tests/functional/fixed\.builder1\.sh$''
''^tests/functional/fixed\.builder2\.sh$'' ''^tests/functional/fixed\.builder2\.sh$''
''^tests/functional/fixed\.sh$'' ''^tests/functional/fixed\.sh$''
''^tests/functional/flakes/absolute-attr-paths\.sh$''
''^tests/functional/flakes/absolute-paths\.sh$'' ''^tests/functional/flakes/absolute-paths\.sh$''
''^tests/functional/flakes/build-paths\.sh$''
''^tests/functional/flakes/bundle\.sh$''
''^tests/functional/flakes/check\.sh$'' ''^tests/functional/flakes/check\.sh$''
''^tests/functional/flakes/circular\.sh$''
''^tests/functional/flakes/common\.sh$'' ''^tests/functional/flakes/common\.sh$''
''^tests/functional/flakes/config\.sh$'' ''^tests/functional/flakes/config\.sh$''
''^tests/functional/flakes/develop\.sh$'' ''^tests/functional/flakes/develop\.sh$''
''^tests/functional/flakes/flake-in-submodule\.sh$''
''^tests/functional/flakes/flakes\.sh$'' ''^tests/functional/flakes/flakes\.sh$''
''^tests/functional/flakes/follow-paths\.sh$'' ''^tests/functional/flakes/follow-paths\.sh$''
''^tests/functional/flakes/init\.sh$''
''^tests/functional/flakes/inputs\.sh$''
''^tests/functional/flakes/mercurial\.sh$''
''^tests/functional/flakes/prefetch\.sh$'' ''^tests/functional/flakes/prefetch\.sh$''
''^tests/functional/flakes/run\.sh$'' ''^tests/functional/flakes/run\.sh$''
''^tests/functional/flakes/search-root\.sh$''
''^tests/functional/flakes/show\.sh$'' ''^tests/functional/flakes/show\.sh$''
''^tests/functional/flakes/unlocked-override\.sh$''
''^tests/functional/fmt\.sh$'' ''^tests/functional/fmt\.sh$''
''^tests/functional/fmt\.simple\.sh$'' ''^tests/functional/fmt\.simple\.sh$''
''^tests/functional/function-trace\.sh$''
''^tests/functional/gc-auto\.sh$'' ''^tests/functional/gc-auto\.sh$''
''^tests/functional/gc-concurrent\.builder\.sh$'' ''^tests/functional/gc-concurrent\.builder\.sh$''
''^tests/functional/gc-concurrent\.sh$'' ''^tests/functional/gc-concurrent\.sh$''
''^tests/functional/gc-concurrent2\.builder\.sh$'' ''^tests/functional/gc-concurrent2\.builder\.sh$''
''^tests/functional/gc-non-blocking\.sh$'' ''^tests/functional/gc-non-blocking\.sh$''
''^tests/functional/gc-runtime\.sh$''
''^tests/functional/gc\.sh$'' ''^tests/functional/gc\.sh$''
''^tests/functional/git-hashing/common\.sh$'' ''^tests/functional/git-hashing/common\.sh$''
''^tests/functional/git-hashing/simple\.sh$'' ''^tests/functional/git-hashing/simple\.sh$''
''^tests/functional/hash-convert\.sh$'' ''^tests/functional/hash-convert\.sh$''
''^tests/functional/hash-path\.sh$''
''^tests/functional/help\.sh$'' ''^tests/functional/help\.sh$''
''^tests/functional/import-derivation\.sh$''
''^tests/functional/impure-derivations\.sh$'' ''^tests/functional/impure-derivations\.sh$''
''^tests/functional/impure-env\.sh$'' ''^tests/functional/impure-env\.sh$''
''^tests/functional/impure-eval\.sh$'' ''^tests/functional/impure-eval\.sh$''

View file

@ -32,17 +32,26 @@ let
doBuild = false; doBuild = false;
}; };
forAllPackages = lib.genAttrs [
"nix"
"nix-util"
"nix-store"
];
in in
{ {
# Binary package for various platforms. # Binary package for various platforms.
build = forAllSystems (system: self.packages.${system}.nix); build = forAllPackages (pkgName:
forAllSystems (system: nixpkgsFor.${system}.native.${pkgName}));
shellInputs = forAllSystems (system: self.devShells.${system}.default.inputDerivation); shellInputs = forAllSystems (system: self.devShells.${system}.default.inputDerivation);
buildStatic = lib.genAttrs linux64BitSystems (system: self.packages.${system}.nix-static); buildStatic = forAllPackages (pkgName:
lib.genAttrs linux64BitSystems (system: nixpkgsFor.${system}.static.${pkgName}));
buildCross = forAllCrossSystems (crossSystem: buildCross = forAllPackages (pkgName:
lib.genAttrs [ "x86_64-linux" ] (system: self.packages.${system}."nix-${crossSystem}")); forAllCrossSystems (crossSystem:
lib.genAttrs [ "x86_64-linux" ] (system: nixpkgsFor.${system}.cross.${crossSystem}.${pkgName})));
buildNoGc = forAllSystems (system: buildNoGc = forAllSystems (system:
self.packages.${system}.nix.override { enableGC = false; } self.packages.${system}.nix.override { enableGC = false; }
@ -76,7 +85,7 @@ in
binaryTarballCross = lib.genAttrs [ "x86_64-linux" ] (system: binaryTarballCross = lib.genAttrs [ "x86_64-linux" ] (system:
forAllCrossSystems (crossSystem: forAllCrossSystems (crossSystem:
binaryTarball binaryTarball
self.packages.${system}."nix-${crossSystem}" nixpkgsFor.${system}.cross.${crossSystem}.nix
nixpkgsFor.${system}.cross.${crossSystem})); nixpkgsFor.${system}.cross.${crossSystem}));
# The first half of the installation script. This is uploaded # The first half of the installation script. This is uploaded

10
meson.build Normal file
View file

@ -0,0 +1,10 @@
# This is just a stub project to include all the others as subprojects
# for development shell purposes
project('nix-dev-shell', 'cpp',
version : files('.version'),
subproject_dir : 'src',
)
subproject('libutil')
subproject('libstore')

View file

@ -8,7 +8,7 @@ GCH = $(buildprefix)precompiled-headers.h.gch
$(GCH): precompiled-headers.h $(GCH): precompiled-headers.h
@rm -f $@ @rm -f $@
@mkdir -p "$(dir $@)" @mkdir -p "$(dir $@)"
$(trace-gen) $(CXX) -x c++-header -o $@ $< $(GLOBAL_CXXFLAGS) $(GCH_CXXFLAGS) $(trace-gen) $(CXX) -c -x c++-header -o $@ $< $(GLOBAL_CXXFLAGS) $(GCH_CXXFLAGS)
clean-files += $(GCH) clean-files += $(GCH)

View file

@ -208,7 +208,9 @@ in {
# If we are doing just build or just docs, the one thing will use # If we are doing just build or just docs, the one thing will use
# "out". We only need additional outputs if we are doing both. # "out". We only need additional outputs if we are doing both.
++ lib.optional (doBuild && (enableManual || enableInternalAPIDocs || enableExternalAPIDocs)) "doc" ++ lib.optional (doBuild && (enableManual || enableInternalAPIDocs || enableExternalAPIDocs)) "doc"
++ lib.optional installUnitTests "check"; ++ lib.optional installUnitTests "check"
++ lib.optional doCheck "testresults"
;
nativeBuildInputs = [ nativeBuildInputs = [
autoconf-archive autoconf-archive
@ -317,6 +319,10 @@ in {
makeFlags = "profiledir=$(out)/etc/profile.d PRECOMPILE_HEADERS=1"; makeFlags = "profiledir=$(out)/etc/profile.d PRECOMPILE_HEADERS=1";
preCheck = ''
mkdir $testresults
'';
installTargets = lib.optional doBuild "install" installTargets = lib.optional doBuild "install"
++ lib.optional enableInternalAPIDocs "internal-api-html" ++ lib.optional enableInternalAPIDocs "internal-api-html"
++ lib.optional enableExternalAPIDocs "external-api-html"; ++ lib.optional enableExternalAPIDocs "external-api-html";
@ -385,8 +391,7 @@ in {
separateDebugInfo = !stdenv.hostPlatform.isStatic; separateDebugInfo = !stdenv.hostPlatform.isStatic;
# TODO `releaseTools.coverageAnalysis` in Nixpkgs needs to be updated # TODO Always true after https://github.com/NixOS/nixpkgs/issues/318564
# to work with `strictDeps`.
strictDeps = !withCoverageChecks; strictDeps = !withCoverageChecks;
hardeningDisable = lib.optional stdenv.hostPlatform.isStatic "pie"; hardeningDisable = lib.optional stdenv.hostPlatform.isStatic "pie";

View file

@ -754,7 +754,7 @@ I will:
(if it does, I will tell you how to clean them up.) (if it does, I will tell you how to clean them up.)
- create local users (see the list above for the users I'll make) - create local users (see the list above for the users I'll make)
- create a local group ($NIX_BUILD_GROUP_NAME) - create a local group ($NIX_BUILD_GROUP_NAME)
- install Nix in to $NIX_ROOT - install Nix in $NIX_ROOT
- create a configuration file in /etc/nix - create a configuration file in /etc/nix
- set up the "default profile" by creating some Nix-related files in - set up the "default profile" by creating some Nix-related files in
$ROOT_HOME $ROOT_HOME

View file

@ -42,56 +42,56 @@ nix_err nix_libexpr_init(nix_c_context * context)
} }
nix_err nix_expr_eval_from_string( nix_err nix_expr_eval_from_string(
nix_c_context * context, EvalState * state, const char * expr, const char * path, Value * value) nix_c_context * context, EvalState * state, const char * expr, const char * path, nix_value * value)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
nix::Expr * parsedExpr = state->state.parseExprFromString(expr, state->state.rootPath(nix::CanonPath(path))); nix::Expr * parsedExpr = state->state.parseExprFromString(expr, state->state.rootPath(nix::CanonPath(path)));
state->state.eval(parsedExpr, *(nix::Value *) value); state->state.eval(parsedExpr, value->value);
state->state.forceValue(*(nix::Value *) value, nix::noPos); state->state.forceValue(value->value, nix::noPos);
} }
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
} }
nix_err nix_value_call(nix_c_context * context, EvalState * state, Value * fn, Value * arg, Value * value) nix_err nix_value_call(nix_c_context * context, EvalState * state, Value * fn, nix_value * arg, nix_value * value)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
state->state.callFunction(*(nix::Value *) fn, *(nix::Value *) arg, *(nix::Value *) value, nix::noPos); state->state.callFunction(fn->value, arg->value, value->value, nix::noPos);
state->state.forceValue(*(nix::Value *) value, nix::noPos); state->state.forceValue(value->value, nix::noPos);
} }
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
} }
nix_err nix_value_call_multi(nix_c_context * context, EvalState * state, Value * fn, size_t nargs, Value ** args, Value * value) nix_err nix_value_call_multi(nix_c_context * context, EvalState * state, nix_value * fn, size_t nargs, nix_value ** args, nix_value * value)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
state->state.callFunction(*(nix::Value *) fn, nargs, (nix::Value * *)args, *(nix::Value *) value, nix::noPos); state->state.callFunction(fn->value, nargs, (nix::Value * *)args, value->value, nix::noPos);
state->state.forceValue(*(nix::Value *) value, nix::noPos); state->state.forceValue(value->value, nix::noPos);
} }
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
} }
nix_err nix_value_force(nix_c_context * context, EvalState * state, Value * value) nix_err nix_value_force(nix_c_context * context, EvalState * state, nix_value * value)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
state->state.forceValue(*(nix::Value *) value, nix::noPos); state->state.forceValue(value->value, nix::noPos);
} }
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
} }
nix_err nix_value_force_deep(nix_c_context * context, EvalState * state, Value * value) nix_err nix_value_force_deep(nix_c_context * context, EvalState * state, nix_value * value)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
state->state.forceValueDeep(*(nix::Value *) value); state->state.forceValueDeep(value->value);
} }
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
} }
@ -181,6 +181,15 @@ nix_err nix_gc_decref(nix_c_context * context, const void *)
void nix_gc_now() {} void nix_gc_now() {}
#endif #endif
nix_err nix_value_incref(nix_c_context * context, nix_value *x)
{
return nix_gc_incref(context, (const void *) x);
}
nix_err nix_value_decref(nix_c_context * context, nix_value *x)
{
return nix_gc_decref(context, (const void *) x);
}
void nix_gc_register_finalizer(void * obj, void * cd, void (*finalizer)(void * obj, void * cd)) void nix_gc_register_finalizer(void * obj, void * cd, void (*finalizer)(void * obj, void * cd))
{ {
#ifdef HAVE_BOEHMGC #ifdef HAVE_BOEHMGC

View file

@ -29,14 +29,23 @@ extern "C" {
* @see nix_state_create * @see nix_state_create
*/ */
typedef struct EvalState EvalState; // nix::EvalState typedef struct EvalState EvalState; // nix::EvalState
/**
* @brief Represents a value in the Nix language. /** @brief A Nix language value, or thunk that may evaluate to a value.
*
* Values are the primary objects manipulated in the Nix language.
* They are considered to be immutable from a user's perspective, but the process of evaluating a value changes its
* ValueType if it was a thunk. After a value has been evaluated, its ValueType does not change.
*
* Evaluation in this context refers to the process of evaluating a single value object, also called "forcing" the
* value; see `nix_value_force`.
*
* The evaluator manages its own memory, but your use of the C API must follow the reference counting rules.
* *
* Owned by the garbage collector.
* @struct Value
* @see value_manip * @see value_manip
* @see nix_value_incref, nix_value_decref
*/ */
typedef void Value; // nix::Value typedef struct nix_value nix_value;
[[deprecated("use nix_value instead")]] typedef nix_value Value;
// Function prototypes // Function prototypes
/** /**
@ -65,7 +74,7 @@ nix_err nix_libexpr_init(nix_c_context * context);
* @return NIX_OK if the evaluation was successful, an error code otherwise. * @return NIX_OK if the evaluation was successful, an error code otherwise.
*/ */
nix_err nix_expr_eval_from_string( nix_err nix_expr_eval_from_string(
nix_c_context * context, EvalState * state, const char * expr, const char * path, Value * value); nix_c_context * context, EvalState * state, const char * expr, const char * path, nix_value * value);
/** /**
* @brief Calls a Nix function with an argument. * @brief Calls a Nix function with an argument.
@ -79,7 +88,7 @@ nix_err nix_expr_eval_from_string(
* @see nix_init_apply() for a similar function that does not performs the call immediately, but stores it as a thunk. * @see nix_init_apply() for a similar function that does not performs the call immediately, but stores it as a thunk.
* Note the different argument order. * Note the different argument order.
*/ */
nix_err nix_value_call(nix_c_context * context, EvalState * state, Value * fn, Value * arg, Value * value); nix_err nix_value_call(nix_c_context * context, EvalState * state, nix_value * fn, nix_value * arg, nix_value * value);
/** /**
* @brief Calls a Nix function with multiple arguments. * @brief Calls a Nix function with multiple arguments.
@ -98,7 +107,7 @@ nix_err nix_value_call(nix_c_context * context, EvalState * state, Value * fn, V
* @see NIX_VALUE_CALL For a macro that wraps this function for convenience. * @see NIX_VALUE_CALL For a macro that wraps this function for convenience.
*/ */
nix_err nix_value_call_multi( nix_err nix_value_call_multi(
nix_c_context * context, EvalState * state, Value * fn, size_t nargs, Value ** args, Value * value); nix_c_context * context, EvalState * state, nix_value * fn, size_t nargs, nix_value ** args, nix_value * value);
/** /**
* @brief Calls a Nix function with multiple arguments. * @brief Calls a Nix function with multiple arguments.
@ -116,7 +125,7 @@ nix_err nix_value_call_multi(
*/ */
#define NIX_VALUE_CALL(context, state, value, fn, ...) \ #define NIX_VALUE_CALL(context, state, value, fn, ...) \
do { \ do { \
Value * args_array[] = {__VA_ARGS__}; \ nix_value * args_array[] = {__VA_ARGS__}; \
size_t nargs = sizeof(args_array) / sizeof(args_array[0]); \ size_t nargs = sizeof(args_array) / sizeof(args_array[0]); \
nix_value_call_multi(context, state, fn, nargs, args_array, value); \ nix_value_call_multi(context, state, fn, nargs, args_array, value); \
} while (0) } while (0)
@ -124,12 +133,10 @@ nix_err nix_value_call_multi(
/** /**
* @brief Forces the evaluation of a Nix value. * @brief Forces the evaluation of a Nix value.
* *
* The Nix interpreter is lazy, and not-yet-evaluated Values can be * The Nix interpreter is lazy, and not-yet-evaluated values can be
* of type NIX_TYPE_THUNK instead of their actual value. * of type NIX_TYPE_THUNK instead of their actual value.
* *
* This function converts these Values into their final type. * This function mutates such a `nix_value`, so that, if successful, it has its final type.
*
* @note This function is mainly needed before calling @ref getters, but not for API calls that return a `Value`.
* *
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
* @param[in] state The state of the evaluation. * @param[in] state The state of the evaluation.
@ -138,7 +145,7 @@ nix_err nix_value_call_multi(
* @return NIX_OK if the force operation was successful, an error code * @return NIX_OK if the force operation was successful, an error code
* otherwise. * otherwise.
*/ */
nix_err nix_value_force(nix_c_context * context, EvalState * state, Value * value); nix_err nix_value_force(nix_c_context * context, EvalState * state, nix_value * value);
/** /**
* @brief Forces the deep evaluation of a Nix value. * @brief Forces the deep evaluation of a Nix value.
@ -154,7 +161,7 @@ nix_err nix_value_force(nix_c_context * context, EvalState * state, Value * valu
* @return NIX_OK if the deep force operation was successful, an error code * @return NIX_OK if the deep force operation was successful, an error code
* otherwise. * otherwise.
*/ */
nix_err nix_value_force_deep(nix_c_context * context, EvalState * state, Value * value); nix_err nix_value_force_deep(nix_c_context * context, EvalState * state, nix_value * value);
/** /**
* @brief Create a new Nix language evaluator state. * @brief Create a new Nix language evaluator state.
@ -188,6 +195,11 @@ void nix_state_free(EvalState * state);
* you're done with a value returned by the evaluator. * you're done with a value returned by the evaluator.
* @{ * @{
*/ */
// TODO: Deprecate nix_gc_incref in favor of the type-specific reference counting functions?
// e.g. nix_value_incref.
// It gives implementors more flexibility, and adds safety, so that generated
// bindings can be used without fighting the host type system (where applicable).
/** /**
* @brief Increment the garbage collector reference counter for the given object. * @brief Increment the garbage collector reference counter for the given object.
* *

View file

@ -20,6 +20,11 @@ struct ListBuilder
nix::ListBuilder builder; nix::ListBuilder builder;
}; };
struct nix_value
{
nix::Value value;
};
struct nix_string_return struct nix_string_return
{ {
std::string str; std::string str;

View file

@ -21,49 +21,54 @@
#endif #endif
// Internal helper functions to check [in] and [out] `Value *` parameters // Internal helper functions to check [in] and [out] `Value *` parameters
static const nix::Value & check_value_not_null(const Value * value) static const nix::Value & check_value_not_null(const nix_value * value)
{ {
if (!value) { if (!value) {
throw std::runtime_error("Value is null"); throw std::runtime_error("nix_value is null");
} }
return *((const nix::Value *) value); return *((const nix::Value *) value);
} }
static nix::Value & check_value_not_null(Value * value) static nix::Value & check_value_not_null(nix_value * value)
{ {
if (!value) { if (!value) {
throw std::runtime_error("Value is null"); throw std::runtime_error("nix_value is null");
} }
return *((nix::Value *) value); return value->value;
} }
static const nix::Value & check_value_in(const Value * value) static const nix::Value & check_value_in(const nix_value * value)
{ {
auto & v = check_value_not_null(value); auto & v = check_value_not_null(value);
if (!v.isValid()) { if (!v.isValid()) {
throw std::runtime_error("Uninitialized Value"); throw std::runtime_error("Uninitialized nix_value");
} }
return v; return v;
} }
static nix::Value & check_value_in(Value * value) static nix::Value & check_value_in(nix_value * value)
{ {
auto & v = check_value_not_null(value); auto & v = check_value_not_null(value);
if (!v.isValid()) { if (!v.isValid()) {
throw std::runtime_error("Uninitialized Value"); throw std::runtime_error("Uninitialized nix_value");
} }
return v; return v;
} }
static nix::Value & check_value_out(Value * value) static nix::Value & check_value_out(nix_value * value)
{ {
auto & v = check_value_not_null(value); auto & v = check_value_not_null(value);
if (v.isValid()) { if (v.isValid()) {
throw std::runtime_error("Value already initialized. Variables are immutable"); throw std::runtime_error("nix_value already initialized. Variables are immutable");
} }
return v; return v;
} }
static inline nix_value * as_nix_value_ptr(nix::Value * v)
{
return reinterpret_cast<nix_value *>(v);
}
/** /**
* Helper function to convert calls from nix into C API. * Helper function to convert calls from nix into C API.
* *
@ -87,7 +92,7 @@ static void nix_c_primop_wrapper(
// or maybe something to make blackholes work better; we don't know). // or maybe something to make blackholes work better; we don't know).
nix::Value vTmp; nix::Value vTmp;
f(userdata, &ctx, (EvalState *) &state, (Value **) args, (Value *) &vTmp); f(userdata, &ctx, (EvalState *) &state, (nix_value **) args, (nix_value *) &vTmp);
if (ctx.last_err_code != NIX_OK) { if (ctx.last_err_code != NIX_OK) {
/* TODO: Throw different errors depending on the error code */ /* TODO: Throw different errors depending on the error code */
@ -154,19 +159,19 @@ nix_err nix_register_primop(nix_c_context * context, PrimOp * primOp)
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
} }
Value * nix_alloc_value(nix_c_context * context, EvalState * state) nix_value * nix_alloc_value(nix_c_context * context, EvalState * state)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
try { try {
Value * res = state->state.allocValue(); nix_value * res = as_nix_value_ptr(state->state.allocValue());
nix_gc_incref(nullptr, res); nix_gc_incref(nullptr, res);
return res; return res;
} }
NIXC_CATCH_ERRS_NULL NIXC_CATCH_ERRS_NULL
} }
ValueType nix_get_type(nix_c_context * context, const Value * value) ValueType nix_get_type(nix_c_context * context, const nix_value * value)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -202,7 +207,7 @@ ValueType nix_get_type(nix_c_context * context, const Value * value)
NIXC_CATCH_ERRS_RES(NIX_TYPE_NULL); NIXC_CATCH_ERRS_RES(NIX_TYPE_NULL);
} }
const char * nix_get_typename(nix_c_context * context, const Value * value) const char * nix_get_typename(nix_c_context * context, const nix_value * value)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -214,7 +219,7 @@ const char * nix_get_typename(nix_c_context * context, const Value * value)
NIXC_CATCH_ERRS_NULL NIXC_CATCH_ERRS_NULL
} }
bool nix_get_bool(nix_c_context * context, const Value * value) bool nix_get_bool(nix_c_context * context, const nix_value * value)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -226,7 +231,8 @@ bool nix_get_bool(nix_c_context * context, const Value * value)
NIXC_CATCH_ERRS_RES(false); NIXC_CATCH_ERRS_RES(false);
} }
nix_err nix_get_string(nix_c_context * context, const Value * value, nix_get_string_callback callback, void * user_data) nix_err
nix_get_string(nix_c_context * context, const nix_value * value, nix_get_string_callback callback, void * user_data)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -238,7 +244,7 @@ nix_err nix_get_string(nix_c_context * context, const Value * value, nix_get_str
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
} }
const char * nix_get_path_string(nix_c_context * context, const Value * value) const char * nix_get_path_string(nix_c_context * context, const nix_value * value)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -257,7 +263,7 @@ const char * nix_get_path_string(nix_c_context * context, const Value * value)
NIXC_CATCH_ERRS_NULL NIXC_CATCH_ERRS_NULL
} }
unsigned int nix_get_list_size(nix_c_context * context, const Value * value) unsigned int nix_get_list_size(nix_c_context * context, const nix_value * value)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -269,7 +275,7 @@ unsigned int nix_get_list_size(nix_c_context * context, const Value * value)
NIXC_CATCH_ERRS_RES(0); NIXC_CATCH_ERRS_RES(0);
} }
unsigned int nix_get_attrs_size(nix_c_context * context, const Value * value) unsigned int nix_get_attrs_size(nix_c_context * context, const nix_value * value)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -281,7 +287,7 @@ unsigned int nix_get_attrs_size(nix_c_context * context, const Value * value)
NIXC_CATCH_ERRS_RES(0); NIXC_CATCH_ERRS_RES(0);
} }
double nix_get_float(nix_c_context * context, const Value * value) double nix_get_float(nix_c_context * context, const nix_value * value)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -293,7 +299,7 @@ double nix_get_float(nix_c_context * context, const Value * value)
NIXC_CATCH_ERRS_RES(0.0); NIXC_CATCH_ERRS_RES(0.0);
} }
int64_t nix_get_int(nix_c_context * context, const Value * value) int64_t nix_get_int(nix_c_context * context, const nix_value * value)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -305,7 +311,7 @@ int64_t nix_get_int(nix_c_context * context, const Value * value)
NIXC_CATCH_ERRS_RES(0); NIXC_CATCH_ERRS_RES(0);
} }
ExternalValue * nix_get_external(nix_c_context * context, Value * value) ExternalValue * nix_get_external(nix_c_context * context, nix_value * value)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -317,7 +323,7 @@ ExternalValue * nix_get_external(nix_c_context * context, Value * value)
NIXC_CATCH_ERRS_NULL; NIXC_CATCH_ERRS_NULL;
} }
Value * nix_get_list_byidx(nix_c_context * context, const Value * value, EvalState * state, unsigned int ix) nix_value * nix_get_list_byidx(nix_c_context * context, const nix_value * value, EvalState * state, unsigned int ix)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -328,12 +334,12 @@ Value * nix_get_list_byidx(nix_c_context * context, const Value * value, EvalSta
nix_gc_incref(nullptr, p); nix_gc_incref(nullptr, p);
if (p != nullptr) if (p != nullptr)
state->state.forceValue(*p, nix::noPos); state->state.forceValue(*p, nix::noPos);
return (Value *) p; return as_nix_value_ptr(p);
} }
NIXC_CATCH_ERRS_NULL NIXC_CATCH_ERRS_NULL
} }
Value * nix_get_attr_byname(nix_c_context * context, const Value * value, EvalState * state, const char * name) nix_value * nix_get_attr_byname(nix_c_context * context, const nix_value * value, EvalState * state, const char * name)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -345,7 +351,7 @@ Value * nix_get_attr_byname(nix_c_context * context, const Value * value, EvalSt
if (attr) { if (attr) {
nix_gc_incref(nullptr, attr->value); nix_gc_incref(nullptr, attr->value);
state->state.forceValue(*attr->value, nix::noPos); state->state.forceValue(*attr->value, nix::noPos);
return attr->value; return as_nix_value_ptr(attr->value);
} }
nix_set_err_msg(context, NIX_ERR_KEY, "missing attribute"); nix_set_err_msg(context, NIX_ERR_KEY, "missing attribute");
return nullptr; return nullptr;
@ -353,7 +359,7 @@ Value * nix_get_attr_byname(nix_c_context * context, const Value * value, EvalSt
NIXC_CATCH_ERRS_NULL NIXC_CATCH_ERRS_NULL
} }
bool nix_has_attr_byname(nix_c_context * context, const Value * value, EvalState * state, const char * name) bool nix_has_attr_byname(nix_c_context * context, const nix_value * value, EvalState * state, const char * name)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -369,8 +375,8 @@ bool nix_has_attr_byname(nix_c_context * context, const Value * value, EvalState
NIXC_CATCH_ERRS_RES(false); NIXC_CATCH_ERRS_RES(false);
} }
Value * nix_value * nix_get_attr_byidx(
nix_get_attr_byidx(nix_c_context * context, const Value * value, EvalState * state, unsigned int i, const char ** name) nix_c_context * context, const nix_value * value, EvalState * state, unsigned int i, const char ** name)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -380,12 +386,13 @@ nix_get_attr_byidx(nix_c_context * context, const Value * value, EvalState * sta
*name = ((const std::string &) (state->state.symbols[a.name])).c_str(); *name = ((const std::string &) (state->state.symbols[a.name])).c_str();
nix_gc_incref(nullptr, a.value); nix_gc_incref(nullptr, a.value);
state->state.forceValue(*a.value, nix::noPos); state->state.forceValue(*a.value, nix::noPos);
return a.value; return as_nix_value_ptr(a.value);
} }
NIXC_CATCH_ERRS_NULL NIXC_CATCH_ERRS_NULL
} }
const char * nix_get_attr_name_byidx(nix_c_context * context, const Value * value, EvalState * state, unsigned int i) const char *
nix_get_attr_name_byidx(nix_c_context * context, const nix_value * value, EvalState * state, unsigned int i)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -397,7 +404,7 @@ const char * nix_get_attr_name_byidx(nix_c_context * context, const Value * valu
NIXC_CATCH_ERRS_NULL NIXC_CATCH_ERRS_NULL
} }
nix_err nix_init_bool(nix_c_context * context, Value * value, bool b) nix_err nix_init_bool(nix_c_context * context, nix_value * value, bool b)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -409,7 +416,7 @@ nix_err nix_init_bool(nix_c_context * context, Value * value, bool b)
} }
// todo string context // todo string context
nix_err nix_init_string(nix_c_context * context, Value * value, const char * str) nix_err nix_init_string(nix_c_context * context, nix_value * value, const char * str)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -420,7 +427,7 @@ nix_err nix_init_string(nix_c_context * context, Value * value, const char * str
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
} }
nix_err nix_init_path_string(nix_c_context * context, EvalState * s, Value * value, const char * str) nix_err nix_init_path_string(nix_c_context * context, EvalState * s, nix_value * value, const char * str)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -431,7 +438,7 @@ nix_err nix_init_path_string(nix_c_context * context, EvalState * s, Value * val
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
} }
nix_err nix_init_float(nix_c_context * context, Value * value, double d) nix_err nix_init_float(nix_c_context * context, nix_value * value, double d)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -442,7 +449,7 @@ nix_err nix_init_float(nix_c_context * context, Value * value, double d)
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
} }
nix_err nix_init_int(nix_c_context * context, Value * value, int64_t i) nix_err nix_init_int(nix_c_context * context, nix_value * value, int64_t i)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -453,7 +460,7 @@ nix_err nix_init_int(nix_c_context * context, Value * value, int64_t i)
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
} }
nix_err nix_init_null(nix_c_context * context, Value * value) nix_err nix_init_null(nix_c_context * context, nix_value * value)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -464,7 +471,7 @@ nix_err nix_init_null(nix_c_context * context, Value * value)
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
} }
nix_err nix_init_apply(nix_c_context * context, Value * value, Value * fn, Value * arg) nix_err nix_init_apply(nix_c_context * context, nix_value * value, nix_value * fn, nix_value * arg)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -477,7 +484,7 @@ nix_err nix_init_apply(nix_c_context * context, Value * value, Value * fn, Value
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
} }
nix_err nix_init_external(nix_c_context * context, Value * value, ExternalValue * val) nix_err nix_init_external(nix_c_context * context, nix_value * value, ExternalValue * val)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -504,7 +511,8 @@ ListBuilder * nix_make_list_builder(nix_c_context * context, EvalState * state,
NIXC_CATCH_ERRS_NULL NIXC_CATCH_ERRS_NULL
} }
nix_err nix_list_builder_insert(nix_c_context * context, ListBuilder * list_builder, unsigned int index, Value * value) nix_err
nix_list_builder_insert(nix_c_context * context, ListBuilder * list_builder, unsigned int index, nix_value * value)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -524,7 +532,7 @@ void nix_list_builder_free(ListBuilder * list_builder)
#endif #endif
} }
nix_err nix_make_list(nix_c_context * context, ListBuilder * list_builder, Value * value) nix_err nix_make_list(nix_c_context * context, ListBuilder * list_builder, nix_value * value)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -535,7 +543,7 @@ nix_err nix_make_list(nix_c_context * context, ListBuilder * list_builder, Value
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
} }
nix_err nix_init_primop(nix_c_context * context, Value * value, PrimOp * p) nix_err nix_init_primop(nix_c_context * context, nix_value * value, PrimOp * p)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -546,7 +554,7 @@ nix_err nix_init_primop(nix_c_context * context, Value * value, PrimOp * p)
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
} }
nix_err nix_copy_value(nix_c_context * context, Value * value, const Value * source) nix_err nix_copy_value(nix_c_context * context, nix_value * value, const nix_value * source)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -558,7 +566,7 @@ nix_err nix_copy_value(nix_c_context * context, Value * value, const Value * sou
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
} }
nix_err nix_make_attrs(nix_c_context * context, Value * value, BindingsBuilder * b) nix_err nix_make_attrs(nix_c_context * context, nix_value * value, BindingsBuilder * b)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -584,7 +592,7 @@ BindingsBuilder * nix_make_bindings_builder(nix_c_context * context, EvalState *
NIXC_CATCH_ERRS_NULL NIXC_CATCH_ERRS_NULL
} }
nix_err nix_bindings_builder_insert(nix_c_context * context, BindingsBuilder * bb, const char * name, Value * value) nix_err nix_bindings_builder_insert(nix_c_context * context, BindingsBuilder * bb, const char * name, nix_value * value)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -605,7 +613,7 @@ void nix_bindings_builder_free(BindingsBuilder * bb)
#endif #endif
} }
nix_realised_string * nix_string_realise(nix_c_context * context, EvalState * state, Value * value, bool isIFD) nix_realised_string * nix_string_realise(nix_c_context * context, EvalState * state, nix_value * value, bool isIFD)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;

View file

@ -35,8 +35,11 @@ typedef enum {
} ValueType; } ValueType;
// forward declarations // forward declarations
typedef void Value; typedef struct nix_value nix_value;
typedef struct EvalState EvalState; typedef struct EvalState EvalState;
[[deprecated("use nix_value instead")]] typedef nix_value Value;
// type defs // type defs
/** @brief Stores an under-construction set of bindings /** @brief Stores an under-construction set of bindings
* @ingroup value_manip * @ingroup value_manip
@ -90,7 +93,8 @@ typedef struct nix_realised_string nix_realised_string;
* @param[out] ret return value * @param[out] ret return value
* @see nix_alloc_primop, nix_init_primop * @see nix_alloc_primop, nix_init_primop
*/ */
typedef void (*PrimOpFun)(void * user_data, nix_c_context * context, EvalState * state, Value ** args, Value * ret); typedef void (*PrimOpFun)(
void * user_data, nix_c_context * context, EvalState * state, nix_value ** args, nix_value * ret);
/** @brief Allocate a PrimOp /** @brief Allocate a PrimOp
* *
@ -142,10 +146,29 @@ nix_err nix_register_primop(nix_c_context * context, PrimOp * primOp);
* @return value, or null in case of errors * @return value, or null in case of errors
* *
*/ */
Value * nix_alloc_value(nix_c_context * context, EvalState * state); nix_value * nix_alloc_value(nix_c_context * context, EvalState * state);
/**
* @brief Increment the garbage collector reference counter for the given `nix_value`.
*
* The Nix language evaluator C API keeps track of alive objects by reference counting.
* When you're done with a refcounted pointer, call nix_value_decref().
*
* @param[out] context Optional, stores error information
* @param[in] value The object to keep alive
*/
nix_err nix_value_incref(nix_c_context * context, nix_value * value);
/**
* @brief Decrement the garbage collector reference counter for the given object
*
* @param[out] context Optional, stores error information
* @param[in] value The object to stop referencing
*/
nix_err nix_value_decref(nix_c_context * context, nix_value * value);
/** @addtogroup value_manip Manipulating values /** @addtogroup value_manip Manipulating values
* @brief Functions to inspect and change Nix language values, represented by Value. * @brief Functions to inspect and change Nix language values, represented by nix_value.
* @{ * @{
*/ */
/** @anchor getters /** @anchor getters
@ -157,7 +180,7 @@ Value * nix_alloc_value(nix_c_context * context, EvalState * state);
* @param[in] value Nix value to inspect * @param[in] value Nix value to inspect
* @return type of nix value * @return type of nix value
*/ */
ValueType nix_get_type(nix_c_context * context, const Value * value); ValueType nix_get_type(nix_c_context * context, const nix_value * value);
/** @brief Get type name of value as defined in the evaluator /** @brief Get type name of value as defined in the evaluator
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
@ -165,14 +188,14 @@ ValueType nix_get_type(nix_c_context * context, const Value * value);
* @return type name, owned string * @return type name, owned string
* @todo way to free the result * @todo way to free the result
*/ */
const char * nix_get_typename(nix_c_context * context, const Value * value); const char * nix_get_typename(nix_c_context * context, const nix_value * value);
/** @brief Get boolean value /** @brief Get boolean value
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
* @param[in] value Nix value to inspect * @param[in] value Nix value to inspect
* @return true or false, error info via context * @return true or false, error info via context
*/ */
bool nix_get_bool(nix_c_context * context, const Value * value); bool nix_get_bool(nix_c_context * context, const nix_value * value);
/** @brief Get the raw string /** @brief Get the raw string
* *
@ -186,7 +209,7 @@ bool nix_get_bool(nix_c_context * context, const Value * value);
* @return error code, NIX_OK on success. * @return error code, NIX_OK on success.
*/ */
nix_err nix_err
nix_get_string(nix_c_context * context, const Value * value, nix_get_string_callback callback, void * user_data); nix_get_string(nix_c_context * context, const nix_value * value, nix_get_string_callback callback, void * user_data);
/** @brief Get path as string /** @brief Get path as string
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
@ -194,42 +217,42 @@ nix_get_string(nix_c_context * context, const Value * value, nix_get_string_call
* @return string * @return string
* @return NULL in case of error. * @return NULL in case of error.
*/ */
const char * nix_get_path_string(nix_c_context * context, const Value * value); const char * nix_get_path_string(nix_c_context * context, const nix_value * value);
/** @brief Get the length of a list /** @brief Get the length of a list
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
* @param[in] value Nix value to inspect * @param[in] value Nix value to inspect
* @return length of list, error info via context * @return length of list, error info via context
*/ */
unsigned int nix_get_list_size(nix_c_context * context, const Value * value); unsigned int nix_get_list_size(nix_c_context * context, const nix_value * value);
/** @brief Get the element count of an attrset /** @brief Get the element count of an attrset
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
* @param[in] value Nix value to inspect * @param[in] value Nix value to inspect
* @return attrset element count, error info via context * @return attrset element count, error info via context
*/ */
unsigned int nix_get_attrs_size(nix_c_context * context, const Value * value); unsigned int nix_get_attrs_size(nix_c_context * context, const nix_value * value);
/** @brief Get float value in 64 bits /** @brief Get float value in 64 bits
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
* @param[in] value Nix value to inspect * @param[in] value Nix value to inspect
* @return float contents, error info via context * @return float contents, error info via context
*/ */
double nix_get_float(nix_c_context * context, const Value * value); double nix_get_float(nix_c_context * context, const nix_value * value);
/** @brief Get int value /** @brief Get int value
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
* @param[in] value Nix value to inspect * @param[in] value Nix value to inspect
* @return int contents, error info via context * @return int contents, error info via context
*/ */
int64_t nix_get_int(nix_c_context * context, const Value * value); int64_t nix_get_int(nix_c_context * context, const nix_value * value);
/** @brief Get external reference /** @brief Get external reference
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
* @param[in] value Nix value to inspect * @param[in] value Nix value to inspect
* @return reference to external, NULL in case of error * @return reference to external, NULL in case of error
*/ */
ExternalValue * nix_get_external(nix_c_context * context, Value *); ExternalValue * nix_get_external(nix_c_context * context, nix_value *);
/** @brief Get the ix'th element of a list /** @brief Get the ix'th element of a list
* *
@ -240,7 +263,7 @@ ExternalValue * nix_get_external(nix_c_context * context, Value *);
* @param[in] ix list element to get * @param[in] ix list element to get
* @return value, NULL in case of errors * @return value, NULL in case of errors
*/ */
Value * nix_get_list_byidx(nix_c_context * context, const Value * value, EvalState * state, unsigned int ix); nix_value * nix_get_list_byidx(nix_c_context * context, const nix_value * value, EvalState * state, unsigned int ix);
/** @brief Get an attr by name /** @brief Get an attr by name
* *
@ -251,7 +274,7 @@ Value * nix_get_list_byidx(nix_c_context * context, const Value * value, EvalSta
* @param[in] name attribute name * @param[in] name attribute name
* @return value, NULL in case of errors * @return value, NULL in case of errors
*/ */
Value * nix_get_attr_byname(nix_c_context * context, const Value * value, EvalState * state, const char * name); nix_value * nix_get_attr_byname(nix_c_context * context, const nix_value * value, EvalState * state, const char * name);
/** @brief Check if an attribute name exists on a value /** @brief Check if an attribute name exists on a value
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
@ -260,7 +283,7 @@ Value * nix_get_attr_byname(nix_c_context * context, const Value * value, EvalSt
* @param[in] name attribute name * @param[in] name attribute name
* @return value, error info via context * @return value, error info via context
*/ */
bool nix_has_attr_byname(nix_c_context * context, const Value * value, EvalState * state, const char * name); bool nix_has_attr_byname(nix_c_context * context, const nix_value * value, EvalState * state, const char * name);
/** @brief Get an attribute by index in the sorted bindings /** @brief Get an attribute by index in the sorted bindings
* *
@ -274,8 +297,8 @@ bool nix_has_attr_byname(nix_c_context * context, const Value * value, EvalState
* @param[out] name will store a pointer to the attribute name * @param[out] name will store a pointer to the attribute name
* @return value, NULL in case of errors * @return value, NULL in case of errors
*/ */
Value * nix_value * nix_get_attr_byidx(
nix_get_attr_byidx(nix_c_context * context, const Value * value, EvalState * state, unsigned int i, const char ** name); nix_c_context * context, const nix_value * value, EvalState * state, unsigned int i, const char ** name);
/** @brief Get an attribute name by index in the sorted bindings /** @brief Get an attribute name by index in the sorted bindings
* *
@ -288,7 +311,8 @@ nix_get_attr_byidx(nix_c_context * context, const Value * value, EvalState * sta
* @param[in] i attribute index * @param[in] i attribute index
* @return name, NULL in case of errors * @return name, NULL in case of errors
*/ */
const char * nix_get_attr_name_byidx(nix_c_context * context, const Value * value, EvalState * state, unsigned int i); const char *
nix_get_attr_name_byidx(nix_c_context * context, const nix_value * value, EvalState * state, unsigned int i);
/**@}*/ /**@}*/
/** @name Initializers /** @name Initializers
@ -305,7 +329,7 @@ const char * nix_get_attr_name_byidx(nix_c_context * context, const Value * valu
* @param[in] b the boolean value * @param[in] b the boolean value
* @return error code, NIX_OK on success. * @return error code, NIX_OK on success.
*/ */
nix_err nix_init_bool(nix_c_context * context, Value * value, bool b); nix_err nix_init_bool(nix_c_context * context, nix_value * value, bool b);
/** @brief Set a string /** @brief Set a string
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
@ -313,7 +337,7 @@ nix_err nix_init_bool(nix_c_context * context, Value * value, bool b);
* @param[in] str the string, copied * @param[in] str the string, copied
* @return error code, NIX_OK on success. * @return error code, NIX_OK on success.
*/ */
nix_err nix_init_string(nix_c_context * context, Value * value, const char * str); nix_err nix_init_string(nix_c_context * context, nix_value * value, const char * str);
/** @brief Set a path /** @brief Set a path
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
@ -321,7 +345,7 @@ nix_err nix_init_string(nix_c_context * context, Value * value, const char * str
* @param[in] str the path string, copied * @param[in] str the path string, copied
* @return error code, NIX_OK on success. * @return error code, NIX_OK on success.
*/ */
nix_err nix_init_path_string(nix_c_context * context, EvalState * s, Value * value, const char * str); nix_err nix_init_path_string(nix_c_context * context, EvalState * s, nix_value * value, const char * str);
/** @brief Set a float /** @brief Set a float
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
@ -329,7 +353,7 @@ nix_err nix_init_path_string(nix_c_context * context, EvalState * s, Value * val
* @param[in] d the float, 64-bits * @param[in] d the float, 64-bits
* @return error code, NIX_OK on success. * @return error code, NIX_OK on success.
*/ */
nix_err nix_init_float(nix_c_context * context, Value * value, double d); nix_err nix_init_float(nix_c_context * context, nix_value * value, double d);
/** @brief Set an int /** @brief Set an int
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
@ -338,13 +362,13 @@ nix_err nix_init_float(nix_c_context * context, Value * value, double d);
* @return error code, NIX_OK on success. * @return error code, NIX_OK on success.
*/ */
nix_err nix_init_int(nix_c_context * context, Value * value, int64_t i); nix_err nix_init_int(nix_c_context * context, nix_value * value, int64_t i);
/** @brief Set null /** @brief Set null
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
* @param[out] value Nix value to modify * @param[out] value Nix value to modify
* @return error code, NIX_OK on success. * @return error code, NIX_OK on success.
*/ */
nix_err nix_init_null(nix_c_context * context, Value * value); nix_err nix_init_null(nix_c_context * context, nix_value * value);
/** @brief Set the value to a thunk that will perform a function application when needed. /** @brief Set the value to a thunk that will perform a function application when needed.
* *
@ -360,7 +384,7 @@ nix_err nix_init_null(nix_c_context * context, Value * value);
* @see nix_value_call() for a similar function that performs the call immediately and only stores the return value. * @see nix_value_call() for a similar function that performs the call immediately and only stores the return value.
* Note the different argument order. * Note the different argument order.
*/ */
nix_err nix_init_apply(nix_c_context * context, Value * value, Value * fn, Value * arg); nix_err nix_init_apply(nix_c_context * context, nix_value * value, nix_value * fn, nix_value * arg);
/** @brief Set an external value /** @brief Set an external value
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
@ -368,7 +392,7 @@ nix_err nix_init_apply(nix_c_context * context, Value * value, Value * fn, Value
* @param[in] val the external value to set. Will be GC-referenced by the value. * @param[in] val the external value to set. Will be GC-referenced by the value.
* @return error code, NIX_OK on success. * @return error code, NIX_OK on success.
*/ */
nix_err nix_init_external(nix_c_context * context, Value * value, ExternalValue * val); nix_err nix_init_external(nix_c_context * context, nix_value * value, ExternalValue * val);
/** @brief Create a list from a list builder /** @brief Create a list from a list builder
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
@ -376,7 +400,7 @@ nix_err nix_init_external(nix_c_context * context, Value * value, ExternalValue
* @param[out] value Nix value to modify * @param[out] value Nix value to modify
* @return error code, NIX_OK on success. * @return error code, NIX_OK on success.
*/ */
nix_err nix_make_list(nix_c_context * context, ListBuilder * list_builder, Value * value); nix_err nix_make_list(nix_c_context * context, ListBuilder * list_builder, nix_value * value);
/** @brief Create a list builder /** @brief Create a list builder
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
@ -393,7 +417,8 @@ ListBuilder * nix_make_list_builder(nix_c_context * context, EvalState * state,
* @param[in] value value to insert * @param[in] value value to insert
* @return error code, NIX_OK on success. * @return error code, NIX_OK on success.
*/ */
nix_err nix_list_builder_insert(nix_c_context * context, ListBuilder * list_builder, unsigned int index, Value * value); nix_err
nix_list_builder_insert(nix_c_context * context, ListBuilder * list_builder, unsigned int index, nix_value * value);
/** @brief Free a list builder /** @brief Free a list builder
* *
@ -408,7 +433,7 @@ void nix_list_builder_free(ListBuilder * list_builder);
* @param[in] b bindings builder to use. Make sure to unref this afterwards. * @param[in] b bindings builder to use. Make sure to unref this afterwards.
* @return error code, NIX_OK on success. * @return error code, NIX_OK on success.
*/ */
nix_err nix_make_attrs(nix_c_context * context, Value * value, BindingsBuilder * b); nix_err nix_make_attrs(nix_c_context * context, nix_value * value, BindingsBuilder * b);
/** @brief Set primop /** @brief Set primop
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
@ -417,14 +442,14 @@ nix_err nix_make_attrs(nix_c_context * context, Value * value, BindingsBuilder *
* @see nix_alloc_primop * @see nix_alloc_primop
* @return error code, NIX_OK on success. * @return error code, NIX_OK on success.
*/ */
nix_err nix_init_primop(nix_c_context * context, Value * value, PrimOp * op); nix_err nix_init_primop(nix_c_context * context, nix_value * value, PrimOp * op);
/** @brief Copy from another value /** @brief Copy from another value
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
* @param[out] value Nix value to modify * @param[out] value Nix value to modify
* @param[in] source value to copy from * @param[in] source value to copy from
* @return error code, NIX_OK on success. * @return error code, NIX_OK on success.
*/ */
nix_err nix_copy_value(nix_c_context * context, Value * value, const Value * source); nix_err nix_copy_value(nix_c_context * context, nix_value * value, const nix_value * source);
/**@}*/ /**@}*/
/** @brief Create a bindings builder /** @brief Create a bindings builder
@ -444,7 +469,7 @@ BindingsBuilder * nix_make_bindings_builder(nix_c_context * context, EvalState *
* @return error code, NIX_OK on success. * @return error code, NIX_OK on success.
*/ */
nix_err nix_err
nix_bindings_builder_insert(nix_c_context * context, BindingsBuilder * builder, const char * name, Value * value); nix_bindings_builder_insert(nix_c_context * context, BindingsBuilder * builder, const char * name, nix_value * value);
/** @brief Free a bindings builder /** @brief Free a bindings builder
* *
@ -471,7 +496,7 @@ void nix_bindings_builder_free(BindingsBuilder * builder);
You should set this to false when building for your application's purpose. You should set this to false when building for your application's purpose.
* @return NULL if failed, are a new nix_realised_string, which must be freed with nix_realised_string_free * @return NULL if failed, are a new nix_realised_string, which must be freed with nix_realised_string_free
*/ */
nix_realised_string * nix_string_realise(nix_c_context * context, EvalState * state, Value * value, bool isIFD); nix_realised_string * nix_string_realise(nix_c_context * context, EvalState * state, nix_value * value, bool isIFD);
/** @brief Start of the string /** @brief Start of the string
* @param[in] realised_string * @param[in] realised_string

View file

@ -31,7 +31,7 @@ struct CachedEvalError : EvalError
class EvalCache : public std::enable_shared_from_this<EvalCache> class EvalCache : public std::enable_shared_from_this<EvalCache>
{ {
friend class AttrCursor; friend class AttrCursor;
friend class CachedEvalError; friend struct CachedEvalError;
std::shared_ptr<AttrDb> db; std::shared_ptr<AttrDb> db;
EvalState & state; EvalState & state;
@ -87,7 +87,7 @@ typedef std::variant<
class AttrCursor : public std::enable_shared_from_this<AttrCursor> class AttrCursor : public std::enable_shared_from_this<AttrCursor>
{ {
friend class EvalCache; friend class EvalCache;
friend class CachedEvalError; friend struct CachedEvalError;
ref<EvalCache> root; ref<EvalCache> root;
typedef std::optional<std::pair<std::shared_ptr<AttrCursor>, Symbol>> Parent; typedef std::optional<std::pair<std::shared_ptr<AttrCursor>, Symbol>> Parent;

226
src/libexpr/eval-gc.cc Normal file
View file

@ -0,0 +1,226 @@
#include "error.hh"
#include "environment-variables.hh"
#include "serialise.hh"
#include "eval-gc.hh"
#if HAVE_BOEHMGC
# include <pthread.h>
# if __FreeBSD__
# include <pthread_np.h>
# endif
# include <gc/gc.h>
# include <gc/gc_cpp.h>
# include <gc/gc_allocator.h>
# include <boost/coroutine2/coroutine.hpp>
# include <boost/coroutine2/protected_fixedsize_stack.hpp>
# include <boost/context/stack_context.hpp>
#endif
namespace nix {
#if HAVE_BOEHMGC
/* Called when the Boehm GC runs out of memory. */
static void * oomHandler(size_t requested)
{
/* Convert this to a proper C++ exception. */
throw std::bad_alloc();
}
class BoehmGCStackAllocator : public StackAllocator
{
boost::coroutines2::protected_fixedsize_stack stack{
// We allocate 8 MB, the default max stack size on NixOS.
// A smaller stack might be quicker to allocate but reduces the stack
// depth available for source filter expressions etc.
std::max(boost::context::stack_traits::default_size(), static_cast<std::size_t>(8 * 1024 * 1024))};
// This is specific to boost::coroutines2::protected_fixedsize_stack.
// The stack protection page is included in sctx.size, so we have to
// subtract one page size from the stack size.
std::size_t pfss_usable_stack_size(boost::context::stack_context & sctx)
{
return sctx.size - boost::context::stack_traits::page_size();
}
public:
boost::context::stack_context allocate() override
{
auto sctx = stack.allocate();
// Stacks generally start at a high address and grow to lower addresses.
// Architectures that do the opposite are rare; in fact so rare that
// boost_routine does not implement it.
// So we subtract the stack size.
GC_add_roots(static_cast<char *>(sctx.sp) - pfss_usable_stack_size(sctx), sctx.sp);
return sctx;
}
void deallocate(boost::context::stack_context sctx) override
{
GC_remove_roots(static_cast<char *>(sctx.sp) - pfss_usable_stack_size(sctx), sctx.sp);
stack.deallocate(sctx);
}
};
static BoehmGCStackAllocator boehmGCStackAllocator;
/**
* When a thread goes into a coroutine, we lose its original sp until
* control flow returns to the thread.
* While in the coroutine, the sp points outside the thread stack,
* so we can detect this and push the entire thread stack instead,
* as an approximation.
* The coroutine's stack is covered by `BoehmGCStackAllocator`.
* This is not an optimal solution, because the garbage is scanned when a
* coroutine is active, for both the coroutine and the original thread stack.
* However, the implementation is quite lean, and usually we don't have active
* coroutines during evaluation, so this is acceptable.
*/
void fixupBoehmStackPointer(void ** sp_ptr, void * _pthread_id)
{
void *& sp = *sp_ptr;
auto pthread_id = reinterpret_cast<pthread_t>(_pthread_id);
pthread_attr_t pattr;
size_t osStackSize;
void * osStackLow;
void * osStackBase;
# ifdef __APPLE__
osStackSize = pthread_get_stacksize_np(pthread_id);
osStackLow = pthread_get_stackaddr_np(pthread_id);
# else
if (pthread_attr_init(&pattr)) {
throw Error("fixupBoehmStackPointer: pthread_attr_init failed");
}
# ifdef HAVE_PTHREAD_GETATTR_NP
if (pthread_getattr_np(pthread_id, &pattr)) {
throw Error("fixupBoehmStackPointer: pthread_getattr_np failed");
}
# elif HAVE_PTHREAD_ATTR_GET_NP
if (!pthread_attr_init(&pattr)) {
throw Error("fixupBoehmStackPointer: pthread_attr_init failed");
}
if (!pthread_attr_get_np(pthread_id, &pattr)) {
throw Error("fixupBoehmStackPointer: pthread_attr_get_np failed");
}
# else
# error "Need one of `pthread_attr_get_np` or `pthread_getattr_np`"
# endif
if (pthread_attr_getstack(&pattr, &osStackLow, &osStackSize)) {
throw Error("fixupBoehmStackPointer: pthread_attr_getstack failed");
}
if (pthread_attr_destroy(&pattr)) {
throw Error("fixupBoehmStackPointer: pthread_attr_destroy failed");
}
# endif
osStackBase = (char *) osStackLow + osStackSize;
// NOTE: We assume the stack grows down, as it does on all architectures we support.
// Architectures that grow the stack up are rare.
if (sp >= osStackBase || sp < osStackLow) { // lo is outside the os stack
sp = osStackBase;
}
}
/* Disable GC while this object lives. Used by CoroutineContext.
*
* Boehm keeps a count of GC_disable() and GC_enable() calls,
* and only enables GC when the count matches.
*/
class BoehmDisableGC
{
public:
BoehmDisableGC()
{
GC_disable();
};
~BoehmDisableGC()
{
GC_enable();
};
};
static inline void initGCReal()
{
/* Initialise the Boehm garbage collector. */
/* Don't look for interior pointers. This reduces the odds of
misdetection a bit. */
GC_set_all_interior_pointers(0);
/* We don't have any roots in data segments, so don't scan from
there. */
GC_set_no_dls(1);
GC_INIT();
GC_set_oom_fn(oomHandler);
StackAllocator::defaultAllocator = &boehmGCStackAllocator;
// TODO: Remove __APPLE__ condition.
// Comment suggests an implementation that works on darwin and windows
// https://github.com/ivmai/bdwgc/issues/362#issuecomment-1936672196
# if GC_VERSION_MAJOR >= 8 && GC_VERSION_MINOR >= 2 && GC_VERSION_MICRO >= 4 && !defined(__APPLE__)
GC_set_sp_corrector(&fixupBoehmStackPointer);
if (!GC_get_sp_corrector()) {
printTalkative("BoehmGC on this platform does not support sp_corrector; will disable GC inside coroutines");
/* Used to disable GC when entering coroutines on macOS */
create_coro_gc_hook = []() -> std::shared_ptr<void> { return std::make_shared<BoehmDisableGC>(); };
}
# else
# warning \
"BoehmGC version does not support GC while coroutine exists. GC will be disabled inside coroutines. Consider updating bdw-gc to 8.2.4 or later."
# endif
/* Set the initial heap size to something fairly big (25% of
physical RAM, up to a maximum of 384 MiB) so that in most cases
we don't need to garbage collect at all. (Collection has a
fairly significant overhead.) The heap size can be overridden
through libgc's GC_INITIAL_HEAP_SIZE environment variable. We
should probably also provide a nix.conf setting for this. Note
that GC_expand_hp() causes a lot of virtual, but not physical
(resident) memory to be allocated. This might be a problem on
systems that don't overcommit. */
if (!getEnv("GC_INITIAL_HEAP_SIZE")) {
size_t size = 32 * 1024 * 1024;
# if HAVE_SYSCONF && defined(_SC_PAGESIZE) && defined(_SC_PHYS_PAGES)
size_t maxSize = 384 * 1024 * 1024;
long pageSize = sysconf(_SC_PAGESIZE);
long pages = sysconf(_SC_PHYS_PAGES);
if (pageSize != -1)
size = (pageSize * pages) / 4; // 25% of RAM
if (size > maxSize)
size = maxSize;
# endif
debug("setting initial heap size to %1% bytes", size);
GC_expand_hp(size);
}
}
#endif
static bool gcInitialised = false;
void initGC()
{
if (gcInitialised)
return;
#if HAVE_BOEHMGC
initGCReal();
#endif
gcInitialised = true;
}
void assertGCInitialized()
{
assert(gcInitialised);
}
}

16
src/libexpr/eval-gc.hh Normal file
View file

@ -0,0 +1,16 @@
#pragma once
///@file
namespace nix {
/**
* Initialise the Boehm GC, if applicable.
*/
void initGC();
/**
* Make sure `initGC` has already been called.
*/
void assertGCInitialized();
}

View file

@ -47,16 +47,10 @@
# define GC_INCLUDE_NEW # define GC_INCLUDE_NEW
#include <pthread.h>
# include <gc/gc.h> # include <gc/gc.h>
# include <gc/gc_cpp.h> # include <gc/gc_cpp.h>
# include <gc/gc_allocator.h> # include <gc/gc_allocator.h>
#include <boost/coroutine2/coroutine.hpp>
#include <boost/coroutine2/protected_fixedsize_stack.hpp>
#include <boost/context/stack_context.hpp>
#endif #endif
using json = nlohmann::json; using json = nlohmann::json;
@ -208,97 +202,6 @@ bool Value::isTrivial() const
} }
#if HAVE_BOEHMGC
/* Called when the Boehm GC runs out of memory. */
static void * oomHandler(size_t requested)
{
/* Convert this to a proper C++ exception. */
throw std::bad_alloc();
}
class BoehmGCStackAllocator : public StackAllocator {
boost::coroutines2::protected_fixedsize_stack stack {
// We allocate 8 MB, the default max stack size on NixOS.
// A smaller stack might be quicker to allocate but reduces the stack
// depth available for source filter expressions etc.
std::max(boost::context::stack_traits::default_size(), static_cast<std::size_t>(8 * 1024 * 1024))
};
// This is specific to boost::coroutines2::protected_fixedsize_stack.
// The stack protection page is included in sctx.size, so we have to
// subtract one page size from the stack size.
std::size_t pfss_usable_stack_size(boost::context::stack_context &sctx) {
return sctx.size - boost::context::stack_traits::page_size();
}
public:
boost::context::stack_context allocate() override {
auto sctx = stack.allocate();
// Stacks generally start at a high address and grow to lower addresses.
// Architectures that do the opposite are rare; in fact so rare that
// boost_routine does not implement it.
// So we subtract the stack size.
GC_add_roots(static_cast<char *>(sctx.sp) - pfss_usable_stack_size(sctx), sctx.sp);
return sctx;
}
void deallocate(boost::context::stack_context sctx) override {
GC_remove_roots(static_cast<char *>(sctx.sp) - pfss_usable_stack_size(sctx), sctx.sp);
stack.deallocate(sctx);
}
};
static BoehmGCStackAllocator boehmGCStackAllocator;
/**
* When a thread goes into a coroutine, we lose its original sp until
* control flow returns to the thread.
* While in the coroutine, the sp points outside the thread stack,
* so we can detect this and push the entire thread stack instead,
* as an approximation.
* The coroutine's stack is covered by `BoehmGCStackAllocator`.
* This is not an optimal solution, because the garbage is scanned when a
* coroutine is active, for both the coroutine and the original thread stack.
* However, the implementation is quite lean, and usually we don't have active
* coroutines during evaluation, so this is acceptable.
*/
void fixupBoehmStackPointer(void ** sp_ptr, void * pthread_id) {
void *& sp = *sp_ptr;
pthread_attr_t pattr;
size_t osStackSize;
void * osStackLow;
void * osStackBase;
#ifdef __APPLE__
osStackSize = pthread_get_stacksize_np((pthread_t)pthread_id);
osStackLow = pthread_get_stackaddr_np((pthread_t)pthread_id);
#else
if (pthread_attr_init(&pattr)) {
throw Error("fixupBoehmStackPointer: pthread_attr_init failed");
}
if (pthread_getattr_np((pthread_t)pthread_id, &pattr)) {
throw Error("fixupBoehmStackPointer: pthread_getattr_np failed");
}
if (pthread_attr_getstack(&pattr, &osStackLow, &osStackSize)) {
throw Error("fixupBoehmStackPointer: pthread_attr_getstack failed");
}
if (pthread_attr_destroy(&pattr)) {
throw Error("fixupBoehmStackPointer: pthread_attr_destroy failed");
}
#endif
osStackBase = (char *)osStackLow + osStackSize;
// NOTE: We assume the stack grows down, as it does on all architectures we support.
// Architectures that grow the stack up are rare.
if (sp >= osStackBase || sp < osStackLow) { // lo is outside the os stack
sp = osStackBase;
}
}
#endif
static Symbol getName(const AttrName & name, EvalState & state, Env & env) static Symbol getName(const AttrName & name, EvalState & state, Env & env)
{ {
if (name.symbol) { if (name.symbol) {
@ -311,92 +214,6 @@ static Symbol getName(const AttrName & name, EvalState & state, Env & env)
} }
} }
#if HAVE_BOEHMGC
/* Disable GC while this object lives. Used by CoroutineContext.
*
* Boehm keeps a count of GC_disable() and GC_enable() calls,
* and only enables GC when the count matches.
*/
class BoehmDisableGC {
public:
BoehmDisableGC() {
GC_disable();
};
~BoehmDisableGC() {
GC_enable();
};
};
#endif
static bool gcInitialised = false;
void initGC()
{
if (gcInitialised) return;
#if HAVE_BOEHMGC
/* Initialise the Boehm garbage collector. */
/* Don't look for interior pointers. This reduces the odds of
misdetection a bit. */
GC_set_all_interior_pointers(0);
/* We don't have any roots in data segments, so don't scan from
there. */
GC_set_no_dls(1);
GC_INIT();
GC_set_oom_fn(oomHandler);
StackAllocator::defaultAllocator = &boehmGCStackAllocator;
// TODO: Remove __APPLE__ condition.
// Comment suggests an implementation that works on darwin and windows
// https://github.com/ivmai/bdwgc/issues/362#issuecomment-1936672196
#if GC_VERSION_MAJOR >= 8 && GC_VERSION_MINOR >= 4 && !defined(__APPLE__)
GC_set_sp_corrector(&fixupBoehmStackPointer);
if (!GC_get_sp_corrector()) {
printTalkative("BoehmGC on this platform does not support sp_corrector; will disable GC inside coroutines");
/* Used to disable GC when entering coroutines on macOS */
create_coro_gc_hook = []() -> std::shared_ptr<void> {
return std::make_shared<BoehmDisableGC>();
};
}
#else
#warning "BoehmGC version does not support GC while coroutine exists. GC will be disabled inside coroutines. Consider updating bwd-gc to 8.4 or later."
#endif
/* Set the initial heap size to something fairly big (25% of
physical RAM, up to a maximum of 384 MiB) so that in most cases
we don't need to garbage collect at all. (Collection has a
fairly significant overhead.) The heap size can be overridden
through libgc's GC_INITIAL_HEAP_SIZE environment variable. We
should probably also provide a nix.conf setting for this. Note
that GC_expand_hp() causes a lot of virtual, but not physical
(resident) memory to be allocated. This might be a problem on
systems that don't overcommit. */
if (!getEnv("GC_INITIAL_HEAP_SIZE")) {
size_t size = 32 * 1024 * 1024;
#if HAVE_SYSCONF && defined(_SC_PAGESIZE) && defined(_SC_PHYS_PAGES)
size_t maxSize = 384 * 1024 * 1024;
long pageSize = sysconf(_SC_PAGESIZE);
long pages = sysconf(_SC_PHYS_PAGES);
if (pageSize != -1)
size = (pageSize * pages) / 4; // 25% of RAM
if (size > maxSize) size = maxSize;
#endif
debug("setting initial heap size to %1% bytes", size);
GC_expand_hp(size);
}
#endif
gcInitialised = true;
}
static constexpr size_t BASE_ENV_SIZE = 128; static constexpr size_t BASE_ENV_SIZE = 128;
EvalState::EvalState( EvalState::EvalState(
@ -493,7 +310,7 @@ EvalState::EvalState(
countCalls = getEnv("NIX_COUNT_CALLS").value_or("0") != "0"; countCalls = getEnv("NIX_COUNT_CALLS").value_or("0") != "0";
assert(gcInitialised); assertGCInitialized();
static_assert(sizeof(Env) <= 16, "environment must be <= 16 bytes"); static_assert(sizeof(Env) <= 16, "environment must be <= 16 bytes");

View file

@ -3,6 +3,7 @@
#include "attr-set.hh" #include "attr-set.hh"
#include "eval-error.hh" #include "eval-error.hh"
#include "eval-gc.hh"
#include "types.hh" #include "types.hh"
#include "value.hh" #include "value.hh"
#include "nixexpr.hh" #include "nixexpr.hh"
@ -146,12 +147,6 @@ std::string printValue(EvalState & state, Value & v);
std::ostream & operator << (std::ostream & os, const ValueType t); std::ostream & operator << (std::ostream & os, const ValueType t);
/**
* Initialise the Boehm GC, if applicable.
*/
void initGC();
struct RegexCache; struct RegexCache;
std::shared_ptr<RegexCache> makeRegexCache(); std::shared_ptr<RegexCache> makeRegexCache();

View file

@ -4061,18 +4061,24 @@ static RegisterPrimOp primop_convertHash({
}); });
struct RegexCache struct RegexCache
{
struct State
{ {
// TODO use C++20 transparent comparison when available // TODO use C++20 transparent comparison when available
std::unordered_map<std::string_view, std::regex> cache; std::unordered_map<std::string_view, std::regex> cache;
std::list<std::string> keys; std::list<std::string> keys;
};
Sync<State> state_;
std::regex get(std::string_view re) std::regex get(std::string_view re)
{ {
auto it = cache.find(re); auto state(state_.lock());
if (it != cache.end()) auto it = state->cache.find(re);
if (it != state->cache.end())
return it->second; return it->second;
keys.emplace_back(re); state->keys.emplace_back(re);
return cache.emplace(keys.back(), std::regex(keys.back(), std::regex::extended)).first->second; return state->cache.emplace(state->keys.back(), std::regex(state->keys.back(), std::regex::extended)).first->second;
} }
}; };

1
src/libstore/.version Symbolic link
View file

@ -0,0 +1 @@
../../.version

View file

@ -25,6 +25,10 @@
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#ifndef _WIN32 // TODO abstract over proc exit status
# include <sys/wait.h>
#endif
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
namespace nix { namespace nix {
@ -1033,7 +1037,7 @@ void DerivationGoal::buildDone()
BuildResult::Status st = BuildResult::MiscFailure; BuildResult::Status st = BuildResult::MiscFailure;
#ifndef _WIN32 #ifndef _WIN32 // TODO abstract over proc exit status
if (hook && WIFEXITED(status) && WEXITSTATUS(status) == 101) if (hook && WIFEXITED(status) && WEXITSTATUS(status) == 101)
st = BuildResult::TimedOut; st = BuildResult::TimedOut;

View file

@ -0,0 +1,10 @@
sources += files(
'personality.cc',
)
include_dirs += include_directories('.')
headers += files(
'fchmodat2-compat.hh',
'personality.hh',
)

View file

@ -233,7 +233,7 @@ LocalStore::LocalStore(const Params & params)
struct group * gr = getgrnam(settings.buildUsersGroup.get().c_str()); struct group * gr = getgrnam(settings.buildUsersGroup.get().c_str());
if (!gr) if (!gr)
printError("warning: the group '%1%' specified in 'build-users-group' does not exist", settings.buildUsersGroup); printError("warning: the group '%1%' specified in 'build-users-group' does not exist", settings.buildUsersGroup);
else { else if (!readOnly) {
struct stat st; struct stat st;
if (stat(realStoreDir.get().c_str(), &st)) if (stat(realStoreDir.get().c_str(), &st))
throw SysError("getting attributes of path '%1%'", realStoreDir); throw SysError("getting attributes of path '%1%'", realStoreDir);

452
src/libstore/meson.build Normal file
View file

@ -0,0 +1,452 @@
project('nix-store', 'cpp',
version : files('.version'),
default_options : [
'cpp_std=c++2a',
# TODO(Qyriad): increase the warning level
'warning_level=1',
'debug=true',
'optimization=2',
'errorlogs=true', # Please print logs for tests that fail
],
meson_version : '>= 1.1',
license : 'LGPL-2.1-or-later',
)
cxx = meson.get_compiler('cpp')
# See note in ../nix-util/meson.build
deps_private = [ ]
# See note in ../nix-util/meson.build
deps_public = [ ]
# See note in ../nix-util/meson.build
deps_other = [ ]
configdata = configuration_data()
# TODO rename, because it will conflict with downstream projects
configdata.set_quoted('PACKAGE_VERSION', meson.project_version())
configdata.set_quoted('SYSTEM', host_machine.system())
nix_util = dependency('nix-util')
if nix_util.type_name() == 'internal'
# subproject sadly no good for pkg-config module
deps_other += nix_util
else
deps_public += nix_util
endif
run_command('ln', '-s',
meson.project_build_root() / '__nothing_link_target',
meson.project_build_root() / '__nothing_symlink',
check : true,
)
can_link_symlink = run_command('ln',
meson.project_build_root() / '__nothing_symlink',
meson.project_build_root() / '__nothing_hardlink',
check : false,
).returncode() == 0
run_command('rm', '-f',
meson.project_build_root() / '__nothing_symlink',
meson.project_build_root() / '__nothing_hardlink',
check : true,
)
summary('can hardlink to symlink', can_link_symlink, bool_yn : true)
configdata.set('CAN_LINK_SYMLINK', can_link_symlink.to_int())
# Check for each of these functions, and create a define like `#define HAVE_LCHOWN 1`.
#
# Only need to do functions that deps (like `libnixutil`) didn't already
# check for.
check_funcs = [
# Optionally used for canonicalising files from the build
'lchown',
]
foreach funcspec : check_funcs
define_name = 'HAVE_' + funcspec.underscorify().to_upper()
define_value = cxx.has_function(funcspec).to_int()
configdata.set(define_name, define_value)
endforeach
has_acl_support = cxx.has_header('sys/xattr.h') \
and cxx.has_function('llistxattr') \
and cxx.has_function('lremovexattr')
configdata.set('HAVE_ACL_SUPPORT', has_acl_support.to_int())
# This is only conditional to work around
# https://github.com/mesonbuild/meson/issues/13293. It should be
# unconditional.
if not (host_machine.system() == 'windows' and cxx.get_id() == 'gcc')
deps_private += dependency('threads')
endif
boost = dependency(
'boost',
modules : ['container'],
)
# boost is a public dependency, but not a pkg-config dependency unfortunately, so we
# put in `deps_other`.
deps_other += boost
curl = dependency('libcurl', 'curl')
deps_private += curl
# seccomp only makes sense on Linux
is_linux = host_machine.system() == 'linux'
seccomp_required = get_option('seccomp-sandboxing')
if not is_linux and seccomp_required.enabled()
warning('Force-enabling seccomp on non-Linux does not make sense')
endif
seccomp = dependency('libseccomp', 'seccomp', required : seccomp_required, version : '>=2.5.5')
if is_linux and not seccomp.found()
warning('Sandbox security is reduced because libseccomp has not been found! Please provide libseccomp if it supports your CPU architecture.')
endif
configdata.set('HAVE_SECCOMP', seccomp.found().to_int())
deps_private += seccomp
nlohmann_json = dependency('nlohmann_json', version : '>= 3.9')
deps_public += nlohmann_json
sqlite = dependency('sqlite3', 'sqlite', version : '>=3.6.19')
deps_private += sqlite
enable_embedded_sandbox_shell = get_option('embedded-sandbox-shell')
if enable_embedded_sandbox_shell
# This one goes in config.h
# The path to busybox is passed as a -D flag when compiling this_library.
# Idk why, ask the old buildsystem.
configdata.set('HAVE_EMBEDDED_SANDBOX_SHELL', 1)
endif
generated_headers = []
foreach header : [ 'schema.sql', 'ca-specific-schema.sql' ]
generated_headers += custom_target(
command : [ 'bash', '-c', '{ echo \'R"__NIX_STR(\' && cat @INPUT@ && echo \')__NIX_STR"\'; } > "$1"', '_ignored_argv0', '@OUTPUT@' ],
input : header,
output : '@PLAINNAME@.gen.hh',
install : true,
install_dir : get_option('includedir') / 'nix'
)
endforeach
if enable_embedded_sandbox_shell
hexdump = find_program('hexdump', native : true)
embedded_sandbox_shell_gen = custom_target(
'embedded-sandbox-shell.gen.hh',
command : [
hexdump,
'-v',
'-e',
'1/1 "0x%x," "\n"'
],
input : busybox.full_path(),
output : 'embedded-sandbox-shell.gen.hh',
capture : true,
feed : true,
)
generated_headers += embedded_sandbox_shell_gen
endif
config_h = configure_file(
configuration : configdata,
output : 'config-store.h',
)
add_project_arguments(
# TODO(Qyriad): Yes this is how the autoconf+Make system did it.
# It would be nice for our headers to be idempotent instead.
'-include', 'config-util.h',
'-include', 'config-store.h',
'-Wno-deprecated-declarations',
'-Wimplicit-fallthrough',
'-Werror=switch',
'-Werror=switch-enum',
'-Wdeprecated-copy',
'-Wignored-qualifiers',
# Enable assertions in libstdc++ by default. Harmless on libc++. Benchmarked
# at ~1% overhead in `nix search`.
#
# FIXME: remove when we get meson 1.4.0 which will default this to on for us:
# https://mesonbuild.com/Release-notes-for-1-4-0.html#ndebug-setting-now-controls-c-stdlib-assertions
'-D_GLIBCXX_ASSERTIONS=1',
language : 'cpp',
)
sources = files(
'binary-cache-store.cc',
'build-result.cc',
'build/derivation-goal.cc',
'build/drv-output-substitution-goal.cc',
'build/entry-points.cc',
'build/goal.cc',
'build/substitution-goal.cc',
'build/worker.cc',
'builtins/buildenv.cc',
'builtins/fetchurl.cc',
'builtins/unpack-channel.cc',
'common-protocol.cc',
'content-address.cc',
'daemon.cc',
'derivations.cc',
'derived-path-map.cc',
'derived-path.cc',
'downstream-placeholder.cc',
'dummy-store.cc',
'export-import.cc',
'filetransfer.cc',
'gc.cc',
'globals.cc',
'http-binary-cache-store.cc',
'indirect-root-store.cc',
'keys.cc',
'legacy-ssh-store.cc',
'local-binary-cache-store.cc',
'local-fs-store.cc',
'local-overlay-store.cc',
'local-store.cc',
'log-store.cc',
'machines.cc',
'make-content-addressed.cc',
'misc.cc',
'names.cc',
'nar-accessor.cc',
'nar-info-disk-cache.cc',
'nar-info.cc',
'optimise-store.cc',
'outputs-spec.cc',
'parsed-derivations.cc',
'path-info.cc',
'path-references.cc',
'path-with-outputs.cc',
'path.cc',
'pathlocks.cc',
'posix-fs-canonicalise.cc',
'profiles.cc',
'realisation.cc',
'remote-fs-accessor.cc',
'remote-store.cc',
's3-binary-cache-store.cc',
'serve-protocol-connection.cc',
'serve-protocol.cc',
'sqlite.cc',
'ssh-store-config.cc',
'ssh-store.cc',
'ssh.cc',
'store-api.cc',
'store-reference.cc',
'uds-remote-store.cc',
'worker-protocol-connection.cc',
'worker-protocol.cc',
)
include_dirs = [
include_directories('.'),
include_directories('build'),
]
headers = [config_h] +files(
'binary-cache-store.hh',
'build-result.hh',
'build/derivation-goal.hh',
'build/drv-output-substitution-goal.hh',
'build/goal.hh',
'build/substitution-goal.hh',
'build/worker.hh',
'builtins.hh',
'builtins/buildenv.hh',
'common-protocol-impl.hh',
'common-protocol.hh',
'content-address.hh',
'daemon.hh',
'derivations.hh',
'derived-path-map.hh',
'derived-path.hh',
'downstream-placeholder.hh',
'filetransfer.hh',
'gc-store.hh',
'globals.hh',
'indirect-root-store.hh',
'keys.hh',
'legacy-ssh-store.hh',
'length-prefixed-protocol-helper.hh',
'local-fs-store.hh',
'local-overlay-store.hh',
'local-store.hh',
'log-store.hh',
'machines.hh',
'make-content-addressed.hh',
'names.hh',
'nar-accessor.hh',
'nar-info-disk-cache.hh',
'nar-info.hh',
'outputs-spec.hh',
'parsed-derivations.hh',
'path-info.hh',
'path-references.hh',
'path-regex.hh',
'path-with-outputs.hh',
'path.hh',
'pathlocks.hh',
'posix-fs-canonicalise.hh',
'profiles.hh',
'realisation.hh',
'remote-fs-accessor.hh',
'remote-store-connection.hh',
'remote-store.hh',
's3-binary-cache-store.hh',
's3.hh',
'serve-protocol-connection.hh',
'serve-protocol-impl.hh',
'serve-protocol.hh',
'sqlite.hh',
'ssh-store-config.hh',
'ssh.hh',
'store-api.hh',
'store-cast.hh',
'store-dir-config.hh',
'store-reference.hh',
'uds-remote-store.hh',
'worker-protocol-connection.hh',
'worker-protocol-impl.hh',
'worker-protocol.hh',
)
if host_machine.system() == 'linux'
subdir('linux')
endif
if host_machine.system() == 'windows'
subdir('windows')
else
subdir('unix')
endif
fs = import('fs')
prefix = get_option('prefix')
# For each of these paths, assume that it is relative to the prefix unless
# it is already an absolute path (which is the default for store-dir, state-dir, and log-dir).
path_opts = [
# Meson built-ins.
'datadir',
'bindir',
'mandir',
'libdir',
'includedir',
'libexecdir',
# Homecooked Nix directories.
'store-dir',
'state-dir',
'log-dir',
]
# For your grepping pleasure, this loop sets the following variables that aren't mentioned
# literally above:
# store_dir
# state_dir
# log_dir
# profile_dir
foreach optname : path_opts
varname = optname.replace('-', '_')
path = get_option(optname)
if fs.is_absolute(path)
set_variable(varname, path)
else
set_variable(varname, prefix / path)
endif
endforeach
# sysconfdir doesn't get anything installed to directly, and is only used to
# tell Nix where to look for nix.conf, so it doesn't get appended to prefix.
sysconfdir = get_option('sysconfdir')
if not fs.is_absolute(sysconfdir)
sysconfdir = '/' / sysconfdir
endif
lsof = find_program('lsof', required : false)
# Aside from prefix itself, each of these was made into an absolute path
# by joining it with prefix, unless it was already an absolute path
# (which is the default for store-dir, state-dir, and log-dir).
cpp_str_defines = {
'NIX_PREFIX': prefix,
'NIX_STORE_DIR': store_dir,
'NIX_DATA_DIR': datadir,
'NIX_STATE_DIR': state_dir / 'nix',
'NIX_LOG_DIR': log_dir,
'NIX_CONF_DIR': sysconfdir / 'nix',
'NIX_BIN_DIR': bindir,
'NIX_MAN_DIR': mandir,
}
if lsof.found()
lsof_path = lsof.full_path()
else
# Just look up on the PATH
lsof_path = 'lsof'
endif
cpp_str_defines += {
'LSOF': lsof_path
}
#if busybox.found()
cpp_str_defines += {
# 'SANDBOX_SHELL': busybox.full_path()
}
#endif
cpp_args = []
foreach name, value : cpp_str_defines
cpp_args += [
'-D' + name + '=' + '"' + value + '"'
]
endforeach
if host_machine.system() == 'cygwin' or host_machine.system() == 'windows'
# See note in `../nix-util/meson.build`
linker_export_flags = ['-Wl,--export-all-symbols']
else
linker_export_flags = []
endif
this_library = library(
'nixstore',
generated_headers,
sources,
dependencies : deps_public + deps_private + deps_other,
include_directories : include_dirs,
cpp_args : cpp_args,
link_args: linker_export_flags,
install : true,
)
install_headers(headers, subdir : 'nix', preserve_path : true)
requires = deps_public
if nix_util.type_name() == 'internal'
# `requires` cannot contain declared dependencies (from the
# subproject), so we need to do this manually
requires = [ 'nix-util' ] + requires
endif
import('pkgconfig').generate(
this_library,
filebase : meson.project_name(),
name : 'Nix',
description : 'Nix Package Manager',
subdirs : ['nix'],
extra_cflags : ['-std=c++2a'],
requires : requires,
requires_private : deps_private,
libraries_private : ['-lboost_container'],
)
meson.override_dependency(meson.project_name(), declare_dependency(
include_directories : include_dirs,
link_with : this_library,
compile_args : ['-std=c++2a'],
dependencies : [nix_util],
))

View file

@ -0,0 +1,25 @@
# vim: filetype=meson
option('embedded-sandbox-shell', type : 'boolean', value : false,
description : 'include the sandbox shell in the Nix binary',
)
option('seccomp-sandboxing', type : 'feature',
description : 'build support for seccomp sandboxing (recommended unless your arch doesn\'t support libseccomp, only relevant on Linux)',
)
option('sandbox-shell', type : 'string', value : 'busybox',
description : 'path to a statically-linked shell to use as /bin/sh in sandboxes (usually busybox)',
)
option('store-dir', type : 'string', value : '/nix/store',
description : 'path of the Nix store',
)
option('state-dir', type : 'string', value : '/nix/var',
description : 'path to store state in for Nix',
)
option('log-dir', type : 'string', value : '/nix/var/log/nix',
description : 'path to store logs in for Nix',
)

142
src/libstore/package.nix Normal file
View file

@ -0,0 +1,142 @@
{ lib
, stdenv
, releaseTools
, fileset
, meson
, ninja
, pkg-config
, nix-util
, boost
, curl
, aws-sdk-cpp
, libseccomp
, nlohmann_json
, man
, sqlite
, busybox-sandbox-shell ? null
# Configuration Options
, versionSuffix ? ""
, officialRelease ? false
# Check test coverage of Nix. Probably want to use with at least
# one of `doCheck` or `doInstallCheck` enabled.
, withCoverageChecks ? false
# Avoid setting things that would interfere with a functioning devShell
, forDevShell ? false
}:
let
version = lib.fileContents ./.version + versionSuffix;
mkDerivation =
if withCoverageChecks
then
# TODO support `finalAttrs` args function in
# `releaseTools.coverageAnalysis`.
argsFun:
releaseTools.coverageAnalysis (let args = argsFun args; in args)
else stdenv.mkDerivation;
in
mkDerivation (finalAttrs: {
pname = "nix-store";
inherit version;
src = fileset.toSource {
root = ./.;
fileset = fileset.unions [
./meson.build
./meson.options
./linux/meson.build
./unix/meson.build
./windows/meson.build
(fileset.fileFilter (file: file.hasExt "cc") ./.)
(fileset.fileFilter (file: file.hasExt "hh") ./.)
(fileset.fileFilter (file: file.hasExt "sb") ./.)
(fileset.fileFilter (file: file.hasExt "md") ./.)
(fileset.fileFilter (file: file.hasExt "sql") ./.)
];
};
outputs = [ "out" "dev" ];
nativeBuildInputs = [
meson
ninja
pkg-config
];
buildInputs = [
boost
curl
sqlite
] ++ lib.optional stdenv.hostPlatform.isLinux libseccomp
# There have been issues building these dependencies
++ lib.optional (stdenv.hostPlatform == stdenv.buildPlatform && (stdenv.isLinux || stdenv.isDarwin))
(aws-sdk-cpp.override {
apis = ["s3" "transfer"];
customMemoryManagement = false;
})
;
propagatedBuildInputs = [
nix-util
nlohmann_json
];
disallowedReferences = [ boost ];
preConfigure =
# "Inline" .version so it's not a symlink, and includes the suffix
''
echo ${version} > .version
'';
mesonFlags = [
(lib.mesonEnable "seccomp-sandboxing" stdenv.hostPlatform.isLinux)
(lib.mesonBool "embedded-sandbox-shell" stdenv.hostPlatform.isStatic)
] ++ lib.optionals stdenv.hostPlatform.isLinux [
(lib.mesonOption "sandbox-shell" "${busybox-sandbox-shell}/bin/busybox")
];
env = {
# Needed for Meson to find Boost.
# https://github.com/NixOS/nixpkgs/issues/86131.
BOOST_INCLUDEDIR = "${lib.getDev boost}/include";
BOOST_LIBRARYDIR = "${lib.getLib boost}/lib";
} // lib.optionalAttrs (stdenv.isLinux && !(stdenv.hostPlatform.isStatic && stdenv.system == "aarch64-linux")) {
LDFLAGS = "-fuse-ld=gold";
};
enableParallelBuilding = true;
postInstall =
# Remove absolute path to boost libs that ends up in `Libs.private`
# by default, and would clash with out `disallowedReferences`. Part
# of the https://github.com/NixOS/nixpkgs/issues/45462 workaround.
''
sed -i "$out/lib/pkgconfig/nix-store.pc" -e 's, ${lib.getLib boost}[^ ]*,,g'
'';
separateDebugInfo = !stdenv.hostPlatform.isStatic;
# TODO Always true after https://github.com/NixOS/nixpkgs/issues/318564
strictDeps = !withCoverageChecks;
hardeningDisable = lib.optional stdenv.hostPlatform.isStatic "pie";
meta = {
platforms = lib.platforms.unix ++ lib.platforms.windows;
};
} // lib.optionalAttrs withCoverageChecks {
lcovFilter = [ "*/boost/*" "*-tab.*" ];
hardeningDisable = [ "fortify" ];
})

View file

@ -1500,7 +1500,7 @@ void LocalDerivationGoal::startDaemon()
throw SysError("accepting connection"); throw SysError("accepting connection");
} }
closeOnExec(remote.get()); unix::closeOnExec(remote.get());
debug("received daemon connection"); debug("received daemon connection");
@ -1961,7 +1961,7 @@ void LocalDerivationGoal::runChild()
throw SysError("changing into '%1%'", tmpDir); throw SysError("changing into '%1%'", tmpDir);
/* Close all other file descriptors. */ /* Close all other file descriptors. */
closeMostFDs({STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO}); unix::closeMostFDs({STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO});
#if __linux__ #if __linux__
linux::setPersonality(drv->platform); linux::setPersonality(drv->platform);

View file

@ -17,6 +17,9 @@ R""(
; Allow POSIX semaphores and shared memory. ; Allow POSIX semaphores and shared memory.
(allow ipc-posix*) (allow ipc-posix*)
; Allow SYSV semaphores and shared memory.
(allow ipc-sysv*)
; Allow socket creation. ; Allow socket creation.
(allow system-socket) (allow system-socket)

View file

@ -0,0 +1,19 @@
sources += files(
'build/child.cc',
'build/hook-instance.cc',
'build/local-derivation-goal.cc',
'pathlocks.cc',
'user-lock.cc',
)
include_dirs += include_directories(
'.',
'build',
)
headers += files(
'build/child.hh',
'build/hook-instance.hh',
'build/local-derivation-goal.hh',
'user-lock.hh',
)

View file

@ -0,0 +1,11 @@
sources += files(
'pathlocks.cc',
)
include_dirs += include_directories(
'.',
#'build',
)
headers += files(
)

1
src/libutil/.version Symbolic link
View file

@ -0,0 +1 @@
../../.version

View file

@ -140,6 +140,7 @@ public:
}; };
#ifndef _WIN32 // Not needed on Windows, where we don't fork #ifndef _WIN32 // Not needed on Windows, where we don't fork
namespace unix {
/** /**
* Close all file descriptors except those listed in the given set. * Close all file descriptors except those listed in the given set.
@ -152,13 +153,16 @@ void closeMostFDs(const std::set<Descriptor> & exceptions);
*/ */
void closeOnExec(Descriptor fd); void closeOnExec(Descriptor fd);
} // namespace unix
#endif #endif
#ifdef _WIN32 #if defined(_WIN32) && _WIN32_WINNT >= 0x0600
# if _WIN32_WINNT >= 0x0600 namespace windows {
Path handleToPath(Descriptor handle); Path handleToPath(Descriptor handle);
std::wstring handleToFileName(Descriptor handle); std::wstring handleToFileName(Descriptor handle);
# endif
} // namespace windows
#endif #endif
MakeError(EndOfFile, Error); MakeError(EndOfFile, Error);

View file

@ -525,7 +525,7 @@ std::pair<AutoCloseFD, Path> createTempFile(const Path & prefix)
if (!fd) if (!fd)
throw SysError("creating temporary file '%s'", tmpl); throw SysError("creating temporary file '%s'", tmpl);
#ifndef _WIN32 #ifndef _WIN32
closeOnExec(fd.get()); unix::closeOnExec(fd.get());
#endif #endif
return {std::move(fd), tmpl}; return {std::move(fd), tmpl};
} }

View file

@ -52,11 +52,11 @@ bool Hash::operator == (const Hash & h2) const
std::strong_ordering Hash::operator <=> (const Hash & h) const std::strong_ordering Hash::operator <=> (const Hash & h) const
{ {
if (auto cmp = algo <=> h.algo; cmp != 0) return cmp;
if (auto cmp = hashSize <=> h.hashSize; cmp != 0) return cmp; if (auto cmp = hashSize <=> h.hashSize; cmp != 0) return cmp;
for (unsigned int i = 0; i < hashSize; i++) { for (unsigned int i = 0; i < hashSize; i++) {
if (auto cmp = hash[i] <=> h.hash[i]; cmp != 0) return cmp; if (auto cmp = hash[i] <=> h.hash[i]; cmp != 0) return cmp;
} }
if (auto cmp = algo <=> h.algo; cmp != 0) return cmp;
return std::strong_ordering::equivalent; return std::strong_ordering::equivalent;
} }

View file

@ -0,0 +1,11 @@
sources += files(
'cgroup.cc',
'namespaces.cc',
)
include_dirs += include_directories('.')
headers += files(
'cgroup.hh',
'namespaces.hh',
)

332
src/libutil/meson.build Normal file
View file

@ -0,0 +1,332 @@
project('nix-util', 'cpp',
version : files('.version'),
default_options : [
'cpp_std=c++2a',
# TODO(Qyriad): increase the warning level
'warning_level=1',
'debug=true',
'optimization=2',
'errorlogs=true', # Please print logs for tests that fail
],
meson_version : '>= 1.1',
license : 'LGPL-2.1-or-later',
)
cxx = meson.get_compiler('cpp')
# These are private dependencies with pkg-config files. What private
# means is that the dependencies are used by the library but they are
# *not* used (e.g. `#include`-ed) in any installed header file, and only
# in regular source code (`*.cc`) or private, uninstalled headers. They
# are thus part of the *implementation* of the library, but not its
# *interface*.
#
# See `man pkg-config` for some details.
deps_private = [ ]
# These are public dependencies with pkg-config files. Public is the
# opposite of private: these dependencies are used in installed header
# files. They are part of the interface (and implementation) of the
# library.
#
# N.B. This concept is mostly unrelated to our own concept of a public
# (stable) API, for consumption outside of the Nix repository.
# `libnixutil` is an unstable C++ library, whose public interface is
# likewise unstable. `libutilc` conversely is a hopefully-soon stable
# C library, whose public interface --- including public but not private
# dependencies --- will also likewise soon be stable.
#
# N.B. For distributions that care about "ABI" stablity and not just
# "API" stability, the private dependencies also matter as they can
# potentially affect the public ABI.
deps_public = [ ]
# These are dependencencies without pkg-config files. Ideally they are
# just private, but they may also be public (e.g. boost).
deps_other = [ ]
configdata = configuration_data()
# Check for each of these functions, and create a define like `#define
# HAVE_LUTIMES 1`. The `#define` is unconditional, 0 for not found and 1
# for found. One therefore uses it with `#if` not `#ifdef`.
check_funcs = [
# Optionally used for changing the mtime of symlinks.
'lutimes',
# Optionally used for creating pipes on Unix
'pipe2',
# Optionally used to preallocate files to be large enough before
# writing to them.
'posix_fallocate',
# Optionally used to get more information about processes failing due
# to a signal on Unix.
'strsignal',
# Optionally used to try to close more file descriptors (e.g. before
# forking) on Unix.
'sysconf',
]
foreach funcspec : check_funcs
define_name = 'HAVE_' + funcspec.underscorify().to_upper()
define_value = cxx.has_function(funcspec).to_int()
configdata.set(define_name, define_value)
endforeach
# This is only conditional to work around
# https://github.com/mesonbuild/meson/issues/13293. It should be
# unconditional.
if not (host_machine.system() == 'windows' and cxx.get_id() == 'gcc')
deps_private += dependency('threads')
endif
if host_machine.system() == 'windows'
socket = cxx.find_library('ws2_32')
deps_other += socket
elif host_machine.system() == 'sunos'
socket = cxx.find_library('socket')
network_service_library = cxx.find_library('nsl')
deps_other += [socket, network_service_library]
endif
boost = dependency(
'boost',
modules : ['context', 'coroutine'],
)
# boost is a public dependency, but not a pkg-config dependency unfortunately, so we
# put in `deps_other`.
deps_other += boost
openssl = dependency(
'libcrypto',
'openssl',
version : '>= 1.1.1',
)
deps_private += openssl
libarchive = dependency('libarchive', version : '>= 3.1.2')
deps_public += libarchive
if get_option('default_library') == 'static'
# Workaround until https://github.com/libarchive/libarchive/issues/1446 is fixed
add_project_arguments('-lz', language : 'cpp')
endif
sodium = dependency('libsodium', 'sodium')
deps_private += sodium
brotli = [
dependency('libbrotlicommon'),
dependency('libbrotlidec'),
dependency('libbrotlienc'),
]
deps_private += brotli
cpuid_required = get_option('cpuid')
if host_machine.cpu_family() != 'x86_64' and cpuid_required.enabled()
warning('Force-enabling seccomp on non-x86_64 does not make sense')
endif
cpuid = dependency('libcpuid', 'cpuid', required : cpuid_required)
configdata.set('HAVE_LIBCPUID', cpuid.found().to_int())
deps_private += cpuid
nlohmann_json = dependency('nlohmann_json', version : '>= 3.9')
deps_public += nlohmann_json
config_h = configure_file(
configuration : configdata,
output : 'config-util.h',
)
add_project_arguments(
# TODO(Qyriad): Yes this is how the autoconf+Make system did it.
# It would be nice for our headers to be idempotent instead.
'-include', 'config-util.h',
'-Wno-deprecated-declarations',
'-Wimplicit-fallthrough',
'-Werror=switch',
'-Werror=switch-enum',
'-Wdeprecated-copy',
'-Wignored-qualifiers',
# Enable assertions in libstdc++ by default. Harmless on libc++. Benchmarked
# at ~1% overhead in `nix search`.
#
# FIXME: remove when we get meson 1.4.0 which will default this to on for us:
# https://mesonbuild.com/Release-notes-for-1-4-0.html#ndebug-setting-now-controls-c-stdlib-assertions
'-D_GLIBCXX_ASSERTIONS=1',
language : 'cpp',
)
sources = files(
'archive.cc',
'args.cc',
'canon-path.cc',
'compression.cc',
'compute-levels.cc',
'config.cc',
'current-process.cc',
'english.cc',
'environment-variables.cc',
'error.cc',
'exit.cc',
'experimental-features.cc',
'file-content-address.cc',
'file-descriptor.cc',
'file-system.cc',
'fs-sink.cc',
'git.cc',
'hash.cc',
'hilite.cc',
'json-utils.cc',
'logging.cc',
'memory-source-accessor.cc',
'position.cc',
'posix-source-accessor.cc',
'references.cc',
'serialise.cc',
'signature/local-keys.cc',
'signature/signer.cc',
'source-accessor.cc',
'source-path.cc',
'suggestions.cc',
'tarfile.cc',
'terminal.cc',
'thread-pool.cc',
'unix-domain-socket.cc',
'url.cc',
'users.cc',
'util.cc',
'xml-writer.cc',
)
include_dirs = [include_directories('.')]
headers = [config_h] + files(
'abstract-setting-to-json.hh',
'ansicolor.hh',
'archive.hh',
'args.hh',
'args/root.hh',
'callback.hh',
'canon-path.hh',
'chunked-vector.hh',
'closure.hh',
'comparator.hh',
'compression.hh',
'compute-levels.hh',
'config-impl.hh',
'config.hh',
'current-process.hh',
'english.hh',
'environment-variables.hh',
'error.hh',
'exit.hh',
'experimental-features.hh',
'file-content-address.hh',
'file-descriptor.hh',
'file-path-impl.hh',
'file-path.hh',
'file-system.hh',
'finally.hh',
'fmt.hh',
'fs-sink.hh',
'git.hh',
'hash.hh',
'hilite.hh',
'json-impls.hh',
'json-utils.hh',
'logging.hh',
'lru-cache.hh',
'memory-source-accessor.hh',
'muxable-pipe.hh',
'pool.hh',
'position.hh',
'posix-source-accessor.hh',
'processes.hh',
'ref.hh',
'references.hh',
'regex-combinators.hh',
'repair-flag.hh',
'serialise.hh',
'signals.hh',
'signature/local-keys.hh',
'signature/signer.hh',
'source-accessor.hh',
'source-path.hh',
'split.hh',
'suggestions.hh',
'sync.hh',
'tarfile.hh',
'terminal.hh',
'thread-pool.hh',
'topo-sort.hh',
'types.hh',
'unix-domain-socket.hh',
'url-parts.hh',
'url.hh',
'users.hh',
'util.hh',
'variant-wrapper.hh',
'xml-writer.hh',
)
if host_machine.system() == 'linux'
subdir('linux')
endif
if host_machine.system() == 'windows'
subdir('windows')
else
subdir('unix')
endif
if host_machine.system() == 'cygwin' or host_machine.system() == 'windows'
# Windows DLLs are stricter about symbol visibility than Unix shared
# objects --- see https://gcc.gnu.org/wiki/Visibility for details.
# This is a temporary sledgehammer to export everything like on Unix,
# and not detail with this yet.
#
# TODO do not do this, and instead do fine-grained export annotations.
linker_export_flags = ['-Wl,--export-all-symbols']
else
linker_export_flags = []
endif
this_library = library(
'nixutil',
sources,
dependencies : deps_public + deps_private + deps_other,
include_directories : include_dirs,
link_args: linker_export_flags,
install : true,
)
install_headers(headers, subdir : 'nix', preserve_path : true)
# Part of how we copy boost libraries to a separate installation to
# reduce closure size. These libraries will be copied to our `$out/bin`,
# and these `-l` flags will pick them up there.
#
# https://github.com/NixOS/nixpkgs/issues/45462
libraries_private = ['-lboost_context', '-lboost_coroutine']
if host_machine.system() == 'windows'
# `libraries_private` cannot contain ad-hoc dependencies (from
# `find_library), so we need to do this manually
libraries_private += ['-lws2_32']
endif
import('pkgconfig').generate(
this_library,
filebase : meson.project_name(),
name : 'Nix',
description : 'Nix Package Manager',
subdirs : ['nix'],
extra_cflags : ['-std=c++2a'],
requires : deps_public,
requires_private : deps_private,
libraries_private : libraries_private,
)
meson.override_dependency(meson.project_name(), declare_dependency(
include_directories : include_dirs,
link_with : this_library,
compile_args : ['-std=c++2a'],
dependencies : [],
))

View file

@ -0,0 +1,5 @@
# vim: filetype=meson
option('cpuid', type : 'feature',
description : 'determine microarchitecture levels with libcpuid (only relevant on x86_64)',
)

149
src/libutil/package.nix Normal file
View file

@ -0,0 +1,149 @@
{ lib
, stdenv
, releaseTools
, fileset
, meson
, ninja
, pkg-config
, boost
, brotli
, libarchive
, libcpuid
, libsodium
, nlohmann_json
, openssl
# Configuration Options
, versionSuffix ? ""
, officialRelease ? false
# Check test coverage of Nix. Probably want to use with at least
# one of `doCheck` or `doInstallCheck` enabled.
, withCoverageChecks ? false
}:
let
version = lib.fileContents ./.version + versionSuffix;
mkDerivation =
if withCoverageChecks
then
# TODO support `finalAttrs` args function in
# `releaseTools.coverageAnalysis`.
argsFun:
releaseTools.coverageAnalysis (let args = argsFun args; in args)
else stdenv.mkDerivation;
in
mkDerivation (finalAttrs: {
pname = "nix-util";
inherit version;
src = fileset.toSource {
root = ./.;
fileset = fileset.unions [
./meson.build
./meson.options
./linux/meson.build
./unix/meson.build
./windows/meson.build
(fileset.fileFilter (file: file.hasExt "cc") ./.)
(fileset.fileFilter (file: file.hasExt "hh") ./.)
];
};
outputs = [ "out" "dev" ];
nativeBuildInputs = [
meson
ninja
pkg-config
];
buildInputs = [
boost
brotli
libsodium
openssl
] ++ lib.optional stdenv.hostPlatform.isx86_64 libcpuid
;
propagatedBuildInputs = [
libarchive
nlohmann_json
];
disallowedReferences = [ boost ];
preConfigure =
# "Inline" .version so it's not a symlink, and includes the suffix
''
echo ${version} > .version
''
# Copy some boost libraries so we don't get all of Boost in our
# closure. https://github.com/NixOS/nixpkgs/issues/45462
+ lib.optionalString (!stdenv.hostPlatform.isStatic) (''
mkdir -p $out/lib
cp -pd ${boost}/lib/{libboost_context*,libboost_thread*,libboost_system*} $out/lib
rm -f $out/lib/*.a
'' + lib.optionalString stdenv.hostPlatform.isLinux ''
chmod u+w $out/lib/*.so.*
patchelf --set-rpath $out/lib:${stdenv.cc.cc.lib}/lib $out/lib/libboost_thread.so.*
'' + lib.optionalString stdenv.hostPlatform.isDarwin ''
for LIB in $out/lib/*.dylib; do
chmod u+w $LIB
install_name_tool -id $LIB $LIB
install_name_tool -delete_rpath ${boost}/lib/ $LIB || true
done
install_name_tool -change ${boost}/lib/libboost_system.dylib $out/lib/libboost_system.dylib $out/lib/libboost_thread.dylib
''
);
mesonFlags = [
(lib.mesonEnable "cpuid" stdenv.hostPlatform.isx86_64)
];
env = {
# Needed for Meson to find Boost.
# https://github.com/NixOS/nixpkgs/issues/86131.
BOOST_INCLUDEDIR = "${lib.getDev boost}/include";
BOOST_LIBRARYDIR = "${lib.getLib boost}/lib";
} // lib.optionalAttrs (stdenv.isLinux && !(stdenv.hostPlatform.isStatic && stdenv.system == "aarch64-linux")) {
LDFLAGS = "-fuse-ld=gold";
};
enableParallelBuilding = true;
postInstall =
# Remove absolute path to boost libs that ends up in `Libs.private`
# by default, and would clash with out `disallowedReferences`. Part
# of the https://github.com/NixOS/nixpkgs/issues/45462 workaround.
''
sed -i "$out/lib/pkgconfig/nix-util.pc" -e 's, ${lib.getLib boost}[^ ]*,,g'
''
+ lib.optionalString stdenv.isDarwin ''
install_name_tool \
-change ${boost}/lib/libboost_context.dylib \
$out/lib/libboost_context.dylib \
$out/lib/libnixutil.dylib
'';
separateDebugInfo = !stdenv.hostPlatform.isStatic;
# TODO Always true after https://github.com/NixOS/nixpkgs/issues/318564
strictDeps = !withCoverageChecks;
hardeningDisable = lib.optional stdenv.hostPlatform.isStatic "pie";
meta = {
platforms = lib.platforms.unix ++ lib.platforms.windows;
};
} // lib.optionalAttrs withCoverageChecks {
lcovFilter = [ "*/boost/*" "*-tab.*" ];
hardeningDisable = [ "fortify" ];
})

View file

@ -79,7 +79,8 @@ TarArchive::TarArchive(Source & source, bool raw, std::optional<std::string> com
} }
if (!raw) { if (!raw) {
archive_read_support_format_all(archive); archive_read_support_format_tar(archive);
archive_read_support_format_zip(archive);
} else { } else {
archive_read_support_format_raw(archive); archive_read_support_format_raw(archive);
archive_read_support_format_empty(archive); archive_read_support_format_empty(archive);
@ -96,7 +97,8 @@ TarArchive::TarArchive(const Path & path)
, buffer(defaultBufferSize) , buffer(defaultBufferSize)
{ {
archive_read_support_filter_all(archive); archive_read_support_filter_all(archive);
archive_read_support_format_all(archive); archive_read_support_format_tar(archive);
archive_read_support_format_zip(archive);
archive_read_set_option(archive, NULL, "mac-ext", NULL); archive_read_set_option(archive, NULL, "mac-ext", NULL);
check(archive_read_open_filename(archive, path.c_str(), 16384), "failed to open archive: %s"); check(archive_read_open_filename(archive, path.c_str(), 16384), "failed to open archive: %s");
} }

View file

@ -24,7 +24,7 @@ AutoCloseFD createUnixDomainSocket()
if (!fdSocket) if (!fdSocket)
throw SysError("cannot create Unix domain socket"); throw SysError("cannot create Unix domain socket");
#ifndef _WIN32 #ifndef _WIN32
closeOnExec(fdSocket.get()); unix::closeOnExec(fdSocket.get());
#endif #endif
return fdSocket; return fdSocket;
} }

View file

@ -110,8 +110,8 @@ void Pipe::create()
if (pipe2(fds, O_CLOEXEC) != 0) throw SysError("creating pipe"); if (pipe2(fds, O_CLOEXEC) != 0) throw SysError("creating pipe");
#else #else
if (pipe(fds) != 0) throw SysError("creating pipe"); if (pipe(fds) != 0) throw SysError("creating pipe");
closeOnExec(fds[0]); unix::closeOnExec(fds[0]);
closeOnExec(fds[1]); unix::closeOnExec(fds[1]);
#endif #endif
readSide = fds[0]; readSide = fds[0];
writeSide = fds[1]; writeSide = fds[1];
@ -120,7 +120,7 @@ void Pipe::create()
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
void closeMostFDs(const std::set<int> & exceptions) void unix::closeMostFDs(const std::set<int> & exceptions)
{ {
#if __linux__ #if __linux__
try { try {
@ -139,14 +139,16 @@ void closeMostFDs(const std::set<int> & exceptions)
#endif #endif
int maxFD = 0; int maxFD = 0;
#if HAVE_SYSCONF
maxFD = sysconf(_SC_OPEN_MAX); maxFD = sysconf(_SC_OPEN_MAX);
#endif
for (int fd = 0; fd < maxFD; ++fd) for (int fd = 0; fd < maxFD; ++fd)
if (!exceptions.count(fd)) if (!exceptions.count(fd))
close(fd); /* ignore result */ close(fd); /* ignore result */
} }
void closeOnExec(int fd) void unix::closeOnExec(int fd)
{ {
int prev; int prev;
if ((prev = fcntl(fd, F_GETFD, 0)) == -1 || if ((prev = fcntl(fd, F_GETFD, 0)) == -1 ||

View file

@ -0,0 +1,17 @@
sources += files(
'environment-variables.cc',
'file-descriptor.cc',
'file-path.cc',
'file-system.cc',
'muxable-pipe.cc',
'processes.cc',
'signals.cc',
'users.cc',
)
include_dirs += include_directories('.')
headers += files(
'monitor-fd.hh',
'signals-impl.hh',
)

View file

@ -122,7 +122,7 @@ void Pipe::create()
#if _WIN32_WINNT >= 0x0600 #if _WIN32_WINNT >= 0x0600
std::wstring handleToFileName(HANDLE handle) { std::wstring windows::handleToFileName(HANDLE handle) {
std::vector<wchar_t> buf(0x100); std::vector<wchar_t> buf(0x100);
DWORD dw = GetFinalPathNameByHandleW(handle, buf.data(), buf.size(), FILE_NAME_OPENED); DWORD dw = GetFinalPathNameByHandleW(handle, buf.data(), buf.size(), FILE_NAME_OPENED);
if (dw == 0) { if (dw == 0) {
@ -141,7 +141,7 @@ std::wstring handleToFileName(HANDLE handle) {
} }
Path handleToPath(HANDLE handle) { Path windows::handleToPath(HANDLE handle) {
return os_string_to_string(handleToFileName(handle)); return os_string_to_string(handleToFileName(handle));
} }

View file

@ -0,0 +1,19 @@
sources += files(
'environment-variables.cc',
'file-descriptor.cc',
'file-path.cc',
'file-system.cc',
'muxable-pipe.cc',
'processes.cc',
'users.cc',
'windows-async-pipe.cc',
'windows-error.cc',
)
include_dirs += include_directories('.')
headers += files(
'signals-impl.hh',
'windows-async-pipe.hh',
'windows-error.hh',
)

View file

@ -477,9 +477,7 @@ static void main_nix_build(int argc, char * * argv)
// Set the environment. // Set the environment.
auto env = getEnv(); auto env = getEnv();
auto tmp = getEnvNonEmpty("TMPDIR"); auto tmp = getEnvNonEmpty("TMPDIR").value_or("/tmp");
if (!tmp)
tmp = getEnvNonEmpty("XDG_RUNTIME_DIR").value_or("/tmp");
if (pure) { if (pure) {
decltype(env) newEnv; decltype(env) newEnv;
@ -491,7 +489,7 @@ static void main_nix_build(int argc, char * * argv)
env["__ETC_PROFILE_SOURCED"] = "1"; env["__ETC_PROFILE_SOURCED"] = "1";
} }
env["NIX_BUILD_TOP"] = env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = *tmp; env["NIX_BUILD_TOP"] = env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = tmp;
env["NIX_STORE"] = store->storeDir; env["NIX_STORE"] = store->storeDir;
env["NIX_BUILD_CORES"] = std::to_string(settings.buildCores); env["NIX_BUILD_CORES"] = std::to_string(settings.buildCores);

View file

@ -295,7 +295,7 @@ static void daemonLoop(std::optional<TrustedFlag> forceTrustClientOpt)
if (getEnv("LISTEN_PID") != std::to_string(getpid()) || listenFds != "1") if (getEnv("LISTEN_PID") != std::to_string(getpid()) || listenFds != "1")
throw Error("unexpected systemd environment variables"); throw Error("unexpected systemd environment variables");
fdSocket = SD_LISTEN_FDS_START; fdSocket = SD_LISTEN_FDS_START;
closeOnExec(fdSocket.get()); unix::closeOnExec(fdSocket.get());
} }
// Otherwise, create and bind to a Unix domain socket. // Otherwise, create and bind to a Unix domain socket.
@ -323,7 +323,7 @@ static void daemonLoop(std::optional<TrustedFlag> forceTrustClientOpt)
throw SysError("accepting connection"); throw SysError("accepting connection");
} }
closeOnExec(remote.get()); unix::closeOnExec(remote.get());
PeerInfo peer { .pidKnown = false }; PeerInfo peer { .pidKnown = false };
TrustedFlag trusted; TrustedFlag trusted;

View file

@ -2,10 +2,10 @@
source common.sh source common.sh
sed -e "s|@localstatedir@|$TEST_ROOT/profile-var|g" -e "s|@coreutils@|$coreutils|g" < ../../scripts/nix-profile.sh.in > $TEST_ROOT/nix-profile.sh sed -e "s|@localstatedir@|$TEST_ROOT/profile-var|g" -e "s|@coreutils@|$coreutils|g" < ../../scripts/nix-profile.sh.in > "$TEST_ROOT"/nix-profile.sh
user=$(whoami) user=$(whoami)
rm -rf $TEST_HOME $TEST_ROOT/profile-var rm -rf "$TEST_HOME" "$TEST_ROOT/profile-var"
mkdir -p $TEST_HOME mkdir -p "$TEST_HOME"
USER=$user $SHELL -e -c ". $TEST_ROOT/nix-profile.sh; set" USER=$user $SHELL -e -c ". $TEST_ROOT/nix-profile.sh; set"
USER=$user $SHELL -e -c ". $TEST_ROOT/nix-profile.sh" # test idempotency USER=$user $SHELL -e -c ". $TEST_ROOT/nix-profile.sh" # test idempotency

View file

@ -12,7 +12,7 @@ clearCacheCache
outPath=$(nix-build --store "file://$cacheDir" --builders 'auto - - 1 1' -j0 dependencies.nix) outPath=$(nix-build --store "file://$cacheDir" --builders 'auto - - 1 1' -j0 dependencies.nix)
# Test that the path exactly exists in the destination store. # Test that the path exactly exists in the destination store.
nix path-info --store "file://$cacheDir" $outPath nix path-info --store "file://$cacheDir" "$outPath"
# Succeeds without any build capability because no-op # Succeeds without any build capability because no-op
nix-build --store "file://$cacheDir" -j0 dependencies.nix nix-build --store "file://$cacheDir" -j0 dependencies.nix

View file

@ -14,9 +14,9 @@ clearStore
clearCache clearCache
outPath=$(nix-build dependencies.nix --no-out-link) outPath=$(nix-build dependencies.nix --no-out-link)
nix copy --to file://$cacheDir $outPath nix copy --to "file://$cacheDir" "$outPath"
readarray -t paths < <(nix path-info --all --json --store file://$cacheDir | jq 'keys|sort|.[]' -r) readarray -t paths < <(nix path-info --all --json --store "file://$cacheDir" | jq 'keys|sort|.[]' -r)
[[ "${#paths[@]}" -eq 3 ]] [[ "${#paths[@]}" -eq 3 ]]
for path in "${paths[@]}"; do for path in "${paths[@]}"; do
[[ "$path" =~ -dependencies-input-0$ ]] \ [[ "$path" =~ -dependencies-input-0$ ]] \
@ -25,16 +25,16 @@ for path in "${paths[@]}"; do
done done
# Test copying build logs to the binary cache. # Test copying build logs to the binary cache.
expect 1 nix log --store file://$cacheDir $outPath 2>&1 | grep 'is not available' expect 1 nix log --store "file://$cacheDir" "$outPath" 2>&1 | grep 'is not available'
nix store copy-log --to file://$cacheDir $outPath nix store copy-log --to "file://$cacheDir" "$outPath"
nix log --store file://$cacheDir $outPath | grep FOO nix log --store "file://$cacheDir" "$outPath" | grep FOO
rm -rf $TEST_ROOT/var/log/nix rm -rf "$TEST_ROOT/var/log/nix"
expect 1 nix log $outPath 2>&1 | grep 'is not available' expect 1 nix log "$outPath" 2>&1 | grep 'is not available'
nix log --substituters file://$cacheDir $outPath | grep FOO nix log --substituters "file://$cacheDir" "$outPath" | grep FOO
# Test copying build logs from the binary cache. # Test copying build logs from the binary cache.
nix store copy-log --from file://$cacheDir $(nix-store -qd $outPath)^'*' nix store copy-log --from "file://$cacheDir" "$(nix-store -qd "$outPath")"^'*'
nix log $outPath | grep FOO nix log "$outPath" | grep FOO
basicDownloadTests() { basicDownloadTests() {
# No uploading tests bcause upload with force HTTP doesn't work. # No uploading tests bcause upload with force HTTP doesn't work.
@ -46,15 +46,15 @@ basicDownloadTests() {
nix-env --substituters "file://$cacheDir" -f dependencies.nix -qas \* | grep -- "---" nix-env --substituters "file://$cacheDir" -f dependencies.nix -qas \* | grep -- "---"
nix-store --substituters "file://$cacheDir" --no-require-sigs -r $outPath nix-store --substituters "file://$cacheDir" --no-require-sigs -r "$outPath"
[ -x $outPath/program ] [ -x "$outPath/program" ]
# But with the right configuration, "nix-env -qas" should also work. # But with the right configuration, "nix-env -qas" should also work.
clearStore clearStore
clearCacheCache clearCacheCache
echo "WantMassQuery: 1" >> $cacheDir/nix-cache-info echo "WantMassQuery: 1" >> "$cacheDir/nix-cache-info"
nix-env --substituters "file://$cacheDir" -f dependencies.nix -qas \* | grep -- "--S" nix-env --substituters "file://$cacheDir" -f dependencies.nix -qas \* | grep -- "--S"
nix-env --substituters "file://$cacheDir" -f dependencies.nix -qas \* | grep -- "--S" nix-env --substituters "file://$cacheDir" -f dependencies.nix -qas \* | grep -- "--S"
@ -62,12 +62,12 @@ basicDownloadTests() {
x=$(nix-env -f dependencies.nix -qas \* --prebuilt-only) x=$(nix-env -f dependencies.nix -qas \* --prebuilt-only)
[ -z "$x" ] [ -z "$x" ]
nix-store --substituters "file://$cacheDir" --no-require-sigs -r $outPath nix-store --substituters "file://$cacheDir" --no-require-sigs -r "$outPath"
nix-store --check-validity $outPath nix-store --check-validity "$outPath"
nix-store -qR $outPath | grep input-2 nix-store -qR "$outPath" | grep input-2
echo "WantMassQuery: 0" >> $cacheDir/nix-cache-info echo "WantMassQuery: 0" >> "$cacheDir/nix-cache-info"
} }
@ -83,22 +83,22 @@ basicDownloadTests
# Test whether Nix notices if the NAR doesn't match the hash in the NAR info. # Test whether Nix notices if the NAR doesn't match the hash in the NAR info.
clearStore clearStore
nar=$(ls $cacheDir/nar/*.nar.xz | head -n1) nar=$(find "$cacheDir/nar/" -type f -name "*.nar.xz" | head -n1)
mv $nar $nar.good mv "$nar" "$nar".good
mkdir -p $TEST_ROOT/empty mkdir -p "$TEST_ROOT/empty"
nix-store --dump $TEST_ROOT/empty | xz > $nar nix-store --dump "$TEST_ROOT/empty" | xz > "$nar"
expect 1 nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o $TEST_ROOT/result 2>&1 | tee $TEST_ROOT/log expect 1 nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o "$TEST_ROOT/result" 2>&1 | tee "$TEST_ROOT/log"
grepQuiet "hash mismatch" $TEST_ROOT/log grepQuiet "hash mismatch" "$TEST_ROOT/log"
mv $nar.good $nar mv "$nar".good "$nar"
# Test whether this unsigned cache is rejected if the user requires signed caches. # Test whether this unsigned cache is rejected if the user requires signed caches.
clearStore clearStore
clearCacheCache clearCacheCache
if nix-store --substituters "file://$cacheDir" -r $outPath; then if nix-store --substituters "file://$cacheDir" -r "$outPath"; then
echo "unsigned binary cache incorrectly accepted" echo "unsigned binary cache incorrectly accepted"
exit 1 exit 1
fi fi
@ -107,131 +107,134 @@ fi
# Test whether fallback works if a NAR has disappeared. This does not require --fallback. # Test whether fallback works if a NAR has disappeared. This does not require --fallback.
clearStore clearStore
mv $cacheDir/nar $cacheDir/nar2 mv "$cacheDir/nar" "$cacheDir/nar2"
nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o $TEST_ROOT/result nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o "$TEST_ROOT/result"
mv $cacheDir/nar2 $cacheDir/nar mv "$cacheDir/nar2" "$cacheDir/nar"
# Test whether fallback works if a NAR is corrupted. This does require --fallback. # Test whether fallback works if a NAR is corrupted. This does require --fallback.
clearStore clearStore
mv $cacheDir/nar $cacheDir/nar2 mv "$cacheDir/nar" "$cacheDir/nar2"
mkdir $cacheDir/nar mkdir "$cacheDir/nar"
for i in $(cd $cacheDir/nar2 && echo *); do touch $cacheDir/nar/$i; done for i in $(cd "$cacheDir/nar2" && echo *); do touch "$cacheDir"/nar/"$i"; done
(! nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o $TEST_ROOT/result) (! nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o "$TEST_ROOT/result")
nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o $TEST_ROOT/result --fallback nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o "$TEST_ROOT/result" --fallback
rm -rf $cacheDir/nar rm -rf "$cacheDir/nar"
mv $cacheDir/nar2 $cacheDir/nar mv "$cacheDir/nar2" "$cacheDir/nar"
# Test whether building works if the binary cache contains an # Test whether building works if the binary cache contains an
# incomplete closure. # incomplete closure.
clearStore clearStore
rm -v $(grep -l "StorePath:.*dependencies-input-2" $cacheDir/*.narinfo) rm -v "$(grep -l "StorePath:.*dependencies-input-2" "$cacheDir"/*.narinfo)"
nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o $TEST_ROOT/result 2>&1 | tee $TEST_ROOT/log nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o "$TEST_ROOT/result" 2>&1 | tee "$TEST_ROOT/log"
grepQuiet "copying path.*input-0" $TEST_ROOT/log grepQuiet "copying path.*input-0" "$TEST_ROOT/log"
grepQuiet "copying path.*input-2" $TEST_ROOT/log grepQuiet "copying path.*input-2" "$TEST_ROOT/log"
grepQuiet "copying path.*top" $TEST_ROOT/log grepQuiet "copying path.*top" "$TEST_ROOT/log"
# Idem, but without cached .narinfo. # Idem, but without cached .narinfo.
clearStore clearStore
clearCacheCache clearCacheCache
nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o $TEST_ROOT/result 2>&1 | tee $TEST_ROOT/log nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o "$TEST_ROOT/result" 2>&1 | tee "$TEST_ROOT/log"
grepQuiet "don't know how to build" $TEST_ROOT/log grepQuiet "don't know how to build" "$TEST_ROOT/log"
grepQuiet "building.*input-1" $TEST_ROOT/log grepQuiet "building.*input-1" "$TEST_ROOT/log"
grepQuiet "building.*input-2" $TEST_ROOT/log grepQuiet "building.*input-2" "$TEST_ROOT/log"
grepQuiet "copying path.*input-0" $TEST_ROOT/log grepQuiet "copying path.*input-0" "$TEST_ROOT/log"
grepQuiet "copying path.*top" $TEST_ROOT/log grepQuiet "copying path.*top" "$TEST_ROOT/log"
# Create a signed binary cache. # Create a signed binary cache.
clearCache clearCache
clearCacheCache clearCacheCache
nix key generate-secret --key-name test.nixos.org-1 > $TEST_ROOT/sk1 nix key generate-secret --key-name test.nixos.org-1 > "$TEST_ROOT/sk1"
publicKey=$(nix key convert-secret-to-public < $TEST_ROOT/sk1) publicKey=$(nix key convert-secret-to-public < "$TEST_ROOT/sk1")
nix key generate-secret --key-name test.nixos.org-1 > $TEST_ROOT/sk2 nix key generate-secret --key-name test.nixos.org-1 > "$TEST_ROOT/sk2"
badKey=$(nix key convert-secret-to-public < $TEST_ROOT/sk2) badKey=$(nix key convert-secret-to-public < "$TEST_ROOT/sk2")
nix key generate-secret --key-name foo.nixos.org-1 > $TEST_ROOT/sk3 nix key generate-secret --key-name foo.nixos.org-1 > "$TEST_ROOT/sk3"
otherKey=$(nix key convert-secret-to-public < $TEST_ROOT/sk3) otherKey=$(nix key convert-secret-to-public < "$TEST_ROOT/sk3")
_NIX_FORCE_HTTP= nix copy --to file://$cacheDir?secret-key=$TEST_ROOT/sk1 $outPath _NIX_FORCE_HTTP='' nix copy --to "file://$cacheDir"?secret-key="$TEST_ROOT"/sk1 "$outPath"
# Downloading should fail if we don't provide a key. # Downloading should fail if we don't provide a key.
clearStore clearStore
clearCacheCache clearCacheCache
(! nix-store -r $outPath --substituters "file://$cacheDir") (! nix-store -r "$outPath" --substituters "file://$cacheDir")
# And it should fail if we provide an incorrect key. # And it should fail if we provide an incorrect key.
clearStore clearStore
clearCacheCache clearCacheCache
(! nix-store -r $outPath --substituters "file://$cacheDir" --trusted-public-keys "$badKey") (! nix-store -r "$outPath" --substituters "file://$cacheDir" --trusted-public-keys "$badKey")
# It should succeed if we provide the correct key. # It should succeed if we provide the correct key.
nix-store -r $outPath --substituters "file://$cacheDir" --trusted-public-keys "$otherKey $publicKey" nix-store -r "$outPath" --substituters "file://$cacheDir" --trusted-public-keys "$otherKey $publicKey"
# It should fail if we corrupt the .narinfo. # It should fail if we corrupt the .narinfo.
clearStore clearStore
cacheDir2=$TEST_ROOT/binary-cache-2 cacheDir2=$TEST_ROOT/binary-cache-2
rm -rf $cacheDir2 rm -rf "$cacheDir2"
cp -r $cacheDir $cacheDir2 cp -r "$cacheDir" "$cacheDir2"
for i in $cacheDir2/*.narinfo; do for i in "$cacheDir2"/*.narinfo; do
grep -v References $i > $i.tmp grep -v References "$i" > "$i".tmp
mv $i.tmp $i mv "$i".tmp "$i"
done done
clearCacheCache clearCacheCache
(! nix-store -r $outPath --substituters "file://$cacheDir2" --trusted-public-keys "$publicKey") (! nix-store -r "$outPath" --substituters "file://$cacheDir2" --trusted-public-keys "$publicKey")
# If we provide a bad and a good binary cache, it should succeed. # If we provide a bad and a good binary cache, it should succeed.
nix-store -r $outPath --substituters "file://$cacheDir2 file://$cacheDir" --trusted-public-keys "$publicKey" nix-store -r "$outPath" --substituters "file://$cacheDir2 file://$cacheDir" --trusted-public-keys "$publicKey"
unset _NIX_FORCE_HTTP unset _NIX_FORCE_HTTP
# Test 'nix verify --all' on a binary cache. # Test 'nix verify --all' on a binary cache.
nix store verify -vvvvv --all --store file://$cacheDir --no-trust nix store verify -vvvvv --all --store "file://$cacheDir" --no-trust
# Test local NAR caching. # Test local NAR caching.
narCache=$TEST_ROOT/nar-cache narCache=$TEST_ROOT/nar-cache
rm -rf $narCache rm -rf "$narCache"
mkdir $narCache mkdir "$narCache"
[[ $(nix store cat --store "file://$cacheDir?local-nar-cache=$narCache" $outPath/foobar) = FOOBAR ]] [[ $(nix store cat --store "file://$cacheDir?local-nar-cache=$narCache" "$outPath/foobar") = FOOBAR ]]
rm -rfv "$cacheDir/nar" rm -rfv "$cacheDir/nar"
[[ $(nix store cat --store "file://$cacheDir?local-nar-cache=$narCache" $outPath/foobar) = FOOBAR ]] [[ $(nix store cat --store "file://$cacheDir?local-nar-cache=$narCache" "$outPath/foobar") = FOOBAR ]]
(! nix store cat --store file://$cacheDir $outPath/foobar) (! nix store cat --store "file://$cacheDir" "$outPath/foobar")
# Test NAR listing generation. # Test NAR listing generation.
clearCache clearCache
# preserve quotes variables in the single-quoted string
# shellcheck disable=SC2016
outPath=$(nix-build --no-out-link -E ' outPath=$(nix-build --no-out-link -E '
with import ./config.nix; with import ./config.nix;
mkDerivation { mkDerivation {
@ -240,16 +243,18 @@ outPath=$(nix-build --no-out-link -E '
} }
') ')
nix copy --to file://$cacheDir?write-nar-listing=1 $outPath nix copy --to "file://$cacheDir"?write-nar-listing=1 "$outPath"
diff -u \ diff -u \
<(jq -S < $cacheDir/$(basename $outPath | cut -c1-32).ls) \ <(jq -S < "$cacheDir/$(basename "$outPath" | cut -c1-32).ls") \
<(echo '{"version":1,"root":{"type":"directory","entries":{"bar":{"type":"regular","size":4,"narOffset":232},"link":{"type":"symlink","target":"xyzzy"}}}}' | jq -S) <(echo '{"version":1,"root":{"type":"directory","entries":{"bar":{"type":"regular","size":4,"narOffset":232},"link":{"type":"symlink","target":"xyzzy"}}}}' | jq -S)
# Test debug info index generation. # Test debug info index generation.
clearCache clearCache
# preserve quotes variables in the single-quoted string
# shellcheck disable=SC2016
outPath=$(nix-build --no-out-link -E ' outPath=$(nix-build --no-out-link -E '
with import ./config.nix; with import ./config.nix;
mkDerivation { mkDerivation {
@ -258,14 +263,16 @@ outPath=$(nix-build --no-out-link -E '
} }
') ')
nix copy --to "file://$cacheDir?index-debug-info=1&compression=none" $outPath nix copy --to "file://$cacheDir?index-debug-info=1&compression=none" "$outPath"
diff -u \ diff -u \
<(cat $cacheDir/debuginfo/02623eda209c26a59b1a8638ff7752f6b945c26b.debug | jq -S) \ <(jq -S < "$cacheDir"/debuginfo/02623eda209c26a59b1a8638ff7752f6b945c26b.debug) \
<(echo '{"archive":"../nar/100vxs724qr46phz8m24iswmg9p3785hsyagz0kchf6q6gf06sw6.nar","member":"lib/debug/.build-id/02/623eda209c26a59b1a8638ff7752f6b945c26b.debug"}' | jq -S) <(echo '{"archive":"../nar/100vxs724qr46phz8m24iswmg9p3785hsyagz0kchf6q6gf06sw6.nar","member":"lib/debug/.build-id/02/623eda209c26a59b1a8638ff7752f6b945c26b.debug"}' | jq -S)
# Test against issue https://github.com/NixOS/nix/issues/3964 # Test against issue https://github.com/NixOS/nix/issues/3964
#
# preserve quotes variables in the single-quoted string
# shellcheck disable=SC2016
expr=' expr='
with import ./config.nix; with import ./config.nix;
mkDerivation { mkDerivation {
@ -275,22 +282,22 @@ expr='
} }
' '
outPath=$(nix-build --no-out-link -E "$expr") outPath=$(nix-build --no-out-link -E "$expr")
docPath=$(nix-store -q --references $outPath) docPath=$(nix-store -q --references "$outPath")
# $ nix-store -q --tree $outPath # $ nix-store -q --tree $outPath
# ...-multi-output # ...-multi-output
# +---...-multi-output-doc # +---...-multi-output-doc
nix copy --to "file://$cacheDir" $outPath nix copy --to "file://$cacheDir" "$outPath"
hashpart() { hashpart() {
basename "$1" | cut -c1-32 basename "$1" | cut -c1-32
} }
# break the closure of out by removing doc # break the closure of out by removing doc
rm $cacheDir/$(hashpart $docPath).narinfo rm "$cacheDir/$(hashpart "$docPath")".narinfo
nix-store --delete $outPath $docPath nix-store --delete "$outPath" "$docPath"
# -vvv is the level that logs during the loop # -vvv is the level that logs during the loop
timeout 60 nix-build --no-out-link -E "$expr" --option substituters "file://$cacheDir" \ timeout 60 nix-build --no-out-link -E "$expr" --option substituters "file://$cacheDir" \
--option trusted-binary-caches "file://$cacheDir" --no-require-sigs --option trusted-binary-caches "file://$cacheDir" --no-require-sigs

View file

@ -9,15 +9,15 @@ cacheURI="file://$cacheDir?compression=br"
outPath=$(nix-build dependencies.nix --no-out-link) outPath=$(nix-build dependencies.nix --no-out-link)
nix copy --to $cacheURI $outPath nix copy --to "$cacheURI" "$outPath"
HASH=$(nix hash path $outPath) HASH=$(nix hash path "$outPath")
clearStore clearStore
clearCacheCache clearCacheCache
nix copy --from $cacheURI $outPath --no-check-sigs nix copy --from "$cacheURI" "$outPath" --no-check-sigs
HASH2=$(nix hash path $outPath) HASH2=$(nix hash path "$outPath")
[[ $HASH = $HASH2 ]] [[ $HASH == "$HASH2" ]]

View file

@ -6,25 +6,25 @@ clearStore
# https://github.com/NixOS/nix/issues/6572 # https://github.com/NixOS/nix/issues/6572
issue_6572_independent_outputs() { issue_6572_independent_outputs() {
nix build -f multiple-outputs.nix --json independent --no-link > $TEST_ROOT/independent.json nix build -f multiple-outputs.nix --json independent --no-link > "$TEST_ROOT"/independent.json
# Make sure that 'nix build' can build a derivation that depends on both outputs of another derivation. # Make sure that 'nix build' can build a derivation that depends on both outputs of another derivation.
p=$(nix build -f multiple-outputs.nix use-independent --no-link --print-out-paths) p=$(nix build -f multiple-outputs.nix use-independent --no-link --print-out-paths)
nix-store --delete "$p" # Clean up for next test nix-store --delete "$p" # Clean up for next test
# Make sure that 'nix build' tracks input-outputs correctly when a single output is already present. # Make sure that 'nix build' tracks input-outputs correctly when a single output is already present.
nix-store --delete "$(jq -r <$TEST_ROOT/independent.json .[0].outputs.first)" nix-store --delete "$(jq -r <"$TEST_ROOT"/independent.json .[0].outputs.first)"
p=$(nix build -f multiple-outputs.nix use-independent --no-link --print-out-paths) p=$(nix build -f multiple-outputs.nix use-independent --no-link --print-out-paths)
cmp $p <<EOF cmp "$p" <<EOF
first first
second second
EOF EOF
nix-store --delete "$p" # Clean up for next test nix-store --delete "$p" # Clean up for next test
# Make sure that 'nix build' tracks input-outputs correctly when a single output is already present. # Make sure that 'nix build' tracks input-outputs correctly when a single output is already present.
nix-store --delete "$(jq -r <$TEST_ROOT/independent.json .[0].outputs.second)" nix-store --delete "$(jq -r <"$TEST_ROOT"/independent.json .[0].outputs.second)"
p=$(nix build -f multiple-outputs.nix use-independent --no-link --print-out-paths) p=$(nix build -f multiple-outputs.nix use-independent --no-link --print-out-paths)
cmp $p <<EOF cmp "$p" <<EOF
first first
second second
EOF EOF
@ -36,16 +36,16 @@ issue_6572_independent_outputs
# https://github.com/NixOS/nix/issues/6572 # https://github.com/NixOS/nix/issues/6572
issue_6572_dependent_outputs() { issue_6572_dependent_outputs() {
nix build -f multiple-outputs.nix --json a --no-link > $TEST_ROOT/a.json nix build -f multiple-outputs.nix --json a --no-link > "$TEST_ROOT"/a.json
# # Make sure that 'nix build' can build a derivation that depends on both outputs of another derivation. # # Make sure that 'nix build' can build a derivation that depends on both outputs of another derivation.
p=$(nix build -f multiple-outputs.nix use-a --no-link --print-out-paths) p=$(nix build -f multiple-outputs.nix use-a --no-link --print-out-paths)
nix-store --delete "$p" # Clean up for next test nix-store --delete "$p" # Clean up for next test
# Make sure that 'nix build' tracks input-outputs correctly when a single output is already present. # Make sure that 'nix build' tracks input-outputs correctly when a single output is already present.
nix-store --delete "$(jq -r <$TEST_ROOT/a.json .[0].outputs.second)" nix-store --delete "$(jq -r <"$TEST_ROOT"/a.json .[0].outputs.second)"
p=$(nix build -f multiple-outputs.nix use-a --no-link --print-out-paths) p=$(nix build -f multiple-outputs.nix use-a --no-link --print-out-paths)
cmp $p <<EOF cmp "$p" <<EOF
first first
second second
EOF EOF

View file

@ -35,17 +35,17 @@ clearStore
clearCache clearCache
RESULT=$TEST_ROOT/result-link RESULT=$TEST_ROOT/result-link
rm -f $RESULT rm -f "$RESULT"
nix-build dependencies.nix -o $RESULT --dry-run nix-build dependencies.nix -o "$RESULT" --dry-run
[[ ! -h $RESULT ]] || fail "nix-build --dry-run created output link" [[ ! -h $RESULT ]] || fail "nix-build --dry-run created output link"
nix build -f dependencies.nix -o $RESULT --dry-run nix build -f dependencies.nix -o "$RESULT" --dry-run
[[ ! -h $RESULT ]] || fail "nix build --dry-run created output link" [[ ! -h $RESULT ]] || fail "nix build --dry-run created output link"
nix build -f dependencies.nix -o $RESULT nix build -f dependencies.nix -o "$RESULT"
[[ -h $RESULT ]] [[ -h $RESULT ]]
@ -58,12 +58,12 @@ RES=$(nix build -f dependencies.nix --dry-run --json)
if [[ -z "${NIX_TESTS_CA_BY_DEFAULT-}" ]]; then if [[ -z "${NIX_TESTS_CA_BY_DEFAULT-}" ]]; then
echo "$RES" | jq '.[0] | [ echo "$RES" | jq '.[0] | [
(.drvPath | test("'$NIX_STORE_DIR'.*\\.drv")), (.drvPath | test("'"$NIX_STORE_DIR"'.*\\.drv")),
(.outputs.out | test("'$NIX_STORE_DIR'")) (.outputs.out | test("'"$NIX_STORE_DIR"'"))
] | all' ] | all'
else else
echo "$RES" | jq '.[0] | [ echo "$RES" | jq '.[0] | [
(.drvPath | test("'$NIX_STORE_DIR'.*\\.drv")), (.drvPath | test("'"$NIX_STORE_DIR"'.*\\.drv")),
.outputs.out == null .outputs.out == null
] | all' ] | all'
fi fi

View file

@ -26,7 +26,8 @@ copyAttr () {
# Note: to copy CA derivations, we need to copy the realisations, which # Note: to copy CA derivations, we need to copy the realisations, which
# currently requires naming the installables, not just the derivation output # currently requires naming the installables, not just the derivation output
# path. # path.
nix copy --to file://$cacheDir "${args[@]}"
nix copy --to "file://$cacheDir" "${args[@]}"
} }
testRemoteCacheFor () { testRemoteCacheFor () {
@ -35,7 +36,7 @@ testRemoteCacheFor () {
copyAttr "$derivationPath" 1 copyAttr "$derivationPath" 1
clearStore clearStore
# Check nothing gets built. # Check nothing gets built.
buildAttr "$derivationPath" 1 --option substituters file://$cacheDir --no-require-sigs |& grepQuietInverse " will be built:" buildAttr "$derivationPath" 1 --option substituters "file://$cacheDir" --no-require-sigs |& grepQuietInverse " will be built:"
} }
testRemoteCache () { testRemoteCache () {

View file

@ -20,11 +20,11 @@ testDeterministicCA () {
testCutoffFor () { testCutoffFor () {
local out1 out2 local out1 out2
out1=$(buildAttr $1 1) out1=$(buildAttr "$1" 1)
# The seed only changes the root derivation, and not it's output, so the # The seed only changes the root derivation, and not it's output, so the
# dependent derivations should only need to be built once. # dependent derivations should only need to be built once.
buildAttr rootCA 2 buildAttr rootCA 2
out2=$(buildAttr $1 2 -j0) out2=$(buildAttr "$1" 2 -j0)
test "$out1" == "$out2" test "$out1" == "$out2"
} }
@ -41,7 +41,7 @@ testGC () {
nix-instantiate ./content-addressed.nix -A rootCA --arg seed 5 nix-instantiate ./content-addressed.nix -A rootCA --arg seed 5
nix-collect-garbage --option keep-derivations true nix-collect-garbage --option keep-derivations true
clearStore clearStore
buildAttr rootCA 1 --out-link $TEST_ROOT/rootCA buildAttr rootCA 1 --out-link "$TEST_ROOT"/rootCA
nix-collect-garbage nix-collect-garbage
buildAttr rootCA 1 -j0 buildAttr rootCA 1 -j0
} }
@ -55,7 +55,7 @@ testNixCommand () {
testNormalization () { testNormalization () {
clearStore clearStore
outPath=$(buildAttr rootCA 1) outPath=$(buildAttr rootCA 1)
test "$(stat -c %Y $outPath)" -eq 1 test "$(stat -c %Y "$outPath")" -eq 1
} }
clearStore clearStore

View file

@ -1,29 +1,31 @@
#!/usr/bin/env bash
#
source common.sh source common.sh
export NIX_TESTS_CA_BY_DEFAULT=1 export NIX_TESTS_CA_BY_DEFAULT=1
drvPath=$(nix-instantiate ../simple.nix) drvPath=$(nix-instantiate ../simple.nix)
nix derivation show $drvPath | jq .[] > $TEST_HOME/simple.json nix derivation show "$drvPath" | jq .[] > "$TEST_HOME"/simple.json
drvPath2=$(nix derivation add < $TEST_HOME/simple.json) drvPath2=$(nix derivation add < "$TEST_HOME"/simple.json)
[[ "$drvPath" = "$drvPath2" ]] [[ "$drvPath" = "$drvPath2" ]]
# Content-addressed derivations can be renamed. # Content-addressed derivations can be renamed.
jq '.name = "foo"' < $TEST_HOME/simple.json > $TEST_HOME/foo.json jq '.name = "foo"' < "$TEST_HOME"/simple.json > "$TEST_HOME"/foo.json
drvPath3=$(nix derivation add --dry-run < $TEST_HOME/foo.json) drvPath3=$(nix derivation add --dry-run < "$TEST_HOME"/foo.json)
# With --dry-run nothing is actually written # With --dry-run nothing is actually written
[[ ! -e "$drvPath3" ]] [[ ! -e "$drvPath3" ]]
# But the JSON is rejected without the experimental feature # But the JSON is rejected without the experimental feature
expectStderr 1 nix derivation add < $TEST_HOME/foo.json --experimental-features nix-command | grepQuiet "experimental Nix feature 'ca-derivations' is disabled" expectStderr 1 nix derivation add < "$TEST_HOME"/foo.json --experimental-features nix-command | grepQuiet "experimental Nix feature 'ca-derivations' is disabled"
# Without --dry-run it is actually written # Without --dry-run it is actually written
drvPath4=$(nix derivation add < $TEST_HOME/foo.json) drvPath4=$(nix derivation add < "$TEST_HOME"/foo.json)
[[ "$drvPath4" = "$drvPath3" ]] [[ "$drvPath4" = "$drvPath3" ]]
[[ -e "$drvPath3" ]] [[ -e "$drvPath3" ]]
# The modified derivation read back as JSON matches # The modified derivation read back as JSON matches
nix derivation show $drvPath3 | jq .[] > $TEST_HOME/foo-read.json nix derivation show "$drvPath3" | jq .[] > "$TEST_HOME"/foo-read.json
diff $TEST_HOME/foo.json $TEST_HOME/foo-read.json diff "$TEST_HOME"/foo.json "$TEST_HOME"/foo-read.json

View file

@ -1,3 +1,5 @@
#!/usr/bin/env bash
source ./common.sh source ./common.sh
requireDaemonNewerThan "2.4pre20210625" requireDaemonNewerThan "2.4pre20210625"
@ -5,7 +7,7 @@ requireDaemonNewerThan "2.4pre20210625"
export REMOTE_STORE_DIR="$TEST_ROOT/remote_store" export REMOTE_STORE_DIR="$TEST_ROOT/remote_store"
export REMOTE_STORE="file://$REMOTE_STORE_DIR" export REMOTE_STORE="file://$REMOTE_STORE_DIR"
rm -rf $REMOTE_STORE_DIR rm -rf "$REMOTE_STORE_DIR"
clearStore clearStore
# Build dep1 and push that to the binary cache. # Build dep1 and push that to the binary cache.

View file

@ -15,13 +15,13 @@ testOneCopy () {
rm -rf "$REMOTE_STORE_DIR" rm -rf "$REMOTE_STORE_DIR"
attrPath="$1" attrPath="$1"
nix copy --to $REMOTE_STORE "$attrPath" --file ./content-addressed.nix nix copy --to "$REMOTE_STORE" "$attrPath" --file ./content-addressed.nix
ensureCorrectlyCopied "$attrPath" ensureCorrectlyCopied "$attrPath"
# Ensure that we can copy back what we put in the store # Ensure that we can copy back what we put in the store
clearStore clearStore
nix copy --from $REMOTE_STORE \ nix copy --from "$REMOTE_STORE" \
--file ./content-addressed.nix "$attrPath" \ --file ./content-addressed.nix "$attrPath" \
--no-check-sigs --no-check-sigs
} }

View file

@ -4,4 +4,4 @@ source common.sh
FLAKE_PATH=path:$PWD FLAKE_PATH=path:$PWD
nix run --no-write-lock-file $FLAKE_PATH#runnable nix run --no-write-lock-file "$FLAKE_PATH#runnable"

View file

@ -1,10 +1,12 @@
#!/usr/bin/env bash
source common.sh source common.sh
clearStore clearStore
clearCache clearCache
nix-store --generate-binary-cache-key cache1.example.org $TEST_ROOT/sk1 $TEST_ROOT/pk1 nix-store --generate-binary-cache-key cache1.example.org "$TEST_ROOT/sk1" "$TEST_ROOT/pk1"
pk1=$(cat $TEST_ROOT/pk1) pk1=$(cat "$TEST_ROOT/pk1")
export REMOTE_STORE_DIR="$TEST_ROOT/remote_store" export REMOTE_STORE_DIR="$TEST_ROOT/remote_store"
export REMOTE_STORE="file://$REMOTE_STORE_DIR" export REMOTE_STORE="file://$REMOTE_STORE_DIR"
@ -19,16 +21,16 @@ testOneCopy () {
rm -rf "$REMOTE_STORE_DIR" rm -rf "$REMOTE_STORE_DIR"
attrPath="$1" attrPath="$1"
nix copy -vvvv --to $REMOTE_STORE "$attrPath" --file ./content-addressed.nix \ nix copy -vvvv --to "$REMOTE_STORE" "$attrPath" --file ./content-addressed.nix \
--secret-key-files "$TEST_ROOT/sk1" --show-trace --secret-key-files "$TEST_ROOT/sk1" --show-trace
ensureCorrectlyCopied "$attrPath" ensureCorrectlyCopied "$attrPath"
# Ensure that we can copy back what we put in the store # Ensure that we can copy back what we put in the store
clearStore clearStore
nix copy --from $REMOTE_STORE \ nix copy --from "$REMOTE_STORE" \
--file ./content-addressed.nix "$attrPath" \ --file ./content-addressed.nix "$attrPath" \
--trusted-public-keys $pk1 --trusted-public-keys "$pk1"
} }
for attrPath in rootCA dependentCA transitivelyDependentCA dependentNonCA dependentFixedOutput; do for attrPath in rootCA dependentCA transitivelyDependentCA dependentNonCA dependentFixedOutput; do

View file

@ -4,9 +4,10 @@
source common.sh source common.sh
# shellcheck disable=SC1111
needLocalStore "“--no-require-sigs” cant be used with the daemon" needLocalStore "“--no-require-sigs” cant be used with the daemon"
rm -rf $TEST_ROOT/binary_cache rm -rf "$TEST_ROOT/binary_cache"
export REMOTE_STORE_DIR=$TEST_ROOT/binary_cache export REMOTE_STORE_DIR=$TEST_ROOT/binary_cache
export REMOTE_STORE=file://$REMOTE_STORE_DIR export REMOTE_STORE=file://$REMOTE_STORE_DIR
@ -17,11 +18,11 @@ buildDrvs () {
# Populate the remote cache # Populate the remote cache
clearStore clearStore
nix copy --to $REMOTE_STORE --file ./content-addressed.nix nix copy --to "$REMOTE_STORE" --file ./content-addressed.nix
# Restart the build on an empty store, ensuring that we don't build # Restart the build on an empty store, ensuring that we don't build
clearStore clearStore
buildDrvs --substitute --substituters $REMOTE_STORE --no-require-sigs -j0 transitivelyDependentCA buildDrvs --substitute --substituters "$REMOTE_STORE" --no-require-sigs -j0 transitivelyDependentCA
# Check that the thing weve just substituted has its realisation stored # Check that the thing weve just substituted has its realisation stored
nix realisation info --file ./content-addressed.nix transitivelyDependentCA nix realisation info --file ./content-addressed.nix transitivelyDependentCA
# Check that its dependencies have it too # Check that its dependencies have it too
@ -63,9 +64,9 @@ clearStore
# Add the realisations of rootCA to the cachecache # Add the realisations of rootCA to the cachecache
clearCacheCache clearCacheCache
export _NIX_FORCE_HTTP=1 export _NIX_FORCE_HTTP=1
buildDrvs --substitute --substituters $REMOTE_STORE --no-require-sigs -j0 buildDrvs --substitute --substituters "$REMOTE_STORE" --no-require-sigs -j0
# Try rebuilding, but remove the realisations from the remote cache to force # Try rebuilding, but remove the realisations from the remote cache to force
# using the cachecache # using the cachecache
clearStore clearStore
rm $REMOTE_STORE_DIR/realisations/* rm "$REMOTE_STORE_DIR"/realisations/*
buildDrvs --substitute --substituters $REMOTE_STORE --no-require-sigs -j0 buildDrvs --substitute --substituters "$REMOTE_STORE" --no-require-sigs -j0

View file

@ -4,18 +4,19 @@ source common.sh
clearStore clearStore
rm -rf $TEST_ROOT/case rm -rf "$TEST_ROOT/case"
opts="--option use-case-hack true" opts=("--option" "use-case-hack" "true")
# Check whether restoring and dumping a NAR that contains case # Check whether restoring and dumping a NAR that contains case
# collisions is round-tripping, even on a case-insensitive system. # collisions is round-tripping, even on a case-insensitive system.
nix-store $opts --restore $TEST_ROOT/case < case.nar
nix-store $opts --dump $TEST_ROOT/case > $TEST_ROOT/case.nar nix-store "${opts[@]}" --restore "$TEST_ROOT/case" < case.nar
cmp case.nar $TEST_ROOT/case.nar nix-store "${opts[@]}" --dump "$TEST_ROOT/case" > "$TEST_ROOT/case.nar"
[ "$(nix-hash $opts --type sha256 $TEST_ROOT/case)" = "$(nix-hash --flat --type sha256 case.nar)" ] cmp case.nar "$TEST_ROOT/case.nar"
[ "$(nix-hash "${opts[@]}" --type sha256 "$TEST_ROOT/case")" = "$(nix-hash --flat --type sha256 case.nar)" ]
# Check whether we detect true collisions (e.g. those remaining after # Check whether we detect true collisions (e.g. those remaining after
# removal of the suffix). # removal of the suffix).
touch "$TEST_ROOT/case/xt_CONNMARK.h~nix~case~hack~3" touch "$TEST_ROOT/case/xt_CONNMARK.h~nix~case~hack~3"
(! nix-store $opts --dump $TEST_ROOT/case > /dev/null) (! nix-store "${opts[@]}" --dump "$TEST_ROOT/case" > /dev/null)

View file

@ -6,42 +6,42 @@ clearStore
RESULT=$TEST_ROOT/result RESULT=$TEST_ROOT/result
dep=$(nix-build -o $RESULT check-refs.nix -A dep) dep=$(nix-build -o "$RESULT" check-refs.nix -A dep)
# test1 references dep, not itself. # test1 references dep, not itself.
test1=$(nix-build -o $RESULT check-refs.nix -A test1) test1=$(nix-build -o "$RESULT" check-refs.nix -A test1)
nix-store -q --references $test1 | grepQuietInverse $test1 nix-store -q --references "$test1" | grepQuietInverse "$test1"
nix-store -q --references $test1 | grepQuiet $dep nix-store -q --references "$test1" | grepQuiet "$dep"
# test2 references src, not itself nor dep. # test2 references src, not itself nor dep.
test2=$(nix-build -o $RESULT check-refs.nix -A test2) test2=$(nix-build -o "$RESULT" check-refs.nix -A test2)
nix-store -q --references $test2 | grepQuietInverse $test2 nix-store -q --references "$test2" | grepQuietInverse "$test2"
nix-store -q --references $test2 | grepQuietInverse $dep nix-store -q --references "$test2" | grepQuietInverse "$dep"
nix-store -q --references $test2 | grepQuiet aux-ref nix-store -q --references "$test2" | grepQuiet aux-ref
# test3 should fail (unallowed ref). # test3 should fail (unallowed ref).
(! nix-build -o $RESULT check-refs.nix -A test3) (! nix-build -o "$RESULT" check-refs.nix -A test3)
# test4 should succeed. # test4 should succeed.
nix-build -o $RESULT check-refs.nix -A test4 nix-build -o "$RESULT" check-refs.nix -A test4
# test5 should succeed. # test5 should succeed.
nix-build -o $RESULT check-refs.nix -A test5 nix-build -o "$RESULT" check-refs.nix -A test5
# test6 should fail (unallowed self-ref). # test6 should fail (unallowed self-ref).
(! nix-build -o $RESULT check-refs.nix -A test6) (! nix-build -o "$RESULT" check-refs.nix -A test6)
# test7 should succeed (allowed self-ref). # test7 should succeed (allowed self-ref).
nix-build -o $RESULT check-refs.nix -A test7 nix-build -o "$RESULT" check-refs.nix -A test7
# test8 should fail (toFile depending on derivation output). # test8 should fail (toFile depending on derivation output).
(! nix-build -o $RESULT check-refs.nix -A test8) (! nix-build -o "$RESULT" check-refs.nix -A test8)
# test9 should fail (disallowed reference). # test9 should fail (disallowed reference).
(! nix-build -o $RESULT check-refs.nix -A test9) (! nix-build -o "$RESULT" check-refs.nix -A test9)
# test10 should succeed (no disallowed references). # test10 should succeed (no disallowed references).
nix-build -o $RESULT check-refs.nix -A test10 nix-build -o "$RESULT" check-refs.nix -A test10
if isDaemonNewer 2.12pre20230103; then if isDaemonNewer 2.12pre20230103; then
if ! isDaemonNewer 2.16.0; then if ! isDaemonNewer 2.16.0; then
@ -50,6 +50,6 @@ if isDaemonNewer 2.12pre20230103; then
fi fi
# test11 should succeed. # test11 should succeed.
test11=$(nix-build -o $RESULT check-refs.nix -A test11) test11=$(nix-build -o "$RESULT" check-refs.nix -A test11)
[[ -z $(nix-store -q --references "$test11") ]] [[ -z $(nix-store -q --references "$test11") ]]
fi fi

View file

@ -6,13 +6,13 @@ clearStore
RESULT=$TEST_ROOT/result RESULT=$TEST_ROOT/result
nix-build -o $RESULT check-reqs.nix -A test1 nix-build -o "$RESULT" check-reqs.nix -A test1
(! nix-build -o $RESULT check-reqs.nix -A test2) (! nix-build -o "$RESULT" check-reqs.nix -A test2)
(! nix-build -o $RESULT check-reqs.nix -A test3) (! nix-build -o "$RESULT" check-reqs.nix -A test3)
(! nix-build -o $RESULT check-reqs.nix -A test4) 2>&1 | grepQuiet 'check-reqs-dep1' (! nix-build -o "$RESULT" check-reqs.nix -A test4) 2>&1 | grepQuiet 'check-reqs-dep1'
(! nix-build -o $RESULT check-reqs.nix -A test4) 2>&1 | grepQuiet 'check-reqs-dep2' (! nix-build -o "$RESULT" check-reqs.nix -A test4) 2>&1 | grepQuiet 'check-reqs-dep2'
(! nix-build -o $RESULT check-reqs.nix -A test5) (! nix-build -o "$RESULT" check-reqs.nix -A test5)
(! nix-build -o $RESULT check-reqs.nix -A test6) (! nix-build -o "$RESULT" check-reqs.nix -A test6)
nix-build -o $RESULT check-reqs.nix -A test7 nix-build -o "$RESULT" check-reqs.nix -A test7

View file

@ -2,34 +2,34 @@
source common.sh source common.sh
echo example > $TEST_ROOT/example.txt echo example > "$TEST_ROOT"/example.txt
mkdir -p $TEST_ROOT/x mkdir -p "$TEST_ROOT/x"
export NIX_STORE_DIR=/nix2/store export NIX_STORE_DIR=/nix2/store
CORRECT_PATH=$(cd $TEST_ROOT && nix-store --store ./x --add example.txt) CORRECT_PATH=$(cd "$TEST_ROOT" && nix-store --store ./x --add example.txt)
[[ $CORRECT_PATH =~ ^/nix2/store/.*-example.txt$ ]] [[ $CORRECT_PATH =~ ^/nix2/store/.*-example.txt$ ]]
PATH1=$(cd $TEST_ROOT && nix path-info --store ./x $CORRECT_PATH) PATH1=$(cd "$TEST_ROOT" && nix path-info --store ./x "$CORRECT_PATH")
[ $CORRECT_PATH == $PATH1 ] [ "$CORRECT_PATH" == "$PATH1" ]
PATH2=$(nix path-info --store "$TEST_ROOT/x" $CORRECT_PATH) PATH2=$(nix path-info --store "$TEST_ROOT/x" "$CORRECT_PATH")
[ $CORRECT_PATH == $PATH2 ] [ "$CORRECT_PATH" == "$PATH2" ]
PATH3=$(nix path-info --store "local?root=$TEST_ROOT/x" $CORRECT_PATH) PATH3=$(nix path-info --store "local?root=$TEST_ROOT/x" "$CORRECT_PATH")
[ $CORRECT_PATH == $PATH3 ] [ "$CORRECT_PATH" == "$PATH3" ]
# Ensure store info trusted works with local store # Ensure store info trusted works with local store
nix --store $TEST_ROOT/x store info --json | jq -e '.trusted' nix --store "$TEST_ROOT/x" store info --json | jq -e '.trusted'
# Test building in a chroot store. # Test building in a chroot store.
if canUseSandbox; then if canUseSandbox; then
flakeDir=$TEST_ROOT/flake flakeDir=$TEST_ROOT/flake
mkdir -p $flakeDir mkdir -p "$flakeDir"
cat > $flakeDir/flake.nix <<EOF cat > "$flakeDir"/flake.nix <<EOF
{ {
outputs = inputs: rec { outputs = inputs: rec {
packages.$system.default = import ./simple.nix; packages.$system.default = import ./simple.nix;
@ -37,11 +37,12 @@ if canUseSandbox; then
} }
EOF EOF
cp simple.nix shell.nix simple.builder.sh config.nix $flakeDir/ cp simple.nix shell.nix simple.builder.sh config.nix "$flakeDir/"
outPath=$(nix build --print-out-paths --no-link --sandbox-paths '/nix? /bin? /lib? /lib64? /usr?' --store $TEST_ROOT/x path:$flakeDir) outPath=$(nix build --print-out-paths --no-link --sandbox-paths '/nix? /bin? /lib? /lib64? /usr?' --store "$TEST_ROOT/x" path:"$flakeDir")
[[ $outPath =~ ^/nix2/store/.*-simple$ ]] [[ $outPath =~ ^/nix2/store/.*-simple$ ]]
[[ $(cat $TEST_ROOT/x/nix/store/$(basename $outPath)/hello) = 'Hello World!' ]] base=$(basename "$outPath")
[[ $(cat "$TEST_ROOT"/x/nix/store/"$base"/hello) = 'Hello World!' ]]
fi fi

View file

@ -13,7 +13,7 @@ mkdir "$TEST_HOME"
mkdir "$NIX_STORE_DIR" mkdir "$NIX_STORE_DIR"
mkdir "$NIX_LOCALSTATE_DIR" mkdir "$NIX_LOCALSTATE_DIR"
mkdir -p "$NIX_LOG_DIR"/drvs mkdir -p "$NIX_LOG_DIR/drvs"
mkdir "$NIX_STATE_DIR" mkdir "$NIX_STATE_DIR"
mkdir "$NIX_CONF_DIR" mkdir "$NIX_CONF_DIR"

View file

@ -9,16 +9,16 @@ outPath=$(nix-build dependencies.nix --no-out-link)
cacheURI="file://$cacheDir?compression=xz&compression-level=0" cacheURI="file://$cacheDir?compression=xz&compression-level=0"
nix copy --to $cacheURI $outPath nix copy --to "$cacheURI" "$outPath"
FILESIZES=$(cat ${cacheDir}/*.narinfo | awk '/FileSize: /{sum+=$2}END{print sum}') FILESIZES=$(cat "${cacheDir}"/*.narinfo | awk '/FileSize: /{sum+=$2}END{print sum}')
clearCache clearCache
cacheURI="file://$cacheDir?compression=xz&compression-level=5" cacheURI="file://$cacheDir?compression=xz&compression-level=5"
nix copy --to $cacheURI $outPath nix copy --to "$cacheURI" "$outPath"
FILESIZES2=$(cat ${cacheDir}/*.narinfo | awk '/FileSize: /{sum+=$2}END{print sum}') FILESIZES2=$(cat "${cacheDir}"/*.narinfo | awk '/FileSize: /{sum+=$2}END{print sum}')
[[ $FILESIZES -gt $FILESIZES2 ]] [[ $FILESIZES -gt $FILESIZES2 ]]

View file

@ -33,7 +33,7 @@ nix-store -q --tree "$outPath" | grep '───.*dependencies-input-2'
echo "output path is $outPath" echo "output path is $outPath"
text=$(cat "$outPath"/foobar) text=$(cat "$outPath/foobar")
if test "$text" != "FOOBAR"; then exit 1; fi if test "$text" != "FOOBAR"; then exit 1; fi
deps=$(nix-store -quR "$drvPath") deps=$(nix-store -quR "$drvPath")

View file

@ -4,11 +4,11 @@ source common.sh
drvPath=$(nix-instantiate simple.nix) drvPath=$(nix-instantiate simple.nix)
nix derivation show $drvPath | jq .[] > $TEST_HOME/simple.json nix derivation show "$drvPath" | jq .[] > "$TEST_HOME"/simple.json
drvPath2=$(nix derivation add < $TEST_HOME/simple.json) drvPath2=$(nix derivation add < "$TEST_HOME"/simple.json)
[[ "$drvPath" = "$drvPath2" ]] [[ "$drvPath" = "$drvPath2" ]]
# Input addressed derivations cannot be renamed. # Input addressed derivations cannot be renamed.
jq '.name = "foo"' < $TEST_HOME/simple.json | expectStderr 1 nix derivation add | grepQuiet "has incorrect output" jq '.name = "foo"' < "$TEST_HOME"/simple.json | expectStderr 1 nix derivation add | grepQuiet "has incorrect output"

View file

@ -20,7 +20,7 @@ nix show-derivation "$drvProducingDrv"
out1=$(nix-build ./text-hashed-output.nix -A producingDrv --no-out-link) out1=$(nix-build ./text-hashed-output.nix -A producingDrv --no-out-link)
nix path-info $drv --derivation --json | jq nix path-info "$drv" --derivation --json | jq
nix path-info $out1 --derivation --json | jq nix path-info "$out1" --derivation --json | jq
test $out1 == $drv test "$out1" == "$drv"

View file

@ -33,35 +33,35 @@ source common.sh
NIX_CONFIG=' NIX_CONFIG='
experimental-features = nix-command experimental-features = nix-command
accept-flake-config = true accept-flake-config = true
' expect 1 nix config show accept-flake-config 1>$TEST_ROOT/stdout 2>$TEST_ROOT/stderr ' expect 1 nix config show accept-flake-config 1>"$TEST_ROOT"/stdout 2>"$TEST_ROOT"/stderr
[[ $(cat $TEST_ROOT/stdout) = '' ]] [[ $(cat "$TEST_ROOT/stdout") = '' ]]
grepQuiet "Ignoring setting 'accept-flake-config' because experimental feature 'flakes' is not enabled" $TEST_ROOT/stderr grepQuiet "Ignoring setting 'accept-flake-config' because experimental feature 'flakes' is not enabled" "$TEST_ROOT/stderr"
grepQuiet "error: could not find setting 'accept-flake-config'" $TEST_ROOT/stderr grepQuiet "error: could not find setting 'accept-flake-config'" "$TEST_ROOT/stderr"
# 'flakes' experimental-feature is disabled after, ignore and warn # 'flakes' experimental-feature is disabled after, ignore and warn
NIX_CONFIG=' NIX_CONFIG='
accept-flake-config = true accept-flake-config = true
experimental-features = nix-command experimental-features = nix-command
' expect 1 nix config show accept-flake-config 1>$TEST_ROOT/stdout 2>$TEST_ROOT/stderr ' expect 1 nix config show accept-flake-config 1>"$TEST_ROOT"/stdout 2>"$TEST_ROOT"/stderr
[[ $(cat $TEST_ROOT/stdout) = '' ]] [[ $(cat "$TEST_ROOT/stdout") = '' ]]
grepQuiet "Ignoring setting 'accept-flake-config' because experimental feature 'flakes' is not enabled" $TEST_ROOT/stderr grepQuiet "Ignoring setting 'accept-flake-config' because experimental feature 'flakes' is not enabled" "$TEST_ROOT/stderr"
grepQuiet "error: could not find setting 'accept-flake-config'" $TEST_ROOT/stderr grepQuiet "error: could not find setting 'accept-flake-config'" "$TEST_ROOT/stderr"
# 'flakes' experimental-feature is enabled before, process # 'flakes' experimental-feature is enabled before, process
NIX_CONFIG=' NIX_CONFIG='
experimental-features = nix-command flakes experimental-features = nix-command flakes
accept-flake-config = true accept-flake-config = true
' nix config show accept-flake-config 1>$TEST_ROOT/stdout 2>$TEST_ROOT/stderr ' nix config show accept-flake-config 1>"$TEST_ROOT"/stdout 2>"$TEST_ROOT"/stderr
grepQuiet "true" $TEST_ROOT/stdout grepQuiet "true" "$TEST_ROOT/stdout"
grepQuietInverse "Ignoring setting 'accept-flake-config'" $TEST_ROOT/stderr grepQuietInverse "Ignoring setting 'accept-flake-config'" "$TEST_ROOT/stderr"
# 'flakes' experimental-feature is enabled after, process # 'flakes' experimental-feature is enabled after, process
NIX_CONFIG=' NIX_CONFIG='
accept-flake-config = true accept-flake-config = true
experimental-features = nix-command flakes experimental-features = nix-command flakes
' nix config show accept-flake-config 1>$TEST_ROOT/stdout 2>$TEST_ROOT/stderr ' nix config show accept-flake-config 1>"$TEST_ROOT"/stdout 2>"$TEST_ROOT"/stderr
grepQuiet "true" $TEST_ROOT/stdout grepQuiet "true" "$TEST_ROOT/stdout"
grepQuietInverse "Ignoring setting 'accept-flake-config'" $TEST_ROOT/stderr grepQuietInverse "Ignoring setting 'accept-flake-config'" "$TEST_ROOT/stderr"
function exit_code_both_ways { function exit_code_both_ways {
expect 1 nix --experimental-features 'nix-command' "$@" 1>/dev/null expect 1 nix --experimental-features 'nix-command' "$@" 1>/dev/null

View file

@ -14,7 +14,7 @@ git init "$repo"
git -C "$repo" config user.email "foobar@example.com" git -C "$repo" config user.email "foobar@example.com"
git -C "$repo" config user.name "Foobar" git -C "$repo" config user.name "Foobar"
echo utrecht > "$repo"/hello echo utrecht > "$repo/hello"
git -C "$repo" add hello git -C "$repo" add hello
git -C "$repo" commit -m 'Bla1' git -C "$repo" commit -m 'Bla1'

View file

@ -2,7 +2,7 @@
source common.sh source common.sh
touch $TEST_ROOT/foo -t 202211111111 touch "$TEST_ROOT/foo" -t 202211111111
# We only check whether 2022-11-1* **:**:** is the last modified date since # We only check whether 2022-11-1* **:**:** is the last modified date since
# `lastModified` is transformed into UTC in `builtins.fetchTarball`. # `lastModified` is transformed into UTC in `builtins.fetchTarball`.
[[ "$(nix eval --impure --raw --expr "(builtins.fetchTree \"path://$TEST_ROOT/foo\").lastModifiedDate")" =~ 2022111.* ]] [[ "$(nix eval --impure --raw --expr "(builtins.fetchTree \"path://$TEST_ROOT/foo\").lastModifiedDate")" =~ 2022111.* ]]

View file

@ -90,7 +90,7 @@ EOF
EOF EOF
# Test tarball URLs on the command line. # Test tarball URLs on the command line.
[[ $(nix flake metadata --json file://$PWD/test_input_no_ext | jq -r .resolved.type) = tarball ]] [[ $(nix flake metadata --json "file://$PWD/test_input_no_ext" | jq -r .resolved.type) = tarball ]]
popd popd

View file

@ -2,26 +2,26 @@
source common.sh source common.sh
rm -rf $TEST_ROOT/filterin rm -rf "$TEST_ROOT/filterin"
mkdir $TEST_ROOT/filterin mkdir "$TEST_ROOT/filterin"
mkdir $TEST_ROOT/filterin/foo mkdir "$TEST_ROOT/filterin/foo"
touch $TEST_ROOT/filterin/foo/bar touch "$TEST_ROOT/filterin/foo/bar"
touch $TEST_ROOT/filterin/xyzzy touch "$TEST_ROOT/filterin/xyzzy"
touch $TEST_ROOT/filterin/b touch "$TEST_ROOT/filterin/b"
touch $TEST_ROOT/filterin/bak touch "$TEST_ROOT/filterin/bak"
touch $TEST_ROOT/filterin/bla.c.bak touch "$TEST_ROOT"/filterin/bla.c.bak
ln -s xyzzy $TEST_ROOT/filterin/link ln -s xyzzy "$TEST_ROOT/filterin/link"
checkFilter() { checkFilter() {
test ! -e $1/foo/bar test ! -e "$1/foo/bar"
test -e $1/xyzzy test -e "$1/xyzzy"
test -e $1/bak test -e "$1/bak"
test ! -e $1/bla.c.bak test ! -e "$1"/bla.c.bak
test ! -L $1/link test ! -L "$1/link"
} }
nix-build ./filter-source.nix -o $TEST_ROOT/filterout1 nix-build ./filter-source.nix -o "$TEST_ROOT/filterout1"
checkFilter $TEST_ROOT/filterout1 checkFilter "$TEST_ROOT/filterout1"
nix-build ./path.nix -o $TEST_ROOT/filterout2 nix-build ./path.nix -o "$TEST_ROOT/filterout2"
checkFilter $TEST_ROOT/filterout2 checkFilter "$TEST_ROOT/filterout2"

View file

@ -4,8 +4,8 @@ source ./common.sh
flake1Dir=$TEST_ROOT/flake1 flake1Dir=$TEST_ROOT/flake1
mkdir -p $flake1Dir mkdir -p "$flake1Dir"
cat > $flake1Dir/flake.nix <<EOF cat > "$flake1Dir"/flake.nix <<EOF
{ {
outputs = { self }: { outputs = { self }: {
x = 1; x = 1;
@ -14,6 +14,6 @@ cat > $flake1Dir/flake.nix <<EOF
} }
EOF EOF
[ "$(nix eval --impure --json $flake1Dir#.x)" -eq 1 ] [ "$(nix eval --impure --json "$flake1Dir"#.x)" -eq 1 ]
[ "$(nix eval --impure --json $flake1Dir#x)" -eq 2 ] [ "$(nix eval --impure --json "$flake1Dir#x")" -eq 2 ]
[ "$(nix eval --impure --json $flake1Dir#.packages.$system.x)" -eq 2 ] [ "$(nix eval --impure --json "$flake1Dir"#.packages."$system".x)" -eq 2 ]

View file

@ -5,15 +5,15 @@ source ./common.sh
flake1Dir=$TEST_ROOT/flake1 flake1Dir=$TEST_ROOT/flake1
flake2Dir=$TEST_ROOT/flake2 flake2Dir=$TEST_ROOT/flake2
mkdir -p $flake1Dir $flake2Dir mkdir -p "$flake1Dir" "$flake2Dir"
writeSimpleFlake $flake2Dir writeSimpleFlake "$flake2Dir"
tar cfz $TEST_ROOT/flake.tar.gz -C $TEST_ROOT flake2 tar cfz "$TEST_ROOT"/flake.tar.gz -C "$TEST_ROOT" flake2
hash=$(nix hash path $flake2Dir) hash=$(nix hash path "$flake2Dir")
dep=$(nix store add-path ./common.sh) dep=$(nix store add-path ./common.sh)
cat > $flake1Dir/flake.nix <<EOF cat > "$flake1Dir"/flake.nix <<EOF
{ {
inputs.flake2.url = "file://$TEST_ROOT/flake.tar.gz"; inputs.flake2.url = "file://$TEST_ROOT/flake.tar.gz";
@ -79,43 +79,43 @@ cat > $flake1Dir/flake.nix <<EOF
} }
EOF EOF
cp ../simple.nix ../simple.builder.sh ../config.nix $flake1Dir/ cp ../simple.nix ../simple.builder.sh ../config.nix "$flake1Dir/"
echo bar > $flake1Dir/foo echo bar > "$flake1Dir/foo"
nix build --json --out-link $TEST_ROOT/result $flake1Dir#a1 nix build --json --out-link "$TEST_ROOT/result" "$flake1Dir#a1"
[[ -e $TEST_ROOT/result/simple.nix ]] [[ -e $TEST_ROOT/result/simple.nix ]]
nix build --json --out-link $TEST_ROOT/result $flake1Dir#a2 nix build --json --out-link "$TEST_ROOT/result" "$flake1Dir#a2"
[[ $(cat $TEST_ROOT/result) = bar ]] [[ $(cat "$TEST_ROOT/result") = bar ]]
nix build --json --out-link $TEST_ROOT/result $flake1Dir#a3 nix build --json --out-link "$TEST_ROOT/result" "$flake1Dir#a3"
nix build --json --out-link $TEST_ROOT/result $flake1Dir#a4 nix build --json --out-link "$TEST_ROOT/result" "$flake1Dir#a4"
nix build --json --out-link $TEST_ROOT/result $flake1Dir#a6 nix build --json --out-link "$TEST_ROOT/result" "$flake1Dir#a6"
[[ -e $TEST_ROOT/result/simple.nix ]] [[ -e $TEST_ROOT/result/simple.nix ]]
nix build --impure --json --out-link $TEST_ROOT/result $flake1Dir#a8 nix build --impure --json --out-link "$TEST_ROOT/result" "$flake1Dir#a8"
diff common.sh $TEST_ROOT/result diff common.sh "$TEST_ROOT/result"
expectStderr 1 nix build --impure --json --out-link $TEST_ROOT/result $flake1Dir#a9 \ expectStderr 1 nix build --impure --json --out-link "$TEST_ROOT/result" "$flake1Dir#a9" \
| grepQuiet "has 0 entries in its context. It should only have exactly one entry" | grepQuiet "has 0 entries in its context. It should only have exactly one entry"
nix build --json --out-link $TEST_ROOT/result $flake1Dir#a10 nix build --json --out-link "$TEST_ROOT/result" "$flake1Dir"#a10
[[ $(readlink -e $TEST_ROOT/result) = *simple.drv ]] [[ $(readlink -e "$TEST_ROOT/result") = *simple.drv ]]
expectStderr 1 nix build --json --out-link $TEST_ROOT/result $flake1Dir#a11 \ expectStderr 1 nix build --json --out-link "$TEST_ROOT/result" "$flake1Dir#a11" \
| grepQuiet "has a context which refers to a complete source and binary closure" | grepQuiet "has a context which refers to a complete source and binary closure"
nix build --json --out-link $TEST_ROOT/result $flake1Dir#a12 nix build --json --out-link "$TEST_ROOT/result" "$flake1Dir#a12"
[[ -e $TEST_ROOT/result/hello ]] [[ -e $TEST_ROOT/result/hello ]]
expectStderr 1 nix build --impure --json --out-link $TEST_ROOT/result $flake1Dir#a13 \ expectStderr 1 nix build --impure --json --out-link "$TEST_ROOT/result" "$flake1Dir#a13" \
| grepQuiet "has 2 entries in its context. It should only have exactly one entry" | grepQuiet "has 2 entries in its context. It should only have exactly one entry"
# Test accessing output in installables with `.` (foobarbaz.<output>) # Test accessing output in installables with `.` (foobarbaz.<output>)
nix build --json --no-link $flake1Dir#a14.foo | jq --exit-status ' nix build --json --no-link "$flake1Dir"#a14.foo | jq --exit-status '
(.[0] | (.[0] |
(.drvPath | match(".*dot-installable.drv")) and (.drvPath | match(".*dot-installable.drv")) and
(.outputs | keys == ["foo"])) (.outputs | keys == ["foo"]))

View file

@ -2,9 +2,9 @@
source common.sh source common.sh
cp ../simple.nix ../simple.builder.sh ../config.nix $TEST_HOME cp ../simple.nix ../simple.builder.sh ../config.nix "$TEST_HOME"
cd $TEST_HOME cd "$TEST_HOME"
cat <<EOF > flake.nix cat <<EOF > flake.nix
{ {
@ -27,8 +27,8 @@ EOF
nix build .# nix build .#
nix bundle --bundler .# .# nix bundle --bundler .# .#
nix bundle --bundler .#bundlers.$system.default .#packages.$system.default nix bundle --bundler .#bundlers."$system".default .#packages."$system".default
nix bundle --bundler .#bundlers.$system.simple .#packages.$system.default nix bundle --bundler .#bundlers."$system".simple .#packages."$system".default
nix bundle --bundler .#bundlers.$system.default .#apps.$system.default nix bundle --bundler .#bundlers."$system".default .#apps."$system".default
nix bundle --bundler .#bundlers.$system.simple .#apps.$system.default nix bundle --bundler .#bundlers."$system".simple .#apps."$system".default

View file

@ -8,10 +8,10 @@ requireGit
flakeA=$TEST_ROOT/flakeA flakeA=$TEST_ROOT/flakeA
flakeB=$TEST_ROOT/flakeB flakeB=$TEST_ROOT/flakeB
createGitRepo $flakeA createGitRepo "$flakeA"
createGitRepo $flakeB createGitRepo "$flakeB"
cat > $flakeA/flake.nix <<EOF cat > "$flakeA"/flake.nix <<EOF
{ {
inputs.b.url = git+file://$flakeB; inputs.b.url = git+file://$flakeB;
inputs.b.inputs.a.follows = "/"; inputs.b.inputs.a.follows = "/";
@ -23,9 +23,9 @@ cat > $flakeA/flake.nix <<EOF
} }
EOF EOF
git -C $flakeA add flake.nix git -C "$flakeA" add flake.nix
cat > $flakeB/flake.nix <<EOF cat > "$flakeB"/flake.nix <<EOF
{ {
inputs.a.url = git+file://$flakeA; inputs.a.url = git+file://$flakeA;
@ -35,18 +35,18 @@ cat > $flakeB/flake.nix <<EOF
} }
EOF EOF
git -C $flakeB add flake.nix git -C "$flakeB" add flake.nix
git -C $flakeB commit -a -m 'Foo' git -C "$flakeB" commit -a -m 'Foo'
[[ $(nix eval $flakeA#foo) = 1579 ]] [[ $(nix eval "$flakeA#foo") = 1579 ]]
[[ $(nix eval $flakeA#foo) = 1579 ]] [[ $(nix eval "$flakeA#foo") = 1579 ]]
sed -i $flakeB/flake.nix -e 's/456/789/' sed -i "$flakeB"/flake.nix -e 's/456/789/'
git -C $flakeB commit -a -m 'Foo' git -C "$flakeB" commit -a -m 'Foo'
nix flake update b --flake $flakeA nix flake update b --flake "$flakeA"
[[ $(nix eval $flakeA#foo) = 1912 ]] [[ $(nix eval "$flakeA#foo") = 1912 ]]
# Test list-inputs with circular dependencies # Test list-inputs with circular dependencies
nix flake metadata $flakeA nix flake metadata "$flakeA"

View file

@ -27,8 +27,8 @@ rootRepo=$TEST_ROOT/rootRepo
subRepo=$TEST_ROOT/submodule subRepo=$TEST_ROOT/submodule
createGitRepo $subRepo createGitRepo "$subRepo"
cat > $subRepo/flake.nix <<EOF cat > "$subRepo"/flake.nix <<EOF
{ {
outputs = { self }: { outputs = { self }: {
sub = import ./sub.nix; sub = import ./sub.nix;
@ -36,28 +36,28 @@ cat > $subRepo/flake.nix <<EOF
}; };
} }
EOF EOF
echo '"expression in submodule"' > $subRepo/sub.nix echo '"expression in submodule"' > "$subRepo"/sub.nix
git -C $subRepo add flake.nix sub.nix git -C "$subRepo" add flake.nix sub.nix
git -C $subRepo commit -m Initial git -C "$subRepo" commit -m Initial
createGitRepo $rootRepo createGitRepo "$rootRepo"
git -C $rootRepo submodule init git -C "$rootRepo" submodule init
git -C $rootRepo submodule add $subRepo submodule git -C "$rootRepo" submodule add "$subRepo" submodule
echo '"expression in root repo"' > $rootRepo/root.nix echo '"expression in root repo"' > "$rootRepo"/root.nix
git -C $rootRepo add root.nix git -C "$rootRepo" add root.nix
git -C $rootRepo commit -m "Add root.nix" git -C "$rootRepo" commit -m "Add root.nix"
flakeref=git+file://$rootRepo\?submodules=1\&dir=submodule flakeref=git+file://$rootRepo\?submodules=1\&dir=submodule
# Flake can live inside a submodule and can be accessed via ?dir=submodule # Flake can live inside a submodule and can be accessed via ?dir=submodule
[[ $(nix eval --json $flakeref#sub ) = '"expression in submodule"' ]] [[ $(nix eval --json "$flakeref#sub" ) = '"expression in submodule"' ]]
# The flake can access content outside of the submodule # The flake can access content outside of the submodule
[[ $(nix eval --json $flakeref#root ) = '"expression in root repo"' ]] [[ $(nix eval --json "$flakeref#root" ) = '"expression in root repo"' ]]
# Check that dirtying a submodule makes the entire thing dirty. # Check that dirtying a submodule makes the entire thing dirty.
[[ $(nix flake metadata --json $flakeref | jq -r .locked.rev) != null ]] [[ $(nix flake metadata --json "$flakeref" | jq -r .locked.rev) != null ]]
echo '"foo"' > $rootRepo/submodule/sub.nix echo '"foo"' > "$rootRepo"/submodule/sub.nix
[[ $(nix eval --json $flakeref#sub ) = '"foo"' ]] [[ $(nix eval --json "$flakeref#sub" ) = '"foo"' ]]
[[ $(nix flake metadata --json $flakeref | jq -r .locked.rev) = null ]] [[ $(nix flake metadata --json "$flakeref" | jq -r .locked.rev) = null ]]

View file

@ -8,16 +8,16 @@ templatesDir=$TEST_ROOT/templates
flakeDir=$TEST_ROOT/flake flakeDir=$TEST_ROOT/flake
nixpkgsDir=$TEST_ROOT/nixpkgs nixpkgsDir=$TEST_ROOT/nixpkgs
nix registry add --registry $registry templates git+file://$templatesDir nix registry add --registry "$registry" templates "git+file://$templatesDir"
nix registry add --registry $registry nixpkgs git+file://$nixpkgsDir nix registry add --registry "$registry" nixpkgs "git+file://$nixpkgsDir"
createGitRepo $nixpkgsDir createGitRepo "$nixpkgsDir"
createSimpleGitFlake $nixpkgsDir createSimpleGitFlake "$nixpkgsDir"
# Test 'nix flake init'. # Test 'nix flake init'.
createGitRepo $templatesDir createGitRepo "$templatesDir"
cat > $templatesDir/flake.nix <<EOF cat > "$templatesDir"/flake.nix <<EOF
{ {
description = "Some templates"; description = "Some templates";
@ -36,9 +36,9 @@ cat > $templatesDir/flake.nix <<EOF
} }
EOF EOF
mkdir $templatesDir/trivial mkdir "$templatesDir/trivial"
cat > $templatesDir/trivial/flake.nix <<EOF cat > "$templatesDir"/trivial/flake.nix <<EOF
{ {
description = "A flake for building Hello World"; description = "A flake for building Hello World";
@ -50,40 +50,40 @@ cat > $templatesDir/trivial/flake.nix <<EOF
}; };
} }
EOF EOF
echo a > $templatesDir/trivial/a echo a > "$templatesDir/trivial/a"
echo b > $templatesDir/trivial/b echo b > "$templatesDir/trivial/b"
git -C $templatesDir add flake.nix trivial/ git -C "$templatesDir" add flake.nix trivial/
git -C $templatesDir commit -m 'Initial' git -C "$templatesDir" commit -m 'Initial'
nix flake check templates nix flake check templates
nix flake show templates nix flake show templates
nix flake show templates --json | jq nix flake show templates --json | jq
createGitRepo $flakeDir createGitRepo "$flakeDir"
(cd $flakeDir && nix flake init) (cd "$flakeDir" && nix flake init)
(cd $flakeDir && nix flake init) # check idempotence (cd "$flakeDir" && nix flake init) # check idempotence
git -C $flakeDir add flake.nix git -C "$flakeDir" add flake.nix
nix flake check $flakeDir nix flake check "$flakeDir"
nix flake show $flakeDir nix flake show "$flakeDir"
nix flake show $flakeDir --json | jq nix flake show "$flakeDir" --json | jq
git -C $flakeDir commit -a -m 'Initial' git -C "$flakeDir" commit -a -m 'Initial'
# Test 'nix flake init' with benign conflicts # Test 'nix flake init' with benign conflicts
createGitRepo "$flakeDir" createGitRepo "$flakeDir"
echo a > $flakeDir/a echo a > "$flakeDir/a"
(cd $flakeDir && nix flake init) # check idempotence (cd "$flakeDir" && nix flake init) # check idempotence
# Test 'nix flake init' with conflicts # Test 'nix flake init' with conflicts
createGitRepo "$flakeDir" createGitRepo "$flakeDir"
echo b > $flakeDir/a echo b > "$flakeDir/a"
pushd $flakeDir pushd "$flakeDir"
(! nix flake init) |& grep "refusing to overwrite existing file '$flakeDir/a'" (! nix flake init) |& grep "refusing to overwrite existing file '$flakeDir/a'"
popd popd
git -C $flakeDir commit -a -m 'Changed' git -C "$flakeDir" commit -a -m 'Changed'
# Test 'nix flake new'. # Test 'nix flake new'.
rm -rf $flakeDir rm -rf "$flakeDir"
nix flake new -t templates#trivial $flakeDir nix flake new -t templates#trivial "$flakeDir"
nix flake new -t templates#trivial $flakeDir # check idempotence nix flake new -t templates#trivial "$flakeDir" # check idempotence
nix flake check $flakeDir nix flake check "$flakeDir"

View file

@ -8,12 +8,12 @@ requireGit
test_subdir_self_path() { test_subdir_self_path() {
baseDir=$TEST_ROOT/$RANDOM baseDir=$TEST_ROOT/$RANDOM
flakeDir=$baseDir/b-low flakeDir=$baseDir/b-low
mkdir -p $flakeDir mkdir -p "$flakeDir"
writeSimpleFlake $baseDir writeSimpleFlake "$baseDir"
writeSimpleFlake $flakeDir writeSimpleFlake "$flakeDir"
echo all good > $flakeDir/message echo all good > "$flakeDir/message"
cat > $flakeDir/flake.nix <<EOF cat > "$flakeDir"/flake.nix <<EOF
{ {
outputs = inputs: rec { outputs = inputs: rec {
packages.$system = rec { packages.$system = rec {
@ -26,7 +26,7 @@ test_subdir_self_path() {
} }
EOF EOF
( (
nix build $baseDir?dir=b-low --no-link nix build "$baseDir"?dir=b-low --no-link
) )
} }
test_subdir_self_path test_subdir_self_path
@ -34,14 +34,14 @@ test_subdir_self_path
test_git_subdir_self_path() { test_git_subdir_self_path() {
repoDir=$TEST_ROOT/repo-$RANDOM repoDir=$TEST_ROOT/repo-$RANDOM
createGitRepo $repoDir createGitRepo "$repoDir"
flakeDir=$repoDir/b-low flakeDir=$repoDir/b-low
mkdir -p $flakeDir mkdir -p "$flakeDir"
writeSimpleFlake $repoDir writeSimpleFlake "$repoDir"
writeSimpleFlake $flakeDir writeSimpleFlake "$flakeDir"
echo all good > $flakeDir/message echo all good > "$flakeDir/message"
cat > $flakeDir/flake.nix <<EOF cat > "$flakeDir"/flake.nix <<EOF
{ {
outputs = inputs: rec { outputs = inputs: rec {
packages.$system = rec { packages.$system = rec {
@ -55,15 +55,15 @@ test_git_subdir_self_path() {
} }
EOF EOF
( (
cd $flakeDir cd "$flakeDir"
git add . git add .
git commit -m init git commit -m init
# nix build # nix build
) )
clientDir=$TEST_ROOT/client-$RANDOM clientDir=$TEST_ROOT/client-$RANDOM
mkdir -p $clientDir mkdir -p "$clientDir"
cat > $clientDir/flake.nix <<EOF cat > "$clientDir"/flake.nix <<EOF
{ {
inputs.inp = { inputs.inp = {
type = "git"; type = "git";
@ -76,7 +76,7 @@ EOF
}; };
} }
EOF EOF
nix build $clientDir --no-link nix build "$clientDir" --no-link
} }
test_git_subdir_self_path test_git_subdir_self_path

View file

@ -5,41 +5,41 @@ source ./common.sh
[[ $(type -p hg) ]] || skipTest "Mercurial not installed" [[ $(type -p hg) ]] || skipTest "Mercurial not installed"
flake1Dir=$TEST_ROOT/flake-hg1 flake1Dir=$TEST_ROOT/flake-hg1
mkdir -p $flake1Dir mkdir -p "$flake1Dir"
writeSimpleFlake $flake1Dir writeSimpleFlake "$flake1Dir"
hg init $flake1Dir hg init "$flake1Dir"
nix registry add --registry $registry flake1 hg+file://$flake1Dir nix registry add --registry "$registry" flake1 "hg+file://$flake1Dir"
flake2Dir=$TEST_ROOT/flake-hg2 flake2Dir=$TEST_ROOT/flake-hg2
mkdir -p $flake2Dir mkdir -p "$flake2Dir"
writeDependentFlake $flake2Dir writeDependentFlake "$flake2Dir"
hg init $flake2Dir hg init "$flake2Dir"
hg add $flake1Dir/* hg add "$flake1Dir"/*
hg commit --config ui.username=foobar@example.org $flake1Dir -m 'Initial commit' hg commit --config ui.username=foobar@example.org "$flake1Dir" -m 'Initial commit'
hg add $flake2Dir/flake.nix hg add "$flake2Dir"/flake.nix
hg commit --config ui.username=foobar@example.org $flake2Dir -m 'Initial commit' hg commit --config ui.username=foobar@example.org "$flake2Dir" -m 'Initial commit'
nix build -o $TEST_ROOT/result hg+file://$flake2Dir nix build -o "$TEST_ROOT/result" "hg+file://$flake2Dir"
[[ -e $TEST_ROOT/result/hello ]] [[ -e $TEST_ROOT/result/hello ]]
(! nix flake metadata --json hg+file://$flake2Dir | jq -e -r .revision) (! nix flake metadata --json "hg+file://$flake2Dir" | jq -e -r .revision)
nix eval hg+file://$flake2Dir#expr nix eval "hg+file://$flake2Dir"#expr
nix eval hg+file://$flake2Dir#expr nix eval "hg+file://$flake2Dir"#expr
(! nix eval hg+file://$flake2Dir#expr --no-allow-dirty) (! nix eval "hg+file://$flake2Dir"#expr --no-allow-dirty)
(! nix flake metadata --json hg+file://$flake2Dir | jq -e -r .revision) (! nix flake metadata --json "hg+file://$flake2Dir" | jq -e -r .revision)
hg commit --config ui.username=foobar@example.org $flake2Dir -m 'Add lock file' hg commit --config ui.username=foobar@example.org "$flake2Dir" -m 'Add lock file'
nix flake metadata --json hg+file://$flake2Dir --refresh | jq -e -r .revision nix flake metadata --json "hg+file://$flake2Dir" --refresh | jq -e -r .revision
nix flake metadata --json hg+file://$flake2Dir nix flake metadata --json "hg+file://$flake2Dir"
[[ $(nix flake metadata --json hg+file://$flake2Dir | jq -e -r .revCount) = 1 ]] [[ $(nix flake metadata --json "hg+file://$flake2Dir" | jq -e -r .revCount) = 1 ]]
nix build -o $TEST_ROOT/result hg+file://$flake2Dir --no-registries --no-allow-dirty nix build -o "$TEST_ROOT/result" "hg+file://$flake2Dir" --no-registries --no-allow-dirty
nix build -o $TEST_ROOT/result hg+file://$flake2Dir --no-use-registries --no-allow-dirty nix build -o "$TEST_ROOT/result" "hg+file://$flake2Dir" --no-use-registries --no-allow-dirty

View file

@ -4,8 +4,8 @@ source common.sh
clearStore clearStore
writeSimpleFlake $TEST_HOME writeSimpleFlake "$TEST_HOME"
cd $TEST_HOME cd "$TEST_HOME"
mkdir -p foo/subdir mkdir -p foo/subdir
echo '{ outputs = _: {}; }' > foo/flake.nix echo '{ outputs = _: {}; }' > foo/flake.nix
@ -27,11 +27,11 @@ success=("" . .# .#test ../subdir ../subdir#test "$PWD")
failure=("path:$PWD" "../simple.nix") failure=("path:$PWD" "../simple.nix")
for i in "${success[@]}"; do for i in "${success[@]}"; do
nix build $i || fail "flake should be found by searching up directories" nix build "$i" || fail "flake should be found by searching up directories"
done done
for i in "${failure[@]}"; do for i in "${failure[@]}"; do
! nix build $i || fail "flake should not search up directories when using 'path:'" ! nix build "$i" || fail "flake should not search up directories when using 'path:'"
done done
popd popd
@ -45,7 +45,7 @@ if [[ -n $(type -p git) ]]; then
pushd subdir pushd subdir
git init git init
for i in "${success[@]}" "${failure[@]}"; do for i in "${success[@]}" "${failure[@]}"; do
! nix build $i || fail "flake should not search past a git repository" ! nix build "$i" || fail "flake should not search past a git repository"
done done
rm -rf .git rm -rf .git
popd popd

View file

@ -7,26 +7,26 @@ requireGit
flake1Dir=$TEST_ROOT/flake1 flake1Dir=$TEST_ROOT/flake1
flake2Dir=$TEST_ROOT/flake2 flake2Dir=$TEST_ROOT/flake2
createGitRepo $flake1Dir createGitRepo "$flake1Dir"
cat > $flake1Dir/flake.nix <<EOF cat > "$flake1Dir"/flake.nix <<EOF
{ {
outputs = { self }: { x = import ./x.nix; }; outputs = { self }: { x = import ./x.nix; };
} }
EOF EOF
echo 123 > $flake1Dir/x.nix echo 123 > "$flake1Dir"/x.nix
git -C $flake1Dir add flake.nix x.nix git -C "$flake1Dir" add flake.nix x.nix
git -C $flake1Dir commit -m Initial git -C "$flake1Dir" commit -m Initial
createGitRepo $flake2Dir createGitRepo "$flake2Dir"
cat > $flake2Dir/flake.nix <<EOF cat > "$flake2Dir"/flake.nix <<EOF
{ {
outputs = { self, flake1 }: { x = flake1.x; }; outputs = { self, flake1 }: { x = flake1.x; };
} }
EOF EOF
git -C $flake2Dir add flake.nix git -C "$flake2Dir" add flake.nix
[[ $(nix eval --json $flake2Dir#x --override-input flake1 $TEST_ROOT/flake1) = 123 ]] [[ $(nix eval --json "$flake2Dir#x" --override-input flake1 "$TEST_ROOT/flake1") = 123 ]]
echo 456 > $flake1Dir/x.nix echo 456 > "$flake1Dir"/x.nix
[[ $(nix eval --json $flake2Dir#x --override-input flake1 $TEST_ROOT/flake1) = 456 ]] [[ $(nix eval --json "$flake2Dir#x" --override-input flake1 "$TEST_ROOT/flake1") = 456 ]]

View file

@ -21,12 +21,12 @@ expect_trace() {
<(echo "$expect") \ <(echo "$expect") \
<(echo "$actual") <(echo "$actual")
) && result=0 || result=$? ) && result=0 || result=$?
if [ $result -eq 0 ]; then if [ "$result" -eq 0 ]; then
echo " ok." echo " ok."
else else
echo " failed. difference:" echo " failed. difference:"
echo "$msg" echo "$msg"
return $result return "$result"
fi fi
} }

View file

@ -20,8 +20,8 @@ outPath3=$(nix-store -r $drvPath3)
touch $outPath3.lock touch $outPath3.lock
rm -f "$NIX_STATE_DIR"/gcroots/foo* rm -f "$NIX_STATE_DIR"/gcroots/foo*
ln -s $drvPath2 "$NIX_STATE_DIR"/gcroots/foo ln -s $drvPath2 "$NIX_STATE_DIR/gcroots/foo"
ln -s $outPath3 "$NIX_STATE_DIR"/gcroots/foo2 ln -s $outPath3 "$NIX_STATE_DIR/gcroots/foo2"
# Start build #1 in the background. It starts immediately. # Start build #1 in the background. It starts immediately.
nix-store -rvv "$drvPath1" & nix-store -rvv "$drvPath1" &

View file

@ -12,27 +12,27 @@ esac
set -m # enable job control, needed for kill set -m # enable job control, needed for kill
profiles="$NIX_STATE_DIR"/profiles profiles="$NIX_STATE_DIR"/profiles
rm -rf $profiles rm -rf "$profiles"
nix-env -p $profiles/test -f ./gc-runtime.nix -i gc-runtime nix-env -p "$profiles/test" -f ./gc-runtime.nix -i gc-runtime
outPath=$(nix-env -p $profiles/test -q --no-name --out-path gc-runtime) outPath=$(nix-env -p "$profiles/test" -q --no-name --out-path gc-runtime)
echo $outPath echo "$outPath"
echo "backgrounding program..." echo "backgrounding program..."
$profiles/test/program & "$profiles"/test/program &
sleep 2 # hack - wait for the program to get started sleep 2 # hack - wait for the program to get started
child=$! child=$!
echo PID=$child echo PID=$child
nix-env -p $profiles/test -e gc-runtime nix-env -p "$profiles/test" -e gc-runtime
nix-env -p $profiles/test --delete-generations old nix-env -p "$profiles/test" --delete-generations old
nix-store --gc nix-store --gc
kill -- -$child kill -- -$child
if ! test -e $outPath; then if ! test -e "$outPath"; then
echo "running program was garbage collected!" echo "running program was garbage collected!"
exit 1 exit 1
fi fi

View file

@ -8,8 +8,8 @@ drvPath=$(nix-instantiate dependencies.nix)
outPath=$(nix-store -rvv "$drvPath") outPath=$(nix-store -rvv "$drvPath")
# Set a GC root. # Set a GC root.
rm -f "$NIX_STATE_DIR"/gcroots/foo rm -f "$NIX_STATE_DIR/gcroots/foo"
ln -sf $outPath "$NIX_STATE_DIR"/gcroots/foo ln -sf $outPath "$NIX_STATE_DIR/gcroots/foo"
[ "$(nix-store -q --roots $outPath)" = "$NIX_STATE_DIR/gcroots/foo -> $outPath" ] [ "$(nix-store -q --roots $outPath)" = "$NIX_STATE_DIR/gcroots/foo -> $outPath" ]
@ -42,7 +42,7 @@ cat $outPath/reference-to-input-2/bar
# Check that the derivation has been GC'd. # Check that the derivation has been GC'd.
if test -e $drvPath; then false; fi if test -e $drvPath; then false; fi
rm "$NIX_STATE_DIR"/gcroots/foo rm "$NIX_STATE_DIR/gcroots/foo"
nix-collect-garbage nix-collect-garbage

View file

@ -3,7 +3,7 @@
source common.sh source common.sh
try () { try () {
printf "%s" "$2" > $TEST_ROOT/vector printf "%s" "$2" > "$TEST_ROOT/vector"
hash="$(nix-hash --flat ${FORMAT+--$FORMAT} --type "$1" "$TEST_ROOT/vector")" hash="$(nix-hash --flat ${FORMAT+--$FORMAT} --type "$1" "$TEST_ROOT/vector")"
if ! (( "${NO_TEST_CLASSIC-}" )) && test "$hash" != "$3"; then if ! (( "${NO_TEST_CLASSIC-}" )) && test "$hash" != "$3"; then
echo "try nix-hash: hash $1, expected $3, got $hash" echo "try nix-hash: hash $1, expected $3, got $hash"
@ -61,7 +61,7 @@ NO_TEST_NIX_COMMAND=1 try sha512 "abc" "ddaf35a193617abacc417349ae20413112e6fa4e
NO_TEST_CLASSIC=1 try sha512 "abc" "sha512-3a81oZNherrMQXNJriBBMRLm+k6JqX6iCp7u5ktV05ohkpkqJ0/BqDa6PCOj/uu9RU1EI2Q86A4qmslPpUyknw==" NO_TEST_CLASSIC=1 try sha512 "abc" "sha512-3a81oZNherrMQXNJriBBMRLm+k6JqX6iCp7u5ktV05ohkpkqJ0/BqDa6PCOj/uu9RU1EI2Q86A4qmslPpUyknw=="
try2 () { try2 () {
hash=$(nix-hash --type "$1" $TEST_ROOT/hash-path) hash=$(nix-hash --type "$1" "$TEST_ROOT/hash-path")
if test "$hash" != "$2"; then if test "$hash" != "$2"; then
echo "try nix-hash; hash $1, expected $2, got $hash" echo "try nix-hash; hash $1, expected $2, got $hash"
exit 1 exit 1
@ -73,22 +73,22 @@ try2 () {
fi fi
} }
rm -rf $TEST_ROOT/hash-path rm -rf "$TEST_ROOT/hash-path"
mkdir $TEST_ROOT/hash-path mkdir "$TEST_ROOT/hash-path"
echo "Hello World" > $TEST_ROOT/hash-path/hello echo "Hello World" > "$TEST_ROOT/hash-path/hello"
try2 md5 "ea9b55537dd4c7e104515b2ccfaf4100" try2 md5 "ea9b55537dd4c7e104515b2ccfaf4100"
# Execute bit matters. # Execute bit matters.
chmod +x $TEST_ROOT/hash-path/hello chmod +x "$TEST_ROOT/hash-path/hello"
try2 md5 "20f3ffe011d4cfa7d72bfabef7882836" try2 md5 "20f3ffe011d4cfa7d72bfabef7882836"
# Mtime and other bits don't. # Mtime and other bits don't.
touch -r . $TEST_ROOT/hash-path/hello touch -r . "$TEST_ROOT/hash-path/hello"
chmod 744 $TEST_ROOT/hash-path/hello chmod 744 "$TEST_ROOT/hash-path/hello"
try2 md5 "20f3ffe011d4cfa7d72bfabef7882836" try2 md5 "20f3ffe011d4cfa7d72bfabef7882836"
# File type (e.g., symlink) does. # File type (e.g., symlink) does.
rm $TEST_ROOT/hash-path/hello rm "$TEST_ROOT/hash-path/hello"
ln -s x $TEST_ROOT/hash-path/hello ln -s x "$TEST_ROOT/hash-path/hello"
try2 md5 "f78b733a68f5edbdf9413899339eaa4a" try2 md5 "f78b733a68f5edbdf9413899339eaa4a"

View file

@ -11,4 +11,4 @@ fi
outPath=$(nix-build ./import-derivation.nix --no-out-link) outPath=$(nix-build ./import-derivation.nix --no-out-link)
[ "$(cat $outPath)" = FOO579 ] [ "$(cat "$outPath")" = FOO579 ]

View file

@ -29,7 +29,7 @@ error:
| ^ | ^
2| 2|
(19997 duplicate frames omitted) (197 duplicate frames omitted)
error: stack overflow; max-call-depth exceeded error: stack overflow; max-call-depth exceeded
at /pwd/lang/eval-fail-infinite-recursion-lambda.nix:1:14: at /pwd/lang/eval-fail-infinite-recursion-lambda.nix:1:14:

View file

@ -0,0 +1 @@
--max-call-depth 100

View file

@ -20,8 +20,8 @@ outPath=$(nix-build ../hermetic.nix --no-out-link --arg busybox "$busybox" --arg
# Set a GC root. # Set a GC root.
mkdir -p "$stateB" mkdir -p "$stateB"
rm -f "$stateB"/gcroots/foo rm -f "$stateB/gcroots/foo"
ln -sf $outPath "$stateB"/gcroots/foo ln -sf $outPath "$stateB/gcroots/foo"
[ "$(nix-store -q --roots $outPath)" = "$stateB/gcroots/foo -> $outPath" ] [ "$(nix-store -q --roots $outPath)" = "$stateB/gcroots/foo -> $outPath" ]
@ -46,7 +46,7 @@ nix-collect-garbage
# Check that the root and its dependencies haven't been deleted. # Check that the root and its dependencies haven't been deleted.
cat "$storeBRoot/$outPath" cat "$storeBRoot/$outPath"
rm "$stateB"/gcroots/foo rm "$stateB/gcroots/foo"
nix-collect-garbage nix-collect-garbage

View file

@ -35,7 +35,7 @@ outPath=$(nix-store -q $drvPath)
echo "building b..." echo "building b..."
outPath=$(nix-build multiple-outputs.nix -A b --no-out-link) outPath=$(nix-build multiple-outputs.nix -A b --no-out-link)
echo "output path is $outPath" echo "output path is $outPath"
[ "$(cat "$outPath"/file)" = "success" ] [ "$(cat "$outPath/file")" = "success" ]
# Test nix-build on a derivation with multiple outputs. # Test nix-build on a derivation with multiple outputs.
outPath1=$(nix-build multiple-outputs.nix -A a -o $TEST_ROOT/result) outPath1=$(nix-build multiple-outputs.nix -A a -o $TEST_ROOT/result)

Some files were not shown because too many files have changed in this diff Show more