Compare commits

..

31 Commits
unique ... 2.1

Author SHA1 Message Date
Eelco Dolstra
b4441c9690 Release notes tweaks
(cherry picked from commit 4dd09210d7)
2018-09-02 21:47:53 +02:00
Graham Christensen
eb40c23dfd Create upgrade notes
(cherry picked from commit c42eaaf684)
2018-09-01 23:30:16 +02:00
Graham Christensen
7fe614b5c9 release notes: note that the multi-user installer is available but not selected for Linux with systemd, and the bug about selinux
(cherry picked from commit 4be7652dd3)
2018-09-01 23:30:16 +02:00
Graham Christensen
95ed61c990 Default to single-user install
(cherry picked from commit 51f9682a8b)
2018-09-01 23:30:16 +02:00
Graham Christensen
93cae69725 Document the multi-user installer some
Use sh <(...) syntax for installation to preserve stdin and prompting

also update installation docs to account for changes in multi-user selection

(cherry picked from commit c3e508d924)
2018-09-01 23:30:16 +02:00
Graham Christensen
a4a72c0152 We support aarch64 now
(cherry picked from commit f66fa7cd20)
2018-09-01 23:30:15 +02:00
Graham Christensen
348a2eb84a nix-build: Print stats even in failing builds
(cherry picked from commit 87702532d2)
2018-09-01 23:30:15 +02:00
Graham Christensen
958e037a08 nix-build: print stats on sucessful builds
(cherry picked from commit b7bb627f67)
2018-09-01 23:30:15 +02:00
Graham Christensen
75a041c36c Drop ssh://... as a required formatting for builtins.fetchGit
(cherry picked from commit 0b7568fb73)
2018-09-01 23:29:51 +02:00
Eelco Dolstra
6202ffdce9 fetchGit/fetchMercurial: Don't absolutize paths
This is already done by coerceToString(), provided that the argument
is a path (e.g. 'fetchGit ./bla'). It fixes the handling of URLs like
git@github.com:owner/repo.git. It breaks 'fetchGit "./bla"', but that
was never intended to work anyway and is inconsistent with other
builtin functions (e.g. 'readFile "./bla"' fails).

(cherry picked from commit 475a0a54a9)
2018-09-01 23:29:51 +02:00
Eelco Dolstra
d2339af44c nix path-info: Remove trailing spaces
Fixes #2390.

(cherry picked from commit b7409c5754)
2018-09-01 23:29:37 +02:00
Eelco Dolstra
b71789885a Add contributors
(cherry picked from commit 4095cd6438)
2018-09-01 23:29:37 +02:00
Graham Christensen
165743b8bf docs: Add IDs to important sections
(cherry picked from commit 149d10c308)
2018-09-01 23:29:37 +02:00
Graham Christensen
81028d5b87 docs: Add some examples to fetchGit
(cherry picked from commit 2df21b78b9)
2018-09-01 23:29:37 +02:00
Graham Christensen
d3088a64db manual: document why ~/.netrc doesn't work
Maybe there is a better place to document this, which is more generic?

(cherry picked from commit 33712fed38)
2018-09-01 23:29:01 +02:00
Niklas Hambüchen
d853b57991 manual: distributed-builds: Mention - as default
(cherry picked from commit 10ebcf8670)
2018-09-01 23:29:01 +02:00
Symphorien Gibol
1d619967ef add manual entries for disallowedRequisites and disallowedReferences
(cherry picked from commit 81d1385437)
2018-09-01 23:29:01 +02:00
Erik Arvstedt
8115c10e59 Docs: Fix install prefix
shell.nix defines the install prefix as $(pwd)/inst

(cherry picked from commit 8ad2defdf0)
2018-08-31 16:12:27 +02:00
Eelco Dolstra
b7a37ab5f2 nix upgrade-nix: Handle .nix-profile being a link to .../profiles/per-user/...
Also some cosmetic improvements.

(cherry picked from commit 39f1722f36)
2018-08-31 16:12:11 +02:00
Eelco Dolstra
f8fbab43f2 nix upgrade-nix: Improve error message if 'nix' is not in a profile
E.g.

  $ nix upgrade-nix
  error: directory '/home/eelco/Dev/nix/inst/bin' does not appear to be part of a Nix profile

instead of

  $ nix upgrade-nix
  error: '/home/eelco/Dev/nix/inst' is not a symlink

(cherry picked from commit f08b14c9d0)
2018-08-31 16:12:11 +02:00
Eelco Dolstra
d7b2c6c92f Add simple test for nix upgrade-nix
(cherry picked from commit 264e66f696)
2018-08-31 16:12:11 +02:00
Michael Bishop
8b0761b172 fix error: unknown serve command 9
(cherry picked from commit 0767e402f1)
2018-08-31 16:12:11 +02:00
Daiderd Jordan
2b25ffbd49 upgrade-nix: resolve profile symlinks
The profile present in PATH is not necessarily the actual profile
location. User profiles are generally added as $HOME/.nix-profile
in which case the indirect profile link needs to be resolved first.

/home/user/.nix-profile -> /nix/var/nix/profiles/per-user/user/profile
/nix/var/nix/profiles/per-user/user/profile -> profile-15-link
/nix/var/nix/profiles/per-user/user/profile-14-link -> /nix/store/hyi4kkjh3bwi2z3wfljrkfymz9904h62-user-environment
/nix/var/nix/profiles/per-user/user/profile-15-link -> /nix/store/6njpl3qvihz46vj911pwx7hfcvwhifl9-user-environment

To upgrade nix here we want /nix/var/nix/profiles/per-user/user/profile-16-link
instead of /home/user/.nix-profile-1-link. The latter is not a gcroot
and would be garbage collected, resulting in a broken profile.

Fixes #2175

(cherry picked from commit d85bb4814f)
2018-08-31 16:12:11 +02:00
Daiderd Jordan
88d2e298f5 upgrade-nix: add --dry-run
(cherry picked from commit 414397759a)
2018-08-31 16:12:11 +02:00
Eelco Dolstra
1fceed528d nix: Remove the -h flag
(cherry picked from commit 5e83b0227f)
2018-08-31 16:11:09 +02:00
Eelco Dolstra
b542267d18 Remove boost from the closure
This reduces the size of the closure by 45 MiB.

(cherry picked from commit 145db703e5)
2018-08-31 16:11:09 +02:00
Eelco Dolstra
e76eec86bd Update release notes
(cherry picked from commit 64d7d1a884)
2018-08-31 16:11:06 +02:00
Eelco Dolstra
25af916eb4 Revert "Fix parser/lexer generation with parallel make"
This reverts commit d277442df5.

Make sucks.

(cherry picked from commit c651b7bdc9)
2018-08-30 12:48:48 +02:00
Tuomas Tynkkynen
0107a8f6d4 Drop all references to NIX_INDENT_MAKE
Dead code since 6669a3b477

(cherry picked from commit 2894197de7)
2018-08-30 12:48:32 +02:00
Tuomas Tynkkynen
c2dcc102e4 Drop all references to --disable-init-state
It's all dead code since 2014 (commit 0c6d62cf27).

(cherry picked from commit 458282be59)
2018-08-30 12:48:32 +02:00
Ivan Kozik
9280d11e54 repl: don't add trailing spaces to history lines
(cherry picked from commit ec49ea28dc)
2018-08-30 12:48:28 +02:00
145 changed files with 8866 additions and 11274 deletions

3
.gitignore vendored
View File

