Compare commits

...

211 Commits

Author SHA1 Message Date
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
Eelco Dolstra
179b896acb Merge branch 'data-dir-non-canon' of https://github.com/shlevy/nix 2018-02-22 14:20:43 +01:00
Eelco Dolstra
e8d53bfdc9 Revert "Enable sandbox builds on Linux by default"
This reverts commit ddc58e7896.

https://hydra.nixos.org/eval/1435322
2018-02-22 14:20:07 +01:00
Shea Levy
ddbcd01c83 Fix restricted mode when installing in non-canonical data dir 2018-02-22 07:18:14 -05:00
Eelco Dolstra
eaa52c34b4 Set release date 2018-02-22 12:44:46 +01:00
Eelco Dolstra
ddc58e7896 Enable sandbox builds on Linux by default
The overhead of sandbox builds is a problem on NixOS (since building a
NixOS configuration involves a lot of small derivations) but not for
typical non-NixOS use cases. So outside of NixOS we can enable it.

Issue #179.
2018-02-22 12:27:25 +01:00
Eelco Dolstra
6964131cd7 Merge branch 'fix/sandbox-shell-features' of https://github.com/dtzWill/nix 2018-02-22 12:20:13 +01:00
Eelco Dolstra
de4c03d201 Merge branch 'fix/dry-run-partially' of https://github.com/dtzWill/nix 2018-02-22 12:18:20 +01:00
Eelco Dolstra
88c90d5e6d Manual: Put configuration options in sorted order 2018-02-21 18:08:47 +01:00
Eelco Dolstra
0d54671b7b Manual: Update chapter on remote builds
Alos add a command "nix ping-store" to make it easier to see if Nix
can connect to a remote builder (e.g. 'nix ping-store --store
ssh://mac').
2018-02-21 16:24:26 +01:00
Eelco Dolstra
e2d71bd186 Revert "libexpr: Fix prim_replaceStrings() to work on an empty source string"
This reverts commit 4ea9707591.

It causes an infinite loop in Nixpkgs evaluation,
e.g. "nix-instantiate -A hello" hung.

PR #1886.
2018-02-21 15:35:28 +01:00
Shea Levy
a6c497f526 Merge branch 'nix-copy' of git://github.com/Mic92/nix-1 2018-02-20 21:05:17 -05:00
Jörg Thalheim
fa7fd76c5e nix-copy: fix examples
maybe a left-over from nix-store -r ?
2018-02-21 01:13:46 +00:00
Shea Levy
7c377dc5cc Merge remote-tracking branch 'dezgeg/afl-fixes' 2018-02-20 16:32:48 -05:00
Eelco Dolstra
4e44025ac5 Release notes: Add contributors 2018-02-20 15:20:14 +01:00
Eelco Dolstra
cea4fb3a31 Fix evaluation of binaryTarball.aarch64-linux 2018-02-20 12:33:32 +01:00
Tuomas Tynkkynen
546f98dace libutil: Fix invalid assert on decoding base64 hashes
The assertion is broken because there is no one-to-one mapping from
length of a base64 string to the length of the output.

E.g.

"1q69lz7Empb06nzfkj651413n9icx0njmyr3xzq1j9q=" results in a 32-byte output.
"1q69lz7Empb06nzfkj651413n9icx0njmyr3xzq1j9qy" results in a 33-byte output.

To reproduce, evaluate:

builtins.derivationStrict {
    name = "0";
    builder = "0";
    system = "0";
    outputHashAlgo = "sha256";
    outputHash = "1q69lz7Empb06nzfkj651413n9icx0njmyr3xzq1j9qy";
}

Found by afl-fuzz.
2018-02-19 23:20:26 +02:00
Tuomas Tynkkynen
4ea9707591 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.
2018-02-19 23:20:26 +02:00
Tuomas Tynkkynen
1d0e42879f libutil: Fix infinite loop in filterANSIEscapes on '\r'
E.g. nix-instantiate --eval -E 'abort "\r"' hangs.

Found by afl-fuzz.
2018-02-19 23:20:26 +02:00
Tuomas Tynkkynen
056d28a601 libexpr: Don't create lots of temporary strings in Bindings::lexicographicOrder
Avoids ~180,000 string temporaries created when evaluating a headless
NixOS system.
2018-02-19 22:47:25 +02:00
Eelco Dolstra
d4e93532e2 Fix incorrect (and unnecessary) format string
https://hydra.nixos.org/eval/1434547#tabs-now-fail
2018-02-19 20:46:39 +01:00
Eelco Dolstra
d7fdfe322b Remove macOS multi-user instructions
This is already handled by the installer.
2018-02-19 20:40:25 +01:00
Eelco Dolstra
70eb64147e Update release notes
Also add some examples to nix --help.
2018-02-19 20:38:53 +01:00
Will Dietz
a6c0b773b7 configure.ac: define HAVE_SECCOMP macro when using seccomp, fix build/tests
Happily the failing tests should prevent anyone from using such a Nix
in situations where they expect sandboxing to be on,
which would otherwise be a risk.
2018-02-19 12:13:51 -06:00
Eelco Dolstra
623fcb071e Merge pull request #1882 from shlevy/no-seccomp-no-filterSyscalls
Don't silently succeed seccomp setup when !HAVE_SECCOMP.
2018-02-19 17:39:46 +01:00
Shea Levy
e1eb63a586 Merge branch 'perf-fixes' of git://github.com/dezgeg/nix 2018-02-19 10:11:52 -05:00
Shea Levy
e59a8a63e1 Don't silently succeed seccomp setup when !HAVE_SECCOMP.
Running Nix with build users without seccomp on Linux is dangerous,
and administrators should very explicitly opt-in to it.
2018-02-19 09:56:24 -05:00
Eelco Dolstra
ed73d40c3b Config::handleUnknownSettings(): Remove unused 'fatal' argument 2018-02-19 14:00:34 +01:00
Eelco Dolstra
75a1d96cfd Merge branch 'register-settings' of https://github.com/shlevy/nix 2018-02-19 13:58:34 +01:00
Eelco Dolstra
7fe5910bf8 Merge pull request #1857 from dtzWill/fix/check-for-lzma-mt
configure.ac: check if lzma has MT support, fix deb build/etc.
2018-02-19 13:06:14 +01:00
Shea Levy
690ac7c90b configure: Add a flag to disable seccomp.
This is needed for new arches where libseccomp support doesn't exist
yet.

Fixes #1878.
2018-02-18 02:35:01 -05:00
Tuomas Tynkkynen
37264ed0ad libexpr: Avoid an unnecessary string copy in prim_derivationStrict 2018-02-17 16:54:21 +02:00
Tuomas Tynkkynen
66eeff3345 libexpr: Remove unnecessary drvName assignment in prim_derivationStrict
drvName is already assigned to the same value right at the start of the
function.
2018-02-17 16:54:21 +02:00
Tuomas Tynkkynen
7e0360504d libexpr: Optimize prim_derivationStrict by using more symbol comparisons 2018-02-17 16:54:21 +02:00
Tuomas Tynkkynen
0845cdf944 libexpr: Rely on Boehm returning zeroed memory in EvalState::allocEnv()
Boehm guarantees that memory returned by GC_malloc() is zeroed, so take
advantage of that.
2018-02-17 16:54:21 +02:00
Tuomas Tynkkynen
b8bed7da14 libexpr: Optimize prim_attrNames a bit
Instead of having lexicographicOrder() create a temporary sorted array
of Attr*:s and copying attr names from that, copy the attr names
first and then sort that.
2018-02-17 16:54:21 +02:00
Tuomas Tynkkynen
f67a7007a2 libexpr: Pre-reserve space in string in unescapeStr()
Avoids some malloc() traffic.
2018-02-16 04:39:43 +02:00
Eelco Dolstra
3a5a241b32 Merge pull request #1873 from matthewbauer/fix-manpath
Set MANPATH in case man path isn’t set correctly.
2018-02-15 17:37:21 +01:00
Matthew Bauer
8f186722a9 Set backup MANPATH in case man path isn’t set correctly.
Previously, this would fail at startup for non-NixOS installs:

nix-env --help

The fix for this is to just use "nixManDir" as the value for MANPATH
when spawning "man".

To test this, I’m using the following:

$ nix-build release.nix -A build
$ MANPATH= ./result/bin/nix-env --help

Fixes #1627
2018-02-15 10:20:02 -06:00
Eelco Dolstra
d26b71fda6 Merge pull request #1872 from shlevy/macOS-poll-fix
monitor-fds: Fix on macOS.
2018-02-15 11:43:56 +01:00
Shea Levy
ac973a6d3c monitor-fds: Fix on macOS.
Fixes #1871.
2018-02-14 18:26:37 -05:00
Eelco Dolstra
96d48318cb Merge pull request #1870 from shlevy/split-version
Add splitVersion primop.
2018-02-14 16:39:53 +01:00
Shea Levy
b095c06139 Add splitVersion primop.
Fixes #1868.
2018-02-14 09:55:43 -05:00
Shea Levy
de4934ab3b Allow plugins to define new settings. 2018-02-13 14:43:32 -05:00
Shea Levy
3fe9767dd3 Fix plugin tests on darwin 2018-02-13 12:49:14 -05:00
Eelco Dolstra
52c777a793 Merge pull request #1863 from shlevy/conf-includes
Allow includes from nix.conf
2018-02-13 17:33:07 +01:00
Eelco Dolstra
7253113fd2 Merge pull request #1862 from shlevy/plugin-dirs
Enable specifying directories in plugin-files.
2018-02-13 17:32:32 +01:00
Shea Levy
b8739f2fb3 Enable specifying directories in plugin-files. 2018-02-13 11:25:01 -05:00
Shea Levy
6eb1040e90 Allow includes from nix.conf 2018-02-13 08:16:32 -05:00
Eelco Dolstra
f471aacff2 Merge pull request #1775 from LnL7/darwin-build-users
installer: create 'enough' build users
2018-02-13 12:31:53 +01:00
Eelco Dolstra
7828dca9e8 Merge branch 'register-constant' of https://github.com/shlevy/nix 2018-02-13 12:24:48 +01:00
Eelco Dolstra
1c10a74c73 Merge branch 'plugins' of https://github.com/shlevy/nix 2018-02-13 12:15:27 +01:00
Eelco Dolstra
c5cc57e962 Merge pull request #1859 from FRidh/flatten
Nix stats: flatten statistics
2018-02-13 11:11:12 +01:00
Eelco Dolstra
9bcb4d2dd9 Fix hang in build-remote 2018-02-12 22:48:55 +01:00
Eelco Dolstra
4f09ce7940 Fix 'deadlock: trying to re-acquire self-held lock'
This was caused by derivations with 'allowSubstitutes = false'. Such
derivations will be built locally. However, if there is another
SubstitionGoal that has the output of the first derivation in its
closure, then the path will be simultaneously built and substituted.

There was a check to catch this situation (via pathIsLockedByMe()),
but it no longer worked reliably because substitutions are now done in
another thread. (Thus the comment 'It can't happen between here and
the lockPaths() call below because we're not allowing multi-threading'
was no longer valid.)

The fix is to handle the path already being locked in both
SubstitutionGoal and DerivationGoal.
2018-02-12 17:06:06 +01:00
Eelco Dolstra
35fd31770c toBuildables -> build 2018-02-12 17:06:06 +01:00
Will Dietz
c6209030c4 compression: make parallel sink separate class 2018-02-11 13:50:28 -06:00
Will Dietz
a0bdc96726 compression: print warning if parallel requested but not supported 2018-02-11 13:03:47 -06:00
Frederik Rietdijk
60eca58533 Nix stats: flatten statistics
Flattens the list of statistics as suggested in
https://github.com/NixOS/ofborg/issues/67. This makes it easier to work
with.
2018-02-11 14:37:50 +01:00
Will Dietz
5a082ad15a configure.ac: check if lzma has MT support, fix deb build/etc. 2018-02-09 21:02:25 -06:00
Eelco Dolstra
960e9c560e nix: Ensure that the user sees errors from substituters 2018-02-09 15:06:47 +01:00
Eelco Dolstra
aa02cdc33c getDefaultSubstituters(): Skip broken substituters
Fixes #1340.
2018-02-09 15:06:47 +01:00
Eelco Dolstra
3d2d207aad Merge pull request #1848 from AmineChikhaoui/parallel-xz
support multi threaded xz encoder
2018-02-09 15:03:25 +01:00
Shea Levy
081f14a169 Allow using RegisterPrimop to define constants.
This enables plugins to add new constants, as well as new primops.
2018-02-08 14:35:50 -05:00
Shea Levy
88cd2d41ac Add plugins to make Nix more extensible.
All plugins in plugin-files will be dlopened, allowing them to
statically construct instances of the various Register* types Nix
supports.
2018-02-08 12:44:37 -05:00
Eelco Dolstra
ad97a21834 nix-env: Fix parsing of --system
https://hydra.nixos.org/build/68827814
2018-02-08 15:25:03 +01:00
Eelco Dolstra
444bae44ef dsa -> ed25519
DSS is disabled by default in NixOS 18.03.

https://hydra.nixos.org/build/68788560
2018-02-08 13:46:23 +01:00
AmineChikhaoui
0685a6480a Merge branch 'master' of https://github.com/NixOS/nix into parallel-xz 2018-02-08 12:24:48 +01:00
Will Dietz
c7e0be1bfc build-dry: disable failing portion of test until issue is fixed 2018-02-07 15:20:54 -06:00
Will Dietz
98031b6050 nix build: Don't create output links with --dry-run.
Fixes #1849.
2018-02-07 15:20:54 -06:00
Will Dietz
3780435a0e tests: Add (failing) tests for reported --dry-run issues. 2018-02-07 15:20:54 -06:00
Will Dietz
f201b7733e More completely fix recursive nix, unbreak tests
See:
88b5d0c8e8 (commitcomment-27406365)
2018-02-07 15:19:28 -06:00
AmineChikhaoui
a56637205a Merge branch 'master' of https://github.com/NixOS/nix into parallel-xz 2018-02-07 21:09:04 +01:00
AmineChikhaoui
47ad88099b move the parallel-compression setting to binary-cache-store, the setting
can be done now from the url e.g s3://nix-cache?parallel-compression=1
instead of nix.conf.
2018-02-07 21:06:11 +01:00
Eelco Dolstra
88b5d0c8e8 Prevent accidental recursive Nix 2018-02-07 19:07:38 +01:00
AmineChikhaoui
55ecdfe2a8 make multi threaded compression configurable and use single threaded
by default.
2018-02-07 17:54:08 +01:00
AmineChikhaoui
163e39547a Merge branch 'master' of https://github.com/NixOS/nix into parallel-xz 2018-02-07 17:53:50 +01:00
Shea Levy
48c192ca2d builtins.path test: Don't rely on shlevy's XDG_RUNTIME_DIR 2018-02-07 10:26:53 -05:00
Eelco Dolstra
84989d3af2 Improve filtering of ANSI escape sequences in build logs
All ANSI sequences except color setting are now filtered out. In
particular, terminal resets (such as from NixOS VM tests) are filtered
out.

Also, fix the completely broken tab character handling.
2018-02-07 15:23:57 +01:00
Eelco Dolstra
cfdfad5c34 Simplify 2018-02-07 14:15:20 +01:00
Eelco Dolstra
0f3dae1064 Merge branch 'fix-aarch64-test' of https://github.com/grahamc/nix 2018-02-07 14:12:15 +01:00
Eelco Dolstra
abe6be578b Merge pull request #1816 from shlevy/add-path
Add path primop.
2018-02-07 13:32:35 +01:00
AmineChikhaoui
9d1e22f743 set block size to 0 to let the lzma lib choose the right one, add
some comments about possible improvements wrt memory usage/threading.
2018-02-07 11:18:55 +01:00
Shea Levy
69d82e5c58 Add path primop.
builtins.path allows specifying the name of a path (which makes paths
with store-illegal names now addable), allows adding paths with flat
instead of recursive hashes, allows specifying a filter (so is a
generalization of filterSource), and allows specifying an expected
hash (enabling safe path adding in pure mode).
2018-02-06 16:48:08 -05:00
AmineChikhaoui
bc7e3a4dd6 support multi threaded xz encoder, this might be particularly useful in
the case of hydra where the overhead of single threaded encoding is more
noticeable e.g most of the time spent in "Sending inputs"/"Receiving outputs"
is due to compression while the actual upload to the binary cache seems
to be negligible.
2018-02-06 22:42:02 +01:00
Eelco Dolstra
6f6bfc8205 Update the progress bar at most 20 times per second
Fixes #1834.
2018-02-06 20:51:37 +01:00
Shea Levy
694b6d229b Merge branch 'fix/busybox-sandbox-shell-attribute' of git://github.com/dtzWill/nix 2018-02-06 14:01:22 -05:00
Eelco Dolstra
43f8ef73c6 realiseContext(): Add derivation outputs to the allowed paths
This makes import-from-derivation work in restricted mode again.
2018-02-06 15:38:45 +01:00
Eelco Dolstra
f24e726ba5 checkURI(): Check file URIs against allowedPaths
This makes e.g. 'fetchGit ./.' work (assuming that ./. is an allowed
path).
2018-02-06 14:35:33 +01:00
Eelco Dolstra
f539085e65 Fix evaluation 2018-02-05 21:48:09 +01:00
Will Dietz
47dc6076af release-common: use shell from nixpkgs, provide fallback for compat 2018-02-05 11:33:18 -06:00
Eelco Dolstra
55012ec0b9 Tweak progress bar message
Say "copying" instead of "fetching" when copying from another local
store. Nice for nixos-install.
2018-02-05 18:32:23 +01:00
Eelco Dolstra
bb1d046f5c Allow substituters to be marked as trusted
This is needed by nixos-install, which uses the Nix store on the
installation CD as a substituter. We don't want to disable signature
checking entirely because substitutes from cache.nixos.org should
still be checked. So now we can pas "local?trusted=1" to mark only the
Nix store in /nix as not requiring signatures.

Fixes #1819.
2018-02-05 18:08:30 +01:00
Eelco Dolstra
2175eee9fe Fix segfault using non-binary cache stores as substituters 2018-02-05 17:46:43 +01:00
Will Dietz
0ffa615420 busybox shell: enable various useful/expected features
Matches changes made in nixpkgs:
https://github.com/NixOS/nixpkgs/pull/34628
2018-02-05 10:25:26 -06:00
Eelco Dolstra
84722d67d2 Remove nix-build --hash
Instead, if a fixed-output derivation produces has an incorrect output
hash, we now unconditionally move the outputs to the path
corresponding with the actual hash and register it as valid. Thus,
after correcting the hash in the Nix expression (e.g. in a fetchurl
call), the fixed-output derivation doesn't have to be built again.

It would still be good to have a command for reporting the actual hash
of a fixed-output derivation (instead of throwing an error), but
"nix-build --hash" didn't do that.
2018-02-03 10:08:05 +01:00
Shea Levy
de96daf54f Merge branch 'master' of git://github.com/catern/nix 2018-02-01 13:21:45 -05:00
Eelco Dolstra
19477e8815 nix-build: Ignore --indirect
Note that nix-build always creates indirect roots.

Fixes #1830.
2018-02-01 17:09:56 +01:00
Eelco Dolstra
e7b23eb5ab Remove docs on removed --drv-link and --add-drv-link options 2018-02-01 16:40:58 +01:00
Eelco Dolstra
855699855f Remove obsolete references to manifests
Closes #323.
2018-02-01 10:39:16 +01:00
Spencer Baugh
e5432574e2 document ability to set NIX_REMOTE=unix://path/to/socket 2018-01-31 22:47:16 +00:00
Eelco Dolstra
c129fc6ee8 Merge pull request #1801 from catern/master
remote_store: register for NIX_REMOTE=unix://path
2018-01-31 23:12:39 +01:00
Eelco Dolstra
88f4f0231b Fix building without aws-sdk-cpp 2018-01-31 22:34:51 +01:00
Eelco Dolstra
c287d73121 Rename 1.12 -> 2.0
Following discussion with Shea and Graham. It's a big enough change
from the last release. Also, from a semver perspective, 2.0 makes more
sense because we did remove some interfaces (like nix-pull/nix-push).
2018-01-31 18:58:45 +01:00
Eelco Dolstra
6fa690291a Add 'nix upgrade-nix' command
This command upgrades Nix to the latest stable version by installing a
store path obtained from

  https://github.com/NixOS/nixpkgs/raw/master/nixos/modules/installer/tools/nix-fallback-paths.nix

which is the same store path that the installer at
https://nixos.org/nix/install.sh uses.

The upgrade fails if Nix is not installed in a profile (e.g. on NixOS,
or when installed outside of the Nix store).
2018-01-31 16:24:43 +01:00
Eelco Dolstra
8af911be5c Merge pull request #1825 from giorgiga/master
Fix macOS installation when umask disallow public read (solves #1582)
2018-01-31 15:16:24 +01:00
Eelco Dolstra
30370f168f Cleanup 2018-01-31 15:14:03 +01:00
Eelco Dolstra
6270b2e50f Merge branch 'http-binary-cache-put-upsert' of https://github.com/adelbertc/nix 2018-01-31 15:10:12 +01:00
Eelco Dolstra
f8e8dd827e Manual: Remove old cruft 2018-01-31 15:08:46 +01:00
Eelco Dolstra
478e3e4649 Indent properly 2018-01-31 13:46:38 +01:00
Giorgio Gallo
9f9393df55 solves #1582 2018-01-29 21:33:17 +01:00
Ben Gamari
f93e890b4d configure: Use $CPP instead of cpp directly
The latter breaks in the case of cross-compilation, when `cpp` bears a
target prefix.
2018-01-29 02:20:48 -05:00
Eric Wolf
0167eac571 Improve manual on inheriting attributes
Expands first paragraph a bit
Adds a more comprehensive example
2018-01-27 16:18:31 +01:00
Spencer Baugh
746f8aed86 remote_store: register for NIX_REMOTE=unix://path
This allows overriding the socket path so the daemon may be listening at
an arbitrary Unix domain socket location.

Fixes #1800
2018-01-26 22:05:16 +00:00
Shea Levy
1d5d277ac7 HttpBinaryCacheStore: Support upsertFile with PUT.
Some servers, such as Artifactory, allow uploading with PUT and BASIC
auth. This allows nix copy to work to upload binaries to those
servers.

Worked on together with @adelbertc
2018-01-26 11:12:30 -08:00
Eelco Dolstra
e09161d05c Remove signed-binary-caches as the default for require-sigs
This was for backward compatibility. However, with security-related
configuration settings, it's best not to have any confusion.

Issue #495.
2018-01-26 17:12:15 +01:00
Eelco Dolstra
98f3c75a0e Merge pull request #1797 from dezgeg/userns-tests-fix
Fix tests using user namespaces on kernels that don't have it
2018-01-24 17:17:48 +01:00
Eelco Dolstra
479692a068 Merge pull request #1811 from dtzWill/update/json-3.0.1
nlohmann-json: 2.1.1 -> 3.0.1
2018-01-24 17:11:25 +01:00
Eelco Dolstra
b76e282da8 Merge pull request #1813 from copumpkin/download-pre-resolve-url
Fix obscure corner case in name resolution for builtin:fetchurl in sandboxed environments
2018-01-23 21:05:04 +01:00
Dan Peebles
d43a8b25f0 Fix obscure corner case in name resolution for builtin:fetchurl in sandboxed environments 2018-01-23 14:45:50 -05:00
Will Dietz
f7c26365eb nlohmann-json: 2.1.1 -> 3.0.1 2018-01-22 12:19:50 -06:00
Eelco Dolstra
c382866cd2 Fix test
https://hydra.nixos.org/build/67806811
2018-01-22 17:04:08 +01:00
Eelco Dolstra
9304fde8de Don't access tarballs.nixos.org in a test
https://hydra.nixos.org/build/67806811
2018-01-22 16:56:28 +01:00
Eelco Dolstra
89a2a11d9f Don't use [[noreturn]] 2018-01-19 15:00:38 +01:00
Eelco Dolstra
3c4c30eadd Rewrite builtin derivation environment
Also add a test.

Fixes #1803.
Closes #1805.
2018-01-19 15:00:38 +01:00
Eelco Dolstra
2896bb6826 Don't retry CURLE_URL_MALFORMAT 2018-01-19 14:05:08 +01:00
Eelco Dolstra
87e3d142cc Add a test for --check / --repeat 2018-01-19 13:58:28 +01:00
Eelco Dolstra
0c95776c3e Don't define builtins.{currentSystem,currentTime} in pure mode
This makes it easier to provide a default, e.g.

  system = builtins.currentSystem or "x86_64-linux";
2018-01-18 16:38:48 +01:00
Eelco Dolstra
5647e55f65 Merge pull request #1793 from peterstuart/fix-extra-space
Remove extra space in chat_about_sudo()
2018-01-18 16:19:44 +01:00
Eelco Dolstra
5cc5c3fb83 Merge pull request #1799 from iavael/manpath-fix-1
Fix manpath detection
2018-01-18 16:19:21 +01:00
Eelco Dolstra
27b510af5c nix eval: Stop progress bar before printing the result 2018-01-17 12:04:44 +01:00
Eelco Dolstra
16e0287556 nix eval: Take only one argument
Thus --json no longer produces a list.
2018-01-17 12:03:06 +01:00
Eelco Dolstra
cfeff3b273 Move show-trace docs 2018-01-17 11:53:16 +01:00
Eelco Dolstra
d8b4cfad82 Typo 2018-01-17 11:53:08 +01:00
Eelco Dolstra
6ddfe9a999 <nix/fetchurl.nix>: Don't access builtins.currentSystem
This doesn't work in pure evaluation mode.
2018-01-16 19:24:23 +01:00
Eelco Dolstra
75b9670df6 Make show-trace a config setting 2018-01-16 19:24:23 +01:00
Eelco Dolstra
d4dcffd643 Add pure evaluation mode
In this mode, the following restrictions apply:

* The builtins currentTime, currentSystem and storePath throw an
  error.

* $NIX_PATH and -I are ignored.

* fetchGit and fetchMercurial require a revision hash.

* fetchurl and fetchTarball require a sha256 attribute.

* No file system access is allowed outside of the paths returned by
  fetch{Git,Mercurial,url,Tarball}. Thus 'nix build -f ./foo.nix' is
  not allowed.

Thus, the evaluation result is completely reproducible from the
command line arguments. E.g.

  nix build --pure-eval '(
    let
      nix = fetchGit { url = https://github.com/NixOS/nixpkgs.git; rev = "9c927de4b179a6dd210dd88d34bda8af4b575680"; };
      nixpkgs = fetchGit { url = https://github.com/NixOS/nixpkgs.git; ref = "release-17.09"; rev = "66b4de79e3841530e6d9c6baf98702aa1f7124e4"; };
    in (import (nix + "/release.nix") { inherit nix nixpkgs; }).build.x86_64-linux
  )'

The goal is to enable completely reproducible and traceable
evaluation. For example, a NixOS configuration could be fully
described by a single Git commit hash. 'nixos-rebuild' would do
something like

  nix build --pure-eval '(
    (import (fetchGit { url = file:///my-nixos-config; rev = "..."; })).system
  ')

where the Git repository /my-nixos-config would use further fetchGit
calls or Git externals to fetch Nixpkgs and whatever other
dependencies it has. Either way, the commit hash would uniquely
identify the NixOS configuration and allow it to reproduced.
2018-01-16 19:23:18 +01:00
Eelco Dolstra
23fa7e3606 parseExprFromFile -> evalFile
parseExprFromFile() should be avoided since it doesn't cache anything.
2018-01-16 17:11:58 +01:00
Eelco Dolstra
ba75c69e00 Barf when using a diverted store on macOS
Fixes #1792.
2018-01-15 12:14:43 +01:00
Eelco Dolstra
53b520708a Merge pull request #1794 from dtzWill/feature/nix-log-pager
nix log: use pager
2018-01-15 11:25:48 +01:00
Iavael
ebc42f8b59 Fix manpath detection
Checking for MANPATH without quotes always returns true, so that it breaks bash-completion for man pages on modern systems without MANPATH environment variable.
2018-01-15 00:43:39 +03:00
Tuomas Tynkkynen
59086e459c Fix tests using user namespaces on kernels that don't have it
Disable various tests if the kernel doesn't support unprivileged user
namespaces (e.g. Arch Linux disables them) or disable them via a sysctl
(Debian, Ubuntu).

Fixes #1521
Fixes #1625
2018-01-13 19:08:41 +02:00
Will Dietz
6454ca393a nix log: use pager 2018-01-12 15:05:26 -06:00
Peter Stuart
a65376b01d Remove extra space. 2018-01-12 14:27:29 -05:00
Eelco Dolstra
74f75c8558 import, builtins.readFile: Handle diverted stores
Fixes #1791
2018-01-12 17:31:08 +01:00
Daiderd Jordan
d15826164c installer: create 'enough' build users 2018-01-03 22:34:34 +01:00
Graham Christensen
e4ece83b1a tests.setuid: only on i686 and x86_64 linuxs 2017-12-12 08:31:31 -05:00
153 changed files with 5377 additions and 3200 deletions

View File

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

1
.gitignore vendored
View File

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

View File

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

View File

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

View File

@@ -61,6 +61,7 @@ CFLAGS=
CXXFLAGS=
AC_PROG_CC
AC_PROG_CXX
AC_PROG_CPP
AX_CXX_COMPILE_STDCXX_11
@@ -174,6 +175,8 @@ AC_SUBST(HAVE_SODIUM, [$have_sodium])
# Look for liblzma, a required dependency.
PKG_CHECK_MODULES([LIBLZMA], [liblzma], [CXXFLAGS="$LIBLZMA_CFLAGS $CXXFLAGS"])
AC_CHECK_LIB([lzma], [lzma_stream_encoder_mt],
[AC_DEFINE([HAVE_LZMA_MT], [1], [xz multithreaded compression support])])
# Look for libbrotli{enc,dec}, optional dependencies
@@ -185,9 +188,22 @@ AC_SUBST(HAVE_BROTLI, [$have_brotli])
# Look for libseccomp, required for Linux sandboxing.
if test "$sys_name" = linux; then
PKG_CHECK_MODULES([LIBSECCOMP], [libseccomp],
[CXXFLAGS="$LIBSECCOMP_CFLAGS $CXXFLAGS"])
AC_ARG_ENABLE([seccomp-sandboxing],
AC_HELP_STRING([--disable-seccomp-sandboxing],
[Don't build support for seccomp sandboxing (only recommended if your arch doesn't support libseccomp yet!)]
))
if test "x$enable_seccomp_sandboxing" != "xno"; then
PKG_CHECK_MODULES([LIBSECCOMP], [libseccomp],
[CXXFLAGS="$LIBSECCOMP_CFLAGS $CXXFLAGS"])
have_seccomp=1
AC_DEFINE([HAVE_SECCOMP], [1], [Whether seccomp is available and should be used for sandboxing.])
else
have_seccomp=
fi
else
have_seccomp=
fi
AC_SUBST(HAVE_SECCOMP, [$have_seccomp])
# Look for aws-cpp-sdk-s3.
@@ -199,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 -E | 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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -31,7 +31,7 @@
<refsection><title>Description</title>
<para>A Nix channel is mechanism that allows you to automatically stay
<para>A Nix channel is a mechanism that allows you to automatically stay
up-to-date with a set of pre-built Nix expressions. A Nix channel is
just a URL that points to a place containing both a set of Nix
expressions and a pointer to a binary cache. <phrase
@@ -165,8 +165,8 @@ following files:</para>
<varlistentry><term><filename>nixexprs.tar.xz</filename></term>
<listitem><para>A tarball containing Nix expressions and files
referenced by them (such as build scripts and patches). At
top-level, the tarball should contain a single directory. That
referenced by them (such as build scripts and patches). At the
top level, the tarball should contain a single directory. That
directory must contain a file <filename>default.nix</filename>
that serves as the channels “entry point”.</para></listitem>
@@ -175,7 +175,7 @@ following files:</para>
<varlistentry><term><filename>binary-cache-url</filename></term>
<listitem><para>A file containing the URL to a binary cache (such
as <uri>https://cache.nixos.org</uri>. Nix will automatically
as <uri>https://cache.nixos.org</uri>). Nix will automatically
check this cache for pre-built binaries, if the user has
sufficient rights to add binary caches. For instance, in a
multi-user Nix setup, the binary caches provided by the channels

View File

@@ -22,12 +22,6 @@
<arg><option>--delete-old</option></arg>
<arg><option>-d</option></arg>
<arg><option>--delete-older-than</option> <replaceable>period</replaceable></arg>
<group choice='opt'>
<arg choice='plain'><option>--print-roots</option></arg>
<arg choice='plain'><option>--print-live</option></arg>
<arg choice='plain'><option>--print-dead</option></arg>
<arg choice='plain'><option>--delete</option></arg>
</group>
<arg><option>--max-freed</option> <replaceable>bytes</replaceable></arg>
<arg><option>--dry-run</option></arg>
</cmdsynopsis>

View File

@@ -501,10 +501,11 @@ error: cannot delete path `/nix/store/zq0h41l75vlb4z45kzgjjmsjxvcv1qk7-mesa-6.4'
<arg choice='plain'><option>--referrers</option></arg>
<arg choice='plain'><option>--referrers-closure</option></arg>
<arg choice='plain'><option>--deriver</option></arg>
<arg choice='plain'><option>--deriver</option></arg>
<arg choice='plain'><option>-d</option></arg>
<arg choice='plain'><option>--graph</option></arg>
<arg choice='plain'><option>--tree</option></arg>
<arg choice='plain'><option>--binding</option> <replaceable>name</replaceable></arg>
<arg choice='plain'><option>-b</option> <replaceable>name</replaceable></arg>
<arg choice='plain'><option>--hash</option></arg>
<arg choice='plain'><option>--size</option></arg>
<arg choice='plain'><option>--roots</option></arg>
@@ -642,6 +643,7 @@ query is applied to the target of the symlink.</para>
</varlistentry>
<varlistentry><term><option>--deriver</option></term>
<term><option>-d</option></term>
<listitem><para>Prints the <link
linkend="gloss-deriver">deriver</link> of the store paths
@@ -678,6 +680,7 @@ query is applied to the target of the symlink.</para>
</varlistentry>
<varlistentry><term><option>--binding</option> <replaceable>name</replaceable></term>
<term><option>-b</option> <replaceable>name</replaceable></term>
<listitem><para>Prints the value of the attribute
<replaceable>name</replaceable> (i.e., environment variable) of

View File

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

View File

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

View File

@@ -126,6 +126,17 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
</varlistentry>
<varlistentry><term><function>builtins.splitVersion</function>
<replaceable>s</replaceable></term>
<listitem><para>Split a string representing a version into its
components, by the same version splitting logic underlying the
version comparison in <link linkend="ssec-version-comparisons">
<command>nix-env -u</command></link>.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.concatLists</function>
<replaceable>lists</replaceable></term>
@@ -296,6 +307,61 @@ stdenv.mkDerivation { … }
</varlistentry>
<varlistentry>
<term>
<function>builtins.fetchGit</function>
<replaceable>args</replaceable>
</term>
<listitem>
<para>
Fetch a path from git. <replaceable>args</replaceable> can be
a URL, in which case the HEAD of the repo at that URL is
fetched. Otherwise, it can be an attribute with the following
attributes (all except <varname>url</varname> optional):
</para>
<variablelist>
<varlistentry>
<term>url</term>
<listitem>
<para>
The URL of the repo.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>name</term>
<listitem>
<para>
The name of the directory the repo should be exported to
in the store. Defaults to the basename of the URL.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>rev</term>
<listitem>
<para>
The git revision to fetch. Defaults to the tip of
<varname>ref</varname>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>ref</term>
<listitem>
<para>
The git ref to look for the requested revision under.
This is often a branch or tag name. Defaults to
<literal>HEAD</literal>.
</para>
</listitem>
</varlistentry>
</variablelist>
</listitem>
</varlistentry>
<varlistentry><term><function>builtins.filter</function>
<replaceable>f</replaceable> <replaceable>xs</replaceable></term>
@@ -308,8 +374,9 @@ stdenv.mkDerivation { … }
</varlistentry>
<varlistentry><term><function>builtins.filterSource</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<varlistentry xml:id='builtin-filterSource'>
<term><function>builtins.filterSource</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<listitem>
@@ -768,6 +835,75 @@ Evaluates to <literal>[ "foo" ]</literal>.
</varlistentry>
<varlistentry>
<term>
<function>builtins.path</function>
<replaceable>args</replaceable>
</term>
<listitem>
<para>
An enrichment of the built-in path type, based on the attributes
present in <replaceable>args</replaceable>. All are optional
except <varname>path</varname>:
</para>
<variablelist>
<varlistentry>
<term>path</term>
<listitem>
<para>The underlying path.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>name</term>
<listitem>
<para>
The name of the path when added to the store. This can
used to reference paths that have nix-illegal characters
in their names, like <literal>@</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>filter</term>
<listitem>
<para>
A function of the type expected by
<link linkend="builtin-filterSource">builtins.filterSource</link>,
with the same semantics.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>recursive</term>
<listitem>
<para>
When <literal>false</literal>, when
<varname>path</varname> is added to the store it is with a
flat hash, rather than a hash of the NAR serialization of
the file. Thus, <varname>path</varname> must refer to a
regular file, not a directory. This allows similar
behavior to <literal>fetchurl</literal>. Defaults to
<literal>true</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>sha256</term>
<listitem>
<para>
When provided, this is the expected hash of the file at
the path. Evaluation will fail if the hash is incorrect,
and providing a hash allows
<literal>builtins.path</literal> to be used even when the
<literal>pure-eval</literal> nix config option is on.
</para>
</listitem>
</varlistentry>
</variablelist>
</listitem>
</varlistentry>
<varlistentry><term><function>builtins.pathExists</function>
<replaceable>path</replaceable></term>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -12,7 +12,7 @@ automatically fetching any store paths in Firefoxs closure if they
are available on the server <literal>avalon</literal>:
<screen>
$ nix-env -i firefox --option ssh-substituter-hosts alice@avalon
$ nix-env -i firefox --substituters ssh://alice@avalon
</screen>
This works similar to the binary cache substituter that Nix usually
@@ -31,7 +31,7 @@ an SSH passphrase interactively. Therefore, you should use
installing it into your profile, e.g.
<screen>
$ nix-store -r /nix/store/m85bxg…-firefox-34.0.5 --option ssh-substituter-hosts alice@avalon
$ nix-store -r /nix/store/m85bxg…-firefox-34.0.5 --substituters ssh://alice@avalon
</screen>
This is essentially equivalent to doing

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,6 +4,8 @@
<dict>
<key>Label</key>
<string>org.nixos.nix-daemon</string>
<key>KeepAlive</key>
<true/>
<key>RunAtLoad</key>
<true/>
<key>Program</key>

View File

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

View File

@@ -51,7 +51,7 @@ define build-program
else
$(DESTDIR)$$($(1)_INSTALL_PATH): $$($(1)_PATH) | $(DESTDIR)$$($(1)_INSTALL_DIR)/
install -t $$($(1)_INSTALL_DIR) $$<
install -t $(DESTDIR)$$($(1)_INSTALL_DIR) $$<
endif

View File

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

View File

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

View File

@@ -1,12 +1,12 @@
{ nix ? builtins.fetchGit ./.
, nixpkgs ? fetchTarball channel:nixos-17.09
, nixpkgs ? builtins.fetchGit https://github.com/NixOS/nixpkgs.git
, officialRelease ? false
, systems ? [ "x86_64-linux" "i686-linux" "x86_64-darwin" "aarch64-linux" ]
}:
let
pkgs = import nixpkgs {};
pkgs = import nixpkgs { system = builtins.currentSystem or "x86_64-linux"; };
jobs = rec {
@@ -127,34 +127,56 @@ let
binaryTarball = pkgs.lib.genAttrs systems (system:
# FIXME: temporarily use a different branch for the Darwin build.
with import nixpkgs { inherit system; };
let
toplevel = builtins.getAttr system jobs.build;
version = toplevel.src.version;
installerClosureInfo = closureInfo { rootPaths = [ toplevel cacert ]; };
in
runCommand "nix-binary-tarball-${version}"
{ exportReferencesGraph = [ "closure1" toplevel "closure2" cacert ];
buildInputs = [ perl shellcheck ];
{ nativeBuildInputs = lib.optional (system != "aarch64-linux") shellcheck;
meta.description = "Distribution-independent Nix bootstrap binaries for ${system}";
}
''
storePaths=$(perl ${pathsFromGraph} ./closure1 ./closure2)
printRegistration=1 perl ${pathsFromGraph} ./closure1 ./closure2 > $TMPDIR/reginfo
cp ${installerClosureInfo}/registration $TMPDIR/reginfo
substitute ${./scripts/install-nix-from-closure.sh} $TMPDIR/install \
--subst-var-by nix ${toplevel} \
--subst-var-by cacert ${cacert}
substitute ${./scripts/install-darwin-multi-user.sh} $TMPDIR/install-darwin-multi-user \
substitute ${./scripts/install-darwin-multi-user.sh} $TMPDIR/install-darwin-multi-user.sh \
--subst-var-by nix ${toplevel} \
--subst-var-by cacert ${cacert}
substitute ${./scripts/install-systemd-multi-user.sh} $TMPDIR/install-systemd-multi-user.sh \
--subst-var-by nix ${toplevel} \
--subst-var-by cacert ${cacert}
substitute ${./scripts/install-multi-user.sh} $TMPDIR/install-multi-user \
--subst-var-by nix ${toplevel} \
--subst-var-by cacert ${cacert}
shellcheck -e SC1090 $TMPDIR/install
shellcheck -e SC1091,SC2002 $TMPDIR/install-darwin-multi-user
if type -p shellcheck; then
# SC1090: Don't worry about not being able to find
# $nix/etc/profile.d/nix.sh
shellcheck --exclude SC1090 $TMPDIR/install
shellcheck $TMPDIR/install-darwin-multi-user.sh
shellcheck $TMPDIR/install-systemd-multi-user.sh
# SC1091: Don't panic about not being able to source
# /etc/profile
# SC2002: Ignore "useless cat" "error", when loading
# .reginfo, as the cat is a much cleaner
# implementation, even though it is "useless"
# SC2116: Allow ROOT_HOME=$(echo ~root) for resolving
# root's home directory
shellcheck --external-sources \
--exclude SC1091,SC2002,SC2116 $TMPDIR/install-multi-user
fi
chmod +x $TMPDIR/install
chmod +x $TMPDIR/install-darwin-multi-user
chmod +x $TMPDIR/install-darwin-multi-user.sh
chmod +x $TMPDIR/install-systemd-multi-user.sh
chmod +x $TMPDIR/install-multi-user
dir=nix-${version}-${system}
fn=$out/$dir.tar.bz2
mkdir -p $out/nix-support
@@ -166,7 +188,10 @@ let
--transform "s,$TMPDIR/install,$dir/install," \
--transform "s,$TMPDIR/reginfo,$dir/.reginfo," \
--transform "s,$NIX_STORE,$dir/store,S" \
$TMPDIR/install $TMPDIR/install-darwin-multi-user $TMPDIR/reginfo $storePaths
$TMPDIR/install $TMPDIR/install-darwin-multi-user.sh \
$TMPDIR/install-systemd-multi-user.sh \
$TMPDIR/install-multi-user $TMPDIR/reginfo \
$(cat ${installerClosureInfo}/store-paths)
'');
@@ -200,8 +225,8 @@ let
};
rpm_fedora25i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora25i386) [ "libsodium-devel" ];
rpm_fedora25x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora25x86_64) [ "libsodium-devel" ];
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" ];
@@ -209,8 +234,6 @@ let
deb_ubuntu1604i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1604i386) [ "libsodium-dev" ] [ "libsodium18" ];
deb_ubuntu1604x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1604x86_64) [ "libsodium-dev" ] [ "libsodium18" ];
deb_ubuntu1610i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1610i386) [ "libsodium-dev" ] [ "libsodium18" ];
deb_ubuntu1610x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1610x86_64) [ "libsodium-dev" ] [ "libsodium18" ];
# System tests.
@@ -224,11 +247,13 @@ let
nix = build.x86_64-linux; system = "x86_64-linux";
});
tests.setuid = pkgs.lib.genAttrs (pkgs.lib.filter (pkgs.lib.hasSuffix "-linux") systems) (system:
import ./tests/setuid.nix rec {
inherit nixpkgs;
nix = build.${system}; inherit system;
});
tests.setuid = pkgs.lib.genAttrs
["i686-linux" "x86_64-linux"]
(system:
import ./tests/setuid.nix rec {
inherit nixpkgs;
nix = build.${system}; inherit system;
});
tests.binaryTarball =
with import nixpkgs { system = "x86_64-linux"; };
@@ -263,7 +288,8 @@ let
export NIX_STATE_DIR=$TMPDIR
nix-store --init
nix-instantiate ${nixpkgs}/nixos/release-combined.nix -A tested --dry-run
nix-instantiate ${nixpkgs}/nixos/release-combined.nix -A tested --dry-run \
--arg nixpkgs '{ outPath = ${nixpkgs}; revCount = 123; shortRev = "abcdefgh"; }'
touch $out
'';
@@ -281,12 +307,6 @@ let
binaryTarball.i686-linux
binaryTarball.x86_64-darwin
binaryTarball.x86_64-linux
#deb_debian8i386
#deb_debian8x86_64
deb_ubuntu1604i386
deb_ubuntu1604x86_64
rpm_fedora25i386
rpm_fedora25x86_64
tests.remoteBuilds
tests.nix-copy-closure
tests.binaryTarball

View File

@@ -1,772 +1,43 @@
#!/bin/bash
#!/usr/bin/env bash
set -eu
set -o pipefail
# Sourced from:
# - https://github.com/LnL7/nix-darwin/blob/8c29d0985d74b4a990238497c47a2542a5616b3c/bootstrap.sh
# - https://gist.github.com/expipiplus1/e571ce88c608a1e83547c918591b149f/ac504c6c1b96e65505fbda437a28ce563408ecb0
# - https://github.com/NixOS/nixos-org-configurations/blob/a122f418797713d519aadf02e677fce0dc1cb446/delft/scripts/nix-mac-installer.sh
# - https://github.com/matthewbauer/macNixOS/blob/f6045394f9153edea417be90c216788e754feaba/install-macNixOS.sh
# - https://gist.github.com/LnL7/9717bd6cdcb30b086fd7f2093e5f8494/86b26f852ce563e973acd30f796a9a416248c34a
#
# however tracking which bits came from which would be impossible.
readonly ESC='\033[0m'
readonly BOLD='\033[38;1m'
readonly BLUE='\033[38;34m'
readonly BLUE_UL='\033[38;4;34m'
readonly GREEN='\033[38;32m'
readonly GREEN_UL='\033[38;4;32m'
readonly RED='\033[38;31m'
readonly RED_UL='\033[38;4;31m'
readonly YELLOW='\033[38;33m'
readonly YELLOW_UL='\033[38;4;33m'
readonly CORES=$(sysctl -n hw.ncpu)
readonly NIX_USER_COUNT="$CORES"
readonly NIX_BUILD_GROUP_ID="30000"
readonly NIX_BUILD_GROUP_NAME="nixbld"
readonly NIX_FIRST_BUILD_UID="30001"
# Please don't change this. We don't support it, because the
# default shell profile that comes with Nix doesn't support it.
readonly NIX_ROOT="/nix"
readonly PLIST_DEST=/Library/LaunchDaemons/org.nixos.nix-daemon.plist
readonly PROFILE_TARGETS=("/etc/bashrc" "/etc/zshrc")
readonly PROFILE_BACKUP_SUFFIX=".backup-before-nix"
readonly PROFILE_NIX_FILE="$NIX_ROOT/var/nix/profiles/default/etc/profile.d/nix-daemon.sh"
readonly NIX_INSTALLED_NIX="@nix@"
readonly NIX_INSTALLED_CACERT="@cacert@"
readonly EXTRACTED_NIX_PATH="$(dirname "$0")"
readonly ROOT_HOME="/var/root"
if [ -t 0 ]; then
readonly IS_HEADLESS='no'
else
readonly IS_HEADLESS='yes'
fi
headless() {
if [ "$IS_HEADLESS" = "yes" ]; then
return 0
else
return 1
fi
}
contactme() {
echo "We'd love to help if you need it."
echo ""
echo "If you can, open an issue at https://github.com/nixos/nix/issues"
echo ""
echo "Or feel free to contact the team,"
echo " - on IRC #nixos on irc.freenode.net"
echo " - on twitter @nixos_org"
}
uninstall_directions() {
subheader "Uninstalling nix:"
local step=0
if [ -e "$PLIST_DEST" ]; then
step=$((step + 1))
cat <<EOF
$step. Delete $PLIST_DEST
sudo launchctl unload $PLIST_DEST
sudo rm $PLIST_DEST
EOF
fi
for profile_target in "${PROFILE_TARGETS[@]}"; do
if [ -e "$profile_target" ] && [ -e "$profile_target$PROFILE_BACKUP_SUFFIX" ]; then
step=$((step + 1))
cat <<EOF
$step. Restore $profile_target$PROFILE_BACKUP_SUFFIX back to $profile_target
sudo mv $profile_target$PROFILE_BACKUP_SUFFIX $profile_target
(after this one, you may need to re-open any terminals that were
opened while it existed.)
EOF
fi
done
step=$((step + 1))
cat <<EOF
$step. Delete the files Nix added to your system:
sudo rm -rf /etc/nix $NIX_ROOT $ROOT_HOME/.nix-profile $ROOT_HOME/.nix-defexpr $ROOT_HOME/.nix-channels $HOME/.nix-profile $HOME/.nix-defexpr $HOME/.nix-channels
and that is it.
EOF
}
nix_user_for_core() {
printf "nixbld%d" "$1"
}
nix_uid_for_core() {
echo $((NIX_FIRST_BUILD_UID + $1 - 1))
}
dsclattr() {
/usr/bin/dscl . -read "$1" \
| awk "/$2/ { print \$2 }"
}
_textout() {
echo -en "$1"
shift
if [ "$*" = "" ]; then
cat
else
echo "$@"
fi
echo -en "$ESC"
}
header() {
follow="---------------------------------------------------------"
header=$(echo "---- $* $follow$follow$follow" | head -c 80)
echo ""
_textout "$BLUE" "$header"
}
warningheader() {
follow="---------------------------------------------------------"
header=$(echo "---- $* $follow$follow$follow" | head -c 80)
echo ""
_textout "$RED" "$header"
}
subheader() {
echo ""
_textout "$BLUE_UL" "$*"
}
row() {
printf "$BOLD%s$ESC:\\t%s\\n" "$1" "$2"
}
task() {
echo ""
ok "~~> $1"
}
bold() {
echo "$BOLD$*$ESC"
}
ok() {
_textout "$GREEN" "$@"
}
warning() {
warningheader "warning!"
cat
echo ""
}
failure() {
header "oh no!"
_textout "$RED" "$@"
echo ""
_textout "$RED" "$(contactme)"
trap finish_cleanup EXIT
exit 1
}
ui_confirm() {
_textout "$GREEN$GREEN_UL" "$1"
if headless; then
echo "No TTY, assuming you would say yes :)"
return 0
fi
local prompt="[y/n] "
echo -n "$prompt"
while read -r y; do
if [ "$y" = "y" ]; then
echo ""
return 0
elif [ "$y" = "n" ]; then
echo ""
return 1
else
_textout "$RED" "Sorry, I didn't understand. I can only understand answers of y or n"
echo -n "$prompt"
fi
done
echo ""
return 1
}
__sudo() {
local expl="$1"
local cmd="$2"
shift
header "sudo execution"
echo "I am executing:"
echo ""
printf " $ sudo %s\\n" "$cmd"
echo ""
echo "$expl"
echo ""
return 0
}
_sudo() {
local expl="$1"
shift
if ! headless; then
__sudo "$expl" "$*"
fi
sudo "$@"
}
readonly SCRATCH=$(mktemp -d -t tmp.XXXXXXXXXX)
function finish_cleanup {
rm -rf "$SCRATCH"
}
function finish_fail {
finish_cleanup
failure <<EOF
Jeeze, something went wrong. If you can take all the output and open
an issue, we'd love to fix the problem so nobody else has this issue.
:(
EOF
}
trap finish_fail EXIT
function finish_success {
finish_cleanup
ok "Alright! We're done!"
cat <<EOF
Before Nix will work in your existing shells, you'll need to close
them and open them again. Other than that, you should be ready to go.
Try it! Open a new terminal, and type:
$ nix-shell -p nix-info --run "nix-info -m"
Thank you for using this installer. If you have any feedback, don't
hesitate:
$(contactme)
EOF
}
validate_starting_assumptions() {
poly_validate_assumptions() {
if [ "$(uname -s)" != "Darwin" ]; then
failure "This script is for use with macOS!"
fi
if [ $EUID -eq 0 ]; then
failure <<EOF
Please do not run this script with root privileges. We will call sudo
when we need to.
EOF
fi
if type nix-env 2> /dev/null >&2; then
failure <<EOF
Nix already appears to be installed, and this tool assumes it is
_not_ yet installed.
$(uninstall_directions)
EOF
fi
if [ "${NIX_REMOTE:-}" != "" ]; then
failure <<EOF
For some reason, \$NIX_REMOTE is set. It really should not be set
before this installer runs, and it hints that Nix is currently
installed. Please delete the old Nix installation and start again.
Note: You might need to close your shell window and open a new shell
to clear the variable.
EOF
fi
if echo "${SSL_CERT_FILE:-}" | grep -qE "(nix/var/nix|nix-profile)"; then
failure <<EOF
It looks like \$SSL_CERT_FILE is set to a path that used to be part of
the old Nix installation. Please unset that variable and try again:
$ unset SSL_CERT_FILE
EOF
fi
for file in ~/.bash_profile ~/.bash_login ~/.profile ~/.zshenv ~/.zprofile ~/.zshrc ~/.zlogin; do
if [ -f "$file" ]; then
if grep -l "^[^#].*.nix-profile" "$file"; then
failure <<EOF
I found a reference to a ".nix-profile" in $file.
This has a high chance of breaking a new nix installation. It was most
likely put there by a previous Nix installer.
Please remove this reference and try running this again. You should
also look for similar references in:
- ~/.bash_profile
- ~/.bash_login
- ~/.profile
or other shell init files that you may have.
$(uninstall_directions)
EOF
fi
fi
done
if [ -d /nix ]; then
failure <<EOF
There are some relics of a previous installation of Nix at /nix, and
this scripts assumes Nix is _not_ yet installed. Please delete the old
Nix installation and start again.
$(uninstall_directions)
EOF
fi
if [ -d /etc/nix ]; then
failure <<EOF
There are some relics of a previous installation of Nix at /etc/nix, and
this scripts assumes Nix is _not_ yet installed. Please delete the old
Nix installation and start again.
$(uninstall_directions)
EOF
fi
for profile_target in "${PROFILE_TARGETS[@]}"; do
if [ -e "$profile_target$PROFILE_BACKUP_SUFFIX" ]; then
failure <<EOF
When this script runs, it backs up the current $profile_target to
$profile_target$PROFILE_BACKUP_SUFFIX. This backup file already exists, though.
Please follow these instructions to clean up the old backup file:
1. Copy $profile_target and $profile_target$PROFILE_BACKUP_SUFFIX to another place, just
in case.
2. Take care to make sure that $profile_target$PROFILE_BACKUP_SUFFIX doesn't look like
it has anything nix-related in it. If it does, something is probably
quite wrong. Please open an issue or get in touch immediately.
3. Take care to make sure that $profile_target doesn't look like it has
anything nix-related in it. If it does, and $profile_target _did not_,
run:
$ /usr/bin/sudo /bin/mv $profile_target$PROFILE_BACKUP_SUFFIX $profile_target
and try again.
EOF
fi
if grep -qi "nix" "$profile_target"; then
failure <<EOF
It looks like $profile_target already has some Nix configuration in
there. There should be no reason to run this again. If you're having
trouble, please open an issue.
EOF
fi
done
danger_paths=("$ROOT_HOME/.nix-defexpr" "$ROOT_HOME/.nix-channels" "$ROOT_HOME/.nix-profile")
for danger_path in "${danger_paths[@]}"; do
if _sudo "making sure that $danger_path doesn't exist" \
test -e "$danger_path"; then
failure <<EOF
I found a file at $danger_path, which is a relic of a previous
installation. You must first delete this file before continuing.
$(uninstall_directions)
EOF
fi
done
}
setup_report() {
header "hardware report"
row " Cores" "$CORES"
header "Nix config report"
row " Temp Dir" "$SCRATCH"
row " Nix Root" "$NIX_ROOT"
row " Build Users" "$NIX_USER_COUNT"
row " Build Group ID" "$NIX_BUILD_GROUP_ID"
row "Build Group Name" "$NIX_BUILD_GROUP_NAME"
if [ "${ALLOW_PREEXISTING_INSTALLATION:-}" != "" ]; then
row "Preexisting Install" "Allowed"
fi
subheader "build users:"
row " Username" "UID"
for i in $(seq 1 "$NIX_USER_COUNT"); do
row " $(nix_user_for_core "$i")" "$(nix_uid_for_core "$i")"
done
echo ""
poly_service_installed_check() {
[ -e "$PLIST_DEST" ]
}
create_build_group() {
local primary_group_id
poly_service_uninstall_directions() {
cat <<EOF
$1. Delete $PLIST_DEST
task "Setting up the build group $NIX_BUILD_GROUP_NAME"
if ! /usr/bin/dscl . -read "/Groups/$NIX_BUILD_GROUP_NAME" > /dev/null 2>&1; then
_sudo "Create the Nix build group, $NIX_BUILD_GROUP_NAME" \
/usr/sbin/dseditgroup -o create \
-r "Nix build group for nix-daemon" \
-i "$NIX_BUILD_GROUP_ID" \
"$NIX_BUILD_GROUP_NAME" >&2
row " Created" "Yes"
else
primary_group_id=$(dsclattr "/Groups/$NIX_BUILD_GROUP_NAME" "PrimaryGroupID")
if [ "$primary_group_id" -ne "$NIX_BUILD_GROUP_ID" ]; then
failure <<EOF
It seems the build group $NIX_BUILD_GROUP_NAME already exists, but
with the UID $primary_group_id. This script can't really handle
that right now, so I'm going to give up.
sudo launchctl unload $PLIST_DEST
sudo rm $PLIST_DEST
You can fix this by editing this script and changing the
NIX_BUILD_GROUP_ID variable near the top to from $NIX_BUILD_GROUP_ID
to $primary_group_id and re-run.
EOF
else
row " Exists" "Yes"
fi
fi
}
create_build_user_for_core() {
local coreid
local username
local uid
coreid="$1"
username=$(nix_user_for_core "$coreid")
uid=$(nix_uid_for_core "$coreid")
dsclpath="/Users/$username"
task "Setting up the build user $username"
if ! /usr/bin/dscl . -read "$dsclpath" > /dev/null 2>&1; then
_sudo "Creating the Nix build user, $username" \
/usr/bin/dscl . create "$dsclpath" \
UniqueID "${uid}"
row " Created" "Yes"
else
actual_uid=$(dsclattr "$dsclpath" "UniqueID")
if [ "$actual_uid" -ne "$uid" ]; then
failure <<EOF
It seems the build user $username already exists, but with the UID
with the UID $actual_uid. This script can't really handle that right
now, so I'm going to give up.
If you already created the users and you know they start from
$actual_uid and go up from there, you can edit this script and change
NIX_FIRST_BUILD_UID near the top of the file to $actual_uid and try
again.
EOF
else
row " Exists" "Yes"
fi
fi
if [ "$(dsclattr "$dsclpath" "IsHidden")" = "1" ]; then
row " IsHidden" "Yes"
else
_sudo "in order to make $username a hidden user" \
/usr/bin/dscl . -create "$dsclpath" "IsHidden" "1"
row " IsHidden" "Yes"
fi
if [ "$(dsclattr "$dsclpath" "NFSHomeDirectory")" = "/var/empty" ]; then
row " NFSHomeDirectory" "/var/empty"
else
_sudo "in order to give $username a safe home directory" \
/usr/bin/dscl . -create "$dsclpath" "NFSHomeDirectory" "/var/empty"
row " NFSHomeDirectory" "/var/empty"
fi
if [ "$(dsclattr "$dsclpath" "RealName")" = "Nix build user $coreid" ]; then
row " RealName" "Nix build user $coreid"
else
_sudo "in order to give $username a useful name" \
/usr/bin/dscl . -create "$dsclpath" "RealName" "Nix build user $coreid"
row " RealName" "Nix build user $coreid"
fi
if [ "$(dsclattr "$dsclpath" "UserShell")" = "/sbin/nologin" ]; then
row " Logins Disabled" "Yes"
else
_sudo "in order to prevent $username from logging in" \
/usr/bin/dscl . -create "$dsclpath" "UserShell" "/sbin/nologin"
row " Logins Disabled" "Yes"
fi
if dseditgroup -o checkmember -m "$username" "$NIX_BUILD_GROUP_NAME" > /dev/null 2>&1 ; then
row " Member of $NIX_BUILD_GROUP_NAME" "Yes"
else
_sudo "Add $username to the $NIX_BUILD_GROUP_NAME group"\
/usr/sbin/dseditgroup -o edit -t user \
-a "$username" "$NIX_BUILD_GROUP_NAME"
row " Member of $NIX_BUILD_GROUP_NAME" "Yes"
fi
if [ "$(dsclattr "$dsclpath" "PrimaryGroupID")" = "$NIX_BUILD_GROUP_ID" ]; then
row " PrimaryGroupID" "$NIX_BUILD_GROUP_ID"
else
_sudo "to let the nix daemon use this user for builds (this might seem redundant, but there are two concepts of group membership)" \
/usr/bin/dscl . -create "$dsclpath" "PrimaryGroupID" "$NIX_BUILD_GROUP_ID"
row " PrimaryGroupID" "$NIX_BUILD_GROUP_ID"
fi
}
create_build_users() {
for i in $(seq 1 "$NIX_USER_COUNT"); do
create_build_user_for_core "$i"
done
}
create_directories() {
_sudo "to make the basic directory structure of Nix (part 1)" \
mkdir -pv -m 0755 /nix /nix/var /nix/var/log /nix/var/log/nix /nix/var/log/nix/drvs /nix/var/nix{,/db,/gcroots,/profiles,/temproots,/userpool}
_sudo "to make the basic directory structure of Nix (part 2)" \
mkdir -pv -m 1777 /nix/var/nix/{gcroots,profiles}/per-user
_sudo "to make the basic directory structure of Nix (part 3)" \
mkdir -pv -m 1775 /nix/store
_sudo "to make the basic directory structure of Nix (part 4)" \
chgrp "$NIX_BUILD_GROUP_NAME" /nix/store
_sudo "to set up the root user's profile (part 1)" \
mkdir -pv -m 0755 /nix/var/nix/profiles/per-user/root
_sudo "to set up the root user's profile (part 2)" \
mkdir -pv -m 0700 "$ROOT_HOME/.nix-defexpr"
_sudo "to place the default nix daemon configuration (part 1)" \
mkdir -pv -m 0555 /etc/nix
}
place_channel_configuration() {
echo "https://nixos.org/channels/nixpkgs-unstable nixpkgs" > "$SCRATCH/.nix-channels"
_sudo "to set up the default system channel (part 1)" \
install -m 0664 "$SCRATCH/.nix-channels" "$ROOT_HOME/.nix-channels"
}
welcome_to_nix() {
ok "Welcome to the Multi-User Nix Installation"
poly_service_setup_note() {
cat <<EOF
This installation tool will set up your computer with the Nix package
manager. This will happen in a few stages:
1. Make sure your computer doesn't already have Nix. If it does, I
will show you instructions on how to clean up your old one.
2. Show you what we are going to install and where. Then we will ask
if you are ready to continue.
3. Create the system users and groups that the Nix daemon uses to run
builds.
4. Perform the basic installation of the Nix files daemon.
5. Configure your shell to import special Nix Profile files, so you
can use Nix.
6. Start the Nix daemon.
EOF
if ui_confirm "Would you like to see a more detailed list of what we will do?"; then
cat <<EOF
We will:
- make sure your computer doesn't already have Nix files
(if it does, I will tell you how to clean them up.)
- create local users (see the list above for the users we'll make)
- create a local group ($NIX_BUILD_GROUP_NAME)
- install Nix in to $NIX_ROOT
- create a configuration file in /etc/nix
- set up the "default profile" by creating some Nix-related files in
$ROOT_HOME
EOF
for profile_target in "${PROFILE_TARGETS[@]}"; do
if [ -e "$profile_target" ]; then
cat <<EOF
- back up $profile_target to $profile_target$PROFILE_BACKUP_SUFFIX
- update $profile_target to include some Nix configuration
EOF
fi
done
cat <<EOF
- load and start a LaunchDaemon (at $PLIST_DEST) for nix-daemon
EOF
if ! ui_confirm "Ready to continue?"; then
failure <<EOF
Okay, maybe you would like to talk to the team.
EOF
fi
fi
}
chat_about_sudo() {
header "let's talk about sudo"
if headless; then
cat <<EOF
This script is going to call sudo a lot. Normally, it would show you
exactly what commands it is running and why. However, the script is
run in a headless fashion, like this:
$ curl https://nixos.org/nix/install | sh
or maybe in a CI pipeline. Because of that, we're going to skip the
verbose output in the interest of brevity.
If you would like to
see the output, try like this:
$ curl -o install-nix https://nixos.org/nix/install
$ sh ./install-nix
EOF
return 0
fi
cat <<EOF
This script is going to call sudo a lot. Every time we do, it'll
output exactly what it'll do, and why.
Just like this:
EOF
__sudo "to demonstrate how our sudo prompts look" \
echo "this is a sudo prompt"
cat <<EOF
This might look scary, but everything can be undone by running just a
few commands. We used to ask you to confirm each time sudo ran, but it
was too many times. Instead, I'll just ask you this one time:
EOF
if ui_confirm "Can we use sudo?"; then
ok "Yay! Thanks! Let's get going!"
else
failure <<EOF
That is okay, but we can't install.
EOF
fi
}
install_from_extracted_nix() {
(
cd "$EXTRACTED_NIX_PATH"
_sudo "to copy the basic Nix files to the new store at $NIX_ROOT/store" \
rsync -rlpt "$(pwd)/store/" "$NIX_ROOT/store/"
if [ -d "$NIX_INSTALLED_NIX" ]; then
echo " Alright! We have our first nix at $NIX_INSTALLED_NIX"
else
failure <<EOF
Something went wrong, and I didn't find Nix installed at
$NIX_INSTALLED_NIX.
EOF
fi
_sudo "to initialize the Nix Database" \
$NIX_INSTALLED_NIX/bin/nix-store --init
cat ./.reginfo \
| _sudo "to load data for the first time in to the Nix Database" \
"$NIX_INSTALLED_NIX/bin/nix-store" --load-db
echo " Just finished getting the nix database ready."
)
}
shell_source_lines() {
cat <<EOF
# Nix
if [ -e '$PROFILE_NIX_FILE' ]; then
. '$PROFILE_NIX_FILE'
fi
# End Nix
EOF
}
configure_shell_profile() {
for profile_target in "${PROFILE_TARGETS[@]}"; do
if [ -e "$profile_target" ]; then
_sudo "to back up your current $profile_target to $profile_target$PROFILE_BACKUP_SUFFIX" \
cp "$profile_target" "$profile_target$PROFILE_BACKUP_SUFFIX"
shell_source_lines \
| _sudo "extend your $profile_target with nix-daemon settings" \
tee -a "$profile_target"
fi
done
}
setup_default_profile() {
_sudo "to installing a bootstrapping Nix in to the default Profile" \
HOME=$ROOT_HOME "$NIX_INSTALLED_NIX/bin/nix-env" -i "$NIX_INSTALLED_NIX"
_sudo "to installing a bootstrapping SSL certificate just for Nix in to the default Profile" \
HOME=$ROOT_HOME "$NIX_INSTALLED_NIX/bin/nix-env" -i "$NIX_INSTALLED_CACERT"
_sudo "to update the default channel in the default profile" \
HOME=$ROOT_HOME NIX_SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt "$NIX_INSTALLED_NIX/bin/nix-channel" --update nixpkgs
}
place_nix_configuration() {
cat <<EOF > "$SCRATCH/nix.conf"
build-users-group = $NIX_BUILD_GROUP_NAME
max-jobs = $NIX_USER_COUNT
cores = 1
sandbox = false
EOF
_sudo "to place the default nix daemon configuration (part 2)" \
install -m 0664 "$SCRATCH/nix.conf" /etc/nix/nix.conf
}
configure_nix_daemon_plist() {
poly_configure_nix_daemon_service() {
_sudo "to set up the nix-daemon as a LaunchDaemon" \
ln -sfn "/nix/var/nix/profiles/default$PLIST_DEST" "$PLIST_DEST"
@@ -778,42 +49,96 @@ configure_nix_daemon_plist() {
}
main() {
welcome_to_nix
chat_about_sudo
if [ "${ALLOW_PREEXISTING_INSTALLATION:-}" = "" ]; then
validate_starting_assumptions
fi
setup_report
if ! ui_confirm "Ready to continue?"; then
ok "Alright, no changes have been made :)"
contactme
trap finish_cleanup EXIT
exit 1
fi
create_build_group
create_build_users
create_directories
place_channel_configuration
install_from_extracted_nix
configure_shell_profile
set +eu
. /etc/profile
set -eu
setup_default_profile
place_nix_configuration
configure_nix_daemon_plist
trap finish_success EXIT
poly_group_exists() {
/usr/bin/dscl . -read "/Groups/$1" > /dev/null 2>&1
}
poly_group_id_get() {
dsclattr "/Groups/$1" "PrimaryGroupID"
}
main
poly_create_build_group() {
_sudo "Create the Nix build group, $NIX_BUILD_GROUP_NAME" \
/usr/sbin/dseditgroup -o create \
-r "Nix build group for nix-daemon" \
-i "$NIX_BUILD_GROUP_ID" \
"$NIX_BUILD_GROUP_NAME" >&2
}
poly_user_exists() {
/usr/bin/dscl . -read "/Users/$1" > /dev/null 2>&1
}
poly_user_id_get() {
dsclattr "/Users/$1" "UniqueID"
}
poly_user_hidden_get() {
dsclattr "/Users/$1" "IsHidden"
}
poly_user_hidden_set() {
_sudo "in order to make $1 a hidden user" \
/usr/bin/dscl . -create "/Users/$1" "IsHidden" "1"
}
poly_user_home_get() {
dsclattr "/Users/$1" "NFSHomeDirectory"
}
poly_user_home_set() {
_sudo "in order to give $1 a safe home directory" \
/usr/bin/dscl . -create "/Users/$1" "NFSHomeDirectory" "$2"
}
poly_user_note_get() {
dsclattr "/Users/$1" "RealName"
}
poly_user_note_set() {
_sudo "in order to give $username a useful note" \
/usr/bin/dscl . -create "/Users/$1" "RealName" "$2"
}
poly_user_shell_get() {
dsclattr "/Users/$1" "UserShell"
}
poly_user_shell_set() {
_sudo "in order to give $1 a safe home directory" \
/usr/bin/dscl . -create "/Users/$1" "UserShell" "$2"
}
poly_user_in_group_check() {
username=$1
group=$2
dseditgroup -o checkmember -m "$username" "$group" > /dev/null 2>&1
}
poly_user_in_group_set() {
username=$1
group=$2
_sudo "Add $username to the $group group"\
/usr/sbin/dseditgroup -o edit -t user \
-a "$username" "$group"
}
poly_user_primary_group_get() {
dsclattr "/Users/$1" "PrimaryGroupID"
}
poly_user_primary_group_set() {
_sudo "to let the nix daemon use this user for builds (this might seem redundant, but there are two concepts of group membership)" \
/usr/bin/dscl . -create "/Users/$1" "PrimaryGroupID" "$2"
}
poly_create_build_user() {
username=$1
uid=$2
builder_num=$3
_sudo "Creating the Nix build user (#$builder_num), $username" \
/usr/bin/dscl . create "/Users/$username" \
UniqueID "${uid}"
}

View File

@@ -0,0 +1,797 @@
#!/usr/bin/env bash
set -eu
set -o pipefail
# Sourced from:
# - https://github.com/LnL7/nix-darwin/blob/8c29d0985d74b4a990238497c47a2542a5616b3c/bootstrap.sh
# - https://gist.github.com/expipiplus1/e571ce88c608a1e83547c918591b149f/ac504c6c1b96e65505fbda437a28ce563408ecb0
# - https://github.com/NixOS/nixos-org-configurations/blob/a122f418797713d519aadf02e677fce0dc1cb446/delft/scripts/nix-mac-installer.sh
# - https://github.com/matthewbauer/macNixOS/blob/f6045394f9153edea417be90c216788e754feaba/install-macNixOS.sh
# - https://gist.github.com/LnL7/9717bd6cdcb30b086fd7f2093e5f8494/86b26f852ce563e973acd30f796a9a416248c34a
#
# however tracking which bits came from which would be impossible.
readonly ESC='\033[0m'
readonly BOLD='\033[38;1m'
readonly BLUE='\033[38;34m'
readonly BLUE_UL='\033[38;4;34m'
readonly GREEN='\033[38;32m'
readonly GREEN_UL='\033[38;4;32m'
readonly RED='\033[38;31m'
readonly RED_UL='\033[38;4;31m'
readonly YELLOW='\033[38;33m'
readonly YELLOW_UL='\033[38;4;33m'
readonly NIX_USER_COUNT="32"
readonly NIX_BUILD_GROUP_ID="30000"
readonly NIX_BUILD_GROUP_NAME="nixbld"
readonly NIX_FIRST_BUILD_UID="30001"
# Please don't change this. We don't support it, because the
# default shell profile that comes with Nix doesn't support it.
readonly NIX_ROOT="/nix"
readonly PROFILE_TARGETS=("/etc/bashrc" "/etc/profile.d/nix.sh" "/etc/zshrc")
readonly PROFILE_BACKUP_SUFFIX=".backup-before-nix"
readonly PROFILE_NIX_FILE="$NIX_ROOT/var/nix/profiles/default/etc/profile.d/nix-daemon.sh"
readonly NIX_INSTALLED_NIX="@nix@"
readonly NIX_INSTALLED_CACERT="@cacert@"
readonly EXTRACTED_NIX_PATH="$(dirname "$0")"
readonly ROOT_HOME=$(echo ~root)
if [ -t 0 ]; then
readonly IS_HEADLESS='no'
else
readonly IS_HEADLESS='yes'
fi
headless() {
if [ "$IS_HEADLESS" = "yes" ]; then
return 0
else
return 1
fi
}
contactme() {
echo "We'd love to help if you need it."
echo ""
echo "If you can, open an issue at https://github.com/nixos/nix/issues"
echo ""
echo "Or feel free to contact the team,"
echo " - on IRC #nixos on irc.freenode.net"
echo " - on twitter @nixos_org"
}
uninstall_directions() {
subheader "Uninstalling nix:"
local step=0
if poly_service_installed_check; then
step=$((step + 1))
poly_service_uninstall_directions "$step"
fi
for profile_target in "${PROFILE_TARGETS[@]}"; do
if [ -e "$profile_target" ] && [ -e "$profile_target$PROFILE_BACKUP_SUFFIX" ]; then
step=$((step + 1))
cat <<EOF
$step. Restore $profile_target$PROFILE_BACKUP_SUFFIX back to $profile_target
sudo mv $profile_target$PROFILE_BACKUP_SUFFIX $profile_target
(after this one, you may need to re-open any terminals that were
opened while it existed.)
EOF
fi
done
step=$((step + 1))
cat <<EOF
$step. Delete the files Nix added to your system:
sudo rm -rf /etc/nix $NIX_ROOT $ROOT_HOME/.nix-profile $ROOT_HOME/.nix-defexpr $ROOT_HOME/.nix-channels $HOME/.nix-profile $HOME/.nix-defexpr $HOME/.nix-channels
and that is it.
EOF
}
nix_user_for_core() {
printf "nixbld%d" "$1"
}
nix_uid_for_core() {
echo $((NIX_FIRST_BUILD_UID + $1 - 1))
}
_textout() {
echo -en "$1"
shift
if [ "$*" = "" ]; then
cat
else
echo "$@"
fi
echo -en "$ESC"
}
header() {
follow="---------------------------------------------------------"
header=$(echo "---- $* $follow$follow$follow" | head -c 80)
echo ""
_textout "$BLUE" "$header"
}
warningheader() {
follow="---------------------------------------------------------"
header=$(echo "---- $* $follow$follow$follow" | head -c 80)
echo ""
_textout "$RED" "$header"
}
subheader() {
echo ""
_textout "$BLUE_UL" "$*"
}
row() {
printf "$BOLD%s$ESC:\\t%s\\n" "$1" "$2"
}
task() {
echo ""
ok "~~> $1"
}
bold() {
echo "$BOLD$*$ESC"
}
ok() {
_textout "$GREEN" "$@"
}
warning() {
warningheader "warning!"
cat
echo ""
}
failure() {
header "oh no!"
_textout "$RED" "$@"
echo ""
_textout "$RED" "$(contactme)"
trap finish_cleanup EXIT
exit 1
}
ui_confirm() {
_textout "$GREEN$GREEN_UL" "$1"
if headless; then
echo "No TTY, assuming you would say yes :)"
return 0
fi
local prompt="[y/n] "
echo -n "$prompt"
while read -r y; do
if [ "$y" = "y" ]; then
echo ""
return 0
elif [ "$y" = "n" ]; then
echo ""
return 1
else
_textout "$RED" "Sorry, I didn't understand. I can only understand answers of y or n"
echo -n "$prompt"
fi
done
echo ""
return 1
}
__sudo() {
local expl="$1"
local cmd="$2"
shift
header "sudo execution"
echo "I am executing:"
echo ""
printf " $ sudo %s\\n" "$cmd"
echo ""
echo "$expl"
echo ""
return 0
}
_sudo() {
local expl="$1"
shift
if ! headless; then
__sudo "$expl" "$*"
fi
sudo "$@"
}
readonly SCRATCH=$(mktemp -d -t tmp.XXXXXXXXXX)
function finish_cleanup {
rm -rf "$SCRATCH"
}
function finish_fail {
finish_cleanup
failure <<EOF
Jeeze, something went wrong. If you can take all the output and open
an issue, we'd love to fix the problem so nobody else has this issue.
:(
EOF
}
trap finish_fail EXIT
function finish_success {
finish_cleanup
ok "Alright! We're done!"
cat <<EOF
Before Nix will work in your existing shells, you'll need to close
them and open them again. Other than that, you should be ready to go.
Try it! Open a new terminal, and type:
$ nix-shell -p nix-info --run "nix-info -m"
Thank you for using this installer. If you have any feedback, don't
hesitate:
$(contactme)
EOF
}
validate_starting_assumptions() {
poly_validate_assumptions
if [ $EUID -eq 0 ]; then
failure <<EOF
Please do not run this script with root privileges. We will call sudo
when we need to.
EOF
fi
if type nix-env 2> /dev/null >&2; then
failure <<EOF
Nix already appears to be installed, and this tool assumes it is
_not_ yet installed.
$(uninstall_directions)
EOF
fi
if [ "${NIX_REMOTE:-}" != "" ]; then
failure <<EOF
For some reason, \$NIX_REMOTE is set. It really should not be set
before this installer runs, and it hints that Nix is currently
installed. Please delete the old Nix installation and start again.
Note: You might need to close your shell window and open a new shell
to clear the variable.
EOF
fi
if echo "${SSL_CERT_FILE:-}" | grep -qE "(nix/var/nix|nix-profile)"; then
failure <<EOF
It looks like \$SSL_CERT_FILE is set to a path that used to be part of
the old Nix installation. Please unset that variable and try again:
$ unset SSL_CERT_FILE
EOF
fi
for file in ~/.bash_profile ~/.bash_login ~/.profile ~/.zshenv ~/.zprofile ~/.zshrc ~/.zlogin; do
if [ -f "$file" ]; then
if grep -l "^[^#].*.nix-profile" "$file"; then
failure <<EOF
I found a reference to a ".nix-profile" in $file.
This has a high chance of breaking a new nix installation. It was most
likely put there by a previous Nix installer.
Please remove this reference and try running this again. You should
also look for similar references in:
- ~/.bash_profile
- ~/.bash_login
- ~/.profile
or other shell init files that you may have.
$(uninstall_directions)
EOF
fi
fi
done
if [ -d /nix ]; then
failure <<EOF
There are some relics of a previous installation of Nix at /nix, and
this scripts assumes Nix is _not_ yet installed. Please delete the old
Nix installation and start again.
$(uninstall_directions)
EOF
fi
if [ -d /etc/nix ]; then
failure <<EOF
There are some relics of a previous installation of Nix at /etc/nix, and
this scripts assumes Nix is _not_ yet installed. Please delete the old
Nix installation and start again.
$(uninstall_directions)
EOF
fi
for profile_target in "${PROFILE_TARGETS[@]}"; do
if [ -e "$profile_target$PROFILE_BACKUP_SUFFIX" ]; then
failure <<EOF
When this script runs, it backs up the current $profile_target to
$profile_target$PROFILE_BACKUP_SUFFIX. This backup file already exists, though.
Please follow these instructions to clean up the old backup file:
1. Copy $profile_target and $profile_target$PROFILE_BACKUP_SUFFIX to another place, just
in case.
2. Take care to make sure that $profile_target$PROFILE_BACKUP_SUFFIX doesn't look like
it has anything nix-related in it. If it does, something is probably
quite wrong. Please open an issue or get in touch immediately.
3. Take care to make sure that $profile_target doesn't look like it has
anything nix-related in it. If it does, and $profile_target _did not_,
run:
$ /usr/bin/sudo /bin/mv $profile_target$PROFILE_BACKUP_SUFFIX $profile_target
and try again.
EOF
fi
if [ -e "$profile_target" ] && grep -qi "nix" "$profile_target"; then
failure <<EOF
It looks like $profile_target already has some Nix configuration in
there. There should be no reason to run this again. If you're having
trouble, please open an issue.
EOF
fi
done
danger_paths=("$ROOT_HOME/.nix-defexpr" "$ROOT_HOME/.nix-channels" "$ROOT_HOME/.nix-profile")
for danger_path in "${danger_paths[@]}"; do
if _sudo "making sure that $danger_path doesn't exist" \
test -e "$danger_path"; then
failure <<EOF
I found a file at $danger_path, which is a relic of a previous
installation. You must first delete this file before continuing.
$(uninstall_directions)
EOF
fi
done
}
setup_report() {
header "Nix config report"
row " Temp Dir" "$SCRATCH"
row " Nix Root" "$NIX_ROOT"
row " Build Users" "$NIX_USER_COUNT"
row " Build Group ID" "$NIX_BUILD_GROUP_ID"
row "Build Group Name" "$NIX_BUILD_GROUP_NAME"
if [ "${ALLOW_PREEXISTING_INSTALLATION:-}" != "" ]; then
row "Preexisting Install" "Allowed"
fi
subheader "build users:"
row " Username" "UID"
for i in $(seq 1 "$NIX_USER_COUNT"); do
row " $(nix_user_for_core "$i")" "$(nix_uid_for_core "$i")"
done
echo ""
}
create_build_group() {
local primary_group_id
task "Setting up the build group $NIX_BUILD_GROUP_NAME"
if ! poly_group_exists "$NIX_BUILD_GROUP_NAME"; then
poly_create_build_group
row " Created" "Yes"
else
primary_group_id=$(poly_group_id_get "$NIX_BUILD_GROUP_NAME")
if [ "$primary_group_id" -ne "$NIX_BUILD_GROUP_ID" ]; then
failure <<EOF
It seems the build group $NIX_BUILD_GROUP_NAME already exists, but
with the UID $primary_group_id. This script can't really handle
that right now, so I'm going to give up.
You can fix this by editing this script and changing the
NIX_BUILD_GROUP_ID variable near the top to from $NIX_BUILD_GROUP_ID
to $primary_group_id and re-run.
EOF
else
row " Exists" "Yes"
fi
fi
}
create_build_user_for_core() {
local coreid
local username
local uid
coreid="$1"
username=$(nix_user_for_core "$coreid")
uid=$(nix_uid_for_core "$coreid")
task "Setting up the build user $username"
if ! poly_user_exists "$username"; then
poly_create_build_user "$username" "$uid" "$coreid"
row " Created" "Yes"
else
actual_uid=$(poly_user_id_get "$username")
if [ "$actual_uid" != "$uid" ]; then
failure <<EOF
It seems the build user $username already exists, but with the UID
with the UID '$actual_uid'. This script can't really handle that right
now, so I'm going to give up.
If you already created the users and you know they start from
$actual_uid and go up from there, you can edit this script and change
NIX_FIRST_BUILD_UID near the top of the file to $actual_uid and try
again.
EOF
else
row " Exists" "Yes"
fi
fi
if [ "$(poly_user_hidden_get "$username")" = "1" ]; then
row " Hidden" "Yes"
else
poly_user_hidden_set "$username"
row " Hidden" "Yes"
fi
if [ "$(poly_user_home_get "$username")" = "/var/empty" ]; then
row " Home Directory" "/var/empty"
else
poly_user_home_set "$username" "/var/empty"
row " Home Directory" "/var/empty"
fi
# 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.
if ! poly_user_note_get "$username" | grep -q "Nix build user $coreid"; then
row " Note" "Nix build user $coreid"
else
poly_user_note_set "$username" "Nix build user $coreid"
row " Note" "Nix build user $coreid"
fi
if [ "$(poly_user_shell_get "$username")" = "/sbin/nologin" ]; then
row " Logins Disabled" "Yes"
else
poly_user_shell_set "$username" "/sbin/nologin"
row " Logins Disabled" "Yes"
fi
if poly_user_in_group_check "$username" "$NIX_BUILD_GROUP_NAME"; then
row " Member of $NIX_BUILD_GROUP_NAME" "Yes"
else
poly_user_in_group_set "$username" "$NIX_BUILD_GROUP_NAME"
row " Member of $NIX_BUILD_GROUP_NAME" "Yes"
fi
if [ "$(poly_user_primary_group_get "$username")" = "$NIX_BUILD_GROUP_ID" ]; then
row " PrimaryGroupID" "$NIX_BUILD_GROUP_ID"
else
poly_user_primary_group_set "$username" "$NIX_BUILD_GROUP_ID"
row " PrimaryGroupID" "$NIX_BUILD_GROUP_ID"
fi
}
create_build_users() {
for i in $(seq 1 "$NIX_USER_COUNT"); do
create_build_user_for_core "$i"
done
}
create_directories() {
_sudo "to make the basic directory structure of Nix (part 1)" \
mkdir -pv -m 0755 /nix /nix/var /nix/var/log /nix/var/log/nix /nix/var/log/nix/drvs /nix/var/nix{,/db,/gcroots,/profiles,/temproots,/userpool}
_sudo "to make the basic directory structure of Nix (part 2)" \
mkdir -pv -m 1777 /nix/var/nix/{gcroots,profiles}/per-user
_sudo "to make the basic directory structure of Nix (part 3)" \
mkdir -pv -m 1775 /nix/store
_sudo "to make the basic directory structure of Nix (part 4)" \
chgrp "$NIX_BUILD_GROUP_NAME" /nix/store
_sudo "to set up the root user's profile (part 1)" \
mkdir -pv -m 0755 /nix/var/nix/profiles/per-user/root
_sudo "to set up the root user's profile (part 2)" \
mkdir -pv -m 0700 "$ROOT_HOME/.nix-defexpr"
_sudo "to place the default nix daemon configuration (part 1)" \
mkdir -pv -m 0555 /etc/nix
}
place_channel_configuration() {
echo "https://nixos.org/channels/nixpkgs-unstable nixpkgs" > "$SCRATCH/.nix-channels"
_sudo "to set up the default system channel (part 1)" \
install -m 0664 "$SCRATCH/.nix-channels" "$ROOT_HOME/.nix-channels"
}
welcome_to_nix() {
ok "Welcome to the Multi-User Nix Installation"
cat <<EOF
This installation tool will set up your computer with the Nix package
manager. This will happen in a few stages:
1. Make sure your computer doesn't already have Nix. If it does, I
will show you instructions on how to clean up your old one.
2. Show you what we are going to install and where. Then we will ask
if you are ready to continue.
3. Create the system users and groups that the Nix daemon uses to run
builds.
4. Perform the basic installation of the Nix files daemon.
5. Configure your shell to import special Nix Profile files, so you
can use Nix.
6. Start the Nix daemon.
EOF
if ui_confirm "Would you like to see a more detailed list of what we will do?"; then
cat <<EOF
We will:
- make sure your computer doesn't already have Nix files
(if it does, I will tell you how to clean them up.)
- create local users (see the list above for the users we'll make)
- create a local group ($NIX_BUILD_GROUP_NAME)
- install Nix in to $NIX_ROOT
- create a configuration file in /etc/nix
- set up the "default profile" by creating some Nix-related files in
$ROOT_HOME
EOF
for profile_target in "${PROFILE_TARGETS[@]}"; do
if [ -e "$profile_target" ]; then
cat <<EOF
- back up $profile_target to $profile_target$PROFILE_BACKUP_SUFFIX
- update $profile_target to include some Nix configuration
EOF
fi
done
poly_service_setup_note
if ! ui_confirm "Ready to continue?"; then
failure <<EOF
Okay, maybe you would like to talk to the team.
EOF
fi
fi
}
chat_about_sudo() {
header "let's talk about sudo"
if headless; then
cat <<EOF
This script is going to call sudo a lot. Normally, it would show you
exactly what commands it is running and why. However, the script is
run in a headless fashion, like this:
$ curl https://nixos.org/nix/install | sh
or maybe in a CI pipeline. Because of that, we're going to skip the
verbose output in the interest of brevity.
If you would like to
see the output, try like this:
$ curl -o install-nix https://nixos.org/nix/install
$ sh ./install-nix
EOF
return 0
fi
cat <<EOF
This script is going to call sudo a lot. Every time we do, it'll
output exactly what it'll do, and why.
Just like this:
EOF
__sudo "to demonstrate how our sudo prompts look" \
echo "this is a sudo prompt"
cat <<EOF
This might look scary, but everything can be undone by running just a
few commands. We used to ask you to confirm each time sudo ran, but it
was too many times. Instead, I'll just ask you this one time:
EOF
if ui_confirm "Can we use sudo?"; then
ok "Yay! Thanks! Let's get going!"
else
failure <<EOF
That is okay, but we can't install.
EOF
fi
}
install_from_extracted_nix() {
(
cd "$EXTRACTED_NIX_PATH"
_sudo "to copy the basic Nix files to the new store at $NIX_ROOT/store" \
rsync -rlpt ./store/* "$NIX_ROOT/store/"
if [ -d "$NIX_INSTALLED_NIX" ]; then
echo " Alright! We have our first nix at $NIX_INSTALLED_NIX"
else
failure <<EOF
Something went wrong, and I didn't find Nix installed at
$NIX_INSTALLED_NIX.
EOF
fi
_sudo "to initialize the Nix Database" \
$NIX_INSTALLED_NIX/bin/nix-store --init
cat ./.reginfo \
| _sudo "to load data for the first time in to the Nix Database" \
"$NIX_INSTALLED_NIX/bin/nix-store" --load-db
echo " Just finished getting the nix database ready."
)
}
shell_source_lines() {
cat <<EOF
# Nix
if [ -e '$PROFILE_NIX_FILE' ]; then
. '$PROFILE_NIX_FILE'
fi
# End Nix
EOF
}
configure_shell_profile() {
# If there is an /etc/profile.d directory, we want to ensure there
# is a nix.sh within it, so we can use the following loop to add
# the source lines to it. Note that I'm _not_ adding the source
# lines here, because we want to be using the regular machinery.
#
# If we go around that machinery, it becomes more complicated and
# adds complications to the uninstall instruction generator and
# old instruction sniffer as well.
if [ -d /etc/profile.d ]; then
_sudo "create a stub /etc/profile.d/nix.sh which will be updated" \
touch /etc/profile.d/nix.sh
fi
for profile_target in "${PROFILE_TARGETS[@]}"; do
if [ -e "$profile_target" ]; then
_sudo "to back up your current $profile_target to $profile_target$PROFILE_BACKUP_SUFFIX" \
cp "$profile_target" "$profile_target$PROFILE_BACKUP_SUFFIX"
shell_source_lines \
| _sudo "extend your $profile_target with nix-daemon settings" \
tee -a "$profile_target"
fi
done
}
setup_default_profile() {
_sudo "to installing a bootstrapping Nix in to the default Profile" \
HOME="$ROOT_HOME" "$NIX_INSTALLED_NIX/bin/nix-env" -i "$NIX_INSTALLED_NIX"
_sudo "to installing a bootstrapping SSL certificate just for Nix in to the default Profile" \
HOME="$ROOT_HOME" "$NIX_INSTALLED_NIX/bin/nix-env" -i "$NIX_INSTALLED_CACERT"
_sudo "to update the default channel in the default profile" \
HOME="$ROOT_HOME" NIX_SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt "$NIX_INSTALLED_NIX/bin/nix-channel" --update nixpkgs
}
place_nix_configuration() {
cat <<EOF > "$SCRATCH/nix.conf"
build-users-group = $NIX_BUILD_GROUP_NAME
max-jobs = $NIX_USER_COUNT
cores = 1
sandbox = false
EOF
_sudo "to place the default nix daemon configuration (part 2)" \
install -m 0664 "$SCRATCH/nix.conf" /etc/nix/nix.conf
}
main() {
if [ "$(uname -s)" = "Darwin" ]; then
# shellcheck source=./install-darwin-multi-user.sh
. "$EXTRACTED_NIX_PATH/install-darwin-multi-user.sh"
elif [ "$(uname -s)" = "Linux" ] && [ -e /run/systemd/system ]; then
# shellcheck source=./install-systemd-multi-user.sh
. "$EXTRACTED_NIX_PATH/install-systemd-multi-user.sh"
else
failure "Sorry, I don't know what to do on $(uname)"
fi
welcome_to_nix
chat_about_sudo
if [ "${ALLOW_PREEXISTING_INSTALLATION:-}" = "" ]; then
validate_starting_assumptions
fi
setup_report
if ! ui_confirm "Ready to continue?"; then
ok "Alright, no changes have been made :)"
contactme
trap finish_cleanup EXIT
exit 1
fi
create_build_group
create_build_users
create_directories
place_channel_configuration
install_from_extracted_nix
configure_shell_profile
set +eu
. /etc/profile
set -eu
setup_default_profile
place_nix_configuration
poly_configure_nix_daemon_service
trap finish_success EXIT
}
main

View File

@@ -28,9 +28,41 @@ if [ "$(uname -s)" = "Darwin" ]; then
echo "$0: macOS $(sw_vers -productVersion) is not supported, upgrade to 10.10 or higher"
exit 1
fi
fi
printf '\e[1;31mSwitching to the Multi-User Darwin Installer\e[0m\n'
exec "$self/install-darwin-multi-user"
# Determine if we should punt to the single-user installer or not
if [ "$(uname -s)" = "Darwin" ]; then
INSTALL_MODE=daemon
elif [ "$(uname -s)" = "Linux" ] && [ -e /run/systemd/system ]; then
INSTALL_MODE=no-daemon
else
INSTALL_MODE=no-daemon
fi
# Trivially handle the --daemon / --no-daemon options
if [ "x${1:-}" = "x--no-daemon" ]; then
INSTALL_MODE=no-daemon
elif [ "x${1:-}" = "x--daemon" ]; then
INSTALL_MODE=daemon
elif [ "x${1:-}" != "x" ]; then
(
echo "Nix Installer [--daemon|--no-daemon]"
echo ""
echo " --daemon: Force the installer to use the Daemon"
echo " based installer, even though it may not"
echo " work."
echo ""
echo " --no-daemon: Force a no-daemon, single-user"
echo " installation even when the preferred"
echo " method is with the daemon."
echo ""
) >&2
exit
fi
if [ "$INSTALL_MODE" = "daemon" ]; then
printf '\e[1;31mSwitching to the Daemon-based Installer\e[0m\n'
exec "$self/install-multi-user"
exit 0
fi

View File

@@ -0,0 +1,154 @@
#!/usr/bin/env bash
set -eu
set -o pipefail
readonly SERVICE_SRC=/lib/systemd/system/nix-daemon.service
readonly SERVICE_DEST=/etc/systemd/system/nix-daemon.service
readonly SOCKET_SRC=/lib/systemd/system/nix-daemon.socket
readonly SOCKET_DEST=/etc/systemd/system/nix-daemon.socket
poly_validate_assumptions() {
if [ "$(uname -s)" != "Linux" ]; then
failure "This script is for use with Linux!"
fi
}
poly_service_installed_check() {
[ "$(systemctl is-enabled nix-daemon.service)" = "linked" ] \
|| [ "$(systemctl is-enabled nix-daemon.socket)" = "enabled" ]
}
poly_service_uninstall_directions() {
cat <<EOF
$1. Delete the systemd service and socket units
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
EOF
}
poly_service_setup_note() {
cat <<EOF
- load and start a service (at $SERVICE_DEST
and $SOCKET_DEST) for nix-daemon
EOF
}
poly_configure_nix_daemon_service() {
_sudo "to set up the nix-daemon service" \
systemctl link "/nix/var/nix/profiles/default$SERVICE_SRC"
_sudo "to set up the nix-daemon socket service" \
systemctl enable "/nix/var/nix/profiles/default$SOCKET_SRC"
_sudo "to load the systemd unit for nix-daemon" \
systemctl daemon-reload
_sudo "to start the nix-daemon.socket" \
systemctl start nix-daemon.socket
_sudo "to start the nix-daemon.service" \
systemctl start nix-daemon.service
}
poly_group_exists() {
getent group "$1" > /dev/null 2>&1
}
poly_group_id_get() {
getent group "$1" | cut -d: -f3
}
poly_create_build_group() {
_sudo "Create the Nix build group, $NIX_BUILD_GROUP_NAME" \
groupadd -g "$NIX_BUILD_GROUP_ID" --system \
"$NIX_BUILD_GROUP_NAME" >&2
}
poly_user_exists() {
getent passwd "$1" > /dev/null 2>&1
}
poly_user_id_get() {
getent passwd "$1" | cut -d: -f3
}
poly_user_hidden_get() {
echo "1"
}
poly_user_hidden_set() {
true
}
poly_user_home_get() {
getent passwd "$1" | cut -d: -f6
}
poly_user_home_set() {
_sudo "in order to give $1 a safe home directory" \
usermod --home "$2" "$1"
}
poly_user_note_get() {
getent passwd "$1" | cut -d: -f5
}
poly_user_note_set() {
_sudo "in order to give $1 a useful comment" \
usermod --comment "$2" "$1"
}
poly_user_shell_get() {
getent passwd "$1" | cut -d: -f7
}
poly_user_shell_set() {
_sudo "in order to prevent $1 from logging in" \
usermod --shell "$2" "$1"
}
poly_user_in_group_check() {
groups "$1" | grep -q "$2" > /dev/null 2>&1
}
poly_user_in_group_set() {
_sudo "Add $1 to the $2 group"\
usermod --append --groups "$2" "$1"
}
poly_user_primary_group_get() {
getent passwd "$1" | cut -d: -f4
}
poly_user_primary_group_set() {
_sudo "to let the nix daemon use this user for builds (this might seem redundant, but there are two concepts of group membership)" \
usermod --gid "$2" "$1"
}
poly_create_build_user() {
username=$1
uid=$2
builder_num=$3
_sudo "Creating the Nix build user, $username" \
useradd \
--home-dir /var/empty \
--comment "Nix build user $builder_num" \
--gid "$NIX_BUILD_GROUP_ID" \
--groups "$NIX_BUILD_GROUP_NAME" \
--no-user-group \
--system \
--shell /sbin/nologin \
--uid "$uid" \
--password "!" \
"$username"
}

View File

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

View File

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

View File

@@ -74,10 +74,10 @@ static void createLinks(const Path & srcDir, const Path & dstDir, int priority)
auto prevPriority = priorities[dstFile];
if (prevPriority == priority)
throw Error(format(
"Packages '%1%' and '%2%' have the same priority '%3%'"
"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)"
" (0 being the highest priority)"
) % srcFile % target % priority);
if (prevPriority < priority)
continue;

View File

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

View File

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

View File

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

View File

@@ -69,16 +69,17 @@ public:
const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName, sValue,
sSystem, sOverrides, sOutputs, sOutputName, sIgnoreNulls,
sFile, sLine, sColumn, sFunctor, sToString,
sRight, sWrong, sStructuredAttrs, sBuilder;
sRight, sWrong, sStructuredAttrs, sBuilder, sArgs,
sOutputHash, sOutputHashAlgo, sOutputHashMode;
Symbol sDerivationNix;
/* If set, force copying files to the Nix store even if they
already exist there. */
RepairFlag repair;
/* If set, don't allow access to files outside of the Nix search
path or to environment variables. */
bool restricted;
/* The allowed filesystem paths in restricted or pure evaluation
mode. */
std::experimental::optional<PathSet> allowedPaths;
Value vEmptySet;
@@ -112,6 +113,15 @@ public:
void checkURI(const std::string & uri);
/* When using a diverted store and 'path' is in the Nix store, map
'path' to the diverted location (e.g. /nix/store/foo is mapped
to /home/alice/my-nix/nix/store/foo). However, this is only
done if the context is not empty, since otherwise we're
probably trying to read from the actual /nix/store. This is
intended to distinguish between import-from-derivation and
sources stored in the actual /nix/store. */
Path toRealPath(const Path & path, const PathSet & context);
/* Parse a Nix expression from the specified file. */
Expr * parseExprFromFile(const Path & path);
Expr * parseExprFromFile(const Path & path, StaticEnv & staticEnv);
@@ -201,9 +211,9 @@ private:
void createBaseEnv();
void addConstant(const string & name, Value & v);
Value * addConstant(const string & name, Value & v);
void addPrimOp(const string & name,
Value * addPrimOp(const string & name,
unsigned int arity, PrimOpFun primOp);
public:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -9,7 +9,18 @@ struct RegisterPrimOp
{
typedef std::vector<std::tuple<std::string, size_t, PrimOpFun>> PrimOps;
static PrimOps * primOps;
/* You can register a constant by passing an arity of 0. fun
will get called during EvalState initialization, so there
may be primops not yet added and builtins is not yet sorted. */
RegisterPrimOp(std::string name, size_t arity, PrimOpFun fun);
};
/* These primops are disabled without enableNativeCode, but plugins
may wish to use them in limited contexts without globally enabling
them. */
/* Load a ValueInitializer from a DSO and return whatever it initializes */
void prim_importNative(EvalState & state, const Pos & pos, Value * * args, Value & v);
/* Execute a program and parse its output */
void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v);
}

View File

@@ -22,10 +22,15 @@ struct GitInfo
uint64_t revCount = 0;
};
std::regex revRegex("^[0-9a-fA-F]{40}$");
GitInfo exportGit(ref<Store> store, const std::string & uri,
std::experimental::optional<std::string> ref, std::string rev,
const std::string & name)
{
if (settings.pureEval && rev == "")
throw Error("in pure evaluation mode, 'fetchGit' requires a Git revision");
if (!ref && rev == "" && hasPrefix(uri, "/") && pathExists(uri + "/.git")) {
bool clean = true;
@@ -74,13 +79,10 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,
ref = "HEAD"s;
}
if (!ref) ref = "master"s;
if (!ref) ref = "HEAD"s;
if (rev != "") {
std::regex revRegex("^[0-9a-fA-F]{40}$");
if (!std::regex_match(rev, revRegex))
throw Error("invalid Git revision '%s'", rev);
}
if (rev != "" && !std::regex_match(rev, revRegex))
throw Error("invalid Git revision '%s'", rev);
Path cacheDir = getCacheDir() + "/nix/git";
@@ -136,7 +138,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,
gitInfo.rev = rev != "" ? rev : chomp(readFile(localRefFile));
gitInfo.shortRev = std::string(gitInfo.rev, 0, 7);
printTalkative("using revision %s of repo '%s'", uri, gitInfo.rev);
printTalkative("using revision %s of repo '%s'", gitInfo.rev, uri);
std::string storeLinkName = hashString(htSHA512, name + std::string("\0"s) + gitInfo.rev).to_string(Base32, false);
Path storeLink = cacheDir + "/" + storeLinkName + ".link";
@@ -231,6 +233,9 @@ static void prim_fetchGit(EvalState & state, const Pos & pos, Value * * args, Va
mkString(*state.allocAttr(v, state.symbols.create("shortRev")), gitInfo.shortRev);
mkInt(*state.allocAttr(v, state.symbols.create("revCount")), gitInfo.revCount);
v.attrs->sort();
if (state.allowedPaths)
state.allowedPaths->insert(gitInfo.storePath);
}
static RegisterPrimOp r("fetchGit", 1, prim_fetchGit);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -17,11 +17,13 @@
#include <curl/curl.h>
#include <queue>
#include <iostream>
#include <thread>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#include <queue>
#include <random>
#include <thread>
using namespace std::string_literals;
@@ -91,6 +93,8 @@ struct CurlDownloader : public Downloader
{
if (!request.expectedETag.empty())
requestHeaders = curl_slist_append(requestHeaders, ("If-None-Match: " + request.expectedETag).c_str());
if (!request.mimeType.empty())
requestHeaders = curl_slist_append(requestHeaders, ("Content-Type: " + request.mimeType).c_str());
}
~DownloadItem()
@@ -185,6 +189,22 @@ struct CurlDownloader : public Downloader
return 0;
}
size_t readOffset = 0;
int readCallback(char *buffer, size_t size, size_t nitems)
{
if (readOffset == request.data->length())
return 0;
auto count = std::min(size * nitems, request.data->length() - readOffset);
memcpy(buffer, request.data->data() + readOffset, count);
readOffset += count;
return count;
}
static int readCallbackWrapper(char *buffer, size_t size, size_t nitems, void * userp)
{
return ((DownloadItem *) userp)->readCallback(buffer, size, nitems);
}
long lowSpeedTimeout = 300;
void init()
@@ -225,6 +245,13 @@ struct CurlDownloader : public Downloader
if (request.head)
curl_easy_setopt(req, CURLOPT_NOBODY, 1);
if (request.data) {
curl_easy_setopt(req, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(req, CURLOPT_READFUNCTION, readCallbackWrapper);
curl_easy_setopt(req, CURLOPT_READDATA, this);
curl_easy_setopt(req, CURLOPT_INFILESIZE_LARGE, (curl_off_t) request.data->length());
}
if (request.verifyTLS) {
if (settings.caFile != "")
curl_easy_setopt(req, CURLOPT_CAINFO, settings.caFile.c_str());
@@ -265,7 +292,7 @@ struct CurlDownloader : public Downloader
}
if (code == CURLE_OK &&
(httpStatus == 200 || httpStatus == 304 || httpStatus == 226 /* FTP */ || httpStatus == 0 /* other protocol */))
(httpStatus == 200 || httpStatus == 201 || httpStatus == 204 || httpStatus == 304 || httpStatus == 226 /* FTP */ || httpStatus == 0 /* other protocol */))
{
result.cached = httpStatus == 304;
done = true;
@@ -303,6 +330,7 @@ struct CurlDownloader : public Downloader
// Don't bother retrying on certain cURL errors either
switch (code) {
case CURLE_FAILED_INIT:
case CURLE_URL_MALFORMAT:
case CURLE_NOT_BUILT_IN:
case CURLE_REMOTE_ACCESS_DENIED:
case CURLE_FILE_COULDNT_READ_FILE:
@@ -311,10 +339,11 @@ struct CurlDownloader : public Downloader
case CURLE_BAD_FUNCTION_ARGUMENT:
case CURLE_INTERFACE_FAILED:
case CURLE_UNKNOWN_OPTION:
err = Misc;
break;
case CURLE_SSL_CACERT_BADFILE:
err = Misc;
break;
default: // Shut up warnings
break;
break;
}
}
@@ -689,7 +718,7 @@ Path Downloader::downloadCached(ref<Store> store, const string & url_, bool unpa
Path tmpDir = createTempDir();
AutoDelete autoDelete(tmpDir, true);
// FIXME: this requires GNU tar for decompression.
runProgram("tar", true, {"xf", storePath, "-C", tmpDir, "--strip-components", "1"});
runProgram("tar", true, {"xf", store->toRealPath(storePath), "-C", tmpDir, "--strip-components", "1"});
unpackedStorePath = store->addToStore(name, tmpDir, true, htSHA256, defaultPathFilter, NoRepair);
}
replaceSymlink(unpackedStorePath, unpackedLink);
@@ -699,7 +728,7 @@ Path Downloader::downloadCached(ref<Store> store, const string & url_, bool unpa
if (expectedStorePath != "" && storePath != expectedStorePath)
throw nix::Error("store path mismatch in file downloaded from '%s'", url);
return storePath;
return store->toRealPath(storePath);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -53,7 +53,6 @@ LocalStore::LocalStore(const Params & params)
, trashDir(realStoreDir + "/trash")
, tempRootsDir(stateDir + "/temproots")
, fnTempRoots(fmt("%s/%d", tempRootsDir, getpid()))
, publicKeys(getDefaultPublicKeys())
{
auto state(_state.lock());
@@ -582,7 +581,8 @@ void LocalStore::checkDerivationOutputs(const Path & drvPath, const Derivation &
uint64_t LocalStore::addValidPath(State & state,
const ValidPathInfo & info, bool checkOutputs)
{
assert(info.ca == "" || info.isContentAddressed(*this));
if (info.ca != "" && !info.isContentAddressed(*this))
throw Error("cannot add path '%s' to the Nix store because it claims to be content-addressed but isn't", info.path);
state.stmtRegisterValidPath.use()
(info.path)
@@ -964,6 +964,15 @@ void LocalStore::invalidatePath(State & state, const Path & path)
}
const PublicKeys & LocalStore::getPublicKeys()
{
auto state(_state.lock());
if (!state->publicKeys)
state->publicKeys = std::make_unique<PublicKeys>(getDefaultPublicKeys());
return *state->publicKeys;
}
void LocalStore::addToStore(const ValidPathInfo & info, const ref<std::string> & nar,
RepairFlag repair, CheckSigsFlag checkSigs, std::shared_ptr<FSAccessor> accessor)
{
@@ -978,7 +987,7 @@ void LocalStore::addToStore(const ValidPathInfo & info, const ref<std::string> &
throw Error("size mismatch importing path '%s'; expected %s, got %s",
info.path, info.narSize, nar->size());
if (requireSigs && checkSigs && !info.checkSignatures(*this, publicKeys))
if (requireSigs && checkSigs && !info.checkSignatures(*this, getPublicKeys()))
throw Error("cannot add path '%s' because it lacks a valid signature", info.path);
addTempRoot(info.path);
@@ -992,8 +1001,7 @@ void LocalStore::addToStore(const ValidPathInfo & info, const ref<std::string> &
/* Lock the output path. But don't lock if we're being called
from a build hook (whose parent process already acquired a
lock on this path). */
Strings locksHeld = tokenizeString<Strings>(getEnv("NIX_HELD_LOCKS"));
if (find(locksHeld.begin(), locksHeld.end(), info.path) == locksHeld.end())
if (!locksHeld.count(info.path))
outputLock.lockPaths({realPath});
if (repair || !isValidPath(info.path)) {
@@ -1216,7 +1224,7 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
/* Check the content hash (optionally - slow). */
printMsg(lvlTalkative, format("checking contents of '%1%'") % i);
HashResult current = hashPath(info->narHash.type, i);
HashResult current = hashPath(info->narHash.type, toRealPath(i));
if (info->narHash != nullHash && info->narHash != current.first) {
printError(format("path '%1%' was modified! "

View File

@@ -19,7 +19,7 @@ namespace nix {
/* Nix store and database schema version. Version 1 (or 0) was Nix <=
0.7. Version 2 was Nix 0.8 and 0.9. Version 3 is Nix 0.10.
Version 4 is Nix 0.11. Version 5 is Nix 0.12-0.16. Version 6 is
Nix 1.0. Version 7 is Nix 1.3. Version 10 is 1.12. */
Nix 1.0. Version 7 is Nix 1.3. Version 10 is 2.0. */
const int nixSchemaVersion = 10;
@@ -77,6 +77,8 @@ private:
minFree but not much below availAfterGC, then there is no
point in starting a new GC. */
uint64_t availAfterGC = std::numeric_limits<uint64_t>::max();
std::unique_ptr<PublicKeys> publicKeys;
};
Sync<State, std::recursive_mutex> _state;
@@ -100,10 +102,13 @@ private:
settings.requireSigs,
"require-sigs", "whether store paths should have a trusted signature on import"};
PublicKeys publicKeys;
const PublicKeys & getPublicKeys();
public:
// Hack for build-remote.cc.
PathSet locksHeld = tokenizeString<PathSet>(getEnv("NIX_HELD_LOCKS"));
/* Initialise the local store, upgrading the schema if
necessary. */
LocalStore(const Params & params);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -122,11 +122,12 @@ protected:
ref<Pool<Connection>> connections;
virtual void setOptions(Connection & conn);
private:
std::atomic_bool failed{false};
void setOptions(Connection & conn);
};
class UDSRemoteStore : public LocalFSStore, public RemoteStore
@@ -134,6 +135,7 @@ class UDSRemoteStore : public LocalFSStore, public RemoteStore
public:
UDSRemoteStore(const Params & params);
UDSRemoteStore(std::string path, const Params & params);
std::string getUri() override;
@@ -145,6 +147,7 @@ private:
};
ref<RemoteStore::Connection> openConnection() override;
std::experimental::optional<std::string> path;
};

View File

@@ -51,6 +51,16 @@ private:
std::string host;
SSHMaster master;
void setOptions(RemoteStore::Connection & conn) override
{
/* TODO Add a way to explicitly ask for some options to be
forwarded. One option: A way to query the daemon for its
settings, and then a series of params to SSHStore like
forward-cores or forward-overridden-cores that only
override the requested settings.
*/
};
};

View File

@@ -222,11 +222,10 @@ Path Store::makeTextPath(const string & name, const Hash & hash,
}
std::pair<Path, Hash> Store::computeStorePathForPath(const Path & srcPath,
bool recursive, HashType hashAlgo, PathFilter & filter) const
std::pair<Path, Hash> Store::computeStorePathForPath(const string & name,
const Path & srcPath, bool recursive, HashType hashAlgo, PathFilter & filter) const
{
Hash h = recursive ? hashPath(hashAlgo, srcPath, filter).first : hashFile(hashAlgo, srcPath);
string name = baseNameOf(srcPath);
Path dstPath = makeFixedOutputPath(recursive, h, name);
return std::pair<Path, Hash>(dstPath, h);
}
@@ -766,7 +765,8 @@ bool ValidPathInfo::isContentAddressed(const Store & store) const
else if (hasPrefix(ca, "fixed:")) {
bool recursive = ca.compare(6, 2, "r:") == 0;
Hash hash(std::string(ca, recursive ? 8 : 6));
if (store.makeFixedOutputPath(recursive, hash, storePathToName(path)) == path)
if (references.empty() &&
store.makeFixedOutputPath(recursive, hash, storePathToName(path)) == path)
return true;
else
warn();
@@ -840,7 +840,7 @@ ref<Store> openStore(const std::string & uri_,
for (auto fun : *RegisterStoreImplementation::implementations) {
auto store = fun(uri, params);
if (store) {
store->warnUnknownSettings();
store->handleUnknownSettings();
return ref<Store>(store);
}
}
@@ -897,7 +897,11 @@ std::list<ref<Store>> getDefaultSubstituters()
auto addStore = [&](const std::string & uri) {
if (done.count(uri)) return;
done.insert(uri);
stores.push_back(openStore(uri));
try {
stores.push_back(openStore(uri));
} catch (Error & e) {
printError("warning: %s", e.what());
}
};
for (auto uri : settings.substituters.get())

View File

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

View File

@@ -1,6 +1,7 @@
#include "compression.hh"
#include "util.hh"
#include "finally.hh"
#include "logging.hh"
#include <lzma.h>
#include <bzlib.h>
@@ -151,10 +152,10 @@ static ref<std::string> decompressBrotli(const std::string & in)
#endif // HAVE_BROTLI
}
ref<std::string> compress(const std::string & method, const std::string & in)
ref<std::string> compress(const std::string & method, const std::string & in, const bool parallel)
{
StringSink ssink;
auto sink = makeCompressionSink(method, ssink);
auto sink = makeCompressionSink(method, ssink, parallel);
(*sink)(in);
sink->finish();
return ssink.s;
@@ -189,10 +190,9 @@ struct XzSink : CompressionSink
lzma_stream strm = LZMA_STREAM_INIT;
bool finished = false;
XzSink(Sink & nextSink) : nextSink(nextSink)
{
lzma_ret ret = lzma_easy_encoder(
&strm, 6, LZMA_CHECK_CRC64);
template <typename F>
XzSink(Sink & nextSink, F&& initEncoder) : nextSink(nextSink) {
lzma_ret ret = initEncoder();
if (ret != LZMA_OK)
throw CompressionError("unable to initialise lzma encoder");
// FIXME: apply the x86 BCJ filter?
@@ -200,6 +200,9 @@ struct XzSink : CompressionSink
strm.next_out = outbuf;
strm.avail_out = sizeof(outbuf);
}
XzSink(Sink & nextSink) : XzSink(nextSink, [this]() {
return lzma_easy_encoder(&strm, 6, LZMA_CHECK_CRC64);
}) {}
~XzSink()
{
@@ -253,6 +256,27 @@ struct XzSink : CompressionSink
}
};
#ifdef HAVE_LZMA_MT
struct ParallelXzSink : public XzSink
{
ParallelXzSink(Sink &nextSink) : XzSink(nextSink, [this]() {
lzma_mt mt_options = {};
mt_options.flags = 0;
mt_options.timeout = 300; // Using the same setting as the xz cmd line
mt_options.preset = LZMA_PRESET_DEFAULT;
mt_options.filters = NULL;
mt_options.check = LZMA_CHECK_CRC64;
mt_options.threads = lzma_cputhreads();
mt_options.block_size = 0;
if (mt_options.threads == 0)
mt_options.threads = 1;
// FIXME: maybe use lzma_stream_encoder_mt_memusage() to control the
// number of threads.
return lzma_stream_encoder_mt(&strm, &mt_options);
}) {}
};
#endif
struct BzipSink : CompressionSink
{
Sink & nextSink;
@@ -301,8 +325,21 @@ struct BzipSink : CompressionSink
}
void write(const unsigned char * data, size_t len) override
{
/* Bzip2's 'avail_in' parameter is an unsigned int, so we need
to split the input into chunks of at most 4 GiB. */
while (len) {
auto n = std::min((size_t) std::numeric_limits<decltype(strm.avail_in)>::max(), len);
writeInternal(data, n);
data += n;
len -= n;
}
}
void writeInternal(const unsigned char * data, size_t len)
{
assert(!finished);
assert(len <= std::numeric_limits<decltype(strm.avail_in)>::max());
strm.next_in = (char *) data;
strm.avail_in = len;
@@ -408,8 +445,6 @@ struct BrotliSink : CompressionSink
void write(const unsigned char * data, size_t len) override
{
assert(!finished);
// Don't feed brotli too much at once
const size_t CHUNK_SIZE = sizeof(outbuf) << 2;
while (len) {
@@ -419,7 +454,7 @@ struct BrotliSink : CompressionSink
len -= n;
}
}
private:
void writeInternal(const unsigned char * data, size_t len)
{
assert(!finished);
@@ -449,8 +484,16 @@ struct BrotliSink : CompressionSink
};
#endif // HAVE_BROTLI
ref<CompressionSink> makeCompressionSink(const std::string & method, Sink & nextSink)
ref<CompressionSink> makeCompressionSink(const std::string & method, Sink & nextSink, const bool parallel)
{
if (parallel) {
#ifdef HAVE_LZMA_MT
if (method == "xz")
return make_ref<ParallelXzSink>(nextSink);
#endif
printMsg(lvlError, format("Warning: parallel compression requested but not supported for method '%1%', falling back to single-threaded compression") % method);
}
if (method == "none")
return make_ref<NoneSink>(nextSink);
else if (method == "xz")

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,7 +6,16 @@
namespace nix {
thread_local ActivityId curActivity = 0;
static thread_local ActivityId curActivity = 0;
ActivityId getCurActivity()
{
return curActivity;
}
void setCurActivity(const ActivityId activityId)
{
curActivity = activityId;
}
Logger * logger = makeDefaultLogger();
@@ -44,7 +53,7 @@ public:
prefix = std::string("<") + c + ">";
}
writeToStderr(prefix + (tty ? fs.s : filterANSIEscapes(fs.s)) + "\n");
writeToStderr(prefix + filterANSIEscapes(fs.s, !tty) + "\n");
}
void startActivity(ActivityId act, Verbosity lvl, ActivityType type,

View File

@@ -77,7 +77,8 @@ public:
virtual void result(ActivityId act, ResultType type, const Fields & fields) { };
};
extern thread_local ActivityId curActivity;
ActivityId getCurActivity();
void setCurActivity(const ActivityId activityId);
struct Activity
{
@@ -86,10 +87,10 @@ struct Activity
const ActivityId id;
Activity(Logger & logger, Verbosity lvl, ActivityType type, const std::string & s = "",
const Logger::Fields & fields = {}, ActivityId parent = curActivity);
const Logger::Fields & fields = {}, ActivityId parent = getCurActivity());
Activity(Logger & logger, ActivityType type,
const Logger::Fields & fields = {}, ActivityId parent = curActivity)
const Logger::Fields & fields = {}, ActivityId parent = getCurActivity())
: Activity(logger, lvlError, type, "", fields, parent) { };
Activity(const Activity & act) = delete;
@@ -122,8 +123,8 @@ struct Activity
struct PushActivity
{
const ActivityId prevAct;
PushActivity(ActivityId act) : prevAct(curActivity) { curActivity = act; }
~PushActivity() { curActivity = prevAct; }
PushActivity(ActivityId act) : prevAct(getCurActivity()) { setCurActivity(act); }
~PushActivity() { setCurActivity(prevAct); }
};
extern Logger * logger;

View File

@@ -2,6 +2,7 @@
#include <map>
#include <list>
#include <experimental/optional>
namespace nix {
@@ -63,18 +64,17 @@ public:
/* Look up an item in the cache. If it exists, it becomes the most
recently used item. */
// FIXME: use boost::optional?
Value * get(const Key & key)
std::experimental::optional<Value> get(const Key & key)
{
auto i = data.find(key);
if (i == data.end()) return 0;
if (i == data.end()) return {};
/* Move this item to the back of the LRU list. */
lru.erase(i->second.first.it);
auto j = lru.insert(lru.end(), i);
i->second.first.it = j;
return &i->second.second;
return i->second.second;
}
size_t size()

View File

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

View File

@@ -67,7 +67,8 @@ void FdSink::write(const unsigned char * data, size_t len)
try {
writeFull(fd, data, len);
} catch (SysError & e) {
_good = true;
_good = false;
throw;
}
}

View File

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

View File

@@ -32,6 +32,9 @@ string getEnv(const string & key, const string & def = "");
/* Get the entire environment. */
std::map<std::string, std::string> getEnv();
/* Clear the environment. */
void clearEnv();
/* Return an absolutized path, resolving paths relative to the
specified directory, or the current directory otherwise. The path
is also canonicalised. */
@@ -53,10 +56,12 @@ Path dirOf(const Path & path);
following the final `/'. */
string baseNameOf(const Path & path);
/* Check whether a given path is a descendant of the given
directory. */
/* Check whether 'path' is a descendant of 'dir'. */
bool isInDir(const Path & path, const Path & dir);
/* Check whether 'path' is equal to 'dir' or a descendant of 'dir'. */
bool isDirOrInDir(const Path & path, const Path & dir);
/* Get status of `path'. */
struct stat lstat(const Path & path);
@@ -386,10 +391,14 @@ void ignoreException();
#define ANSI_BLUE "\e[34;1m"
/* Filter out ANSI escape codes from the given string. If nixOnly is
set, only filter escape codes generated by Nixpkgs' stdenv (used to
denote nesting etc.). */
string filterANSIEscapes(const string & s, bool nixOnly = false);
/* Truncate a string to 'width' printable characters. If 'filterAll'
is true, all ANSI escape sequences are filtered out. Otherwise,
some escape sequences (such as colour setting) are copied but not
included in the character count. Also, tabs are expanded to
spaces. */
std::string filterANSIEscapes(const std::string & s,
bool filterAll = false,
unsigned int width = std::numeric_limits<unsigned int>::max());
/* Base64 encoding/decoding. */

View File

@@ -141,7 +141,7 @@ void mainWrapped(int argc, char * * argv)
else if (*arg == "--version")
printVersion(myName);
else if (*arg == "--add-drv-link")
else if (*arg == "--add-drv-link" || *arg == "--indirect")
; // obsolete
else if (*arg == "--no-out-link" || *arg == "--no-link")
@@ -167,9 +167,6 @@ void mainWrapped(int argc, char * * argv)
buildMode = bmRepair;
}
else if (*arg == "--hash")
buildMode = bmHash;
else if (*arg == "--run-env") // obsolete
runEnv = true;
@@ -215,7 +212,7 @@ void mainWrapped(int argc, char * * argv)
// read the shebang to understand which packages to read from. Since
// this is handled via nix-shell -p, we wrap our ruby script execution
// in ruby -e 'load' which ignores the shebangs.
envCommand = (format("exec %1% %2% -e 'load(\"%3%\") -- %4%") % execArgs % interpreter % script % joined.str()).str();
envCommand = (format("exec %1% %2% -e 'load(\"%3%\")' -- %4%") % execArgs % interpreter % script % joined.str()).str();
} else {
envCommand = (format("exec %1% %2% %3% %4%") % execArgs % interpreter % script % joined.str()).str();
}
@@ -235,6 +232,8 @@ void mainWrapped(int argc, char * * argv)
myArgs.parseCmdline(args);
initPlugins();
if (packages && fromArgs)
throw UsageError("'-p' and '-E' are mutually exclusive");
@@ -279,8 +278,8 @@ void mainWrapped(int argc, char * * argv)
else
/* If we're in a #! script, interpret filenames
relative to the script. */
exprs.push_back(state.parseExprFromFile(resolveExprPath(lookupFileArg(state,
inShebang && !packages ? absPath(i, absPath(dirOf(script))) : i))));
exprs.push_back(state.parseExprFromFile(resolveExprPath(state.checkSourcePath(lookupFileArg(state,
inShebang && !packages ? absPath(i, absPath(dirOf(script))) : i)))));
}
/* Evaluate them into derivations. */

View File

@@ -162,11 +162,6 @@ int main(int argc, char ** argv)
return handleExceptions(argv[0], [&]() {
initNix();
// Turn on caching in nix-prefetch-url.
auto channelCache = settings.nixStateDir + "/channel-cache";
createDirs(channelCache);
setenv("NIX_DOWNLOAD_CACHE", channelCache.c_str(), 1);
// Figure out the name of the `.nix-channels' file to use
auto home = getHome();
channelsList = home + "/.nix-channels";
@@ -213,6 +208,9 @@ int main(int argc, char ** argv)
}
return true;
});
initPlugins();
switch (cmd) {
case cNone:
throw UsageError("no command specified");

View File

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

View File

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

View File

@@ -816,8 +816,11 @@ static void processConnection(bool trusted)
static void sigChldHandler(int sigNo)
{
// Ensure we don't modify errno of whatever we've interrupted
auto saved_errno = errno;
/* Reap all dead children. */
while (waitpid(-1, 0, WNOHANG) > 0) ;
errno = saved_errno;
}
@@ -994,7 +997,7 @@ static void daemonLoop(char * * argv)
if (matchUser(user, group, trustedUsers))
trusted = true;
if (!trusted && !matchUser(user, group, allowedUsers))
if ((!trusted && !matchUser(user, group, allowedUsers)) || group == settings.buildUsersGroup)
throw Error(format("user '%1%' is not allowed to connect to the Nix daemon") % user);
printInfo(format((string) "accepted connection from pid %1%, user %2%" + (trusted ? " (trusted)" : ""))
@@ -1032,7 +1035,7 @@ static void daemonLoop(char * * argv)
}, options);
} catch (Interrupted & e) {
throw;
return;
} catch (Error & e) {
printError(format("error processing connection: %1%") % e.msg());
}
@@ -1060,6 +1063,8 @@ int main(int argc, char * * argv)
return true;
});
initPlugins();
if (stdio) {
if (getStoreType() == tDaemon) {
/* Forward on this connection to the real daemon */

View File

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

View File

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

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