Compare commits
75 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a3d874175c | ||
|
|
bb6e6923f2 | ||
|
|
41ba5135e0 | ||
|
|
2bc6304793 | ||
|
|
2f59b30251 | ||
|
|
f32fbf952d | ||
|
|
e489f5cabf | ||
|
|
6e9e34ea1f | ||
|
|
75ec68f93a | ||
|
|
5c05c238e6 | ||
|
|
63e7fc5096 | ||
|
|
1f9c8cd68b | ||
|
|
42e2d5e7b7 | ||
|
|
0bebca402a | ||
|
|
6f0359012c | ||
|
|
514b3c7f83 | ||
|
|
56f1ed5579 | ||
|
|
2aa89daab3 | ||
|
|
6a3dfcb623 | ||
|
|
6f093073b6 | ||
|
|
ffeabf8390 | ||
|
|
684c7fff80 | ||
|
|
806291d18c | ||
|
|
81a23fa7e2 | ||
|
|
caf297a9d3 | ||
|
|
34fade478a | ||
|
|
1f64f4c7c8 | ||
|
|
ef52ccf035 | ||
|
|
86f3b94c8c | ||
|
|
578ed7a259 | ||
|
|
53522cb6ac | ||
|
|
a3f37d87ea | ||
|
|
115e2c8c67 | ||
|
|
4f4391193c | ||
|
|
38ee16ae9c | ||
|
|
9d7221183a | ||
|
|
9d87e3fbd2 | ||
|
|
5c56570726 | ||
|
|
fc02b1b3ee | ||
|
|
8574b70342 | ||
|
|
ebc86550f9 | ||
|
|
a17f86ce3a | ||
|
|
43331d6344 | ||
|
|
5886bc5996 | ||
|
|
fff8db205c | ||
|
|
b71e1fb342 | ||
|
|
4cfc131ec4 | ||
|
|
0963479741 | ||
|
|
ad6dbecc1d | ||
|
|
ebd4d50e6e | ||
|
|
06d6335987 | ||
|
|
ac200c3678 | ||
|
|
56c18c67d9 | ||
|
|
07f992a74b | ||
|
|
d7a7a029ff | ||
|
|
6bfb082ea2 | ||
|
|
b402148d8f | ||
|
|
e58a71442a | ||
|
|
d8fe447139 | ||
|
|
25722bd39a | ||
|
|
7ce1fae59f | ||
|
|
7a7ec22298 | ||
|
|
8ac1130cc2 | ||
|
|
01d07b1e92 | ||
|
|
b30be6b450 | ||
|
|
5f1891b795 | ||
|
|
92d08c02c8 | ||
|
|
15efd54373 | ||
|
|
7cc1a2593e | ||
|
|
df03430586 | ||
|
|
2ae5624b2f | ||
|
|
1d757292d0 | ||
|
|
087be7281a | ||
|
|
4ae6e84901 | ||
|
|
8ce1986611 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -81,6 +81,9 @@ perl/Makefile.config
|
||||
/tests/common.sh
|
||||
/tests/dummy
|
||||
/tests/result*
|
||||
/tests/restricted-innocent
|
||||
/tests/shell
|
||||
/tests/shell.drv
|
||||
|
||||
# /tests/lang/
|
||||
/tests/lang/*.out
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
AR = @AR@
|
||||
BDW_GC_LIBS = @BDW_GC_LIBS@
|
||||
BUILD_SHARED_LIBS = @BUILD_SHARED_LIBS@
|
||||
CC = @CC@
|
||||
CFLAGS = @CFLAGS@
|
||||
CXX = @CXX@
|
||||
|
||||
14
configure.ac
14
configure.ac
@@ -1,4 +1,4 @@
|
||||
AC_INIT(nix, m4_esyscmd([bash -c "echo -n $(cat ./version)$VERSION_SUFFIX"]))
|
||||
AC_INIT(nix, m4_esyscmd([bash -c "echo -n $(cat ./.version)$VERSION_SUFFIX"]))
|
||||
AC_CONFIG_SRCDIR(README.md)
|
||||
AC_CONFIG_AUX_DIR(config)
|
||||
|
||||
@@ -62,8 +62,9 @@ CXXFLAGS=
|
||||
AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
AC_PROG_CPP
|
||||
AX_CXX_COMPILE_STDCXX_14
|
||||
AX_CXX_COMPILE_STDCXX_17
|
||||
|
||||
AC_CHECK_TOOL([AR], [ar])
|
||||
|
||||
# Use 64-bit file system calls so that we can support files > 2 GiB.
|
||||
AC_SYS_LARGEFILE
|
||||
@@ -267,6 +268,15 @@ AC_ARG_WITH(sandbox-shell, AC_HELP_STRING([--with-sandbox-shell=PATH],
|
||||
sandbox_shell=$withval)
|
||||
AC_SUBST(sandbox_shell)
|
||||
|
||||
AC_ARG_ENABLE(shared, AC_HELP_STRING([--enable-shared],
|
||||
[Build shared libraries for Nix [default=yes]]),
|
||||
shared=$enableval, shared=yes)
|
||||
if test "$shared" = yes; then
|
||||
AC_SUBST(BUILD_SHARED_LIBS, 1, [Whether to build shared libraries.])
|
||||
else
|
||||
AC_SUBST(BUILD_SHARED_LIBS, 0, [Whether to build shared libraries.])
|
||||
fi
|
||||
|
||||
|
||||
# Expand all variables in config.status.
|
||||
test "$prefix" = NONE && prefix=$ac_default_prefix
|
||||
|
||||
@@ -180,4 +180,8 @@ builders = @/etc/nix/machines
|
||||
causes the list of machines in <filename>/etc/nix/machines</filename>
|
||||
to be included. (This is the default.)</para>
|
||||
|
||||
<para>If you want the builders to use caches, you likely want to set
|
||||
the option <link linkend='conf-builders-use-substitutes'><literal>builders-use-substitutes</literal></link>
|
||||
in your local <filename>nix.conf</filename>.</para>
|
||||
|
||||
</chapter>
|
||||
|
||||
@@ -657,7 +657,8 @@ password <replaceable>my-password</replaceable>
|
||||
<varname>__noChroot</varname> attribute set to
|
||||
<literal>true</literal> do not run in sandboxes.</para>
|
||||
|
||||
<para>The default is <literal>false</literal>.</para>
|
||||
<para>The default is <literal>true</literal> on Linux and
|
||||
<literal>false</literal> on all other platforms.</para>
|
||||
|
||||
</listitem>
|
||||
|
||||
|
||||
@@ -52,10 +52,15 @@ nixpkgs=/home/eelco/Dev/nixpkgs-branch:/etc/nixos</screen>
|
||||
<envar>NIX_PATH</envar> to
|
||||
|
||||
<screen>
|
||||
nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/nixos-14.12.tar.gz</screen>
|
||||
nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/nixos-15.09.tar.gz</screen>
|
||||
|
||||
tells Nix to download the latest revision in the Nixpkgs/NixOS
|
||||
14.12 channel.</para>
|
||||
15.09 channel.</para>
|
||||
|
||||
<para>A following shorthand can be used to refer to the official channels:
|
||||
|
||||
<screen>nixpkgs=channel:nixos-15.09</screen>
|
||||
</para>
|
||||
|
||||
<para>The search path can be extended using the <option
|
||||
linkend="opt-I">-I</option> option, which takes precedence over
|
||||
|
||||
@@ -337,7 +337,7 @@ following Haskell script uses a specific branch of Nixpkgs/NixOS (the
|
||||
|
||||
<programlisting><![CDATA[
|
||||
#! /usr/bin/env nix-shell
|
||||
#! nix-shell -i runghc -p haskellPackages.ghc haskellPackages.HTTP haskellPackages.tagsoup
|
||||
#! nix-shell -i runghc -p "haskellPackages.ghcWithPackages (ps: [ps.HTTP ps.tagsoup])"
|
||||
#! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/nixos-18.03.tar.gz
|
||||
|
||||
import Network.HTTP
|
||||
|
||||
@@ -1282,6 +1282,7 @@ ktorrent-2.2.1/NEWS
|
||||
<cmdsynopsis>
|
||||
<command>nix-store</command>
|
||||
<arg choice='plain'><option>--dump-db</option></arg>
|
||||
<arg rep='repeat'><replaceable>paths</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsection>
|
||||
|
||||
@@ -1292,6 +1293,13 @@ Nix database to standard output. It can be loaded into an empty Nix
|
||||
store using <option>--load-db</option>. This is useful for making
|
||||
backups and when migrating to different database schemas.</para>
|
||||
|
||||
<para>By default, <option>--dump-db</option> will dump the entire Nix
|
||||
database. When one or more store paths is passed, only the subset of
|
||||
the Nix database for those store paths is dumped. As with
|
||||
<option>--export</option>, the user is responsible for passing all the
|
||||
store paths for a closure. See <option>--export</option> for an
|
||||
example.</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
</refsection>
|
||||
|
||||
@@ -23,6 +23,7 @@ available as <function>builtins.derivation</function>.</para>
|
||||
|
||||
<varlistentry xml:id='builtin-abort'>
|
||||
<term><function>abort</function> <replaceable>s</replaceable></term>
|
||||
<term><function>builtins.abort</function> <replaceable>s</replaceable></term>
|
||||
|
||||
<listitem><para>Abort Nix expression evaluation, print error
|
||||
message <replaceable>s</replaceable>.</para></listitem>
|
||||
@@ -251,6 +252,8 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
|
||||
<varlistentry xml:id='builtin-derivation'>
|
||||
<term><function>derivation</function>
|
||||
<replaceable>attrs</replaceable></term>
|
||||
<term><function>builtins.derivation</function>
|
||||
<replaceable>attrs</replaceable></term>
|
||||
|
||||
<listitem><para><function>derivation</function> is described in
|
||||
<xref linkend='ssec-derivation' />.</para></listitem>
|
||||
@@ -260,6 +263,7 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
|
||||
|
||||
<varlistentry xml:id='builtin-dirOf'>
|
||||
<term><function>dirOf</function> <replaceable>s</replaceable></term>
|
||||
<term><function>builtins.dirOf</function> <replaceable>s</replaceable></term>
|
||||
|
||||
<listitem><para>Return the directory part of the string
|
||||
<replaceable>s</replaceable>, that is, everything before the final
|
||||
@@ -318,6 +322,8 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
|
||||
<varlistentry xml:id='builtin-fetchTarball'>
|
||||
<term><function>fetchTarball</function>
|
||||
<replaceable>url</replaceable></term>
|
||||
<term><function>builtins.fetchTarball</function>
|
||||
<replaceable>url</replaceable></term>
|
||||
|
||||
<listitem><para>Download the specified URL, unpack it and return
|
||||
the path of the unpacked tree. The file must be a tape archive
|
||||
@@ -693,8 +699,8 @@ builtins.genList (x: x * x) 5
|
||||
<listitem><para>Return a base-16 representation of the
|
||||
cryptographic hash of string <replaceable>s</replaceable>. The
|
||||
hash algorithm specified by <replaceable>type</replaceable> must
|
||||
be one of <literal>"md5"</literal>, <literal>"sha1"</literal> or
|
||||
<literal>"sha256"</literal>.</para></listitem>
|
||||
be one of <literal>"md5"</literal>, <literal>"sha1"</literal>,
|
||||
<literal>"sha256"</literal> or <literal>"sha512"</literal>.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
@@ -714,6 +720,8 @@ builtins.genList (x: x * x) 5
|
||||
<varlistentry xml:id='builtin-import'>
|
||||
<term><function>import</function>
|
||||
<replaceable>path</replaceable></term>
|
||||
<term><function>builtins.import</function>
|
||||
<replaceable>path</replaceable></term>
|
||||
|
||||
<listitem><para>Load, parse and return the Nix expression in the
|
||||
file <replaceable>path</replaceable>. If <replaceable>path
|
||||
@@ -853,10 +861,20 @@ x: x + 456</programlisting>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><function>builtins.isPath</function>
|
||||
<replaceable>e</replaceable></term>
|
||||
|
||||
<listitem><para>Return <literal>true</literal> if
|
||||
<replaceable>e</replaceable> evaluates to a path, and
|
||||
<literal>false</literal> otherwise.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry xml:id='builtin-isNull'>
|
||||
<term><function>isNull</function>
|
||||
<replaceable>e</replaceable></term>
|
||||
<term><function>builtins.isNull</function>
|
||||
<replaceable>e</replaceable></term>
|
||||
|
||||
<listitem><para>Return <literal>true</literal> if
|
||||
<replaceable>e</replaceable> evaluates to <literal>null</literal>,
|
||||
@@ -925,6 +943,8 @@ builtins.listToAttrs
|
||||
<varlistentry xml:id='builtin-map'>
|
||||
<term><function>map</function>
|
||||
<replaceable>f</replaceable> <replaceable>list</replaceable></term>
|
||||
<term><function>builtins.map</function>
|
||||
<replaceable>f</replaceable> <replaceable>list</replaceable></term>
|
||||
|
||||
<listitem><para>Apply the function <replaceable>f</replaceable> to
|
||||
each element in the list <replaceable>list</replaceable>. For
|
||||
@@ -1119,6 +1139,8 @@ Evaluates to <literal>[ "foo" ]</literal>.
|
||||
<varlistentry xml:id='builtin-removeAttrs'>
|
||||
<term><function>removeAttrs</function>
|
||||
<replaceable>set</replaceable> <replaceable>list</replaceable></term>
|
||||
<term><function>builtins.removeAttrs</function>
|
||||
<replaceable>set</replaceable> <replaceable>list</replaceable></term>
|
||||
|
||||
<listitem><para>Remove the attributes listed in
|
||||
<replaceable>list</replaceable> from
|
||||
@@ -1287,6 +1309,8 @@ builtins.substring 0 3 "nixos"
|
||||
<varlistentry xml:id='builtin-throw'>
|
||||
<term><function>throw</function>
|
||||
<replaceable>s</replaceable></term>
|
||||
<term><function>builtins.throw</function>
|
||||
<replaceable>s</replaceable></term>
|
||||
|
||||
<listitem><para>Throw an error message
|
||||
<replaceable>s</replaceable>. This usually aborts Nix expression
|
||||
@@ -1405,6 +1429,7 @@ in foo</programlisting>
|
||||
|
||||
<varlistentry xml:id='builtin-toString'>
|
||||
<term><function>toString</function> <replaceable>e</replaceable></term>
|
||||
<term><function>builtins.toString</function> <replaceable>e</replaceable></term>
|
||||
|
||||
<listitem><para>Convert the expression
|
||||
<replaceable>e</replaceable> to a string.
|
||||
|
||||
@@ -89,7 +89,7 @@ the S3 URL:</para>
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "AlowDirectReads",
|
||||
"Sid": "AllowDirectReads",
|
||||
"Action": [
|
||||
"s3:GetObject",
|
||||
"s3:GetBucketLocation"
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>OBJC_DISABLE_INITIALIZE_FORK_SAFETY</key>
|
||||
<string>YES</string>
|
||||
</dict>
|
||||
<key>Label</key>
|
||||
<string>org.nixos.nix-daemon</string>
|
||||
<key>KeepAlive</key>
|
||||
|
||||
@@ -125,7 +125,7 @@ define build-library
|
||||
$(1)_PATH := $$(_d)/$$($(1)_NAME).a
|
||||
|
||||
$$($(1)_PATH): $$($(1)_OBJS) | $$(_d)/
|
||||
$(trace-ar) ar crs $$@ $$?
|
||||
$(trace-ar) $(AR) crs $$@ $$?
|
||||
|
||||
$(1)_LDFLAGS_USE += $$($(1)_PATH) $$($(1)_LDFLAGS)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
AC_INIT(nix-perl, m4_esyscmd([bash -c "echo -n $(cat ../version)$VERSION_SUFFIX"]))
|
||||
AC_INIT(nix-perl, m4_esyscmd([bash -c "echo -n $(cat ../.version)$VERSION_SUFFIX"]))
|
||||
AC_CONFIG_SRCDIR(MANIFEST)
|
||||
AC_CONFIG_AUX_DIR(../config)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{ nix ? builtins.fetchGit ./.
|
||||
, nixpkgs ? builtins.fetchGit { url = https://github.com/NixOS/nixpkgs-channels.git; ref = "nixos-18.09"; }
|
||||
, nixpkgs ? builtins.fetchGit { url = https://github.com/NixOS/nixpkgs-channels.git; ref = "nixos-19.03"; }
|
||||
, officialRelease ? false
|
||||
, systems ? [ "x86_64-linux" "i686-linux" "x86_64-darwin" "aarch64-linux" ]
|
||||
}:
|
||||
@@ -18,7 +18,7 @@ let
|
||||
|
||||
releaseTools.sourceTarball {
|
||||
name = "nix-tarball";
|
||||
version = builtins.readFile ./version;
|
||||
version = builtins.readFile ./.version;
|
||||
versionSuffix = if officialRelease then "" else "pre${toString nix.revCount}_${nix.shortRev}";
|
||||
src = nix;
|
||||
inherit officialRelease;
|
||||
@@ -278,7 +278,6 @@ let
|
||||
pkgs.runCommand "eval-nixos" { buildInputs = [ build.x86_64-linux ]; }
|
||||
''
|
||||
export NIX_STATE_DIR=$TMPDIR
|
||||
nix-store --init
|
||||
|
||||
nix-instantiate ${nixpkgs}/nixos/release-combined.nix -A tested --dry-run \
|
||||
--arg nixpkgs '{ outPath = ${nixpkgs}; revCount = 123; shortRev = "abcdefgh"; }'
|
||||
@@ -296,7 +295,7 @@ let
|
||||
|
||||
substitute ${./scripts/install.in} $out/install \
|
||||
${pkgs.lib.concatMapStrings
|
||||
(system: "--replace '@binaryTarball_${system}@' $(nix hash-file --type sha256 ${binaryTarball.${system}}/*.tar.bz2) ")
|
||||
(system: "--replace '@binaryTarball_${system}@' $(nix hash-file --base16 --type sha256 ${binaryTarball.${system}}/*.tar.bz2) ")
|
||||
[ "x86_64-linux" "i686-linux" "x86_64-darwin" "aarch64-linux" ]
|
||||
} \
|
||||
--replace '@nixVersion@' ${build.x86_64-linux.src.version}
|
||||
|
||||
@@ -674,9 +674,6 @@ $NIX_INSTALLED_NIX.
|
||||
EOF
|
||||
fi
|
||||
|
||||
_sudo "to initialize the Nix Database" \
|
||||
$NIX_INSTALLED_NIX/bin/nix-store --init
|
||||
|
||||
cat ./.reginfo \
|
||||
| _sudo "to load data for the first time in to the Nix Database" \
|
||||
"$NIX_INSTALLED_NIX/bin/nix-store" --load-db
|
||||
@@ -747,7 +744,6 @@ build-users-group = $NIX_BUILD_GROUP_NAME
|
||||
|
||||
max-jobs = $NIX_USER_COUNT
|
||||
cores = 1
|
||||
sandbox = false
|
||||
EOF
|
||||
_sudo "to place the default nix daemon configuration (part 2)" \
|
||||
install -m 0664 "$SCRATCH/nix.conf" /etc/nix/nix.conf
|
||||
|
||||
@@ -109,12 +109,6 @@ for i in $(cd "$self/store" >/dev/null && echo ./*); do
|
||||
done
|
||||
echo "" >&2
|
||||
|
||||
echo "initialising Nix database..." >&2
|
||||
if ! $nix/bin/nix-store --init; then
|
||||
echo "$0: failed to initialize the Nix database" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! "$nix/bin/nix-store" --load-db < "$self/.reginfo"; then
|
||||
echo "$0: unable to register valid paths" >&2
|
||||
exit 1
|
||||
|
||||
@@ -75,7 +75,7 @@ if [ -n "$HOME" ] && [ -n "$USER" ]; then
|
||||
export NIX_SSL_CERT_FILE="$NIX_LINK/etc/ca-bundle.crt"
|
||||
fi
|
||||
|
||||
if [ -n "${MANPATH}" ]; then
|
||||
if [ -n "${MANPATH-}" ]; then
|
||||
export MANPATH="$NIX_LINK/share/man:$MANPATH"
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{ useClang ? false }:
|
||||
|
||||
with import (builtins.fetchGit { url = https://github.com/NixOS/nixpkgs-channels.git; ref = "nixos-18.09"; }) {};
|
||||
with import (builtins.fetchGit { url = https://github.com/NixOS/nixpkgs-channels.git; ref = "nixos-19.03"; }) {};
|
||||
|
||||
with import ./release-common.nix { inherit pkgs; };
|
||||
|
||||
|
||||
@@ -38,6 +38,12 @@ static AutoCloseFD openSlotLock(const Machine & m, unsigned long long slot)
|
||||
return openLockFile(fmt("%s/%s-%d", currentLoad, escapeUri(m.storeUri), slot), true);
|
||||
}
|
||||
|
||||
static bool allSupportedLocally(const std::set<std::string>& requiredFeatures) {
|
||||
for (auto & feature : requiredFeatures)
|
||||
if (!settings.systemFeatures.get().count(feature)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int _main(int argc, char * * argv)
|
||||
{
|
||||
{
|
||||
@@ -97,9 +103,10 @@ static int _main(int argc, char * * argv)
|
||||
source >> drvPath;
|
||||
auto requiredFeatures = readStrings<std::set<std::string>>(source);
|
||||
|
||||
auto canBuildLocally = amWilling
|
||||
&& ( neededSystem == settings.thisSystem
|
||||
|| settings.extraPlatforms.get().count(neededSystem) > 0);
|
||||
auto canBuildLocally = amWilling
|
||||
&& ( neededSystem == settings.thisSystem
|
||||
|| settings.extraPlatforms.get().count(neededSystem) > 0)
|
||||
&& allSupportedLocally(requiredFeatures);
|
||||
|
||||
/* Error ignored here, will be caught later */
|
||||
mkdir(currentLoad.c_str(), 0777);
|
||||
|
||||
@@ -130,6 +130,16 @@ std::ostream & operator << (std::ostream & str, const Value & v)
|
||||
}
|
||||
|
||||
|
||||
const Value *getPrimOp(const Value &v) {
|
||||
const Value * primOp = &v;
|
||||
while (primOp->type == tPrimOpApp) {
|
||||
primOp = primOp->primOpApp.left;
|
||||
}
|
||||
assert(primOp->type == tPrimOp);
|
||||
return primOp;
|
||||
}
|
||||
|
||||
|
||||
string showType(const Value & v)
|
||||
{
|
||||
switch (v.type) {
|
||||
@@ -144,8 +154,10 @@ string showType(const Value & v)
|
||||
case tApp: return "a function application";
|
||||
case tLambda: return "a function";
|
||||
case tBlackhole: return "a black hole";
|
||||
case tPrimOp: return "a built-in function";
|
||||
case tPrimOpApp: return "a partially applied built-in function";
|
||||
case tPrimOp:
|
||||
return fmt("the built-in function '%s'", string(v.primOp->name));
|
||||
case tPrimOpApp:
|
||||
return fmt("the partially applied built-in function '%s'", string(getPrimOp(v)->primOp->name));
|
||||
case tExternal: return v.external->showType();
|
||||
case tFloat: return "a float";
|
||||
}
|
||||
@@ -1799,6 +1811,7 @@ void EvalState::printStats()
|
||||
gc.attr("totalBytes", totalBytes);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (countCalls) {
|
||||
{
|
||||
auto obj = topObj.object("primops");
|
||||
@@ -1834,6 +1847,11 @@ void EvalState::printStats()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (getEnv("NIX_SHOW_SYMBOLS", "0") != "0") {
|
||||
auto list = topObj.list("symbols");
|
||||
symbols.dump([&](const std::string & s) { list.elem(s); });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ public:
|
||||
|
||||
/* The allowed filesystem paths in restricted or pure evaluation
|
||||
mode. */
|
||||
std::experimental::optional<PathSet> allowedPaths;
|
||||
std::optional<PathSet> allowedPaths;
|
||||
|
||||
Value vEmptySet;
|
||||
|
||||
@@ -316,6 +316,9 @@ private:
|
||||
/* Return a string representing the type of the value `v'. */
|
||||
string showType(const Value & v);
|
||||
|
||||
/* Decode a context string ‘!<name>!<path>’ into a pair <path,
|
||||
name>. */
|
||||
std::pair<string, string> decodeContext(const string & s);
|
||||
|
||||
/* If `path' refers to a directory, then append "/default.nix". */
|
||||
Path resolveExprPath(Path path);
|
||||
|
||||
@@ -295,7 +295,7 @@ static bool getDerivation(EvalState & state, Value & v,
|
||||
}
|
||||
|
||||
|
||||
std::experimental::optional<DrvInfo> getDerivation(EvalState & state, Value & v,
|
||||
std::optional<DrvInfo> getDerivation(EvalState & state, Value & v,
|
||||
bool ignoreAssertionFailures)
|
||||
{
|
||||
Done done;
|
||||
|
||||
@@ -78,7 +78,7 @@ typedef list<DrvInfo> DrvInfos;
|
||||
|
||||
/* If value `v' denotes a derivation, return a DrvInfo object
|
||||
describing it. Otherwise return nothing. */
|
||||
std::experimental::optional<DrvInfo> getDerivation(EvalState & state,
|
||||
std::optional<DrvInfo> getDerivation(EvalState & state,
|
||||
Value & v, bool ignoreAssertionFailures);
|
||||
|
||||
void getDerivations(EvalState & state, Value & v, const string & pathPrefix,
|
||||
|
||||
@@ -7,4 +7,4 @@ Description: Nix Package Manager
|
||||
Version: @PACKAGE_VERSION@
|
||||
Requires: nix-store bdw-gc
|
||||
Libs: -L${libdir} -lnixexpr
|
||||
Cflags: -I${includedir}/nix -std=c++14
|
||||
Cflags: -I${includedir}/nix -std=c++17
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
%glr-parser
|
||||
%pure-parser
|
||||
%locations
|
||||
%error-verbose
|
||||
%define parse.error verbose
|
||||
%defines
|
||||
/* %no-lines */
|
||||
%parse-param { void * scanner }
|
||||
|
||||
@@ -315,6 +315,12 @@ static void prim_isBool(EvalState & state, const Pos & pos, Value * * args, Valu
|
||||
mkBool(v, args[0]->type == tBool);
|
||||
}
|
||||
|
||||
/* Determine whether the argument is a path. */
|
||||
static void prim_isPath(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceValue(*args[0]);
|
||||
mkBool(v, args[0]->type == tPath);
|
||||
}
|
||||
|
||||
struct CompareValues
|
||||
{
|
||||
@@ -335,6 +341,8 @@ struct CompareValues
|
||||
return strcmp(v1->string.s, v2->string.s) < 0;
|
||||
case tPath:
|
||||
return strcmp(v1->path, v2->path) < 0;
|
||||
case tAttrs:
|
||||
return v1 < v2; // FIXME
|
||||
default:
|
||||
throw EvalError(format("cannot compare %1% with %2%") % showType(*v1) % showType(*v2));
|
||||
}
|
||||
@@ -555,7 +563,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
|
||||
|
||||
PathSet context;
|
||||
|
||||
std::experimental::optional<std::string> outputHash;
|
||||
std::optional<std::string> outputHash;
|
||||
std::string outputHashAlgo;
|
||||
bool outputHashRecursive = false;
|
||||
|
||||
@@ -687,21 +695,12 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
|
||||
}
|
||||
}
|
||||
|
||||
/* See prim_unsafeDiscardOutputDependency. */
|
||||
else if (path.at(0) == '~')
|
||||
drv.inputSrcs.insert(string(path, 1));
|
||||
|
||||
/* Handle derivation outputs of the form ‘!<name>!<path>’. */
|
||||
else if (path.at(0) == '!') {
|
||||
std::pair<string, string> ctx = decodeContext(path);
|
||||
drv.inputDrvs[ctx.first].insert(ctx.second);
|
||||
}
|
||||
|
||||
/* Handle derivation contexts returned by
|
||||
‘builtins.storePath’. */
|
||||
else if (isDerivation(path))
|
||||
drv.inputDrvs[path] = state.store->queryDerivationOutputNames(path);
|
||||
|
||||
/* Otherwise it's a source file. */
|
||||
else
|
||||
drv.inputSrcs.insert(path);
|
||||
@@ -1004,13 +1003,8 @@ static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Valu
|
||||
PathSet refs;
|
||||
|
||||
for (auto path : context) {
|
||||
if (path.at(0) == '=') path = string(path, 1);
|
||||
if (isDerivation(path)) {
|
||||
/* See prim_unsafeDiscardOutputDependency. */
|
||||
if (path.at(0) != '~')
|
||||
throw EvalError(format("in 'toFile': the file '%1%' cannot refer to derivation outputs, at %2%") % name % pos);
|
||||
path = string(path, 1);
|
||||
}
|
||||
if (path.at(0) != '/')
|
||||
throw EvalError(format("in 'toFile': the file '%1%' cannot refer to derivation outputs, at %2%") % name % pos);
|
||||
refs.insert(path);
|
||||
}
|
||||
|
||||
@@ -1584,7 +1578,6 @@ static void prim_sort(EvalState & state, const Pos & pos, Value * * args, Value
|
||||
v.listElems()[n] = args[1]->listElems()[n];
|
||||
}
|
||||
|
||||
|
||||
auto comparator = [&](Value * a, Value * b) {
|
||||
/* Optimization: if the comparator is lessThan, bypass
|
||||
callFunction. */
|
||||
@@ -1604,6 +1597,62 @@ static void prim_sort(EvalState & state, const Pos & pos, Value * * args, Value
|
||||
}
|
||||
|
||||
|
||||
static void prim_unique(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceFunction(*args[0], pos);
|
||||
state.forceList(*args[1], pos);
|
||||
|
||||
auto len = args[1]->listSize();
|
||||
|
||||
Value * vs[len];
|
||||
for (size_t n = 0; n < len; ++n) {
|
||||
auto v2 = args[1]->listElems()[n];
|
||||
state.forceValue(*v2);
|
||||
vs[n] = v2;
|
||||
}
|
||||
|
||||
auto comparator = [&](Value * a, Value * b) {
|
||||
/* Optimization: if the comparator is lessThan, bypass
|
||||
callFunction. */
|
||||
if (args[0]->type == tPrimOp && args[0]->primOp->fun == prim_lessThan)
|
||||
return CompareValues()(a, b);
|
||||
|
||||
Value vTmp1, vTmp2;
|
||||
state.callFunction(*args[0], *a, vTmp1, pos);
|
||||
state.callFunction(vTmp1, *b, vTmp2, pos);
|
||||
return state.forceBool(vTmp2, pos);
|
||||
};
|
||||
|
||||
std::sort(vs, vs + len, comparator);
|
||||
|
||||
auto outLen = std::min((size_t) 1, len);
|
||||
for (size_t n = 1; n < len; n++) {
|
||||
if (comparator(vs[outLen - 1], vs[n])) {
|
||||
vs[outLen++] = vs[n];
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(vs, vs + outLen);
|
||||
|
||||
state.mkList(v, outLen);
|
||||
|
||||
size_t outPos = 0;
|
||||
for (size_t n = 0; n < len; n++) {
|
||||
auto v2 = args[1]->listElems()[n];
|
||||
auto i = std::lower_bound(vs, vs + outLen, v2);
|
||||
if (*i == v2) {
|
||||
// Remove v2 from the set by setting its least significant
|
||||
// bit. (This doesn't change the sort order.)
|
||||
*i = (Value *) (((ptrdiff_t) v2) | 1);
|
||||
assert(outPos < outLen);
|
||||
v.listElems()[outPos++] = v2;
|
||||
}
|
||||
}
|
||||
|
||||
assert(outPos == outLen);
|
||||
}
|
||||
|
||||
|
||||
static void prim_partition(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceFunction(*args[0], pos);
|
||||
@@ -1794,41 +1843,6 @@ static void prim_stringLength(EvalState & state, const Pos & pos, Value * * args
|
||||
}
|
||||
|
||||
|
||||
static void prim_unsafeDiscardStringContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
PathSet context;
|
||||
string s = state.coerceToString(pos, *args[0], context);
|
||||
mkString(v, s, PathSet());
|
||||
}
|
||||
|
||||
|
||||
static void prim_hasContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
PathSet context;
|
||||
state.forceString(*args[0], context, pos);
|
||||
mkBool(v, !context.empty());
|
||||
}
|
||||
|
||||
|
||||
/* Sometimes we want to pass a derivation path (i.e. pkg.drvPath) to a
|
||||
builder without causing the derivation to be built (for instance,
|
||||
in the derivation that builds NARs in nix-push, when doing
|
||||
source-only deployment). This primop marks the string context so
|
||||
that builtins.derivation adds the path to drv.inputSrcs rather than
|
||||
drv.inputDrvs. */
|
||||
static void prim_unsafeDiscardOutputDependency(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
PathSet context;
|
||||
string s = state.coerceToString(pos, *args[0], context);
|
||||
|
||||
PathSet context2;
|
||||
for (auto & p : context)
|
||||
context2.insert(p.at(0) == '=' ? "~" + string(p, 1) : p);
|
||||
|
||||
mkString(v, s, context2);
|
||||
}
|
||||
|
||||
|
||||
/* Return the cryptographic hash of a string in base-16. */
|
||||
static void prim_hashString(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
@@ -2218,6 +2232,7 @@ void EvalState::createBaseEnv()
|
||||
addPrimOp("__isInt", 1, prim_isInt);
|
||||
addPrimOp("__isFloat", 1, prim_isFloat);
|
||||
addPrimOp("__isBool", 1, prim_isBool);
|
||||
addPrimOp("__isPath", 1, prim_isPath);
|
||||
addPrimOp("__genericClosure", 1, prim_genericClosure);
|
||||
addPrimOp("abort", 1, prim_abort);
|
||||
addPrimOp("__addErrorContext", 2, prim_addErrorContext);
|
||||
@@ -2282,6 +2297,7 @@ void EvalState::createBaseEnv()
|
||||
addPrimOp("__all", 2, prim_all);
|
||||
addPrimOp("__genList", 2, prim_genList);
|
||||
addPrimOp("__sort", 2, prim_sort);
|
||||
addPrimOp("__unique", 2, prim_unique);
|
||||
addPrimOp("__partition", 2, prim_partition);
|
||||
addPrimOp("__concatMap", 2, prim_concatMap);
|
||||
|
||||
@@ -2299,9 +2315,6 @@ void EvalState::createBaseEnv()
|
||||
addPrimOp("toString", 1, prim_toString);
|
||||
addPrimOp("__substring", 3, prim_substring);
|
||||
addPrimOp("__stringLength", 1, prim_stringLength);
|
||||
addPrimOp("__hasContext", 1, prim_hasContext);
|
||||
addPrimOp("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext);
|
||||
addPrimOp("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency);
|
||||
addPrimOp("__hashString", 2, prim_hashString);
|
||||
addPrimOp("__match", 2, prim_match);
|
||||
addPrimOp("__split", 2, prim_split);
|
||||
|
||||
187
src/libexpr/primops/context.cc
Normal file
187
src/libexpr/primops/context.cc
Normal file
@@ -0,0 +1,187 @@
|
||||
#include "primops.hh"
|
||||
#include "eval-inline.hh"
|
||||
#include "derivations.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
static void prim_unsafeDiscardStringContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
PathSet context;
|
||||
string s = state.coerceToString(pos, *args[0], context);
|
||||
mkString(v, s, PathSet());
|
||||
}
|
||||
|
||||
static RegisterPrimOp r1("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext);
|
||||
|
||||
|
||||
static void prim_hasContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
PathSet context;
|
||||
state.forceString(*args[0], context, pos);
|
||||
mkBool(v, !context.empty());
|
||||
}
|
||||
|
||||
static RegisterPrimOp r2("__hasContext", 1, prim_hasContext);
|
||||
|
||||
|
||||
/* Sometimes we want to pass a derivation path (i.e. pkg.drvPath) to a
|
||||
builder without causing the derivation to be built (for instance,
|
||||
in the derivation that builds NARs in nix-push, when doing
|
||||
source-only deployment). This primop marks the string context so
|
||||
that builtins.derivation adds the path to drv.inputSrcs rather than
|
||||
drv.inputDrvs. */
|
||||
static void prim_unsafeDiscardOutputDependency(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
PathSet context;
|
||||
string s = state.coerceToString(pos, *args[0], context);
|
||||
|
||||
PathSet context2;
|
||||
for (auto & p : context)
|
||||
context2.insert(p.at(0) == '=' ? string(p, 1) : p);
|
||||
|
||||
mkString(v, s, context2);
|
||||
}
|
||||
|
||||
static RegisterPrimOp r3("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency);
|
||||
|
||||
|
||||
/* Extract the context of a string as a structured Nix value.
|
||||
|
||||
The context is represented as an attribute set whose keys are the
|
||||
paths in the context set and whose values are attribute sets with
|
||||
the following keys:
|
||||
path: True if the relevant path is in the context as a plain store
|
||||
path (i.e. the kind of context you get when interpolating
|
||||
a Nix path (e.g. ./.) into a string). False if missing.
|
||||
allOutputs: True if the relevant path is a derivation and it is
|
||||
in the context as a drv file with all of its outputs
|
||||
(i.e. the kind of context you get when referencing
|
||||
.drvPath of some derivation). False if missing.
|
||||
outputs: If a non-empty list, the relevant path is a derivation
|
||||
and the provided outputs are referenced in the context
|
||||
(i.e. the kind of context you get when referencing
|
||||
.outPath of some derivation). Empty list if missing.
|
||||
Note that for a given path any combination of the above attributes
|
||||
may be present.
|
||||
*/
|
||||
static void prim_getContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
struct ContextInfo {
|
||||
bool path = false;
|
||||
bool allOutputs = false;
|
||||
Strings outputs;
|
||||
};
|
||||
PathSet context;
|
||||
state.forceString(*args[0], context, pos);
|
||||
auto contextInfos = std::map<Path, ContextInfo>();
|
||||
for (const auto & p : context) {
|
||||
Path drv;
|
||||
string output;
|
||||
const Path * path = &p;
|
||||
if (p.at(0) == '=') {
|
||||
drv = string(p, 1);
|
||||
path = &drv;
|
||||
} else if (p.at(0) == '!') {
|
||||
std::pair<string, string> ctx = decodeContext(p);
|
||||
drv = ctx.first;
|
||||
output = ctx.second;
|
||||
path = &drv;
|
||||
}
|
||||
auto isPath = drv.empty();
|
||||
auto isAllOutputs = (!drv.empty()) && output.empty();
|
||||
|
||||
auto iter = contextInfos.find(*path);
|
||||
if (iter == contextInfos.end()) {
|
||||
contextInfos.emplace(*path, ContextInfo{isPath, isAllOutputs, output.empty() ? Strings{} : Strings{std::move(output)}});
|
||||
} else {
|
||||
if (isPath)
|
||||
iter->second.path = true;
|
||||
else if (isAllOutputs)
|
||||
iter->second.allOutputs = true;
|
||||
else
|
||||
iter->second.outputs.emplace_back(std::move(output));
|
||||
}
|
||||
}
|
||||
|
||||
state.mkAttrs(v, contextInfos.size());
|
||||
|
||||
auto sPath = state.symbols.create("path");
|
||||
auto sAllOutputs = state.symbols.create("allOutputs");
|
||||
for (const auto & info : contextInfos) {
|
||||
auto & infoVal = *state.allocAttr(v, state.symbols.create(info.first));
|
||||
state.mkAttrs(infoVal, 3);
|
||||
if (info.second.path)
|
||||
mkBool(*state.allocAttr(infoVal, sPath), true);
|
||||
if (info.second.allOutputs)
|
||||
mkBool(*state.allocAttr(infoVal, sAllOutputs), true);
|
||||
if (!info.second.outputs.empty()) {
|
||||
auto & outputsVal = *state.allocAttr(infoVal, state.sOutputs);
|
||||
state.mkList(outputsVal, info.second.outputs.size());
|
||||
size_t i = 0;
|
||||
for (const auto & output : info.second.outputs) {
|
||||
mkString(*(outputsVal.listElems()[i++] = state.allocValue()), output);
|
||||
}
|
||||
}
|
||||
infoVal.attrs->sort();
|
||||
}
|
||||
v.attrs->sort();
|
||||
}
|
||||
|
||||
static RegisterPrimOp r4("__getContext", 1, prim_getContext);
|
||||
|
||||
|
||||
/* Append the given context to a given string.
|
||||
|
||||
See the commentary above unsafeGetContext for details of the
|
||||
context representation.
|
||||
*/
|
||||
static void prim_appendContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
PathSet context;
|
||||
auto orig = state.forceString(*args[0], context, pos);
|
||||
|
||||
state.forceAttrs(*args[1], pos);
|
||||
|
||||
auto sPath = state.symbols.create("path");
|
||||
auto sAllOutputs = state.symbols.create("allOutputs");
|
||||
for (auto & i : *args[1]->attrs) {
|
||||
if (!state.store->isStorePath(i.name))
|
||||
throw EvalError("Context key '%s' is not a store path, at %s", i.name, i.pos);
|
||||
if (!settings.readOnlyMode)
|
||||
state.store->ensurePath(i.name);
|
||||
state.forceAttrs(*i.value, *i.pos);
|
||||
auto iter = i.value->attrs->find(sPath);
|
||||
if (iter != i.value->attrs->end()) {
|
||||
if (state.forceBool(*iter->value, *iter->pos))
|
||||
context.insert(i.name);
|
||||
}
|
||||
|
||||
iter = i.value->attrs->find(sAllOutputs);
|
||||
if (iter != i.value->attrs->end()) {
|
||||
if (state.forceBool(*iter->value, *iter->pos)) {
|
||||
if (!isDerivation(i.name)) {
|
||||
throw EvalError("Tried to add all-outputs context of %s, which is not a derivation, to a string, at %s", i.name, i.pos);
|
||||
}
|
||||
context.insert("=" + string(i.name));
|
||||
}
|
||||
}
|
||||
|
||||
iter = i.value->attrs->find(state.sOutputs);
|
||||
if (iter != i.value->attrs->end()) {
|
||||
state.forceList(*iter->value, *iter->pos);
|
||||
if (iter->value->listSize() && !isDerivation(i.name)) {
|
||||
throw EvalError("Tried to add derivation output context of %s, which is not a derivation, to a string, at %s", i.name, i.pos);
|
||||
}
|
||||
for (unsigned int n = 0; n < iter->value->listSize(); ++n) {
|
||||
auto name = state.forceStringNoCtx(*iter->value->listElems()[n], *iter->pos);
|
||||
context.insert("!" + name + "!" + string(i.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mkString(v, orig, context);
|
||||
}
|
||||
|
||||
static RegisterPrimOp r5("__appendContext", 2, prim_appendContext);
|
||||
|
||||
}
|
||||
@@ -26,7 +26,7 @@ struct GitInfo
|
||||
std::regex revRegex("^[0-9a-fA-F]{40}$");
|
||||
|
||||
GitInfo exportGit(ref<Store> store, const std::string & uri,
|
||||
std::experimental::optional<std::string> ref, std::string rev,
|
||||
std::optional<std::string> ref, std::string rev,
|
||||
const std::string & name)
|
||||
{
|
||||
if (evalSettings.pureEval && rev == "")
|
||||
@@ -190,7 +190,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,
|
||||
static void prim_fetchGit(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
std::string url;
|
||||
std::experimental::optional<std::string> ref;
|
||||
std::optional<std::string> ref;
|
||||
std::string rev;
|
||||
std::string name = "source";
|
||||
PathSet context;
|
||||
|
||||
@@ -75,6 +75,13 @@ public:
|
||||
}
|
||||
|
||||
size_t totalSize() const;
|
||||
|
||||
template<typename T>
|
||||
void dump(T callback)
|
||||
{
|
||||
for (auto & s : symbols)
|
||||
callback(s);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -6,4 +6,4 @@ Name: Nix
|
||||
Description: Nix Package Manager
|
||||
Version: @PACKAGE_VERSION@
|
||||
Libs: -L${libdir} -lnixmain
|
||||
Cflags: -I${includedir}/nix -std=c++14
|
||||
Cflags: -I${includedir}/nix -std=c++17
|
||||
|
||||
@@ -72,24 +72,11 @@ public:
|
||||
|
||||
bool isValidPathUncached(const Path & path) override;
|
||||
|
||||
PathSet queryAllValidPaths() override
|
||||
{ unsupported(); }
|
||||
|
||||
void queryPathInfoUncached(const Path & path,
|
||||
Callback<std::shared_ptr<ValidPathInfo>> callback) override;
|
||||
|
||||
void queryReferrers(const Path & path,
|
||||
PathSet & referrers) override
|
||||
{ unsupported(); }
|
||||
|
||||
PathSet queryDerivationOutputs(const Path & path) override
|
||||
{ unsupported(); }
|
||||
|
||||
StringSet queryDerivationOutputNames(const Path & path) override
|
||||
{ unsupported(); }
|
||||
|
||||
Path queryPathFromHashPart(const string & hashPart) override
|
||||
{ unsupported(); }
|
||||
{ unsupported("queryPathFromHashPart"); }
|
||||
|
||||
bool wantMassQuery() override { return wantMassQuery_; }
|
||||
|
||||
@@ -108,22 +95,10 @@ public:
|
||||
|
||||
BuildResult buildDerivation(const Path & drvPath, const BasicDerivation & drv,
|
||||
BuildMode buildMode) override
|
||||
{ unsupported(); }
|
||||
{ unsupported("buildDerivation"); }
|
||||
|
||||
void ensurePath(const Path & path) override
|
||||
{ unsupported(); }
|
||||
|
||||
void addTempRoot(const Path & path) override
|
||||
{ unsupported(); }
|
||||
|
||||
void addIndirectRoot(const Path & path) override
|
||||
{ unsupported(); }
|
||||
|
||||
Roots findRoots() override
|
||||
{ unsupported(); }
|
||||
|
||||
void collectGarbage(const GCOptions & options, GCResults & results) override
|
||||
{ unsupported(); }
|
||||
{ unsupported("ensurePath"); }
|
||||
|
||||
ref<FSAccessor> getFSAccessor() override;
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "json.hh"
|
||||
#include "nar-info.hh"
|
||||
#include "parsed-derivations.hh"
|
||||
#include "machines.hh"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
@@ -2193,7 +2194,6 @@ void DerivationGoal::startBuilder()
|
||||
userNamespaceSync.create();
|
||||
|
||||
options.allowVfork = false;
|
||||
options.restoreMountNamespace = false;
|
||||
|
||||
Pid helper = startProcess([&]() {
|
||||
|
||||
@@ -2260,7 +2260,6 @@ void DerivationGoal::startBuilder()
|
||||
#endif
|
||||
{
|
||||
options.allowVfork = !buildUser && !drv->isBuiltin();
|
||||
options.restoreMountNamespace = false;
|
||||
pid = startProcess([&]() {
|
||||
runChild();
|
||||
}, options);
|
||||
@@ -2415,7 +2414,7 @@ void DerivationGoal::writeStructuredAttrs()
|
||||
objects consisting entirely of those values. (So nested
|
||||
arrays or objects are not supported.) */
|
||||
|
||||
auto handleSimpleType = [](const nlohmann::json & value) -> std::experimental::optional<std::string> {
|
||||
auto handleSimpleType = [](const nlohmann::json & value) -> std::optional<std::string> {
|
||||
if (value.is_string())
|
||||
return shellEscape(value);
|
||||
|
||||
@@ -3313,8 +3312,8 @@ void DerivationGoal::checkOutputs(const std::map<Path, ValidPathInfo> & outputs)
|
||||
struct Checks
|
||||
{
|
||||
bool ignoreSelfRefs = false;
|
||||
std::experimental::optional<uint64_t> maxSize, maxClosureSize;
|
||||
std::experimental::optional<Strings> allowedReferences, allowedRequisites, disallowedReferences, disallowedRequisites;
|
||||
std::optional<uint64_t> maxSize, maxClosureSize;
|
||||
std::optional<Strings> allowedReferences, allowedRequisites, disallowedReferences, disallowedRequisites;
|
||||
};
|
||||
|
||||
/* Compute the closure and closure size of some output. This
|
||||
@@ -3361,7 +3360,7 @@ void DerivationGoal::checkOutputs(const std::map<Path, ValidPathInfo> & outputs)
|
||||
info.path, closureSize, *checks.maxClosureSize);
|
||||
}
|
||||
|
||||
auto checkRefs = [&](const std::experimental::optional<Strings> & value, bool allowed, bool recursive)
|
||||
auto checkRefs = [&](const std::optional<Strings> & value, bool allowed, bool recursive)
|
||||
{
|
||||
if (!value) return;
|
||||
|
||||
@@ -3415,7 +3414,7 @@ void DerivationGoal::checkOutputs(const std::map<Path, ValidPathInfo> & outputs)
|
||||
if (maxClosureSize != output->end())
|
||||
checks.maxClosureSize = maxClosureSize->get<uint64_t>();
|
||||
|
||||
auto get = [&](const std::string & name) -> std::experimental::optional<Strings> {
|
||||
auto get = [&](const std::string & name) -> std::optional<Strings> {
|
||||
auto i = output->find(name);
|
||||
if (i != output->end()) {
|
||||
Strings res;
|
||||
@@ -4413,6 +4412,11 @@ static void primeCache(Store & store, const PathSet & paths)
|
||||
PathSet willBuild, willSubstitute, unknown;
|
||||
unsigned long long downloadSize, narSize;
|
||||
store.queryMissing(paths, willBuild, willSubstitute, unknown, downloadSize, narSize);
|
||||
|
||||
if (!willBuild.empty() && 0 == settings.maxBuildJobs && getMachines().empty())
|
||||
throw Error(
|
||||
"%d derivations need to be built, but neither local builds ('--max-jobs') "
|
||||
"nor remote builds ('--builders') are enabled", willBuild.size());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -614,6 +614,22 @@ struct CurlDownloader : public Downloader
|
||||
writeFull(wakeupPipe.writeSide.get(), " ");
|
||||
}
|
||||
|
||||
#ifdef ENABLE_S3
|
||||
std::tuple<std::string, std::string, Store::Params> parseS3Uri(std::string uri)
|
||||
{
|
||||
auto [path, params] = splitUriAndParams(uri);
|
||||
|
||||
auto slash = path.find('/', 5); // 5 is the length of "s3://" prefix
|
||||
if (slash == std::string::npos)
|
||||
throw nix::Error("bad S3 URI '%s'", path);
|
||||
|
||||
std::string bucketName(path, 5, slash - 5);
|
||||
std::string key(path, slash + 1);
|
||||
|
||||
return {bucketName, key, params};
|
||||
}
|
||||
#endif
|
||||
|
||||
void enqueueDownload(const DownloadRequest & request,
|
||||
Callback<DownloadResult> callback) override
|
||||
{
|
||||
@@ -622,12 +638,15 @@ struct CurlDownloader : public Downloader
|
||||
// FIXME: do this on a worker thread
|
||||
try {
|
||||
#ifdef ENABLE_S3
|
||||
S3Helper s3Helper("", Aws::Region::US_EAST_1, "", ""); // FIXME: make configurable
|
||||
auto slash = request.uri.find('/', 5);
|
||||
if (slash == std::string::npos)
|
||||
throw nix::Error("bad S3 URI '%s'", request.uri);
|
||||
std::string bucketName(request.uri, 5, slash - 5);
|
||||
std::string key(request.uri, slash + 1);
|
||||
auto [bucketName, key, params] = parseS3Uri(request.uri);
|
||||
|
||||
std::string profile = get(params, "profile", "");
|
||||
std::string region = get(params, "region", Aws::Region::US_EAST_1);
|
||||
std::string scheme = get(params, "scheme", "");
|
||||
std::string endpoint = get(params, "endpoint", "");
|
||||
|
||||
S3Helper s3Helper(profile, region, scheme, endpoint);
|
||||
|
||||
// FIXME: implement ETag
|
||||
auto s3Res = s3Helper.getObject(bucketName, key);
|
||||
DownloadResult res;
|
||||
|
||||
@@ -129,8 +129,8 @@ Path LocalFSStore::addPermRoot(const Path & _storePath,
|
||||
check if the root is in a directory in or linked from the
|
||||
gcroots directory. */
|
||||
if (settings.checkRootReachability) {
|
||||
Roots roots = findRoots();
|
||||
if (roots.find(gcRoot) == roots.end())
|
||||
Roots roots = findRoots(false);
|
||||
if (roots[storePath].count(gcRoot) == 0)
|
||||
printError(
|
||||
format(
|
||||
"warning: '%1%' is not in a directory where the garbage collector looks for roots; "
|
||||
@@ -197,10 +197,11 @@ void LocalStore::addTempRoot(const Path & path)
|
||||
}
|
||||
|
||||
|
||||
std::set<std::pair<pid_t, Path>> LocalStore::readTempRoots(FDs & fds)
|
||||
{
|
||||
std::set<std::pair<pid_t, Path>> tempRoots;
|
||||
static std::string censored = "{censored}";
|
||||
|
||||
|
||||
void LocalStore::findTempRoots(FDs & fds, Roots & tempRoots, bool censor)
|
||||
{
|
||||
/* Read the `temproots' directory for per-process temporary root
|
||||
files. */
|
||||
for (auto & i : readDirectory(tempRootsDir)) {
|
||||
@@ -250,14 +251,12 @@ std::set<std::pair<pid_t, Path>> LocalStore::readTempRoots(FDs & fds)
|
||||
Path root(contents, pos, end - pos);
|
||||
debug("got temporary root '%s'", root);
|
||||
assertStorePath(root);
|
||||
tempRoots.emplace(pid, root);
|
||||
tempRoots[root].emplace(censor ? censored : fmt("{temp:%d}", pid));
|
||||
pos = end + 1;
|
||||
}
|
||||
|
||||
fds.push_back(fd); /* keep open */
|
||||
}
|
||||
|
||||
return tempRoots;
|
||||
}
|
||||
|
||||
|
||||
@@ -266,7 +265,7 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots)
|
||||
auto foundRoot = [&](const Path & path, const Path & target) {
|
||||
Path storePath = toStorePath(target);
|
||||
if (isStorePath(storePath) && isValidPath(storePath))
|
||||
roots[path] = storePath;
|
||||
roots[storePath].emplace(path);
|
||||
else
|
||||
printInfo(format("skipping invalid root from '%1%' to '%2%'") % path % storePath);
|
||||
};
|
||||
@@ -306,7 +305,7 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots)
|
||||
else if (type == DT_REG) {
|
||||
Path storePath = storeDir + "/" + baseNameOf(path);
|
||||
if (isStorePath(storePath) && isValidPath(storePath))
|
||||
roots[path] = storePath;
|
||||
roots[storePath].emplace(path);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -321,10 +320,8 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots)
|
||||
}
|
||||
|
||||
|
||||
Roots LocalStore::findRootsNoTemp()
|
||||
void LocalStore::findRootsNoTemp(Roots & roots, bool censor)
|
||||
{
|
||||
Roots roots;
|
||||
|
||||
/* Process direct roots in {gcroots,profiles}. */
|
||||
findRoots(stateDir + "/" + gcRootsDir, DT_UNKNOWN, roots);
|
||||
findRoots(stateDir + "/profiles", DT_UNKNOWN, roots);
|
||||
@@ -333,32 +330,22 @@ Roots LocalStore::findRootsNoTemp()
|
||||
NIX_ROOT_FINDER environment variable. This is typically used
|
||||
to add running programs to the set of roots (to prevent them
|
||||
from being garbage collected). */
|
||||
size_t n = 0;
|
||||
for (auto & root : findRuntimeRoots())
|
||||
roots[fmt("{memory:%d}", n++)] = root;
|
||||
|
||||
return roots;
|
||||
findRuntimeRoots(roots, censor);
|
||||
}
|
||||
|
||||
|
||||
Roots LocalStore::findRoots()
|
||||
Roots LocalStore::findRoots(bool censor)
|
||||
{
|
||||
Roots roots = findRootsNoTemp();
|
||||
Roots roots;
|
||||
findRootsNoTemp(roots, censor);
|
||||
|
||||
FDs fds;
|
||||
pid_t prev = -1;
|
||||
size_t n = 0;
|
||||
for (auto & root : readTempRoots(fds)) {
|
||||
if (prev != root.first) n = 0;
|
||||
prev = root.first;
|
||||
roots[fmt("{temp:%d:%d}", root.first, n++)] = root.second;
|
||||
}
|
||||
findTempRoots(fds, roots, censor);
|
||||
|
||||
return roots;
|
||||
}
|
||||
|
||||
|
||||
static void readProcLink(const string & file, StringSet & paths)
|
||||
static void readProcLink(const string & file, Roots & roots)
|
||||
{
|
||||
/* 64 is the starting buffer size gnu readlink uses... */
|
||||
auto bufsiz = ssize_t{64};
|
||||
@@ -377,8 +364,8 @@ try_again:
|
||||
goto try_again;
|
||||
}
|
||||
if (res > 0 && buf[0] == '/')
|
||||
paths.emplace(static_cast<char *>(buf), res);
|
||||
return;
|
||||
roots[std::string(static_cast<char *>(buf), res)]
|
||||
.emplace(file);
|
||||
}
|
||||
|
||||
static string quoteRegexChars(const string & raw)
|
||||
@@ -387,20 +374,20 @@ static string quoteRegexChars(const string & raw)
|
||||
return std::regex_replace(raw, specialRegex, R"(\$&)");
|
||||
}
|
||||
|
||||
static void readFileRoots(const char * path, StringSet & paths)
|
||||
static void readFileRoots(const char * path, Roots & roots)
|
||||
{
|
||||
try {
|
||||
paths.emplace(readFile(path));
|
||||
roots[readFile(path)].emplace(path);
|
||||
} catch (SysError & e) {
|
||||
if (e.errNo != ENOENT && e.errNo != EACCES)
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
PathSet LocalStore::findRuntimeRoots()
|
||||
void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
|
||||
{
|
||||
PathSet roots;
|
||||
StringSet paths;
|
||||
Roots unchecked;
|
||||
|
||||
auto procDir = AutoCloseDir{opendir("/proc")};
|
||||
if (procDir) {
|
||||
struct dirent * ent;
|
||||
@@ -410,10 +397,10 @@ PathSet LocalStore::findRuntimeRoots()
|
||||
while (errno = 0, ent = readdir(procDir.get())) {
|
||||
checkInterrupt();
|
||||
if (std::regex_match(ent->d_name, digitsRegex)) {
|
||||
readProcLink((format("/proc/%1%/exe") % ent->d_name).str(), paths);
|
||||
readProcLink((format("/proc/%1%/cwd") % ent->d_name).str(), paths);
|
||||
readProcLink(fmt("/proc/%s/exe" ,ent->d_name), unchecked);
|
||||
readProcLink(fmt("/proc/%s/cwd", ent->d_name), unchecked);
|
||||
|
||||
auto fdStr = (format("/proc/%1%/fd") % ent->d_name).str();
|
||||
auto fdStr = fmt("/proc/%s/fd", ent->d_name);
|
||||
auto fdDir = AutoCloseDir(opendir(fdStr.c_str()));
|
||||
if (!fdDir) {
|
||||
if (errno == ENOENT || errno == EACCES)
|
||||
@@ -422,9 +409,8 @@ PathSet LocalStore::findRuntimeRoots()
|
||||
}
|
||||
struct dirent * fd_ent;
|
||||
while (errno = 0, fd_ent = readdir(fdDir.get())) {
|
||||
if (fd_ent->d_name[0] != '.') {
|
||||
readProcLink((format("%1%/%2%") % fdStr % fd_ent->d_name).str(), paths);
|
||||
}
|
||||
if (fd_ent->d_name[0] != '.')
|
||||
readProcLink(fmt("%s/%s", fdStr, fd_ent->d_name), unchecked);
|
||||
}
|
||||
if (errno) {
|
||||
if (errno == ESRCH)
|
||||
@@ -434,18 +420,19 @@ PathSet LocalStore::findRuntimeRoots()
|
||||
fdDir.reset();
|
||||
|
||||
try {
|
||||
auto mapLines =
|
||||
tokenizeString<std::vector<string>>(readFile((format("/proc/%1%/maps") % ent->d_name).str(), true), "\n");
|
||||
for (const auto& line : mapLines) {
|
||||
auto mapFile = fmt("/proc/%s/maps", ent->d_name);
|
||||
auto mapLines = tokenizeString<std::vector<string>>(readFile(mapFile, true), "\n");
|
||||
for (const auto & line : mapLines) {
|
||||
auto match = std::smatch{};
|
||||
if (std::regex_match(line, match, mapRegex))
|
||||
paths.emplace(match[1]);
|
||||
unchecked[match[1]].emplace(mapFile);
|
||||
}
|
||||
|
||||
auto envString = readFile((format("/proc/%1%/environ") % ent->d_name).str(), true);
|
||||
auto envFile = fmt("/proc/%s/environ", ent->d_name);
|
||||
auto envString = readFile(envFile, true);
|
||||
auto env_end = std::sregex_iterator{};
|
||||
for (auto i = std::sregex_iterator{envString.begin(), envString.end(), storePathRegex}; i != env_end; ++i)
|
||||
paths.emplace(i->str());
|
||||
unchecked[i->str()].emplace(envFile);
|
||||
} catch (SysError & e) {
|
||||
if (errno == ENOENT || errno == EACCES || errno == ESRCH)
|
||||
continue;
|
||||
@@ -465,7 +452,7 @@ PathSet LocalStore::findRuntimeRoots()
|
||||
for (const auto & line : lsofLines) {
|
||||
std::smatch match;
|
||||
if (std::regex_match(line, match, lsofRegex))
|
||||
paths.emplace(match[1]);
|
||||
unchecked[match[1]].emplace("{lsof}");
|
||||
}
|
||||
} catch (ExecError & e) {
|
||||
/* lsof not installed, lsof failed */
|
||||
@@ -473,21 +460,23 @@ PathSet LocalStore::findRuntimeRoots()
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
readFileRoots("/proc/sys/kernel/modprobe", paths);
|
||||
readFileRoots("/proc/sys/kernel/fbsplash", paths);
|
||||
readFileRoots("/proc/sys/kernel/poweroff_cmd", paths);
|
||||
readFileRoots("/proc/sys/kernel/modprobe", unchecked);
|
||||
readFileRoots("/proc/sys/kernel/fbsplash", unchecked);
|
||||
readFileRoots("/proc/sys/kernel/poweroff_cmd", unchecked);
|
||||
#endif
|
||||
|
||||
for (auto & i : paths)
|
||||
if (isInStore(i)) {
|
||||
Path path = toStorePath(i);
|
||||
if (roots.find(path) == roots.end() && isStorePath(path) && isValidPath(path)) {
|
||||
for (auto & [target, links] : unchecked) {
|
||||
if (isInStore(target)) {
|
||||
Path path = toStorePath(target);
|
||||
if (isStorePath(path) && isValidPath(path)) {
|
||||
debug(format("got additional root '%1%'") % path);
|
||||
roots.insert(path);
|
||||
if (censor)
|
||||
roots[path].insert(censored);
|
||||
else
|
||||
roots[path].insert(links.begin(), links.end());
|
||||
}
|
||||
}
|
||||
|
||||
return roots;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -754,16 +743,20 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
||||
/* Find the roots. Since we've grabbed the GC lock, the set of
|
||||
permanent roots cannot increase now. */
|
||||
printError(format("finding garbage collector roots..."));
|
||||
Roots rootMap = options.ignoreLiveness ? Roots() : findRootsNoTemp();
|
||||
Roots rootMap;
|
||||
if (!options.ignoreLiveness)
|
||||
findRootsNoTemp(rootMap, true);
|
||||
|
||||
for (auto & i : rootMap) state.roots.insert(i.second);
|
||||
for (auto & i : rootMap) state.roots.insert(i.first);
|
||||
|
||||
/* Read the temporary roots. This acquires read locks on all
|
||||
per-process temporary root files. So after this point no paths
|
||||
can be added to the set of temporary roots. */
|
||||
FDs fds;
|
||||
for (auto & root : readTempRoots(fds))
|
||||
state.tempRoots.insert(root.second);
|
||||
Roots tempRoots;
|
||||
findTempRoots(fds, tempRoots, true);
|
||||
for (auto & root : tempRoots)
|
||||
state.tempRoots.insert(root.first);
|
||||
state.roots.insert(state.tempRoots.begin(), state.tempRoots.end());
|
||||
|
||||
/* After this point the set of roots or temporary roots cannot
|
||||
|
||||
@@ -187,28 +187,17 @@ struct LegacySSHStore : public Store
|
||||
copyNAR(conn->from, sink);
|
||||
}
|
||||
|
||||
PathSet queryAllValidPaths() override { unsupported(); }
|
||||
|
||||
void queryReferrers(const Path & path, PathSet & referrers) override
|
||||
{ unsupported(); }
|
||||
|
||||
PathSet queryDerivationOutputs(const Path & path) override
|
||||
{ unsupported(); }
|
||||
|
||||
StringSet queryDerivationOutputNames(const Path & path) override
|
||||
{ unsupported(); }
|
||||
|
||||
Path queryPathFromHashPart(const string & hashPart) override
|
||||
{ unsupported(); }
|
||||
{ unsupported("queryPathFromHashPart"); }
|
||||
|
||||
Path addToStore(const string & name, const Path & srcPath,
|
||||
bool recursive, HashType hashAlgo,
|
||||
PathFilter & filter, RepairFlag repair) override
|
||||
{ unsupported(); }
|
||||
{ unsupported("addToStore"); }
|
||||
|
||||
Path addTextToStore(const string & name, const string & s,
|
||||
const PathSet & references, RepairFlag repair) override
|
||||
{ unsupported(); }
|
||||
{ unsupported("addTextToStore"); }
|
||||
|
||||
BuildResult buildDerivation(const Path & drvPath, const BasicDerivation & drv,
|
||||
BuildMode buildMode) override
|
||||
@@ -242,25 +231,7 @@ struct LegacySSHStore : public Store
|
||||
}
|
||||
|
||||
void ensurePath(const Path & path) override
|
||||
{ unsupported(); }
|
||||
|
||||
void addTempRoot(const Path & path) override
|
||||
{ unsupported(); }
|
||||
|
||||
void addIndirectRoot(const Path & path) override
|
||||
{ unsupported(); }
|
||||
|
||||
Roots findRoots() override
|
||||
{ unsupported(); }
|
||||
|
||||
void collectGarbage(const GCOptions & options, GCResults & results) override
|
||||
{ unsupported(); }
|
||||
|
||||
ref<FSAccessor> getFSAccessor() override
|
||||
{ unsupported(); }
|
||||
|
||||
void addSignatures(const Path & storePath, const StringSet & sigs) override
|
||||
{ unsupported(); }
|
||||
{ unsupported("ensurePath"); }
|
||||
|
||||
void computeFSClosure(const PathSet & paths,
|
||||
PathSet & out, bool flipDirection = false,
|
||||
|
||||
@@ -366,8 +366,6 @@ void LocalStore::makeStoreWritable()
|
||||
throw SysError("getting info about the Nix store mount point");
|
||||
|
||||
if (stat.f_flag & ST_RDONLY) {
|
||||
saveMountNamespace();
|
||||
|
||||
if (unshare(CLONE_NEWNS) == -1)
|
||||
throw SysError("setting up a private mount namespace");
|
||||
|
||||
|
||||
@@ -180,11 +180,11 @@ private:
|
||||
typedef std::shared_ptr<AutoCloseFD> FDPtr;
|
||||
typedef list<FDPtr> FDs;
|
||||
|
||||
std::set<std::pair<pid_t, Path>> readTempRoots(FDs & fds);
|
||||
void findTempRoots(FDs & fds, Roots & roots, bool censor);
|
||||
|
||||
public:
|
||||
|
||||
Roots findRoots() override;
|
||||
Roots findRoots(bool censor) override;
|
||||
|
||||
void collectGarbage(const GCOptions & options, GCResults & results) override;
|
||||
|
||||
@@ -267,9 +267,9 @@ private:
|
||||
|
||||
void findRoots(const Path & path, unsigned char type, Roots & roots);
|
||||
|
||||
Roots findRootsNoTemp();
|
||||
void findRootsNoTemp(Roots & roots, bool censor);
|
||||
|
||||
PathSet findRuntimeRoots();
|
||||
void findRuntimeRoots(Roots & roots, bool censor);
|
||||
|
||||
void removeUnusedLinks(const GCState & state);
|
||||
|
||||
|
||||
@@ -89,10 +89,11 @@ void parseMachines(const std::string & s, Machines & machines)
|
||||
|
||||
Machines getMachines()
|
||||
{
|
||||
Machines machines;
|
||||
|
||||
parseMachines(settings.builders, machines);
|
||||
|
||||
static auto machines = [&]() {
|
||||
Machines machines;
|
||||
parseMachines(settings.builders, machines);
|
||||
return machines;
|
||||
}();
|
||||
return machines;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,4 +6,4 @@ Name: Nix
|
||||
Description: Nix Package Manager
|
||||
Version: @PACKAGE_VERSION@
|
||||
Libs: -L${libdir} -lnixstore -lnixutil
|
||||
Cflags: -I${includedir}/nix -std=c++14
|
||||
Cflags: -I${includedir}/nix -std=c++17
|
||||
|
||||
@@ -16,7 +16,7 @@ ParsedDerivation::ParsedDerivation(const Path & drvPath, BasicDerivation & drv)
|
||||
}
|
||||
}
|
||||
|
||||
std::experimental::optional<std::string> ParsedDerivation::getStringAttr(const std::string & name) const
|
||||
std::optional<std::string> ParsedDerivation::getStringAttr(const std::string & name) const
|
||||
{
|
||||
if (structuredAttrs) {
|
||||
auto i = structuredAttrs->find(name);
|
||||
@@ -56,7 +56,7 @@ bool ParsedDerivation::getBoolAttr(const std::string & name, bool def) const
|
||||
}
|
||||
}
|
||||
|
||||
std::experimental::optional<Strings> ParsedDerivation::getStringsAttr(const std::string & name) const
|
||||
std::optional<Strings> ParsedDerivation::getStringsAttr(const std::string & name) const
|
||||
{
|
||||
if (structuredAttrs) {
|
||||
auto i = structuredAttrs->find(name);
|
||||
|
||||
@@ -8,22 +8,22 @@ class ParsedDerivation
|
||||
{
|
||||
Path drvPath;
|
||||
BasicDerivation & drv;
|
||||
std::experimental::optional<nlohmann::json> structuredAttrs;
|
||||
std::optional<nlohmann::json> structuredAttrs;
|
||||
|
||||
public:
|
||||
|
||||
ParsedDerivation(const Path & drvPath, BasicDerivation & drv);
|
||||
|
||||
const std::experimental::optional<nlohmann::json> & getStructuredAttrs() const
|
||||
const std::optional<nlohmann::json> & getStructuredAttrs() const
|
||||
{
|
||||
return structuredAttrs;
|
||||
}
|
||||
|
||||
std::experimental::optional<std::string> getStringAttr(const std::string & name) const;
|
||||
std::optional<std::string> getStringAttr(const std::string & name) const;
|
||||
|
||||
bool getBoolAttr(const std::string & name, bool def = false) const;
|
||||
|
||||
std::experimental::optional<Strings> getStringsAttr(const std::string & name) const;
|
||||
std::optional<Strings> getStringsAttr(const std::string & name) const;
|
||||
|
||||
StringSet getRequiredSystemFeatures() const;
|
||||
|
||||
|
||||
@@ -596,7 +596,7 @@ void RemoteStore::syncWithGC()
|
||||
}
|
||||
|
||||
|
||||
Roots RemoteStore::findRoots()
|
||||
Roots RemoteStore::findRoots(bool censor)
|
||||
{
|
||||
auto conn(getConnection());
|
||||
conn->to << wopFindRoots;
|
||||
@@ -606,7 +606,7 @@ Roots RemoteStore::findRoots()
|
||||
while (count--) {
|
||||
Path link = readString(conn->from);
|
||||
Path target = readStorePath(*this, conn->from);
|
||||
result[link] = target;
|
||||
result[target].emplace(link);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ public:
|
||||
|
||||
void syncWithGC() override;
|
||||
|
||||
Roots findRoots() override;
|
||||
Roots findRoots(bool censor) override;
|
||||
|
||||
void collectGarbage(const GCOptions & options, GCResults & results) override;
|
||||
|
||||
@@ -149,7 +149,7 @@ public:
|
||||
private:
|
||||
|
||||
ref<RemoteStore::Connection> openConnection() override;
|
||||
std::experimental::optional<std::string> path;
|
||||
std::optional<std::string> path;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -126,6 +126,7 @@ ref<Aws::Client::ClientConfiguration> S3Helper::makeConfig(const string & region
|
||||
res->endpointOverride = endpoint;
|
||||
}
|
||||
res->requestTimeoutMs = 600 * 1000;
|
||||
res->connectTimeoutMs = 5 * 1000;
|
||||
res->retryStrategy = std::make_shared<RetryStrategy>();
|
||||
res->caFile = settings.caFile;
|
||||
return res;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "ssh.hh"
|
||||
#include "affinity.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -35,9 +34,7 @@ std::unique_ptr<SSHMaster::Connection> SSHMaster::startCommand(const std::string
|
||||
|
||||
auto conn = std::make_unique<Connection>();
|
||||
conn->sshPid = startProcess([&]() {
|
||||
restoreAffinity();
|
||||
restoreSignals();
|
||||
restoreMountNamespace();
|
||||
|
||||
close(in.writeSide.get());
|
||||
close(out.readSide.get());
|
||||
|
||||
@@ -562,10 +562,10 @@ void Store::buildPaths(const PathSet & paths, BuildMode buildMode)
|
||||
{
|
||||
for (auto & path : paths)
|
||||
if (isDerivation(path))
|
||||
unsupported();
|
||||
unsupported("buildPaths");
|
||||
|
||||
if (queryValidPaths(paths).size() != paths.size())
|
||||
unsupported();
|
||||
unsupported("buildPaths");
|
||||
}
|
||||
|
||||
|
||||
@@ -842,12 +842,11 @@ namespace nix {
|
||||
|
||||
RegisterStoreImplementation::Implementations * RegisterStoreImplementation::implementations = 0;
|
||||
|
||||
|
||||
ref<Store> openStore(const std::string & uri_,
|
||||
const Store::Params & extraParams)
|
||||
/* Split URI into protocol+hierarchy part and its parameter set. */
|
||||
std::pair<std::string, Store::Params> splitUriAndParams(const std::string & uri_)
|
||||
{
|
||||
auto uri(uri_);
|
||||
Store::Params params(extraParams);
|
||||
Store::Params params;
|
||||
auto q = uri.find('?');
|
||||
if (q != std::string::npos) {
|
||||
for (auto s : tokenizeString<Strings>(uri.substr(q + 1), "&")) {
|
||||
@@ -873,6 +872,15 @@ ref<Store> openStore(const std::string & uri_,
|
||||
}
|
||||
uri = uri_.substr(0, q);
|
||||
}
|
||||
return {uri, params};
|
||||
}
|
||||
|
||||
ref<Store> openStore(const std::string & uri_,
|
||||
const Store::Params & extraParams)
|
||||
{
|
||||
auto [uri, uriParams] = splitUriAndParams(uri_);
|
||||
auto params = extraParams;
|
||||
params.insert(uriParams.begin(), uriParams.end());
|
||||
|
||||
for (auto fun : *RegisterStoreImplementation::implementations) {
|
||||
auto store = fun(uri, params);
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include <atomic>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
@@ -47,7 +49,7 @@ const size_t storePathHashLen = 32; // i.e. 160 bits
|
||||
const uint32_t exportMagic = 0x4558494e;
|
||||
|
||||
|
||||
typedef std::map<Path, Path> Roots;
|
||||
typedef std::unordered_map<Path, std::unordered_set<std::string>> Roots;
|
||||
|
||||
|
||||
struct GCOptions
|
||||
@@ -349,7 +351,8 @@ public:
|
||||
(i.e. you'll get /nix/store/<hash> rather than
|
||||
/nix/store/<hash>-<name>). Use queryPathInfo() to obtain the
|
||||
full store path. */
|
||||
virtual PathSet queryAllValidPaths() = 0;
|
||||
virtual PathSet queryAllValidPaths()
|
||||
{ unsupported("queryAllValidPaths"); }
|
||||
|
||||
/* Query information about a valid path. It is permitted to omit
|
||||
the name part of the store path. */
|
||||
@@ -368,8 +371,8 @@ public:
|
||||
|
||||
/* Queries the set of incoming FS references for a store path.
|
||||
The result is not cleared. */
|
||||
virtual void queryReferrers(const Path & path,
|
||||
PathSet & referrers) = 0;
|
||||
virtual void queryReferrers(const Path & path, PathSet & referrers)
|
||||
{ unsupported("queryReferrers"); }
|
||||
|
||||
/* Return all currently valid derivations that have `path' as an
|
||||
output. (Note that the result of `queryDeriver()' is the
|
||||
@@ -378,10 +381,12 @@ public:
|
||||
virtual PathSet queryValidDerivers(const Path & path) { return {}; };
|
||||
|
||||
/* Query the outputs of the derivation denoted by `path'. */
|
||||
virtual PathSet queryDerivationOutputs(const Path & path) = 0;
|
||||
virtual PathSet queryDerivationOutputs(const Path & path)
|
||||
{ unsupported("queryDerivationOutputs"); }
|
||||
|
||||
/* Query the output names of the derivation denoted by `path'. */
|
||||
virtual StringSet queryDerivationOutputNames(const Path & path) = 0;
|
||||
virtual StringSet queryDerivationOutputNames(const Path & path)
|
||||
{ unsupported("queryDerivationOutputNames"); }
|
||||
|
||||
/* Query the full store path given the hash part of a valid store
|
||||
path, or "" if the path doesn't exist. */
|
||||
@@ -447,14 +452,16 @@ public:
|
||||
|
||||
/* Add a store path as a temporary root of the garbage collector.
|
||||
The root disappears as soon as we exit. */
|
||||
virtual void addTempRoot(const Path & path) = 0;
|
||||
virtual void addTempRoot(const Path & path)
|
||||
{ unsupported("addTempRoot"); }
|
||||
|
||||
/* Add an indirect root, which is merely a symlink to `path' from
|
||||
/nix/var/nix/gcroots/auto/<hash of `path'>. `path' is supposed
|
||||
to be a symlink to a store path. The garbage collector will
|
||||
automatically remove the indirect root when it finds that
|
||||
`path' has disappeared. */
|
||||
virtual void addIndirectRoot(const Path & path) = 0;
|
||||
virtual void addIndirectRoot(const Path & path)
|
||||
{ unsupported("addIndirectRoot"); }
|
||||
|
||||
/* Acquire the global GC lock, then immediately release it. This
|
||||
function must be called after registering a new permanent root,
|
||||
@@ -478,11 +485,15 @@ public:
|
||||
|
||||
/* Find the roots of the garbage collector. Each root is a pair
|
||||
(link, storepath) where `link' is the path of the symlink
|
||||
outside of the Nix store that point to `storePath'. */
|
||||
virtual Roots findRoots() = 0;
|
||||
outside of the Nix store that point to `storePath'. If
|
||||
'censor' is true, privacy-sensitive information about roots
|
||||
found in /proc is censored. */
|
||||
virtual Roots findRoots(bool censor)
|
||||
{ unsupported("findRoots"); }
|
||||
|
||||
/* Perform a garbage collection. */
|
||||
virtual void collectGarbage(const GCOptions & options, GCResults & results) = 0;
|
||||
virtual void collectGarbage(const GCOptions & options, GCResults & results)
|
||||
{ unsupported("collectGarbage"); }
|
||||
|
||||
/* Return a string representing information about the path that
|
||||
can be loaded into the database using `nix-store --load-db' or
|
||||
@@ -513,11 +524,13 @@ public:
|
||||
virtual bool verifyStore(bool checkContents, RepairFlag repair = NoRepair) { return false; };
|
||||
|
||||
/* Return an object to access files in the Nix store. */
|
||||
virtual ref<FSAccessor> getFSAccessor() = 0;
|
||||
virtual ref<FSAccessor> getFSAccessor()
|
||||
{ unsupported("getFSAccessor"); }
|
||||
|
||||
/* Add signatures to the specified store path. The signatures are
|
||||
not verified. */
|
||||
virtual void addSignatures(const Path & storePath, const StringSet & sigs) = 0;
|
||||
virtual void addSignatures(const Path & storePath, const StringSet & sigs)
|
||||
{ unsupported("addSignatures"); }
|
||||
|
||||
/* Utility functions. */
|
||||
|
||||
@@ -620,9 +633,9 @@ protected:
|
||||
Stats stats;
|
||||
|
||||
/* Unsupported methods. */
|
||||
[[noreturn]] void unsupported()
|
||||
[[noreturn]] void unsupported(const std::string & op)
|
||||
{
|
||||
throw Unsupported("requested operation is not supported by store '%s'", getUri());
|
||||
throw Unsupported("operation '%s' is not supported by store '%s'", op, getUri());
|
||||
}
|
||||
|
||||
};
|
||||
@@ -789,4 +802,8 @@ ValidPathInfo decodeValidPathInfo(std::istream & str,
|
||||
for paths created by makeFixedOutputPath() / addToStore(). */
|
||||
std::string makeFixedOutputCA(bool recursive, const Hash & hash);
|
||||
|
||||
|
||||
/* Split URI into protocol+hierarchy part and its parameter set. */
|
||||
std::pair<std::string, Store::Params> splitUriAndParams(const std::string & uri);
|
||||
|
||||
}
|
||||
|
||||
@@ -331,7 +331,7 @@ struct RestoreSink : ParseSink
|
||||
filesystem doesn't support preallocation (e.g. on
|
||||
OpenSolaris). Since preallocation is just an
|
||||
optimisation, ignore it. */
|
||||
if (errno && errno != EINVAL)
|
||||
if (errno && errno != EINVAL && errno != EOPNOTSUPP && errno != ENOSYS)
|
||||
throw SysError(format("preallocating file of %1% bytes") % len);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <experimental/optional>
|
||||
#include <optional>
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
|
||||
/* Look up an item in the cache. If it exists, it becomes the most
|
||||
recently used item. */
|
||||
std::experimental::optional<Value> get(const Key & key)
|
||||
std::optional<Value> get(const Key & key)
|
||||
{
|
||||
auto i = data.find(key);
|
||||
if (i == data.end()) return {};
|
||||
|
||||
@@ -171,7 +171,7 @@ std::unique_ptr<Source> sinkToSource(
|
||||
|
||||
std::function<void(Sink &)> fun;
|
||||
std::function<void()> eof;
|
||||
std::experimental::optional<coro_t::pull_type> coro;
|
||||
std::optional<coro_t::pull_type> coro;
|
||||
bool started = false;
|
||||
|
||||
SinkToSource(std::function<void(Sink &)> fun, std::function<void()> eof)
|
||||
|
||||
@@ -936,8 +936,6 @@ pid_t startProcess(std::function<void()> fun, const ProcessOptions & options)
|
||||
throw SysError("setting death signal");
|
||||
#endif
|
||||
restoreAffinity();
|
||||
if (options.restoreMountNamespace)
|
||||
restoreMountNamespace();
|
||||
fun();
|
||||
} catch (std::exception & e) {
|
||||
try {
|
||||
@@ -967,7 +965,7 @@ std::vector<char *> stringsToCharPtrs(const Strings & ss)
|
||||
|
||||
|
||||
string runProgram(Path program, bool searchPath, const Strings & args,
|
||||
const std::experimental::optional<std::string> & input)
|
||||
const std::optional<std::string> & input)
|
||||
{
|
||||
RunOptions opts(program, args);
|
||||
opts.searchPath = searchPath;
|
||||
@@ -1506,26 +1504,4 @@ std::unique_ptr<InterruptCallback> createInterruptCallback(std::function<void()>
|
||||
return std::unique_ptr<InterruptCallback>(res.release());
|
||||
}
|
||||
|
||||
static AutoCloseFD fdSavedMountNamespace;
|
||||
|
||||
void saveMountNamespace()
|
||||
{
|
||||
#if __linux__
|
||||
std::once_flag done;
|
||||
std::call_once(done, []() {
|
||||
fdSavedMountNamespace = open("/proc/self/ns/mnt", O_RDONLY);
|
||||
if (!fdSavedMountNamespace)
|
||||
throw SysError("saving parent mount namespace");
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void restoreMountNamespace()
|
||||
{
|
||||
#if __linux__
|
||||
if (fdSavedMountNamespace && setns(fdSavedMountNamespace.get(), CLONE_NEWNS) == -1)
|
||||
throw SysError("restoring parent mount namespace");
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <cstdio>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <experimental/optional>
|
||||
#include <optional>
|
||||
#include <future>
|
||||
|
||||
#ifndef HAVE_STRUCT_DIRENT_D_TYPE
|
||||
@@ -250,7 +250,6 @@ struct ProcessOptions
|
||||
bool dieWithParent = true;
|
||||
bool runExitHandlers = false;
|
||||
bool allowVfork = true;
|
||||
bool restoreMountNamespace = true;
|
||||
};
|
||||
|
||||
pid_t startProcess(std::function<void()> fun, const ProcessOptions & options = ProcessOptions());
|
||||
@@ -260,14 +259,14 @@ pid_t startProcess(std::function<void()> fun, const ProcessOptions & options = P
|
||||
shell backtick operator). */
|
||||
string runProgram(Path program, bool searchPath = false,
|
||||
const Strings & args = Strings(),
|
||||
const std::experimental::optional<std::string> & input = {});
|
||||
const std::optional<std::string> & input = {});
|
||||
|
||||
struct RunOptions
|
||||
{
|
||||
Path program;
|
||||
bool searchPath = true;
|
||||
Strings args;
|
||||
std::experimental::optional<std::string> input;
|
||||
std::optional<std::string> input;
|
||||
Source * standardIn = nullptr;
|
||||
Sink * standardOut = nullptr;
|
||||
bool _killStderr = false;
|
||||
@@ -515,13 +514,4 @@ typedef std::function<bool(const Path & path)> PathFilter;
|
||||
extern PathFilter defaultPathFilter;
|
||||
|
||||
|
||||
/* Save the current mount namespace. Ignored if called more than
|
||||
once. */
|
||||
void saveMountNamespace();
|
||||
|
||||
/* Restore the mount namespace saved by saveMountNamespace(). Ignored
|
||||
if saveMountNamespace() was never called. */
|
||||
void restoreMountNamespace();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -401,6 +401,8 @@ static void _main(int argc, char * * argv)
|
||||
} else
|
||||
env[var.first] = var.second;
|
||||
|
||||
restoreAffinity();
|
||||
|
||||
/* Run a shell using the derivation's environment. For
|
||||
convenience, source $stdenv/setup to setup additional
|
||||
environment variables and shell functions. Also don't
|
||||
@@ -444,9 +446,7 @@ static void _main(int argc, char * * argv)
|
||||
|
||||
auto argPtrs = stringsToCharPtrs(args);
|
||||
|
||||
restoreAffinity();
|
||||
restoreSignals();
|
||||
restoreMountNamespace();
|
||||
|
||||
execvp(shell.c_str(), argPtrs.data());
|
||||
|
||||
|
||||
@@ -475,11 +475,19 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||
|
||||
case wopFindRoots: {
|
||||
logger->startWork();
|
||||
Roots roots = store->findRoots();
|
||||
Roots roots = store->findRoots(!trusted);
|
||||
logger->stopWork();
|
||||
to << roots.size();
|
||||
|
||||
size_t size = 0;
|
||||
for (auto & i : roots)
|
||||
to << i.first << i.second;
|
||||
size += i.second.size();
|
||||
|
||||
to << size;
|
||||
|
||||
for (auto & [target, links] : roots)
|
||||
for (auto & link : links)
|
||||
to << link << target;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -427,10 +427,11 @@ static void opQuery(Strings opFlags, Strings opArgs)
|
||||
maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise),
|
||||
referrers, true, settings.gcKeepOutputs, settings.gcKeepDerivations);
|
||||
}
|
||||
Roots roots = store->findRoots();
|
||||
for (auto & i : roots)
|
||||
if (referrers.find(i.second) != referrers.end())
|
||||
cout << format("%1%\n") % i.first;
|
||||
Roots roots = store->findRoots(false);
|
||||
for (auto & [target, links] : roots)
|
||||
if (referrers.find(target) != referrers.end())
|
||||
for (auto & link : links)
|
||||
cout << format("%1% -> %2%\n") % link % target;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -485,11 +486,16 @@ static void opReadLog(Strings opFlags, Strings opArgs)
|
||||
static void opDumpDB(Strings opFlags, Strings opArgs)
|
||||
{
|
||||
if (!opFlags.empty()) throw UsageError("unknown flag");
|
||||
if (!opArgs.empty())
|
||||
throw UsageError("no arguments expected");
|
||||
PathSet validPaths = store->queryAllValidPaths();
|
||||
for (auto & i : validPaths)
|
||||
cout << store->makeValidityRegistration({i}, true, true);
|
||||
if (!opArgs.empty()) {
|
||||
for (auto & i : opArgs)
|
||||
i = store->followLinksToStorePath(i);
|
||||
for (auto & i : opArgs)
|
||||
cout << store->makeValidityRegistration({i}, true, true);
|
||||
} else {
|
||||
PathSet validPaths = store->queryAllValidPaths();
|
||||
for (auto & i : validPaths)
|
||||
cout << store->makeValidityRegistration({i}, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -585,9 +591,14 @@ static void opGC(Strings opFlags, Strings opArgs)
|
||||
if (!opArgs.empty()) throw UsageError("no arguments expected");
|
||||
|
||||
if (printRoots) {
|
||||
Roots roots = store->findRoots();
|
||||
for (auto & i : roots)
|
||||
cout << i.first << " -> " << i.second << std::endl;
|
||||
Roots roots = store->findRoots(false);
|
||||
std::set<std::pair<Path, Path>> roots2;
|
||||
// Transpose and sort the roots.
|
||||
for (auto & [target, links] : roots)
|
||||
for (auto & link : links)
|
||||
roots2.emplace(link, target);
|
||||
for (auto & [link, target] : roots2)
|
||||
std::cout << link << " -> " << target << "\n";
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
@@ -8,7 +8,7 @@ using namespace nix;
|
||||
struct CmdAddToStore : MixDryRun, StoreCommand
|
||||
{
|
||||
Path path;
|
||||
std::experimental::optional<std::string> namePart;
|
||||
std::optional<std::string> namePart;
|
||||
|
||||
CmdAddToStore()
|
||||
{
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "eval.hh"
|
||||
#include "attr-path.hh"
|
||||
#include "progress-bar.hh"
|
||||
#include "affinity.hh"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -73,10 +72,6 @@ struct CmdEdit : InstallableCommand
|
||||
|
||||
stopProgressBar();
|
||||
|
||||
restoreAffinity();
|
||||
restoreSignals();
|
||||
restoreMountNamespace();
|
||||
|
||||
execvp(args.front().c_str(), stringsToCharPtrs(args).data());
|
||||
|
||||
throw SysError("cannot run editor '%s'", editor);
|
||||
|
||||
@@ -337,8 +337,6 @@ static int runProgram(const string & program, const Strings & args)
|
||||
if (pid == -1) throw SysError("forking");
|
||||
if (pid == 0) {
|
||||
restoreAffinity();
|
||||
restoreSignals();
|
||||
restoreMountNamespace();
|
||||
execvp(program.c_str(), stringsToCharPtrs(args2).data());
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
@@ -153,9 +153,9 @@ struct CmdRun : InstallablesCommand
|
||||
|
||||
stopProgressBar();
|
||||
|
||||
restoreAffinity();
|
||||
restoreSignals();
|
||||
restoreMountNamespace();
|
||||
|
||||
restoreAffinity();
|
||||
|
||||
/* If this is a diverted store (i.e. its "logical" location
|
||||
(typically /nix/store) differs from its "physical" location
|
||||
|
||||
@@ -7,7 +7,7 @@ outPath=$(nix-store -rvv "$drvPath")
|
||||
rm -f "$NIX_STATE_DIR"/gcroots/foo
|
||||
ln -sf $outPath "$NIX_STATE_DIR"/gcroots/foo
|
||||
|
||||
[ "$(nix-store -q --roots $outPath)" = "$NIX_STATE_DIR"/gcroots/foo ]
|
||||
[ "$(nix-store -q --roots $outPath)" = "$NIX_STATE_DIR/gcroots/foo -> $outPath" ]
|
||||
|
||||
nix-store --gc --print-roots | grep $outPath
|
||||
nix-store --gc --print-live | grep $outPath
|
||||
|
||||
1
tests/lang/eval-okay-context-introspection.exp
Normal file
1
tests/lang/eval-okay-context-introspection.exp
Normal file
@@ -0,0 +1 @@
|
||||
true
|
||||
24
tests/lang/eval-okay-context-introspection.nix
Normal file
24
tests/lang/eval-okay-context-introspection.nix
Normal file
@@ -0,0 +1,24 @@
|
||||
let
|
||||
drv = derivation {
|
||||
name = "fail";
|
||||
builder = "/bin/false";
|
||||
system = "x86_64-linux";
|
||||
outputs = [ "out" "foo" ];
|
||||
};
|
||||
|
||||
path = "${./eval-okay-context-introspection.nix}";
|
||||
|
||||
desired-context = {
|
||||
"${builtins.unsafeDiscardStringContext path}" = {
|
||||
path = true;
|
||||
};
|
||||
"${builtins.unsafeDiscardStringContext drv.drvPath}" = {
|
||||
outputs = [ "foo" "out" ];
|
||||
allOutputs = true;
|
||||
};
|
||||
};
|
||||
|
||||
legit-context = builtins.getContext "${path}${drv.outPath}${drv.foo.outPath}${drv.drvPath}";
|
||||
|
||||
constructed-context = builtins.getContext (builtins.appendContext "" desired-context);
|
||||
in legit-context == constructed-context
|
||||
@@ -1 +1 @@
|
||||
[ true false true false true false true false true true true true true true true true true true true false true false "int" "bool" "string" "null" "set" "list" "lambda" "lambda" "lambda" "lambda" ]
|
||||
[ true false true false true false true false true true true true true true true true true true true false true true true false "int" "bool" "string" "null" "set" "list" "lambda" "lambda" "lambda" "lambda" ]
|
||||
|
||||
@@ -20,6 +20,8 @@ with builtins;
|
||||
(isFloat (1 - 2.0))
|
||||
(isBool (true && false))
|
||||
(isBool null)
|
||||
(isPath /nix/store)
|
||||
(isPath ./.)
|
||||
(isAttrs { x = 123; })
|
||||
(isAttrs null)
|
||||
(typeOf (3 * 4))
|
||||
|
||||
Reference in New Issue
Block a user