@@ -81,9 +81,6 @@ perl/Makefile.config
/tests/common.sh
/tests/dummy
/tests/result*
/tests/restricted-innocent
/tests/shell
/tests/shell.drv
# /tests/lang/
/tests/lang/*.out

View File

@@ -1 +0,0 @@
2.3

View File

@@ -5,7 +5,17 @@ makefiles = \
src/libmain/local.mk \
src/libexpr/local.mk \
src/nix/local.mk \
src/nix-store/local.mk \
src/nix-instantiate/local.mk \
src/nix-env/local.mk \
src/nix-daemon/local.mk \
src/nix-collect-garbage/local.mk \
src/nix-copy-closure/local.mk \
src/nix-prefetch-url/local.mk \
src/resolve-system-dependencies/local.mk \
src/nix-channel/local.mk \
src/nix-build/local.mk \
src/build-remote/local.mk \
scripts/local.mk \
corepkgs/local.mk \
misc/systemd/local.mk \

View File

@@ -1,6 +1,4 @@
AR = @AR@
BDW_GC_LIBS = @BDW_GC_LIBS@
BUILD_SHARED_LIBS = @BUILD_SHARED_LIBS@
CC = @CC@
CFLAGS = @CFLAGS@
CXX = @CXX@
@@ -17,9 +15,9 @@ SODIUM_LIBS = @SODIUM_LIBS@
LIBLZMA_LIBS = @LIBLZMA_LIBS@
SQLITE3_LIBS = @SQLITE3_LIBS@
LIBBROTLI_LIBS = @LIBBROTLI_LIBS@
EDITLINE_LIBS = @EDITLINE_LIBS@
bash = @bash@
bindir = @bindir@
brotli = @brotli@
lsof = @lsof@
datadir = @datadir@
datarootdir = @datarootdir@

View File

@@ -1,4 +1,4 @@
AC_INIT(nix, m4_esyscmd([bash -c "echo -n $(cat ./.version)$VERSION_SUFFIX"]))
AC_INIT(nix, m4_esyscmd([bash -c "echo -n $(cat ./version)$VERSION_SUFFIX"]))
AC_CONFIG_SRCDIR(README.md)
AC_CONFIG_AUX_DIR(config)
@@ -62,9 +62,8 @@ CXXFLAGS=
AC_PROG_CC
AC_PROG_CXX
AC_PROG_CPP
AX_CXX_COMPILE_STDCXX_17
AX_CXX_COMPILE_STDCXX_14
AC_CHECK_TOOL([AR], [ar])
# Use 64-bit file system calls so that we can support files > 2 GiB.
AC_SYS_LARGEFILE
@@ -128,6 +127,8 @@ NEED_PROG(bzip2, bzip2)
NEED_PROG(gzip, gzip)
NEED_PROG(xz, xz)
AC_PATH_PROG(dot, dot)
AC_PATH_PROG(pv, pv, pv)
AC_PATH_PROGS(brotli, brotli bro, bro)
AC_PATH_PROG(lsof, lsof, lsof)
@@ -151,9 +152,9 @@ PKG_CHECK_MODULES([OPENSSL], [libcrypto], [CXXFLAGS="$OPENSSL_CFLAGS $CXXFLAGS"]
# Look for libbz2, a required dependency.
AC_CHECK_LIB([bz2], [BZ2_bzWriteOpen], [true],
[AC_MSG_ERROR([Nix requires libbz2, which is part of bzip2. See https://web.archive.org/web/20180624184756/http://www.bzip.org/.])])
[AC_MSG_ERROR([Nix requires libbz2, which is part of bzip2. See http://www.bzip.org/.])])
AC_CHECK_HEADERS([bzlib.h], [true],
[AC_MSG_ERROR([Nix requires libbz2, which is part of bzip2. See https://web.archive.org/web/20180624184756/http://www.bzip.org/.])])
[AC_MSG_ERROR([Nix requires libbz2, which is part of bzip2. See http://www.bzip.org/.])])
# Look for SQLite, a required dependency.
@@ -163,8 +164,6 @@ PKG_CHECK_MODULES([SQLITE3], [sqlite3 >= 3.6.19], [CXXFLAGS="$SQLITE3_CFLAGS $CX
# Look for libcurl, a required dependency.
PKG_CHECK_MODULES([LIBCURL], [libcurl], [CXXFLAGS="$LIBCURL_CFLAGS $CXXFLAGS"])
# Look for editline, a required dependency.
PKG_CHECK_MODULES([EDITLINE], [libeditline], [CXXFLAGS="$EDITLINE_CFLAGS $CXXFLAGS"])
# Look for libsodium, an optional dependency.
PKG_CHECK_MODULES([SODIUM], [libsodium],
@@ -252,6 +251,11 @@ if test "$(uname)" = "Darwin"; then
fi
# Figure out the extension of dynamic libraries.
eval dynlib_suffix=$shrext_cmds
AC_SUBST(dynlib_suffix)
# Do we have GNU tar?
AC_MSG_CHECKING([if you have a recent GNU tar])
if $tar --version 2> /dev/null | grep -q GNU && tar cvf /dev/null --warning=no-timestamp ./config.log > /dev/null; then
@@ -268,15 +272,6 @@ AC_ARG_WITH(sandbox-shell, AC_HELP_STRING([--with-sandbox-shell=PATH],
sandbox_shell=$withval)
AC_SUBST(sandbox_shell)
AC_ARG_ENABLE(shared, AC_HELP_STRING([--enable-shared],
[Build shared libraries for Nix [default=yes]]),
shared=$enableval, shared=yes)
if test "$shared" = yes; then
AC_SUBST(BUILD_SHARED_LIBS, 1, [Whether to build shared libraries.])
else
AC_SUBST(BUILD_SHARED_LIBS, 0, [Whether to build shared libraries.])
fi
# Expand all variables in config.status.
test "$prefix" = NONE && prefix=$ac_default_prefix

View File

@@ -1,14 +1,10 @@
{ system ? "" # obsolete
, url
, hash ? "" # an SRI ash
# Legacy hash specification
, md5 ? "", sha1 ? "", sha256 ? "", sha512 ? ""
, outputHash ?
if hash != "" then hash else if sha512 != "" then sha512 else if sha1 != "" then sha1 else if md5 != "" then md5 else sha256
if sha512 != "" then sha512 else if sha1 != "" then sha1 else if md5 != "" then md5 else sha256
, outputHashAlgo ?
if hash != "" then "" else if sha512 != "" then "sha512" else if sha1 != "" then "sha1" else if md5 != "" then "md5" else "sha256"
if sha512 != "" then "sha512" else if sha1 != "" then "sha1" else if md5 != "" then "md5" else "sha256"
, executable ? false
, unpack ? false
, name ? baseNameOf (toString url)

View File

@@ -180,8 +180,4 @@ builders = @/etc/nix/machines
causes the list of machines in <filename>/etc/nix/machines</filename>
to be included. (This is the default.)</para>
<para>If you want the builders to use caches, you likely want to set
the option <link linkend='conf-builders-use-substitutes'><literal>builders-use-substitutes</literal></link>
in your local <filename>nix.conf</filename>.</para>
</chapter>

View File

@@ -135,6 +135,7 @@ false</literal>.</para>
</varlistentry>
<varlistentry xml:id="conf-builders">
<term><literal>builders</literal></term>
<listitem>
@@ -158,6 +159,7 @@ false</literal>.</para>
</varlistentry>
<varlistentry xml:id="conf-build-users-group"><term><literal>build-users-group</literal></term>
<listitem><para>This options specifies the Unix group containing
@@ -208,6 +210,7 @@ false</literal>.</para>
</varlistentry>
<varlistentry xml:id="conf-connect-timeout"><term><literal>connect-timeout</literal></term>
<listitem>
@@ -240,6 +243,7 @@ false</literal>.</para>
</varlistentry>
<varlistentry xml:id="conf-extra-sandbox-paths">
<term><literal>extra-sandbox-paths</literal></term>
@@ -279,6 +283,7 @@ false</literal>.</para>
</varlistentry>
<varlistentry xml:id="conf-fallback"><term><literal>fallback</literal></term>
<listitem><para>If set to <literal>true</literal>, Nix will fall
@@ -288,6 +293,7 @@ false</literal>.</para>
</varlistentry>
<varlistentry xml:id="conf-fsync-metadata"><term><literal>fsync-metadata</literal></term>
<listitem><para>If set to <literal>true</literal>, changes to the
@@ -298,6 +304,7 @@ false</literal>.</para>
</varlistentry>
<varlistentry xml:id="conf-hashed-mirrors"><term><literal>hashed-mirrors</literal></term>
<listitem><para>A list of web servers used by
@@ -360,8 +367,10 @@ builtins.fetchurl {
options a store path was built), so by default this option is on.
Turn it off to save a bit of disk space (or a lot if
<literal>keep-outputs</literal> is also turned on).</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-keep-env-derivations"><term><literal>keep-env-derivations</literal></term>
<listitem><para>If <literal>false</literal> (default), derivations
@@ -385,6 +394,7 @@ builtins.fetchurl {
</varlistentry>
<varlistentry xml:id="conf-keep-outputs"><term><literal>keep-outputs</literal></term>
<listitem><para>If <literal>true</literal>, the garbage collector
@@ -398,8 +408,10 @@ builtins.fetchurl {
only at build time (e.g., the C compiler, or source tarballs
downloaded from the network). To prevent it from doing so, set
this option to <literal>true</literal>.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-max-build-log-size"><term><literal>max-build-log-size</literal></term>
<listitem>
@@ -425,15 +437,14 @@ builtins.fetchurl {
<listitem><para>This option defines the maximum number of jobs
that Nix will try to build in parallel. The default is
<literal>1</literal>. The special value <literal>auto</literal>
causes Nix to use the number of CPUs in your system. <literal>0</literal>
is useful when using remote builders to prevent any local builds (except for
<literal>preferLocalBuild</literal> derivation attribute which executes locally
regardless). It can be
causes Nix to use the number of CPUs in your system. It can be
overridden using the <option
linkend='opt-max-jobs'>--max-jobs</option> (<option>-j</option>)
command line switch.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-max-silent-time"><term><literal>max-silent-time</literal></term>
<listitem>
@@ -589,6 +600,7 @@ password <replaceable>my-password</replaceable>
</varlistentry>
<varlistentry xml:id="conf-repeat"><term><literal>repeat</literal></term>
<listitem><para>How many times to repeat builds to check whether
@@ -600,6 +612,7 @@ password <replaceable>my-password</replaceable>
</varlistentry>
<varlistentry xml:id="conf-require-sigs"><term><literal>require-sigs</literal></term>
<listitem><para>If set to <literal>true</literal> (the default),
@@ -657,13 +670,13 @@ password <replaceable>my-password</replaceable>
<varname>__noChroot</varname> attribute set to
<literal>true</literal> do not run in sandboxes.</para>
<para>The default is <literal>true</literal> on Linux and
<literal>false</literal> on all other platforms.</para>
<para>The default is <literal>false</literal>.</para>
</listitem>
</varlistentry>
<varlistentry xml:id="conf-sandbox-dev-shm-size"><term><literal>sandbox-dev-shm-size</literal></term>
<listitem><para>This option determines the maximum size of the
@@ -729,6 +742,7 @@ password <replaceable>my-password</replaceable>
</varlistentry>
<varlistentry xml:id="conf-substituters"><term><literal>substituters</literal></term>
<listitem><para>A list of URLs of substituters, separated by
@@ -737,6 +751,7 @@ password <replaceable>my-password</replaceable>
</varlistentry>
<varlistentry xml:id="conf-system"><term><literal>system</literal></term>
<listitem><para>This option specifies the canonical Nix system
@@ -758,33 +773,6 @@ password <replaceable>my-password</replaceable>
</varlistentry>
<varlistentry xml:id="conf-system-features"><term><literal>system-features</literal></term>
<listitem><para>A set of system “features” supported by this
machine, e.g. <literal>kvm</literal>. Derivations can express a
dependency on such features through the derivation attribute
<varname>requiredSystemFeatures</varname>. For example, the
attribute
<programlisting>
requiredSystemFeatures = [ "kvm" ];
</programlisting>
ensures that the derivation can only be built on a machine with
the <literal>kvm</literal> feature.</para>
<para>This setting by default includes <literal>kvm</literal> if
<filename>/dev/kvm</filename> is accessible, and the
pseudo-features <literal>nixos-test</literal>,
<literal>benchmark</literal> and <literal>big-parallel</literal>
that are used in Nixpkgs to route builds to specific
machines.</para>
</listitem>
</varlistentry>
<varlistentry xml:id="conf-timeout"><term><literal>timeout</literal></term>
<listitem>
@@ -804,6 +792,7 @@ requiredSystemFeatures = [ "kvm" ];
</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
@@ -814,6 +803,7 @@ requiredSystemFeatures = [ "kvm" ];
</varlistentry>
<varlistentry xml:id="conf-trusted-substituters"><term><literal>trusted-substituters</literal></term>
<listitem><para>A list of URLs of substituters, separated by
@@ -826,6 +816,7 @@ requiredSystemFeatures = [ "kvm" ];
</varlistentry>
<varlistentry xml:id="conf-trusted-users"><term><literal>trusted-users</literal></term>
<listitem>
@@ -851,178 +842,9 @@ requiredSystemFeatures = [ "kvm" ];
</varlistentry>
</variablelist>
</para>
<refsection>
<title>Deprecated Settings</title>
<para>
<variablelist>
<varlistentry xml:id="conf-binary-caches">
<term><literal>binary-caches</literal></term>
<listitem><para><emphasis>Deprecated:</emphasis>
<literal>binary-caches</literal> is now an alias to
<xref linkend="conf-substituters" />.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-binary-cache-public-keys">
<term><literal>binary-cache-public-keys</literal></term>
<listitem><para><emphasis>Deprecated:</emphasis>
<literal>binary-cache-public-keys</literal> is now an alias to
<xref linkend="conf-trusted-public-keys" />.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-build-compress-log">
<term><literal>build-compress-log</literal></term>
<listitem><para><emphasis>Deprecated:</emphasis>
<literal>build-compress-log</literal> is now an alias to
<xref linkend="conf-compress-build-log" />.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-build-cores">
<term><literal>build-cores</literal></term>
<listitem><para><emphasis>Deprecated:</emphasis>
<literal>build-cores</literal> is now an alias to
<xref linkend="conf-cores" />.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-build-extra-chroot-dirs">
<term><literal>build-extra-chroot-dirs</literal></term>
<listitem><para><emphasis>Deprecated:</emphasis>
<literal>build-extra-chroot-dirs</literal> is now an alias to
<xref linkend="conf-extra-sandbox-paths" />.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-build-extra-sandbox-paths">
<term><literal>build-extra-sandbox-paths</literal></term>
<listitem><para><emphasis>Deprecated:</emphasis>
<literal>build-extra-sandbox-paths</literal> is now an alias to
<xref linkend="conf-extra-sandbox-paths" />.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-build-fallback">
<term><literal>build-fallback</literal></term>
<listitem><para><emphasis>Deprecated:</emphasis>
<literal>build-fallback</literal> is now an alias to
<xref linkend="conf-fallback" />.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-build-max-jobs">
<term><literal>build-max-jobs</literal></term>
<listitem><para><emphasis>Deprecated:</emphasis>
<literal>build-max-jobs</literal> is now an alias to
<xref linkend="conf-max-jobs" />.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-build-max-log-size">
<term><literal>build-max-log-size</literal></term>
<listitem><para><emphasis>Deprecated:</emphasis>
<literal>build-max-log-size</literal> is now an alias to
<xref linkend="conf-max-build-log-size" />.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-build-max-silent-time">
<term><literal>build-max-silent-time</literal></term>
<listitem><para><emphasis>Deprecated:</emphasis>
<literal>build-max-silent-time</literal> is now an alias to
<xref linkend="conf-max-silent-time" />.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-build-repeat">
<term><literal>build-repeat</literal></term>
<listitem><para><emphasis>Deprecated:</emphasis>
<literal>build-repeat</literal> is now an alias to
<xref linkend="conf-repeat" />.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-build-timeout">
<term><literal>build-timeout</literal></term>
<listitem><para><emphasis>Deprecated:</emphasis>
<literal>build-timeout</literal> is now an alias to
<xref linkend="conf-timeout" />.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-build-use-chroot">
<term><literal>build-use-chroot</literal></term>
<listitem><para><emphasis>Deprecated:</emphasis>
<literal>build-use-chroot</literal> is now an alias to
<xref linkend="conf-sandbox" />.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-build-use-sandbox">
<term><literal>build-use-sandbox</literal></term>
<listitem><para><emphasis>Deprecated:</emphasis>
<literal>build-use-sandbox</literal> is now an alias to
<xref linkend="conf-sandbox" />.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-build-use-substitutes">
<term><literal>build-use-substitutes</literal></term>
<listitem><para><emphasis>Deprecated:</emphasis>
<literal>build-use-substitutes</literal> is now an alias to
<xref linkend="conf-substitute" />.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-gc-keep-derivations">
<term><literal>gc-keep-derivations</literal></term>
<listitem><para><emphasis>Deprecated:</emphasis>
<literal>gc-keep-derivations</literal> is now an alias to
<xref linkend="conf-keep-derivations" />.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-gc-keep-outputs">
<term><literal>gc-keep-outputs</literal></term>
<listitem><para><emphasis>Deprecated:</emphasis>
<literal>gc-keep-outputs</literal> is now an alias to
<xref linkend="conf-keep-outputs" />.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-env-keep-derivations">
<term><literal>env-keep-derivations</literal></term>
<listitem><para><emphasis>Deprecated:</emphasis>
<literal>env-keep-derivations</literal> is now an alias to
<xref linkend="conf-keep-env-derivations" />.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-extra-binary-caches">
<term><literal>extra-binary-caches</literal></term>
<listitem><para><emphasis>Deprecated:</emphasis>
<literal>extra-binary-caches</literal> is now an alias to
<xref linkend="conf-extra-substituters" />.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-trusted-binary-caches">
<term><literal>trusted-binary-caches</literal></term>
<listitem><para><emphasis>Deprecated:</emphasis>
<literal>trusted-binary-caches</literal> is now an alias to
<xref linkend="conf-trusted-substituters" />.</para></listitem>
</varlistentry>
</variablelist>
</para>
</refsection>
</refsection>
</refentry>

View File

@@ -52,15 +52,10 @@ nixpkgs=/home/eelco/Dev/nixpkgs-branch:/etc/nixos</screen>
<envar>NIX_PATH</envar> to
<screen>
nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/nixos-15.09.tar.gz</screen>
nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/nixos-14.12.tar.gz</screen>
tells Nix to download the latest revision in the Nixpkgs/NixOS
15.09 channel.</para>
<para>A following shorthand can be used to refer to the official channels:
<screen>nixpkgs=channel:nixos-15.09</screen>
</para>
14.12 channel.</para>
<para>The search path can be extended using the <option
linkend="opt-I">-I</option> option, which takes precedence over

View File

@@ -95,6 +95,15 @@ those paths. If this bothers you, use
</varlistentry>
<!--
<varlistentry><term><option>- -show-progress</option></term>
<listitem><para>Show the progress of each path's transfer as it's made.
This requires the <command>pv</command> utility to be in <envar>PATH</envar>.</para></listitem>
</varlistentry>
-->
<varlistentry><term><option>--include-outputs</option></term>
<listitem><para>Also copy the outputs of store derivations

View File

@@ -154,9 +154,7 @@ input.</para>
<listitem><para>When used with <option>--eval</option>, perform
evaluation in read/write mode so nix language features that
require it will still work (at the cost of needing to do
instantiation of every evaluated derivation). If this option is
not enabled, there may be uninstantiated store paths in the final
output.</para>
instantiation of every evaluated derivation).</para>
</listitem>

View File

@@ -317,28 +317,13 @@ while (my $token = $p->get_tag("a")) {
</para>
<para>Sometimes you need to pass a simple Nix expression to customize
a package like Terraform:
<para>Finally, the following Haskell script uses a specific branch of
Nixpkgs/NixOS (the 14.12 stable branch):
<programlisting><![CDATA[
#! /usr/bin/env nix-shell
#! nix-shell -i bash -p "terraform.withPlugins (plugins: [ plugins.openstack ])"
terraform apply
]]></programlisting>
<note><para>You must use double quotes (<literal>"</literal>) when
passing a simple Nix expression in a nix-shell shebang.</para></note>
</para>
<para>Finally, using the merging of multiple nix-shell shebangs the
following Haskell script uses a specific branch of Nixpkgs/NixOS (the
18.03 stable branch):
<programlisting><![CDATA[
#! /usr/bin/env nix-shell
#! nix-shell -i runghc -p "haskellPackages.ghcWithPackages (ps: [ps.HTTP ps.tagsoup])"
#! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/nixos-18.03.tar.gz
#! nix-shell -i runghc -p haskellPackages.ghc haskellPackages.HTTP haskellPackages.tagsoup
#! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/nixos-14.12.tar.gz
import Network.HTTP
import Text.HTML.TagSoup

View File

@@ -275,7 +275,7 @@ as a means of providing Nix store access to a restricted ssh user.
<listitem><para>Allow the connected client to request the realization
of derivations. In effect, this can be used to make the host act
as a remote builder.</para></listitem>
as a build slave.</para></listitem>
</varlistentry>
@@ -679,18 +679,6 @@ query is applied to the target of the symlink.</para>
</varlistentry>
<varlistentry><term><option>--graphml</option></term>
<listitem><para>Prints the references graph of the store paths
<replaceable>paths</replaceable> in the <link
xlink:href="http://graphml.graphdrawing.org/">GraphML</link> file format.
This can be used to visualise dependency graphs. To obtain a
build-time dependency graph, apply this to a store derivation. To
obtain a runtime dependency graph, apply it to an output
path.</para></listitem>
</varlistentry>
<varlistentry><term><option>--binding</option> <replaceable>name</replaceable></term>
<term><option>-b</option> <replaceable>name</replaceable></term>
@@ -1282,7 +1270,6 @@ ktorrent-2.2.1/NEWS
<cmdsynopsis>
<command>nix-store</command>
<arg choice='plain'><option>--dump-db</option></arg>
<arg rep='repeat'><replaceable>paths</replaceable></arg>
</cmdsynopsis>
</refsection>
@@ -1293,13 +1280,6 @@ Nix database to standard output. It can be loaded into an empty Nix
store using <option>--load-db</option>. This is useful for making
backups and when migrating to different database schemas.</para>
<para>By default, <option>--dump-db</option> will dump the entire Nix
database. When one or more store paths is passed, only the subset of
the Nix database for those store paths is dumped. As with
<option>--export</option>, the user is responsible for passing all the
store paths for a closure. See <option>--export</option> for an
example.</para>
</refsection>
</refsection>

View File

@@ -216,7 +216,7 @@ fetchurl {
<programlisting>
{ stdenv, curl }: # The <command>curl</command> program is used for downloading.
{ url, sha256 }:
{ url, md5 }:
stdenv.mkDerivation {
name = baseNameOf (toString url);
@@ -224,10 +224,10 @@ stdenv.mkDerivation {
buildInputs = [ curl ];
# This is a fixed-output derivation; the output must be a regular
# file with SHA256 hash <varname>sha256</varname>.
# file with MD5 hash <varname>md5</varname>.
outputHashMode = "flat";
outputHashAlgo = "sha256";
outputHash = sha256;
outputHashAlgo = "md5";
outputHash = md5;
inherit url;
}
@@ -237,8 +237,8 @@ stdenv.mkDerivation {
<para>The <varname>outputHashAlgo</varname> attribute specifies
the hash algorithm used to compute the hash. It can currently be
<literal>"sha1"</literal>, <literal>"sha256"</literal> or
<literal>"sha512"</literal>.</para>
<literal>"md5"</literal>, <literal>"sha1"</literal> or
<literal>"sha256"</literal>.</para>
<para>The <varname>outputHashMode</varname> attribute determines
how the hash is computed. It must be one of the following two
@@ -251,7 +251,7 @@ stdenv.mkDerivation {
<listitem><para>The output must be a non-executable regular
file. If it isnt, the build fails. The hash is simply
computed over the contents of that file (so its equal to what
Unix commands like <command>sha256sum</command> or
Unix commands like <command>md5sum</command> or
<command>sha1sum</command> produce).</para>
<para>This is the default.</para></listitem>
@@ -312,7 +312,9 @@ big = "a very long string";
<varlistentry><term><varname>preferLocalBuild</varname></term>
<listitem><para>If this attribute is set to
<literal>true</literal> and <link
<literal>true</literal>, it has two effects. First, the
derivation will always be built, not substituted, even if a
substitute is available. Second, if <link
linkend="chap-distributed-builds">distributed building is
enabled</link>, then, if possible, the derivaton will be built
locally instead of forwarded to a remote machine. This is
@@ -322,19 +324,6 @@ big = "a very long string";
</varlistentry>
<varlistentry><term><varname>allowSubstitutes</varname></term>
<listitem><para>If this attribute is set to
<literal>false</literal>, then Nix will always build this
derivation; it will not try to substitute its outputs. This is
useful for very trivial derivations (such as
<function>writeText</function> in Nixpkgs) that are cheaper to
build than to substitute from a binary cache.</para></listitem>
</varlistentry>
</variablelist>
</section>

View File

@@ -21,9 +21,7 @@ available as <function>builtins.derivation</function>.</para>
<variablelist>
<varlistentry xml:id='builtin-abort'>
<term><function>abort</function> <replaceable>s</replaceable></term>
<term><function>builtins.abort</function> <replaceable>s</replaceable></term>
<varlistentry><term><function>abort</function> <replaceable>s</replaceable></term>
<listitem><para>Abort Nix expression evaluation, print error
message <replaceable>s</replaceable>.</para></listitem>
@@ -31,10 +29,8 @@ available as <function>builtins.derivation</function>.</para>
</varlistentry>
<varlistentry xml:id='builtin-add'>
<term><function>builtins.add</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable>
</term>
<varlistentry><term><function>builtins.add</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<listitem><para>Return the sum of the numbers
<replaceable>e1</replaceable> and
@@ -43,9 +39,8 @@ available as <function>builtins.derivation</function>.</para>
</varlistentry>
<varlistentry xml:id='builtin-all'>
<term><function>builtins.all</function>
<replaceable>pred</replaceable> <replaceable>list</replaceable></term>
<varlistentry><term><function>builtins.all</function>
<replaceable>pred</replaceable> <replaceable>list</replaceable></term>
<listitem><para>Return <literal>true</literal> if the function
<replaceable>pred</replaceable> returns <literal>true</literal>
@@ -55,9 +50,8 @@ available as <function>builtins.derivation</function>.</para>
</varlistentry>
<varlistentry xml:id='builtin-any'>
<term><function>builtins.any</function>
<replaceable>pred</replaceable> <replaceable>list</replaceable></term>
<varlistentry><term><function>builtins.any</function>
<replaceable>pred</replaceable> <replaceable>list</replaceable></term>
<listitem><para>Return <literal>true</literal> if the function
<replaceable>pred</replaceable> returns <literal>true</literal>
@@ -67,9 +61,8 @@ available as <function>builtins.derivation</function>.</para>
</varlistentry>
<varlistentry xml:id='builtin-attrNames'>
<term><function>builtins.attrNames</function>
<replaceable>set</replaceable></term>
<varlistentry><term><function>builtins.attrNames</function>
<replaceable>set</replaceable></term>
<listitem><para>Return the names of the attributes in the set
<replaceable>set</replaceable> in an alphabetically sorted list. For instance,
@@ -79,9 +72,8 @@ available as <function>builtins.derivation</function>.</para>
</varlistentry>
<varlistentry xml:id='builtin-attrValues'>
<term><function>builtins.attrValues</function>
<replaceable>set</replaceable></term>
<varlistentry><term><function>builtins.attrValues</function>
<replaceable>set</replaceable></term>
<listitem><para>Return the values of the attributes in the set
<replaceable>set</replaceable> in the order corresponding to the
@@ -90,8 +82,7 @@ available as <function>builtins.derivation</function>.</para>
</varlistentry>
<varlistentry xml:id='builtin-baseNameOf'>
<term><function>baseNameOf</function> <replaceable>s</replaceable></term>
<varlistentry><term><function>baseNameOf</function> <replaceable>s</replaceable></term>
<listitem><para>Return the <emphasis>base name</emphasis> of the
string <replaceable>s</replaceable>, that is, everything following
@@ -101,9 +92,8 @@ available as <function>builtins.derivation</function>.</para>
</varlistentry>
<varlistentry xml:id='builtin-bitAnd'>
<term><function>builtins.bitAnd</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<varlistentry><term><function>builtins.bitAnd</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<listitem><para>Return the bitwise AND of the integers
<replaceable>e1</replaceable> and
@@ -112,9 +102,8 @@ available as <function>builtins.derivation</function>.</para>
</varlistentry>
<varlistentry xml:id='builtin-bitOr'>
<term><function>builtins.bitOr</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<varlistentry><term><function>builtins.bitOr</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<listitem><para>Return the bitwise OR of the integers
<replaceable>e1</replaceable> and
@@ -123,9 +112,8 @@ available as <function>builtins.derivation</function>.</para>
</varlistentry>
<varlistentry xml:id='builtin-bitXor'>
<term><function>builtins.bitXor</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<varlistentry><term><function>builtins.bitXor</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<listitem><para>Return the bitwise XOR of the integers
<replaceable>e1</replaceable> and
@@ -134,8 +122,7 @@ available as <function>builtins.derivation</function>.</para>
</varlistentry>
<varlistentry xml:id='builtin-builtins'>
<term><varname>builtins</varname></term>
<varlistentry><term><varname>builtins</varname></term>
<listitem><para>The set <varname>builtins</varname> contains all
the built-in functions and values. You can use
@@ -152,9 +139,8 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-compareVersions'>
<term><function>builtins.compareVersions</function>
<replaceable>s1</replaceable> <replaceable>s2</replaceable></term>
<varlistentry><term><function>builtins.compareVersions</function>
<replaceable>s1</replaceable> <replaceable>s2</replaceable></term>
<listitem><para>Compare two strings representing versions and
return <literal>-1</literal> if version
@@ -170,9 +156,8 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-splitVersion'>
<term><function>builtins.splitVersion</function>
<replaceable>s</replaceable></term>
<varlistentry><term><function>builtins.splitVersion</function>
<replaceable>s</replaceable></term>
<listitem><para>Split a string representing a version into its
components, by the same version splitting logic underlying the
@@ -182,18 +167,16 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-concatLists'>
<term><function>builtins.concatLists</function>
<replaceable>lists</replaceable></term>
<varlistentry><term><function>builtins.concatLists</function>
<replaceable>lists</replaceable></term>
<listitem><para>Concatenate a list of lists into a single
list.</para></listitem>
</varlistentry>
<varlistentry xml:id='builtin-concatStringsSep'>
<term><function>builtins.concatStringsSep</function>
<replaceable>separator</replaceable> <replaceable>list</replaceable></term>
<varlistentry><term><function>builtins.concatStringsSep</function>
<replaceable>separator</replaceable> <replaceable>list</replaceable></term>
<listitem><para>Concatenate a list of strings with a separator
between each element, e.g. <literal>concatStringsSep "/"
@@ -201,8 +184,8 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-currentSystem'>
<term><varname>builtins.currentSystem</varname></term>
<varlistentry
xml:id='builtin-currentSystem'><term><varname>builtins.currentSystem</varname></term>
<listitem><para>The built-in value <varname>currentSystem</varname>
evaluates to the Nix platform identifier for the Nix installation
@@ -235,9 +218,8 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
-->
<varlistentry xml:id='builtin-deepSeq'>
<term><function>builtins.deepSeq</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<varlistentry><term><function>builtins.deepSeq</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<listitem><para>This is like <literal>seq
<replaceable>e1</replaceable>
@@ -249,11 +231,8 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-derivation'>
<term><function>derivation</function>
<replaceable>attrs</replaceable></term>
<term><function>builtins.derivation</function>
<replaceable>attrs</replaceable></term>
<varlistentry><term><function>derivation</function>
<replaceable>attrs</replaceable></term>
<listitem><para><function>derivation</function> is described in
<xref linkend='ssec-derivation' />.</para></listitem>
@@ -261,9 +240,7 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-dirOf'>
<term><function>dirOf</function> <replaceable>s</replaceable></term>
<term><function>builtins.dirOf</function> <replaceable>s</replaceable></term>
<varlistentry><term><function>dirOf</function> <replaceable>s</replaceable></term>
<listitem><para>Return the directory part of the string
<replaceable>s</replaceable>, that is, everything before the final
@@ -273,9 +250,8 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-div'>
<term><function>builtins.div</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<varlistentry><term><function>builtins.div</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<listitem><para>Return the quotient of the numbers
<replaceable>e1</replaceable> and
@@ -283,9 +259,8 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-elem'>
<term><function>builtins.elem</function>
<replaceable>x</replaceable> <replaceable>xs</replaceable></term>
<varlistentry><term><function>builtins.elem</function>
<replaceable>x</replaceable> <replaceable>xs</replaceable></term>
<listitem><para>Return <literal>true</literal> if a value equal to
<replaceable>x</replaceable> occurs in the list
@@ -295,9 +270,8 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-elemAt'>
<term><function>builtins.elemAt</function>
<replaceable>xs</replaceable> <replaceable>n</replaceable></term>
<varlistentry><term><function>builtins.elemAt</function>
<replaceable>xs</replaceable> <replaceable>n</replaceable></term>
<listitem><para>Return element <replaceable>n</replaceable> from
the list <replaceable>xs</replaceable>. Elements are counted
@@ -307,9 +281,8 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-fetchurl'>
<term><function>builtins.fetchurl</function>
<replaceable>url</replaceable></term>
<varlistentry><term><function>builtins.fetchurl</function>
<replaceable>url</replaceable></term>
<listitem><para>Download the specified URL and return the path of
the downloaded file. This function is not available if <link
@@ -319,11 +292,8 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-fetchTarball'>
<term><function>fetchTarball</function>
<replaceable>url</replaceable></term>
<term><function>builtins.fetchTarball</function>
<replaceable>url</replaceable></term>
<varlistentry><term><function>fetchTarball</function>
<replaceable>url</replaceable></term>
<listitem><para>Download the specified URL, unpack it and return
the path of the unpacked tree. The file must be a tape archive
@@ -376,7 +346,7 @@ stdenv.mkDerivation { … }
</varlistentry>
<varlistentry xml:id='builtin-fetchGit'>
<varlistentry>
<term>
<function>builtins.fetchGit</function>
<replaceable>args</replaceable>
@@ -442,7 +412,7 @@ stdenv.mkDerivation { … }
<title>Fetching a repository's specific commit on an arbitrary branch</title>
<para>
If the revision you're looking for is in the default branch
of the git repository you don't strictly need to specify
of the gift repository you don't strictly need to specify
the branch name in the <varname>ref</varname> attribute.
</para>
<para>
@@ -471,7 +441,7 @@ stdenv.mkDerivation { … }
<title>Fetching a repository's specific commit on the default branch</title>
<para>
If the revision you're looking for is in the default branch
of the git repository you may omit the
of the gift repository you may omit the
<varname>ref</varname> attribute.
</para>
<programlisting>builtins.fetchGit {
@@ -576,8 +546,7 @@ stdenv.mkDerivation {
</varlistentry>
<varlistentry xml:id='builtin-foldl-prime'>
<term><function>builtins.foldl</function>
<varlistentry><term><function>builtins.foldl</function>
<replaceable>op</replaceable> <replaceable>nul</replaceable> <replaceable>list</replaceable></term>
<listitem><para>Reduce a list by applying a binary operator, from
@@ -590,8 +559,7 @@ stdenv.mkDerivation {
</varlistentry>
<varlistentry xml:id='builtin-functionArgs'>
<term><function>builtins.functionArgs</function>
<varlistentry><term><function>builtins.functionArgs</function>
<replaceable>f</replaceable></term>
<listitem><para>
@@ -609,8 +577,7 @@ stdenv.mkDerivation {
</varlistentry>
<varlistentry xml:id='builtin-fromJSON'>
<term><function>builtins.fromJSON</function> <replaceable>e</replaceable></term>
<varlistentry><term><function>builtins.fromJSON</function> <replaceable>e</replaceable></term>
<listitem><para>Convert a JSON string to a Nix
value. For example,
@@ -625,9 +592,8 @@ builtins.fromJSON ''{"x": [1, 2, 3], "y": null}''
</varlistentry>
<varlistentry xml:id='builtin-genList'>
<term><function>builtins.genList</function>
<replaceable>generator</replaceable> <replaceable>length</replaceable></term>
<varlistentry><term><function>builtins.genList</function>
<replaceable>generator</replaceable> <replaceable>length</replaceable></term>
<listitem><para>Generate list of size
<replaceable>length</replaceable>, with each element
@@ -644,9 +610,8 @@ builtins.genList (x: x * x) 5
</varlistentry>
<varlistentry xml:id='builtin-getAttr'>
<term><function>builtins.getAttr</function>
<replaceable>s</replaceable> <replaceable>set</replaceable></term>
<varlistentry><term><function>builtins.getAttr</function>
<replaceable>s</replaceable> <replaceable>set</replaceable></term>
<listitem><para><function>getAttr</function> returns the attribute
named <replaceable>s</replaceable> from
@@ -658,9 +623,8 @@ builtins.genList (x: x * x) 5
</varlistentry>
<varlistentry xml:id='builtin-getEnv'>
<term><function>builtins.getEnv</function>
<replaceable>s</replaceable></term>
<varlistentry><term><function>builtins.getEnv</function>
<replaceable>s</replaceable></term>
<listitem><para><function>getEnv</function> returns the value of
the environment variable <replaceable>s</replaceable>, or an empty
@@ -677,9 +641,8 @@ builtins.genList (x: x * x) 5
</varlistentry>
<varlistentry xml:id='builtin-hasAttr'>
<term><function>builtins.hasAttr</function>
<replaceable>s</replaceable> <replaceable>set</replaceable></term>
<varlistentry><term><function>builtins.hasAttr</function>
<replaceable>s</replaceable> <replaceable>set</replaceable></term>
<listitem><para><function>hasAttr</function> returns
<literal>true</literal> if <replaceable>set</replaceable> has an
@@ -692,22 +655,20 @@ builtins.genList (x: x * x) 5
</varlistentry>
<varlistentry xml:id='builtin-hashString'>
<term><function>builtins.hashString</function>
<replaceable>type</replaceable> <replaceable>s</replaceable></term>
<varlistentry><term><function>builtins.hashString</function>
<replaceable>type</replaceable> <replaceable>s</replaceable></term>
<listitem><para>Return a base-16 representation of the
cryptographic hash of string <replaceable>s</replaceable>. The
hash algorithm specified by <replaceable>type</replaceable> must
be one of <literal>"md5"</literal>, <literal>"sha1"</literal>,
<literal>"sha256"</literal> or <literal>"sha512"</literal>.</para></listitem>
be one of <literal>"md5"</literal>, <literal>"sha1"</literal> or
<literal>"sha256"</literal>.</para></listitem>
</varlistentry>
<varlistentry xml:id='builtin-head'>
<term><function>builtins.head</function>
<replaceable>list</replaceable></term>
<varlistentry><term><function>builtins.head</function>
<replaceable>list</replaceable></term>
<listitem><para>Return the first element of a list; abort
evaluation if the argument isnt a list or is an empty list. You
@@ -717,11 +678,8 @@ builtins.genList (x: x * x) 5
</varlistentry>
<varlistentry xml:id='builtin-import'>
<term><function>import</function>
<replaceable>path</replaceable></term>
<term><function>builtins.import</function>
<replaceable>path</replaceable></term>
<varlistentry><term><function>import</function>
<replaceable>path</replaceable></term>
<listitem><para>Load, parse and return the Nix expression in the
file <replaceable>path</replaceable>. If <replaceable>path
@@ -775,9 +733,8 @@ x: x + 456</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-intersectAttrs'>
<term><function>builtins.intersectAttrs</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<varlistentry><term><function>builtins.intersectAttrs</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<listitem><para>Return a set consisting of the attributes in the
set <replaceable>e2</replaceable> that also exist in the set
@@ -786,9 +743,8 @@ x: x + 456</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-isAttrs'>
<term><function>builtins.isAttrs</function>
<replaceable>e</replaceable></term>
<varlistentry><term><function>builtins.isAttrs</function>
<replaceable>e</replaceable></term>
<listitem><para>Return <literal>true</literal> if
<replaceable>e</replaceable> evaluates to a set, and
@@ -797,9 +753,8 @@ x: x + 456</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-isList'>
<term><function>builtins.isList</function>
<replaceable>e</replaceable></term>
<varlistentry><term><function>builtins.isList</function>
<replaceable>e</replaceable></term>
<listitem><para>Return <literal>true</literal> if
<replaceable>e</replaceable> evaluates to a list, and
@@ -808,7 +763,7 @@ x: x + 456</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-isFunction'><term><function>builtins.isFunction</function>
<varlistentry><term><function>builtins.isFunction</function>
<replaceable>e</replaceable></term>
<listitem><para>Return <literal>true</literal> if
@@ -818,9 +773,8 @@ x: x + 456</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-isString'>
<term><function>builtins.isString</function>
<replaceable>e</replaceable></term>
<varlistentry><term><function>builtins.isString</function>
<replaceable>e</replaceable></term>
<listitem><para>Return <literal>true</literal> if
<replaceable>e</replaceable> evaluates to a string, and
@@ -829,9 +783,8 @@ x: x + 456</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-isInt'>
<term><function>builtins.isInt</function>
<replaceable>e</replaceable></term>
<varlistentry><term><function>builtins.isInt</function>
<replaceable>e</replaceable></term>
<listitem><para>Return <literal>true</literal> if
<replaceable>e</replaceable> evaluates to an int, and
@@ -840,9 +793,8 @@ x: x + 456</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-isFloat'>
<term><function>builtins.isFloat</function>
<replaceable>e</replaceable></term>
<varlistentry><term><function>builtins.isFloat</function>
<replaceable>e</replaceable></term>
<listitem><para>Return <literal>true</literal> if
<replaceable>e</replaceable> evaluates to a float, and
@@ -851,9 +803,8 @@ x: x + 456</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-isBool'>
<term><function>builtins.isBool</function>
<replaceable>e</replaceable></term>
<varlistentry><term><function>builtins.isBool</function>
<replaceable>e</replaceable></term>
<listitem><para>Return <literal>true</literal> if
<replaceable>e</replaceable> evaluates to a bool, and
@@ -861,21 +812,10 @@ x: x + 456</programlisting>
</varlistentry>
<varlistentry><term><function>builtins.isPath</function>
<varlistentry><term><function>isNull</function>
<replaceable>e</replaceable></term>
<listitem><para>Return <literal>true</literal> if
<replaceable>e</replaceable> evaluates to a path, and
<literal>false</literal> otherwise.</para></listitem>
</varlistentry>
<varlistentry xml:id='builtin-isNull'>
<term><function>isNull</function>
<replaceable>e</replaceable></term>
<term><function>builtins.isNull</function>
<replaceable>e</replaceable></term>
<listitem><para>Return <literal>true</literal> if
<replaceable>e</replaceable> evaluates to <literal>null</literal>,
and <literal>false</literal> otherwise.</para>
@@ -888,9 +828,8 @@ x: x + 456</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-length'>
<term><function>builtins.length</function>
<replaceable>e</replaceable></term>
<varlistentry><term><function>builtins.length</function>
<replaceable>e</replaceable></term>
<listitem><para>Return the length of the list
<replaceable>e</replaceable>.</para></listitem>
@@ -898,9 +837,8 @@ x: x + 456</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-lessThan'>
<term><function>builtins.lessThan</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<varlistentry><term><function>builtins.lessThan</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<listitem><para>Return <literal>true</literal> if the number
<replaceable>e1</replaceable> is less than the number
@@ -912,9 +850,8 @@ x: x + 456</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-listToAttrs'>
<term><function>builtins.listToAttrs</function>
<replaceable>e</replaceable></term>
<varlistentry><term><function>builtins.listToAttrs</function>
<replaceable>e</replaceable></term>
<listitem><para>Construct a set from a list specifying the names
and values of each attribute. Each element of the list should be
@@ -940,11 +877,8 @@ builtins.listToAttrs
</varlistentry>
<varlistentry xml:id='builtin-map'>
<term><function>map</function>
<replaceable>f</replaceable> <replaceable>list</replaceable></term>
<term><function>builtins.map</function>
<replaceable>f</replaceable> <replaceable>list</replaceable></term>
<varlistentry><term><function>map</function>
<replaceable>f</replaceable> <replaceable>list</replaceable></term>
<listitem><para>Apply the function <replaceable>f</replaceable> to
each element in the list <replaceable>list</replaceable>. For
@@ -959,15 +893,14 @@ map (x: "foo" + x) [ "bar" "bla" "abc" ]</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-match'>
<term><function>builtins.match</function>
<replaceable>regex</replaceable> <replaceable>str</replaceable></term>
<varlistentry><term><function>builtins.match</function>
<replaceable>regex</replaceable> <replaceable>str</replaceable></term>
<listitem><para>Returns a list if the <link
xlink:href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_04">extended
POSIX regular expression</link> <replaceable>regex</replaceable>
matches <replaceable>str</replaceable> precisely, otherwise returns
<literal>null</literal>. Each item in the list is a regex group.
<listitem><para>Returns a list if the <link
xlink:href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_04">extended
POSIX regular expression</link> <replaceable>regex</replaceable>
matches <replaceable>str</replaceable> precisely, otherwise returns
<literal>null</literal>. Each item in the list is a regex group.
<programlisting>
builtins.match "ab" "abc"
@@ -993,12 +926,11 @@ builtins.match "[[:space:]]+([[:upper:]]+)[[:space:]]+" " FOO "
Evaluates to <literal>[ "foo" ]</literal>.
</para></listitem>
</para></listitem>
</varlistentry>
<varlistentry xml:id='builtin-mul'>
<term><function>builtins.mul</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<varlistentry><term><function>builtins.mul</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<listitem><para>Return the product of the numbers
<replaceable>e1</replaceable> and
@@ -1007,9 +939,8 @@ Evaluates to <literal>[ "foo" ]</literal>.
</varlistentry>
<varlistentry xml:id='builtin-parseDrvName'>
<term><function>builtins.parseDrvName</function>
<replaceable>s</replaceable></term>
<varlistentry><term><function>builtins.parseDrvName</function>
<replaceable>s</replaceable></term>
<listitem><para>Split the string <replaceable>s</replaceable> into
a package name and version. The package name is everything up to
@@ -1022,7 +953,7 @@ Evaluates to <literal>[ "foo" ]</literal>.
</varlistentry>
<varlistentry xml:id='builtin-path'>
<varlistentry>
<term>
<function>builtins.path</function>
<replaceable>args</replaceable>
@@ -1092,20 +1023,32 @@ Evaluates to <literal>[ "foo" ]</literal>.
</listitem>
</varlistentry>
<varlistentry xml:id='builtin-pathExists'>
<term><function>builtins.pathExists</function>
<replaceable>path</replaceable></term>
<varlistentry><term><function>builtins.pathExists</function>
<replaceable>path</replaceable></term>
<listitem><para>Return <literal>true</literal> if the path
<replaceable>path</replaceable> exists at evaluation time, and
<literal>false</literal> otherwise.</para></listitem>
<replaceable>path</replaceable> exists, and
<literal>false</literal> otherwise. One application of this
function is to conditionally include a Nix expression containing
user configuration:
<programlisting>
let
fileName = builtins.getEnv "CONFIG_FILE";
config =
if fileName != "" &amp;&amp; builtins.pathExists (builtins.toPath fileName)
then import (builtins.toPath fileName)
else { someSetting = false; }; <lineannotation># default configuration</lineannotation>
in config.someSetting</programlisting>
(Note that <envar>CONFIG_FILE</envar> must be an absolute path for
this to work.)</para></listitem>
</varlistentry>
<varlistentry xml:id='builtin-readDir'>
<term><function>builtins.readDir</function>
<replaceable>path</replaceable></term>
<varlistentry><term><function>builtins.readDir</function>
<replaceable>path</replaceable></term>
<listitem><para>Return the contents of the directory
<replaceable>path</replaceable> as a set mapping directory entries
@@ -1126,9 +1069,8 @@ Evaluates to <literal>[ "foo" ]</literal>.
</varlistentry>
<varlistentry xml:id='builtin-readFile'>
<term><function>builtins.readFile</function>
<replaceable>path</replaceable></term>
<varlistentry><term><function>builtins.readFile</function>
<replaceable>path</replaceable></term>
<listitem><para>Return the contents of the file
<replaceable>path</replaceable> as a string.</para></listitem>
@@ -1136,11 +1078,8 @@ Evaluates to <literal>[ "foo" ]</literal>.
</varlistentry>
<varlistentry xml:id='builtin-removeAttrs'>
<term><function>removeAttrs</function>
<replaceable>set</replaceable> <replaceable>list</replaceable></term>
<term><function>builtins.removeAttrs</function>
<replaceable>set</replaceable> <replaceable>list</replaceable></term>
<varlistentry><term><function>removeAttrs</function>
<replaceable>set</replaceable> <replaceable>list</replaceable></term>
<listitem><para>Remove the attributes listed in
<replaceable>list</replaceable> from
@@ -1155,9 +1094,8 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-replaceStrings'>
<term><function>builtins.replaceStrings</function>
<replaceable>from</replaceable> <replaceable>to</replaceable> <replaceable>s</replaceable></term>
<varlistentry><term><function>builtins.replaceStrings</function>
<replaceable>from</replaceable> <replaceable>to</replaceable> <replaceable>s</replaceable></term>
<listitem><para>Given string <replaceable>s</replaceable>, replace
every occurrence of the strings in <replaceable>from</replaceable>
@@ -1173,9 +1111,8 @@ builtins.replaceStrings ["oo" "a"] ["a" "i"] "foobar"
</varlistentry>
<varlistentry xml:id='builtin-seq'>
<term><function>builtins.seq</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<varlistentry><term><function>builtins.seq</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<listitem><para>Evaluate <replaceable>e1</replaceable>, then
evaluate and return <replaceable>e2</replaceable>. This ensures
@@ -1185,9 +1122,8 @@ builtins.replaceStrings ["oo" "a"] ["a" "i"] "foobar"
</varlistentry>
<varlistentry xml:id='builtin-sort'>
<term><function>builtins.sort</function>
<replaceable>comparator</replaceable> <replaceable>list</replaceable></term>
<varlistentry><term><function>builtins.sort</function>
<replaceable>comparator</replaceable> <replaceable>list</replaceable></term>
<listitem><para>Return <replaceable>list</replaceable> in sorted
order. It repeatedly calls the function
@@ -1209,16 +1145,15 @@ builtins.sort builtins.lessThan [ 483 249 526 147 42 77 ]
</varlistentry>
<varlistentry xml:id='builtin-split'>
<term><function>builtins.split</function>
<replaceable>regex</replaceable> <replaceable>str</replaceable></term>
<varlistentry><term><function>builtins.split</function>
<replaceable>regex</replaceable> <replaceable>str</replaceable></term>
<listitem><para>Returns a list composed of non matched strings interleaved
with the lists of the <link
xlink:href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_04">extended
POSIX regular expression</link> <replaceable>regex</replaceable> matches
of <replaceable>str</replaceable>. Each item in the lists of matched
sequences is a regex group.
<listitem><para>Returns a list composed of non matched strings interleaved
with the lists of the <link
xlink:href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_04">extended
POSIX regular expression</link> <replaceable>regex</replaceable> matches
of <replaceable>str</replaceable>. Each item in the lists of matched
sequences is a regex group.
<programlisting>
builtins.split "(a)b" "abc"
@@ -1244,12 +1179,11 @@ builtins.split "([[:upper:]]+)" " FOO "
Evaluates to <literal>[ " " [ "FOO" ] " " ]</literal>.
</para></listitem>
</para></listitem>
</varlistentry>
<varlistentry xml:id='builtin-stringLength'>
<term><function>builtins.stringLength</function>
<replaceable>e</replaceable></term>
<varlistentry><term><function>builtins.stringLength</function>
<replaceable>e</replaceable></term>
<listitem><para>Return the length of the string
<replaceable>e</replaceable>. If <replaceable>e</replaceable> is
@@ -1258,9 +1192,8 @@ Evaluates to <literal>[ " " [ "FOO" ] " " ]</literal>.
</varlistentry>
<varlistentry xml:id='builtin-sub'>
<term><function>builtins.sub</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<varlistentry><term><function>builtins.sub</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<listitem><para>Return the difference between the numbers
<replaceable>e1</replaceable> and
@@ -1269,10 +1202,9 @@ Evaluates to <literal>[ " " [ "FOO" ] " " ]</literal>.
</varlistentry>
<varlistentry xml:id='builtin-substring'>
<term><function>builtins.substring</function>
<replaceable>start</replaceable> <replaceable>len</replaceable>
<replaceable>s</replaceable></term>
<varlistentry><term><function>builtins.substring</function>
<replaceable>start</replaceable> <replaceable>len</replaceable>
<replaceable>s</replaceable></term>
<listitem><para>Return the substring of
<replaceable>s</replaceable> from character position
@@ -1295,9 +1227,8 @@ builtins.substring 0 3 "nixos"
</varlistentry>
<varlistentry xml:id='builtin-tail'>
<term><function>builtins.tail</function>
<replaceable>list</replaceable></term>
<varlistentry><term><function>builtins.tail</function>
<replaceable>list</replaceable></term>
<listitem><para>Return the second to last elements of a list;
abort evaluation if the argument isnt a list or is an empty
@@ -1306,11 +1237,8 @@ builtins.substring 0 3 "nixos"
</varlistentry>
<varlistentry xml:id='builtin-throw'>
<term><function>throw</function>
<replaceable>s</replaceable></term>
<term><function>builtins.throw</function>
<replaceable>s</replaceable></term>
<varlistentry><term><function>throw</function>
<replaceable>s</replaceable></term>
<listitem><para>Throw an error message
<replaceable>s</replaceable>. This usually aborts Nix expression
@@ -1323,10 +1251,9 @@ builtins.substring 0 3 "nixos"
</varlistentry>
<varlistentry xml:id='builtin-toFile'>
<term><function>builtins.toFile</function>
<replaceable>name</replaceable>
<replaceable>s</replaceable></term>
<varlistentry
xml:id='builtin-toFile'><term><function>builtins.toFile</function>
<replaceable>name</replaceable> <replaceable>s</replaceable></term>
<listitem><para>Store the string <replaceable>s</replaceable> in a
file in the Nix store and return its path. The file has suffix
@@ -1402,8 +1329,7 @@ in foo</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-toJSON'>
<term><function>builtins.toJSON</function> <replaceable>e</replaceable></term>
<varlistentry><term><function>builtins.toJSON</function> <replaceable>e</replaceable></term>
<listitem><para>Return a string containing a JSON representation
of <replaceable>e</replaceable>. Strings, integers, floats, booleans,
@@ -1416,20 +1342,20 @@ in foo</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-toPath'>
<term><function>builtins.toPath</function> <replaceable>s</replaceable></term>
<varlistentry><term><function>builtins.toPath</function> <replaceable>s</replaceable></term>
<listitem><para> DEPRECATED. Use <literal>/. + "/path"</literal>
to convert a string into an absolute path. For relative paths,
use <literal>./. + "/path"</literal>.
</para></listitem>
<listitem><para>Convert the string value
<replaceable>s</replaceable> into a path value. The string
<replaceable>s</replaceable> must represent an absolute path
(i.e., must start with <literal>/</literal>). The path need not
exist. The resulting path is canonicalised, e.g.,
<literal>builtins.toPath "//foo/xyzzy/../bar/"</literal> returns
<literal>/foo/bar</literal>.</para></listitem>
</varlistentry>
<varlistentry xml:id='builtin-toString'>
<term><function>toString</function> <replaceable>e</replaceable></term>
<term><function>builtins.toString</function> <replaceable>e</replaceable></term>
<varlistentry><term><function>toString</function> <replaceable>e</replaceable></term>
<listitem><para>Convert the expression
<replaceable>e</replaceable> to a string.
@@ -1448,8 +1374,7 @@ in foo</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-toXML'>
<term><function>builtins.toXML</function> <replaceable>e</replaceable></term>
<varlistentry xml:id='builtin-toXML'><term><function>builtins.toXML</function> <replaceable>e</replaceable></term>
<listitem><para>Return a string containing an XML representation
of <replaceable>e</replaceable>. The main application for
@@ -1505,7 +1430,7 @@ stdenv.mkDerivation (rec {
builder = builtins.toFile "builder.sh" "
source $stdenv/setup
mkdir $out
echo "$servlets" | xsltproc ${stylesheet} - > $out/server-conf.xml]]> <co xml:id='ex-toxml-co-apply' /> <![CDATA[
echo $servlets | xsltproc ${stylesheet} - > $out/server-conf.xml]]> <co xml:id='ex-toxml-co-apply' /> <![CDATA[
";
stylesheet = builtins.toFile "stylesheet.xsl"]]> <co xml:id='ex-toxml-co-stylesheet' /> <![CDATA[
@@ -1564,9 +1489,8 @@ stdenv.mkDerivation (rec {
</varlistentry>
<varlistentry xml:id='builtin-trace'>
<term><function>builtins.trace</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<varlistentry><term><function>builtins.trace</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<listitem><para>Evaluate <replaceable>e1</replaceable> and print its
abstract syntax representation on standard error. Then return
@@ -1575,9 +1499,8 @@ stdenv.mkDerivation (rec {
</varlistentry>
<varlistentry xml:id='builtin-tryEval'>
<term><function>builtins.tryEval</function>
<replaceable>e</replaceable></term>
<varlistentry><term><function>builtins.tryEval</function>
<replaceable>e</replaceable></term>
<listitem><para>Try to evaluate <replaceable>e</replaceable>.
Return a set containing the attributes <literal>success</literal>
@@ -1590,9 +1513,8 @@ stdenv.mkDerivation (rec {
</varlistentry>
<varlistentry xml:id='builtin-typeOf'>
<term><function>builtins.typeOf</function>
<replaceable>e</replaceable></term>
<varlistentry><term><function>builtins.typeOf</function>
<replaceable>e</replaceable></term>
<listitem><para>Return a string representing the type of the value
<replaceable>e</replaceable>, namely <literal>"int"</literal>,

View File

@@ -25,18 +25,11 @@
If your distribution does not provide it, you can get it from <link
xlink:href="https://www.openssl.org"/>.</para></listitem>
<listitem><para>The <literal>libbrotlienc</literal> and
<literal>libbrotlidec</literal> libraries to provide implementation
of the Brotli compression algorithm. They are available for download
from the official repository <link
xlink:href="https://github.com/google/brotli" />.</para></listitem>
<listitem><para>The bzip2 compressor program and the
<literal>libbz2</literal> library. Thus you must have bzip2
installed, including development headers and libraries. If your
distribution does not provide these, you can obtain bzip2 from <link
xlink:href="https://web.archive.org/web/20180624184756/http://www.bzip.org/"
/>.</para></listitem>
xlink:href="http://www.bzip.org/"/>.</para></listitem>
<listitem><para><literal>liblzma</literal>, which is provided by
XZ Utils. If your distribution does not provide this, you can
@@ -58,10 +51,6 @@
pass the flag <option>--enable-gc</option> to
<command>configure</command>.</para></listitem>
<listitem><para>The <literal>boost</literal> library of version
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 <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
@@ -87,15 +76,6 @@
modify the parser or when you are building from the Git
repository.</para></listitem>
<listitem><para>The <literal>libseccomp</literal> is used to provide
syscall filtering on Linux. This is an optional dependency and can
be disabled passing a <option>--disable-seccomp-sandboxing</option>
option to the <command>configure</command> script (Not recommended
unless your system doesn't support
<literal>libseccomp</literal>). To get the library, visit <link
xlink:href="https://github.com/seccomp/libseccomp"
/>.</para></listitem>
</itemizedlist>
</section>

View File

@@ -7,16 +7,15 @@
<title>Upgrading Nix</title>
<para>
Multi-user Nix users on macOS can upgrade Nix by running:
<command>sudo -i sh -c 'nix-channel --update &amp;&amp;
nix-env -iA nixpkgs.nix &amp;&amp;
launchctl remove org.nixos.nix-daemon &amp;&amp;
launchctl load /Library/LaunchDaemons/org.nixos.nix-daemon.plist'</command>
Multi-user Nix users on macOS can upgrade Nix by running
<command>sudo -i sh -c 'nix-channel --update &amp;&amp; nix-env
-iA nixpkgs.nix'; sudo launchctl stop org.nixos.nix-daemon; sudo
launchctl start org.nixos.nix-daemon</command>.
</para>
<para>
Single-user installations of Nix should run this:
<command>nix-channel --update; nix-env -iA nixpkgs.nix</command>
Single-user installations of Nix should run <command>nix-channel
--update; nix-env -iA nixpkgs.nix</command>.
</para>
</chapter>

View File

@@ -262,6 +262,12 @@ xlink:href="http://nixos.org/">NixOS homepage</link>.</para>
xlink:href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html">GNU
LGPLv2.1 or (at your option) any later version</link>.</para>
<para>Nix uses the <link
xlink:href="https://github.com/arangodb/linenoise-ng">linenoise-ng
library</link>, which has the following license:</para>
<programlisting><xi:include href="../../../src/linenoise/LICENSE" parse="text" /></programlisting>
</simplesect>

View File

@@ -12,61 +12,8 @@ from Amazon S3 and S3 compatible services. This uses the same
<emphasis>binary</emphasis> cache mechanism that Nix usually uses to
fetch prebuilt binaries from <uri>cache.nixos.org</uri>.</para>
<para>The following options can be specified as URL parameters to
the S3 URL:</para>
<variablelist>
<varlistentry><term><literal>profile</literal></term>
<listitem>
<para>
The name of the AWS configuration profile to use. By default
Nix will use the <literal>default</literal> profile.
</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>region</literal></term>
<listitem>
<para>
The region of the S3 bucket. <literal>useast-1</literal> by
default.
</para>
<para>
If your bucket is not in <literal>useast-1</literal>, you
should always explicitly specify the region parameter.
</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>endpoint</literal></term>
<listitem>
<para>
The URL to your S3-compatible service, for when not using
Amazon S3. Do not specify this value if you're using Amazon
S3.
</para>
<note><para>This endpoint must support HTTPS and will use
path-based addressing instead of virtual host based
addressing.</para></note>
</listitem>
</varlistentry>
<varlistentry><term><literal>scheme</literal></term>
<listitem>
<para>
The scheme used for S3 requests, <literal>https</literal>
(default) or <literal>http</literal>. This option allows you to
disable HTTPS for binary caches which don't support it.
</para>
<note><para>HTTPS should be used if the cache might contain
sensitive information.</para></note>
</listitem>
</varlistentry>
</variablelist>
<para>In this example we will use the bucket named
<literal>example-nix-cache</literal>.</para>
<literal>example-bucket</literal>.</para>
<section xml:id="ssec-s3-substituter-anonymous-reads">
<title>Anonymous Reads to your S3-compatible binary cache</title>
@@ -77,56 +24,65 @@ the S3 URL:</para>
cache.</para>
<para>For AWS S3 the binary cache URL for example bucket will be
exactly <uri>https://example-nix-cache.s3.amazonaws.com</uri> or
<uri>s3://example-nix-cache</uri>. For S3 compatible binary caches,
consult that cache's documentation.</para>
exactly <uri>https://example-bucket.s3.amazonaws.com</uri>. For S3
compatible binary caches ago have to consult your software's
documentation.</para>
<para>Your bucket will need the following bucket policy:</para>
<programlisting><![CDATA[
<programlisting>
<![CDATA[
{
"Id": "DirectReads",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowDirectReads",
"Action": [
"s3:GetObject",
"s3:GetBucketLocation"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::example-nix-cache",
"arn:aws:s3:::example-nix-cache/*"
],
"Principal": "*"
}
]
"Id": "DirectReads",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AlowDirectReads",
"Action": [
"s3:GetObject"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::example-bucket/*",
"Principal": "*"
}
]
}
]]></programlisting>
]]>
</programlisting>
</section>
<section xml:id="ssec-s3-substituter-authenticated-reads">
<title>Authenticated Reads to your S3 binary cache</title>
<para>For AWS S3 the binary cache URL for example bucket will be
exactly <uri>s3://example-nix-cache</uri>.</para>
exactly <uri>s3://example-bucket</uri>.</para>
<para>Nix will use the <link
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>
<para>Nix supports authenticated reads from Amazon S3 and S3
compatible binary caches.</para>
<para>Nix supports authenticated writes to S3 compatible binary
caches but only supports Authenticated reads from Amazon S3.
Additionally, the following limitations are in place for
authenticated reads:</para>
<itemizedlist>
<listitem><para>The bucket must actually be hosted by Amazon S3 and
<emphasis>not</emphasis> an S3 compatible
service.</para></listitem>
<listitem><para>The bucket must be within the
<literal>us-east-1</literal> region.</para></listitem>
<listitem><para>The Amazon credentials, if stored in a credential
profile, must be stored in the <literal>default</literal>
profile.</para></listitem>
</itemizedlist>
<para>Your bucket will need a bucket policy allowing the desired
users to perform the <literal>s3:GetObject</literal> and
<literal>s3:GetBucketLocation</literal> action on all objects in the
bucket. The anonymous policy in <xref
linkend="ssec-s3-substituter-anonymous-reads" /> can be updated to
have a restricted <literal>Principal</literal> to support
this.</para>
users to perform the <literal>s3:GetObject</literal> action on all
objects in the bucket.</para>
</section>
@@ -135,49 +91,69 @@ the S3 URL:</para>
<para>Nix support fully supports writing to Amazon S3 and S3
compatible buckets. The binary cache URL for our example bucket will
be <uri>s3://example-nix-cache</uri>.</para>
be <uri>s3://example-bucket</uri>.</para>
<para>Nix will use the <link
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>
<para>Your account will need the following IAM policy to
upload to the cache:</para>
<para>The following options can be specified as URL parameters to
the S3 URL:</para>
<variablelist>
<varlistentry><term><literal>profile</literal></term>
<listitem>
<para>
The name of the AWS configuration profile to use. By default
Nix will use the <literal>default</literal> profile.
</para>
</listitem>
</varlistentry>
<programlisting><![CDATA[
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "UploadToCache",
"Effect": "Allow",
"Action": [
"s3:AbortMultipartUpload",
"s3:GetBucketLocation",
"s3:GetObject",
"s3:ListBucket",
"s3:ListBucketMultipartUploads",
"s3:ListMultipartUploadParts",
"s3:ListObjects",
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::example-nix-cache",
"arn:aws:s3:::example-nix-cache/*"
]
}
]
}
]]></programlisting>
<varlistentry><term><literal>region</literal></term>
<listitem>
<para>
The region of the S3 bucket. <literal>useast-1</literal> by
default.
</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>endpoint</literal></term>
<listitem>
<para>
The URL to your S3-compatible service, for when not using
Amazon S3. Do not specify this value if you're using Amazon
S3.
</para>
<note><para>This endpoint must support HTTPS and will use
path-based addressing instead of virtual host based
addressing.</para></note>
</listitem>
</varlistentry>
</variablelist>
<example><title>Uploading with a specific credential profile for Amazon S3</title>
<para><command>nix copy --to 's3://example-nix-cache?profile=cache-upload&amp;region=eu-west-2' nixpkgs.hello</command></para>
<example><title>Uploading with non-default credential profile for Amazon S3</title>
<para><command>nix copy --to ssh://machine nixpkgs.hello s3://example-bucket?profile=cache-upload</command></para>
</example>
<example><title>Uploading to an S3-Compatible Binary Cache</title>
<para><command>nix copy --to 's3://example-nix-cache?profile=cache-upload&amp;scheme=https&amp;endpoint=minio.example.com' nixpkgs.hello</command></para>
<para><command>nix copy --to ssh://machine nixpkgs.hello s3://example-bucket?profile=cache-upload&amp;endpoint=minio.example.com</command></para>
</example>
<para>The user writing to the bucket will need to perform the
following actions against the bucket:</para>
<itemizedlist>
<listitem><para><literal>s3:ListBucket</literal></para></listitem>
<listitem><para><literal>s3:GetBucketLocation</literal></para></listitem>
<listitem><para><literal>s3:ListObjects</literal></para></listitem>
<listitem><para><literal>s3:GetObject</literal></para></listitem>
<listitem><para><literal>s3:PutObject</literal></para></listitem>
<listitem><para><literal>s3:ListBucketMultipartUploads</literal></para></listitem>
<listitem><para><literal>s3:CreateMultipartUpload</literal></para></listitem>
<listitem><para><literal>s3:ListMultipartUploadParts</literal></para></listitem>
<listitem><para><literal>s3:AbortMultipartUpload</literal></para></listitem>
</itemizedlist>
</section>
</section>

View File

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

View File

@@ -1,143 +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.2">
<title>Release 2.2 (2019-01-11)</title>
<para>This is primarily a bug fix release. It also has the following
changes:</para>
<itemizedlist>
<listitem>
<para>In derivations that use structured attributes (i.e. that
specify set the <varname>__structuredAttrs</varname> attribute to
<literal>true</literal> to cause all attributes to be passed to
the builder in JSON format), you can now specify closure checks
per output, e.g.:
<programlisting>
outputChecks."out" = {
# The closure of 'out' must not be larger than 256 MiB.
maxClosureSize = 256 * 1024 * 1024;
# It must not refer to C compiler or to the 'dev' output.
disallowedRequisites = [ stdenv.cc "dev" ];
};
outputChecks."dev" = {
# The 'dev' output must not be larger than 128 KiB.
maxSize = 128 * 1024;
};
</programlisting>
</para>
</listitem>
<listitem>
<para>The derivation attribute
<varname>requiredSystemFeatures</varname> is now enforced for
local builds, and not just to route builds to remote builders.
The supported features of a machine can be specified through the
configuration setting <varname>system-features</varname>.</para>
<para>By default, <varname>system-features</varname> includes
<literal>kvm</literal> if <filename>/dev/kvm</filename>
exists. For compatibility, it also includes the pseudo-features
<literal>nixos-test</literal>, <literal>benchmark</literal> and
<literal>big-parallel</literal> which are used by Nixpkgs to route
builds to particular Hydra build machines.</para>
</listitem>
<listitem>
<para>Sandbox builds are now enabled by default on Linux.</para>
</listitem>
<listitem>
<para>The new command <command>nix doctor</command> shows
potential issues with your Nix installation.</para>
</listitem>
<listitem>
<para>The <literal>fetchGit</literal> builtin function now uses a
caching scheme that puts different remote repositories in distinct
local repositories, rather than a single shared repository. This
may require more disk space but is faster.</para>
</listitem>
<listitem>
<para>The <literal>dirOf</literal> builtin function now works on
relative paths.</para>
</listitem>
<listitem>
<para>Nix now supports <link
xlink:href="https://www.w3.org/TR/SRI/">SRI hashes</link>,
allowing the hash algorithm and hash to be specified in a single
string. For example, you can write:
<programlisting>
import &lt;nix/fetchurl.nix> {
url = https://nixos.org/releases/nix/nix-2.1.3/nix-2.1.3.tar.xz;
hash = "sha256-XSLa0FjVyADWWhFfkZ2iKTjFDda6mMXjoYMXLRSYQKQ=";
};
</programlisting>
instead of
<programlisting>
import &lt;nix/fetchurl.nix> {
url = https://nixos.org/releases/nix/nix-2.1.3/nix-2.1.3.tar.xz;
sha256 = "5d22dad058d5c800d65a115f919da22938c50dd6ba98c5e3a183172d149840a4";
};
</programlisting>
</para>
<para>In fixed-output derivations, the
<varname>outputHashAlgo</varname> attribute is no longer mandatory
if <varname>outputHash</varname> specifies the hash.</para>
<para><command>nix hash-file</command> and <command>nix
hash-path</command> now print hashes in SRI format by
default. They also use SHA-256 by default instead of SHA-512
because that's what we use most of the time in Nixpkgs.</para>
</listitem>
<listitem>
<para>Integers are now 64 bits on all platforms.</para>
</listitem>
<listitem>
<para>The evaluator now prints profiling statistics (enabled via
the <envar>NIX_SHOW_STATS</envar> and
<envar>NIX_COUNT_CALLS</envar> environment variables) in JSON
format.</para>
</listitem>
<listitem>
<para>The option <option>--xml</option> in <command>nix-store
--query</command> has been removed. Instead, there now is an
option <option>--graphml</option> to output the dependency graph
in GraphML format.</para>
</listitem>
<listitem>
<para>All <filename>nix-*</filename> commands are now symlinks to
<filename>nix</filename>. This saves a bit of disk space.</para>
</listitem>
<listitem>
<para><command>nix repl</command> now uses
<literal>libeditline</literal> or
<literal>libreadline</literal>.</para>
</listitem>
</itemizedlist>
</section>

View File

@@ -6,7 +6,7 @@ dist-files += configure config.h.in nix.spec perl/configure
clean-files += Makefile.config
GLOBAL_CXXFLAGS += -I . -I src -I src/libutil -I src/libstore -I src/libmain -I src/libexpr -I src/nix
GLOBAL_CXXFLAGS += -I . -I src -I src/libutil -I src/libstore -I src/libmain -I src/libexpr
$(foreach i, config.h $(call rwildcard, src/lib*, *.hh), \
$(eval $(call install-file-in, $(i), $(includedir)/nix, 0644)))

View File

@@ -91,8 +91,6 @@ downloadFile("binaryTarball.aarch64-linux", "1");
downloadFile("binaryTarball.x86_64-darwin", "1");
downloadFile("installerScript", "1");
exit if $version =~ /pre/;
# Update Nixpkgs in a very hacky way.
system("cd $nixpkgsDir && git pull") == 0 or die;
my $oldName = `nix-instantiate --eval $nixpkgsDir -A nix.name`; chomp $oldName;

View File

@@ -2,11 +2,6 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>EnvironmentVariables</key>
<dict>
<key>OBJC_DISABLE_INITIALIZE_FORK_SAFETY</key>
<string>YES</string>
</dict>
<key>Label</key>
<string>org.nixos.nix-daemon</string>
<key>KeepAlive</key>

View File

@@ -125,7 +125,7 @@ define build-library
$(1)_PATH := $$(_d)/$$($(1)_NAME).a
$$($(1)_PATH): $$($(1)_OBJS) | $$(_d)/
$(trace-ar) $(AR) crs $$@ $$?
$(trace-ar) ar crs $$@ $$?
$(1)_LDFLAGS_USE += $$($(1)_PATH) $$($(1)_LDFLAGS)

View File

@@ -1,4 +1,4 @@
AC_INIT(nix-perl, m4_esyscmd([bash -c "echo -n $(cat ../.version)$VERSION_SUFFIX"]))
AC_INIT(nix-perl, m4_esyscmd([bash -c "echo -n $(cat ../version)$VERSION_SUFFIX"]))
AC_CONFIG_SRCDIR(MANIFEST)
AC_CONFIG_AUX_DIR(../config)

View File

@@ -49,7 +49,7 @@ rec {
buildDeps =
[ curl
bzip2 xz brotli editline
bzip2 xz brotli
openssl pkgconfig sqlite boehmgc
boost
@@ -64,12 +64,10 @@ rec {
apis = ["s3" "transfer"];
customMemoryManagement = false;
}).overrideDerivation (args: {
/*
patches = args.patches or [] ++ [ (fetchpatch {
url = https://github.com/edolstra/aws-sdk-cpp/commit/3e07e1f1aae41b4c8b340735ff9e8c735f0c063f.patch;
sha256 = "1pij0v449p166f9l29x7ppzk8j7g9k9mp15ilh5qxp29c7fnvxy2";
}) ];
*/
}));
perlDeps =

