Compare commits

..

1 Commits

Author SHA1 Message Date
Eelco Dolstra
a3d874175c Add builtins.unique [WIP]
This cuts ~4.5s from "nix-env -qaP -f `<nixpkgs>` --out-path" and
reduces memory allocations from 7.49 to 7.16 GiB.

Note that builtins.unique requires a less-than comparator function,
which is a change from the 'unique' function in Nixpkgs which uses an
equality function.
2019-04-12 22:47:14 +02:00
159 changed files with 1386 additions and 4347 deletions

View File

@@ -1 +1 @@
2.3.4
2.3

View File

@@ -19,4 +19,11 @@ GLOBAL_CXXFLAGS += -g -Wall -include config.h
-include Makefile.config
OPTIMIZE = 1
ifeq ($(OPTIMIZE), 1)
GLOBAL_CFLAGS += -O3
GLOBAL_CXXFLAGS += -O3
endif
include mk/lib.mk

View File

@@ -5,11 +5,10 @@ CC = @CC@
CFLAGS = @CFLAGS@
CXX = @CXX@
CXXFLAGS = @CXXFLAGS@
LDFLAGS = @LDFLAGS@
ENABLE_S3 = @ENABLE_S3@
HAVE_SODIUM = @HAVE_SODIUM@
HAVE_READLINE = @HAVE_READLINE@
HAVE_SECCOMP = @HAVE_SECCOMP@
BOOST_LDFLAGS = @BOOST_LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
OPENSSL_LIBS = @OPENSSL_LIBS@
PACKAGE_NAME = @PACKAGE_NAME@

View File

