Compare commits

..

88 Commits

Author SHA1 Message Date
Graham Christensen
f66a512290 Document s3 substitutions
(cherry picked from commit b27431b7cb)
2018-08-02 08:24:47 -04:00
Eelco Dolstra
8189f754e4 Merge pull request #2313 from LnL7/no-sandbox-profile
buildenv: remove darwin sandbox profile
2018-07-31 10:34:34 +02:00
Daiderd Jordan
848ecbb5bc buildenv: remove sandbox profile
This shouldn't be necessary anymore and it breaks nix-env/nix-channel
when non 'relaxed' sandboxing is enabled.
2018-07-28 00:32:29 +02:00
Eelco Dolstra
e2ac8756ae Handle HTTP 410 Gone errors
(cherry picked from commit 691b7582c7)
2018-06-20 16:14:20 +02:00
Eelco Dolstra
811645ed01 Detect redirect loops
Fixes #2225.

(cherry picked from commit b920b90857)
2018-06-20 16:13:30 +02:00
Will Dietz
2a2b1ac083 download: improve error for hash mismatch ("store mismatch")
Fixes #1905

(cherry picked from commit 74da813912)
2018-06-20 16:13:15 +02:00
Shea Levy
300594f053 Merge pull request #2221 from 7c6f434c/doc-floats-2.0
backport: manual: builtins.fromJSON: floats
2018-06-10 11:59:20 -04:00
Michael Raskin
dbcde5f2e8 manual: builtins.fromJSON: remove the claim that floats are not allowed
floating-point numbers are supported now, including the fromJSON
builtin. Reported on IRC by inquisitiv3

(cherry picked from commit 17bc757980)
2018-06-10 16:40:53 +02:00
Shea Levy
c57948e94a Explicitly describe the effects of filterSource excluding a directory.
(cherry picked from commit bbbfc180d9)
2018-05-30 16:32:31 -04:00
Eelco Dolstra
9dc0af1116 release.nix: Generate the installer script
(cherry picked from commit 7c3c635d4f)
2018-05-30 17:45:03 +02:00
Eelco Dolstra
217768cf97 Move installer script from nixos-homepage
(cherry picked from commit 4caaa4c5fe)
2018-05-30 17:45:02 +02:00
Graham Christensen
9f820e5a09 install-multi-user: support 'set -u' runs, closes #2193
(cherry picked from commit 6ba1726eeb)
2018-05-30 17:44:42 +02:00
Graham Christensen
929152c0a8 nix-daemon.sh profile script: operate under set -u
If the profile is sourced inside a script with `set -u`, the check for
__ETC_PROFILE_NIX_SOURCED and NIX_SSL_CERT_FILE would raise an error.
A simple guard around this check allows the script to operate under
standard environments (where it is fairly reasonable to assume USER
and HOME are set.)

(cherry picked from commit d459d3307c)
2018-05-30 17:44:42 +02:00
Michael Mercier
c3a69d5c50 Explain fetchTarball timeout behavior in the doc
(cherry picked from commit 8dd2e28374)
2018-05-30 17:44:22 +02:00
Eelco Dolstra
8fff7bafa7 Bump version 2018-05-30 17:43:16 +02:00
Eelco Dolstra
47c42cd5d8 nix-shell: Only download requested outputs
Fixes #2116.

(cherry picked from commit a1adcdf087)
2018-05-29 14:18:55 +02:00
Eelco Dolstra
cf2a751a93 In restricted eval mode, allow access to the closure of store paths
E.g. this makes

  nix eval --restrict-eval -I /nix/store/foo '(builtins.readFile "/nix/store/foo/symlink/bla")'

(where /nix/store/foo/symlink is a symlink to another path in the
closure of /nix/store/foo) succeed.

This fixes a regression in Hydra compared to Nix 1.x (where there were
no restrictions at all on access to the Nix store).

(cherry picked from commit a91c4ca01f)
2018-05-29 14:18:42 +02:00
Eelco Dolstra
e96b498791 Bump version 2018-05-29 14:17:23 +02:00
Eelco Dolstra
4c1c40b4c8 Merge pull request #2183 from grahamc/omnibus-backport
Omnibus backport: #2178: doc fix for --check, #2181: MITM HTTPS proxy fix at install time
2018-05-29 13:54:48 +02:00
Graham Christensen
5f7b9243f1 Document NIX_SSL_CERT_FILE for installation 2018-05-26 12:42:54 -04:00
Graham Christensen
3d81ad8835 multi-user profile: borrow single user profiles' NIX_SSL_CERT_FILE finding logic 2018-05-26 12:42:54 -04:00
Graham Christensen
7102f8060d install-multi-user: don't force NIX_SSL_CERT_FILE
Following the lead of the single user installer, if NIX_SSL_CERT_FILE is explicitly set prior to running, accept the user-provided version.
2018-05-26 12:29:05 -04:00
Alexandre Esteves
bfcfc978b7 Fix docs on --check suffix 2018-05-26 12:29:02 -04:00
Eelco Dolstra
9d13ba6dc1 Bump version 2018-05-04 12:33:35 +02:00
Eelco Dolstra
f97e3a24ff Don't set a CA assertion for paths with references
Really fixes #2133.

(cherry picked from commit c717d8e3bd)
2018-05-03 14:50:28 +02:00
Will Dietz
686241825c build.cc: fix bind-mount of /dev/{pts,ptmx} fallback
Don't bind-mount these to themselves,
mount them into the chroot directory.

Fixes pty issues when using sandbox on CentOS 7.4.
(build of perlPackages.IOTty fails before this change)

(cherry picked from commit 6d9129014d)
2018-05-03 13:59:24 +02:00
Eelco Dolstra
8eceb32e0a LocalStore::addValidPath(): Throw error when the CA assertion is wrong
Closes #2133.

(cherry picked from commit 80a7b16593)
2018-05-03 13:59:04 +02:00
Danylo Hlynskyi
3c6dd39750 nix-collect-garbage: little doc fix
This removes confusing documentation. It's better to remove doc than add implementation, because Nix 1.12 will surely have new GC interface anyway.

Fixes https://github.com/NixOS/nix/issues/641

(cherry picked from commit ac22d77fd1)
2018-05-03 13:58:53 +02:00
Eelco Dolstra
1a67d4155f Fix bzip2 compression of files > 4 GiB
Bzip2's 'avail_in' parameter is declared as an unsigned int, so
assigning a size_t length to it led to silent truncation.

Fixes #2111.

(cherry picked from commit 4a2c948943)
2018-05-03 13:27:56 +02:00
Eelco Dolstra
444b921fcb Fix #1921
(cherry picked from commit d34fa2bcc3)
Signed-off-by: Domen Kožar <domen@dev.si>
2018-04-20 12:47:14 +01:00
Shea Levy
dab3a9d37b Export required C++ version in pkgconfig.
(cherry picked from commit a38fe5c1a8)
2018-04-20 11:13:56 +02:00
Shea Levy
51415f1004 Make prim_exec and prim_importNative available to plugins
(cherry picked from commit fd98fca7bb)
2018-04-20 11:13:56 +02:00
Eelco Dolstra
338a3cc0cb Merge pull request #2093 from grahamc/re-backport-multi-user-linux
Re backport multi user linux, but default to no daemon on Linux
2018-04-20 00:37:22 +02:00
Graham Christensen
572192ec52 installer: allow opting in / out to the daemon installer
By passing --daemon or --no-daemon, the installer can be forced to
select one or the other installation options, despite what the
automatic detection can provide.

This commit can be backported to 2.0-maintenance because it explicitly
turns off the daemon installation for Linux under systemd.

(cherry picked from commit 17b158af85)
2018-04-19 13:56:00 -04:00
Graham Christensen
fa44fa36d1 Revert "Revert "Merge pull request #2027 from grahamc/backport-linux-multi-user""
This reverts commit 4a7b3d1f4c.
2018-04-19 13:55:37 -04:00
Shea Levy
0ccf36be35 ssh-ng: Don't forward options to the daemon.
This can be iterated on and currently leaves out settings we know we
want to forward, but it fixes #1713 and fixes #1935 and isn't
fundamentally broken like the status quo. Future changes are suggested
in a comment.

(cherry picked from commit 088ef81759)
2018-04-19 11:46:25 -04:00
Eelco Dolstra
c67476fb7a Bump version to 2.0.1 2018-04-19 16:28:28 +02:00
Asad Saeeduddin
e30bd3502e Wrap thread local in function for Cygwin
Fixes #1826. See #1352 for a previous instance of a similar change.

(cherry picked from commit be54f4a0b6)
2018-04-19 16:28:07 +02:00
Eelco Dolstra
5a01ff6b47 Fix tests.evalNixOS
This failed because NixOS' release.nix calls builtins.fetchGit.

(cherry picked from commit a99027d587)
2018-04-19 16:18:59 +02:00
Eelco Dolstra
f7454db452 Remove Fedora / Ubuntu releases that are no longer in Nixpkgs
(cherry picked from commit ed87fd17dd)
2018-04-19 14:49:58 +02:00
Eelco Dolstra
497325a75d Remove some release-critical jobs
The release does not in fact depend on Ubuntu/Fedora builds (we don't
publish the build results).

(cherry picked from commit 92aee1b7d6)
2018-04-19 14:49:49 +02:00
Shea Levy
b61ea7b24e initPlugins: Fix dlopen error message.
(cherry picked from commit dc0a542c9f)
2018-04-18 17:47:59 +02:00
Eelco Dolstra
b1ade66815 Handle arguments in $EDITOR
Fixes #2079.

(cherry picked from commit a4aac7f88c)
2018-04-18 17:47:33 +02:00
Félix Baylac-Jacqué
5be4f48c2d nix repl: Fix multiline SIGINT handling.
Fixes #2076

(cherry picked from commit a91fb422fe)
2018-04-18 17:47:21 +02:00
Eelco Dolstra
effbbca812 Fix #2057
(cherry picked from commit 1839a5542a)
2018-04-11 11:47:43 +02:00
Shea Levy
f226d56d25 nix-daemon: Exit successfully when interrupted.
Fixes #2058.

(cherry picked from commit 346c0ac361)
2018-04-11 11:47:43 +02:00
Andrew Dunham
2463b4eb07 Fix missing $DESTDIR when installing programs
(cherry picked from commit f8ab9cef6c)
2018-04-11 11:47:43 +02:00
Samuel Dionne-Riel
b8a5acc203 nix-shell: Fixes use with ruby shebangs.
The ported code in 80ebc553ec was incorrectly ported.

```
-            $envCommand = "exec $execArgs $interpreter -e 'load(\"$script\")' -- ${\(join ' ', (map shellEscape, @savedArgs))}";
...
+                    envCommand = (format("exec %1% %2% -e 'load(\"%3%\") -- %4%") % execArgs % interpreter % script % joined.str()).str();
```

The single-quote finishing the small ruby snippet was lost in
translation.

(cherry picked from commit 399f43c3d5)
2018-04-11 11:47:43 +02:00
zimbatm
1e17079915 nix copy: add an example with S3
I couldn't find a good example how to use it with non-us-east-1 buckets.

(cherry picked from commit 865ca2402f)
2018-04-11 11:47:43 +02:00
Eelco Dolstra
3556a7c254 Remove reference to non-existent manpages
(cherry picked from commit 446bb88f13)
2018-04-11 11:47:43 +02:00
Eelco Dolstra
d0699defd6 Process --option use-case-hack properly
Fixes https://github.com/NixOS/nix/issues/2009.

(cherry picked from commit 2b61c74922)
2018-04-11 11:47:43 +02:00
Eelco Dolstra
247630287b ValidPathInfo::isContentAddressed(): Ensure there are no references
(cherry picked from commit 9d1220a01d)
2018-04-11 11:47:43 +02:00
Tuomas Tynkkynen
59c54f877c release.nix: Use pkgs.closureInfo for binaryTarball
pathsFromGraph is legacy since Nix 2.0.

(cherry picked from commit cc6712ae90)
2018-04-11 11:47:43 +02:00
Eelco Dolstra
4a7b3d1f4c Revert "Merge pull request #2027 from grahamc/backport-linux-multi-user"
This reverts commit a198670ab2,
reversing changes made to
a1cc741d9c. For the stable release
branch, we can't really change the fundamental behaviour of the
installer (i.e. by doing a multi-user install on Linux).
2018-04-11 11:47:43 +02:00
Shea Levy
33dc83821d Document fetchGit.
Fixes #1981.

(cherry picked from commit 6856fe62b0)
2018-04-11 11:47:43 +02:00
Dmitry Kalinkin
26bc4b9557 doc: don't mention obsolete ssh-substituter-hosts
#1840

(cherry picked from commit e2f56c1333)
2018-04-11 11:47:42 +02:00
Corey O'Connor
7a35b10ade manual: correct repeated "--deriver". Add missing single char option aliases.
(cherry picked from commit 22b144fea6)
2018-04-11 11:47:42 +02:00
Eelco Dolstra
ccb81b2622 Remove unused channel-cache directory
(cherry picked from commit 03d8136b02)
2018-04-11 11:47:42 +02:00
Eelco Dolstra
073dac149b Don't retry on CURLE_SSL_CACERT_BADFILE
The certificates won't get any better if we retry.

(cherry picked from commit eb75bc5afb)
2018-04-11 11:47:42 +02:00
Eelco Dolstra
225ae5b62a Filter ANSI colors when not writing to a terminal
Fixes https://github.com/NixOS/nixpkgs/issues/37114.

(cherry picked from commit 4868721506)
2018-04-11 11:47:42 +02:00
Will Dietz
434cdab511 nix-daemon: preserve errno in signal handler (thanks tsan)
(cherry picked from commit d98755b0c2)
2018-04-11 11:47:42 +02:00
Eelco Dolstra
ac5a36c2f3 build-remote: Don't substitute the build result
(cherry picked from commit 7afdc8d4a1)
2018-04-11 11:47:42 +02:00
Eelco Dolstra
25b24a5542 Typo
(cherry picked from commit 6e60141a80)
2018-04-11 11:47:42 +02:00
Guillaume Maudoux
4c737abe3e fetchGit: Fix debug message
(cherry picked from commit 80735c4cc9)
2018-04-11 11:47:42 +02:00
Eelco Dolstra
dd214bb087 Fix double free in Store::queryPathInfo()
It was holding on to a Value* (i.e. a std::shared_ptr<ValidPathInfo>*)
outside of the pathInfoCache lock, so the std::shared_ptr could be
destroyed between the release of the lock and the decrement of the
std::shared_ptr refcount. This can happen if more than
'path-info-cache-size' paths are added in the meantime, *or* if
clearPathInfoCache() is called. The hydra-queue-runner queue monitor
thread periodically calls the later, so is likely to trigger a crash.

Fixes https://github.com/NixOS/hydra/issues/542.

(cherry picked from commit 24b739817f)
2018-04-11 11:47:42 +02:00
Eelco Dolstra
d306287abd Fix #1957
(cherry picked from commit 16551f54c9)
2018-04-11 11:47:41 +02:00
Will Dietz
33bfcbdbdd release.nix: don't try to use nix-2.0 branch, no longer exists
Probably should point at the 18.03 release branch once that's made.

(cherry picked from commit e9a5ce9b07)
2018-04-11 11:47:41 +02:00
Eelco Dolstra
2bbea0d96f Fix error message
(cherry picked from commit 939cf4cceb)
2018-04-11 11:47:41 +02:00
Michael Fiano
d64618de01 nix-channel grammar and punctuation
Minor changes to the nix-channel manpage for my first contribution

(cherry picked from commit ad97d1a786)
2018-04-11 11:47:41 +02:00
Will Dietz
5df25a35b7 fetchGit: use "HEAD" as default ref
(cherry picked from commit e89d02bf03)
2018-04-11 11:47:41 +02:00
Shea Levy
7e989da790 Actually fix nixDataDir in non-canonical path
(cherry picked from commit 14ca85688c)
2018-04-11 11:47:41 +02:00
Tuomas Tynkkynen
77a2cd2f5e libexpr: Fix prim_replaceStrings() to work on an empty source string
Otherwise, running e.g.

nix-instantiate --eval -E --strict 'builtins.replaceStrings [""] ["X"] "abc"'

would just hang in an infinite loop.

Found by afl-fuzz.

First attempt of this was reverted in e2d71bd186 because it caused
another infinite loop, which is fixed now and a test added.

(cherry picked from commit 77e9e1ed91)
2018-04-11 11:47:41 +02:00
Eelco Dolstra
d0665a22cc nix run: Fix segfault on macOS
Note that clearenv() is not available on macOS.

Fixes #1907.

(cherry picked from commit 24ec750003)
2018-04-11 11:47:41 +02:00
Will Dietz
bdd88cabd3 nix search: explicitly handle empty search string, fixes #1893
This is important since this is given as an example.
Other patterns containing "empty search string" will still
be handled differently on different platforms ("asdf|")
but that's less of an issue.

(cherry picked from commit 009cf9cd23)
2018-04-11 11:47:41 +02:00
Will Dietz
e9c5be6fe7 nix search: fix bug where we wrote to cache when shouldn't, breaking
This is exposed by the tests added previously,
and resolves the error reported in #1892:
"expected JSON value".

(cherry picked from commit 3cac8734ac)
2018-04-11 11:47:41 +02:00
Eelco Dolstra
0995763eb1 Fix downloadCached() with a chroot store
E.g.

  nix run --store ~/my-nix -f channel:nixos-17.03 hello -c hello

This problem was mentioned in #1897.

(cherry picked from commit 64e486ab63)
2018-04-11 11:47:41 +02:00
Eelco Dolstra
741a9e9ec3 Fix example in release notes
(cherry picked from commit 39b4177500)
2018-04-11 11:47:40 +02:00
Eelco Dolstra
af81bb7845 Doh
(cherry picked from commit 2691d51a33)
2018-04-11 11:47:40 +02:00
Linus Heckemann
3b9eb5385f Fix #1762
nix-store --export, nix-store --dump, and nix dump-path would previously
fail silently if writing the data out failed, because
 a) FdSink::write ignored exceptions, and
 b) the commands relied on FdSink's destructor, which ignores
    exceptions, to flush the data out.

This could cause rather opaque issues with installing nixos, because
nix-store --export would happily proceed even if it couldn't write its
data out (e.g. if nix-store --import on the other side of the pipe
failed).

This commit adds tests that expose these issues in the nix-store
commands, and fixes them for all three.

(cherry picked from commit 78ac3eb4eb)
2018-04-11 11:47:40 +02:00
Daniel Peebles
d8141deebe Merge pull request #2067 from LnL7/darwin-daemon-keepalive
launchd: enable keepalive for the nix-daemon service
2018-04-10 15:39:12 -04:00
Daiderd Jordan
3cc790bd20 launchd: enable keepalive for the nix-daemon service
Without this the daemon won't be restarted if the process ever dies, for
example when sending a SIGHUP to reload nix.conf.

(cherry picked from commit 05cb8e5c5a)
2018-04-10 21:35:51 +02:00
Graham Christensen
a198670ab2 Merge pull request #2027 from grahamc/backport-linux-multi-user
Backport #2026: Expand the multi-user installer to support Linuxes with systemd
2018-03-30 16:04:17 -04:00
Graham Christensen
b037be7e33 macos: Handle when a build user doesn't have a user ID
(cherry picked from commit 4eb40c72ed)
2018-03-30 15:17:03 -04:00
Graham Christensen
985f0dafe8 Use a looser comparison for the 'user note' check
We use grep instead of an equality check because it is difficult
to extract _just_ the user's note, instead it is prefixed with
some plist junk. This was causing the user note to always be set,
even if there was no reason for it.

(cherry picked from commit f06f8102bd)
2018-03-30 15:17:03 -04:00
Graham Christensen
1b493df892 Check for the existence of a profile target before seeing if it mentions Nix
Grep would ignore files that didn't exist, but would complain
about files in a directory if the directory didn't exist. Simply check
for the directory first, prior to grepping it.

(cherry picked from commit 4ba91f5bae)
2018-03-30 15:17:03 -04:00
Graham Christensen
fb6a41a227 Expand the multi-user installer to support Linuxes with systemd
- darwin installer: delete hardware report, not necessary
 - moves os-specific code from the darwin installer to to `poly_*`
   functions
 - adds profile.d support to the profile targets, which automatically
   handles many distros which don't have a /etc/bashrc but do have an
   /etc/profile.d
 - /bin/bash -> /usr/bin/env bash
 - document why each excluded shellcheck check is excluded
 - rename the multi-user to Daemon-based

(cherry picked from commit 2921165a9d)
2018-03-30 15:16:59 -04:00
Dmitry Kalinkin
a1cc741d9c Fix a small typo in the release notes
(cherry picked from commit d9d8a84a96)
2018-02-24 10:26:27 -05:00
Michael Weiss
bc0899dcc1 doc: Fix a URL in the release notes for Nix 2.0
(cherry picked from commit bd94e63853)
2018-02-24 10:22:47 -05:00
242 changed files with 14514 additions and 19508 deletions

6
.gitignore vendored
View File

@@ -13,6 +13,9 @@ perl/Makefile.config
/corepkgs/config.nix
# /corepkgs/buildenv/
/corepkgs/buildenv/builder.pl
# /corepkgs/channels/
/corepkgs/channels/unpack.sh
@@ -69,6 +72,9 @@ perl/Makefile.config
# /src/nix-channel/
/src/nix-channel/nix-channel
# /src/buildenv/
/src/buildenv/buildenv
# /src/nix-build/
/src/nix-build/nix-build

View File

@@ -1,11 +1,23 @@
makefiles = \
local.mk \
src/boost/format/local.mk \
src/libutil/local.mk \
src/libstore/local.mk \
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/buildenv/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 \
@@ -15,7 +27,7 @@ makefiles = \
tests/local.mk \
tests/plugins/local.mk
GLOBAL_CXXFLAGS += -g -Wall -include config.h
GLOBAL_CXXFLAGS += -std=c++14 -g -Wall -include config.h
-include Makefile.config

View File

@@ -6,6 +6,7 @@ CXXFLAGS = @CXXFLAGS@
ENABLE_S3 = @ENABLE_S3@
HAVE_SODIUM = @HAVE_SODIUM@
HAVE_READLINE = @HAVE_READLINE@
HAVE_BROTLI = @HAVE_BROTLI@
HAVE_SECCOMP = @HAVE_SECCOMP@
LIBCURL_LIBS = @LIBCURL_LIBS@
OPENSSL_LIBS = @OPENSSL_LIBS@
@@ -15,9 +16,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@

983
config/config.guess vendored

File diff suppressed because it is too large Load Diff

1976
config/config.sub vendored

File diff suppressed because it is too large Load Diff

View File