View File

@@ -1,5 +1,5 @@
{ nix ? builtins.fetchGit ./.
, nixpkgs ? builtins.fetchGit { url = https://github.com/NixOS/nixpkgs-channels.git; ref = "nixos-19.03"; }
, nixpkgs ? builtins.fetchGit { url = https://github.com/NixOS/nixpkgs-channels.git; ref = "nixos-18.03"; }
, officialRelease ? false
, systems ? [ "x86_64-linux" "i686-linux" "x86_64-darwin" "aarch64-linux" ]
}:
@@ -18,7 +18,7 @@ let
releaseTools.sourceTarball {
name = "nix-tarball";
version = builtins.readFile ./.version;
version = builtins.readFile ./version;
versionSuffix = if officialRelease then "" else "pre${toString nix.revCount}_${nix.shortRev}";
src = nix;
inherit officialRelease;
@@ -278,6 +278,7 @@ let
pkgs.runCommand "eval-nixos" { buildInputs = [ build.x86_64-linux ]; }
''
export NIX_STATE_DIR=$TMPDIR
nix-store --init
nix-instantiate ${nixpkgs}/nixos/release-combined.nix -A tested --dry-run \
--arg nixpkgs '{ outPath = ${nixpkgs}; revCount = 123; shortRev = "abcdefgh"; }'
@@ -295,7 +296,7 @@ let
substitute ${./scripts/install.in} $out/install \
${pkgs.lib.concatMapStrings
(system: "--replace '@binaryTarball_${system}@' $(nix hash-file --base16 --type sha256 ${binaryTarball.${system}}/*.tar.bz2) ")
(system: "--replace '@binaryTarball_${system}@' $(nix hash-file --type sha256 ${binaryTarball.${system}}/*.tar.bz2) ")
[ "x86_64-linux" "i686-linux" "x86_64-darwin" "aarch64-linux" ]
} \
--replace '@nixVersion@' ${build.x86_64-linux.src.version}

View File

@@ -674,6 +674,9 @@ $NIX_INSTALLED_NIX.
EOF
fi
_sudo "to initialize the Nix Database" \
$NIX_INSTALLED_NIX/bin/nix-store --init
cat ./.reginfo \
| _sudo "to load data for the first time in to the Nix Database" \
"$NIX_INSTALLED_NIX/bin/nix-store" --load-db
@@ -744,6 +747,7 @@ build-users-group = $NIX_BUILD_GROUP_NAME
max-jobs = $NIX_USER_COUNT
cores = 1
sandbox = false
EOF
_sudo "to place the default nix daemon configuration (part 2)" \
install -m 0664 "$SCRATCH/nix.conf" /etc/nix/nix.conf

View File

@@ -109,6 +109,12 @@ for i in $(cd "$self/store" >/dev/null && echo ./*); do
done
echo "" >&2
echo "initialising Nix database..." >&2
if ! $nix/bin/nix-store --init; then
echo "$0: failed to initialize the Nix database" >&2
exit 1
fi
if ! "$nix/bin/nix-store" --load-db < "$self/.reginfo"; then
echo "$0: unable to register valid paths" >&2
exit 1

View File

@@ -11,14 +11,14 @@ oops() {
}
tmpDir="$(mktemp -d -t nix-binary-tarball-unpack.XXXXXXXXXX || \
oops "Can't create temporary directory for downloading the Nix binary tarball")"
oops "Can\'t create temporary directory for downloading the Nix binary tarball")"
cleanup() {
rm -rf "$tmpDir"
}
trap cleanup EXIT INT QUIT TERM
require_util() {
type "$1" > /dev/null 2>&1 || command -v "$1" > /dev/null 2>&1 ||
type "$1" > /dev/null 2>&1 || which "$1" > /dev/null 2>&1 ||
oops "you do not have '$1' installed, which I need to $2"
}

View File

@@ -61,14 +61,11 @@ elif [ -e /etc/ssl/certs/ca-bundle.crt ]; then # Old NixOS
export NIX_SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt
elif [ -e /etc/pki/tls/certs/ca-bundle.crt ]; then # Fedora, CentOS
export NIX_SSL_CERT_FILE=/etc/pki/tls/certs/ca-bundle.crt
else
# Fall back to what is in the nix profiles, favouring whatever is defined last.
for i in $NIX_PROFILES; do
if [ -e $i/etc/ssl/certs/ca-bundle.crt ]; then
export NIX_SSL_CERT_FILE=$i/etc/ssl/certs/ca-bundle.crt
fi
done
elif [ -e "$NIX_USER_PROFILE_DIR/etc/ssl/certs/ca-bundle.crt" ]; then # fall back to cacert in the user's Nix profile
export NIX_SSL_CERT_FILE=$NIX_USER_PROFILE_DIR/etc/ssl/certs/ca-bundle.crt
elif [ -e "/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt" ]; then # fall back to cacert in the default Nix profile
export NIX_SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt
fi
export NIX_PATH="nixpkgs=@localstatedir@/nix/profiles/per-user/root/channels/nixpkgs:@localstatedir@/nix/profiles/per-user/root/channels"
export PATH="$HOME/.nix-profile/bin:@localstatedir@/nix/profiles/default/bin:$PATH"
export PATH="$HOME/.nix-profile/bin:$HOME/.nix-profile/lib/kde4/libexec:@localstatedir@/nix/profiles/default/bin:@localstatedir@/nix/profiles/default:@localstatedir@/nix/profiles/default/lib/kde4/libexec:$PATH"

View File

@@ -75,7 +75,7 @@ if [ -n "$HOME" ] && [ -n "$USER" ]; then
export NIX_SSL_CERT_FILE="$NIX_LINK/etc/ca-bundle.crt"
fi
if [ -n "${MANPATH-}" ]; then
if [ -n "${MANPATH}" ]; then
export MANPATH="$NIX_LINK/share/man:$MANPATH"
fi

View File

@@ -1,6 +1,6 @@
{ useClang ? false }:
with import (builtins.fetchGit { url = https://github.com/NixOS/nixpkgs-channels.git; ref = "nixos-19.03"; }) {};
with import (builtins.fetchGit { url = https://github.com/NixOS/nixpkgs-channels.git; ref = "nixos-18.03"; }) {};
with import ./release-common.nix { inherit pkgs; };

View File

@@ -17,7 +17,6 @@
#include "store-api.hh"
#include "derivations.hh"
#include "local-store.hh"
#include "legacy.hh"
using namespace nix;
using std::cin;
@@ -38,15 +37,11 @@ static AutoCloseFD openSlotLock(const Machine & m, unsigned long long slot)
return openLockFile(fmt("%s/%s-%d", currentLoad, escapeUri(m.storeUri), slot), true);
}
static bool allSupportedLocally(const std::set<std::string>& requiredFeatures) {
for (auto & feature : requiredFeatures)
if (!settings.systemFeatures.get().count(feature)) return false;
return true;
}
static int _main(int argc, char * * argv)
int main (int argc, char * * argv)
{
{
return handleExceptions(argv[0], [&]() {
initNix();
logger = makeJSONLogger(*logger);
/* Ensure we don't get any SSH passphrase or host key popups. */
@@ -85,7 +80,7 @@ static int _main(int argc, char * * argv)
if (machines.empty()) {
std::cerr << "# decline-permanently\n";
return 0;
return;
}
string drvPath;
@@ -95,18 +90,17 @@ static int _main(int argc, char * * argv)
try {
auto s = readString(source);
if (s != "try") return 0;
} catch (EndOfFile &) { return 0; }
if (s != "try") return;
} catch (EndOfFile &) { return; }
auto amWilling = readInt(source);
auto neededSystem = readString(source);
source >> drvPath;
auto requiredFeatures = readStrings<std::set<std::string>>(source);
auto canBuildLocally = amWilling
&& ( neededSystem == settings.thisSystem
|| settings.extraPlatforms.get().count(neededSystem) > 0)
&& allSupportedLocally(requiredFeatures);
auto canBuildLocally = amWilling
&& ( neededSystem == settings.thisSystem
|| settings.extraPlatforms.get().count(neededSystem) > 0);
/* Error ignored here, will be caught later */
mkdir(currentLoad.c_str(), 0777);
@@ -259,8 +253,6 @@ connected:
copyPaths(ref<Store>(sshStore), store, missing, NoRepair, NoCheckSigs, NoSubstitute);
}
return 0;
}
return;
});
}
static RegisterLegacyCommand s1("build-remote", _main);

View File

@@ -0,0 +1,9 @@
programs += build-remote
build-remote_DIR := $(d)
build-remote_INSTALL_DIR := $(libexecdir)/nix
build-remote_LIBS = libmain libformat libstore libutil
build-remote_SOURCES := $(d)/build-remote.cc

View File