@@ -1,5 +1,3 @@
[![Open Collective supporters](https://opencollective.com/nixos/tiers/supporter/badge.svg?label=Supporters&color=brightgreen)](https://opencollective.com/nixos)
Nix, the purely functional package manager
------------------------------------------

View File

@@ -1,5 +1,4 @@
AC_INIT(nix, m4_esyscmd([bash -c "echo -n $(cat ./.version)$VERSION_SUFFIX"]))
AC_CONFIG_MACRO_DIRS([m4])
AC_CONFIG_SRCDIR(README.md)
AC_CONFIG_AUX_DIR(config)
@@ -43,28 +42,13 @@ esac
AC_MSG_RESULT($system)
AC_SUBST(system)
AC_DEFINE_UNQUOTED(SYSTEM, ["$system"], [platform identifier ('cpu-os')])
AC_DEFINE_UNQUOTED(SYSTEM, ["$system"], [platform identifier (`cpu-os')])
# State should be stored in /nix/var, unless the user overrides it explicitly.
test "$localstatedir" = '${prefix}/var' && localstatedir=/nix/var
# Set default flags for nix (as per AC_PROG_CC/CXX docs),
# while still allowing the user to override them from the command line.
: ${CFLAGS="-O3"}
: ${CXXFLAGS="-O3"}
AC_PROG_CC
AC_PROG_CXX
AC_PROG_CPP
AX_CXX_COMPILE_STDCXX_17([noext], [mandatory])
AC_CHECK_TOOL([AR], [ar])
# Use 64-bit file system calls so that we can support files > 2 GiB.
AC_SYS_LARGEFILE
# Solaris-specific stuff.
AC_STRUCT_DIRENT_D_TYPE
if test "$sys_name" = sunos; then
@@ -73,6 +57,19 @@ if test "$sys_name" = sunos; then
fi
CFLAGS=
CXXFLAGS=
AC_PROG_CC
AC_PROG_CXX
AC_PROG_CPP
AX_CXX_COMPILE_STDCXX_17
AC_CHECK_TOOL([AR], [ar])
# Use 64-bit file system calls so that we can support files > 2 GiB.
AC_SYS_LARGEFILE
# Check for pubsetbuf.
AC_MSG_CHECKING([for pubsetbuf])
AC_LANG_PUSH(C++)
@@ -148,16 +145,6 @@ AC_ARG_WITH(store-dir, AC_HELP_STRING([--with-store-dir=PATH],
AC_SUBST(storedir)
# Look for boost, a required dependency.
# Note that AX_BOOST_BASE only exports *CPP* BOOST_CPPFLAGS, no CXX flags,
# and CPPFLAGS are not passed to the C++ compiler automatically.
# Thus we append the returned CPPFLAGS to the CXXFLAGS here.
AX_BOOST_BASE([1.66], [CXXFLAGS="$BOOST_CPPFLAGS $CXXFLAGS"], [AC_MSG_ERROR([Nix requires boost.])])
# For unknown reasons, setting this directly in the ACTION-IF-FOUND above
# ends up with LDFLAGS being empty, so we set it afterwards.
LDFLAGS="$BOOST_LDFLAGS $LDFLAGS"
# Look for OpenSSL, a required dependency.
PKG_CHECK_MODULES([OPENSSL], [libcrypto], [CXXFLAGS="$OPENSSL_CFLAGS $CXXFLAGS"])
@@ -177,16 +164,7 @@ PKG_CHECK_MODULES([SQLITE3], [sqlite3 >= 3.6.19], [CXXFLAGS="$SQLITE3_CFLAGS $CX
PKG_CHECK_MODULES([LIBCURL], [libcurl], [CXXFLAGS="$LIBCURL_CFLAGS $CXXFLAGS"])
# Look for editline, a required dependency.
# The the libeditline.pc file was added only in libeditline >= 1.15.2,
# see https://github.com/troglobit/editline/commit/0a8f2ef4203c3a4a4726b9dd1336869cd0da8607,
# but e.g. Ubuntu 16.04 has an older version, so we fall back to searching for
# editline.h when the pkg-config approach fails.
PKG_CHECK_MODULES([EDITLINE], [libeditline], [CXXFLAGS="$EDITLINE_CFLAGS $CXXFLAGS"], [
AC_CHECK_HEADERS([editline.h], [true],
[AC_MSG_ERROR([Nix requires libeditline; it was found neither via pkg-config nor its normal header.])])
AC_SEARCH_LIBS([readline read_history], [editline], [],
[AC_MSG_ERROR([Nix requires libeditline; it was not found via pkg-config, but via its header, but required functions do not work. Maybe it is too old? >= 1.14 is required.])])
])
PKG_CHECK_MODULES([EDITLINE], [libeditline], [CXXFLAGS="$EDITLINE_CFLAGS $CXXFLAGS"])
# Look for libsodium, an optional dependency.
PKG_CHECK_MODULES([SODIUM], [libsodium],

View File

@@ -1,38 +0,0 @@
#!/usr/bin/env nix-shell
#!nix-shell -i python3 -p python3 --pure
# To be used with `--trace-function-calls` and `flamegraph.pl`.
#
# For example:
#
# nix-instantiate --trace-function-calls '<nixpkgs>' -A hello 2> nix-function-calls.trace
# ./contrib/stack-collapse.py nix-function-calls.trace > nix-function-calls.folded
# nix-shell -p flamegraph --run "flamegraph.pl nix-function-calls.folded > nix-function-calls.svg"
import sys
from pprint import pprint
import fileinput
stack = []
timestack = []
for line in fileinput.input():
components = line.strip().split(" ", 2)
if components[0] != "function-trace":
continue
direction = components[1]
components = components[2].rsplit(" ", 2)
loc = components[0]
_at = components[1]
time = int(components[2])
if direction == "entered":
stack.append(loc)
timestack.append(time)
elif direction == "exited":
dur = time - timestack.pop()
vst = ";".join(stack)
print(f"{vst} {dur}")
stack.pop()

View File

@@ -18,17 +18,21 @@ let
if [ * != $channelName ]; then
mv * $out/$channelName
fi
if [ -n "$binaryCacheURL" ]; then
mkdir $out/binary-caches
echo -n "$binaryCacheURL" > $out/binary-caches/$channelName
fi
'';
in
{ name, channelName, src }:
{ name, channelName, src, binaryCacheURL ? "" }:
derivation {
system = builtins.currentSystem;
builder = shell;
args = [ "-e" builder ];
inherit name channelName src;
inherit name channelName src binaryCacheURL;
PATH = "${nixBinDir}:${coreutils}";

View File

@@ -7,8 +7,5 @@
<title>Advanced Topics</title>
<xi:include href="distributed-builds.xml" />
<xi:include href="cores-vs-jobs.xml" />
<xi:include href="diff-hook.xml" />
<xi:include href="post-build-hook.xml" />
</part>

View File

@@ -1,121 +0,0 @@
<chapter 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="chap-tuning-cores-and-jobs">
<title>Tuning Cores and Jobs</title>
<para>Nix has two relevant settings with regards to how your CPU cores
will be utilized: <xref linkend="conf-cores" /> and
<xref linkend="conf-max-jobs" />. This chapter will talk about what
they are, how they interact, and their configuration trade-offs.</para>
<variablelist>
<varlistentry>
<term><xref linkend="conf-max-jobs" /></term>
<listitem><para>
Dictates how many separate derivations will be built at the same
time. If you set this to zero, the local machine will do no
builds. Nix will still substitute from binary caches, and build
remotely if remote builders are configured.
</para></listitem>
</varlistentry>
<varlistentry>
<term><xref linkend="conf-cores" /></term>
<listitem><para>
Suggests how many cores each derivation should use. Similar to
<command>make -j</command>.
</para></listitem>
</varlistentry>
</variablelist>
<para>The <xref linkend="conf-cores" /> setting determines the value of
<envar>NIX_BUILD_CORES</envar>. <envar>NIX_BUILD_CORES</envar> is equal
to <xref linkend="conf-cores" />, unless <xref linkend="conf-cores" />
equals <literal>0</literal>, in which case <envar>NIX_BUILD_CORES</envar>
will be the total number of cores in the system.</para>
<para>The total number of consumed cores is a simple multiplication,
<xref linkend="conf-cores" /> * <envar>NIX_BUILD_CORES</envar>.</para>
<para>The balance on how to set these two independent variables depends
upon each builder's workload and hardware. Here are a few example
scenarios on a machine with 24 cores:</para>
<table>
<caption>Balancing 24 Build Cores</caption>
<thead>
<tr>
<th><xref linkend="conf-max-jobs" /></th>
<th><xref linkend="conf-cores" /></th>
<th><envar>NIX_BUILD_CORES</envar></th>
<th>Maximum Processes</th>
<th>Result</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>24</td>
<td>24</td>
<td>24</td>
<td>
One derivation will be built at a time, each one can use 24
cores. Undersold if a job cant use 24 cores.
</td>
</tr>
<tr>
<td>4</td>
<td>6</td>
<td>6</td>
<td>24</td>
<td>
Four derivations will be built at once, each given access to
six cores.
</td>
</tr>
<tr>
<td>12</td>
<td>6</td>
<td>6</td>
<td>72</td>
<td>
12 derivations will be built at once, each given access to six
cores. This configuration is over-sold. If all 12 derivations
being built simultaneously try to use all six cores, the
machine's performance will be degraded due to extensive context
switching between the 12 builds.
</td>
</tr>
<tr>
<td>24</td>
<td>1</td>
<td>1</td>
<td>24</td>
<td>
24 derivations can build at the same time, each using a single
core. Never oversold, but derivations which require many cores
will be very slow to compile.
</td>
</tr>
<tr>
<td>24</td>
<td>0</td>
<td>24</td>
<td>576</td>
<td>
24 derivations can build at the same time, each using all the
available cores of the machine. Very likely to be oversold,
and very likely to suffer context switches.
</td>
</tr>
</tbody>
</table>
<para>It is up to the derivations' build script to respect
host's requested cores-per-build by following the value of the
<envar>NIX_BUILD_CORES</envar> environment variable.</para>
</chapter>

View File

@@ -1,205 +0,0 @@
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xml:id="chap-diff-hook"
version="5.0"
>
<title>Verifying Build Reproducibility with <option linkend="conf-diff-hook">diff-hook</option></title>
<subtitle>Check build reproducibility by running builds multiple times
and comparing their results.</subtitle>
<para>Specify a program with Nix's <xref linkend="conf-diff-hook" /> to
compare build results when two builds produce different results. Note:
this hook is only executed if the results are not the same, this hook
is not used for determining if the results are the same.</para>
<para>For purposes of demonstration, we'll use the following Nix file,
<filename>deterministic.nix</filename> for testing:</para>
<programlisting>
let
inherit (import &lt;nixpkgs&gt; {}) runCommand;
in {
stable = runCommand "stable" {} ''
touch $out
'';
unstable = runCommand "unstable" {} ''
echo $RANDOM > $out
'';
}
</programlisting>
<para>Additionally, <filename>nix.conf</filename> contains:
<programlisting>
diff-hook = /etc/nix/my-diff-hook
run-diff-hook = true
</programlisting>
where <filename>/etc/nix/my-diff-hook</filename> is an executable
file containing:
<programlisting>
#!/bin/sh
exec &gt;&amp;2
echo "For derivation $3:"
/run/current-system/sw/bin/diff -r "$1" "$2"
</programlisting>
</para>
<para>The diff hook is executed by the same user and group who ran the
build. However, the diff hook does not have write access to the store
path just built.</para>
<section>
<title>
Spot-Checking Build Determinism
</title>
<para>
Verify a path which already exists in the Nix store by passing
<option>--check</option> to the build command.
</para>
<para>If the build passes and is deterministic, Nix will exit with a
status code of 0:</para>
<screen>
$ nix-build ./deterministic.nix -A stable
these derivations will be built:
/nix/store/z98fasz2jqy9gs0xbvdj939p27jwda38-stable.drv
building '/nix/store/z98fasz2jqy9gs0xbvdj939p27jwda38-stable.drv'...
/nix/store/yyxlzw3vqaas7wfp04g0b1xg51f2czgq-stable
$ nix-build ./deterministic.nix -A stable --check
checking outputs of '/nix/store/z98fasz2jqy9gs0xbvdj939p27jwda38-stable.drv'...
/nix/store/yyxlzw3vqaas7wfp04g0b1xg51f2czgq-stable
</screen>
<para>If the build is not deterministic, Nix will exit with a status
code of 1:</para>
<screen>
$ nix-build ./deterministic.nix -A unstable
these derivations will be built:
/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv
building '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv'...
/nix/store/krpqk0l9ib0ibi1d2w52z293zw455cap-unstable
$ nix-build ./deterministic.nix -A unstable --check
checking outputs of '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv'...
error: derivation '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv' may not be deterministic: output '/nix/store/krpqk0l9ib0ibi1d2w52z293zw455cap-unstable' differs
</screen>
<para>In the Nix daemon's log, we will now see:
<screen>
For derivation /nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv:
1c1
&lt; 8108
---
&gt; 30204
</screen>
</para>
<para>Using <option>--check</option> with <option>--keep-failed</option>
will cause Nix to keep the second build's output in a special,
<literal>.check</literal> path:</para>
<screen>
$ nix-build ./deterministic.nix -A unstable --check --keep-failed
checking outputs of '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv'...
note: keeping build directory '/tmp/nix-build-unstable.drv-0'
error: derivation '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv' may not be deterministic: output '/nix/store/krpqk0l9ib0ibi1d2w52z293zw455cap-unstable' differs from '/nix/store/krpqk0l9ib0ibi1d2w52z293zw455cap-unstable.check'
</screen>
<para>In particular, notice the
<literal>/nix/store/krpqk0l9ib0ibi1d2w52z293zw455cap-unstable.check</literal>
output. Nix has copied the build results to that directory where you
can examine it.</para>
<note xml:id="check-dirs-are-unregistered">
<title><literal>.check</literal> paths are not registered store paths</title>
<para>Check paths are not protected against garbage collection,
and this path will be deleted on the next garbage collection.</para>
<para>The path is guaranteed to be alive for the duration of
<xref linkend="conf-diff-hook" />'s execution, but may be deleted
any time after.</para>
<para>If the comparison is performed as part of automated tooling,
please use the diff-hook or author your tooling to handle the case
where the build was not deterministic and also a check path does
not exist.</para>
</note>
<para>
<option>--check</option> is only usable if the derivation has
been built on the system already. If the derivation has not been
built Nix will fail with the error:
<screen>
error: some outputs of '/nix/store/hzi1h60z2qf0nb85iwnpvrai3j2w7rr6-unstable.drv' are not valid, so checking is not possible
</screen>
Run the build without <option>--check</option>, and then try with
<option>--check</option> again.
</para>
</section>
<section>
<title>
Automatic and Optionally Enforced Determinism Verification
</title>
<para>
Automatically verify every build at build time by executing the
build multiple times.
</para>
<para>
Setting <xref linkend="conf-repeat" /> and
<xref linkend="conf-enforce-determinism" /> in your
<filename>nix.conf</filename> permits the automated verification
of every build Nix performs.
</para>
<para>
The following configuration will run each build three times, and
will require the build to be deterministic:
<programlisting>
enforce-determinism = true
repeat = 2
</programlisting>
</para>
<para>
Setting <xref linkend="conf-enforce-determinism" /> to false as in
the following configuration will run the build multiple times,
execute the build hook, but will allow the build to succeed even
if it does not build reproducibly:
<programlisting>
enforce-determinism = false
repeat = 1
</programlisting>
</para>
<para>
An example output of this configuration:
<screen>
$ nix-build ./test.nix -A unstable
these derivations will be built:
/nix/store/ch6llwpr2h8c3jmnf3f2ghkhx59aa97f-unstable.drv
building '/nix/store/ch6llwpr2h8c3jmnf3f2ghkhx59aa97f-unstable.drv' (round 1/2)...
building '/nix/store/ch6llwpr2h8c3jmnf3f2ghkhx59aa97f-unstable.drv' (round 2/2)...
output '/nix/store/6xg356v9gl03hpbbg8gws77n19qanh02-unstable' of '/nix/store/ch6llwpr2h8c3jmnf3f2ghkhx59aa97f-unstable.drv' differs from '/nix/store/6xg356v9gl03hpbbg8gws77n19qanh02-unstable.check' from previous round
/nix/store/6xg356v9gl03hpbbg8gws77n19qanh02-unstable
</screen>
</para>
</section>
</chapter>

View File

@@ -184,7 +184,4 @@ to be included. (This is the default.)</para>
the option <link linkend='conf-builders-use-substitutes'><literal>builders-use-substitutes</literal></link>
in your local <filename>nix.conf</filename>.</para>
<para>To build only on remote builders and disable building on the local machine,
you can use the option <option>--max-jobs 0</option>.</para>
</chapter>

View File

@@ -1,160 +0,0 @@
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xml:id="chap-post-build-hook"
version="5.0"
>
<title>Using the <xref linkend="conf-post-build-hook" /></title>
<subtitle>Uploading to an S3-compatible binary cache after each build</subtitle>
<section xml:id="chap-post-build-hook-caveats">
<title>Implementation Caveats</title>
<para>Here we use the post-build hook to upload to a binary cache.
This is a simple and working example, but it is not suitable for all
use cases.</para>
<para>The post build hook program runs after each executed build,
and blocks the build loop. The build loop exits if the hook program
fails.</para>
<para>Concretely, this implementation will make Nix slow or unusable
when the internet is slow or unreliable.</para>
<para>A more advanced implementation might pass the store paths to a
user-supplied daemon or queue for processing the store paths outside
of the build loop.</para>
</section>
<section>
<title>Prerequisites</title>
<para>
This tutorial assumes you have configured an S3-compatible binary cache
according to the instructions at
<xref linkend="ssec-s3-substituter-authenticated-writes" />, and
that the <literal>root</literal> user's default AWS profile can
upload to the bucket.
</para>
</section>
<section>
<title>Set up a Signing Key</title>
<para>Use <command>nix-store --generate-binary-cache-key</command> to
create our public and private signing keys. We will sign paths
with the private key, and distribute the public key for verifying
the authenticity of the paths.</para>
<screen>
# nix-store --generate-binary-cache-key example-nix-cache-1 /etc/nix/key.private /etc/nix/key.public
# cat /etc/nix/key.public
example-nix-cache-1:1/cKDz3QCCOmwcztD2eV6Coggp6rqc9DGjWv7C0G+rM=
</screen>
<para>Then, add the public key and the cache URL to your
<filename>nix.conf</filename>'s <xref linkend="conf-trusted-public-keys" />
and <xref linkend="conf-substituters" /> like:</para>
<programlisting>
substituters = https://cache.nixos.org/ s3://example-nix-cache
trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= example-nix-cache-1:1/cKDz3QCCOmwcztD2eV6Coggp6rqc9DGjWv7C0G+rM=
</programlisting>
<para>we will restart the Nix daemon a later step.</para>
</section>
<section>
<title>Implementing the build hook</title>
<para>Write the following script to
<filename>/etc/nix/upload-to-cache.sh</filename>:
</para>
<programlisting>
#!/bin/sh
set -eu
set -f # disable globbing
export IFS=' '
echo "Signing paths" $OUT_PATHS
nix sign-paths --key-file /etc/nix/key.private $OUT_PATHS
echo "Uploading paths" $OUT_PATHS
exec nix copy --to 's3://example-nix-cache' $OUT_PATHS
</programlisting>
<note>
<title>Should <literal>$OUT_PATHS</literal> be quoted?</title>
<para>
The <literal>$OUT_PATHS</literal> variable is a space-separated
list of Nix store paths. In this case, we expect and want the
shell to perform word splitting to make each output path its
own argument to <command>nix sign-paths</command>. Nix guarantees
the paths will not contain any spaces, however a store path
might contain glob characters. The <command>set -f</command>
disables globbing in the shell.
</para>
</note>
<para>
Then make sure the hook program is executable by the <literal>root</literal> user:
<screen>
# chmod +x /etc/nix/upload-to-cache.sh
</screen></para>
</section>
<section>
<title>Updating Nix Configuration</title>
<para>Edit <filename>/etc/nix/nix.conf</filename> to run our hook,
by adding the following configuration snippet at the end:</para>
<programlisting>
post-build-hook = /etc/nix/upload-to-cache.sh
</programlisting>
<para>Then, restart the <command>nix-daemon</command>.</para>
</section>
<section>
<title>Testing</title>
<para>Build any derivation, for example:</para>
<screen>
$ nix-build -E '(import &lt;nixpkgs&gt; {}).writeText "example" (builtins.toString builtins.currentTime)'
these derivations will be built:
/nix/store/s4pnfbkalzy5qz57qs6yybna8wylkig6-example.drv
building '/nix/store/s4pnfbkalzy5qz57qs6yybna8wylkig6-example.drv'...
running post-build-hook '/home/grahamc/projects/github.com/NixOS/nix/post-hook.sh'...
post-build-hook: Signing paths /nix/store/ibcyipq5gf91838ldx40mjsp0b8w9n18-example
post-build-hook: Uploading paths /nix/store/ibcyipq5gf91838ldx40mjsp0b8w9n18-example
/nix/store/ibcyipq5gf91838ldx40mjsp0b8w9n18-example
</screen>
<para>Then delete the path from the store, and try substituting it from the binary cache:</para>
<screen>
$ rm ./result
$ nix-store --delete /nix/store/ibcyipq5gf91838ldx40mjsp0b8w9n18-example
</screen>
<para>Now, copy the path back from the cache:</para>
<screen>
$ nix store --realize /nix/store/ibcyipq5gf91838ldx40mjsp0b8w9n18-example
copying path '/nix/store/m8bmqwrch6l3h8s0k3d673xpmipcdpsa-example from 's3://example-nix-cache'...
warning: you did not specify '--add-root'; the result might be removed by the garbage collector
/nix/store/m8bmqwrch6l3h8s0k3d673xpmipcdpsa-example
</screen>
</section>
<section>
<title>Conclusion</title>
<para>
We now have a Nix installation configured to automatically sign and
upload every local build to a remote binary cache.
</para>
<para>
Before deploying this to production, be sure to consider the
implementation caveats in <xref linkend="chap-post-build-hook-caveats" />.
</para>
</section>
</chapter>

View File

@@ -1,9 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<refentry xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xml:id="sec-conf-file"
version="5">
xml:id="sec-conf-file">
<refmeta>
<refentrytitle>nix.conf</refentrytitle>
@@ -238,74 +236,8 @@ false</literal>.</para>
linkend='opt-cores'>--cores</option> command line switch and
defaults to <literal>1</literal>. The value <literal>0</literal>
means that the builder should use all available CPU cores in the
system.</para>
system.</para></listitem>
<para>See also <xref linkend="chap-tuning-cores-and-jobs" />.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-diff-hook"><term><literal>diff-hook</literal></term>
<listitem>
<para>
Absolute path to an executable capable of diffing build results.
The hook executes if <xref linkend="conf-run-diff-hook" /> is
true, and the output of a build is known to not be the same.
This program is not executed to determine if two results are the
same.
</para>
<para>
The diff hook is executed by the same user and group who ran the
build. However, the diff hook does not have write access to the
store path just built.
</para>
<para>The diff hook program receives three parameters:</para>
<orderedlist>
<listitem>
<para>
A path to the previous build's results
</para>
</listitem>
<listitem>
<para>
A path to the current build's results
</para>
</listitem>
<listitem>
<para>
The path to the build's derivation
</para>
</listitem>
<listitem>
<para>
The path to the build's scratch directory. This directory
will exist only if the build was run with
<option>--keep-failed</option>.
</para>
</listitem>
</orderedlist>
<para>
The stderr and stdout output from the diff hook will not be
displayed to the user. Instead, it will print to the nix-daemon's
log.
</para>
<para>When using the Nix daemon, <literal>diff-hook</literal> must
be set in the <filename>nix.conf</filename> configuration file, and
cannot be passed at the command line.
</para>
</listitem>
</varlistentry>
<varlistentry xml:id="conf-enforce-determinism">
<term><literal>enforce-determinism</literal></term>
<listitem><para>See <xref linkend="conf-repeat" />.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-extra-sandbox-paths">
@@ -433,7 +365,7 @@ builtins.fetchurl {
<varlistentry xml:id="conf-keep-env-derivations"><term><literal>keep-env-derivations</literal></term>
<listitem><para>If <literal>false</literal> (default), derivations
are not stored in Nix user environments. That is, the derivations of
are not stored in Nix user environments. That is, the derivation
any build-time-only dependencies may be garbage-collected.</para>
<para>If <literal>true</literal>, when you add a Nix derivation to
@@ -483,10 +415,8 @@ builtins.fetchurl {
<varlistentry xml:id="conf-max-free"><term><literal>max-free</literal></term>
<listitem><para>When a garbage collection is triggered by the
<literal>min-free</literal> option, it stops as soon as
<literal>max-free</literal> bytes are available. The default is
infinity (i.e. delete all garbage).</para></listitem>
<listitem><para>This option defines after how many free bytes to stop collecting
garbage once the <literal>min-free</literal> condition gets triggered.</para></listitem>
</varlistentry>
@@ -501,10 +431,7 @@ builtins.fetchurl {
regardless). It can be
overridden using the <option
linkend='opt-max-jobs'>--max-jobs</option> (<option>-j</option>)
command line switch.</para>
<para>See also <xref linkend="chap-tuning-cores-and-jobs" />.</para>
</listitem>
command line switch.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-max-silent-time"><term><literal>max-silent-time</literal></term>
@@ -530,11 +457,9 @@ builtins.fetchurl {
<varlistentry xml:id="conf-min-free"><term><literal>min-free</literal></term>
<listitem>
<para>When free disk space in <filename>/nix/store</filename>
drops below <literal>min-free</literal> during a build, Nix
performs a garbage-collection until <literal>max-free</literal>
bytes are available or there is no more garbage. A value of
<literal>0</literal> (the default) disables this feature.</para>
<para>When the disk reaches <literal>min-free</literal> bytes of free disk space during a build, nix
will start to garbage-collection until <literal>max-free</literal> bytes are available on the disk.
A value of <literal>0</literal> (the default) means that this feature is disabled.</para>
</listitem>
</varlistentry>
@@ -664,71 +589,15 @@ password <replaceable>my-password</replaceable>
</varlistentry>
<varlistentry xml:id="conf-post-build-hook">
<term><literal>post-build-hook</literal></term>
<listitem>
<para>Optional. The path to a program to execute after each build.</para>
<para>This option is only settable in the global
<filename>nix.conf</filename>, or on the command line by trusted
users.</para>
<para>When using the nix-daemon, the daemon executes the hook as
<literal>root</literal>. If the nix-daemon is not involved, the
hook runs as the user executing the nix-build.</para>
<itemizedlist>
<listitem><para>The hook executes after an evaluation-time build.</para></listitem>
<listitem><para>The hook does not execute on substituted paths.</para></listitem>
<listitem><para>The hook's output always goes to the user's terminal.</para></listitem>
<listitem><para>If the hook fails, the build succeeds but no further builds execute.</para></listitem>
<listitem><para>The hook executes synchronously, and blocks other builds from progressing while it runs.</para></listitem>
</itemizedlist>
<para>The program executes with no arguments. The program's environment
contains the following environment variables:</para>
<variablelist>
<varlistentry>
<term><envar>DRV_PATH</envar></term>
<listitem>
<para>The derivation for the built paths.</para>
<para>Example:
<literal>/nix/store/5nihn1a7pa8b25l9zafqaqibznlvvp3f-bash-4.4-p23.drv</literal>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><envar>OUT_PATHS</envar></term>
<listitem>
<para>Output paths of the built derivation, separated by a space character.</para>
<para>Example:
<literal>/nix/store/zf5lbh336mnzf1nlswdn11g4n2m8zh3g-bash-4.4-p23-dev
/nix/store/rjxwxwv1fpn9wa2x5ssk5phzwlcv4mna-bash-4.4-p23-doc
/nix/store/6bqvbzjkcp9695dq0dpl5y43nvy37pq1-bash-4.4-p23-info
/nix/store/r7fng3kk3vlpdlh2idnrbn37vh4imlj2-bash-4.4-p23-man
/nix/store/xfghy8ixrhz3kyy6p724iv3cxji088dx-bash-4.4-p23</literal>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>See <xref linkend="chap-post-build-hook" /> for an example
implementation.</para>
</listitem>
</varlistentry>
<varlistentry xml:id="conf-repeat"><term><literal>repeat</literal></term>
<listitem><para>How many times to repeat builds to check whether
they are deterministic. The default value is 0. If the value is
non-zero, every build is repeated the specified number of
times. If the contents of any of the runs differs from the
previous ones and <xref linkend="conf-enforce-determinism" /> is
true, the build is rejected and the resulting store paths are not
registered as “valid” in Nixs database.</para></listitem>
previous ones, the build is rejected and the resulting store paths
are not registered as “valid” in Nixs database.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-require-sigs"><term><literal>require-sigs</literal></term>
@@ -759,19 +628,6 @@ password <replaceable>my-password</replaceable>
</varlistentry>
<varlistentry xml:id="conf-run-diff-hook"><term><literal>run-diff-hook</literal></term>
<listitem>
<para>
If true, enable the execution of <xref linkend="conf-diff-hook" />.
</para>
<para>
When using the Nix daemon, <literal>run-diff-hook</literal> must
be set in the <filename>nix.conf</filename> configuration file,
and cannot be passed at the command line.
</para>
</listitem>
</varlistentry>
<varlistentry xml:id="conf-sandbox"><term><literal>sandbox</literal></term>
@@ -873,14 +729,6 @@ password <replaceable>my-password</replaceable>
</varlistentry>
<varlistentry xml:id="conf-stalled-download-timeout"><term><literal>stalled-download-timeout</literal></term>
<listitem>
<para>The timeout (in seconds) for receiving data from servers
during download. Nix cancels idle downloads after this timeout's
duration.</para>
</listitem>
</varlistentry>
<varlistentry xml:id="conf-substituters"><term><literal>substituters</literal></term>
<listitem><para>A list of URLs of substituters, separated by
@@ -936,31 +784,6 @@ requiredSystemFeatures = [ "kvm" ];
</varlistentry>
<varlistentry xml:id="conf-tarball-ttl"><term><literal>tarball-ttl</literal></term>
<listitem>
<para>Default: <literal>3600</literal> seconds.</para>
<para>The number of seconds a downloaded tarball is considered
fresh. If the cached tarball is stale, Nix will check whether
it is still up to date using the ETag header. Nix will download
a new version if the ETag header is unsupported, or the
cached ETag doesn't match.
</para>
<para>Setting the TTL to <literal>0</literal> forces Nix to always
check if the tarball is up to date.</para>
<para>Nix caches tarballs in
<filename>$XDG_CACHE_HOME/nix/tarballs</filename>.</para>
<para>Files fetched via <envar>NIX_PATH</envar>,
<function>fetchGit</function>, <function>fetchMercurial</function>,
<function>fetchTarball</function>, and <function>fetchurl</function>
respect this TTL.
</para>
</listitem>
</varlistentry>
<varlistentry xml:id="conf-timeout"><term><literal>timeout</literal></term>
@@ -981,34 +804,6 @@ requiredSystemFeatures = [ "kvm" ];
</varlistentry>
<varlistentry xml:id="conf-trace-function-calls"><term><literal>trace-function-calls</literal></term>
<listitem>
<para>Default: <literal>false</literal>.</para>
<para>If set to <literal>true</literal>, the Nix evaluator will
trace every function call. Nix will print a log message at the
"vomit" level for every function entrance and function exit.</para>
<informalexample><screen>
function-trace entered undefined position at 1565795816999559622
function-trace exited undefined position at 1565795816999581277
function-trace entered /nix/store/.../example.nix:226:41 at 1565795253249935150
function-trace exited /nix/store/.../example.nix:226:41 at 1565795253249941684
</screen></informalexample>
<para>The <literal>undefined position</literal> means the function
call is a builtin.</para>
<para>Use the <literal>contrib/stack-collapse.py</literal> script
distributed with the Nix source code to convert the trace logs
in to a format suitable for <command>flamegraph.pl</command>.</para>
</listitem>
</varlistentry>
<varlistentry xml:id="conf-trusted-public-keys"><term><literal>trusted-public-keys</literal></term>
<listitem><para>A whitespace-separated list of public keys. When

View File

@@ -14,8 +14,7 @@
<varlistentry><term><envar>IN_NIX_SHELL</envar></term>
<listitem><para>Indicator that tells if the current environment was set up by
<command>nix-shell</command>. Since Nix 2.0 the values are
<literal>"pure"</literal> and <literal>"impure"</literal></para></listitem>
<command>nix-shell</command>.</para></listitem>
</varlistentry>
@@ -122,7 +121,7 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
<varlistentry><term><envar>NIX_LOG_DIR</envar></term>
<listitem><para>Overrides the location of the Nix log directory
(default <filename><replaceable>prefix</replaceable>/var/log/nix</filename>).</para></listitem>
(default <filename><replaceable>prefix</replaceable>/log/nix</filename>).</para></listitem>
</varlistentry>

View File

@@ -30,7 +30,6 @@
<replaceable>attrPath</replaceable>
</arg>
<arg><option>--no-out-link</option></arg>
<arg><option>--dry-run</option></arg>
<arg>
<group choice='req'>
<arg choice='plain'><option>--out-link</option></arg>
@@ -99,10 +98,6 @@ also <xref linkend="sec-common-options" />.</phrase></para>
</varlistentry>
<varlistentry><term><option>--dry-run</option></term>
<listitem><para>Show what store paths would be built or downloaded</para></listitem>
</varlistentry>
<varlistentry xml:id='opt-out-link'><term><option>--out-link</option> /
<option>-o</option> <replaceable>outlink</replaceable></term>

View File

@@ -31,11 +31,12 @@
<refsection><title>Description</title>
<para>A Nix channel is a mechanism that allows you to automatically
stay up-to-date with a set of pre-built Nix expressions. A Nix
channel is just a URL that points to a place containing a set of Nix
expressions. <phrase condition="manual">See also <xref
linkend="sec-channels" />.</phrase></para>
<para>A Nix channel is a mechanism that allows you to automatically stay
up-to-date with a set of pre-built Nix expressions. A Nix channel is
just a URL that points to a place containing both a set of Nix
expressions and a pointer to a binary cache. <phrase
condition="manual">See also <xref linkend="sec-channels"
/>.</phrase></para>
<para>This command has the following operations:
@@ -171,6 +172,18 @@ following files:</para>
</varlistentry>
<varlistentry><term><filename>binary-cache-url</filename></term>
<listitem><para>A file containing the URL to a binary cache (such
as <uri>https://cache.nixos.org</uri>). Nix will automatically
check this cache for pre-built binaries, if the user has
sufficient rights to add binary caches. For instance, in a
multi-user Nix setup, the binary caches provided by the channels
of the root user are used automatically, but caches corresponding
to the channels of non-root users are ignored.</para></listitem>
</varlistentry>
</variablelist>
</refsection>

View File

@@ -221,53 +221,31 @@ also <xref linkend="sec-common-options" />.</phrase></para>
<varlistentry><term><filename>~/.nix-defexpr</filename></term>
<listitem><para>The source for the default Nix
<listitem><para>A directory that contains the default Nix
expressions used by the <option>--install</option>,
<option>--upgrade</option>, and <option>--query
--available</option> operations to obtain derivations. The
--available</option> operations to obtain derivations. The
<option>--file</option> option may be used to override this
default.</para>
<para>If <filename>~/.nix-defexpr</filename> is a file,
it is loaded as a Nix expression. If the expression
is a set, it is used as the default Nix expression.
If the expression is a function, an empty set is passed
as argument and the return value is used as
the default Nix expression.</para>
<para>If <filename>~/.nix-defexpr</filename> is a directory
containing a <filename>default.nix</filename> file, that file
is loaded as in the above paragraph.</para>
<para>If <filename>~/.nix-defexpr</filename> is a directory without
a <filename>default.nix</filename> file, then its contents
(both files and subdirectories) are loaded as Nix expressions.
The expressions are combined into a single set, each expression
under an attribute with the same name as the original file
or subdirectory.
</para>
<para>For example, if <filename>~/.nix-defexpr</filename> contains
two files, <filename>foo.nix</filename> and <filename>bar.nix</filename>,
<para>The Nix expressions in this directory are combined into a
single set, with each file as an attribute that has the name of
the file. Thus, if <filename>~/.nix-defexpr</filename> contains
two files, <filename>foo</filename> and <filename>bar</filename>,
then the default Nix expression will essentially be
<programlisting>
{
foo = import ~/.nix-defexpr/foo.nix;
bar = import ~/.nix-defexpr/bar.nix;
foo = import ~/.nix-defexpr/foo;
bar = import ~/.nix-defexpr/bar;
}</programlisting>
</para>
<para>The file <filename>manifest.nix</filename> is always ignored.
Subdirectories without a <filename>default.nix</filename> file
are traversed recursively in search of more Nix expressions,
but the names of these intermediate directories are not
added to the attribute paths of the default Nix expression.</para>
<para>The command <command>nix-channel</command> places symlinks
to the downloaded Nix expressions from each subscribed channel in
this directory.</para>
</listitem>
</varlistentry>
@@ -659,7 +637,7 @@ upgrading `mozilla-1.2' to `mozilla-1.4'</screen>
<literal>gcc-3.3.1</literal> are split into two parts: the package
name (<literal>gcc</literal>), and the version
(<literal>3.3.1</literal>). The version part starts after the first
dash not followed by a letter. <varname>x</varname> is considered an
dash not following by a letter. <varname>x</varname> is considered an
upgrade of <varname>y</varname> if their package names match, and the
version of <varname>y</varname> is higher that that of
<varname>x</varname>.</para>
@@ -1370,13 +1348,10 @@ profile. The generations can be a list of generation numbers, the
special value <literal>old</literal> to delete all non-current
generations, a value such as <literal>30d</literal> to delete all
generations older than the specified number of days (except for the
generation that was active at that point in time), or a value such as
<literal>+5</literal> to keep the last <literal>5</literal> generations
ignoring any newer than current, e.g., if <literal>30</literal> is the current
generation <literal>+5</literal> will delete generation <literal>25</literal>
and all older generations.
Periodically deleting old generations is important to make garbage collection
effective.</para>
generation that was active at that point in time), or a value such as.
<literal>+5</literal> to only keep the specified items older than the
current generation. Periodically deleting old generations is important
to make garbage collection effective.</para>
</refsection>

View File

@@ -53,7 +53,7 @@ avoided.</para>
<para>If <replaceable>hash</replaceable> is specified, then a download
is not performed if the Nix store already contains a file with the
same hash and base name. Otherwise, the file is downloaded, and an
error is signaled if the actual hash of the file does not match the
error if signaled if the actual hash of the file does not match the
specified hash.</para>
<para>This command prints the hash on standard output. Additionally,

View File

@@ -215,48 +215,6 @@ printed.)</para>
</variablelist>
<para>Special exit codes:</para>
<variablelist>
<varlistentry><term><literal>100</literal></term>
<listitem><para>Generic build failure, the builder process
returned with a non-zero exit code.</para></listitem>
</varlistentry>
<varlistentry><term><literal>101</literal></term>
<listitem><para>Build timeout, the build was aborted because it
did not complete within the specified <link
linkend='conf-timeout'><literal>timeout</literal></link>.
</para></listitem>
</varlistentry>
<varlistentry><term><literal>102</literal></term>
<listitem><para>Hash mismatch, the build output was rejected
because it does not match the specified <link
linkend="fixed-output-drvs"><varname>outputHash</varname></link>.
</para></listitem>
</varlistentry>
<varlistentry><term><literal>104</literal></term>
<listitem><para>Not deterministic, the build succeeded in check
mode but the resulting output is not binary reproducable.</para>
</listitem>
</varlistentry>
</variablelist>
<para>With the <option>--keep-going</option> flag it's possible for
multiple failures to occur, in this case the 1xx status codes are or combined
using binary or. <screen>
1100100
^^^^
|||`- timeout
||`-- output hash mismatch
|`--- build failure
`---- not deterministic
</screen></para>
</refsection>
@@ -925,60 +883,6 @@ $ nix-store --add ./foo.c
</refsection>
<!--######################################################################-->
<refsection><title>Operation <option>--add-fixed</option></title>
<refsection><title>Synopsis</title>
<cmdsynopsis>
<command>nix-store</command>
<arg><option>--recursive</option></arg>
<arg choice='plain'><option>--add-fixed</option></arg>
<arg choice='plain'><replaceable>algorithm</replaceable></arg>
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
</cmdsynopsis>
</refsection>
<refsection><title>Description</title>
<para>The operation <option>--add-fixed</option> adds the specified paths to
the Nix store. Unlike <option>--add</option> paths are registered using the
specified hashing algorithm, resulting in the same output path as a fixed output
derivation. This can be used for sources that are not available from a public
url or broke since the download expression was written.
</para>
<para>This operation has the following options:
<variablelist>
<varlistentry><term><option>--recursive</option></term>
<listitem><para>
Use recursive instead of flat hashing mode, used when adding directories
to the store.
</para></listitem>
</varlistentry>
</variablelist>
</para>
</refsection>
<refsection><title>Example</title>
<screen>
$ nix-store --add-fixed sha256 ./hello-2.10.tar.gz
/nix/store/3x7dwzq014bblazs7kq20p9hyzz0qh8g-hello-2.10.tar.gz</screen>
</refsection>
</refsection>
<!--######################################################################-->

View File

@@ -107,22 +107,14 @@
<varlistentry xml:id="opt-max-jobs"><term><option>--max-jobs</option> / <option>-j</option>
<replaceable>number</replaceable></term>
<listitem>
<para>Sets the maximum number of build jobs that Nix will
<listitem><para>Sets the maximum number of build jobs that Nix will
perform in parallel to the specified number. Specify
<literal>auto</literal> to use the number of CPUs in the system.
The default is specified by the <link
linkend='conf-max-jobs'><literal>max-jobs</literal></link>
configuration setting, which itself defaults to
<literal>1</literal>. A higher value is useful on SMP systems or to
exploit I/O latency.</para>
<para> Setting it to <literal>0</literal> disallows building on the local
machine, which is useful when you want builds to happen only on remote
builders.</para>
</listitem>
exploit I/O latency.</para></listitem>
</varlistentry>

View File

@@ -170,6 +170,18 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-splitVersion'>
<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 xml:id='builtin-concatLists'>
<term><function>builtins.concatLists</function>
<replaceable>lists</replaceable></term>
@@ -289,7 +301,7 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
<listitem><para>Return element <replaceable>n</replaceable> from
the list <replaceable>xs</replaceable>. Elements are counted
starting from 0. A fatal error occurs if the index is out of
starting from 0. A fatal error occurs in the index is out of
bounds.</para></listitem>
</varlistentry>
@@ -335,7 +347,7 @@ stdenv.mkDerivation { … }
You can change the cache timeout either on the command line with
<option>--option tarball-ttl <replaceable>number of seconds</replaceable></option> or
in the Nix configuration file with this option:
<literal><xref linkend="conf-tarball-ttl" /> <replaceable>number of seconds to cache</replaceable></literal>.
<literal>tarball-ttl <replaceable>number of seconds to cache</replaceable></literal>.
</para>
<para>Note that when obtaining the hash with <varname>nix-prefetch-url
@@ -413,13 +425,6 @@ stdenv.mkDerivation { … }
This is often a branch or tag name. Defaults to
<literal>HEAD</literal>.
</para>
<para>
By default, the <varname>ref</varname> value is prefixed
with <literal>refs/heads/</literal>. As of Nix 2.3.0
Nix will not prefix <literal>refs/heads/</literal> if
<varname>ref</varname> starts with <literal>refs/</literal>.
</para>
</listitem>
</varlistentry>
</variablelist>
@@ -433,14 +438,6 @@ stdenv.mkDerivation { … }
}</programlisting>
</example>
<example>
<title>Fetching an arbitrary ref</title>
<programlisting>builtins.fetchGit {
url = "https://github.com/NixOS/nix.git";
ref = "refs/heads/0.5-release";
}</programlisting>
</example>
<example>
<title>Fetching a repository's specific commit on an arbitrary branch</title>
<para>
@@ -487,8 +484,11 @@ stdenv.mkDerivation { … }
<title>Fetching a tag</title>
<programlisting>builtins.fetchGit {
url = "https://github.com/nixos/nix.git";
ref = "refs/tags/1.9";
ref = "tags/1.9";
}</programlisting>
<note><para>Due to a bug (<link
xlink:href="https://github.com/NixOS/nix/issues/2385">#2385</link>),
only non-annotated tags can be fetched.</para></note>
</example>
<example>
@@ -498,7 +498,7 @@ stdenv.mkDerivation { … }
fetch the latest version of a remote branch.
</para>
<note><para>Nix will refetch the branch in accordance to
<xref linkend="conf-tarball-ttl" />.</para></note>
<option>tarball-ttl</option>.</para></note>
<note><para>This behavior is disabled in
<emphasis>Pure evaluation mode</emphasis>.</para></note>
<programlisting>builtins.fetchGit {
@@ -705,19 +705,6 @@ builtins.genList (x: x * x) 5
</varlistentry>
<varlistentry xml:id='builtin-hashFile'>
<term><function>builtins.hashFile</function>
<replaceable>type</replaceable> <replaceable>p</replaceable></term>
<listitem><para>Return a base-16 representation of the
cryptographic hash of the file at path <replaceable>p</replaceable>. The
hash algorithm specified by <replaceable>type</replaceable> must
be one of <literal>"md5"</literal>, <literal>"sha1"</literal>,
<literal>"sha256"</literal> or <literal>"sha512"</literal>.</para></listitem>
</varlistentry>
<varlistentry xml:id='builtin-head'>
<term><function>builtins.head</function>
<replaceable>list</replaceable></term>
@@ -746,11 +733,6 @@ builtins.genList (x: x * x) 5
separate file, and use it from Nix expressions in other
files.</para>
<note><para>Unlike some languages, <function>import</function> is a regular
function in Nix. Paths using the angle bracket syntax (e.g., <function>
import</function> <replaceable>&lt;foo&gt;</replaceable>) are normal path
values (see <xref linkend='ssec-values' />).</para></note>
<para>A Nix expression loaded by <function>import</function> must
not contain any <emphasis>free variables</emphasis> (identifiers
that are not defined in the Nix expression itself and are not
@@ -1120,16 +1102,6 @@ Evaluates to <literal>[ "foo" ]</literal>.
</varlistentry>
<varlistentry xml:id='builtin-placeholder'>
<term><function>builtins.placeholder</function>
<replaceable>output</replaceable></term>
<listitem><para>Return a placeholder string for the specified
<replaceable>output</replaceable> that will be substituted by the
corresponding output path at build time. Typical outputs would be
<literal>"out"</literal>, <literal>"bin"</literal> or
<literal>"dev"</literal>.</para></listitem>
</varlistentry>
<varlistentry xml:id='builtin-readDir'>
<term><function>builtins.readDir</function>
@@ -1275,19 +1247,6 @@ Evaluates to <literal>[ " " [ "FOO" ] " " ]</literal>.
</para></listitem>
</varlistentry>
<varlistentry xml:id='builtin-splitVersion'>
<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 xml:id='builtin-stringLength'>
<term><function>builtins.stringLength</function>
<replaceable>e</replaceable></term>
@@ -1481,7 +1440,7 @@ in foo</programlisting>
<listitem><para>A set containing <literal>{ __toString = self: ...; }</literal>.</para></listitem>
<listitem><para>An integer.</para></listitem>
<listitem><para>A list, in which case the string representations of its elements are joined with spaces.</para></listitem>
<listitem><para>A Boolean (<literal>false</literal> yields <literal>""</literal>, <literal>true</literal> yields <literal>"1"</literal>).</para></listitem>
<listitem><para>A Boolean (<literal>false</literal> yields <literal>""</literal>, <literal>true</literal> yields <literal>"1"</literal>.</para></listitem>
<listitem><para><literal>null</literal>, which yields the empty string.</para></listitem>
</itemizedlist>
</listitem>
@@ -1620,18 +1579,12 @@ stdenv.mkDerivation (rec {
<term><function>builtins.tryEval</function>
<replaceable>e</replaceable></term>
<listitem><para>Try to shallowly evaluate <replaceable>e</replaceable>.
<listitem><para>Try to evaluate <replaceable>e</replaceable>.
Return a set containing the attributes <literal>success</literal>
(<literal>true</literal> if <replaceable>e</replaceable> evaluated
successfully, <literal>false</literal> if an error was thrown) and
<literal>value</literal>, equalling <replaceable>e</replaceable>
if successful and <literal>false</literal> otherwise. Note that this
doesn't evaluate <replaceable>e</replaceable> deeply, so
<literal>let e = { x = throw ""; }; in (builtins.tryEval e).success
</literal> will be <literal>true</literal>. Using <literal>builtins.deepSeq
</literal> one can get the expected result: <literal>let e = { x = throw "";
}; in (builtins.tryEval (builtins.deepSeq e e)).success</literal> will be
<literal>false</literal>.
if successful and <literal>false</literal> otherwise.
</para></listitem>
</varlistentry>

View File

@@ -43,7 +43,7 @@ encountered</quote>).</para></footnote>.</para>
<simplesect xml:id="sect-let-expressions"><title>Let-expressions</title>
<para>A let-expression allows you to define local variables for an
<para>A let-expression allows you define local variables for an
expression. For instance,
<programlisting>
@@ -217,25 +217,7 @@ but can also be written as:
ellipsis(<literal>...</literal>) as you can access attribute names as
<literal>a</literal>, using <literal>args.a</literal>, which was given as an
additional attribute to the function.
</para>
<warning>
<para>
The <literal>args@</literal> expression is bound to the argument passed to the function which
means that attributes with defaults that aren't explicitly specified in the function call
won't cause an evaluation error, but won't exist in <literal>args</literal>.
</para>
<para>
For instance
<programlisting>
let
function = args@{ a ? 23, ... }: args;
in
function {}
</programlisting>
will evaluate to an empty attribute set.
</para>
</warning></listitem>
</para></listitem>
</itemizedlist>

View File

@@ -15,16 +15,13 @@ weakest binding).</para>
<tgroup cols='3'>
<thead>
<row>
<entry>Name</entry>
<entry>Syntax</entry>
<entry>Associativity</entry>
<entry>Description</entry>
<entry>Precedence</entry>
</row>
</thead>
<tbody>
<row>
<entry>Select</entry>
<entry><replaceable>e</replaceable> <literal>.</literal>
<replaceable>attrpath</replaceable>
[ <literal>or</literal> <replaceable>def</replaceable> ]
@@ -36,25 +33,19 @@ weakest binding).</para>
dot-separated list of attribute names.) If the attribute
doesnt exist, return <replaceable>def</replaceable> if
provided, otherwise abort evaluation.</entry>
<entry>1</entry>
</row>
<row>
<entry>Application</entry>
<entry><replaceable>e1</replaceable> <replaceable>e2</replaceable></entry>
<entry>left</entry>
<entry>Call function <replaceable>e1</replaceable> with
argument <replaceable>e2</replaceable>.</entry>
<entry>2</entry>
</row>
<row>
<entry>Arithmetic Negation</entry>
<entry><literal>-</literal> <replaceable>e</replaceable></entry>
<entry>none</entry>
<entry>Arithmetic negation.</entry>
<entry>3</entry>
</row>
<row>
<entry>Has Attribute</entry>
<entry><replaceable>e</replaceable> <literal>?</literal>
<replaceable>attrpath</replaceable></entry>
<entry>none</entry>
@@ -62,69 +53,34 @@ weakest binding).</para>
the attribute denoted by <replaceable>attrpath</replaceable>;
return <literal>true</literal> or
<literal>false</literal>.</entry>
<entry>4</entry>
</row>
<row>
<entry>List Concatenation</entry>
<entry><replaceable>e1</replaceable> <literal>++</literal> <replaceable>e2</replaceable></entry>
<entry>right</entry>
<entry>List concatenation.</entry>
<entry>5</entry>
</row>
<row>
<entry>Multiplication</entry>
<entry>
<replaceable>e1</replaceable> <literal>*</literal> <replaceable>e2</replaceable>,
</entry>
<entry>left</entry>
<entry>Arithmetic multiplication.</entry>
<entry>6</entry>
</row>
<row>
<entry>Division</entry>
<entry>
<replaceable>e1</replaceable> <literal>/</literal> <replaceable>e2</replaceable>
</entry>
<entry>left</entry>
<entry>Arithmetic division.</entry>
<entry>6</entry>
<entry>Arithmetic multiplication and division.</entry>
</row>
<row>
<entry>Addition</entry>
<entry>
<replaceable>e1</replaceable> <literal>+</literal> <replaceable>e2</replaceable>
</entry>
<entry>left</entry>
<entry>Arithmetic addition.</entry>
<entry>7</entry>
</row>
<row>
<entry>Subtraction</entry>
<entry>
<replaceable>e1</replaceable> <literal>+</literal> <replaceable>e2</replaceable>,
<replaceable>e1</replaceable> <literal>-</literal> <replaceable>e2</replaceable>
</entry>
<entry>left</entry>
<entry>Arithmetic subtraction.</entry>
<entry>7</entry>
<entry>Arithmetic addition and subtraction. String or path concatenation (only by <literal>+</literal>).</entry>
</row>
<row>
<entry>String Concatenation</entry>
<entry>
<replaceable>string1</replaceable> <literal>+</literal> <replaceable>string2</replaceable>
</entry>
<entry>left</entry>
<entry>String concatenation.</entry>
<entry>7</entry>
</row>
<row>
<entry>Not</entry>
<entry><literal>!</literal> <replaceable>e</replaceable></entry>
<entry>none</entry>
<entry>Boolean negation.</entry>
<entry>8</entry>
</row>
<row>
<entry>Update</entry>
<entry><replaceable>e1</replaceable> <literal>//</literal>
<replaceable>e2</replaceable></entry>
<entry>right</entry>
@@ -133,90 +89,47 @@ weakest binding).</para>
<replaceable>e2</replaceable> (with the latter taking
precedence over the former in case of equally named
attributes).</entry>
<entry>9</entry>
</row>
<row>
<entry>Less Than</entry>
<entry>
<replaceable>e1</replaceable> <literal>&lt;</literal> <replaceable>e2</replaceable>,
</entry>
<entry>none</entry>
<entry>Arithmetic comparison.</entry>
<entry>10</entry>
</row>
<row>
<entry>Less Than or Equal To</entry>
<entry>
<replaceable>e1</replaceable> <literal>&lt;=</literal> <replaceable>e2</replaceable>
</entry>
<entry>none</entry>
<entry>Arithmetic comparison.</entry>
<entry>10</entry>
</row>
<row>
<entry>Greater Than</entry>
<entry>
<replaceable>e1</replaceable> <literal>&gt;</literal> <replaceable>e2</replaceable>
</entry>
<entry>none</entry>
<entry>Arithmetic comparison.</entry>
<entry>10</entry>
</row>
<row>
<entry>Greater Than or Equal To</entry>
<entry>
<replaceable>e1</replaceable> <literal>&gt;</literal> <replaceable>e2</replaceable>,
<replaceable>e1</replaceable> <literal>&lt;=</literal> <replaceable>e2</replaceable>,
<replaceable>e1</replaceable> <literal>&gt;=</literal> <replaceable>e2</replaceable>
</entry>
<entry>none</entry>
<entry>Arithmetic comparison.</entry>
<entry>10</entry>
</row>
<row>
<entry>Equality</entry>
<entry>
<replaceable>e1</replaceable> <literal>==</literal> <replaceable>e2</replaceable>
</entry>
<entry>none</entry>
<entry>Equality.</entry>
<entry>11</entry>
</row>
<row>
<entry>Inequality</entry>
<entry>
<replaceable>e1</replaceable> <literal>==</literal> <replaceable>e2</replaceable>,
<replaceable>e1</replaceable> <literal>!=</literal> <replaceable>e2</replaceable>
</entry>
<entry>none</entry>
<entry>Inequality.</entry>
<entry>11</entry>
<entry>Equality and inequality.</entry>
</row>
<row>
<entry>Logical AND</entry>
<entry><replaceable>e1</replaceable> <literal>&amp;&amp;</literal>
<replaceable>e2</replaceable></entry>
<entry>left</entry>
<entry>Logical AND.</entry>
<entry>12</entry>
</row>
<row>
<entry>Logical OR</entry>
<entry><replaceable>e1</replaceable> <literal>||</literal>
<replaceable>e2</replaceable></entry>
<entry>left</entry>
<entry>Logical OR.</entry>
<entry>13</entry>
</row>
<row>
<entry>Logical Implication</entry>
<entry><replaceable>e1</replaceable> <literal>-></literal>
<replaceable>e2</replaceable></entry>
<entry>none</entry>
<entry>Logical implication (equivalent to
<literal>!<replaceable>e1</replaceable> ||
<replaceable>e2</replaceable></literal>).</entry>
<entry>14</entry>
</row>
</tbody>
</tgroup>
</table>
</section>
</section>

View File

@@ -43,7 +43,7 @@ use <command>nix-build</command>s <option
linkend='opt-out-link'>-o</option> switch to give the symlink another
name.</para>
<para>Nix has transactional semantics. Once a build finishes
<para>Nix has a transactional semantics. Once a build finishes
successfully, Nix makes a note of this in its database: it registers
that the path denoted by <envar>out</envar> is now
<quote>valid</quote>. If you try to build the derivation again, Nix

View File

@@ -67,23 +67,5 @@ $ sudo launchctl kickstart -k system/org.nixos.nix-daemon
</screen>
</section>
<section xml:id="sec-installer-proxy-settings">
<title>Proxy Environment Variables</title>
<para>The Nix installer has special handling for these proxy-related
environment variables:
<varname>http_proxy</varname>, <varname>https_proxy</varname>,
<varname>ftp_proxy</varname>, <varname>no_proxy</varname>,
<varname>HTTP_PROXY</varname>, <varname>HTTPS_PROXY</varname>,
<varname>FTP_PROXY</varname>, <varname>NO_PROXY</varname>.
</para>
<para>If any of these variables are set when running the Nix installer,
then the installer will create an override file at
<filename>/etc/systemd/system/nix-daemon.service.d/override.conf</filename>
so <command>nix-daemon</command> will use them.
</para>
</section>
</section>
</chapter>

View File

@@ -13,7 +13,7 @@
<listitem><para>Bash Shell. The <literal>./configure</literal> script
relies on bashisms, so Bash is required.</para></listitem>
<listitem><para>A version of GCC or Clang that supports C++17.</para></listitem>
<listitem><para>A version of GCC or Clang that supports C++14.</para></listitem>
<listitem><para><command>pkg-config</command> to locate
dependencies. If your distribution does not provide it, you can get
@@ -62,10 +62,6 @@
1.66.0 or higher. It can be obtained from the official web site
<link xlink:href="https://www.boost.org/" />.</para></listitem>
<listitem><para>The <literal>editline</literal> library of version
1.14.0 or higher. It can be obtained from the its repository
<link xlink:href="https://github.com/troglobit/editline" />.</para></listitem>
<listitem><para>The <command>xmllint</command> and
<command>xsltproc</command> programs to build this manual and the
man-pages. These are part of the <literal>libxml2</literal> and

View File

@@ -4,6 +4,7 @@ ifeq ($(doc_generate),yes)
XSLTPROC = $(xsltproc) --nonet $(xmlflags) \
--param section.autolabel 1 \
--param section.label.includes.component.label 1 \
--param html.stylesheet \'style.css\' \
--param xref.with.number.and.title 1 \
--param toc.section.depth 3 \
--param admon.style \'\' \
@@ -65,7 +66,7 @@ $(d)/manual.html: $(d)/manual.xml $(MANUAL_SRCS) $(d)/manual.is-valid
$(docbookxsl)/profiling/profile.xsl $< | \
$(XSLTPROC) --output $@ $(docbookxsl)/xhtml/docbook.xsl -
$(foreach file, $(d)/manual.html, $(eval $(call install-data-in, $(file), $(docdir)/manual)))
$(foreach file, $(d)/manual.html $(d)/style.css, $(eval $(call install-data-in, $(file), $(docdir)/manual)))
$(foreach file, $(wildcard $(d)/figures/*.png), $(eval $(call install-data-in, $(file), $(docdir)/manual/figures)))

View File

@@ -24,11 +24,11 @@ symlinks to the files of the active applications. </para>
<para>Components are installed from a set of <emphasis>Nix
expressions</emphasis> that tell Nix how to build those packages,
including, if necessary, their dependencies. There is a collection of
Nix expressions called the Nixpkgs package collection that contains
Nix expressions called the Nix Package collection that contains
packages ranging from basic development stuff such as GCC and Glibc,
to end-user applications like Mozilla Firefox. (Nix is however not
tied to the Nixpkgs package collection; you could write your own Nix
expressions based on Nixpkgs, or completely new ones.)</para>
tied to the Nix Package collection; you could write your own Nix
expressions based on it, or completely new ones.)</para>
<para>You can manually download the latest version of Nixpkgs from
<link xlink:href='http://nixos.org/nixpkgs/download.html'/>. However,

View File

@@ -52,13 +52,12 @@ garbage collector as follows:
<screen>
$ nix-store --gc</screen>
The behaviour of the gargage collector is affected by the
<literal>keep-derivations</literal> (default: true) and <literal>keep-outputs</literal>
The behaviour of the gargage collector is affected by the <literal>keep-
derivations</literal> (default: true) and <literal>keep-outputs</literal>
(default: false) options in the Nix configuration file. The defaults will ensure
that all derivations that are build-time dependencies of garbage collector roots
will be kept and that all output paths that are runtime dependencies
will be kept as well. All other derivations or paths will be collected.
(This is usually what you want, but while you are developing
that all derivations that are not build-time dependencies of garbage collector roots
will be collected but that all output paths that are not runtime dependencies
will be collected. (This is usually what you want, but while you are developing
it may make sense to keep outputs to ensure that rebuild times are quick.)
If you are feeling uncertain, you can also first view what files would

View File

@@ -113,7 +113,7 @@ the S3 URL:</para>
exactly <uri>s3://example-nix-cache</uri>.</para>
<para>Nix will use the <link
xlink:href="https://docs.aws.amazon.com/sdk-for-cpp/v1/developer-guide/credentials.html">default
xlink:href="https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html#credentials-default.">default
credential provider chain</link> for authenticating requests to
Amazon S3.</para>
@@ -138,7 +138,7 @@ the S3 URL:</para>
be <uri>s3://example-nix-cache</uri>.</para>
<para>Nix will use the <link
xlink:href="https://docs.aws.amazon.com/sdk-for-cpp/v1/developer-guide/credentials.html">default
xlink:href="https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html#credentials-default.">default
credential provider chain</link> for authenticating requests to
Amazon S3.</para>
@@ -159,6 +159,7 @@ the S3 URL:</para>
"s3:ListBucket",
"s3:ListBucketMultipartUploads",
"s3:ListMultipartUploadParts",
"s3:ListObjects",
"s3:PutObject"
],
"Resource": [

View File

@@ -12,7 +12,6 @@
</partintro>
-->
<xi:include href="rl-2.3.xml" />
<xi:include href="rl-2.2.xml" />
<xi:include href="rl-2.1.xml" />
<xi:include href="rl-2.0.xml" />

View File

@@ -1,91 +0,0 @@
<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-2.3">
<title>Release 2.3 (2019-09-04)</title>
<para>This is primarily a bug fix release. However, it makes some
incompatible changes:</para>
<itemizedlist>
<listitem>
<para>Nix now uses BSD file locks instead of POSIX file
locks. Because of this, you should not use Nix 2.3 and previous
releases at the same time on a Nix store.</para>
</listitem>
</itemizedlist>
<para>It also has the following changes:</para>
<itemizedlist>
<listitem>
<para><function>builtins.fetchGit</function>'s <varname>ref</varname>
argument now allows specifying an absolute remote ref.
Nix will automatically prefix <varname>ref</varname> with
<literal>refs/heads</literal> only if <varname>ref</varname> doesn't
already begin with <literal>refs/</literal>.
</para>
</listitem>
<listitem>
<para>The installer now enables sandboxing by default on Linux when the
system has the necessary kernel support.
</para>
</listitem>
<listitem>
<para>The <literal>max-jobs</literal> setting now defaults to 1.</para>
</listitem>
<listitem>
<para>New builtin functions:
<literal>builtins.isPath</literal>,
<literal>builtins.hashFile</literal>.
</para>
</listitem>
<listitem>
<para>The <command>nix</command> command has a new
<option>--print-build-logs</option> (<option>-L</option>) flag to
print build log output to stderr, rather than showing the last log
line in the progress bar. To distinguish between concurrent
builds, log lines are prefixed by the name of the package.
</para>
</listitem>
<listitem>
<para>Builds are now executed in a pseudo-terminal, and the
<envar>TERM</envar> environment variable is set to
<literal>xterm-256color</literal>. This allows many programs
(e.g. <command>gcc</command>, <command>clang</command>,
<command>cmake</command>) to print colorized log output.</para>
</listitem>
<listitem>
<para>Add <option>--no-net</option> convenience flag. This flag
disables substituters; sets the <literal>tarball-ttl</literal>
setting to infinity (ensuring that any previously downloaded files
are considered current); and disables retrying downloads and sets
the connection timeout to the minimum. This flag is enabled
automatically if there are no configured non-loopback network
interfaces.</para>
</listitem>
<listitem>
<para>Add a <literal>post-build-hook</literal> setting to run a
program after a build has succeeded.</para>
</listitem>
<listitem>
<para>Add a <literal>trace-function-calls</literal> setting to log
the duration of Nix function calls to stderr.</para>
</listitem>
</itemizedlist>
</section>

263
doc/manual/style.css Normal file
View File

@@ -0,0 +1,263 @@
/* Copied from http://bakefile.sourceforge.net/, which appears
licensed under the GNU GPL. */
/***************************************************************************
Basic headers and text:
***************************************************************************/
body
{
font-family: "Nimbus Sans L", sans-serif;
background: white;
margin: 2em 1em 2em 1em;
}
h1, h2, h3, h4
{
color: #005aa0;
}
h1 /* title */
{
font-size: 200%;
}
div.part h1
{
font-size: 240%;
}
h2 /* chapters, appendices, subtitle */
{
font-size: 180%;
}
div.part
{
margin-top: 4em;
}
/* Extra space between chapters, appendices. */
div.chapter > div.titlepage h2, div.appendix > div.titlepage h2
{
margin-top: 1.5em;
}
div.section > div.titlepage h2 /* sections */
{
font-size: 150%;
margin-top: 1.5em;
}
h3 /* subsections */
{
font-size: 125%;
}
div.simplesect h2
{
font-size: 110%;
}
div.appendix h3
{
font-size: 150%;
margin-top: 1.5em;
}
div.refentry\.separator
{
margin-top: 2.5em;
margin-bottom: 2em;
}
div.refnamediv h2, div.refsynopsisdiv h2, div.refsection h2 /* refentry parts */
{
margin-top: 1.4em;
font-size: 125%;
}
div.refsection h3
{
font-size: 110%;
}
/***************************************************************************
Examples:
***************************************************************************/
div.example
{
border: 1px solid #b0b0b0;
padding: 6px 6px;
margin-left: 1.5em;
margin-right: 1.5em;
background: #f4f4f8;
border-radius: 0.4em;
}
div.example p.title
{
margin-top: 0em;
}
div.example pre
{
}
/***************************************************************************
Screen dumps:
***************************************************************************/
pre.screen, pre.programlisting
{
padding: 6px 6px;
margin-left: 1.5em;
margin-right: 1.5em;
color: #600000;
background: #f4f4f8;
font-family: monospace;
}
div.example pre.programlisting
{
border: 0px;
padding: 0 0;
margin: 0 0 0 0;
}
/***************************************************************************
Notes, warnings etc:
***************************************************************************/
.note, .warning
{
border: 1px solid #b0b0b0;
padding: 3px 3px;
margin-left: 1.5em;
margin-right: 1.5em;
margin-bottom: 1em;
padding: 0.3em 0.3em 0.3em 0.3em;
background: #fffff5;
border-radius: 0.4em;
}
div.note, div.warning
{
font-style: italic;
}
div.note h3, div.warning h3
{
color: red;
font-size: 100%;
padding-right: 0.5em;
display: inline;
}
div.note p, div.warning p
{
margin-bottom: 0em;
}
div.note h3 + p, div.warning h3 + p
{
display: inline;
}
div.note h3
{
color: blue;
font-size: 100%;
}
div.navfooter *
{
font-size: 90%;
}
/***************************************************************************
Links colors and highlighting:
***************************************************************************/
a { text-decoration: none; }
a:hover { text-decoration: underline; }
a:link { color: #0048b3; }
a:visited { color: #002a6a; }
/***************************************************************************
Table of contents:
***************************************************************************/
div.toc
{
font-size: 90%;
}
div.toc dl
{
margin-top: 0em;
margin-bottom: 0em;
}
/***************************************************************************
Special elements:
***************************************************************************/
tt, code
{
color: #400000;
}
.term
{
font-weight: bold;
}
div.variablelist dd p, div.glosslist dd p
{
margin-top: 0em;
}
div.variablelist dd, div.glosslist dd
{
margin-left: 1.5em;
}
div.glosslist dt
{
font-style: italic;
}
.varname
{
color: #400000;
}
span.command strong
{
font-weight: normal;
color: #400000;
}
div.calloutlist table
{
}
table
{
border-collapse: collapse;
}
div.affiliation
{
font-style: italic;
}

View File

@@ -1,951 +0,0 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
#
# DESCRIPTION
#
# Check for baseline language coverage in the compiler for the specified
# version of the C++ standard. If necessary, add switches to CXX and
# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard)
# or '14' (for the C++14 standard).
#
# The second argument, if specified, indicates whether you insist on an
# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
# -std=c++11). If neither is specified, you get whatever works, with
# preference for an extended mode.
#
# The third argument, if specified 'mandatory' or if left unspecified,
# indicates that baseline support for the specified C++ standard is
# required and that the macro should error out if no mode with that
# support is found. If specified 'optional', then configuration proceeds
# regardless, after defining HAVE_CXX${VERSION} if and only if a
# supporting mode is found.
#
# LICENSE
#
# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
# Copyright (c) 2015 Paul Norman <penorman@mac.com>
# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
# Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz@gmail.com>
# Copyright (c) 2019 Enji Cooper <yaneurabeya@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 11
dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
dnl (serial version number 13).
AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
[$1], [14], [ax_cxx_compile_alternatives="14 1y"],
[$1], [17], [ax_cxx_compile_alternatives="17 1z"],
[m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
m4_if([$2], [], [],
[$2], [ext], [],
[$2], [noext], [],
[m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
[$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
[$3], [optional], [ax_cxx_compile_cxx$1_required=false],
[m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
AC_LANG_PUSH([C++])dnl
ac_success=no
m4_if([$2], [noext], [], [dnl
if test x$ac_success = xno; then
for alternative in ${ax_cxx_compile_alternatives}; do
switch="-std=gnu++${alternative}"
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
[ac_save_CXX="$CXX"
CXX="$CXX $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXX="$ac_save_CXX"])
if eval test x\$$cachevar = xyes; then
CXX="$CXX $switch"
if test -n "$CXXCPP" ; then
CXXCPP="$CXXCPP $switch"
fi
ac_success=yes
break
fi
done
fi])
m4_if([$2], [ext], [], [dnl
if test x$ac_success = xno; then
dnl HP's aCC needs +std=c++11 according to:
dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
dnl Cray's crayCC needs "-h std=c++11"
for alternative in ${ax_cxx_compile_alternatives}; do
for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
[ac_save_CXX="$CXX"
CXX="$CXX $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXX="$ac_save_CXX"])
if eval test x\$$cachevar = xyes; then
CXX="$CXX $switch"
if test -n "$CXXCPP" ; then
CXXCPP="$CXXCPP $switch"
fi
ac_success=yes
break
fi
done
if test x$ac_success = xyes; then
break
fi
done
fi])
AC_LANG_POP([C++])
if test x$ax_cxx_compile_cxx$1_required = xtrue; then
if test x$ac_success = xno; then
AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
fi
fi
if test x$ac_success = xno; then
HAVE_CXX$1=0
AC_MSG_NOTICE([No compiler with C++$1 support was found])
else
HAVE_CXX$1=1
AC_DEFINE(HAVE_CXX$1,1,
[define if the compiler supports basic C++$1 syntax])
fi
AC_SUBST(HAVE_CXX$1)
])
dnl Test body for checking C++11 support
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
)
dnl Test body for checking C++14 support
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
)
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
_AX_CXX_COMPILE_STDCXX_testbody_new_in_17
)
dnl Tests for new features in C++11
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
// If the compiler admits that it is not ready for C++11, why torture it?
// Hopefully, this will speed up the test.
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus < 201103L
#error "This is not a C++11 compiler"
#else
namespace cxx11
{
namespace test_static_assert
{
template <typename T>
struct check
{
static_assert(sizeof(int) <= sizeof(T), "not big enough");
};
}
namespace test_final_override
{
struct Base
{
virtual ~Base() {}
virtual void f() {}
};
struct Derived : public Base
{
virtual ~Derived() override {}
virtual void f() override {}
};
}
namespace test_double_right_angle_brackets
{
template < typename T >
struct check {};
typedef check<void> single_type;
typedef check<check<void>> double_type;
typedef check<check<check<void>>> triple_type;
typedef check<check<check<check<void>>>> quadruple_type;
}
namespace test_decltype
{
int
f()
{
int a = 1;
decltype(a) b = 2;
return a + b;
}
}
namespace test_type_deduction
{
template < typename T1, typename T2 >
struct is_same
{
static const bool value = false;
};
template < typename T >
struct is_same<T, T>
{
static const bool value = true;
};
template < typename T1, typename T2 >
auto
add(T1 a1, T2 a2) -> decltype(a1 + a2)
{
return a1 + a2;
}
int
test(const int c, volatile int v)
{
static_assert(is_same<int, decltype(0)>::value == true, "");
static_assert(is_same<int, decltype(c)>::value == false, "");
static_assert(is_same<int, decltype(v)>::value == false, "");
auto ac = c;
auto av = v;
auto sumi = ac + av + 'x';
auto sumf = ac + av + 1.0;
static_assert(is_same<int, decltype(ac)>::value == true, "");
static_assert(is_same<int, decltype(av)>::value == true, "");
static_assert(is_same<int, decltype(sumi)>::value == true, "");
static_assert(is_same<int, decltype(sumf)>::value == false, "");
static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
return (sumf > 0.0) ? sumi : add(c, v);
}
}
namespace test_noexcept
{
int f() { return 0; }
int g() noexcept { return 0; }
static_assert(noexcept(f()) == false, "");
static_assert(noexcept(g()) == true, "");
}
namespace test_constexpr
{
template < typename CharT >
unsigned long constexpr
strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
{
return *s ? strlen_c_r(s + 1, acc + 1) : acc;
}
template < typename CharT >
unsigned long constexpr
strlen_c(const CharT *const s) noexcept
{
return strlen_c_r(s, 0UL);
}
static_assert(strlen_c("") == 0UL, "");
static_assert(strlen_c("1") == 1UL, "");
static_assert(strlen_c("example") == 7UL, "");
static_assert(strlen_c("another\0example") == 7UL, "");
}
namespace test_rvalue_references
{
template < int N >
struct answer
{
static constexpr int value = N;
};
answer<1> f(int&) { return answer<1>(); }
answer<2> f(const int&) { return answer<2>(); }
answer<3> f(int&&) { return answer<3>(); }
void
test()
{
int i = 0;
const int c = 0;
static_assert(decltype(f(i))::value == 1, "");
static_assert(decltype(f(c))::value == 2, "");
static_assert(decltype(f(0))::value == 3, "");
}
}
namespace test_uniform_initialization
{
struct test
{
static const int zero {};
static const int one {1};
};
static_assert(test::zero == 0, "");
static_assert(test::one == 1, "");
}
namespace test_lambdas
{
void
test1()
{
auto lambda1 = [](){};
auto lambda2 = lambda1;
lambda1();
lambda2();
}
int
test2()
{
auto a = [](int i, int j){ return i + j; }(1, 2);
auto b = []() -> int { return '0'; }();
auto c = [=](){ return a + b; }();
auto d = [&](){ return c; }();
auto e = [a, &b](int x) mutable {
const auto identity = [](int y){ return y; };
for (auto i = 0; i < a; ++i)
a += b--;
return x + identity(a + b);
}(0);
return a + b + c + d + e;
}
int
test3()
{
const auto nullary = [](){ return 0; };
const auto unary = [](int x){ return x; };
using nullary_t = decltype(nullary);
using unary_t = decltype(unary);
const auto higher1st = [](nullary_t f){ return f(); };
const auto higher2nd = [unary](nullary_t f1){
return [unary, f1](unary_t f2){ return f2(unary(f1())); };
};
return higher1st(nullary) + higher2nd(nullary)(unary);
}
}
namespace test_variadic_templates
{
template <int...>
struct sum;
template <int N0, int... N1toN>
struct sum<N0, N1toN...>
{
static constexpr auto value = N0 + sum<N1toN...>::value;
};
template <>
struct sum<>
{
static constexpr auto value = 0;
};
static_assert(sum<>::value == 0, "");
static_assert(sum<1>::value == 1, "");
static_assert(sum<23>::value == 23, "");
static_assert(sum<1, 2>::value == 3, "");
static_assert(sum<5, 5, 11>::value == 21, "");
static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
}
// http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
// Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
// because of this.
namespace test_template_alias_sfinae
{
struct foo {};
template<typename T>
using member = typename T::member_type;
template<typename T>
void func(...) {}
template<typename T>
void func(member<T>*) {}
void test();
void test() { func<foo>(0); }
}
} // namespace cxx11
#endif // __cplusplus >= 201103L
]])
dnl Tests for new features in C++14
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
// If the compiler admits that it is not ready for C++14, why torture it?
// Hopefully, this will speed up the test.
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus < 201402L
#error "This is not a C++14 compiler"
#else
namespace cxx14
{
namespace test_polymorphic_lambdas
{
int
test()
{
const auto lambda = [](auto&&... args){
const auto istiny = [](auto x){
return (sizeof(x) == 1UL) ? 1 : 0;
};
const int aretiny[] = { istiny(args)... };
return aretiny[0];
};
return lambda(1, 1L, 1.0f, '1');
}
}
namespace test_binary_literals
{
constexpr auto ivii = 0b0000000000101010;
static_assert(ivii == 42, "wrong value");
}
namespace test_generalized_constexpr
{
template < typename CharT >
constexpr unsigned long
strlen_c(const CharT *const s) noexcept
{
auto length = 0UL;
for (auto p = s; *p; ++p)
++length;
return length;
}
static_assert(strlen_c("") == 0UL, "");
static_assert(strlen_c("x") == 1UL, "");
static_assert(strlen_c("test") == 4UL, "");
static_assert(strlen_c("another\0test") == 7UL, "");
}
namespace test_lambda_init_capture
{
int
test()
{
auto x = 0;
const auto lambda1 = [a = x](int b){ return a + b; };
const auto lambda2 = [a = lambda1(x)](){ return a; };
return lambda2();
}
}
namespace test_digit_separators
{
constexpr auto ten_million = 100'000'000;
static_assert(ten_million == 100000000, "");
}
namespace test_return_type_deduction
{
auto f(int& x) { return x; }
decltype(auto) g(int& x) { return x; }
template < typename T1, typename T2 >
struct is_same
{
static constexpr auto value = false;
};
template < typename T >
struct is_same<T, T>
{
static constexpr auto value = true;
};
int
test()
{
auto x = 0;
static_assert(is_same<int, decltype(f(x))>::value, "");
static_assert(is_same<int&, decltype(g(x))>::value, "");
return x;
}
}
} // namespace cxx14
#endif // __cplusplus >= 201402L
]])
dnl Tests for new features in C++17
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
// If the compiler admits that it is not ready for C++17, why torture it?
// Hopefully, this will speed up the test.
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus < 201703L
#error "This is not a C++17 compiler"
#else
#include <initializer_list>
#include <utility>
#include <type_traits>
namespace cxx17
{
namespace test_constexpr_lambdas
{
constexpr int foo = [](){return 42;}();
}
namespace test::nested_namespace::definitions
{
}
namespace test_fold_expression
{
template<typename... Args>
int multiply(Args... args)
{
return (args * ... * 1);
}
template<typename... Args>
bool all(Args... args)
{
return (args && ...);
}
}
namespace test_extended_static_assert
{
static_assert (true);
}
namespace test_auto_brace_init_list
{
auto foo = {5};
auto bar {5};
static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);
static_assert(std::is_same<int, decltype(bar)>::value);
}
namespace test_typename_in_template_template_parameter
{
template<template<typename> typename X> struct D;
}
namespace test_fallthrough_nodiscard_maybe_unused_attributes
{
int f1()
{
return 42;
}
[[nodiscard]] int f2()
{
[[maybe_unused]] auto unused = f1();
switch (f1())
{
case 17:
f1();
[[fallthrough]];
case 42:
f1();
}
return f1();
}
}
namespace test_extended_aggregate_initialization
{
struct base1
{
int b1, b2 = 42;
};
struct base2
{
base2() {
b3 = 42;
}
int b3;
};
struct derived : base1, base2
{
int d;
};
derived d1 {{1, 2}, {}, 4}; // full initialization
derived d2 {{}, {}, 4}; // value-initialized bases
}
namespace test_general_range_based_for_loop
{
struct iter
{
int i;
int& operator* ()
{
return i;
}
const int& operator* () const
{
return i;
}
iter& operator++()
{
++i;
return *this;
}
};
struct sentinel
{
int i;
};
bool operator== (const iter& i, const sentinel& s)
{
return i.i == s.i;
}
bool operator!= (const iter& i, const sentinel& s)
{
return !(i == s);
}
struct range
{
iter begin() const
{
return {0};
}
sentinel end() const
{
return {5};
}
};
void f()
{
range r {};
for (auto i : r)
{
[[maybe_unused]] auto v = i;
}
}
}
namespace test_lambda_capture_asterisk_this_by_value
{
struct t
{
int i;
int foo()
{
return [*this]()
{
return i;
}();
}
};
}
namespace test_enum_class_construction
{
enum class byte : unsigned char
{};
byte foo {42};
}
namespace test_constexpr_if
{
template <bool cond>
int f ()
{
if constexpr(cond)
{
return 13;
}
else
{
return 42;
}
}
}
namespace test_selection_statement_with_initializer
{
int f()
{
return 13;
}
int f2()
{
if (auto i = f(); i > 0)
{
return 3;
}
switch (auto i = f(); i + 4)
{
case 17:
return 2;
default:
return 1;
}
}
}
namespace test_template_argument_deduction_for_class_templates
{
template <typename T1, typename T2>
struct pair
{
pair (T1 p1, T2 p2)
: m1 {p1},
m2 {p2}
{}
T1 m1;
T2 m2;
};
void f()
{
[[maybe_unused]] auto p = pair{13, 42u};
}
}
namespace test_non_type_auto_template_parameters
{
template <auto n>
struct B
{};
B<5> b1;
B<'a'> b2;
}
namespace test_structured_bindings
{
int arr[2] = { 1, 2 };
std::pair<int, int> pr = { 1, 2 };
auto f1() -> int(&)[2]
{
return arr;
}
auto f2() -> std::pair<int, int>&
{
return pr;
}
struct S
{
int x1 : 2;
volatile double y1;
};
S f3()
{
return {};
}
auto [ x1, y1 ] = f1();
auto& [ xr1, yr1 ] = f1();
auto [ x2, y2 ] = f2();
auto& [ xr2, yr2 ] = f2();
const auto [ x3, y3 ] = f3();
}
namespace test_exception_spec_type_system
{
struct Good {};
struct Bad {};
void g1() noexcept;
void g2();
template<typename T>
Bad
f(T*, T*);
template<typename T1, typename T2>
Good
f(T1*, T2*);
static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
}
namespace test_inline_variables
{
template<class T> void f(T)
{}
template<class T> inline T g(T)
{
return T{};
}
template<> inline void f<>(int)
{}
template<> int g<>(int)
{
return 5;
}
}
} // namespace cxx17
#endif // __cplusplus < 201703L
]])

