Compare commits

..

1 Commits
2.0 ... memoise

Author SHA1 Message Date
Eelco Dolstra
0395b9b94a Add memoise primop
'builtins.memoise f x' is equal to 'f x', but uses a cache to speed up
repeated invocations of 'f' with the same 'x'. A typical application
is memoising evaluations of Nixpkgs in NixOps network
specifications. For example, with the patch below, the time to
evaluate a 10-machine NixOps network is reduced from 17.1s to 9.6s,
while memory consumption goes from 4486 MiB to 3089 MiB. (This is with
GC_INITIAL_HEAP_SIZE=16G.)

Nixpkgs patch:

diff --git a/pkgs/top-level/impure.nix b/pkgs/top-level/impure.nix
index a9f21e45aed..f641067e022 100644
--- a/pkgs/top-level/impure.nix
+++ b/pkgs/top-level/impure.nix
@@ -79,7 +79,7 @@ in
 # not be passed.
 assert args ? localSystem -> !(args ? system || args ? platform);

-import ./. (builtins.removeAttrs args [ "system" "platform" ] // {
+builtins.memoise or (x: x) (import ./.) (builtins.removeAttrs args [ "system" "platform" ] // {
   inherit config overlays crossSystem;
   # Fallback: Assume we are building packages on the current (build, in GNU
   # Autotools parlance) system.
2018-01-11 19:24:22 +01:00
128 changed files with 2526 additions and 4104 deletions

View File

@@ -14,7 +14,7 @@ Examples of _Nix_ issues:
- Nix segfaults when I run `nix-build -A blahblah`
- The Nix language needs a new builtin: `builtins.foobar`
- Regression in the behavior of `nix-env` in Nix 2.0
- Regression in the behavior of `nix-env` in Nix 1.12
Examples of _nixpkgs_ issues:
@@ -24,4 +24,4 @@ Examples of _nixpkgs_ issues:
Chances are if you're a newcomer to the Nix world, you'll probably want the [nixpkgs tracker](https://github.com/NixOS/nixpkgs/issues). It also gets a lot more eyeball traffic so you'll probably get a response a lot more quickly.
-->
-->

1
.gitignore vendored
View File

@@ -38,7 +38,6 @@ perl/Makefile.config
/scripts/nix-copy-closure
/scripts/nix-reduce-build
/scripts/nix-http-export.cgi
/scripts/nix-profile-daemon.sh
# /src/libexpr/
/src/libexpr/lexer-tab.cc

View File

@@ -24,8 +24,7 @@ makefiles = \
misc/launchd/local.mk \
misc/upstart/local.mk \
doc/manual/local.mk \
tests/local.mk \
tests/plugins/local.mk
tests/local.mk
GLOBAL_CXXFLAGS += -std=c++14 -g -Wall -include config.h

View File

@@ -7,7 +7,6 @@ ENABLE_S3 = @ENABLE_S3@
HAVE_SODIUM = @HAVE_SODIUM@
HAVE_READLINE = @HAVE_READLINE@
HAVE_BROTLI = @HAVE_BROTLI@
HAVE_SECCOMP = @HAVE_SECCOMP@
LIBCURL_LIBS = @LIBCURL_LIBS@
OPENSSL_LIBS = @OPENSSL_LIBS@
PACKAGE_NAME = @PACKAGE_NAME@

View File

@@ -61,7 +61,6 @@ CFLAGS=
CXXFLAGS=
AC_PROG_CC
AC_PROG_CXX
AC_PROG_CPP
AX_CXX_COMPILE_STDCXX_11
@@ -175,8 +174,6 @@ AC_SUBST(HAVE_SODIUM, [$have_sodium])
# Look for liblzma, a required dependency.
PKG_CHECK_MODULES([LIBLZMA], [liblzma], [CXXFLAGS="$LIBLZMA_CFLAGS $CXXFLAGS"])
AC_CHECK_LIB([lzma], [lzma_stream_encoder_mt],
[AC_DEFINE([HAVE_LZMA_MT], [1], [xz multithreaded compression support])])
# Look for libbrotli{enc,dec}, optional dependencies
@@ -188,22 +185,9 @@ AC_SUBST(HAVE_BROTLI, [$have_brotli])
# Look for libseccomp, required for Linux sandboxing.
if test "$sys_name" = linux; then
AC_ARG_ENABLE([seccomp-sandboxing],
AC_HELP_STRING([--disable-seccomp-sandboxing],
[Don't build support for seccomp sandboxing (only recommended if your arch doesn't support libseccomp yet!)]
))
if test "x$enable_seccomp_sandboxing" != "xno"; then
PKG_CHECK_MODULES([LIBSECCOMP], [libseccomp],
[CXXFLAGS="$LIBSECCOMP_CFLAGS $CXXFLAGS"])
have_seccomp=1
AC_DEFINE([HAVE_SECCOMP], [1], [Whether seccomp is available and should be used for sandboxing.])
else
have_seccomp=
fi
else
have_seccomp=
PKG_CHECK_MODULES([LIBSECCOMP], [libseccomp],
[CXXFLAGS="$LIBSECCOMP_CFLAGS $CXXFLAGS"])
fi
AC_SUBST(HAVE_SECCOMP, [$have_seccomp])
# Look for aws-cpp-sdk-s3.
@@ -215,7 +199,7 @@ AC_SUBST(ENABLE_S3, [$enable_s3])
AC_LANG_POP(C++)
if test -n "$enable_s3"; then
declare -a aws_version_tokens=($(printf '#include <aws/core/VersionConfig.h>\nAWS_SDK_VERSION_STRING' | $CPP - | grep -v '^#.*' | sed 's/"//g' | tr '.' ' '))
declare -a aws_version_tokens=($(printf '#include <aws/core/VersionConfig.h>\nAWS_SDK_VERSION_STRING' | cpp -E | grep -v '^#.*' | sed 's/"//g' | tr '.' ' '))
AC_DEFINE_UNQUOTED([AWS_VERSION_MAJOR], ${aws_version_tokens@<:@0@:>@}, [Major version of aws-sdk-cpp.])
AC_DEFINE_UNQUOTED([AWS_VERSION_MINOR], ${aws_version_tokens@<:@1@:>@}, [Minor version of aws-sdk-cpp.])
fi

View File

@@ -1,4 +1,4 @@
{ system ? "" # obsolete
{ system ? builtins.currentSystem
, url
, md5 ? "", sha1 ? "", sha256 ? "", sha512 ? ""
, outputHash ?
@@ -17,9 +17,7 @@ derivation {
inherit outputHashAlgo outputHash;
outputHashMode = if unpack || executable then "recursive" else "flat";
inherit name url executable unpack;
system = "builtin";
inherit name system url executable unpack;
# No need to double the amount of network traffic
preferLocalBuild = true;

View File

@@ -4,109 +4,71 @@
version="5.0"
xml:id='chap-distributed-builds'>
<title>Remote Builds</title>
<title>Distributed Builds</title>
<para>Nix supports remote builds, where a local Nix installation can
forward Nix builds to other machines. This allows multiple builds to
be performed in parallel and allows Nix to perform multi-platform
builds in a semi-transparent way. For instance, if you perform a
build for a <literal>x86_64-darwin</literal> on an
<literal>i686-linux</literal> machine, Nix can automatically forward
the build to a <literal>x86_64-darwin</literal> machine, if
available.</para>
<para>Nix supports distributed builds, where a local Nix installation can
forward Nix builds to other machines over the network. This allows
multiple builds to be performed in parallel (thus improving
performance) and allows Nix to perform multi-platform builds in a
semi-transparent way. For instance, if you perform a build for a
<literal>x86_64-darwin</literal> on an <literal>i686-linux</literal>
machine, Nix can automatically forward the build to a
<literal>x86_64-darwin</literal> machine, if available.</para>
<para>To forward a build to a remote machine, its required that the
remote machine is accessible via SSH and that it has Nix
installed. You can test whether connecting to the remote Nix instance
works, e.g.
<para>You can enable distributed builds by setting the environment
variable <envar>NIX_BUILD_HOOK</envar> to point to a program that Nix
will call whenever it wants to build a derivation. The build hook
(typically a shell or Perl script) can decline the build, in which Nix
will perform it in the usual way if possible, or it can accept it, in
which case it is responsible for somehow getting the inputs of the
build to another machine, doing the build there, and getting the
results back.</para>
<screen>
$ nix ping-store --store ssh://mac
</screen>
<example xml:id='ex-remote-systems'><title>Remote machine configuration:
<filename>remote-systems.conf</filename></title>
<programlisting>
nix@mcflurry.labs.cs.uu.nl x86_64-darwin /home/nix/.ssh/id_quarterpounder_auto 2
nix@scratchy.labs.cs.uu.nl i686-linux /home/nix/.ssh/id_scratchy_auto 8 1 kvm
nix@itchy.labs.cs.uu.nl i686-linux /home/nix/.ssh/id_scratchy_auto 8 2
nix@poochie.labs.cs.uu.nl i686-linux /home/nix/.ssh/id_scratchy_auto 8 2 kvm perf
</programlisting>
</example>
will try to connect to the machine named <literal>mac</literal>. It is
possible to specify an SSH identity file as part of the remote store
URI, e.g.
<screen>
$ nix ping-store --store ssh://mac?ssh-key=/home/alice/my-key
</screen>
Since builds should be non-interactive, the key should not have a
passphrase. Alternatively, you can load identities ahead of time into
<command>ssh-agent</command> or <command>gpg-agent</command>.</para>
<para>If you get the error
<screen>
bash: nix-store: command not found
error: cannot connect to 'mac'
</screen>
then you need to ensure that the <envar>PATH</envar> of
non-interactive login shells contains Nix.</para>
<warning><para>If you are building via the Nix daemon, it is the Nix
daemon user account (that is, <literal>root</literal>) that should
have SSH access to the remote machine. If you cant or dont want to
configure <literal>root</literal> to be able to access to remote
machine, you can use a private Nix store instead by passing
e.g. <literal>--store ~/my-nix</literal>.</para></warning>
<para>The list of remote machines can be specified on the command line
or in the Nix configuration file. The former is convenient for
testing. For example, the following command allows you to build a
derivation for <literal>x86_64-darwin</literal> on a Linux machine:
<screen>
$ uname
Linux
$ nix build \
'(with import &lt;nixpkgs> { system = "x86_64-darwin"; }; runCommand "foo" {} "uname > $out")' \
--builders 'ssh://mac x86_64-darwin'
[1/0/1 built, 0.0 MiB DL] building foo on ssh://mac
$ cat ./result
Darwin
</screen>
It is possible to specify multiple builders separated by a semicolon
or a newline, e.g.
<screen>
--builders 'ssh://mac x86_64-darwin ; ssh://beastie x86_64-freebsd'
</screen>
</para>
<para>Each machine specification consists of the following elements,
separated by spaces. Only the first element is required.
<para>Nix ships with a build hook that should be suitable for most
purposes. It uses <command>ssh</command> and
<command>nix-copy-closure</command> to copy the build inputs and
outputs and perform the remote build. To use it, you should set
<envar>NIX_BUILD_HOOK</envar> to
<filename><replaceable>prefix</replaceable>/libexec/nix/build-remote</filename>.
You should also define a list of available build machines and point
the environment variable <envar>NIX_REMOTE_SYSTEMS</envar> to
it. <envar>NIX_REMOTE_SYSTEMS</envar> must be an absolute path. An
example configuration is shown in <xref linkend='ex-remote-systems'
/>. Each line in the file specifies a machine, with the following
bits of information:
<orderedlist>
<listitem><para>The URI of the remote store in the format
<literal>ssh://[<replaceable>username</replaceable>@]<replaceable>hostname</replaceable></literal>,
e.g. <literal>ssh://nix@mac</literal> or
<literal>ssh://mac</literal>. For backward compatibility,
<literal>ssh://</literal> may be omitted. The hostname may be an
alias defined in your
<listitem><para>The name of the remote machine, with optionally the
user under which the remote build should be performed. This is
actually passed as an argument to <command>ssh</command>, so it can
be an alias defined in your
<filename>~/.ssh/config</filename>.</para></listitem>
<listitem><para>A comma-separated list of Nix platform type
identifiers, such as <literal>x86_64-darwin</literal>. It is
possible for a machine to support multiple platform types, e.g.,
<literal>i686-linux,x86_64-linux</literal>. If omitted, this
defaults to the local platform type.</para></listitem>
<literal>i686-linux,x86_64-linux</literal>.</para></listitem>
<listitem><para>The SSH identity file to be used to log in to the
remote machine. If omitted, SSH will use its regular
identities.</para></listitem>
<listitem><para>The SSH private key to be used to log in to the
remote machine. Since builds should be non-interactive, this key
should not have a passphrase!</para></listitem>
<listitem><para>The maximum number of builds that Nix will execute
in parallel on the machine. Typically this should be equal to the
number of CPU cores. For instance, the machine
<literal>itchy</literal> in the example will execute up to 8 builds
in parallel.</para></listitem>
<listitem><para>The maximum number of builds that
<filename>build-remote</filename> will execute in parallel on the
machine. Typically this should be equal to the number of CPU cores.
For instance, the machine <literal>itchy</literal> in the example
will execute up to 8 builds in parallel.</para></listitem>
<listitem><para>The “speed factor”, indicating the relative speed of
the machine. If there are multiple machines of the right type, Nix
@@ -114,69 +76,30 @@ separated by spaces. Only the first element is required.
<listitem><para>A comma-separated list of <emphasis>supported
features</emphasis>. If a derivation has the
<varname>requiredSystemFeatures</varname> attribute, then Nix will
only perform the derivation on a machine that has the specified
features. For instance, the attribute
<varname>requiredSystemFeatures</varname> attribute, then
<filename>build-remote</filename> will only perform the
derivation on a machine that has the specified features. For
instance, the attribute
<programlisting>
requiredSystemFeatures = [ "kvm" ];
</programlisting>
will cause the build to be performed on a machine that has the
<literal>kvm</literal> feature.</para></listitem>
<literal>kvm</literal> feature (i.e., <literal>scratchy</literal> in
the example above).</para></listitem>
<listitem><para>A comma-separated list of <emphasis>mandatory
features</emphasis>. A machine will only be used to build a
derivation if all of the machines mandatory features appear in the
derivations <varname>requiredSystemFeatures</varname>
attribute..</para></listitem>
derivations <varname>requiredSystemFeatures</varname> attribute.
Thus, in the example, the machine <literal>poochie</literal> will
only do derivations that have
<varname>requiredSystemFeatures</varname> set to <literal>["kvm"
"perf"]</literal> or <literal>["perf"]</literal>.</para></listitem>
</orderedlist>
For example, the machine specification
<programlisting>
nix@scratchy.labs.cs.uu.nl i686-linux /home/nix/.ssh/id_scratchy_auto 8 1 kvm
nix@itchy.labs.cs.uu.nl i686-linux /home/nix/.ssh/id_scratchy_auto 8 2
nix@poochie.labs.cs.uu.nl i686-linux /home/nix/.ssh/id_scratchy_auto 1 2 kvm benchmark
</programlisting>
specifies several machines that can perform
<literal>i686-linux</literal> builds. However,
<literal>poochie</literal> will only do builds that have the attribute
<programlisting>
requiredSystemFeatures = [ "benchmark" ];
</programlisting>
or
<programlisting>
requiredSystemFeatures = [ "benchmark" "kvm" ];
</programlisting>
<literal>itchy</literal> cannot do builds that require
<literal>kvm</literal>, but <literal>scratchy</literal> does support
such builds. For regular builds, <literal>itchy</literal> will be
preferred over <literal>scratchy</literal> because it has a higher
speed factor.</para>
<para>Remote builders can also be configured in
<filename>nix.conf</filename>, e.g.
<programlisting>
builders = ssh://mac x86_64-darwin ; ssh://beastie x86_64-freebsd
</programlisting>
Finally, remote builders can be configured in a separate configuration
file included in <option>builders</option> via the syntax
<literal>@<replaceable>file</replaceable></literal>. For example,
<programlisting>
builders = @/etc/nix/machines
</programlisting>
causes the list of machines in <filename>/etc/nix/machines</filename>
to be included. (This is the default.)</para>
</para>
</chapter>

File diff suppressed because it is too large Load Diff

View File

@@ -154,8 +154,6 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
<literal>daemon</literal> if you want to use the Nix daemon to
execute Nix operations. This is necessary in <link
linkend="ssec-multi-user">multi-user Nix installations</link>.
If the Nix daemon's Unix socket is at some non-standard path,
this variable should be set to <literal>unix://path/to/socket</literal>.
Otherwise, it should be left unset.</para></listitem>
</varlistentry>

View File

@@ -29,6 +29,8 @@
</group>
<replaceable>attrPath</replaceable>
</arg>
<arg><option>--drv-link</option> <replaceable>drvlink</replaceable></arg>
<arg><option>--add-drv-link</option></arg>
<arg><option>--no-out-link</option></arg>
<arg>
<group choice='req'>
@@ -89,6 +91,25 @@ also <xref linkend="sec-common-options" />.</phrase></para>
<variablelist>
<varlistentry><term><option>--drv-link</option> <replaceable>drvlink</replaceable></term>
<listitem><para>Add a symlink named
<replaceable>drvlink</replaceable> to the store derivation
produced by <command>nix-instantiate</command>. The derivation is
a root of the garbage collector until the symlink is deleted or
renamed. If there are multiple derivations, numbers are suffixed
to <replaceable>drvlink</replaceable> to distinguish between
them.</para></listitem>
</varlistentry>
<varlistentry><term><option>--add-drv-link</option></term>
<listitem><para>Shorthand for <option>--drv-link</option>
<filename>./derivation</filename>.</para></listitem>
</varlistentry>
<varlistentry><term><option>--no-out-link</option></term>
<listitem><para>Do not create a symlink to the output path. Note

View File

@@ -47,6 +47,7 @@
</arg>
<arg><option>--fallback</option></arg>
<arg><option>--readonly-mode</option></arg>
<arg><option>--show-trace</option></arg>
<arg>
<option>-I</option>
<replaceable>path</replaceable>

View File

@@ -301,6 +301,13 @@
</varlistentry>
<varlistentry><term><option>--show-trace</option></term>
<listitem><para>Causes Nix to print out a stack trace in case of Nix
expression evaluation errors.</para></listitem>
</varlistentry>
<varlistentry xml:id="opt-I"><term><option>-I</option> <replaceable>path</replaceable></term>

View File

@@ -126,17 +126,6 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
</varlistentry>
<varlistentry><term><function>builtins.splitVersion</function>
<replaceable>s</replaceable></term>
<listitem><para>Split a string representing a version into its
components, by the same version splitting logic underlying the
version comparison in <link linkend="ssec-version-comparisons">
<command>nix-env -u</command></link>.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.concatLists</function>
<replaceable>lists</replaceable></term>
@@ -319,9 +308,8 @@ stdenv.mkDerivation { … }
</varlistentry>
<varlistentry xml:id='builtin-filterSource'>
<term><function>builtins.filterSource</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<varlistentry><term><function>builtins.filterSource</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<listitem>
@@ -780,75 +768,6 @@ Evaluates to <literal>[ "foo" ]</literal>.
</varlistentry>
<varlistentry>
<term>
<function>builtins.path</function>
<replaceable>args</replaceable>
</term>
<listitem>
<para>
An enrichment of the built-in path type, based on the attributes
present in <replaceable>args</replaceable>. All are optional
except <varname>path</varname>:
</para>
<variablelist>
<varlistentry>
<term>path</term>
<listitem>
<para>The underlying path.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>name</term>
<listitem>
<para>
The name of the path when added to the store. This can
used to reference paths that have nix-illegal characters
in their names, like <literal>@</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>filter</term>
<listitem>
<para>
A function of the type expected by
<link linkend="builtin-filterSource">builtins.filterSource</link>,
with the same semantics.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>recursive</term>
<listitem>
<para>
When <literal>false</literal>, when
<varname>path</varname> is added to the store it is with a
flat hash, rather than a hash of the NAR serialization of
the file. Thus, <varname>path</varname> must refer to a
regular file, not a directory. This allows similar
behavior to <literal>fetchurl</literal>. Defaults to
<literal>true</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>sha256</term>
<listitem>
<para>
When provided, this is the expected hash of the file at
the path. Evaluation will fail if the hash is incorrect,
and providing a hash allows
<literal>builtins.path</literal> to be used even when the
<literal>pure-eval</literal> nix config option is on.
</para>
</listitem>
</varlistentry>
</variablelist>
</listitem>
</varlistentry>
<varlistentry><term><function>builtins.pathExists</function>
<replaceable>path</replaceable></term>

View File

@@ -0,0 +1,34 @@
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="sec-debug-build">
<title>Debugging Build Failures</title>
<para>At the beginning of each phase of the build (such as unpacking,
building or installing), the set of all shell variables is written to
the file <filename>env-vars</filename> at the top-level build
directory. This is useful for debugging: it allows you to recreate
the environment in which a build was performed. For instance, if a
build fails, then assuming you used the <option>-K</option> flag, you
can go to the output directory and <quote>switch</quote> to the
environment of the builder:
<screen>
$ nix-build -K ./foo.nix
... fails, keeping build directory `/tmp/nix-1234-0'
$ cd /tmp/nix-1234-0
$ source env-vars
<lineannotation>(edit some files...)</lineannotation>
$ make
<lineannotation>(execution continues with the same GCC, make, etc.)</lineannotation></screen>
</para>
</section>

View File

@@ -61,7 +61,7 @@ evaluates to <literal>"foobar"</literal>.
<simplesect><title>Inheriting attributes</title>
<para>When defining a set or in a let-expression it is often convenient to copy variables
<para>When defining a set it is often convenient to copy variables
from the surrounding lexical scope (e.g., when you want to propagate
attributes). This can be shortened using the
<literal>inherit</literal> keyword. For instance,
@@ -72,15 +72,7 @@ let x = 123; in
y = 456;
}</programlisting>
is equivalent to
<programlisting>
let x = 123; in
{ x = x;
y = 456;
}</programlisting>
and both evaluate to <literal>{ x = 123; y = 456; }</literal>. (Note that
evaluates to <literal>{ x = 123; y = 456; }</literal>. (Note that
this works because <varname>x</varname> is added to the lexical scope
by the <literal>let</literal> construct.) It is also possible to
inherit attributes from another set. For instance, in this fragment
@@ -109,26 +101,6 @@ variables from the surrounding scope (<varname>fetchurl</varname>
<varname>libXaw</varname> (the X Athena Widgets) from the
<varname>xlibs</varname> (X11 client-side libraries) set.</para>
<para>
Summarizing the fragment
<programlisting>
...
inherit x y z;
inherit (src-set) a b c;
...</programlisting>
is equivalent to
<programlisting>
...
x = x; y = y; z = z;
a = src-set.a; b = src-set.b; c = src-set.c;
...</programlisting>
when used while defining local variables in a let-expression or
while defining a set.</para>
</simplesect>

View File

@@ -81,4 +81,6 @@ Just pass the option <link linkend='opt-max-jobs'><option>-j
in parallel, or set. Typically this should be the number of
CPUs.</para>
<xi:include href="debug-build.xml" />
</section>

View File

@@ -79,6 +79,16 @@ alice$ ./install
</para>
<para>Nix can be uninstalled using <command>rpm -e nix</command> or
<command>dpkg -r nix</command> on RPM- and Dpkg-based systems,
respectively. After this you should manually remove the Nix store and
other auxiliary data, if desired:
<screen>
$ rm -rf /nix</screen>
</para>
<para>You can uninstall Nix simply by running:
<screen>

View File

@@ -52,6 +52,34 @@ This creates 10 build users. There can never be more concurrent builds
than the number of build users, so you may want to increase this if
you expect to do many builds at the same time.</para>
<para>On macOS, you can create the required group and users by
running the following script:
<programlisting>
#! /bin/bash -e
dseditgroup -o create nixbld -q
gid=$(dscl . -read /Groups/nixbld | awk '($1 == "PrimaryGroupID:") {print $2 }')
echo "created nixbld group with gid $gid"
for i in $(seq 1 10); do
user=/Users/nixbld$i
uid="$((30000 + $i))"
dscl . create $user
dscl . create $user RealName "Nix build user $i"
dscl . create $user PrimaryGroupID "$gid"
dscl . create $user UserShell /usr/bin/false
dscl . create $user NFSHomeDirectory /var/empty
dscl . create $user UniqueID "$uid"
dseditgroup -o edit -a nixbld$i -t user nixbld
echo "created nixbld$i user with uid $uid"
done
</programlisting>
</para>
</simplesect>

View File

@@ -33,4 +33,7 @@
</para>
<para>Nix is fairly portable, so it should work on most platforms that
support POSIX threads and have a C++11 compiler.</para>
</chapter>

View File

@@ -15,7 +15,7 @@ to subsequent chapters.</para>
<step><para>Install single-user Nix by running the following:
<screen>
$ bash &lt;(curl https://nixos.org/nix/install)
$ curl https://nixos.org/nix/install | sh
</screen>
This will install Nix in <filename>/nix</filename>. The install script

View File

@@ -12,14 +12,19 @@
<firstname>Eelco</firstname>
<surname>Dolstra</surname>
</personname>
<affiliation>
<orgname>LogicBlox</orgname>
</affiliation>
<contrib>Author</contrib>
</author>
<copyright>
<year>2004-2018</year>
<year>2004-2014</year>
<holder>Eelco Dolstra</holder>
</copyright>
<date>November 2014</date>
</info>
<!--
@@ -36,6 +41,7 @@
<xi:include href="expressions/writing-nix-expressions.xml" />
<xi:include href="advanced-topics/advanced-topics.xml" />
<xi:include href="command-ref/command-ref.xml" />
<xi:include href="troubleshooting/troubleshooting.xml" />
<xi:include href="glossary/glossary.xml" />
<xi:include href="hacking.xml" />
<xi:include href="release-notes/release-notes.xml" />

View File

@@ -12,7 +12,7 @@
</partintro>
-->
<xi:include href="rl-2.0.xml" />
<xi:include href="rl-1.12.xml" />
<xi:include href="rl-1.11.10.xml" />
<xi:include href="rl-1.11.xml" />
<xi:include href="rl-1.10.xml" />

View File

@@ -0,0 +1,426 @@
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="ssec-relnotes-1.12">
<title>Release 1.12 (TBA)</title>
<para>This release has the following new features:</para>
<itemizedlist>
<listitem>
<para>Start of new <command>nix</command> command line
interface. This is a work in progress and the interface is subject
to change.</para>
<itemizedlist>
<listitem><para>Self-documenting: <option>--help</option> shows
all available command-line arguments.</para></listitem>
<listitem><para><option>--help-config</option> shows all
configuration options.</para></listitem>
<listitem><para><command>nix build</command>: Replacement for
<command>nix-build</command>.</para></listitem>
<listitem><para><command>nix ls-store</command> and <command>nix
ls-nar</command> allow listing the contents of a store path or
NAR file.</para></listitem>
<listitem><para><command>nix cat-store</command> and
<command>nix cat-nar</command> allow extracting a file from a
store path or NAR file.</para></listitem>
<listitem><para><command>nix verify</command> checks whether a
store path is unmodified and/or is trusted.</para></listitem>
<listitem><para><command>nix copy-sigs</command> copies
signatures from one store to another.</para></listitem>
<listitem><para><command>nix sign-paths</command> signs store
paths.</para></listitem>
<listitem><para><command>nix copy</command> copies paths between
arbitrary Nix stores, generalising
<command>nix-copy-closure</command> and
<command>nix-push</command>.</para></listitem>
<listitem><para><command>nix path-info</command> shows
information about store paths.</para></listitem>
<listitem><para><command>nix run</command> starts a shell in
which the specified packages are available.</para></listitem>
<listitem><para><command>nix log</command> shows the build log
of a package or path. If the build log is not available locally,
it will try to obtain it from a binary cache.</para></listitem>
<listitem><para><command>nix eval</command> replaces
<command>nix-instantiate --eval</command>.</para></listitem>
<listitem><para><command>nix dump-path</command> to get a NAR
from a store path.</para></listitem>
<listitem><para><command>nix edit</command> opens the source
code of a package in an editor.</para></listitem>
<listitem><para><command>nix search</command> replaces
<command>nix-env -qa</command>. It searches the available
packages for occurences of a search string in the attribute
name, package name or description. It caches available packages
to speed up searches.</para></listitem>
<listitem><para><command>nix why-depends</command> (d41c5eb13f4f3a37d80dbc6d3888644170c3b44a).</para></listitem>
<listitem><para><command>nix show-derivation</command> (e8d6ee7c1b90a2fe6d824f1a875acc56799ae6e2).</para></listitem>
<listitem><para><command>nix add-to-store</command> (970366266b8df712f5f9cedb45af183ef5a8357f).</para></listitem>
<listitem><para>Progress indicator.</para></listitem>
<listitem><para>All options are available as flags now
(b8283773bd64d7da6859ed520ee19867742a03ba).</para></listitem>
</itemizedlist>
</listitem>
<listitem>
<para>The external program <command>nix-repl</command> has been
integrated into Nix as <command>nix repl</command>.</para>
</listitem>
<listitem>
<para>New build mode <command>nix-build --hash</command> that
builds a derivation, computes the hash of the output, and moves
the output to the store path corresponding to what a fixed-output
derivation with that hash would produce.
(Add docs and examples; see d367b8e7875161e655deaa96bf8a5dd0bcf8229e)</para>
</listitem>
<listitem>
<para>It is no longer necessary to set the
<envar>NIX_REMOTE</envar> environment variable if you need to use
the Nix daemon. Nix will use the daemon automatically if you dont
have write access to the Nix database.</para>
</listitem>
<listitem>
<para>The Nix language now supports floating point numbers. They are
based on regular C++ <literal>float</literal> and compatible with
existing integers and number-related operations. Export and import to and
from JSON and XML works, too.</para>
</listitem>
<listitem>
<para><command>nix-shell</command> now sets the
<varname>IN_NIX_SHELL</varname> environment variable during
evaluation and in the shell itself. This can be used to perform
different actions depending on whether youre in a Nix shell or in
a regular build. Nixpkgs provides
<varname>lib.inNixShell</varname> to check this variable during
evaluation. (bb36a1a3cf3fbe6bc9d0afcc5fa0f928bed03170)</para>
</listitem>
<listitem>
<para>Internal: all <classname>Store</classname> classes are now
thread-safe. <classname>RemoteStore</classname> supports multiple
concurrent connections to the daemon. This is primarily useful in
multi-threaded programs such as
<command>hydra-queue-runner</command>.</para>
</listitem>
<listitem>
<para>The dependency on Perl has been removed. As a result, some
(obsolete) programs have been removed: <command>nix-push</command>
(replaced by <command>nix copy</command>),
<command>nix-pull</command> (obsoleted by binary caches),
<command>nix-generate-patches</command>,
<command>bsdiff</command>, <command>bspatch</command>.</para>
</listitem>
<listitem>
<para>Improved store abstraction. Substituters
eliminated. BinaryCacheStore, LocalBinaryCacheStore,
HttpBinaryCacheStore, S3BinaryCacheStore (compile-time
optional), SSHStore. Add docs + examples?
</para>
</listitem>
<listitem>
<para>Nix now stores signatures for local store
paths. Locally-built paths are now signed automatically using the
secret keys specified by the <option>secret-key-files</option>
store option.</para>
<para>In addition, store paths that have been built locally are
marked as “ultimately trusted”, and content-addressable store
paths carry a “content-addressability assertion” that allow them
to be trusted without any signatures.</para>
</listitem>
<listitem>
<para><envar>NIX_PATH</envar> is now lazy, so URIs in the path are
only downloaded if they are needed for evaluation.</para>
</listitem>
<listitem>
<para>You can now use
<uri>channel:<replaceable>channel-name</replaceable></uri> as a
short-hand for
<uri>https://nixos.org/channels/<replaceable>channel-name</replaceable>/nixexprs.tar.xz</uri>. For
example, <literal>nix-build channel:nixos-15.09 -A hello</literal>
will build the GNU Hello package from the
<literal>nixos-15.09</literal> channel.</para>
</listitem>
<listitem>
<para>When <option>--no-build-output</option> is given, the last
10 lines of the build log will be shown if a build
fails.</para>
</listitem>
<listitem>
<para><function>builtins.fetchGit</function>.
(38539b943a060d9cdfc24d6e5d997c0885b8aa2f)</para>
</listitem>
<listitem>
<para><literal>&lt;nix/fetchurl.nix&gt;</literal> now uses the
content-addressable tarball cache at
<uri>http://tarballs.nixos.org/</uri>, just like
<function>fetchurl</function> in
Nixpkgs. (f2682e6e18a76ecbfb8a12c17e3a0ca15c084197)</para>
</listitem>
<listitem>
<para>Chroot Nix stores: allow the “physical” location of the Nix
store (e.g. <filename>/home/alice/nix/store</filename>) to differ
from its “logical” location (typically
<filename>/nix/store</filename>). This allows non-root users to
use Nix while still getting the benefits from prebuilt binaries
from
<uri>cache.nixos.org</uri>. (4494000e04122f24558e1436e66d20d89028b4bd,
3eb621750848e0e6b30e5a79f76afbb096bb6c8a)</para>
</listitem>
<listitem>
<para>On Linux, builds are now executed in a user
namespace with uid 1000 and gid 100.</para>
</listitem>
<listitem>
<para><function>builtins.fetchurl</function> and
<function>builtins.fetchTarball</function> now support
<varname>sha256</varname> and <varname>name</varname>
attributes.</para>
</listitem>
<listitem>
<para><literal>HttpBinaryCacheStore</literal> (the replacement of
<command>download-from-binary-cache</command>) now retries
automatically on certain HTTP error codes.</para>
</listitem>
<listitem>
<para>Derivation attributes can now reference the outputs of the
derivation using the <function>placeholder</function> builtin
function. For example, the attribute
<programlisting>
configureFlags = "--prefix=${placeholder "out"} --includedir=${placeholder "dev"}";
</programlisting>
will cause the <envar>configureFlags</envar> environment variable
to contain the actual store paths corresponding to the
<literal>out</literal> and <literal>dev</literal> outputs. TODO:
add docs.</para>
</listitem>
<listitem>
<para>Support for HTTP/2. This makes binary cache lookups much
more efficient. (90ad02bf626b885a5dd8967894e2eafc953bdf92)</para>
</listitem>
<listitem>
<para>The <option>build-sandbox-paths</option> configuration
option can now specify optional paths by appending a
<literal>?</literal>, e.g. <literal>/dev/nvidiactl?</literal> will
bind-mount <varname>/dev/nvidiactl</varname> only if it
exists.</para>
</listitem>
<listitem>
<para>More support for testing build reproducibility: when
<option>enforce-determinism</option> is set to
<literal>false</literal>, its no longer a fatal error build
rounds produce different output
(8bdf83f936adae6f2c907a6d2541e80d4120f051); add a hook to run
diffoscope when build rounds produce different output
(9a313469a4bdea2d1e8df24d16289dc2a172a169w).</para>
</listitem>
<listitem>
<para>Kill builds as soon as stdout/stderr is closed. This fixes a
bug that allowed builds to hang Nix indefinitely (regardless of
timeouts). (21948deed99a3295e4d5666e027a6ca42dc00b40)</para>
</listitem>
<listitem>
<para>Add support for passing structured data to builders. TODO:
document. (6de33a9c675b187437a2e1abbcb290981a89ecb1)</para>
</listitem>
<listitem>
<para><varname>exportReferencesGraph</varname>: Export more
complete info in JSON
format. (c2b0d8749f7e77afc1c4b3e8dd36b7ee9720af4a)</para>
</listitem>
<listitem>
<para>Support for
netrc. (e6e74f987f0fa284d220432d426eb965269a97d6,
302386f775eea309679654e5ea7c972fb6e7b9af)</para>
</listitem>
<listitem>
<para>Support <uri>s3://</uri> URIs in all places where Nix allows
URIs. (9ff9c3f2f80ba4108e9c945bbfda2c64735f987b)</para>
</listitem>
<listitem>
<para>The <option>build-max-jobs</option> option can be set to
<literal>auto</literal> to use the number of CPUs in the
system. (7251d048fa812d2551b7003bc9f13a8f5d4c95a5)</para>
</listitem>
<listitem>
<para>Add support for Brotli compression.
<uri>cache.nixos.org</uri> compresses build logs using
Brotli.</para>
</listitem>
<listitem>
<para>Substitutions from binary caches now require signatures by
default. This was already the case on
NixOS. (ecbc3fedd3d5bdc5a0e1a0a51b29062f2874ac8b)</para>
</listitem>
<listitem>
<para><command>nix-env</command> now ignores packages with bad
derivation names (in particular those starting with a digit or
containing a
dot). (b0cb11722626e906a73f10dd9a0c9eea29faf43a)</para>
</listitem>
<listitem>
<para>Renamed various configuration options. (TODO: in progress)</para>
</listitem>
<listitem>
<para>Remote machines can now be specified on the command
line. TODO:
document. (1a68710d4dff609bbaf61db3e17a2573f0aadf17)</para>
</listitem>
<listitem>
<para>In Linux sandbox builds, we now use
<filename>/build</filename> instead of <filename>/tmp</filename>
as the temporary build directory. This fixes potential security
problems when a build accidentally stores its
<envar>TMPDIR</envar> in some critical place, such as an
RPATH. (eba840c8a13b465ace90172ff76a0db2899ab11b)</para>
</listitem>
<listitem>
<para>In Linux sandbox builds, we now provide a default
<filename>/bin/sh</filename> (namely <filename>ash</filename> from
BusyBox). (a2d92bb20e82a0957067ede60e91fab256948b41)</para>
</listitem>
<listitem>
<para>Make all configuration options available as command line
flags (b8283773bd64d7da6859ed520ee19867742a03ba).</para>
</listitem>
<listitem>
<para>Support base-64
hashes. (c0015e87af70f539f24d2aa2bc224a9d8b84276b)</para>
</listitem>
<listitem>
<para><command>nix-shell</command> now uses
<varname>bashInteractive</varname> from Nixpkgs, rather than the
<command>bash</command> command that happens to be in the callers
<envar>PATH</envar>. This is especially important on macOS where
the <command>bash</command> provided by the system is seriously
outdated and cannot execute <literal>stdenv</literal>s setup
script.</para>
</listitem>
<listitem>
<para>New builtin functions: <function>builtins.split</function>
(b8867a0239b1930a16f9ef3f7f3e864b01416dff),
<function>builtins.partition</function>.</para>
</listitem>
<listitem>
<para>Automatic garbage collection.</para>
</listitem>
<listitem>
<para><command>nix-store -q --roots</command> and
<command>nix-store --gc --print-roots</command> now show temporary
and in-memory roots.</para>
</listitem>
<listitem>
<para>Builders can now communicate what build phase they are in by
writing messages to the file descriptor specified in
<envar>NIX_LOG_FD</envar>. (88e6bb76de5564b3217be9688677d1c89101b2a3)
</para>
</listitem>
</itemizedlist>
<para>Some features were removed:</para>
<itemizedlist>
<listitem>
<para>“Nested” log output. As a result,
<command>nix-log2xml</command> was also removed.</para>
</listitem>
<listitem>
<para>OpenSSL-based signing. (f435f8247553656774dd1b2c88e9de5d59cab203)</para>
</listitem>
<listitem>
<para>Caching of failed
builds. (8cffec84859cec8b610a2a22ab0c4d462a9351ff)</para>
</listitem>
<listitem>
<para><filename>nix-mode.el</filename> has been removed from
Nix. It is now a separate repository in
<uri>https://github.com/NixOS/nix-mode</uri> and can be installed
through the MELPA package repository.</para>
</listitem>
<listitem>
<para>In restricted evaluation mode
(<option>--restrict-eval</option>), builtin functions that
download from the network (such as <function>fetchGit</function>)
are permitted to fetch underneath the list of URI prefixes
specified in the option <option>allowed-uris</option>.</para>
</listitem>
</itemizedlist>
<para>This release has contributions from TBD.</para>
</section>

File diff suppressed because it is too large Load Diff

View File

@@ -96,6 +96,7 @@ div.example
margin-right: 1.5em;
background: #f4f4f8;
border-radius: 0.4em;
box-shadow: 0.4em 0.4em 0.5em #e0e0e0;
}
div.example p.title
@@ -105,6 +106,7 @@ div.example p.title
div.example pre
{
box-shadow: none;
}
@@ -114,12 +116,15 @@ div.example pre
pre.screen, pre.programlisting
{
padding: 6px 6px;
border: 1px solid #b0b0b0;
padding: 3px 3px;
margin-left: 1.5em;
margin-right: 1.5em;
color: #600000;
background: #f4f4f8;
font-family: monospace;
border-radius: 0.4em;
box-shadow: 0.4em 0.4em 0.5em #e0e0e0;
}
div.example pre.programlisting
@@ -144,6 +149,7 @@ div.example pre.programlisting
padding: 0.3em 0.3em 0.3em 0.3em;
background: #fffff5;
border-radius: 0.4em;
box-shadow: 0.4em 0.4em 0.5em #e0e0e0;
}
div.note, div.warning
@@ -250,14 +256,16 @@ span.command strong
div.calloutlist table
{
box-shadow: none;
}
table
{
border-collapse: collapse;
box-shadow: 0.4em 0.4em 0.5em #e0e0e0;
}
div.affiliation
{
font-style: italic;
}
}

View File

@@ -0,0 +1,38 @@
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="sec-collisions-nixenv">
<title>Collisions in <command>nix-env</command></title>
<para>Symptom: when installing or upgrading, you get an error message such as
<screen>
$ nix-env -i docbook-xml
...
adding /nix/store/s5hyxgm62gk2...-docbook-xml-4.2
collision between `/nix/store/s5hyxgm62gk2...-docbook-xml-4.2/xml/dtd/docbook/calstblx.dtd'
and `/nix/store/06h377hr4b33...-docbook-xml-4.3/xml/dtd/docbook/calstblx.dtd'
at /nix/store/...-builder.pl line 62.</screen>
</para>
<para>The cause is that two installed packages in the user environment
have overlapping filenames (e.g.,
<filename>xml/dtd/docbook/calstblx.dtd</filename>. This usually
happens when you accidentally try to install two versions of the same
package. For instance, in the example above, the Nix Packages
collection contains two versions of <literal>docbook-xml</literal>, so
<command>nix-env -i</command> will try to install both. The default
user environment builder has no way to way to resolve such conflicts,
so it just gives up.</para>
<para>Solution: remove one of the offending packages from the user
environment (if already installed) using <command>nix-env
-e</command>, or specify exactly which version should be installed
(e.g., <literal>nix-env -i docbook-xml-4.2</literal>).</para>
<!-- FIXME: describe priorities -->
</section>

View File

@@ -0,0 +1,43 @@
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="sec-links-nix-store">
<title><quote>Too many links</quote> Error in the Nix store</title>
<para>Symptom: when building something, you get an error message such as
<screen>
...
<literal>mkdir: cannot create directory `/nix/store/<replaceable>name</replaceable>': Too many links</literal></screen>
</para>
<para>This is usually because you have more than 32,000 subdirectories
in <filename>/nix/store</filename>, as can be seen using <command>ls
-l</command>:
<screen>
$ ls -ld /nix/store
drwxrwxrwt 32000 nix nix 4620288 Sep 8 15:08 store</screen>
The <literal>ext2</literal> file system is limited to an inode link
count of 32,000 (each subdirectory increasing the count by one).
Furthermore, the <literal>st_nlink</literal> field of the
<function>stat</function> system call is a 16-bit value.</para>
<para>This only happens on very large Nix installations (such as build
machines).</para>
<para>Quick solution: run the garbage collector. You may want to use
the <option>--max-links</option> option.</para>
<para>Real solution: put the Nix store on a file system that supports
more than 32,000 subdirectories per directory, such as ext4. (This
doesnt solve the <literal>st_nlink</literal> limit, but ext4 lies to
the kernel by reporting a link count of 1 if it exceeds the
limit.)</para>
</section>

View File

@@ -0,0 +1,16 @@
<appendix xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="ch-troubleshooting">
<title>Troubleshooting</title>
<para>This section provides solutions for some common problems. See
the <link xlink:href="https://github.com/NixOS/nix/issues">Nix bug
tracker</link> for a list of currently known issues.</para>
<xi:include href="collisions-nixenv.xml" />
<xi:include href="links-nix-store.xml" />
</appendix>

View File

@@ -45,11 +45,6 @@ endif
# - $(1)_INSTALL_DIR: the directory where the library will be
# installed. Defaults to $(libdir).
#
# - $(1)_EXCLUDE_FROM_LIBRARY_LIST: if defined, the library will not
# be automatically marked as a dependency of the top-level all
# target andwill not be listed in the make help output. This is
# useful for libraries built solely for testing, for example.
#
# - BUILD_SHARED_LIBS: if equal to 1, a dynamic library will be
# built, otherwise a static library.
define build-library
@@ -154,9 +149,7 @@ define build-library
$(1)_DEPS := $$(foreach fn, $$($(1)_OBJS), $$(call filename-to-dep, $$(fn)))
-include $$($(1)_DEPS)
ifndef $(1)_EXCLUDE_FROM_LIBRARY_LIST
libs-list += $$($(1)_PATH)
endif
clean-files += $$(_d)/*.a $$(_d)/*.$(SO_EXT) $$(_d)/*.o $$(_d)/.*.dep $$($(1)_DEPS) $$($(1)_OBJS)
dist-files += $$(_srcs)
endef

View File

@@ -39,7 +39,7 @@ installcheck:
echo "$${red}$$failed out of $$total tests failed $$normal"; \
exit 1; \
else \
echo "$${green}All tests succeeded$$normal"; \
echo "$${green}All tests succeeded"; \
fi
.PHONY: check installcheck

View File

@@ -1,31 +1,17 @@
{ pkgs }:
rec {
# Use "busybox-sandbox-shell" if present,
# if not (legacy) fallback and hope it's sufficient.
sh = pkgs.busybox-sandbox-shell or (pkgs.busybox.override {
sh = pkgs.busybox.override {
useMusl = true;
enableStatic = true;
enableMinimal = true;
extraConfig = ''
CONFIG_FEATURE_FANCY_ECHO y
CONFIG_FEATURE_SH_MATH y
CONFIG_FEATURE_SH_MATH_64 y
CONFIG_ASH y
CONFIG_ASH_OPTIMIZE_FOR_SIZE y
CONFIG_ASH_ALIAS y
CONFIG_ASH_BASH_COMPAT y
CONFIG_ASH_CMDCMD y
CONFIG_ASH_ECHO y
CONFIG_ASH_GETOPTS y
CONFIG_ASH_INTERNAL_GLOB y
CONFIG_ASH_JOB_CONTROL y
CONFIG_ASH_PRINTF y
CONFIG_ASH_TEST y
CONFIG_ASH_OPTIMIZE_FOR_SIZE y
'';
});
};
configureFlags =
[ "--disable-init-state"

View File

@@ -1,12 +1,12 @@
{ nix ? builtins.fetchGit ./.
, nixpkgs ? builtins.fetchGit { url = https://github.com/NixOS/nixpkgs.git; ref = "nix-2.0"; }
, nixpkgs ? fetchTarball channel:nixos-17.09
, officialRelease ? false
, systems ? [ "x86_64-linux" "i686-linux" "x86_64-darwin" "aarch64-linux" ]
}:
let
pkgs = import nixpkgs { system = builtins.currentSystem or "x86_64-linux"; };
pkgs = import nixpkgs {};
jobs = rec {
@@ -127,6 +127,7 @@ let
binaryTarball = pkgs.lib.genAttrs systems (system:
# FIXME: temporarily use a different branch for the Darwin build.
with import nixpkgs { inherit system; };
let
@@ -136,7 +137,7 @@ let
runCommand "nix-binary-tarball-${version}"
{ exportReferencesGraph = [ "closure1" toplevel "closure2" cacert ];
buildInputs = [ perl ] ++ lib.optional (system != "aarch64-linux") shellcheck;
buildInputs = [ perl shellcheck ];
meta.description = "Distribution-independent Nix bootstrap binaries for ${system}";
}
''
@@ -149,10 +150,8 @@ let
--subst-var-by nix ${toplevel} \
--subst-var-by cacert ${cacert}
if type -p shellcheck; then
shellcheck -e SC1090 $TMPDIR/install
shellcheck -e SC1091,SC2002 $TMPDIR/install-darwin-multi-user
fi
shellcheck -e SC1090 $TMPDIR/install
shellcheck -e SC1091,SC2002 $TMPDIR/install-darwin-multi-user
chmod +x $TMPDIR/install
chmod +x $TMPDIR/install-darwin-multi-user
@@ -225,13 +224,11 @@ let
nix = build.x86_64-linux; system = "x86_64-linux";
});
tests.setuid = pkgs.lib.genAttrs
["i686-linux" "x86_64-linux"]
(system:
import ./tests/setuid.nix rec {
inherit nixpkgs;
nix = build.${system}; inherit system;
});
tests.setuid = pkgs.lib.genAttrs (pkgs.lib.filter (pkgs.lib.hasSuffix "-linux") systems) (system:
import ./tests/setuid.nix rec {
inherit nixpkgs;
nix = build.${system}; inherit system;
});
tests.binaryTarball =
with import nixpkgs { system = "x86_64-linux"; };

View File

@@ -24,7 +24,7 @@ readonly YELLOW='\033[38;33m'
readonly YELLOW_UL='\033[38;4;33m'
readonly CORES=$(sysctl -n hw.ncpu)
readonly NIX_USER_COUNT="32"
readonly NIX_USER_COUNT="$CORES"
readonly NIX_BUILD_GROUP_ID="30000"
readonly NIX_BUILD_GROUP_NAME="nixbld"
readonly NIX_FIRST_BUILD_UID="30001"
@@ -647,7 +647,7 @@ chat_about_sudo() {
cat <<EOF
This script is going to call sudo a lot. Normally, it would show you
exactly what commands it is running and why. However, the script is
run in a headless fashion, like this:
run in a headless fashion, like this:
$ curl https://nixos.org/nix/install | sh
@@ -695,7 +695,7 @@ install_from_extracted_nix() {
cd "$EXTRACTED_NIX_PATH"
_sudo "to copy the basic Nix files to the new store at $NIX_ROOT/store" \
rsync -rlpt ./store/* "$NIX_ROOT/store/"
rsync -rlpt "$(pwd)/store/" "$NIX_ROOT/store/"
if [ -d "$NIX_INSTALLED_NIX" ]; then
echo " Alright! We have our first nix at $NIX_INSTALLED_NIX"

View File

@@ -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

View File

@@ -64,8 +64,6 @@ int main (int argc, char * * argv)
settings.maxBuildJobs.set("1"); // hack to make tests with local?root= work
initPlugins();
auto store = openStore().cast<LocalStore>();
/* It would be more appropriate to use $XDG_RUNTIME_DIR, since
@@ -243,7 +241,7 @@ connected:
if (!missing.empty()) {
Activity act(*logger, lvlTalkative, actUnknown, fmt("copying outputs from '%s'", storeUri));
store->locksHeld.insert(missing.begin(), missing.end()); /* FIXME: ugly */
setenv("NIX_HELD_LOCKS", concatStringsSep(" ", missing).c_str(), 1); /* FIXME: ugly */
copyPaths(ref<Store>(sshStore), store, missing, NoRepair, NoCheckSigs, substitute);
}

View File

@@ -7,14 +7,13 @@
namespace nix {
/* Note: Various places expect the allocated memory to be zeroed. */
static void * allocBytes(size_t n)
{
void * p;
#if HAVE_BOEHMGC
p = GC_malloc(n);
#else
p = calloc(n, 1);
p = malloc(n);
#endif
if (!p) throw std::bad_alloc();
return p;

View File

@@ -83,7 +83,7 @@ public:
for (size_t n = 0; n < size_; n++)
res.emplace_back(&attrs[n]);
std::sort(res.begin(), res.end(), [](const Attr * a, const Attr * b) {
return (const string &) a->name < (const string &) b->name;
return (string) a->name < (string) b->name;
});
return res;
}

View File

@@ -43,14 +43,13 @@ static char * dupString(const char * s)
}
/* Note: Various places expect the allocated memory to be zeroed. */
static void * allocBytes(size_t n)
{
void * p;
#if HAVE_BOEHMGC
p = GC_malloc(n);
#else
p = calloc(n, 1);
p = malloc(n);
#endif
if (!p) throw std::bad_alloc();
return p;
@@ -294,10 +293,6 @@ EvalState::EvalState(const Strings & _searchPath, ref<Store> store)
, sWrong(symbols.create("wrong"))
, sStructuredAttrs(symbols.create("__structuredAttrs"))
, sBuilder(symbols.create("builder"))
, sArgs(symbols.create("args"))
, sOutputHash(symbols.create("outputHash"))
, sOutputHashAlgo(symbols.create("outputHashAlgo"))
, sOutputHashMode(symbols.create("outputHashMode"))
, repair(NoRepair)
, store(store)
, baseEnv(allocEnv(128))
@@ -305,24 +300,15 @@ EvalState::EvalState(const Strings & _searchPath, ref<Store> store)
{
countCalls = getEnv("NIX_COUNT_CALLS", "0") != "0";
restricted = settings.restrictEval;
assert(gcInitialised);
/* Initialise the Nix expression search path. */
if (!settings.pureEval) {
Strings paths = parseNixPath(getEnv("NIX_PATH", ""));
for (auto & i : _searchPath) addToSearchPath(i);
for (auto & i : paths) addToSearchPath(i);
}
addToSearchPath("nix=" + canonPath(settings.nixDataDir + "/nix/corepkgs"));
if (settings.restrictEval || settings.pureEval) {
allowedPaths = PathSet();
for (auto & i : searchPath) {
auto r = resolveSearchPathElem(i);
if (!r.first) continue;
allowedPaths->insert(r.second);
}
}
Strings paths = parseNixPath(getEnv("NIX_PATH", ""));
for (auto & i : _searchPath) addToSearchPath(i);
for (auto & i : paths) addToSearchPath(i);
addToSearchPath("nix=" + settings.nixDataDir + "/nix/corepkgs");
clearValue(vEmptySet);
vEmptySet.type = tAttrs;
@@ -340,36 +326,38 @@ EvalState::~EvalState()
Path EvalState::checkSourcePath(const Path & path_)
{
if (!allowedPaths) return path_;
bool found = false;
for (auto & i : *allowedPaths) {
if (isDirOrInDir(path_, i)) {
found = true;
break;
}
}
if (!found)
throw RestrictedPathError("access to path '%1%' is forbidden in restricted mode", path_);
if (!restricted) return path_;
/* Resolve symlinks. */
debug(format("checking access to '%s'") % path_);
Path path = canonPath(path_, true);
for (auto & i : *allowedPaths) {
if (isDirOrInDir(path, i))
for (auto & i : searchPath) {
auto r = resolveSearchPathElem(i);
if (!r.first) continue;
if (path == r.second || isInDir(path, r.second))
return path;
}
throw RestrictedPathError("access to path '%1%' is forbidden in restricted mode", path);
/* To support import-from-derivation, allow access to anything in
the store. FIXME: only allow access to paths that have been
constructed by this evaluation. */
if (store->isInStore(path)) return path;
#if 0
/* Hack to support the chroot dependencies of corepkgs (see
corepkgs/config.nix.in). */
if (path == settings.nixPrefix && isStorePath(settings.nixPrefix))
return path;
#endif
throw RestrictedPathError(format("access to path '%1%' is forbidden in restricted mode") % path_);
}
void EvalState::checkURI(const std::string & uri)
{
if (!settings.restrictEval) return;
if (!restricted) return;
/* 'uri' should be equal to a prefix, or in a subdirectory of a
prefix. Thus, the prefix https://github.co does not permit
@@ -383,33 +371,11 @@ void EvalState::checkURI(const std::string & uri)
&& (prefix[prefix.size() - 1] == '/' || uri[prefix.size()] == '/')))
return;
/* If the URI is a path, then check it against allowedPaths as
well. */
if (hasPrefix(uri, "/")) {
checkSourcePath(uri);
return;
}
if (hasPrefix(uri, "file://")) {
checkSourcePath(std::string(uri, 7));
return;
}
throw RestrictedPathError("access to URI '%s' is forbidden in restricted mode", uri);
}
Path EvalState::toRealPath(const Path & path, const PathSet & context)
{
// FIXME: check whether 'path' is in 'context'.
return
!context.empty() && store->isInStore(path)
? store->toRealPath(path)
: path;
};
Value * EvalState::addConstant(const string & name, Value & v)
void EvalState::addConstant(const string & name, Value & v)
{
Value * v2 = allocValue();
*v2 = v;
@@ -417,18 +383,12 @@ Value * EvalState::addConstant(const string & name, Value & v)
baseEnv.values[baseEnvDispl++] = v2;
string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name;
baseEnv.values[0]->attrs->push_back(Attr(symbols.create(name2), v2));
return v2;
}
Value * EvalState::addPrimOp(const string & name,
void EvalState::addPrimOp(const string & name,
unsigned int arity, PrimOpFun primOp)
{
if (arity == 0) {
Value v;
primOp(*this, noPos, nullptr, v);
return addConstant(name, v);
}
Value * v = allocValue();
string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name;
Symbol sym = symbols.create(name2);
@@ -437,7 +397,6 @@ Value * EvalState::addPrimOp(const string & name,
staticBaseEnv.vars[symbols.create(name)] = baseEnvDispl;
baseEnv.values[baseEnvDispl++] = v;
baseEnv.values[0]->attrs->push_back(Attr(sym, v));
return v;
}
@@ -587,7 +546,9 @@ Env & EvalState::allocEnv(unsigned int size)
Env * env = (Env *) allocBytes(sizeof(Env) + size * sizeof(Value *));
env->size = size;
/* We assume that env->values has been cleared by the allocator; maybeThunk() and lookupVar fromWith expect this. */
/* Clear the values because maybeThunk() and lookupVar fromWith expect this. */
for (unsigned i = 0; i < size; ++i)
env->values[i] = 0;
return *env;
}
@@ -688,10 +649,8 @@ Value * ExprPath::maybeThunk(EvalState & state, Env & env)
}
void EvalState::evalFile(const Path & path_, Value & v)
void EvalState::evalFile(const Path & path, Value & v)
{
auto path = checkSourcePath(path_);
FileEvalCache::iterator i;
if ((i = fileEvalCache.find(path)) != fileEvalCache.end()) {
v = i->second;
@@ -1587,7 +1546,7 @@ string EvalState::copyPathToStore(PathSet & context, const Path & path)
dstPath = srcToStore[path];
else {
dstPath = settings.readOnlyMode
? store->computeStorePathForPath(baseNameOf(path), checkSourcePath(path)).first
? store->computeStorePathForPath(checkSourcePath(path)).first
: store->addToStore(baseNameOf(path), checkSourcePath(path), true, htSHA256, defaultPathFilter, repair);
srcToStore[path] = dstPath;
printMsg(lvlChatty, format("copied source '%1%' -> '%2%'")
@@ -1709,13 +1668,10 @@ void EvalState::printStats()
printMsg(v, format(" time elapsed: %1%") % cpuTime);
printMsg(v, format(" size of a value: %1%") % sizeof(Value));
printMsg(v, format(" size of an attr: %1%") % sizeof(Attr));
printMsg(v, format(" environments allocated count: %1%") % nrEnvs);
printMsg(v, format(" environments allocated bytes: %1%") % bEnvs);
printMsg(v, format(" list elements count: %1%") % nrListElems);
printMsg(v, format(" list elements bytes: %1%") % bLists);
printMsg(v, format(" environments allocated: %1% (%2% bytes)") % nrEnvs % bEnvs);
printMsg(v, format(" list elements: %1% (%2% bytes)") % nrListElems % bLists);
printMsg(v, format(" list concatenations: %1%") % nrListConcats);
printMsg(v, format(" values allocated count: %1%") % nrValues);
printMsg(v, format(" values allocated bytes: %1%") % bValues);
printMsg(v, format(" values allocated: %1% (%2% bytes)") % nrValues % bValues);
printMsg(v, format(" sets allocated: %1% (%2% bytes)") % nrAttrsets % bAttrsets);
printMsg(v, format(" right-biased unions: %1%") % nrOpUpdates);
printMsg(v, format(" values copied in right-biased unions: %1%") % nrOpUpdateValuesCopied);
@@ -1727,6 +1683,8 @@ void EvalState::printStats()
printMsg(v, format(" number of primop calls: %1%") % nrPrimOpCalls);
printMsg(v, format(" number of function calls: %1%") % nrFunctionCalls);
printMsg(v, format(" total allocations: %1% bytes") % (bEnvs + bLists + bValues + bAttrsets));
printMsg(v, format(" memoisation hits: %d") % nrMemoiseHits);
printMsg(v, format(" memoisation misses: %d") % nrMemoiseMisses);
#if HAVE_BOEHMGC
GC_word heapSize, totalBytes;

View File

@@ -69,17 +69,16 @@ public:
const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName, sValue,
sSystem, sOverrides, sOutputs, sOutputName, sIgnoreNulls,
sFile, sLine, sColumn, sFunctor, sToString,
sRight, sWrong, sStructuredAttrs, sBuilder, sArgs,
sOutputHash, sOutputHashAlgo, sOutputHashMode;
sRight, sWrong, sStructuredAttrs, sBuilder;
Symbol sDerivationNix;
/* If set, force copying files to the Nix store even if they
already exist there. */
RepairFlag repair;
/* The allowed filesystem paths in restricted or pure evaluation
mode. */
std::experimental::optional<PathSet> allowedPaths;
/* If set, don't allow access to files outside of the Nix search
path or to environment variables. */
bool restricted;
Value vEmptySet;
@@ -90,7 +89,7 @@ private:
/* A cache from path names to values. */
#if HAVE_BOEHMGC
typedef std::map<Path, Value, std::less<Path>, traceable_allocator<std::pair<const Path, Value> > > FileEvalCache;
typedef std::map<Path, Value, std::less<Path>, traceable_allocator<std::pair<const Path, Value>>> FileEvalCache;
#else
typedef std::map<Path, Value> FileEvalCache;
#endif
@@ -113,15 +112,6 @@ public:
void checkURI(const std::string & uri);
/* When using a diverted store and 'path' is in the Nix store, map
'path' to the diverted location (e.g. /nix/store/foo is mapped
to /home/alice/my-nix/nix/store/foo). However, this is only
done if the context is not empty, since otherwise we're
probably trying to read from the actual /nix/store. This is
intended to distinguish between import-from-derivation and
sources stored in the actual /nix/store. */
Path toRealPath(const Path & path, const PathSet & context);
/* Parse a Nix expression from the specified file. */
Expr * parseExprFromFile(const Path & path);
Expr * parseExprFromFile(const Path & path, StaticEnv & staticEnv);
@@ -211,9 +201,9 @@ private:
void createBaseEnv();
Value * addConstant(const string & name, Value & v);
void addConstant(const string & name, Value & v);
Value * addPrimOp(const string & name,
void addPrimOp(const string & name,
unsigned int arity, PrimOpFun primOp);
public:
@@ -279,6 +269,8 @@ private:
unsigned long nrListConcats = 0;
unsigned long nrPrimOpCalls = 0;
unsigned long nrFunctionCalls = 0;
unsigned long nrMemoiseHits = 0;
unsigned long nrMemoiseMisses = 0;
bool countCalls;
@@ -297,6 +289,22 @@ private:
friend struct ExprOpConcatLists;
friend struct ExprSelect;
friend void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v);
friend void prim_memoise(EvalState & state, const Pos & pos, Value * * args, Value & v);
/* State for builtins.memoise. */
struct MemoArgComparator
{
EvalState & state;
MemoArgComparator(EvalState & state) : state(state) { }
bool operator()(Value * a, Value * b);
};
typedef std::map<Value *, Value, MemoArgComparator, traceable_allocator<std::pair<const Value *, Value>>> PerLambdaMemo;
typedef std::pair<Env *, ExprLambda *> LambdaKey;
// FIXME: use std::unordered_map
std::map<LambdaKey, PerLambdaMemo, std::less<LambdaKey>, traceable_allocator<std::pair<const LambdaKey, PerLambdaMemo>>> memos;
};

View File

@@ -49,10 +49,9 @@ static void adjustLoc(YYLTYPE * loc, const char * s, size_t len)
}
static Expr * unescapeStr(SymbolTable & symbols, const char * s, size_t length)
static Expr * unescapeStr(SymbolTable & symbols, const char * s)
{
string t;
t.reserve(length);
char c;
while ((c = *s++)) {
if (c == '\\') {
@@ -151,7 +150,7 @@ or { return OR_KW; }
/* It is impossible to match strings ending with '$' with one
regex because trailing contexts are only valid at the end
of a rule. (A sane but undocumented limitation.) */
yylval->e = unescapeStr(data->symbols, yytext, yyleng);
yylval->e = unescapeStr(data->symbols, yytext);
return STR;
}
<STRING>\$\{ { PUSH_STATE(INSIDE_DOLLAR_CURLY); return DOLLAR_CURLY; }
@@ -179,7 +178,7 @@ or { return OR_KW; }
return IND_STR;
}
<IND_STRING>\'\'\\. {
yylval->e = unescapeStr(data->symbols, yytext + 2, yyleng - 2);
yylval->e = unescapeStr(data->symbols, yytext + 2);
return IND_STR;
}
<IND_STRING>\$\{ { PUSH_STATE(INSIDE_DOLLAR_CURLY); return DOLLAR_CURLY; }

View File

@@ -41,7 +41,7 @@ bool DrvName::matches(DrvName & n)
}
string nextComponent(string::const_iterator & p,
static string nextComponent(string::const_iterator & p,
const string::const_iterator end)
{
/* Skip any dots and dashes (component separators). */

View File

@@ -24,8 +24,6 @@ private:
typedef list<DrvName> DrvNames;
string nextComponent(string::const_iterator & p,
const string::const_iterator end);
int compareVersions(const string & v1, const string & v2);
DrvNames drvNamesFromArgs(const Strings & opArgs);

View File

@@ -39,7 +39,7 @@ std::pair<string, string> decodeContext(const string & s)
size_t index = s.find("!", 1);
return std::pair<string, string>(string(s, index + 1), string(s, 1, index - 1));
} else
return std::pair<string, string>(s.at(0) == '/' ? s : string(s, 1), "");
return std::pair<string, string>(s.at(0) == '/' ? s: string(s, 1), "");
}
@@ -49,38 +49,24 @@ InvalidPathError::InvalidPathError(const Path & path) :
void EvalState::realiseContext(const PathSet & context)
{
PathSet drvs;
for (auto & i : context) {
std::pair<string, string> decoded = decodeContext(i);
Path ctx = decoded.first;
assert(store->isStorePath(ctx));
if (!store->isValidPath(ctx))
throw InvalidPathError(ctx);
if (!decoded.second.empty() && nix::isDerivation(ctx)) {
if (!decoded.second.empty() && nix::isDerivation(ctx))
drvs.insert(decoded.first + "!" + decoded.second);
/* Add the output of this derivation to the allowed
paths. */
if (allowedPaths) {
auto drv = store->derivationFromPath(decoded.first);
DerivationOutputs::iterator i = drv.outputs.find(decoded.second);
if (i == drv.outputs.end())
throw Error("derivation '%s' does not have an output named '%s'", decoded.first, decoded.second);
allowedPaths->insert(i->second.path);
}
}
}
if (drvs.empty()) return;
if (!settings.enableImportFromDerivation)
throw EvalError(format("attempted to realize '%1%' during evaluation but 'allow-import-from-derivation' is false") % *(drvs.begin()));
/* For performance, prefetch all substitute info. */
PathSet willBuild, willSubstitute, unknown;
unsigned long long downloadSize, narSize;
store->queryMissing(drvs, willBuild, willSubstitute, unknown, downloadSize, narSize);
store->buildPaths(drvs);
if (!drvs.empty()) {
if (!settings.enableImportFromDerivation)
throw EvalError(format("attempted to realize '%1%' during evaluation but 'allow-import-from-derivation' is false") % *(drvs.begin()));
/* For performance, prefetch all substitute info. */
PathSet willBuild, willSubstitute, unknown;
unsigned long long downloadSize, narSize;
store->queryMissing(drvs, willBuild, willSubstitute, unknown, downloadSize, narSize);
store->buildPaths(drvs);
}
}
@@ -98,10 +84,10 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args
% path % e.path % pos);
}
Path realPath = state.checkSourcePath(state.toRealPath(path, context));
path = state.checkSourcePath(path);
if (state.store->isStorePath(path) && state.store->isValidPath(path) && isDerivation(path)) {
Derivation drv = readDerivation(realPath);
Derivation drv = readDerivation(path);
Value & w = *state.allocValue();
state.mkAttrs(w, 3 + drv.outputs.size());
Value * v2 = state.allocAttr(w, state.sDrvPath);
@@ -128,7 +114,7 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args
} else {
state.forceAttrs(*args[0]);
if (args[0]->attrs->empty())
state.evalFile(realPath, v);
state.evalFile(path, v);
else {
Env * env = &state.allocEnv(args[0]->attrs->size());
env->up = &state.baseEnv;
@@ -141,8 +127,8 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args
env->values[displ++] = attr.value;
}
printTalkative("evaluating file '%1%'", realPath);
Expr * e = state.parseExprFromFile(resolveExprPath(realPath), staticEnv);
printTalkative("evaluating file '%1%'", path);
Expr * e = state.parseExprFromFile(resolveExprPath(path), staticEnv);
e->eval(state, *env, v);
}
@@ -453,7 +439,7 @@ static void prim_tryEval(EvalState & state, const Pos & pos, Value * * args, Val
static void prim_getEnv(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
string name = state.forceStringNoCtx(*args[0], pos);
mkString(v, settings.restrictEval || settings.pureEval ? "" : getEnv(name));
mkString(v, state.restricted ? "" : getEnv(name));
}
@@ -553,7 +539,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
for (auto & i : args[0]->attrs->lexicographicOrder()) {
if (i->name == state.sIgnoreNulls) continue;
const string & key = i->name;
string key = i->name;
vomit("processing attribute '%1%'", key);
auto handleHashMode = [&](const std::string & s) {
@@ -589,7 +575,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
/* The `args' attribute is special: it supplies the
command-line arguments to the builder. */
if (i->name == state.sArgs) {
if (key == "args") {
state.forceList(*i->value, pos);
for (unsigned int n = 0; n < i->value->listSize(); ++n) {
string s = state.coerceToString(posDrvName, *i->value->listElems()[n], context, true);
@@ -612,13 +598,15 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
drv.builder = state.forceString(*i->value, context, posDrvName);
else if (i->name == state.sSystem)
drv.platform = state.forceStringNoCtx(*i->value, posDrvName);
else if (i->name == state.sOutputHash)
else if (i->name == state.sName)
drvName = state.forceStringNoCtx(*i->value, posDrvName);
else if (key == "outputHash")
outputHash = state.forceStringNoCtx(*i->value, posDrvName);
else if (i->name == state.sOutputHashAlgo)
else if (key == "outputHashAlgo")
outputHashAlgo = state.forceStringNoCtx(*i->value, posDrvName);
else if (i->name == state.sOutputHashMode)
else if (key == "outputHashMode")
handleHashMode(state.forceStringNoCtx(*i->value, posDrvName));
else if (i->name == state.sOutputs) {
else if (key == "outputs") {
/* Require outputs to be a list of strings. */
state.forceList(*i->value, posDrvName);
Strings ss;
@@ -632,10 +620,14 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
drv.env.emplace(key, s);
if (i->name == state.sBuilder) drv.builder = s;
else if (i->name == state.sSystem) drv.platform = s;
else if (i->name == state.sOutputHash) outputHash = s;
else if (i->name == state.sOutputHashAlgo) outputHashAlgo = s;
else if (i->name == state.sOutputHashMode) handleHashMode(s);
else if (i->name == state.sOutputs)
else if (i->name == state.sName) {
drvName = s;
printMsg(lvlVomit, format("derivation name is '%1%'") % drvName);
}
else if (key == "outputHash") outputHash = s;
else if (key == "outputHashAlgo") outputHashAlgo = s;
else if (key == "outputHashMode") handleHashMode(s);
else if (key == "outputs")
handleOutputs(tokenizeString<Strings>(s));
}
@@ -871,7 +863,7 @@ static void prim_readFile(EvalState & state, const Pos & pos, Value * * args, Va
throw EvalError(format("cannot read '%1%', since path '%2%' is not valid, at %3%")
% path % e.path % pos);
}
string s = readFile(state.checkSourcePath(state.toRealPath(path, context)));
string s = readFile(state.checkSourcePath(path));
if (s.find((char) 0) != string::npos)
throw Error(format("the contents of the file '%1%' cannot be represented as a Nix string") % path);
mkString(v, s.c_str());
@@ -1017,13 +1009,20 @@ static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Valu
}
static void addPath(EvalState & state, const Pos & pos, const string & name, const Path & path_,
Value * filterFun, bool recursive, const Hash & expectedHash, Value & v)
static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
const auto path = settings.pureEval && expectedHash ?
path_ :
state.checkSourcePath(path_);
PathFilter filter = filterFun ? ([&](const Path & path) {
PathSet context;
Path path = state.coerceToPath(pos, *args[1], context);
if (!context.empty())
throw EvalError(format("string '%1%' cannot refer to other paths, at %2%") % path % pos);
state.forceValue(*args[0]);
if (args[0]->type != tLambda)
throw TypeError(format("first argument in call to 'filterSource' is not a function but %1%, at %2%") % showType(*args[0]) % pos);
path = state.checkSourcePath(path);
PathFilter filter = [&](const Path & path) {
auto st = lstat(path);
/* Call the filter function. The first argument is the path,
@@ -1032,7 +1031,7 @@ static void addPath(EvalState & state, const Pos & pos, const string & name, con
mkString(arg1, path);
Value fun2;
state.callFunction(*filterFun, arg1, fun2, noPos);
state.callFunction(*args[0], arg1, fun2, noPos);
Value arg2;
mkString(arg2,
@@ -1045,79 +1044,16 @@ static void addPath(EvalState & state, const Pos & pos, const string & name, con
state.callFunction(fun2, arg2, res, noPos);
return state.forceBool(res, pos);
}) : defaultPathFilter;
};
Path expectedStorePath;
if (expectedHash) {
expectedStorePath =
state.store->makeFixedOutputPath(recursive, expectedHash, name);
}
Path dstPath;
if (!expectedHash || !state.store->isValidPath(expectedStorePath)) {
dstPath = settings.readOnlyMode
? state.store->computeStorePathForPath(name, path, recursive, htSHA256, filter).first
: state.store->addToStore(name, path, recursive, htSHA256, filter, state.repair);
if (expectedHash && expectedStorePath != dstPath) {
throw Error(format("store path mismatch in (possibly filtered) path added from '%1%'") % path);
}
} else
dstPath = expectedStorePath;
Path dstPath = settings.readOnlyMode
? state.store->computeStorePathForPath(path, true, htSHA256, filter).first
: state.store->addToStore(baseNameOf(path), path, true, htSHA256, filter, state.repair);
mkString(v, dstPath, {dstPath});
}
static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
Path path = state.coerceToPath(pos, *args[1], context);
if (!context.empty())
throw EvalError(format("string '%1%' cannot refer to other paths, at %2%") % path % pos);
state.forceValue(*args[0]);
if (args[0]->type != tLambda)
throw TypeError(format("first argument in call to 'filterSource' is not a function but %1%, at %2%") % showType(*args[0]) % pos);
addPath(state, pos, baseNameOf(path), path, args[0], true, Hash(), v);
}
static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceAttrs(*args[0], pos);
Path path;
string name;
Value * filterFun = nullptr;
auto recursive = true;
Hash expectedHash;
for (auto & attr : *args[0]->attrs) {
const string & n(attr.name);
if (n == "path") {
PathSet context;
path = state.coerceToPath(*attr.pos, *attr.value, context);
if (!context.empty())
throw EvalError(format("string '%1%' cannot refer to other paths, at %2%") % path % *attr.pos);
} else if (attr.name == state.sName)
name = state.forceStringNoCtx(*attr.value, *attr.pos);
else if (n == "filter") {
state.forceValue(*attr.value);
filterFun = attr.value;
} else if (n == "recursive")
recursive = state.forceBool(*attr.value, *attr.pos);
else if (n == "sha256")
expectedHash = Hash(state.forceStringNoCtx(*attr.value, *attr.pos), htSHA256);
else
throw EvalError(format("unsupported argument '%1%' to 'addPath', at %2%") % attr.name % *attr.pos);
}
if (path.empty())
throw EvalError(format("'path' required, at %1%") % pos);
if (name.empty())
name = baseNameOf(path);
addPath(state, pos, name, path, filterFun, recursive, expectedHash, v);
}
/*************************************************************
* Sets
*************************************************************/
@@ -1132,11 +1068,8 @@ static void prim_attrNames(EvalState & state, const Pos & pos, Value * * args, V
state.mkList(v, args[0]->attrs->size());
size_t n = 0;
for (auto & i : *args[0]->attrs)
mkString(*(v.listElems()[n++] = state.allocValue()), i.name);
std::sort(v.listElems(), v.listElems() + n,
[](Value * v1, Value * v2) { return strcmp(v1->string.s, v2->string.s) < 0; });
for (auto & i : args[0]->attrs->lexicographicOrder())
mkString(*(v.listElems()[n++] = state.allocValue()), i->name);
}
@@ -1958,26 +1891,6 @@ static void prim_compareVersions(EvalState & state, const Pos & pos, Value * * a
}
static void prim_splitVersion(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
string version = state.forceStringNoCtx(*args[0], pos);
auto iter = version.cbegin();
Strings components;
while (iter != version.cend()) {
auto component = nextComponent(iter, version.cend());
if (component.empty())
break;
components.emplace_back(std::move(component));
}
state.mkList(v, components.size());
unsigned int n = 0;
for (auto & component : components) {
auto listElem = v.listElems()[n++] = state.allocValue();
mkString(*listElem, std::move(component));
}
}
/*************************************************************
* Networking
*************************************************************/
@@ -2016,14 +1929,7 @@ void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
state.checkURI(url);
if (settings.pureEval && !expectedHash)
throw Error("in pure evaluation mode, '%s' requires a 'sha256' argument", who);
Path res = getDownloader()->downloadCached(state.store, url, unpack, name, expectedHash);
if (state.allowedPaths)
state.allowedPaths->insert(res);
mkString(v, res, PathSet({res}));
}
@@ -2075,24 +1981,11 @@ void EvalState::createBaseEnv()
mkNull(v);
addConstant("null", v);
auto vThrow = addPrimOp("throw", 1, prim_throw);
mkInt(v, time(0));
addConstant("__currentTime", v);
auto addPurityError = [&](const std::string & name) {
Value * v2 = allocValue();
mkString(*v2, fmt("'%s' is not allowed in pure evaluation mode", name));
mkApp(v, *vThrow, *v2);
addConstant(name, v);
};
if (!settings.pureEval) {
mkInt(v, time(0));
addConstant("__currentTime", v);
}
if (!settings.pureEval) {
mkString(v, settings.thisSystem);
addConstant("__currentSystem", v);
}
mkString(v, settings.thisSystem);
addConstant("__currentSystem", v);
mkString(v, nixVersion);
addConstant("__nixVersion", v);
@@ -2108,10 +2001,10 @@ void EvalState::createBaseEnv()
addConstant("__langVersion", v);
// Miscellaneous
auto vScopedImport = addPrimOp("scopedImport", 2, prim_scopedImport);
addPrimOp("scopedImport", 2, prim_scopedImport);
Value * v2 = allocValue();
mkAttrs(*v2, 0);
mkApp(v, *vScopedImport, *v2);
mkApp(v, *baseEnv.values[baseEnvDispl - 1], *v2);
forceValue(v);
addConstant("import", v);
if (settings.enableNativeCode) {
@@ -2127,6 +2020,7 @@ void EvalState::createBaseEnv()
addPrimOp("__isBool", 1, prim_isBool);
addPrimOp("__genericClosure", 1, prim_genericClosure);
addPrimOp("abort", 1, prim_abort);
addPrimOp("throw", 1, prim_throw);
addPrimOp("__addErrorContext", 2, prim_addErrorContext);
addPrimOp("__tryEval", 1, prim_tryEval);
addPrimOp("__getEnv", 1, prim_getEnv);
@@ -2141,10 +2035,7 @@ void EvalState::createBaseEnv()
// Paths
addPrimOp("__toPath", 1, prim_toPath);
if (settings.pureEval)
addPurityError("__storePath");
else
addPrimOp("__storePath", 1, prim_storePath);
addPrimOp("__storePath", 1, prim_storePath);
addPrimOp("__pathExists", 1, prim_pathExists);
addPrimOp("baseNameOf", 1, prim_baseNameOf);
addPrimOp("dirOf", 1, prim_dirOf);
@@ -2158,7 +2049,6 @@ void EvalState::createBaseEnv()
addPrimOp("__fromJSON", 1, prim_fromJSON);
addPrimOp("__toFile", 2, prim_toFile);
addPrimOp("__filterSource", 2, prim_filterSource);
addPrimOp("__path", 1, prim_path);
// Sets
addPrimOp("__attrNames", 1, prim_attrNames);
@@ -2213,7 +2103,6 @@ void EvalState::createBaseEnv()
// Versions
addPrimOp("__parseDrvName", 1, prim_parseDrvName);
addPrimOp("__compareVersions", 2, prim_compareVersions);
addPrimOp("__splitVersion", 1, prim_splitVersion);
// Derivations
addPrimOp("derivationStrict", 1, prim_derivationStrict);

View File

@@ -9,9 +9,6 @@ struct RegisterPrimOp
{
typedef std::vector<std::tuple<std::string, size_t, PrimOpFun>> PrimOps;
static PrimOps * primOps;
/* You can register a constant by passing an arity of 0. fun
will get called during EvalState initialization, so there
may be primops not yet added and builtins is not yet sorted. */
RegisterPrimOp(std::string name, size_t arity, PrimOpFun fun);
};

View File

@@ -22,15 +22,10 @@ struct GitInfo
uint64_t revCount = 0;
};
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,
const std::string & name)
{
if (settings.pureEval && rev == "")
throw Error("in pure evaluation mode, 'fetchGit' requires a Git revision");
if (!ref && rev == "" && hasPrefix(uri, "/") && pathExists(uri + "/.git")) {
bool clean = true;
@@ -81,8 +76,11 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,
if (!ref) ref = "master"s;
if (rev != "" && !std::regex_match(rev, revRegex))
throw Error("invalid Git revision '%s'", rev);
if (rev != "") {
std::regex revRegex("^[0-9a-fA-F]{40}$");
if (!std::regex_match(rev, revRegex))
throw Error("invalid Git revision '%s'", rev);
}
Path cacheDir = getCacheDir() + "/nix/git";
@@ -233,9 +231,6 @@ static void prim_fetchGit(EvalState & state, const Pos & pos, Value * * args, Va
mkString(*state.allocAttr(v, state.symbols.create("shortRev")), gitInfo.shortRev);
mkInt(*state.allocAttr(v, state.symbols.create("revCount")), gitInfo.revCount);
v.attrs->sort();
if (state.allowedPaths)
state.allowedPaths->insert(gitInfo.storePath);
}
static RegisterPrimOp r("fetchGit", 1, prim_fetchGit);

View File

@@ -27,9 +27,6 @@ std::regex commitHashRegex("^[0-9a-fA-F]{40}$");
HgInfo exportMercurial(ref<Store> store, const std::string & uri,
std::string rev, const std::string & name)
{
if (settings.pureEval && rev == "")
throw Error("in pure evaluation mode, 'fetchMercurial' requires a Mercurial revision");
if (rev == "" && hasPrefix(uri, "/") && pathExists(uri + "/.hg")) {
bool clean = runProgram("hg", true, { "status", "-R", uri, "--modified", "--added", "--removed" }) == "";
@@ -199,9 +196,6 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar
mkString(*state.allocAttr(v, state.symbols.create("shortRev")), std::string(hgInfo.rev, 0, 12));
mkInt(*state.allocAttr(v, state.symbols.create("revCount")), hgInfo.revCount);
v.attrs->sort();
if (state.allowedPaths)
state.allowedPaths->insert(hgInfo.storePath);
}
static RegisterPrimOp r("fetchMercurial", 1, prim_fetchMercurial);

View File

@@ -0,0 +1,95 @@
#include "primops.hh"
#include "eval-inline.hh"
#include <cstring>
namespace nix {
bool EvalState::MemoArgComparator::operator()(Value * v1, Value * v2)
{
if (v1 == v2) return false;
state.forceValue(*v1);
state.forceValue(*v2);
if (v1->type == v2->type) {
switch (v1->type) {
case tInt:
return v1->integer < v2->integer;
case tBool:
return v1->boolean < v2->boolean;
case tString:
return strcmp(v1->string.s, v2->string.s);
case tPath:
return strcmp(v1->path, v2->path);
case tNull:
return false;
case tList1:
case tList2:
case tListN:
unsigned int n;
for (n = 0; n < v1->listSize() && n < v2->listSize(); ++n) {
if ((*this)(v1->listElems()[n], v2->listElems()[n])) return true;
if ((*this)(v2->listElems()[n], v1->listElems()[n])) return false;
}
return n == v1->listSize() && n < v2->listSize();
case tAttrs:
Bindings::iterator i, j;
for (i = v1->attrs->begin(), j = v2->attrs->begin(); i != v1->attrs->end() && j != v2->attrs->end(); ++i, ++j) {
if (i->name < j->name) return true;
if (j->name < i->name) return false;
if ((*this)(i->value, j->value)) return true;
if ((*this)(j->value, i->value)) return false;
}
return i == v1->attrs->end() && j != v2->attrs->end();
case tLambda:
return std::make_pair(v1->lambda.env, v1->lambda.fun) < std::make_pair(v2->lambda.env, v2->lambda.fun);
case tFloat:
return v1->fpoint < v2->fpoint;
default:
break;
}
}
// As a fallback, use pointer equality.
return v1 < v2;
}
void prim_memoise(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceFunction(*args[0], pos);
EvalState::PerLambdaMemo foo(state);
auto & memo = state.memos.emplace(std::make_pair(args[0]->lambda.env, args[0]->lambda.fun), state).first->second;
auto result = memo.find(args[1]);
if (result != memo.end()) {
state.nrMemoiseHits++;
v = result->second;
return;
}
state.nrMemoiseMisses++;
state.callFunction(*args[0], *args[1], v, pos);
memo[args[1]] = v;
}
static RegisterPrimOp r("memoise", 2, prim_memoise);
}

View File

@@ -37,10 +37,6 @@ MixCommonArgs::MixCommonArgs(const string & programName)
std::string cat = "config";
settings.convertToArgs(*this, cat);
// Backward compatibility hack: nix-env already had a --system flag.
if (programName == "nix-env") longFlags.erase("system");
hiddenCategories.insert(cat);
}

View File

@@ -193,6 +193,9 @@ LegacyArgs::LegacyArgs(const std::string & programName,
mkFlag(0, "readonly-mode", "do not write to the Nix store",
&settings.readOnlyMode);
mkFlag(0, "show-trace", "show Nix expression stack trace in evaluation errors",
&settings.showTrace);
mkFlag(0, "no-gc-warning", "disable warning about not using '--add-root'",
&gcWarning, false);
@@ -262,7 +265,6 @@ void printVersion(const string & programName)
void showManPage(const string & name)
{
restoreSignals();
setenv("MANPATH", settings.nixManDir.c_str(), 1);
execlp("man", "man", name.c_str(), NULL);
throw SysError(format("command 'man %1%' failed") % name.c_str());
}

View File

@@ -22,7 +22,6 @@ public:
int handleExceptions(const string & programName, std::function<void()> fun);
/* Don't forget to call initPlugins() after settings are initialized! */
void initNix();
void parseCmdLine(int argc, char * * argv,

View File

@@ -149,7 +149,7 @@ void BinaryCacheStore::addToStore(const ValidPathInfo & info, const ref<std::str
/* Compress the NAR. */
narInfo->compression = compression;
auto now1 = std::chrono::steady_clock::now();
auto narCompressed = compress(compression, *nar, parallelCompression);
auto narCompressed = compress(compression, *nar);
auto now2 = std::chrono::steady_clock::now();
narInfo->fileHash = hashString(htSHA256, *narCompressed);
narInfo->fileSize = narCompressed->size();

View File

@@ -19,8 +19,6 @@ public:
const Setting<bool> writeNARListing{this, false, "write-nar-listing", "whether to write a JSON file listing the files in each NAR"};
const Setting<Path> secretKeyFile{this, "", "secret-key", "path to secret key used to sign the binary cache"};
const Setting<Path> localNarCache{this, "", "local-nar-cache", "path to a local cache of NARs"};
const Setting<bool> parallelCompression{this, false, "parallel-compression",
"enable multi-threading compression, available for xz only currently"};
private:

View File

@@ -6,7 +6,6 @@
#include "archive.hh"
#include "affinity.hh"
#include "builtins.hh"
#include "download.hh"
#include "finally.hh"
#include "compression.hh"
#include "json.hh"
@@ -49,9 +48,7 @@
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/syscall.h>
#if HAVE_SECCOMP
#include <seccomp.h>
#endif
#define pivot_root(new_root, put_old) (syscall(SYS_pivot_root, new_root, put_old))
#endif
@@ -1126,6 +1123,11 @@ void DerivationGoal::haveDerivation()
return;
}
/* Reject doing a hash build of anything other than a fixed-output
derivation. */
if (buildMode == bmHash && !drv->isFixedOutput())
throw Error("cannot do a hash build of non-fixed-output derivation '%1%'", drvPath);
/* We are first going to try to create the invalid output paths
through substitutes. If that doesn't work, we'll build
them. */
@@ -1317,7 +1319,9 @@ void DerivationGoal::inputsRealised()
allPaths.insert(inputPaths.begin(), inputPaths.end());
/* Is this a fixed-output derivation? */
fixedOutput = drv->isFixedOutput();
fixedOutput = true;
for (auto & i : drv->outputs)
if (i.second.hash == "") fixedOutput = false;
/* Don't repeat fixed-output derivations since they're already
verified by their output hash.*/
@@ -1337,6 +1341,19 @@ void DerivationGoal::tryToBuild()
{
trace("trying to build");
/* Check for the possibility that some other goal in this process
has locked the output since we checked in haveDerivation().
(It can't happen between here and the lockPaths() call below
because we're not allowing multi-threading.) If so, put this
goal to sleep until another goal finishes, then try again. */
for (auto & i : drv->outputs)
if (pathIsLockedByMe(worker.store.toRealPath(i.second.path))) {
debug(format("putting derivation '%1%' to sleep because '%2%' is locked by another goal")
% drvPath % i.second.path);
worker.waitForAnyGoal(shared_from_this());
return;
}
/* Obtain locks on all output paths. The locks are automatically
released when we exit this function or Nix crashes. If we
can't acquire the lock, then continue; hopefully some other
@@ -1760,19 +1777,6 @@ PathSet exportReferences(Store & store, PathSet storePaths)
return paths;
}
static std::once_flag dns_resolve_flag;
static void preloadNSS() {
/* builtin:fetchurl can trigger a DNS lookup, which with glibc can trigger a dynamic library load of
one of the glibc NSS libraries in a sandboxed child, which will fail unless the library's already
been loaded in the parent. So we force a download of an invalid URL to force the NSS machinery to
load its lookup libraries in the parent before any child gets a chance to. */
std::call_once(dns_resolve_flag, []() {
DownloadRequest request("http://this.pre-initializes.the.dns.resolvers.invalid");
request.tries = 1; // We only need to do it once, and this also suppresses an annoying warning
try { getDownloader()->download(request); } catch (...) {}
});
}
void DerivationGoal::startBuilder()
{
@@ -1783,9 +1787,6 @@ void DerivationGoal::startBuilder()
% drv->platform % settings.thisSystem % drvPath);
}
if (drv->isBuiltin())
preloadNSS();
#if __APPLE__
additionalSandboxProfile = get(drv->env, "__sandboxProfile");
#endif
@@ -1809,13 +1810,8 @@ void DerivationGoal::startBuilder()
useChroot = !fixedOutput && get(drv->env, "__noChroot") != "1";
}
if (worker.store.storeDir != worker.store.realStoreDir) {
#if __linux__
useChroot = true;
#else
throw Error("building using a diverted store is not supported on this platform");
#endif
}
if (worker.store.storeDir != worker.store.realStoreDir)
useChroot = true;
/* If `build-users-group' is not empty, then we have to build as
one of the members of that group. */
@@ -2473,7 +2469,7 @@ void setupSeccomp()
{
#if __linux__
if (!settings.filterSyscalls) return;
#if HAVE_SECCOMP
scmp_filter_ctx ctx;
if (!(ctx = seccomp_init(SCMP_ACT_ALLOW)))
@@ -2519,11 +2515,6 @@ void setupSeccomp()
if (seccomp_load(ctx) != 0)
throw SysError("unable to load seccomp BPF program");
#else
throw Error(
"seccomp is not supported on this platform; "
"you can bypass this error by setting the option 'filter-syscalls' to false, but note that untrusted builds can then create setuid binaries!");
#endif
#endif
}
@@ -2937,13 +2928,8 @@ void DerivationGoal::runChild()
if (drv->isBuiltin()) {
try {
logger = makeJSONLogger(*logger);
BasicDerivation drv2(*drv);
for (auto & e : drv2.env)
e.second = rewriteStrings(e.second, inputRewrites);
if (drv->builder == "builtin:fetchurl")
builtinFetchurl(drv2, netrcData);
builtinFetchurl(*drv, netrcData);
else
throw Error(format("unsupported builtin function '%1%'") % string(drv->builder, 8));
_exit(0);
@@ -3006,8 +2992,6 @@ void DerivationGoal::registerOutputs()
bool runDiffHook = settings.runDiffHook;
bool keepPreviousRound = settings.keepFailed || runDiffHook;
std::exception_ptr delayedException;
/* Check whether the output paths were created, and grep each
output path to determine what other paths it references. Also make all
output paths read-only. */
@@ -3082,7 +3066,7 @@ void DerivationGoal::registerOutputs()
/* Check that fixed-output derivations produced the right
outputs (i.e., the content hash should match the specified
hash). */
if (fixedOutput) {
if (i.second.hash != "") {
bool recursive; Hash h;
i.second.parseHashInfo(recursive, h);
@@ -3098,34 +3082,27 @@ void DerivationGoal::registerOutputs()
/* Check the hash. In hash mode, move the path produced by
the derivation to its content-addressed location. */
Hash h2 = recursive ? hashPath(h.type, actualPath).first : hashFile(h.type, actualPath);
Path dest = worker.store.makeFixedOutputPath(recursive, h2, drv->env["name"]);
if (h != h2) {
/* Throw an error after registering the path as
valid. */
delayedException = std::make_exception_ptr(
BuildError("fixed-output derivation produced path '%s' with %s hash '%s' instead of the expected hash '%s'",
dest, printHashType(h.type), printHash16or32(h2), printHash16or32(h)));
Path actualDest = worker.store.toRealPath(dest);
if (buildMode == bmHash) {
Path dest = worker.store.makeFixedOutputPath(recursive, h2, drv->env["name"]);
printError(format("build produced path '%1%' with %2% hash '%3%'")
% dest % printHashType(h.type) % printHash16or32(h2));
if (worker.store.isValidPath(dest))
std::rethrow_exception(delayedException);
return;
Path actualDest = worker.store.toRealPath(dest);
if (actualPath != actualDest) {
PathLocks outputLocks({actualDest});
deletePath(actualDest);
if (rename(actualPath.c_str(), actualDest.c_str()) == -1)
throw SysError(format("moving '%1%' to '%2%'") % actualPath % dest);
}
path = dest;
actualPath = actualDest;
} else {
if (h != h2)
throw BuildError(
format("output path '%1%' has %2% hash '%3%' when '%4%' was expected")
% path % i.second.hashAlgo % printHash16or32(h2) % printHash16or32(h));
}
else
assert(path == dest);
info.ca = makeFixedOutputCA(recursive, h2);
}
@@ -3302,11 +3279,6 @@ void DerivationGoal::registerOutputs()
paths referenced by each of them. If there are cycles in the
outputs, this will fail. */
worker.store.registerValidPaths(infos);
/* In case of a fixed-output derivation hash mismatch, throw an
exception now that we have registered the output as valid. */
if (delayedException)
std::rethrow_exception(delayedException);
}
@@ -3422,7 +3394,7 @@ void DerivationGoal::flushLine()
else {
if (settings.verboseBuild &&
(settings.printRepeatedBuilds || curRound == 1))
printError(currentLogLine);
printError(filterANSIEscapes(currentLogLine, true));
else {
logTail.push_back(currentLogLine);
if (logTail.size() > settings.logLines) logTail.pop_front();
@@ -3664,7 +3636,7 @@ void SubstitutionGoal::tryNext()
/* Update the total expected download size. */
auto narInfo = std::dynamic_pointer_cast<const NarInfo>(info);
maintainExpectedNar = std::make_unique<MaintainCount<uint64_t>>(worker.expectedNarSize, info->narSize);
maintainExpectedNar = std::make_unique<MaintainCount<uint64_t>>(worker.expectedNarSize, narInfo->narSize);
maintainExpectedDownload =
narInfo && narInfo->fileSize
@@ -3678,12 +3650,9 @@ void SubstitutionGoal::tryNext()
/* Bail out early if this substituter lacks a valid
signature. LocalStore::addToStore() also checks for this, but
only after we've downloaded the path. */
if (worker.store.requireSigs
&& !sub->isTrusted
&& !info->checkSignatures(worker.store, worker.store.publicKeys))
{
printError("warning: substituter '%s' does not have a valid signature for path '%s'",
sub->getUri(), storePath);
if (worker.store.requireSigs && !info->checkSignatures(worker.store, worker.store.publicKeys)) {
printInfo(format("warning: substituter '%s' does not have a valid signature for path '%s'")
% sub->getUri() % storePath);
tryNext();
return;
}
@@ -3733,17 +3702,6 @@ void SubstitutionGoal::tryToRun()
return;
}
/* If the store path is already locked (probably by a
DerivationGoal), then put this goal to sleep. Note: we don't
acquire a lock here since that breaks addToStore(), so below we
handle an AlreadyLocked exception from addToStore(). The check
here is just an optimisation to prevent having to redo a
download due to a locked path. */
if (pathIsLockedByMe(worker.store.toRealPath(storePath))) {
worker.waitForAWhile(shared_from_this());
return;
}
maintainRunningSubstitutions = std::make_unique<MaintainCount<uint64_t>>(worker.runningSubstitutions);
worker.updateProgress();
@@ -3760,7 +3718,7 @@ void SubstitutionGoal::tryToRun()
PushActivity pact(act.id);
copyStorePath(ref<Store>(sub), ref<Store>(worker.store.shared_from_this()),
storePath, repair, sub->isTrusted ? NoCheckSigs : CheckSigs);
storePath, repair);
promise.set_value();
} catch (...) {
@@ -3783,14 +3741,8 @@ void SubstitutionGoal::finished()
try {
promise.get_future().get();
} catch (AlreadyLocked & e) {
/* Probably a DerivationGoal is already building this store
path. Sleep for a while and try again. */
state = &SubstitutionGoal::init;
worker.waitForAWhile(shared_from_this());
return;
} catch (Error & e) {
printError(e.msg());
printInfo(e.msg());
/* Try the next substitute. */
state = &SubstitutionGoal::tryNext;

View File

@@ -17,13 +17,11 @@
#include <curl/curl.h>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#include <queue>
#include <random>
#include <iostream>
#include <thread>
#include <cmath>
#include <random>
using namespace std::string_literals;
@@ -93,8 +91,6 @@ struct CurlDownloader : public Downloader
{
if (!request.expectedETag.empty())
requestHeaders = curl_slist_append(requestHeaders, ("If-None-Match: " + request.expectedETag).c_str());
if (!request.mimeType.empty())
requestHeaders = curl_slist_append(requestHeaders, ("Content-Type: " + request.mimeType).c_str());
}
~DownloadItem()
@@ -189,22 +185,6 @@ struct CurlDownloader : public Downloader
return 0;
}
size_t readOffset = 0;
int readCallback(char *buffer, size_t size, size_t nitems)
{
if (readOffset == request.data->length())
return 0;
auto count = std::min(size * nitems, request.data->length() - readOffset);
memcpy(buffer, request.data->data() + readOffset, count);
readOffset += count;
return count;
}
static int readCallbackWrapper(char *buffer, size_t size, size_t nitems, void * userp)
{
return ((DownloadItem *) userp)->readCallback(buffer, size, nitems);
}
long lowSpeedTimeout = 300;
void init()
@@ -245,13 +225,6 @@ struct CurlDownloader : public Downloader
if (request.head)
curl_easy_setopt(req, CURLOPT_NOBODY, 1);
if (request.data) {
curl_easy_setopt(req, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(req, CURLOPT_READFUNCTION, readCallbackWrapper);
curl_easy_setopt(req, CURLOPT_READDATA, this);
curl_easy_setopt(req, CURLOPT_INFILESIZE_LARGE, (curl_off_t) request.data->length());
}
if (request.verifyTLS) {
if (settings.caFile != "")
curl_easy_setopt(req, CURLOPT_CAINFO, settings.caFile.c_str());
@@ -292,7 +265,7 @@ struct CurlDownloader : public Downloader
}
if (code == CURLE_OK &&
(httpStatus == 200 || httpStatus == 201 || httpStatus == 204 || httpStatus == 304 || httpStatus == 226 /* FTP */ || httpStatus == 0 /* other protocol */))
(httpStatus == 200 || httpStatus == 304 || httpStatus == 226 /* FTP */ || httpStatus == 0 /* other protocol */))
{
result.cached = httpStatus == 304;
done = true;
@@ -330,7 +303,6 @@ struct CurlDownloader : public Downloader
// Don't bother retrying on certain cURL errors either
switch (code) {
case CURLE_FAILED_INIT:
case CURLE_URL_MALFORMAT:
case CURLE_NOT_BUILT_IN:
case CURLE_REMOTE_ACCESS_DENIED:
case CURLE_FILE_COULDNT_READ_FILE:
@@ -339,10 +311,10 @@ struct CurlDownloader : public Downloader
case CURLE_BAD_FUNCTION_ARGUMENT:
case CURLE_INTERFACE_FAILED:
case CURLE_UNKNOWN_OPTION:
err = Misc;
break;
err = Misc;
break;
default: // Shut up warnings
break;
break;
}
}

View File

@@ -18,8 +18,6 @@ struct DownloadRequest
unsigned int baseRetryTimeMs = 250;
ActivityId parentAct;
bool decompress = true;
std::shared_ptr<std::string> data;
std::string mimeType;
DownloadRequest(const std::string & uri)
: uri(uri), parentAct(curActivity) { }

View File

@@ -324,8 +324,10 @@ Roots LocalStore::findRootsNoTemp()
{
Roots roots;
/* Process direct roots in {gcroots,profiles}. */
/* Process direct roots in {gcroots,manifests,profiles}. */
findRoots(stateDir + "/" + gcRootsDir, DT_UNKNOWN, roots);
if (pathExists(stateDir + "/manifests"))
findRoots(stateDir + "/manifests", DT_UNKNOWN, roots);
findRoots(stateDir + "/profiles", DT_UNKNOWN, roots);
/* Add additional roots returned by the program specified by the

View File

@@ -6,7 +6,6 @@
#include <algorithm>
#include <map>
#include <thread>
#include <dlfcn.h>
namespace nix {
@@ -38,7 +37,6 @@ Settings::Settings()
, nixConfDir(canonPath(getEnv("NIX_CONF_DIR", NIX_CONF_DIR)))
, nixLibexecDir(canonPath(getEnv("NIX_LIBEXEC_DIR", NIX_LIBEXEC_DIR)))
, nixBinDir(canonPath(getEnv("NIX_BIN_DIR", NIX_BIN_DIR)))
, nixManDir(canonPath(NIX_MAN_DIR))
, nixDaemonSocketFile(canonPath(nixStateDir + DEFAULT_SOCKET_PATH))
{
buildUsersGroup = getuid() == 0 ? "nixbld" : "";
@@ -139,46 +137,4 @@ void MaxBuildJobsSetting::set(const std::string & str)
throw UsageError("configuration setting '%s' should be 'auto' or an integer", name);
}
void initPlugins()
{
for (const auto & pluginFile : settings.pluginFiles.get()) {
Paths pluginFiles;
try {
auto ents = readDirectory(pluginFile);
for (const auto & ent : ents)
pluginFiles.emplace_back(pluginFile + "/" + ent.name);
} catch (SysError & e) {
if (e.errNo != ENOTDIR)
throw;
pluginFiles.emplace_back(pluginFile);
}
for (const auto & file : pluginFiles) {
/* handle is purposefully leaked as there may be state in the
DSO needed by the action of the plugin. */
void *handle =
dlopen(file.c_str(), RTLD_LAZY | RTLD_LOCAL);
if (!handle)
throw Error("could not dynamically open plugin file '%s%': %s%", file, dlerror());
}
}
/* We handle settings registrations here, since plugins can add settings */
if (RegisterSetting::settingRegistrations) {
for (auto & registration : *RegisterSetting::settingRegistrations)
settings.addSetting(registration);
delete RegisterSetting::settingRegistrations;
}
settings.handleUnknownSettings();
}
RegisterSetting::SettingRegistrations * RegisterSetting::settingRegistrations;
RegisterSetting::RegisterSetting(AbstractSetting * s)
{
if (!settingRegistrations)
settingRegistrations = new SettingRegistrations;
settingRegistrations->emplace_back(s);
}
}

View File

@@ -82,9 +82,6 @@ public:
/* The directory where the main programs are stored. */
Path nixBinDir;
/* The directory where the man pages are stored. */
Path nixManDir;
/* File name of the socket the daemon listens to. */
Path nixDaemonSocketFile;
@@ -214,8 +211,7 @@ public:
bool lockCPU;
/* Whether to show a stack trace if Nix evaluation fails. */
Setting<bool> showTrace{this, false, "show-trace",
"Whether to show a stack trace on evaluation errors."};
bool showTrace = false;
Setting<bool> enableNativeCode{this, false, "allow-unsafe-native-code-during-evaluation",
"Whether builtin functions that allow executing native code should be enabled."};
@@ -236,9 +232,6 @@ public:
"Whether to restrict file system access to paths in $NIX_PATH, "
"and network access to the URI prefixes listed in 'allowed-uris'."};
Setting<bool> pureEval{this, false, "pure-eval",
"Whether to restrict file system and network access to files specified by cryptographic hash."};
Setting<size_t> buildRepeat{this, 0, "repeat",
"The number of times to repeat a build in order to verify determinism.",
{"build-repeat"}};
@@ -290,7 +283,10 @@ public:
Setting<unsigned int> tarballTtl{this, 60 * 60, "tarball-ttl",
"How soon to expire files fetched by builtins.fetchTarball and builtins.fetchurl."};
Setting<bool> requireSigs{this, true, "require-sigs",
Setting<std::string> signedBinaryCaches{this, "*", "signed-binary-caches",
"Obsolete."};
Setting<bool> requireSigs{this, signedBinaryCaches == "*", "require-sigs",
"Whether to check that any non-content-addressed path added to the "
"Nix store has a valid signature (that is, one signed using a key "
"listed in 'trusted-public-keys'."};
@@ -370,28 +366,14 @@ public:
Setting<Strings> allowedUris{this, {}, "allowed-uris",
"Prefixes of URIs that builtin functions such as fetchurl and fetchGit are allowed to fetch."};
Setting<Paths> pluginFiles{this, {}, "plugin-files",
"Plugins to dynamically load at nix initialization time."};
};
// FIXME: don't use a global variable.
extern Settings settings;
/* This should be called after settings are initialized, but before
anything else */
void initPlugins();
extern const string nixVersion;
struct RegisterSetting
{
typedef std::vector<AbstractSetting *> SettingRegistrations;
static SettingRegistrations * settingRegistrations;
RegisterSetting(AbstractSetting * s);
};
}

View File

@@ -38,7 +38,7 @@ public:
try {
BinaryCacheStore::init();
} catch (UploadToHTTP &) {
throw Error("'%s' does not appear to be a binary cache", cacheUri);
throw Error(format("'%s' does not appear to be a binary cache") % cacheUri);
}
diskCache->createCache(cacheUri, storeDir, wantMassQuery_, priority);
}
@@ -67,14 +67,7 @@ protected:
const std::string & data,
const std::string & mimeType) override
{
auto req = DownloadRequest(cacheUri + "/" + path);
req.data = std::make_shared<string>(data); // FIXME: inefficient
req.mimeType = mimeType;
try {
getDownloader()->download(req);
} catch (DownloadError & e) {
throw UploadToHTTP(format("uploading to HTTP binary cache at %1% not supported: %2%") % cacheUri % e.msg());
}
throw UploadToHTTP("uploading to an HTTP binary cache is not supported");
}
void getFile(const std::string & path,

View File

@@ -992,7 +992,8 @@ void LocalStore::addToStore(const ValidPathInfo & info, const ref<std::string> &
/* Lock the output path. But don't lock if we're being called
from a build hook (whose parent process already acquired a
lock on this path). */
if (!locksHeld.count(info.path))
Strings locksHeld = tokenizeString<Strings>(getEnv("NIX_HELD_LOCKS"));
if (find(locksHeld.begin(), locksHeld.end(), info.path) == locksHeld.end())
outputLock.lockPaths({realPath});
if (repair || !isValidPath(info.path)) {

View File

@@ -19,7 +19,7 @@ namespace nix {
/* Nix store and database schema version. Version 1 (or 0) was Nix <=
0.7. Version 2 was Nix 0.8 and 0.9. Version 3 is Nix 0.10.
Version 4 is Nix 0.11. Version 5 is Nix 0.12-0.16. Version 6 is
Nix 1.0. Version 7 is Nix 1.3. Version 10 is 2.0. */
Nix 1.0. Version 7 is Nix 1.3. Version 10 is 1.12. */
const int nixSchemaVersion = 10;
@@ -104,9 +104,6 @@ private:
public:
// Hack for build-remote.cc.
PathSet locksHeld = tokenizeString<PathSet>(getEnv("NIX_HELD_LOCKS"));
/* Initialise the local store, upgrading the schema if
necessary. */
LocalStore(const Params & params);

View File

@@ -9,9 +9,6 @@ libstore_SOURCES := $(wildcard $(d)/*.cc)
libstore_LIBS = libutil libformat
libstore_LDFLAGS = $(SQLITE3_LIBS) -lbz2 $(LIBCURL_LIBS) $(SODIUM_LIBS) -pthread
ifneq ($(OS), FreeBSD)
libstore_LDFLAGS += -ldl
endif
libstore_FILES = sandbox-defaults.sb sandbox-minimal.sb sandbox-network.sb
@@ -25,7 +22,7 @@ ifeq ($(OS), SunOS)
libstore_LDFLAGS += -lsocket
endif
ifeq ($(HAVE_SECCOMP), 1)
ifeq ($(OS), Linux)
libstore_LDFLAGS += -lseccomp
endif
@@ -38,7 +35,6 @@ libstore_CXXFLAGS = \
-DNIX_CONF_DIR=\"$(sysconfdir)/nix\" \
-DNIX_LIBEXEC_DIR=\"$(libexecdir)\" \
-DNIX_BIN_DIR=\"$(bindir)\" \
-DNIX_MAN_DIR=\"$(mandir)\" \
-DSANDBOX_SHELL="\"$(sandbox_shell)\"" \
-DLSOF=\"$(lsof)\"

View File

@@ -113,10 +113,8 @@ bool PathLocks::lockPaths(const PathSet & _paths,
{
auto lockedPaths(lockedPaths_.lock());
if (lockedPaths->count(lockPath)) {
if (!wait) return false;
throw AlreadyLocked("deadlock: trying to re-acquire self-held lock '%s'", lockPath);
}
if (lockedPaths->count(lockPath))
throw Error("deadlock: trying to re-acquire self-held lock '%s'", lockPath);
lockedPaths->insert(lockPath);
}

View File

@@ -2,8 +2,10 @@
#include "util.hh"
namespace nix {
/* Open (possibly create) a lock file and return the file descriptor.
-1 is returned if create is false and the lock could not be opened
because it doesn't exist. Any other error throws an exception. */
@@ -16,7 +18,6 @@ enum LockType { ltRead, ltWrite, ltNone };
bool lockFile(int fd, LockType lockType, bool wait);
MakeError(AlreadyLocked, Error);
class PathLocks
{
@@ -37,6 +38,9 @@ public:
void setDeletion(bool deletePaths);
};
// FIXME: not thread-safe!
bool pathIsLockedByMe(const Path & path);
}

View File

@@ -78,22 +78,9 @@ UDSRemoteStore::UDSRemoteStore(const Params & params)
}
UDSRemoteStore::UDSRemoteStore(std::string socket_path, const Params & params)
: Store(params)
, LocalFSStore(params)
, RemoteStore(params)
, path(socket_path)
{
}
std::string UDSRemoteStore::getUri()
{
if (path) {
return std::string("unix://") + *path;
} else {
return "daemon";
}
return "daemon";
}
@@ -111,7 +98,7 @@ ref<RemoteStore::Connection> UDSRemoteStore::openConnection()
throw SysError("cannot create Unix domain socket");
closeOnExec(conn->fd.get());
string socketPath = path ? *path : settings.nixDaemonSocketFile;
string socketPath = settings.nixDaemonSocketFile;
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
@@ -734,14 +721,5 @@ void RemoteStore::Connection::processStderr(Sink * sink, Source * source)
}
}
static std::string uriScheme = "unix://";
static RegisterStoreImplementation regStore([](
const std::string & uri, const Store::Params & params)
-> std::shared_ptr<Store>
{
if (std::string(uri, 0, uriScheme.size()) != uriScheme) return 0;
return std::make_shared<UDSRemoteStore>(std::string(uri, uriScheme.size()), params);
});
}

View File

@@ -134,7 +134,6 @@ class UDSRemoteStore : public LocalFSStore, public RemoteStore
public:
UDSRemoteStore(const Params & params);
UDSRemoteStore(std::string path, const Params & params);
std::string getUri() override;
@@ -146,7 +145,6 @@ private:
};
ref<RemoteStore::Connection> openConnection() override;
std::experimental::optional<std::string> path;
};

View File

@@ -222,10 +222,11 @@ Path Store::makeTextPath(const string & name, const Hash & hash,
}
std::pair<Path, Hash> Store::computeStorePathForPath(const string & name,
const Path & srcPath, bool recursive, HashType hashAlgo, PathFilter & filter) const
std::pair<Path, Hash> Store::computeStorePathForPath(const Path & srcPath,
bool recursive, HashType hashAlgo, PathFilter & filter) const
{
Hash h = recursive ? hashPath(hashAlgo, srcPath, filter).first : hashFile(hashAlgo, srcPath);
string name = baseNameOf(srcPath);
Path dstPath = makeFixedOutputPath(recursive, h, name);
return std::pair<Path, Hash>(dstPath, h);
}
@@ -839,7 +840,7 @@ ref<Store> openStore(const std::string & uri_,
for (auto fun : *RegisterStoreImplementation::implementations) {
auto store = fun(uri, params);
if (store) {
store->handleUnknownSettings();
store->warnUnknownSettings();
return ref<Store>(store);
}
}
@@ -896,11 +897,7 @@ std::list<ref<Store>> getDefaultSubstituters()
auto addStore = [&](const std::string & uri) {
if (done.count(uri)) return;
done.insert(uri);
try {
stores.push_back(openStore(uri));
} catch (Error & e) {
printError("warning: %s", e.what());
}
stores.push_back(openStore(uri));
};
for (auto uri : settings.substituters.get())

View File

@@ -192,7 +192,7 @@ struct ValidPathInfo
typedef list<ValidPathInfo> ValidPathInfos;
enum BuildMode { bmNormal, bmRepair, bmCheck };
enum BuildMode { bmNormal, bmRepair, bmCheck, bmHash };
struct BuildResult
@@ -248,8 +248,6 @@ public:
const Setting<int> pathInfoCacheSize{this, 65536, "path-info-cache-size", "size of the in-memory store path information cache"};
const Setting<bool> isTrusted{this, false, "trusted", "whether paths from this store can be used as substitutes even when they lack trusted signatures"};
protected:
struct State
@@ -307,9 +305,9 @@ public:
/* This is the preparatory part of addToStore(); it computes the
store path to which srcPath is to be copied. Returns the store
path and the cryptographic hash of the contents of srcPath. */
std::pair<Path, Hash> computeStorePathForPath(const string & name,
const Path & srcPath, bool recursive = true,
HashType hashAlgo = htSHA256, PathFilter & filter = defaultPathFilter) const;
std::pair<Path, Hash> computeStorePathForPath(const Path & srcPath,
bool recursive = true, HashType hashAlgo = htSHA256,
PathFilter & filter = defaultPathFilter) const;
/* Preparatory part of addTextToStore().
@@ -599,11 +597,6 @@ public:
"nix-cache-info" file. Lower value means higher priority. */
virtual int getPriority() { return 0; }
virtual Path toRealPath(const Path & storePath)
{
return storePath;
}
protected:
Stats stats;
@@ -646,10 +639,9 @@ public:
virtual Path getRealStoreDir() { return storeDir; }
Path toRealPath(const Path & storePath) override
Path toRealPath(const Path & storePath)
{
assert(isInStore(storePath));
return getRealStoreDir() + "/" + std::string(storePath, storeDir.size() + 1);
return getRealStoreDir() + "/" + baseNameOf(storePath);
}
std::shared_ptr<std::string> getBuildLog(const Path & path) override;
@@ -707,9 +699,6 @@ void removeTempRoots();
* daemon: The Nix store accessed via a Unix domain socket
connection to nix-daemon.
* unix://<path>: The Nix store accessed via a Unix domain socket
connection to nix-daemon, with the socket located at <path>.
* auto or : Equivalent to local or daemon depending on
whether the user has write access to the local Nix
store/database.

View File

@@ -1,7 +1,6 @@
#include "compression.hh"
#include "util.hh"
#include "finally.hh"
#include "logging.hh"
#include <lzma.h>
#include <bzlib.h>
@@ -152,10 +151,10 @@ static ref<std::string> decompressBrotli(const std::string & in)
#endif // HAVE_BROTLI
}
ref<std::string> compress(const std::string & method, const std::string & in, const bool parallel)
ref<std::string> compress(const std::string & method, const std::string & in)
{
StringSink ssink;
auto sink = makeCompressionSink(method, ssink, parallel);
auto sink = makeCompressionSink(method, ssink);
(*sink)(in);
sink->finish();
return ssink.s;
@@ -190,9 +189,10 @@ struct XzSink : CompressionSink
lzma_stream strm = LZMA_STREAM_INIT;
bool finished = false;
template <typename F>
XzSink(Sink & nextSink, F&& initEncoder) : nextSink(nextSink) {
lzma_ret ret = initEncoder();
XzSink(Sink & nextSink) : nextSink(nextSink)
{
lzma_ret ret = lzma_easy_encoder(
&strm, 6, LZMA_CHECK_CRC64);
if (ret != LZMA_OK)
throw CompressionError("unable to initialise lzma encoder");
// FIXME: apply the x86 BCJ filter?
@@ -200,9 +200,6 @@ struct XzSink : CompressionSink
strm.next_out = outbuf;
strm.avail_out = sizeof(outbuf);
}
XzSink(Sink & nextSink) : XzSink(nextSink, [this]() {
return lzma_easy_encoder(&strm, 6, LZMA_CHECK_CRC64);
}) {}
~XzSink()
{
@@ -256,27 +253,6 @@ struct XzSink : CompressionSink
}
};
#ifdef HAVE_LZMA_MT
struct ParallelXzSink : public XzSink
{
ParallelXzSink(Sink &nextSink) : XzSink(nextSink, [this]() {
lzma_mt mt_options = {};
mt_options.flags = 0;
mt_options.timeout = 300; // Using the same setting as the xz cmd line
mt_options.preset = LZMA_PRESET_DEFAULT;
mt_options.filters = NULL;
mt_options.check = LZMA_CHECK_CRC64;
mt_options.threads = lzma_cputhreads();
mt_options.block_size = 0;
if (mt_options.threads == 0)
mt_options.threads = 1;
// FIXME: maybe use lzma_stream_encoder_mt_memusage() to control the
// number of threads.
return lzma_stream_encoder_mt(&strm, &mt_options);
}) {}
};
#endif
struct BzipSink : CompressionSink
{
Sink & nextSink;
@@ -473,16 +449,8 @@ struct BrotliSink : CompressionSink
};
#endif // HAVE_BROTLI
ref<CompressionSink> makeCompressionSink(const std::string & method, Sink & nextSink, const bool parallel)
ref<CompressionSink> makeCompressionSink(const std::string & method, Sink & nextSink)
{
if (parallel) {
#ifdef HAVE_LZMA_MT
if (method == "xz")
return make_ref<ParallelXzSink>(nextSink);
#endif
printMsg(lvlError, format("Warning: parallel compression requested but not supported for method '%1%', falling back to single-threaded compression") % method);
}
if (method == "none")
return make_ref<NoneSink>(nextSink);
else if (method == "xz")

View File

@@ -8,7 +8,7 @@
namespace nix {
ref<std::string> compress(const std::string & method, const std::string & in, const bool parallel = false);
ref<std::string> compress(const std::string & method, const std::string & in);
ref<std::string> decompress(const std::string & method, const std::string & in);
@@ -17,7 +17,7 @@ struct CompressionSink : BufferedSink
virtual void finish() = 0;
};
ref<CompressionSink> makeCompressionSink(const std::string & method, Sink & nextSink, const bool parallel = false);
ref<CompressionSink> makeCompressionSink(const std::string & method, Sink & nextSink);
MakeError(UnknownCompressionMethod, Error);

View File

@@ -7,12 +7,10 @@ namespace nix {
void Config::set(const std::string & name, const std::string & value)
{
auto i = _settings.find(name);
if (i == _settings.end()) {
extras.emplace(name, value);
} else {
i->second.setting->set(value);
i->second.setting->overriden = true;
}
if (i == _settings.end())
throw UsageError("unknown setting '%s'", name);
i->second.setting->set(value);
i->second.setting->overriden = true;
}
void Config::addSetting(AbstractSetting * setting)
@@ -23,34 +21,34 @@ void Config::addSetting(AbstractSetting * setting)
bool set = false;
auto i = extras.find(setting->name);
if (i != extras.end()) {
auto i = initials.find(setting->name);
if (i != initials.end()) {
setting->set(i->second);
setting->overriden = true;
extras.erase(i);
initials.erase(i);
set = true;
}
for (auto & alias : setting->aliases) {
auto i = extras.find(alias);
if (i != extras.end()) {
auto i = initials.find(alias);
if (i != initials.end()) {
if (set)
warn("setting '%s' is set, but it's an alias of '%s' which is also set",
alias, setting->name);
else {
setting->set(i->second);
setting->overriden = true;
extras.erase(i);
initials.erase(i);
set = true;
}
}
}
}
void Config::handleUnknownSettings()
void Config::warnUnknownSettings()
{
for (auto & s : extras)
warn("unknown setting '%s'", s.first);
for (auto & i : initials)
warn("unknown setting '%s'", i.first);
}
StringMap Config::getSettings(bool overridenOnly)
@@ -62,7 +60,7 @@ StringMap Config::getSettings(bool overridenOnly)
return res;
}
void Config::applyConfigFile(const Path & path)
void Config::applyConfigFile(const Path & path, bool fatal)
{
try {
string contents = readFile(path);
@@ -82,31 +80,7 @@ void Config::applyConfigFile(const Path & path)
vector<string> tokens = tokenizeString<vector<string> >(line);
if (tokens.empty()) continue;
if (tokens.size() < 2)
throw UsageError("illegal configuration line '%1%' in '%2%'", line, path);
auto include = false;
auto ignoreMissing = false;
if (tokens[0] == "include")
include = true;
else if (tokens[0] == "!include") {
include = true;
ignoreMissing = true;
}
if (include) {
if (tokens.size() != 2)
throw UsageError("illegal configuration line '%1%' in '%2%'", line, path);
auto p = absPath(tokens[1], dirOf(path));
if (pathExists(p)) {
applyConfigFile(p);
} else if (!ignoreMissing) {
throw Error("file '%1%' included from '%2%' not found", p, path);
}
continue;
}
if (tokens[1] != "=")
if (tokens.size() < 2 || tokens[1] != "=")
throw UsageError("illegal configuration line '%1%' in '%2%'", line, path);
string name = tokens[0];
@@ -114,7 +88,12 @@ void Config::applyConfigFile(const Path & path)
vector<string>::iterator i = tokens.begin();
advance(i, 2);
set(name, concatStringsSep(" ", Strings(i, tokens.end()))); // FIXME: slow
try {
set(name, concatStringsSep(" ", Strings(i, tokens.end()))); // FIXME: slow
} catch (UsageError & e) {
if (fatal) throw;
warn("in configuration file '%s': %s", path, e.what());
}
};
} catch (SysError &) { }
}

View File

@@ -48,25 +48,25 @@ private:
Settings _settings;
StringMap extras;
StringMap initials;
public:
Config(const StringMap & initials)
: extras(initials)
: initials(initials)
{ }
void set(const std::string & name, const std::string & value);
void addSetting(AbstractSetting * setting);
void handleUnknownSettings();
void warnUnknownSettings();
StringMap getSettings(bool overridenOnly = false);
const Settings & _getSettings() { return _settings; }
void applyConfigFile(const Path & path);
void applyConfigFile(const Path & path, bool fatal = false);
void resetOverriden();

View File

@@ -189,8 +189,7 @@ Hash::Hash(const std::string & s, HashType type)
else if (size == base64Len()) {
auto d = base64Decode(std::string(s, pos));
if (d.size() != hashSize)
throw BadHash("invalid base-64 hash '%s'", s);
assert(d.size() == hashSize);
memcpy(hash, d.data(), hashSize);
}

View File

@@ -44,7 +44,7 @@ public:
prefix = std::string("<") + c + ">";
}
writeToStderr(prefix + filterANSIEscapes(fs.s) + "\n");
writeToStderr(prefix + (tty ? fs.s : filterANSIEscapes(fs.s)) + "\n");
}
void startActivity(ActivityId act, Verbosity lvl, ActivityType type,

View File

@@ -21,29 +21,13 @@ public:
MonitorFdHup(int fd)
{
thread = std::thread([fd]() {
while (true) {
/* Wait indefinitely until a POLLHUP occurs. */
struct pollfd fds[1];
fds[0].fd = fd;
/* This shouldn't be necessary, but macOS doesn't seem to
like a zeroed out events field.
See rdar://37537852.
*/
fds[0].events = POLLHUP;
auto count = poll(fds, 1, -1);
if (count == -1) abort(); // can't happen
/* This shouldn't happen, but can on macOS due to a bug.
See rdar://37550628.
This may eventually need a delay or further
coordination with the main thread if spinning proves
too harmful.
*/
if (count == 0) continue;
assert(fds[0].revents & POLLHUP);
triggerInterrupt();
break;
}
/* Wait indefinitely until a POLLHUP occurs. */
struct pollfd fds[1];
fds[0].fd = fd;
fds[0].events = 0;
if (poll(fds, 1, -1) == -1) abort(); // can't happen
assert(fds[0].revents & POLLHUP);
triggerInterrupt();
});
};

View File

@@ -192,12 +192,6 @@ bool isInDir(const Path & path, const Path & dir)
}
bool isDirOrInDir(const Path & path, const Path & dir)
{
return path == dir or isInDir(path, dir);
}
struct stat lstat(const Path & path)
{
struct stat st;
@@ -1178,51 +1172,36 @@ void ignoreException()
}
std::string filterANSIEscapes(const std::string & s, unsigned int width)
string filterANSIEscapes(const string & s, bool nixOnly)
{
std::string t, e;
size_t w = 0;
auto i = s.begin();
while (w < (size_t) width && i != s.end()) {
if (*i == '\e') {
std::string e;
e += *i++;
char last = 0;
if (i != s.end() && *i == '[') {
e += *i++;
// eat parameter bytes
while (i != s.end() && *i >= 0x30 && *i <= 0x3f) e += *i++;
// eat intermediate bytes
while (i != s.end() && *i >= 0x20 && *i <= 0x2f) e += *i++;
// eat final byte
if (i != s.end() && *i >= 0x40 && *i <= 0x7e) e += last = *i++;
} else {
if (i != s.end() && *i >= 0x40 && *i <= 0x5f) e += *i++;
string t, r;
enum { stTop, stEscape, stCSI } state = stTop;
for (auto c : s) {
if (state == stTop) {
if (c == '\e') {
state = stEscape;
r = c;
} else
t += c;
} else if (state == stEscape) {
r += c;
if (c == '[')
state = stCSI;
else {
t += r;
state = stTop;
}
if (last == 'm')
t += e;
}
else if (*i == '\t') {
i++; t += ' '; w++;
while (w < (size_t) width && w % 8) {
t += ' '; w++;
} else {
r += c;
if (c >= 0x40 && c <= 0x7e) {
if (nixOnly && (c != 'p' && c != 'q' && c != 's' && c != 'a' && c != 'b'))
t += r;
state = stTop;
r.clear();
}
}
else if (*i == '\r')
// do nothing for now
i++;
else {
t += *i++; w++;
}
}
t += r;
return t;
}

View File

@@ -53,12 +53,10 @@ Path dirOf(const Path & path);
following the final `/'. */
string baseNameOf(const Path & path);
/* Check whether 'path' is a descendant of 'dir'. */
/* Check whether a given path is a descendant of the given
directory. */
bool isInDir(const Path & path, const Path & dir);
/* Check whether 'path' is equal to 'dir' or a descendant of 'dir'. */
bool isDirOrInDir(const Path & path, const Path & dir);
/* Get status of `path'. */
struct stat lstat(const Path & path);
@@ -388,12 +386,10 @@ void ignoreException();
#define ANSI_BLUE "\e[34;1m"
/* Truncate a string to 'width' printable characters. Certain ANSI
escape sequences (such as colour setting) are copied but not
included in the character count. Other ANSI escape sequences are
filtered. Also, tabs are expanded to spaces. */
std::string filterANSIEscapes(const std::string & s,
unsigned int width = std::numeric_limits<unsigned int>::max());
/* Filter out ANSI escape codes from the given string. If nixOnly is
set, only filter escape codes generated by Nixpkgs' stdenv (used to
denote nesting etc.). */
string filterANSIEscapes(const string & s, bool nixOnly = false);
/* Base64 encoding/decoding. */

View File

@@ -141,7 +141,7 @@ void mainWrapped(int argc, char * * argv)
else if (*arg == "--version")
printVersion(myName);
else if (*arg == "--add-drv-link" || *arg == "--indirect")
else if (*arg == "--add-drv-link")
; // obsolete
else if (*arg == "--no-out-link" || *arg == "--no-link")
@@ -167,6 +167,9 @@ void mainWrapped(int argc, char * * argv)
buildMode = bmRepair;
}
else if (*arg == "--hash")
buildMode = bmHash;
else if (*arg == "--run-env") // obsolete
runEnv = true;
@@ -232,8 +235,6 @@ void mainWrapped(int argc, char * * argv)
myArgs.parseCmdline(args);
initPlugins();
if (packages && fromArgs)
throw UsageError("'-p' and '-E' are mutually exclusive");
@@ -278,8 +279,8 @@ void mainWrapped(int argc, char * * argv)
else
/* If we're in a #! script, interpret filenames
relative to the script. */
exprs.push_back(state.parseExprFromFile(resolveExprPath(state.checkSourcePath(lookupFileArg(state,
inShebang && !packages ? absPath(i, absPath(dirOf(script))) : i)))));
exprs.push_back(state.parseExprFromFile(resolveExprPath(lookupFileArg(state,
inShebang && !packages ? absPath(i, absPath(dirOf(script))) : i))));
}
/* Evaluate them into derivations. */

View File

@@ -213,9 +213,6 @@ int main(int argc, char ** argv)
}
return true;
});
initPlugins();
switch (cmd) {
case cNone:
throw UsageError("no command specified");

View File

@@ -77,8 +77,6 @@ int main(int argc, char * * argv)
return true;
});
initPlugins();
auto profilesDir = settings.nixStateDir + "/profiles";
if (removeOld) removeOldGenerations(profilesDir);

View File

@@ -44,8 +44,6 @@ int main(int argc, char ** argv)
return true;
});
initPlugins();
if (sshHost.empty())
throw UsageError("no host name specified");

View File

@@ -994,7 +994,7 @@ static void daemonLoop(char * * argv)
if (matchUser(user, group, trustedUsers))
trusted = true;
if ((!trusted && !matchUser(user, group, allowedUsers)) || group == settings.buildUsersGroup)
if (!trusted && !matchUser(user, group, allowedUsers))
throw Error(format("user '%1%' is not allowed to connect to the Nix daemon") % user);
printInfo(format((string) "accepted connection from pid %1%, user %2%" + (trusted ? " (trusted)" : ""))
@@ -1060,8 +1060,6 @@ int main(int argc, char * * argv)
return true;
});
initPlugins();
if (stdio) {
if (getStoreType() == tDaemon) {
/* Forward on this connection to the real daemon */

View File

@@ -1393,8 +1393,6 @@ int main(int argc, char * * argv)
myArgs.parseCmdline(argvToStrings(argc, argv));
initPlugins();
if (!op) throw UsageError("no operation specified");
auto store = openStore();

View File

@@ -151,8 +151,6 @@ int main(int argc, char * * argv)
myArgs.parseCmdline(argvToStrings(argc, argv));
initPlugins();
if (evalOnly && !wantsReadWrite)
settings.readOnlyMode = true;
@@ -184,7 +182,7 @@ int main(int argc, char * * argv)
for (auto & i : files) {
Expr * e = fromArgs
? state.parseExprFromString(i, absPath("."))
: state.parseExprFromFile(resolveExprPath(state.checkSourcePath(lookupFileArg(state, i))));
: state.parseExprFromFile(resolveExprPath(lookupFileArg(state, i)));
processExpr(state, attrPaths, parseOnly, strict, autoArgs,
evalOnly, outputKind, xmlOutputSourceLocation, e);
}

View File

@@ -89,8 +89,6 @@ int main(int argc, char * * argv)
myArgs.parseCmdline(argvToStrings(argc, argv));
initPlugins();
if (args.size() > 2)
throw UsageError("too many arguments");

View File

@@ -122,6 +122,7 @@ static void opRealise(Strings opFlags, Strings opArgs)
if (i == "--dry-run") dryRun = true;
else if (i == "--repair") buildMode = bmRepair;
else if (i == "--check") buildMode = bmCheck;
else if (i == "--hash") buildMode = bmHash;
else if (i == "--ignore-unknown") ignoreUnknown = true;
else throw UsageError(format("unknown flag '%1%'") % i);
@@ -1052,8 +1053,6 @@ int main(int argc, char * * argv)
return true;
});
initPlugins();
if (!op) throw UsageError("no operation specified");
if (op != opDump && op != opRestore) /* !!! hack */

View File

@@ -50,9 +50,7 @@ struct CmdBuild : MixDryRun, InstallablesCommand
void run(ref<Store> store) override
{
auto buildables = build(store, dryRun ? DryRun : Build, installables);
if (dryRun) return;
auto buildables = toBuildables(store, dryRun ? DryRun : Build, installables);
for (size_t i = 0; i < buildables.size(); ++i) {
auto & b(buildables[i]);

View File

@@ -5,8 +5,6 @@
namespace nix {
extern std::string programPath;
struct Value;
class Bindings;
class EvalState;
@@ -198,7 +196,7 @@ std::shared_ptr<Installable> parseInstallable(
SourceExprCommand & cmd, ref<Store> store, const std::string & installable,
bool useDefaultInstallables);
Buildables build(ref<Store> store, RealiseMode mode,
Buildables toBuildables(ref<Store> store, RealiseMode mode,
std::vector<std::shared_ptr<Installable>> installables);
PathSet toStorePaths(ref<Store> store, RealiseMode mode,

View File

@@ -57,15 +57,15 @@ struct CmdCopy : StorePathsCommand
return {
Example{
"To copy Firefox from the local store to a binary cache in file:///tmp/cache:",
"nix copy --to file:///tmp/cache $(type -p firefox)"
"nix copy --to file:///tmp/cache -r $(type -p firefox)"
},
Example{
"To copy the entire current NixOS system closure to another machine via SSH:",
"nix copy --to ssh://server /run/current-system"
"nix copy --to ssh://server -r /run/current-system"
},
Example{
"To copy a closure from another machine via SSH:",
"nix copy --from ssh://server /nix/store/a6cnl93nk1wxnq84brbbwr6hxw9gp2w9-blender-2.79-rc2"
"nix copy --from ssh://server -r /nix/store/a6cnl93nk1wxnq84brbbwr6hxw9gp2w9-blender-2.79-rc2"
},
};
}

View File

@@ -5,11 +5,10 @@
#include "eval.hh"
#include "json.hh"
#include "value-to-json.hh"
#include "progress-bar.hh"
using namespace nix;
struct CmdEval : MixJSON, InstallableCommand
struct CmdEval : MixJSON, InstallablesCommand
{
bool raw = false;
@@ -57,19 +56,20 @@ struct CmdEval : MixJSON, InstallableCommand
auto state = getEvalState();
auto v = installable->toValue(*state);
PathSet context;
auto jsonOut = json ? std::make_unique<JSONList>(std::cout) : nullptr;
stopProgressBar();
if (raw) {
std::cout << state->coerceToString(noPos, *v, context);
} else if (json) {
JSONPlaceholder jsonOut(std::cout);
printValueAsJSON(*state, true, *v, jsonOut, context);
} else {
state->forceValueDeep(*v);
std::cout << *v << "\n";
for (auto & i : installables) {
auto v = i->toValue(*state);
PathSet context;
if (raw) {
std::cout << state->coerceToString(noPos, *v, context);
} else if (json) {
auto jsonElem = jsonOut->placeholder();
printValueAsJSON(*state, true, *v, jsonElem, context);
} else {
state->forceValueDeep(*v);
std::cout << *v << "\n";
}
}
}
};

View File

@@ -30,8 +30,10 @@ Value * SourceExprCommand::getSourceExpr(EvalState & state)
vSourceExpr = state.allocValue();
if (file != "")
state.evalFile(lookupFileArg(state, file), *vSourceExpr);
if (file != "") {
Expr * e = state.parseExprFromFile(resolveExprPath(lookupFileArg(state, file)));
state.eval(e, *vSourceExpr);
}
else {
@@ -253,7 +255,7 @@ std::shared_ptr<Installable> parseInstallable(
return installables.front();
}
Buildables build(ref<Store> store, RealiseMode mode,
Buildables toBuildables(ref<Store> store, RealiseMode mode,
std::vector<std::shared_ptr<Installable>> installables)
{
if (mode != Build)
@@ -291,7 +293,7 @@ PathSet toStorePaths(ref<Store> store, RealiseMode mode,
{
PathSet outPaths;
for (auto & b : build(store, mode, installables))
for (auto & b : toBuildables(store, mode, installables))
for (auto & output : b.outputs)
outPaths.insert(output.second);

View File

@@ -6,6 +6,4 @@ nix_SOURCES := $(wildcard $(d)/*.cc) $(wildcard src/linenoise/*.cpp)
nix_LIBS = libexpr libmain libstore libutil libformat
nix_LDFLAGS = -pthread
$(eval $(call install-symlink, nix, $(bindir)/nix-hash))

View File

@@ -50,7 +50,6 @@ struct CmdLog : InstallableCommand
auto b = installable->toBuildable();
RunPager pager;
for (auto & sub : subs) {
auto log = b.drvPath != "" ? sub->getBuildLog(b.drvPath) : nullptr;
for (auto & output : b.outputs) {

View File

@@ -90,16 +90,6 @@ struct CmdLsStore : StoreCommand, MixLs
expectArg("path", &path);
}
Examples examples() override
{
return {
Example{
"To list the contents of a store path in a binary cache:",
"nix ls-store --store https://cache.nixos.org/ -lR /nix/store/0i2jd68mp5g6h2sa5k9c85rb80sn8hi9-hello-2.10"
},
};
}
std::string name() override
{
return "ls-store";
@@ -126,16 +116,6 @@ struct CmdLsNar : Command, MixLs
expectArg("path", &path);
}
Examples examples() override
{
return {
Example{
"To list a specific file in a NAR:",
"nix ls-nar -l hello.nar /bin/hello"
},
};
}
std::string name() override
{
return "ls-nar";

View File

@@ -16,8 +16,6 @@ void chrootHelper(int argc, char * * argv);
namespace nix {
std::string programPath;
struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
{
NixArgs() : MultiCommand(*RegisterCommand::commands), MixCommonArgs("nix")
@@ -80,8 +78,7 @@ void mainWrapped(int argc, char * * argv)
initNix();
initGC();
programPath = argv[0];
string programName = baseNameOf(programPath);
string programName = baseNameOf(argv[0]);
{
auto legacy = (*RegisterLegacyCommand::commands)[programName];
@@ -92,8 +89,6 @@ void mainWrapped(int argc, char * * argv)
args.parseCmdline(argvToStrings(argc, argv));
initPlugins();
if (!args.command) args.showHelpAndExit();
Finally f([]() { stopProgressBar(); });

View File

@@ -1,35 +0,0 @@
#include "command.hh"
#include "shared.hh"
#include "store-api.hh"
using namespace nix;
struct CmdPingStore : StoreCommand
{
std::string name() override
{
return "ping-store";
}
std::string description() override
{
return "test whether a store can be opened";
}
Examples examples() override
{
return {
Example{
"To test whether connecting to a remote Nix store via SSH works:",
"nix ping-store --store ssh://mac1"
},
};
}
void run(ref<Store> store) override
{
store->connect();
}
};
static RegisterCommand r1(make_ref<CmdPingStore>());

View File

@@ -3,9 +3,8 @@
#include "sync.hh"
#include "store-api.hh"
#include <atomic>
#include <map>
#include <thread>
#include <atomic>
namespace nix {
@@ -23,6 +22,44 @@ static uint64_t getI(const std::vector<Logger::Field> & fields, size_t n)
return fields[n].i;
}
/* Truncate a string to 'width' printable characters. ANSI escape
sequences are copied but not included in the character count. Also,
tabs are expanded to spaces. */
static std::string ansiTruncate(const std::string & s, int width)
{
if (width <= 0) return s;
std::string t;
size_t w = 0;
auto i = s.begin();
while (w < (size_t) width && i != s.end()) {
if (*i == '\e') {
t += *i++;
if (i != s.end() && *i == '[') {
t += *i++;
while (i != s.end() && (*i < 0x40 || *i > 0x7e)) {
t += *i++;
}
if (i != s.end()) t += *i++;
}
}
else if (*i == '\t') {
t += ' '; w++;
while (w < (size_t) width && w & 8) {
t += ' '; w++;
}
}
else {
t += *i++; w++;
}
}
return t;
}
class ProgressBar : public Logger
{
private:
@@ -64,28 +101,15 @@ private:
Sync<State> state_;
std::thread updateThread;
std::condition_variable quitCV, updateCV;
public:
ProgressBar()
{
updateThread = std::thread([&]() {
auto state(state_.lock());
while (state->active) {
state.wait(updateCV);
draw(*state);
state.wait_for(quitCV, std::chrono::milliseconds(50));
}
});
}
~ProgressBar()
{
stop();
updateThread.join();
}
void stop()
@@ -97,8 +121,6 @@ public:
writeToStderr("\r\e[K");
if (status != "")
writeToStderr("[" + status + "]\n");
updateCV.notify_one();
quitCV.notify_one();
}
void log(Verbosity lvl, const FormatOrString & fs) override
@@ -110,7 +132,7 @@ public:
void log(State & state, Verbosity lvl, const std::string & s)
{
writeToStderr("\r\e[K" + s + ANSI_NORMAL "\n");
draw(state);
update(state);
}
void startActivity(ActivityId act, Verbosity lvl, ActivityType type,
@@ -145,12 +167,7 @@ public:
if (type == actSubstitute) {
auto name = storePathToName(getS(fields, 0));
auto sub = getS(fields, 1);
i->s = fmt(
hasPrefix(sub, "local")
? "copying " ANSI_BOLD "%s" ANSI_NORMAL " from %s"
: "fetching " ANSI_BOLD "%s" ANSI_NORMAL " from %s",
name, sub);
i->s = fmt("fetching " ANSI_BOLD "%s" ANSI_NORMAL " from %s", name, getS(fields, 1));
}
if (type == actQueryPathInfo) {
@@ -163,7 +180,7 @@ public:
|| (type == actCopyPath && hasAncestor(*state, actSubstitute, parent)))
i->visible = false;
update();
update(*state);
}
/* Check whether an activity has an ancestore with the specified
@@ -198,7 +215,7 @@ public:
state->its.erase(i);
}
update();
update(*state);
}
void result(ActivityId act, ResultType type, const std::vector<Field> & fields) override
@@ -208,7 +225,7 @@ public:
if (type == resFileLinked) {
state->filesLinked++;
state->bytesLinked += getI(fields, 0);
update();
update(*state);
}
else if (type == resBuildLogLine) {
@@ -221,25 +238,25 @@ public:
info.lastLine = lastLine;
state->activities.emplace_back(info);
i->second = std::prev(state->activities.end());
update();
update(*state);
}
}
else if (type == resUntrustedPath) {
state->untrustedPaths++;
update();
update(*state);
}
else if (type == resCorruptedPath) {
state->corruptedPaths++;
update();
update(*state);
}
else if (type == resSetPhase) {
auto i = state->its.find(act);
assert(i != state->its.end());
i->second->phase = getS(fields, 0);
update();
update(*state);
}
else if (type == resProgress) {
@@ -250,7 +267,7 @@ public:
actInfo.expected = getI(fields, 1);
actInfo.running = getI(fields, 2);
actInfo.failed = getI(fields, 3);
update();
update(*state);
}
else if (type == resSetExpected) {
@@ -262,16 +279,17 @@ public:
state->activitiesByType[type].expected -= j;
j = getI(fields, 1);
state->activitiesByType[type].expected += j;
update();
update(*state);
}
}
void update()
{
updateCV.notify_one();
auto state(state_.lock());
update(*state);
}
void draw(State & state)
void update(State & state)
{
if (!state.active) return;
@@ -305,10 +323,7 @@ public:
}
}
auto width = getWindowSize().second;
if (width <= 0) std::numeric_limits<decltype(width)>::max();
writeToStderr("\r" + filterANSIEscapes(line, width) + "\e[K");
writeToStderr("\r" + ansiTruncate(line, getWindowSize().second) + "\e[K");
}
std::string getStatus(State & state)

View File

@@ -85,10 +85,6 @@ struct CmdRun : InstallablesCommand
"To run GNU Hello:",
"nix run nixpkgs.hello -c hello --greeting 'Hi everybody!'"
},
Example{
"To run GNU Hello in a chroot store:",
"nix run --store ~/my-nix nixpkgs.hello -c hello"
},
};
}

View File

@@ -1,131 +0,0 @@
#include "command.hh"
#include "store-api.hh"
#include "download.hh"
#include "eval.hh"
#include "attr-path.hh"
using namespace nix;
struct CmdUpgradeNix : StoreCommand
{
Path profileDir;
CmdUpgradeNix()
{
mkFlag()
.longName("profile")
.shortName('p')
.labels({"profile-dir"})
.description("the Nix profile to upgrade")
.dest(&profileDir);
}
std::string name() override
{
return "upgrade-nix";
}
std::string description() override
{
return "upgrade Nix to the latest stable version";
}
Examples examples() override
{
return {
Example{
"To upgrade Nix to the latest stable version:",
"nix upgrade-nix"
},
Example{
"To upgrade Nix in a specific profile:",
"nix upgrade-nix -p /nix/var/nix/profiles/per-user/alice/profile"
},
};
}
void run(ref<Store> store) override
{
settings.pureEval = true;
if (profileDir == "")
profileDir = getProfileDir(store);
printInfo("upgrading Nix in profile '%s'", profileDir);
Path storePath;
{
Activity act(*logger, lvlInfo, actUnknown, "querying latest Nix version");
storePath = getLatestNix(store);
}
{
Activity act(*logger, lvlInfo, actUnknown, fmt("downloading '%s'...", storePath));
store->ensurePath(storePath);
}
{
Activity act(*logger, lvlInfo, actUnknown, fmt("verifying that '%s' works...", storePath));
auto program = storePath + "/bin/nix-env";
auto s = runProgram(program, false, {"--version"});
if (s.find("Nix") == std::string::npos)
throw Error("could not verify that '%s' works", program);
}
{
Activity act(*logger, lvlInfo, actUnknown, fmt("installing '%s' into profile '%s'...", storePath, profileDir));
runProgram(settings.nixBinDir + "/nix-env", false,
{"--profile", profileDir, "-i", storePath, "--no-sandbox"});
}
}
/* Return the profile in which Nix is installed. */
Path getProfileDir(ref<Store> store)
{
Path where;
for (auto & dir : tokenizeString<Strings>(getEnv("PATH"), ":"))
if (pathExists(dir + "/nix-env")) {
where = dir;
break;
}
if (where == "")
throw Error("couldn't figure out how Nix is installed, so I can't upgrade it");
printInfo("found Nix in '%s'", where);
if (hasPrefix(where, "/run/current-system"))
throw Error("Nix on NixOS must be upgraded via 'nixos-rebuild'");
Path profileDir;
Path userEnv;
if (baseNameOf(where) != "bin" ||
!hasSuffix(userEnv = canonPath(profileDir = dirOf(where), true), "user-environment"))
throw Error("directory '%s' does not appear to be part of a Nix profile", where);
if (!store->isValidPath(userEnv))
throw Error("directory '%s' is not in the Nix store", userEnv);
return profileDir;
}
/* Return the store path of the latest stable Nix. */
Path getLatestNix(ref<Store> store)
{
// FIXME: use nixos.org?
auto req = DownloadRequest("https://github.com/NixOS/nixpkgs/raw/master/nixos/modules/installer/tools/nix-fallback-paths.nix");
auto res = getDownloader()->download(req);
EvalState state(Strings(), store);
auto v = state.allocValue();
state.eval(state.parseExprFromString(*res.data, "/no-such-path"), *v);
Bindings & bindings(*state.allocBindings(0));
auto v2 = findAlongAttrPath(state, settings.thisSystem, bindings, *v);
return state.forceString(*v2);
}
};
static RegisterCommand r1(make_ref<CmdUpgradeNix>());

File diff suppressed because it is too large Load Diff

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