@@ -6,15 +6,12 @@
#include "globals.hh"
#include "eval-inline.hh"
#include "download.hh"
#include "json.hh"
#include <algorithm>
#include <cstring>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <iostream>
#include <fstream>
#include <sys/time.h>
#include <sys/resource.h>
@@ -26,6 +23,7 @@
#endif
namespace nix {
@@ -130,16 +128,6 @@ std::ostream & operator << (std::ostream & str, const Value & v)
}
const Value *getPrimOp(const Value &v) {
const Value * primOp = &v;
while (primOp->type == tPrimOpApp) {
primOp = primOp->primOpApp.left;
}
assert(primOp->type == tPrimOp);
return primOp;
}
string showType(const Value & v)
{
switch (v.type) {
@@ -154,10 +142,8 @@ string showType(const Value & v)
case tApp: return "a function application";
case tLambda: return "a function";
case tBlackhole: return "a black hole";
case tPrimOp:
return fmt("the built-in function '%s'", string(v.primOp->name));
case tPrimOpApp:
return fmt("the partially applied built-in function '%s'", string(getPrimOp(v)->primOp->name));
case tPrimOp: return "a built-in function";
case tPrimOpApp: return "a partially applied built-in function";
case tExternal: return v.external->showType();
case tFloat: return "a float";
}
@@ -769,7 +755,6 @@ void EvalState::evalFile(const Path & path_, Value & v)
void EvalState::resetFileCache()
{
fileEvalCache.clear();
fileParseCache.clear();
}
@@ -1738,9 +1723,12 @@ bool EvalState::eqValues(Value & v1, Value & v2)
}
}
void EvalState::printStats()
{
bool showStats = getEnv("NIX_SHOW_STATS", "0") != "0";
Verbosity v = showStats ? lvlInfo : lvlDebug;
printMsg(v, "evaluation statistics:");
struct rusage buf;
getrusage(RUSAGE_SELF, &buf);
@@ -1751,107 +1739,62 @@ void EvalState::printStats()
uint64_t bValues = nrValues * sizeof(Value);
uint64_t bAttrsets = nrAttrsets * sizeof(Bindings) + nrAttrsInAttrsets * sizeof(Attr);
printMsg(v, format(" time elapsed: %1%") % cpuTime);
printMsg(v, format(" size of a value: %1%") % sizeof(Value));
printMsg(v, format(" size of an attr: %1%") % sizeof(Attr));
printMsg(v, format(" environments allocated count: %1%") % nrEnvs);
printMsg(v, format(" environments allocated bytes: %1%") % bEnvs);
printMsg(v, format(" list elements count: %1%") % nrListElems);
printMsg(v, format(" list elements bytes: %1%") % bLists);
printMsg(v, format(" list concatenations: %1%") % nrListConcats);
printMsg(v, format(" values allocated count: %1%") % nrValues);
printMsg(v, format(" values allocated bytes: %1%") % bValues);
printMsg(v, format(" sets allocated: %1% (%2% bytes)") % nrAttrsets % bAttrsets);
printMsg(v, format(" right-biased unions: %1%") % nrOpUpdates);
printMsg(v, format(" values copied in right-biased unions: %1%") % nrOpUpdateValuesCopied);
printMsg(v, format(" symbols in symbol table: %1%") % symbols.size());
printMsg(v, format(" size of symbol table: %1%") % symbols.totalSize());
printMsg(v, format(" number of thunks: %1%") % nrThunks);
printMsg(v, format(" number of thunks avoided: %1%") % nrAvoided);
printMsg(v, format(" number of attr lookups: %1%") % nrLookups);
printMsg(v, format(" number of primop calls: %1%") % nrPrimOpCalls);
printMsg(v, format(" number of function calls: %1%") % nrFunctionCalls);
printMsg(v, format(" total allocations: %1% bytes") % (bEnvs + bLists + bValues + bAttrsets));
#if HAVE_BOEHMGC
GC_word heapSize, totalBytes;
GC_get_heap_usage_safe(&heapSize, 0, 0, 0, &totalBytes);
#endif
if (showStats) {
auto outPath = getEnv("NIX_SHOW_STATS_PATH","-");
std::fstream fs;
if (outPath != "-")
fs.open(outPath, std::fstream::out);
JSONObject topObj(outPath == "-" ? std::cerr : fs, true);
topObj.attr("cpuTime",cpuTime);
{
auto envs = topObj.object("envs");
envs.attr("number", nrEnvs);
envs.attr("elements", nrValuesInEnvs);
envs.attr("bytes", bEnvs);
}
{
auto lists = topObj.object("list");
lists.attr("elements", nrListElems);
lists.attr("bytes", bLists);
lists.attr("concats", nrListConcats);
}
{
auto values = topObj.object("values");
values.attr("number", nrValues);
values.attr("bytes", bValues);
}
{
auto syms = topObj.object("symbols");
syms.attr("number", symbols.size());
syms.attr("bytes", symbols.totalSize());
}
{
auto sets = topObj.object("sets");
sets.attr("number", nrAttrsets);
sets.attr("bytes", bAttrsets);
sets.attr("elements", nrAttrsInAttrsets);
}
{
auto sizes = topObj.object("sizes");
sizes.attr("Env", sizeof(Env));
sizes.attr("Value", sizeof(Value));
sizes.attr("Bindings", sizeof(Bindings));
sizes.attr("Attr", sizeof(Attr));
}
topObj.attr("nrOpUpdates", nrOpUpdates);
topObj.attr("nrOpUpdateValuesCopied", nrOpUpdateValuesCopied);
topObj.attr("nrThunks", nrThunks);
topObj.attr("nrAvoided", nrAvoided);
topObj.attr("nrLookups", nrLookups);
topObj.attr("nrPrimOpCalls", nrPrimOpCalls);
topObj.attr("nrFunctionCalls", nrFunctionCalls);
#if HAVE_BOEHMGC
{
auto gc = topObj.object("gc");
gc.attr("heapSize", heapSize);
gc.attr("totalBytes", totalBytes);
}
printMsg(v, format(" current Boehm heap size: %1% bytes") % heapSize);
printMsg(v, format(" total Boehm heap allocations: %1% bytes") % totalBytes);
#endif
if (countCalls) {
{
auto obj = topObj.object("primops");
for (auto & i : primOpCalls)
obj.attr(i.first, i.second);
}
{
auto list = topObj.list("functions");
for (auto & i : functionCalls) {
auto obj = list.object();
if (i.first->name.set())
obj.attr("name", (const string &) i.first->name);
else
obj.attr("name", nullptr);
if (i.first->pos) {
obj.attr("file", (const string &) i.first->pos.file);
obj.attr("line", i.first->pos.line);
obj.attr("column", i.first->pos.column);
}
obj.attr("count", i.second);
}
}
{
auto list = topObj.list("attributes");
for (auto & i : attrSelects) {
auto obj = list.object();
if (i.first) {
obj.attr("file", (const string &) i.first.file);
obj.attr("line", i.first.line);
obj.attr("column", i.first.column);
}
obj.attr("count", i.second);
}
}
}
if (countCalls) {
v = lvlInfo;
printMsg(v, format("calls to %1% primops:") % primOpCalls.size());
typedef std::multimap<size_t, Symbol> PrimOpCalls_;
PrimOpCalls_ primOpCalls_;
for (auto & i : primOpCalls)
primOpCalls_.insert(std::pair<size_t, Symbol>(i.second, i.first));
for (auto i = primOpCalls_.rbegin(); i != primOpCalls_.rend(); ++i)
printMsg(v, format("%1$10d %2%") % i->first % i->second);
printMsg(v, format("calls to %1% functions:") % functionCalls.size());
typedef std::multimap<size_t, ExprLambda *> FunctionCalls_;
FunctionCalls_ functionCalls_;
for (auto & i : functionCalls)
functionCalls_.insert(std::pair<size_t, ExprLambda *>(i.second, i.first));
for (auto i = functionCalls_.rbegin(); i != functionCalls_.rend(); ++i)
printMsg(v, format("%1$10d %2%") % i->first % i->second->showNamePos());
printMsg(v, format("evaluations of %1% attributes:") % attrSelects.size());
typedef std::multimap<size_t, Pos> AttrSelects_;
AttrSelects_ attrSelects_;
for (auto & i : attrSelects)
attrSelects_.insert(std::pair<size_t, Pos>(i.second, i.first));
for (auto i = attrSelects_.rbegin(); i != attrSelects_.rend(); ++i)
printMsg(v, format("%1$10d %2%") % i->first % i->second);
if (getEnv("NIX_SHOW_SYMBOLS", "0") != "0") {
auto list = topObj.list("symbols");
symbols.dump([&](const std::string & s) { list.elem(s); });
}
}
}

View File

@@ -81,7 +81,7 @@ public:
/* The allowed filesystem paths in restricted or pure evaluation
mode. */
std::optional<PathSet> allowedPaths;
std::experimental::optional<PathSet> allowedPaths;
Value vEmptySet;
@@ -316,9 +316,6 @@ private:
/* Return a string representing the type of the value `v'. */
string showType(const Value & v);
/* Decode a context string !<name>!<path> into a pair <path,
name>. */
std::pair<string, string> decodeContext(const string & s);
/* If `path' refers to a directory, then append "/default.nix". */
Path resolveExprPath(Path path);

View File

@@ -295,7 +295,7 @@ static bool getDerivation(EvalState & state, Value & v,
}
std::optional<DrvInfo> getDerivation(EvalState & state, Value & v,
std::experimental::optional<DrvInfo> getDerivation(EvalState & state, Value & v,
bool ignoreAssertionFailures)
{
Done done;

View File

@@ -44,7 +44,7 @@ public:
string queryDrvPath() const;
string queryOutPath() const;
string queryOutputName() const;
/** Return the list of outputs. The "outputs to install" are determined by `meta.outputsToInstall`. */
/** Return the list of outputs. The "outputs to install" are determined by `mesa.outputsToInstall`. */
Outputs queryOutputs(bool onlyOutputsToInstall = false);
StringSet queryMetaNames();
@@ -78,7 +78,7 @@ typedef list<DrvInfo> DrvInfos;
/* If value `v' denotes a derivation, return a DrvInfo object
describing it. Otherwise return nothing. */
std::optional<DrvInfo> getDerivation(EvalState & state,
std::experimental::optional<DrvInfo> getDerivation(EvalState & state,
Value & v, bool ignoreAssertionFailures);
void getDerivations(EvalState & state, Value & v, const string & pathPrefix,

View File

@@ -6,14 +6,12 @@
%option nounput noyy_top_state
%s DEFAULT
%x STRING
%x IND_STRING
%x INSIDE_DOLLAR_CURLY
%{
#include <boost/lexical_cast.hpp>
#include "nixexpr.hh"
#include "parser-tab.hh"
@@ -99,6 +97,8 @@ URI [a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~
%%
<INITIAL,INSIDE_DOLLAR_CURLY>{
if { return IF; }
then { return THEN; }
@@ -124,11 +124,9 @@ or { return OR_KW; }
{ID} { yylval->id = strdup(yytext); return ID; }
{INT} { errno = 0;
try {
yylval->n = boost::lexical_cast<int64_t>(yytext);
} catch (const boost::bad_lexical_cast &) {
yylval->n = strtol(yytext, 0, 10);
if (errno != 0)
throw ParseError(format("invalid integer '%1%'") % yytext);
}
return INT;
}
{FLOAT} { errno = 0;
@@ -138,19 +136,17 @@ or { return OR_KW; }
return FLOAT;
}
\$\{ { PUSH_STATE(DEFAULT); return DOLLAR_CURLY; }
\$\{ { PUSH_STATE(INSIDE_DOLLAR_CURLY); return DOLLAR_CURLY; }
}
\} { /* State INITIAL only exists at the bottom of the stack and is
used as a marker. DEFAULT replaces it everywhere else.
Popping when in INITIAL state causes an empty stack exception,
so don't */
if (YYSTATE != INITIAL)
POP_STATE();
return '}';
}
\{ { PUSH_STATE(DEFAULT); return '{'; }
\} { return '}'; }
<INSIDE_DOLLAR_CURLY>\} { POP_STATE(); return '}'; }
\{ { return '{'; }
<INSIDE_DOLLAR_CURLY>\{ { PUSH_STATE(INSIDE_DOLLAR_CURLY); return '{'; }
\" { PUSH_STATE(STRING); return '"'; }
<INITIAL,INSIDE_DOLLAR_CURLY>\" {
PUSH_STATE(STRING); return '"';
}
<STRING>([^\$\"\\]|\$[^\{\"\\]|\\{ANY}|\$\\{ANY})*\$/\" |
<STRING>([^\$\"\\]|\$[^\{\"\\]|\\{ANY}|\$\\{ANY})+ {
/* It is impossible to match strings ending with '$' with one
@@ -159,7 +155,7 @@ or { return OR_KW; }
yylval->e = unescapeStr(data->symbols, yytext, yyleng);
return STR;
}
<STRING>\$\{ { PUSH_STATE(DEFAULT); return DOLLAR_CURLY; }
<STRING>\$\{ { PUSH_STATE(INSIDE_DOLLAR_CURLY); return DOLLAR_CURLY; }
<STRING>\" { POP_STATE(); return '"'; }
<STRING>\$|\\|\$\\ {
/* This can only occur when we reach EOF, otherwise the above
@@ -169,7 +165,7 @@ or { return OR_KW; }
return STR;
}
\'\'(\ *\n)? { PUSH_STATE(IND_STRING); return IND_STRING_OPEN; }
<INITIAL,INSIDE_DOLLAR_CURLY>\'\'(\ *\n)? { PUSH_STATE(IND_STRING); return IND_STRING_OPEN; }
<IND_STRING>([^\$\']|\$[^\{\']|\'[^\'\$])+ {
yylval->e = new ExprIndStr(yytext);
return IND_STR;
@@ -187,13 +183,14 @@ or { return OR_KW; }
yylval->e = unescapeStr(data->symbols, yytext + 2, yyleng - 2);
return IND_STR;
}
<IND_STRING>\$\{ { PUSH_STATE(DEFAULT); return DOLLAR_CURLY; }
<IND_STRING>\$\{ { PUSH_STATE(INSIDE_DOLLAR_CURLY); return DOLLAR_CURLY; }
<IND_STRING>\'\' { POP_STATE(); return IND_STRING_CLOSE; }
<IND_STRING>\' {
yylval->e = new ExprIndStr("'");
return IND_STR;
}
<INITIAL,INSIDE_DOLLAR_CURLY>{
{PATH} { if (yytext[yyleng-1] == '/')
throw ParseError("path '%s' has a trailing slash", yytext);
@@ -218,5 +215,7 @@ or { return OR_KW; }
return (unsigned char) yytext[0];
}
}
%%

View File

@@ -6,7 +6,7 @@ libexpr_DIR := $(d)
libexpr_SOURCES := $(wildcard $(d)/*.cc) $(wildcard $(d)/primops/*.cc) $(d)/lexer-tab.cc $(d)/parser-tab.cc
libexpr_LIBS = libutil libstore
libexpr_LIBS = libutil libstore libformat
libexpr_LDFLAGS =
ifneq ($(OS), FreeBSD)

View File

@@ -7,4 +7,4 @@ Description: Nix Package Manager
Version: @PACKAGE_VERSION@
Requires: nix-store bdw-gc
Libs: -L${libdir} -lnixexpr
Cflags: -I${includedir}/nix -std=c++17
Cflags: -I${includedir}/nix -std=c++14

View File

@@ -1,7 +1,7 @@
%glr-parser
%pure-parser
%locations
%define parse.error verbose
%error-verbose
%defines
/* %no-lines */
%parse-param { void * scanner }

View File

@@ -315,12 +315,6 @@ static void prim_isBool(EvalState & state, const Pos & pos, Value * * args, Valu
mkBool(v, args[0]->type == tBool);
}
/* Determine whether the argument is a path. */
static void prim_isPath(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceValue(*args[0]);
mkBool(v, args[0]->type == tPath);
}
struct CompareValues
{
@@ -341,8 +335,6 @@ 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));
}
@@ -563,7 +555,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
PathSet context;
std::optional<std::string> outputHash;
std::experimental::optional<std::string> outputHash;
std::string outputHashAlgo;
bool outputHashRecursive = false;
@@ -695,12 +687,21 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
}
}
/* See prim_unsafeDiscardOutputDependency. */
else if (path.at(0) == '~')
drv.inputSrcs.insert(string(path, 1));
/* Handle derivation outputs of the form !<name>!<path>. */
else if (path.at(0) == '!') {
std::pair<string, string> ctx = decodeContext(path);
drv.inputDrvs[ctx.first].insert(ctx.second);
}
/* Handle derivation contexts returned by
builtins.storePath. */
else if (isDerivation(path))
drv.inputDrvs[path] = state.store->queryDerivationOutputNames(path);
/* Otherwise it's a source file. */
else
drv.inputSrcs.insert(path);
@@ -723,14 +724,16 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
if (outputs.size() != 1 || *(outputs.begin()) != "out")
throw Error(format("multiple outputs are not supported in fixed-output derivations, at %1%") % posDrvName);
HashType ht = outputHashAlgo.empty() ? htUnknown : parseHashType(outputHashAlgo);
HashType ht = parseHashType(outputHashAlgo);
if (ht == htUnknown)
throw EvalError(format("unknown hash algorithm '%1%', at %2%") % outputHashAlgo % posDrvName);
Hash h(*outputHash, ht);
outputHash = h.to_string(Base16, false);
if (outputHashRecursive) outputHashAlgo = "r:" + outputHashAlgo;
Path outPath = state.store->makeFixedOutputPath(outputHashRecursive, h, drvName);
if (!jsonObject) drv.env["out"] = outPath;
drv.outputs["out"] = DerivationOutput(outPath,
(outputHashRecursive ? "r:" : "") + printHashType(h.type),
h.to_string(Base16, false));
drv.outputs["out"] = DerivationOutput(outPath, outputHashAlgo, *outputHash);
}
else {
@@ -863,7 +866,7 @@ static void prim_baseNameOf(EvalState & state, const Pos & pos, Value * * args,
static void prim_dirOf(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
Path dir = dirOf(state.coerceToString(pos, *args[0], context, false, false));
Path dir = dirOf(state.coerceToPath(pos, *args[0], context));
if (args[0]->type == tPath) mkPath(v, dir.c_str()); else mkString(v, dir, context);
}
@@ -1003,8 +1006,13 @@ static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Valu
PathSet refs;
for (auto path : context) {
if (path.at(0) != '/')
throw EvalError(format("in 'toFile': the file '%1%' cannot refer to derivation outputs, at %2%") % name % pos);
if (path.at(0) == '=') path = string(path, 1);
if (isDerivation(path)) {
/* See prim_unsafeDiscardOutputDependency. */
if (path.at(0) != '~')
throw EvalError(format("in 'toFile': the file '%1%' cannot refer to derivation outputs, at %2%") % name % pos);
path = string(path, 1);
}
refs.insert(path);
}
@@ -1578,6 +1586,7 @@ 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. */
@@ -1597,62 +1606,6 @@ 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);
@@ -1843,6 +1796,41 @@ static void prim_stringLength(EvalState & state, const Pos & pos, Value * * args
}
static void prim_unsafeDiscardStringContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
string s = state.coerceToString(pos, *args[0], context);
mkString(v, s, PathSet());
}
static void prim_hasContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
state.forceString(*args[0], context, pos);
mkBool(v, !context.empty());
}
/* Sometimes we want to pass a derivation path (i.e. pkg.drvPath) to a
builder without causing the derivation to be built (for instance,
in the derivation that builds NARs in nix-push, when doing
source-only deployment). This primop marks the string context so
that builtins.derivation adds the path to drv.inputSrcs rather than
drv.inputDrvs. */
static void prim_unsafeDiscardOutputDependency(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
string s = state.coerceToString(pos, *args[0], context);
PathSet context2;
for (auto & p : context)
context2.insert(p.at(0) == '=' ? "~" + string(p, 1) : p);
mkString(v, s, context2);
}
/* Return the cryptographic hash of a string in base-16. */
static void prim_hashString(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
@@ -2232,7 +2220,6 @@ void EvalState::createBaseEnv()
addPrimOp("__isInt", 1, prim_isInt);
addPrimOp("__isFloat", 1, prim_isFloat);
addPrimOp("__isBool", 1, prim_isBool);
addPrimOp("__isPath", 1, prim_isPath);
addPrimOp("__genericClosure", 1, prim_genericClosure);
addPrimOp("abort", 1, prim_abort);
addPrimOp("__addErrorContext", 2, prim_addErrorContext);
@@ -2297,7 +2284,6 @@ 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);
@@ -2315,6 +2301,9 @@ void EvalState::createBaseEnv()
addPrimOp("toString", 1, prim_toString);
addPrimOp("__substring", 3, prim_substring);
addPrimOp("__stringLength", 1, prim_stringLength);
addPrimOp("__hasContext", 1, prim_hasContext);
addPrimOp("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext);
addPrimOp("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency);
addPrimOp("__hashString", 2, prim_hashString);
addPrimOp("__match", 2, prim_match);
addPrimOp("__split", 2, prim_split);

View File

@@ -1,187 +0,0 @@
#include "primops.hh"
#include "eval-inline.hh"
#include "derivations.hh"
namespace nix {
static void prim_unsafeDiscardStringContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
string s = state.coerceToString(pos, *args[0], context);
mkString(v, s, PathSet());
}
static RegisterPrimOp r1("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext);
static void prim_hasContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
state.forceString(*args[0], context, pos);
mkBool(v, !context.empty());
}
static RegisterPrimOp r2("__hasContext", 1, prim_hasContext);
/* Sometimes we want to pass a derivation path (i.e. pkg.drvPath) to a
builder without causing the derivation to be built (for instance,
in the derivation that builds NARs in nix-push, when doing
source-only deployment). This primop marks the string context so
that builtins.derivation adds the path to drv.inputSrcs rather than
drv.inputDrvs. */
static void prim_unsafeDiscardOutputDependency(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
string s = state.coerceToString(pos, *args[0], context);
PathSet context2;
for (auto & p : context)
context2.insert(p.at(0) == '=' ? string(p, 1) : p);
mkString(v, s, context2);
}
static RegisterPrimOp r3("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency);
/* Extract the context of a string as a structured Nix value.
The context is represented as an attribute set whose keys are the
paths in the context set and whose values are attribute sets with
the following keys:
path: True if the relevant path is in the context as a plain store
path (i.e. the kind of context you get when interpolating
a Nix path (e.g. ./.) into a string). False if missing.
allOutputs: True if the relevant path is a derivation and it is
in the context as a drv file with all of its outputs
(i.e. the kind of context you get when referencing
.drvPath of some derivation). False if missing.
outputs: If a non-empty list, the relevant path is a derivation
and the provided outputs are referenced in the context
(i.e. the kind of context you get when referencing
.outPath of some derivation). Empty list if missing.
Note that for a given path any combination of the above attributes
may be present.
*/
static void prim_getContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
struct ContextInfo {
bool path = false;
bool allOutputs = false;
Strings outputs;
};
PathSet context;
state.forceString(*args[0], context, pos);
auto contextInfos = std::map<Path, ContextInfo>();
for (const auto & p : context) {
Path drv;
string output;
const Path * path = &p;
if (p.at(0) == '=') {
drv = string(p, 1);
path = &drv;
} else if (p.at(0) == '!') {
std::pair<string, string> ctx = decodeContext(p);
drv = ctx.first;
output = ctx.second;
path = &drv;
}
auto isPath = drv.empty();
auto isAllOutputs = (!drv.empty()) && output.empty();
auto iter = contextInfos.find(*path);
if (iter == contextInfos.end()) {
contextInfos.emplace(*path, ContextInfo{isPath, isAllOutputs, output.empty() ? Strings{} : Strings{std::move(output)}});
} else {
if (isPath)
iter->second.path = true;
else if (isAllOutputs)
iter->second.allOutputs = true;
else
iter->second.outputs.emplace_back(std::move(output));
}
}
state.mkAttrs(v, contextInfos.size());
auto sPath = state.symbols.create("path");
auto sAllOutputs = state.symbols.create("allOutputs");
for (const auto & info : contextInfos) {
auto & infoVal = *state.allocAttr(v, state.symbols.create(info.first));
state.mkAttrs(infoVal, 3);
if (info.second.path)
mkBool(*state.allocAttr(infoVal, sPath), true);
if (info.second.allOutputs)
mkBool(*state.allocAttr(infoVal, sAllOutputs), true);
if (!info.second.outputs.empty()) {
auto & outputsVal = *state.allocAttr(infoVal, state.sOutputs);
state.mkList(outputsVal, info.second.outputs.size());
size_t i = 0;
for (const auto & output : info.second.outputs) {
mkString(*(outputsVal.listElems()[i++] = state.allocValue()), output);
}
}
infoVal.attrs->sort();
}
v.attrs->sort();
}
static RegisterPrimOp r4("__getContext", 1, prim_getContext);
/* Append the given context to a given string.
See the commentary above unsafeGetContext for details of the
context representation.
*/
static void prim_appendContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
auto orig = state.forceString(*args[0], context, pos);
state.forceAttrs(*args[1], pos);
auto sPath = state.symbols.create("path");
auto sAllOutputs = state.symbols.create("allOutputs");
for (auto & i : *args[1]->attrs) {
if (!state.store->isStorePath(i.name))
throw EvalError("Context key '%s' is not a store path, at %s", i.name, i.pos);
if (!settings.readOnlyMode)
state.store->ensurePath(i.name);
state.forceAttrs(*i.value, *i.pos);
auto iter = i.value->attrs->find(sPath);
if (iter != i.value->attrs->end()) {
if (state.forceBool(*iter->value, *iter->pos))
context.insert(i.name);
}
iter = i.value->attrs->find(sAllOutputs);
if (iter != i.value->attrs->end()) {
if (state.forceBool(*iter->value, *iter->pos)) {
if (!isDerivation(i.name)) {
throw EvalError("Tried to add all-outputs context of %s, which is not a derivation, to a string, at %s", i.name, i.pos);
}
context.insert("=" + string(i.name));
}
}
iter = i.value->attrs->find(state.sOutputs);
if (iter != i.value->attrs->end()) {
state.forceList(*iter->value, *iter->pos);
if (iter->value->listSize() && !isDerivation(i.name)) {
throw EvalError("Tried to add derivation output context of %s, which is not a derivation, to a string, at %s", i.name, i.pos);
}
for (unsigned int n = 0; n < iter->value->listSize(); ++n) {
auto name = state.forceStringNoCtx(*iter->value->listElems()[n], *iter->pos);
context.insert("!" + name + "!" + string(i.name));
}
}
}
mkString(v, orig, context);
}
static RegisterPrimOp r5("__appendContext", 2, prim_appendContext);
}

View File

@@ -3,7 +3,6 @@
#include "download.hh"
#include "store-api.hh"
#include "pathlocks.hh"
#include "hash.hh"
#include <sys/time.h>
@@ -26,7 +25,7 @@ struct GitInfo
std::regex revRegex("^[0-9a-fA-F]{40}$");
GitInfo exportGit(ref<Store> store, const std::string & uri,
std::optional<std::string> ref, std::string rev,
std::experimental::optional<std::string> ref, std::string rev,
const std::string & name)
{
if (evalSettings.pureEval && rev == "")
@@ -85,16 +84,15 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,
if (rev != "" && !std::regex_match(rev, revRegex))
throw Error("invalid Git revision '%s'", rev);
deletePath(getCacheDir() + "/nix/git");
Path cacheDir = getCacheDir() + "/nix/gitv2/" + hashString(htSHA256, uri).to_string(Base32, false);
Path cacheDir = getCacheDir() + "/nix/git";
if (!pathExists(cacheDir)) {
createDirs(dirOf(cacheDir));
runProgram("git", true, { "init", "--bare", cacheDir });
}
Path localRefFile = cacheDir + "/refs/heads/" + *ref;
std::string localRef = hashString(htSHA256, fmt("%s-%s", uri, *ref)).to_string(Base32, false);
Path localRefFile = cacheDir + "/refs/heads/" + localRef;
bool doFetch;
time_t now = time(0);
@@ -124,7 +122,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,
// FIXME: git stderr messes up our progress indicator, so
// we're using --quiet for now. Should process its stderr.
runProgram("git", true, { "-C", cacheDir, "fetch", "--quiet", "--force", "--", uri, fmt("%s:%s", *ref, *ref) });
runProgram("git", true, { "-C", cacheDir, "fetch", "--quiet", "--force", "--", uri, *ref + ":" + localRef });
struct timeval times[2];
times[0].tv_sec = now;
@@ -190,7 +188,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,
static void prim_fetchGit(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
std::string url;
std::optional<std::string> ref;
std::experimental::optional<std::string> ref;
std::string rev;
std::string name = "source";
PathSet context;

View File

@@ -93,22 +93,7 @@ HgInfo exportMercurial(ref<Store> store, const std::string & uri,
Activity act(*logger, lvlTalkative, actUnknown, fmt("fetching Mercurial repository '%s'", uri));
if (pathExists(cacheDir)) {
try {
runProgram("hg", true, { "pull", "-R", cacheDir, "--", uri });
}
catch (ExecError & e){
string transJournal = cacheDir + "/.hg/store/journal";
/* hg throws "abandoned transaction" error only if this file exists */
if (pathExists(transJournal))
{
runProgram("hg", true, { "recover", "-R", cacheDir });
runProgram("hg", true, { "pull", "-R", cacheDir, "--", uri });
}
else
{
throw ExecError(e.status, fmt("program hg '%1%' ", statusToString(e.status)));
}
}
runProgram("hg", true, { "pull", "-R", cacheDir, "--", uri });
} else {
createDirs(dirOf(cacheDir));
runProgram("hg", true, { "clone", "--noupdate", "--", uri, cacheDir });

View File

@@ -75,13 +75,6 @@ public:
}
size_t totalSize() const;
template<typename T>
void dump(T callback)
{
for (auto & s : symbols)
callback(s);
}
};
}

View File

@@ -43,7 +43,7 @@ class XMLWriter;
class JSONPlaceholder;
typedef int64_t NixInt;
typedef long NixInt;
typedef double NixFloat;
/* External values must descend from ExternalValueBase, so that

View File

@@ -8,7 +8,7 @@ libmain_SOURCES := $(wildcard $(d)/*.cc)
libmain_LDFLAGS = $(OPENSSL_LIBS)
libmain_LIBS = libstore libutil
libmain_LIBS = libstore libutil libformat
libmain_ALLOW_UNDEFINED = 1

View File

@@ -6,4 +6,4 @@ Name: Nix
Description: Nix Package Manager
Version: @PACKAGE_VERSION@
Libs: -L${libdir} -lnixmain
Cflags: -I${includedir}/nix -std=c++17
Cflags: -I${includedir}/nix -std=c++14

View File

@@ -63,7 +63,7 @@ void detectStackOverflow()
act.sa_sigaction = sigsegvHandler;
act.sa_flags = SA_SIGINFO | SA_ONSTACK;
if (sigaction(SIGSEGV, &act, 0))
throw SysError("resetting SIGSEGV");
throw SysError("resetting SIGCHLD");
#endif
}

View File

@@ -72,11 +72,24 @@ public:
bool isValidPathUncached(const Path & path) override;
PathSet queryAllValidPaths() override
{ unsupported(); }
void queryPathInfoUncached(const Path & path,
Callback<std::shared_ptr<ValidPathInfo>> callback) override;
void queryReferrers(const Path & path,
PathSet & referrers) override
{ unsupported(); }
PathSet queryDerivationOutputs(const Path & path) override
{ unsupported(); }
StringSet queryDerivationOutputNames(const Path & path) override
{ unsupported(); }
Path queryPathFromHashPart(const string & hashPart) override
{ unsupported("queryPathFromHashPart"); }
{ unsupported(); }
bool wantMassQuery() override { return wantMassQuery_; }
@@ -95,10 +108,22 @@ public:
BuildResult buildDerivation(const Path & drvPath, const BasicDerivation & drv,
BuildMode buildMode) override
{ unsupported("buildDerivation"); }
{ unsupported(); }
void ensurePath(const Path & path) override
{ unsupported("ensurePath"); }
{ unsupported(); }
void addTempRoot(const Path & path) override
{ unsupported(); }
void addIndirectRoot(const Path & path) override
{ unsupported(); }
Roots findRoots() override
{ unsupported(); }
void collectGarbage(const GCOptions & options, GCResults & results) override
{ unsupported(); }
ref<FSAccessor> getFSAccessor() override;

View File

@@ -11,8 +11,6 @@
#include "compression.hh"
#include "json.hh"
#include "nar-info.hh"
#include "parsed-derivations.hh"
#include "machines.hh"
#include <algorithm>
#include <iostream>
@@ -22,7 +20,6 @@
#include <future>
#include <chrono>
#include <regex>
#include <queue>
#include <limits.h>
#include <sys/time.h>
@@ -743,8 +740,6 @@ private:
/* The derivation stored at drvPath. */
std::unique_ptr<BasicDerivation> drv;
std::unique_ptr<ParsedDerivation> parsedDrv;
/* The remainder is state held during the build. */
/* Locks on the output paths. */
@@ -859,7 +854,7 @@ private:
building multiple times. Since this contains the hash, it
allows us to compare whether two rounds produced the same
result. */
std::map<Path, ValidPathInfo> prevInfos;
ValidPathInfos prevInfos;
const uid_t sandboxUid = 1000;
const gid_t sandboxGid = 100;
@@ -940,11 +935,6 @@ private:
as valid. */
void registerOutputs();
/* Check that an output meets the requirements specified by the
'outputChecks' attribute (or the legacy
'{allowed,disallowed}{References,Requisites}' attributes). */
void checkOutputs(const std::map<std::string, ValidPathInfo> & outputs);
/* Open a log file and a pipe to it. */
Path openLogFile();
@@ -1149,8 +1139,6 @@ void DerivationGoal::haveDerivation()
return;
}
parsedDrv = std::make_unique<ParsedDerivation>(drvPath, *drv);
/* We are first going to try to create the invalid output paths
through substitutes. If that doesn't work, we'll build
them. */
@@ -1407,7 +1395,7 @@ void DerivationGoal::tryToBuild()
/* Don't do a remote build if the derivation has the attribute
`preferLocalBuild' set. Also, check and repair modes are only
supported for local builds. */
bool buildLocally = buildMode != bmNormal || parsedDrv->willBuildLocally();
bool buildLocally = buildMode != bmNormal || drv->willBuildLocally();
auto started = [&]() {
auto msg = fmt(
@@ -1653,13 +1641,19 @@ HookReply DerivationGoal::tryBuildHook()
try {
/* Tell the hook about system features (beyond the system type)
required from the build machine. (The hook could parse the
drv file itself, but this is easier.) */
Strings features = tokenizeString<Strings>(get(drv->env, "requiredSystemFeatures"));
for (auto & i : features) checkStoreName(i); /* !!! abuse */
/* Send the request to the hook. */
worker.hook->sink
<< "try"
<< (worker.getNrLocalBuilds() < settings.maxBuildJobs ? 1 : 0)
<< drv->platform
<< drvPath
<< parsedDrv->getRequiredSystemFeatures();
<< features;
worker.hook->sink.flush();
/* Read the first line of input, which should be a word indicating
@@ -1799,26 +1793,23 @@ static void preloadNSS() {
void DerivationGoal::startBuilder()
{
/* Right platform? */
if (!parsedDrv->canBuildLocally())
throw Error("a '%s' with features {%s} is required to build '%s', but I am a '%s' with features {%s}",
drv->platform,
concatStringsSep(", ", parsedDrv->getRequiredSystemFeatures()),
drvPath,
settings.thisSystem,
concatStringsSep(", ", settings.systemFeatures));
if (!drv->canBuildLocally()) {
throw Error(
format("a '%1%' is required to build '%3%', but I am a '%2%'")
% drv->platform % settings.thisSystem % drvPath);
}
if (drv->isBuiltin())
preloadNSS();
#if __APPLE__
additionalSandboxProfile = parsedDrv->getStringAttr("__sandboxProfile").value_or("");
additionalSandboxProfile = get(drv->env, "__sandboxProfile");
#endif
/* Are we doing a chroot build? */
{
auto noChroot = parsedDrv->getBoolAttr("__noChroot");
if (settings.sandboxMode == smEnabled) {
if (noChroot)
if (get(drv->env, "__noChroot") == "1")
throw Error(format("derivation '%1%' has '__noChroot' set, "
"but that's not allowed when 'sandbox' is 'true'") % drvPath);
#if __APPLE__
@@ -1831,7 +1822,7 @@ void DerivationGoal::startBuilder()
else if (settings.sandboxMode == smDisabled)
useChroot = false;
else if (settings.sandboxMode == smRelaxed)
useChroot = !fixedOutput && !noChroot;
useChroot = !fixedOutput && get(drv->env, "__noChroot") != "1";
}
if (worker.store.storeDir != worker.store.realStoreDir) {
@@ -1882,7 +1873,7 @@ void DerivationGoal::startBuilder()
writeStructuredAttrs();
/* Handle exportReferencesGraph(), if set. */
if (!parsedDrv->getStructuredAttrs()) {
if (!drv->env.count("__json")) {
/* The `exportReferencesGraph' feature allows the references graph
to be passed to a builder. This attribute should be a list of
pairs [name1 path1 name2 path2 ...]. The references graph of
@@ -1947,7 +1938,7 @@ void DerivationGoal::startBuilder()
PathSet allowedPaths = settings.allowedImpureHostPrefixes;
/* This works like the above, except on a per-derivation level */
auto impurePaths = parsedDrv->getStringsAttr("__impureHostDeps").value_or(Strings());
Strings impurePaths = tokenizeString<Strings>(get(drv->env, "__impureHostDeps"));
for (auto & i : impurePaths) {
bool found = false;
@@ -2016,7 +2007,7 @@ void DerivationGoal::startBuilder()
/* Create /etc/hosts with localhost entry. */
if (!fixedOutput)
writeFile(chrootRootDir + "/etc/hosts", "127.0.0.1 localhost\n::1 localhost\n");
writeFile(chrootRootDir + "/etc/hosts", "127.0.0.1 localhost\n");
/* Make the closure of the inputs available in the chroot,
rather than the whole Nix store. This prevents any access
@@ -2315,7 +2306,7 @@ void DerivationGoal::initEnv()
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()) {
if (!drv->env.count("__json")) {
StringSet passAsFile = tokenizeString<StringSet>(get(drv->env, "passAsFile"));
int fileNr = 0;
@@ -2362,8 +2353,8 @@ void DerivationGoal::initEnv()
fixed-output derivations is by definition pure (since we
already know the cryptographic hash of the output). */
if (fixedOutput) {
for (auto & i : parsedDrv->getStringsAttr("impureEnvVars").value_or(Strings()))
env[i] = getEnv(i);
Strings varNames = tokenizeString<Strings>(get(drv->env, "impureEnvVars"));
for (auto & i : varNames) env[i] = getEnv(i);
}
/* Currently structured log messages piggyback on stderr, but we
@@ -2378,103 +2369,111 @@ static std::regex shVarName("[A-Za-z_][A-Za-z0-9_]*");
void DerivationGoal::writeStructuredAttrs()
{
auto & structuredAttrs = parsedDrv->getStructuredAttrs();
if (!structuredAttrs) return;
auto jsonAttr = drv->env.find("__json");
if (jsonAttr == drv->env.end()) return;
auto json = *structuredAttrs;
try {
/* Add an "outputs" object containing the output paths. */
nlohmann::json outputs;
for (auto & i : drv->outputs)
outputs[i.first] = rewriteStrings(i.second.path, inputRewrites);
json["outputs"] = outputs;
auto jsonStr = rewriteStrings(jsonAttr->second, inputRewrites);
/* Handle exportReferencesGraph. */
auto e = json.find("exportReferencesGraph");
if (e != json.end() && e->is_object()) {
for (auto i = e->begin(); i != e->end(); ++i) {
std::ostringstream str;
{
JSONPlaceholder jsonRoot(str, true);
PathSet storePaths;
for (auto & p : *i)
storePaths.insert(p.get<std::string>());
worker.store.pathInfoToJSON(jsonRoot,
exportReferences(storePaths), false, true);
auto json = nlohmann::json::parse(jsonStr);
/* Add an "outputs" object containing the output paths. */
nlohmann::json outputs;
for (auto & i : drv->outputs)
outputs[i.first] = rewriteStrings(i.second.path, inputRewrites);
json["outputs"] = outputs;
/* Handle exportReferencesGraph. */
auto e = json.find("exportReferencesGraph");
if (e != json.end() && e->is_object()) {
for (auto i = e->begin(); i != e->end(); ++i) {
std::ostringstream str;
{
JSONPlaceholder jsonRoot(str, true);
PathSet storePaths;
for (auto & p : *i)
storePaths.insert(p.get<std::string>());
worker.store.pathInfoToJSON(jsonRoot,
exportReferences(storePaths), false, true);
}
json[i.key()] = nlohmann::json::parse(str.str()); // urgh
}
json[i.key()] = nlohmann::json::parse(str.str()); // urgh
}
writeFile(tmpDir + "/.attrs.json", json.dump());
/* As a convenience to bash scripts, write a shell file that
maps all attributes that are representable in bash -
namely, strings, integers, nulls, Booleans, and arrays and
objects consisting entirely of those values. (So nested
arrays or objects are not supported.) */
auto handleSimpleType = [](const nlohmann::json & value) -> std::experimental::optional<std::string> {
if (value.is_string())
return shellEscape(value);
if (value.is_number()) {
auto f = value.get<float>();
if (std::ceil(f) == f)
return std::to_string(value.get<int>());
}
if (value.is_null())
return std::string("''");
if (value.is_boolean())
return value.get<bool>() ? std::string("1") : std::string("");
return {};
};
std::string jsonSh;
for (auto i = json.begin(); i != json.end(); ++i) {
if (!std::regex_match(i.key(), shVarName)) continue;
auto & value = i.value();
auto s = handleSimpleType(value);
if (s)
jsonSh += fmt("declare %s=%s\n", i.key(), *s);
else if (value.is_array()) {
std::string s2;
bool good = true;
for (auto i = value.begin(); i != value.end(); ++i) {
auto s3 = handleSimpleType(i.value());
if (!s3) { good = false; break; }
s2 += *s3; s2 += ' ';
}
if (good)
jsonSh += fmt("declare -a %s=(%s)\n", i.key(), s2);
}
else if (value.is_object()) {
std::string s2;
bool good = true;
for (auto i = value.begin(); i != value.end(); ++i) {
auto s3 = handleSimpleType(i.value());
if (!s3) { good = false; break; }
s2 += fmt("[%s]=%s ", shellEscape(i.key()), *s3);
}
if (good)
jsonSh += fmt("declare -A %s=(%s)\n", i.key(), s2);
}
}
writeFile(tmpDir + "/.attrs.sh", jsonSh);
} catch (std::exception & e) {
throw Error("cannot process __json attribute of '%s': %s", drvPath, e.what());
}
writeFile(tmpDir + "/.attrs.json", rewriteStrings(json.dump(), inputRewrites));
/* As a convenience to bash scripts, write a shell file that
maps all attributes that are representable in bash -
namely, strings, integers, nulls, Booleans, and arrays and
objects consisting entirely of those values. (So nested
arrays or objects are not supported.) */
auto handleSimpleType = [](const nlohmann::json & value) -> std::optional<std::string> {
if (value.is_string())
return shellEscape(value);
if (value.is_number()) {
auto f = value.get<float>();
if (std::ceil(f) == f)
return std::to_string(value.get<int>());
}
if (value.is_null())
return std::string("''");
if (value.is_boolean())
return value.get<bool>() ? std::string("1") : std::string("");
return {};
};
std::string jsonSh;
for (auto i = json.begin(); i != json.end(); ++i) {
if (!std::regex_match(i.key(), shVarName)) continue;
auto & value = i.value();
auto s = handleSimpleType(value);
if (s)
jsonSh += fmt("declare %s=%s\n", i.key(), *s);
else if (value.is_array()) {
std::string s2;
bool good = true;
for (auto i = value.begin(); i != value.end(); ++i) {
auto s3 = handleSimpleType(i.value());
if (!s3) { good = false; break; }
s2 += *s3; s2 += ' ';
}
if (good)
jsonSh += fmt("declare -a %s=(%s)\n", i.key(), s2);
}
else if (value.is_object()) {
std::string s2;
bool good = true;
for (auto i = value.begin(); i != value.end(); ++i) {
auto s3 = handleSimpleType(i.value());
if (!s3) { good = false; break; }
s2 += fmt("[%s]=%s ", shellEscape(i.key()), *s3);
}
if (good)
jsonSh += fmt("declare -A %s=(%s)\n", i.key(), s2);
}
}
writeFile(tmpDir + "/.attrs.sh", rewriteStrings(jsonSh, inputRewrites));
}
@@ -2629,7 +2628,7 @@ void DerivationGoal::runChild()
createDirs(chrootRootDir + "/dev/shm");
createDirs(chrootRootDir + "/dev/pts");
ss.push_back("/dev/full");
if (settings.systemFeatures.get().count("kvm") && pathExists("/dev/kvm"))
if (pathExists("/dev/kvm"))
ss.push_back("/dev/kvm");
ss.push_back("/dev/null");
ss.push_back("/dev/random");
@@ -2918,7 +2917,7 @@ void DerivationGoal::runChild()
writeFile(sandboxFile, sandboxProfile);
bool allowLocalNetworking = parsedDrv->getBoolAttr("__darwinAllowLocalNetworking");
bool allowLocalNetworking = get(drv->env, "__darwinAllowLocalNetworking") == "1";
/* The tmpDir in scope points at the temporary build directory for our derivation. Some packages try different mechanisms
to find temporary directories, so we want to open up a broader place for them to dump their files, if needed. */
@@ -2990,9 +2989,10 @@ void DerivationGoal::runChild()
/* Parse a list of reference specifiers. Each element must either be
a store path, or the symbolic name of the output of the derivation
(such as `out'). */
PathSet parseReferenceSpecifiers(Store & store, const BasicDerivation & drv, const Strings & paths)
PathSet parseReferenceSpecifiers(Store & store, const BasicDerivation & drv, string attr)
{
PathSet result;
Paths paths = tokenizeString<Paths>(attr);
for (auto & i : paths) {
if (store.isStorePath(i))
result.insert(i);
@@ -3017,7 +3017,7 @@ void DerivationGoal::registerOutputs()
if (allValid) return;
}
std::map<std::string, ValidPathInfo> infos;
ValidPathInfos infos;
/* Set of inodes seen during calls to canonicalisePathMetaData()
for this build's outputs. This needs to be shared between
@@ -3121,15 +3121,15 @@ void DerivationGoal::registerOutputs()
the derivation to its content-addressed location. */
Hash h2 = recursive ? hashPath(h.type, actualPath).first : hashFile(h.type, actualPath);
Path dest = worker.store.makeFixedOutputPath(recursive, h2, storePathToName(path));
Path dest = worker.store.makeFixedOutputPath(recursive, h2, drv->env["name"]);
if (h != h2) {
/* Throw an error after registering the path as
valid. */
delayedException = std::make_exception_ptr(
BuildError("hash mismatch in fixed-output derivation '%s':\n wanted: %s\n got: %s",
dest, h.to_string(), h2.to_string()));
BuildError("fixed-output derivation produced path '%s' with %s hash '%s' instead of the expected hash '%s'",
dest, printHashType(h.type), printHash16or32(h2), printHash16or32(h)));
Path actualDest = worker.store.toRealPath(dest);
@@ -3202,6 +3202,48 @@ void DerivationGoal::registerOutputs()
debug(format("referenced input: '%1%'") % i);
}
/* Enforce `allowedReferences' and friends. */
auto checkRefs = [&](const string & attrName, bool allowed, bool recursive) {
if (drv->env.find(attrName) == drv->env.end()) return;
PathSet spec = parseReferenceSpecifiers(worker.store, *drv, get(drv->env, attrName));
PathSet used;
if (recursive) {
/* Our requisites are the union of the closures of our references. */
for (auto & i : references)
/* Don't call computeFSClosure on ourselves. */
if (path != i)
worker.store.computeFSClosure(i, used);
} else
used = references;
PathSet badPaths;
for (auto & i : used)
if (allowed) {
if (spec.find(i) == spec.end())
badPaths.insert(i);
} else {
if (spec.find(i) != spec.end())
badPaths.insert(i);
}
if (!badPaths.empty()) {
string badPathsStr;
for (auto & i : badPaths) {
badPathsStr += "\n\t";
badPathsStr += i;
}
throw BuildError(format("output '%1%' is not allowed to refer to the following paths:%2%") % actualPath % badPathsStr);
}
};
checkRefs("allowedReferences", true, false);
checkRefs("allowedRequisites", true, true);
checkRefs("disallowedReferences", false, false);
checkRefs("disallowedRequisites", false, true);
if (curRound == nrRounds) {
worker.store.optimisePath(actualPath); // FIXME: combine with scanForReferences()
worker.markContentsGood(path);
@@ -3217,14 +3259,11 @@ void DerivationGoal::registerOutputs()
if (!info.references.empty()) info.ca.clear();
infos[i.first] = info;
infos.push_back(info);
}
if (buildMode == bmCheck) return;
/* Apply output checks. */
checkOutputs(infos);
/* Compare the result with the previous round, and report which
path is different, if any.*/
if (curRound > 1 && prevInfos != infos) {
@@ -3232,16 +3271,16 @@ void DerivationGoal::registerOutputs()
for (auto i = prevInfos.begin(), j = infos.begin(); i != prevInfos.end(); ++i, ++j)
if (!(*i == *j)) {
result.isNonDeterministic = true;
Path prev = i->second.path + checkSuffix;
Path prev = i->path + checkSuffix;
bool prevExists = keepPreviousRound && pathExists(prev);
auto msg = prevExists
? 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);
? fmt("output '%1%' of '%2%' differs from '%3%' from previous round", i->path, drvPath, prev)
: fmt("output '%1%' of '%2%' differs from previous round", i->path, drvPath);
auto diffHook = settings.diffHook;
if (prevExists && diffHook != "" && runDiffHook) {
try {
auto diff = runProgram(diffHook, true, {prev, i->second.path});
auto diff = runProgram(diffHook, true, {prev, i->path});
if (diff != "")
printError(chomp(diff));
} catch (Error & error) {
@@ -3286,11 +3325,7 @@ void DerivationGoal::registerOutputs()
/* Register each output path as valid, and register the sets of
paths referenced by each of them. If there are cycles in the
outputs, this will fail. */
{
ValidPathInfos infos2;
for (auto & i : infos) infos2.push_back(i.second);
worker.store.registerValidPaths(infos2);
}
worker.store.registerValidPaths(infos);
/* In case of a fixed-output derivation hash mismatch, throw an
exception now that we have registered the output as valid. */
@@ -3299,158 +3334,6 @@ void DerivationGoal::registerOutputs()
}
void DerivationGoal::checkOutputs(const std::map<Path, ValidPathInfo> & outputs)
{
std::map<Path, const ValidPathInfo &> outputsByPath;
for (auto & output : outputs)
outputsByPath.emplace(output.second.path, output.second);
for (auto & output : outputs) {
auto & outputName = output.first;
auto & info = output.second;
struct Checks
{
bool ignoreSelfRefs = false;
std::optional<uint64_t> maxSize, maxClosureSize;
std::optional<Strings> allowedReferences, allowedRequisites, disallowedReferences, disallowedRequisites;
};
/* Compute the closure and closure size of some output. This
is slightly tricky because some of its references (namely
other outputs) may not be valid yet. */
auto getClosure = [&](const Path & path)
{
uint64_t closureSize = 0;
PathSet pathsDone;
std::queue<Path> pathsLeft;
pathsLeft.push(path);
while (!pathsLeft.empty()) {
auto path = pathsLeft.front();
pathsLeft.pop();
if (!pathsDone.insert(path).second) continue;
auto i = outputsByPath.find(path);
if (i != outputsByPath.end()) {
closureSize += i->second.narSize;
for (auto & ref : i->second.references)
pathsLeft.push(ref);
} else {
auto info = worker.store.queryPathInfo(path);
closureSize += info->narSize;
for (auto & ref : info->references)
pathsLeft.push(ref);
}
}
return std::make_pair(pathsDone, closureSize);
};
auto applyChecks = [&](const Checks & checks)
{
if (checks.maxSize && info.narSize > *checks.maxSize)
throw BuildError("path '%s' is too large at %d bytes; limit is %d bytes",
info.path, info.narSize, *checks.maxSize);
if (checks.maxClosureSize) {
uint64_t closureSize = getClosure(info.path).second;
if (closureSize > *checks.maxClosureSize)
throw BuildError("closure of path '%s' is too large at %d bytes; limit is %d bytes",
info.path, closureSize, *checks.maxClosureSize);
}
auto checkRefs = [&](const std::optional<Strings> & value, bool allowed, bool recursive)
{
if (!value) return;
PathSet spec = parseReferenceSpecifiers(worker.store, *drv, *value);
PathSet used = recursive ? getClosure(info.path).first : info.references;
if (recursive && checks.ignoreSelfRefs)
used.erase(info.path);
PathSet badPaths;
for (auto & i : used)
if (allowed) {
if (!spec.count(i))
badPaths.insert(i);
} else {
if (spec.count(i))
badPaths.insert(i);
}
if (!badPaths.empty()) {
string badPathsStr;
for (auto & i : badPaths) {
badPathsStr += "\n ";
badPathsStr += i;
}
throw BuildError("output '%s' is not allowed to refer to the following paths:%s", info.path, badPathsStr);
}
};
checkRefs(checks.allowedReferences, true, false);
checkRefs(checks.allowedRequisites, true, true);
checkRefs(checks.disallowedReferences, false, false);
checkRefs(checks.disallowedRequisites, false, true);
};
if (auto structuredAttrs = parsedDrv->getStructuredAttrs()) {
auto outputChecks = structuredAttrs->find("outputChecks");
if (outputChecks != structuredAttrs->end()) {
auto output = outputChecks->find(outputName);
if (output != outputChecks->end()) {
Checks checks;
auto maxSize = output->find("maxSize");
if (maxSize != output->end())
checks.maxSize = maxSize->get<uint64_t>();
auto maxClosureSize = output->find("maxClosureSize");
if (maxClosureSize != output->end())
checks.maxClosureSize = maxClosureSize->get<uint64_t>();
auto get = [&](const std::string & name) -> std::optional<Strings> {
auto i = output->find(name);
if (i != output->end()) {
Strings res;
for (auto j = i->begin(); j != i->end(); ++j) {
if (!j->is_string())
throw Error("attribute '%s' of derivation '%s' must be a list of strings", name, drvPath);
res.push_back(j->get<std::string>());
}
checks.disallowedRequisites = res;
return res;
}
return {};
};
checks.allowedReferences = get("allowedReferences");
checks.allowedRequisites = get("allowedRequisites");
checks.disallowedReferences = get("disallowedReferences");
checks.disallowedRequisites = get("disallowedRequisites");
applyChecks(checks);
}
}
} else {
// legacy non-structured-attributes case
Checks checks;
checks.ignoreSelfRefs = true;
checks.allowedReferences = parsedDrv->getStringsAttr("allowedReferences");
checks.allowedRequisites = parsedDrv->getStringsAttr("allowedRequisites");
checks.disallowedReferences = parsedDrv->getStringsAttr("disallowedReferences");
checks.disallowedRequisites = parsedDrv->getStringsAttr("disallowedRequisites");
applyChecks(checks);
}
}
}
Path DerivationGoal::openLogFile()
{
logSize = 0;
@@ -3799,19 +3682,6 @@ void SubstitutionGoal::tryNext()
} catch (InvalidPath &) {
tryNext();
return;
} catch (SubstituterDisabled &) {
if (settings.tryFallback) {
tryNext();
return;
}
throw;
} catch (Error & e) {
if (settings.tryFallback) {
printError(e.what());
tryNext();
return;
}
throw;
}
/* Update the total expected download size. */
@@ -4412,11 +4282,6 @@ static void primeCache(Store & store, const PathSet & paths)
PathSet willBuild, willSubstitute, unknown;
unsigned long long downloadSize, narSize;
store.queryMissing(paths, willBuild, willSubstitute, unknown, downloadSize, narSize);
if (!willBuild.empty() && 0 == settings.maxBuildJobs && getMachines().empty())
throw Error(
"%d derivations need to be built, but neither local builds ('--max-jobs') "
"nor remote builds ('--builders') are enabled", willBuild.size());
}

View File

@@ -24,7 +24,6 @@ void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData)
Path storePath = getAttr("out");
auto mainUrl = getAttr("url");
bool unpack = get(drv.env, "unpack", "") == "1";
/* Note: have to use a fresh downloader here because we're in
a forked process. */
@@ -41,12 +40,12 @@ void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData)
request.decompress = false;
auto decompressor = makeDecompressionSink(
unpack && hasSuffix(mainUrl, ".xz") ? "xz" : "none", sink);
hasSuffix(mainUrl, ".xz") ? "xz" : "none", sink);
downloader->download(std::move(request), *decompressor);
decompressor->finish();
});
if (unpack)
if (get(drv.env, "unpack", "") == "1")
restorePath(storePath, *source);
else
writeFile(storePath, *source);

View File

@@ -36,6 +36,12 @@ Path BasicDerivation::findOutput(const string & id) const
}
bool BasicDerivation::willBuildLocally() const
{
return get(env, "preferLocalBuild") == "1" && canBuildLocally();
}
bool BasicDerivation::substitutesAllowed() const
{
return get(env, "allowSubstitutes", "1") == "1";
@@ -48,6 +54,14 @@ bool BasicDerivation::isBuiltin() const
}
bool BasicDerivation::canBuildLocally() const
{
return platform == settings.thisSystem
|| settings.extraPlatforms.get().count(platform) > 0
|| isBuiltin();
}
Path writeDerivation(ref<Store> store,
const Derivation & drv, const string & name, RepairFlag repair)
{

View File

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

View File

@@ -345,7 +345,7 @@ struct CurlDownloader : public Downloader
done = true;
try {
act.progress(result.bodySize, result.bodySize);
act.progress(result.data->size(), result.data->size());
callback(std::move(result));
} catch (...) {
done = true;
@@ -528,11 +528,10 @@ struct CurlDownloader : public Downloader
extraFDs[0].fd = wakeupPipe.readSide.get();
extraFDs[0].events = CURL_WAIT_POLLIN;
extraFDs[0].revents = 0;
long maxSleepTimeMs = items.empty() ? 10000 : 100;
auto sleepTimeMs =
nextWakeup != std::chrono::steady_clock::time_point()
? std::max(0, (int) std::chrono::duration_cast<std::chrono::milliseconds>(nextWakeup - std::chrono::steady_clock::now()).count())
: maxSleepTimeMs;
: 10000;
vomit("download thread waiting for %d ms", sleepTimeMs);
mc = curl_multi_wait(curlm, extraFDs, 1, sleepTimeMs, &numfds);
if (mc != CURLM_OK)
@@ -614,22 +613,6 @@ struct CurlDownloader : public Downloader
writeFull(wakeupPipe.writeSide.get(), " ");
}
#ifdef ENABLE_S3
std::tuple<std::string, std::string, Store::Params> parseS3Uri(std::string uri)
{
auto [path, params] = splitUriAndParams(uri);
auto slash = path.find('/', 5); // 5 is the length of "s3://" prefix
if (slash == std::string::npos)
throw nix::Error("bad S3 URI '%s'", path);
std::string bucketName(path, 5, slash - 5);
std::string key(path, slash + 1);
return {bucketName, key, params};
}
#endif
void enqueueDownload(const DownloadRequest & request,
Callback<DownloadResult> callback) override
{
@@ -638,15 +621,12 @@ struct CurlDownloader : public Downloader
// FIXME: do this on a worker thread
try {
#ifdef ENABLE_S3
auto [bucketName, key, params] = parseS3Uri(request.uri);
std::string profile = get(params, "profile", "");
std::string region = get(params, "region", Aws::Region::US_EAST_1);
std::string scheme = get(params, "scheme", "");
std::string endpoint = get(params, "endpoint", "");
S3Helper s3Helper(profile, region, scheme, endpoint);
S3Helper s3Helper("", Aws::Region::US_EAST_1, ""); // FIXME: make configurable
auto slash = request.uri.find('/', 5);
if (slash == std::string::npos)
throw nix::Error("bad S3 URI '%s'", request.uri);
std::string bucketName(request.uri, 5, slash - 5);
std::string key(request.uri, slash + 1);
// FIXME: implement ETag
auto s3Res = s3Helper.getObject(bucketName, key);
DownloadResult res;
@@ -730,12 +710,11 @@ void Downloader::download(DownloadRequest && request, Sink & sink)
/* If the buffer is full, then go to sleep until the calling
thread wakes us up (i.e. when it has removed data from the
buffer). We don't wait forever to prevent stalling the
download thread. (Hopefully sleeping will throttle the
sender.) */
if (state->data.size() > 1024 * 1024) {
buffer). Note: this does stall the download thread. */
while (state->data.size() > 1024 * 1024) {
if (state->quit) return;
debug("download buffer is full; going to sleep");
state.wait_for(state->request, std::chrono::seconds(10));
state.wait(state->request);
}
/* Append data to the buffer and wake up the calling
@@ -757,36 +736,30 @@ void Downloader::download(DownloadRequest && request, Sink & sink)
state->request.notify_one();
}});
auto state(_state->lock());
while (true) {
checkInterrupt();
std::string chunk;
/* If no data is available, then wait for the download thread
to wake us up. */
if (state->data.empty()) {
/* Grab data if available, otherwise wait for the download
thread to wake us up. */
{
auto state(_state->lock());
while (state->data.empty()) {
if (state->quit) {
if (state->exc) std::rethrow_exception(state->exc);
return;
}
state.wait(state->avail);
if (state->quit) {
if (state->exc) std::rethrow_exception(state->exc);
break;
}
chunk = std::move(state->data);
state->request.notify_one();
state.wait(state->avail);
}
/* Flush the data to the sink and wake up the download thread
if it's blocked on a full buffer. We don't hold the state
lock while doing this to prevent blocking the download
thread if sink() takes a long time. */
sink((unsigned char *) chunk.data(), chunk.size());
/* If data is available, then flush it to the sink and wake up
the download thread if it's blocked on a full buffer. */
if (!state->data.empty()) {
sink((unsigned char *) state->data.data(), state->data.size());
state->data.clear();
state->request.notify_one();
}
}
}
@@ -900,8 +873,8 @@ Path Downloader::downloadCached(ref<Store> store, const string & url_, bool unpa
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());
throw nix::Error("hash mismatch in file downloaded from '%s': got hash '%s' instead of the expected hash '%s'",
url, gotHash.to_string(), expectedHash.to_string());
}
return store->toRealPath(storePath);

View File

@@ -129,8 +129,8 @@ Path LocalFSStore::addPermRoot(const Path & _storePath,
check if the root is in a directory in or linked from the
gcroots directory. */
if (settings.checkRootReachability) {
Roots roots = findRoots(false);
if (roots[storePath].count(gcRoot) == 0)
Roots roots = findRoots();
if (roots.find(gcRoot) == roots.end())
printError(
format(
"warning: '%1%' is not in a directory where the garbage collector looks for roots; "
@@ -197,11 +197,10 @@ void LocalStore::addTempRoot(const Path & path)
}
static std::string censored = "{censored}";
void LocalStore::findTempRoots(FDs & fds, Roots & tempRoots, bool censor)
std::set<std::pair<pid_t, Path>> LocalStore::readTempRoots(FDs & fds)
{
std::set<std::pair<pid_t, Path>> tempRoots;
/* Read the `temproots' directory for per-process temporary root
files. */
for (auto & i : readDirectory(tempRootsDir)) {
@@ -251,12 +250,14 @@ void LocalStore::findTempRoots(FDs & fds, Roots & tempRoots, bool censor)
Path root(contents, pos, end - pos);
debug("got temporary root '%s'", root);
assertStorePath(root);
tempRoots[root].emplace(censor ? censored : fmt("{temp:%d}", pid));
tempRoots.emplace(pid, root);
pos = end + 1;
}
fds.push_back(fd); /* keep open */
}
return tempRoots;
}
@@ -265,7 +266,7 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots)
auto foundRoot = [&](const Path & path, const Path & target) {
Path storePath = toStorePath(target);
if (isStorePath(storePath) && isValidPath(storePath))
roots[storePath].emplace(path);
roots[path] = storePath;
else
printInfo(format("skipping invalid root from '%1%' to '%2%'") % path % storePath);
};
@@ -305,7 +306,7 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots)
else if (type == DT_REG) {
Path storePath = storeDir + "/" + baseNameOf(path);
if (isStorePath(storePath) && isValidPath(storePath))
roots[storePath].emplace(path);
roots[path] = storePath;
}
}
@@ -320,8 +321,10 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots)
}
void LocalStore::findRootsNoTemp(Roots & roots, bool censor)
Roots LocalStore::findRootsNoTemp()
{
Roots roots;
/* Process direct roots in {gcroots,profiles}. */
findRoots(stateDir + "/" + gcRootsDir, DT_UNKNOWN, roots);
findRoots(stateDir + "/profiles", DT_UNKNOWN, roots);
@@ -330,22 +333,32 @@ void LocalStore::findRootsNoTemp(Roots & roots, bool censor)
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);
}
Roots LocalStore::findRoots(bool censor)
{
Roots roots;
findRootsNoTemp(roots, censor);
FDs fds;
findTempRoots(fds, roots, censor);
size_t n = 0;
for (auto & root : findRuntimeRoots())
roots[fmt("{memory:%d}", n++)] = root;
return roots;
}
static void readProcLink(const string & file, Roots & roots)
Roots LocalStore::findRoots()
{
Roots roots = findRootsNoTemp();
FDs fds;
pid_t prev = -1;
size_t n = 0;
for (auto & root : readTempRoots(fds)) {
if (prev != root.first) n = 0;
prev = root.first;
roots[fmt("{temp:%d:%d}", root.first, n++)] = root.second;
}
return roots;
}
static void readProcLink(const string & file, StringSet & paths)
{
/* 64 is the starting buffer size gnu readlink uses... */
auto bufsiz = ssize_t{64};
@@ -364,8 +377,8 @@ try_again:
goto try_again;
}
if (res > 0 && buf[0] == '/')
roots[std::string(static_cast<char *>(buf), res)]
.emplace(file);
paths.emplace(static_cast<char *>(buf), res);
return;
}
static string quoteRegexChars(const string & raw)
@@ -374,20 +387,20 @@ static string quoteRegexChars(const string & raw)
return std::regex_replace(raw, specialRegex, R"(\$&)");
}
static void readFileRoots(const char * path, Roots & roots)
static void readFileRoots(const char * path, StringSet & paths)
{
try {
roots[readFile(path)].emplace(path);
paths.emplace(readFile(path));
} catch (SysError & e) {
if (e.errNo != ENOENT && e.errNo != EACCES)
throw;
}
}
void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
PathSet LocalStore::findRuntimeRoots()
{
Roots unchecked;
PathSet roots;
StringSet paths;
auto procDir = AutoCloseDir{opendir("/proc")};
if (procDir) {
struct dirent * ent;
@@ -397,10 +410,10 @@ void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
while (errno = 0, ent = readdir(procDir.get())) {
checkInterrupt();
if (std::regex_match(ent->d_name, digitsRegex)) {
readProcLink(fmt("/proc/%s/exe" ,ent->d_name), unchecked);
readProcLink(fmt("/proc/%s/cwd", ent->d_name), unchecked);
readProcLink((format("/proc/%1%/exe") % ent->d_name).str(), paths);
readProcLink((format("/proc/%1%/cwd") % ent->d_name).str(), paths);
auto fdStr = fmt("/proc/%s/fd", ent->d_name);
auto fdStr = (format("/proc/%1%/fd") % ent->d_name).str();
auto fdDir = AutoCloseDir(opendir(fdStr.c_str()));
if (!fdDir) {
if (errno == ENOENT || errno == EACCES)
@@ -409,8 +422,9 @@ void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
}
struct dirent * fd_ent;
while (errno = 0, fd_ent = readdir(fdDir.get())) {
if (fd_ent->d_name[0] != '.')
readProcLink(fmt("%s/%s", fdStr, fd_ent->d_name), unchecked);
if (fd_ent->d_name[0] != '.') {
readProcLink((format("%1%/%2%") % fdStr % fd_ent->d_name).str(), paths);
}
}
if (errno) {
if (errno == ESRCH)
@@ -420,19 +434,18 @@ void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
fdDir.reset();
try {
auto mapFile = fmt("/proc/%s/maps", ent->d_name);
auto mapLines = tokenizeString<std::vector<string>>(readFile(mapFile, true), "\n");
for (const auto & line : mapLines) {
auto mapLines =
tokenizeString<std::vector<string>>(readFile((format("/proc/%1%/maps") % ent->d_name).str(), true), "\n");
for (const auto& line : mapLines) {
auto match = std::smatch{};
if (std::regex_match(line, match, mapRegex))
unchecked[match[1]].emplace(mapFile);
paths.emplace(match[1]);
}
auto envFile = fmt("/proc/%s/environ", ent->d_name);
auto envString = readFile(envFile, true);
auto envString = readFile((format("/proc/%1%/environ") % ent->d_name).str(), true);
auto env_end = std::sregex_iterator{};
for (auto i = std::sregex_iterator{envString.begin(), envString.end(), storePathRegex}; i != env_end; ++i)
unchecked[i->str()].emplace(envFile);
paths.emplace(i->str());
} catch (SysError & e) {
if (errno == ENOENT || errno == EACCES || errno == ESRCH)
continue;
@@ -452,7 +465,7 @@ void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
for (const auto & line : lsofLines) {
std::smatch match;
if (std::regex_match(line, match, lsofRegex))
unchecked[match[1]].emplace("{lsof}");
paths.emplace(match[1]);
}
} catch (ExecError & e) {
/* lsof not installed, lsof failed */
@@ -460,23 +473,21 @@ void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
#endif
#if defined(__linux__)
readFileRoots("/proc/sys/kernel/modprobe", unchecked);
readFileRoots("/proc/sys/kernel/fbsplash", unchecked);
readFileRoots("/proc/sys/kernel/poweroff_cmd", unchecked);
readFileRoots("/proc/sys/kernel/modprobe", paths);
readFileRoots("/proc/sys/kernel/fbsplash", paths);
readFileRoots("/proc/sys/kernel/poweroff_cmd", paths);
#endif
for (auto & [target, links] : unchecked) {
if (isInStore(target)) {
Path path = toStorePath(target);
if (isStorePath(path) && isValidPath(path)) {
for (auto & i : paths)
if (isInStore(i)) {
Path path = toStorePath(i);
if (roots.find(path) == roots.end() && isStorePath(path) && isValidPath(path)) {
debug(format("got additional root '%1%'") % path);
if (censor)
roots[path].insert(censored);
else
roots[path].insert(links.begin(), links.end());
roots.insert(path);
}
}
}
return roots;
}
@@ -743,20 +754,16 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
/* Find the roots. Since we've grabbed the GC lock, the set of
permanent roots cannot increase now. */
printError(format("finding garbage collector roots..."));
Roots rootMap;
if (!options.ignoreLiveness)
findRootsNoTemp(rootMap, true);
Roots rootMap = options.ignoreLiveness ? Roots() : findRootsNoTemp();
for (auto & i : rootMap) state.roots.insert(i.first);
for (auto & i : rootMap) state.roots.insert(i.second);
/* Read the temporary roots. This acquires read locks on all
per-process temporary root files. So after this point no paths
can be added to the set of temporary roots. */
FDs fds;
Roots tempRoots;
findTempRoots(fds, tempRoots, true);
for (auto & root : tempRoots)
state.tempRoots.insert(root.first);
for (auto & root : readTempRoots(fds))
state.tempRoots.insert(root.second);
state.roots.insert(state.tempRoots.begin(), state.tempRoots.end());
/* After this point the set of roots or temporary roots cannot

View File

@@ -78,11 +78,7 @@ void loadConfFile()
~/.nix/nix.conf or the command line. */
globalConfig.resetOverriden();
auto dirs = getConfigDirs();
// Iterate over them in reverse so that the ones appearing first in the path take priority
for (auto dir = dirs.rbegin(); dir != dirs.rend(); dir++) {
globalConfig.applyConfigFile(*dir + "/nix/nix.conf");
}
globalConfig.applyConfigFile(getConfigDir() + "/nix/nix.conf");
}
unsigned int Settings::getDefaultCores()
@@ -90,21 +86,6 @@ unsigned int Settings::getDefaultCores()
return std::max(1U, std::thread::hardware_concurrency());
}
StringSet Settings::getDefaultSystemFeatures()
{
/* For backwards compatibility, accept some "features" that are
used in Nixpkgs to route builds to certain machines but don't
actually require anything special on the machines. */
StringSet features{"nixos-test", "benchmark", "big-parallel"};
#if __linux__
if (access("/dev/kvm", R_OK | W_OK) == 0)
features.insert("kvm");
#endif
return features;
}
const string nixVersion = PACKAGE_VERSION;
template<> void BaseSetting<SandboxMode>::set(const std::string & str)

View File

@@ -32,8 +32,6 @@ class Settings : public Config {
unsigned int getDefaultCores();
StringSet getDefaultSystemFeatures();
public:
Settings();
@@ -82,9 +80,9 @@ public:
/* Whether to show build log output in real time. */
bool verboseBuild = true;
Setting<size_t> logLines{this, 10, "log-lines",
"If verbose-build is false, the number of lines of the tail of "
"the log to show if a build fails."};
/* If verboseBuild is false, the number of lines of the tail of
the log to show if a build fails. */
size_t logLines = 10;
MaxBuildJobsSetting maxBuildJobs{this, 1, "max-jobs",
"Maximum number of parallel build jobs. \"auto\" means use number of cores.",
@@ -195,13 +193,7 @@ public:
Setting<bool> showTrace{this, false, "show-trace",
"Whether to show a stack trace on evaluation errors."};
Setting<SandboxMode> sandboxMode{this,
#if __linux__
smEnabled
#else
smDisabled
#endif
, "sandbox",
Setting<SandboxMode> sandboxMode{this, smDisabled, "sandbox",
"Whether to enable sandboxed builds. Can be \"true\", \"false\" or \"relaxed\".",
{"build-use-chroot", "build-use-sandbox"}};
@@ -269,10 +261,6 @@ public:
"These may be supported natively (e.g. armv7 on some aarch64 CPUs "
"or using hacks like qemu-user."};
Setting<StringSet> systemFeatures{this, getDefaultSystemFeatures(),
"system-features",
"Optional features that this system implements (like \"kvm\")."};
Setting<Strings> substituters{this,
nixStore == "/nix/store" ? Strings{"https://cache.nixos.org/"} : Strings(),
"substituters",

View File

@@ -13,14 +13,6 @@ private:
Path cacheUri;
struct State
{
bool enabled = true;
std::chrono::steady_clock::time_point disabledUntil;
};
Sync<State> _state;
public:
HttpBinaryCacheStore(
@@ -54,33 +46,8 @@ public:
protected:
void maybeDisable()
{
auto state(_state.lock());
if (state->enabled && settings.tryFallback) {
int t = 60;
printError("disabling binary cache '%s' for %s seconds", getUri(), t);
state->enabled = false;
state->disabledUntil = std::chrono::steady_clock::now() + std::chrono::seconds(t);
}
}
void checkEnabled()
{
auto state(_state.lock());
if (state->enabled) return;
if (std::chrono::steady_clock::now() > state->disabledUntil) {
state->enabled = true;
debug("re-enabling binary cache '%s'", getUri());
return;
}
throw SubstituterDisabled("substituter '%s' is disabled", getUri());
}
bool fileExists(const std::string & path) override
{
checkEnabled();
try {
DownloadRequest request(cacheUri + "/" + path);
request.head = true;
@@ -92,7 +59,6 @@ protected:
bucket is unlistable, so treat 403 as 404. */
if (e.error == Downloader::NotFound || e.error == Downloader::Forbidden)
return false;
maybeDisable();
throw;
}
}
@@ -120,14 +86,12 @@ protected:
void getFile(const std::string & path, Sink & sink) override
{
checkEnabled();
auto request(makeRequest(path));
try {
getDownloader()->download(std::move(request), sink);
} catch (DownloadError & e) {
if (e.error == Downloader::NotFound || e.error == Downloader::Forbidden)
throw NoSuchBinaryCacheFile("file '%s' does not exist in binary cache '%s'", path, getUri());
maybeDisable();
throw;
}
}
@@ -135,18 +99,15 @@ protected:
void getFile(const std::string & path,
Callback<std::shared_ptr<std::string>> callback) override
{
checkEnabled();
auto request(makeRequest(path));
getDownloader()->enqueueDownload(request,
{[callback, this](std::future<DownloadResult> result) {
{[callback](std::future<DownloadResult> result) {
try {
callback(result.get().data);
} catch (DownloadError & e) {
if (e.error == Downloader::NotFound || e.error == Downloader::Forbidden)
return callback(std::shared_ptr<std::string>());
maybeDisable();
callback.rethrow();
} catch (...) {
callback.rethrow();

View File

@@ -187,17 +187,28 @@ struct LegacySSHStore : public Store
copyNAR(conn->from, sink);
}
PathSet queryAllValidPaths() override { unsupported(); }
void queryReferrers(const Path & path, PathSet & referrers) override
{ unsupported(); }
PathSet queryDerivationOutputs(const Path & path) override
{ unsupported(); }
StringSet queryDerivationOutputNames(const Path & path) override
{ unsupported(); }
Path queryPathFromHashPart(const string & hashPart) override
{ unsupported("queryPathFromHashPart"); }
{ unsupported(); }
Path addToStore(const string & name, const Path & srcPath,
bool recursive, HashType hashAlgo,
PathFilter & filter, RepairFlag repair) override
{ unsupported("addToStore"); }
{ unsupported(); }
Path addTextToStore(const string & name, const string & s,
const PathSet & references, RepairFlag repair) override
{ unsupported("addTextToStore"); }
{ unsupported(); }
BuildResult buildDerivation(const Path & drvPath, const BasicDerivation & drv,
BuildMode buildMode) override
@@ -231,7 +242,25 @@ struct LegacySSHStore : public Store
}
void ensurePath(const Path & path) override
{ unsupported("ensurePath"); }
{ unsupported(); }
void addTempRoot(const Path & path) override
{ unsupported(); }
void addIndirectRoot(const Path & path) override
{ unsupported(); }
Roots findRoots() override
{ unsupported(); }
void collectGarbage(const GCOptions & options, GCResults & results) override
{ unsupported(); }
ref<FSAccessor> getFSAccessor() override
{ unsupported(); }
void addSignatures(const Path & storePath, const StringSet & sigs) override
{ unsupported(); }
void computeFSClosure(const PathSet & paths,
PathSet & out, bool flipDirection = false,
@@ -274,12 +303,6 @@ struct LegacySSHStore : public Store
{
auto conn(connections->get());
}
unsigned int getProtocol() override
{
auto conn(connections->get());
return conn->remoteVersion;
}
};
static RegisterStoreImplementation regStore([](

View File

@@ -880,12 +880,6 @@ void LocalStore::querySubstitutablePathInfos(const PathSet & paths,
narInfo ? narInfo->fileSize : 0,
info->narSize};
} catch (InvalidPath) {
} catch (SubstituterDisabled) {
} catch (Error & e) {
if (settings.tryFallback)
printError(e.what());
else
throw;
}
}
}
@@ -1020,11 +1014,11 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
auto hashResult = hashSink.finish();
if (hashResult.first != info.narHash)
throw Error("hash mismatch importing path '%s';\n wanted: %s\n got: %s",
throw Error("hash mismatch importing path '%s'; expected hash '%s', got '%s'",
info.path, info.narHash.to_string(), hashResult.first.to_string());
if (hashResult.second != info.narSize)
throw Error("size mismatch importing path '%s';\n wanted: %s\n got: %s",
throw Error("size mismatch importing path '%s'; expected %s, got %s",
info.path, info.narSize, hashResult.second);
autoGC();
@@ -1338,12 +1332,6 @@ void LocalStore::verifyPath(const Path & path, const PathSet & store,
}
unsigned int LocalStore::getProtocol()
{
return PROTOCOL_VERSION;
}
#if defined(FS_IOC_SETFLAGS) && defined(FS_IOC_GETFLAGS) && defined(FS_IMMUTABLE_FL)
static void makeMutable(const Path & path)

View File

@@ -180,11 +180,11 @@ private:
typedef std::shared_ptr<AutoCloseFD> FDPtr;
typedef list<FDPtr> FDs;
void findTempRoots(FDs & fds, Roots & roots, bool censor);
std::set<std::pair<pid_t, Path>> readTempRoots(FDs & fds);
public:
Roots findRoots(bool censor) override;
Roots findRoots() override;
void collectGarbage(const GCOptions & options, GCResults & results) override;
@@ -209,8 +209,6 @@ public:
void registerValidPaths(const ValidPathInfos & infos);
unsigned int getProtocol() override;
void vacuumDB();
/* Repair the contents of the given path by redownloading it using
@@ -267,9 +265,9 @@ private:
void findRoots(const Path & path, unsigned char type, Roots & roots);
void findRootsNoTemp(Roots & roots, bool censor);
Roots findRootsNoTemp();
void findRuntimeRoots(Roots & roots, bool censor);
PathSet findRuntimeRoots();
void removeUnusedLinks(const GCState & state);

View File

@@ -6,7 +6,7 @@ libstore_DIR := $(d)
libstore_SOURCES := $(wildcard $(d)/*.cc $(d)/builtins/*.cc)
libstore_LIBS = libutil
libstore_LIBS = libutil libformat
libstore_LDFLAGS = $(SQLITE3_LIBS) -lbz2 $(LIBCURL_LIBS) $(SODIUM_LIBS) -pthread
ifneq ($(OS), FreeBSD)

View File

@@ -89,11 +89,10 @@ void parseMachines(const std::string & s, Machines & machines)
Machines getMachines()
{
static auto machines = [&]() {
Machines machines;
parseMachines(settings.builders, machines);
return machines;
}();
Machines machines;
parseMachines(settings.builders, machines);
return machines;
}

View File

@@ -31,7 +31,6 @@ create table if not exists NARs (
refs text,
deriver text,
sigs text,
ca text,
timestamp integer not null,
present integer not null,
primary key (cache, hashPart),
@@ -73,7 +72,7 @@ public:
{
auto state(_state.lock());
Path dbPath = getCacheDir() + "/nix/binary-cache-v6.sqlite";
Path dbPath = getCacheDir() + "/nix/binary-cache-v5.sqlite";
createDirs(dirOf(dbPath));
state->db = SQLite(dbPath);
@@ -95,13 +94,13 @@ public:
state->insertNAR.create(state->db,
"insert or replace into NARs(cache, hashPart, namePart, url, compression, fileHash, fileSize, narHash, "
"narSize, refs, deriver, sigs, ca, timestamp, present) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1)");
"narSize, refs, deriver, sigs, timestamp, present) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1)");
state->insertMissingNAR.create(state->db,
"insert or replace into NARs(cache, hashPart, timestamp, present) values (?, ?, ?, 0)");
state->queryNAR.create(state->db,
"select present, namePart, url, compression, fileHash, fileSize, narHash, narSize, refs, deriver, sigs, ca from NARs where cache = ? and hashPart = ? and ((present = 0 and timestamp > ?) or (present = 1 and timestamp > ?))");
"select * from NARs where cache = ? and hashPart = ? and ((present = 0 and timestamp > ?) or (present = 1 and timestamp > ?))");
/* Periodically purge expired entries from the database. */
retrySQLite<void>([&]() {
@@ -190,28 +189,27 @@ public:
if (!queryNAR.next())
return {oUnknown, 0};
if (!queryNAR.getInt(0))
if (!queryNAR.getInt(13))
return {oInvalid, 0};
auto narInfo = make_ref<NarInfo>();
auto namePart = queryNAR.getStr(1);
auto namePart = queryNAR.getStr(2);
narInfo->path = cache.storeDir + "/" +
hashPart + (namePart.empty() ? "" : "-" + namePart);
narInfo->url = queryNAR.getStr(2);
narInfo->compression = queryNAR.getStr(3);
if (!queryNAR.isNull(4))
narInfo->fileHash = Hash(queryNAR.getStr(4));
narInfo->fileSize = queryNAR.getInt(5);
narInfo->narHash = Hash(queryNAR.getStr(6));
narInfo->narSize = queryNAR.getInt(7);
for (auto & r : tokenizeString<Strings>(queryNAR.getStr(8), " "))
narInfo->url = queryNAR.getStr(3);
narInfo->compression = queryNAR.getStr(4);
if (!queryNAR.isNull(5))
narInfo->fileHash = Hash(queryNAR.getStr(5));
narInfo->fileSize = queryNAR.getInt(6);
narInfo->narHash = Hash(queryNAR.getStr(7));
narInfo->narSize = queryNAR.getInt(8);
for (auto & r : tokenizeString<Strings>(queryNAR.getStr(9), " "))
narInfo->references.insert(cache.storeDir + "/" + r);
if (!queryNAR.isNull(9))
narInfo->deriver = cache.storeDir + "/" + queryNAR.getStr(9);
for (auto & sig : tokenizeString<Strings>(queryNAR.getStr(10), " "))
if (!queryNAR.isNull(10))
narInfo->deriver = cache.storeDir + "/" + queryNAR.getStr(10);
for (auto & sig : tokenizeString<Strings>(queryNAR.getStr(11), " "))
narInfo->sigs.insert(sig);
narInfo->ca = queryNAR.getStr(11);
return {oValid, narInfo};
});
@@ -245,7 +243,6 @@ public:
(concatStringsSep(" ", info->shortRefs()))
(info->deriver != "" ? baseNameOf(info->deriver) : "", info->deriver != "")
(concatStringsSep(" ", info->sigs))
(info->ca)
(time(0)).exec();
} else {

View File

@@ -6,4 +6,4 @@ Name: Nix
Description: Nix Package Manager
Version: @PACKAGE_VERSION@
Libs: -L${libdir} -lnixstore -lnixutil
Cflags: -I${includedir}/nix -std=c++17
Cflags: -I${includedir}/nix -std=c++14

View File

@@ -1,111 +0,0 @@
#include "parsed-derivations.hh"
namespace nix {
ParsedDerivation::ParsedDerivation(const Path & drvPath, BasicDerivation & drv)
: drvPath(drvPath), drv(drv)
{
/* Parse the __json attribute, if any. */
auto jsonAttr = drv.env.find("__json");
if (jsonAttr != drv.env.end()) {
try {
structuredAttrs = nlohmann::json::parse(jsonAttr->second);
} catch (std::exception & e) {
throw Error("cannot process __json attribute of '%s': %s", drvPath, e.what());
}
}
}
std::optional<std::string> ParsedDerivation::getStringAttr(const std::string & name) const
{
if (structuredAttrs) {
auto i = structuredAttrs->find(name);
if (i == structuredAttrs->end())
return {};
else {
if (!i->is_string())
throw Error("attribute '%s' of derivation '%s' must be a string", name, drvPath);
return i->get<std::string>();
}
} else {
auto i = drv.env.find(name);
if (i == drv.env.end())
return {};
else
return i->second;
}
}
bool ParsedDerivation::getBoolAttr(const std::string & name, bool def) const
{
if (structuredAttrs) {
auto i = structuredAttrs->find(name);
if (i == structuredAttrs->end())
return def;
else {
if (!i->is_boolean())
throw Error("attribute '%s' of derivation '%s' must be a Boolean", name, drvPath);
return i->get<bool>();
}
} else {
auto i = drv.env.find(name);
if (i == drv.env.end())
return def;
else
return i->second == "1";
}
}
std::optional<Strings> ParsedDerivation::getStringsAttr(const std::string & name) const
{
if (structuredAttrs) {
auto i = structuredAttrs->find(name);
if (i == structuredAttrs->end())
return {};
else {
if (!i->is_array())
throw Error("attribute '%s' of derivation '%s' must be a list of strings", name, drvPath);
Strings res;
for (auto j = i->begin(); j != i->end(); ++j) {
if (!j->is_string())
throw Error("attribute '%s' of derivation '%s' must be a list of strings", name, drvPath);
res.push_back(j->get<std::string>());
}
return res;
}
} else {
auto i = drv.env.find(name);
if (i == drv.env.end())
return {};
else
return tokenizeString<Strings>(i->second);
}
}
StringSet ParsedDerivation::getRequiredSystemFeatures() const
{
StringSet res;
for (auto & i : getStringsAttr("requiredSystemFeatures").value_or(Strings()))
res.insert(i);
return res;
}
bool ParsedDerivation::canBuildLocally() const
{
if (drv.platform != settings.thisSystem.get()
&& !settings.extraPlatforms.get().count(drv.platform)
&& !drv.isBuiltin())
return false;
for (auto & feature : getRequiredSystemFeatures())
if (!settings.systemFeatures.get().count(feature)) return false;
return true;
}
bool ParsedDerivation::willBuildLocally() const
{
return getBoolAttr("preferLocalBuild") && canBuildLocally();
}
}

View File

@@ -1,35 +0,0 @@
#include "derivations.hh"
#include <nlohmann/json.hpp>
namespace nix {
class ParsedDerivation
{
Path drvPath;
BasicDerivation & drv;
std::optional<nlohmann::json> structuredAttrs;
public:
ParsedDerivation(const Path & drvPath, BasicDerivation & drv);
const std::optional<nlohmann::json> & getStructuredAttrs() const
{
return structuredAttrs;
}
std::optional<std::string> getStringAttr(const std::string & name) const;
bool getBoolAttr(const std::string & name, bool def = false) const;
std::optional<Strings> getStringsAttr(const std::string & name) const;
StringSet getRequiredSystemFeatures() const;
bool canBuildLocally() const;
bool willBuildLocally() const;
};
}

View File

@@ -161,8 +161,7 @@ void RemoteStore::initConnection(Connection & conn)
if (GET_PROTOCOL_MINOR(conn.daemonVersion) >= 11)
conn.to << false;
auto ex = conn.processStderr();
if (ex) std::rethrow_exception(ex);
conn.processStderr();
}
catch (Error & e) {
throw Error("cannot open connection to remote store '%s': %s", getUri(), e.what());
@@ -196,68 +195,22 @@ void RemoteStore::setOptions(Connection & conn)
conn.to << i.first << i.second.value;
}
auto ex = conn.processStderr();
if (ex) std::rethrow_exception(ex);
}
/* A wrapper around Pool<RemoteStore::Connection>::Handle that marks
the connection as bad (causing it to be closed) if a non-daemon
exception is thrown before the handle is closed. Such an exception
causes a deviation from the expected protocol and therefore a
desynchronization between the client and daemon. */
struct ConnectionHandle
{
Pool<RemoteStore::Connection>::Handle handle;
bool daemonException = false;
ConnectionHandle(Pool<RemoteStore::Connection>::Handle && handle)
: handle(std::move(handle))
{ }
ConnectionHandle(ConnectionHandle && h)
: handle(std::move(h.handle))
{ }
~ConnectionHandle()
{
if (!daemonException && std::uncaught_exception()) {
handle.markBad();
debug("closing daemon connection because of an exception");
}
}
RemoteStore::Connection * operator -> () { return &*handle; }
void processStderr(Sink * sink = 0, Source * source = 0)
{
auto ex = handle->processStderr(sink, source);
if (ex) {
daemonException = true;
std::rethrow_exception(ex);
}
}
};
ConnectionHandle RemoteStore::getConnection()
{
return ConnectionHandle(connections->get());
conn.processStderr();
}
bool RemoteStore::isValidPathUncached(const Path & path)
{
auto conn(getConnection());
auto conn(connections->get());
conn->to << wopIsValidPath << path;
conn.processStderr();
conn->processStderr();
return readInt(conn->from);
}
PathSet RemoteStore::queryValidPaths(const PathSet & paths, SubstituteFlag maybeSubstitute)
{
auto conn(getConnection());
auto conn(connections->get());
if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 12) {
PathSet res;
for (auto & i : paths)
@@ -265,7 +218,7 @@ PathSet RemoteStore::queryValidPaths(const PathSet & paths, SubstituteFlag maybe
return res;
} else {
conn->to << wopQueryValidPaths << paths;
conn.processStderr();
conn->processStderr();
return readStorePaths<PathSet>(*this, conn->from);
}
}
@@ -273,27 +226,27 @@ PathSet RemoteStore::queryValidPaths(const PathSet & paths, SubstituteFlag maybe
PathSet RemoteStore::queryAllValidPaths()
{
auto conn(getConnection());
auto conn(connections->get());
conn->to << wopQueryAllValidPaths;
conn.processStderr();
conn->processStderr();
return readStorePaths<PathSet>(*this, conn->from);
}
PathSet RemoteStore::querySubstitutablePaths(const PathSet & paths)
{
auto conn(getConnection());
auto conn(connections->get());
if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 12) {
PathSet res;
for (auto & i : paths) {
conn->to << wopHasSubstitutes << i;
conn.processStderr();
conn->processStderr();
if (readInt(conn->from)) res.insert(i);
}
return res;
} else {
conn->to << wopQuerySubstitutablePaths << paths;
conn.processStderr();
conn->processStderr();
return readStorePaths<PathSet>(*this, conn->from);
}
}
@@ -304,14 +257,14 @@ void RemoteStore::querySubstitutablePathInfos(const PathSet & paths,
{
if (paths.empty()) return;
auto conn(getConnection());
auto conn(connections->get());
if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 12) {
for (auto & i : paths) {
SubstitutablePathInfo info;
conn->to << wopQuerySubstitutablePathInfo << i;
conn.processStderr();
conn->processStderr();
unsigned int reply = readInt(conn->from);
if (reply == 0) continue;
info.deriver = readString(conn->from);
@@ -325,7 +278,7 @@ void RemoteStore::querySubstitutablePathInfos(const PathSet & paths,
} else {
conn->to << wopQuerySubstitutablePathInfos << paths;
conn.processStderr();
conn->processStderr();
size_t count = readNum<size_t>(conn->from);
for (size_t n = 0; n < count; n++) {
Path path = readStorePath(*this, conn->from);
@@ -347,10 +300,10 @@ void RemoteStore::queryPathInfoUncached(const Path & path,
try {
std::shared_ptr<ValidPathInfo> info;
{
auto conn(getConnection());
auto conn(connections->get());
conn->to << wopQueryPathInfo << path;
try {
conn.processStderr();
conn->processStderr();
} catch (Error & e) {
// Ugly backwards compatibility hack.
if (e.msg().find("is not valid") != std::string::npos)
@@ -382,9 +335,9 @@ void RemoteStore::queryPathInfoUncached(const Path & path,
void RemoteStore::queryReferrers(const Path & path,
PathSet & referrers)
{
auto conn(getConnection());
auto conn(connections->get());
conn->to << wopQueryReferrers << path;
conn.processStderr();
conn->processStderr();
PathSet referrers2 = readStorePaths<PathSet>(*this, conn->from);
referrers.insert(referrers2.begin(), referrers2.end());
}
@@ -392,36 +345,36 @@ void RemoteStore::queryReferrers(const Path & path,
PathSet RemoteStore::queryValidDerivers(const Path & path)
{
auto conn(getConnection());
auto conn(connections->get());
conn->to << wopQueryValidDerivers << path;
conn.processStderr();
conn->processStderr();
return readStorePaths<PathSet>(*this, conn->from);
}
PathSet RemoteStore::queryDerivationOutputs(const Path & path)
{
auto conn(getConnection());
auto conn(connections->get());
conn->to << wopQueryDerivationOutputs << path;
conn.processStderr();
conn->processStderr();
return readStorePaths<PathSet>(*this, conn->from);
}
PathSet RemoteStore::queryDerivationOutputNames(const Path & path)
{
auto conn(getConnection());
auto conn(connections->get());
conn->to << wopQueryDerivationOutputNames << path;
conn.processStderr();
conn->processStderr();
return readStrings<PathSet>(conn->from);
}
Path RemoteStore::queryPathFromHashPart(const string & hashPart)
{
auto conn(getConnection());
auto conn(connections->get());
conn->to << wopQueryPathFromHashPart << hashPart;
conn.processStderr();
conn->processStderr();
Path path = readString(conn->from);
if (!path.empty()) assertStorePath(path);
return path;
@@ -431,7 +384,7 @@ Path RemoteStore::queryPathFromHashPart(const string & hashPart)
void RemoteStore::addToStore(const ValidPathInfo & info, Source & source,
RepairFlag repair, CheckSigsFlag checkSigs, std::shared_ptr<FSAccessor> accessor)
{
auto conn(getConnection());
auto conn(connections->get());
if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 18) {
conn->to << wopImportPaths;
@@ -450,7 +403,7 @@ void RemoteStore::addToStore(const ValidPathInfo & info, Source & source,
;
});
conn.processStderr(0, source2.get());
conn->processStderr(0, source2.get());
auto importedPaths = readStorePaths<PathSet>(*this, conn->from);
assert(importedPaths.size() <= 1);
@@ -464,7 +417,7 @@ void RemoteStore::addToStore(const ValidPathInfo & info, Source & source,
<< repair << !checkSigs;
bool tunnel = GET_PROTOCOL_MINOR(conn->daemonVersion) >= 21;
if (!tunnel) copyNAR(source, conn->to);
conn.processStderr(0, tunnel ? &source : nullptr);
conn->processStderr(0, tunnel ? &source : nullptr);
}
}
@@ -474,7 +427,7 @@ Path RemoteStore::addToStore(const string & name, const Path & _srcPath,
{
if (repair) throw Error("repairing is not supported when building through the Nix daemon");
auto conn(getConnection());
auto conn(connections->get());
Path srcPath(absPath(_srcPath));
@@ -492,13 +445,13 @@ Path RemoteStore::addToStore(const string & name, const Path & _srcPath,
dumpPath(srcPath, conn->to, filter);
}
conn->to.warn = false;
conn.processStderr();
conn->processStderr();
} catch (SysError & e) {
/* Daemon closed while we were sending the path. Probably OOM
or I/O error. */
if (e.errNo == EPIPE)
try {
conn.processStderr();
conn->processStderr();
} catch (EndOfFile & e) { }
throw;
}
@@ -512,17 +465,17 @@ Path RemoteStore::addTextToStore(const string & name, const string & s,
{
if (repair) throw Error("repairing is not supported when building through the Nix daemon");
auto conn(getConnection());
auto conn(connections->get());
conn->to << wopAddTextToStore << name << s << references;
conn.processStderr();
conn->processStderr();
return readStorePath(*this, conn->from);
}
void RemoteStore::buildPaths(const PathSet & drvPaths, BuildMode buildMode)
{
auto conn(getConnection());
auto conn(connections->get());
conn->to << wopBuildPaths;
if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 13) {
conn->to << drvPaths;
@@ -541,7 +494,7 @@ void RemoteStore::buildPaths(const PathSet & drvPaths, BuildMode buildMode)
drvPaths2.insert(string(i, 0, i.find('!')));
conn->to << drvPaths2;
}
conn.processStderr();
conn->processStderr();
readInt(conn->from);
}
@@ -549,9 +502,9 @@ void RemoteStore::buildPaths(const PathSet & drvPaths, BuildMode buildMode)
BuildResult RemoteStore::buildDerivation(const Path & drvPath, const BasicDerivation & drv,
BuildMode buildMode)
{
auto conn(getConnection());
auto conn(connections->get());
conn->to << wopBuildDerivation << drvPath << drv << buildMode;
conn.processStderr();
conn->processStderr();
BuildResult res;
unsigned int status;
conn->from >> status >> res.errorMsg;
@@ -562,51 +515,51 @@ BuildResult RemoteStore::buildDerivation(const Path & drvPath, const BasicDeriva
void RemoteStore::ensurePath(const Path & path)
{
auto conn(getConnection());
auto conn(connections->get());
conn->to << wopEnsurePath << path;
conn.processStderr();
conn->processStderr();
readInt(conn->from);
}
void RemoteStore::addTempRoot(const Path & path)
{
auto conn(getConnection());
auto conn(connections->get());
conn->to << wopAddTempRoot << path;
conn.processStderr();
conn->processStderr();
readInt(conn->from);
}
void RemoteStore::addIndirectRoot(const Path & path)
{
auto conn(getConnection());
auto conn(connections->get());
conn->to << wopAddIndirectRoot << path;
conn.processStderr();
conn->processStderr();
readInt(conn->from);
}
void RemoteStore::syncWithGC()
{
auto conn(getConnection());
auto conn(connections->get());
conn->to << wopSyncWithGC;
conn.processStderr();
conn->processStderr();
readInt(conn->from);
}
Roots RemoteStore::findRoots(bool censor)
Roots RemoteStore::findRoots()
{
auto conn(getConnection());
auto conn(connections->get());
conn->to << wopFindRoots;
conn.processStderr();
conn->processStderr();
size_t count = readNum<size_t>(conn->from);
Roots result;
while (count--) {
Path link = readString(conn->from);
Path target = readStorePath(*this, conn->from);
result[target].emplace(link);
result[link] = target;
}
return result;
}
@@ -614,7 +567,7 @@ Roots RemoteStore::findRoots(bool censor)
void RemoteStore::collectGarbage(const GCOptions & options, GCResults & results)
{
auto conn(getConnection());
auto conn(connections->get());
conn->to
<< wopCollectGarbage << options.action << options.pathsToDelete << options.ignoreLiveness
@@ -622,7 +575,7 @@ void RemoteStore::collectGarbage(const GCOptions & options, GCResults & results)
/* removed options */
<< 0 << 0 << 0;
conn.processStderr();
conn->processStderr();
results.paths = readStrings<PathSet>(conn->from);
results.bytesFreed = readLongLong(conn->from);
@@ -637,27 +590,27 @@ void RemoteStore::collectGarbage(const GCOptions & options, GCResults & results)
void RemoteStore::optimiseStore()
{
auto conn(getConnection());
auto conn(connections->get());
conn->to << wopOptimiseStore;
conn.processStderr();
conn->processStderr();
readInt(conn->from);
}
bool RemoteStore::verifyStore(bool checkContents, RepairFlag repair)
{
auto conn(getConnection());
auto conn(connections->get());
conn->to << wopVerifyStore << checkContents << repair;
conn.processStderr();
conn->processStderr();
return readInt(conn->from);
}
void RemoteStore::addSignatures(const Path & storePath, const StringSet & sigs)
{
auto conn(getConnection());
auto conn(connections->get());
conn->to << wopAddSignatures << storePath << sigs;
conn.processStderr();
conn->processStderr();
readInt(conn->from);
}
@@ -667,13 +620,13 @@ void RemoteStore::queryMissing(const PathSet & targets,
unsigned long long & downloadSize, unsigned long long & narSize)
{
{
auto conn(getConnection());
auto conn(connections->get());
if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 19)
// Don't hold the connection handle in the fallback case
// to prevent a deadlock.
goto fallback;
conn->to << wopQueryMissing << targets;
conn.processStderr();
conn->processStderr();
willBuild = readStorePaths<PathSet>(*this, conn->from);
willSubstitute = readStorePaths<PathSet>(*this, conn->from);
unknown = readStorePaths<PathSet>(*this, conn->from);
@@ -688,15 +641,8 @@ void RemoteStore::queryMissing(const PathSet & targets,
void RemoteStore::connect()
{
auto conn(getConnection());
}
unsigned int RemoteStore::getProtocol()
{
auto conn(connections->get());
return conn->daemonVersion;
}
@@ -733,7 +679,7 @@ static Logger::Fields readFields(Source & from)
}
std::exception_ptr RemoteStore::Connection::processStderr(Sink * sink, Source * source)
void RemoteStore::Connection::processStderr(Sink * sink, Source * source)
{
to.flush();
@@ -758,7 +704,7 @@ std::exception_ptr RemoteStore::Connection::processStderr(Sink * sink, Source *
else if (msg == STDERR_ERROR) {
string error = readString(from);
unsigned int status = readInt(from);
return std::make_exception_ptr(Error(status, error));
throw Error(status, error);
}
else if (msg == STDERR_NEXT)
@@ -792,8 +738,6 @@ std::exception_ptr RemoteStore::Connection::processStderr(Sink * sink, Source *
else
throw Error("got unknown message type %x from Nix daemon", msg);
}
return nullptr;
}
static std::string uriScheme = "unix://";

View File

@@ -14,7 +14,6 @@ class Pid;
struct FdSink;
struct FdSource;
template<typename T> class Pool;
struct ConnectionHandle;
/* FIXME: RemoteStore is a misnomer - should be something like
@@ -82,7 +81,7 @@ public:
void syncWithGC() override;
Roots findRoots(bool censor) override;
Roots findRoots() override;
void collectGarbage(const GCOptions & options, GCResults & results) override;
@@ -98,15 +97,12 @@ public:
void connect() override;
unsigned int getProtocol() override;
void flushBadConnections();
protected:
struct Connection
{
AutoCloseFD fd;
FdSink to;
FdSource from;
unsigned int daemonVersion;
@@ -114,7 +110,7 @@ protected:
virtual ~Connection();
std::exception_ptr processStderr(Sink * sink = 0, Source * source = 0);
void processStderr(Sink * sink = 0, Source * source = 0);
};
ref<Connection> openConnectionWrapper();
@@ -127,10 +123,6 @@ protected:
virtual void setOptions(Connection & conn);
ConnectionHandle getConnection();
friend struct ConnectionHandle;
private:
std::atomic_bool failed{false};
@@ -148,8 +140,13 @@ public:
private:
struct Connection : RemoteStore::Connection
{
AutoCloseFD fd;
};
ref<RemoteStore::Connection> openConnection() override;
std::optional<std::string> path;
std::experimental::optional<std::string> path;
};

View File

@@ -19,6 +19,8 @@
#include <aws/core/utils/logging/LogMacros.h>
#include <aws/core/utils/threading/Executor.h>
#include <aws/s3/S3Client.h>
#include <aws/s3/model/CreateBucketRequest.h>
#include <aws/s3/model/GetBucketLocationRequest.h>
#include <aws/s3/model/GetObjectRequest.h>
#include <aws/s3/model/HeadObjectRequest.h>
#include <aws/s3/model/ListObjectsRequest.h>
@@ -82,8 +84,8 @@ static void initAWS()
});
}
S3Helper::S3Helper(const string & profile, const string & region, const string & scheme, const string & endpoint)
: config(makeConfig(region, scheme, endpoint))
S3Helper::S3Helper(const std::string & profile, const std::string & region, const std::string & endpoint)
: config(makeConfig(region, endpoint))
, client(make_ref<Aws::S3::S3Client>(
profile == ""
? std::dynamic_pointer_cast<Aws::Auth::AWSCredentialsProvider>(
@@ -114,19 +116,15 @@ class RetryStrategy : public Aws::Client::DefaultRetryStrategy
}
};
ref<Aws::Client::ClientConfiguration> S3Helper::makeConfig(const string & region, const string & scheme, const string & endpoint)
ref<Aws::Client::ClientConfiguration> S3Helper::makeConfig(const string & region, const string & endpoint)
{
initAWS();
auto res = make_ref<Aws::Client::ClientConfiguration>();
res->region = region;
if (!scheme.empty()) {
res->scheme = Aws::Http::SchemeMapper::FromString(scheme.c_str());
}
if (!endpoint.empty()) {
res->endpointOverride = endpoint;
}
res->requestTimeoutMs = 600 * 1000;
res->connectTimeoutMs = 5 * 1000;
res->retryStrategy = std::make_shared<RetryStrategy>();
res->caFile = settings.caFile;
return res;
@@ -173,13 +171,10 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
{
const Setting<std::string> profile{this, "", "profile", "The name of the AWS configuration profile to use."};
const Setting<std::string> region{this, Aws::Region::US_EAST_1, "region", {"aws-region"}};
const Setting<std::string> scheme{this, "", "scheme", "The scheme to use for S3 requests, https by default."};
const Setting<std::string> endpoint{this, "", "endpoint", "An optional override of the endpoint to use when talking to S3."};
const Setting<std::string> narinfoCompression{this, "", "narinfo-compression", "compression method for .narinfo files"};
const Setting<std::string> lsCompression{this, "", "ls-compression", "compression method for .ls files"};
const Setting<std::string> logCompression{this, "", "log-compression", "compression method for log/* files"};
const Setting<bool> multipartUpload{
this, false, "multipart-upload", "whether to use multi-part uploads"};
const Setting<uint64_t> bufferSize{
this, 5 * 1024 * 1024, "buffer-size", "size (in bytes) of each part in multi-part uploads"};
@@ -193,7 +188,7 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
const Params & params, const std::string & bucketName)
: S3BinaryCacheStore(params)
, bucketName(bucketName)
, s3Helper(profile, region, scheme, endpoint)
, s3Helper(profile, region, endpoint)
{
diskCache = getNarInfoDiskCache();
}
@@ -207,6 +202,32 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
{
if (!diskCache->cacheExists(getUri(), wantMassQuery_, priority)) {
/* Create the bucket if it doesn't already exists. */
// FIXME: HeadBucket would be more appropriate, but doesn't return
// an easily parsed 404 message.
auto res = s3Helper.client->GetBucketLocation(
Aws::S3::Model::GetBucketLocationRequest().WithBucket(bucketName));
if (!res.IsSuccess()) {
if (res.GetError().GetErrorType() != Aws::S3::S3Errors::NO_SUCH_BUCKET)
throw Error(format("AWS error checking bucket '%s': %s") % bucketName % res.GetError().GetMessage());
printInfo("creating S3 bucket '%s'...", bucketName);
// Stupid S3 bucket locations.
auto bucketConfig = Aws::S3::Model::CreateBucketConfiguration();
if (s3Helper.config->region != "us-east-1")
bucketConfig.SetLocationConstraint(
Aws::S3::Model::BucketLocationConstraintMapper::GetBucketLocationConstraintForName(
s3Helper.config->region));
checkAws(format("AWS error creating bucket '%s'") % bucketName,
s3Helper.client->CreateBucket(
Aws::S3::Model::CreateBucketRequest()
.WithBucket(bucketName)
.WithCreateBucketConfiguration(bucketConfig)));
}
BinaryCacheStore::init();
diskCache->createCache(getUri(), storeDir, wantMassQuery_, priority);
@@ -268,73 +289,48 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
static std::shared_ptr<Aws::Utils::Threading::PooledThreadExecutor>
executor = std::make_shared<Aws::Utils::Threading::PooledThreadExecutor>(maxThreads);
std::call_once(transferManagerCreated, [&]()
{
if (multipartUpload) {
TransferManagerConfiguration transferConfig(executor.get());
std::call_once(transferManagerCreated, [&]() {
transferConfig.s3Client = s3Helper.client;
transferConfig.bufferSize = bufferSize;
TransferManagerConfiguration transferConfig(executor.get());
transferConfig.uploadProgressCallback =
[](const TransferManager *transferManager,
const std::shared_ptr<const TransferHandle>
&transferHandle)
{
//FIXME: find a way to properly abort the multipart upload.
//checkInterrupt();
debug("upload progress ('%s'): '%d' of '%d' bytes",
transferHandle->GetKey(),
transferHandle->GetBytesTransferred(),
transferHandle->GetBytesTotalSize());
};
transferConfig.s3Client = s3Helper.client;
transferConfig.bufferSize = bufferSize;
transferManager = TransferManager::Create(transferConfig);
}
transferConfig.uploadProgressCallback =
[&](const TransferManager *transferManager,
const std::shared_ptr<const TransferHandle>
&transferHandle)
{
//FIXME: find a way to properly abort the multipart upload.
//checkInterrupt();
debug("upload progress ('%s'): '%d' of '%d' bytes",
path,
transferHandle->GetBytesTransferred(),
transferHandle->GetBytesTotalSize());
};
transferManager = TransferManager::Create(transferConfig);
});
auto now1 = std::chrono::steady_clock::now();
if (transferManager) {
std::shared_ptr<TransferHandle> transferHandle =
transferManager->UploadFile(
stream, bucketName, path, mimeType,
Aws::Map<Aws::String, Aws::String>(),
nullptr, contentEncoding);
if (contentEncoding != "")
throw Error("setting a content encoding is not supported with S3 multi-part uploads");
transferHandle->WaitUntilFinished();
std::shared_ptr<TransferHandle> transferHandle =
transferManager->UploadFile(
stream, bucketName, path, mimeType,
Aws::Map<Aws::String, Aws::String>(),
nullptr /*, contentEncoding */);
if (transferHandle->GetStatus() == TransferStatus::FAILED)
throw Error("AWS error: failed to upload 's3://%s/%s': %s",
bucketName, path, transferHandle->GetLastError().GetMessage());
transferHandle->WaitUntilFinished();
if (transferHandle->GetStatus() != TransferStatus::COMPLETED)
throw Error("AWS error: transfer status of 's3://%s/%s' in unexpected state",
bucketName, path);
if (transferHandle->GetStatus() == TransferStatus::FAILED)
throw Error("AWS error: failed to upload 's3://%s/%s': %s",
bucketName, path, transferHandle->GetLastError().GetMessage());
if (transferHandle->GetStatus() != TransferStatus::COMPLETED)
throw Error("AWS error: transfer status of 's3://%s/%s' in unexpected state",
bucketName, path);
} else {
auto request =
Aws::S3::Model::PutObjectRequest()
.WithBucket(bucketName)
.WithKey(path);
request.SetContentType(mimeType);
if (contentEncoding != "")
request.SetContentEncoding(contentEncoding);
auto stream = std::make_shared<istringstream_nocopy>(data);
request.SetBody(stream);
auto result = checkAws(fmt("AWS error uploading '%s'", path),
s3Helper.client->PutObject(request));
}
printTalkative("upload of '%s' completed", path);
auto now2 = std::chrono::steady_clock::now();

View File

@@ -14,9 +14,9 @@ struct S3Helper
ref<Aws::Client::ClientConfiguration> config;
ref<Aws::S3::S3Client> client;
S3Helper(const std::string & profile, const std::string & region, const std::string & scheme, const std::string & endpoint);
S3Helper(const std::string & profile, const std::string & region, const std::string & endpoint);
ref<Aws::Client::ClientConfiguration> makeConfig(const std::string & region, const std::string & scheme, const std::string & endpoint);
ref<Aws::Client::ClientConfiguration> makeConfig(const std::string & region, const std::string & endpoint);
struct DownloadResult
{

View File

@@ -320,8 +320,6 @@ ref<const ValidPathInfo> Store::queryPathInfo(const Path & storePath)
void Store::queryPathInfo(const Path & storePath,
Callback<ref<ValidPathInfo>> callback)
{
assertStorePath(storePath);
auto hashPart = storePathToHash(storePath);
try {
@@ -562,10 +560,10 @@ void Store::buildPaths(const PathSet & paths, BuildMode buildMode)
{
for (auto & path : paths)
if (isDerivation(path))
unsupported("buildPaths");
unsupported();
if (queryValidPaths(paths).size() != paths.size())
unsupported("buildPaths");
unsupported();
}
@@ -588,19 +586,15 @@ void copyStorePath(ref<Store> srcStore, ref<Store> dstStore,
uint64_t total = 0;
// FIXME
#if 0
if (!info->narHash) {
StringSink sink;
srcStore->narFromPath({storePath}, sink);
auto info2 = make_ref<ValidPathInfo>(*info);
info2->narHash = hashString(htSHA256, *sink.s);
if (!info->narSize) info2->narSize = sink.s->size();
if (info->ultimate) info2->ultimate = false;
info = info2;
StringSource source(*sink.s);
dstStore->addToStore(*info, source, repair, checkSigs);
return;
}
#endif
if (info->ultimate) {
auto info2 = make_ref<ValidPathInfo>(*info);
@@ -616,7 +610,7 @@ void copyStorePath(ref<Store> srcStore, ref<Store> dstStore,
});
srcStore->narFromPath({storePath}, wrapperSink);
}, [&]() {
throw EndOfFile("NAR for '%s' fetched from '%s' is incomplete", storePath, srcStore->getUri());
throw EndOfFile("NAR for '%s' fetched from '%s' is incomplete", storePath, srcStore->getUri());
});
dstStore->addToStore(*info, *source, repair, checkSigs);
@@ -842,11 +836,12 @@ namespace nix {
RegisterStoreImplementation::Implementations * RegisterStoreImplementation::implementations = 0;
/* Split URI into protocol+hierarchy part and its parameter set. */
std::pair<std::string, Store::Params> splitUriAndParams(const std::string & uri_)
ref<Store> openStore(const std::string & uri_,
const Store::Params & extraParams)
{
auto uri(uri_);
Store::Params params;
Store::Params params(extraParams);
auto q = uri.find('?');
if (q != std::string::npos) {
for (auto s : tokenizeString<Strings>(uri.substr(q + 1), "&")) {
@@ -872,15 +867,6 @@ std::pair<std::string, Store::Params> splitUriAndParams(const std::string & uri_
}
uri = uri_.substr(0, q);
}
return {uri, params};
}
ref<Store> openStore(const std::string & uri_,
const Store::Params & extraParams)
{
auto [uri, uriParams] = splitUriAndParams(uri_);
auto params = extraParams;
params.insert(uriParams.begin(), uriParams.end());
for (auto fun : *RegisterStoreImplementation::implementations) {
auto store = fun(uri, params);

View File

@@ -11,8 +11,6 @@
#include <atomic>
#include <limits>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <memory>
#include <string>
@@ -25,7 +23,6 @@ MakeError(BuildError, Error) /* denotes a permanent build failure */
MakeError(InvalidPath, Error)
MakeError(Unsupported, Error)
MakeError(SubstituteGone, Error)
MakeError(SubstituterDisabled, Error)
struct BasicDerivation;
@@ -49,7 +46,7 @@ const size_t storePathHashLen = 32; // i.e. 160 bits
const uint32_t exportMagic = 0x4558494e;
typedef std::unordered_map<Path, std::unordered_set<std::string>> Roots;
typedef std::map<Path, Path> Roots;
struct GCOptions
@@ -351,8 +348,7 @@ public:
(i.e. you'll get /nix/store/<hash> rather than
/nix/store/<hash>-<name>). Use queryPathInfo() to obtain the
full store path. */
virtual PathSet queryAllValidPaths()
{ unsupported("queryAllValidPaths"); }
virtual PathSet queryAllValidPaths() = 0;
/* Query information about a valid path. It is permitted to omit
the name part of the store path. */
@@ -371,8 +367,8 @@ public:
/* Queries the set of incoming FS references for a store path.
The result is not cleared. */
virtual void queryReferrers(const Path & path, PathSet & referrers)
{ unsupported("queryReferrers"); }
virtual void queryReferrers(const Path & path,
PathSet & referrers) = 0;
/* Return all currently valid derivations that have `path' as an
output. (Note that the result of `queryDeriver()' is the
@@ -381,12 +377,10 @@ public:
virtual PathSet queryValidDerivers(const Path & path) { return {}; };
/* Query the outputs of the derivation denoted by `path'. */
virtual PathSet queryDerivationOutputs(const Path & path)
{ unsupported("queryDerivationOutputs"); }
virtual PathSet queryDerivationOutputs(const Path & path) = 0;
/* Query the output names of the derivation denoted by `path'. */
virtual StringSet queryDerivationOutputNames(const Path & path)
{ unsupported("queryDerivationOutputNames"); }
virtual StringSet queryDerivationOutputNames(const Path & path) = 0;
/* Query the full store path given the hash part of a valid store
path, or "" if the path doesn't exist. */
@@ -452,16 +446,14 @@ public:
/* Add a store path as a temporary root of the garbage collector.
The root disappears as soon as we exit. */
virtual void addTempRoot(const Path & path)
{ unsupported("addTempRoot"); }
virtual void addTempRoot(const Path & path) = 0;
/* Add an indirect root, which is merely a symlink to `path' from
/nix/var/nix/gcroots/auto/<hash of `path'>. `path' is supposed
to be a symlink to a store path. The garbage collector will
automatically remove the indirect root when it finds that
`path' has disappeared. */
virtual void addIndirectRoot(const Path & path)
{ unsupported("addIndirectRoot"); }
virtual void addIndirectRoot(const Path & path) = 0;
/* Acquire the global GC lock, then immediately release it. This
function must be called after registering a new permanent root,
@@ -485,15 +477,11 @@ public:
/* Find the roots of the garbage collector. Each root is a pair
(link, storepath) where `link' is the path of the symlink
outside of the Nix store that point to `storePath'. If
'censor' is true, privacy-sensitive information about roots
found in /proc is censored. */
virtual Roots findRoots(bool censor)
{ unsupported("findRoots"); }
outside of the Nix store that point to `storePath'. */
virtual Roots findRoots() = 0;
/* Perform a garbage collection. */
virtual void collectGarbage(const GCOptions & options, GCResults & results)
{ unsupported("collectGarbage"); }
virtual void collectGarbage(const GCOptions & options, GCResults & results) = 0;
/* Return a string representing information about the path that
can be loaded into the database using `nix-store --load-db' or
@@ -524,13 +512,11 @@ public:
virtual bool verifyStore(bool checkContents, RepairFlag repair = NoRepair) { return false; };
/* Return an object to access files in the Nix store. */
virtual ref<FSAccessor> getFSAccessor()
{ unsupported("getFSAccessor"); }
virtual ref<FSAccessor> getFSAccessor() = 0;
/* Add signatures to the specified store path. The signatures are
not verified. */
virtual void addSignatures(const Path & storePath, const StringSet & sigs)
{ unsupported("addSignatures"); }
virtual void addSignatures(const Path & storePath, const StringSet & sigs) = 0;
/* Utility functions. */
@@ -612,12 +598,6 @@ public:
a notion of connection. Otherwise this is a no-op. */
virtual void connect() { };
/* Get the protocol version of this store or it's connection. */
virtual unsigned int getProtocol()
{
return 0;
};
/* Get the priority of the store, used to order substituters. In
particular, binary caches can specify a priority field in their
"nix-cache-info" file. Lower value means higher priority. */
@@ -633,9 +613,9 @@ protected:
Stats stats;
/* Unsupported methods. */
[[noreturn]] void unsupported(const std::string & op)
[[noreturn]] void unsupported()
{
throw Unsupported("operation '%s' is not supported by store '%s'", op, getUri());
throw Unsupported("requested operation is not supported by store '%s'", getUri());
}
};
@@ -802,8 +782,4 @@ ValidPathInfo decodeValidPathInfo(std::istream & str,
for paths created by makeFixedOutputPath() / addToStore(). */
std::string makeFixedOutputCA(bool recursive, const Hash & hash);
/* Split URI into protocol+hierarchy part and its parameter set. */
std::pair<std::string, Store::Params> splitUriAndParams(const std::string & uri);
}

View File

@@ -283,7 +283,7 @@ void parseDump(ParseSink & sink, Source & source)
{
string version;
try {
version = readString(source, narVersionMagic1.size());
version = readString(source);
} catch (SerialisationError & e) {
/* This generally means the integer at the start couldn't be
decoded. Ignore and throw the exception below. */
@@ -331,7 +331,7 @@ struct RestoreSink : ParseSink
filesystem doesn't support preallocation (e.g. on
OpenSolaris). Since preallocation is just an
optimisation, ignore it. */
if (errno && errno != EINVAL && errno != EOPNOTSUPP && errno != ENOSYS)
if (errno && errno != EINVAL)
throw SysError(format("preallocating file of %1% bytes") % len);
}
#endif

View File

@@ -250,7 +250,7 @@ struct XzCompressionSink : CompressionSink
ret = lzma_stream_encoder_mt(&strm, &mt_options);
done = true;
#else
printMsg(lvlError, "warning: parallel XZ compression requested but not supported, falling back to single-threaded compression");
printMsg(lvlError, "warning: parallel compression requested but not supported for metho d '%1%', falling back to single-threaded compression", method);
#endif
}

View File

@@ -105,9 +105,9 @@ string printHash16or32(const Hash & hash)
std::string Hash::to_string(Base base, bool includeType) const
{
std::string s;
if (base == SRI || includeType) {
if (includeType) {
s += printHashType(type);
s += base == SRI ? '-' : ':';
s += ':';
}
switch (base) {
case Base16:
@@ -117,7 +117,6 @@ std::string Hash::to_string(Base base, bool includeType) const
s += printHash32(*this);
break;
case Base64:
case SRI:
s += base64Encode(std::string((const char *) hash, hashSize));
break;
}
@@ -128,33 +127,28 @@ std::string Hash::to_string(Base base, bool includeType) const
Hash::Hash(const std::string & s, HashType type)
: type(type)
{
auto colon = s.find(':');
size_t pos = 0;
bool isSRI = false;
auto sep = s.find(':');
if (sep == string::npos) {
sep = s.find('-');
if (sep != string::npos) {
isSRI = true;
} else if (type == htUnknown)
if (colon == string::npos) {
if (type == htUnknown)
throw BadHash("hash '%s' does not include a type", s);
}
if (sep != string::npos) {
string hts = string(s, 0, sep);
} else {
string hts = string(s, 0, colon);
this->type = parseHashType(hts);
if (this->type == htUnknown)
throw BadHash("unknown hash type '%s'", hts);
if (type != htUnknown && type != this->type)
throw BadHash("hash '%s' should have type '%s'", s, printHashType(type));
pos = sep + 1;
pos = colon + 1;
}
init();
size_t size = s.size() - pos;
if (!isSRI && size == base16Len()) {
if (size == base16Len()) {
auto parseHexDigit = [&](char c) {
if (c >= '0' && c <= '9') return c - '0';
@@ -170,7 +164,7 @@ Hash::Hash(const std::string & s, HashType type)
}
}
else if (!isSRI && size == base32Len()) {
else if (size == base32Len()) {
for (unsigned int n = 0; n < size; ++n) {
char c = s[pos + size - n - 1];
@@ -193,10 +187,10 @@ Hash::Hash(const std::string & s, HashType type)
}
}
else if (isSRI || size == base64Len()) {
else if (size == base64Len()) {
auto d = base64Decode(std::string(s, pos));
if (d.size() != hashSize)
throw BadHash("invalid %s hash '%s'", isSRI ? "SRI" : "base-64", s);
throw BadHash("invalid base-64 hash '%s'", s);
assert(hashSize);
memcpy(hash, d.data(), hashSize);
}

View File

@@ -20,7 +20,7 @@ const int sha512HashSize = 64;
extern const string base32Chars;
enum Base : int { Base64, Base32, Base16, SRI };
enum Base : int { Base64, Base32, Base16 };
struct Hash
@@ -38,9 +38,8 @@ struct Hash
Hash(HashType type) : type(type) { init(); };
/* Initialize the hash from a string representation, in the format
"[<type>:]<base16|base32|base64>" or "<type>-<base64>" (a
Subresource Integrity hash expression). If the 'type' argument
is htUnknown, then the hash type must be specified in the
"[<type>:]<base16|base32|base64>". If the 'type' argument is
htUnknown, then the hash type must be specified in the
string. */
Hash(const std::string & s, HashType type = htUnknown);

View File

@@ -7,3 +7,7 @@ libutil_DIR := $(d)
libutil_SOURCES := $(wildcard $(d)/*.cc)
libutil_LDFLAGS = $(LIBLZMA_LIBS) -lbz2 -pthread $(OPENSSL_LIBS) $(LIBBROTLI_LIBS) -lboost_context
libutil_LIBS = libformat
libutil_CXXFLAGS = -DBROTLI=\"$(brotli)\"

View File

@@ -2,7 +2,7 @@
#include <map>
#include <list>
#include <optional>
#include <experimental/optional>
namespace nix {
@@ -64,7 +64,7 @@ public:
/* Look up an item in the cache. If it exists, it becomes the most
recently used item. */
std::optional<Value> get(const Key & key)
std::experimental::optional<Value> get(const Key & key)
{
auto i = data.find(key);
if (i == data.end()) return {};

View File

@@ -97,7 +97,6 @@ public:
private:
Pool & pool;
std::shared_ptr<R> r;
bool bad = false;
friend Pool;
@@ -113,8 +112,7 @@ public:
if (!r) return;
{
auto state_(pool.state.lock());
if (!bad)
state_->idle.push_back(ref<R>(r));
state_->idle.push_back(ref<R>(r));
assert(state_->inUse);
state_->inUse--;
}
@@ -123,8 +121,6 @@ public:
R * operator -> () { return &*r; }
R & operator * () { return *r; }
void markBad() { bad = true; }
};
Handle get()

View File

@@ -169,13 +169,17 @@ std::unique_ptr<Source> sinkToSource(
{
typedef boost::coroutines2::coroutine<std::string> coro_t;
std::function<void(Sink &)> fun;
std::function<void()> eof;
std::optional<coro_t::pull_type> coro;
bool started = false;
coro_t::pull_type coro;
SinkToSource(std::function<void(Sink &)> fun, std::function<void()> eof)
: fun(fun), eof(eof)
: eof(eof)
, coro([&](coro_t::push_type & yield) {
LambdaSink sink([&](const unsigned char * data, size_t len) {
if (len) yield(std::string((const char *) data, len));
});
fun(sink);
})
{
}
@@ -184,19 +188,11 @@ std::unique_ptr<Source> sinkToSource(
size_t read(unsigned char * data, size_t len) override
{
if (!coro)
coro = coro_t::pull_type([&](coro_t::push_type & yield) {
LambdaSink sink([&](const unsigned char * data, size_t len) {
if (len) yield(std::string((const char *) data, len));
});
fun(sink);
});
if (!*coro) { eof(); abort(); }
if (!coro) { eof(); abort(); }
if (pos == cur.size()) {
if (!cur.empty()) (*coro)();
cur = coro->get();
if (!cur.empty()) coro();
cur = coro.get();
pos = 0;
}
@@ -272,17 +268,16 @@ void readPadding(size_t len, Source & source)
size_t readString(unsigned char * buf, size_t max, Source & source)
{
auto len = readNum<size_t>(source);
if (len > max) throw SerialisationError("string is too long");
if (len > max) throw Error("string is too long");
source(buf, len);
readPadding(len, source);
return len;
}
string readString(Source & source, size_t max)
string readString(Source & source)
{
auto len = readNum<size_t>(source);
if (len > max) throw SerialisationError("string is too long");
std::string res(len, 0);
source((unsigned char*) res.data(), len);
readPadding(len, source);

View File

@@ -284,7 +284,7 @@ inline uint64_t readLongLong(Source & source)
void readPadding(size_t len, Source & source);
size_t readString(unsigned char * buf, size_t max, Source & source);
string readString(Source & source, size_t max = std::numeric_limits<size_t>::max());
string readString(Source & source);
template<class T> T readStrings(Source & source);
Source & operator >> (Source & in, string & s);

View File

@@ -167,7 +167,7 @@ Path dirOf(const Path & path)
{
Path::size_type pos = path.rfind('/');
if (pos == string::npos)
return ".";
throw Error(format("invalid file name '%1%'") % path);
return pos == 0 ? "/" : Path(path, 0, pos);
}
@@ -202,7 +202,7 @@ bool isInDir(const Path & path, const Path & dir)
bool isDirOrInDir(const Path & path, const Path & dir)
{
return path == dir || isInDir(path, dir);
return path == dir or isInDir(path, dir);
}
@@ -468,7 +468,7 @@ static Lazy<Path> getHome2([]() {
std::vector<char> buf(16384);
struct passwd pwbuf;
struct passwd * pw;
if (getpwuid_r(geteuid(), &pwbuf, buf.data(), buf.size(), &pw) != 0
if (getpwuid_r(getuid(), &pwbuf, buf.data(), buf.size(), &pw) != 0
|| !pw || !pw->pw_dir || !pw->pw_dir[0])
throw Error("cannot determine user's home directory");
homeDir = pw->pw_dir;
@@ -496,15 +496,6 @@ Path getConfigDir()
return configDir;
}
std::vector<Path> getConfigDirs()
{
Path configHome = getConfigDir();
string configDirs = getEnv("XDG_CONFIG_DIRS");
std::vector<Path> result = tokenizeString<std::vector<string>>(configDirs, ":");
result.insert(result.begin(), configHome);
return result;
}
Path getDataDir()
{
@@ -965,7 +956,7 @@ std::vector<char *> stringsToCharPtrs(const Strings & ss)
string runProgram(Path program, bool searchPath, const Strings & args,
const std::optional<std::string> & input)
const std::experimental::optional<std::string> & input)
{
RunOptions opts(program, args);
opts.searchPath = searchPath;

View File

@@ -14,7 +14,7 @@
#include <cstdio>
#include <map>
#include <sstream>
#include <optional>
#include <experimental/optional>
#include <future>
#ifndef HAVE_STRUCT_DIRENT_D_TYPE
@@ -131,9 +131,6 @@ Path getCacheDir();
/* Return $XDG_CONFIG_HOME or $HOME/.config. */
Path getConfigDir();
/* Return the directories to search for user configuration files */
std::vector<Path> getConfigDirs();
/* Return $XDG_DATA_HOME or $HOME/.local/share. */
Path getDataDir();
@@ -259,14 +256,14 @@ pid_t startProcess(std::function<void()> fun, const ProcessOptions & options = P
shell backtick operator). */
string runProgram(Path program, bool searchPath = false,
const Strings & args = Strings(),
const std::optional<std::string> & input = {});
const std::experimental::optional<std::string> & input = {});
struct RunOptions
{
Path program;
bool searchPath = true;
Strings args;
std::optional<std::string> input;
std::experimental::optional<std::string> input;
Source * standardIn = nullptr;
Sink * standardOut = nullptr;
bool _killStderr = false;

View File

@@ -0,0 +1,542 @@
/*
* Copyright 2001-2004 Unicode, Inc.
*
* Disclaimer
*
* This source code is provided as is by Unicode, Inc. No claims are
* made as to fitness for any particular purpose. No warranties of any
* kind are expressed or implied. The recipient agrees to determine
* applicability of information provided. If this file has been
* purchased on magnetic or optical media from Unicode, Inc., the
* sole remedy for any claim will be exchange of defective media
* within 90 days of receipt.
*
* Limitations on Rights to Redistribute This Code
*
* Unicode, Inc. hereby grants the right to freely use the information
* supplied in this file in the creation of products supporting the
* Unicode Standard, and to make copies of this file in any form
* for internal or external distribution as long as this notice
* remains attached.
*/
/* ---------------------------------------------------------------------
Conversions between UTF32, UTF-16, and UTF-8. Source code file.
Author: Mark E. Davis, 1994.
Rev History: Rick McGowan, fixes & updates May 2001.
Sept 2001: fixed const & error conditions per
mods suggested by S. Parent & A. Lillich.
June 2002: Tim Dodd added detection and handling of incomplete
source sequences, enhanced error detection, added casts
to eliminate compiler warnings.
July 2003: slight mods to back out aggressive FFFE detection.
Jan 2004: updated switches in from-UTF8 conversions.
Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
See the header file "ConvertUTF.h" for complete documentation.
------------------------------------------------------------------------ */
#include "ConvertUTF.h"
#ifdef CVTUTF_DEBUG
#include <stdio.h>
#endif
namespace linenoise_ng {
static const int halfShift = 10; /* used for shifting by 10 bits */
static const UTF32 halfBase = 0x0010000UL;
static const UTF32 halfMask = 0x3FFUL;
#define UNI_SUR_HIGH_START (UTF32)0xD800
#define UNI_SUR_HIGH_END (UTF32)0xDBFF
#define UNI_SUR_LOW_START (UTF32)0xDC00
#define UNI_SUR_LOW_END (UTF32)0xDFFF
#define false 0
#define true 1
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF32toUTF16 (
const UTF32** sourceStart, const UTF32* sourceEnd,
char16_t** targetStart, char16_t* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF32* source = *sourceStart;
char16_t* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch;
if (target >= targetEnd) {
result = targetExhausted; break;
}
ch = *source++;
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
/* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
if (flags == strictConversion) {
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
*target++ = (UTF16)ch; /* normal case */
}
} else if (ch > UNI_MAX_LEGAL_UTF32) {
if (flags == strictConversion) {
result = sourceIllegal;
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
/* target is a character in range 0xFFFF - 0x10FFFF. */
if (target + 1 >= targetEnd) {
--source; /* Back up source pointer! */
result = targetExhausted; break;
}
ch -= halfBase;
*target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
*target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
}
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF16toUTF32 (
const UTF16** sourceStart, const UTF16* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF16* source = *sourceStart;
UTF32* target = *targetStart;
UTF32 ch, ch2;
while (source < sourceEnd) {
const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
ch = *source++;
/* If we have a surrogate pair, convert to UTF32 first. */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
/* If the 16 bits following the high surrogate are in the source buffer... */
if (source < sourceEnd) {
ch2 = *source;
/* If it's a low surrogate, convert to UTF32. */
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+ (ch2 - UNI_SUR_LOW_START) + halfBase;
++source;
} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
} else { /* We don't have the 16 bits following the high surrogate. */
--source; /* return to the high surrogate */
result = sourceExhausted;
break;
}
} else if (flags == strictConversion) {
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
}
if (target >= targetEnd) {
source = oldSource; /* Back up source pointer! */
result = targetExhausted; break;
}
*target++ = ch;
}
*sourceStart = source;
*targetStart = target;
#ifdef CVTUTF_DEBUG
if (result == sourceIllegal) {
fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
fflush(stderr);
}
#endif
return result;
}
/* --------------------------------------------------------------------- */
/*
* Index into the table below with the first byte of a UTF-8 sequence to
* get the number of trailing bytes that are supposed to follow it.
* Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
* left as-is for anyone who may want to do such conversion, which was
* allowed in earlier algorithms.
*/
static const char trailingBytesForUTF8[256] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
};
/*
* Magic values subtracted from a buffer value during UTF8 conversion.
* This table contains as many values as there might be trailing bytes
* in a UTF-8 sequence.
*/
static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
0x03C82080UL, 0xFA082080UL, 0x82082080UL };
/*
* Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
* into the first byte, depending on how many bytes follow. There are
* as many entries in this table as there are UTF-8 sequence types.
* (I.e., one byte sequence, two byte... etc.). Remember that sequencs
* for *legal* UTF-8 will be 4 or fewer bytes total.
*/
static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
/* --------------------------------------------------------------------- */
/* The interface converts a whole buffer to avoid function-call overhead.
* Constants have been gathered. Loops & conditionals have been removed as
* much as possible for efficiency, in favor of drop-through switches.
* (See "Note A" at the bottom of the file for equivalent code.)
* If your compiler supports it, the "isLegalUTF8" call can be turned
* into an inline function.
*/
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF16toUTF8 (
const UTF16** sourceStart, const UTF16* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF16* source = *sourceStart;
UTF8* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch;
unsigned short bytesToWrite = 0;
const UTF32 byteMask = 0xBF;
const UTF32 byteMark = 0x80;
const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
ch = *source++;
/* If we have a surrogate pair, convert to UTF32 first. */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
/* If the 16 bits following the high surrogate are in the source buffer... */
if (source < sourceEnd) {
UTF32 ch2 = *source;
/* If it's a low surrogate, convert to UTF32. */
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+ (ch2 - UNI_SUR_LOW_START) + halfBase;
++source;
} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
} else { /* We don't have the 16 bits following the high surrogate. */
--source; /* return to the high surrogate */
result = sourceExhausted;
break;
}
} else if (flags == strictConversion) {
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
}
/* Figure out how many bytes the result will require */
if (ch < (UTF32)0x80) { bytesToWrite = 1;
} else if (ch < (UTF32)0x800) { bytesToWrite = 2;
} else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
} else if (ch < (UTF32)0x110000) { bytesToWrite = 4;
} else { bytesToWrite = 3;
ch = UNI_REPLACEMENT_CHAR;
}
target += bytesToWrite;
if (target > targetEnd) {
source = oldSource; /* Back up source pointer! */
target -= bytesToWrite; result = targetExhausted; break;
}
switch (bytesToWrite) { /* note: everything falls through. */
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]);
}
target += bytesToWrite;
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
/*
* Utility routine to tell whether a sequence of bytes is legal UTF-8.
* This must be called with the length pre-determined by the first byte.
* If not calling this from ConvertUTF8to*, then the length can be set by:
* length = trailingBytesForUTF8[*source]+1;
* and the sequence is illegal right away if there aren't that many bytes
* available.
* If presented with a length > 4, this returns false. The Unicode
* definition of UTF-8 goes up to 4-byte sequences.
*/
static Boolean isLegalUTF8(const UTF8 *source, int length) {
UTF8 a;
const UTF8 *srcptr = source+length;
switch (length) {
default: return false;
/* Everything else falls through when "true"... */
case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
case 2: if ((a = (*--srcptr)) > 0xBF) return false;
switch (*source) {
/* no fall-through in this inner switch */
case 0xE0: if (a < 0xA0) return false; break;
case 0xED: if (a > 0x9F) return false; break;
case 0xF0: if (a < 0x90) return false; break;
case 0xF4: if (a > 0x8F) return false; break;
default: if (a < 0x80) return false;
}
case 1: if (*source >= 0x80 && *source < 0xC2) return false;
}
if (*source > 0xF4) return false;
return true;
}
/* --------------------------------------------------------------------- */
/*
* Exported function to return whether a UTF-8 sequence is legal or not.
* This is not used here; it's just exported.
*/
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
int length = trailingBytesForUTF8[*source]+1;
if (source+length > sourceEnd) {
return false;
}
return isLegalUTF8(source, length);
}
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF8toUTF16 (
const UTF8** sourceStart, const UTF8* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF8* source = *sourceStart;
UTF16* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch = 0;
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
if (source + extraBytesToRead >= sourceEnd) {
result = sourceExhausted; break;
}
/* Do this check whether lenient or strict */
if (! isLegalUTF8(source, extraBytesToRead+1)) {
result = sourceIllegal;
break;
}
/*
* The cases all fall through. See "Note A" below.
*/
switch (extraBytesToRead) {
case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
case 3: ch += *source++; ch <<= 6;
case 2: ch += *source++; ch <<= 6;
case 1: ch += *source++; ch <<= 6;
case 0: ch += *source++;
}
ch -= offsetsFromUTF8[extraBytesToRead];
if (target >= targetEnd) {
source -= (extraBytesToRead+1); /* Back up source pointer! */
result = targetExhausted; break;
}
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
if (flags == strictConversion) {
source -= (extraBytesToRead+1); /* return to the illegal value itself */
result = sourceIllegal;
break;
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
*target++ = (UTF16)ch; /* normal case */
}
} else if (ch > UNI_MAX_UTF16) {
if (flags == strictConversion) {
result = sourceIllegal;
source -= (extraBytesToRead+1); /* return to the start */
break; /* Bail out; shouldn't continue */
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
/* target is a character in range 0xFFFF - 0x10FFFF. */
if (target + 1 >= targetEnd) {
source -= (extraBytesToRead+1); /* Back up source pointer! */
result = targetExhausted; break;
}
ch -= halfBase;
*target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
*target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
}
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF32toUTF8 (
const UTF32** sourceStart, const UTF32* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF32* source = *sourceStart;
UTF8* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch;
unsigned short bytesToWrite = 0;
const UTF32 byteMask = 0xBF;
const UTF32 byteMark = 0x80;
ch = *source++;
if (flags == strictConversion ) {
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
}
/*
* Figure out how many bytes the result will require. Turn any
* illegally large UTF32 things (> Plane 17) into replacement chars.
*/
if (ch < (UTF32)0x80) { bytesToWrite = 1;
} else if (ch < (UTF32)0x800) { bytesToWrite = 2;
} else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
} else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4;
} else { bytesToWrite = 3;
ch = UNI_REPLACEMENT_CHAR;
result = sourceIllegal;
}
target += bytesToWrite;
if (target > targetEnd) {
--source; /* Back up source pointer! */
target -= bytesToWrite; result = targetExhausted; break;
}
switch (bytesToWrite) { /* note: everything falls through. */
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
}
target += bytesToWrite;
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF8toUTF32 (
const UTF8** sourceStart, const UTF8* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF8* source = *sourceStart;
UTF32* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch = 0;
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
if (source + extraBytesToRead >= sourceEnd) {
result = sourceExhausted; break;
}
/* Do this check whether lenient or strict */
if (! isLegalUTF8(source, extraBytesToRead+1)) {
result = sourceIllegal;
break;
}
/*
* The cases all fall through. See "Note A" below.
*/
switch (extraBytesToRead) {
case 5: ch += *source++; ch <<= 6;
case 4: ch += *source++; ch <<= 6;
case 3: ch += *source++; ch <<= 6;
case 2: ch += *source++; ch <<= 6;
case 1: ch += *source++; ch <<= 6;
case 0: ch += *source++;
}
ch -= offsetsFromUTF8[extraBytesToRead];
if (target >= targetEnd) {
source -= (extraBytesToRead+1); /* Back up the source pointer! */
result = targetExhausted; break;
}
if (ch <= UNI_MAX_LEGAL_UTF32) {
/*
* UTF-16 surrogate values are illegal in UTF-32, and anything
* over Plane 17 (> 0x10FFFF) is illegal.
*/
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
if (flags == strictConversion) {
source -= (extraBytesToRead+1); /* return to the illegal value itself */
result = sourceIllegal;
break;
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
*target++ = ch;
}
} else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
result = sourceIllegal;
*target++ = UNI_REPLACEMENT_CHAR;
}
}
*sourceStart = source;
*targetStart = target;
return result;
}
}
/* ---------------------------------------------------------------------
Note A.
The fall-through switches in UTF-8 reading code save a
temp variable, some decrements & conditionals. The switches
are equivalent to the following loop:
{
int tmpBytesToRead = extraBytesToRead+1;
do {
ch += *source++;
--tmpBytesToRead;
if (tmpBytesToRead) ch <<= 6;
} while (tmpBytesToRead > 0);
}
In UTF-8 writing code, the switches on "bytesToWrite" are
similarly unrolled loops.
--------------------------------------------------------------------- */

162
src/linenoise/ConvertUTF.h Executable file
View File

@@ -0,0 +1,162 @@
/*
* Copyright 2001-2004 Unicode, Inc.
*
* Disclaimer
*
* This source code is provided as is by Unicode, Inc. No claims are
* made as to fitness for any particular purpose. No warranties of any
* kind are expressed or implied. The recipient agrees to determine
* applicability of information provided. If this file has been
* purchased on magnetic or optical media from Unicode, Inc., the
* sole remedy for any claim will be exchange of defective media
* within 90 days of receipt.
*
* Limitations on Rights to Redistribute This Code
*
* Unicode, Inc. hereby grants the right to freely use the information
* supplied in this file in the creation of products supporting the
* Unicode Standard, and to make copies of this file in any form
* for internal or external distribution as long as this notice
* remains attached.
*/
/* ---------------------------------------------------------------------
Conversions between UTF32, UTF-16, and UTF-8. Header file.
Several funtions are included here, forming a complete set of
conversions between the three formats. UTF-7 is not included
here, but is handled in a separate source file.
Each of these routines takes pointers to input buffers and output
buffers. The input buffers are const.
Each routine converts the text between *sourceStart and sourceEnd,
putting the result into the buffer between *targetStart and
targetEnd. Note: the end pointers are *after* the last item: e.g.
*(sourceEnd - 1) is the last item.
The return result indicates whether the conversion was successful,
and if not, whether the problem was in the source or target buffers.
(Only the first encountered problem is indicated.)
After the conversion, *sourceStart and *targetStart are both
updated to point to the end of last text successfully converted in
the respective buffers.
Input parameters:
sourceStart - pointer to a pointer to the source buffer.
The contents of this are modified on return so that
it points at the next thing to be converted.
targetStart - similarly, pointer to pointer to the target buffer.
sourceEnd, targetEnd - respectively pointers to the ends of the
two buffers, for overflow checking only.
These conversion functions take a ConversionFlags argument. When this
flag is set to strict, both irregular sequences and isolated surrogates
will cause an error. When the flag is set to lenient, both irregular
sequences and isolated surrogates are converted.
Whether the flag is strict or lenient, all illegal sequences will cause
an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
must check for illegal sequences.
When the flag is set to lenient, characters over 0x10FFFF are converted
to the replacement character; otherwise (when the flag is set to strict)
they constitute an error.
Output parameters:
The value "sourceIllegal" is returned from some routines if the input
sequence is malformed. When "sourceIllegal" is returned, the source
value will point to the illegal value that caused the problem. E.g.,
in UTF-8 when a sequence is malformed, it points to the start of the
malformed sequence.
Author: Mark E. Davis, 1994.
Rev History: Rick McGowan, fixes & updates May 2001.
Fixes & updates, Sept 2001.
------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------
The following 4 definitions are compiler-specific.
The C standard does not guarantee that wchar_t has at least
16 bits, so wchar_t is no less portable than unsigned short!
All should be unsigned values to avoid sign extension during
bit mask & shift operations.
------------------------------------------------------------------------ */
#if 0
typedef unsigned long UTF32; /* at least 32 bits */
typedef unsigned short UTF16; /* at least 16 bits */
typedef unsigned char UTF8; /* typically 8 bits */
#endif
#include <stdint.h>
#include <string>
namespace linenoise_ng {
typedef uint32_t UTF32;
typedef uint16_t UTF16;
typedef uint8_t UTF8;
typedef unsigned char Boolean; /* 0 or 1 */
/* Some fundamental constants */
#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
#define UNI_MAX_BMP (UTF32)0x0000FFFF
#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
typedef enum {
conversionOK, /* conversion successful */
sourceExhausted, /* partial character in source, but hit end */
targetExhausted, /* insuff. room in target for conversion */
sourceIllegal /* source sequence is illegal/malformed */
} ConversionResult;
typedef enum {
strictConversion = 0,
lenientConversion
} ConversionFlags;
// /* This is for C++ and does no harm in C */
// #ifdef __cplusplus
// extern "C" {
// #endif
ConversionResult ConvertUTF8toUTF16 (
const UTF8** sourceStart, const UTF8* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF16toUTF8 (
const UTF16** sourceStart, const UTF16* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF8toUTF32 (
const UTF8** sourceStart, const UTF8* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF32toUTF8 (
const UTF32** sourceStart, const UTF32* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF16toUTF32 (
const UTF16** sourceStart, const UTF16* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF32toUTF16 (
const UTF32** sourceStart, const UTF32* sourceEnd,
char16_t** targetStart, char16_t* targetEnd, ConversionFlags flags);
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
// #ifdef __cplusplus
// }
// #endif
}
/* --------------------------------------------------------------------- */

66
src/linenoise/LICENSE Normal file
View File

@@ -0,0 +1,66 @@
linenoise.cpp
=============
Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Redis nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
wcwidth.cpp
===========
Markus Kuhn -- 2007-05-26 (Unicode 5.0)
Permission to use, copy, modify, and distribute this software
for any purpose and without fee is hereby granted. The author
disclaims all warranties with regard to this software.
ConvertUTF.cpp
==============
Copyright 2001-2004 Unicode, Inc.
Disclaimer
This source code is provided as is by Unicode, Inc. No claims are
made as to fitness for any particular purpose. No warranties of any
kind are expressed or implied. The recipient agrees to determine
applicability of information provided. If this file has been
purchased on magnetic or optical media from Unicode, Inc., the
sole remedy for any claim will be exchange of defective media
within 90 days of receipt.
Limitations on Rights to Redistribute This Code
Unicode, Inc. hereby grants the right to freely use the information
supplied in this file in the creation of products supporting the
Unicode Standard, and to make copies of this file in any form
for internal or external distribution as long as this notice
remains attached.

3450
src/linenoise/linenoise.cpp Normal file

File diff suppressed because it is too large Load Diff

73
src/linenoise/linenoise.h Normal file
View File

@@ -0,0 +1,73 @@
/* linenoise.h -- guerrilla line editing library against the idea that a
* line editing lib needs to be 20,000 lines of C code.
*
* See linenoise.c for more information.
*
* Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __LINENOISE_H
#define __LINENOISE_H
#define LINENOISE_VERSION "1.0.0"
#define LINENOISE_VERSION_MAJOR 1
#define LINENOISE_VERSION_MINOR 1
#ifdef __cplusplus
extern "C" {
#endif
typedef struct linenoiseCompletions linenoiseCompletions;
typedef void(linenoiseCompletionCallback)(const char*, linenoiseCompletions*);
void linenoiseSetCompletionCallback(linenoiseCompletionCallback* fn);
void linenoiseAddCompletion(linenoiseCompletions* lc, const char* str);
char* linenoise(const char* prompt);
void linenoisePreloadBuffer(const char* preloadText);
int linenoiseHistoryAdd(const char* line);
int linenoiseHistorySetMaxLen(int len);
char* linenoiseHistoryLine(int index);
int linenoiseHistorySave(const char* filename);
int linenoiseHistoryLoad(const char* filename);
void linenoiseHistoryFree(void);
void linenoiseClearScreen(void);
void linenoiseSetMultiLine(int ml);
void linenoisePrintKeyCodes(void);
/* the following are extensions to the original linenoise API */
int linenoiseInstallWindowChangeHandler(void);
/* returns type of key pressed: 1 = CTRL-C, 2 = CTRL-D, 0 = other */
int linenoiseKeyType(void);
#ifdef __cplusplus
}
#endif
#endif /* __LINENOISE_H */

315
src/linenoise/wcwidth.cpp Normal file
View File

@@ -0,0 +1,315 @@
/*
* This is an implementation of wcwidth() and wcswidth() (defined in
* IEEE Std 1002.1-2001) for Unicode.
*
* http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html
* http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html
*
* In fixed-width output devices, Latin characters all occupy a single
* "cell" position of equal width, whereas ideographic CJK characters
* occupy two such cells. Interoperability between terminal-line
* applications and (teletype-style) character terminals using the
* UTF-8 encoding requires agreement on which character should advance
* the cursor by how many cell positions. No established formal
* standards exist at present on which Unicode character shall occupy
* how many cell positions on character terminals. These routines are
* a first attempt of defining such behavior based on simple rules
* applied to data provided by the Unicode Consortium.
*
* For some graphical characters, the Unicode standard explicitly
* defines a character-cell width via the definition of the East Asian
* FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes.
* In all these cases, there is no ambiguity about which width a
* terminal shall use. For characters in the East Asian Ambiguous (A)
* class, the width choice depends purely on a preference of backward
* compatibility with either historic CJK or Western practice.
* Choosing single-width for these characters is easy to justify as
* the appropriate long-term solution, as the CJK practice of
* displaying these characters as double-width comes from historic
* implementation simplicity (8-bit encoded characters were displayed
* single-width and 16-bit ones double-width, even for Greek,
* Cyrillic, etc.) and not any typographic considerations.
*
* Much less clear is the choice of width for the Not East Asian
* (Neutral) class. Existing practice does not dictate a width for any
* of these characters. It would nevertheless make sense
* typographically to allocate two character cells to characters such
* as for instance EM SPACE or VOLUME INTEGRAL, which cannot be
* represented adequately with a single-width glyph. The following
* routines at present merely assign a single-cell width to all
* neutral characters, in the interest of simplicity. This is not
* entirely satisfactory and should be reconsidered before
* establishing a formal standard in this area. At the moment, the
* decision which Not East Asian (Neutral) characters should be
* represented by double-width glyphs cannot yet be answered by
* applying a simple rule from the Unicode database content. Setting
* up a proper standard for the behavior of UTF-8 character terminals
* will require a careful analysis not only of each Unicode character,
* but also of each presentation form, something the author of these
* routines has avoided to do so far.
*
* http://www.unicode.org/unicode/reports/tr11/
*
* Markus Kuhn -- 2007-05-26 (Unicode 5.0)
*
* Permission to use, copy, modify, and distribute this software
* for any purpose and without fee is hereby granted. The author
* disclaims all warranties with regard to this software.
*
* Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
*/
#include <wchar.h>
#include <string>
#include <memory>
namespace linenoise_ng {
struct interval {
char32_t first;
char32_t last;
};
/* auxiliary function for binary search in interval table */
static int bisearch(char32_t ucs, const struct interval *table, int max) {
int min = 0;
int mid;
if (ucs < table[0].first || ucs > table[max].last)
return 0;
while (max >= min) {
mid = (min + max) / 2;
if (ucs > table[mid].last)
min = mid + 1;
else if (ucs < table[mid].first)
max = mid - 1;
else
return 1;
}
return 0;
}
/* The following two functions define the column width of an ISO 10646
* character as follows:
*
* - The null character (U+0000) has a column width of 0.
*
* - Other C0/C1 control characters and DEL will lead to a return
* value of -1.
*
* - Non-spacing and enclosing combining characters (general
* category code Mn or Me in the Unicode database) have a
* column width of 0.
*
* - SOFT HYPHEN (U+00AD) has a column width of 1.
*
* - Other format characters (general category code Cf in the Unicode
* database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
*
* - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
* have a column width of 0.
*
* - Spacing characters in the East Asian Wide (W) or East Asian
* Full-width (F) category as defined in Unicode Technical
* Report #11 have a column width of 2.
*
* - All remaining characters (including all printable
* ISO 8859-1 and WGL4 characters, Unicode control characters,
* etc.) have a column width of 1.
*
* This implementation assumes that wchar_t characters are encoded
* in ISO 10646.
*/
int mk_wcwidth(char32_t ucs)
{
/* sorted list of non-overlapping intervals of non-spacing characters */
/* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
static const struct interval combining[] = {
{ 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 },
{ 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 },
{ 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 },
{ 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 },
{ 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
{ 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
{ 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 },
{ 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D },
{ 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 },
{ 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD },
{ 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C },
{ 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D },
{ 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC },
{ 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD },
{ 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C },
{ 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D },
{ 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 },
{ 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 },
{ 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC },
{ 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD },
{ 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D },
{ 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 },
{ 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E },
{ 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC },
{ 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 },
{ 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E },
{ 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 },
{ 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 },
{ 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 },
{ 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F },
{ 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 },
{ 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD },
{ 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD },
{ 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 },
{ 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B },
{ 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 },
{ 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 },
{ 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF },
{ 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 },
{ 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F },
{ 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B },
{ 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F },
{ 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB },
{ 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F },
{ 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 },
{ 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD },
{ 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F },
{ 0xE0100, 0xE01EF }
};
/* test for 8-bit control characters */
if (ucs == 0)
return 0;
if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
return -1;
/* binary search in table of non-spacing characters */
if (bisearch(ucs, combining,
sizeof(combining) / sizeof(struct interval) - 1))
return 0;
/* if we arrive here, ucs is not a combining or C0/C1 control character */
return 1 +
(ucs >= 0x1100 &&
(ucs <= 0x115f || /* Hangul Jamo init. consonants */
ucs == 0x2329 || ucs == 0x232a ||
(ucs >= 0x2e80 && ucs <= 0xa4cf &&
ucs != 0x303f) || /* CJK ... Yi */
(ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
(ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
(ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */
(ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
(ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */
(ucs >= 0xffe0 && ucs <= 0xffe6) ||
(ucs >= 0x20000 && ucs <= 0x2fffd) ||
(ucs >= 0x30000 && ucs <= 0x3fffd)));
}
int mk_wcswidth(const char32_t* pwcs, size_t n)
{
int w, width = 0;
for (;*pwcs && n-- > 0; pwcs++)
if ((w = mk_wcwidth(*pwcs)) < 0)
return -1;
else
width += w;
return width;
}
/*
* The following functions are the same as mk_wcwidth() and
* mk_wcswidth(), except that spacing characters in the East Asian
* Ambiguous (A) category as defined in Unicode Technical Report #11
* have a column width of 2. This variant might be useful for users of
* CJK legacy encodings who want to migrate to UCS without changing
* the traditional terminal character-width behaviour. It is not
* otherwise recommended for general use.
*/
int mk_wcwidth_cjk(wchar_t ucs)
{
/* sorted list of non-overlapping intervals of East Asian Ambiguous
* characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */
static const struct interval ambiguous[] = {
{ 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 },
{ 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 },
{ 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 },
{ 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 },
{ 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED },
{ 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA },
{ 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 },
{ 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B },
{ 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 },
{ 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 },
{ 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 },
{ 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE },
{ 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 },
{ 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA },
{ 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 },
{ 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB },
{ 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB },
{ 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x03A1 },
{ 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 },
{ 0x0401, 0x0401 }, { 0x0410, 0x044F }, { 0x0451, 0x0451 },
{ 0x2010, 0x2010 }, { 0x2013, 0x2016 }, { 0x2018, 0x2019 },
{ 0x201C, 0x201D }, { 0x2020, 0x2022 }, { 0x2024, 0x2027 },
{ 0x2030, 0x2030 }, { 0x2032, 0x2033 }, { 0x2035, 0x2035 },
{ 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 },
{ 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC },
{ 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 },
{ 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2122 },
{ 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2154 },
{ 0x215B, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 },
{ 0x2190, 0x2199 }, { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 },
{ 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 },
{ 0x2202, 0x2203 }, { 0x2207, 0x2208 }, { 0x220B, 0x220B },
{ 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 },
{ 0x221A, 0x221A }, { 0x221D, 0x2220 }, { 0x2223, 0x2223 },
{ 0x2225, 0x2225 }, { 0x2227, 0x222C }, { 0x222E, 0x222E },
{ 0x2234, 0x2237 }, { 0x223C, 0x223D }, { 0x2248, 0x2248 },
{ 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2261 },
{ 0x2264, 0x2267 }, { 0x226A, 0x226B }, { 0x226E, 0x226F },
{ 0x2282, 0x2283 }, { 0x2286, 0x2287 }, { 0x2295, 0x2295 },
{ 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF },
{ 0x2312, 0x2312 }, { 0x2460, 0x24E9 }, { 0x24EB, 0x254B },
{ 0x2550, 0x2573 }, { 0x2580, 0x258F }, { 0x2592, 0x2595 },
{ 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 },
{ 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 },
{ 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 },
{ 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2606 },
{ 0x2609, 0x2609 }, { 0x260E, 0x260F }, { 0x2614, 0x2615 },
{ 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 },
{ 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 },
{ 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F },
{ 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF },
{ 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD }
};
/* binary search in table of non-spacing characters */
if (bisearch(ucs, ambiguous,
sizeof(ambiguous) / sizeof(struct interval) - 1))
return 2;
return mk_wcwidth(ucs);
}
int mk_wcswidth_cjk(const wchar_t *pwcs, size_t n)
{
int w, width = 0;
for (;*pwcs && n-- > 0; pwcs++)
if ((w = mk_wcwidth_cjk(*pwcs)) < 0)
return -1;
else
width += w;
return width;
}
}

9
src/nix-build/local.mk Normal file
View File

@@ -0,0 +1,9 @@
programs += nix-build
nix-build_DIR := $(d)
nix-build_SOURCES := $(d)/nix-build.cc
nix-build_LIBS = libmain libexpr libstore libutil libformat
$(eval $(call install-symlink, nix-build, $(bindir)/nix-shell))

View File

@@ -16,7 +16,6 @@
#include "get-drvs.hh"
#include "common-eval-args.hh"
#include "attr-path.hh"
#include "legacy.hh"
using namespace nix;
using namespace std::string_literals;
@@ -67,8 +66,11 @@ std::vector<string> shellwords(const string & s)
return res;
}
static void _main(int argc, char * * argv)
void mainWrapped(int argc, char * * argv)
{
initNix();
initGC();
auto dryRun = false;
auto runEnv = std::regex_search(argv[0], std::regex("nix-shell$"));
auto pure = false;
@@ -415,20 +417,16 @@ static void _main(int argc, char * * argv)
"dontAddDisableDepTrack=1; "
"[ -e $stdenv/setup ] && source $stdenv/setup; "
"%3%"
"PATH=\"%4%:$PATH\"; "
"SHELL=%5%; "
"set +e; "
R"s([ -n "$PS1" ] && PS1='\n\[\033[1;32m\][nix-shell:\w]\$\[\033[0m\] '; )s"
"if [ \"$(type -t runHook)\" = function ]; then runHook shellHook; fi; "
"unset NIX_ENFORCE_PURITY; "
"shopt -u nullglob; "
"unset TZ; %6%"
"%7%",
"unset TZ; %4%"
"%5%",
(Path) tmpDir,
(pure ? "" : "p=$PATH; "),
(pure ? "" : "PATH=$PATH:$p; unset p; "),
dirOf(shell),
shell,
(getenv("TZ") ? (string("export TZ='") + getenv("TZ") + "'; ") : ""),
envCommand));
@@ -502,5 +500,9 @@ static void _main(int argc, char * * argv)
}
}
static RegisterLegacyCommand s1("nix-build", _main);
static RegisterLegacyCommand s2("nix-shell", _main);
int main(int argc, char * * argv)
{
return handleExceptions(argv[0], [&]() {
return mainWrapped(argc, argv);
});
}

7
src/nix-channel/local.mk Normal file
View File

@@ -0,0 +1,7 @@
programs += nix-channel
nix-channel_DIR := $(d)
nix-channel_LIBS = libmain libformat libstore libutil
nix-channel_SOURCES := $(d)/nix-channel.cc

View File

@@ -1,11 +1,9 @@
#include "shared.hh"
#include "globals.hh"
#include "download.hh"
#include "store-api.hh"
#include "legacy.hh"
#include <fcntl.h>
#include <regex>
#include "store-api.hh"
#include <pwd.h>
using namespace nix;
@@ -159,9 +157,11 @@ static void update(const StringSet & channelNames)
replaceSymlink(profile, channelLink);
}
static int _main(int argc, char ** argv)
int main(int argc, char ** argv)
{
{
return handleExceptions(argv[0], [&]() {
initNix();
// Figure out the name of the `.nix-channels' file to use
auto home = getHome();
channelsList = home + "/.nix-channels";
@@ -169,7 +169,7 @@ static int _main(int argc, char ** argv)
// Figure out the name of the channels profile.
;
auto pw = getpwuid(geteuid());
auto pw = getpwuid(getuid());
std::string name = pw ? pw->pw_name : getEnv("USER", "");
if (name.empty())
throw Error("cannot figure out user name");
@@ -255,9 +255,5 @@ static int _main(int argc, char ** argv)
runProgram(settings.nixBinDir + "/nix-env", false, envArgs);
break;
}
return 0;
}
});
}
static RegisterLegacyCommand s1("nix-channel", _main);

View File

@@ -0,0 +1,7 @@
programs += nix-collect-garbage
nix-collect-garbage_DIR := $(d)
nix-collect-garbage_SOURCES := $(d)/nix-collect-garbage.cc
nix-collect-garbage_LIBS = libmain libstore libutil libformat

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