View File

@@ -1,35 +0,0 @@
# =============================================================================
# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_17.html
# =============================================================================
#
# SYNOPSIS
#
# AX_CXX_COMPILE_STDCXX_17([ext|noext], [mandatory|optional])
#
# DESCRIPTION
#
# Check for baseline language coverage in the compiler for the C++17
# standard; if necessary, add switches to CXX and CXXCPP to enable
# support.
#
# This macro is a convenience alias for calling the AX_CXX_COMPILE_STDCXX
# macro with the version set to C++17. The two optional arguments are
# forwarded literally as the second and third argument respectively.
# Please see the documentation for the AX_CXX_COMPILE_STDCXX macro for
# more information. If you want to use this macro, you also need to
# download the ax_cxx_compile_stdcxx.m4 file.
#
# LICENSE
#
# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
# Copyright (c) 2016 Krzesimir Nowak <qdlacz@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 2
AX_REQUIRE_DEFINED([AX_CXX_COMPILE_STDCXX])
AC_DEFUN([AX_CXX_COMPILE_STDCXX_17], [AX_CXX_COMPILE_STDCXX([17], [$1], [$2])])

View File

@@ -67,10 +67,10 @@ sub downloadFile {
}
my $sha256_expected = $buildInfo->{buildproducts}->{$productNr}->{sha256hash} or die;
my $sha256_actual = `nix hash-file --base16 --type sha256 '$dstFile'`;
my $sha256_actual = `nix hash-file --type sha256 '$dstFile'`;
chomp $sha256_actual;
if ($sha256_expected ne $sha256_actual) {
print STDERR "file $dstFile is corrupt, got $sha256_actual, expected $sha256_expected\n";
print STDERR "file $dstFile is corrupt\n";
exit 1;
}

View File

@@ -13,12 +13,8 @@
<true/>
<key>RunAtLoad</key>
<true/>
<key>ProgramArguments</key>
<array>
<string>/bin/sh</string>
<string>-c</string>
<string>/bin/wait4path /nix/var/nix/profiles/default/bin/nix-daemon &amp;&amp; /nix/var/nix/profiles/default/bin/nix-daemon</string>
</array>
<key>Program</key>
<string>@bindir@/nix-daemon</string>
<key>StandardErrorPath</key>
<string>/var/log/nix-daemon.log</string>
<key>StandardOutPath</key>

View File

@@ -7,6 +7,3 @@ ConditionPathIsReadWrite=@localstatedir@/nix/daemon-socket
[Service]
ExecStart=@@bindir@/nix-daemon nix-daemon --daemon
KillMode=process
[Install]
WantedBy=multi-user.target

6
mk/README.md Normal file
View File

@@ -0,0 +1,6 @@
This is a set of helper Makefiles for doing non-recursive builds with
GNU Make. The canonical source can be found at
https://github.com/edolstra/make-rules. You should copy the files
into the `mk` subdirectory of your project.
TODO: write more documentation.

View File