@@ -62,7 +62,7 @@ CXXFLAGS=
AC_PROG_CC
AC_PROG_CXX
AC_PROG_CPP
AX_CXX_COMPILE_STDCXX_14
AX_CXX_COMPILE_STDCXX_11
# Use 64-bit file system calls so that we can support files > 2 GiB.
@@ -127,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)
@@ -150,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.
@@ -162,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],
@@ -179,9 +179,12 @@ AC_CHECK_LIB([lzma], [lzma_stream_encoder_mt],
[AC_DEFINE([HAVE_LZMA_MT], [1], [xz multithreaded compression support])])
# Look for libbrotli{enc,dec}.
PKG_CHECK_MODULES([LIBBROTLI], [libbrotlienc libbrotlidec], [CXXFLAGS="$LIBBROTLI_CFLAGS $CXXFLAGS"])
# Look for libbrotli{enc,dec}, optional dependencies
PKG_CHECK_MODULES([LIBBROTLI], [libbrotlienc libbrotlidec],
[AC_DEFINE([HAVE_BROTLI], [1], [Whether to use libbrotli.])
CXXFLAGS="$LIBBROTLI_CFLAGS $CXXFLAGS"]
have_brotli=1], [have_brotli=])
AC_SUBST(HAVE_BROTLI, [$have_brotli])
# Look for libseccomp, required for Linux sandboxing.
if test "$sys_name" = linux; then
@@ -212,7 +215,7 @@ AC_SUBST(ENABLE_S3, [$enable_s3])
AC_LANG_POP(C++)
if test -n "$enable_s3"; then
declare -a aws_version_tokens=($(printf '#include <aws/core/VersionConfig.h>\nAWS_SDK_VERSION_STRING' | $CPP $CPPFLAGS - | grep -v '^#.*' | sed 's/"//g' | tr '.' ' '))
declare -a aws_version_tokens=($(printf '#include <aws/core/VersionConfig.h>\nAWS_SDK_VERSION_STRING' | $CPP - | grep -v '^#.*' | sed 's/"//g' | tr '.' ' '))
AC_DEFINE_UNQUOTED([AWS_VERSION_MAJOR], ${aws_version_tokens@<:@0@:>@}, [Major version of aws-sdk-cpp.])
AC_DEFINE_UNQUOTED([AWS_VERSION_MINOR], ${aws_version_tokens@<:@1@:>@}, [Minor version of aws-sdk-cpp.])
fi
@@ -229,6 +232,12 @@ if test "$gc" = yes; then
fi
AC_ARG_ENABLE(init-state, AC_HELP_STRING([--disable-init-state],
[do not initialise DB etc. in `make install']),
init_state=$enableval, init_state=yes)
#AM_CONDITIONAL(INIT_STATE, test "$init_state" = "yes")
# documentation generation switch
AC_ARG_ENABLE(doc-gen, AC_HELP_STRING([--disable-doc-gen],
[disable documentation generation]),
@@ -251,6 +260,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

View File

@@ -1,9 +1,11 @@
with import <nix/config.nix>;
{ derivations, manifest }:
derivation {
name = "user-environment";
system = "builtin";
builder = "builtin:buildenv";
system = builtins.currentSystem;
builder = nixLibexecDir + "/nix/buildenv";
inherit manifest;
@@ -22,4 +24,6 @@ derivation {
# Also don't bother substituting.
allowSubstitutes = false;
inherit chrootDeps;
}

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

@@ -1,7 +1,6 @@
<part xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xml:id="part-advanced-topics"
version="5.0">
<title>Advanced Topics</title>

View File

@@ -81,7 +81,6 @@ or a newline, e.g.
<para>Each machine specification consists of the following elements,
separated by spaces. Only the first element is required.
To leave a field at its default, set it to <literal>-</literal>.
<orderedlist>

View File

@@ -123,7 +123,7 @@ false</literal>.</para>
</varlistentry>
<varlistentry xml:id="conf-auto-optimise-store"><term><literal>auto-optimise-store</literal></term>
<varlistentry><term><literal>auto-optimise-store</literal></term>
<listitem><para>If set to <literal>true</literal>, Nix
automatically detects files in the store that have identical
@@ -135,6 +135,7 @@ false</literal>.</para>
</varlistentry>
<varlistentry xml:id="conf-builders">
<term><literal>builders</literal></term>
<listitem>
@@ -145,7 +146,7 @@ false</literal>.</para>
</varlistentry>
<varlistentry xml:id="conf-builders-use-substitutes"><term><literal>builders-use-substitutes</literal></term>
<varlistentry><term><literal>builders-use-substitutes</literal></term>
<listitem><para>If set to <literal>true</literal>, Nix will instruct
remote build machines to use their own binary substitutes if available. In
@@ -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
@@ -199,7 +201,7 @@ false</literal>.</para>
</varlistentry>
<varlistentry xml:id="conf-compress-build-log"><term><literal>compress-build-log</literal></term>
<varlistentry><term><literal>compress-build-log</literal></term>
<listitem><para>If set to <literal>true</literal> (the default),
build logs written to <filename>/nix/var/log/nix/drvs</filename>
@@ -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>
@@ -250,26 +254,7 @@ false</literal>.</para>
</varlistentry>
<varlistentry xml:id="conf-extra-platforms"><term><literal>extra-platforms</literal></term>
<listitem><para>Platforms other than the native one which
this machine is capable of building for. This can be useful for
supporting additional architectures on compatible machines:
i686-linux can be built on x86_64-linux machines (and the default
for this setting reflects this); armv7 is backwards-compatible with
armv6 and armv5tel; some aarch64 machines can also natively run
32-bit ARM code; and qemu-user may be used to support non-native
platforms (though this may be slow and buggy). Most values for this
are not enabled by default because build systems will often
misdetect the target platform and generate incompatible code, so you
may wish to cross-check the results of using this option against
proper natively-built versions of your
derivations.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-extra-substituters"><term><literal>extra-substituters</literal></term>
<varlistentry><term><literal>extra-substituters</literal></term>
<listitem><para>Additional binary caches appended to those
specified in <option>substituters</option>. When used by
@@ -279,7 +264,8 @@ false</literal>.</para>
</varlistentry>
<varlistentry xml:id="conf-fallback"><term><literal>fallback</literal></term>
<varlistentry><term><literal>fallback</literal></term>
<listitem><para>If set to <literal>true</literal>, Nix will fall
back to building from source if a binary substitute fails. This
@@ -288,7 +274,8 @@ false</literal>.</para>
</varlistentry>
<varlistentry xml:id="conf-fsync-metadata"><term><literal>fsync-metadata</literal></term>
<varlistentry><term><literal>fsync-metadata</literal></term>
<listitem><para>If set to <literal>true</literal>, changes to the
Nix store metadata (in <filename>/nix/var/nix/db</filename>) are
@@ -298,6 +285,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
@@ -326,7 +314,7 @@ builtins.fetchurl {
</varlistentry>
<varlistentry xml:id="conf-http-connections"><term><literal>http-connections</literal></term>
<varlistentry><term><literal>http-connections</literal></term>
<listitem><para>The maximum number of parallel TCP connections
used to fetch files from binary caches and by other downloads. It
@@ -335,7 +323,7 @@ builtins.fetchurl {
</varlistentry>
<varlistentry xml:id="conf-keep-build-log"><term><literal>keep-build-log</literal></term>
<varlistentry><term><literal>keep-build-log</literal></term>
<listitem><para>If set to <literal>true</literal> (the default),
Nix will write the build log of a derivation (i.e. the standard
@@ -360,9 +348,11 @@ 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>
<varlistentry><term><literal>keep-env-derivations</literal></term>
<listitem><para>If <literal>false</literal> (default), derivations
are not stored in Nix user environments. That is, the derivation
@@ -385,6 +375,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 +389,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>
@@ -413,27 +406,20 @@ builtins.fetchurl {
</varlistentry>
<varlistentry xml:id="conf-max-free"><term><literal>max-free</literal></term>
<listitem><para>This option defines after how many free bytes to stop collecting
garbage once the <literal>min-free</literal> condition gets triggered.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-max-jobs"><term><literal>max-jobs</literal></term>
<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>
@@ -454,48 +440,8 @@ builtins.fetchurl {
</varlistentry>
<varlistentry xml:id="conf-min-free"><term><literal>min-free</literal></term>
<listitem>
<para>When the disk reaches <literal>min-free</literal> bytes of free disk space during a build, nix
will start to garbage-collection until <literal>max-free</literal> bytes are available on the disk.
A value of <literal>0</literal> (the default) means that this feature is disabled.</para>
</listitem>
</varlistentry>
<varlistentry xml:id="conf-narinfo-cache-negative-ttl"><term><literal>narinfo-cache-negative-ttl</literal></term>
<listitem>
<para>The TTL in seconds for negative lookups. If a store path is
queried from a substituter but was not found, there will be a
negative lookup cached in the local disk cache database for the
specified duration.</para>
</listitem>
</varlistentry>
<varlistentry xml:id="conf-narinfo-cache-positive-ttl"><term><literal>narinfo-cache-positive-ttl</literal></term>
<listitem>
<para>The TTL in seconds for positive lookups. If a store path is
queried from a substituter, the result of the query will be cached
in the local disk cache database including some of the NAR
metadata. The default TTL is a month, setting a shorter TTL for
positive lookups can be useful for binary caches that have
frequent garbage collection, in which case having a more frequent
cache invalidation would prevent trying to pull the path again and
failing with a hash mismatch if the build isn't reproducible.
</para>
</listitem>
</varlistentry>
<varlistentry xml:id="conf-netrc-file"><term><literal>netrc-file</literal></term>
<varlistentry><term><literal>netrc-file</literal></term>
<listitem><para>If set to an absolute path to a <filename>netrc</filename>
file, Nix will use the HTTP authentication credentials in this file when
@@ -513,12 +459,7 @@ password <replaceable>my-password</replaceable>
For the exact syntax, see <link
xlink:href="https://ec.haxx.se/usingcurl-netrc.html">the
<literal>curl</literal> documentation.</link></para>
<note><para>This must be an absolute path, and <literal>~</literal>
is not resolved. For example, <filename>~/.netrc</filename> won't
resolve to your home directory's <filename>.netrc</filename>.</para></note>
</listitem>
<literal>curl</literal> documentation.</link></para></listitem>
</varlistentry>
@@ -554,6 +495,7 @@ password <replaceable>my-password</replaceable>
</varlistentry>
<varlistentry xml:id="conf-pre-build-hook"><term><literal>pre-build-hook</literal></term>
<listitem>
@@ -589,6 +531,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,7 +543,8 @@ password <replaceable>my-password</replaceable>
</varlistentry>
<varlistentry xml:id="conf-require-sigs"><term><literal>require-sigs</literal></term>
<varlistentry><term><literal>require-sigs</literal></term>
<listitem><para>If set to <literal>true</literal> (the default),
any non-content-addressed path added or copied to the Nix store
@@ -629,7 +573,7 @@ password <replaceable>my-password</replaceable>
</varlistentry>
<varlistentry xml:id="conf-sandbox"><term><literal>sandbox</literal></term>
<varlistentry><term><literal>sandbox</literal></term>
<listitem><para>If set to <literal>true</literal>, builds will be
performed in a <emphasis>sandboxed environment</emphasis>, i.e.,
@@ -663,6 +607,7 @@ password <replaceable>my-password</replaceable>
</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
@@ -699,7 +644,7 @@ password <replaceable>my-password</replaceable>
</varlistentry>
<varlistentry xml:id="conf-secret-key-files"><term><literal>secret-key-files</literal></term>
<varlistentry><term><literal>secret-key-files</literal></term>
<listitem><para>A whitespace-separated list of files containing
secret (private) keys. These are used to sign locally-built
@@ -720,7 +665,7 @@ password <replaceable>my-password</replaceable>
</varlistentry>
<varlistentry xml:id="conf-substitute"><term><literal>substitute</literal></term>
<varlistentry><term><literal>substitute</literal></term>
<listitem><para>If set to <literal>true</literal> (default), Nix
will use binary substitutes if available. This option can be
@@ -728,7 +673,8 @@ password <replaceable>my-password</replaceable>
</varlistentry>
<varlistentry xml:id="conf-substituters"><term><literal>substituters</literal></term>
<varlistentry><term><literal>substituters</literal></term>
<listitem><para>A list of URLs of substituters, separated by
whitespace. The default is
@@ -736,7 +682,8 @@ password <replaceable>my-password</replaceable>
</varlistentry>
<varlistentry xml:id="conf-system"><term><literal>system</literal></term>
<varlistentry><term><literal>system</literal></term>
<listitem><para>This option specifies the canonical Nix system
name of the current installation, such as
@@ -757,33 +704,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>
@@ -803,7 +723,8 @@ requiredSystemFeatures = [ "kvm" ];
</varlistentry>
<varlistentry xml:id="conf-trusted-public-keys"><term><literal>trusted-public-keys</literal></term>
<varlistentry><term><literal>trusted-public-keys</literal></term>
<listitem><para>A whitespace-separated list of public keys. When
paths are copied from another Nix store (such as a binary cache),
@@ -813,7 +734,8 @@ requiredSystemFeatures = [ "kvm" ];
</varlistentry>
<varlistentry xml:id="conf-trusted-substituters"><term><literal>trusted-substituters</literal></term>
<varlistentry><term><literal>trusted-substituters</literal></term>
<listitem><para>A list of URLs of substituters, separated by
whitespace. These are not used by default, but can be enabled by
@@ -825,6 +747,7 @@ requiredSystemFeatures = [ "kvm" ];
</varlistentry>
<varlistentry xml:id="conf-trusted-users"><term><literal>trusted-users</literal></term>
<listitem>
@@ -849,179 +772,11 @@ 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

@@ -456,7 +456,7 @@ $ nix-env -f ~/foo.nix -i '.*'</screen>
from another profile:
<screen>
$ nix-env -i --from-profile /nix/var/nix/profiles/foo gcc</screen>
$ nix-env -i --from-profile /nix/var/nix/profiles/foo -i gcc</screen>
</para>
@@ -1346,12 +1346,11 @@ $ nix-env --list-generations
<para>This operation deletes the specified generations of the current
profile. The generations can be a list of generation numbers, the
special value <literal>old</literal> to delete all non-current
generations, a value such as <literal>30d</literal> to delete all
generations, or a value such as <literal>30d</literal> to delete all
generations older than the specified number of days (except for the
generation that was active at that point in time), or a value such as.
<literal>+5</literal> to only keep the specified items older than the
current generation. Periodically deleting old generations is important
to make garbage collection effective.</para>
generation that was active at that point in time).
Periodically deleting old generations is important to make garbage
collection effective.</para>
</refsection>
@@ -1360,8 +1359,6 @@ to make garbage collection effective.</para>
<screen>
$ nix-env --delete-generations 3 4 8
$ nix-env --delete-generations +5
$ nix-env --delete-generations 30d
$ nix-env -p other_profile --delete-generations old</screen>
@@ -1461,7 +1458,7 @@ error: no generation older than the current (91) exists</screen>
<refsection condition="manpage"><title>Environment variables</title>
<variablelist>
<varlistentry><term><envar>NIX_PROFILE</envar></term>
<listitem><para>Location of the Nix profile. Defaults to the
@@ -1475,6 +1472,6 @@ error: no generation older than the current (91) exists</screen>
</variablelist>
</refsection>
</refentry>

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

@@ -32,7 +32,6 @@
<arg><option>--run</option> <replaceable>cmd</replaceable></arg>
<arg><option>--exclude</option> <replaceable>regexp</replaceable></arg>
<arg><option>--pure</option></arg>
<arg><option>--keep</option> <replaceable>name</replaceable></arg>
<group choice='req'>
<arg choice='plain'>
<group choice='req'>
@@ -166,13 +165,6 @@ also <xref linkend="sec-common-options" />.</phrase></para>
</listitem></varlistentry>
<varlistentry><term><option>--keep</option> <replaceable>name</replaceable></term>
<listitem><para>When a <option>--pure</option> shell is started,
keep the listed environment variables.</para></listitem>
</varlistentry>
</variablelist>
<para>The following common options are supported:</para>
@@ -317,28 +309,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:
<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):
<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 runghc -p haskellPackages.ghc haskellPackages.HTTP haskellPackages.tagsoup
#! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/nixos-18.03.tar.gz
#! 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>

View File

@@ -8,9 +8,6 @@
<arg choice='plain'><option>-v</option></arg>
</group>
</arg>
<arg>
<arg choice='plain'><option>--quiet</option></arg>
</arg>
<arg>
<group choice='plain'>
<arg choice='plain'><option>--no-build-output</option></arg>

View File

@@ -75,23 +75,6 @@
</varlistentry>
<varlistentry><term><option>--quiet</option></term>
<listitem>
<para>Decreases the level of verbosity of diagnostic messages
printed on standard error. This is the inverse option to
<option>-v</option> / <option>--verbose</option>.
</para>
<para>This option may be specified repeatedly. See the previous
verbosity levels list.</para>
</listitem>
</varlistentry>
<varlistentry><term><option>--no-build-output</option> / <option>-Q</option></term>
<listitem><para>By default, output written by builders to standard

View File

@@ -50,40 +50,6 @@ allowedRequisites = [ foobar ];
</varlistentry>
<varlistentry><term><varname>disallowedReferences</varname></term>
<listitem><para>The optional attribute
<varname>disallowedReferences</varname> specifies a list of illegal
references (dependencies) of the output of the builder. For
example,
<programlisting>
disallowedReferences = [ foo ];
</programlisting>
enforces that the output of a derivation cannot have a direct runtime
dependencies on the derivation <varname>foo</varname>.</para></listitem>
</varlistentry>
<varlistentry><term><varname>disallowedRequisites</varname></term>
<listitem><para>This attribute is similar to
<varname>disallowedReferences</varname>, but it specifies illegal
requisites for the whole closure, so all the dependencies
recursively. For example,
<programlisting>
disallowedRequisites = [ foobar ];
</programlisting>
enforces that the output of a derivation cannot have any
runtime dependency on <varname>foobar</varname> or any other derivation
depending recursively on <varname>foobar</varname>.</para></listitem>
</varlistentry>
<varlistentry><term><varname>exportReferencesGraph</varname></term>
@@ -146,13 +112,7 @@ impureEnvVars = [ "http_proxy" "https_proxy" <replaceable>...</replaceable> ];
linkend="fixed-output-drvs">fixed-output derivations</link>, where
impurities such as these are okay since (the hash of) the output
is known in advance. It is ignored for all other
derivations.</para>
<warning><para><varname>impureEnvVars</varname> implementation takes
environment variables from the current builder process. When a daemon is
building its environmental variables are used. Without the daemon, the
environmental variables come from the environment of the
<command>nix-build</command>.</para></warning></listitem>
derivations.</para></listitem>
</varlistentry>
@@ -216,7 +176,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 +184,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 +197,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 +211,7 @@ stdenv.mkDerivation {
<listitem><para>The output must be a non-executable regular
file. If it isn’t, the build fails. The hash is simply
computed over the contents of that file (so it’s 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 +272,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 +284,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,41 +92,7 @@ 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>
<listitem><para>Return the bitwise AND of the integers
<replaceable>e1</replaceable> and
<replaceable>e2</replaceable>.</para></listitem>
</varlistentry>
<varlistentry xml:id='builtin-bitOr'>
<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
<replaceable>e2</replaceable>.</para></listitem>
</varlistentry>
<varlistentry xml:id='builtin-bitXor'>
<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
<replaceable>e2</replaceable>.</para></listitem>
</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 +109,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 +126,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 +137,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 +154,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 +188,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 +201,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 +210,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 +220,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 +229,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 +240,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 +251,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 +262,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 +316,7 @@ stdenv.mkDerivation { … }
</varlistentry>
<varlistentry xml:id='builtin-fetchGit'>
<varlistentry>
<term>
<function>builtins.fetchGit</function>
<replaceable>args</replaceable>
@@ -428,84 +368,6 @@ stdenv.mkDerivation { … }
</listitem>
</varlistentry>
</variablelist>
<example>
<title>Fetching a private repository over SSH</title>
<programlisting>builtins.fetchGit {
url = "git@github.com:my-secret/repository.git";
ref = "master";
rev = "adab8b916a45068c044658c4158d81878f9ed1c3";
}</programlisting>
</example>
<example>
<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
the branch name in the <varname>ref</varname> attribute.
</para>
<para>
However, if the revision you're looking for is in a future
branch for the non-default branch you will need to specify
the the <varname>ref</varname> attribute as well.
</para>
<programlisting>builtins.fetchGit {
url = "https://github.com/nixos/nix.git";
rev = "841fcbd04755c7a2865c51c1e2d3b045976b7452";
ref = "1.11-maintenance";
}</programlisting>
<note>
<para>
It is nice to always specify the branch which a revision
belongs to. Without the branch being specified, the
fetcher might fail if the default branch changes.
Additionally, it can be confusing to try a commit from a
non-default branch and see the fetch fail. If the branch
is specified the fault is much more obvious.
</para>
</note>
</example>
<example>
<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
<varname>ref</varname> attribute.
</para>
<programlisting>builtins.fetchGit {
url = "https://github.com/nixos/nix.git";
rev = "841fcbd04755c7a2865c51c1e2d3b045976b7452";
}</programlisting>
</example>
<example>
<title>Fetching a tag</title>
<programlisting>builtins.fetchGit {
url = "https://github.com/nixos/nix.git";
ref = "tags/1.9";
}</programlisting>
<note><para>Due to a bug (<link
xlink:href="https://github.com/NixOS/nix/issues/2385">#2385</link>),
only non-annotated tags can be fetched.</para></note>
</example>
<example>
<title>Fetching the latest version of a remote branch</title>
<para>
<function>builtins.fetchGit</function> can behave impurely
fetch the latest version of a remote branch.
</para>
<note><para>Nix will refetch the branch in accordance to
<option>tarball-ttl</option>.</para></note>
<note><para>This behavior is disabled in
<emphasis>Pure evaluation mode</emphasis>.</para></note>
<programlisting>builtins.fetchGit {
url = "ssh://git@github.com/nixos/nix.git";
ref = "master";
}</programlisting>
</example>
</listitem>
</varlistentry>
@@ -576,8 +438,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 +451,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 +469,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 +484,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 +502,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 +515,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 +533,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,9 +547,8 @@ 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
@@ -705,9 +559,8 @@ builtins.genList (x: x * x) 5
</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 isn’t a list or is an empty list. You
@@ -717,11 +570,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 +625,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 +635,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 +645,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 +655,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 +665,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 +675,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 +685,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 +695,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
@@ -862,11 +705,8 @@ x: x + 456</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-isNull'>
<term><function>isNull</function>
<replaceable>e</replaceable></term>
<term><function>builtins.isNull</function>
<replaceable>e</replaceable></term>
<varlistentry><term><function>isNull</function>
<replaceable>e</replaceable></term>
<listitem><para>Return <literal>true</literal> if
<replaceable>e</replaceable> evaluates to <literal>null</literal>,
@@ -880,9 +720,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>
@@ -890,9 +729,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
@@ -904,9 +742,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
@@ -932,11 +769,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
@@ -951,15 +785,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"
@@ -985,12 +818,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
@@ -999,9 +831,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
@@ -1014,7 +845,7 @@ Evaluates to <literal>[ "foo" ]</literal>.
</varlistentry>
<varlistentry xml:id='builtin-path'>
<varlistentry>
<term>
<function>builtins.path</function>
<replaceable>args</replaceable>
@@ -1084,20 +915,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
@@ -1118,9 +961,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>
@@ -1128,11 +970,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
@@ -1147,9 +986,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>
@@ -1165,9 +1003,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
@@ -1177,9 +1014,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
@@ -1201,16 +1037,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"
@@ -1236,12 +1071,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
@@ -1250,9 +1084,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
@@ -1261,10 +1094,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
@@ -1287,9 +1119,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 isn’t a list or is an empty
@@ -1298,11 +1129,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
@@ -1315,10 +1143,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
@@ -1386,16 +1213,12 @@ in foo</programlisting>
This is not allowed because it would cause a cyclic dependency in
the computation of the cryptographic hashes for
<varname>foo</varname> and <varname>bar</varname>.</para>
<para>It is also not possible to reference the result of a derivation.
If you are using Nixpkgs, the <literal>writeTextFile</literal> function is able to
do that.</para></listitem>
<varname>foo</varname> and <varname>bar</varname>.</para></listitem>
</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,
@@ -1408,20 +1231,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.
@@ -1440,8 +1263,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
@@ -1497,7 +1319,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[
@@ -1556,9 +1378,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
@@ -1567,9 +1388,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>
@@ -1582,9 +1402,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

@@ -41,7 +41,7 @@ encountered</quote>).</para></footnote>.</para>
</simplesect>
<simplesect xml:id="sect-let-expressions"><title>Let-expressions</title>
<simplesect><title>Let-expressions</title>
<para>A let-expression allows you define local variables for an
expression. For instance,

View File

@@ -1,6 +1,5 @@
<appendix xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xml:id="part-glossary">
xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Glossary</title>
@@ -86,48 +85,29 @@
<glossentry xml:id="gloss-reference"><glossterm>reference</glossterm>
<glossdef>
<para>A store path <varname>P</varname> is said to have a
reference to a store path <varname>Q</varname> if the store object
at <varname>P</varname> contains the path <varname>Q</varname>
somewhere. The <emphasis>references</emphasis> of a store path are
the set of store paths to which it has a reference.
</para>
<para>A derivation can reference other derivations and sources
(but not output paths), whereas an output path only references other
output paths.
</para>
</glossdef>
<glossdef><para>A store path <varname>P</varname> is said to have a
reference to a store path <varname>Q</varname> if the store object
at <varname>P</varname> contains the path <varname>Q</varname>
somewhere. This implies than an execution involving
<varname>P</varname> potentially needs <varname>Q</varname> to be
present. The <emphasis>references</emphasis> of a store path are
the set of store paths to which it has a reference.</para></glossdef>
</glossentry>
<glossentry xml:id="gloss-reachable"><glossterm>reachable</glossterm>
<glossdef><para>A store path <varname>Q</varname> is reachable from
another store path <varname>P</varname> if <varname>Q</varname> is in the
<link linkend="gloss-closure">closure</link> of the
<link linkend="gloss-reference">references</link> relation.
</para></glossdef>
</glossentry>
<glossentry xml:id="gloss-closure"><glossterm>closure</glossterm>
<glossdef><para>The closure of a store path is the set of store
paths that are directly or indirectly “reachable” from that store
path; that is, it’s the closure of the path under the <link
linkend="gloss-reference">references</link> relation. For a package, the
closure of its derivation is equivalent to the build-time
dependencies, while the closure of its output path is equivalent to its
runtime dependencies. For correct deployment it is necessary to deploy whole
closures, since otherwise at runtime files could be missing. The command
<command>nix-store -qR</command> prints out closures of store paths.
</para>
<para>As an example, if the store object at path <varname>P</varname> contains
a reference to path <varname>Q</varname>, then <varname>Q</varname> is
in the closure of <varname>P</varname>. Further, if <varname>Q</varname>
references <varname>R</varname> then <varname>R</varname> is also in
the closure of <varname>P</varname>.
</para></glossdef>
linkend="gloss-reference">references</link> relation. For instance,
if the store object at path <varname>P</varname> contains a
reference to path <varname>Q</varname>, then <varname>Q</varname> is
in the closure of <varname>P</varname>. For correct deployment it
is necessary to deploy whole closures, since otherwise at runtime
files could be missing. The command <command>nix-store
-qR</command> prints out closures of store paths.</para></glossdef>
</glossentry>
@@ -167,7 +147,7 @@
linkend="sec-profiles" />.</para>
</glossdef>
</glossentry>

View File

@@ -30,7 +30,7 @@ To build Nix itself in this shell:
[nix-shell]$ configurePhase
[nix-shell]$ make
</screen>
To install it in <literal>$(pwd)/inst</literal> and test it:
To install it in <literal>$(pwd)/nix</literal> and test it:
<screen>
[nix-shell]$ make install
[nix-shell]$ make installcheck

View File

@@ -39,7 +39,7 @@ bundle.</para>
<step><para>Set the environment variable and install Nix</para>
<screen>
$ export NIX_SSL_CERT_FILE=/etc/ssl/my-certificate-bundle.crt
$ sh &lt;(curl https://nixos.org/nix/install)
$ curl https://nixos.org/nix/install | sh
</screen></step>
<step><para>In the shell profile and rc files (for example,
@@ -55,7 +55,7 @@ export NIX_SSL_CERT_FILE=/etc/ssl/my-certificate-bundle.crt
the Nix installer will detect the presense of Nix configuration, and
abort.</para></note>
<section xml:id="sec-nix-ssl-cert-file-with-nix-daemon-and-macos">
<section>
<title><envar>NIX_SSL_CERT_FILE</envar> with macOS and the Nix daemon</title>
<para>On macOS you must specify the environment variable for the Nix

View File

@@ -6,30 +6,13 @@
<title>Installing a Binary Distribution</title>
<para>If you are using Linux or macOS, the easiest way to install Nix
is to run the following command:
<para>If you are using Linux or macOS, the easiest way to install
Nix is to run the following command:
<screen>
$ sh &lt;(curl https://nixos.org/nix/install)
$ bash &lt;(curl https://nixos.org/nix/install)
</screen>
As of Nix 2.1.0, the Nix installer will always default to creating a
single-user installation, however opting in to the multi-user
installation is highly recommended.
</para>
<section xml:id="sect-single-user-installation">
<title>Single User Installation</title>
<para>
To explicitly select a single-user installation on your system:
<screen>
sh &lt;(curl https://nixos.org/nix/install) --no-daemon
</screen>
</para>
<para>
This will perform a single-user installation of Nix, meaning that
<filename>/nix</filename> is owned by the invoking user. You should
run this under your usual user account, <emphasis>not</emphasis> as
@@ -50,8 +33,51 @@ and <filename>.profile</filename> to source
the <command>NIX_INSTALLER_NO_MODIFY_PROFILE</command> environment
variable before executing the install script to disable this
behaviour.
</para>
<!--
<para>You can also manually download and install a binary package.
Binary packages of the latest stable release are available for Fedora,
Debian, Ubuntu, macOS and various other systems from the <link
xlink:href="http://nixos.org/nix/download.html">Nix homepage</link>.
You can also get builds of the latest development release from our
<link
xlink:href="http://hydra.nixos.org/job/nix/master/release/latest-finished#tabs-constituents">continuous
build system</link>.</para>
<para>For Fedora, RPM packages are available. These can be installed
or upgraded using <command>rpm -U</command>. For example,
<screen>
$ rpm -U nix-1.8-1.i386.rpm</screen>
</para>
<para>For Debian and Ubuntu, you can download a Deb package and
install it like this:
<screen>
$ dpkg -i nix_1.8-1_amd64.deb</screen>
</para>
-->
<para>You can also download a binary tarball that contains Nix and all
its dependencies. (This is what the install script at
<uri>https://nixos.org/nix/install</uri> does automatically.) You
should unpack it somewhere (e.g. in <filename>/tmp</filename>), and
then run the script named <command>install</command> inside the binary
tarball:
<screen>
alice$ cd /tmp
alice$ tar xfj nix-1.8-x86_64-darwin.tar.bz2
alice$ cd nix-1.8-x86_64-darwin
alice$ ./install
</screen>
</para>
<para>You can uninstall Nix simply by running:
@@ -60,131 +86,5 @@ $ rm -rf /nix
</screen>
</para>
</section>
<section xml:id="sect-multi-user-installation">
<title>Multi User Installation</title>
<para>
The multi-user Nix installation creates system users, and a system
service for the Nix daemon.
</para>
<itemizedlist>
<title>Supported Systems</title>
<listitem>
<para>Linux running systemd, with SELinux disabled</para>
</listitem>
<listitem><para>macOS</para></listitem>
</itemizedlist>
<para>
You can instruct the installer to perform a multi-user
installation on your system:
<screen>
sh &lt;(curl https://nixos.org/nix/install) --daemon
</screen>
</para>
<para>
The multi-user installation of Nix will create build users between
the user IDs 30001 and 30032, and a group with the group ID 30000.
You should run this under your usual user account,
<emphasis>not</emphasis> as root. The script will invoke
<command>sudo</command> as needed.
</para>
<note><para>
If you need Nix to use a different group ID or user ID set, you
will have to download the tarball manually and <link
linkend="sect-nix-install-binary-tarball">edit the install
script</link>.
</para></note>
<para>
The installer will modify <filename>/etc/bashrc</filename>, and
<filename>/etc/zshrc</filename> if they exist. The installer will
first back up these files with a
<literal>.backup-before-nix</literal> extension. The installer
will also create <filename>/etc/profile.d/nix.sh</filename>.
</para>
<para>You can uninstall Nix with the following commands:
<screen>
sudo rm -rf /etc/profile/nix.sh /etc/nix /nix ~root/.nix-profile ~root/.nix-defexpr ~root/.nix-channels ~/.nix-profile ~/.nix-defexpr ~/.nix-channels
# If you are on Linux with systemd, you will need to run:
sudo systemctl stop nix-daemon.socket
sudo systemctl stop nix-daemon.service
sudo systemctl disable nix-daemon.socket
sudo systemctl disable nix-daemon.service
sudo systemctl daemon-reload
# If you are on macOS, you will need to run:
sudo launchctl unload /Library/LaunchDaemons/org.nixos.nix-daemon.plist
sudo rm /Library/LaunchDaemons/org.nixos.nix-daemon.plist
</screen>
There may also be references to Nix in
<filename>/etc/profile</filename>,
<filename>/etc/bashrc</filename>, and
<filename>/etc/zshrc</filename> which you may remove.
</para>
</section>
<section xml:id="sect-nix-install-pinned-version-url">
<title>Installing a pinned Nix version from a URL</title>
<para>
NixOS.org hosts version-specific installation URLs for all Nix
versions since 1.11.16, at
<literal>https://nixos.org/releases/nix/nix-VERSION/install</literal>.
</para>
<para>
These install scripts can be used the same as the main
NixOS.org installation script:
<screen>
sh &lt;(curl https://nixos.org/nix/install)
</screen>
</para>
<para>
In the same directory of the install script are sha256 sums, and
gpg signature files.
</para>
</section>
<section xml:id="sect-nix-install-binary-tarball">
<title>Installing from a binary tarball</title>
<para>
You can also download a binary tarball that contains Nix and all
its dependencies. (This is what the install script at
<uri>https://nixos.org/nix/install</uri> does automatically.) You
should unpack it somewhere (e.g. in <filename>/tmp</filename>),
and then run the script named <command>install</command> inside
the binary tarball:
<screen>
alice$ cd /tmp
alice$ tar xfj nix-1.8-x86_64-darwin.tar.bz2
alice$ cd nix-1.8-x86_64-darwin
alice$ ./install
</screen>
</para>
<para>
If you need to edit the multi-user installation script to use
different group ID or a different user ID range, modify the
variables set in the file named
<filename>install-multi-user</filename>.
</para>
</section>
</chapter>

View File

@@ -9,9 +9,6 @@
<itemizedlist>
<listitem><para>GNU Make.</para></listitem>
<listitem><para>Bash Shell. The <literal>./configure</literal> script
relies on bashisms, so Bash is required.</para></listitem>
<listitem><para>A version of GCC or Clang that supports C++14.</para></listitem>
@@ -25,27 +22,12 @@
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
get it from <link xlink:href="https://tukaani.org/xz/"/>.</para></listitem>
<listitem><para>cURL and its library. If your distribution does not
provide it, you can get it from <link
xlink:href="https://curl.haxx.se/"/>.</para></listitem>
<listitem><para>The SQLite embedded database library, version 3.6.19
or higher. If your distribution does not provide it, please install
it from <link xlink:href="http://www.sqlite.org/" />.</para></listitem>
@@ -58,10 +40,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 +65,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

@@ -10,7 +10,7 @@
<itemizedlist>
<listitem><para>Linux (i686, x86_64, aarch64).</para></listitem>
<listitem><para>Linux (i686, x86_64).</para></listitem>
<listitem><para>macOS (x86_64).</para></listitem>

View File

@@ -1,22 +0,0 @@
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="ch-upgrading-nix">
<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>
</para>
<para>
Single-user installations of Nix should run this:
<command>nix-channel --update; nix-env -iA nixpkgs.nix</command>
</para>
</chapter>

View File

@@ -60,8 +60,7 @@ This is because tools such as compilers don’t search in per-packages
directories such as
<filename>/nix/store/5lbfaxb722zp…-openssl-0.9.8d/include</filename>,
so if a package builds correctly on your system, this is because you
specified the dependency explicitly. This takes care of the build-time
dependencies.</para>
specified the dependency explicitly.</para>
<para>Once a package is built, runtime dependencies are found by
scanning binaries for the hash parts of Nix store paths (such as
@@ -262,6 +261,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

@@ -32,7 +32,6 @@
<xi:include href="introduction/introduction.xml" />
<xi:include href="installation/installation.xml" />
<xi:include href="installation/upgrading.xml" />
<xi:include href="packages/package-management.xml" />
<xi:include href="expressions/writing-nix-expressions.xml" />
<xi:include href="advanced-topics/advanced-topics.xml" />

View File

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

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>us–east-1</literal> by
default.
</para>
<para>
If your bucket is not in <literal>us–east-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,52 @@ 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>us–east-1</literal> by
default.
</para>
</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>
</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,8 +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" />
<xi:include href="rl-1.11.xml" />

View File

@@ -1,133 +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.1">
<title>Release 2.1 (2018-09-02)</title>
<para>This is primarily a bug fix release. It also reduces memory
consumption in certain situations. In addition, it has the following
new features:</para>
<itemizedlist>
<listitem>
<para>The Nix installer will no longer default to the Multi-User
installation for macOS. You can still <link
linkend="sect-multi-user-installation">instruct the installer to
run in multi-user mode</link>.
</para>
</listitem>
<listitem>
<para>The Nix installer now supports performing a Multi-User
installation for Linux computers which are running systemd. You
can <link
linkend="sect-multi-user-installation">select a Multi-User installation</link> by passing the
<option>--daemon</option> flag to the installer: <command>sh &lt;(curl
https://nixos.org/nix/install) --daemon</command>.
</para>
<para>The multi-user installer cannot handle systems with SELinux.
If your system has SELinux enabled, you can <link
linkend="sect-single-user-installation">force the installer to run
in single-user mode</link>.</para>
</listitem>
<listitem>
<para>New builtin functions:
<literal>builtins.bitAnd</literal>,
<literal>builtins.bitOr</literal>,
<literal>builtins.bitXor</literal>,
<literal>builtins.fromTOML</literal>,
<literal>builtins.concatMap</literal>,
<literal>builtins.mapAttrs</literal>.
</para>
</listitem>
<listitem>
<para>The S3 binary cache store now supports uploading NARs larger
than 5 GiB.</para>
</listitem>
<listitem>
<para>The S3 binary cache store now supports uploading to
S3-compatible services with the <literal>endpoint</literal>
option.</para>
</listitem>
<listitem>
<para>The flag <option>--fallback</option> is no longer required
to recover from disappeared NARs in binary caches.</para>
</listitem>
<listitem>
<para><command>nix-daemon</command> now respects
<option>--store</option>.</para>
</listitem>
<listitem>
<para><command>nix run</command> now respects
<varname>nix-support/propagated-user-env-packages</varname>.</para>
</listitem>
</itemizedlist>
<para>This release has contributions from
Adrien Devresse,
Aleksandr Pashkov,
Alexandre Esteves,
Amine Chikhaoui,
Andrew Dunham,
Asad Saeeduddin,
aszlig,
Ben Challenor,
Ben Gamari,
Benjamin Hipple,
Bogdan Seniuc,
Corey O'Connor,
Daiderd Jordan,
Daniel Peebles,
Daniel Poelzleithner,
Danylo Hlynskyi,
Dmitry Kalinkin,
Domen Kožar,
Doug Beardsley,
Eelco Dolstra,
Erik Arvstedt,
Félix Baylac-Jacqué,
Gleb Peregud,
Graham Christensen,
Guillaume Maudoux,
Ivan Kozik,
John Arnold,
Justin Humm,
Linus Heckemann,
Lorenzo Manacorda,
Matthew Justin Bauer,
Matthew O'Gorman,
Maximilian Bosch,
Michael Bishop,
Michael Fiano,
Michael Mercier,
Michael Raskin,
Michael Weiss,
Nicolas Dudebout,
Peter Simons,
Ryan Trinkle,
Samuel Dionne-Riel,
Sean Seefried,
Shea Levy,
Symphorien Gibol,
Tim Engler,
Tim Sears,
Tuomas Tynkkynen,
volth,
Will Dietz,
Yorick van Pelt and
zimbatm.
</para>
</section>

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,9 @@ 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)))
$(foreach i, $(call rwildcard, src/boost, *.hpp), $(eval $(call install-file-in, $(i), $(includedir)/nix/$(patsubst src/%/,%,$(dir $(i))), 0644)))

View File

@@ -6,7 +6,6 @@ use Data::Dumper;
use File::Basename;
use File::Path;
use File::Slurp;
use File::Copy;
use JSON::PP;
use LWP::UserAgent;
@@ -55,7 +54,7 @@ sub downloadFile {
my $buildInfo = decode_json(fetch("$evalUrl/job/$jobName", 'application/json'));
my $srcFile = $buildInfo->{buildproducts}->{$productNr}->{path} or die "job '$jobName' lacks product $productNr\n";
my $srcFile = $buildInfo->{buildproducts}->{$productNr}->{path} or die;
$dstName //= basename($srcFile);
my $dstFile = "$releaseDir/" . $dstName;
@@ -76,22 +75,16 @@ sub downloadFile {
write_file("$dstFile.sha256", $sha256_expected);
if (! -e "$dstFile.asc") {
system("gpg2 --detach-sign --armor $dstFile") == 0 or die "unable to sign $dstFile\n";
}
return ($dstFile, $sha256_expected);
}
downloadFile("tarball", "2"); # .tar.bz2
my ($tarball, $tarballHash) = downloadFile("tarball", "3"); # .tar.xz
downloadFile("binaryTarball.i686-linux", "1");
downloadFile("binaryTarball.x86_64-linux", "1");
downloadFile("binaryTarball.aarch64-linux", "1");
downloadFile("binaryTarball.x86_64-darwin", "1");
downloadFile("installerScript", "1");
exit if $version =~ /pre/;
downloadFile("tarball", "2"); # PDF
downloadFile("tarball", "3"); # .tar.bz2
my ($tarball, $tarballHash) = downloadFile("tarball", "4"); # .tar.xz
my ($tarball_i686_linux, $tarball_i686_linux_hash) = downloadFile("binaryTarball.i686-linux", "1");
my ($tarball_x86_64_linux, $tarball_x86_64_linux_hash) = downloadFile("binaryTarball.x86_64-linux", "1");
my ($tarball_aarch64_linux, $tarball_aarch64_linux_hash) = downloadFile("binaryTarball.aarch64-linux", "1");
my ($tarball_x86_64_darwin, $tarball_x86_64_darwin_hash) = downloadFile("binaryTarball.x86_64-darwin", "1");
# Update Nixpkgs in a very hacky way.
system("cd $nixpkgsDir && git pull") == 0 or die;
@@ -151,6 +144,12 @@ system("cd $siteDir && git pull") == 0 or die;
write_file("$siteDir/nix-release.tt",
"[%-\n" .
"latestNixVersion = \"$version\"\n" .
"nix_hash_i686_linux = \"$tarball_i686_linux_hash\"\n" .
"nix_hash_x86_64_linux = \"$tarball_x86_64_linux_hash\"\n" .
"nix_hash_aarch64_linux = \"$tarball_aarch64_linux_hash\"\n" .
"nix_hash_x86_64_darwin = \"$tarball_x86_64_darwin_hash\"\n" .
"-%]\n");
system("cd $siteDir && nix-shell --run 'make nix/install nix/install.sig'") == 0 or die;
system("cd $siteDir && git commit -a -m 'Nix $version released'") == 0 or die;

26
misc/docker/Dockerfile Normal file
View File

@@ -0,0 +1,26 @@
FROM alpine
# Enable HTTPS support in wget.
RUN apk add --update openssl
# Download Nix and install it into the system.
RUN wget -O- https://nixos.org/releases/nix/nix-1.11.14/nix-1.11.14-x86_64-linux.tar.bz2 | bzcat - | tar xf - \
&& addgroup -g 30000 -S nixbld \
&& for i in $(seq 1 30); do adduser -S -D -h /var/empty -g "Nix build user $i" -u $((30000 + i)) -G nixbld nixbld$i ; done \
&& mkdir -m 0755 /nix && USER=root sh nix-*-x86_64-linux/install \
&& ln -s /nix/var/nix/profiles/default/etc/profile.d/nix.sh /etc/profile.d/ \
&& rm -r /nix-*-x86_64-linux \
&& rm -r /var/cache/apk/*
ONBUILD ENV \
ENV=/etc/profile \
PATH=/nix/var/nix/profiles/default/bin:/nix/var/nix/profiles/default/sbin:/bin:/sbin:/usr/bin:/usr/sbin \
GIT_SSL_CAINFO=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt \
NIX_SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt
ENV \
ENV=/etc/profile \
PATH=/nix/var/nix/profiles/default/bin:/nix/var/nix/profiles/default/sbin:/bin:/sbin:/usr/bin:/usr/sbin \
GIT_SSL_CAINFO=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt \
NIX_SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt \
NIX_PATH=/nix/var/nix/profiles/per-user/root/channels

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

@@ -3,47 +3,31 @@
%global nixbld_user "nix-builder-"
%global nixbld_group "nixbld"
# NOTE: BUILD on EL7 requires
# - Centos / RHEL7 software collection repository
# yum install centos-release-scl
#
# - Recent boost backport
# curl https://copr.fedorainfracloud.org/coprs/whosthere/boost/repo/epel-7/whosthere-boost-epel-7.repo -o /etc/yum.repos.d/whosthere-boost-epel-7.repo
#
# Disable documentation generation
# necessary on some platforms
%bcond_without docgen
Summary: The Nix software deployment system
Name: nix
Version: @PACKAGE_VERSION@
Release: 2%{?dist}
License: LGPLv2+
%if 0%{?rhel} && 0%{?rhel} < 7
Group: Applications/System
%endif
URL: http://nixos.org/
Source0: %{name}-%{version}.tar.bz2
%if 0%{?el5}
BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
%endif
Requires: curl
Requires: bzip2
Requires: gzip
Requires: xz
BuildRequires: bison
BuildRequires: boost-devel >= 1.60
Requires: libseccomp
BuildRequires: bzip2-devel
# for RHEL <= 7, we need software collections for a C++14 compatible compatible compiler
%if 0%{?rhel}
BuildRequires: devtoolset-7-gcc
BuildRequires: devtoolset-7-gcc-c++
%endif
BuildRequires: flex
BuildRequires: sqlite-devel
BuildRequires: libcurl-devel
BuildRequires: libseccomp-devel
BuildRequires: openssl-devel
BuildRequires: sqlite-devel
BuildRequires: xz-devel
# Hack to make that shitty RPM scanning hack shut up.
Provides: perl(Nix::SSH)
%description
Nix is a purely functional package manager. It allows multiple
@@ -55,6 +39,9 @@ it can be used equally well under other Unix systems.
%package devel
Summary: Development files for %{name}
%if 0%{?rhel} && 0%{?rhel} < 7
Group: Development/Libraries
%endif
Requires: %{name}%{?_isa} = %{version}-%{release}
%description devel
@@ -64,6 +51,9 @@ developing applications that use %{name}.
%package doc
Summary: Documentation files for %{name}
%if 0%{?rhel} && 0%{?rhel} < 7
Group: Documentation
%endif
BuildArch: noarch
Requires: %{name} = %{version}-%{release}
@@ -75,25 +65,20 @@ The %{name}-doc package contains documentation files for %{name}.
%build
%if 0%{?rhel}
source /opt/rh/devtoolset-7/enable
%endif
extraFlags=
# - override docdir so large documentation files are owned by the
# -doc subpackage
# - set localstatedir by hand to the preferred nix value
%configure --localstatedir=/nix/var \
%{!?without_docgen:--disable-doc-gen} \
--docdir=%{_defaultdocdir}/%{name}-doc-%{version} \
$extraFlags
make V=1 %{?_smp_mflags}
make -j$NIX_BUILD_CORES -l$NIX_BUILD_CORES
%install
%if 0%{?rhel}
source /opt/rh/devtoolset-7/enable
%if 0%{?el5}
rm -rf $RPM_BUILD_ROOT
%endif
make DESTDIR=$RPM_BUILD_ROOT install
find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';'
@@ -143,7 +128,6 @@ systemctl start nix-daemon.socket
%endif
%files
%license COPYING
%{_bindir}/nix*
%{_libdir}/*.so
%{_prefix}/libexec/*
@@ -152,11 +136,9 @@ systemctl start nix-daemon.socket
%{_prefix}/lib/systemd/system/nix-daemon.service
%endif
%{_datadir}/nix
#%if ! %{without docgen}
#%{_mandir}/man1/*.1*
#%{_mandir}/man5/*.5*
#%{_mandir}/man8/*.8*
#%endif
%{_mandir}/man1/*.1*
%{_mandir}/man5/*.5*
%{_mandir}/man8/*.8*
%config(noreplace) %{_sysconfdir}/profile.d/nix.sh
%config(noreplace) %{_sysconfdir}/profile.d/nix-daemon.sh
/nix
@@ -165,9 +147,6 @@ systemctl start nix-daemon.socket
%{_includedir}/nix
%{_prefix}/lib/pkgconfig/*.pc
#%if ! %{without docgen}
#%files doc
#%docdir %{_defaultdocdir}/%{name}-doc-%{version}
#%{_defaultdocdir}/%{name}-doc-%{version}
#%endif
%files doc
%docdir %{_defaultdocdir}/%{name}-doc-%{version}
%{_defaultdocdir}/%{name}-doc-%{version}

View File

@@ -1,6 +1,6 @@
makefiles = local.mk
GLOBAL_CXXFLAGS += -g -Wall
GLOBAL_CXXFLAGS += -std=c++14 -g -Wall
-include Makefile.config

View File

@@ -27,7 +27,7 @@ static ref<Store> store()
static std::shared_ptr<Store> _store;
if (!_store) {
try {
loadConfFile();
settings.loadConfFile();
settings.lockCPU = false;
_store = openStore();
} catch (Error & e) {

View File

@@ -1,11 +1,9 @@
{ pkgs }:
with pkgs;
rec {
# Use "busybox-sandbox-shell" if present,
# if not (legacy) fallback and hope it's sufficient.
sh = pkgs.busybox-sandbox-shell or (busybox.override {
sh = pkgs.busybox-sandbox-shell or (pkgs.busybox.override {
useMusl = true;
enableStatic = true;
enableMinimal = true;
@@ -30,50 +28,9 @@ rec {
});
configureFlags =
[
[ "--disable-init-state"
"--enable-gc"
] ++ lib.optionals stdenv.isLinux [
] ++ pkgs.lib.optionals pkgs.stdenv.isLinux [
"--with-sandbox-shell=${sh}/bin/busybox"
];
tarballDeps =
[ bison
flex
libxml2
libxslt
docbook5
docbook5_xsl
autoconf-archive
autoreconfHook
];
buildDeps =
[ curl
bzip2 xz brotli editline
openssl pkgconfig sqlite boehmgc
boost
# Tests
git
mercurial
]
++ lib.optionals stdenv.isLinux [libseccomp utillinuxMinimal]
++ lib.optional (stdenv.isLinux || stdenv.isDarwin) libsodium
++ lib.optional (stdenv.isLinux || stdenv.isDarwin)
((aws-sdk-cpp.override {
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 =
[ perl
perlPackages.DBDSQLite
];
}

View File

@@ -1,5 +1,5 @@
{ nix ? builtins.fetchGit ./.
, nixpkgs ? builtins.fetchGit { url = https://github.com/NixOS/nixpkgs-channels.git; ref = "nixos-18.09"; }
, nixpkgs ? builtins.fetchGit https://github.com/NixOS/nixpkgs.git
, officialRelease ? false
, systems ? [ "x86_64-linux" "i686-linux" "x86_64-darwin" "aarch64-linux" ]
}:
@@ -14,8 +14,6 @@ let
tarball =
with pkgs;
with import ./release-common.nix { inherit pkgs; };
releaseTools.sourceTarball {
name = "nix-tarball";
version = builtins.readFile ./version;
@@ -23,13 +21,19 @@ let
src = nix;
inherit officialRelease;
buildInputs = tarballDeps ++ buildDeps;
buildInputs =
[ curl bison flex libxml2 libxslt
bzip2 xz brotli
pkgconfig sqlite libsodium boehmgc
docbook5 docbook5_xsl
autoconf-archive
] ++ lib.optional stdenv.isLinux libseccomp;
configureFlags = "--enable-gc";
postUnpack = ''
(cd $sourceRoot && find . -type f) | cut -c3- > $sourceRoot/.dist-files
cat $sourceRoot/.dist-files
(cd source && find . -type f) | cut -c3- > source/.dist-files
cat source/.dist-files
'';
preConfigure = ''
@@ -55,9 +59,7 @@ let
build = pkgs.lib.genAttrs systems (system:
let pkgs = import nixpkgs { inherit system; }; in
with pkgs;
with import nixpkgs { inherit system; };
with import ./release-common.nix { inherit pkgs; };
@@ -65,15 +67,22 @@ let
name = "nix";
src = tarball;
buildInputs = buildDeps;
buildInputs =
[ curl
bzip2 xz brotli
openssl pkgconfig sqlite boehmgc
preConfigure =
# Copy libboost_context so we don't get all of Boost in our closure.
# https://github.com/NixOS/nixpkgs/issues/45462
''
mkdir -p $out/lib
cp ${boost}/lib/libboost_context* $out/lib
'';
# Tests
git
mercurial
]
++ lib.optional stdenv.isLinux libseccomp
++ lib.optional (stdenv.isLinux || stdenv.isDarwin) libsodium
++ lib.optional (stdenv.isLinux || stdenv.isDarwin)
(aws-sdk-cpp.override {
apis = ["s3"];
customMemoryManagement = false;
});
configureFlags = configureFlags ++
[ "--sysconfdir=/etc" ];
@@ -82,6 +91,8 @@ let
makeFlags = "profiledir=$(out)/etc/profile.d";
preBuild = "unset NIX_INDENT_MAKE";
installFlags = "sysconfdir=$(out)/etc";
doInstallCheck = true;
@@ -98,7 +109,7 @@ let
src = tarball;
buildInputs =
[ jobs.build.${system} curl bzip2 xz pkgconfig pkgs.perl boost ]
[ (builtins.getAttr system jobs.build) curl bzip2 xz pkgconfig pkgs.perl ]
++ lib.optional (stdenv.isLinux || stdenv.isDarwin) libsodium;
configureFlags = ''
@@ -109,6 +120,8 @@ let
enableParallelBuilding = true;
postUnpack = "sourceRoot=$sourceRoot/perl";
preBuild = "unset NIX_INDENT_MAKE";
});
@@ -183,15 +196,21 @@ let
coverage =
with pkgs;
with import ./release-common.nix { inherit pkgs; };
with import nixpkgs { system = "x86_64-linux"; };
releaseTools.coverageAnalysis {
name = "nix-build";
src = tarball;
buildInputs = buildDeps;
buildInputs =
[ curl bzip2 openssl pkgconfig sqlite xz libsodium libseccomp
# These are for "make check" only:
graphviz libxml2 libxslt git mercurial
];
configureFlags = ''
--disable-init-state
'';
dontInstall = false;
@@ -206,14 +225,15 @@ let
};
#rpm_fedora27x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora27x86_64) [ ];
rpm_fedora27i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora27i386) [ "libsodium-devel" ];
rpm_fedora27x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora27x86_64) [ "libsodium-devel" ];
#deb_debian8i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.debian8i386) [ "libsodium-dev" ] [ "libsodium13" ];
#deb_debian8x86_64 = makeDeb_x86_64 (diskImageFunsFun: diskImageFunsFun.debian8x86_64) [ "libsodium-dev" ] [ "libsodium13" ];
#deb_ubuntu1710i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1710i386) [ ] [ "libsodium18" ];
#deb_ubuntu1710x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1710x86_64) [ ] [ "libsodium18" "libboost-context1.62.0" ];
deb_ubuntu1604i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1604i386) [ "libsodium-dev" ] [ "libsodium18" ];
deb_ubuntu1604x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1604x86_64) [ "libsodium-dev" ] [ "libsodium18" ];
# System tests.
@@ -241,7 +261,6 @@ let
{ diskImage = vmTools.diskImages.ubuntu1204x86_64;
}
''
set -x
useradd -m alice
su - alice -c 'tar xf ${binaryTarball.x86_64-linux}/*.tar.*'
mkdir /dest-nix
@@ -250,17 +269,6 @@ let
su - alice -c '_NIX_INSTALLER_TEST=1 ./nix-*/install'
su - alice -c 'nix-store --verify'
su - alice -c 'PAGER= nix-store -qR ${build.x86_64-linux}'
# Check whether 'nix upgrade-nix' works.
cat > /tmp/paths.nix <<EOF
{
x86_64-linux = "${build.x86_64-linux}";
}
EOF
su - alice -c 'nix upgrade-nix -vvv --nix-store-paths-url file:///tmp/paths.nix'
(! [ -L /home/alice/.profile-1-link ])
su - alice -c 'PAGER= nix-store -qR ${build.x86_64-linux}'
mkdir -p $out/nix-support
touch $out/nix-support/hydra-build-products
umount /nix
@@ -296,7 +304,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}
@@ -344,7 +352,7 @@ let
src = jobs.tarball;
diskImage = (diskImageFun vmTools.diskImageFuns)
{ extraPackages =
[ "sqlite" "sqlite-devel" "bzip2-devel" "libcurl-devel" "openssl-devel" "xz-devel" "libseccomp-devel" "libsodium-devel" "boost-devel" "bison" "flex" ]
[ "sqlite" "sqlite-devel" "bzip2-devel" "libcurl-devel" "openssl-devel" "xz-devel" "libseccomp-devel" ]
++ extraPackages; };
# At most 2047MB can be simulated in qemu-system-i386
memSize = 2047;
@@ -367,9 +375,9 @@ let
src = jobs.tarball;
diskImage = (diskImageFun vmTools.diskImageFuns)
{ extraPackages =
[ "libsqlite3-dev" "libbz2-dev" "libcurl-dev" "libcurl3-nss" "libssl-dev" "liblzma-dev" "libseccomp-dev" "libsodium-dev" "libboost-all-dev" ]
[ "libsqlite3-dev" "libbz2-dev" "libcurl-dev" "libcurl3-nss" "libssl-dev" "liblzma-dev" "libseccomp-dev" ]
++ extraPackages; };
memSize = 2047;
memSize = 1024;
meta.schedulingPriority = 50;
postInstall = "make installcheck";
configureFlags = "--sysconfdir=/etc";

View File

@@ -30,14 +30,15 @@ if [ "$(uname -s)" = "Darwin" ]; then
fi
fi
# Determine if we could use the multi-user installer or not
# Determine if we should punt to the single-user installer or not
if [ "$(uname -s)" = "Darwin" ]; then
echo "Note: a multi-user installation is possible. See https://nixos.org/nix/manual/#sect-multi-user-installation" >&2
INSTALL_MODE=daemon
elif [ "$(uname -s)" = "Linux" ] && [ -e /run/systemd/system ]; then
echo "Note: a multi-user installation is possible. See https://nixos.org/nix/manual/#sect-multi-user-installation" >&2
INSTALL_MODE=no-daemon
else
INSTALL_MODE=no-daemon
fi
INSTALL_MODE=no-daemon
# Trivially handle the --daemon / --no-daemon options
if [ "x${1:-}" = "x--no-daemon" ]; then
INSTALL_MODE=no-daemon
@@ -46,18 +47,14 @@ elif [ "x${1:-}" = "x--daemon" ]; then
elif [ "x${1:-}" != "x" ]; then
(
echo "Nix Installer [--daemon|--no-daemon]"
echo "Choose installation method."
echo ""
echo " --daemon: Installs and configures a background daemon that manages the store,"
echo " providing multi-user support and better isolation for local builds."
echo " Both for security and reproducibility, this method is recommended if"
echo " supported on your platform."
echo " See https://nixos.org/nix/manual/#sect-multi-user-installation"
echo " --daemon: Force the installer to use the Daemon"
echo " based installer, even though it may not"
echo " work."
echo ""
echo " --no-daemon: Simple, single-user installation that does not require root and is"
echo " trivial to uninstall."
echo " (default)"
echo " --no-daemon: Force a no-daemon, single-user"
echo " installation even when the preferred"
echo " method is with the daemon."
echo ""
) >&2
exit

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

@@ -49,7 +49,6 @@ if test -w $HOME; then
fi
fi
# Set $NIX_SSL_CERT_FILE so that Nixpkgs applications like curl work.
if [ ! -z "${NIX_SSL_CERT_FILE:-}" ]; then
: # Allow users to override the NIX_SSL_CERT_FILE
@@ -61,14 +60,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 "@localstatedir@/nix/profiles/default/etc/ssl/certs/ca-bundle.crt" ]; then # fall back to cacert in the default Nix profile
export NIX_SSL_CERT_FILE=@localstatedir@/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 NIX_PATH="@localstatedir@/nix/profiles/per-user/root/channels"
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

@@ -1,13 +1,33 @@
{ useClang ? false }:
with import (builtins.fetchGit { url = https://github.com/NixOS/nixpkgs-channels.git; ref = "nixos-18.09"; }) {};
with import <nixpkgs> {};
with import ./release-common.nix { inherit pkgs; };
(if useClang then clangStdenv else stdenv).mkDerivation {
name = "nix";
buildInputs = buildDeps ++ tarballDeps ++ perlDeps;
buildInputs =
[ curl bison flex libxml2 libxslt
bzip2 xz brotli
pkgconfig sqlite libsodium boehmgc
docbook5 docbook5_xsl
autoconf-archive
(aws-sdk-cpp.override {
apis = ["s3"];
customMemoryManagement = false;
})
autoreconfHook
# For nix-perl
perl
perlPackages.DBDSQLite
# Tests
git
mercurial
]
++ lib.optional stdenv.isLinux libseccomp;
inherit configureFlags;

38
src/boost/assert.hpp Normal file
View File

@@ -0,0 +1,38 @@
//
// boost/assert.hpp - BOOST_ASSERT(expr)
//
// Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd.
//
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies.
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// Note: There are no include guards. This is intentional.
//
// See http://www.boost.org/libs/utility/assert.html for documentation.
//
#undef BOOST_ASSERT
#if defined(BOOST_DISABLE_ASSERTS)
# define BOOST_ASSERT(expr) ((void)0)
#elif defined(BOOST_ENABLE_ASSERT_HANDLER)
#include <boost/current_function.hpp>
namespace boost
{
void assertion_failed(char const * expr, char const * function, char const * file, long line); // user defined
} // namespace boost
#define BOOST_ASSERT(expr) ((expr)? ((void)0): ::boost::assertion_failed(#expr, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__))
#else
# include <assert.h>
# define BOOST_ASSERT(expr) assert(expr)
#endif

64
src/boost/format.hpp Normal file
View File

@@ -0,0 +1,64 @@
// -*- C++ -*-
// Boost general library 'format' ---------------------------
// See http://www.boost.org for updates, documentation, and revision history.
// (C) Samuel Krempp 2001
// krempp@crans.ens-cachan.fr
// Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
// ideas taken from Rüdiger Loos's format class
// and Karl Nelson's ofstream
// ----------------------------------------------------------------------------
// format.hpp : primary header
// ----------------------------------------------------------------------------
#ifndef BOOST_FORMAT_HPP
#define BOOST_FORMAT_HPP
#include <vector>
#include <string>
#include <sstream>
#include <cassert>
#if HAVE_LOCALE
#include <locale>
#else
#define BOOST_NO_STD_LOCALE
#define BOOST_NO_LOCALE_ISIDIGIT
#include <cctype>
#endif
#include <boost/format/macros_default.hpp>
// **** Forward declarations ----------------------------------
#include <boost/format/format_fwd.hpp> // basic_format<Ch,Tr>, and other frontends
#include <boost/format/internals_fwd.hpp> // misc forward declarations for internal use
// **** Auxiliary structs (stream_format_state<Ch,Tr> , and format_item<Ch,Tr> )
#include <boost/format/internals.hpp>
// **** Format class interface --------------------------------
#include <boost/format/format_class.hpp>
// **** Exceptions -----------------------------------------------
#include <boost/format/exceptions.hpp>
// **** Implementation -------------------------------------------
//#include <boost/format/format_implementation.hpp> // member functions
#include <boost/format/group.hpp> // class for grouping arguments
#include <boost/format/feed_args.hpp> // argument-feeding functions
//#include <boost/format/parsing.hpp> // format-string parsing (member-)functions
// **** Implementation of the free functions ----------------------
//#include <boost/format/free_funcs.hpp>
#endif // BOOST_FORMAT_HPP

View File

@@ -0,0 +1,96 @@
// -*- C++ -*-
// Boost general library 'format' ---------------------------
// See http://www.boost.org for updates, documentation, and revision history.
// (C) Samuel Krempp 2001
// krempp@crans.ens-cachan.fr
// Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
// ideas taken from Rüdiger Loos's format class
// and Karl Nelson's ofstream (also took its parsing code as basis for printf parsing)
// ------------------------------------------------------------------------------
// exceptions.hpp
// ------------------------------------------------------------------------------
#ifndef BOOST_FORMAT_EXCEPTIONS_HPP
#define BOOST_FORMAT_EXCEPTIONS_HPP
#include <stdexcept>
namespace boost {
namespace io {
// **** exceptions -----------------------------------------------
class format_error : public std::exception
{
public:
format_error() { abort(); }
virtual const char *what() const throw()
{
return "boost::format_error: "
"format generic failure";
}
};
class bad_format_string : public format_error
{
public:
bad_format_string() { abort(); }
virtual const char *what() const throw()
{
return "boost::bad_format_string: "
"format-string is ill-formed";
}
};
class too_few_args : public format_error
{
public:
too_few_args() { abort(); }
virtual const char *what() const throw()
{
return "boost::too_few_args: "
"format-string refered to more arguments than were passed";
}
};
class too_many_args : public format_error
{
public:
too_many_args() { abort(); }
virtual const char *what() const throw()
{
return "boost::too_many_args: "
"format-string refered to less arguments than were passed";
}
};
class out_of_range : public format_error
{
public:
out_of_range() { abort(); }
virtual const char *what() const throw()
{
return "boost::out_of_range: "
"tried to refer to an argument (or item) number which is out of range, "
"according to the format string.";
}
};
} // namespace io
} // namespace boost
#endif // BOOST_FORMAT_EXCEPTIONS_HPP

View File

@@ -0,0 +1,254 @@
// -*- C++ -*-
// Boost general library 'format' ---------------------------
// See http://www.boost.org for updates, documentation, and revision history.
// (C) Samuel Krempp 2001
// krempp@crans.ens-cachan.fr
// Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
// ideas taken from Rüdiger Loos's format class
// and Karl Nelson's ofstream
// ----------------------------------------------------------------------------
// feed_args.hpp : functions for processing each argument
// (feed, feed_manip, and distribute)
// ----------------------------------------------------------------------------
#ifndef BOOST_FORMAT_FEED_ARGS_HPP
#define BOOST_FORMAT_FEED_ARGS_HPP
#include "boost/format/format_class.hpp"
#include "boost/format/group.hpp"
#include "boost/throw_exception.hpp"
namespace boost {
namespace io {
namespace detail {
namespace {
inline
void empty_buf(BOOST_IO_STD ostringstream & os) {
static const std::string emptyStr;
os.str(emptyStr);
}
void do_pad( std::string & s,
std::streamsize w,
const char c,
std::ios::fmtflags f,
bool center)
__attribute__ ((unused));
void do_pad( std::string & s,
std::streamsize w,
const char c,
std::ios::fmtflags f,
bool center)
// applies centered / left / right padding to the string s.
// Effects : string s is padded.
{
std::streamsize n=w-s.size();
if(n<=0) {
return;
}
if(center)
{
s.reserve(w); // allocate once for the 2 inserts
const std::streamsize n1 = n /2, n0 = n - n1;
s.insert(s.begin(), n0, c);
s.append(n1, c);
}
else
{
if(f & std::ios::left) {
s.append(n, c);
}
else {
s.insert(s.begin(), n, c);
}
}
} // -do_pad(..)
template<class T> inline
void put_head(BOOST_IO_STD ostream& , const T& ) {
}
template<class T> inline
void put_head( BOOST_IO_STD ostream& os, const group1<T>& x ) {
os << group_head(x.a1_); // send the first N-1 items, not the last
}
template<class T> inline
void put_last( BOOST_IO_STD ostream& os, const T& x ) {
os << x ;
}
template<class T> inline
void put_last( BOOST_IO_STD ostream& os, const group1<T>& x ) {
os << group_last(x.a1_); // this selects the last element
}
#ifndef BOOST_NO_OVERLOAD_FOR_NON_CONST
template<class T> inline
void put_head( BOOST_IO_STD ostream& , T& ) {
}
template<class T> inline
void put_last( BOOST_IO_STD ostream& os, T& x ) {
os << x ;
}
#endif
template<class T>
void put( T x,
const format_item& specs,
std::string & res,
BOOST_IO_STD ostringstream& oss_ )
{
// does the actual conversion of x, with given params, into a string
// using the *supplied* strinstream. (the stream state is important)
typedef std::string string_t;
typedef format_item format_item_t;
stream_format_state prev_state(oss_);
specs.state_.apply_on(oss_);
// in case x is a group, apply the manip part of it,
// in order to find width
put_head( oss_, x );
empty_buf( oss_);
const std::streamsize w=oss_.width();
const std::ios::fmtflags fl=oss_.flags();
const bool internal = (fl & std::ios::internal) != 0;
const bool two_stepped_padding = internal
&& ! ( specs.pad_scheme_ & format_item_t::spacepad )
&& specs.truncate_ < 0 ;
if(! two_stepped_padding)
{
if(w>0) // handle simple padding via do_pad, not natively in stream
oss_.width(0);
put_last( oss_, x);
res = oss_.str();
if (specs.truncate_ >= 0)
res.erase(specs.truncate_);
// complex pads :
if(specs.pad_scheme_ & format_item_t::spacepad)
{
if( res.size()==0 || ( res[0]!='+' && res[0]!='-' ))
{
res.insert(res.begin(), 1, ' '); // insert 1 space at pos 0
}
}
if(w > 0) // need do_pad
{
do_pad(res,w,oss_.fill(), fl, (specs.pad_scheme_ & format_item_t::centered) !=0 );
}
}
else // 2-stepped padding
{
put_last( oss_, x); // oss_.width() may result in padding.
res = oss_.str();
if (specs.truncate_ >= 0)
res.erase(specs.truncate_);
if( res.size() - w > 0)
{ // length w exceeded
// either it was multi-output with first output padding up all width..
// either it was one big arg and we are fine.
empty_buf( oss_);
oss_.width(0);
put_last(oss_, x );
string_t tmp = oss_.str(); // minimal-length output
std::streamsize d;
if( (d=w - tmp.size()) <=0 )
{
// minimal length is already >= w, so no padding (cool!)
res.swap(tmp);
}
else
{ // hum.. we need to pad (it was necessarily multi-output)
typedef typename string_t::size_type size_type;
size_type i = 0;
while( i<tmp.size() && tmp[i] == res[i] ) // find where we should pad.
++i;
tmp.insert(i, static_cast<size_type>( d ), oss_.fill());
res.swap( tmp );
}
}
else
{ // okay, only one thing was printed and padded, so res is fine.
}
}
prev_state.apply_on(oss_);
empty_buf( oss_);
oss_.clear();
} // end- put(..)
} // local namespace
template<class T>
void distribute(basic_format& self, T x)
// call put(x, ..) on every occurence of the current argument :
{
if(self.cur_arg_ >= self.num_args_)
{
if( self.exceptions() & too_many_args_bit )
boost::throw_exception(too_many_args()); // too many variables have been supplied !
else return;
}
for(unsigned long i=0; i < self.items_.size(); ++i)
{
if(self.items_[i].argN_ == self.cur_arg_)
{
put<T> (x, self.items_[i], self.items_[i].res_, self.oss_ );
}
}
}
template<class T>
basic_format& feed(basic_format& self, T x)
{
if(self.dumped_) self.clear();
distribute<T> (self, x);
++self.cur_arg_;
if(self.bound_.size() != 0)
{
while( self.cur_arg_ < self.num_args_ && self.bound_[self.cur_arg_] )
++self.cur_arg_;
}
// this arg is finished, reset the stream's format state
self.state0_.apply_on(self.oss_);
return self;
}
} // namespace detail
} // namespace io
} // namespace boost
#endif // BOOST_FORMAT_FEED_ARGS_HPP

View File

@@ -0,0 +1,135 @@
// -*- C++ -*-
// Boost general library 'format' ---------------------------
// See http://www.boost.org for updates, documentation, and revision history.
// (C) Samuel Krempp 2001
// krempp@crans.ens-cachan.fr
// Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
// ideas taken from Rüdiger Loos's format class
// and Karl Nelson's ofstream (also took its parsing code as basis for printf parsing)
// ------------------------------------------------------------------------------
// format_class.hpp : class interface
// ------------------------------------------------------------------------------
#ifndef BOOST_FORMAT_CLASS_HPP
#define BOOST_FORMAT_CLASS_HPP
#include <vector>
#include <string>
#include <boost/format/format_fwd.hpp>
#include <boost/format/internals_fwd.hpp>
#include <boost/format/internals.hpp>
namespace boost {
class basic_format
{
public:
typedef std::string string_t;
typedef BOOST_IO_STD ostringstream internal_stream_t;
private:
typedef BOOST_IO_STD ostream stream_t;
typedef io::detail::stream_format_state stream_format_state;
typedef io::detail::format_item format_item_t;
public:
basic_format(const char* str);
basic_format(const string_t& s);
#ifndef BOOST_NO_STD_LOCALE
basic_format(const char* str, const std::locale & loc);
basic_format(const string_t& s, const std::locale & loc);
#endif // no locale
basic_format(const basic_format& x);
basic_format& operator= (const basic_format& x);
basic_format& clear(); // empty the string buffers (except bound arguments, see clear_binds() )
// pass arguments through those operators :
template<class T> basic_format& operator%(const T& x)
{
return io::detail::feed<const T&>(*this,x);
}
#ifndef BOOST_NO_OVERLOAD_FOR_NON_CONST
template<class T> basic_format& operator%(T& x)
{
return io::detail::feed<T&>(*this,x);
}
#endif
// system for binding arguments :
template<class T>
basic_format& bind_arg(int argN, const T& val)
{
return io::detail::bind_arg_body(*this, argN, val);
}
basic_format& clear_bind(int argN);
basic_format& clear_binds();
// modify the params of a directive, by applying a manipulator :
template<class T>
basic_format& modify_item(int itemN, const T& manipulator)
{
return io::detail::modify_item_body(*this, itemN, manipulator) ;
}
// Choosing which errors will throw exceptions :
unsigned char exceptions() const;
unsigned char exceptions(unsigned char newexcept);
// final output
string_t str() const;
friend BOOST_IO_STD ostream&
operator<< ( BOOST_IO_STD ostream& , const basic_format& );
template<class T> friend basic_format&
io::detail::feed(basic_format&, T);
template<class T> friend
void io::detail::distribute(basic_format&, T);
template<class T> friend
basic_format& io::detail::modify_item_body(basic_format&, int, const T&);
template<class T> friend
basic_format& io::detail::bind_arg_body(basic_format&, int, const T&);
// make the members private only if the friend templates are supported
private:
// flag bits, used for style_
enum style_values { ordered = 1, // set only if all directives are positional directives
special_needs = 4 };
// parse the format string :
void parse(const string_t&);
int style_; // style of format-string : positional or not, etc
int cur_arg_; // keep track of wich argument will come
int num_args_; // number of expected arguments
mutable bool dumped_; // true only after call to str() or <<
std::vector<format_item_t> items_; // vector of directives (aka items)
string_t prefix_; // piece of string to insert before first item
std::vector<bool> bound_; // stores which arguments were bound
// size = num_args OR zero
internal_stream_t oss_; // the internal stream.
stream_format_state state0_; // reference state for oss_
unsigned char exceptions_;
}; // class basic_format
} // namespace boost
#endif // BOOST_FORMAT_CLASS_HPP

View File

@@ -0,0 +1,49 @@
// -*- C++ -*-
// Boost general library 'format' ---------------------------
// See http://www.boost.org for updates, documentation, and revision history.
// (C) Samuel Krempp 2001
// krempp@crans.ens-cachan.fr
// Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
// ideas taken from Rüdiger Loos's format class
// and Karl Nelson's ofstream (also took its parsing code as basis for printf parsing)
// ------------------------------------------------------------------------------
// format_fwd.hpp : forward declarations, for primary header format.hpp
// ------------------------------------------------------------------------------
#ifndef BOOST_FORMAT_FWD_HPP
#define BOOST_FORMAT_FWD_HPP
#include <string>
#include <iosfwd>
namespace boost {
class basic_format;
typedef basic_format format;
namespace io {
enum format_error_bits { bad_format_string_bit = 1,
too_few_args_bit = 2, too_many_args_bit = 4,
out_of_range_bit = 8,
all_error_bits = 255, no_error_bits=0 };
// Convertion: format to string
std::string str(const basic_format& ) ;
} // namespace io
BOOST_IO_STD ostream&
operator<<( BOOST_IO_STD ostream&, const basic_format&);
} // namespace boost
#endif // BOOST_FORMAT_FWD_HPP

View File

@@ -0,0 +1,256 @@
// -*- C++ -*-
// Boost general library format ---------------------------
// See http://www.boost.org for updates, documentation, and revision history.
// (C) Samuel Krempp 2001
// krempp@crans.ens-cachan.fr
// Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
// ideas taken from Rüdiger Loos's format class
// and Karl Nelson's ofstream
// ----------------------------------------------------------------------------
// format_implementation.hpp Implementation of the basic_format class
// ----------------------------------------------------------------------------
#ifndef BOOST_FORMAT_IMPLEMENTATION_HPP
#define BOOST_FORMAT_IMPLEMENTATION_HPP
#include <boost/throw_exception.hpp>
#include <boost/assert.hpp>
#include <boost/format.hpp>
namespace boost {
// -------- format:: -------------------------------------------
basic_format::basic_format(const char* str)
: style_(0), cur_arg_(0), num_args_(0), dumped_(false),
items_(), oss_(), exceptions_(io::all_error_bits)
{
state0_.set_by_stream(oss_);
string_t emptyStr;
if( !str) str = emptyStr.c_str();
parse( str );
}
#ifndef BOOST_NO_STD_LOCALE
basic_format::basic_format(const char* str, const std::locale & loc)
: style_(0), cur_arg_(0), num_args_(0), dumped_(false),
items_(), oss_(), exceptions_(io::all_error_bits)
{
oss_.imbue( loc );
state0_.set_by_stream(oss_);
string_t emptyStr;
if( !str) str = emptyStr.c_str();
parse( str );
}
basic_format::basic_format(const string_t& s, const std::locale & loc)
: style_(0), cur_arg_(0), num_args_(0), dumped_(false),
items_(), oss_(), exceptions_(io::all_error_bits)
{
oss_.imbue( loc );
state0_.set_by_stream(oss_);
parse(s);
}
#endif //BOOST_NO_STD_LOCALE
basic_format::basic_format(const string_t& s)
: style_(0), cur_arg_(0), num_args_(0), dumped_(false),
items_(), oss_(), exceptions_(io::all_error_bits)
{
state0_.set_by_stream(oss_);
parse(s);
}
basic_format:: basic_format(const basic_format& x)
: style_(x.style_), cur_arg_(x.cur_arg_), num_args_(x.num_args_), dumped_(false),
items_(x.items_), prefix_(x.prefix_), bound_(x.bound_),
oss_(), // <- we obviously can't copy x.oss_
state0_(x.state0_), exceptions_(x.exceptions_)
{
state0_.apply_on(oss_);
}
basic_format& basic_format::operator= (const basic_format& x)
{
if(this == &x)
return *this;
state0_ = x.state0_;
state0_.apply_on(oss_);
// plus all the other (trivial) assignments :
exceptions_ = x.exceptions_;
items_ = x.items_;
prefix_ = x.prefix_;
bound_=x.bound_;
style_=x.style_;
cur_arg_=x.cur_arg_;
num_args_=x.num_args_;
dumped_=x.dumped_;
return *this;
}
unsigned char basic_format::exceptions() const
{
return exceptions_;
}
unsigned char basic_format::exceptions(unsigned char newexcept)
{
unsigned char swp = exceptions_;
exceptions_ = newexcept;
return swp;
}
basic_format& basic_format ::clear()
// empty the string buffers (except bound arguments, see clear_binds() )
// and make the format object ready for formatting a new set of arguments
{
BOOST_ASSERT( bound_.size()==0 || num_args_ == static_cast<int>(bound_.size()) );
for(unsigned long i=0; i<items_.size(); ++i){
items_[i].state_ = items_[i].ref_state_;
// clear converted strings only if the corresponding argument is not bound :
if( bound_.size()==0 || !bound_[ items_[i].argN_ ] ) items_[i].res_.resize(0);
}
cur_arg_=0; dumped_=false;
// maybe first arg is bound:
if(bound_.size() != 0)
{
while(cur_arg_ < num_args_ && bound_[cur_arg_] ) ++cur_arg_;
}
return *this;
}
basic_format& basic_format ::clear_binds()
// cancel all bindings, and clear()
{
bound_.resize(0);
clear();
return *this;
}
basic_format& basic_format::clear_bind(int argN)
// cancel the binding of ONE argument, and clear()
{
if(argN<1 || argN > num_args_ || bound_.size()==0 || !bound_[argN-1] )
{
if( exceptions() & io::out_of_range_bit )
boost::throw_exception(io::out_of_range()); // arg not in range.
else return *this;
}
bound_[argN-1]=false;
clear();
return *this;
}
std::string basic_format::str() const
{
dumped_=true;
if(items_.size()==0)
return prefix_;
if( cur_arg_ < num_args_)
if( exceptions() & io::too_few_args_bit )
boost::throw_exception(io::too_few_args()); // not enough variables have been supplied !
unsigned long sz = prefix_.size();
unsigned long i;
for(i=0; i < items_.size(); ++i)
sz += items_[i].res_.size() + items_[i].appendix_.size();
string_t res;
res.reserve(sz);
res += prefix_;
for(i=0; i < items_.size(); ++i)
{
const format_item_t& item = items_[i];
res += item.res_;
if( item.argN_ == format_item_t::argN_tabulation)
{
BOOST_ASSERT( item.pad_scheme_ & format_item_t::tabulation);
std::streamsize n = item.state_.width_ - res.size();
if( n > 0 )
res.append( n, item.state_.fill_ );
}
res += item.appendix_;
}
return res;
}
namespace io {
namespace detail {
template<class T>
basic_format& bind_arg_body( basic_format& self,
int argN,
const T& val)
// bind one argument to a fixed value
// this is persistent over clear() calls, thus also over str() and <<
{
if(self.dumped_) self.clear(); // needed, because we will modify cur_arg_..
if(argN<1 || argN > self.num_args_)
{
if( self.exceptions() & io::out_of_range_bit )
boost::throw_exception(io::out_of_range()); // arg not in range.
else return self;
}
if(self.bound_.size()==0)
self.bound_.assign(self.num_args_,false);
else
BOOST_ASSERT( self.num_args_ == static_cast<signed int>(self.bound_.size()) );
int o_cur_arg = self.cur_arg_;
self.cur_arg_ = argN-1; // arrays begin at 0
self.bound_[self.cur_arg_]=false; // if already set, we unset and re-sets..
self.operator%(val); // put val at the right place, because cur_arg is set
// Now re-position cur_arg before leaving :
self.cur_arg_ = o_cur_arg;
self.bound_[argN-1]=true;
if(self.cur_arg_ == argN-1 )
// hum, now this arg is bound, so move to next free arg
{
while(self.cur_arg_ < self.num_args_ && self.bound_[self.cur_arg_]) ++self.cur_arg_;
}
// In any case, we either have all args, or are on a non-binded arg :
BOOST_ASSERT( self.cur_arg_ >= self.num_args_ || ! self.bound_[self.cur_arg_]);
return self;
}
template<class T>
basic_format& modify_item_body( basic_format& self,
int itemN,
const T& manipulator)
// applies a manipulator to the format_item describing a given directive.
// this is a permanent change, clear or clear_binds won't cancel that.
{
if(itemN<1 || itemN >= static_cast<signed int>(self.items_.size() ))
{
if( self.exceptions() & io::out_of_range_bit )
boost::throw_exception(io::out_of_range()); // item not in range.
else return self;
}
self.items_[itemN-1].ref_state_.apply_manip( manipulator );
self.items_[itemN-1].state_ = self.items_[itemN-1].ref_state_;
return self;
}
} // namespace detail
} // namespace io
} // namespace boost
#endif // BOOST_FORMAT_IMPLEMENTATION_HPP

View File

@@ -0,0 +1,71 @@
// -*- C++ -*-
// Boost general library 'format' ---------------------------
// See http://www.boost.org for updates, documentation, and revision history.
// (C) Samuel Krempp 2001
// krempp@crans.ens-cachan.fr
// Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
// ideas taken from Rüdiger Loos's format class
// and Karl Nelson's ofstream (also took its parsing code as basis for printf parsing)
// ------------------------------------------------------------------------------
// free_funcs.hpp : implementation of the free functions declared in namespace format
// ------------------------------------------------------------------------------
#ifndef BOOST_FORMAT_FUNCS_HPP
#define BOOST_FORMAT_FUNCS_HPP
#include "boost/format.hpp"
#include "boost/throw_exception.hpp"
namespace boost {
namespace io {
inline
std::string str(const basic_format& f)
// adds up all pieces of strings and converted items, and return the formatted string
{
return f.str();
}
} // - namespace io
BOOST_IO_STD ostream&
operator<<( BOOST_IO_STD ostream& os,
const boost::basic_format& f)
// effect: "return os << str(f);" but we can try to do it faster
{
typedef boost::basic_format format_t;
if(f.items_.size()==0)
os << f.prefix_;
else {
if(f.cur_arg_ < f.num_args_)
if( f.exceptions() & io::too_few_args_bit )
boost::throw_exception(io::too_few_args()); // not enough variables have been supplied !
if(f.style_ & format_t::special_needs)
os << f.str();
else {
// else we dont have to count chars output, so we dump directly to os :
os << f.prefix_;
for(unsigned long i=0; i<f.items_.size(); ++i)
{
const format_t::format_item_t& item = f.items_[i];
os << item.res_;
os << item.appendix_;
}
}
}
f.dumped_=true;
return os;
}
} // namespace boost
#endif // BOOST_FORMAT_FUNCS_HPP

680
src/boost/format/group.hpp Normal file
View File

@@ -0,0 +1,680 @@
// -*- C++ -*-
// Boost general library 'format' ---------------------------
// See http://www.boost.org for updates, documentation, and revision history.
// (C) Samuel Krempp 2001
// krempp@crans.ens-cachan.fr
// Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
// ideas taken from Rüdiger Loos's format class
// and Karl Nelson's ofstream
// ----------------------------------------------------------------------------
// group.hpp : encapsulates a group of manipulators along with an argument
//
// group_head : cut the last element of a group out.
// (is overloaded below on each type of group)
// group_last : returns the last element of a group
// (is overloaded below on each type of group)
// ----------------------------------------------------------------------------
#ifndef BOOST_FORMAT_GROUP_HPP
#define BOOST_FORMAT_GROUP_HPP
namespace boost {
namespace io {
namespace detail {
// empty group, but useful even though.
struct group0
{
group0() {}
};
template <class Ch, class Tr>
inline
BOOST_IO_STD ostream&
operator << ( BOOST_IO_STD ostream& os,
const group0& )
{
return os;
}
template <class T1>
struct group1
{
T1 a1_;
group1(T1 a1)
: a1_(a1)
{}
};
template <class Ch, class Tr, class T1>
inline
BOOST_IO_STD ostream&
operator << (BOOST_IO_STD ostream& os,
const group1<T1>& x)
{
os << x.a1_;
return os;
}
template <class T1,class T2>
struct group2
{
T1 a1_;
T2 a2_;
group2(T1 a1,T2 a2)
: a1_(a1),a2_(a2)
{}
};
template <class Ch, class Tr, class T1,class T2>
inline
BOOST_IO_STD ostream&
operator << (BOOST_IO_STD ostream& os,
const group2<T1,T2>& x)
{
os << x.a1_<< x.a2_;
return os;
}
template <class T1,class T2,class T3>
struct group3
{
T1 a1_;
T2 a2_;
T3 a3_;
group3(T1 a1,T2 a2,T3 a3)
: a1_(a1),a2_(a2),a3_(a3)
{}
};
template <class Ch, class Tr, class T1,class T2,class T3>
inline
BOOST_IO_STD ostream&
operator << (BOOST_IO_STD ostream& os,
const group3<T1,T2,T3>& x)
{
os << x.a1_<< x.a2_<< x.a3_;
return os;
}
template <class T1,class T2,class T3,class T4>
struct group4
{
T1 a1_;
T2 a2_;
T3 a3_;
T4 a4_;
group4(T1 a1,T2 a2,T3 a3,T4 a4)
: a1_(a1),a2_(a2),a3_(a3),a4_(a4)
{}
};
template <class Ch, class Tr, class T1,class T2,class T3,class T4>
inline
BOOST_IO_STD ostream&
operator << (BOOST_IO_STD ostream& os,
const group4<T1,T2,T3,T4>& x)
{
os << x.a1_<< x.a2_<< x.a3_<< x.a4_;
return os;
}
template <class T1,class T2,class T3,class T4,class T5>
struct group5
{
T1 a1_;
T2 a2_;
T3 a3_;
T4 a4_;
T5 a5_;
group5(T1 a1,T2 a2,T3 a3,T4 a4,T5 a5)
: a1_(a1),a2_(a2),a3_(a3),a4_(a4),a5_(a5)
{}
};
template <class Ch, class Tr, class T1,class T2,class T3,class T4,class T5>
inline
BOOST_IO_STD ostream&
operator << (BOOST_IO_STD ostream& os,
const group5<T1,T2,T3,T4,T5>& x)
{
os << x.a1_<< x.a2_<< x.a3_<< x.a4_<< x.a5_;
return os;
}
template <class T1,class T2,class T3,class T4,class T5,class T6>
struct group6
{
T1 a1_;
T2 a2_;
T3 a3_;
T4 a4_;
T5 a5_;
T6 a6_;
group6(T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6)
: a1_(a1),a2_(a2),a3_(a3),a4_(a4),a5_(a5),a6_(a6)
{}
};
template <class Ch, class Tr, class T1,class T2,class T3,class T4,class T5,class T6>
inline
BOOST_IO_STD ostream&
operator << (BOOST_IO_STD ostream& os,
const group6<T1,T2,T3,T4,T5,T6>& x)
{
os << x.a1_<< x.a2_<< x.a3_<< x.a4_<< x.a5_<< x.a6_;
return os;
}
template <class T1,class T2,class T3,class T4,class T5,class T6,class T7>
struct group7
{
T1 a1_;
T2 a2_;
T3 a3_;
T4 a4_;
T5 a5_;
T6 a6_;
T7 a7_;
group7(T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6,T7 a7)
: a1_(a1),a2_(a2),a3_(a3),a4_(a4),a5_(a5),a6_(a6),a7_(a7)
{}
};
template <class Ch, class Tr, class T1,class T2,class T3,class T4,class T5,class T6,class T7>
inline
BOOST_IO_STD ostream&
operator << (BOOST_IO_STD ostream& os,
const group7<T1,T2,T3,T4,T5,T6,T7>& x)
{
os << x.a1_<< x.a2_<< x.a3_<< x.a4_<< x.a5_<< x.a6_<< x.a7_;
return os;
}
template <class T1,class T2,class T3,class T4,class T5,class T6,class T7,class T8>
struct group8
{
T1 a1_;
T2 a2_;
T3 a3_;
T4 a4_;
T5 a5_;
T6 a6_;
T7 a7_;
T8 a8_;
group8(T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6,T7 a7,T8 a8)
: a1_(a1),a2_(a2),a3_(a3),a4_(a4),a5_(a5),a6_(a6),a7_(a7),a8_(a8)
{}
};
template <class Ch, class Tr, class T1,class T2,class T3,class T4,class T5,class T6,class T7,class T8>
inline
BOOST_IO_STD ostream&
operator << (BOOST_IO_STD ostream& os,
const group8<T1,T2,T3,T4,T5,T6,T7,T8>& x)
{
os << x.a1_<< x.a2_<< x.a3_<< x.a4_<< x.a5_<< x.a6_<< x.a7_<< x.a8_;
return os;
}
template <class T1,class T2,class T3,class T4,class T5,class T6,class T7,class T8,class T9>
struct group9
{
T1 a1_;
T2 a2_;
T3 a3_;
T4 a4_;
T5 a5_;
T6 a6_;
T7 a7_;
T8 a8_;
T9 a9_;
group9(T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6,T7 a7,T8 a8,T9 a9)
: a1_(a1),a2_(a2),a3_(a3),a4_(a4),a5_(a5),a6_(a6),a7_(a7),a8_(a8),a9_(a9)
{}
};
template <class Ch, class Tr, class T1,class T2,class T3,class T4,class T5,class T6,class T7,class T8,class T9>
inline
BOOST_IO_STD ostream&
operator << (BOOST_IO_STD ostream& os,
const group9<T1,T2,T3,T4,T5,T6,T7,T8,T9>& x)
{
os << x.a1_<< x.a2_<< x.a3_<< x.a4_<< x.a5_<< x.a6_<< x.a7_<< x.a8_<< x.a9_;
return os;
}
template <class T1,class T2,class T3,class T4,class T5,class T6,class T7,class T8,class T9,class T10>
struct group10
{
T1 a1_;
T2 a2_;
T3 a3_;
T4 a4_;
T5 a5_;
T6 a6_;
T7 a7_;
T8 a8_;
T9 a9_;
T10 a10_;
group10(T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6,T7 a7,T8 a8,T9 a9,T10 a10)
: a1_(a1),a2_(a2),a3_(a3),a4_(a4),a5_(a5),a6_(a6),a7_(a7),a8_(a8),a9_(a9),a10_(a10)
{}
};
template <class Ch, class Tr, class T1,class T2,class T3,class T4,class T5,class T6,class T7,class T8,class T9,class T10>
inline
BOOST_IO_STD ostream&
operator << (BOOST_IO_STD ostream& os,
const group10<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10>& x)
{
os << x.a1_<< x.a2_<< x.a3_<< x.a4_<< x.a5_<< x.a6_<< x.a7_<< x.a8_<< x.a9_<< x.a10_;
return os;
}
template <class T1,class T2>
inline
group1<T1>
group_head( group2<T1,T2> const& x)
{
return group1<T1> (x.a1_);
}
template <class T1,class T2>
inline
group1<T2>
group_last( group2<T1,T2> const& x)
{
return group1<T2> (x.a2_);
}
template <class T1,class T2,class T3>
inline
group2<T1,T2>
group_head( group3<T1,T2,T3> const& x)
{
return group2<T1,T2> (x.a1_,x.a2_);
}
template <class T1,class T2,class T3>
inline
group1<T3>
group_last( group3<T1,T2,T3> const& x)
{
return group1<T3> (x.a3_);
}
template <class T1,class T2,class T3,class T4>
inline
group3<T1,T2,T3>
group_head( group4<T1,T2,T3,T4> const& x)
{
return group3<T1,T2,T3> (x.a1_,x.a2_,x.a3_);
}
template <class T1,class T2,class T3,class T4>
inline
group1<T4>
group_last( group4<T1,T2,T3,T4> const& x)
{
return group1<T4> (x.a4_);
}
template <class T1,class T2,class T3,class T4,class T5>
inline
group4<T1,T2,T3,T4>
group_head( group5<T1,T2,T3,T4,T5> const& x)
{
return group4<T1,T2,T3,T4> (x.a1_,x.a2_,x.a3_,x.a4_);
}
template <class T1,class T2,class T3,class T4,class T5>
inline
group1<T5>
group_last( group5<T1,T2,T3,T4,T5> const& x)
{
return group1<T5> (x.a5_);
}
template <class T1,class T2,class T3,class T4,class T5,class T6>
inline
group5<T1,T2,T3,T4,T5>
group_head( group6<T1,T2,T3,T4,T5,T6> const& x)
{
return group5<T1,T2,T3,T4,T5> (x.a1_,x.a2_,x.a3_,x.a4_,x.a5_);
}
template <class T1,class T2,class T3,class T4,class T5,class T6>
inline
group1<T6>
group_last( group6<T1,T2,T3,T4,T5,T6> const& x)
{
return group1<T6> (x.a6_);
}
template <class T1,class T2,class T3,class T4,class T5,class T6,class T7>
inline
group6<T1,T2,T3,T4,T5,T6>
group_head( group7<T1,T2,T3,T4,T5,T6,T7> const& x)
{
return group6<T1,T2,T3,T4,T5,T6> (x.a1_,x.a2_,x.a3_,x.a4_,x.a5_,x.a6_);
}
template <class T1,class T2,class T3,class T4,class T5,class T6,class T7>
inline
group1<T7>
group_last( group7<T1,T2,T3,T4,T5,T6,T7> const& x)
{
return group1<T7> (x.a7_);
}
template <class T1,class T2,class T3,class T4,class T5,class T6,class T7,class T8>
inline
group7<T1,T2,T3,T4,T5,T6,T7>
group_head( group8<T1,T2,T3,T4,T5,T6,T7,T8> const& x)
{
return group7<T1,T2,T3,T4,T5,T6,T7> (x.a1_,x.a2_,x.a3_,x.a4_,x.a5_,x.a6_,x.a7_);
}
template <class T1,class T2,class T3,class T4,class T5,class T6,class T7,class T8>
inline
group1<T8>
group_last( group8<T1,T2,T3,T4,T5,T6,T7,T8> const& x)
{
return group1<T8> (x.a8_);
}
template <class T1,class T2,class T3,class T4,class T5,class T6,class T7,class T8,class T9>
inline
group8<T1,T2,T3,T4,T5,T6,T7,T8>
group_head( group9<T1,T2,T3,T4,T5,T6,T7,T8,T9> const& x)
{
return group8<T1,T2,T3,T4,T5,T6,T7,T8> (x.a1_,x.a2_,x.a3_,x.a4_,x.a5_,x.a6_,x.a7_,x.a8_);
}
template <class T1,class T2,class T3,class T4,class T5,class T6,class T7,class T8,class T9>
inline
group1<T9>
group_last( group9<T1,T2,T3,T4,T5,T6,T7,T8,T9> const& x)
{
return group1<T9> (x.a9_);
}
template <class T1,class T2,class T3,class T4,class T5,class T6,class T7,class T8,class T9,class T10>
inline
group9<T1,T2,T3,T4,T5,T6,T7,T8,T9>
group_head( group10<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10> const& x)
{
return group9<T1,T2,T3,T4,T5,T6,T7,T8,T9> (x.a1_,x.a2_,x.a3_,x.a4_,x.a5_,x.a6_,x.a7_,x.a8_,x.a9_);
}
template <class T1,class T2,class T3,class T4,class T5,class T6,class T7,class T8,class T9,class T10>
inline
group1<T10>
group_last( group10<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10> const& x)
{
return group1<T10> (x.a10_);
}
} // namespace detail
// helper functions
inline detail::group1< detail::group0 >
group() { return detail::group1< detail::group0 > ( detail::group0() ); }
template <class T1, class Var>
inline
detail::group1< detail::group2<T1, Var const&> >
group(T1 a1, Var const& var)
{
return detail::group1< detail::group2<T1, Var const&> >
( detail::group2<T1, Var const&>
(a1, var)
);
}
template <class T1,class T2, class Var>
inline
detail::group1< detail::group3<T1,T2, Var const&> >
group(T1 a1,T2 a2, Var const& var)
{
return detail::group1< detail::group3<T1,T2, Var const&> >
( detail::group3<T1,T2, Var const&>
(a1,a2, var)
);
}
template <class T1,class T2,class T3, class Var>
inline
detail::group1< detail::group4<T1,T2,T3, Var const&> >
group(T1 a1,T2 a2,T3 a3, Var const& var)
{
return detail::group1< detail::group4<T1,T2,T3, Var const&> >
( detail::group4<T1,T2,T3, Var const&>
(a1,a2,a3, var)
);
}
template <class T1,class T2,class T3,class T4, class Var>
inline
detail::group1< detail::group5<T1,T2,T3,T4, Var const&> >
group(T1 a1,T2 a2,T3 a3,T4 a4, Var const& var)
{
return detail::group1< detail::group5<T1,T2,T3,T4, Var const&> >
( detail::group5<T1,T2,T3,T4, Var const&>
(a1,a2,a3,a4, var)
);
}
template <class T1,class T2,class T3,class T4,class T5, class Var>
inline
detail::group1< detail::group6<T1,T2,T3,T4,T5, Var const&> >
group(T1 a1,T2 a2,T3 a3,T4 a4,T5 a5, Var const& var)
{
return detail::group1< detail::group6<T1,T2,T3,T4,T5, Var const&> >
( detail::group6<T1,T2,T3,T4,T5, Var const&>
(a1,a2,a3,a4,a5, var)
);
}
template <class T1,class T2,class T3,class T4,class T5,class T6, class Var>
inline
detail::group1< detail::group7<T1,T2,T3,T4,T5,T6, Var const&> >
group(T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6, Var const& var)
{
return detail::group1< detail::group7<T1,T2,T3,T4,T5,T6, Var const&> >
( detail::group7<T1,T2,T3,T4,T5,T6, Var const&>
(a1,a2,a3,a4,a5,a6, var)
);
}
template <class T1,class T2,class T3,class T4,class T5,class T6,class T7, class Var>
inline
detail::group1< detail::group8<T1,T2,T3,T4,T5,T6,T7, Var const&> >
group(T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6,T7 a7, Var const& var)
{
return detail::group1< detail::group8<T1,T2,T3,T4,T5,T6,T7, Var const&> >
( detail::group8<T1,T2,T3,T4,T5,T6,T7, Var const&>
(a1,a2,a3,a4,a5,a6,a7, var)
);
}
template <class T1,class T2,class T3,class T4,class T5,class T6,class T7,class T8, class Var>
inline
detail::group1< detail::group9<T1,T2,T3,T4,T5,T6,T7,T8, Var const&> >
group(T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6,T7 a7,T8 a8, Var const& var)
{
return detail::group1< detail::group9<T1,T2,T3,T4,T5,T6,T7,T8, Var const&> >
( detail::group9<T1,T2,T3,T4,T5,T6,T7,T8, Var const&>
(a1,a2,a3,a4,a5,a6,a7,a8, var)
);
}
template <class T1,class T2,class T3,class T4,class T5,class T6,class T7,class T8,class T9, class Var>
inline
detail::group1< detail::group10<T1,T2,T3,T4,T5,T6,T7,T8,T9, Var const&> >
group(T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6,T7 a7,T8 a8,T9 a9, Var const& var)
{
return detail::group1< detail::group10<T1,T2,T3,T4,T5,T6,T7,T8,T9, Var const&> >
( detail::group10<T1,T2,T3,T4,T5,T6,T7,T8,T9, Var const&>
(a1,a2,a3,a4,a5,a6,a7,a8,a9, var)
);
}
#ifndef BOOST_NO_OVERLOAD_FOR_NON_CONST
template <class T1, class Var>
inline
detail::group1< detail::group2<T1, Var&> >
group(T1 a1, Var& var)
{
return detail::group1< detail::group2<T1, Var&> >
( detail::group2<T1, Var&>
(a1, var)
);
}
template <class T1,class T2, class Var>
inline
detail::group1< detail::group3<T1,T2, Var&> >
group(T1 a1,T2 a2, Var& var)
{
return detail::group1< detail::group3<T1,T2, Var&> >
( detail::group3<T1,T2, Var&>
(a1,a2, var)
);
}
template <class T1,class T2,class T3, class Var>
inline
detail::group1< detail::group4<T1,T2,T3, Var&> >
group(T1 a1,T2 a2,T3 a3, Var& var)
{
return detail::group1< detail::group4<T1,T2,T3, Var&> >
( detail::group4<T1,T2,T3, Var&>
(a1,a2,a3, var)
);
}
template <class T1,class T2,class T3,class T4, class Var>
inline
detail::group1< detail::group5<T1,T2,T3,T4, Var&> >
group(T1 a1,T2 a2,T3 a3,T4 a4, Var& var)
{
return detail::group1< detail::group5<T1,T2,T3,T4, Var&> >
( detail::group5<T1,T2,T3,T4, Var&>
(a1,a2,a3,a4, var)
);
}
template <class T1,class T2,class T3,class T4,class T5, class Var>
inline
detail::group1< detail::group6<T1,T2,T3,T4,T5, Var&> >
group(T1 a1,T2 a2,T3 a3,T4 a4,T5 a5, Var& var)
{
return detail::group1< detail::group6<T1,T2,T3,T4,T5, Var&> >
( detail::group6<T1,T2,T3,T4,T5, Var&>
(a1,a2,a3,a4,a5, var)
);
}
template <class T1,class T2,class T3,class T4,class T5,class T6, class Var>
inline
detail::group1< detail::group7<T1,T2,T3,T4,T5,T6, Var&> >
group(T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6, Var& var)
{
return detail::group1< detail::group7<T1,T2,T3,T4,T5,T6, Var&> >
( detail::group7<T1,T2,T3,T4,T5,T6, Var&>
(a1,a2,a3,a4,a5,a6, var)
);
}
template <class T1,class T2,class T3,class T4,class T5,class T6,class T7, class Var>
inline
detail::group1< detail::group8<T1,T2,T3,T4,T5,T6,T7, Var&> >
group(T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6,T7 a7, Var& var)
{
return detail::group1< detail::group8<T1,T2,T3,T4,T5,T6,T7, Var&> >
( detail::group8<T1,T2,T3,T4,T5,T6,T7, Var&>
(a1,a2,a3,a4,a5,a6,a7, var)
);
}
template <class T1,class T2,class T3,class T4,class T5,class T6,class T7,class T8, class Var>
inline
detail::group1< detail::group9<T1,T2,T3,T4,T5,T6,T7,T8, Var&> >
group(T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6,T7 a7,T8 a8, Var& var)
{
return detail::group1< detail::group9<T1,T2,T3,T4,T5,T6,T7,T8, Var&> >
( detail::group9<T1,T2,T3,T4,T5,T6,T7,T8, Var&>
(a1,a2,a3,a4,a5,a6,a7,a8, var)
);
}
template <class T1,class T2,class T3,class T4,class T5,class T6,class T7,class T8,class T9, class Var>
inline
detail::group1< detail::group10<T1,T2,T3,T4,T5,T6,T7,T8,T9, Var&> >
group(T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6,T7 a7,T8 a8,T9 a9, Var& var)
{
return detail::group1< detail::group10<T1,T2,T3,T4,T5,T6,T7,T8,T9, Var&> >
( detail::group10<T1,T2,T3,T4,T5,T6,T7,T8,T9, Var&>
(a1,a2,a3,a4,a5,a6,a7,a8,a9, var)
);
}
#endif //end- #ifndef BOOST_NO_OVERLOAD_FOR_NON_CONST
} // namespace io
} // namespace boost
#endif // BOOST_FORMAT_GROUP_HPP

View File

@@ -0,0 +1,167 @@
// -*- C++ -*-
// Boost general library 'format' ---------------------------
// See http://www.boost.org for updates, documentation, and revision history.
// (C) Samuel Krempp 2001
// krempp@crans.ens-cachan.fr
// Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
// ideas taken from Rüdiger Loos's format class
// and Karl Nelson's ofstream
// ----------------------------------------------------------------------------
// internals.hpp : internal structs. included by format.hpp
// stream_format_state, and format_item
// ----------------------------------------------------------------------------
#ifndef BOOST_FORMAT_INTERNALS_HPP
#define BOOST_FORMAT_INTERNALS_HPP
#include <string>
#include <sstream>
namespace boost {
namespace io {
namespace detail {
// --------------
// set of params that define the format state of a stream
struct stream_format_state
{
typedef std::ios basic_ios;
std::streamsize width_;
std::streamsize precision_;
char fill_;
std::ios::fmtflags flags_;
stream_format_state() : width_(-1), precision_(-1), fill_(0), flags_(std::ios::dec) {}
stream_format_state(basic_ios& os) {set_by_stream(os); }
void apply_on(basic_ios & os) const; //- applies format_state to the stream
template<class T> void apply_manip(T manipulator) //- modifies state by applying manipulator.
{ apply_manip_body<T>( *this, manipulator) ; }
void reset(); //- sets to default state.
void set_by_stream(const basic_ios& os); //- sets to os's state.
};
// --------------
// format_item : stores all parameters that can be defined by directives in the format-string
struct format_item
{
enum pad_values { zeropad = 1, spacepad =2, centered=4, tabulation = 8 };
enum arg_values { argN_no_posit = -1, // non-positional directive. argN will be set later.
argN_tabulation = -2, // tabulation directive. (no argument read)
argN_ignored = -3 // ignored directive. (no argument read)
};
typedef BOOST_IO_STD ios basic_ios;
typedef detail::stream_format_state stream_format_state;
typedef std::string string_t;
typedef BOOST_IO_STD ostringstream internal_stream_t;
int argN_; //- argument number (starts at 0, eg : %1 => argN=0)
// negative values are used for items that don't process
// an argument
string_t res_; //- result of the formatting of this item
string_t appendix_; //- piece of string between this item and the next
stream_format_state ref_state_;// set by parsing the format_string, is only affected by modify_item
stream_format_state state_; // always same as ref_state, _unless_ modified by manipulators 'group(..)'
// non-stream format-state parameters
signed int truncate_; //- is >=0 for directives like %.5s (take 5 chars from the string)
unsigned int pad_scheme_; //- several possible padding schemes can mix. see pad_values
format_item() : argN_(argN_no_posit), truncate_(-1), pad_scheme_(0) {}
void compute_states(); // sets states according to truncate and pad_scheme.
};
// -----------------------------------------------------------
// Definitions
// -----------------------------------------------------------
// --- stream_format_state:: -------------------------------------------
inline
void stream_format_state::apply_on(basic_ios & os) const
// set the state of this stream according to our params
{
if(width_ != -1)
os.width(width_);
if(precision_ != -1)
os.precision(precision_);
if(fill_ != 0)
os.fill(fill_);
os.flags(flags_);
}
inline
void stream_format_state::set_by_stream(const basic_ios& os)
// set our params according to the state of this stream
{
flags_ = os.flags();
width_ = os.width();
precision_ = os.precision();
fill_ = os.fill();
}
template<class T> inline
void apply_manip_body( stream_format_state& self,
T manipulator)
// modify our params according to the manipulator
{
BOOST_IO_STD stringstream ss;
self.apply_on( ss );
ss << manipulator;
self.set_by_stream( ss );
}
inline
void stream_format_state::reset()
// set our params to standard's default state
{
width_=-1; precision_=-1; fill_=0;
flags_ = std::ios::dec;
}
// --- format_items:: -------------------------------------------
inline
void format_item::compute_states()
// reflect pad_scheme_ on state_ and ref_state_
// because some pad_schemes has complex consequences on several state params.
{
if(pad_scheme_ & zeropad)
{
if(ref_state_.flags_ & std::ios::left)
{
pad_scheme_ = pad_scheme_ & (~zeropad); // ignore zeropad in left alignment
}
else
{
ref_state_.fill_='0';
ref_state_.flags_ |= std::ios::internal;
}
}
state_ = ref_state_;
}
} } } // namespaces boost :: io :: detail
#endif // BOOST_FORMAT_INTERNALS_HPP

View File

@@ -0,0 +1,65 @@
// -*- C++ -*-
// Boost general library 'format' ---------------------------
// See http://www.boost.org for updates, documentation, and revision history.
// (C) Samuel Krempp 2001
// krempp@crans.ens-cachan.fr
// Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
// ideas taken from Rüdiger Loos's format class
// and Karl Nelson's ofstream (also took its parsing code as basis for printf parsing)
// ------------------------------------------------------------------------------
// internals_fwd.hpp : forward declarations, for internal headers
// ------------------------------------------------------------------------------
#ifndef BOOST_FORMAT_INTERNAL_FWD_HPP
#define BOOST_FORMAT_INTERNAL_FWD_HPP
#include "boost/format/format_fwd.hpp"
namespace boost {
namespace io {
namespace detail {
struct stream_format_state;
struct format_item;
}
namespace detail {
// these functions were intended as methods,
// but MSVC have problems with template member functions :
// defined in format_implementation.hpp :
template<class T>
basic_format& modify_item_body( basic_format& self,
int itemN, const T& manipulator);
template<class T>
basic_format& bind_arg_body( basic_format& self,
int argN, const T& val);
template<class T>
void apply_manip_body( stream_format_state& self,
T manipulator);
// argument feeding (defined in feed_args.hpp ) :
template<class T>
void distribute(basic_format& self, T x);
template<class T>
basic_format& feed(basic_format& self, T x);
} // namespace detail
} // namespace io
} // namespace boost
#endif // BOOST_FORMAT_INTERNAL_FWD_HPP

View File

@@ -0,0 +1,7 @@
libraries += libformat
libformat_NAME = libnixformat
libformat_DIR := $(d)
libformat_SOURCES := $(wildcard $(d)/*.cc)

View File

@@ -0,0 +1,48 @@
// -*- C++ -*-
// Boost general library 'format' ---------------------------
// See http://www.boost.org for updates, documentation, and revision history.
// (C) Samuel Krempp 2001
// krempp@crans.ens-cachan.fr
// Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
// ideas taken from Rüdiger Loos's format class
// and Karl Nelson's ofstream (also took its parsing code as basis for printf parsing)
// ------------------------------------------------------------------------------
// macros_default.hpp : configuration for the format library
// provides default values for the stl workaround macros
// ------------------------------------------------------------------------------
#ifndef BOOST_FORMAT_MACROS_DEFAULT_HPP
#define BOOST_FORMAT_MACROS_DEFAULT_HPP
// *** This should go to "boost/config/suffix.hpp".
#ifndef BOOST_IO_STD
# define BOOST_IO_STD std::
#endif
// **** Workaround for io streams, stlport and msvc.
#ifdef BOOST_IO_NEEDS_USING_DECLARATION
namespace boost {
using std::char_traits;
using std::basic_ostream;
using std::basic_ostringstream;
namespace io {
using std::basic_ostream;
namespace detail {
using std::basic_ios;
using std::basic_ostream;
using std::basic_ostringstream;
}
}
}
#endif
// ------------------------------------------------------------------------------
#endif // BOOST_FORMAT_MACROS_DEFAULT_HPP

454
src/boost/format/parsing.cc Normal file
View File

@@ -0,0 +1,454 @@
// -*- C++ -*-
// Boost general library 'format' ---------------------------
// See http://www.boost.org for updates, documentation, and revision history.
// (C) Samuel Krempp 2001
// krempp@crans.ens-cachan.fr
// Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
// ideas taken from Rudiger Loos's format class
// and Karl Nelson's ofstream (also took its parsing code as basis for printf parsing)
// ------------------------------------------------------------------------------
// parsing.hpp : implementation of the parsing member functions
// ( parse, parse_printf_directive)
// ------------------------------------------------------------------------------
#ifndef BOOST_FORMAT_PARSING_HPP
#define BOOST_FORMAT_PARSING_HPP
#include <boost/format.hpp>
#include <boost/throw_exception.hpp>
#include <boost/assert.hpp>
namespace boost {
namespace io {
namespace detail {
template<class Stream> inline
bool wrap_isdigit(char c, Stream &os)
{
#ifndef BOOST_NO_LOCALE_ISIDIGIT
return std::isdigit(c, os.rdbuf()->getloc() );
# else
using namespace std;
return isdigit(c);
#endif
} //end- wrap_isdigit(..)
template<class Res> inline
Res str2int(const std::string& s,
std::string::size_type start,
BOOST_IO_STD ios &os,
const Res = Res(0) )
// Input : char string, with starting index
// a basic_ios& merely to call its widen/narrow member function in the desired locale.
// Effects : reads s[start:] and converts digits into an integral n, of type Res
// Returns : n
{
Res n = 0;
while(start<s.size() && wrap_isdigit(s[start], os) ) {
char cur_ch = s[start];
BOOST_ASSERT(cur_ch != 0 ); // since we called isdigit, this should not happen.
n *= 10;
n += cur_ch - '0'; // 22.2.1.1.2 of the C++ standard
++start;
}
return n;
}
void skip_asterisk(const std::string & buf,
std::string::size_type * pos_p,
BOOST_IO_STD ios &os)
// skip printf's "asterisk-fields" directives in the format-string buf
// Input : char string, with starting index *pos_p
// a basic_ios& merely to call its widen/narrow member function in the desired locale.
// Effects : advance *pos_p by skipping printf's asterisk fields.
// Returns : nothing
{
using namespace std;
BOOST_ASSERT( pos_p != 0);
if(*pos_p >= buf.size() ) return;
if(buf[ *pos_p]=='*') {
++ (*pos_p);
while (*pos_p < buf.size() && wrap_isdigit(buf[*pos_p],os)) ++(*pos_p);
if(buf[*pos_p]=='$') ++(*pos_p);
}
}
inline void maybe_throw_exception( unsigned char exceptions)
// auxiliary func called by parse_printf_directive
// for centralising error handling
// it either throws if user sets the corresponding flag, or does nothing.
{
if(exceptions & io::bad_format_string_bit)
boost::throw_exception(io::bad_format_string());
}
bool parse_printf_directive(const std::string & buf,
std::string::size_type * pos_p,
detail::format_item * fpar,
BOOST_IO_STD ios &os,
unsigned char exceptions)
// Input : a 'printf-directive' in the format-string, starting at buf[ *pos_p ]
// a basic_ios& merely to call its widen/narrow member function in the desired locale.
// a bitset'excpetions' telling whether to throw exceptions on errors.
// Returns : true if parse somehow succeeded (possibly ignoring errors if exceptions disabled)
// false if it failed so bad that the directive should be printed verbatim
// Effects : - *pos_p is incremented so that buf[*pos_p] is the first char after the directive
// - *fpar is set with the parameters read in the directive
{
typedef format_item format_item_t;
BOOST_ASSERT( pos_p != 0);
std::string::size_type &i1 = *pos_p,
i0;
fpar->argN_ = format_item_t::argN_no_posit; // if no positional-directive
bool in_brackets=false;
if(buf[i1]=='|')
{
in_brackets=true;
if( ++i1 >= buf.size() ) {
maybe_throw_exception(exceptions);
return false;
}
}
// the flag '0' would be picked as a digit for argument order, but here it's a flag :
if(buf[i1]=='0')
goto parse_flags;
// handle argument order (%2$d) or possibly width specification: %2d
i0 = i1; // save position before digits
while (i1 < buf.size() && wrap_isdigit(buf[i1], os))
++i1;
if (i1!=i0)
{
if( i1 >= buf.size() ) {
maybe_throw_exception(exceptions);
return false;
}
int n=str2int(buf,i0, os, int(0) );
// %N% case : this is already the end of the directive
if( buf[i1] == '%' )
{
fpar->argN_ = n-1;
++i1;
if( in_brackets)
maybe_throw_exception(exceptions);
// but don't return. maybe "%" was used in lieu of '$', so we go on.
else return true;
}
if ( buf[i1]=='$' )
{
fpar->argN_ = n-1;
++i1;
}
else
{
// non-positionnal directive
fpar->ref_state_.width_ = n;
fpar->argN_ = format_item_t::argN_no_posit;
goto parse_precision;
}
}
parse_flags:
// handle flags
while ( i1 <buf.size()) // as long as char is one of + - = # 0 l h or ' '
{
// misc switches
switch (buf[i1])
{
case '\'' : break; // no effect yet. (painful to implement)
case 'l':
case 'h': // short/long modifier : for printf-comaptibility (no action needed)
break;
case '-':
fpar->ref_state_.flags_ |= std::ios::left;
break;
case '=':
fpar->pad_scheme_ |= format_item_t::centered;
break;
case ' ':
fpar->pad_scheme_ |= format_item_t::spacepad;
break;
case '+':
fpar->ref_state_.flags_ |= std::ios::showpos;
break;
case '0':
fpar->pad_scheme_ |= format_item_t::zeropad;
// need to know alignment before really setting flags,
// so just add 'zeropad' flag for now, it will be processed later.
break;
case '#':
fpar->ref_state_.flags_ |= std::ios::showpoint | std::ios::showbase;
break;
default:
goto parse_width;
}
++i1;
} // loop on flag.
if( i1>=buf.size()) {
maybe_throw_exception(exceptions);
return true;
}
parse_width:
// handle width spec
skip_asterisk(buf, &i1, os); // skips 'asterisk fields' : *, or *N$
i0 = i1; // save position before digits
while (i1<buf.size() && wrap_isdigit(buf[i1], os))
i1++;
if (i1!=i0)
{ fpar->ref_state_.width_ = str2int( buf,i0, os, std::streamsize(0) ); }
parse_precision:
if( i1>=buf.size()) {
maybe_throw_exception(exceptions);
return true;
}
// handle precision spec
if (buf[i1]=='.')
{
++i1;
skip_asterisk(buf, &i1, os);
i0 = i1; // save position before digits
while (i1<buf.size() && wrap_isdigit(buf[i1], os))
++i1;
if(i1==i0)
fpar->ref_state_.precision_ = 0;
else
fpar->ref_state_.precision_ = str2int(buf,i0, os, std::streamsize(0) );
}
// handle formatting-type flags :
while( i1<buf.size() &&
( buf[i1]=='l' || buf[i1]=='L' || buf[i1]=='h') )
++i1;
if( i1>=buf.size()) {
maybe_throw_exception(exceptions);
return true;
}
if( in_brackets && buf[i1]=='|' )
{
++i1;
return true;
}
switch (buf[i1])
{
case 'X':
fpar->ref_state_.flags_ |= std::ios::uppercase;
case 'p': // pointer => set hex.
case 'x':
fpar->ref_state_.flags_ &= ~std::ios::basefield;
fpar->ref_state_.flags_ |= std::ios::hex;
break;
case 'o':
fpar->ref_state_.flags_ &= ~std::ios::basefield;
fpar->ref_state_.flags_ |= std::ios::oct;
break;
case 'E':
fpar->ref_state_.flags_ |= std::ios::uppercase;
case 'e':
fpar->ref_state_.flags_ &= ~std::ios::floatfield;
fpar->ref_state_.flags_ |= std::ios::scientific;
fpar->ref_state_.flags_ &= ~std::ios::basefield;
fpar->ref_state_.flags_ |= std::ios::dec;
break;
case 'f':
fpar->ref_state_.flags_ &= ~std::ios::floatfield;
fpar->ref_state_.flags_ |= std::ios::fixed;
case 'u':
case 'd':
case 'i':
fpar->ref_state_.flags_ &= ~std::ios::basefield;
fpar->ref_state_.flags_ |= std::ios::dec;
break;
case 'T':
++i1;
if( i1 >= buf.size())
maybe_throw_exception(exceptions);
else
fpar->ref_state_.fill_ = buf[i1];
fpar->pad_scheme_ |= format_item_t::tabulation;
fpar->argN_ = format_item_t::argN_tabulation;
break;
case 't':
fpar->ref_state_.fill_ = ' ';
fpar->pad_scheme_ |= format_item_t::tabulation;
fpar->argN_ = format_item_t::argN_tabulation;
break;
case 'G':
fpar->ref_state_.flags_ |= std::ios::uppercase;
break;
case 'g': // 'g' conversion is default for floats.
fpar->ref_state_.flags_ &= ~std::ios::basefield;
fpar->ref_state_.flags_ |= std::ios::dec;
// CLEAR all floatield flags, so stream will CHOOSE
fpar->ref_state_.flags_ &= ~std::ios::floatfield;
break;
case 'C':
case 'c':
fpar->truncate_ = 1;
break;
case 'S':
case 's':
fpar->truncate_ = fpar->ref_state_.precision_;
fpar->ref_state_.precision_ = -1;
break;
case 'n' :
fpar->argN_ = format_item_t::argN_ignored;
break;
default:
maybe_throw_exception(exceptions);
}
++i1;
if( in_brackets )
{
if( i1<buf.size() && buf[i1]=='|' )
{
++i1;
return true;
}
else maybe_throw_exception(exceptions);
}
return true;
}
} // detail namespace
} // io namespace
// -----------------------------------------------
// format :: parse(..)
void basic_format::parse(const string_t & buf)
// parse the format-string
{
using namespace std;
const char arg_mark = '%';
bool ordered_args=true;
int max_argN=-1;
string_t::size_type i1=0;
int num_items=0;
// A: find upper_bound on num_items and allocates arrays
i1=0;
while( (i1=buf.find(arg_mark,i1)) != string::npos )
{
if( i1+1 >= buf.size() ) {
if(exceptions() & io::bad_format_string_bit)
boost::throw_exception(io::bad_format_string()); // must not end in "bla bla %"
else break; // stop there, ignore last '%'
}
if(buf[i1+1] == buf[i1] ) { i1+=2; continue; } // escaped "%%" / "##"
++i1;
// in case of %N% directives, dont count it double (wastes allocations..) :
while(i1 < buf.size() && io::detail::wrap_isdigit(buf[i1],oss_)) ++i1;
if( i1 < buf.size() && buf[i1] == arg_mark ) ++ i1;
++num_items;
}
items_.assign( num_items, format_item_t() );
// B: Now the real parsing of the format string :
num_items=0;
i1 = 0;
string_t::size_type i0 = i1;
bool special_things=false;
int cur_it=0;
while( (i1=buf.find(arg_mark,i1)) != string::npos )
{
string_t & piece = (cur_it==0) ? prefix_ : items_[cur_it-1].appendix_;
if( buf[i1+1] == buf[i1] ) // escaped mark, '%%'
{
piece += buf.substr(i0, i1-i0) + buf[i1];
i1+=2; i0=i1;
continue;
}
BOOST_ASSERT( static_cast<unsigned int>(cur_it) < items_.size() || cur_it==0);
if(i1!=i0) piece += buf.substr(i0, i1-i0);
++i1;
bool parse_ok;
parse_ok = io::detail::parse_printf_directive(buf, &i1, &items_[cur_it], oss_, exceptions());
if( ! parse_ok ) continue; // the directive will be printed verbatim
i0=i1;
items_[cur_it].compute_states(); // process complex options, like zeropad, into stream params.
int argN=items_[cur_it].argN_;
if(argN == format_item_t::argN_ignored)
continue;
if(argN ==format_item_t::argN_no_posit)
ordered_args=false;
else if(argN == format_item_t::argN_tabulation) special_things=true;
else if(argN > max_argN) max_argN = argN;
++num_items;
++cur_it;
} // loop on %'s
BOOST_ASSERT(cur_it == num_items);
// store the final piece of string
string_t & piece = (cur_it==0) ? prefix_ : items_[cur_it-1].appendix_;
piece += buf.substr(i0);
if( !ordered_args)
{
if(max_argN >= 0 ) // dont mix positional with non-positionnal directives
{
if(exceptions() & io::bad_format_string_bit)
boost::throw_exception(io::bad_format_string());
// else do nothing. => positionnal arguments are processed as non-positionnal
}
// set things like it would have been with positional directives :
int non_ordered_items = 0;
for(int i=0; i< num_items; ++i)
if(items_[i].argN_ == format_item_t::argN_no_posit)
{
items_[i].argN_ = non_ordered_items;
++non_ordered_items;
}
max_argN = non_ordered_items-1;
}
// C: set some member data :
items_.resize(num_items);
if(special_things) style_ |= special_needs;
num_args_ = max_argN + 1;
if(ordered_args) style_ |= ordered;
else style_ &= ~ordered;
}
} // namespace boost
#endif // BOOST_FORMAT_PARSING_HPP

View File

@@ -0,0 +1,47 @@
#ifndef BOOST_THROW_EXCEPTION_HPP_INCLUDED
#define BOOST_THROW_EXCEPTION_HPP_INCLUDED
// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
//
// boost/throw_exception.hpp
//
// Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
//
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies.
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// http://www.boost.org/libs/utility/throw_exception.html
//
//#include <boost/config.hpp>
#ifdef BOOST_NO_EXCEPTIONS
# include <exception>
#endif
namespace boost
{
#ifdef BOOST_NO_EXCEPTIONS
void throw_exception(std::exception const & e); // user defined
#else
template<class E> void throw_exception(E const & e)
{
throw e;
}
#endif
} // namespace boost
#endif // #ifndef BOOST_THROW_EXCEPTION_HPP_INCLUDED

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,9 +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 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. */
@@ -79,7 +80,7 @@ static int _main(int argc, char * * argv)
if (machines.empty()) {
std::cerr << "# decline-permanently\n";
return 0;
return;
}
string drvPath;
@@ -89,17 +90,15 @@ 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);
auto canBuildLocally = amWilling && (neededSystem == settings.thisSystem);
/* Error ignored here, will be caught later */
mkdir(currentLoad.c_str(), 0777);
@@ -192,10 +191,8 @@ static int _main(int argc, char * * argv)
storeUri = bestMachine->storeUri;
} catch (std::exception & e) {
auto msg = chomp(drainFD(5, false));
printError("cannot build on '%s': %s%s",
bestMachine->storeUri, e.what(),
(msg.empty() ? "" : ": " + msg));
printError("unable to open SSH connection to '%s': %s; trying other available machines...",
bestMachine->storeUri, e.what());
bestMachine->enabled = false;
continue;
}
@@ -205,8 +202,6 @@ static int _main(int argc, char * * argv)
}
connected:
close(5);
std::cerr << "# accept\n" << storeUri << "\n";
auto inputs = readStrings<PathSet>(source);
@@ -252,8 +247,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 libutil libformat libstore
build-remote_SOURCES := $(d)/build-remote.cc

187
src/buildenv/buildenv.cc Normal file
View File

@@ -0,0 +1,187 @@
#include "shared.hh"
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <algorithm>
using namespace nix;
typedef std::map<Path,int> Priorities;
static bool isDirectory (const Path & path)
{
struct stat st;
if (stat(path.c_str(), &st) == -1)
throw SysError(format("getting status of '%1%'") % path);
return S_ISDIR(st.st_mode);
}
static auto priorities = Priorities{};
static auto symlinks = 0;
/* For each activated package, create symlinks */
static void createLinks(const Path & srcDir, const Path & dstDir, int priority)
{
auto srcFiles = readDirectory(srcDir);
for (const auto & ent : srcFiles) {
if (ent.name[0] == '.')
/* not matched by glob */
continue;
const auto & srcFile = srcDir + "/" + ent.name;
auto dstFile = dstDir + "/" + ent.name;
/* The files below are special-cased to that they don't show up
* in user profiles, either because they are useless, or
* because they would cauase pointless collisions (e.g., each
* Python package brings its own
* `$out/lib/pythonX.Y/site-packages/easy-install.pth'.)
*/
if (hasSuffix(srcFile, "/propagated-build-inputs") ||
hasSuffix(srcFile, "/nix-support") ||
hasSuffix(srcFile, "/perllocal.pod") ||
hasSuffix(srcFile, "/info/dir") ||
hasSuffix(srcFile, "/log")) {
continue;
} else if (isDirectory(srcFile)) {
struct stat dstSt;
auto res = lstat(dstFile.c_str(), &dstSt);
if (res == 0) {
if (S_ISDIR(dstSt.st_mode)) {
createLinks(srcFile, dstFile, priority);
continue;
} else if (S_ISLNK(dstSt.st_mode)) {
auto target = readLink(dstFile);
if (!isDirectory(target))
throw Error(format("collision between '%1%' and non-directory '%2%'")
% srcFile % target);
if (unlink(dstFile.c_str()) == -1)
throw SysError(format("unlinking '%1%'") % dstFile);
if (mkdir(dstFile.c_str(), 0755) == -1)
throw SysError(format("creating directory '%1%'"));
createLinks(target, dstFile, priorities[dstFile]);
createLinks(srcFile, dstFile, priority);
continue;
}
} else if (errno != ENOENT)
throw SysError(format("getting status of '%1%'") % dstFile);
} else {
struct stat dstSt;
auto res = lstat(dstFile.c_str(), &dstSt);
if (res == 0) {
if (S_ISLNK(dstSt.st_mode)) {
auto target = readLink(dstFile);
auto prevPriority = priorities[dstFile];
if (prevPriority == priority)
throw Error(format(
"packages '%1%' and '%2%' have the same priority %3%; "
"use 'nix-env --set-flag priority NUMBER INSTALLED_PKGNAME' "
"to change the priority of one of the conflicting packages"
" (0 being the highest priority)"
) % srcFile % target % priority);
if (prevPriority < priority)
continue;
if (unlink(dstFile.c_str()) == -1)
throw SysError(format("unlinking '%1%'") % dstFile);
}
} else if (errno != ENOENT)
throw SysError(format("getting status of '%1%'") % dstFile);
}
createSymlink(srcFile, dstFile);
priorities[dstFile] = priority;
symlinks++;
}
}
typedef std::set<Path> FileProp;
static auto done = FileProp{};
static auto postponed = FileProp{};
static auto out = string{};
static void addPkg(const Path & pkgDir, int priority)
{
if (done.find(pkgDir) != done.end())
return;
done.insert(pkgDir);
createLinks(pkgDir, out, priority);
auto propagatedFN = pkgDir + "/nix-support/propagated-user-env-packages";
auto propagated = string{};
{
AutoCloseFD fd = open(propagatedFN.c_str(), O_RDONLY | O_CLOEXEC);
if (!fd) {
if (errno == ENOENT)
return;
throw SysError(format("opening '%1%'") % propagatedFN);
}
propagated = readFile(fd.get());
}
for (const auto & p : tokenizeString<std::vector<string>>(propagated, " \n"))
if (done.find(p) == done.end())
postponed.insert(p);
}
struct Package {
Path path;
bool active;
int priority;
Package(Path path, bool active, int priority) : path{std::move(path)}, active{active}, priority{priority} {}
};
typedef std::vector<Package> Packages;
int main(int argc, char ** argv)
{
return handleExceptions(argv[0], [&]() {
initNix();
out = getEnv("out");
if (mkdir(out.c_str(), 0755) == -1)
throw SysError(format("creating %1%") % out);
/* Convert the stuff we get from the environment back into a coherent
* data type.
*/
auto pkgs = Packages{};
auto derivations = tokenizeString<Strings>(getEnv("derivations"));
while (!derivations.empty()) {
/* !!! We're trusting the caller to structure derivations env var correctly */
auto active = derivations.front(); derivations.pop_front();
auto priority = stoi(derivations.front()); derivations.pop_front();
auto outputs = stoi(derivations.front()); derivations.pop_front();
for (auto n = 0; n < outputs; n++) {
auto path = derivations.front(); derivations.pop_front();
pkgs.emplace_back(path, active != "false", priority);
}
}
/* Symlink to the packages that have been installed explicitly by the
* user. Process in priority order to reduce unnecessary
* symlink/unlink steps.
*/
std::sort(pkgs.begin(), pkgs.end(), [](const Package & a, const Package & b) {
return a.priority < b.priority || (a.priority == b.priority && a.path < b.path);
});
for (const auto & pkg : pkgs)
if (pkg.active)
addPkg(pkg.path, pkg.priority);
/* Symlink to the packages that have been "propagated" by packages
* installed by the user (i.e., package X declares that it wants Y
* installed as well). We do these later because they have a lower
* priority in case of collisions.
*/
auto priorityCounter = 1000;
while (!postponed.empty()) {
auto pkgDirs = postponed;
postponed = FileProp{};
for (const auto & pkgDir : pkgDirs)
addPkg(pkgDir, priorityCounter++);
}
std::cerr << "created " << symlinks << " symlinks in user environment\n";
createSymlink(getEnv("manifest"), out + "/manifest.nix");
});
}

9
src/buildenv/local.mk Normal file
View File

@@ -0,0 +1,9 @@
programs += buildenv
buildenv_DIR := $(d)
buildenv_INSTALL_DIR := $(libexecdir)/nix
buildenv_LIBS = libmain libstore libutil libformat
buildenv_SOURCES := $(d)/buildenv.cc

View File

@@ -1,18 +0,0 @@
Copyright (c) 2014 Chase Geigle
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
#include "attr-set.hh"
#include "eval-inline.hh"
#include "eval.hh"
#include <algorithm>
@@ -7,18 +7,30 @@
namespace nix {
/* Allocate a new array of attributes for an attribute set with a specific
capacity. The space is implicitly reserved after the Bindings
structure. */
Bindings * EvalState::allocBindings(size_t capacity)
/* Note: Various places expect the allocated memory to be zeroed. */
static void * allocBytes(size_t n)
{
if (capacity > std::numeric_limits<Bindings::size_t>::max())
throw Error("attribute set of size %d is too big", capacity);
return new (allocBytes(sizeof(Bindings) + sizeof(Attr) * capacity)) Bindings((Bindings::size_t) capacity);
void * p;
#if HAVE_BOEHMGC
p = GC_malloc(n);
#else
p = calloc(n, 1);
#endif
if (!p) throw std::bad_alloc();
return p;
}
void EvalState::mkAttrs(Value & v, size_t capacity)
/* Allocate a new array of attributes for an attribute set with a specific
capacity. The space is implicitly reserved after the Bindings
structure. */
Bindings * EvalState::allocBindings(Bindings::size_t capacity)
{
return new (allocBytes(sizeof(Bindings) + sizeof(Attr) * capacity)) Bindings(capacity);
}
void EvalState::mkAttrs(Value & v, unsigned int capacity)
{
if (capacity == 0) {
v = vEmptySet;

View File

@@ -78,18 +78,4 @@ inline void EvalState::forceList(Value & v, const Pos & pos)
throwTypeError("value is %1% while a list was expected, at %2%", v, pos);
}
/* Note: Various places expect the allocated memory to be zeroed. */
inline void * allocBytes(size_t n)
{
void * p;
#if HAVE_BOEHMGC
p = GC_MALLOC(n);
#else
p = calloc(n, 1);
#endif
if (!p) throw std::bad_alloc();
return p;
}
}

View File

@@ -6,16 +6,10 @@
#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>
@@ -24,8 +18,15 @@
#include <gc/gc.h>
#include <gc/gc_cpp.h>
#define NEW new (UseGC)
#else
#define NEW new
#endif
namespace nix {
@@ -33,7 +34,7 @@ static char * dupString(const char * s)
{
char * t;
#if HAVE_BOEHMGC
t = GC_STRDUP(s);
t = GC_strdup(s);
#else
t = strdup(s);
#endif
@@ -42,6 +43,20 @@ static char * dupString(const char * s)
}
/* Note: Various places expect the allocated memory to be zeroed. */
static void * allocBytes(size_t n)
{
void * p;
#if HAVE_BOEHMGC
p = GC_malloc(n);
#else
p = calloc(n, 1);
#endif
if (!p) throw std::bad_alloc();
return p;
}
static void printValue(std::ostream & str, std::set<const Value *> & active, const Value & v)
{
checkInterrupt();
@@ -130,16 +145,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 +159,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";
}
@@ -196,15 +199,8 @@ void initGC()
#if HAVE_BOEHMGC
/* Initialise the Boehm garbage collector. */
/* Don't look for interior pointers. This reduces the odds of
misdetection a bit. */
GC_set_all_interior_pointers(0);
/* We don't have any roots in data segments, so don't scan from
there. */
GC_set_no_dls(1);
GC_INIT();
GC_set_oom_fn(oomHandler);
@@ -311,17 +307,15 @@ EvalState::EvalState(const Strings & _searchPath, ref<Store> store)
assert(gcInitialised);
static_assert(sizeof(Env) <= 16, "environment must be <= 16 bytes");
/* Initialise the Nix expression search path. */
if (!evalSettings.pureEval) {
if (!settings.pureEval) {
Strings paths = parseNixPath(getEnv("NIX_PATH", ""));
for (auto & i : _searchPath) addToSearchPath(i);
for (auto & i : paths) addToSearchPath(i);
}
addToSearchPath("nix=" + canonPath(settings.nixDataDir + "/nix/corepkgs", true));
if (evalSettings.restrictEval || evalSettings.pureEval) {
if (settings.restrictEval || settings.pureEval) {
allowedPaths = PathSet();
for (auto & i : searchPath) {
@@ -350,6 +344,7 @@ EvalState::EvalState(const Strings & _searchPath, ref<Store> store)
EvalState::~EvalState()
{
fileEvalCache.clear();
}
@@ -357,37 +352,25 @@ Path EvalState::checkSourcePath(const Path & path_)
{
if (!allowedPaths) return path_;
auto i = resolvedPaths.find(path_);
if (i != resolvedPaths.end())
return i->second;
bool found = false;
/* First canonicalize the path without symlinks, so we make sure an
* attacker can't append ../../... to a path that would be in allowedPaths
* and thus leak symlink targets.
*/
Path abspath = canonPath(path_);
for (auto & i : *allowedPaths) {
if (isDirOrInDir(abspath, i)) {
if (isDirOrInDir(path_, i)) {
found = true;
break;
}
}
if (!found)
throw RestrictedPathError("access to path '%1%' is forbidden in restricted mode", abspath);
throw RestrictedPathError("access to path '%1%' is forbidden in restricted mode", path_);
/* Resolve symlinks. */
debug(format("checking access to '%s'") % abspath);
Path path = canonPath(abspath, true);
debug(format("checking access to '%s'") % path_);
Path path = canonPath(path_, true);
for (auto & i : *allowedPaths) {
if (isDirOrInDir(path, i)) {
resolvedPaths[path_] = path;
if (isDirOrInDir(path, i))
return path;
}
}
throw RestrictedPathError("access to path '%1%' is forbidden in restricted mode", path);
@@ -396,13 +379,13 @@ Path EvalState::checkSourcePath(const Path & path_)
void EvalState::checkURI(const std::string & uri)
{
if (!evalSettings.restrictEval) return;
if (!settings.restrictEval) return;
/* 'uri' should be equal to a prefix, or in a subdirectory of a
prefix. Thus, the prefix https://github.co does not permit
access to https://github.com. Note: this allows 'http://' and
'https://' as prefixes for any http/https URI. */
for (auto & prefix : evalSettings.allowedUris.get())
for (auto & prefix : settings.allowedUris.get())
if (uri == prefix ||
(uri.size() > prefix.size()
&& prefix.size() > 0
@@ -449,7 +432,7 @@ Value * EvalState::addConstant(const string & name, Value & v)
Value * EvalState::addPrimOp(const string & name,
size_t arity, PrimOpFun primOp)
unsigned int arity, PrimOpFun primOp)
{
if (arity == 0) {
Value v;
@@ -460,7 +443,7 @@ Value * EvalState::addPrimOp(const string & name,
string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name;
Symbol sym = symbols.create(name2);
v->type = tPrimOp;
v->primOp = new PrimOp(primOp, arity, sym);
v->primOp = NEW PrimOp(primOp, arity, sym);
staticBaseEnv.vars[symbols.create(name)] = baseEnvDispl;
baseEnv.values[baseEnvDispl++] = v;
baseEnv.values[0]->attrs->push_back(Attr(sym, v));
@@ -555,7 +538,7 @@ Value & mkString(Value & v, const string & s, const PathSet & context)
{
mkString(v, s.c_str());
if (!context.empty()) {
size_t n = 0;
unsigned int n = 0;
v.string.context = (const char * *)
allocBytes((context.size() + 1) * sizeof(char *));
for (auto & i : context)
@@ -574,17 +557,17 @@ void mkPath(Value & v, const char * s)
inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
{
for (size_t l = var.level; l; --l, env = env->up) ;
for (unsigned int l = var.level; l; --l, env = env->up) ;
if (!var.fromWith) return env->values[var.displ];
while (1) {
if (env->type == Env::HasWithExpr) {
if (!env->haveWithAttrs) {
if (noEval) return 0;
Value * v = allocValue();
evalAttrs(*env->up, (Expr *) env->values[0], *v);
env->values[0] = v;
env->type = Env::HasWithAttrs;
env->haveWithAttrs = true;
}
Bindings::iterator j = env->values[0]->attrs->find(var.name);
if (j != env->values[0]->attrs->end()) {
@@ -593,37 +576,26 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
}
if (!env->prevWith)
throwUndefinedVarError("undefined variable '%1%' at %2%", var.name, var.pos);
for (size_t l = env->prevWith; l; --l, env = env->up) ;
for (unsigned int l = env->prevWith; l; --l, env = env->up) ;
}
}
std::atomic<uint64_t> nrValuesFreed{0};
void finalizeValue(void * obj, void * data)
{
nrValuesFreed++;
}
Value * EvalState::allocValue()
{
nrValues++;
auto v = (Value *) allocBytes(sizeof(Value));
//GC_register_finalizer_no_order(v, finalizeValue, nullptr, nullptr, nullptr);
return v;
return (Value *) allocBytes(sizeof(Value));
}
Env & EvalState::allocEnv(size_t size)
Env & EvalState::allocEnv(unsigned int size)
{
if (size > std::numeric_limits<decltype(Env::size)>::max())
throw Error("environment size %d is too big", size);
assert(size <= std::numeric_limits<decltype(Env::size)>::max());
nrEnvs++;
nrValuesInEnvs += size;
Env * env = (Env *) allocBytes(sizeof(Env) + size * sizeof(Value *));
env->size = (decltype(Env::size)) size;
env->type = Env::Plain;
env->size = size;
/* We assume that env->values has been cleared by the allocator; maybeThunk() and lookupVar fromWith expect this. */
@@ -631,7 +603,7 @@ Env & EvalState::allocEnv(size_t size)
}
void EvalState::mkList(Value & v, size_t size)
void EvalState::mkList(Value & v, unsigned int size)
{
clearValue(v);
if (size == 1)
@@ -666,7 +638,7 @@ void EvalState::mkThunk_(Value & v, Expr * expr)
void EvalState::mkPos(Value & v, Pos * pos)
{
if (pos && pos->file.set()) {
if (pos) {
mkAttrs(v, 3);
mkString(*allocAttr(v, sFile), pos->file);
mkInt(*allocAttr(v, sLine), pos->line);
@@ -743,17 +715,7 @@ void EvalState::evalFile(const Path & path_, Value & v)
}
printTalkative("evaluating file '%1%'", path2);
Expr * e = nullptr;
auto j = fileParseCache.find(path2);
if (j != fileParseCache.end())
e = j->second;
if (!e)
e = parseExprFromFile(checkSourcePath(path2));
fileParseCache[path2] = e;
Expr * e = parseExprFromFile(checkSourcePath(path2));
try {
eval(e, v);
} catch (Error & e) {
@@ -769,7 +731,6 @@ void EvalState::evalFile(const Path & path_, Value & v)
void EvalState::resetFileCache()
{
fileEvalCache.clear();
fileParseCache.clear();
}
@@ -854,7 +815,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
/* The recursive attributes are evaluated in the new
environment, while the inherited attributes are evaluated
in the original environment. */
size_t displ = 0;
unsigned int displ = 0;
for (auto & i : attrs) {
Value * vAttr;
if (hasOverrides && !i.second.inherited) {
@@ -928,7 +889,7 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v)
/* The recursive attributes are evaluated in the new environment,
while the inherited attributes are evaluated in the original
environment. */
size_t displ = 0;
unsigned int displ = 0;
for (auto & i : attrs->attrs)
env2.values[displ++] = i.second.e->maybeThunk(state, i.second.inherited ? env : env2);
@@ -939,7 +900,7 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v)
void ExprList::eval(EvalState & state, Env & env, Value & v)
{
state.mkList(v, elems.size());
for (size_t n = 0; n < elems.size(); ++n)
for (unsigned int n = 0; n < elems.size(); ++n)
v.listElems()[n] = elems[n]->maybeThunk(state, env);
}
@@ -1061,22 +1022,22 @@ void ExprApp::eval(EvalState & state, Env & env, Value & v)
void EvalState::callPrimOp(Value & fun, Value & arg, Value & v, const Pos & pos)
{
/* Figure out the number of arguments still needed. */
size_t argsDone = 0;
unsigned int argsDone = 0;
Value * primOp = &fun;
while (primOp->type == tPrimOpApp) {
argsDone++;
primOp = primOp->primOpApp.left;
}
assert(primOp->type == tPrimOp);
auto arity = primOp->primOp->arity;
auto argsLeft = arity - argsDone;
unsigned int arity = primOp->primOp->arity;
unsigned int argsLeft = arity - argsDone;
if (argsLeft == 1) {
/* We have all the arguments, so call the primop. */
/* Put all the arguments in an array. */
Value * vArgs[arity];
auto n = arity - 1;
unsigned int n = arity - 1;
vArgs[n--] = &arg;
for (Value * arg = &fun; arg->type == tPrimOpApp; arg = arg->primOpApp.left)
vArgs[n--] = arg->primOpApp.right;
@@ -1097,8 +1058,6 @@ void EvalState::callPrimOp(Value & fun, Value & arg, Value & v, const Pos & pos)
void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & pos)
{
forceValue(fun, pos);
if (fun.type == tPrimOp || fun.type == tPrimOpApp) {
callPrimOp(fun, arg, v, pos);
return;
@@ -1114,8 +1073,10 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po
auto & fun2 = *allocValue();
fun2 = fun;
/* !!! Should we use the attr pos here? */
forceValue(*found->value, pos);
Value v2;
callFunction(*found->value, fun2, v2, pos);
forceValue(v2, pos);
return callFunction(v2, arg, v, pos);
}
}
@@ -1125,13 +1086,13 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po
ExprLambda & lambda(*fun.lambda.fun);
auto size =
unsigned int size =
(lambda.arg.empty() ? 0 : 1) +
(lambda.matchAttrs ? lambda.formals->formals.size() : 0);
Env & env2(allocEnv(size));
env2.up = fun.lambda.env;
size_t displ = 0;
unsigned int displ = 0;
if (!lambda.matchAttrs)
env2.values[displ++] = &arg;
@@ -1145,7 +1106,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po
/* For each formal argument, get the actual argument. If
there is no matching actual argument but the formal
argument has a default, use the default. */
size_t attrsUsed = 0;
unsigned int attrsUsed = 0;
for (auto & i : lambda.formals->formals) {
Bindings::iterator j = arg.attrs->find(i.name);
if (j == arg.attrs->end()) {
@@ -1202,6 +1163,7 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
if (fun.type == tAttrs) {
auto found = fun.attrs->find(sFunctor);
if (found != fun.attrs->end()) {
forceValue(*found->value);
Value * v = allocValue();
callFunction(*found->value, fun, *v, noPos);
forceValue(*v);
@@ -1236,7 +1198,7 @@ void ExprWith::eval(EvalState & state, Env & env, Value & v)
Env & env2(state.allocEnv(1));
env2.up = &env;
env2.prevWith = prevWith;
env2.type = Env::HasWithExpr;
env2.haveWithAttrs = false;
env2.values[0] = (Value *) attrs;
body->eval(state, env2, v);
@@ -1342,15 +1304,15 @@ void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v)
}
void EvalState::concatLists(Value & v, size_t nrLists, Value * * lists, const Pos & pos)
void EvalState::concatLists(Value & v, unsigned int nrLists, Value * * lists, const Pos & pos)
{
nrListConcats++;
Value * nonEmpty = 0;
size_t len = 0;
for (size_t n = 0; n < nrLists; ++n) {
unsigned int len = 0;
for (unsigned int n = 0; n < nrLists; ++n) {
forceList(*lists[n], pos);
auto l = lists[n]->listSize();
unsigned int l = lists[n]->listSize();
len += l;
if (l) nonEmpty = lists[n];
}
@@ -1362,10 +1324,9 @@ void EvalState::concatLists(Value & v, size_t nrLists, Value * * lists, const Po
mkList(v, len);
auto out = v.listElems();
for (size_t n = 0, pos = 0; n < nrLists; ++n) {
auto l = lists[n]->listSize();
if (l)
memcpy(out + pos, lists[n]->listElems(), l * sizeof(Value *));
for (unsigned int n = 0, pos = 0; n < nrLists; ++n) {
unsigned int l = lists[n]->listSize();
memcpy(out + pos, lists[n]->listElems(), l * sizeof(Value *));
pos += l;
}
}
@@ -1458,7 +1419,7 @@ void EvalState::forceValueDeep(Value & v)
}
else if (v.isList()) {
for (size_t n = 0; n < v.listSize(); ++n)
for (unsigned int n = 0; n < v.listSize(); ++n)
recurse(*v.listElems()[n]);
}
};
@@ -1585,6 +1546,7 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
if (v.type == tAttrs) {
auto i = v.attrs->find(sToString);
if (i != v.attrs->end()) {
forceValue(*i->value, pos);
Value v1;
callFunction(*i->value, v, v1, pos);
return coerceToString(pos, v1, context, coerceMore, copyToStore);
@@ -1609,7 +1571,7 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
if (v.isList()) {
string result;
for (size_t n = 0; n < v.listSize(); ++n) {
for (unsigned int n = 0; n < v.listSize(); ++n) {
result += coerceToString(pos, *v.listElems()[n],
context, coerceMore, copyToStore);
if (n < v.listSize() - 1
@@ -1696,7 +1658,7 @@ bool EvalState::eqValues(Value & v1, Value & v2)
case tList2:
case tListN:
if (v1.listSize() != v2.listSize()) return false;
for (size_t n = 0; n < v1.listSize(); ++n)
for (unsigned int n = 0; n < v1.listSize(); ++n)
if (!eqValues(*v1.listElems()[n], *v2.listElems()[n])) return false;
return true;
@@ -1738,9 +1700,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,101 +1716,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);
printMsg(v, format(" current Boehm heap size: %1% bytes") % heapSize);
printMsg(v, format(" total Boehm heap allocations: %1% bytes") % 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);
}
#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<unsigned int, Symbol> PrimOpCalls_;
PrimOpCalls_ primOpCalls_;
for (auto & i : primOpCalls)
primOpCalls_.insert(std::pair<unsigned int, 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<unsigned int, ExprLambda *> FunctionCalls_;
FunctionCalls_ functionCalls_;
for (auto & i : functionCalls)
functionCalls_.insert(std::pair<unsigned int, 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<unsigned int, Pos> AttrSelects_;
AttrSelects_ attrSelects_;
for (auto & i : attrSelects)
attrSelects_.insert(std::pair<unsigned int, Pos>(i.second, i.first));
for (auto i = attrSelects_.rbegin(); i != attrSelects_.rend(); ++i)
printMsg(v, format("%1$10d %2%") % i->first % i->second);
}
}
@@ -1893,7 +1819,7 @@ size_t valueSize(Value & v)
if (seen.find(v.listElems()) == seen.end()) {
seen.insert(v.listElems());
sz += v.listSize() * sizeof(Value *);
for (size_t n = 0; n < v.listSize(); ++n)
for (unsigned int n = 0; n < v.listSize(); ++n)
sz += doValue(*v.listElems()[n]);
}
break;
@@ -1929,10 +1855,9 @@ size_t valueSize(Value & v)
size_t sz = sizeof(Env) + sizeof(Value *) * env.size;
if (env.type != Env::HasWithExpr)
for (size_t i = 0; i < env.size; ++i)
if (env.values[i])
sz += doValue(*env.values[i]);
for (unsigned int i = 0; i < env.size; ++i)
if (env.values[i])
sz += doValue(*env.values[i]);
if (env.up) sz += doEnv(*env.up);
@@ -1961,9 +1886,4 @@ std::ostream & operator << (std::ostream & str, const ExternalValueBase & v) {
}
EvalSettings evalSettings;
static GlobalConfig::Register r1(&evalSettings);
}

View File

@@ -5,10 +5,8 @@
#include "nixexpr.hh"
#include "symbol-table.hh"
#include "hash.hh"
#include "config.hh"
#include <map>
#include <unordered_map>
namespace nix {
@@ -36,8 +34,8 @@ struct Env
{
Env * up;
unsigned short size; // used by ‘valueSize’
unsigned short prevWith:14; // nr of levels up to next `with' environment
enum { Plain = 0, HasWithExpr, HasWithAttrs } type:2;
unsigned short prevWith:15; // nr of levels up to next `with' environment
unsigned short haveWithAttrs:1;
Value * values[0];
};
@@ -90,14 +88,6 @@ public:
private:
SrcToStore srcToStore;
/* A cache from path names to parse trees. */
#if HAVE_BOEHMGC
typedef std::map<Path, Expr *, std::less<Path>, traceable_allocator<std::pair<const Path, Expr *> > > FileParseCache;
#else
typedef std::map<Path, Expr *> FileParseCache;
#endif
FileParseCache fileParseCache;
/* A cache from path names to values. */
#if HAVE_BOEHMGC
typedef std::map<Path, Value, std::less<Path>, traceable_allocator<std::pair<const Path, Value> > > FileEvalCache;
@@ -110,9 +100,6 @@ private:
std::map<std::string, std::pair<bool, std::string>> searchPathResolved;
/* Cache used by checkSourcePath(). */
std::unordered_map<Path, Path> resolvedPaths;
public:
EvalState(const Strings & _searchPath, ref<Store> store);
@@ -227,7 +214,7 @@ private:
Value * addConstant(const string & name, Value & v);
Value * addPrimOp(const string & name,
size_t arity, PrimOpFun primOp);
unsigned int arity, PrimOpFun primOp);
public:
@@ -261,18 +248,18 @@ public:
/* Allocation primitives. */
Value * allocValue();
Env & allocEnv(size_t size);
Env & allocEnv(unsigned int size);
Value * allocAttr(Value & vAttrs, const Symbol & name);
Bindings * allocBindings(size_t capacity);
Bindings * allocBindings(Bindings::size_t capacity);
void mkList(Value & v, size_t length);
void mkAttrs(Value & v, size_t capacity);
void mkList(Value & v, unsigned int length);
void mkAttrs(Value & v, unsigned int capacity);
void mkThunk_(Value & v, Expr * expr);
void mkPos(Value & v, Pos * pos);
void concatLists(Value & v, size_t nrLists, Value * * lists, const Pos & pos);
void concatLists(Value & v, unsigned int nrLists, Value * * lists, const Pos & pos);
/* Print statistics. */
void printStats();
@@ -295,15 +282,15 @@ private:
bool countCalls;
typedef std::map<Symbol, size_t> PrimOpCalls;
typedef std::map<Symbol, unsigned int> PrimOpCalls;
PrimOpCalls primOpCalls;
typedef std::map<ExprLambda *, size_t> FunctionCalls;
typedef std::map<ExprLambda *, unsigned int> FunctionCalls;
FunctionCalls functionCalls;
void incrFunctionCall(ExprLambda * fun);
typedef std::map<Pos, size_t> AttrSelects;
typedef std::map<Pos, unsigned int> AttrSelects;
AttrSelects attrSelects;
friend struct ExprOpUpdate;
@@ -329,25 +316,4 @@ struct InvalidPathError : EvalError
#endif
};
struct EvalSettings : Config
{
Setting<bool> enableNativeCode{this, false, "allow-unsafe-native-code-during-evaluation",
"Whether builtin functions that allow executing native code should be enabled."};
Setting<bool> restrictEval{this, false, "restrict-eval",
"Whether to restrict file system access to paths in $NIX_PATH, "
"and network access to the URI prefixes listed in 'allowed-uris'."};
Setting<bool> pureEval{this, false, "pure-eval",
"Whether to restrict file system and network access to files specified by cryptographic hash."};
Setting<bool> enableImportFromDerivation{this, true, "allow-import-from-derivation",
"Whether the evaluator allows importing the result of a derivation."};
Setting<Strings> allowedUris{this, {}, "allowed-uris",
"Prefixes of URIs that builtin functions such as fetchurl and fetchGit are allowed to fetch."};
};
extern EvalSettings evalSettings;
}

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();

View File

@@ -110,7 +110,7 @@ static void parseJSON(EvalState & state, const char * & s, Value & v)
if (number_type == tFloat)
mkFloat(v, stod(tmp_number));
else
mkInt(v, stol(tmp_number));
mkInt(v, stoi(tmp_number));
} catch (std::invalid_argument e) {
throw JSONParseError("invalid JSON number");
} catch (std::out_of_range e) {

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"
@@ -87,7 +85,6 @@ static Expr * unescapeStr(SymbolTable & symbols, const char * s, size_t length)
%}
ANY .|\n
ID [a-zA-Z\_][a-zA-Z0-9\_\'\-]*
INT [0-9]+
FLOAT (([1-9][0-9]*\.[0-9]*)|(0?\.[0-9]+))([Ee][+-]?[0-9]+)?
@@ -99,6 +96,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 +123,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,28 +135,26 @@ 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 '"'; }
<STRING>([^\$\"\\]|\$[^\{\"\\]|\\{ANY}|\$\\{ANY})*\$/\" |
<STRING>([^\$\"\\]|\$[^\{\"\\]|\\{ANY}|\$\\{ANY})+ {
<INITIAL,INSIDE_DOLLAR_CURLY>\" {
PUSH_STATE(STRING); return '"';
}
<STRING>([^\$\"\\]|\$[^\{\"\\]|\\.|\$\\.)*\$/\" |
<STRING>([^\$\"\\]|\$[^\{\"\\]|\\.|\$\\.)+ {
/* It is impossible to match strings ending with '$' with one
regex because trailing contexts are only valid at the end
of a rule. (A sane but undocumented limitation.) */
yylval->e = unescapeStr(data->symbols, yytext, yyleng);
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 +164,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;
@@ -183,17 +178,18 @@ or { return OR_KW; }
yylval->e = new ExprIndStr("''");
return IND_STR;
}
<IND_STRING>\'\'\\{ANY} {
<IND_STRING>\'\'\\. {
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);
@@ -212,11 +208,11 @@ or { return OR_KW; }
\#[^\r\n]* /* single-line comments */
\/\*([^*]|\*+[^*/])*\*+\/ /* long comments */
{ANY} {
/* Don't return a negative number, as this will cause
Bison to stop parsing without an error. */
return (unsigned char) yytext[0];
}
. return yytext[0];
}
<<EOF>> { data->atEnd = true; return 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

@@ -10,7 +10,7 @@ namespace nix {
/* Displaying abstract syntax trees. */
std::ostream & operator << (std::ostream & str, const Expr & e)
std::ostream & operator << (std::ostream & str, Expr & e)
{
e.show(str);
return str;
@@ -58,48 +58,48 @@ std::ostream & operator << (std::ostream & str, const Symbol & sym)
return str;
}
void Expr::show(std::ostream & str) const
void Expr::show(std::ostream & str)
{
abort();
}
void ExprInt::show(std::ostream & str) const
void ExprInt::show(std::ostream & str)
{
str << n;
}
void ExprFloat::show(std::ostream & str) const
void ExprFloat::show(std::ostream & str)
{
str << nf;
}
void ExprString::show(std::ostream & str) const
void ExprString::show(std::ostream & str)
{
showString(str, s);
}
void ExprPath::show(std::ostream & str) const
void ExprPath::show(std::ostream & str)
{
str << s;
}
void ExprVar::show(std::ostream & str) const
void ExprVar::show(std::ostream & str)
{
str << name;
}
void ExprSelect::show(std::ostream & str) const
void ExprSelect::show(std::ostream & str)
{
str << "(" << *e << ")." << showAttrPath(attrPath);
if (def) str << " or (" << *def << ")";
}
void ExprOpHasAttr::show(std::ostream & str) const
void ExprOpHasAttr::show(std::ostream & str)
{
str << "((" << *e << ") ? " << showAttrPath(attrPath) << ")";
}
void ExprAttrs::show(std::ostream & str) const
void ExprAttrs::show(std::ostream & str)
{
if (recursive) str << "rec ";
str << "{ ";
@@ -113,7 +113,7 @@ void ExprAttrs::show(std::ostream & str) const
str << "}";
}
void ExprList::show(std::ostream & str) const
void ExprList::show(std::ostream & str)
{
str << "[ ";
for (auto & i : elems)
@@ -121,7 +121,7 @@ void ExprList::show(std::ostream & str) const
str << "]";
}
void ExprLambda::show(std::ostream & str) const
void ExprLambda::show(std::ostream & str)
{
str << "(";
if (matchAttrs) {
@@ -143,7 +143,7 @@ void ExprLambda::show(std::ostream & str) const
str << ": " << *body << ")";
}
void ExprLet::show(std::ostream & str) const
void ExprLet::show(std::ostream & str)
{
str << "(let ";
for (auto & i : attrs->attrs)
@@ -155,27 +155,27 @@ void ExprLet::show(std::ostream & str) const
str << "in " << *body << ")";
}
void ExprWith::show(std::ostream & str) const
void ExprWith::show(std::ostream & str)
{
str << "(with " << *attrs << "; " << *body << ")";
}
void ExprIf::show(std::ostream & str) const
void ExprIf::show(std::ostream & str)
{
str << "(if " << *cond << " then " << *then << " else " << *else_ << ")";
}
void ExprAssert::show(std::ostream & str) const
void ExprAssert::show(std::ostream & str)
{
str << "assert " << *cond << "; " << *body;
}
void ExprOpNot::show(std::ostream & str) const
void ExprOpNot::show(std::ostream & str)
{
str << "(! " << *e << ")";
}
void ExprConcatStrings::show(std::ostream & str) const
void ExprConcatStrings::show(std::ostream & str)
{
bool first = true;
str << "(";
@@ -186,7 +186,7 @@ void ExprConcatStrings::show(std::ostream & str) const
str << ")";
}
void ExprPos::show(std::ostream & str) const
void ExprPos::show(std::ostream & str)
{
str << "__curPos";
}

View File

@@ -11,6 +11,7 @@ namespace nix {
MakeError(EvalError, Error)
MakeError(ParseError, Error)
MakeError(IncompleteParseError, ParseError)
MakeError(AssertionError, EvalError)
MakeError(ThrownError, AssertionError)
MakeError(Abort, EvalError)
@@ -75,17 +76,17 @@ string showAttrPath(const AttrPath & attrPath);
struct Expr
{
virtual ~Expr() { };
virtual void show(std::ostream & str) const;
virtual void show(std::ostream & str);
virtual void bindVars(const StaticEnv & env);
virtual void eval(EvalState & state, Env & env, Value & v);
virtual Value * maybeThunk(EvalState & state, Env & env);
virtual void setName(Symbol & name);
};
std::ostream & operator << (std::ostream & str, const Expr & e);
std::ostream & operator << (std::ostream & str, Expr & e);
#define COMMON_METHODS \
void show(std::ostream & str) const; \
void show(std::ostream & str); \
void eval(EvalState & state, Env & env, Value & v); \
void bindVars(const StaticEnv & env);
@@ -254,7 +255,7 @@ struct ExprWith : Expr
{
Pos pos;
Expr * attrs, * body;
size_t prevWith;
unsigned int prevWith;
ExprWith(const Pos & pos, Expr * attrs, Expr * body) : pos(pos), attrs(attrs), body(body) { };
COMMON_METHODS
};
@@ -282,13 +283,13 @@ struct ExprOpNot : Expr
};
#define MakeBinOp(name, s) \
struct name : Expr \
struct Expr##name : Expr \
{ \
Pos pos; \
Expr * e1, * e2; \
name(Expr * e1, Expr * e2) : e1(e1), e2(e2) { }; \
name(const Pos & pos, Expr * e1, Expr * e2) : pos(pos), e1(e1), e2(e2) { }; \
void show(std::ostream & str) const \
Expr##name(Expr * e1, Expr * e2) : e1(e1), e2(e2) { }; \
Expr##name(const Pos & pos, Expr * e1, Expr * e2) : pos(pos), e1(e1), e2(e2) { }; \
void show(std::ostream & str) \
{ \
str << "(" << *e1 << " " s " " << *e2 << ")"; \
} \
@@ -299,14 +300,14 @@ struct ExprOpNot : Expr
void eval(EvalState & state, Env & env, Value & v); \
};
MakeBinOp(ExprApp, "")
MakeBinOp(ExprOpEq, "==")
MakeBinOp(ExprOpNEq, "!=")
MakeBinOp(ExprOpAnd, "&&")
MakeBinOp(ExprOpOr, "||")
MakeBinOp(ExprOpImpl, "->")
MakeBinOp(ExprOpUpdate, "//")
MakeBinOp(ExprOpConcatLists, "++")
MakeBinOp(App, "")
MakeBinOp(OpEq, "==")
MakeBinOp(OpNEq, "!=")
MakeBinOp(OpAnd, "&&")
MakeBinOp(OpOr, "||")
MakeBinOp(OpImpl, "->")
MakeBinOp(OpUpdate, "//")
MakeBinOp(OpConcatLists, "++")
struct ExprConcatStrings : Expr
{

View File

@@ -31,10 +31,12 @@ namespace nix {
Path basePath;
Symbol path;
string error;
bool atEnd;
Symbol sLetBody;
ParseData(EvalState & state)
: state(state)
, symbols(state.symbols)
, atEnd(false)
, sLetBody(symbols.create("<let-body>"))
{ };
};
@@ -134,8 +136,8 @@ static Expr * stripIndentation(const Pos & pos, SymbolTable & symbols, vector<Ex
whitespace-only final lines are not taken into account. (So
the " " in "\n ''" is ignored, but the " " in "\n foo''" is.) */
bool atStartOfLine = true; /* = seen only whitespace in the current line */
size_t minIndent = 1000000;
size_t curIndent = 0;
unsigned int minIndent = 1000000;
unsigned int curIndent = 0;
for (auto & i : es) {
ExprIndStr * e = dynamic_cast<ExprIndStr *>(i);
if (!e) {
@@ -146,7 +148,7 @@ static Expr * stripIndentation(const Pos & pos, SymbolTable & symbols, vector<Ex
}
continue;
}
for (size_t j = 0; j < e->s.size(); ++j) {
for (unsigned int j = 0; j < e->s.size(); ++j) {
if (atStartOfLine) {
if (e->s[j] == ' ')
curIndent++;
@@ -168,8 +170,8 @@ static Expr * stripIndentation(const Pos & pos, SymbolTable & symbols, vector<Ex
/* Strip spaces from each line. */
vector<Expr *> * es2 = new vector<Expr *>;
atStartOfLine = true;
size_t curDropped = 0;
size_t n = es.size();
unsigned int curDropped = 0;
unsigned int n = es.size();
for (vector<Expr *>::iterator i = es.begin(); i != es.end(); ++i, --n) {
ExprIndStr * e = dynamic_cast<ExprIndStr *>(*i);
if (!e) {
@@ -180,7 +182,7 @@ static Expr * stripIndentation(const Pos & pos, SymbolTable & symbols, vector<Ex
}
string s2;
for (size_t j = 0; j < e->s.size(); ++j) {
for (unsigned int j = 0; j < e->s.size(); ++j) {
if (atStartOfLine) {
if (e->s[j] == ' ') {
if (curDropped++ >= minIndent)
@@ -273,11 +275,11 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
%token IND_STRING_OPEN IND_STRING_CLOSE
%token ELLIPSIS
%right IMPL
%nonassoc IMPL
%left OR
%left AND
%nonassoc EQ NEQ
%nonassoc '<' '>' LEQ GEQ
%left '<' '>' LEQ GEQ
%right UPDATE
%left NOT
%left '+' '-'
@@ -539,7 +541,12 @@ Expr * EvalState::parse(const char * text,
int res = yyparse(scanner, &data);
yylex_destroy(scanner);
if (res) throw ParseError(data.error);
if (res) {
if (data.atEnd)
throw IncompleteParseError(data.error);
else
throw ParseError(data.error);
}
data.result->bindVars(staticEnv);

View File

@@ -73,7 +73,7 @@ void EvalState::realiseContext(const PathSet & context)
if (drvs.empty()) return;
if (!evalSettings.enableImportFromDerivation)
if (!settings.enableImportFromDerivation)
throw EvalError(format("attempted to realize '%1%' during evaluation but 'allow-import-from-derivation' is false") % *(drvs.begin()));
/* For performance, prefetch all substitute info. */
@@ -271,18 +271,7 @@ static void prim_isNull(EvalState & state, const Pos & pos, Value * * args, Valu
static void prim_isFunction(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceValue(*args[0]);
bool res;
switch (args[0]->type) {
case tLambda:
case tPrimOp:
case tPrimOpApp:
res = true;
break;
default:
res = false;
break;
}
mkBool(v, res);
mkBool(v, args[0]->type == tLambda);
}
@@ -464,7 +453,7 @@ static void prim_tryEval(EvalState & state, const Pos & pos, Value * * args, Val
static void prim_getEnv(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
string name = state.forceStringNoCtx(*args[0], pos);
mkString(v, evalSettings.restrictEval || evalSettings.pureEval ? "" : getEnv(name));
mkString(v, settings.restrictEval || settings.pureEval ? "" : getEnv(name));
}
@@ -724,14 +713,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 {
@@ -864,7 +855,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);
}
@@ -1029,7 +1020,7 @@ static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Valu
static void addPath(EvalState & state, const Pos & pos, const string & name, const Path & path_,
Value * filterFun, bool recursive, const Hash & expectedHash, Value & v)
{
const auto path = evalSettings.pureEval && expectedHash ?
const auto path = settings.pureEval && expectedHash ?
path_ :
state.checkSourcePath(path_);
PathFilter filter = filterFun ? ([&](const Path & path) {
@@ -1354,24 +1345,6 @@ static void prim_functionArgs(EvalState & state, const Pos & pos, Value * * args
}
/* Apply a function to every element of an attribute set. */
static void prim_mapAttrs(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceAttrs(*args[1], pos);
state.mkAttrs(v, args[1]->attrs->size());
for (auto & i : *args[1]->attrs) {
Value * vName = state.allocValue();
Value * vFun2 = state.allocValue();
mkString(*vName, i.name);
mkApp(*vFun2, *args[0], *vName);
mkApp(*state.allocAttr(v, i.name), *vFun2, *i.value);
}
}
/*************************************************************
* Lists
*************************************************************/
@@ -1426,6 +1399,7 @@ static void prim_tail(EvalState & state, const Pos & pos, Value * * args, Value
/* Apply a function to every element of a list. */
static void prim_map(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceFunction(*args[0], pos);
state.forceList(*args[1], pos);
state.mkList(v, args[1]->listSize());
@@ -1504,20 +1478,19 @@ static void prim_foldlStrict(EvalState & state, const Pos & pos, Value * * args,
state.forceFunction(*args[0], pos);
state.forceList(*args[2], pos);
if (args[2]->listSize()) {
Value * vCur = args[1];
Value * vCur = args[1];
if (args[2]->listSize())
for (unsigned int n = 0; n < args[2]->listSize(); ++n) {
Value vTmp;
state.callFunction(*args[0], *vCur, vTmp, pos);
vCur = n == args[2]->listSize() - 1 ? &v : state.allocValue();
state.callFunction(vTmp, *args[2]->listElems()[n], *vCur, pos);
}
state.forceValue(v);
} else {
state.forceValue(*args[1]);
v = *args[1];
}
else
v = *vCur;
state.forceValue(v);
}
@@ -1554,6 +1527,7 @@ static void prim_all(EvalState & state, const Pos & pos, Value * * args, Value &
static void prim_genList(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceFunction(*args[0], pos);
auto len = state.forceInt(*args[1], pos);
if (len < 0)
@@ -1627,50 +1601,17 @@ static void prim_partition(EvalState & state, const Pos & pos, Value * * args, V
state.mkAttrs(v, 2);
Value * vRight = state.allocAttr(v, state.sRight);
auto rsize = right.size();
state.mkList(*vRight, rsize);
if (rsize)
memcpy(vRight->listElems(), right.data(), sizeof(Value *) * rsize);
state.mkList(*vRight, right.size());
memcpy(vRight->listElems(), right.data(), sizeof(Value *) * right.size());
Value * vWrong = state.allocAttr(v, state.sWrong);
auto wsize = wrong.size();
state.mkList(*vWrong, wsize);
if (wsize)
memcpy(vWrong->listElems(), wrong.data(), sizeof(Value *) * wsize);
state.mkList(*vWrong, wrong.size());
memcpy(vWrong->listElems(), wrong.data(), sizeof(Value *) * wrong.size());
v.attrs->sort();
}
/* concatMap = f: list: concatLists (map f list); */
/* C++-version is to avoid allocating `mkApp', call `f' eagerly */
static void prim_concatMap(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceFunction(*args[0], pos);
state.forceList(*args[1], pos);
auto nrLists = args[1]->listSize();
Value lists[nrLists];
size_t len = 0;
for (unsigned int n = 0; n < nrLists; ++n) {
Value * vElem = args[1]->listElems()[n];
state.callFunction(*args[0], *vElem, lists[n], pos);
state.forceList(lists[n], pos);
len += lists[n].listSize();
}
state.mkList(v, len);
auto out = v.listElems();
for (unsigned int n = 0, pos = 0; n < nrLists; ++n) {
auto l = lists[n].listSize();
if (l)
memcpy(out + pos, lists[n].listElems(), l * sizeof(Value *));
pos += l;
}
}
/*************************************************************
* Integer arithmetic
*************************************************************/
@@ -1678,8 +1619,6 @@ static void prim_concatMap(EvalState & state, const Pos & pos, Value * * args, V
static void prim_add(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceValue(*args[0], pos);
state.forceValue(*args[1], pos);
if (args[0]->type == tFloat || args[1]->type == tFloat)
mkFloat(v, state.forceFloat(*args[0], pos) + state.forceFloat(*args[1], pos));
else
@@ -1689,8 +1628,6 @@ static void prim_add(EvalState & state, const Pos & pos, Value * * args, Value &
static void prim_sub(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceValue(*args[0], pos);
state.forceValue(*args[1], pos);
if (args[0]->type == tFloat || args[1]->type == tFloat)
mkFloat(v, state.forceFloat(*args[0], pos) - state.forceFloat(*args[1], pos));
else
@@ -1700,8 +1637,6 @@ static void prim_sub(EvalState & state, const Pos & pos, Value * * args, Value &
static void prim_mul(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceValue(*args[0], pos);
state.forceValue(*args[1], pos);
if (args[0]->type == tFloat || args[1]->type == tFloat)
mkFloat(v, state.forceFloat(*args[0], pos) * state.forceFloat(*args[1], pos));
else
@@ -1711,9 +1646,6 @@ static void prim_mul(EvalState & state, const Pos & pos, Value * * args, Value &
static void prim_div(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceValue(*args[0], pos);
state.forceValue(*args[1], pos);
NixFloat f2 = state.forceFloat(*args[1], pos);
if (f2 == 0) throw EvalError(format("division by zero, at %1%") % pos);
@@ -1729,20 +1661,6 @@ static void prim_div(EvalState & state, const Pos & pos, Value * * args, Value &
}
}
static void prim_bitAnd(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
mkInt(v, state.forceInt(*args[0], pos) & state.forceInt(*args[1], pos));
}
static void prim_bitOr(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
mkInt(v, state.forceInt(*args[0], pos) | state.forceInt(*args[1], pos));
}
static void prim_bitXor(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
mkInt(v, state.forceInt(*args[0], pos) ^ state.forceInt(*args[1], pos));
}
static void prim_lessThan(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
@@ -2109,7 +2027,7 @@ void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
state.checkURI(url);
if (evalSettings.pureEval && !expectedHash)
if (settings.pureEval && !expectedHash)
throw Error("in pure evaluation mode, '%s' requires a 'sha256' argument", who);
Path res = getDownloader()->downloadCached(state.store, url, unpack, name, expectedHash);
@@ -2177,12 +2095,12 @@ void EvalState::createBaseEnv()
addConstant(name, v);
};
if (!evalSettings.pureEval) {
if (!settings.pureEval) {
mkInt(v, time(0));
addConstant("__currentTime", v);
}
if (!evalSettings.pureEval) {
if (!settings.pureEval) {
mkString(v, settings.thisSystem);
addConstant("__currentSystem", v);
}
@@ -2207,7 +2125,7 @@ void EvalState::createBaseEnv()
mkApp(v, *vScopedImport, *v2);
forceValue(v);
addConstant("import", v);
if (evalSettings.enableNativeCode) {
if (settings.enableNativeCode) {
addPrimOp("__importNative", 2, prim_importNative);
addPrimOp("__exec", 1, prim_exec);
}
@@ -2234,7 +2152,7 @@ void EvalState::createBaseEnv()
// Paths
addPrimOp("__toPath", 1, prim_toPath);
if (evalSettings.pureEval)
if (settings.pureEval)
addPurityError("__storePath");
else
addPrimOp("__storePath", 1, prim_storePath);
@@ -2265,7 +2183,6 @@ void EvalState::createBaseEnv()
addPrimOp("__intersectAttrs", 2, prim_intersectAttrs);
addPrimOp("__catAttrs", 2, prim_catAttrs);
addPrimOp("__functionArgs", 1, prim_functionArgs);
addPrimOp("__mapAttrs", 2, prim_mapAttrs);
// Lists
addPrimOp("__isList", 1, prim_isList);
@@ -2283,16 +2200,12 @@ void EvalState::createBaseEnv()
addPrimOp("__genList", 2, prim_genList);
addPrimOp("__sort", 2, prim_sort);
addPrimOp("__partition", 2, prim_partition);
addPrimOp("__concatMap", 2, prim_concatMap);
// Integer arithmetic
addPrimOp("__add", 2, prim_add);
addPrimOp("__sub", 2, prim_sub);
addPrimOp("__mul", 2, prim_mul);
addPrimOp("__div", 2, prim_div);
addPrimOp("__bitAnd", 2, prim_bitAnd);
addPrimOp("__bitOr", 2, prim_bitOr);
addPrimOp("__bitXor", 2, prim_bitXor);
addPrimOp("__lessThan", 2, prim_lessThan);
// String manipulation

View File

@@ -3,7 +3,6 @@
#include "download.hh"
#include "store-api.hh"
#include "pathlocks.hh"
#include "hash.hh"
#include <sys/time.h>
@@ -29,7 +28,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,
std::experimental::optional<std::string> ref, std::string rev,
const std::string & name)
{
if (evalSettings.pureEval && rev == "")
if (settings.pureEval && rev == "")
throw Error("in pure evaluation mode, 'fetchGit' requires a Git revision");
if (!ref && rev == "" && hasPrefix(uri, "/") && pathExists(uri + "/.git")) {
@@ -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);
@@ -116,7 +114,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,
git fetch to update the local ref to the remote ref. */
struct stat st;
doFetch = stat(localRefFile.c_str(), &st) != 0 ||
st.st_mtime + settings.tarballTtl <= now;
st.st_mtime <= now - settings.tarballTtl;
}
if (doFetch)
{
@@ -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;
@@ -221,6 +219,8 @@ static void prim_fetchGit(EvalState & state, const Pos & pos, Value * * args, Va
} else
url = state.coerceToString(pos, *args[0], context, false, false);
if (!isUri(url)) url = absPath(url);
// FIXME: git externals probably can be used to bypass the URI
// whitelist. Ah well.
state.checkURI(url);

View File

@@ -27,7 +27,7 @@ std::regex commitHashRegex("^[0-9a-fA-F]{40}$");
HgInfo exportMercurial(ref<Store> store, const std::string & uri,
std::string rev, const std::string & name)
{
if (evalSettings.pureEval && rev == "")
if (settings.pureEval && rev == "")
throw Error("in pure evaluation mode, 'fetchMercurial' requires a Mercurial revision");
if (rev == "" && hasPrefix(uri, "/") && pathExists(uri + "/.hg")) {
@@ -80,7 +80,7 @@ HgInfo exportMercurial(ref<Store> store, const std::string & uri,
time_t now = time(0);
struct stat st;
if (stat(stampFile.c_str(), &st) != 0 ||
st.st_mtime + settings.tarballTtl <= now)
st.st_mtime <= now - settings.tarballTtl)
{
/* Except that if this is a commit hash that we already have,
we don't have to pull again. */
@@ -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 });
@@ -199,6 +184,8 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar
} else
url = state.coerceToString(pos, *args[0], context, false, false);
if (!isUri(url)) url = absPath(url);
// FIXME: git externals probably can be used to bypass the URI
// whitelist. Ah well.
state.checkURI(url);

View File

@@ -1,77 +0,0 @@
#include "primops.hh"
#include "eval-inline.hh"
#include "cpptoml/cpptoml.h"
namespace nix {
static void prim_fromTOML(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
using namespace cpptoml;
auto toml = state.forceStringNoCtx(*args[0], pos);
std::istringstream tomlStream(toml);
std::function<void(Value &, std::shared_ptr<base>)> visit;
visit = [&](Value & v, std::shared_ptr<base> t) {
if (auto t2 = t->as_table()) {
size_t size = 0;
for (auto & i : *t2) { (void) i; size++; }
state.mkAttrs(v, size);
for (auto & i : *t2) {
auto & v2 = *state.allocAttr(v, state.symbols.create(i.first));
if (auto i2 = i.second->as_table_array()) {
size_t size2 = i2->get().size();
state.mkList(v2, size2);
for (size_t j = 0; j < size2; ++j)
visit(*(v2.listElems()[j] = state.allocValue()), i2->get()[j]);
}
else
visit(v2, i.second);
}
v.attrs->sort();
}
else if (auto t2 = t->as_array()) {
size_t size = t2->get().size();
state.mkList(v, size);
for (size_t i = 0; i < size; ++i)
visit(*(v.listElems()[i] = state.allocValue()), t2->get()[i]);
}
else if (t->is_value()) {
if (auto val = t->as<int64_t>())
mkInt(v, val->get());
else if (auto val = t->as<NixFloat>())
mkFloat(v, val->get());
else if (auto val = t->as<bool>())
mkBool(v, val->get());
else if (auto val = t->as<std::string>())
mkString(v, val->get());
else
throw EvalError("unsupported value type in TOML");
}
else abort();
};
try {
visit(v, parser(tomlStream).parse());
} catch (std::runtime_error & e) {
throw EvalError("while parsing a TOML string at %s: %s", pos, e.what());
}
}
static RegisterPrimOp r("fromTOML", 1, prim_fromTOML);
}

View File

@@ -69,7 +69,7 @@ public:
return Symbol(&*res.first);
}
size_t size() const
unsigned int size() const
{
return symbols.size();
}

View File

@@ -43,8 +43,8 @@ class XMLWriter;
class JSONPlaceholder;
typedef int64_t NixInt;
typedef double NixFloat;
typedef long NixInt;
typedef float NixFloat;
/* External values must descend from ExternalValueBase, so that
* type-agnostic nix functions (e.g. showType) can be implemented
@@ -128,7 +128,7 @@ struct Value
const char * path;
Bindings * attrs;
struct {
size_t size;
unsigned int size;
Value * * elems;
} bigList;
Value * smallList[2];
@@ -166,7 +166,7 @@ struct Value
return type == tList1 || type == tList2 ? smallList : bigList.elems;
}
size_t listSize() const
unsigned int listSize() const
{
return type == tList1 ? 1 : type == tList2 ? 2 : bigList.size;
}

View File

@@ -29,14 +29,14 @@ MixCommonArgs::MixCommonArgs(const string & programName)
.arity(2)
.handler([](std::vector<std::string> ss) {
try {
globalConfig.set(ss[0], ss[1]);
settings.set(ss[0], ss[1]);
} catch (UsageError & e) {
warn(e.what());
}
});
std::string cat = "config";
globalConfig.convertToArgs(*this, cat);
settings.convertToArgs(*this, cat);
// Backward compatibility hack: nix-env already had a --system flag.
if (programName == "nix-env") longFlags.erase("system");

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

@@ -109,7 +109,7 @@ void initNix()
opensslLocks = std::vector<std::mutex>(CRYPTO_num_locks());
CRYPTO_set_locking_callback(opensslLockCallback);
loadConfFile();
settings.loadConfFile();
startSignalHandlerThread();
@@ -263,7 +263,7 @@ void showManPage(const string & name)
{
restoreSignals();
setenv("MANPATH", settings.nixManDir.c_str(), 1);
execlp("man", "man", name.c_str(), nullptr);
execlp("man", "man", name.c_str(), NULL);
throw SysError(format("command 'man %1%' failed") % name.c_str());
}
@@ -325,10 +325,10 @@ RunPager::RunPager()
setenv("LESS", "FRSXMK", 1);
restoreSignals();
if (pager)
execl("/bin/sh", "sh", "-c", pager, nullptr);
execlp("pager", "pager", nullptr);
execlp("less", "less", nullptr);
execlp("more", "more", nullptr);
execl("/bin/sh", "sh", "-c", pager, NULL);
execlp("pager", "pager", NULL);
execlp("less", "less", NULL);
execlp("more", "more", NULL);
throw SysError(format("executing '%1%'") % pager);
});

View File

@@ -30,7 +30,7 @@ static void sigsegvHandler(int signo, siginfo_t * info, void * ctx)
if (diff < 0) diff = -diff;
if (diff < 4096) {
char msg[] = "error: stack overflow (possible infinite recursion)\n";
[[gnu::unused]] auto res = write(2, msg, strlen(msg));
[[gnu::unused]] int res = write(2, msg, strlen(msg));
_exit(1); // maybe abort instead?
}
}
@@ -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

@@ -54,38 +54,17 @@ void BinaryCacheStore::init()
}
}
void BinaryCacheStore::getFile(const std::string & path,
Callback<std::shared_ptr<std::string>> callback)
{
try {
callback(getFile(path));
} catch (...) { callback.rethrow(); }
}
void BinaryCacheStore::getFile(const std::string & path, Sink & sink)
std::shared_ptr<std::string> BinaryCacheStore::getFile(const std::string & path)
{
std::promise<std::shared_ptr<std::string>> promise;
getFile(path,
{[&](std::future<std::shared_ptr<std::string>> result) {
try {
promise.set_value(result.get());
} catch (...) {
promise.set_exception(std::current_exception());
}
}});
auto data = promise.get_future().get();
sink((unsigned char *) data->data(), data->size());
}
std::shared_ptr<std::string> BinaryCacheStore::getFile(const std::string & path)
{
StringSink sink;
try {
getFile(path, sink);
} catch (NoSuchBinaryCacheFile &) {
return nullptr;
}
return sink.s;
[&](std::shared_ptr<std::string> result) {
promise.set_value(result);
},
[&](std::exception_ptr exc) {
promise.set_exception(exc);
});
return promise.get_future().get();
}
Path BinaryCacheStore::narInfoFileFor(const Path & storePath)
@@ -217,30 +196,34 @@ void BinaryCacheStore::narFromPath(const Path & storePath, Sink & sink)
{
auto info = queryPathInfo(storePath).cast<const NarInfo>();
uint64_t narSize = 0;
auto nar = getFile(info->url);
LambdaSink wrapperSink([&](const unsigned char * data, size_t len) {
sink(data, len);
narSize += len;
});
auto decompressor = makeDecompressionSink(info->compression, wrapperSink);
try {
getFile(info->url, *decompressor);
} catch (NoSuchBinaryCacheFile & e) {
throw SubstituteGone(e.what());
}
decompressor->finish();
if (!nar) throw Error(format("file '%s' missing from binary cache") % info->url);
stats.narRead++;
//stats.narReadCompressedBytes += nar->size(); // FIXME
stats.narReadBytes += narSize;
stats.narReadCompressedBytes += nar->size();
/* Decompress the NAR. FIXME: would be nice to have the remote
side do this. */
try {
nar = decompress(info->compression, *nar);
} catch (UnknownCompressionMethod &) {
throw Error(format("binary cache path '%s' uses unknown compression method '%s'")
% storePath % info->compression);
}
stats.narReadBytes += nar->size();
printMsg(lvlTalkative, format("exporting path '%1%' (%2% bytes)") % storePath % nar->size());
assert(nar->size() % 8 == 0);
sink((unsigned char *) nar->c_str(), nar->size());
}
void BinaryCacheStore::queryPathInfoUncached(const Path & storePath,
Callback<std::shared_ptr<ValidPathInfo>> callback)
std::function<void(std::shared_ptr<ValidPathInfo>)> success,
std::function<void(std::exception_ptr exc)> failure)
{
auto uri = getUri();
auto act = std::make_shared<Activity>(*logger, lvlTalkative, actQueryPathInfo,
@@ -250,22 +233,17 @@ void BinaryCacheStore::queryPathInfoUncached(const Path & storePath,
auto narInfoFile = narInfoFileFor(storePath);
getFile(narInfoFile,
{[=](std::future<std::shared_ptr<std::string>> fut) {
try {
auto data = fut.get();
[=](std::shared_ptr<std::string> data) {
if (!data) return success(0);
if (!data) return callback(nullptr);
stats.narInfoRead++;
stats.narInfoRead++;
callSuccess(success, failure, (std::shared_ptr<ValidPathInfo>)
std::make_shared<NarInfo>(*this, *data, narInfoFile));
callback((std::shared_ptr<ValidPathInfo>)
std::make_shared<NarInfo>(*this, *data, narInfoFile));
(void) act; // force Activity into this lambda to ensure it stays alive
} catch (...) {
callback.rethrow();
}
}});
(void) act; // force Activity into this lambda to ensure it stays alive
},
failure);
}
Path BinaryCacheStore::addToStore(const string & name, const Path & srcPath,

View File

@@ -38,16 +38,11 @@ public:
const std::string & data,
const std::string & mimeType) = 0;
/* Note: subclasses must implement at least one of the two
following getFile() methods. */
/* Dump the contents of the specified file to a sink. */
virtual void getFile(const std::string & path, Sink & sink);
/* Fetch the specified file and call the specified callback with
the result. A subclass may implement this asynchronously. */
/* Return the contents of the specified file, or null if it
doesn't exist. */
virtual void getFile(const std::string & path,
Callback<std::shared_ptr<std::string>> callback);
std::function<void(std::shared_ptr<std::string>)> success,
std::function<void(std::exception_ptr exc)> failure) = 0;
std::shared_ptr<std::string> getFile(const std::string & path);
@@ -76,7 +71,8 @@ public:
{ unsupported(); }
void queryPathInfoUncached(const Path & path,
Callback<std::shared_ptr<ValidPathInfo>> callback) override;
std::function<void(std::shared_ptr<ValidPathInfo>)> success,
std::function<void(std::exception_ptr exc)> failure) override;
void queryReferrers(const Path & path,
PathSet & referrers) override
@@ -135,6 +131,4 @@ public:
};
MakeError(NoSuchBinaryCacheFile, Error);
}

View File

@@ -11,7 +11,6 @@
#include "compression.hh"
#include "json.hh"
#include "nar-info.hh"
#include "parsed-derivations.hh"
#include <algorithm>
#include <iostream>
@@ -21,7 +20,6 @@
#include <future>
#include <chrono>
#include <regex>
#include <queue>
#include <limits.h>
#include <sys/time.h>
@@ -31,9 +29,7 @@
#include <sys/utsname.h>
#include <sys/select.h>
#include <sys/resource.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <cstring>
@@ -160,7 +156,7 @@ public:
abort();
}
void trace(const FormatOrString & fs);
void trace(const format & f);
string getName()
{
@@ -421,9 +417,9 @@ void Goal::amDone(ExitCode result)
}
void Goal::trace(const FormatOrString & fs)
void Goal::trace(const format & f)
{
debug("%1%: %2%", name, fs.s);
debug(format("%1%: %2%") % name % f);
}
@@ -656,11 +652,6 @@ HookInstance::HookInstance()
if (dup2(builderOut.writeSide.get(), 4) == -1)
throw SysError("dupping builder's stdout/stderr");
/* Hack: pass the read side of that fd to allow build-remote
to read SSH error messages. */
if (dup2(builderOut.readSide.get(), 5) == -1)
throw SysError("dupping builder's stdout/stderr");
Strings args = {
baseNameOf(settings.buildHook),
std::to_string(verbosity),
@@ -676,10 +667,8 @@ HookInstance::HookInstance()
toHook.readSide = -1;
sink = FdSink(toHook.writeSide.get());
std::map<std::string, Config::SettingInfo> settings;
globalConfig.getSettings(settings);
for (auto & setting : settings)
sink << 1 << setting.first << setting.second.value;
for (auto & setting : settings.getSettings())
sink << 1 << setting.first << setting.second;
sink << 0;
}
@@ -737,13 +726,11 @@ private:
/* Whether to retry substituting the outputs after building the
inputs. */
bool retrySubstitution;
bool retrySubstitution = false;
/* 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. */
@@ -850,15 +837,15 @@ private:
BuildResult result;
/* The current round, if we're building multiple times. */
size_t curRound = 1;
unsigned int curRound = 1;
size_t nrRounds;
unsigned int nrRounds;
/* Path registration info from the previous round, if we're
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;
@@ -939,11 +926,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();
@@ -977,8 +959,6 @@ private:
}
void done(BuildResult::Status status, const string & msg = "");
PathSet exportReferences(PathSet storePaths);
};
@@ -1134,8 +1114,6 @@ void DerivationGoal::haveDerivation()
{
trace("have derivation");
retrySubstitution = false;
for (auto & i : drv->outputs)
worker.store.addTempRoot(i.second.path);
@@ -1148,8 +1126,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. */
@@ -1176,7 +1152,7 @@ void DerivationGoal::outputsSubstituted()
/* If the substitutes form an incomplete closure, then we should
build the dependencies of this derivation, but after that, we
can still use the substitutes for this derivation itself. */
if (nrIncompleteClosure > 0) retrySubstitution = true;
if (nrIncompleteClosure > 0 && !retrySubstitution) retrySubstitution = true;
nrFailed = nrNoSubstituters = nrIncompleteClosure = 0;
@@ -1186,7 +1162,7 @@ void DerivationGoal::outputsSubstituted()
return;
}
auto nrInvalid = checkPathValidity(false, buildMode == bmRepair).size();
unsigned int nrInvalid = checkPathValidity(false, buildMode == bmRepair).size();
if (buildMode == bmNormal && nrInvalid == 0) {
done(BuildResult::Substituted);
return;
@@ -1406,7 +1382,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(
@@ -1482,7 +1458,7 @@ void replaceValidPath(const Path & storePath, const Path tmpPath)
tmpPath (the replacement), so we have to move it out of the
way first. We'd better not be interrupted here, because if
we're repairing (say) Glibc, we end up with a broken system. */
Path oldPath = (format("%1%.old-%2%-%3%") % storePath % getpid() % random()).str();
Path oldPath = (format("%1%.old-%2%-%3%") % storePath % getpid() % rand()).str();
if (pathExists(storePath))
rename(storePath.c_str(), oldPath.c_str());
if (rename(tmpPath.c_str(), storePath.c_str()) == -1)
@@ -1652,13 +1628,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
@@ -1743,23 +1725,22 @@ int childEntry(void * arg)
}
PathSet DerivationGoal::exportReferences(PathSet storePaths)
PathSet exportReferences(Store & store, PathSet storePaths)
{
PathSet paths;
for (auto storePath : storePaths) {
/* Check that the store path is valid. */
if (!worker.store.isInStore(storePath))
if (!store.isInStore(storePath))
throw BuildError(format("'exportReferencesGraph' contains a non-store path '%1%'")
% storePath);
storePath = store.toStorePath(storePath);
if (!store.isValidPath(storePath))
throw BuildError(format("'exportReferencesGraph' contains an invalid path '%1%'")
% storePath);
storePath = worker.store.toStorePath(storePath);
if (!inputPaths.count(storePath))
throw BuildError("cannot export references of path '%s' because it is not in the input closure of the derivation", storePath);
worker.store.computeFSClosure(storePath, paths);
store.computeFSClosure(storePath, paths);
}
/* If there are derivations in the graph, then include their
@@ -1770,9 +1751,9 @@ PathSet DerivationGoal::exportReferences(PathSet storePaths)
for (auto & j : paths2) {
if (isDerivation(j)) {
Derivation drv = worker.store.derivationFromPath(j);
Derivation drv = store.derivationFromPath(j);
for (auto & k : drv.outputs)
worker.store.computeFSClosure(k.second.path, paths);
store.computeFSClosure(k.second.path, paths);
}
}
@@ -1784,40 +1765,35 @@ static std::once_flag dns_resolve_flag;
static void preloadNSS() {
/* builtin:fetchurl can trigger a DNS lookup, which with glibc can trigger a dynamic library load of
one of the glibc NSS libraries in a sandboxed child, which will fail unless the library's already
been loaded in the parent. So we force a lookup of an invalid domain to force the NSS machinery to
been loaded in the parent. So we force a download of an invalid URL to force the NSS machinery to
load its lookup libraries in the parent before any child gets a chance to. */
std::call_once(dns_resolve_flag, []() {
struct addrinfo *res = NULL;
if (getaddrinfo("this.pre-initializes.the.dns.resolvers.invalid.", "http", NULL, &res) != 0) {
if (res) freeaddrinfo(res);
}
DownloadRequest request("http://this.pre-initializes.the.dns.resolvers.invalid");
request.tries = 1; // We only need to do it once, and this also suppresses an annoying warning
try { getDownloader()->download(request); } catch (...) {}
});
}
void DerivationGoal::startBuilder()
{
/* 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__
@@ -1830,7 +1806,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) {
@@ -1881,7 +1857,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
@@ -1901,7 +1877,7 @@ void DerivationGoal::startBuilder()
/* Write closure info to <fileName>. */
writeFile(tmpDir + "/" + fileName,
worker.store.makeValidityRegistration(
exportReferences({storePath}), false, false));
exportReferences(worker.store, {storePath}), false, false));
}
}
@@ -1946,7 +1922,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;
@@ -2015,7 +1991,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
@@ -2314,7 +2290,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;
@@ -2361,8 +2337,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
@@ -2377,103 +2353,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(worker.store, 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::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", rewriteStrings(jsonSh, inputRewrites));
}
@@ -2507,10 +2491,6 @@ void setupSeccomp()
seccomp_arch_add(ctx, SCMP_ARCH_X32) != 0)
throw SysError("unable to add X32 seccomp architecture");
if (settings.thisSystem == "aarch64-linux" &&
seccomp_arch_add(ctx, SCMP_ARCH_ARM) != 0)
printError("unsable to add ARM seccomp architecture; this may result in spurious build failures if running 32-bit ARM processes.");
/* Prevent builders from creating setuid/setgid binaries. */
for (int perm : { S_ISUID, S_ISGID }) {
if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(chmod), 1,
@@ -2628,7 +2608,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");
@@ -2917,7 +2897,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. */
@@ -2964,8 +2944,6 @@ void DerivationGoal::runChild()
if (drv->builder == "builtin:fetchurl")
builtinFetchurl(drv2, netrcData);
else if (drv->builder == "builtin:buildenv")
builtinBuildenv(drv2);
else
throw Error(format("unsupported builtin function '%1%'") % string(drv->builder, 8));
_exit(0);
@@ -2989,9 +2967,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);
@@ -3016,7 +2995,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
@@ -3120,15 +3099,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);
@@ -3201,6 +3180,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);
@@ -3216,14 +3237,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) {
@@ -3231,16 +3249,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) {
@@ -3285,11 +3303,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. */
@@ -3298,158 +3312,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::experimental::optional<uint64_t> maxSize, maxClosureSize;
std::experimental::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::experimental::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::experimental::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;
@@ -3646,8 +3508,8 @@ private:
/* The current substituter. */
std::shared_ptr<Store> sub;
/* Whether a substituter failed. */
bool substituterFailed = false;
/* Whether any substituter can realise this path. */
bool hasSubstitute;
/* Path info returned by the substituter's query info operation. */
std::shared_ptr<const ValidPathInfo> info;
@@ -3711,6 +3573,7 @@ public:
SubstitutionGoal::SubstitutionGoal(const Path & storePath, Worker & worker, RepairFlag repair)
: Goal(worker)
, hasSubstitute(false)
, repair(repair)
{
this->storePath = storePath;
@@ -3774,9 +3637,9 @@ void SubstitutionGoal::tryNext()
/* Hack: don't indicate failure if there were no substituters.
In that case the calling derivation should just do a
build. */
amDone(substituterFailed ? ecFailed : ecNoSubstituters);
amDone(hasSubstitute ? ecFailed : ecNoSubstituters);
if (substituterFailed) {
if (hasSubstitute) {
worker.failedSubstitutions++;
worker.updateProgress();
}
@@ -3798,19 +3661,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. */
@@ -3825,6 +3675,8 @@ void SubstitutionGoal::tryNext()
worker.updateProgress();
hasSubstitute = true;
/* Bail out early if this substituter lacks a valid
signature. LocalStore::addToStore() also checks for this, but
only after we've downloaded the path. */
@@ -3939,19 +3791,8 @@ void SubstitutionGoal::finished()
state = &SubstitutionGoal::init;
worker.waitForAWhile(shared_from_this());
return;
} catch (std::exception & e) {
printError(e.what());
/* Cause the parent build to fail unless --fallback is given,
or the substitute has disappeared. The latter case behaves
the same as the substitute never having existed in the
first place. */
try {
throw;
} catch (SubstituteGone &) {
} catch (...) {
substituterFailed = true;
}
} catch (Error & e) {
printError(e.msg());
/* Try the next substitute. */
state = &SubstitutionGoal::tryNext;
@@ -4315,10 +4156,10 @@ void Worker::waitForInput()
assert(goal);
set<int> fds2(j->fds);
std::vector<unsigned char> buffer(4096);
for (auto & k : fds2) {
if (FD_ISSET(k, &fds)) {
ssize_t rd = read(k, buffer.data(), buffer.size());
unsigned char buffer[4096];
ssize_t rd = read(k, buffer, sizeof(buffer));
if (rd == -1) {
if (errno != EINTR)
throw SysError(format("reading from %1%")
@@ -4330,7 +4171,7 @@ void Worker::waitForInput()
} else {
printMsg(lvlVomit, format("%1%: read %2% bytes")
% goal->getName() % rd);
string data((char *) buffer.data(), rd);
string data((char *) buffer, rd);
j->lastOutput = after;
goal->handleChildOutput(k, data);
}

73
src/libstore/builtins.cc Normal file
View File

@@ -0,0 +1,73 @@
#include "builtins.hh"
#include "download.hh"
#include "store-api.hh"
#include "archive.hh"
#include "compression.hh"
namespace nix {
void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData)
{
/* Make the host's netrc data available. Too bad curl requires
this to be stored in a file. It would be nice if we could just
pass a pointer to the data. */
if (netrcData != "") {
settings.netrcFile = "netrc";
writeFile(settings.netrcFile, netrcData, 0600);
}
auto getAttr = [&](const string & name) {
auto i = drv.env.find(name);
if (i == drv.env.end()) throw Error(format("attribute '%s' missing") % name);
return i->second;
};
auto fetch = [&](const string & url) {
/* No need to do TLS verification, because we check the hash of
the result anyway. */
DownloadRequest request(url);
request.verifyTLS = false;
request.decompress = false;
/* Note: have to use a fresh downloader here because we're in
a forked process. */
auto data = makeDownloader()->download(request);
assert(data.data);
return data.data;
};
std::shared_ptr<std::string> data;
if (getAttr("outputHashMode") == "flat")
for (auto hashedMirror : settings.hashedMirrors.get())
try {
if (!hasSuffix(hashedMirror, "/")) hashedMirror += '/';
auto ht = parseHashType(getAttr("outputHashAlgo"));
data = fetch(hashedMirror + printHashType(ht) + "/" + Hash(getAttr("outputHash"), ht).to_string(Base16, false));
break;
} catch (Error & e) {
debug(e.what());
}
if (!data) data = fetch(getAttr("url"));
Path storePath = getAttr("out");
auto unpack = drv.env.find("unpack");
if (unpack != drv.env.end() && unpack->second == "1") {
if (string(*data, 0, 6) == string("\xfd" "7zXZ\0", 6))
data = decompress("xz", *data);
StringSource source(*data);
restorePath(storePath, source);
} else
writeFile(storePath, *data);
auto executable = drv.env.find("executable");
if (executable != drv.env.end() && executable->second == "1") {
if (chmod(storePath.c_str(), 0755) == -1)
throw SysError(format("making '%1%' executable") % storePath);
}
}
}

View File

@@ -4,8 +4,6 @@
namespace nix {
// TODO: make pluggable.
void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData);
void builtinBuildenv(const BasicDerivation & drv);
}

View File

@@ -1,204 +0,0 @@
#include "builtins.hh"
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <algorithm>
namespace nix {
typedef std::map<Path,int> Priorities;
// FIXME: change into local variables.
static Priorities priorities;
static unsigned long symlinks;
/* For each activated package, create symlinks */
static void createLinks(const Path & srcDir, const Path & dstDir, int priority)
{
DirEntries srcFiles;
try {
srcFiles = readDirectory(srcDir);
} catch (SysError & e) {
if (e.errNo == ENOTDIR) {
printError("warning: not including '%s' in the user environment because it's not a directory", srcDir);
return;
}
throw;
}
for (const auto & ent : srcFiles) {
if (ent.name[0] == '.')
/* not matched by glob */
continue;
auto srcFile = srcDir + "/" + ent.name;
auto dstFile = dstDir + "/" + ent.name;
struct stat srcSt;
try {
if (stat(srcFile.c_str(), &srcSt) == -1)
throw SysError("getting status of '%1%'", srcFile);
} catch (SysError & e) {
if (e.errNo == ENOENT || e.errNo == ENOTDIR) {
printError("warning: skipping dangling symlink '%s'", dstFile);
continue;
}
throw;
}
/* The files below are special-cased to that they don't show up
* in user profiles, either because they are useless, or
* because they would cauase pointless collisions (e.g., each
* Python package brings its own
* `$out/lib/pythonX.Y/site-packages/easy-install.pth'.)
*/
if (hasSuffix(srcFile, "/propagated-build-inputs") ||
hasSuffix(srcFile, "/nix-support") ||
hasSuffix(srcFile, "/perllocal.pod") ||
hasSuffix(srcFile, "/info/dir") ||
hasSuffix(srcFile, "/log"))
continue;
else if (S_ISDIR(srcSt.st_mode)) {
struct stat dstSt;
auto res = lstat(dstFile.c_str(), &dstSt);
if (res == 0) {
if (S_ISDIR(dstSt.st_mode)) {
createLinks(srcFile, dstFile, priority);
continue;
} else if (S_ISLNK(dstSt.st_mode)) {
auto target = canonPath(dstFile, true);
if (!S_ISDIR(lstat(target).st_mode))
throw Error("collision between '%1%' and non-directory '%2%'", srcFile, target);
if (unlink(dstFile.c_str()) == -1)
throw SysError(format("unlinking '%1%'") % dstFile);
if (mkdir(dstFile.c_str(), 0755) == -1)
throw SysError(format("creating directory '%1%'"));
createLinks(target, dstFile, priorities[dstFile]);
createLinks(srcFile, dstFile, priority);
continue;
}
} else if (errno != ENOENT)
throw SysError(format("getting status of '%1%'") % dstFile);
}
else {
struct stat dstSt;
auto res = lstat(dstFile.c_str(), &dstSt);
if (res == 0) {
if (S_ISLNK(dstSt.st_mode)) {
auto prevPriority = priorities[dstFile];
if (prevPriority == priority)
throw Error(
"packages '%1%' and '%2%' have the same priority %3%; "
"use 'nix-env --set-flag priority NUMBER INSTALLED_PKGNAME' "
"to change the priority of one of the conflicting packages"
" (0 being the highest priority)",
srcFile, readLink(dstFile), priority);
if (prevPriority < priority)
continue;
if (unlink(dstFile.c_str()) == -1)
throw SysError(format("unlinking '%1%'") % dstFile);
} else if (S_ISDIR(dstSt.st_mode))
throw Error("collision between non-directory '%1%' and directory '%2%'", srcFile, dstFile);
} else if (errno != ENOENT)
throw SysError(format("getting status of '%1%'") % dstFile);
}
createSymlink(srcFile, dstFile);
priorities[dstFile] = priority;
symlinks++;
}
}
typedef std::set<Path> FileProp;
static FileProp done;
static FileProp postponed = FileProp{};
static Path out;
static void addPkg(const Path & pkgDir, int priority)
{
if (done.count(pkgDir)) return;
done.insert(pkgDir);
createLinks(pkgDir, out, priority);
try {
for (const auto & p : tokenizeString<std::vector<string>>(
readFile(pkgDir + "/nix-support/propagated-user-env-packages"), " \n"))
if (!done.count(p))
postponed.insert(p);
} catch (SysError & e) {
if (e.errNo != ENOENT && e.errNo != ENOTDIR) throw;
}
}
struct Package {
Path path;
bool active;
int priority;
Package(Path path, bool active, int priority) : path{path}, active{active}, priority{priority} {}
};
typedef std::vector<Package> Packages;
void builtinBuildenv(const BasicDerivation & drv)
{
auto getAttr = [&](const string & name) {
auto i = drv.env.find(name);
if (i == drv.env.end()) throw Error("attribute '%s' missing", name);
return i->second;
};
out = getAttr("out");
createDirs(out);
/* Convert the stuff we get from the environment back into a
* coherent data type. */
Packages pkgs;
auto derivations = tokenizeString<Strings>(getAttr("derivations"));
while (!derivations.empty()) {
/* !!! We're trusting the caller to structure derivations env var correctly */
auto active = derivations.front(); derivations.pop_front();
auto priority = stoi(derivations.front()); derivations.pop_front();
auto outputs = stoi(derivations.front()); derivations.pop_front();
for (auto n = 0; n < outputs; n++) {
auto path = derivations.front(); derivations.pop_front();
pkgs.emplace_back(path, active != "false", priority);
}
}
/* Symlink to the packages that have been installed explicitly by the
* user. Process in priority order to reduce unnecessary
* symlink/unlink steps.
*/
std::sort(pkgs.begin(), pkgs.end(), [](const Package & a, const Package & b) {
return a.priority < b.priority || (a.priority == b.priority && a.path < b.path);
});
for (const auto & pkg : pkgs)
if (pkg.active)
addPkg(pkg.path, pkg.priority);
/* Symlink to the packages that have been "propagated" by packages
* installed by the user (i.e., package X declares that it wants Y
* installed as well). We do these later because they have a lower
* priority in case of collisions.
*/
auto priorityCounter = 1000;
while (!postponed.empty()) {
auto pkgDirs = postponed;
postponed = FileProp{};
for (const auto & pkgDir : pkgDirs)
addPkg(pkgDir, priorityCounter++);
}
printError("created %d symlinks in user environment", symlinks);
createSymlink(getAttr("manifest"), out + "/manifest.nix");
}
}

View File

@@ -1,77 +0,0 @@
#include "builtins.hh"
#include "download.hh"
#include "store-api.hh"
#include "archive.hh"
#include "compression.hh"
namespace nix {
void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData)
{
/* Make the host's netrc data available. Too bad curl requires
this to be stored in a file. It would be nice if we could just
pass a pointer to the data. */
if (netrcData != "") {
settings.netrcFile = "netrc";
writeFile(settings.netrcFile, netrcData, 0600);
}
auto getAttr = [&](const string & name) {
auto i = drv.env.find(name);
if (i == drv.env.end()) throw Error(format("attribute '%s' missing") % name);
return i->second;
};
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. */
auto downloader = makeDownloader();
auto fetch = [&](const std::string & url) {
auto source = sinkToSource([&](Sink & sink) {
/* No need to do TLS verification, because we check the hash of
the result anyway. */
DownloadRequest request(url);
request.verifyTLS = false;
request.decompress = false;
auto decompressor = makeDecompressionSink(
unpack && hasSuffix(mainUrl, ".xz") ? "xz" : "none", sink);
downloader->download(std::move(request), *decompressor);
decompressor->finish();
});
if (unpack)
restorePath(storePath, *source);
else
writeFile(storePath, *source);
auto executable = drv.env.find("executable");
if (executable != drv.env.end() && executable->second == "1") {
if (chmod(storePath.c_str(), 0755) == -1)
throw SysError(format("making '%1%' executable") % storePath);
}
};
/* Try the hashed mirrors first. */
if (getAttr("outputHashMode") == "flat")
for (auto hashedMirror : settings.hashedMirrors.get())
try {
if (!hasSuffix(hashedMirror, "/")) hashedMirror += '/';
auto ht = parseHashType(getAttr("outputHashAlgo"));
fetch(hashedMirror + printHashType(ht) + "/" + Hash(getAttr("outputHash"), ht).to_string(Base16, false));
return;
} catch (Error & e) {
debug(e.what());
}
/* Otherwise try the specified URL. */
fetch(mainUrl);
}
}

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,22 @@ bool BasicDerivation::isBuiltin() const
}
bool BasicDerivation::canBuildLocally() const
{
return platform == settings.thisSystem
|| isBuiltin()
#if __linux__
|| (platform == "i686-linux" && settings.thisSystem == "x86_64-linux")
|| (platform == "armv6l-linux" && settings.thisSystem == "armv7l-linux")
|| (platform == "armv5tel-linux" && (settings.thisSystem == "armv7l-linux" || settings.thisSystem == "armv6l-linux"))
#elif __FreeBSD__
|| (platform == "i686-linux" && settings.thisSystem == "x86_64-freebsd")
|| (platform == "i686-linux" && settings.thisSystem == "i686-freebsd")
#endif
;
}
Path writeDerivation(ref<Store> store,
const Derivation & drv, const string & name, RepairFlag repair)
{
@@ -328,7 +350,7 @@ Hash hashDerivationModulo(Store & store, Derivation drv)
Hash h = drvHashes[i.first];
if (!h) {
assert(store.isValidPath(i.first));
Derivation drv2 = readDerivation(store.toRealPath(i.first));
Derivation drv2 = readDerivation(i.first);
h = hashDerivationModulo(store, drv2);
drvHashes[i.first] = h;
}

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;

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