@@ -91,7 +91,7 @@ define build-library
$(1)_PATH := $$(_d)/$$($(1)_NAME).$(SO_EXT)
$$($(1)_PATH): $$($(1)_OBJS) $$(_libs) | $$(_d)/
$$(trace-ld) $(CXX) -o $$(abspath $$@) -shared $$(LDFLAGS) $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$($(1)_LDFLAGS_PROPAGATED) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE)) $$($(1)_LDFLAGS_UNINSTALLED)
$$(trace-ld) $(CXX) -o $$(abspath $$@) -shared $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$($(1)_LDFLAGS_PROPAGATED) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE)) $$($(1)_LDFLAGS_UNINSTALLED)
ifneq ($(OS), Darwin)
$(1)_LDFLAGS_USE += -Wl,-rpath,$$(abspath $$(_d))
@@ -105,7 +105,7 @@ define build-library
$$(eval $$(call create-dir, $$($(1)_INSTALL_DIR)))
$$($(1)_INSTALL_PATH): $$($(1)_OBJS) $$(_libs_final) | $(DESTDIR)$$($(1)_INSTALL_DIR)/
$$(trace-ld) $(CXX) -o $$@ -shared $$(LDFLAGS) $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$($(1)_LDFLAGS_PROPAGATED) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE_INSTALLED))
$$(trace-ld) $(CXX) -o $$@ -shared $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$($(1)_LDFLAGS_PROPAGATED) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE_INSTALLED))
$(1)_LDFLAGS_USE_INSTALLED += -L$$(DESTDIR)$$($(1)_INSTALL_DIR) -l$$(patsubst lib%,%,$$(strip $$($(1)_NAME)))
ifneq ($(OS), Darwin)

View File

@@ -32,7 +32,7 @@ define build-program
$$(eval $$(call create-dir, $$(_d)))
$$($(1)_PATH): $$($(1)_OBJS) $$(_libs) | $$(_d)/
$$(trace-ld) $(CXX) -o $$@ $$(LDFLAGS) $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE))
$$(trace-ld) $(CXX) -o $$@ $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE))
$(1)_INSTALL_DIR ?= $$(bindir)
$(1)_INSTALL_PATH := $$($(1)_INSTALL_DIR)/$(1)
@@ -46,7 +46,7 @@ define build-program
_libs_final := $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_INSTALL_PATH))
$(DESTDIR)$$($(1)_INSTALL_PATH): $$($(1)_OBJS) $$(_libs_final) | $(DESTDIR)$$($(1)_INSTALL_DIR)/
$$(trace-ld) $(CXX) -o $$@ $$(LDFLAGS) $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE_INSTALLED))
$$(trace-ld) $(CXX) -o $$@ $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE_INSTALLED))
else

View File

@@ -106,7 +106,7 @@ chmod 1775 $RPM_BUILD_ROOT/nix/store
for d in profiles gcroots;
do
mkdir -p $RPM_BUILD_ROOT/nix/var/nix/$d/per-user
chmod 755 $RPM_BUILD_ROOT/nix/var/nix/$d/per-user
chmod 1777 $RPM_BUILD_ROOT/nix/var/nix/$d/per-user
done
# fix permission of nix profile

View File

@@ -4,4 +4,11 @@ GLOBAL_CXXFLAGS += -g -Wall
-include Makefile.config
OPTIMIZE = 1
ifeq ($(OPTIMIZE), 1)
GLOBAL_CFLAGS += -O3
GLOBAL_CXXFLAGS += -O3
endif
include mk/lib.mk

View File

@@ -2,10 +2,8 @@ AC_INIT(nix-perl, m4_esyscmd([bash -c "echo -n $(cat ../.version)$VERSION_SUFFIX
AC_CONFIG_SRCDIR(MANIFEST)
AC_CONFIG_AUX_DIR(../config)
# Set default flags for nix (as per AC_PROG_CC/CXX docs),
# while still allowing the user to override them from the command line.
: ${CFLAGS="-O3"}
: ${CXXFLAGS="-O3"}
CFLAGS=
CXXFLAGS=
AC_PROG_CC
AC_PROG_CXX
AX_CXX_COMPILE_STDCXX_11

View File

@@ -42,7 +42,7 @@ rec {
libxml2
libxslt
docbook5
docbook_xsl_ns
docbook5_xsl
autoconf-archive
autoreconfHook
];
@@ -50,7 +50,7 @@ rec {
buildDeps =
[ curl
bzip2 xz brotli editline
openssl pkgconfig sqlite
openssl pkgconfig sqlite boehmgc
boost
# Tests
@@ -72,10 +72,6 @@ rec {
*/
}));
propagatedDeps =
[ (boehmgc.override { enableLargeConfig = true; })
];
perlDeps =
[ perl
perlPackages.DBDSQLite

View File

@@ -1,5 +1,5 @@
{ nix ? builtins.fetchGit ./.
, nixpkgs ? builtins.fetchTarball https://github.com/NixOS/nixpkgs-channels/archive/nixos-19.03.tar.gz
, nixpkgs ? builtins.fetchGit { url = https://github.com/NixOS/nixpkgs-channels.git; ref = "nixos-19.03"; }
, officialRelease ? false
, systems ? [ "x86_64-linux" "i686-linux" "x86_64-darwin" "aarch64-linux" ]
}:
@@ -23,7 +23,7 @@ let
src = nix;
inherit officialRelease;
buildInputs = tarballDeps ++ buildDeps ++ propagatedDeps;
buildInputs = tarballDeps ++ buildDeps;
configureFlags = "--enable-gc";
@@ -67,19 +67,12 @@ let
buildInputs = buildDeps;
propagatedBuildInputs = propagatedDeps;
preConfigure =
# Copy libboost_context so we don't get all of Boost in our closure.
# https://github.com/NixOS/nixpkgs/issues/45462
''
mkdir -p $out/lib
cp -pd ${boost}/lib/{libboost_context*,libboost_thread*,libboost_system*} $out/lib
rm -f $out/lib/*.a
${lib.optionalString stdenv.isLinux ''
chmod u+w $out/lib/*.so.*
patchelf --set-rpath $out/lib:${stdenv.cc.cc.lib}/lib $out/lib/libboost_thread.so.*
''}
cp ${boost}/lib/libboost_context* $out/lib
'';
configureFlags = configureFlags ++
@@ -93,8 +86,6 @@ let
doInstallCheck = true;
installCheckFlags = "sysconfdir=$(out)/etc";
separateDebugInfo = true;
});
@@ -132,7 +123,7 @@ let
in
runCommand "nix-binary-tarball-${version}"
{ #nativeBuildInputs = lib.optional (system != "aarch64-linux") shellcheck;
{ nativeBuildInputs = lib.optional (system != "aarch64-linux") shellcheck;
meta.description = "Distribution-independent Nix bootstrap binaries for ${system}";
}
''
@@ -174,10 +165,10 @@ let
chmod +x $TMPDIR/install-systemd-multi-user.sh
chmod +x $TMPDIR/install-multi-user
dir=nix-${version}-${system}
fn=$out/$dir.tar.xz
fn=$out/$dir.tar.bz2
mkdir -p $out/nix-support
echo "file binary-dist $fn" >> $out/nix-support/hydra-build-products
tar cvfJ $fn \
tar cvfj $fn \
--owner=0 --group=0 --mode=u+rw,uga+r \
--absolute-names \
--hard-dereference \
@@ -200,9 +191,7 @@ let
name = "nix-build";
src = tarball;
enableParallelBuilding = true;
buildInputs = buildDeps ++ propagatedDeps;
buildInputs = buildDeps;
dontInstall = false;
@@ -277,7 +266,6 @@ let
umount /nix
''); # */
/*
tests.evalNixpkgs =
import (nixpkgs + "/pkgs/top-level/make-tarball.nix") {
inherit nixpkgs;
@@ -296,7 +284,6 @@ let
touch $out
'';
*/
installerScript =
@@ -308,7 +295,7 @@ let
substitute ${./scripts/install.in} $out/install \
${pkgs.lib.concatMapStrings
(system: "--replace '@binaryTarball_${system}@' $(nix hash-file --base16 --type sha256 ${binaryTarball.${system}}/*.tar.xz) ")
(system: "--replace '@binaryTarball_${system}@' $(nix hash-file --base16 --type sha256 ${binaryTarball.${system}}/*.tar.bz2) ")
[ "x86_64-linux" "i686-linux" "x86_64-darwin" "aarch64-linux" ]
} \
--replace '@nixVersion@' ${build.x86_64-linux.src.version}
@@ -334,8 +321,8 @@ let
tests.remoteBuilds
tests.nix-copy-closure
tests.binaryTarball
#tests.evalNixpkgs
#tests.evalNixOS
tests.evalNixpkgs
tests.evalNixOS
installerScript
];
};

View File

@@ -39,7 +39,7 @@ EOF
poly_configure_nix_daemon_service() {
_sudo "to set up the nix-daemon as a LaunchDaemon" \
cp -f "/nix/var/nix/profiles/default$PLIST_DEST" "$PLIST_DEST"
ln -sfn "/nix/var/nix/profiles/default$PLIST_DEST" "$PLIST_DEST"
_sudo "to load the LaunchDaemon plist for nix-daemon" \
launchctl load /Library/LaunchDaemons/org.nixos.nix-daemon.plist

View File

@@ -13,12 +13,15 @@ set -o pipefail
# however tracking which bits came from which would be impossible.
readonly ESC='\033[0m'
readonly BOLD='\033[1m'
readonly BLUE='\033[34m'
readonly BLUE_UL='\033[4;34m'
readonly GREEN='\033[32m'
readonly GREEN_UL='\033[4;32m'
readonly RED='\033[31m'
readonly BOLD='\033[38;1m'
readonly BLUE='\033[38;34m'
readonly BLUE_UL='\033[38;4;34m'
readonly GREEN='\033[38;32m'
readonly GREEN_UL='\033[38;4;32m'
readonly RED='\033[38;31m'
readonly RED_UL='\033[38;4;31m'
readonly YELLOW='\033[38;33m'
readonly YELLOW_UL='\033[38;4;33m'
readonly NIX_USER_COUNT="32"
readonly NIX_BUILD_GROUP_ID="30000"
@@ -237,16 +240,10 @@ EOF
}
trap finish_fail EXIT
channel_update_failed=0
function finish_success {
finish_cleanup
ok "Alright! We're done!"
if [ "x$channel_update_failed" = x1 ]; then
echo ""
echo "But fetching the nixpkgs channel failed. (Are you offline?)"
echo "To try again later, run \"sudo -i nix-channel --update nixpkgs\"."
fi
cat <<EOF
Before Nix will work in your existing shells, you'll need to close
@@ -327,7 +324,7 @@ EOF
fi
done
if [ -d /nix/store ] || [ -d /nix/var ]; then
if [ -d /nix ]; then
failure <<EOF
There are some relics of a previous installation of Nix at /nix, and
this scripts assumes Nix is _not_ yet installed. Please delete the old
@@ -526,17 +523,24 @@ create_build_users() {
}
create_directories() {
# FIXME: remove all of this because it duplicates LocalStore::LocalStore().
_sudo "to make the basic directory structure of Nix (part 1)" \
mkdir -pv -m 0755 /nix /nix/var /nix/var/log /nix/var/log/nix /nix/var/log/nix/drvs /nix/var/nix{,/db,/gcroots,/profiles,/temproots,/userpool} /nix/var/nix/{gcroots,profiles}/per-user
mkdir -pv -m 0755 /nix /nix/var /nix/var/log /nix/var/log/nix /nix/var/log/nix/drvs /nix/var/nix{,/db,/gcroots,/profiles,/temproots,/userpool}
_sudo "to make the basic directory structure of Nix (part 2)" \
mkdir -pv -m 1775 /nix/store
mkdir -pv -m 1777 /nix/var/nix/{gcroots,profiles}/per-user
_sudo "to make the basic directory structure of Nix (part 3)" \
mkdir -pv -m 1775 /nix/store
_sudo "to make the basic directory structure of Nix (part 4)" \
chgrp "$NIX_BUILD_GROUP_NAME" /nix/store
_sudo "to set up the root user's profile (part 1)" \
mkdir -pv -m 0755 /nix/var/nix/profiles/per-user/root
_sudo "to set up the root user's profile (part 2)" \
mkdir -pv -m 0700 "$ROOT_HOME/.nix-defexpr"
_sudo "to place the default nix daemon configuration (part 1)" \
mkdir -pv -m 0555 /etc/nix
}
@@ -579,7 +583,7 @@ EOF
We will:
- make sure your computer doesn't already have Nix files
(if it does, I will tell you how to clean them up.)
(if it does, I will tell you how to clean them up.)
- create local users (see the list above for the users we'll make)
- create a local group ($NIX_BUILD_GROUP_NAME)
- install Nix in to $NIX_ROOT
@@ -730,15 +734,16 @@ setup_default_profile() {
# otherwise it will be lost in environments where sudo doesn't pass
# all the environment variables by default.
_sudo "to update the default channel in the default profile" \
HOME="$ROOT_HOME" NIX_SSL_CERT_FILE="$NIX_SSL_CERT_FILE" "$NIX_INSTALLED_NIX/bin/nix-channel" --update nixpkgs \
|| channel_update_failed=1
HOME="$ROOT_HOME" NIX_SSL_CERT_FILE="$NIX_SSL_CERT_FILE" "$NIX_INSTALLED_NIX/bin/nix-channel" --update nixpkgs
}
place_nix_configuration() {
cat <<EOF > "$SCRATCH/nix.conf"
build-users-group = $NIX_BUILD_GROUP_NAME
max-jobs = $NIX_USER_COUNT
cores = 1
EOF
_sudo "to place the default nix daemon configuration (part 2)" \
install -m 0664 "$SCRATCH/nix.conf" /etc/nix/nix.conf
@@ -748,13 +753,9 @@ main() {
if [ "$(uname -s)" = "Darwin" ]; then
# shellcheck source=./install-darwin-multi-user.sh
. "$EXTRACTED_NIX_PATH/install-darwin-multi-user.sh"
elif [ "$(uname -s)" = "Linux" ]; then
if [ -e /run/systemd/system ]; then
# shellcheck source=./install-systemd-multi-user.sh
. "$EXTRACTED_NIX_PATH/install-systemd-multi-user.sh"
else
failure "Sorry, the multi-user installation requires systemd on Linux (detected using /run/systemd/system)"
fi
elif [ "$(uname -s)" = "Linux" ] && [ -e /run/systemd/system ]; then
# shellcheck source=./install-systemd-multi-user.sh
. "$EXTRACTED_NIX_PATH/install-systemd-multi-user.sh"
else
failure "Sorry, I don't know what to do on $(uname)"
fi

View File

@@ -12,7 +12,7 @@ if ! [ -e "$self/.reginfo" ]; then
echo "$0: incomplete installer (.reginfo is missing)" >&2
fi
if [ -z "$USER" ] && ! USER=$(id -u -n); then
if [ -z "$USER" ]; then
echo "$0: \$USER is not set" >&2
exit 1
fi
@@ -22,12 +22,10 @@ if [ -z "$HOME" ]; then
exit 1
fi
# macOS support for 10.12.6 or higher
# macOS support for 10.10 or higher
if [ "$(uname -s)" = "Darwin" ]; then
macos_major=$(sw_vers -productVersion | cut -d '.' -f 2)
macos_minor=$(sw_vers -productVersion | cut -d '.' -f 3)
if [ "$macos_major" -lt 12 ] || { [ "$macos_major" -eq 12 ] && [ "$macos_minor" -lt 6 ]; }; then
echo "$0: macOS $(sw_vers -productVersion) is not supported, upgrade to 10.12.6 or higher"
if [ $(($(sw_vers -productVersion | cut -d '.' -f 2))) -lt 10 ]; then
echo "$0: macOS $(sw_vers -productVersion) is not supported, upgrade to 10.10 or higher"
exit 1
fi
fi
@@ -134,16 +132,15 @@ if ! $nix/bin/nix-channel --list | grep -q "^nixpkgs "; then
$nix/bin/nix-channel --add https://nixos.org/channels/nixpkgs-unstable
fi
if [ -z "$_NIX_INSTALLER_TEST" ]; then
if ! $nix/bin/nix-channel --update nixpkgs; then
echo "Fetching the nixpkgs channel failed. (Are you offline?)"
echo "To try again later, run \"nix-channel --update nixpkgs\"."
fi
$nix/bin/nix-channel --update nixpkgs
fi
added=
p=$HOME/.nix-profile/etc/profile.d/nix.sh
if [ -z "$NIX_INSTALLER_NO_MODIFY_PROFILE" ]; then
# Make the shell source nix.sh during login.
p=$HOME/.nix-profile/etc/profile.d/nix.sh
for i in .bash_profile .bash_login .profile; do
fn="$HOME/$i"
if [ -w "$fn" ]; then
@@ -155,6 +152,7 @@ if [ -z "$NIX_INSTALLER_NO_MODIFY_PROFILE" ]; then
break
fi
done
fi
if [ -z "$added" ]; then

34
scripts/install-systemd-multi-user.sh Executable file → Normal file
View File

@@ -9,38 +9,6 @@ readonly SERVICE_DEST=/etc/systemd/system/nix-daemon.service
readonly SOCKET_SRC=/lib/systemd/system/nix-daemon.socket
readonly SOCKET_DEST=/etc/systemd/system/nix-daemon.socket
# Path for the systemd override unit file to contain the proxy settings
readonly SERVICE_OVERRIDE=${SERVICE_DEST}.d/override.conf
create_systemd_override() {
header "Configuring proxy for the nix-daemon service"
_sudo "create directory for systemd unit override" mkdir -p "$(dirname $SERVICE_OVERRIDE)"
cat <<EOF | _sudo "create systemd unit override" tee "$SERVICE_OVERRIDE"
[Service]
$1
EOF
}
# Gather all non-empty proxy environment variables into a string
create_systemd_proxy_env() {
vars="http_proxy https_proxy ftp_proxy no_proxy HTTP_PROXY HTTPS_PROXY FTP_PROXY NO_PROXY"
for v in $vars; do
if [ "x${!v:-}" != "x" ]; then
echo "Environment=${v}=${!v}"
fi
done
}
handle_network_proxy() {
# Create a systemd unit override with proxy environment variables
# if any proxy environment variables are not empty.
PROXY_ENV_STRING=$(create_systemd_proxy_env)
if [ -n "${PROXY_ENV_STRING}" ]; then
create_systemd_override "${PROXY_ENV_STRING}"
fi
}
poly_validate_assumptions() {
if [ "$(uname -s)" != "Linux" ]; then
failure "This script is for use with Linux!"
@@ -79,8 +47,6 @@ poly_configure_nix_daemon_service() {
_sudo "to set up the nix-daemon socket service" \
systemctl enable "/nix/var/nix/profiles/default$SOCKET_SRC"
handle_network_proxy
_sudo "to load the systemd unit for nix-daemon" \
systemctl daemon-reload

View File

@@ -18,7 +18,7 @@ cleanup() {
trap cleanup EXIT INT QUIT TERM
require_util() {
command -v "$1" > /dev/null 2>&1 ||
type "$1" > /dev/null 2>&1 || command -v "$1" > /dev/null 2>&1 ||
oops "you do not have '$1' installed, which I need to $2"
}
@@ -30,21 +30,22 @@ case "$(uname -s).$(uname -m)" in
*) oops "sorry, there is no binary distribution of Nix for your platform";;
esac
url="https://nixos.org/releases/nix/nix-@nixVersion@/nix-@nixVersion@-$system.tar.xz"
url="https://nixos.org/releases/nix/nix-@nixVersion@/nix-@nixVersion@-$system.tar.bz2"
tarball="$tmpDir/$(basename "$tmpDir/nix-@nixVersion@-$system.tar.xz")"
tarball="$tmpDir/$(basename "$tmpDir/nix-@nixVersion@-$system.tar.bz2")"
require_util curl "download the binary tarball"
require_util bzcat "decompress the binary tarball"
require_util tar "unpack the binary tarball"
echo "downloading Nix @nixVersion@ binary tarball for $system from '$url' to '$tmpDir'..."
curl -L "$url" -o "$tarball" || oops "failed to download '$url'"
if command -v sha256sum > /dev/null 2>&1; then
if type sha256sum > /dev/null 2>&1; then
hash2="$(sha256sum -b "$tarball" | cut -c1-64)"
elif command -v shasum > /dev/null 2>&1; then
elif type shasum > /dev/null 2>&1; then
hash2="$(shasum -a 256 -b "$tarball" | cut -c1-64)"
elif command -v openssl > /dev/null 2>&1; then
elif type openssl > /dev/null 2>&1; then
hash2="$(openssl dgst -r -sha256 "$tarball" | cut -c1-64)"
else
oops "cannot verify the SHA-256 hash of '$url'; you need one of 'shasum', 'sha256sum', or 'openssl'"
@@ -56,7 +57,7 @@ fi
unpack=$tmpDir/unpack
mkdir -p "$unpack"
tar -xf "$tarball" -C "$unpack" || oops "failed to unpack '$url'"
< "$tarball" bzcat | tar -xf - -C "$unpack" || oops "failed to unpack '$url'"
script=$(echo "$unpack"/*/install)

View File

@@ -2,9 +2,54 @@
if [ -n "${__ETC_PROFILE_NIX_SOURCED:-}" ]; then return; fi
__ETC_PROFILE_NIX_SOURCED=1
# Set up secure multi-user builds: non-root users build through the
# Nix daemon.
if [ "$USER" != root -o ! -w @localstatedir@/nix/db ]; then
export NIX_REMOTE=daemon
fi
export NIX_USER_PROFILE_DIR="@localstatedir@/nix/profiles/per-user/$USER"
export NIX_PROFILES="@localstatedir@/nix/profiles/default $HOME/.nix-profile"
# Set up the per-user profile.
mkdir -m 0755 -p $NIX_USER_PROFILE_DIR
if ! test -O "$NIX_USER_PROFILE_DIR"; then
echo "WARNING: bad ownership on $NIX_USER_PROFILE_DIR" >&2
fi
if test -w $HOME; then
if ! test -L $HOME/.nix-profile; then
if test "$USER" != root; then
ln -s $NIX_USER_PROFILE_DIR/profile $HOME/.nix-profile
else
# Root installs in the system-wide profile by default.
ln -s @localstatedir@/nix/profiles/default $HOME/.nix-profile
fi
fi
# Subscribe the root user to the NixOS channel by default.
if [ "$USER" = root -a ! -e $HOME/.nix-channels ]; then
echo "https://nixos.org/channels/nixpkgs-unstable nixpkgs" > $HOME/.nix-channels
fi
# Create the per-user garbage collector roots directory.
NIX_USER_GCROOTS_DIR=@localstatedir@/nix/gcroots/per-user/$USER
mkdir -m 0755 -p $NIX_USER_GCROOTS_DIR
if ! test -O "$NIX_USER_GCROOTS_DIR"; then
echo "WARNING: bad ownership on $NIX_USER_GCROOTS_DIR" >&2
fi
# Set up a default Nix expression from which to install stuff.
if [ ! -e $HOME/.nix-defexpr -o -L $HOME/.nix-defexpr ]; then
rm -f $HOME/.nix-defexpr
mkdir -p $HOME/.nix-defexpr
if [ "$USER" != root ]; then
ln -s @localstatedir@/nix/profiles/per-user/root/channels $HOME/.nix-defexpr/channels_root
fi
fi
fi
# Set $NIX_SSL_CERT_FILE so that Nixpkgs applications like curl work.
if [ ! -z "${NIX_SSL_CERT_FILE:-}" ]; then
: # Allow users to override the NIX_SSL_CERT_FILE

View File

@@ -1,4 +1,6 @@
if [ -n "$HOME" ] && [ -n "$USER" ]; then
__savedpath="$PATH"
export PATH=@coreutils@
# Set up the per-user profile.
# This part should be kept in sync with nixpkgs:nixos/modules/programs/shell.nix
@@ -7,13 +9,56 @@ if [ -n "$HOME" ] && [ -n "$USER" ]; then
NIX_USER_PROFILE_DIR=@localstatedir@/nix/profiles/per-user/$USER
# Append ~/.nix-defexpr/channels to $NIX_PATH so that <nixpkgs>
# paths work when the user has fetched the Nixpkgs channel.
export NIX_PATH=${NIX_PATH:+$NIX_PATH:}$HOME/.nix-defexpr/channels
mkdir -m 0755 -p "$NIX_USER_PROFILE_DIR"
if [ "$(stat --printf '%u' "$NIX_USER_PROFILE_DIR")" != "$(id -u)" ]; then
echo "Nix: WARNING: bad ownership on "$NIX_USER_PROFILE_DIR", should be $(id -u)" >&2
fi
if [ -w "$HOME" ]; then
if ! [ -L "$NIX_LINK" ]; then
echo "Nix: creating $NIX_LINK" >&2
if [ "$USER" != root ]; then
if ! ln -s "$NIX_USER_PROFILE_DIR"/profile "$NIX_LINK"; then
echo "Nix: WARNING: could not create $NIX_LINK -> $NIX_USER_PROFILE_DIR/profile" >&2
fi
else
# Root installs in the system-wide profile by default.
ln -s @localstatedir@/nix/profiles/default "$NIX_LINK"
fi
fi
# Subscribe the user to the unstable Nixpkgs channel by default.
if [ ! -e "$HOME/.nix-channels" ]; then
echo "https://nixos.org/channels/nixpkgs-unstable nixpkgs" > "$HOME/.nix-channels"
fi
# Create the per-user garbage collector roots directory.
__user_gcroots=@localstatedir@/nix/gcroots/per-user/"$USER"
mkdir -m 0755 -p "$__user_gcroots"
if [ "$(stat --printf '%u' "$__user_gcroots")" != "$(id -u)" ]; then
echo "Nix: WARNING: bad ownership on $__user_gcroots, should be $(id -u)" >&2
fi
unset __user_gcroots
# Set up a default Nix expression from which to install stuff.
__nix_defexpr="$HOME"/.nix-defexpr
[ -L "$__nix_defexpr" ] && rm -f "$__nix_defexpr"
mkdir -m 0755 -p "$__nix_defexpr"
if [ "$USER" != root ] && [ ! -L "$__nix_defexpr"/channels_root ]; then
ln -s @localstatedir@/nix/profiles/per-user/root/channels "$__nix_defexpr"/channels_root
fi
unset __nix_defexpr
fi
# Append ~/.nix-defexpr/channels/nixpkgs to $NIX_PATH so that
# <nixpkgs> paths work when the user has fetched the Nixpkgs
# channel.
export NIX_PATH="${NIX_PATH:+$NIX_PATH:}nixpkgs=$HOME/.nix-defexpr/channels/nixpkgs"
# Set up environment.
# This part should be kept in sync with nixpkgs:nixos/modules/programs/environment.nix
export NIX_PROFILES="@localstatedir@/nix/profiles/default $HOME/.nix-profile"
NIX_PROFILES="@localstatedir@/nix/profiles/default $NIX_USER_PROFILE_DIR"
# Set $NIX_SSL_CERT_FILE so that Nixpkgs applications like curl work.
if [ -e /etc/ssl/certs/ca-certificates.crt ]; then # NixOS, Ubuntu, Debian, Gentoo, Arch
@@ -34,6 +79,6 @@ if [ -n "$HOME" ] && [ -n "$USER" ]; then
export MANPATH="$NIX_LINK/share/man:$MANPATH"
fi
export PATH="$NIX_LINK/bin:$PATH"
unset NIX_LINK NIX_USER_PROFILE_DIR
export PATH="$NIX_LINK/bin:$__savedpath"
unset __savedpath NIX_LINK NIX_USER_PROFILE_DIR NIX_PROFILES
fi

View File

@@ -1,13 +1,13 @@
{ useClang ? false }:
with import (builtins.fetchTarball https://github.com/NixOS/nixpkgs-channels/archive/nixos-19.03.tar.gz) {};
with import (builtins.fetchGit { url = https://github.com/NixOS/nixpkgs-channels.git; ref = "nixos-19.03"; }) {};
with import ./release-common.nix { inherit pkgs; };
(if useClang then clangStdenv else stdenv).mkDerivation {
name = "nix";
buildInputs = buildDeps ++ propagatedDeps ++ tarballDeps ++ perlDeps;
buildInputs = buildDeps ++ tarballDeps ++ perlDeps;
inherit configureFlags;

View File

@@ -4,8 +4,8 @@
* @date May 2013
*/
#ifndef CPPTOML_H
#define CPPTOML_H
#ifndef _CPPTOML_H_
#define _CPPTOML_H_
#include <algorithm>
#include <cassert>
@@ -84,12 +84,11 @@ class option
return &value_;
}
template <class U>
T value_or(U&& alternative) const
const T& value_or(const T& alternative) const
{
if (!empty_)
return value_;
return static_cast<T>(std::forward<U>(alternative));
return alternative;
}
private:
@@ -296,12 +295,13 @@ struct valid_value_or_string_convertible
};
template <class T>
struct value_traits<T, typename std::enable_if<
valid_value_or_string_convertible<T>::value>::type>
struct value_traits<T, typename std::
enable_if<valid_value_or_string_convertible<T>::
value>::type>
{
using value_type = typename std::conditional<
valid_value<typename std::decay<T>::type>::value,
typename std::decay<T>::type, std::string>::type;
using value_type = typename std::
conditional<valid_value<typename std::decay<T>::type>::value,
typename std::decay<T>::type, std::string>::type;
using type = value<value_type>;
@@ -312,11 +312,12 @@ struct value_traits<T, typename std::enable_if<
};
template <class T>
struct value_traits<
T,
typename std::enable_if<
!valid_value_or_string_convertible<T>::value
&& std::is_floating_point<typename std::decay<T>::type>::value>::type>
struct value_traits<T,
typename std::
enable_if<!valid_value_or_string_convertible<T>::value
&& std::is_floating_point<
typename std::decay<T>::type>::value>::
type>
{
using value_type = typename std::decay<T>::type;
@@ -329,11 +330,11 @@ struct value_traits<
};
template <class T>
struct value_traits<
T, typename std::enable_if<
!valid_value_or_string_convertible<T>::value
&& !std::is_floating_point<typename std::decay<T>::type>::value
&& std::is_signed<typename std::decay<T>::type>::value>::type>
struct value_traits<T,
typename std::
enable_if<!valid_value_or_string_convertible<T>::value
&& std::is_signed<typename std::decay<T>::
type>::value>::type>
{
using value_type = int64_t;
@@ -355,10 +356,11 @@ struct value_traits<
};
template <class T>
struct value_traits<
T, typename std::enable_if<
!valid_value_or_string_convertible<T>::value
&& std::is_unsigned<typename std::decay<T>::type>::value>::type>
struct value_traits<T,
typename std::
enable_if<!valid_value_or_string_convertible<T>::value
&& std::is_unsigned<typename std::decay<T>::
type>::value>::type>
{
using value_type = int64_t;
@@ -393,15 +395,10 @@ struct array_of_trait<array>
template <class T>
inline std::shared_ptr<typename value_traits<T>::type> make_value(T&& val);
inline std::shared_ptr<array> make_array();
namespace detail
{
template <class T>
inline std::shared_ptr<T> make_element();
}
inline std::shared_ptr<table> make_table();
inline std::shared_ptr<table_array> make_table_array(bool is_inline = false);
inline std::shared_ptr<table_array> make_table_array();
#if defined(CPPTOML_NO_RTTI)
/// Base type used to store underlying data type explicitly if RTTI is disabled
@@ -579,7 +576,7 @@ class base : public std::enable_shared_from_this<base>
#if defined(CPPTOML_NO_RTTI)
base_type type() const
{
return type_;
return type_;
}
protected:
@@ -701,7 +698,7 @@ inline std::shared_ptr<value<double>> base::as()
if (type() == base_type::INT)
{
auto v = std::static_pointer_cast<value<int64_t>>(shared_from_this());
return make_value<double>(static_cast<double>(v->get()));
return make_value<double>(static_cast<double>(v->get()));;
}
#else
if (auto v = std::dynamic_pointer_cast<value<double>>(shared_from_this()))
@@ -734,8 +731,7 @@ inline std::shared_ptr<const value<double>> base::as() const
{
#if defined(CPPTOML_NO_RTTI)
if (type() == base_type::FLOAT)
return std::static_pointer_cast<const value<double>>(
shared_from_this());
return std::static_pointer_cast<const value<double>>(shared_from_this());
if (type() == base_type::INT)
{
@@ -1031,14 +1027,11 @@ inline std::shared_ptr<array> make_array()
return std::make_shared<make_shared_enabler>();
}
namespace detail
{
template <>
inline std::shared_ptr<array> make_element<array>()
{
return make_array();
}
} // namespace detail
/**
* Obtains a option<vector<T>>. The option will be empty if the array
@@ -1067,7 +1060,7 @@ class table;
class table_array : public base
{
friend class table;
friend std::shared_ptr<table_array> make_table_array(bool);
friend std::shared_ptr<table_array> make_table_array();
public:
std::shared_ptr<base> clone() const override;
@@ -1159,25 +1152,14 @@ class table_array : public base
array_.reserve(n);
}
/**
* Whether or not the table array is declared inline. This mostly
* matters for parsing, where statically defined arrays cannot be
* appended to using the array-of-table syntax.
*/
bool is_inline() const
{
return is_inline_;
}
private:
#if defined(CPPTOML_NO_RTTI)
table_array(bool is_inline = false)
: base(base_type::TABLE_ARRAY), is_inline_(is_inline)
table_array() : base(base_type::TABLE_ARRAY)
{
// nothing
}
#else
table_array(bool is_inline = false) : is_inline_(is_inline)
table_array()
{
// nothing
}
@@ -1187,30 +1169,26 @@ class table_array : public base
table_array& operator=(const table_array& rhs) = delete;
std::vector<std::shared_ptr<table>> array_;
const bool is_inline_ = false;
};
inline std::shared_ptr<table_array> make_table_array(bool is_inline)
inline std::shared_ptr<table_array> make_table_array()
{
struct make_shared_enabler : public table_array
{
make_shared_enabler(bool mse_is_inline) : table_array(mse_is_inline)
make_shared_enabler()
{
// nothing
}
};
return std::make_shared<make_shared_enabler>(is_inline);
return std::make_shared<make_shared_enabler>();
}
namespace detail
{
template <>
inline std::shared_ptr<table_array> make_element<table_array>()
{
return make_table_array(true);
return make_table_array();
}
} // namespace detail
// The below are overloads for fetching specific value types out of a value
// where special casting behavior (like bounds checking) is desired
@@ -1701,14 +1679,11 @@ std::shared_ptr<table> make_table()
return std::make_shared<make_shared_enabler>();
}
namespace detail
{
template <>
inline std::shared_ptr<table> make_element<table>()
{
return make_table();
}
} // namespace detail
template <class T>
std::shared_ptr<base> value<T>::clone() const
@@ -1727,7 +1702,7 @@ inline std::shared_ptr<base> array::clone() const
inline std::shared_ptr<base> table_array::clone() const
{
auto result = make_table_array(is_inline());
auto result = make_table_array();
result->reserve(array_.size());
for (const auto& ptr : array_)
result->array_.push_back(ptr->clone()->as_table());
@@ -1763,11 +1738,6 @@ inline bool is_number(char c)
return c >= '0' && c <= '9';
}
inline bool is_hex(char c)
{
return is_number(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
/**
* Helper object for consuming expected characters.
*/
@@ -1796,13 +1766,6 @@ class consumer
[&](char c) { (*this)(c); });
}
void eat_or(char a, char b)
{
if (it_ == end_ || (*it_ != a && *it_ != b))
on_error_();
++it_;
}
int eat_digits(int len)
{
int val = 0;
@@ -1867,7 +1830,7 @@ inline std::istream& getline(std::istream& input, std::string& line)
line.push_back(static_cast<char>(c));
}
}
} // namespace detail
}
/**
* The parser class.
@@ -1951,25 +1914,21 @@ class parser
std::string full_table_name;
bool inserted = false;
while (it != end && *it != ']')
{
auto part = parse_key(it, end,
[](char c) { return c == '.' || c == ']'; });
auto key_end = [](char c) { return c == ']'; };
auto key_part_handler = [&](const std::string& part) {
if (part.empty())
throw_parse_exception("Empty component of table name");
if (!full_table_name.empty())
full_table_name += '.';
full_table_name += ".";
full_table_name += part;
if (curr_table->contains(part))
{
#if !defined(__PGI)
auto b = curr_table->get(part);
#else
// Workaround for PGI compiler
std::shared_ptr<base> b = curr_table->get(part);
#endif
if (b->is_table())
curr_table = static_cast<table*>(b.get());
else if (b->is_table_array())
@@ -1987,23 +1946,16 @@ class parser
curr_table->insert(part, make_table());
curr_table = static_cast<table*>(curr_table->get(part).get());
}
};
key_part_handler(parse_key(it, end, key_end, key_part_handler));
consume_whitespace(it, end);
if (it != end && *it == '.')
++it;
consume_whitespace(it, end);
}
if (it == end)
throw_parse_exception(
"Unterminated table declaration; did you forget a ']'?");
if (*it != ']')
{
std::string errmsg{"Unexpected character in table definition: "};
errmsg += '"';
errmsg += *it;
errmsg += '"';
throw_parse_exception(errmsg);
}
// table already existed
if (!inserted)
{
@@ -2017,9 +1969,8 @@ class parser
// since it has already been defined. If there aren't any
// values, then it was implicitly created by something like
// [a.b]
if (curr_table->empty()
|| std::any_of(curr_table->begin(), curr_table->end(),
is_value))
if (curr_table->empty() || std::any_of(curr_table->begin(),
curr_table->end(), is_value))
{
throw_parse_exception("Redefinition of table "
+ full_table_name);
@@ -2038,45 +1989,36 @@ class parser
if (it == end || *it == ']')
throw_parse_exception("Table array name cannot be empty");
auto key_end = [](char c) { return c == ']'; };
std::string full_ta_name;
auto key_part_handler = [&](const std::string& part) {
while (it != end && *it != ']')
{
auto part = parse_key(it, end,
[](char c) { return c == '.' || c == ']'; });
if (part.empty())
throw_parse_exception("Empty component of table array name");
if (!full_ta_name.empty())
full_ta_name += '.';
full_ta_name += ".";
full_ta_name += part;
consume_whitespace(it, end);
if (it != end && *it == '.')
++it;
consume_whitespace(it, end);
if (curr_table->contains(part))
{
#if !defined(__PGI)
auto b = curr_table->get(part);
#else
// Workaround for PGI compiler
std::shared_ptr<base> b = curr_table->get(part);
#endif
// if this is the end of the table array name, add an
// element to the table array that we just looked up,
// provided it was not declared inline
// element to the table array that we just looked up
if (it != end && *it == ']')
{
if (!b->is_table_array())
{
throw_parse_exception("Key " + full_ta_name
+ " is not a table array");
}
auto v = b->as_table_array();
if (v->is_inline())
{
throw_parse_exception("Static array " + full_ta_name
+ " cannot be appended to");
}
v->get().push_back(make_table());
curr_table = v->get().back().get();
}
@@ -2117,16 +2059,15 @@ class parser
= static_cast<table*>(curr_table->get(part).get());
}
}
};
key_part_handler(parse_key(it, end, key_end, key_part_handler));
}
// consume the last "]]"
auto eat = make_consumer(it, end, [this]() {
if (it == end)
throw_parse_exception("Unterminated table array name");
});
eat(']');
eat(']');
++it;
if (it == end)
throw_parse_exception("Unterminated table array name");
++it;
consume_whitespace(it, end);
eol_or_comment(it, end);
@@ -2135,35 +2076,7 @@ class parser
void parse_key_value(std::string::iterator& it, std::string::iterator& end,
table* curr_table)
{
auto key_end = [](char c) { return c == '='; };
auto key_part_handler = [&](const std::string& part) {
// two cases: this key part exists already, in which case it must
// be a table, or it doesn't exist in which case we must create
// an implicitly defined table
if (curr_table->contains(part))
{
auto val = curr_table->get(part);
if (val->is_table())
{
curr_table = static_cast<table*>(val.get());
}
else
{
throw_parse_exception("Key " + part
+ " already exists as a value");
}
}
else
{
auto newtable = make_table();
curr_table->insert(part, newtable);
curr_table = newtable.get();
}
};
auto key = parse_key(it, end, key_end, key_part_handler);
auto key = parse_key(it, end, [](char c) { return c == '='; });
if (curr_table->contains(key))
throw_parse_exception("Key " + key + " already present");
if (it == end || *it != '=')
@@ -2174,57 +2087,18 @@ class parser
consume_whitespace(it, end);
}
template <class KeyEndFinder, class KeyPartHandler>
std::string
parse_key(std::string::iterator& it, const std::string::iterator& end,
KeyEndFinder&& key_end, KeyPartHandler&& key_part_handler)
{
// parse the key as a series of one or more simple-keys joined with '.'
while (it != end && !key_end(*it))
{
auto part = parse_simple_key(it, end);
consume_whitespace(it, end);
if (it == end || key_end(*it))
{
return part;
}
if (*it != '.')
{
std::string errmsg{"Unexpected character in key: "};
errmsg += '"';
errmsg += *it;
errmsg += '"';
throw_parse_exception(errmsg);
}
key_part_handler(part);
// consume the dot
++it;
}
throw_parse_exception("Unexpected end of key");
}
std::string parse_simple_key(std::string::iterator& it,
const std::string::iterator& end)
template <class Function>
std::string parse_key(std::string::iterator& it,
const std::string::iterator& end, Function&& fun)
{
consume_whitespace(it, end);
if (it == end)
throw_parse_exception("Unexpected end of key (blank key?)");
if (*it == '"' || *it == '\'')
if (*it == '"')
{
return string_literal(it, end, *it);
return parse_quoted_key(it, end);
}
else
{
auto bke = std::find_if(it, end, [](char c) {
return c == '.' || c == '=' || c == ']';
});
auto bke = std::find_if(it, end, std::forward<Function>(fun));
return parse_bare_key(it, bke);
}
}
@@ -2268,6 +2142,12 @@ class parser
return key;
}
std::string parse_quoted_key(std::string::iterator& it,
const std::string::iterator& end)
{
return string_literal(it, end, '"');
}
enum class parse_type
{
STRING = 1,
@@ -2313,7 +2193,7 @@ class parser
parse_type determine_value_type(const std::string::iterator& it,
const std::string::iterator& end)
{
if (it == end)
if(it == end)
{
throw_parse_exception("Failed to parse value type");
}
@@ -2329,11 +2209,7 @@ class parser
{
return *dtype;
}
else if (is_number(*it) || *it == '-' || *it == '+'
|| (*it == 'i' && it + 1 != end && it[1] == 'n'
&& it + 2 != end && it[2] == 'f')
|| (*it == 'n' && it + 1 != end && it[1] == 'a'
&& it + 2 != end && it[2] == 'n'))
else if (is_number(*it) || *it == '-' || *it == '+')
{
return determine_number_type(it, end);
}
@@ -2359,13 +2235,6 @@ class parser
auto check_it = it;
if (*check_it == '-' || *check_it == '+')
++check_it;
if (check_it == end)
throw_parse_exception("Malformed number");
if (*check_it == 'i' || *check_it == 'n')
return parse_type::FLOAT;
while (check_it != end && is_number(*check_it))
++check_it;
if (check_it != end && *check_it == '.')
@@ -2414,56 +2283,57 @@ class parser
bool consuming = false;
std::shared_ptr<value<std::string>> ret;
auto handle_line = [&](std::string::iterator& local_it,
std::string::iterator& local_end) {
if (consuming)
{
local_it = std::find_if_not(local_it, local_end, is_ws);
auto handle_line
= [&](std::string::iterator& local_it,
std::string::iterator& local_end) {
if (consuming)
{
local_it = std::find_if_not(local_it, local_end, is_ws);
// whole line is whitespace
if (local_it == local_end)
return;
}
// whole line is whitespace
if (local_it == local_end)
return;
}
consuming = false;
consuming = false;
while (local_it != local_end)
{
// handle escaped characters
if (delim == '"' && *local_it == '\\')
{
auto check = local_it;
// check if this is an actual escape sequence or a
// whitespace escaping backslash
++check;
consume_whitespace(check, local_end);
if (check == local_end)
{
consuming = true;
break;
}
while (local_it != local_end)
{
// handle escaped characters
if (delim == '"' && *local_it == '\\')
{
auto check = local_it;
// check if this is an actual escape sequence or a
// whitespace escaping backslash
++check;
consume_whitespace(check, local_end);
if (check == local_end)
{
consuming = true;
break;
}
ss << parse_escape_code(local_it, local_end);
continue;
}
ss << parse_escape_code(local_it, local_end);
continue;
}
// if we can end the string
if (std::distance(local_it, local_end) >= 3)
{
auto check = local_it;
// check for """
if (*check++ == delim && *check++ == delim
&& *check++ == delim)
{
local_it = check;
ret = make_value<std::string>(ss.str());
break;
}
}
// if we can end the string
if (std::distance(local_it, local_end) >= 3)
{
auto check = local_it;
// check for """
if (*check++ == delim && *check++ == delim
&& *check++ == delim)
{
local_it = check;
ret = make_value<std::string>(ss.str());
break;
}
}
ss << *local_it++;
}
};
ss << *local_it++;
}
};
// handle the remainder of the current line
handle_line(it, end);
@@ -2644,13 +2514,17 @@ class parser
return value;
}
bool is_hex(char c)
{
return is_number(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
uint32_t hex_to_digit(char c)
{
if (is_number(c))
return static_cast<uint32_t>(c - '0');
return 10
+ static_cast<uint32_t>(c
- ((c >= 'a' && c <= 'f') ? 'a' : 'A'));
return 10 + static_cast<uint32_t>(
c - ((c >= 'a' && c <= 'f') ? 'a' : 'A'));
}
std::shared_ptr<base> parse_number(std::string::iterator& it,
@@ -2664,23 +2538,17 @@ class parser
++check_it;
};
auto check_no_leading_zero = [&]() {
if (check_it != end && *check_it == '0' && check_it + 1 != check_end
&& check_it[1] != '.')
{
throw_parse_exception("Numbers may not have leading zeros");
}
};
eat_sign();
auto eat_digits = [&](bool (*check_char)(char)) {
auto eat_numbers = [&]() {
auto beg = check_it;
while (check_it != end && check_char(*check_it))
while (check_it != end && is_number(*check_it))
{
++check_it;
if (check_it != end && *check_it == '_')
{
++check_it;
if (check_it == end || !check_char(*check_it))
if (check_it == end || !is_number(*check_it))
throw_parse_exception("Malformed number");
}
}
@@ -2689,63 +2557,15 @@ class parser
throw_parse_exception("Malformed number");
};
auto eat_hex = [&]() { eat_digits(&is_hex); };
auto eat_numbers = [&]() { eat_digits(&is_number); };
if (check_it != end && *check_it == '0' && check_it + 1 != check_end
&& (check_it[1] == 'x' || check_it[1] == 'o' || check_it[1] == 'b'))
{
++check_it;
char base = *check_it;
++check_it;
if (base == 'x')
auto check_no_leading_zero = [&]() {
if (check_it != end && *check_it == '0' && check_it + 1 != check_end
&& check_it[1] != '.')
{
eat_hex();
return parse_int(it, check_it, 16);
throw_parse_exception("Numbers may not have leading zeros");
}
else if (base == 'o')
{
auto start = check_it;
eat_numbers();
auto val = parse_int(start, check_it, 8, "0");
it = start;
return val;
}
else // if (base == 'b')
{
auto start = check_it;
eat_numbers();
auto val = parse_int(start, check_it, 2);
it = start;
return val;
}
}
};
eat_sign();
check_no_leading_zero();
if (check_it != end && check_it + 1 != end && check_it + 2 != end)
{
if (check_it[0] == 'i' && check_it[1] == 'n' && check_it[2] == 'f')
{
auto val = std::numeric_limits<double>::infinity();
if (*it == '-')
val = -val;
it = check_it + 3;
return make_value(val);
}
else if (check_it[0] == 'n' && check_it[1] == 'a'
&& check_it[2] == 'n')
{
auto val = std::numeric_limits<double>::quiet_NaN();
if (*it == '-')
val = -val;
it = check_it + 3;
return make_value(val);
}
}
eat_numbers();
if (check_it != end
@@ -2784,17 +2604,14 @@ class parser
}
std::shared_ptr<value<int64_t>> parse_int(std::string::iterator& it,
const std::string::iterator& end,
int base = 10,
const char* prefix = "")
const std::string::iterator& end)
{
std::string v{it, end};
v = prefix + v;
v.erase(std::remove(v.begin(), v.end(), '_'), v.end());
it = end;
try
{
return make_value<int64_t>(std::stoll(v, nullptr, base));
return make_value<int64_t>(std::stoll(v));
}
catch (const std::invalid_argument& ex)
{
@@ -2857,33 +2674,18 @@ class parser
std::string::iterator find_end_of_number(std::string::iterator it,
std::string::iterator end)
{
auto ret = std::find_if(it, end, [](char c) {
return std::find_if(it, end, [](char c) {
return !is_number(c) && c != '_' && c != '.' && c != 'e' && c != 'E'
&& c != '-' && c != '+' && c != 'x' && c != 'o' && c != 'b';
&& c != '-' && c != '+';
});
if (ret != end && ret + 1 != end && ret + 2 != end)
{
if ((ret[0] == 'i' && ret[1] == 'n' && ret[2] == 'f')
|| (ret[0] == 'n' && ret[1] == 'a' && ret[2] == 'n'))
{
ret = ret + 3;
}
}
return ret;
}
std::string::iterator find_end_of_date(std::string::iterator it,
std::string::iterator end)
{
auto end_of_date = std::find_if(it, end, [](char c) {
return !is_number(c) && c != '-';
});
if (end_of_date != end && *end_of_date == ' ' && end_of_date + 1 != end
&& is_number(end_of_date[1]))
end_of_date++;
return std::find_if(end_of_date, end, [](char c) {
return !is_number(c) && c != 'T' && c != 'Z' && c != ':'
&& c != '-' && c != '+' && c != '.';
return std::find_if(it, end, [](char c) {
return !is_number(c) && c != 'T' && c != 'Z' && c != ':' && c != '-'
&& c != '+' && c != '.';
});
}
@@ -2952,7 +2754,7 @@ class parser
if (it == date_end)
return make_value(ldate);
eat.eat_or('T', ' ');
eat('T');
local_datetime ldt;
static_cast<local_date&>(ldt) = ldate;
@@ -3048,9 +2850,9 @@ class parser
auto arr = make_array();
while (it != end && *it != ']')
{
auto val = parse_value(it, end);
if (auto v = val->as<Value>())
arr->get().push_back(val);
auto value = parse_value(it, end);
if (auto v = value->as<Value>())
arr->get().push_back(value);
else
throw_parse_exception("Arrays must be homogeneous");
skip_whitespace_and_comments(it, end);
@@ -3069,7 +2871,7 @@ class parser
std::string::iterator& it,
std::string::iterator& end)
{
auto arr = detail::make_element<Object>();
auto arr = make_element<Object>();
while (it != end && *it != ']')
{
@@ -3079,7 +2881,7 @@ class parser
arr->get().push_back(((*this).*fun)(it, end));
skip_whitespace_and_comments(it, end);
if (it == end || *it != ',')
if (*it != ',')
break;
++it;
@@ -3104,11 +2906,8 @@ class parser
throw_parse_exception("Unterminated inline table");
consume_whitespace(it, end);
if (it != end && *it != '}')
{
parse_key_value(it, end, tbl.get());
consume_whitespace(it, end);
}
parse_key_value(it, end, tbl.get());
consume_whitespace(it, end);
} while (*it == ',');
if (it == end || *it != '}')
@@ -3188,8 +2987,7 @@ class parser
if (it[4] != '-' || it[7] != '-')
return {};
if (len >= 19 && (it[10] == 'T' || it[10] == ' ')
&& is_time(it + 11, date_end))
if (len >= 19 && it[10] == 'T' && is_time(it + 11, date_end))
{
// datetime type
auto time_end = find_end_of_time(it + 11, date_end);
@@ -3445,7 +3243,7 @@ class toml_writer
{
res += "\\\\";
}
else if (static_cast<uint32_t>(*it) <= UINT32_C(0x001f))
else if ((const uint32_t)*it <= 0x001f)
{
res += "\\u";
std::stringstream ss;
@@ -3476,21 +3274,12 @@ class toml_writer
*/
void write(const value<double>& v)
{
std::stringstream ss;
ss << std::showpoint
<< std::setprecision(std::numeric_limits<double>::max_digits10)
<< v.get();
std::ios::fmtflags flags{stream_.flags()};
auto double_str = ss.str();
auto pos = double_str.find("e0");
if (pos != std::string::npos)
double_str.replace(pos, 2, "e");
pos = double_str.find("e-0");
if (pos != std::string::npos)
double_str.replace(pos, 3, "e-");
stream_ << std::showpoint;
write(v.get());
stream_ << double_str;
has_naked_endline_ = false;
stream_.flags(flags);
}
/**
@@ -3498,9 +3287,9 @@ class toml_writer
* offset_datetime.
*/
template <class T>
typename std::enable_if<
is_one_of<T, int64_t, local_date, local_time, local_datetime,
offset_datetime>::value>::type
typename std::enable_if<is_one_of<T, int64_t, local_date, local_time,
local_datetime,
offset_datetime>::value>::type
write(const value<T>& v)
{
write(v.get());
@@ -3664,5 +3453,5 @@ inline std::ostream& operator<<(std::ostream& stream, const array& a)
a.accept(writer);
return stream;
}
} // namespace cpptoml
#endif // CPPTOML_H
}
#endif

View File

@@ -45,11 +45,9 @@ Bindings * MixEvalArgs::getAutoArgs(EvalState & state)
Path lookupFileArg(EvalState & state, string s)
{
if (isUri(s)) {
CachedDownloadRequest request(s);
request.unpack = true;
return getDownloader()->downloadCached(state.store, request).path;
} else if (s.size() > 2 && s.at(0) == '<' && s.at(s.size() - 1) == '>') {
if (isUri(s))
return getDownloader()->downloadCached(state.store, s, true);
else if (s.size() > 2 && s.at(0) == '<' && s.at(s.size() - 1) == '>') {
Path p = s.substr(1, s.size() - 2);
return state.findFile(p);
} else

View File

@@ -7,10 +7,8 @@
#include "eval-inline.hh"
#include "download.hh"
#include "json.hh"
#include "function-trace.hh"
#include <algorithm>
#include <chrono>
#include <cstring>
#include <unistd.h>
#include <sys/time.h>
@@ -18,6 +16,7 @@
#include <iostream>
#include <fstream>
#include <sys/time.h>
#include <sys/resource.h>
#if HAVE_BOEHMGC
@@ -520,9 +519,9 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s, const ExprLambda & fun
throw TypeError(format(s) % fun.showNamePos() % s2 % pos);
}
LocalNoInlineNoReturn(void throwAssertionError(const char * s, const string & s1, const Pos & pos))
LocalNoInlineNoReturn(void throwAssertionError(const char * s, const Pos & pos))
{
throw AssertionError(format(s) % s1 % pos);
throw AssertionError(format(s) % pos);
}
LocalNoInlineNoReturn(void throwUndefinedVarError(const char * s, const string & s1, const Pos & pos))
@@ -878,7 +877,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
if (hasOverrides) {
Value * vOverrides = (*v.attrs)[overrides->second.displ].value;
state.forceAttrs(*vOverrides);
Bindings * newBnds = state.allocBindings(v.attrs->capacity() + vOverrides->attrs->size());
Bindings * newBnds = state.allocBindings(v.attrs->size() + vOverrides->attrs->size());
for (auto & i : *v.attrs)
newBnds->push_back(i);
for (auto & i : *vOverrides->attrs) {
@@ -1095,10 +1094,9 @@ void EvalState::callPrimOp(Value & fun, Value & arg, Value & v, const Pos & pos)
}
}
void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & pos)
{
auto trace = evalSettings.traceFunctionCalls ? std::make_unique<FunctionCallTrace>(pos) : nullptr;
forceValue(fun, pos);
if (fun.type == tPrimOp || fun.type == tPrimOpApp) {
@@ -1253,11 +1251,8 @@ void ExprIf::eval(EvalState & state, Env & env, Value & v)
void ExprAssert::eval(EvalState & state, Env & env, Value & v)
{
if (!state.evalBool(env, cond, pos)) {
std::ostringstream out;
cond->show(out);
throwAssertionError("assertion %1% failed at %2%", out.str(), pos);
}
if (!state.evalBool(env, cond, pos))
throwAssertionError("assertion failed at %1%", pos);
body->eval(state, env, v);
}
@@ -1570,19 +1565,6 @@ bool EvalState::isDerivation(Value & v)
}
std::optional<string> EvalState::tryAttrsToString(const Pos & pos, Value & v,
PathSet & context, bool coerceMore, bool copyToStore)
{
auto i = v.attrs->find(sToString);
if (i != v.attrs->end()) {
Value v1;
callFunction(*i->value, v, v1, pos);
return coerceToString(pos, v1, context, coerceMore, copyToStore);
}
return {};
}
string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
bool coerceMore, bool copyToStore)
{
@@ -1601,11 +1583,13 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
}
if (v.type == tAttrs) {
auto maybeString = tryAttrsToString(pos, v, context, coerceMore, copyToStore);
if (maybeString) {
return *maybeString;
auto i = v.attrs->find(sToString);
if (i != v.attrs->end()) {
Value v1;
callFunction(*i->value, v, v1, pos);
return coerceToString(pos, v1, context, coerceMore, copyToStore);
}
auto i = v.attrs->find(sOutPath);
i = v.attrs->find(sOutPath);
if (i == v.attrs->end()) throwTypeError("cannot coerce a set to a string, at %1%", pos);
return coerceToString(pos, *i->value, context, coerceMore, copyToStore);
}

View File

@@ -8,7 +8,6 @@
#include "config.hh"
#include <map>
#include <optional>
#include <unordered_map>
@@ -196,9 +195,6 @@ public:
set with attribute `type = "derivation"'). */
bool isDerivation(Value & v);
std::optional<string> tryAttrsToString(const Pos & pos, Value & v,
PathSet & context, bool coerceMore = false, bool copyToStore = true);
/* String coercion. Converts strings, paths and derivations to a
string. If `coerceMore' is set, also converts nulls, integers,
booleans and lists to a string. If `copyToStore' is set,
@@ -353,9 +349,6 @@ struct EvalSettings : Config
Setting<Strings> allowedUris{this, {}, "allowed-uris",
"Prefixes of URIs that builtin functions such as fetchurl and fetchGit are allowed to fetch."};
Setting<bool> traceFunctionCalls{this, false, "trace-function-calls",
"Emit log messages for each function entry and exit at the 'vomit' log level (-vvvv)"};
};
extern EvalSettings evalSettings;

View File

@@ -1,17 +0,0 @@
#include "function-trace.hh"
namespace nix {
FunctionCallTrace::FunctionCallTrace(const Pos & pos) : pos(pos) {
auto duration = std::chrono::high_resolution_clock::now().time_since_epoch();
auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(duration);
printMsg(lvlInfo, "function-trace entered %1% at %2%", pos, ns.count());
}
FunctionCallTrace::~FunctionCallTrace() {
auto duration = std::chrono::high_resolution_clock::now().time_since_epoch();
auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(duration);
printMsg(lvlInfo, "function-trace exited %1% at %2%", pos, ns.count());
}
}

View File

@@ -1,15 +0,0 @@
#pragma once
#include "eval.hh"
#include <chrono>
namespace nix {
struct FunctionCallTrace
{
const Pos & pos;
FunctionCallTrace(const Pos & pos);
~FunctionCallTrace();
};
}

View File

@@ -111,9 +111,9 @@ static void parseJSON(EvalState & state, const char * & s, Value & v)
mkFloat(v, stod(tmp_number));
else
mkInt(v, stol(tmp_number));
} catch (std::invalid_argument & e) {
} catch (std::invalid_argument e) {
throw JSONParseError("invalid JSON number");
} catch (std::out_of_range & e) {
} catch (std::out_of_range e) {
throw JSONParseError("out-of-range JSON number");
}
}

View File

@@ -81,8 +81,6 @@ static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
AttrPath::iterator i;
// All attrpaths have at least one attr
assert(!attrPath.empty());
// Checking attrPath validity.
// ===========================
for (i = attrPath.begin(); i + 1 < attrPath.end(); i++) {
if (i->symbol.set()) {
ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(i->symbol);
@@ -104,29 +102,11 @@ static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
attrs = nested;
}
}
// Expr insertion.
// ==========================
if (i->symbol.set()) {
ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(i->symbol);
if (j != attrs->attrs.end()) {
// This attr path is already defined. However, if both
// e and the expr pointed by the attr path are two attribute sets,
// we want to merge them.
// Otherwise, throw an error.
auto ae = dynamic_cast<ExprAttrs *>(e);
auto jAttrs = dynamic_cast<ExprAttrs *>(j->second.e);
if (jAttrs && ae) {
for (auto & ad : ae->attrs) {
auto j2 = jAttrs->attrs.find(ad.first);
if (j2 != jAttrs->attrs.end()) // Attr already defined in iAttrs, error.
dupAttr(ad.first, j2->second.pos, ad.second.pos);
jAttrs->attrs[ad.first] = ad.second;
}
} else {
dupAttr(attrPath, pos, j->second.pos);
}
dupAttr(attrPath, pos, j->second.pos);
} else {
// This attr path is not defined. Let's create it.
attrs->attrs[i->symbol] = ExprAttrs::AttrDef(e, pos);
e->setName(i->symbol);
}
@@ -677,9 +657,7 @@ std::pair<bool, std::string> EvalState::resolveSearchPathElem(const SearchPathEl
if (isUri(elem.second)) {
try {
CachedDownloadRequest request(elem.second);
request.unpack = true;
res = { true, getDownloader()->downloadCached(store, request).path };
res = { true, getDownloader()->downloadCached(store, elem.second, true) };
} catch (DownloadError & e) {
printError(format("warning: Nix search path entry '%1%' cannot be downloaded, ignoring") % elem.second);
res = { false, "" };

View File

@@ -341,6 +341,8 @@ struct CompareValues
return strcmp(v1->string.s, v2->string.s) < 0;
case tPath:
return strcmp(v1->path, v2->path) < 0;
case tAttrs:
return v1 < v2; // FIXME
default:
throw EvalError(format("cannot compare %1% with %2%") % showType(*v1) % showType(*v2));
}
@@ -832,14 +834,8 @@ static void prim_pathExists(EvalState & state, const Pos & pos, Value * * args,
{
PathSet context;
Path path = state.coerceToPath(pos, *args[0], context);
try {
state.realiseContext(context);
} catch (InvalidPathError & e) {
throw EvalError(format(
"cannot check the existence of '%1%', since path '%2%' is not valid, at %3%")
% path % e.path % pos);
}
if (!context.empty())
throw EvalError(format("string '%1%' cannot refer to other paths, at %2%") % path % pos);
try {
mkBool(v, pathExists(state.checkSourcePath(path)));
} catch (SysError & e) {
@@ -929,20 +925,6 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
mkPath(v, state.checkSourcePath(state.findFile(searchPath, path, pos)).c_str());
}
/* Return the cryptographic hash of a file in base-16. */
static void prim_hashFile(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
string type = state.forceStringNoCtx(*args[0], pos);
HashType ht = parseHashType(type);
if (ht == htUnknown)
throw Error(format("unknown hash type '%1%', at %2%") % type % pos);
PathSet context; // discarded
Path p = state.coerceToPath(pos, *args[1], context);
mkString(v, hashFile(ht, state.checkSourcePath(p)).to_string(Base16, false), context);
}
/* Read a directory (without . or ..) */
static void prim_readDir(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
@@ -1596,7 +1578,6 @@ static void prim_sort(EvalState & state, const Pos & pos, Value * * args, Value
v.listElems()[n] = args[1]->listElems()[n];
}
auto comparator = [&](Value * a, Value * b) {
/* Optimization: if the comparator is lessThan, bypass
callFunction. */
@@ -1616,6 +1597,62 @@ static void prim_sort(EvalState & state, const Pos & pos, Value * * args, Value
}
static void prim_unique(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceFunction(*args[0], pos);
state.forceList(*args[1], pos);
auto len = args[1]->listSize();
Value * vs[len];
for (size_t n = 0; n < len; ++n) {
auto v2 = args[1]->listElems()[n];
state.forceValue(*v2);
vs[n] = v2;
}
auto comparator = [&](Value * a, Value * b) {
/* Optimization: if the comparator is lessThan, bypass
callFunction. */
if (args[0]->type == tPrimOp && args[0]->primOp->fun == prim_lessThan)
return CompareValues()(a, b);
Value vTmp1, vTmp2;
state.callFunction(*args[0], *a, vTmp1, pos);
state.callFunction(vTmp1, *b, vTmp2, pos);
return state.forceBool(vTmp2, pos);
};
std::sort(vs, vs + len, comparator);
auto outLen = std::min((size_t) 1, len);
for (size_t n = 1; n < len; n++) {
if (comparator(vs[outLen - 1], vs[n])) {
vs[outLen++] = vs[n];
}
}
std::sort(vs, vs + outLen);
state.mkList(v, outLen);
size_t outPos = 0;
for (size_t n = 0; n < len; n++) {
auto v2 = args[1]->listElems()[n];
auto i = std::lower_bound(vs, vs + outLen, v2);
if (*i == v2) {
// Remove v2 from the set by setting its least significant
// bit. (This doesn't change the sort order.)
*i = (Value *) (((ptrdiff_t) v2) | 1);
assert(outPos < outLen);
v.listElems()[outPos++] = v2;
}
}
assert(outPos == outLen);
}
static void prim_partition(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceFunction(*args[0], pos);
@@ -2056,9 +2093,9 @@ static void prim_splitVersion(EvalState & state, const Pos & pos, Value * * args
void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
const string & who, bool unpack, const std::string & defaultName)
{
CachedDownloadRequest request("");
request.unpack = unpack;
request.name = defaultName;
string url;
Hash expectedHash;
string name = defaultName;
state.forceValue(*args[0]);
@@ -2069,32 +2106,32 @@ void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
for (auto & attr : *args[0]->attrs) {
string n(attr.name);
if (n == "url")
request.uri = state.forceStringNoCtx(*attr.value, *attr.pos);
url = state.forceStringNoCtx(*attr.value, *attr.pos);
else if (n == "sha256")
request.expectedHash = Hash(state.forceStringNoCtx(*attr.value, *attr.pos), htSHA256);
expectedHash = Hash(state.forceStringNoCtx(*attr.value, *attr.pos), htSHA256);
else if (n == "name")
request.name = state.forceStringNoCtx(*attr.value, *attr.pos);
name = state.forceStringNoCtx(*attr.value, *attr.pos);
else
throw EvalError(format("unsupported argument '%1%' to '%2%', at %3%") % attr.name % who % attr.pos);
}
if (request.uri.empty())
if (url.empty())
throw EvalError(format("'url' argument required, at %1%") % pos);
} else
request.uri = state.forceStringNoCtx(*args[0], pos);
url = state.forceStringNoCtx(*args[0], pos);
state.checkURI(request.uri);
state.checkURI(url);
if (evalSettings.pureEval && !request.expectedHash)
if (evalSettings.pureEval && !expectedHash)
throw Error("in pure evaluation mode, '%s' requires a 'sha256' argument", who);
auto res = getDownloader()->downloadCached(state.store, request);
Path res = getDownloader()->downloadCached(state.store, url, unpack, name, expectedHash);
if (state.allowedPaths)
state.allowedPaths->insert(res.path);
state.allowedPaths->insert(res);
mkString(v, res.storePath, PathSet({res.storePath}));
mkString(v, res, PathSet({res}));
}
@@ -2222,7 +2259,6 @@ void EvalState::createBaseEnv()
addPrimOp("__readFile", 1, prim_readFile);
addPrimOp("__readDir", 1, prim_readDir);
addPrimOp("__findFile", 2, prim_findFile);
addPrimOp("__hashFile", 2, prim_hashFile);
// Creating files
addPrimOp("__toXML", 1, prim_toXML);
@@ -2261,6 +2297,7 @@ void EvalState::createBaseEnv()
addPrimOp("__all", 2, prim_all);
addPrimOp("__genList", 2, prim_genList);
addPrimOp("__sort", 2, prim_sort);
addPrimOp("__unique", 2, prim_unique);
addPrimOp("__partition", 2, prim_partition);
addPrimOp("__concatMap", 2, prim_concatMap);

View File

@@ -38,7 +38,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,
try {
runProgram("git", true, { "-C", uri, "diff-index", "--quiet", "HEAD", "--" });
} catch (ExecError & e) {
} catch (ExecError e) {
if (!WIFEXITED(e.status) || WEXITSTATUS(e.status) != 1) throw;
clean = false;
}
@@ -94,11 +94,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,
runProgram("git", true, { "init", "--bare", cacheDir });
}
Path localRefFile;
if (ref->compare(0, 5, "refs/") == 0)
localRefFile = cacheDir + "/" + *ref;
else
localRefFile = cacheDir + "/refs/heads/" + *ref;
Path localRefFile = cacheDir + "/refs/heads/" + *ref;
bool doFetch;
time_t now = time(0);
@@ -120,7 +116,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,
git fetch to update the local ref to the remote ref. */
struct stat st;
doFetch = stat(localRefFile.c_str(), &st) != 0 ||
(uint64_t) st.st_mtime + settings.tarballTtl <= (uint64_t) now;
st.st_mtime + settings.tarballTtl <= now;
}
if (doFetch)
{
@@ -239,7 +235,7 @@ static void prim_fetchGit(EvalState & state, const Pos & pos, Value * * args, Va
v.attrs->sort();
if (state.allowedPaths)
state.allowedPaths->insert(state.store->toRealPath(gitInfo.storePath));
state.allowedPaths->insert(gitInfo.storePath);
}
static RegisterPrimOp r("fetchGit", 1, prim_fetchGit);

View File

@@ -80,7 +80,7 @@ HgInfo exportMercurial(ref<Store> store, const std::string & uri,
time_t now = time(0);
struct stat st;
if (stat(stampFile.c_str(), &st) != 0 ||
(uint64_t) st.st_mtime + settings.tarballTtl <= (uint64_t) now)
st.st_mtime + settings.tarballTtl <= now)
{
/* Except that if this is a commit hash that we already have,
we don't have to pull again. */
@@ -96,14 +96,17 @@ HgInfo exportMercurial(ref<Store> store, const std::string & uri,
try {
runProgram("hg", true, { "pull", "-R", cacheDir, "--", uri });
}
catch (ExecError & e) {
catch (ExecError & e){
string transJournal = cacheDir + "/.hg/store/journal";
/* hg throws "abandoned transaction" error only if this file exists */
if (pathExists(transJournal)) {
if (pathExists(transJournal))
{
runProgram("hg", true, { "recover", "-R", cacheDir });
runProgram("hg", true, { "pull", "-R", cacheDir, "--", uri });
} else {
throw ExecError(e.status, fmt("'hg pull' %s", statusToString(e.status)));
}
else
{
throw ExecError(e.status, fmt("program hg '%1%' ", statusToString(e.status)));
}
}
} else {
@@ -211,7 +214,7 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar
v.attrs->sort();
if (state.allowedPaths)
state.allowedPaths->insert(state.store->toRealPath(hgInfo.storePath));
state.allowedPaths->insert(hgInfo.storePath);
}
static RegisterPrimOp r("fetchMercurial", 1, prim_fetchMercurial);

View File

@@ -49,19 +49,6 @@ static void prim_fromTOML(EvalState & state, const Pos & pos, Value * * args, Va
visit(*(v.listElems()[i] = state.allocValue()), t2->get()[i]);
}
// Handle cases like 'a = [[{ a = true }]]', which IMHO should be
// parsed as a array containing an array containing a table,
// but instead are parsed as an array containing a table array
// containing a table.
else if (auto t2 = t->as_table_array()) {
size_t size = t2->get().size();
state.mkList(v, size);
for (size_t j = 0; j < size; ++j)
visit(*(v.listElems()[j] = state.allocValue()), t2->get()[j]);
}
else if (t->is_value()) {
if (auto val = t->as<int64_t>())
mkInt(v, val->get());

View File

@@ -40,12 +40,7 @@ void printValueAsJSON(EvalState & state, bool strict,
break;
case tAttrs: {
auto maybeString = state.tryAttrsToString(noPos, v, context, false, false);
if (maybeString) {
out.write(*maybeString);
break;
}
auto i = v.attrs->find(state.sOutPath);
Bindings::iterator i = v.attrs->find(state.sOutPath);
if (i == v.attrs->end()) {
auto obj(out.object());
StringSet names;

View File

@@ -35,15 +35,6 @@ MixCommonArgs::MixCommonArgs(const string & programName)
}
});
mkFlag()
.longName("max-jobs")
.shortName('j')
.label("jobs")
.description("maximum number of parallel builds")
.handler([=](std::string s) {
settings.set("max-jobs", s);
});
std::string cat = "config";
globalConfig.convertToArgs(*this, cat);

View File

@@ -80,7 +80,6 @@ string getArg(const string & opt,
}
#if OPENSSL_VERSION_NUMBER < 0x10101000L
/* OpenSSL is not thread-safe by default - it will randomly crash
unless the user supplies a mutex locking function. So let's do
that. */
@@ -93,7 +92,6 @@ static void opensslLockCallback(int mode, int type, const char * file, int line)
else
opensslLocks[type].unlock();
}
#endif
static void sigHandler(int signo) { }
@@ -107,11 +105,9 @@ void initNix()
std::cerr.rdbuf()->pubsetbuf(buf, sizeof(buf));
#endif
#if OPENSSL_VERSION_NUMBER < 0x10101000L
/* Initialise OpenSSL locking. */
opensslLocks = std::vector<std::mutex>(CRYPTO_num_locks());
CRYPTO_set_locking_callback(opensslLockCallback);
#endif
loadConfFile();
@@ -129,15 +125,6 @@ void initNix()
act.sa_handler = sigHandler;
if (sigaction(SIGUSR1, &act, 0)) throw SysError("handling SIGUSR1");
#if __APPLE__
/* HACK: on darwin, we need cant use sigprocmask with SIGWINCH.
* Instead, add a dummy sigaction handler, and signalHandlerThread
* can handle the rest. */
struct sigaction sa;
sa.sa_handler = sigHandler;
if (sigaction(SIGWINCH, &sa, 0)) throw SysError("handling SIGWINCH");
#endif
/* Register a SIGSEGV handler to detect stack overflows. */
detectStackOverflow();
@@ -188,6 +175,10 @@ LegacyArgs::LegacyArgs(const std::string & programName,
.description("build from source if substitution fails")
.set(&(bool&) settings.tryFallback, true);
mkFlag1('j', "max-jobs", "jobs", "maximum number of parallel builds", [=](std::string s) {
settings.set("max-jobs", s);
});
auto intSettingAlias = [&](char shortName, const std::string & longName,
const std::string & description, const std::string & dest) {
mkFlag<unsigned int>(shortName, longName, description, [=](unsigned int n) {

View File

@@ -55,7 +55,7 @@ void BinaryCacheStore::init()
}
void BinaryCacheStore::getFile(const std::string & path,
Callback<std::shared_ptr<std::string>> callback) noexcept
Callback<std::shared_ptr<std::string>> callback)
{
try {
callback(getFile(path));
@@ -240,7 +240,7 @@ void BinaryCacheStore::narFromPath(const Path & storePath, Sink & sink)
}
void BinaryCacheStore::queryPathInfoUncached(const Path & storePath,
Callback<std::shared_ptr<ValidPathInfo>> callback) noexcept
Callback<std::shared_ptr<ValidPathInfo>> callback)
{
auto uri = getUri();
auto act = std::make_shared<Activity>(*logger, lvlTalkative, actQueryPathInfo,
@@ -249,23 +249,21 @@ void BinaryCacheStore::queryPathInfoUncached(const Path & storePath,
auto narInfoFile = narInfoFileFor(storePath);
auto callbackPtr = std::make_shared<decltype(callback)>(std::move(callback));
getFile(narInfoFile,
{[=](std::future<std::shared_ptr<std::string>> fut) {
try {
auto data = fut.get();
if (!data) return (*callbackPtr)(nullptr);
if (!data) return callback(nullptr);
stats.narInfoRead++;
(*callbackPtr)((std::shared_ptr<ValidPathInfo>)
callback((std::shared_ptr<ValidPathInfo>)
std::make_shared<NarInfo>(*this, *data, narInfoFile));
(void) act; // force Activity into this lambda to ensure it stays alive
} catch (...) {
callbackPtr->rethrow();
callback.rethrow();
}
}});
}

View File

@@ -47,7 +47,7 @@ public:
/* Fetch the specified file and call the specified callback with
the result. A subclass may implement this asynchronously. */
virtual void getFile(const std::string & path,
Callback<std::shared_ptr<std::string>> callback) noexcept;
Callback<std::shared_ptr<std::string>> callback);
std::shared_ptr<std::string> getFile(const std::string & path);
@@ -73,7 +73,7 @@ public:
bool isValidPathUncached(const Path & path) override;
void queryPathInfoUncached(const Path & path,
Callback<std::shared_ptr<ValidPathInfo>> callback) noexcept override;
Callback<std::shared_ptr<ValidPathInfo>> callback) override;
Path queryPathFromHashPart(const string & hashPart) override
{ unsupported("queryPathFromHashPart"); }

View File

@@ -38,7 +38,6 @@
#include <unistd.h>
#include <errno.h>
#include <cstring>
#include <termios.h>
#include <pwd.h>
#include <grp.h>
@@ -266,12 +265,6 @@ public:
/* Set if at least one derivation had a timeout. */
bool timedOut;
/* Set if at least one derivation fails with a hash mismatch. */
bool hashMismatch;
/* Set if at least one derivation is not deterministic in check mode. */
bool checkMismatch;
LocalStore & store;
std::unique_ptr<HookInstance> hook;
@@ -468,28 +461,6 @@ static void commonChildInit(Pipe & logPipe)
close(fdDevNull);
}
void handleDiffHook(uid_t uid, uid_t gid, Path tryA, Path tryB, Path drvPath, Path tmpDir)
{
auto diffHook = settings.diffHook;
if (diffHook != "" && settings.runDiffHook) {
try {
RunOptions diffHookOptions(diffHook,{tryA, tryB, drvPath, tmpDir});
diffHookOptions.searchPath = true;
diffHookOptions.uid = uid;
diffHookOptions.gid = gid;
diffHookOptions.chdir = "/";
auto diffRes = runProgram(diffHookOptions);
if (!statusOk(diffRes.first))
throw ExecError(diffRes.first, fmt("diff-hook program '%1%' %2%", diffHook, statusToString(diffRes.first)));
if (diffRes.second != "")
printError(chomp(diffRes.second));
} catch (Error & error) {
printError("diff hook execution failed: %s", error.what());
}
}
}
//////////////////////////////////////////////////////////////////////
@@ -911,9 +882,6 @@ public:
Worker & worker, BuildMode buildMode = bmNormal);
~DerivationGoal();
/* Whether we need to perform hash rewriting if there are valid output paths. */
bool needsHashRewrite();
void timedOut() override;
string key() override
@@ -957,9 +925,6 @@ private:
/* Fill in the environment for the builder. */
void initEnv();
/* Setup tmp dir location. */
void initTmpDir();
/* Write a JSON file containing the derivation attributes. */
void writeStructuredAttrs();
@@ -1069,17 +1034,6 @@ DerivationGoal::~DerivationGoal()
}
inline bool DerivationGoal::needsHashRewrite()
{
#if __linux__
return !useChroot;
#else
/* Darwin requires hash rewriting even when sandboxing is enabled. */
return true;
#endif
}
void DerivationGoal::killChild()
{
if (pid != -1) {
@@ -1200,7 +1154,7 @@ void DerivationGoal::haveDerivation()
/* We are first going to try to create the invalid output paths
through substitutes. If that doesn't work, we'll build
them. */
if (settings.useSubstitutes && parsedDrv->substitutesAllowed())
if (settings.useSubstitutes && drv->substitutesAllowed())
for (auto & i : invalidOutputs)
addWaitee(worker.makeSubstitutionGoal(i, buildMode == bmRepair ? Repair : NoRepair));
@@ -1568,8 +1522,8 @@ void DerivationGoal::buildDone()
if (hook) {
hook->builderOut.readSide = -1;
hook->fromHook.readSide = -1;
} else
builderOut.readSide = -1;
}
else builderOut.readSide = -1;
/* Close the log file. */
closeLogFile();
@@ -1632,61 +1586,6 @@ void DerivationGoal::buildDone()
being valid. */
registerOutputs();
if (settings.postBuildHook != "") {
Activity act(*logger, lvlInfo, actPostBuildHook,
fmt("running post-build-hook '%s'", settings.postBuildHook),
Logger::Fields{drvPath});
PushActivity pact(act.id);
auto outputPaths = drv->outputPaths();
std::map<std::string, std::string> hookEnvironment = getEnv();
hookEnvironment.emplace("DRV_PATH", drvPath);
hookEnvironment.emplace("OUT_PATHS", chomp(concatStringsSep(" ", outputPaths)));
RunOptions opts(settings.postBuildHook, {});
opts.environment = hookEnvironment;
struct LogSink : Sink {
Activity & act;
std::string currentLine;
LogSink(Activity & act) : act(act) { }
void operator() (const unsigned char * data, size_t len) override {
for (size_t i = 0; i < len; i++) {
auto c = data[i];
if (c == '\n') {
flushLine();
} else {
currentLine += c;
}
}
}
void flushLine() {
if (settings.verboseBuild) {
printError("post-build-hook: " + currentLine);
} else {
act.result(resPostBuildLogLine, currentLine);
}
currentLine.clear();
}
~LogSink() {
if (currentLine != "") {
currentLine += '\n';
flushLine();
}
}
};
LogSink sink(act);
opts.standardOut = &sink;
opts.mergeStderrToStdout = true;
runProgram2(opts);
}
if (buildMode == bmCheck) {
done(BuildResult::Built);
return;
@@ -1964,6 +1863,13 @@ void DerivationGoal::startBuilder()
auto drvName = storePathToName(drvPath);
tmpDir = createTempDir("", "nix-build-" + drvName, false, false, 0700);
/* In a sandbox, for determinism, always use the same temporary
directory. */
#if __linux__
tmpDirInSandbox = useChroot ? settings.sandboxBuildDir : tmpDir;
#else
tmpDirInSandbox = tmpDir;
#endif
chownToBuilder(tmpDir);
/* Substitute output placeholders with the actual output paths. */
@@ -2167,7 +2073,7 @@ void DerivationGoal::startBuilder()
#endif
}
if (needsHashRewrite()) {
else {
if (pathExists(homeDir))
throw Error(format("directory '%1%' exists; please remove it") % homeDir);
@@ -2239,48 +2145,7 @@ void DerivationGoal::startBuilder()
Path logFile = openLogFile();
/* Create a pipe to get the output of the builder. */
//builderOut.create();
builderOut.readSide = posix_openpt(O_RDWR | O_NOCTTY);
if (!builderOut.readSide)
throw SysError("opening pseudoterminal master");
std::string slaveName(ptsname(builderOut.readSide.get()));
if (buildUser) {
if (chmod(slaveName.c_str(), 0600))
throw SysError("changing mode of pseudoterminal slave");
if (chown(slaveName.c_str(), buildUser->getUID(), 0))
throw SysError("changing owner of pseudoterminal slave");
} else {
if (grantpt(builderOut.readSide.get()))
throw SysError("granting access to pseudoterminal slave");
}
#if 0
// Mount the pt in the sandbox so that the "tty" command works.
// FIXME: this doesn't work with the new devpts in the sandbox.
if (useChroot)
dirsInChroot[slaveName] = {slaveName, false};
#endif
if (unlockpt(builderOut.readSide.get()))
throw SysError("unlocking pseudoterminal");
builderOut.writeSide = open(slaveName.c_str(), O_RDWR | O_NOCTTY);
if (!builderOut.writeSide)
throw SysError("opening pseudoterminal slave");
// Put the pt into raw mode to prevent \n -> \r\n translation.
struct termios term;
if (tcgetattr(builderOut.writeSide.get(), &term))
throw SysError("getting pseudoterminal attributes");
cfmakeraw(&term);
if (tcsetattr(builderOut.writeSide.get(), TCSANOW, &term))
throw SysError("putting pseudoterminal into raw mode");
builderOut.create();
result.startTime = time(0);
@@ -2353,37 +2218,17 @@ void DerivationGoal::startBuilder()
flags |= CLONE_NEWNET;
pid_t child = clone(childEntry, stack + stackSize, flags, this);
if (child == -1 && errno == EINVAL) {
if (child == -1 && errno == EINVAL)
/* Fallback for Linux < 2.13 where CLONE_NEWPID and
CLONE_PARENT are not allowed together. */
flags &= ~CLONE_NEWPID;
child = clone(childEntry, stack + stackSize, flags, this);
}
if (child == -1 && (errno == EPERM || errno == EINVAL)) {
/* Some distros patch Linux to not allow unpriveleged
* user namespaces. If we get EPERM or EINVAL, try
* without CLONE_NEWUSER and see if that works.
*/
flags &= ~CLONE_NEWUSER;
child = clone(childEntry, stack + stackSize, flags, this);
}
/* Otherwise exit with EPERM so we can handle this in the
parent. This is only done when sandbox-fallback is set
to true (the default). */
if (child == -1 && (errno == EPERM || errno == EINVAL) && settings.sandboxFallback)
_exit(1);
child = clone(childEntry, stack + stackSize, flags & ~CLONE_NEWPID, this);
if (child == -1) throw SysError("cloning builder process");
writeFull(builderOut.writeSide.get(), std::to_string(child) + "\n");
_exit(0);
}, options);
int res = helper.wait();
if (res != 0 && settings.sandboxFallback) {
useChroot = false;
initTmpDir();
goto fallback;
} else if (res != 0)
if (helper.wait() != 0)
throw Error("unable to start build process");
userNamespaceSync.readSide = -1;
@@ -2414,7 +2259,6 @@ void DerivationGoal::startBuilder()
} else
#endif
{
fallback:
options.allowVfork = !buildUser && !drv->isBuiltin();
pid = startProcess([&]() {
runChild();
@@ -2438,54 +2282,6 @@ void DerivationGoal::startBuilder()
}
void DerivationGoal::initTmpDir() {
/* In a sandbox, for determinism, always use the same temporary
directory. */
#if __linux__
tmpDirInSandbox = useChroot ? settings.sandboxBuildDir : tmpDir;
#else
tmpDirInSandbox = tmpDir;
#endif
/* In non-structured mode, add all bindings specified in the
derivation via the environment, except those listed in the
passAsFile attribute. Those are passed as file names pointing
to temporary files containing the contents. Note that
passAsFile is ignored in structure mode because it's not
needed (attributes are not passed through the environment, so
there is no size constraint). */
if (!parsedDrv->getStructuredAttrs()) {
StringSet passAsFile = tokenizeString<StringSet>(get(drv->env, "passAsFile"));
int fileNr = 0;
for (auto & i : drv->env) {
if (passAsFile.find(i.first) == passAsFile.end()) {
env[i.first] = i.second;
} else {
string fn = ".attr-" + std::to_string(fileNr++);
Path p = tmpDir + "/" + fn;
writeFile(p, rewriteStrings(i.second, inputRewrites));
chownToBuilder(p);
env[i.first + "Path"] = tmpDirInSandbox + "/" + fn;
}
}
}
/* For convenience, set an environment pointing to the top build
directory. */
env["NIX_BUILD_TOP"] = tmpDirInSandbox;
/* Also set TMPDIR and variants to point to this directory. */
env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = tmpDirInSandbox;
/* Explicitly set PWD to prevent problems with chroot builds. In
particular, dietlibc cannot figure out the cwd because the
inode of the current directory doesn't appear in .. (because
getdents returns the inode of the mount point). */
env["PWD"] = tmpDirInSandbox;
}
void DerivationGoal::initEnv()
{
env.clear();
@@ -2512,7 +2308,43 @@ void DerivationGoal::initEnv()
/* The maximum number of cores to utilize for parallel building. */
env["NIX_BUILD_CORES"] = (format("%d") % settings.buildCores).str();
initTmpDir();
/* In non-structured mode, add all bindings specified in the
derivation via the environment, except those listed in the
passAsFile attribute. Those are passed as file names pointing
to temporary files containing the contents. Note that
passAsFile is ignored in structure mode because it's not
needed (attributes are not passed through the environment, so
there is no size constraint). */
if (!parsedDrv->getStructuredAttrs()) {
StringSet passAsFile = tokenizeString<StringSet>(get(drv->env, "passAsFile"));
int fileNr = 0;
for (auto & i : drv->env) {
if (passAsFile.find(i.first) == passAsFile.end()) {
env[i.first] = i.second;
} else {
string fn = ".attr-" + std::to_string(fileNr++);
Path p = tmpDir + "/" + fn;
writeFile(p, i.second);
chownToBuilder(p);
env[i.first + "Path"] = tmpDirInSandbox + "/" + fn;
}
}
}
/* For convenience, set an environment pointing to the top build
directory. */
env["NIX_BUILD_TOP"] = tmpDirInSandbox;
/* Also set TMPDIR and variants to point to this directory. */
env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = tmpDirInSandbox;
/* Explicitly set PWD to prevent problems with chroot builds. In
particular, dietlibc cannot figure out the cwd because the
inode of the current directory doesn't appear in .. (because
getdents returns the inode of the mount point). */
env["PWD"] = tmpDirInSandbox;
/* Compatibility hack with Nix <= 0.7: if this is a fixed-output
derivation, tell the builder, so that for instance `fetchurl'
@@ -2538,9 +2370,6 @@ void DerivationGoal::initEnv()
may change that in the future. So tell the builder which file
descriptor to use for that. */
env["NIX_LOG_FD"] = "2";
/* Trigger colored output in various tools. */
env["TERM"] = "xterm-256color";
}
@@ -2578,7 +2407,6 @@ void DerivationGoal::writeStructuredAttrs()
}
writeFile(tmpDir + "/.attrs.json", rewriteStrings(json.dump(), inputRewrites));
chownToBuilder(tmpDir + "/.attrs.json");
/* As a convenience to bash scripts, write a shell file that
maps all attributes that are representable in bash -
@@ -2647,7 +2475,6 @@ void DerivationGoal::writeStructuredAttrs()
}
writeFile(tmpDir + "/.attrs.sh", rewriteStrings(jsonSh, inputRewrites));
chownToBuilder(tmpDir + "/.attrs.sh");
}
@@ -2673,17 +2500,17 @@ void setupSeccomp()
seccomp_release(ctx);
});
if (nativeSystem == "x86_64-linux" &&
if (settings.thisSystem == "x86_64-linux" &&
seccomp_arch_add(ctx, SCMP_ARCH_X86) != 0)
throw SysError("unable to add 32-bit seccomp architecture");
if (nativeSystem == "x86_64-linux" &&
if (settings.thisSystem == "x86_64-linux" &&
seccomp_arch_add(ctx, SCMP_ARCH_X32) != 0)
throw SysError("unable to add X32 seccomp architecture");
if (nativeSystem == "aarch64-linux" &&
if (settings.thisSystem == "aarch64-linux" &&
seccomp_arch_add(ctx, SCMP_ARCH_ARM) != 0)
printError("unable to add ARM seccomp architecture; this may result in spurious build failures if running 32-bit ARM processes");
printError("unsable to add ARM seccomp architecture; this may result in spurious build failures if running 32-bit ARM processes.");
/* Prevent builders from creating setuid/setgid binaries. */
for (int perm : { S_ISUID, S_ISGID }) {
@@ -2820,13 +2647,7 @@ void DerivationGoal::runChild()
on. */
if (fixedOutput) {
ss.push_back("/etc/resolv.conf");
// Only use nss functions to resolve hosts and
// services. Dont use it for anything else that may
// be configured for this system. This limits the
// potential impurities introduced in fixed outputs.
writeFile(chrootRootDir + "/etc/nsswitch.conf", "hosts: files dns\nservices: files\n");
ss.push_back("/etc/nsswitch.conf");
ss.push_back("/etc/services");
ss.push_back("/etc/hosts");
if (pathExists("/var/run/nscd/socket"))
@@ -3052,10 +2873,6 @@ void DerivationGoal::runChild()
for (auto & i : missingPaths) {
sandboxProfile += (format("\t(subpath \"%1%\")\n") % i.c_str()).str();
}
/* Also add redirected outputs to the chroot */
for (auto & i : redirectedOutputs) {
sandboxProfile += (format("\t(subpath \"%1%\")\n") % i.second.c_str()).str();
}
sandboxProfile += ")\n";
/* Our inputs (transitive dependencies and any impurities computed above)
@@ -3208,7 +3025,8 @@ void DerivationGoal::registerOutputs()
InodesSeen inodesSeen;
Path checkSuffix = ".check";
bool keepPreviousRound = settings.keepFailed || settings.runDiffHook;
bool runDiffHook = settings.runDiffHook;
bool keepPreviousRound = settings.keepFailed || runDiffHook;
std::exception_ptr delayedException;
@@ -3233,9 +3051,7 @@ void DerivationGoal::registerOutputs()
throw SysError(format("moving build output '%1%' from the sandbox to the Nix store") % path);
}
if (buildMode != bmCheck) actualPath = worker.store.toRealPath(path);
}
if (needsHashRewrite()) {
} else {
Path redirected = redirectedOutputs[path];
if (buildMode == bmRepair
&& redirectedBadOutputs.find(path) != redirectedBadOutputs.end()
@@ -3311,7 +3127,6 @@ void DerivationGoal::registerOutputs()
/* Throw an error after registering the path as
valid. */
worker.hashMismatch = true;
delayedException = std::make_exception_ptr(
BuildError("hash mismatch in fixed-output derivation '%s':\n wanted: %s\n got: %s",
dest, h.to_string(), h2.to_string()));
@@ -3354,22 +3169,15 @@ void DerivationGoal::registerOutputs()
if (!worker.store.isValidPath(path)) continue;
auto info = *worker.store.queryPathInfo(path);
if (hash.first != info.narHash) {
worker.checkMismatch = true;
if (settings.runDiffHook || settings.keepFailed) {
if (settings.keepFailed) {
Path dst = worker.store.toRealPath(path + checkSuffix);
deletePath(dst);
if (rename(actualPath.c_str(), dst.c_str()))
throw SysError(format("renaming '%1%' to '%2%'") % actualPath % dst);
handleDiffHook(
buildUser ? buildUser->getUID() : getuid(),
buildUser ? buildUser->getGID() : getgid(),
path, dst, drvPath, tmpDir);
throw NotDeterministic(format("derivation '%1%' may not be deterministic: output '%2%' differs from '%3%'")
throw Error(format("derivation '%1%' may not be deterministic: output '%2%' differs from '%3%'")
% drvPath % path % dst);
} else
throw NotDeterministic(format("derivation '%1%' may not be deterministic: output '%2%' differs")
throw Error(format("derivation '%1%' may not be deterministic: output '%2%' differs")
% drvPath % path);
}
@@ -3430,10 +3238,16 @@ void DerivationGoal::registerOutputs()
? fmt("output '%1%' of '%2%' differs from '%3%' from previous round", i->second.path, drvPath, prev)
: fmt("output '%1%' of '%2%' differs from previous round", i->second.path, drvPath);
handleDiffHook(
buildUser ? buildUser->getUID() : getuid(),
buildUser ? buildUser->getGID() : getgid(),
prev, i->second.path, drvPath, tmpDir);
auto diffHook = settings.diffHook;
if (prevExists && diffHook != "" && runDiffHook) {
try {
auto diff = runProgram(diffHook, true, {prev, i->second.path});
if (diff != "")
printError(chomp(diff));
} catch (Error & error) {
printError("diff hook execution failed: %s", error.what());
}
}
if (settings.enforceDeterminism)
throw NotDeterministic(msg);
@@ -4070,6 +3884,17 @@ 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();
@@ -4109,6 +3934,12 @@ 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 (std::exception & e) {
printError(e.what());
@@ -4184,8 +4015,6 @@ Worker::Worker(LocalStore & store)
lastWokenUp = steady_time_point::min();
permanentFailure = false;
timedOut = false;
hashMismatch = false;
checkMismatch = false;
}
@@ -4491,15 +4320,14 @@ void Worker::waitForInput()
for (auto & k : fds2) {
if (FD_ISSET(k, &fds)) {
ssize_t rd = read(k, buffer.data(), buffer.size());
// FIXME: is there a cleaner way to handle pt close
// than EIO? Is this even standard?
if (rd == 0 || (rd == -1 && errno == EIO)) {
if (rd == -1) {
if (errno != EINTR)
throw SysError(format("reading from %1%")
% goal->getName());
} else if (rd == 0) {
debug(format("%1%: got EOF") % goal->getName());
goal->handleEOF(k);
j->fds.erase(k);
} else if (rd == -1) {
if (errno != EINTR)
throw SysError("%s: read failed", goal->getName());
} else {
printMsg(lvlVomit, format("%1%: read %2% bytes")
% goal->getName() % rd);
@@ -4546,29 +4374,7 @@ void Worker::waitForInput()
unsigned int Worker::exitStatus()
{
/*
* 1100100
* ^^^^
* |||`- timeout
* ||`-- output hash mismatch
* |`--- build failure
* `---- not deterministic
*/
unsigned int mask = 0;
bool buildFailure = permanentFailure || timedOut || hashMismatch;
if (buildFailure)
mask |= 0x04; // 100
if (timedOut)
mask |= 0x01; // 101
if (hashMismatch)
mask |= 0x02; // 102
if (checkMismatch) {
mask |= 0x08; // 104
}
if (mask)
mask |= 0x60;
return mask ? mask : 1;
return timedOut ? 101 : (permanentFailure ? 100 : 1);
}

View File

@@ -64,8 +64,7 @@ void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData)
try {
if (!hasSuffix(hashedMirror, "/")) hashedMirror += '/';
auto ht = parseHashType(getAttr("outputHashAlgo"));
auto h = Hash(getAttr("outputHash"), ht);
fetch(hashedMirror + printHashType(h.type) + "/" + h.to_string(Base16, false));
fetch(hashedMirror + printHashType(ht) + "/" + Hash(getAttr("outputHash"), ht).to_string(Base16, false));
return;
} catch (Error & e) {
debug(e.what());

View File

@@ -36,6 +36,12 @@ Path BasicDerivation::findOutput(const string & id) const
}
bool BasicDerivation::substitutesAllowed() const
{
return get(env, "allowSubstitutes", "1") == "1";
}
bool BasicDerivation::isBuiltin() const
{
return string(builder, 0, 8) == "builtin:";

View File

@@ -56,6 +56,8 @@ struct BasicDerivation
the given derivation. */
Path findOutput(const string & id) const;
bool substitutesAllowed() const;
bool isBuiltin() const;
/* Return true iff this is a fixed-output derivation. */

View File

@@ -30,7 +30,23 @@ using namespace std::string_literals;
namespace nix {
DownloadSettings downloadSettings;
struct DownloadSettings : Config
{
Setting<bool> enableHttp2{this, true, "http2",
"Whether to enable HTTP/2 support."};
Setting<std::string> userAgentSuffix{this, "", "user-agent-suffix",
"String appended to the user agent in HTTP requests."};
Setting<size_t> httpConnections{this, 25, "http-connections",
"Number of parallel HTTP connections.",
{"binary-caches-parallel-connections"}};
Setting<unsigned long> connectTimeout{this, 0, "connect-timeout",
"Timeout for connecting to servers during downloads. 0 means use curl's builtin default."};
};
static DownloadSettings downloadSettings;
static GlobalConfig::Register r1(&downloadSettings);
@@ -71,31 +87,19 @@ struct CurlDownloader : public Downloader
std::string encoding;
bool acceptRanges = false;
curl_off_t writtenToSink = 0;
DownloadItem(CurlDownloader & downloader,
const DownloadRequest & request,
Callback<DownloadResult> && callback)
Callback<DownloadResult> callback)
: downloader(downloader)
, request(request)
, act(*logger, lvlTalkative, actDownload,
fmt(request.data ? "uploading '%s'" : "downloading '%s'", request.uri),
{request.uri}, request.parentAct)
, callback(std::move(callback))
, callback(callback)
, finalSink([this](const unsigned char * data, size_t len) {
if (this->request.dataCallback) {
long httpStatus = 0;
curl_easy_getinfo(req, CURLINFO_RESPONSE_CODE, &httpStatus);
/* Only write data to the sink if this is a
successful response. */
if (httpStatus == 0 || httpStatus == 200 || httpStatus == 201 || httpStatus == 206) {
writtenToSink += len;
this->request.dataCallback((char *) data, len);
}
} else
if (this->request.dataCallback)
this->request.dataCallback((char *) data, len);
else
this->result.data->append((char *) data, len);
})
{
@@ -173,7 +177,6 @@ struct CurlDownloader : public Downloader
status = ss.size() >= 2 ? ss[1] : "";
result.data = std::make_shared<std::string>();
result.bodySize = 0;
acceptRanges = false;
encoding = "";
} else {
auto i = line.find(':');
@@ -191,9 +194,7 @@ struct CurlDownloader : public Downloader
return 0;
}
} else if (name == "content-encoding")
encoding = trim(string(line, i + 1));
else if (name == "accept-ranges" && toLower(trim(std::string(line, i + 1))) == "bytes")
acceptRanges = true;
encoding = trim(string(line, i + 1));;
}
}
return realSize;
@@ -243,6 +244,8 @@ struct CurlDownloader : public Downloader
return ((DownloadItem *) userp)->readCallback(buffer, size, nitems);
}
long lowSpeedTimeout = 300;
void init()
{
if (!req) req = curl_easy_init();
@@ -267,8 +270,6 @@ struct CurlDownloader : public Downloader
#if LIBCURL_VERSION_NUM >= 0x072f00
if (downloadSettings.enableHttp2)
curl_easy_setopt(req, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
else
curl_easy_setopt(req, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
#endif
curl_easy_setopt(req, CURLOPT_WRITEFUNCTION, DownloadItem::writeCallbackWrapper);
curl_easy_setopt(req, CURLOPT_WRITEDATA, this);
@@ -302,16 +303,13 @@ struct CurlDownloader : public Downloader
curl_easy_setopt(req, CURLOPT_CONNECTTIMEOUT, downloadSettings.connectTimeout.get());
curl_easy_setopt(req, CURLOPT_LOW_SPEED_LIMIT, 1L);
curl_easy_setopt(req, CURLOPT_LOW_SPEED_TIME, downloadSettings.stalledDownloadTimeout.get());
curl_easy_setopt(req, CURLOPT_LOW_SPEED_TIME, lowSpeedTimeout);
/* If no file exist in the specified path, curl continues to work
anyway as if netrc support was disabled. */
curl_easy_setopt(req, CURLOPT_NETRC_FILE, settings.netrcFile.get().c_str());
curl_easy_setopt(req, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
if (writtenToSink)
curl_easy_setopt(req, CURLOPT_RESUME_FROM_LARGE, writtenToSink);
result.data = std::make_shared<std::string>();
result.bodySize = 0;
}
@@ -321,21 +319,16 @@ struct CurlDownloader : public Downloader
long httpStatus = 0;
curl_easy_getinfo(req, CURLINFO_RESPONSE_CODE, &httpStatus);
char * effectiveUriCStr;
curl_easy_getinfo(req, CURLINFO_EFFECTIVE_URL, &effectiveUriCStr);
if (effectiveUriCStr)
result.effectiveUri = effectiveUriCStr;
char * effectiveUrlCStr;
curl_easy_getinfo(req, CURLINFO_EFFECTIVE_URL, &effectiveUrlCStr);
if (effectiveUrlCStr)
result.effectiveUrl = effectiveUrlCStr;
debug("finished %s of '%s'; curl status = %d, HTTP status = %d, body = %d bytes",
request.verb(), request.uri, code, httpStatus, result.bodySize);
if (decompressionSink) {
try {
decompressionSink->finish();
} catch (...) {
writeException = std::current_exception();
}
}
if (decompressionSink)
decompressionSink->finish();
if (code == CURLE_WRITE_ERROR && result.etag == request.expectedETag) {
code = CURLE_OK;
@@ -346,12 +339,18 @@ struct CurlDownloader : public Downloader
failEx(writeException);
else if (code == CURLE_OK &&
(httpStatus == 200 || httpStatus == 201 || httpStatus == 204 || httpStatus == 206 || httpStatus == 304 || httpStatus == 226 /* FTP */ || httpStatus == 0 /* other protocol */))
(httpStatus == 200 || httpStatus == 201 || httpStatus == 204 || httpStatus == 304 || httpStatus == 226 /* FTP */ || httpStatus == 0 /* other protocol */))
{
result.cached = httpStatus == 304;
act.progress(result.bodySize, result.bodySize);
done = true;
callback(std::move(result));
try {
act.progress(result.bodySize, result.bodySize);
callback(std::move(result));
} catch (...) {
done = true;
callback.rethrow();
}
}
else {
@@ -364,10 +363,9 @@ struct CurlDownloader : public Downloader
} else if (httpStatus == 401 || httpStatus == 403 || httpStatus == 407) {
// Don't retry on authentication/authorization failures
err = Forbidden;
} else if (httpStatus >= 400 && httpStatus < 500 && httpStatus != 408 && httpStatus != 429) {
} else if (httpStatus >= 400 && httpStatus < 500 && httpStatus != 408) {
// Most 4xx errors are client errors and are probably not worth retrying:
// * 408 means the server timed out waiting for us, so we try again
// * 429 means too many requests, so we retry (with a delay)
err = Misc;
} else if (httpStatus == 501 || httpStatus == 505 || httpStatus == 511) {
// Let's treat most 5xx (server) errors as transient, except for a handful:
@@ -391,7 +389,6 @@ struct CurlDownloader : public Downloader
case CURLE_SSL_CACERT_BADFILE:
case CURLE_TOO_MANY_REDIRECTS:
case CURLE_WRITE_ERROR:
case CURLE_UNSUPPORTED_PROTOCOL:
err = Misc;
break;
default: // Shut up warnings
@@ -415,20 +412,10 @@ struct CurlDownloader : public Downloader
request.verb(), request.uri, curl_easy_strerror(code), code));
/* If this is a transient error, then maybe retry the
download after a while. If we're writing to a
sink, we can only retry if the server supports
ranged requests. */
if (err == Transient
&& attempt < request.tries
&& (!this->request.dataCallback
|| writtenToSink == 0
|| (acceptRanges && encoding.empty())))
{
download after a while. */
if (err == Transient && attempt < request.tries) {
int ms = request.baseRetryTimeMs * std::pow(2.0f, attempt - 1 + std::uniform_real_distribution<>(0.0, 0.5)(downloader.mt19937));
if (writtenToSink)
warn("%s; retrying from offset %d in %d ms", exc.what(), writtenToSink, ms);
else
warn("%s; retrying in %d ms", exc.what(), ms);
printError(format("warning: %s; retrying in %d ms") % exc.what() % ms);
embargo = std::chrono::steady_clock::now() + std::chrono::milliseconds(ms);
downloader.enqueueItem(shared_from_this());
}
@@ -601,7 +588,7 @@ struct CurlDownloader : public Downloader
workerThreadMain();
} catch (nix::Interrupted & e) {
} catch (std::exception & e) {
printError("unexpected error in download thread: %s", e.what());
printError(format("unexpected error in download thread: %s") % e.what());
}
{
@@ -674,7 +661,7 @@ struct CurlDownloader : public Downloader
return;
}
enqueueItem(std::make_shared<DownloadItem>(*this, request, std::move(callback)));
enqueueItem(std::make_shared<DownloadItem>(*this, request, callback));
}
};
@@ -803,26 +790,20 @@ void Downloader::download(DownloadRequest && request, Sink & sink)
}
}
CachedDownloadResult Downloader::downloadCached(
ref<Store> store, const CachedDownloadRequest & request)
Path Downloader::downloadCached(ref<Store> store, const string & url_, bool unpack, string name, const Hash & expectedHash, string * effectiveUrl, int ttl)
{
auto url = resolveUri(request.uri);
auto url = resolveUri(url_);
auto name = request.name;
if (name == "") {
auto p = url.rfind('/');
if (p != string::npos) name = string(url, p + 1);
}
Path expectedStorePath;
if (request.expectedHash) {
expectedStorePath = store->makeFixedOutputPath(request.unpack, request.expectedHash, name);
if (store->isValidPath(expectedStorePath)) {
CachedDownloadResult result;
result.storePath = expectedStorePath;
result.path = store->toRealPath(expectedStorePath);
return result;
}
if (expectedHash) {
expectedStorePath = store->makeFixedOutputPath(unpack, expectedHash, name);
if (store->isValidPath(expectedStorePath))
return store->toRealPath(expectedStorePath);
}
Path cacheDir = getCacheDir() + "/nix/tarballs";
@@ -841,8 +822,6 @@ CachedDownloadResult Downloader::downloadCached(
bool skip = false;
CachedDownloadResult result;
if (pathExists(fileLink) && pathExists(dataFile)) {
storePath = readLink(fileLink);
store->addTempRoot(storePath);
@@ -850,10 +829,10 @@ CachedDownloadResult Downloader::downloadCached(
auto ss = tokenizeString<vector<string>>(readFile(dataFile), "\n");
if (ss.size() >= 3 && ss[0] == url) {
time_t lastChecked;
if (string2Int(ss[2], lastChecked) && (uint64_t) lastChecked + request.ttl >= (uint64_t) time(0)) {
if (string2Int(ss[2], lastChecked) && lastChecked + ttl >= time(0)) {
skip = true;
result.effectiveUri = request.uri;
result.etag = ss[1];
if (effectiveUrl)
*effectiveUrl = url_;
} else if (!ss[1].empty()) {
debug(format("verifying previous ETag '%1%'") % ss[1]);
expectedETag = ss[1];
@@ -866,17 +845,17 @@ CachedDownloadResult Downloader::downloadCached(
if (!skip) {
try {
DownloadRequest request2(url);
request2.expectedETag = expectedETag;
auto res = download(request2);
result.effectiveUri = res.effectiveUri;
result.etag = res.etag;
DownloadRequest request(url);
request.expectedETag = expectedETag;
auto res = download(request);
if (effectiveUrl)
*effectiveUrl = res.effectiveUrl;
if (!res.cached) {
ValidPathInfo info;
StringSink sink;
dumpString(*res.data, sink);
Hash hash = hashString(request.expectedHash ? request.expectedHash.type : htSHA256, *res.data);
Hash hash = hashString(expectedHash ? expectedHash.type : htSHA256, *res.data);
info.path = store->makeFixedOutputPath(false, hash, name);
info.narHash = hashString(htSHA256, *sink.s);
info.narSize = sink.s->size();
@@ -891,12 +870,11 @@ CachedDownloadResult Downloader::downloadCached(
writeFile(dataFile, url + "\n" + res.etag + "\n" + std::to_string(time(0)) + "\n");
} catch (DownloadError & e) {
if (storePath.empty()) throw;
warn("warning: %s; using cached result", e.msg());
result.etag = expectedETag;
printError(format("warning: %1%; using cached result") % e.msg());
}
}
if (request.unpack) {
if (unpack) {
Path unpackedLink = cacheDir + "/" + baseNameOf(storePath) + "-unpacked";
PathLocks lock2({unpackedLink}, fmt("waiting for lock on '%1%'...", unpackedLink));
Path unpackedStorePath;
@@ -919,17 +897,14 @@ CachedDownloadResult Downloader::downloadCached(
}
if (expectedStorePath != "" && storePath != expectedStorePath) {
unsigned int statusCode = 102;
Hash gotHash = request.unpack
? hashPath(request.expectedHash.type, store->toRealPath(storePath)).first
: hashFile(request.expectedHash.type, store->toRealPath(storePath));
throw nix::Error(statusCode, "hash mismatch in file downloaded from '%s':\n wanted: %s\n got: %s",
url, request.expectedHash.to_string(), gotHash.to_string());
Hash gotHash = unpack
? hashPath(expectedHash.type, store->toRealPath(storePath)).first
: hashFile(expectedHash.type, store->toRealPath(storePath));
throw nix::Error("hash mismatch in file downloaded from '%s':\n wanted: %s\n got: %s",
url, expectedHash.to_string(), gotHash.to_string());
}
result.storePath = storePath;
result.path = store->toRealPath(storePath);
return result;
return store->toRealPath(storePath);
}

View File

@@ -9,37 +9,13 @@
namespace nix {
struct DownloadSettings : Config
{
Setting<bool> enableHttp2{this, true, "http2",
"Whether to enable HTTP/2 support."};
Setting<std::string> userAgentSuffix{this, "", "user-agent-suffix",
"String appended to the user agent in HTTP requests."};
Setting<size_t> httpConnections{this, 25, "http-connections",
"Number of parallel HTTP connections.",
{"binary-caches-parallel-connections"}};
Setting<unsigned long> connectTimeout{this, 0, "connect-timeout",
"Timeout for connecting to servers during downloads. 0 means use curl's builtin default."};
Setting<unsigned long> stalledDownloadTimeout{this, 300, "stalled-download-timeout",
"Timeout (in seconds) for receiving data from servers during download. Nix cancels idle downloads after this timeout's duration."};
Setting<unsigned int> tries{this, 5, "download-attempts",
"How often Nix will attempt to download a file before giving up."};
};
extern DownloadSettings downloadSettings;
struct DownloadRequest
{
std::string uri;
std::string expectedETag;
bool verifyTLS = true;
bool head = false;
size_t tries = downloadSettings.tries;
size_t tries = 5;
unsigned int baseRetryTimeMs = 250;
ActivityId parentAct;
bool decompress = true;
@@ -60,39 +36,15 @@ struct DownloadResult
{
bool cached = false;
std::string etag;
std::string effectiveUri;
std::string effectiveUrl;
std::shared_ptr<std::string> data;
uint64_t bodySize = 0;
};
struct CachedDownloadRequest
{
std::string uri;
bool unpack = false;
std::string name;
Hash expectedHash;
unsigned int ttl = settings.tarballTtl;
CachedDownloadRequest(const std::string & uri)
: uri(uri) { }
};
struct CachedDownloadResult
{
// Note: 'storePath' may be different from 'path' when using a
// chroot store.
Path storePath;
Path path;
std::optional<std::string> etag;
std::string effectiveUri;
};
class Store;
struct Downloader
{
virtual ~Downloader() { }
/* Enqueue a download request, returning a future to the result of
the download. The future may throw a DownloadError
exception. */
@@ -112,7 +64,8 @@ struct Downloader
and is more recent than tarball-ttl seconds. Otherwise,
use the recorded ETag to verify if the server has a more
recent version, and if so, download it to the Nix store. */
CachedDownloadResult downloadCached(ref<Store> store, const CachedDownloadRequest & request);
Path downloadCached(ref<Store> store, const string & uri, bool unpack, string name = "",
const Hash & expectedHash = Hash(), string * effectiveUri = nullptr, int ttl = settings.tarballTtl);
enum Error { NotFound, Forbidden, Misc, Transient, Interrupted };
};

View File

@@ -19,8 +19,6 @@ public:
uint64_t narOffset = 0; // regular files only
};
virtual ~FSAccessor() { }
virtual Stat stat(const Path & path) = 0;
virtual StringSet readDirectory(const Path & path) = 0;

View File

@@ -29,7 +29,7 @@ static string gcRootsDir = "gcroots";
read. To be precise: when they try to create a new temporary root
file, they will block until the garbage collector has finished /
yielded the GC lock. */
AutoCloseFD LocalStore::openGCLock(LockType lockType)
int LocalStore::openGCLock(LockType lockType)
{
Path fnGCLock = (format("%1%/%2%")
% stateDir % gcLockName).str();
@@ -49,7 +49,7 @@ AutoCloseFD LocalStore::openGCLock(LockType lockType)
process that can open the file for reading can DoS the
collector. */
return fdGCLock;
return fdGCLock.release();
}
@@ -221,21 +221,25 @@ void LocalStore::findTempRoots(FDs & fds, Roots & tempRoots, bool censor)
//FDPtr fd(new AutoCloseFD(openLockFile(path, false)));
//if (*fd == -1) continue;
/* Try to acquire a write lock without blocking. This can
only succeed if the owning process has died. In that case
we don't care about its temporary roots. */
if (lockFile(fd->get(), ltWrite, false)) {
printError(format("removing stale temporary roots file '%1%'") % path);
unlink(path.c_str());
writeFull(fd->get(), "d");
continue;
}
if (path != fnTempRoots) {
/* Acquire a read lock. This will prevent the owning process
from upgrading to a write lock, therefore it will block in
addTempRoot(). */
debug(format("waiting for read lock on '%1%'") % path);
lockFile(fd->get(), ltRead, true);
/* Try to acquire a write lock without blocking. This can
only succeed if the owning process has died. In that case
we don't care about its temporary roots. */
if (lockFile(fd->get(), ltWrite, false)) {
printError(format("removing stale temporary roots file '%1%'") % path);
unlink(path.c_str());
writeFull(fd->get(), "d");
continue;
}
/* Acquire a read lock. This will prevent the owning process
from upgrading to a write lock, therefore it will block in
addTempRoot(). */
debug(format("waiting for read lock on '%1%'") % path);
lockFile(fd->get(), ltRead, true);
}
/* Read the entire file. */
string contents = readFile(fd->get());
@@ -322,9 +326,10 @@ void LocalStore::findRootsNoTemp(Roots & roots, bool censor)
findRoots(stateDir + "/" + gcRootsDir, DT_UNKNOWN, roots);
findRoots(stateDir + "/profiles", DT_UNKNOWN, roots);
/* Add additional roots returned by different platforms-specific
heuristics. This is typically used to add running programs to
the set of roots (to prevent them from being garbage collected). */
/* Add additional roots returned by the program specified by the
NIX_ROOT_FINDER environment variable. This is typically used
to add running programs to the set of roots (to prevent them
from being garbage collected). */
findRuntimeRoots(roots, censor);
}
@@ -440,22 +445,17 @@ void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
}
#if !defined(__linux__)
// lsof is really slow on OS X. This actually causes the gc-concurrent.sh test to fail.
// See: https://github.com/NixOS/nix/issues/3011
// Because of this we disable lsof when running the tests.
if (getEnv("_NIX_TEST_NO_LSOF") == "") {
try {
std::regex lsofRegex(R"(^n(/.*)$)");
auto lsofLines =
tokenizeString<std::vector<string>>(runProgram(LSOF, true, { "-n", "-w", "-F", "n" }), "\n");
for (const auto & line : lsofLines) {
std::smatch match;
if (std::regex_match(line, match, lsofRegex))
unchecked[match[1]].emplace("{lsof}");
}
} catch (ExecError & e) {
/* lsof not installed, lsof failed */
try {
std::regex lsofRegex(R"(^n(/.*)$)");
auto lsofLines =
tokenizeString<std::vector<string>>(runProgram(LSOF, true, { "-n", "-w", "-F", "n" }), "\n");
for (const auto & line : lsofLines) {
std::smatch match;
if (std::regex_match(line, match, lsofRegex))
unchecked[match[1]].emplace("{lsof}");
}
} catch (ExecError & e) {
/* lsof not installed, lsof failed */
}
#endif
@@ -690,8 +690,9 @@ void LocalStore::removeUnusedLinks(const GCState & state)
throw SysError(format("statting '%1%'") % path);
if (st.st_nlink != 1) {
actualSize += st.st_size;
unsharedSize += (st.st_nlink - 1) * st.st_size;
unsigned long long size = st.st_blocks * 512ULL;
actualSize += size;
unsharedSize += (st.st_nlink - 1) * size;
continue;
}
@@ -700,7 +701,7 @@ void LocalStore::removeUnusedLinks(const GCState & state)
if (unlink(path.c_str()) == -1)
throw SysError(format("deleting '%1%'") % path);
state.results.bytesFreed += st.st_size;
state.results.bytesFreed += st.st_blocks * 512ULL;
}
struct stat st;
@@ -866,12 +867,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
void LocalStore::autoGC(bool sync)
{
static auto fakeFreeSpaceFile = getEnv("_NIX_TEST_FREE_SPACE_FILE", "");
auto getAvail = [this]() -> uint64_t {
if (!fakeFreeSpaceFile.empty())
return std::stoll(readFile(fakeFreeSpaceFile));
auto getAvail = [this]() {
struct statvfs st;
if (statvfs(realStoreDir.c_str(), &st))
throw SysError("getting filesystem info about '%s'", realStoreDir);
@@ -892,7 +888,7 @@ void LocalStore::autoGC(bool sync)
auto now = std::chrono::steady_clock::now();
if (now < state->lastGCCheck + std::chrono::seconds(settings.minFreeCheckInterval)) return;
if (now < state->lastGCCheck + std::chrono::seconds(5)) return;
auto avail = getAvail();
@@ -919,11 +915,11 @@ void LocalStore::autoGC(bool sync)
promise.set_value();
});
printInfo("running auto-GC to free %d bytes", settings.maxFree - avail);
GCOptions options;
options.maxFreed = settings.maxFree - avail;
printInfo("running auto-GC to free %d bytes", options.maxFreed);
GCResults results;
collectGarbage(options, results);

View File

@@ -209,9 +209,6 @@ public:
"The paths to make available inside the build sandbox.",
{"build-chroot-dirs", "build-sandbox-paths"}};
Setting<bool> sandboxFallback{this, true, "sandbox-fallback",
"Whether to disable sandboxing when the kernel doesn't allow it."};
Setting<PathSet> extraSandboxPaths{this, {}, "extra-sandbox-paths",
"Additional paths to make available inside the build sandbox.",
{"build-extra-chroot-dirs", "build-extra-sandbox-paths"}};
@@ -258,7 +255,7 @@ public:
"Secret keys with which to sign local builds."};
Setting<unsigned int> tarballTtl{this, 60 * 60, "tarball-ttl",
"How long downloaded files are considered up-to-date."};
"How soon to expire files fetched by builtins.fetchTarball and builtins.fetchurl."};
Setting<bool> requireSigs{this, true, "require-sigs",
"Whether to check that any non-content-addressed path added to the "
@@ -318,9 +315,6 @@ public:
"pre-build-hook",
"A program to run just before a build to set derivation-specific build settings."};
Setting<std::string> postBuildHook{this, "", "post-build-hook",
"A program to run just after each successful build."};
Setting<std::string> netrcFile{this, fmt("%s/%s", nixConfDir, "netrc"), "netrc-file",
"Path to the netrc file used to obtain usernames/passwords for downloads."};
@@ -348,9 +342,6 @@ public:
Setting<uint64_t> maxFree{this, std::numeric_limits<uint64_t>::max(), "max-free",
"Stop deleting garbage when free disk space is above the specified amount."};
Setting<uint64_t> minFreeCheckInterval{this, 5, "min-free-check-interval",
"Number of seconds between checking free disk space."};
Setting<Paths> pluginFiles{this, {}, "plugin-files",
"Plugins to dynamically load at nix initialization time."};
};

View File

@@ -84,6 +84,7 @@ protected:
try {
DownloadRequest request(cacheUri + "/" + path);
request.head = true;
request.tries = 5;
getDownloader()->download(request);
return true;
} catch (DownloadError & e) {
@@ -113,6 +114,7 @@ protected:
DownloadRequest makeRequest(const std::string & path)
{
DownloadRequest request(cacheUri + "/" + path);
request.tries = 8;
return request;
}
@@ -131,25 +133,23 @@ protected:
}
void getFile(const std::string & path,
Callback<std::shared_ptr<std::string>> callback) noexcept override
Callback<std::shared_ptr<std::string>> callback) override
{
checkEnabled();
auto request(makeRequest(path));
auto callbackPtr = std::make_shared<decltype(callback)>(std::move(callback));
getDownloader()->enqueueDownload(request,
{[callbackPtr, this](std::future<DownloadResult> result) {
{[callback, this](std::future<DownloadResult> result) {
try {
(*callbackPtr)(result.get().data);
callback(result.get().data);
} catch (DownloadError & e) {
if (e.error == Downloader::NotFound || e.error == Downloader::Forbidden)
return (*callbackPtr)(std::shared_ptr<std::string>());
return callback(std::shared_ptr<std::string>());
maybeDisable();
callbackPtr->rethrow();
callback.rethrow();
} catch (...) {
callbackPtr->rethrow();
callback.rethrow();
}
}});
}

View File

@@ -88,7 +88,7 @@ struct LegacySSHStore : public Store
}
void queryPathInfoUncached(const Path & path,
Callback<std::shared_ptr<ValidPathInfo>> callback) noexcept override
Callback<std::shared_ptr<ValidPathInfo>> callback) override
{
try {
auto conn(connections->get());

View File

@@ -70,17 +70,15 @@ LocalStore::LocalStore(const Params & params)
createSymlink(profilesDir, gcRootsDir + "/profiles");
}
for (auto & perUserDir : {profilesDir + "/per-user", gcRootsDir + "/per-user"}) {
createDirs(perUserDir);
if (chmod(perUserDir.c_str(), 0755) == -1)
throw SysError("could not set permissions on '%s' to 755", perUserDir);
}
createUser(getUserName(), getuid());
/* Optionally, create directories and set permissions for a
multi-user install. */
if (getuid() == 0 && settings.buildUsersGroup != "") {
Path perUserDir = profilesDir + "/per-user";
createDirs(perUserDir);
if (chmod(perUserDir.c_str(), 01777) == -1)
throw SysError(format("could not set permissions on '%1%' to 1777") % perUserDir);
mode_t perm = 01775;
struct group * gr = getgrnam(settings.buildUsersGroup.get().c_str());
@@ -631,7 +629,7 @@ uint64_t LocalStore::addValidPath(State & state,
void LocalStore::queryPathInfoUncached(const Path & path,
Callback<std::shared_ptr<ValidPathInfo>> callback) noexcept
Callback<std::shared_ptr<ValidPathInfo>> callback)
{
try {
auto info = std::make_shared<ValidPathInfo>();
@@ -881,8 +879,8 @@ void LocalStore::querySubstitutablePathInfos(const PathSet & paths,
info->references,
narInfo ? narInfo->fileSize : 0,
info->narSize};
} catch (InvalidPath &) {
} catch (SubstituterDisabled &) {
} catch (InvalidPath) {
} catch (SubstituterDisabled) {
} catch (Error & e) {
if (settings.tryFallback)
printError(e.what());
@@ -1212,8 +1210,7 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
bool errors = false;
/* Acquire the global GC lock to get a consistent snapshot of
existing and valid paths. */
/* Acquire the global GC lock to prevent a garbage collection. */
AutoCloseFD fdGCLock = openGCLock(ltWrite);
PathSet store;
@@ -1224,11 +1221,13 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
PathSet validPaths2 = queryAllValidPaths(), validPaths, done;
fdGCLock = -1;
for (auto & i : validPaths2)
verifyPath(i, store, done, validPaths, repair, errors);
/* Release the GC lock so that checking content hashes (which can
take ages) doesn't block the GC or builds. */
fdGCLock = -1;
/* Optionally, check the content hashes (slow). */
if (checkContents) {
printInfo("checking hashes...");
@@ -1435,19 +1434,4 @@ void LocalStore::signPathInfo(ValidPathInfo & info)
}
void LocalStore::createUser(const std::string & userName, uid_t userId)
{
for (auto & dir : {
fmt("%s/profiles/per-user/%s", stateDir, userName),
fmt("%s/gcroots/per-user/%s", stateDir, userName)
}) {
createDirs(dir);
if (chmod(dir.c_str(), 0755) == -1)
throw SysError("changing permissions of directory '%s'", dir);
if (chown(dir.c_str(), userId, getgid()) == -1)
throw SysError("changing owner of directory '%s'", dir);
}
}
}

View File

@@ -127,7 +127,7 @@ public:
PathSet queryAllValidPaths() override;
void queryPathInfoUncached(const Path & path,
Callback<std::shared_ptr<ValidPathInfo>> callback) noexcept override;
Callback<std::shared_ptr<ValidPathInfo>> callback) override;
void queryReferrers(const Path & path, PathSet & referrers) override;
@@ -263,7 +263,7 @@ private:
bool isActiveTempFile(const GCState & state,
const Path & path, const string & suffix);
AutoCloseFD openGCLock(LockType lockType);
int openGCLock(LockType lockType);
void findRoots(const Path & path, unsigned char type, Roots & roots);
@@ -293,8 +293,6 @@ private:
Path getRealStoreDir() override { return realStoreDir; }
void createUser(const std::string & userName, uid_t userId) override;
friend class DerivationGoal;
friend class SubstitutionGoal;
};

View File

@@ -39,12 +39,9 @@ libstore_CXXFLAGS = \
-DNIX_LIBEXEC_DIR=\"$(libexecdir)\" \
-DNIX_BIN_DIR=\"$(bindir)\" \
-DNIX_MAN_DIR=\"$(mandir)\" \
-DSANDBOX_SHELL="\"$(sandbox_shell)\"" \
-DLSOF=\"$(lsof)\"
ifneq ($(sandbox_shell),)
libstore_CXXFLAGS += -DSANDBOX_SHELL="\"$(sandbox_shell)\""
endif
$(d)/local-store.cc: $(d)/schema.sql.gen.hh
$(d)/build.cc:

View File

@@ -1,5 +1,4 @@
#include "derivations.hh"
#include "parsed-derivations.hh"
#include "globals.hh"
#include "local-store.hh"
#include "store-api.hh"
@@ -190,7 +189,6 @@ void Store::queryMissing(const PathSet & targets,
}
Derivation drv = derivationFromPath(i2.first);
ParsedDerivation parsedDrv(i2.first, drv);
PathSet invalid;
for (auto & j : drv.outputs)
@@ -199,7 +197,7 @@ void Store::queryMissing(const PathSet & targets,
invalid.insert(j.second.path);
if (invalid.empty()) return;
if (settings.useSubstitutes && parsedDrv.substitutesAllowed()) {
if (settings.useSubstitutes && drv.substitutesAllowed()) {
auto drvState = make_ref<Sync<DrvState>>(DrvState(invalid.size()));
for (auto & output : invalid)
pool.enqueue(std::bind(checkOutput, i2.first, make_ref<Derivation>(drv), output, drvState));

View File

@@ -108,9 +108,4 @@ bool ParsedDerivation::willBuildLocally() const
return getBoolAttr("preferLocalBuild") && canBuildLocally();
}
bool ParsedDerivation::substitutesAllowed() const
{
return getBoolAttr("allowSubstitutes", true);
}
}

View File

@@ -30,8 +30,6 @@ public:
bool canBuildLocally() const;
bool willBuildLocally() const;
bool substitutesAllowed() const;
};
}

View File

@@ -5,10 +5,9 @@
#include <cerrno>
#include <cstdlib>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <fcntl.h>
namespace nix {
@@ -41,14 +40,17 @@ void deleteLockFile(const Path & path, int fd)
bool lockFile(int fd, LockType lockType, bool wait)
{
int type;
if (lockType == ltRead) type = LOCK_SH;
else if (lockType == ltWrite) type = LOCK_EX;
else if (lockType == ltNone) type = LOCK_UN;
struct flock lock;
if (lockType == ltRead) lock.l_type = F_RDLCK;
else if (lockType == ltWrite) lock.l_type = F_WRLCK;
else if (lockType == ltNone) lock.l_type = F_UNLCK;
else abort();
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0; /* entire file */
if (wait) {
while (flock(fd, type) != 0) {
while (fcntl(fd, F_SETLKW, &lock) != 0) {
checkInterrupt();
if (errno != EINTR)
throw SysError(format("acquiring/releasing lock"));
@@ -56,9 +58,9 @@ bool lockFile(int fd, LockType lockType, bool wait)
return false;
}
} else {
while (flock(fd, type | LOCK_NB) != 0) {
while (fcntl(fd, F_SETLK, &lock) != 0) {
checkInterrupt();
if (errno == EWOULDBLOCK) return false;
if (errno == EACCES || errno == EAGAIN) return false;
if (errno != EINTR)
throw SysError(format("acquiring/releasing lock"));
}
@@ -68,6 +70,14 @@ bool lockFile(int fd, LockType lockType, bool wait)
}
/* This enables us to check whether are not already holding a lock on
a file ourselves. POSIX locks (fcntl) suck in this respect: if we
close a descriptor, the previous lock will be closed as well. And
there is no way to query whether we already have a lock (F_GETLK
only works on locks held by other processes). */
static Sync<StringSet> lockedPaths_;
PathLocks::PathLocks()
: deletePaths(false)
{
@@ -81,7 +91,7 @@ PathLocks::PathLocks(const PathSet & paths, const string & waitMsg)
}
bool PathLocks::lockPaths(const PathSet & paths,
bool PathLocks::lockPaths(const PathSet & _paths,
const string & waitMsg, bool wait)
{
assert(fds.empty());
@@ -89,54 +99,75 @@ bool PathLocks::lockPaths(const PathSet & paths,
/* Note that `fds' is built incrementally so that the destructor
will only release those locks that we have already acquired. */
/* Acquire the lock for each path in sorted order. This ensures
that locks are always acquired in the same order, thus
preventing deadlocks. */
/* Sort the paths. This assures that locks are always acquired in
the same order, thus preventing deadlocks. */
Paths paths(_paths.begin(), _paths.end());
paths.sort();
/* Acquire the lock for each path. */
for (auto & path : paths) {
checkInterrupt();
Path lockPath = path + ".lock";
debug(format("locking path '%1%'") % path);
AutoCloseFD fd;
while (1) {
/* Open/create the lock file. */
fd = openLockFile(lockPath, true);
/* Acquire an exclusive lock. */
if (!lockFile(fd.get(), ltWrite, false)) {
if (wait) {
if (waitMsg != "") printError(waitMsg);
lockFile(fd.get(), ltWrite, true);
} else {
/* Failed to lock this path; release all other
locks. */
unlock();
return false;
}
{
auto lockedPaths(lockedPaths_.lock());
if (lockedPaths->count(lockPath)) {
if (!wait) return false;
throw AlreadyLocked("deadlock: trying to re-acquire self-held lock '%s'", lockPath);
}
debug(format("lock acquired on '%1%'") % lockPath);
/* Check that the lock file hasn't become stale (i.e.,
hasn't been unlinked). */
struct stat st;
if (fstat(fd.get(), &st) == -1)
throw SysError(format("statting lock file '%1%'") % lockPath);
if (st.st_size != 0)
/* This lock file has been unlinked, so we're holding
a lock on a deleted file. This means that other
processes may create and acquire a lock on
`lockPath', and proceed. So we must retry. */
debug(format("open lock file '%1%' has become stale") % lockPath);
else
break;
lockedPaths->insert(lockPath);
}
try {
AutoCloseFD fd;
while (1) {
/* Open/create the lock file. */
fd = openLockFile(lockPath, true);
/* Acquire an exclusive lock. */
if (!lockFile(fd.get(), ltWrite, false)) {
if (wait) {
if (waitMsg != "") printError(waitMsg);
lockFile(fd.get(), ltWrite, true);
} else {
/* Failed to lock this path; release all other
locks. */
unlock();
lockedPaths_.lock()->erase(lockPath);
return false;
}
}
debug(format("lock acquired on '%1%'") % lockPath);
/* Check that the lock file hasn't become stale (i.e.,
hasn't been unlinked). */
struct stat st;
if (fstat(fd.get(), &st) == -1)
throw SysError(format("statting lock file '%1%'") % lockPath);
if (st.st_size != 0)
/* This lock file has been unlinked, so we're holding
a lock on a deleted file. This means that other
processes may create and acquire a lock on
`lockPath', and proceed. So we must retry. */
debug(format("open lock file '%1%' has become stale") % lockPath);
else
break;
}
/* Use borrow so that the descriptor isn't closed. */
fds.push_back(FDPair(fd.release(), lockPath));
} catch (...) {
lockedPaths_.lock()->erase(lockPath);
throw;
}
/* Use borrow so that the descriptor isn't closed. */
fds.push_back(FDPair(fd.release(), lockPath));
}
return true;
@@ -158,6 +189,8 @@ void PathLocks::unlock()
for (auto & i : fds) {
if (deletePaths) deleteLockFile(i.second, i.first);
lockedPaths_.lock()->erase(i.second);
if (close(i.first) == -1)
printError(
format("error (ignored): cannot close lock file on '%1%'") % i.second);
@@ -175,4 +208,11 @@ void PathLocks::setDeletion(bool deletePaths)
}
bool pathIsLockedByMe(const Path & path)
{
Path lockPath = path + ".lock";
return lockedPaths_.lock()->count(lockPath);
}
}

View File

@@ -16,6 +16,8 @@ enum LockType { ltRead, ltWrite, ltNone };
bool lockFile(int fd, LockType lockType, bool wait);
MakeError(AlreadyLocked, Error);
class PathLocks
{
private:
@@ -35,4 +37,6 @@ public:
void setDeletion(bool deletePaths);
};
bool pathIsLockedByMe(const Path & path);
}

View File

@@ -151,7 +151,7 @@ void RemoteStore::initConnection(Connection & conn)
conn.to << PROTOCOL_VERSION;
if (GET_PROTOCOL_MINOR(conn.daemonVersion) >= 14) {
int cpu = sameMachine() && settings.lockCPU ? lockToCurrentCPU() : -1;
int cpu = settings.lockCPU ? lockToCurrentCPU() : -1;
if (cpu != -1)
conn.to << 1 << cpu;
else
@@ -191,14 +191,6 @@ void RemoteStore::setOptions(Connection & conn)
if (GET_PROTOCOL_MINOR(conn.daemonVersion) >= 12) {
std::map<std::string, Config::SettingInfo> overrides;
globalConfig.getSettings(overrides, true);
overrides.erase(settings.keepFailed.name);
overrides.erase(settings.keepGoing.name);
overrides.erase(settings.tryFallback.name);
overrides.erase(settings.maxBuildJobs.name);
overrides.erase(settings.maxSilentTime.name);
overrides.erase(settings.buildCores.name);
overrides.erase(settings.useSubstitutes.name);
overrides.erase(settings.showTrace.name);
conn.to << overrides.size();
for (auto & i : overrides)
conn.to << i.first << i.second.value;
@@ -350,7 +342,7 @@ void RemoteStore::querySubstitutablePathInfos(const PathSet & paths,
void RemoteStore::queryPathInfoUncached(const Path & path,
Callback<std::shared_ptr<ValidPathInfo>> callback) noexcept
Callback<std::shared_ptr<ValidPathInfo>> callback)
{
try {
std::shared_ptr<ValidPathInfo> info;

View File

@@ -29,8 +29,6 @@ public:
const Setting<unsigned int> maxConnectionAge{(Store*) this, std::numeric_limits<unsigned int>::max(),
"max-connection-age", "number of seconds to reuse a connection"};
virtual bool sameMachine() = 0;
RemoteStore(const Params & params);
/* Implementations of abstract store API methods. */
@@ -43,7 +41,7 @@ public:
PathSet queryAllValidPaths() override;
void queryPathInfoUncached(const Path & path,
Callback<std::shared_ptr<ValidPathInfo>> callback) noexcept override;
Callback<std::shared_ptr<ValidPathInfo>> callback) override;
void queryReferrers(const Path & path, PathSet & referrers) override;
@@ -148,9 +146,6 @@ public:
std::string getUri() override;
bool sameMachine()
{ return true; }
private:
ref<RemoteStore::Connection> openConnection() override;

View File

@@ -35,9 +35,6 @@ public:
return uriScheme + host;
}
bool sameMachine()
{ return false; }
void narFromPath(const Path & path, Sink & sink) override;
ref<FSAccessor> getFSAccessor() override;

View File

@@ -33,9 +33,6 @@ std::unique_ptr<SSHMaster::Connection> SSHMaster::startCommand(const std::string
out.create();
auto conn = std::make_unique<Connection>();
ProcessOptions options;
options.dieWithParent = false;
conn->sshPid = startProcess([&]() {
restoreSignals();
@@ -65,9 +62,8 @@ std::unique_ptr<SSHMaster::Connection> SSHMaster::startCommand(const std::string
args.push_back(command);
execvp(args.begin()->c_str(), stringsToCharPtrs(args).data());
// could not exec ssh/bash
throw SysError("unable to execute '%s'", args.front());
}, options);
throw SysError("executing '%s' on '%s'", command, host);
});
in.readSide = -1;
@@ -94,9 +90,6 @@ Path SSHMaster::startMaster()
Pipe out;
out.create();
ProcessOptions options;
options.dieWithParent = false;
state->sshMaster = startProcess([&]() {
restoreSignals();
@@ -115,8 +108,8 @@ Path SSHMaster::startMaster()
addCommonSSHOpts(args);
execvp(args.begin()->c_str(), stringsToCharPtrs(args).data());
throw SysError("unable to execute '%s'", args.front());
}, options);
throw SysError("starting SSH master");
});
out.writeSide = -1;

View File

@@ -85,29 +85,18 @@ string storePathToHash(const Path & path)
void checkStoreName(const string & name)
{
string validChars = "+-._?=";
auto baseError = format("The path name '%2%' is invalid: %3%. "
"Path names are alphanumeric and can include the symbols %1% "
"and must not begin with a period. "
"Note: If '%2%' is a source file and you cannot rename it on "
"disk, builtins.path { name = ... } can be used to give it an "
"alternative name.") % validChars % name;
/* Disallow names starting with a dot for possible security
reasons (e.g., "." and ".."). */
if (string(name, 0, 1) == ".")
throw Error(baseError % "it is illegal to start the name with a period");
/* Disallow names longer than 211 characters. ext4s max is 256,
but we need extra space for the hash and .chroot extensions. */
if (name.length() > 211)
throw Error(baseError % "name must be less than 212 characters");
throw Error(format("illegal name: '%1%'") % name);
for (auto & i : name)
if (!((i >= 'A' && i <= 'Z') ||
(i >= 'a' && i <= 'z') ||
(i >= '0' && i <= '9') ||
validChars.find(i) != string::npos))
{
throw Error(baseError % (format("the '%1%' character is invalid") % i));
throw Error(format("invalid character '%1%' in name '%2%'")
% i % name);
}
}
@@ -329,14 +318,13 @@ ref<const ValidPathInfo> Store::queryPathInfo(const Path & storePath)
void Store::queryPathInfo(const Path & storePath,
Callback<ref<ValidPathInfo>> callback) noexcept
Callback<ref<ValidPathInfo>> callback)
{
std::string hashPart;
assertStorePath(storePath);
auto hashPart = storePathToHash(storePath);
try {
assertStorePath(storePath);
hashPart = storePathToHash(storePath);
{
auto res = state.lock()->pathInfoCache.get(hashPart);
@@ -366,10 +354,8 @@ void Store::queryPathInfo(const Path & storePath,
} catch (...) { return callback.rethrow(); }
auto callbackPtr = std::make_shared<decltype(callback)>(std::move(callback));
queryPathInfoUncached(storePath,
{[this, storePath, hashPart, callbackPtr](std::future<std::shared_ptr<ValidPathInfo>> fut) {
{[this, storePath, hashPart, callback](std::future<std::shared_ptr<ValidPathInfo>> fut) {
try {
auto info = fut.get();
@@ -389,8 +375,8 @@ void Store::queryPathInfo(const Path & storePath,
throw InvalidPath("path '%s' is not valid", storePath);
}
(*callbackPtr)(ref<ValidPathInfo>(info));
} catch (...) { callbackPtr->rethrow(); }
callback(ref<ValidPathInfo>(info));
} catch (...) { callback.rethrow(); }
}});
}

View File

@@ -360,12 +360,12 @@ public:
/* Asynchronous version of queryPathInfo(). */
void queryPathInfo(const Path & path,
Callback<ref<ValidPathInfo>> callback) noexcept;
Callback<ref<ValidPathInfo>> callback);
protected:
virtual void queryPathInfoUncached(const Path & path,
Callback<std::shared_ptr<ValidPathInfo>> callback) noexcept = 0;
Callback<std::shared_ptr<ValidPathInfo>> callback) = 0;
public:
@@ -561,7 +561,7 @@ public:
unsigned long long & downloadSize, unsigned long long & narSize);
/* Sort a set of paths topologically under the references
relation. If p refers to q, then p precedes q in this list. */
relation. If p refers to q, then p preceeds q in this list. */
Paths topoSortPaths(const PathSet & paths);
/* Export multiple paths in the format expected by nix-store
@@ -628,9 +628,6 @@ public:
return storePath;
}
virtual void createUser(const std::string & userName, uid_t userId)
{ }
protected:
Stats stats;
@@ -769,7 +766,8 @@ StoreType getStoreType(const std::string & uri = settings.storeUri.get(),
const std::string & stateDir = settings.nixStateDir);
/* Return the default substituter stores, defined by the
substituters option and various legacy options. */
substituters option and various legacy options like
binary-caches. */
std::list<ref<Store>> getDefaultSubstituters();

View File

@@ -6,4 +6,4 @@ libutil_DIR := $(d)
libutil_SOURCES := $(wildcard $(d)/*.cc)
libutil_LDFLAGS = $(LIBLZMA_LIBS) -lbz2 -pthread $(OPENSSL_LIBS) $(LIBBROTLI_LIBS) $(BOOST_LDFLAGS) -lboost_context
libutil_LDFLAGS = $(LIBLZMA_LIBS) -lbz2 -pthread $(OPENSSL_LIBS) $(LIBBROTLI_LIBS) -lboost_context

View File

@@ -21,7 +21,7 @@ Logger * logger = makeDefaultLogger();
void Logger::warn(const std::string & msg)
{
log(lvlWarn, ANSI_RED "warning:" ANSI_NORMAL " " + msg);
log(lvlInfo, ANSI_RED "warning:" ANSI_NORMAL " " + msg);
}
class SimpleLogger : public Logger
@@ -46,7 +46,6 @@ public:
char c;
switch (lvl) {
case lvlError: c = '3'; break;
case lvlWarn: c = '4'; break;
case lvlInfo: c = '5'; break;
case lvlTalkative: case lvlChatty: c = '6'; break;
default: c = '7';

View File

@@ -6,7 +6,6 @@ namespace nix {
typedef enum {
lvlError = 0,
lvlWarn,
lvlInfo,
lvlTalkative,
lvlChatty,
@@ -26,7 +25,6 @@ typedef enum {
actVerifyPaths = 107,
actSubstitute = 108,
actQueryPathInfo = 109,
actPostBuildHook = 110,
} ActivityType;
typedef enum {
@@ -37,7 +35,6 @@ typedef enum {
resSetPhase = 104,
resProgress = 105,
resSetExpected = 106,
resPostBuildLogLine = 107,
} ResultType;
typedef uint64_t ActivityId;

View File

@@ -179,36 +179,6 @@ struct TeeSource : Source
}
};
/* A reader that consumes the original Source until 'size'. */
struct SizedSource : Source
{
Source & orig;
size_t remain;
SizedSource(Source & orig, size_t size)
: orig(orig), remain(size) { }
size_t read(unsigned char * data, size_t len)
{
if (this->remain <= 0) {
throw EndOfFile("sized: unexpected end-of-file");
}
len = std::min(len, this->remain);
size_t n = this->orig.read(data, len);
this->remain -= n;
return n;
}
/* Consume the original source until no remain data is left to consume. */
size_t drainAll()
{
std::vector<unsigned char> buf(8192);
size_t sum = 0;
while (this->remain > 0) {
size_t n = read(buf.data(), buf.size());
sum += n;
}
return sum;
}
};
/* Convert a function into a sink. */
struct LambdaSink : Sink

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