Compare commits

...
105 Commits
Author SHA1 Message Date
Eelco Dolstra fecad91b67 Update release notes 2013-09-10 11:21:30 +02:00
Eelco Dolstra 0220da3e10 Remove stray debug line 2013-09-06 17:20:19 +02:00
Eelco Dolstra 936f9d45ba Don't apply the CPU affinity hack to nix-shell (and other Perl programs)
As discovered by Todd Veldhuizen, the shell started by nix-shell has
its affinity set to a single CPU.  This is because nix-shell connects
to the Nix daemon, which causes the affinity hack to be applied.  So
we turn this off for Perl programs.
2013-09-06 16:36:56 +02:00
Domen KožarandEelco Dolstra 4b83830d0c typo 2013-09-06 15:18:07 +02:00
Eelco Dolstra 5904262640 nix-shell: Support a .drv as argument
Fixes #161.
2013-09-06 14:58:05 +02:00
Eelco Dolstra 2c1ecf8e81 nix-env -i: Add a flag ‘--remove-all’ / ‘-r’
This is equivalent to running ‘nix-env -e '*'’ first, except that it
happens in a single transaction.  Thus, ‘nix-env -i pkgs...’ replaces
the profile with the specified set of packages.

The main motivation is to support declarative package management
(similar to environment.systemPackages in NixOS).  That is, if you
have a specification ‘profile.nix’ like this:

  with import <nixpkgs> {};
  [ thunderbird
    geeqie
    ...
  ]

then after any change to ‘profile.nix’, you can run:

  $ nix-env -f profile.nix -ir

to update the profile to match the specification.  (Without the ‘-r’
flag, if you remove a package from ‘profile.nix’, it won't be removed
from the actual profile.)

Suggested by @zefhemel.
2013-09-03 21:21:14 +02:00
Eelco Dolstra 88c07341a6 nix-env: Use wildcard match by default
That is, you don't need to pass '*' anymore, so

  nix-env -qa

is equivalent to

  nix-env -qa '*'
2013-09-03 16:35:49 +02:00
Eelco Dolstra 07a08bddf0 nix-env: Load files in ~/.nix-defexpr on demand
So if you do "nix-env -qa -A nixos", then other channels won't be
parsed/evaluated at all.
2013-09-03 15:45:32 +02:00
Eelco Dolstra c57ed84e28 Check for name collisions in the input Nix expressions 2013-09-03 15:25:51 +02:00
Eelco Dolstra ef4f5ba85e Work on Values instead of Exprs
This prevents some duplicate evaluation in nix-env and
nix-instantiate.

Also, when traversing ~/.nix-defexpr, only read regular files with the
extension .nix.  Previously it was reading files like
.../channels/binary-caches/<name>.  The only reason this didn't cause
problems is pure luck (namely, <name> shadows an actual Nix
expression, the binary-caches files happen to be syntactically valid
Nix expressions, and we iterate over the directory contents in just
the right order).
2013-09-03 13:17:51 +00:00
Eelco Dolstra 06bb2d95b4 Reformat 2013-09-03 11:04:21 +00:00
Eelco Dolstra 6f809194d7 Get rid of the parse tree cache
Since we already cache files in normal form (fileEvalCache), caching
parse trees is redundant.

Note that getting rid of this cache doesn't actually save much memory
at the moment, because parse trees are currently not freed / GC'ed.
2013-09-03 13:01:42 +02:00
Eelco Dolstra 57d18df7d0 Add some support code for nix-repl 2013-09-02 18:34:04 +02:00
Eelco Dolstra 92077b4547 Get rid of a signedness warning 2013-09-02 16:39:17 +02:00
Eelco Dolstra 33972629d7 Fix whitespace 2013-09-02 16:29:15 +02:00
Eelco Dolstra ac1b754138 Lower xz compression level
Fixes #84.
2013-09-02 13:32:51 +02:00
Eelco Dolstra c28dfc0305 Manual: Make '' a bit clearer
Issue #162.
2013-09-02 13:24:29 +02:00
Eelco Dolstra e9b92169a5 Fix manual error
Reported by Matija Šuklje.

Fixes #163.
2013-09-02 13:19:34 +02:00
Eelco Dolstra ecd830b3b9 Update the release notes 2013-09-02 13:11:36 +02:00
Eelco Dolstra 6ec8dab06a Adda test for build-max-log-size 2013-09-02 12:44:30 +02:00
Eelco Dolstra b29d3f4aee Only show trace messages when tracing is enabled 2013-09-02 12:01:04 +02:00
Eelco Dolstra efe4289464 Add an option to limit the log output of builders
This is mostly useful for Hydra to deal with builders that get stuck
in an infinite loop writing data to stdout/stderr.
2013-09-02 11:58:18 +02:00
Shea LevyandEelco Dolstra afc6c1bad6 Simplify inherited attribute handling
This reduces the difference between inherited and non-inherited
attribute handling to the choice of which env to use (in recs and lets)
by setting the AttrDef::e to a new ExprVar in the parser rather than
carrying a separate AttrDef::v VarRef member.

As an added bonus, this allows inherited attributes that inherit from a
with to delay forcing evaluation of the with's attributes.

Signed-off-by: Shea Levy <shea@shealevy.com>
2013-08-26 11:31:56 +02:00
Ivan KozikandEelco Dolstra 6cd6ce5608 Fix nix-shell command 2013-08-26 11:15:22 +02:00
Ivan KozikandEelco Dolstra 34bb806f74 Fix typos, especially those that end up in the Nix manual 2013-08-26 11:15:22 +02:00
Gergely RiskoandEelco Dolstra c6c024ca6f Fix personality switching from x86_64 to i686
On Linux, Nix can build i686 packages even on x86_64 systems.  It's not
enough to recognize this situation by settings.thisSystem, we also have
to consult uname().  E.g. we can be running on a i686 Debian with an
amd64 kernel.  In that situation settings.thisSystem is i686-linux, but
we still need to change personality to i686 to make builds consistent.
2013-08-26 11:12:35 +02:00
Eelco Dolstra 03eaef3d7a Manual: Don't use actual hashes of Nix dependencies
These cause an unnecessary runtime dependency :-)
2013-08-23 10:12:20 +02:00
Eelco Dolstra b3110a15e9 Fix corrupt PNG
Libpng used to accept this, but no longer does.
2013-08-21 12:53:51 +02:00
Eelco Dolstra 25a108bb9c Hack to clean up tests/test-tmp 2013-08-21 12:53:46 +02:00
Eelco Dolstra d308aeaf53 Store Nix integers as longs
So on 64-bit systems, integers are now 64-bit.

Fixes #158.
2013-08-19 12:35:03 +02:00
Eelco Dolstra 297b762513 Turn on -Wall 2013-08-19 11:41:15 +02:00
Eelco Dolstra 46222bbc43 Typo 2013-08-14 22:32:49 +02:00
Shea LevyandEelco Dolstra 58204a3c39 corepkgs/nar.nix: Prefer local builds
nar.nix's builder depends on coreutils and nix itself being in $PATH.
Unfortunately, there's no good way to ensure that these packages exist
in the same place on the remote machine: The local machine may have nix
installed in /usr, and the remote machine in /usr/local, but the
generated nar.sh builder will refer to /usr and thus fail on the remote
machine. This ensures that nar.sh is run on the same machine that
instantiates it.

Signed-off-by: Shea Levy <shea@shealevy.com>
2013-08-14 22:32:41 +02:00
Eelco Dolstra 3fb7ae0586 Respect MINSIGSTKSZ when allocating an alternative stack
http://hydra.nixos.org/build/5663577
2013-08-07 15:44:19 +00:00
Eelco Dolstra 161a2ccf7a Fix build on non-Linux
http://hydra.nixos.org/build/5662914
2013-08-07 17:26:41 +02:00
Eelco Dolstra a583a2bc59 Run the daemon worker on the same CPU as the client
On a system with multiple CPUs, running Nix operations through the
daemon is significantly slower than "direct" mode:

$ NIX_REMOTE= nix-instantiate '<nixos>' -A system
real    0m0.974s
user    0m0.875s
sys     0m0.088s

$ NIX_REMOTE=daemon nix-instantiate '<nixos>' -A system
real    0m2.118s
user    0m1.463s
sys     0m0.218s

The main reason seems to be that the client and the worker get moved
to a different CPU after every call to the worker.  This patch adds a
hack to lock them to the same CPU.  With this, the overhead of going
through the daemon is very small:

$ NIX_REMOTE=daemon nix-instantiate '<nixos>' -A system
real    0m1.074s
user    0m0.809s
sys     0m0.098s
2013-08-07 14:02:04 +02:00
Eelco Dolstra 263d668222 Set the default GCC optimisation level to -O3 2013-08-06 14:21:46 +02:00
Eelco Dolstra fd7d979c79 Remove obsolete reference to ATerms 2013-08-06 14:15:11 +02:00
Eelco Dolstra 46ffcce0c3 In the profiler output, show function names (if available) 2013-08-02 18:29:23 +00:00
Eelco Dolstra 8e74c0bfd1 Let the ordering operators also work on strings
E.g. ‘"foo" < "bar"’ now works.
2013-08-02 18:53:02 +02:00
Eelco Dolstra 3d77b28eac Add comparison operators ‘<’, ‘<=’, ‘>’ and ‘>=’ 2013-08-02 18:39:40 +02:00
Eelco Dolstra 47701677e8 Add integer ‘-’, ‘*’ and ‘/’ operators 2013-08-02 16:03:02 +00:00
Eelco Dolstra 5d147e125c Add a unary integer negation operator
This allows saying "-1" instead of "builtins.sub 0 1".
2013-08-02 15:43:31 +00:00
Eelco Dolstra 159e621d1a Overload the ‘+’ operator to support integer addition 2013-08-02 15:21:17 +00:00
Eelco Dolstra 511455965e nix-shell: Don't disable Automake dependency tracking
Nixpkgs' stdenv disables dependency tracking by default.  That makes
sense for one-time builds, but in an interactive environment we expect
repeated "make" invocations to do the right thing.
2013-07-31 13:17:50 +02:00
Eelco Dolstra 7df4ef983e Test the delayed with a bit more 2013-07-31 13:12:35 +02:00
Eelco Dolstra 0a470fc345 Make Env smaller
Commit 20866a7031 added a ‘withAttrs’
field to Env, which is annoying because it makes every Env structure
bigger and we allocate millions of them.  E.g. NixOS evaluation took
18 MiB more.  So this commit squeezes ‘withAttrs’ into values[0].
Probably should use a union...
2013-07-31 12:44:21 +02:00
Eelco Dolstra 8ae6d55db1 Don't use NULL 2013-07-31 12:11:14 +02:00
Shea LevyandEelco Dolstra e068f49f7d Avoid thunks when a fromWith var can be looked up without evaluation
Signed-off-by: Shea Levy <shea@shealevy.com>
2013-07-31 11:48:39 +02:00
Shea LevyandEelco Dolstra 20866a7031 Delay evaulation of with attrs until a variable lookup needs them
Evaluation of attribute sets is strict in the attribute names, which
means immediate evaluation of `with` attribute sets rules out some
potentially interesting use cases (e.g. where the attribute names of one
set depend in some way on another but we want to bring those names into
scope for some values in the second set).

The major example of this is overridable self-referential package sets
(e.g. all-packages.nix). With immediate `with` evaluation, the only
options for such sets are to either make them non-recursive and
explicitly use the name of the overridden set in non-overridden one
every time you want to reference another package, or make the set
recursive and use the `__overrides` hack. As shown in the test case that
comes with this commit, though, delayed `with` evaluation allows a nicer
third alternative.

Signed-off-by: Shea Levy <shea@shealevy.com>
2013-07-31 11:48:39 +02:00
Eelco Dolstra 70e68e0ec6 Detect stack overflows
Previously, if the Nix evaluator gets a stack overflow due to a deep
or infinite recursion in the Nix expression, the user gets an
unhelpful message ("Segmentation fault") that doesn't indicate that
the problem is in the user's code rather than Nix itself.  Now it
prints:

  error: stack overflow (possible infinite recursion)

This only works on x86_64-linux and i686-linux.

Fixes #35.
2013-07-30 23:37:10 +02:00
Shea LevyandEelco Dolstra e87d1a63bd killUser: Don't let the child kill itself on Apple
The kill(2) in Apple's libc follows POSIX semantics, which means that
kill(-1, SIGKILL) will kill the calling process too. Since nix has no
way to distinguish between the process successfully killing everything
and the process being killed by a rogue builder in that case, it can't
safely conclude that killUser was successful.

Luckily, the actual kill syscall takes a parameter that determines
whether POSIX semantics are followed, so we can call that syscall
directly and avoid the issue on Apple.

Signed-off-by: Shea Levy <shea@shealevy.com>
2013-07-30 21:25:16 +02:00
Florian FriesdorfandEelco Dolstra 7cf539c728 buildenv: remove special treatment of python files
buildPythonPackage does not leave easy_install.pth and site.py
anymore. A python package that leaves these files is broken. An
exception to this is setuptoolsSite which packages setuptools'
site.py. To include it into a buildenv, this patch is even needed, not
just cosmetic.
2013-07-23 20:13:43 +02:00
Eelco Dolstra 7b09e9f2c4 Add hacking notes plus a script for running nix-shell 2013-07-19 16:51:31 +02:00
Eelco Dolstra 15e5ac8039 nix-shell: Set $IN_NIX_SHELL
This allows scripts to distinguish between a real build and a Nix
shell.
2013-07-19 14:32:05 +02:00
Eelco Dolstra 48858ad5ca nix-shell: Set some environment variables also set by build.cc
Setting $NIX_STORE causes the purity checks in gcc/ld-wrapper to kick
in, so that's why we unset $NIX_ENFORCE_PURITY.
2013-07-19 14:06:58 +02:00
Eelco Dolstra 2bc5de8635 Rename ‘nix-build --run-env’ to ‘nix-shell’ 2013-07-19 12:02:44 +02:00
Eelco Dolstra dc5f2e7da6 nix-build --run-env: Add a ‘--pure’ flag
This causes the environment to be (almost) cleared, thus giving a
shell that more closely resembled the actual Nix derivation.
2013-07-19 11:23:32 +02:00
Eelco Dolstra a4921b8ceb Revert "build-remote.pl: Enforce timeouts locally"
This reverts commit 69b8f9980f.

The timeout should be enforced remotely.  Otherwise, if the garbage
collector is running either locally or remotely, if will block the
build or closure copying for some time.  If the garbage collector
takes too long, the build may time out, which is not what we want.
Also, on heavily loaded systems, copying large paths to and from the
remote machine can take a long time, also potentially resulting in a
timeout.
2013-07-18 12:52:29 +02:00
Shea LevyandEelco Dolstra 16591eb3cc Allow bind-mounting regular files into the chroot
mount(2) with MS_BIND allows mounting a regular file on top of a regular
file, so there's no reason to only bind directories. This allows finer
control over just which files are and aren't included in the chroot
without having to build symlink trees or the like.

Signed-off-by: Shea Levy <shea@shealevy.com>
2013-07-15 16:01:33 +02:00
Eelco Dolstra c3f5413e80 Fix syntax error in unpack-channel 2013-07-12 14:06:05 +02:00
Eelco Dolstra aeb810b01e Garbage collector: Don't follow symlinks arbitrarily
Only indirect roots (symlinks to symlinks to the Nix store) are now
supported.
2013-07-12 14:03:36 +02:00
Gergely RiskoandEelco Dolstra 25a00cae5b Add gzip support for channel unpacking 2013-07-12 11:29:37 +02:00
Domen KožarandEelco Dolstra 620d57f036 doc: typo 2013-07-12 11:27:43 +02:00
Eelco Dolstra 6fcc290619 build-remote.pl: Move "building ..." message to a better place 2013-07-11 17:16:45 +02:00
Eelco Dolstra ed09d0c0a4 nix-build --run-env: Always use Bash
Fixes #113.
Fixes #131.
2013-07-11 14:40:29 +02:00
Eelco Dolstra 656390062a nix-build --run-env: Source $stdenv/setup in the interactive shell
This ensures that not just environment variables are set, but also
shell functions such as unpackPhase, configurePhase and so on.
2013-07-11 14:32:22 +02:00
Ludovic CourtèsandEelco Dolstra 212e96f39c Leave `HAVE_HUP_NOTIFICATION' undefined on GNU/Hurd. 2013-07-07 13:21:06 +02:00
Eelco Dolstra b584a42e3d Manual: auto-optimise-store is disabled by default 2013-07-03 18:35:59 +02:00
Eelco Dolstra 5116214343 Add support for uncompressed NARs in binary caches
Issue NixOS/hydra#102.
2013-07-01 21:03:14 +02:00
Eelco Dolstra 7986711632 copy-from-other-stores.pl: Respect $NIX_BIN_DIR 2013-07-01 13:30:28 +02:00
Eelco Dolstra 1917d750a0 copy-from-other-stores.pl: Report downloaded size as 0 2013-07-01 13:29:59 +02:00
Eelco Dolstra 7ccd946407 Don't set $preferLocalBuild and $requiredSystemFeatures in builders
With C++ std::map, doing a comparison like ‘map["foo"] == ...’ has the
side-effect of adding a mapping from "foo" to the empty string if
"foo" doesn't exist in the map.  So we ended up setting some
environment variables by accident.
2013-06-20 18:07:27 +00:00
Eelco Dolstra 5558652709 Don't substitute derivations that have preferLocalBuild set
In particular this means that "trivial" derivations such as writeText
are not substituted, reducing the number of GET requests to the binary
cache by about 200 on a typical NixOS configuration.
2013-06-20 19:26:31 +02:00
Eelco Dolstra 1906cce6fc Increase SQLite's auto-checkpoint interval
Common operations like instantiating a NixOS system config no longer
fitted in 8192 pages, leading to more fsyncs.  So increase this limit.
2013-06-20 14:01:33 +00:00
Eelco Dolstra 9b11165aec Disable the copy-from-other-stores substituter
This substituter basically cannot work reliably since we switched to
SQLite, since SQLite databases may need write access to open them even
just for reading (and in WAL mode they always do).
2013-06-20 12:01:33 +02:00
Eelco Dolstra 22144afa8d Don't keep "disabled" substituters running
For instance, it's pointless to keep copy-from-other-stores running if
there are no other stores, or download-using-manifests if there are no
manifests.  This also speeds things up because we don't send queries
to those substituters.
2013-06-20 11:55:15 +02:00
Eelco Dolstra 2b29e4b852 Bump version 2013-06-17 15:39:45 +02:00
Eelco Dolstra 6016bcd30e Update release notes for Nix 1.5.3 2013-06-17 11:47:38 +02:00
Eelco Dolstra 1b6ee8f4c7 Allow hard links between the outputs of a derivation 2013-06-13 17:29:56 +02:00
Eelco Dolstra cd49ee0897 Fix a security bug in hash rewriting
Before calling dumpPath(), we have to make sure the files are owned by
the build user.  Otherwise, the build could contain a hard link to
(say) /etc/shadow, which would then be read by the daemon and
rewritten as a world-readable file.

This only affects systems that don't have hard link restrictions
enabled.
2013-06-13 17:12:24 +02:00
Eelco Dolstra 1e2c7c04b1 Fix assertion failure in canonicalisePathMetaData() after hash rewriting
The assertion in canonicalisePathMetaData() failed because the
ownership of the path already changed due to the hash rewriting.  The
solution is not to check the ownership of rewritten paths.

Issue #122.
2013-06-13 17:12:06 +02:00
Eelco Dolstra 6cc2a8f8ed computeFSClosure: Only process the missing/corrupt paths
Issue #122.
2013-06-13 16:43:20 +02:00
Eelco Dolstra bfee9a2581 Typo 2013-06-13 14:51:11 +02:00
Eelco Dolstra f9ff67e948 In repair mode, update the hash of rebuilt paths
Otherwise subsequent invocations of "--repair" will keep rebuilding
the path.  This only happens if the path content differs between
builds (e.g. due to timestamps).
2013-06-13 14:46:07 +02:00
Eelco Dolstra 6b05f688ee nix-daemon: Trust options like binary-caches when the client is root
Fixes #127.
2013-06-12 12:10:26 +02:00
Eelco Dolstra 5c06e5297d download-from-binary-cache.pl: Respect $NIX_CONNECT_TIMEOUT 2013-06-07 16:25:12 +02:00
Eelco Dolstra 24a356bf71 Replace $NIX_DEBUG_SUBST with an option ‘debug-subst’
Thus passing ‘--option debug-subst 1’ allows daemon users to turn on
debug info and see what the substituter is doing.
2013-06-07 15:36:36 +02:00
Eelco Dolstra 24e063efdc download-from-binary-cache.pl: Show if we're waiting for a URL
Previously, if a binary cache is hanging/unreachable/slow,
download-from-binary-cache.pl would also hang without any indication
to the user.  Now, if fetching a URL takes more than 5 seconds, it
will print a message to that effect.
2013-06-07 15:33:44 +02:00
Eelco Dolstra ca70fba0bf Remove obsolete EOF checks 2013-06-07 15:10:23 +02:00
Eelco Dolstra 5959c591a0 Process stderr from substituters while doing have/info queries 2013-06-07 15:02:14 +02:00
Eelco Dolstra c5f9d0d080 Buffer reads from the substituter
This greatly reduces the number of system calls.
2013-06-07 14:00:23 +02:00
Eelco Dolstra 75e12b8e66 download-from-binary-cache.pl: Fix race condition
Fixes the error "DBD::SQLite::db do failed: column url is not unique".
2013-06-05 16:25:07 +02:00
Eelco Dolstra f0576d6775 Update the default binary cache URL to cache.nixos.org 2013-06-05 13:36:43 +02:00
Eelco Dolstra ff08306746 download-from-binary-cache.pl: Treat a 403 error as a 404
Amazon S3 returns HTTP status code 403 if a file doesn't exist and the
user has no permission to list the contents of the bucket.  So treat
it as 404 (meaning it's cached in the NARExistence table).
2013-06-04 15:20:37 +02:00
Eelco Dolstra bc2e43f3c8 build-remote.pl: Remove meaningless signing when importing the output paths
The "$UID != 0" makes no sense: if the local side has write access to
the Nix store (which is always the case) then it doesn't matter if
we're root - we can import unsigned paths either way.
2013-05-29 18:18:59 +02:00
Eelco Dolstra 039d5a023f .bashrc -> .profile 2013-05-29 12:36:56 +02:00
Eelco Dolstra b09b87321c nix-store --export: Export paths in topologically sorted order
Fixes #118.
2013-05-23 14:55:36 -04:00
Eelco Dolstra 107505e13a build-remote.pl: Copy all outputs in one operation 2013-05-23 14:39:58 -04:00
Eelco Dolstra 72d8209548 build-remote.pl: Indicate if remote machine is refusing builds
Fixes #120.
2013-05-23 14:04:46 -04:00
Eelco Dolstra 18a48d80a0 Show function names in error messages
Functions in Nix are anonymous, but if they're assigned to a
variable/attribute, we can use the variable/attribute name in error
messages, e.g.

while evaluating `concatMapStrings' at `/nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs/pkgs/lib/strings.nix:18:25':
...
2013-05-16 19:08:02 +02:00
Eelco Dolstra 1b3a03f161 Show which function argument was unexpected
Fixes #116.
2013-05-16 17:56:14 +02:00
Eelco Dolstra 229567293c Shut up a compiler warning 2013-05-16 17:48:19 +02:00
Eelco Dolstra a4cb62ac25 download-from-binary-cache.pl: Get rid of an uninitialized value warning
Reported by Pablo Costa.
2013-05-15 15:47:05 +02:00
Eelco Dolstra 31a551a60f Bump version 2013-05-13 23:50:31 +02:00
89 changed files with 1719 additions and 710 deletions
-2
View File
@@ -27,11 +27,9 @@ init-state:
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/profiles
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/gcroots
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/temproots
ln -sfn $(localstatedir)/nix/profiles $(DESTDIR)$(localstatedir)/nix/gcroots/profiles
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/userpool
-$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(storedir)
$(INSTALL) $(INIT_FLAGS) $(GROUP_WRITABLE) -d $(DESTDIR)$(localstatedir)/nix/manifests
ln -sfn $(localstatedir)/nix/manifests $(DESTDIR)$(localstatedir)/nix/gcroots/manifests
else
+7 -1
View File
@@ -68,6 +68,8 @@ if test "$sys_name" = sunos; then
fi
CFLAGS=${CFLAGS:--g -O3 -Wall}
CXXFLAGS=${CXXFLAGS:--g -O3 -Wall}
AC_PROG_CC
AC_PROG_CXX
@@ -125,6 +127,10 @@ AC_CHECK_HEADERS([sys/mount.h], [], [],
AC_CHECK_FUNCS([lutimes])
# Check for sched_setaffinity.
AC_CHECK_FUNCS([sched_setaffinity])
# Check whether the store optimiser can optimise symlinks.
AC_MSG_CHECKING([whether it is possible to create a link to a symlink])
ln -s bla tmp_link
@@ -183,10 +189,10 @@ NEED_PROG(perl, perl)
NEED_PROG(sed, sed)
NEED_PROG(tar, tar)
NEED_PROG(bzip2, bzip2)
NEED_PROG(gzip, gzip)
NEED_PROG(xz, xz)
AC_PATH_PROG(dot, dot)
AC_PATH_PROG(dblatex, dblatex)
AC_PATH_PROG(gzip, gzip)
AC_PATH_PROG(pv, pv, pv)
+2 -5
View File
@@ -36,9 +36,6 @@ sub createLinks {
if ($srcFile =~ /\/propagated-build-inputs$/ ||
$srcFile =~ /\/nix-support$/ ||
$srcFile =~ /\/perllocal.pod$/ ||
$srcFile =~ /\/easy-install.pth$/ ||
$srcFile =~ /\/site.py$/ ||
$srcFile =~ /\/site.pyc$/ ||
$srcFile =~ /\/info\/dir$/ ||
$srcFile =~ /\/log$/)
{
@@ -56,7 +53,7 @@ sub createLinks {
elsif (-l _) {
my $target = readlink $dstFile or die;
if (!-d $target) {
die "collission between directory `$srcFile' and non-directory `$target'";
die "collision between directory `$srcFile' and non-directory `$target'";
}
unlink $dstFile or die "error unlinking `$dstFile': $!";
mkdir $dstFile, 0755 ||
@@ -78,7 +75,7 @@ sub createLinks {
if (-l $dstFile) {
my $target = readlink $dstFile;
my $prevPriority = $priorities{$dstFile};
die ( "collission between `$srcFile' and `$target'; "
die ( "collision between `$srcFile' and `$target'; "
. "use `nix-env --set-flag "
. "priority NUMBER PKGNAME' to change the priority of "
. "one of the conflicting packages\n" )
+1
View File
@@ -7,6 +7,7 @@ in {
shell = "@shell@";
coreutils = "@coreutils@";
bzip2 = "@bzip2@";
gzip = "@gzip@";
xz = "@xz@";
tar = "@tar@";
tarFlags = "@tarFlags@";
+14 -8
View File
@@ -6,25 +6,28 @@ let
''
export PATH=${nixBinDir}:${coreutils}
if [ $compressionType = "xz" ]; then
ext=xz
compressor="${xz} -9"
if [ $compressionType = xz ]; then
ext=.xz
compressor="| ${xz} -7"
elif [ $compressionType = bzip2 ]; then
ext=.bz2
compressor="| ${bzip2}"
else
ext=bz2
compressor="${bzip2}"
ext=
compressor=
fi
echo "packing $storePath..."
mkdir $out
dst=$out/tmp.nar.$ext
dst=$out/tmp.nar$ext
set -o pipefail
nix-store --dump "$storePath" | $compressor > $dst
eval "nix-store --dump \"$storePath\" $compressor > $dst"
hash=$(nix-hash --flat --type $hashAlgo --base32 $dst)
echo -n $hash > $out/nar-compressed-hash
mv $dst $out/$hash.nar.$ext
mv $dst $out/$hash.nar$ext
'';
in
@@ -40,4 +43,7 @@ derivation {
# Don't build in a chroot because Nix's dependencies may not be there.
__noChroot = true;
# Remote machines may not have ${nixBinDir} or ${coreutils} in the same prefixes
preferLocalBuild = true;
}
+5 -2
View File
@@ -6,9 +6,12 @@ let
''
mkdir $out
cd $out
pat="\.xz\$"
if [[ "$src" =~ $pat ]]; then
xzpat="\.xz\$"
gzpat="\.gz\$"
if [[ "$src" =~ $xzpat ]]; then
${xz} -d < $src | ${tar} xf - ${tarFlags}
elif [[ "$src" =~ $gzpat ]]; then
${gzip} -d < $src | ${tar} xf - ${tarFlags}
else
${bzip2} -d < $src | ${tar} xf - ${tarFlags}
fi
Executable
+17
View File
@@ -0,0 +1,17 @@
#! /bin/sh
if [ -e tests/test-tmp ]; then
chmod -R u+w tests/test-tmp
rm -rf tests/test-tmp
fi
s=$(type -p nix-shell)
exec $s release.nix -A tarball --command "
export NIX_REMOTE=daemon
export NIX_PATH='$NIX_PATH'
export NIX_BUILD_SHELL=$(type -p bash)
export c=\$configureFlags
exec $s release.nix -A build.x86_64-linux --exclude tarball --command '
configureFlags+=\" \$c --prefix=$(pwd)/inst --sysconfdir=$(pwd)/inst/etc\"
return
'" \
"$@"
+1 -1
View File
@@ -16,7 +16,7 @@ dblatex_opts = \
# Note: we use GIF for now, since the PNGs shipped with Docbook aren't
# transparent.
man1_MANS = nix-env.1 nix-build.1 nix-store.1 nix-instantiate.1 \
man1_MANS = nix-env.1 nix-build.1 nix-shell.1 nix-store.1 nix-instantiate.1 \
nix-collect-garbage.1 nix-push.1 nix-pull.1 \
nix-prefetch-url.1 nix-channel.1 \
nix-install-package.1 nix-hash.1 nix-copy-closure.1
+1 -1
View File
@@ -434,7 +434,7 @@ x: x + 456</programlisting>
<replaceable>e</replaceable></term>
<listitem><para>Return <literal>true</literal> if
<replaceable>e</replaceable> evaluates to a int, and
<replaceable>e</replaceable> evaluates to an int, and
<literal>false</literal> otherwise.</para></listitem>
</varlistentry>
+29 -13
View File
@@ -101,8 +101,8 @@ flag, e.g. <literal>--option gc-keep-outputs false</literal>.</para>
<listitem><para>This option defines the maximum number of jobs
that Nix will try to build in parallel. The default is
<literal>1</literal>. You should generally set it to the number
of CPUs in your system (e.g., <literal>2</literal> on a Athlon 64
X2). It can be overriden using the <option
of CPUs in your system (e.g., <literal>2</literal> on an Athlon 64
X2). It can be overridden using the <option
linkend='opt-max-jobs'>--max-jobs</option> (<option>-j</option>)
command line switch.</para></listitem>
@@ -119,7 +119,7 @@ flag, e.g. <literal>--option gc-keep-outputs false</literal>.</para>
<varname>enableParallelBuilding</varname> is set to
<literal>true</literal>, the builder passes the
<option>-j<replaceable>N</replaceable></option> flag to GNU Make.
It can be overriden using the <option
It can be overridden using the <option
linkend='opt-cores'>--cores</option> command line switch and
defaults to <literal>1</literal>. The value <literal>0</literal>
means that the builder should use all available CPU cores in the
@@ -134,10 +134,10 @@ flag, e.g. <literal>--option gc-keep-outputs false</literal>.</para>
<para>This option defines the maximum number of seconds that a
builder can go without producing any data on standard output or
standard error. This is useful (for instance in a automated
standard error. This is useful (for instance in an automated
build system) to catch builds that are stuck in an infinite
loop, or to catch remote builds that are hanging due to network
problems. It can be overriden using the <option
problems. It can be overridden using the <option
linkend="opt-max-silent-time">--max-silent-time</option> command
line switch.</para>
@@ -148,15 +148,16 @@ flag, e.g. <literal>--option gc-keep-outputs false</literal>.</para>
</varlistentry>
<varlistentry xml:id="conf-build-timeout"><term><literal>build-timeout</literal></term>
<listitem>
<para>This option defines the maximum number of seconds that a
builder can run. This is useful (for instance in a automated
builder can run. This is useful (for instance in an automated
build system) to catch builds that are stuck in an infinite loop
but keep writing to their standard output or standard error. It
can be overriden using the <option
can be overridden using the <option
linkend="opt-timeout">--timeout</option> command line
switch.</para>
@@ -168,6 +169,20 @@ flag, e.g. <literal>--option gc-keep-outputs false</literal>.</para>
</varlistentry>
<varlistentry xml:id="conf-build-max-log-size"><term><literal>build-max-log-size</literal></term>
<listitem>
<para>This option defines the maximum number of bytes that a
builder can write to its stdout/stderr. If the builder exceeds
this limit, its killed. A value of <literal>0</literal> (the
default) means that there is no limit.</para>
</listitem>
</varlistentry>
<varlistentry xml:id="conf-build-users-group"><term><literal>build-users-group</literal></term>
<listitem><para>This options specifies the Unix group containing
@@ -325,7 +340,7 @@ flag, e.g. <literal>--option gc-keep-outputs false</literal>.</para>
<listitem><para>A list of URLs of binary caches, separated by
whitespace. The default is
<literal>http://nixos.org/binary-cache</literal>.</para></listitem>
<literal>http://cache.nixos.org</literal>.</para></listitem>
</varlistentry>
@@ -425,12 +440,13 @@ flag, e.g. <literal>--option gc-keep-outputs false</literal>.</para>
<varlistentry><term><literal>auto-optimise-store</literal></term>
<listitem><para>If set to <literal>true</literal> (the default),
Nix automatically detects files in the store that have identical
<listitem><para>If set to <literal>true</literal>, Nix
automatically detects files in the store that have identical
contents, and replaces them with hard links to a single copy.
This saves disk space. If set to <literal>false</literal>, you
can still run <command>nix-store --optimise</command> to get rid
of duplicate files.</para></listitem>
This saves disk space. If set to <literal>false</literal> (the
default), you can still run <command>nix-store
--optimise</command> to get rid of duplicate
files.</para></listitem>
</varlistentry>
+1 -1
View File
@@ -293,7 +293,7 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
<varlistentry xml:id="envar-other-stores"><term><envar>NIX_OTHER_STORES</envar></term>
<listitem><para>This variable contains the paths of remote Nix
installations from whichs paths can be copied, separated by colons.
installations from which packages can be copied, separated by colons.
<phrase condition="manual">See <xref linkend="sec-sharing-packages"
/> for details.</phrase> Each path should be the
<filename>/nix</filename> directory of a remote Nix installation
Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 83 KiB

+41
View File
@@ -0,0 +1,41 @@
<appendix xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xml:id="chap-hacking">
<title>Hacking</title>
<para>This section provides some notes on how to hack on Nix. To get
the latest version of Nix from GitHub:
<screen>
$ git clone git://github.com/NixOS/nix.git
$ cd hydra
</screen>
</para>
<para>To build it and its dependencies:
<screen>
$ nix-build release.nix -A build.x86_64-linux
</screen>
</para>
<para>To build all dependencies and start a shell in which all
environment variables are set up so that those dependencies can be
found:
<screen>
$ ./dev-shell
</screen>
To build Nix itself in this shell:
<screen>
[nix-shell]$ ./bootstrap
[nix-shell]$ configurePhase
[nix-shell]$ make
</screen>
To test it:
<screen>
[nix-shell]$ make install
[nix-shell]$ make installcheck
</screen>
</para>
</appendix>
+1 -1
View File
@@ -538,7 +538,7 @@ a symbolic link to the current <emphasis>user environment</emphasis>
installed packages). The simplest way to set the required environment
variables is to include the file
<filename><replaceable>prefix</replaceable>/etc/profile.d/nix.sh</filename>
in your <filename>~/.bashrc</filename> (or similar), like this:</para>
in your <filename>~/.profile</filename> (or similar), like this:</para>
<screen>
source <replaceable>prefix</replaceable>/etc/profile.d/nix.sh</screen>
+4 -2
View File
@@ -19,11 +19,11 @@
</author>
<copyright>
<year>2004-2012</year>
<year>2004-2013</year>
<holder>Eelco Dolstra</holder>
</copyright>
<date>May 2012</date>
<date>July 2013</date>
</info>
@@ -51,6 +51,7 @@
<section>
<title>Utilities</title>
<xi:include href="nix-build.xml" />
<xi:include href="nix-shell.xml" />
<xi:include href="nix-channel.xml" />
<xi:include href="nix-collect-garbage.xml" />
<xi:include href="nix-copy-closure.xml" />
@@ -72,6 +73,7 @@
<xi:include href="troubleshooting.xml" />
<!-- <xi:include href="bugs.xml" /> -->
<xi:include href="glossary.xml" />
<xi:include href="hacking.xml" />
<appendix>
<title>Nix Release Notes</title>
+2 -48
View File
@@ -38,11 +38,6 @@
</group>
<replaceable>outlink</replaceable>
</arg>
<arg>
<option>--run-env</option>
<arg><option>--command</option> <replaceable>cmd</replaceable></arg>
<arg><option>--exclude</option> <replaceable>regexp</replaceable></arg>
</arg>
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
@@ -75,13 +70,6 @@ a root of the Nix garbage collector. This root disappears
automatically when the <filename>result</filename> symlink is deleted
or renamed. So dont rename the symlink.</para></warning>
<para>The subcommand <command>nix-build --run-env</command> will build
the dependencies of the derivation, but not the derivation itself. It
will then start an interactive shell in which all environment
variables defined by the derivation have been set to their
corresponding values. This is useful for reproducing the environment
of a derivation for development.</para>
</refsection>
@@ -134,32 +122,12 @@ also <xref linkend="sec-common-options" />.</phrase></para>
</variablelist>
<para>The following common options are supported:</para>
<variablelist condition="manpage">
<xi:include href="opt-common.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(//db:variablelist[@xml:id='opt-common']/*)" />
</variablelist>
<para>The following options apply to <command>nix-build --run-env</command>.</para>
<variablelist>
<varlistentry><term><option>--command</option> <replaceable>cmd</replaceable></term>
<listitem><para>In the environment of the derivation, executeq the
command <replaceable>cmd</replaceable> instead of the default
interactive shell.</para></listitem>
</varlistentry>
<varlistentry><term><option>--exclude</option> <replaceable>regexp</replaceable></term>
<listitem><para>Do not build any dependencies whose store path
matches the regular expression <replaceable>regexp</replaceable>.
This option may be specified multiple times.</para></listitem>
</varlistentry>
</variablelist>
</refsection>
@@ -176,20 +144,6 @@ lrwxrwxrwx <replaceable>...</replaceable> result -> /nix/store/d18hyl92g30l...
$ ls ./result/bin/
firefox firefox-config</screen>
<para>To build the dependencies of the package Pan, and start an
interactive shell in which to build it:
<screen>
$ nix-build '&lt;nixpkgs>' --run-env -A pan
$ tar xf $src
$ cd pan-*
$ ./configure
$ make
$ ./pan/gui/pan
</screen>
</para>
<para>If a derivation has multiple outputs,
<command>nix-build</command> will build the default (first) output.
You can also build all outputs:
+17 -3
View File
@@ -209,6 +209,10 @@ also <xref linkend="sec-common-options" />.</phrase></para>
<arg choice='plain'><option>--preserve-installed</option></arg>
<arg choice='plain'><option>-P</option></arg>
</group>
<group choice='opt'>
<arg choice='plain'><option>--remove-all</option></arg>
<arg choice='plain'><option>-r</option></arg>
</group>
<arg choice='plain' rep='repeat'><replaceable>args</replaceable></arg>
</cmdsynopsis>
@@ -272,7 +276,7 @@ number of possible ways:
linkend="ss-functions">functions</link> that are called with the
active Nix expression as their single argument. The derivations
returned by those function calls are installed. This allows
derivations to be specified in a unambiguous way, which is necessary
derivations to be specified in an unambiguous way, which is necessary
if there are multiple derivations with the same
name.</para></listitem>
@@ -318,6 +322,16 @@ number of possible ways:
</varlistentry>
<varlistentry><term><option>--remove-all</option></term>
<term><option>-r</option></term>
<listitem><para>Remove all previously installed packages first.
This is equivalent to running <literal>nix-env -e '*'</literal>
first, except that everything happens in a single
transaction.</para></listitem>
</varlistentry>
</variablelist>
</refsection>
@@ -692,7 +706,7 @@ firefox-2.0.0.9 <lineannotation>(the current one)</lineannotation>
$ nix-env --preserve-installed -i firefox-2.0.0.11
installing `firefox-2.0.0.11'
building path(s) `/nix/store/myy0y59q3ig70dgq37jqwg1j0rsapzsl-user-environment'
Collission between `/nix/store/<replaceable>...</replaceable>-firefox-2.0.0.11/bin/firefox'
collision between `/nix/store/<replaceable>...</replaceable>-firefox-2.0.0.11/bin/firefox'
and `/nix/store/<replaceable>...</replaceable>-firefox-2.0.0.9/bin/firefox'.
<lineannotation>(i.e., cant have two active at the same time)</lineannotation>
@@ -1244,7 +1258,7 @@ wrapper around <option>--list-generations</option> and
$ nix-env --rollback
switching from generation 92 to 91
$ nix-env --rolback
$ nix-env --rollback
error: no generation older than the current (91) exists</screen>
</refsection>
+11 -4
View File
@@ -20,6 +20,7 @@
<command>nix-push</command>
<arg choice='plain'><option>--dest</option> <replaceable>dest-dir</replaceable></arg>
<arg><option>--bzip2</option></arg>
<arg><option>--none</option></arg>
<arg><option>--force</option></arg>
<arg><option>--link</option></arg>
<arg><option>--manifest</option></arg>
@@ -106,6 +107,12 @@ automatically.</para>
</varlistentry>
<varlistentry><term><option>--none</option></term>
<listitem><para>Do not compress NARs.</para></listitem>
</varlistentry>
<varlistentry><term><option>--force</option></term>
<listitem><para>Overwrite <filename>.narinfo</filename> files if
@@ -252,7 +259,7 @@ The properties that are currently supported are:
<listitem><para>Each binary cache has a priority (defaulting to
50). Binary caches are checked for binaries in order of ascending
priority; thus a higher number denotes a lower priority. The
binary cache <uri>http://nixos.org/binary-cache</uri> has priority
binary cache <uri>http://cache.nixos.org</uri> has priority
40.</para></listitem>
</varlistentry>
@@ -270,14 +277,14 @@ URL <replaceable>url</replaceable> has a binary for
<replaceable>p</replaceable>, Nix fetches
<replaceable>url/h</replaceable>, where <replaceable>h</replaceable>
is the hash part of <replaceable>p</replaceable>. Thus, if we have a
cache <uri>http://nixos.org/binary-cache</uri> and we want to obtain
cache <uri>http://cache.nixos.org</uri> and we want to obtain
the store path
<screen>
/nix/store/a8922c0h87iilxzzvwn2hmv8x210aqb9-glibc-2.7
</screen>
then Nix will attempt to fetch
<screen>
http://nixos.org/binary-cache/a8922c0h87iilxzzvwn2hmv8x210aqb9.narinfo
http://cache.nixos.org/a8922c0h87iilxzzvwn2hmv8x210aqb9.narinfo
</screen>
(Commands such as <command>nix-env -qas</command> will issue an HTTP
HEAD request, since it only needs to know if the
@@ -381,7 +388,7 @@ The fields are as follows:
references exist (e.g.,
<filename>/nix/store/2ma2k0ys8knh4an48n28vigcmc2z8773-linux-headers-2.6.23.16</filename>),
Nix will fetch <screen>
http://nixos.org/binary-cache/nar/0zzjpdz46mdn74v09m053yczlz4am038g8r74iy8w43gx8801h70.nar.bz2
http://cache.nixos.org/nar/0zzjpdz46mdn74v09m053yczlz4am038g8r74iy8w43gx8801h70.nar.bz2
</screen> and decompress and unpack it to
<filename>/nix/store/a8922c0h87iilxzzvwn2hmv8x210aqb9-glibc-2.7</filename>.</para>
+142
View File
@@ -0,0 +1,142 @@
<refentry xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xml:id="sec-nix-shell">
<refmeta>
<refentrytitle>nix-shell</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo class="source">Nix</refmiscinfo>
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
</refmeta>
<refnamediv>
<refname>nix-shell</refname>
<refpurpose>start an interactive shell based on a Nix expression</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>nix-shell</command>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="opt-common-syn.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(/db:nop/*)" />
<arg><option>--arg</option> <replaceable>name</replaceable> <replaceable>value</replaceable></arg>
<arg><option>--argstr</option> <replaceable>name</replaceable> <replaceable>value</replaceable></arg>
<arg>
<group choice='req'>
<arg choice='plain'><option>--attr</option></arg>
<arg choice='plain'><option>-A</option></arg>
</group>
<replaceable>attrPath</replaceable>
</arg>
<arg><option>--command</option> <replaceable>cmd</replaceable></arg>
<arg><option>--exclude</option> <replaceable>regexp</replaceable></arg>
<arg><option>--pure</option></arg>
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsection><title>Description</title>
<para>The command <command>nix-shell</command> will build
the dependencies of the specified derivation, but not the derivation
itself. It will then start an interactive shell in which all
environment variables defined by the derivation have been set to their
corresponding values, and the script <literal>$stdenv/setup</literal>
has been sourced. This is useful for reproducing the environment of a
derivation for development.</para>
</refsection>
<refsection><title>Options</title>
<para>All options not listed here are passed to <command>nix-store
--realise</command>, except for <option>--arg</option> and
<option>--attr</option> / <option>-A</option> which are passed to
<command>nix-instantiate</command>. <phrase condition="manual">See
also <xref linkend="sec-common-options" />.</phrase></para>
<variablelist>
<varlistentry><term><option>--command</option> <replaceable>cmd</replaceable></term>
<listitem><para>In the environment of the derivation, run the
shell command <replaceable>cmd</replaceable> instead of starting
an interactive shell. However, if you end the shell command with
<literal>return</literal>, you still get an interactive shell.
This can be useful for doing any additional
initialisation.</para></listitem>
</varlistentry>
<varlistentry><term><option>--exclude</option> <replaceable>regexp</replaceable></term>
<listitem><para>Do not build any dependencies whose store path
matches the regular expression <replaceable>regexp</replaceable>.
This option may be specified multiple times.</para></listitem>
</varlistentry>
<varlistentry><term><option>--pure</option></term>
<listitem><para>If this flag is specified, the environment is
almost entirely cleared before the interactive shell is started,
so you get an environment that more closely corresponds to the
“real” Nix build. A few variables, in particular
<envar>HOME</envar>, <envar>USER</envar> and
<envar>DISPLAY</envar>, are retained. Note that
<filename>~/.bashrc</filename> and (depending on your Bash
installation) <filename>/etc/bashrc</filename> are still sourced,
so any variables set there will affect the interactive
shell.</para></listitem>
</varlistentry>
</variablelist>
<para>The following common options are supported:</para>
<variablelist condition="manpage">
<xi:include href="opt-common.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(//db:variablelist[@xml:id='opt-common']/*)" />
</variablelist>
</refsection>
<refsection><title>Examples</title>
<para>To build the dependencies of the package Pan, and start an
interactive shell in which to build it:
<screen>
$ nix-shell '&lt;nixpkgs>' -A pan
$ unpackPhase
$ cd pan-*
$ configurePhase
$ buildPhase
$ ./pan/gui/pan
</screen>
To clear the environment first, and do some additional automatic
initialisation of the interactive shell:
<screen>
$ nix-shell '&lt;nixpkgs>' -A pan --pure \
--command 'export NIX_DEBUG=1; export NIX_CORES=8; return'
</screen>
</para>
</refsection>
<refsection condition="manpage"><title>Environment variables</title>
<variablelist>
<xi:include href="env-common.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(//db:variablelist[@xml:id='env-common']/*)" />
</variablelist>
</refsection>
</refentry>
+4 -4
View File
@@ -164,7 +164,7 @@ the specified store paths. Realisation is a somewhat overloaded term:
exist in the file system). If the path is already valid, we are
done immediately. Otherwise, the path and any missing paths in its
closure may be produced through substitutes. If there are no
(succesful) subsitutes, realisation fails.</para></listitem>
(successful) subsitutes, realisation fails.</para></listitem>
</itemizedlist>
@@ -852,7 +852,7 @@ in Nix itself.</para>
<refsection><title>Description</title>
<para>The operation <option>--verify-paths</option> compares the
<para>The operation <option>--verify-path</option> compares the
contents of the given store paths to their cryptographic hashes stored
in Nixs database. For every changed path, it prints a warning
message. The exit status is 0 if no path has changed, and 1
@@ -1242,9 +1242,9 @@ variable <envar>_args</envar>.</para>
$ nix-store --print-env $(nix-instantiate '&lt;nixpkgs>' -A firefox)
<replaceable></replaceable>
export src; src='/nix/store/plpj7qrwcz94z2psh6fchsi7s8yihc7k-firefox-12.0.source.tar.bz2'
export stdenv; stdenv='/nix/store/7c8asx3yfrg5dg1gzhzyq2236zfgibnm-stdenv'
export stdenv; stdenv='/nix/store/7c8asx3yfrg5dg1gzhzyq2236zfgibnn-stdenv'
export system; system='x86_64-linux'
export _args; _args='-e /nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh'
export _args; _args='-e /nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25c-default-builder.sh'
</screen>
</refsection>
+2 -2
View File
@@ -181,7 +181,7 @@
from, say, a network repository. If the repository is down, the
realisation of the derivation will fail. When this option is
specified, Nix will build the derivation instead. Thus,
installation from binaries falls back on nstallation from source.
installation from binaries falls back on installation from source.
This option is not the default since it is generally not desirable
for a transient failure in obtaining the substitutes to lead to a
full build from source (with the related consumption of
@@ -236,7 +236,7 @@
interpreted by the <command>nix-log2xml</command> tool in the
Nix source distribution. The resulting XML file can be fed into
the <command>log2html.xsl</command> stylesheet to create an HTML
file that can be browsed interactively, using Javascript to
file that can be browsed interactively, using JavaScript to
expand and collapse parts of the output.</para></listitem>
</varlistentry>
+2 -2
View File
@@ -129,7 +129,7 @@ downloading binaries from <systemitem
class='fqdomainname'>nixos.org</systemitem>, instead of building
them from source. This might still take a while since all
dependencies must be downloaded, but on a reasonably fast connection
such as an DSL line its on the order of a few minutes.</para>
such as a DSL line its on the order of a few minutes.</para>
<para>Naturally, packages can also be uninstalled:
@@ -225,7 +225,7 @@ uses is to create directory trees of symlinks to
themselves (though automatically generated by
<command>nix-env</command>), so they too reside in the Nix store. For
instance, in <xref linkend='fig-user-environments' /> the user
environment <filename>/nix/store/5mq2jcn36ldl...-user-env</filename>
environment <filename>/nix/store/0c1p5z4kda11...-user-env</filename>
contains a symlink to just Subversion 1.1.2 (arrows in the figure
indicate symlinks). This would be what we would obtain if we had done
+1 -1
View File
@@ -36,7 +36,7 @@ changed using
<listitem><para>You should add
<filename><replaceable>prefix</replaceable>/etc/profile.d/nix.sh</filename>
to your <filename>~/.bashrc</filename> (or some other login
to your <filename>~/.profile</filename> (or some other login
file).</para></listitem>
<listitem><para>Subscribe to the Nix Packages channel.
+180 -7
View File
@@ -6,6 +6,179 @@
<!--==================================================================-->
<section xml:id="ssec-relnotes-1.6.0"><title>Release 1.6.0 (September 10, 2013)</title>
<para>In addition to the usual bug fixes, this release has several new
features:</para>
<itemizedlist>
<listitem>
<para>The command <command>nix-build --run-env</command> has been
renamed to <command>nix-shell</command>.</para>
</listitem>
<listitem>
<para><command>nix-shell</command> now sources
<filename>$stdenv/setup</filename> <emphasis>inside</emphasis> the
interactive shell, rather than in a parent shell. This ensures
that shell functions defined by <literal>stdenv</literal> can be
used in the interactive shell.</para>
</listitem>
<listitem>
<para><command>nix-shell</command> has a new flag
<option>--pure</option> to clear the environment, so you get an
environment that more closely corresponds to the “real” Nix build.
</para>
</listitem>
<listitem>
<para><command>nix-shell</command> now sets the shell prompt
(<envar>PS1</envar>) to ensure that Nix shells are distinguishable
from your regular shells.</para>
</listitem>
<listitem>
<para><command>nix-env</command> no longer requires a
<literal>*</literal> argument to match all packages, so
<literal>nix-env -qa</literal> is equivalent to <literal>nix-env
-qa '*'</literal>.</para>
</listitem>
<listitem>
<para><command>nix-env -i</command> has a new flag
<option>--remove-all</option> (<option>-r</option>) to remove all
previous packages from the profile. This makes it easier to do
declarative package management similar to NixOSs
<option>environment.systemPackages</option>. For instance, if you
have a specification <filename>my-packages.nix</filename> like this:
<programlisting>
with import &lt;nixpkgs> {};
[ thunderbird
geeqie
...
]
</programlisting>
then after any change to this file, you can run:
<screen>
$ nix-env -f my-packages.nix -ir
</screen>
to update your profile to match the specification.</para>
</listitem>
<listitem>
<para>The <literal>with</literal> language construct is now more
lazy. It only evaluates its argument if a variable might actually
refer to an attribute in the argument. For instance, this now
works:
<programlisting>
let
pkgs = with pkgs; { foo = "old"; bar = foo; } // overrides;
overrides = { foo = "new"; };
in pkgs.bar
</programlisting>
This evaluates to <literal>"new"</literal>, while previously it
gave an “infinite recursion” error.</para>
</listitem>
<listitem>
<para>Nix now has proper integer arithmetic operators. For
instance, you can write <literal>x + y</literal> instead of
<literal>builtins.add x y</literal>, or <literal>x &lt;
y</literal> instead of <literal>builtins.lessThan x y</literal>.
The comparison operators also work on strings.</para>
</listitem>
<listitem>
<para>On 64-bit systems, Nix integers are now 64 bits rather than
32 bits.</para>
</listitem>
<listitem>
<para>When using the Nix daemon, the <command>nix-daemon</command>
worker process now runs on the same CPU as the client, on systems
that support setting CPU affinity. This gives a significant speedup
on some systems.</para>
</listitem>
<listitem>
<para>If a stack overflow occurs in the Nix evaluator, you now get
a proper error message (rather than “Segmentation fault”) on some
systems.</para>
</listitem>
<listitem>
<para>In addition to directories, you can now bind-mount regular
files in chroots through the (now misnamed) option
<option>build-chroot-dirs</option>.</para>
</listitem>
</itemizedlist>
<para>This release has contributions from Domen Kožar, Eelco Dolstra,
Florian Friesdorf, Gergely Risko, Ivan Kozik, Ludovic Courtès and Shea
Levy.</para>
</section>
<!--==================================================================-->
<section xml:id="ssec-relnotes-1.5.3"><title>Release 1.5.3 (June 17, 2013)</title>
<para>This is primarily a bug fix release. The following changes are
noteworthy:</para>
<itemizedlist>
<listitem>
<para>Yet another security bug involving hard links to files
outside the store was fixed. This bug only affected multi-user
installations that do not have hard link restrictions
enabled. (NixOS is thus not vulnerable.)</para>
</listitem>
<listitem>
<para>The default binary cache URL has changed from
<uri>http://nixos.org/binary-cache</uri> to
<uri>http://cache.nixos.org</uri>. The latter is hosted on Amazon
CloudFront (courtesy of <link
xlink:href="http://www.logicblox.com/">LogicBlox</link>) and
should provide better performance for users in both Europe and
North America.</para>
</listitem>
<listitem>
<para>The binary cache substituter now prints a warning message if
fetching information from the cache takes more than five seconds.
Thus network or server problems no longer make Nix appear to just
hang.</para>
</listitem>
<listitem>
<para>Stack traces now show function names, e.g.
<screen>
while evaluating `concatMapStrings' at `<replaceable>...</replaceable>/nixpkgs/pkgs/lib/strings.nix:18:25':
</screen>
Also, if a function is called with an unexpected argument, Nix
now shows the name of the argument.
</para>
</listitem>
</itemizedlist>
</section>
<!--==================================================================-->
<section xml:id="ssec-relnotes-1.5.2"><title>Release 1.5.2 (May 13, 2013)</title>
@@ -107,10 +280,10 @@ Pernsteiner.</para>
configuration setting <option>binary-caches</option> contains a
list of URLs of binary caches. For instance, doing
<screen>
$ nix-env -i thunderbird --option binary-caches http://nixos.org/binary-cache
$ nix-env -i thunderbird --option binary-caches http://cache.nixos.org
</screen>
will install Thunderbird and its dependencies, using the available
pre-built binaries in <uri>http://nixos.org/binary-cache</uri>.
pre-built binaries in <uri>http://cache.nixos.org</uri>.
The main advantage over the old “manifest”-based method of getting
pre-built binaries is that you dont have to worry about your
manifest being in sync with the Nix expressions youre installing
@@ -123,7 +296,7 @@ $ nix-env -i thunderbird --option binary-caches http://nixos.org/binary-cache
used automatically if you subscribe to that channel. If you use
the Nixpkgs or NixOS channels
(<uri>http://nixos.org/channels</uri>) you automatically get the
cache <uri>http://nixos.org/binary-cache</uri>.</para>
cache <uri>http://cache.nixos.org</uri>.</para>
<para>Binary caches are created using <command>nix-push</command>.
For details on the operation and format of binary caches, see the
@@ -1273,7 +1446,7 @@ irreversible.</para></warning>
</para></listitem>
<listitem><para>You can now unambigously specify which derivation to
<listitem><para>You can now unambiguously specify which derivation to
build or install in <command>nix-env</command>,
<command>nix-instantiate</command> and <command>nix-build</command>
using the <option>--attr</option> / <option>-A</option> flags, which
@@ -1413,7 +1586,7 @@ irreversible.</para></warning>
<itemizedlist>
<listitem><para>Make sure that the garbage collector can run
succesfully when the disk is full
successfully when the disk is full
(<literal>NIX-18</literal>).</para></listitem>
<listitem><para><command>nix-env</command> now locks the profile
@@ -1768,7 +1941,7 @@ $ nix-env -f .../i686-linux.nix -i -E 'x: x.firefoxWrapper'</screen>
</itemizedlist></para></listitem>
<listitem><para>A hash of the contents of a store path is now stored
in the database after a succesful build. This allows you to check
in the database after a successful build. This allows you to check
whether store paths have been tampered with: <command>nix-store
--verify --check-contents</command>.</para></listitem>
@@ -1932,7 +2105,7 @@ $ nix-env -f .../i686-linux.nix -i -E 'x: x.firefoxWrapper'</screen>
<itemizedlist>
<listitem><para>Derivations for other platforms are filtered out
(which can be overriden using
(which can be overridden using
<option>--system-filter</option>).</para></listitem>
<listitem><para><option>--install</option> by default now
+2 -2
View File
@@ -17,7 +17,7 @@ bug tracker</link> for a list of currently known issues.</para>
$ nix-env -i docbook-xml
...
adding /nix/store/s5hyxgm62gk2...-docbook-xml-4.2
collission between `/nix/store/s5hyxgm62gk2...-docbook-xml-4.2/xml/dtd/docbook/calstblx.dtd'
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>
@@ -68,7 +68,7 @@ in <filename>/nix/store</filename>, as can be seen using <command>ls
$ ls -l /nix/store
drwxrwxrwt 32000 nix nix 4620288 Sep 8 15:08 store</screen>
The <literal>ext2</literal> file system is limited to a inode link
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>
+9 -9
View File
@@ -617,7 +617,7 @@ Laziness means that arguments to functions are evaluated only when
they are needed. Functional means that functions are
<quote>normal</quote> values that can be passed around and manipulated
in interesting ways. The language is not a full-featured, general
purpose language. It's main job is to describe packages,
purpose language. Its main job is to describe packages,
compositions of packages, and the variability within
packages.</para>
@@ -714,18 +714,18 @@ configureFlags = "
text on the initial line.</para>
<para>Antiquotation
(<literal>${<replaceable>expr</replaceable>}}</literal>) is
(<literal>${<replaceable>expr</replaceable>}</literal>) is
supported in indented strings.</para>
<para>Since <literal>${</literal> and <literal>''</literal> have
special meaning in indented strings, you need a way to quote them.
<literal>${</literal> can be escaped by prefixing it with
<literal>''</literal>, i.e., <literal>''${</literal>.
<literal>''</literal> can be escaped by prefixing it with
<literal>'</literal>, i.e., <literal>'''</literal>. Finally,
linefeed, carriage-return and tab characters can be writted as
<literal>''\n</literal>, <literal>''\r</literal>,
<literal>''\t</literal>.</para>
<literal>''</literal> (that is, two single quotes), i.e.,
<literal>''${</literal>. <literal>''</literal> can be escaped by
prefixing it with <literal>'</literal>, i.e.,
<literal>'''</literal>. Finally, linefeed, carriage-return and
tab characters can be written as <literal>''\n</literal>,
<literal>''\r</literal>, <literal>''\t</literal>.</para>
<para>Indented strings are primarily useful in that they allow
multi-line string literals to follow the indentation of the
@@ -775,7 +775,7 @@ stdenv.mkDerivation {
absolute at parse time relative to the directory of the Nix
expression that contained it. For instance, if a Nix expression in
<filename>/foo/bar/bla.nix</filename> refers to
<filename>../xyzzy/fnord.nix</filename>, the absolutised path is
<filename>../xyzzy/fnord.nix</filename>, the absolute path is
<filename>/foo/xyzzy/fnord.nix</filename>.</para></listitem>
<listitem><para><emphasis>Booleans</emphasis> with values
+1
View File
@@ -22,6 +22,7 @@ Requires: /usr/bin/perl
Requires: curl
Requires: perl-DBD-SQLite
Requires: bzip2
Requires: gzip
Requires: xz
BuildRequires: bzip2-devel
BuildRequires: sqlite-devel
+4 -1
View File
@@ -227,6 +227,9 @@ sub writeManifest {
sub updateManifestDB {
my $manifestDir = $Nix::Config::manifestDir;
my @manifests = glob "$manifestDir/*.nixmanifest";
return undef if scalar @manifests == 0;
mkpath($manifestDir);
unlink "$manifestDir/cache.sqlite"; # remove obsolete cache
@@ -311,7 +314,7 @@ EOF
# unless we've already done so on a previous run.
my %seen;
for my $manifestLink (glob "$manifestDir/*.nixmanifest") {
for my $manifestLink (@manifests) {
my $manifest = Cwd::abs_path($manifestLink);
next unless -f $manifest;
my $timestamp = lstat($manifest)->mtime;
+1
View File
@@ -20,6 +20,7 @@ void doInit()
if (!store) {
try {
settings.processEnvironment();
settings.lockCPU = false;
store = openStore();
} catch (Error & e) {
croak(e.what());
+1
View File
@@ -18,6 +18,7 @@ install-exec-local: download-using-manifests.pl copy-from-other-stores.pl downlo
$(INSTALL) -d $(DESTDIR)$(libexecdir)/nix/substituters
$(INSTALL_PROGRAM) download-using-manifests.pl copy-from-other-stores.pl download-from-binary-cache.pl $(DESTDIR)$(libexecdir)/nix/substituters
$(INSTALL) -d $(DESTDIR)$(sysconfdir)/nix
ln -sf nix-build $(DESTDIR)$(bindir)/nix-shell
include ../substitute.mk
+12 -12
View File
@@ -46,7 +46,7 @@ sub all { $_ || return 0 for @_; 1 }
# Initialisation.
my $loadIncreased = 0;
my ($localSystem, $printBuildTrace) = @ARGV;
my ($localSystem, $maxSilentTime, $printBuildTrace, $buildTimeout) = @ARGV;
my $currentLoad = $ENV{"NIX_CURRENT_LOAD"};
my $conf = $ENV{"NIX_REMOTE_SYSTEMS"};
@@ -197,10 +197,11 @@ REQ: while (1) {
$hostName = $machine->{hostName};
if (openSSHConnection($hostName)) {
last REQ if system("ssh $hostName @sshOpts nix-builds-inhibited < /dev/null > /dev/null 2>&1") != 0;
warn "machine `$hostName' is refusing builds, trying other available machines...\n";
closeSSHConnection;
} else {
warn "unable to open SSH connection to `$hostName', trying other available machines...\n";
}
warn "unable to open SSH connection to $hostName, trying other available machines...\n";
$machine->{enabled} = 0;
}
}
@@ -212,7 +213,6 @@ my @inputs = split /\s/, readline(STDIN);
my @outputs = split /\s/, readline(STDIN);
print STDERR "building `$drvPath' on `$hostName'\n";
print STDERR "@ build-remote $drvPath $hostName\n" if $printBuildTrace;
@@ -261,7 +261,8 @@ close UPLOADLOCK;
# Perform the build.
my $buildFlags =
" --fallback --add-root $rootsDir/\$PPID.out --quiet"
"--max-silent-time $maxSilentTime --option build-timeout $buildTimeout"
. " --fallback --add-root $rootsDir/\$PPID.out --quiet"
. " --option build-keep-log false";
# We let the remote side kill its process group when the connection is
@@ -271,6 +272,7 @@ my $buildFlags =
# is interrupted unless the `-tt' flag is used to force a pseudo-tty,
# in which case every child receives SIGHUP; however, `-tt' doesn't
# work on some platforms when connection sharing is used.)
print STDERR "building `$drvPath' on `$hostName'\n";
pipe STDIN, DUMMY; # make sure we have a readable STDIN
if (system("exec ssh $hostName @sshOpts '(read; kill -INT -\$\$) <&0 & exec nix-store -r $drvPath $buildFlags > /dev/null' 2>&4") != 0) {
# Note that if we get exit code 100 from `nix-store -r', it
@@ -288,13 +290,11 @@ if (system("exec ssh $hostName @sshOpts '(read; kill -INT -\$\$) <&0 & exec nix-
# Copy the output from the build machine.
foreach my $output (@outputs) {
my $maybeSignRemote = "";
$maybeSignRemote = "--sign" if $UID != 0;
next if isValidPath($output);
system("exec ssh $hostName @sshOpts 'nix-store --export $maybeSignRemote $output'" .
"| NIX_HELD_LOCKS=$output @bindir@/nix-store --import > /dev/null") == 0
or die "cannot copy $output from $hostName: $?";
my @outputs2 = grep { !isValidPath($_) } @outputs;
if (scalar @outputs2 > 0) {
system("exec ssh $hostName @sshOpts 'nix-store --export @outputs2'" .
"| NIX_HELD_LOCKS='@outputs2' @bindir@/nix-store --import > /dev/null") == 0
or die("cannot copy paths " . join(", ", @outputs) . " from `$hostName': $?");
}
+8 -5
View File
@@ -16,6 +16,9 @@ foreach my $dir (@remoteStoresAll) {
push @remoteStores, glob($dir);
}
exit if scalar @remoteStores == 0;
print "\n";
$ENV{"NIX_REMOTE"} = "";
@@ -27,7 +30,7 @@ sub findStorePath {
next unless -e $sourcePath || -l $sourcePath;
$ENV{"NIX_DB_DIR"} = "$store/var/nix/db";
return ($store, $sourcePath) if
system("@bindir@/nix-store --check-validity $storePath") == 0;
system("$binDir/nix-store --check-validity $storePath") == 0;
}
return undef;
}
@@ -53,16 +56,16 @@ if ($ARGV[0] eq "--query") {
$ENV{"NIX_DB_DIR"} = "$store/var/nix/db";
my $deriver = `@bindir@/nix-store --query --deriver $storePath`;
my $deriver = `$binDir/nix-store --query --deriver $storePath`;
die "cannot query deriver of `$storePath'" if $? != 0;
chomp $deriver;
$deriver = "" if $deriver eq "unknown-deriver";
my @references = split "\n",
`@bindir@/nix-store --query --references $storePath`;
`$binDir/nix-store --query --references $storePath`;
die "cannot query references of `$storePath'" if $? != 0;
my $narSize = `@bindir@/nix-store --query --size $storePath`;
my $narSize = `$binDir/nix-store --query --size $storePath`;
die "cannot query size of `$storePath'" if $? != 0;
chomp $narSize;
@@ -70,7 +73,7 @@ if ($ARGV[0] eq "--query") {
print "$deriver\n";
print scalar @references, "\n";
print "$_\n" foreach @references;
print "$narSize\n";
print "0\n";
print "$narSize\n";
}
+36 -18
View File
@@ -24,8 +24,9 @@ my $ttlNegative = 24 * 3600; # when to purge negative lookups from the database
my $ttlNegativeUse = 3600; # how long negative lookups are valid for non-"have" lookups
my $didExpiration = 0;
my $debug = ($ENV{"NIX_DEBUG_SUBST"} // "") eq 1;
open(STDERR, ">>/dev/tty") if $debug;
my $showAfter = 5; # show that we're waiting for a request after this many seconds
my $debug = ($Nix::Config::config{"debug-subst"} // "") eq 1 || ($Nix::Config::config{"untrusted-debug-subst"} // "") eq 1;
my $cacheFileURLs = ($ENV{"_NIX_CACHE_FILE_URLS"} // "") eq 1; # for testing
@@ -46,7 +47,8 @@ sub addRequest {
my $curl = WWW::Curl::Easy->new;
my $curlId = $curlIdCount++;
$requests{$curlId} = { storePath => $storePath, url => $url, handle => $curl, content => "", type => $head ? "HEAD" : "GET" };
$requests{$curlId} = { storePath => $storePath, url => $url, handle => $curl, content => "", type => $head ? "HEAD" : "GET"
, shown => 0, started => time() };
$curl->setopt(CURLOPT_PRIVATE, $curlId);
$curl->setopt(CURLOPT_URL, $url);
@@ -57,6 +59,7 @@ sub addRequest {
$curl->setopt(CURLOPT_USERAGENT, "Nix/$Nix::Config::version");
$curl->setopt(CURLOPT_NOBODY, 1) if $head;
$curl->setopt(CURLOPT_FAILONERROR, 1);
$curl->setopt(CURLOPT_TIMEOUT, int($ENV{"NIX_CONNECT_TIMEOUT"} // 0));
if ($activeRequests >= $maxParallelRequests) {
$scheduled{$curlId} = 1;
@@ -76,7 +79,7 @@ sub processRequests {
# Sleep until we can read or write some data.
if (scalar @{$rfds} + scalar @{$wfds} + scalar @{$efds} > 0) {
IO::Select->select(IO::Select->new(@{$rfds}), IO::Select->new(@{$wfds}), IO::Select->new(@{$efds}), 0.1);
IO::Select->select(IO::Select->new(@{$rfds}), IO::Select->new(@{$wfds}), IO::Select->new(@{$efds}), 1.0);
}
if ($curlm->perform() != $activeRequests) {
@@ -101,6 +104,16 @@ sub processRequests {
}
}
}
my $time = time();
while (my ($key, $request) = each %requests) {
next unless defined $request->{handle};
next if $request->{shown};
if ($time > $request->{started} + $showAfter) {
print STDERR "still waiting for $request->{url} after $showAfter seconds...\n";
$request->{shown} = 1;
}
}
}
}
@@ -186,17 +199,13 @@ sub getAvailableCaches {
return if $gotCaches;
$gotCaches = 1;
return if
($Nix::Config::config{"use-binary-caches"} // "true") eq "false" ||
($Nix::Config::config{"untrusted-use-binary-caches"} // "true") eq "false";
sub strToList {
my ($s) = @_;
return map { s/\/+$//; $_ } split(/ /, $s);
}
my @urls = strToList($Nix::Config::config{"binary-caches"} //
($Nix::Config::storeDir eq "/nix/store" ? "http://nixos.org/binary-cache" : ""));
($Nix::Config::storeDir eq "/nix/store" ? "http://cache.nixos.org" : ""));
my $urlsFiles = $Nix::Config::config{"binary-cache-files"}
// "$Nix::Config::stateDir/profiles/per-user/$userName/channels/binary-caches/*";
@@ -225,7 +234,7 @@ sub getAvailableCaches {
}
}
my @untrustedUrls = strToList $Nix::Config::config{"untrusted-extra-binary-caches"};
my @untrustedUrls = strToList $Nix::Config::config{"untrusted-extra-binary-caches"} // "";
foreach my $url (@untrustedUrls) {
next unless scalar(grep { $url eq $_ } @trustedUrls) > 0;
push @urls, $url;
@@ -265,11 +274,12 @@ sub getAvailableCaches {
elsif ($1 eq "Priority") { $priority = int($2); }
}
$dbh->do("insert into BinaryCaches(url, timestamp, storeDir, wantMassQuery, priority) values (?, ?, ?, ?, ?)",
$dbh->do("insert or replace into BinaryCaches(url, timestamp, storeDir, wantMassQuery, priority) values (?, ?, ?, ?, ?)",
{}, $url, time(), $storeDir, $wantMassQuery, $priority);
my $id = $dbh->last_insert_id("", "", "", "");
$queryCache->execute($url);
$res = $queryCache->fetchrow_hashref() or die;
next if $storeDir ne $Nix::Config::storeDir;
push @caches, { id => $id, url => $url, wantMassQuery => $wantMassQuery, priority => $priority };
push @caches, { id => $res->{id}, url => $url, wantMassQuery => $wantMassQuery, priority => $priority };
}
@caches = sort { $a->{priority} <=> $b->{priority} } @caches;
@@ -288,7 +298,7 @@ sub processNARInfo {
my ($storePath, $cache, $request) = @_;
if ($request->{result} != 0) {
if ($request->{result} != 37 && $request->{httpStatus} != 404) {
if ($request->{result} != 37 && $request->{httpStatus} != 404 && $request->{httpStatus} != 403) {
print STDERR "could not download $request->{url} (" .
($request->{result} != 0 ? "Curl error $request->{result}" : "HTTP status $request->{httpStatus}") . ")\n";
} else {
@@ -467,7 +477,7 @@ sub printSubstitutablePaths {
foreach my $request (values %requests) {
if ($request->{result} != 0) {
if ($request->{result} != 37 && $request->{httpStatus} != 404) {
if ($request->{result} != 37 && $request->{httpStatus} != 404 && $request->{httpStatus} != 403) {
print STDERR "could not check $request->{url} (" .
($request->{result} != 0 ? "Curl error $request->{result}" : "HTTP status $request->{httpStatus}") . ")\n";
} else {
@@ -503,8 +513,9 @@ sub downloadBinary {
next unless defined $info;
my $decompressor;
if ($info->{compression} eq "bzip2") { $decompressor = "$Nix::Config::bzip2 -d"; }
elsif ($info->{compression} eq "xz") { $decompressor = "$Nix::Config::xz -d"; }
if ($info->{compression} eq "bzip2") { $decompressor = "| $Nix::Config::bzip2 -d"; }
elsif ($info->{compression} eq "xz") { $decompressor = "| $Nix::Config::xz -d"; }
elsif ($info->{compression} eq "none") { $decompressor = ""; }
else {
print STDERR "unknown compression method $info->{compression}\n";
next;
@@ -512,7 +523,7 @@ sub downloadBinary {
my $url = "$cache->{url}/$info->{url}"; # FIXME: handle non-relative URLs
print STDERR "\n*** Downloading $url to $storePath...\n";
checkURL $url;
if (system("$Nix::Config::curl --fail --location --insecure '$url' | $decompressor | $Nix::Config::binDir/nix-store --restore $destPath") != 0) {
if (system("$Nix::Config::curl --fail --location --insecure '$url' $decompressor | $Nix::Config::binDir/nix-store --restore $destPath") != 0) {
warn "download of `$url' failed" . ($! ? ": $!" : "") . "\n";
next;
}
@@ -529,6 +540,13 @@ sub downloadBinary {
}
# Bail out right away if binary caches are disabled.
exit 0 if
($Nix::Config::config{"use-binary-caches"} // "true") eq "false" ||
($Nix::Config::config{"untrusted-use-binary-caches"} // "true") eq "false";
print "\n";
flush STDOUT;
initCache();
+7 -4
View File
@@ -22,6 +22,8 @@ my $curl = "$Nix::Config::curl --fail --location --insecure";
# Open the manifest cache and update it if necessary.
my $dbh = updateManifestDB();
exit 0 unless defined $dbh; # exit if there are no manifests
print "\n";
# $hashCache->{$algo}->{$path} yields the $algo-hash of $path.
@@ -342,17 +344,18 @@ while (scalar @path > 0) {
checkURL $narFile->{url};
my $decompressor =
$narFile->{compressionType} eq "bzip2" ? "$Nix::Config::bzip2 -d" :
$narFile->{compressionType} eq "xz" ? "$Nix::Config::xz -d" :
$narFile->{compressionType} eq "bzip2" ? "| $Nix::Config::bzip2 -d" :
$narFile->{compressionType} eq "xz" ? "| $Nix::Config::xz -d" :
$narFile->{compressionType} eq "none" ? "" :
die "unknown compression type `$narFile->{compressionType}'";
if ($curStep < $maxStep) {
# The archive will be used a base to a patch.
system("$curl '$narFile->{url}' | $decompressor > $tmpNar") == 0
system("$curl '$narFile->{url}' $decompressor > $tmpNar") == 0
or die "cannot download and unpack `$narFile->{url}' to `$v'\n";
} else {
# Unpack the archive to the target path.
system("$curl '$narFile->{url}' | $decompressor | $Nix::Config::binDir/nix-store --restore '$destPath'") == 0
system("$curl '$narFile->{url}' $decompressor | $Nix::Config::binDir/nix-store --restore '$destPath'") == 0
or die "cannot download and unpack `$narFile->{url}' to `$v'\n";
}
+50 -16
View File
@@ -3,23 +3,27 @@
use strict;
use Nix::Config;
use Nix::Store;
use Nix::Utils;
use File::Temp qw(tempdir);
my $dryRun = 0;
my $verbose = 0;
my $runEnv = 0;
my $runEnv = $0 =~ /nix-shell$/;
my $pure = 0;
my @instArgs = ();
my @buildArgs = ();
my @exprs = ();
my $shell = $ENV{SHELL} || "/bin/sh";
my $envCommand = "p=\$PATH; source \$stdenv/setup; PATH=\$PATH:\$p; exec $shell";
my $envCommand = ""; # interactive shell
my @envExclude = ();
my $myName = $runEnv ? "nix-shell" : "nix-build";
my $tmpDir = tempdir("nix-build.XXXXXX", CLEANUP => 1, TMPDIR => 1)
my $tmpDir = tempdir("$myName.XXXXXX", CLEANUP => 1, TMPDIR => 1)
or die "cannot create a temporary directory";
my $outLink = "./result";
@@ -33,11 +37,11 @@ for (my $n = 0; $n < scalar @ARGV; $n++) {
my $arg = $ARGV[$n];
if ($arg eq "--help") {
exec "man nix-build" or die;
exec "man $myName" or die;
}
elsif ($arg eq "--version") {
print "nix-build (Nix) $Nix::Config::version\n";
print "$myName (Nix) $Nix::Config::version\n";
exit 0;
}
@@ -117,14 +121,14 @@ for (my $n = 0; $n < scalar @ARGV; $n++) {
push @instArgs, $arg;
}
elsif ($arg eq "--run-env") {
elsif ($arg eq "--run-env") { # obsolete
$runEnv = 1;
}
elsif ($arg eq "--command") {
$n++;
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
$envCommand = $ARGV[$n];
$envCommand = "$ARGV[$n]\nexit $!";
}
elsif ($arg eq "--exclude") {
@@ -133,6 +137,10 @@ for (my $n = 0; $n < scalar @ARGV; $n++) {
push @envExclude, $ARGV[$n];
}
elsif ($arg eq "--pure") {
$pure = 1;
}
elsif (substr($arg, 0, 1) eq "-") {
push @buildArgs, $arg;
}
@@ -149,6 +157,7 @@ foreach my $expr (@exprs) {
# Instantiate.
my @drvPaths;
if ($expr !~ /^\/.*\.drv$/) {
# !!! would prefer the perl 5.8.0 pipe open feature here.
my $pid = open(DRVPATHS, "-|") || exec "$Nix::Config::binDir/nix-instantiate", "--add-root", $drvLink, "--indirect", @instArgs, $expr;
while (<DRVPATHS>) {chomp; push @drvPaths, $_;}
@@ -156,10 +165,14 @@ foreach my $expr (@exprs) {
die "nix-instantiate killed by signal " . ($? & 127) . "\n" if ($? & 127);
exit 1;
}
} else {
push @drvPaths, $expr;
}
if ($runEnv) {
die "$0: --run-env requires a single derivation\n" if scalar @drvPaths != 1;
my $drvPath = readlink $drvPaths[0] or die "cannot read symlink `$drvPaths[0]'";
die "$0: a single derivation is required\n" if scalar @drvPaths != 1;
my $drvPath = $drvPaths[0];
$drvPath = readlink $drvPath or die "cannot read symlink `$drvPath'" if -l $drvPath;
my $drv = derivationFromPath($drvPath);
# Build or fetch all dependencies of the derivation.
@@ -168,16 +181,37 @@ foreach my $expr (@exprs) {
or die "$0: failed to build all dependencies\n";
# Set the environment.
$ENV{'NIX_BUILD_TOP'} = $ENV{'TMPDIR'} || "/tmp";
foreach (keys %{$drv->{env}}) {
$ENV{$_} = $drv->{env}->{$_};
if ($pure) {
foreach my $name (keys %ENV) {
next if $name eq "HOME" || $name eq "USER" || $name eq "LOGNAME" || $name eq "DISPLAY" || $name eq "PATH";
delete $ENV{$name};
}
# NixOS hack: prevent /etc/bashrc from sourcing /etc/profile.
$ENV{'__ETC_PROFILE_SOURCED'} = 1;
}
$ENV{'NIX_BUILD_TOP'} = $ENV{'TMPDIR'} = $ENV{'TEMPDIR'} = $ENV{'TMP'} = $ENV{'TEMP'} = $ENV{'TMPDIR'} // "/tmp";
$ENV{'NIX_STORE'} = $Nix::Config::storeDir;
$ENV{$_} = $drv->{env}->{$_} foreach keys %{$drv->{env}};
$ENV{'IN_NIX_SHELL'} = 1;
# Run a shell using the derivation's environment. For
# convenience, source $stdenv/setup to setup additional
# environment variables. Also don't lose the current $PATH
# directories.
exec($ENV{SHELL}, "-c", $envCommand);
# environment variables and shell functions. Also don't lose
# the current $PATH directories.
my $rcfile = "$tmpDir/rc";
writeFile(
$rcfile,
'[ -e ~/.bashrc ] && source ~/.bashrc; ' .
($pure ? '' : 'p=$PATH; ' ) .
'dontAddDisableDepTrack=1; ' .
'[ -e $stdenv/setup ] && source $stdenv/setup; ' .
($pure ? '' : 'PATH=$PATH:$p; ') .
'set +e; ' .
'PS1="\n\[\033[1;32m\][nix-shell:\w]$\[\033[0m\] "; ' .
'unset NIX_ENFORCE_PURITY; ' .
$envCommand);
exec($ENV{NIX_BUILD_SHELL} // "bash", "--rcfile", $rcfile);
die;
}
@@ -206,7 +240,7 @@ foreach my $expr (@exprs) {
# Build.
my @outPaths;
$pid = open(OUTPATHS, "-|") || exec "$Nix::Config::binDir/nix-store", "--add-root", $outLink, "--indirect", "-r",
my $pid = open(OUTPATHS, "-|") || exec "$Nix::Config::binDir/nix-store", "--add-root", $outLink, "--indirect", "-r",
@buildArgs, @drvPaths2;
while (<OUTPATHS>) {chomp; push @outPaths, $_;}
if (!close OUTPATHS) {
+3 -1
View File
@@ -34,6 +34,8 @@ for (my $n = 0; $n < scalar @ARGV; $n++) {
exec "man nix-push" or die;
} elsif ($arg eq "--bzip2") {
$compressionType = "bzip2";
} elsif ($arg eq "--none") {
$compressionType = "none";
} elsif ($arg eq "--force") {
$force = 1;
} elsif ($arg eq "--dest") {
@@ -202,7 +204,7 @@ for (my $n = 0; $n < scalar @storePaths2; $n++) {
$compressedHash =~ /^[0-9a-z]+$/ or die "invalid hash";
close HASH;
my $narName = "$compressedHash.nar." . ($compressionType eq "xz" ? "xz" : "bz2");
my $narName = "$compressedHash.nar" . ($compressionType eq "xz" ? ".xz" : $compressionType eq "bzip2" ? ".bz2" : "");
my $narFile = "$narDir/$narName";
(-f $narFile) or die "NAR file for $storePath not found";
+19 -18
View File
@@ -6,9 +6,8 @@
namespace nix {
// !!! Shouldn't we return a pointer to a Value?
void findAlongAttrPath(EvalState & state, const string & attrPath,
Bindings & autoArgs, Expr * e, Value & v)
Value * findAlongAttrPath(EvalState & state, const string & attrPath,
Bindings & autoArgs, Value & vIn)
{
Strings tokens = tokenizeString<Strings>(attrPath, ".");
@@ -17,7 +16,7 @@ void findAlongAttrPath(EvalState & state, const string & attrPath,
string curPath;
state.mkThunk_(v, e);
Value * v = &vIn;
foreach (Strings::iterator, i, tokens) {
@@ -27,14 +26,14 @@ void findAlongAttrPath(EvalState & state, const string & attrPath,
/* Is *i an index (integer) or a normal attribute name? */
enum { apAttr, apIndex } apType = apAttr;
string attr = *i;
int attrIndex = -1;
unsigned int attrIndex;
if (string2Int(attr, attrIndex)) apType = apIndex;
/* Evaluate the expression. */
Value vTmp;
state.autoCallFunction(autoArgs, v, vTmp);
v = vTmp;
state.forceValue(v);
Value * vNew = state.allocValue();
state.autoCallFunction(autoArgs, *v, *vNew);
v = vNew;
state.forceValue(*v);
/* It should evaluate to either an attribute set or an
expression, according to what is specified in the
@@ -42,31 +41,33 @@ void findAlongAttrPath(EvalState & state, const string & attrPath,
if (apType == apAttr) {
if (v.type != tAttrs)
if (v->type != tAttrs)
throw TypeError(
format("the expression selected by the selection path `%1%' should be an attribute set but is %2%")
% curPath % showType(v));
% curPath % showType(*v));
Bindings::iterator a = v.attrs->find(state.symbols.create(attr));
if (a == v.attrs->end())
Bindings::iterator a = v->attrs->find(state.symbols.create(attr));
if (a == v->attrs->end())
throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath);
v = *a->value;
v = &*a->value;
}
else if (apType == apIndex) {
if (v.type != tList)
if (v->type != tList)
throw TypeError(
format("the expression selected by the selection path `%1%' should be a list but is %2%")
% curPath % showType(v));
% curPath % showType(*v));
if (attrIndex >= v.list.length)
if (attrIndex >= v->list.length)
throw Error(format("list index %1% in selection path `%2%' is out of range") % attrIndex % curPath);
v = *v.list.elems[attrIndex];
v = v->list.elems[attrIndex];
}
}
return v;
}
+2 -2
View File
@@ -7,7 +7,7 @@
namespace nix {
void findAlongAttrPath(EvalState & state, const string & attrPath,
Bindings & autoArgs, Expr * e, Value & v);
Value * findAlongAttrPath(EvalState & state, const string & attrPath,
Bindings & autoArgs, Value & vIn);
}
+91 -64
View File
@@ -141,10 +141,10 @@ EvalState::EvalState()
, sOutputs(symbols.create("outputs"))
, sOutputName(symbols.create("outputName"))
, sIgnoreNulls(symbols.create("__ignoreNulls"))
, baseEnv(allocEnv(128))
, baseEnvDispl(0)
, staticBaseEnv(false, 0)
, repair(false)
, baseEnv(allocEnv(128))
, staticBaseEnv(false, 0)
, baseEnvDispl(0)
{
nrEnvs = nrValuesInEnvs = nrValues = nrListElems = 0;
nrAttrsets = nrOpUpdates = nrOpUpdateValuesCopied = 0;
@@ -158,7 +158,7 @@ EvalState::EvalState()
physical RAM, up to a maximum of 384 MiB) so that in most
cases we don't need to garbage collect at all. (Collection
has a fairly significant overhead.) The heap size can be
overriden through libgc's GC_INITIAL_HEAP_SIZE environment
overridden through libgc's GC_INITIAL_HEAP_SIZE environment
variable. We should probably also provide a nix.conf
setting for this. Note that GC_expand_hp() causes a lot of
virtual, but not physical (resident) memory to be
@@ -222,6 +222,12 @@ void EvalState::addPrimOp(const string & name,
}
void EvalState::getBuiltin(const string & name, Value & v)
{
v = *baseEnv.values[0]->attrs->find(symbols.create(name))->value;
}
/* Every "format" object (even temporary) takes up a few hundred bytes
of stack space, which is a real killer in the recursive
evaluator. So here are some helper functions for throwing
@@ -247,6 +253,11 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s, const Pos & pos, const
throw TypeError(format(s) % pos % s2);
}
LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s1, const string & s2))
{
throw TypeError(format(s) % s1 % s2);
}
LocalNoInlineNoReturn(void throwTypeError(const char * s, const Pos & pos))
{
throw TypeError(format(s) % pos);
@@ -299,23 +310,29 @@ void mkPath(Value & v, const char * s)
}
inline Value * EvalState::lookupVar(Env * env, const VarRef & var)
inline Value * EvalState::lookupVar(Env * env, const VarRef & var, bool noEval)
{
for (unsigned int l = var.level; l; --l, env = env->up) ;
if (var.fromWith) {
if (!var.fromWith) return env->values[var.displ];
while (1) {
if (!env->haveWithAttrs) {
if (noEval) return 0;
Expr * attrs = (Expr *) env->values[0];
env->values[0] = allocValue();
evalAttrs(*env->up, attrs, *env->values[0]);
env->haveWithAttrs = true;
}
Bindings::iterator j = env->values[0]->attrs->find(var.name);
if (j != env->values[0]->attrs->end()) {
if (countCalls && j->pos) attrSelects[*j->pos]++;
return j->value;
}
if (env->prevWith == 0)
if (!env->prevWith)
throwEvalError("undefined variable `%1%'", var.name);
for (unsigned int l = env->prevWith; l; --l, env = env->up) ;
}
} else
return env->values[var.displ];
}
@@ -332,7 +349,7 @@ Env & EvalState::allocEnv(unsigned int size)
nrValuesInEnvs += size;
Env * env = (Env *) GC_MALLOC(sizeof(Env) + size * sizeof(Value *));
/* Clear the values because maybeThunk() expects this. */
/* Clear the values because maybeThunk() and lookupVar fromWith expects this. */
for (unsigned i = 0; i < size; ++i)
env->values[i] = 0;
@@ -400,7 +417,7 @@ unsigned long nrAvoided = 0;
Value * ExprVar::maybeThunk(EvalState & state, Env & env)
{
Value * v = state.lookupVar(&env, info);
Value * v = state.lookupVar(&env, info, true);
/* The value might not be initialised in the environment yet.
In that case, ignore it. */
if (v) { nrAvoided++; return v; }
@@ -429,19 +446,30 @@ Value * ExprPath::maybeThunk(EvalState & state, Env & env)
void EvalState::evalFile(const Path & path, Value & v)
{
FileEvalCache::iterator i = fileEvalCache.find(path);
if (i == fileEvalCache.end()) {
startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path);
Expr * e = parseExprFromFile(path);
Path path2 = resolveExprPath(path);
FileEvalCache::iterator i = fileEvalCache.find(path2);
if (i != fileEvalCache.end()) {
v = i->second;
return;
}
startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path2);
Expr * e = parseExprFromFile(path2);
try {
eval(e, v);
} catch (Error & e) {
addErrorPrefix(e, "while evaluating the file `%1%':\n", path);
addErrorPrefix(e, "while evaluating the file `%1%':\n", path2);
throw;
}
fileEvalCache[path] = v;
} else
v = i->second;
fileEvalCache[path2] = v;
//if (path != path2) fileEvalCache[path2] = v;
}
void EvalState::resetFileCache()
{
fileEvalCache.clear();
}
@@ -510,19 +538,13 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
environment, while the inherited attributes are evaluated
in the original environment. */
unsigned int displ = 0;
foreach (AttrDefs::iterator, i, attrs)
if (i->second.inherited) {
/* !!! handle overrides? */
Value * vAttr = state.lookupVar(&env, i->second.var);
env2.values[displ++] = vAttr;
v.attrs->push_back(Attr(i->first, vAttr, &i->second.pos));
} else {
foreach (AttrDefs::iterator, i, attrs) {
Value * vAttr;
if (hasOverrides) {
if (hasOverrides && !i->second.inherited) {
vAttr = state.allocValue();
mkThunk(*vAttr, env2, i->second.e);
} else
vAttr = i->second.e->maybeThunk(state, env2);
vAttr = i->second.e->maybeThunk(state, i->second.inherited ? env : env2);
env2.values[displ++] = vAttr;
v.attrs->push_back(Attr(i->first, vAttr, &i->second.pos));
}
@@ -552,9 +574,6 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
else {
foreach (AttrDefs::iterator, i, attrs)
if (i->second.inherited)
v.attrs->push_back(Attr(i->first, state.lookupVar(&env, i->second.var), &i->second.pos));
else
v.attrs->push_back(Attr(i->first, i->second.e->maybeThunk(state, env), &i->second.pos));
}
}
@@ -572,10 +591,7 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v)
environment. */
unsigned int displ = 0;
foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs)
if (i->second.inherited)
env2.values[displ++] = state.lookupVar(&env, i->second.var);
else
env2.values[displ++] = i->second.e->maybeThunk(state, env2);
env2.values[displ++] = i->second.e->maybeThunk(state, i->second.inherited ? env : env2);
body->eval(state, env2, v);
}
@@ -591,7 +607,7 @@ void ExprList::eval(EvalState & state, Env & env, Value & v)
void ExprVar::eval(EvalState & state, Env & env, Value & v)
{
Value * v2 = state.lookupVar(&env, info);
Value * v2 = state.lookupVar(&env, info, false);
state.forceValue(*v2);
v = *v2;
}
@@ -755,8 +771,8 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) {
Bindings::iterator j = arg.attrs->find(i->name);
if (j == arg.attrs->end()) {
if (!i->def) throwTypeError("function at %1% called without required argument `%2%'",
fun.lambda.fun->pos, i->name);
if (!i->def) throwTypeError("%1% called without required argument `%2%'",
fun.lambda.fun->showNamePos(), i->name);
env2.values[displ++] = i->def->maybeThunk(*this, env2);
} else {
attrsUsed++;
@@ -765,20 +781,24 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
}
/* Check that each actual argument is listed as a formal
argument (unless the attribute match specifies a `...').
TODO: show the names of the expected/unexpected
arguments. */
if (!fun.lambda.fun->formals->ellipsis && attrsUsed != arg.attrs->size())
throwTypeError("function at %1% called with unexpected argument", fun.lambda.fun->pos);
argument (unless the attribute match specifies a `...'). */
if (!fun.lambda.fun->formals->ellipsis && attrsUsed != arg.attrs->size()) {
/* Nope, so show the first unexpected argument to the
user. */
foreach (Bindings::iterator, i, *arg.attrs)
if (fun.lambda.fun->formals->argNames.find(i->name) == fun.lambda.fun->formals->argNames.end())
throwTypeError("%1% called with unexpected argument `%2%'", fun.lambda.fun->showNamePos(), i->name);
abort(); // can't happen
}
}
nrFunctionCalls++;
if (countCalls) functionCalls[fun.lambda.fun->pos]++;
if (countCalls) functionCalls[fun.lambda.fun]++;
try {
fun.lambda.fun->body->eval(*this, env2, v);
} catch (Error & e) {
addErrorPrefix(e, "while evaluating the function at %1%:\n", fun.lambda.fun->pos);
addErrorPrefix(e, "while evaluating %1%:\n", fun.lambda.fun->showNamePos());
throw;
}
}
@@ -815,9 +835,8 @@ void ExprWith::eval(EvalState & state, Env & env, Value & v)
Env & env2(state.allocEnv(1));
env2.up = &env;
env2.prevWith = prevWith;
env2.values[0] = state.allocValue();
state.evalAttrs(env, attrs, *env2.values[0]);
env2.haveWithAttrs = false;
env2.values[0] = (Value *) attrs;
body->eval(state, env2, v);
}
@@ -954,31 +973,39 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
{
PathSet context;
std::ostringstream s;
NixInt n = 0;
bool first = true, isPath = false;
Value vStr;
bool first = true;
ValueType firstType;
foreach (vector<Expr *>::iterator, i, *es) {
(*i)->eval(state, env, vStr);
Value vTmp;
(*i)->eval(state, env, vTmp);
/* If the first element is a path, then the result will also
be a path, we don't copy anything (yet - that's done later,
since paths are copied when they are used in a derivation),
and none of the strings are allowed to have contexts. */
if (first) {
isPath = !forceString && vStr.type == tPath;
firstType = vTmp.type;
first = false;
}
s << state.coerceToString(vStr, context, false, !isPath);
if (firstType == tInt && !forceString) {
if (vTmp.type != tInt)
throwEvalError("cannot add %1% to an integer", showType(vTmp));
n += vTmp.integer;
} else
s << state.coerceToString(vTmp, context, false, firstType != tPath);
}
if (isPath && !context.empty())
if (firstType == tInt)
mkInt(v, n);
else if (firstType == tPath) {
if (!context.empty())
throwEvalError("a string that refers to a store path cannot be appended to a path, in `%1%'", s.str());
if (isPath)
mkPath(v, s.str().c_str());
else
} else
mkString(v, s.str(), context);
}
@@ -999,7 +1026,7 @@ void EvalState::strictForceValue(Value & v)
}
int EvalState::forceInt(Value & v)
NixInt EvalState::forceInt(Value & v)
{
forceValue(v);
if (v.type != tInt)
@@ -1261,23 +1288,23 @@ void EvalState::printStats()
printMsg(v, format("calls to %1% primops:") % primOpCalls.size());
typedef std::multimap<unsigned int, Symbol> PrimOpCalls_;
std::multimap<unsigned int, Symbol> primOpCalls_;
PrimOpCalls_ primOpCalls_;
foreach (PrimOpCalls::iterator, i, primOpCalls)
primOpCalls_.insert(std::pair<unsigned int, Symbol>(i->second, i->first));
foreach_reverse (PrimOpCalls_::reverse_iterator, i, primOpCalls_)
printMsg(v, format("%1$10d %2%") % i->first % i->second);
printMsg(v, format("calls to %1% functions:") % functionCalls.size());
typedef std::multimap<unsigned int, Pos> FunctionCalls_;
std::multimap<unsigned int, Pos> functionCalls_;
typedef std::multimap<unsigned int, ExprLambda *> FunctionCalls_;
FunctionCalls_ functionCalls_;
foreach (FunctionCalls::iterator, i, functionCalls)
functionCalls_.insert(std::pair<unsigned int, Pos>(i->second, i->first));
functionCalls_.insert(std::pair<unsigned int, ExprLambda *>(i->second, i->first));
foreach_reverse (FunctionCalls_::reverse_iterator, i, functionCalls_)
printMsg(v, format("%1$10d %2%") % i->first % i->second);
printMsg(v, format("%1$10d %2%") % i->first % i->second->showNamePos());
printMsg(v, format("evaluations of %1% attributes:") % attrSelects.size());
typedef std::multimap<unsigned int, Pos> AttrSelects_;
std::multimap<unsigned int, Pos> attrSelects_;
AttrSelects_ attrSelects_;
foreach (AttrSelects::iterator, i, attrSelects)
attrSelects_.insert(std::pair<unsigned int, Pos>(i->second, i->first));
foreach_reverse (AttrSelects_::reverse_iterator, i, attrSelects_)
+26 -18
View File
@@ -52,7 +52,8 @@ struct PrimOp
struct Env
{
Env * up;
unsigned int prevWith; // nr of levels up to next `with' environment
unsigned short prevWith; // nr of levels up to next `with' environment
bool haveWithAttrs;
Value * values[0];
};
@@ -102,9 +103,6 @@ public:
private:
SrcToStore srcToStore;
/* A cache from path names to parse trees. */
std::map<Path, Expr *> parseTrees;
/* A cache from path names to values. */
#if HAVE_BOEHMGC
typedef std::map<Path, Value, std::less<Path>, gc_allocator<std::pair<const Path, Value> > > FileEvalCache;
@@ -124,17 +122,19 @@ public:
void addToSearchPath(const string & s);
/* Parse a Nix expression from the specified file. If `path'
refers to a directory, then "/default.nix" is appended. */
Expr * parseExprFromFile(Path path);
/* Parse a Nix expression from the specified file. */
Expr * parseExprFromFile(const Path & path);
/* Parse a Nix expression from the specified string. */
Expr * parseExprFromString(const string & s, const Path & basePath, StaticEnv & staticEnv);
Expr * parseExprFromString(const string & s, const Path & basePath);
/* Evaluate an expression read from the given file to normal
form. */
void evalFile(const Path & path, Value & v);
void resetFileCache();
/* Look up a file in the search path. */
Path findFile(const string & path);
@@ -158,7 +158,7 @@ public:
void strictForceValue(Value & v);
/* Force `v', and then verify that it has the expected type. */
int forceInt(Value & v);
NixInt forceInt(Value & v);
bool forceBool(Value & v);
inline void forceAttrs(Value & v);
inline void forceList(Value & v);
@@ -174,7 +174,7 @@ public:
/* String coercion. Converts strings, paths and derivations to a
string. If `coerceMore' is set, also converts nulls, integers,
booleans and lists to a string. If `copyToStore' is set,
referenced paths are copied to the Nix store as a side effect.q */
referenced paths are copied to the Nix store as a side effect. */
string coerceToString(Value & v, PathSet & context,
bool coerceMore = false, bool copyToStore = true);
@@ -183,21 +183,19 @@ public:
path. Nothing is copied to the store. */
Path coerceToPath(Value & v, PathSet & context);
private:
public:
/* The base environment, containing the builtin functions and
values. */
Env & baseEnv;
unsigned int baseEnvDispl;
public:
/* The same, but used during parsing to resolve variables. */
StaticEnv staticBaseEnv; // !!! should be private
private:
unsigned int baseEnvDispl;
void createBaseEnv();
void addConstant(const string & name, Value & v);
@@ -205,14 +203,20 @@ private:
void addPrimOp(const string & name,
unsigned int arity, PrimOpFun primOp);
inline Value * lookupVar(Env * env, const VarRef & var);
public:
void getBuiltin(const string & name, Value & v);
private:
inline Value * lookupVar(Env * env, const VarRef & var, bool noEval);
friend class ExprVar;
friend class ExprAttrs;
friend class ExprLet;
Expr * parse(const char * text,
const Path & path, const Path & basePath);
Expr * parse(const char * text, const Path & path,
const Path & basePath, StaticEnv & staticEnv);
public:
@@ -259,7 +263,7 @@ private:
typedef std::map<Symbol, unsigned int> PrimOpCalls;
PrimOpCalls primOpCalls;
typedef std::map<Pos, unsigned int> FunctionCalls;
typedef std::map<ExprLambda *, unsigned int> FunctionCalls;
FunctionCalls functionCalls;
typedef std::map<Pos, unsigned int> AttrSelects;
@@ -276,4 +280,8 @@ private:
string showType(const Value & v);
/* If `path' refers to a directory, then append "/default.nix". */
Path resolveExprPath(Path path);
}
+6 -2
View File
@@ -101,6 +101,8 @@ or { return OR_KW; }
\=\= { return EQ; }
\!\= { return NEQ; }
\<\= { return LEQ; }
\>\= { return GEQ; }
\&\& { return AND; }
\|\| { return OR; }
\-\> { return IMPL; }
@@ -108,8 +110,10 @@ or { return OR_KW; }
\+\+ { return CONCAT; }
{ID} { yylval->id = strdup(yytext); return ID; }
{INT} { int n = atoi(yytext); /* !!! overflow */
yylval->n = n;
{INT} { errno = 0;
yylval->n = strtol(yytext, 0, 10);
if (errno != 0)
throw ParseError(format("invalid integer `%1%'") % yytext);
return INT;
}
+1 -2
View File
@@ -95,8 +95,7 @@ int compareVersions(const string & v1, const string & v2)
DrvNames drvNamesFromArgs(const Strings & opArgs)
{
DrvNames result;
for (Strings::const_iterator i = opArgs.begin();
i != opArgs.end(); ++i)
foreach (Strings::const_iterator, i, opArgs)
result.push_back(DrvName(*i));
return result;
}
+23 -6
View File
@@ -230,14 +230,12 @@ void ExprAttrs::bindVars(const StaticEnv & env)
newEnv.vars[i->first] = i->second.displ = displ++;
foreach (AttrDefs::iterator, i, attrs)
if (i->second.inherited) i->second.var.bind(env);
else i->second.e->bindVars(newEnv);
i->second.e->bindVars(i->second.inherited ? env : newEnv);
}
else
foreach (AttrDefs::iterator, i, attrs)
if (i->second.inherited) i->second.var.bind(env);
else i->second.e->bindVars(env);
i->second.e->bindVars(env);
}
void ExprList::bindVars(const StaticEnv & env)
@@ -274,8 +272,7 @@ void ExprLet::bindVars(const StaticEnv & env)
newEnv.vars[i->first] = i->second.displ = displ++;
foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs)
if (i->second.inherited) i->second.var.bind(env);
else i->second.e->bindVars(newEnv);
i->second.e->bindVars(i->second.inherited ? env : newEnv);
body->bindVars(newEnv);
}
@@ -324,4 +321,24 @@ void ExprConcatStrings::bindVars(const StaticEnv & env)
}
/* Storing function names. */
void Expr::setName(Symbol & name)
{
}
void ExprLambda::setName(Symbol & name)
{
this->name = name;
body->setName(name);
}
string ExprLambda::showNamePos()
{
return (format("%1% at %2%") % (name.set() ? "`" + (string) name + "'" : "an anonymous function") % pos).str();
}
}
+8 -6
View File
@@ -63,6 +63,7 @@ struct Expr
virtual void bindVars(const StaticEnv & env);
virtual void eval(EvalState & state, Env & env, Value & v);
virtual Value * maybeThunk(EvalState & state, Env & env);
virtual void setName(Symbol & name);
};
std::ostream & operator << (std::ostream & str, Expr & e);
@@ -74,9 +75,9 @@ std::ostream & operator << (std::ostream & str, Expr & e);
struct ExprInt : Expr
{
int n;
NixInt n;
Value v;
ExprInt(int n) : n(n) { mkInt(v, n); };
ExprInt(NixInt n) : n(n) { mkInt(v, n); };
COMMON_METHODS
Value * maybeThunk(EvalState & state, Env & env);
};
@@ -158,12 +159,10 @@ struct ExprAttrs : Expr
bool recursive;
struct AttrDef {
bool inherited;
Expr * e; // if not inherited
VarRef var; // if inherited
Expr * e;
Pos pos;
unsigned int displ; // displacement
AttrDef(Expr * e, const Pos & pos) : inherited(false), e(e), pos(pos) { };
AttrDef(const Symbol & name, const Pos & pos) : inherited(true), var(name), pos(pos) { };
AttrDef(Expr * e, const Pos & pos, bool inherited=false) : inherited(inherited), e(e), pos(pos) { };
AttrDef() { };
};
typedef std::map<Symbol, AttrDef> AttrDefs;
@@ -197,6 +196,7 @@ struct Formals
struct ExprLambda : Expr
{
Pos pos;
Symbol name;
Symbol arg;
bool matchAttrs;
Formals * formals;
@@ -208,6 +208,8 @@ struct ExprLambda : Expr
throw ParseError(format("duplicate formal function argument `%1%' at %2%")
% arg % pos);
};
void setName(Symbol & name);
string showNamePos();
COMMON_METHODS
};
+33 -17
View File
@@ -104,6 +104,7 @@ static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
}
}
}
e->setName(attrPath.back());
}
@@ -237,7 +238,7 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
nix::ExprAttrs * attrs;
nix::Formals * formals;
nix::Formal * formal;
int n;
nix::NixInt n;
char * id; // !!! -> Symbol
char * path;
char * uri;
@@ -268,12 +269,15 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
%left OR
%left AND
%nonassoc EQ NEQ
%left '<' '>' LEQ GEQ
%right UPDATE
%left NEG
%left '+'
%left NOT
%left '+' '-'
%left '*' '/'
%right CONCAT
%nonassoc '?'
%nonassoc '~'
%nonassoc NEGATE
%%
@@ -305,9 +309,14 @@ expr_if
;
expr_op
: '!' expr_op %prec NEG { $$ = new ExprOpNot($2); }
: '!' expr_op %prec NOT { $$ = new ExprOpNot($2); }
| '-' expr_op %prec NEGATE { $$ = new ExprApp(new ExprApp(new ExprVar(data->symbols.create("__sub")), new ExprInt(0)), $2); }
| expr_op EQ expr_op { $$ = new ExprOpEq($1, $3); }
| expr_op NEQ expr_op { $$ = new ExprOpNEq($1, $3); }
| expr_op '<' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(data->symbols.create("__lessThan")), $1), $3); }
| expr_op LEQ expr_op { $$ = new ExprOpNot(new ExprApp(new ExprApp(new ExprVar(data->symbols.create("__lessThan")), $3), $1)); }
| expr_op '>' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(data->symbols.create("__lessThan")), $3), $1); }
| expr_op GEQ expr_op { $$ = new ExprOpNot(new ExprApp(new ExprApp(new ExprVar(data->symbols.create("__lessThan")), $1), $3)); }
| expr_op AND expr_op { $$ = new ExprOpAnd($1, $3); }
| expr_op OR expr_op { $$ = new ExprOpOr($1, $3); }
| expr_op IMPL expr_op { $$ = new ExprOpImpl($1, $3); }
@@ -319,6 +328,9 @@ expr_op
l->push_back($3);
$$ = new ExprConcatStrings(false, l);
}
| expr_op '-' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(data->symbols.create("__sub")), $1), $3); }
| expr_op '*' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(data->symbols.create("__mul")), $1), $3); }
| expr_op '/' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(data->symbols.create("__div")), $1), $3); }
| expr_op CONCAT expr_op { $$ = new ExprOpConcatLists($1, $3); }
| expr_app
;
@@ -401,7 +413,7 @@ binds
if ($$->attrs.find(*i) != $$->attrs.end())
dupAttr(*i, makeCurPos(@3, data), $$->attrs[*i].pos);
Pos pos = makeCurPos(@3, data);
$$->attrs[*i] = ExprAttrs::AttrDef(*i, pos);
$$->attrs[*i] = ExprAttrs::AttrDef(new ExprVar(*i), pos, true);
}
}
| binds INHERIT '(' expr ')' attrs ';'
@@ -469,7 +481,7 @@ namespace nix {
Expr * EvalState::parse(const char * text,
const Path & path, const Path & basePath)
const Path & path, const Path & basePath, StaticEnv & staticEnv)
{
yyscan_t scanner;
ParseData data(*this);
@@ -484,7 +496,7 @@ Expr * EvalState::parse(const char * text,
if (res) throw ParseError(data.error);
try {
data.result->bindVars(staticBaseEnv);
data.result->bindVars(staticEnv);
} catch (Error & e) {
throw ParseError(format("%1%, in `%2%'") % e.msg() % path);
}
@@ -493,7 +505,7 @@ Expr * EvalState::parse(const char * text,
}
Expr * EvalState::parseExprFromFile(Path path)
Path resolveExprPath(Path path)
{
assert(path[0] == '/');
@@ -511,21 +523,25 @@ Expr * EvalState::parseExprFromFile(Path path)
if (S_ISDIR(st.st_mode))
path = canonPath(path + "/default.nix");
/* Read and parse the input file, unless it's already in the parse
tree cache. */
Expr * e = parseTrees[path];
if (!e) {
e = parse(readFile(path).c_str(), path, dirOf(path));
parseTrees[path] = e;
}
return path;
}
return e;
Expr * EvalState::parseExprFromFile(const Path & path)
{
return parse(readFile(path).c_str(), path, dirOf(path), staticBaseEnv);
}
Expr * EvalState::parseExprFromString(const string & s, const Path & basePath, StaticEnv & staticEnv)
{
return parse(s.c_str(), "(string)", basePath, staticEnv);
}
Expr * EvalState::parseExprFromString(const string & s, const Path & basePath)
{
return parse(s.c_str(), "(string)", basePath);
return parseExprFromString(s, basePath, staticBaseEnv);
}
+7 -5
View File
@@ -82,8 +82,7 @@ static void prim_import(EvalState & state, Value * * args, Value & v)
}
w.attrs->sort();
Value fun;
state.mkThunk_(fun,
state.parseExprFromFile(state.findFile("nix/imported-drv-to-derivation.nix")));
state.evalFile(state.findFile("nix/imported-drv-to-derivation.nix"), fun);
state.forceFunction(fun);
mkApp(v, fun, w);
state.forceAttrs(v);
@@ -1024,7 +1023,7 @@ static void prim_mul(EvalState & state, Value * * args, Value & v)
static void prim_div(EvalState & state, Value * * args, Value & v)
{
int i2 = state.forceInt(*args[1]);
NixInt i2 = state.forceInt(*args[1]);
if (i2 == 0) throw EvalError("division by zero");
mkInt(v, state.forceInt(*args[0]) / i2);
}
@@ -1032,7 +1031,10 @@ static void prim_div(EvalState & state, Value * * args, Value & v)
static void prim_lessThan(EvalState & state, Value * * args, Value & v)
{
mkBool(v, state.forceInt(*args[0]) < state.forceInt(*args[1]));
state.forceValue(*args[0]);
state.forceValue(*args[1]);
CompareValues comp;
mkBool(v, comp(*args[0], *args[1]));
}
@@ -1260,7 +1262,7 @@ void EvalState::createBaseEnv()
/* Add a wrapper around the derivation primop that computes the
`drvPath' and `outPath' attributes lazily. */
mkThunk_(v, parseExprFromFile(findFile("nix/derivation.nix")));
evalFile(findFile("nix/derivation.nix"), v);
addConstant("derivation", v);
/* Now that we've added all primops, sort the `builtins' attribute
+5
View File
@@ -49,6 +49,11 @@ public:
return *s;
}
bool set() const
{
return s;
}
bool empty() const
{
return s->empty();
+8 -5
View File
@@ -31,17 +31,20 @@ struct PrimOp;
struct Symbol;
typedef long NixInt;
struct Value
{
ValueType type;
union
{
int integer;
NixInt integer;
bool boolean;
/* Strings in the evaluator carry a so-called `context' (the
ATermList) which is a list of strings representing store
paths. This is to allow users to write things like
/* Strings in the evaluator carry a so-called `context' which
is a list of strings representing store paths. This is to
allow users to write things like
"--with-freetype2-library=" + freetype + "/lib"
@@ -97,7 +100,7 @@ static inline void clearValue(Value & v)
}
static inline void mkInt(Value & v, int n)
static inline void mkInt(Value & v, NixInt n)
{
clearValue(v);
v.type = tInt;
+1 -1
View File
@@ -1,6 +1,6 @@
pkglib_LTLIBRARIES = libmain.la
libmain_la_SOURCES = shared.cc
libmain_la_SOURCES = shared.cc stack.cc
libmain_la_LIBADD = ../libstore/libstore.la @BDW_GC_LIBS@
+7
View File
@@ -13,6 +13,7 @@
#include <sys/time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>
#if HAVE_BOEHMGC
#include <gc/gc.h>
@@ -100,6 +101,9 @@ string getArg(const string & opt,
}
void detectStackOverflow();
/* Initialize and reorder arguments, then call the actual argument
processor. */
static void initAndRun(int argc, char * * argv)
@@ -131,6 +135,9 @@ static void initAndRun(int argc, char * * argv)
if (sigaction(SIGCHLD, &act, 0))
throw SysError("resetting SIGCHLD");
/* Register a SIGSEGV handler to detect stack overflows. */
detectStackOverflow();
/* There is no privacy in the Nix system ;-) At least not for
now. In particular, store objects should be readable by
everybody. */
+72
View File
@@ -0,0 +1,72 @@
#include "config.h"
#include "types.hh"
#include <cstring>
#include <cstddef>
#include <cstdlib>
#include <unistd.h>
#include <signal.h>
namespace nix {
static void sigsegvHandler(int signo, siginfo_t * info, void * ctx)
{
/* Detect stack overflows by comparing the faulting address with
the stack pointer. Unfortunately, getting the stack pointer is
not portable. */
bool haveSP = true;
char * sp;
#if defined(__x86_64__) && defined(REG_RSP)
sp = (char *) ((ucontext *) ctx)->uc_mcontext.gregs[REG_RSP];
#elif defined(REG_ESP)
sp = (char *) ((ucontext *) ctx)->uc_mcontext.gregs[REG_ESP];
#else
haveSP = false;
#endif
if (haveSP) {
ptrdiff_t diff = (char *) info->si_addr - sp;
if (diff < 0) diff = -diff;
if (diff < 4096) {
char msg[] = "error: stack overflow (possible infinite recursion)\n";
write(2, msg, strlen(msg));
_exit(1); // maybe abort instead?
}
}
/* Restore default behaviour (i.e. segfault and dump core). */
struct sigaction act;
sigfillset(&act.sa_mask);
act.sa_handler = SIG_DFL;
act.sa_flags = 0;
if (sigaction(SIGSEGV, &act, 0)) abort();
}
void detectStackOverflow()
{
#if defined(SA_SIGINFO) && defined (SA_ONSTACK)
/* Install a SIGSEGV handler to detect stack overflows. This
requires an alternative stack, otherwise the signal cannot be
delivered when we're out of stack space. */
stack_t stack;
stack.ss_size = 4096 * 4 + MINSIGSTKSZ;
stack.ss_sp = new char[stack.ss_size];
if (!stack.ss_sp) throw Error("cannot allocate alternative stack");
stack.ss_flags = 0;
if (sigaltstack(&stack, 0) == -1) throw SysError("cannot set alternative stack");
struct sigaction act;
sigfillset(&act.sa_mask);
act.sa_sigaction = sigsegvHandler;
act.sa_flags = SA_SIGINFO | SA_ONSTACK;
if (sigaction(SIGSEGV, &act, 0))
throw SysError("resetting SIGCHLD");
#endif
}
}
+96 -29
View File
@@ -7,6 +7,7 @@
#include "local-store.hh"
#include "util.hh"
#include "archive.hh"
#include "affinity.hh"
#include <map>
#include <sstream>
@@ -20,6 +21,7 @@
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
@@ -366,6 +368,8 @@ void Goal::trace(const format & f)
/* Common initialisation performed in child processes. */
static void commonChildInit(Pipe & logPipe)
{
restoreAffinity();
/* Put the child in a separate session (and thus a separate
process group) so that it has no controlling terminal (meaning
that e.g. ssh cannot open /dev/tty) and it doesn't receive
@@ -568,6 +572,7 @@ static void runSetuidHelper(const string & command,
args.push_back(0);
restoreSIGPIPE();
restoreAffinity();
execve(program.c_str(), (char * *) &args[0], 0);
throw SysError(format("executing `%1%'") % program);
@@ -695,7 +700,9 @@ HookInstance::HookInstance()
throw SysError("dupping builder's stdout/stderr");
execl(buildHook.c_str(), buildHook.c_str(), settings.thisSystem.c_str(),
(format("%1%") % settings.maxSilentTime).str().c_str(),
(format("%1%") % settings.printBuildTrace).str().c_str(),
(format("%1%") % settings.buildTimeout).str().c_str(),
NULL);
throw SysError(format("executing `%1%'") % buildHook);
@@ -786,6 +793,12 @@ private:
/* Outputs that are already valid. */
PathSet validPaths;
/* Outputs that are corrupt or not valid. */
PathSet missingPaths;
/* Paths that have been subject to hash rewriting. */
PathSet rewrittenPaths;
/* User selected for running the builder. */
UserLock buildUser;
@@ -800,6 +813,9 @@ private:
BZFILE * bzLogFile;
AutoCloseFD fdLogFile;
/* Number of bytes received from the builder's stdout/stderr. */
unsigned long logSize;
/* Pipe for the builder's standard output/error. */
Pipe builderOut;
@@ -838,6 +854,11 @@ private:
bool repair;
map<Path, Path> redirectedBadOutputs;
/* Set of inodes seen during calls to canonicalisePathMetaData()
for this build's outputs. This needs to be shared between
outputs to allow hard links between outputs. */
InodesSeen inodesSeen;
/* Magic exit code denoting that setting up the child environment
failed. (It's possible that the child actually returns the
exit code, but ah well.) */
@@ -975,7 +996,7 @@ void DerivationGoal::killChild()
void DerivationGoal::cancel(bool timeout)
{
if (timeout)
if (settings.printBuildTrace && timeout)
printMsg(lvlError, format("@ build-failed %1% - timeout") % drvPath);
killChild();
amDone(ecFailed);
@@ -1061,7 +1082,7 @@ void DerivationGoal::haveDerivation()
/* We are first going to try to create the invalid output paths
through substitutes. If that doesn't work, we'll build
them. */
if (settings.useSubstitutes)
if (settings.useSubstitutes && !willBuildLocally(drv))
foreach (PathSet::iterator, i, invalidOutputs)
addWaitee(worker.makeSubstitutionGoal(*i, repair));
@@ -1252,6 +1273,13 @@ PathSet outputPaths(const DerivationOutputs & outputs)
}
static string get(const StringPairs & map, const string & key)
{
StringPairs::const_iterator i = map.find(key);
return i == map.end() ? (string) "" : i->second;
}
static bool canBuildLocally(const string & platform)
{
return platform == settings.thisSystem
@@ -1262,6 +1290,12 @@ static bool canBuildLocally(const string & platform)
}
bool willBuildLocally(const Derivation & drv)
{
return get(drv.env, "preferLocalBuild") == "1" && canBuildLocally(drv.platform);
}
void DerivationGoal::tryToBuild()
{
trace("trying to build");
@@ -1305,6 +1339,9 @@ void DerivationGoal::tryToBuild()
return;
}
missingPaths = outputPaths(drv.outputs);
foreach (PathSet::iterator, i, validPaths) missingPaths.erase(*i);
/* If any of the outputs already exist but are not valid, delete
them. */
foreach (DerivationOutputs::iterator, i, drv.outputs) {
@@ -1323,11 +1360,10 @@ void DerivationGoal::tryToBuild()
/* Don't do a remote build if the derivation has the attribute
`preferLocalBuild' set. */
bool preferLocalBuild =
drv.env["preferLocalBuild"] == "1" && canBuildLocally(drv.platform);
bool buildLocally = willBuildLocally(drv);
/* Is the build hook willing to accept this job? */
if (!preferLocalBuild) {
if (!buildLocally) {
switch (tryBuildHook()) {
case rpAccept:
/* Yes, it has started doing so. Wait until we get
@@ -1350,7 +1386,7 @@ void DerivationGoal::tryToBuild()
derivation prefers to be done locally, do it even if
maxBuildJobs is 0. */
unsigned int curBuilds = worker.getNrLocalBuilds();
if (curBuilds >= settings.maxBuildJobs && !(preferLocalBuild && curBuilds == 0)) {
if (curBuilds >= settings.maxBuildJobs && !(buildLocally && curBuilds == 0)) {
worker.waitForBuildSlot(shared_from_this());
outputLocks.unlock();
return;
@@ -1442,8 +1478,8 @@ void DerivationGoal::buildDone()
/* Some cleanup per path. We do this here and not in
computeClosure() for convenience when the build has
failed. */
foreach (DerivationOutputs::iterator, i, drv.outputs) {
Path path = i->second.path;
foreach (PathSet::iterator, i, missingPaths) {
Path path = *i;
/* If the output was already valid, just skip (discard) it. */
if (validPaths.find(path) != validPaths.end()) continue;
@@ -1480,6 +1516,12 @@ void DerivationGoal::buildDone()
/* Apply hash rewriting if necessary. */
if (!rewritesFromTmp.empty()) {
printMsg(lvlError, format("warning: rewriting hashes in `%1%'; cross fingers") % path);
/* Canonicalise first. This ensures that the path
we're rewriting doesn't contain a hard link to
/etc/shadow or something like that. */
canonicalisePathMetaData(path, buildUser.enabled() ? buildUser.getUID() : -1, inodesSeen);
/* FIXME: this is in-memory. */
StringSink sink;
dumpPath(path, sink);
@@ -1487,6 +1529,8 @@ void DerivationGoal::buildDone()
sink.s = rewriteHashes(sink.s, rewritesFromTmp);
StringSource source(sink.s);
restorePath(path, source);
rewrittenPaths.insert(path);
}
/* Gain ownership of the build result using the setuid
@@ -1565,9 +1609,8 @@ void DerivationGoal::buildDone()
/* Release the build user, if applicable. */
buildUser.release();
if (settings.printBuildTrace) {
if (settings.printBuildTrace)
printMsg(lvlError, format("@ build-succeeded %1% -") % drvPath);
}
amDone(ecSuccess);
}
@@ -1583,7 +1626,7 @@ HookReply DerivationGoal::tryBuildHook()
/* Tell the hook about system features (beyond the system type)
required from the build machine. (The hook could parse the
drv file itself, but this is easier.) */
Strings features = tokenizeString<Strings>(drv.env["requiredSystemFeatures"]);
Strings features = tokenizeString<Strings>(get(drv.env, "requiredSystemFeatures"));
foreach (Strings::iterator, i, features) checkStoreName(*i); /* !!! abuse */
/* Send the request to the hook. */
@@ -1645,7 +1688,7 @@ HookReply DerivationGoal::tryBuildHook()
set<int> fds;
fds.insert(hook->fromHook.readSide);
fds.insert(hook->builderOut.readSide);
worker.childStarted(shared_from_this(), hook->pid, fds, false, true);
worker.childStarted(shared_from_this(), hook->pid, fds, false, false);
if (settings.printBuildTrace)
printMsg(lvlError, format("@ build-started %1% - %2% %3%")
@@ -1671,9 +1714,7 @@ int childEntry(void * arg)
void DerivationGoal::startBuilder()
{
PathSet missing = outputPaths(drv.outputs);
foreach (PathSet::iterator, i, validPaths) missing.erase(*i);
startNest(nest, lvlInfo, format("building path(s) %1%") % showPaths(missing));
startNest(nest, lvlInfo, format(repair ? "repairing path(s) %1%" : "building path(s) %1%") % showPaths(missingPaths));
/* Right platform? */
if (!canBuildLocally(drv.platform))
@@ -1743,7 +1784,7 @@ void DerivationGoal::startBuilder()
fixed-output derivations is by definition pure (since we
already know the cryptographic hash of the output). */
if (fixedOutput) {
Strings varNames = tokenizeString<Strings>(drv.env["impureEnvVars"]);
Strings varNames = tokenizeString<Strings>(get(drv.env, "impureEnvVars"));
foreach (Strings::iterator, i, varNames) env[*i] = getEnv(*i);
}
@@ -1754,7 +1795,7 @@ void DerivationGoal::startBuilder()
temporary build directory. The text files have the format used
by `nix-store --register-validity'. However, the deriver
fields are left empty. */
string s = drv.env["exportReferencesGraph"];
string s = get(drv.env, "exportReferencesGraph");
Strings ss = tokenizeString<Strings>(s);
if (ss.size() % 2 != 0)
throw BuildError(format("odd number of tokens in `exportReferencesGraph': `%1%'") % s);
@@ -1840,7 +1881,7 @@ void DerivationGoal::startBuilder()
if (fixedOutput) useChroot = false;
/* Hack to allow derivations to disable chroot builds. */
if (drv.env["__noChroot"] == "1") useChroot = false;
if (get(drv.env, "__noChroot") == "1") useChroot = false;
if (useChroot) {
#if CHROOT_ENABLED
@@ -1964,7 +2005,7 @@ void DerivationGoal::startBuilder()
/* If we're repairing, then we don't want to delete the
corrupt outputs in advance. So rewrite them as well. */
if (repair)
foreach (PathSet::iterator, i, missing)
foreach (PathSet::iterator, i, missingPaths)
if (worker.store.isValidPath(*i) && pathExists(*i))
redirectedBadOutputs[*i] = addHashRewrite(*i);
}
@@ -2085,11 +2126,19 @@ void DerivationGoal::initChild()
filesystem that we want in the chroot
environment. */
foreach (DirsInChroot::iterator, i, dirsInChroot) {
struct stat st;
Path source = i->second;
Path target = chrootRootDir + i->first;
if (source == "/proc") continue; // backwards compatibility
debug(format("bind mounting `%1%' to `%2%'") % source % target);
if (stat(source.c_str(), &st) == -1)
throw SysError(format("getting attributes of path `%1%'") % source);
if (S_ISDIR(st.st_mode))
createDirs(target);
else {
createDirs(dirOf(target));
writeFile(target, "");
}
if (mount(source.c_str(), target.c_str(), "", MS_BIND, 0) == -1)
throw SysError(format("bind mount from `%1%' to `%2%' failed") % source % target);
}
@@ -2127,7 +2176,11 @@ void DerivationGoal::initChild()
#ifdef CAN_DO_LINUX32_BUILDS
/* Change the personality to 32-bit if we're doing an
i686-linux build on an x86_64-linux machine. */
if (drv.platform == "i686-linux" && settings.thisSystem == "x86_64-linux") {
struct utsname utsbuf;
uname(&utsbuf);
if (drv.platform == "i686-linux" &&
(settings.thisSystem == "x86_64-linux" ||
(!strcmp(utsbuf.sysname, "Linux") && !strcmp(utsbuf.machine, "x86_64")))) {
if (personality(0x0008 | 0x8000000 /* == PER_LINUX32_3GB */) == -1)
throw SysError("cannot set i686-linux personality");
}
@@ -2249,6 +2302,8 @@ void DerivationGoal::computeClosure()
output paths read-only. */
foreach (DerivationOutputs::iterator, i, drv.outputs) {
Path path = i->second.path;
if (missingPaths.find(path) == missingPaths.end()) continue;
if (!pathExists(path)) {
throw BuildError(
format("builder for `%1%' failed to produce output path `%2%'")
@@ -2287,8 +2342,10 @@ void DerivationGoal::computeClosure()
% path % i->second.hashAlgo % printHash16or32(h) % printHash16or32(h2));
}
/* Get rid of all weird permissions. */
canonicalisePathMetaData(path, buildUser.enabled() ? buildUser.getUID() : -1);
/* Get rid of all weird permissions. This also checks that
all files are owned by the build user, if applicable. */
canonicalisePathMetaData(path,
buildUser.enabled() && rewrittenPaths.find(path) == rewrittenPaths.end() ? buildUser.getUID() : -1, inodesSeen);
/* For this output path, find the references to other paths
contained in it. Compute the SHA-256 NAR hash at the same
@@ -2315,7 +2372,7 @@ void DerivationGoal::computeClosure()
refer to), check that all references are in that list. !!!
allowedReferences should really be per-output. */
if (drv.env.find("allowedReferences") != drv.env.end()) {
PathSet allowed = parseReferenceSpecifiers(drv, drv.env["allowedReferences"]);
PathSet allowed = parseReferenceSpecifiers(drv, get(drv.env, "allowedReferences"));
foreach (PathSet::iterator, i, references)
if (allowed.find(*i) == allowed.end())
throw BuildError(format("output is not allowed to refer to path `%1%'") % *i);
@@ -2330,12 +2387,12 @@ void DerivationGoal::computeClosure()
paths referenced by each of them. If there are cycles in the
outputs, this will fail. */
ValidPathInfos infos;
foreach (DerivationOutputs::iterator, i, drv.outputs) {
foreach (PathSet::iterator, i, missingPaths) {
ValidPathInfo info;
info.path = i->second.path;
info.hash = contentHashes[i->second.path].first;
info.narSize = contentHashes[i->second.path].second;
info.references = allReferences[i->second.path];
info.path = *i;
info.hash = contentHashes[*i].first;
info.narSize = contentHashes[*i].second;
info.references = allReferences[*i];
info.deriver = drvPath;
infos.push_back(info);
}
@@ -2348,6 +2405,8 @@ string drvsLogDir = "drvs";
Path DerivationGoal::openLogFile()
{
logSize = 0;
if (!settings.keepLog) return "";
string baseName = baseNameOf(drvPath);
@@ -2423,6 +2482,14 @@ void DerivationGoal::handleChildOutput(int fd, const string & data)
if ((hook && fd == hook->builderOut.readSide) ||
(!hook && fd == builderOut.readSide))
{
logSize += data.size();
if (settings.maxLogSize && logSize > settings.maxLogSize) {
printMsg(lvlError,
format("%1% killed after writing more than %2% bytes of log output")
% getName() % settings.maxLogSize);
cancel(true); // not really a timeout, but close enough
return;
}
if (verbosity >= settings.buildVerbosity)
writeToStderr(data);
if (bzLogFile) {
@@ -2581,7 +2648,7 @@ SubstitutionGoal::~SubstitutionGoal()
void SubstitutionGoal::cancel(bool timeout)
{
if (timeout)
if (settings.printBuildTrace && timeout)
printMsg(lvlError, format("@ substituter-failed %1% timeout") % storePath);
if (pid != -1) {
pid_t savedPid = pid;
+42 -44
View File
@@ -258,8 +258,7 @@ static void readTempRoots(PathSet & tempRoots, FDs & fds)
only succeed if the owning process has died. In that case
we don't care about its temporary roots. */
if (lockFile(*fd, ltWrite, false)) {
printMsg(lvlError, format("removing stale temporary roots file `%1%'")
% path);
printMsg(lvlError, format("removing stale temporary roots file `%1%'") % path);
unlink(path.c_str());
writeFull(*fd, (const unsigned char *) "d", 1);
continue;
@@ -290,47 +289,48 @@ static void readTempRoots(PathSet & tempRoots, FDs & fds)
}
static void findRoots(StoreAPI & store, const Path & path,
bool recurseSymlinks, bool deleteStale, Roots & roots)
static void foundRoot(StoreAPI & store,
const Path & path, const Path & target, Roots & roots)
{
try {
struct stat st;
if (lstat(path.c_str(), &st) == -1)
throw SysError(format("statting `%1%'") % path);
printMsg(lvlVomit, format("looking at `%1%'") % path);
if (S_ISDIR(st.st_mode)) {
Strings names = readDirectory(path);
foreach (Strings::iterator, i, names)
findRoots(store, path + "/" + *i, recurseSymlinks, deleteStale, roots);
}
else if (S_ISLNK(st.st_mode)) {
Path target = absPath(readLink(path), dirOf(path));
if (isInStore(target)) {
debug(format("found root `%1%' in `%2%'")
% target % path);
Path storePath = toStorePath(target);
if (store.isValidPath(storePath))
roots[path] = storePath;
else
printMsg(lvlInfo, format("skipping invalid root from `%1%' to `%2%'")
% path % storePath);
printMsg(lvlInfo, format("skipping invalid root from `%1%' to `%2%'") % path % storePath);
}
static void findRoots(StoreAPI & store, const Path & path, Roots & roots)
{
try {
struct stat st = lstat(path);
if (S_ISDIR(st.st_mode)) {
Strings names = readDirectory(path);
foreach (Strings::iterator, i, names)
findRoots(store, path + "/" + *i, roots);
}
else if (recurseSymlinks) {
if (pathExists(target))
findRoots(store, target, false, deleteStale, roots);
else if (deleteStale) {
else if (S_ISLNK(st.st_mode)) {
Path target = readLink(path);
if (isInStore(target))
foundRoot(store, path, target, roots);
/* Handle indirect roots. */
else {
target = absPath(target, dirOf(path));
if (!pathExists(target)) {
if (isInDir(path, settings.nixStateDir + "/" + gcRootsDir + "/auto")) {
printMsg(lvlInfo, format("removing stale link from `%1%' to `%2%'") % path % target);
/* Note that we only delete when recursing, i.e.,
when we are still in the `gcroots' tree. We
never delete stuff outside that tree. */
unlink(path.c_str());
}
} else {
struct stat st2 = lstat(target);
if (!S_ISLNK(st2.st_mode)) return;
Path target2 = readLink(target);
if (isInStore(target2)) foundRoot(store, path, target2, roots);
}
}
}
@@ -346,18 +346,16 @@ static void findRoots(StoreAPI & store, const Path & path,
}
static Roots findRoots(StoreAPI & store, bool deleteStale)
{
Roots roots;
Path rootsDir = canonPath((format("%1%/%2%") % settings.nixStateDir % gcRootsDir).str());
findRoots(store, rootsDir, true, deleteStale, roots);
return roots;
}
Roots LocalStore::findRoots()
{
return nix::findRoots(*this, false);
Roots roots;
/* Process direct roots in {gcroots,manifests,profiles}. */
nix::findRoots(*this, settings.nixStateDir + "/" + gcRootsDir, roots);
nix::findRoots(*this, settings.nixStateDir + "/manifests", roots);
nix::findRoots(*this, settings.nixStateDir + "/profiles", roots);
return roots;
}
@@ -637,7 +635,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
/* Find the roots. Since we've grabbed the GC lock, the set of
permanent roots cannot increase now. */
printMsg(lvlError, format("finding garbage collector roots..."));
Roots rootMap = options.ignoreLiveness ? Roots() : nix::findRoots(*this, true);
Roots rootMap = options.ignoreLiveness ? Roots() : findRoots();
foreach (Roots::iterator, i, rootMap) state.roots.insert(i->second);
+5
View File
@@ -46,6 +46,7 @@ Settings::Settings()
impersonateLinux26 = false;
keepLog = true;
compressLog = true;
maxLogSize = 0;
cacheFailure = false;
pollInterval = 5;
checkRootReachability = false;
@@ -53,6 +54,7 @@ Settings::Settings()
gcKeepDerivations = true;
autoOptimiseStore = false;
envKeepDerivations = false;
lockCPU = getEnv("NIX_AFFINITY_HACK", "1") == "1";
}
@@ -70,8 +72,10 @@ void Settings::processEnvironment()
string subs = getEnv("NIX_SUBSTITUTERS", "default");
if (subs == "default") {
#if 0
if (getEnv("NIX_OTHER_STORES") != "")
substituters.push_back(nixLibexecDir + "/nix/substituters/copy-from-other-stores.pl");
#endif
substituters.push_back(nixLibexecDir + "/nix/substituters/download-using-manifests.pl");
substituters.push_back(nixLibexecDir + "/nix/substituters/download-from-binary-cache.pl");
} else
@@ -138,6 +142,7 @@ void Settings::update()
get(impersonateLinux26, "build-impersonate-linux-26");
get(keepLog, "build-keep-log");
get(compressLog, "build-compress-log");
get(maxLogSize, "build-max-log-size");
get(cacheFailure, "build-cache-failure");
get(pollInterval, "build-poll-interval");
get(checkRootReachability, "gc-check-reachability");
+7
View File
@@ -153,6 +153,10 @@ struct Settings {
/* Whether to compress logs. */
bool compressLog;
/* Maximum number of bytes a builder can write to stdout/stderr
before being killed (0 means no limit). */
unsigned long maxLogSize;
/* Whether to cache build failures. */
bool cacheFailure;
@@ -179,6 +183,9 @@ struct Settings {
(to prevent them from being GCed). */
bool envKeepDerivations;
/* Whether to lock the Nix client and worker to the same CPU. */
bool lockCPU;
private:
SettingsMap settings, overrides;
+108 -36
View File
@@ -5,6 +5,7 @@
#include "pathlocks.hh"
#include "worker-protocol.hh"
#include "derivations.hh"
#include "affinity.hh"
#include <iostream>
#include <algorithm>
@@ -317,8 +318,10 @@ LocalStore::~LocalStore()
{
try {
foreach (RunningSubstituters::iterator, i, runningSubstituters) {
if (i->second.disabled) continue;
i->second.to.close();
i->second.from.close();
i->second.error.close();
i->second.pid.wait(true);
}
} catch (...) {
@@ -378,10 +381,10 @@ void LocalStore::openDB(bool create)
sqlite3_exec(db, ("pragma main.journal_mode = " + mode + ";").c_str(), 0, 0, 0) != SQLITE_OK)
throwSQLiteError(db, "setting journal mode");
/* Increase the auto-checkpoint interval to 8192 pages. This
/* Increase the auto-checkpoint interval to 40000 pages. This
seems enough to ensure that instantiating the NixOS system
derivation is done in a single fsync(). */
if (mode == "wal" && sqlite3_exec(db, "pragma wal_autocheckpoint = 8192;", 0, 0, 0) != SQLITE_OK)
if (mode == "wal" && sqlite3_exec(db, "pragma wal_autocheckpoint = 40000;", 0, 0, 0) != SQLITE_OK)
throwSQLiteError(db, "setting autocheckpoint interval");
/* Initialise the database schema, if necessary. */
@@ -500,10 +503,6 @@ void canonicaliseTimestampAndPermissions(const Path & path)
}
typedef std::pair<dev_t, ino_t> Inode;
typedef set<Inode> InodesSeen;
static void canonicalisePathMetaData_(const Path & path, uid_t fromUid, InodesSeen & inodesSeen)
{
checkInterrupt();
@@ -561,10 +560,8 @@ static void canonicalisePathMetaData_(const Path & path, uid_t fromUid, InodesSe
}
void canonicalisePathMetaData(const Path & path, uid_t fromUid)
void canonicalisePathMetaData(const Path & path, uid_t fromUid, InodesSeen & inodesSeen)
{
InodesSeen inodesSeen;
canonicalisePathMetaData_(path, fromUid, inodesSeen);
/* On platforms that don't have lchown(), the top-level path can't
@@ -580,6 +577,13 @@ void canonicalisePathMetaData(const Path & path, uid_t fromUid)
}
void canonicalisePathMetaData(const Path & path, uid_t fromUid)
{
InodesSeen inodesSeen;
canonicalisePathMetaData(path, fromUid, inodesSeen);
}
void LocalStore::checkDerivationOutputs(const Path & drvPath, const Derivation & drv)
{
string drvName = storePathToName(drvPath);
@@ -987,7 +991,7 @@ void LocalStore::setSubstituterEnv()
{
if (didSetSubstituterEnv) return;
/* Pass configuration options (including those overriden with
/* Pass configuration options (including those overridden with
--option) to substituters. */
setenv("_NIX_OPTIONS", settings.pack().c_str(), 1);
@@ -997,7 +1001,7 @@ void LocalStore::setSubstituterEnv()
void LocalStore::startSubstituter(const Path & substituter, RunningSubstituter & run)
{
if (run.pid != -1) return;
if (run.disabled || run.pid != -1) return;
debug(format("starting substituter program `%1%'") % substituter);
@@ -1007,10 +1011,6 @@ void LocalStore::startSubstituter(const Path & substituter, RunningSubstituter &
fromPipe.create();
errorPipe.create();
/* Hack: prevent substituters that write too much to stderr from
deadlocking our read() from stdout. */
fcntl(errorPipe.writeSide, F_SETFL, O_NONBLOCK);
setSubstituterEnv();
run.pid = maybeVfork();
@@ -1022,6 +1022,7 @@ void LocalStore::startSubstituter(const Path & substituter, RunningSubstituter &
case 0: /* child */
try {
restoreAffinity();
if (dup2(toPipe.readSide, STDIN_FILENO) == -1)
throw SysError("dupping stdin");
if (dup2(fromPipe.writeSide, STDOUT_FILENO) == -1)
@@ -1038,15 +1039,91 @@ void LocalStore::startSubstituter(const Path & substituter, RunningSubstituter &
/* Parent. */
run.program = baseNameOf(substituter);
run.to = toPipe.writeSide.borrow();
run.from = fromPipe.readSide.borrow();
run.from = run.fromBuf.fd = fromPipe.readSide.borrow();
run.error = errorPipe.readSide.borrow();
toPipe.readSide.close();
fromPipe.writeSide.close();
errorPipe.writeSide.close();
/* The substituter may exit right away if it's disabled in any way
(e.g. copy-from-other-stores.pl will exit if no other stores
are configured). */
try {
getLineFromSubstituter(run);
} catch (EndOfFile & e) {
run.to.close();
run.from.close();
run.error.close();
run.disabled = true;
if (run.pid.wait(true) != 0) throw;
}
}
template<class T> T getIntLine(int fd)
/* Read a line from the substituter's stdout, while also processing
its stderr. */
string LocalStore::getLineFromSubstituter(RunningSubstituter & run)
{
string s = readLine(fd);
string res, err;
/* We might have stdout data left over from the last time. */
if (run.fromBuf.hasData()) goto haveData;
while (1) {
checkInterrupt();
fd_set fds;
FD_ZERO(&fds);
FD_SET(run.from, &fds);
FD_SET(run.error, &fds);
/* Wait for data to appear on the substituter's stdout or
stderr. */
if (select(run.from > run.error ? run.from + 1 : run.error + 1, &fds, 0, 0, 0) == -1) {
if (errno == EINTR) continue;
throw SysError("waiting for input from the substituter");
}
/* Completely drain stderr before dealing with stdout. */
if (FD_ISSET(run.error, &fds)) {
char buf[4096];
ssize_t n = read(run.error, (unsigned char *) buf, sizeof(buf));
if (n == -1) {
if (errno == EINTR) continue;
throw SysError("reading from substituter's stderr");
}
if (n == 0) throw EndOfFile(format("substituter `%1%' died unexpectedly") % run.program);
err.append(buf, n);
string::size_type p;
while ((p = err.find('\n')) != string::npos) {
printMsg(lvlError, run.program + ": " + string(err, 0, p));
err = string(err, p + 1);
}
}
/* Read from stdout until we get a newline or the buffer is empty. */
else if (run.fromBuf.hasData() || FD_ISSET(run.from, &fds)) {
haveData:
do {
unsigned char c;
run.fromBuf(&c, 1);
if (c == '\n') {
if (!err.empty()) printMsg(lvlError, run.program + ": " + err);
return res;
}
res += c;
} while (run.fromBuf.hasData());
}
}
}
template<class T> T LocalStore::getIntLineFromSubstituter(RunningSubstituter & run)
{
string s = getLineFromSubstituter(run);
T res;
if (!string2Int(s, res)) throw Error("integer expected from stream");
return res;
@@ -1060,6 +1137,7 @@ PathSet LocalStore::querySubstitutablePaths(const PathSet & paths)
if (res.size() == paths.size()) break;
RunningSubstituter & run(runningSubstituters[*i]);
startSubstituter(*i, run);
if (run.disabled) continue;
string s = "have ";
foreach (PathSet::const_iterator, j, paths)
if (res.find(*j) == res.end()) { s += *j; s += " "; }
@@ -1069,13 +1147,9 @@ PathSet LocalStore::querySubstitutablePaths(const PathSet & paths)
substituters should only write (short) messages to
stderr when they fail. I.e. they shouldn't write debug
output. */
try {
Path path = readLine(run.from);
Path path = getLineFromSubstituter(run);
if (path == "") break;
res.insert(path);
} catch (EndOfFile e) {
throw Error(format("substituter `%1%' failed: %2%") % *i % chomp(drainFD(run.error)));
}
}
}
return res;
@@ -1087,6 +1161,7 @@ void LocalStore::querySubstitutablePathInfos(const Path & substituter,
{
RunningSubstituter & run(runningSubstituters[substituter]);
startSubstituter(substituter, run);
if (run.disabled) return;
string s = "info ";
foreach (PathSet::const_iterator, i, paths)
@@ -1094,26 +1169,22 @@ void LocalStore::querySubstitutablePathInfos(const Path & substituter,
writeLine(run.to, s);
while (true) {
try {
Path path = readLine(run.from);
Path path = getLineFromSubstituter(run);
if (path == "") break;
if (paths.find(path) == paths.end())
throw Error(format("got unexpected path `%1%' from substituter") % path);
paths.erase(path);
SubstitutablePathInfo & info(infos[path]);
info.deriver = readLine(run.from);
info.deriver = getLineFromSubstituter(run);
if (info.deriver != "") assertStorePath(info.deriver);
int nrRefs = getIntLine<int>(run.from);
int nrRefs = getIntLineFromSubstituter<int>(run);
while (nrRefs--) {
Path p = readLine(run.from);
Path p = getLineFromSubstituter(run);
assertStorePath(p);
info.references.insert(p);
}
info.downloadSize = getIntLine<long long>(run.from);
info.narSize = getIntLine<long long>(run.from);
} catch (EndOfFile e) {
throw Error(format("substituter `%1%' failed: %2%") % substituter % chomp(drainFD(run.error)));
}
info.downloadSize = getIntLineFromSubstituter<long long>(run);
info.narSize = getIntLineFromSubstituter<long long>(run);
}
}
@@ -1157,9 +1228,10 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos)
foreach (ValidPathInfos::const_iterator, i, infos) {
assert(i->hash.type == htSHA256);
/* !!! Maybe the registration info should be updated if the
path is already valid. */
if (!isValidPath(i->path)) addValidPath(*i);
if (isValidPath(i->path))
updatePathInfo(*i);
else
addValidPath(*i);
paths.insert(i->path);
}
+14 -1
View File
@@ -44,8 +44,12 @@ struct OptimiseStats
struct RunningSubstituter
{
Path program;
Pid pid;
AutoCloseFD to, from, error;
FdSource fromBuf;
bool disabled;
RunningSubstituter() : disabled(false) { };
};
@@ -173,7 +177,7 @@ public:
/* Register the validity of a path, i.e., that `path' exists, that
the paths referenced by it exists, and in the case of an output
path of a derivation, that it has been produced by a succesful
path of a derivation, that it has been produced by a successful
execution of the derivation (or something equivalent). Also
register the hash of the file system contents of the path. The
hash must be a SHA-256 hash. */
@@ -289,6 +293,10 @@ private:
void startSubstituter(const Path & substituter,
RunningSubstituter & runningSubstituter);
string getLineFromSubstituter(RunningSubstituter & run);
template<class T> T getIntLineFromSubstituter(RunningSubstituter & run);
Path createTempDirInStore();
Path importPath(bool requireSignature, Source & source);
@@ -299,6 +307,10 @@ private:
};
typedef std::pair<dev_t, ino_t> Inode;
typedef set<Inode> InodesSeen;
/* "Fix", or canonicalise, the meta-data of the files in a store path
after it has been built. In particular:
- the last modification date on each file is set to 1 (i.e.,
@@ -307,6 +319,7 @@ private:
without execute permission; setuid bits etc. are cleared)
- the owner and group are set to the Nix user and group, if we're
in a setuid Nix installation. */
void canonicalisePathMetaData(const Path & path, uid_t fromUid, InodesSeen & inodesSeen);
void canonicalisePathMetaData(const Path & path, uid_t fromUid);
void canonicaliseTimestampAndPermissions(const Path & path);
+3 -2
View File
@@ -120,7 +120,8 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
if (invalid.empty()) continue;
todoDrv.insert(*i);
if (settings.useSubstitutes) query.insert(invalid.begin(), invalid.end());
if (settings.useSubstitutes && !willBuildLocally(drv))
query.insert(invalid.begin(), invalid.end());
}
else {
@@ -143,7 +144,7 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
PathSet outputs;
bool mustBuild = false;
if (settings.useSubstitutes) {
if (settings.useSubstitutes && !willBuildLocally(drv)) {
foreach (DerivationOutputs::iterator, j, drv.outputs) {
if (!wantOutput(j->first, i2.second)) continue;
if (!store.isValidPath(j->second.path)) {
+2
View File
@@ -32,5 +32,7 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
PathSet & willBuild, PathSet & willSubstitute, PathSet & unknown,
unsigned long long & downloadSize, unsigned long long & narSize);
bool willBuildLocally(const Derivation & drv);
}
+12 -1
View File
@@ -3,6 +3,7 @@
#include "remote-store.hh"
#include "worker-protocol.hh"
#include "archive.hh"
#include "affinity.hh"
#include "globals.hh"
#include <sys/types.h>
@@ -15,7 +16,6 @@
#include <unistd.h>
#include <cstring>
namespace nix {
@@ -71,8 +71,19 @@ void RemoteStore::openConnection(bool reserveSpace)
if (GET_PROTOCOL_MAJOR(daemonVersion) != GET_PROTOCOL_MAJOR(PROTOCOL_VERSION))
throw Error("Nix daemon protocol version not supported");
writeInt(PROTOCOL_VERSION, to);
if (GET_PROTOCOL_MINOR(daemonVersion) >= 14) {
int cpu = settings.lockCPU ? lockToCurrentCPU() : -1;
if (cpu != -1) {
writeInt(1, to);
writeInt(cpu, to);
} else
writeInt(0, to);
}
if (GET_PROTOCOL_MINOR(daemonVersion) >= 11)
writeInt(reserveSpace, to);
processStderr();
}
catch (Error & e) {
+1 -4
View File
@@ -18,10 +18,7 @@ GCOptions::GCOptions()
bool isInStore(const Path & path)
{
return path[0] == '/'
&& string(path, 0, settings.nixStore.size()) == settings.nixStore
&& path.size() >= settings.nixStore.size() + 2
&& path[settings.nixStore.size()] == '/';
return isInDir(path, settings.nixStore);
}
+1 -1
View File
@@ -328,7 +328,7 @@ Path addPermRoot(StoreAPI & store, const Path & storePath,
/* Sort a set of paths topologically under the references relation.
If p refers to q, then p follows q in this list. */
If p refers to q, then p preceeds q in this list. */
Paths topoSortPaths(StoreAPI & store, const PathSet & paths);
+1 -1
View File
@@ -6,7 +6,7 @@ namespace nix {
#define WORKER_MAGIC_1 0x6e697863
#define WORKER_MAGIC_2 0x6478696f
#define PROTOCOL_VERSION 0x10d
#define PROTOCOL_VERSION 0x10e
#define GET_PROTOCOL_MAJOR(x) ((x) & 0xff00)
#define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff)
+2 -2
View File
@@ -1,12 +1,12 @@
pkglib_LTLIBRARIES = libutil.la
libutil_la_SOURCES = util.cc hash.cc serialise.cc \
archive.cc xml-writer.cc
archive.cc xml-writer.cc affinity.cc
libutil_la_LIBADD = ../boost/format/libformat.la
pkginclude_HEADERS = util.hh hash.hh serialise.hh \
archive.hh xml-writer.hh types.hh
archive.hh xml-writer.hh types.hh affinity.hh
if !HAVE_OPENSSL
libutil_la_SOURCES += \
+55
View File
@@ -0,0 +1,55 @@
#include "types.hh"
#include "util.hh"
#include "affinity.hh"
#if HAVE_SCHED_H
#include <sched.h>
#endif
namespace nix {
#if HAVE_SCHED_SETAFFINITY
static bool didSaveAffinity = false;
static cpu_set_t savedAffinity;
#endif
void setAffinityTo(int cpu)
{
#if HAVE_SCHED_SETAFFINITY
if (sched_getaffinity(0, sizeof(cpu_set_t), &savedAffinity) == -1) return;
didSaveAffinity = true;
printMsg(lvlDebug, format("locking this thread to CPU %1%") % cpu);
cpu_set_t newAffinity;
CPU_ZERO(&newAffinity);
CPU_SET(cpu, &newAffinity);
if (sched_setaffinity(0, sizeof(cpu_set_t), &newAffinity) == -1)
printMsg(lvlError, format("failed to lock thread to CPU %1%") % cpu);
#endif
}
int lockToCurrentCPU()
{
#if HAVE_SCHED_SETAFFINITY
int cpu = sched_getcpu();
if (cpu != -1) setAffinityTo(cpu);
return cpu;
#else
return -1;
#endif
}
void restoreAffinity()
{
#if HAVE_SCHED_SETAFFINITY
if (!didSaveAffinity) return;
if (sched_setaffinity(0, sizeof(cpu_set_t), &savedAffinity) == -1)
printMsg(lvlError, "failed to restore affinity %1%");
#endif
}
}
+9
View File
@@ -0,0 +1,9 @@
#pragma once
namespace nix {
void setAffinityTo(int cpu);
int lockToCurrentCPU();
void restoreAffinity();
}
+6
View File
@@ -90,6 +90,12 @@ size_t BufferedSource::read(unsigned char * data, size_t len)
}
bool BufferedSource::hasData()
{
return bufPosOut < bufPosIn;
}
size_t FdSource::readUnbuffered(unsigned char * data, size_t len)
{
ssize_t n;
+3 -1
View File
@@ -61,8 +61,10 @@ struct BufferedSource : Source
size_t read(unsigned char * data, size_t len);
/* Underlying read call, to be overriden. */
/* Underlying read call, to be overridden. */
virtual size_t readUnbuffered(unsigned char * data, size_t len) = 0;
bool hasData();
};
+25 -10
View File
@@ -12,6 +12,10 @@
#include <fcntl.h>
#include <limits.h>
#ifdef __APPLE__
#include <sys/syscall.h>
#endif
#include "util.hh"
@@ -148,6 +152,15 @@ string baseNameOf(const Path & path)
}
bool isInDir(const Path & path, const Path & dir)
{
return path[0] == '/'
&& string(path, 0, dir.size()) == dir
&& path.size() >= dir.size() + 2
&& path[dir.size()] == '/';
}
struct stat lstat(const Path & path)
{
struct stat st;
@@ -616,8 +629,8 @@ AutoCloseFD::AutoCloseFD(int fd)
AutoCloseFD::AutoCloseFD(const AutoCloseFD & fd)
{
/* Copying a AutoCloseFD isn't allowed (who should get to close
it?). But as a edge case, allow copying of closed
/* Copying an AutoCloseFD isn't allowed (who should get to close
it?). But as an edge case, allow copying of closed
AutoCloseFDs. This is necessary due to tiresome reasons
involving copy constructor use on default object values in STL
containers (like when you do `map[value]' where value isn't in
@@ -790,6 +803,7 @@ void Pid::kill()
int Pid::wait(bool block)
{
assert(pid != -1);
while (1) {
int status;
int res = waitpid(pid, &status, block ? 0 : WNOHANG);
@@ -841,7 +855,16 @@ void killUser(uid_t uid)
throw SysError("setting uid");
while (true) {
#ifdef __APPLE__
/* OSX's kill syscall takes a third parameter that, among other
things, determines if kill(-1, signo) affects the calling
process. In the OSX libc, it's set to true, which means
"follow POSIX", which we don't want here
*/
if (syscall(SYS_kill, -1, SIGKILL, false) == 0) break;
#else
if (kill(-1, SIGKILL) == 0) break;
#endif
if (errno == ESRCH) break; /* no more processes */
if (errno != EINTR)
throw SysError(format("cannot kill processes for uid `%1%'") % uid);
@@ -1060,14 +1083,6 @@ bool statusOk(int status)
}
string int2String(int n)
{
std::ostringstream str;
str << n;
return str.str();
}
bool hasSuffix(const string & s, const string & suffix)
{
return s.size() >= suffix.size() && string(s, s.size() - suffix.size()) == suffix;
+10 -1
View File
@@ -45,6 +45,10 @@ 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. */
bool isInDir(const Path & path, const Path & dir);
/* Get status of `path'. */
struct stat lstat(const Path & path);
@@ -315,7 +319,12 @@ template<class N> bool string2Int(const string & s, N & n)
return str && str.get() == EOF;
}
string int2String(int n);
template<class N> string int2String(N n)
{
std::ostringstream str;
str << n;
return str.str();
}
/* Return true iff `s' ends in `suffix'. */
+18 -7
View File
@@ -4,6 +4,7 @@
#include "serialise.hh"
#include "worker-protocol.hh"
#include "archive.hh"
#include "affinity.hh"
#include "globals.hh"
#include <cstring>
@@ -25,8 +26,13 @@ using namespace nix;
that lack it, we only notice the disconnection the next time we try
to write to the client. So if you have a builder that never
generates output on stdout/stderr, the daemon will never notice
that the client has disconnected until the builder terminates. */
#ifdef O_ASYNC
that the client has disconnected until the builder terminates.
GNU/Hurd does have O_ASYNC, but its Unix-domain socket translator
(pflocal) does not implement F_SETOWN. See
<http://lists.gnu.org/archive/html/bug-guix/2013-07/msg00021.html> for
details.*/
#if defined O_ASYNC && !defined __GNU__
#define HAVE_HUP_NOTIFICATION
#ifndef SIGPOLL
#define SIGPOLL SIGIO
@@ -273,7 +279,7 @@ struct SavingSourceAdapter : Source
};
static void performOp(unsigned int clientVersion,
static void performOp(bool trusted, unsigned int clientVersion,
Source & from, Sink & to, unsigned int op)
{
switch (op) {
@@ -554,7 +560,7 @@ static void performOp(unsigned int clientVersion,
if (name == "build-timeout")
string2Int(value, settings.buildTimeout);
else
settings.set("untrusted-" + name, value);
settings.set(trusted ? name : "untrusted-" + name, value);
}
}
startWork();
@@ -643,7 +649,7 @@ static void performOp(unsigned int clientVersion,
}
static void processConnection()
static void processConnection(bool trusted)
{
canSendStderr = false;
myPid = getpid();
@@ -666,6 +672,9 @@ static void processConnection()
to.flush();
unsigned int clientVersion = readInt(from);
if (GET_PROTOCOL_MINOR(clientVersion) >= 14 && readInt(from))
setAffinityTo(readInt(from));
bool reserveSpace = true;
if (GET_PROTOCOL_MINOR(clientVersion) >= 11)
reserveSpace = readInt(from) != 0;
@@ -711,7 +720,7 @@ static void processConnection()
opCount++;
try {
performOp(clientVersion, from, to, op);
performOp(trusted, clientVersion, from, to, op);
} catch (Error & e) {
/* If we're not in a state were we can send replies, then
something went wrong processing the input of the
@@ -839,6 +848,7 @@ static void daemonLoop()
/* Get the identity of the caller, if possible. */
uid_t clientUid = -1;
pid_t clientPid = -1;
bool trusted = false;
#if defined(SO_PEERCRED)
ucred cred;
@@ -846,6 +856,7 @@ static void daemonLoop()
if (getsockopt(remote, SOL_SOCKET, SO_PEERCRED, &cred, &credLen) != -1) {
clientPid = cred.pid;
clientUid = cred.uid;
if (clientUid == 0) trusted = true;
}
#endif
@@ -879,7 +890,7 @@ static void daemonLoop()
/* Handle the connection. */
from.fd = remote;
to.fd = remote;
processConnection();
processConnection(trusted);
} catch (std::exception & e) {
writeToStderr("child error: " + string(e.what()) + "\n");
+63 -43
View File
@@ -54,6 +54,7 @@ struct Globals
EvalState state;
bool dryRun;
bool preserveInstalled;
bool removeAll;
string forceName;
bool prebuiltOnly;
};
@@ -94,18 +95,14 @@ static bool parseInstallSourceOptions(Globals & globals,
}
static bool isNixExpr(const Path & path)
static bool isNixExpr(const Path & path, struct stat & st)
{
struct stat st;
if (stat(path.c_str(), &st) == -1)
throw SysError(format("getting information about `%1%'") % path);
return !S_ISDIR(st.st_mode) || pathExists(path + "/default.nix");
return S_ISREG(st.st_mode) || (S_ISDIR(st.st_mode) && pathExists(path + "/default.nix"));
}
static void getAllExprs(EvalState & state,
const Path & path, ExprAttrs & attrs)
const Path & path, StringSet & attrs, Value & v)
{
Strings names = readDirectory(path);
StringSet namesSorted(names.begin(), names.end());
@@ -122,7 +119,7 @@ static void getAllExprs(EvalState & state,
if (stat(path2.c_str(), &st) == -1)
continue; // ignore dangling symlinks in ~/.nix-defexpr
if (isNixExpr(path2)) {
if (isNixExpr(path2, st) && (!S_ISREG(st.st_mode) || hasSuffix(path2, ".nix"))) {
/* Strip off the `.nix' filename suffix (if applicable),
otherwise the attribute cannot be selected with the
`-A' option. Useful if you want to stick a Nix
@@ -130,20 +127,36 @@ static void getAllExprs(EvalState & state,
string attrName = *i;
if (hasSuffix(attrName, ".nix"))
attrName = string(attrName, 0, attrName.size() - 4);
attrs.attrs[state.symbols.create(attrName)] =
ExprAttrs::AttrDef(state.parseExprFromFile(absPath(path2)), noPos);
if (attrs.find(attrName) != attrs.end()) {
printMsg(lvlError, format("warning: name collision in input Nix expressions, skipping `%1%'") % path2);
continue;
}
else
attrs.insert(attrName);
/* Load the expression on demand. */
Value & vFun(*state.allocValue());
Value & vArg(*state.allocValue());
state.getBuiltin("import", vFun);
mkString(vArg, path2);
mkApp(*state.allocAttr(v, state.symbols.create(attrName)), vFun, vArg);
}
else if (S_ISDIR(st.st_mode))
/* `path2' is a directory (with no default.nix in it);
recurse into it. */
getAllExprs(state, path2, attrs);
getAllExprs(state, path2, attrs, v);
}
}
static Expr * loadSourceExpr(EvalState & state, const Path & path)
static void loadSourceExpr(EvalState & state, const Path & path, Value & v)
{
if (isNixExpr(path)) return state.parseExprFromFile(absPath(path));
struct stat st;
if (stat(path.c_str(), &st) == -1)
throw SysError(format("getting information about `%1%'") % path);
if (isNixExpr(path, st)) {
state.evalFile(path, v);
return;
}
/* The path is a directory. Put the Nix expressions in the
directory in an attribute set, with the file name of each
@@ -151,11 +164,13 @@ static Expr * loadSourceExpr(EvalState & state, const Path & path)
(but keep the attribute set flat, not nested, to make it easier
for a user to have a ~/.nix-defexpr directory that includes
some system-wide directory). */
ExprAttrs * attrs = new ExprAttrs;
attrs->attrs[state.symbols.create("_combineChannels")] =
ExprAttrs::AttrDef(new ExprList(), noPos);
getAllExprs(state, path, *attrs);
return attrs;
if (S_ISDIR(st.st_mode)) {
state.mkAttrs(v, 16);
state.mkList(*state.allocAttr(v, state.symbols.create("_combineChannels")), 0);
StringSet attrs;
getAllExprs(state, path, attrs, v);
v.attrs->sort();
}
}
@@ -163,8 +178,10 @@ static void loadDerivations(EvalState & state, Path nixExprPath,
string systemFilter, Bindings & autoArgs,
const string & pathPrefix, DrvInfos & elems)
{
Value v;
findAlongAttrPath(state, pathPrefix, autoArgs, loadSourceExpr(state, nixExprPath), v);
Value vRoot;
loadSourceExpr(state, nixExprPath, vRoot);
Value & v(*findAlongAttrPath(state, pathPrefix, autoArgs, vRoot));
getDerivations(state, v, pathPrefix, autoArgs, elems, true);
@@ -227,13 +244,13 @@ static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems,
const Strings & args, bool newestOnly)
{
DrvNames selectors = drvNamesFromArgs(args);
if (selectors.empty())
selectors.push_back(DrvName("*"));
DrvInfos elems;
set<unsigned int> done;
for (DrvNames::iterator i = selectors.begin();
i != selectors.end(); ++i)
{
foreach (DrvNames::iterator, i, selectors) {
typedef list<std::pair<DrvInfo, unsigned int> > Matches;
Matches matches;
unsigned int n = 0;
@@ -305,8 +322,7 @@ static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems,
}
/* Check that all selectors have been used. */
for (DrvNames::iterator i = selectors.begin();
i != selectors.end(); ++i)
foreach (DrvNames::iterator, i, selectors)
if (i->hits == 0 && i->fullName != "*")
throw Error(format("selector `%1%' matches no derivations")
% i->fullName);
@@ -356,13 +372,15 @@ static void queryInstSources(EvalState & state,
(import ./foo.nix)' = `(import ./foo.nix).bar'. */
case srcNixExprs: {
Expr * e1 = loadSourceExpr(state, instSource.nixExprPath);
Value vArg;
loadSourceExpr(state, instSource.nixExprPath, vArg);
foreach (Strings::const_iterator, i, args) {
Expr * e2 = state.parseExprFromString(*i, absPath("."));
Expr * call = new ExprApp(e2, e1);
Value v; state.eval(call, v);
getDerivations(state, v, "", instSource.autoArgs, elems, true);
Expr * eFun = state.parseExprFromString(*i, absPath("."));
Value vFun, vTmp;
state.eval(eFun, vFun);
mkApp(vTmp, vFun, vArg);
getDerivations(state, vTmp, "", instSource.autoArgs, elems, true);
}
break;
@@ -413,10 +431,10 @@ static void queryInstSources(EvalState & state,
}
case srcAttrPath: {
Value vRoot;
loadSourceExpr(state, instSource.nixExprPath, vRoot);
foreach (Strings::const_iterator, i, args) {
Value v;
findAlongAttrPath(state, *i, instSource.autoArgs,
loadSourceExpr(state, instSource.nixExprPath), v);
Value & v(*findAlongAttrPath(state, *i, instSource.autoArgs, vRoot));
getDerivations(state, v, "", instSource.autoArgs, elems, true);
}
break;
@@ -472,29 +490,31 @@ static void installDerivations(Globals & globals,
newNames.insert(DrvName(i->name).name);
}
/* Add in the already installed derivations, unless they have the
same name as a to-be-installed element. */
while (true) {
string lockToken = optimisticLockProfile(profile);
DrvInfos allElems(newElems);
/* Add in the already installed derivations, unless they have
the same name as a to-be-installed element. */
if (!globals.removeAll) {
DrvInfos installedElems = queryInstalled(globals.state, profile);
DrvInfos allElems(newElems);
foreach (DrvInfos::iterator, i, installedElems) {
DrvName drvName(i->name);
MetaInfo meta = i->queryMetaInfo(globals.state);
if (!globals.preserveInstalled &&
newNames.find(drvName.name) != newNames.end() &&
!keep(meta))
printMsg(lvlInfo,
format("replacing old `%1%'") % i->name);
printMsg(lvlInfo, format("replacing old `%1%'") % i->name);
else
allElems.push_back(*i);
}
foreach (DrvInfos::iterator, i, newElems)
printMsg(lvlInfo, format("installing `%1%'") % i->name);
}
printMissing(globals.state, newElems);
@@ -514,6 +534,8 @@ static void opInstall(Globals & globals,
if (parseInstallSourceOptions(globals, i, opFlags, arg)) ;
else if (arg == "--preserve-installed" || arg == "-P")
globals.preserveInstalled = true;
else if (arg == "--remove-all" || arg == "-r")
globals.removeAll = true;
else throw UsageError(format("unknown flag `%1%'") % arg);
}
@@ -804,7 +826,7 @@ void printTable(Table & table)
}
/* This function compares the version of a element against the
/* This function compares the version of an element against the
versions in the given set of elements. `cvLess' means that only
lower versions are in the set, `cvEqual' means that at most an
equal version is in the set, and `cvGreater' means that there is at
@@ -895,9 +917,6 @@ static void opQuery(Globals & globals,
else remaining.push_back(arg);
}
if (remaining.size() == 0)
printMsg(lvlInfo, "warning: you probably meant to specify the argument '*' to show all packages");
/* Obtain derivation information from the specified source. */
DrvInfos availElems, installedElems;
@@ -1284,6 +1303,7 @@ void run(Strings args)
globals.dryRun = false;
globals.preserveInstalled = false;
globals.removeAll = false;
globals.prebuiltOnly = false;
for (Strings::iterator i = args.begin(); i != args.end(); ) {
+9 -5
View File
@@ -39,12 +39,16 @@ void processExpr(EvalState & state, const Strings & attrPaths,
bool parseOnly, bool strict, Bindings & autoArgs,
bool evalOnly, bool xmlOutput, bool location, Expr * e)
{
if (parseOnly)
if (parseOnly) {
std::cout << format("%1%\n") % *e;
else
return;
}
Value vRoot;
state.eval(e, vRoot);
foreach (Strings::const_iterator, i, attrPaths) {
Value v;
findAlongAttrPath(state, *i, autoArgs, e, v);
Value & v(*findAlongAttrPath(state, *i, autoArgs, vRoot));
state.forceValue(v);
PathSet context;
@@ -160,7 +164,7 @@ void run(Strings args)
files.push_back("./default.nix");
foreach (Strings::iterator, i, files) {
Expr * e = state.parseExprFromFile(lookupFileArg(state, *i));
Expr * e = state.parseExprFromFile(resolveExprPath(lookupFileArg(state, *i)));
processExpr(state, attrPaths, parseOnly, strict, autoArgs,
evalOnly, xmlOutput, xmlOutputSourceLocation, e);
}
+3 -1
View File
@@ -694,7 +694,9 @@ static void opExport(Strings opFlags, Strings opArgs)
else throw UsageError(format("unknown flag `%1%'") % *i);
FdSink sink(STDOUT_FILENO);
exportPaths(*store, opArgs, sign, sink);
Paths sorted = topoSortPaths(*store, PathSet(opArgs.begin(), opArgs.end()));
reverse(sorted.begin(), sorted.end());
exportPaths(*store, sorted, sign, sink);
}
+1 -1
View File
@@ -47,7 +47,7 @@ clearStore
nix-build --option binary-caches "file://$cacheDir" dependencies.nix --dry-run # get info
mkdir $cacheDir/tmp
mv $cacheDir/*.nar.xz $cacheDir/tmp/
mv $cacheDir/*.nar* $cacheDir/tmp/
NIX_DEBUG_SUBST=1 nix-build --option binary-caches "file://$cacheDir" dependencies.nix -o $TEST_ROOT/result --fallback
+1 -1
View File
@@ -40,7 +40,7 @@ for i in lang/eval-okay-*.nix; do
if test -e lang/$i.flags; then
flags=$(cat lang/$i.flags)
fi
if ! NIX_PATH=lang/dir3:lang/dir4:$NIX_PATH nix-instantiate $flags --eval-only --strict lang/$i.nix > lang/$i.out; then
if ! NIX_PATH=lang/dir3:lang/dir4_PATH nix-instantiate $flags --eval-only --strict lang/$i.nix > lang/$i.out; then
echo "FAIL: $i should evaluate"
fail=1
elif ! diff lang/$i.out lang/$i.exp; then
+1 -1
View File
@@ -1 +1 @@
1275
2188
+40 -1
View File
@@ -16,6 +16,45 @@ let {
range = range_ [];
*/
body = sum (range 1 50);
x = 12;
err = abort "urgh";
body = sum
[ (sum (range 1 50))
(123 + 456)
(0 + -10 + -(-11) + -x)
(10 - 7 - -2)
(10 - (6 - -1))
(10 - 1 + 2)
(3 * 4 * 5)
(56088 / 123 / 2)
(3 + 4 * const 5 0 - 6 / id 2)
(if 3 < 7 then 1 else err)
(if 7 < 3 then err else 1)
(if 3 < 3 then err else 1)
(if 3 <= 7 then 1 else err)
(if 7 <= 3 then err else 1)
(if 3 <= 3 then 1 else err)
(if 3 > 7 then err else 1)
(if 7 > 3 then 1 else err)
(if 3 > 3 then err else 1)
(if 3 >= 7 then err else 1)
(if 7 >= 3 then 1 else err)
(if 3 >= 3 then 1 else err)
(if 2 > 1 == 1 < 2 then 1 else err)
(if 1 + 2 * 3 >= 7 then 1 else err)
(if 1 + 2 * 3 < 7 then err else 1)
# Not integer, but so what.
(if "aa" < "ab" then 1 else err)
(if "aa" < "aa" then err else 1)
(if "foo" < "foobar" then 1 else err)
];
}
+1 -1
View File
@@ -5,7 +5,7 @@ let
in
{ xyzzy2 ? xyzzy # mutually recursive args
, xyzzy ? "blaat" # will be overriden by --argstr
, xyzzy ? "blaat" # will be overridden by --argstr
, fb ? foobar
, lib # will be set by --arg
}:
@@ -0,0 +1 @@
"b-overridden"
@@ -0,0 +1,24 @@
let
pkgs_ = with pkgs; {
a = derivation {
name = "a";
system = builtins.currentSystem;
builder = "/bin/sh";
args = [ "-c" "touch $out" ];
inherit b;
};
inherit b;
};
packageOverrides = p: {
b = derivation {
name = "b-overridden";
system = builtins.currentSystem;
builder = "/bin/sh";
args = [ "-c" "touch $out" ];
};
};
pkgs = pkgs_ // (packageOverrides pkgs_);
in pkgs.a.b.name
+1
View File
@@ -0,0 +1 @@
"b-overridden b-overridden a"
+29
View File
@@ -0,0 +1,29 @@
let
pkgs_ = with pkgs; {
a = derivation {
name = "a";
system = builtins.currentSystem;
builder = "/bin/sh";
args = [ "-c" "touch $out" ];
inherit b;
};
b = derivation {
name = "b";
system = builtins.currentSystem;
builder = "/bin/sh";
args = [ "-c" "touch $out" ];
inherit a;
};
c = b;
};
packageOverrides = pkgs: with pkgs; {
b = derivation (b.drvAttrs // { name = "${b.name}-overridden"; });
};
pkgs = pkgs_ // (packageOverrides pkgs_);
in "${pkgs.a.b.name} ${pkgs.c.name} ${pkgs.b.a.name}"
+4
View File
@@ -49,4 +49,8 @@ rec {
if comp (head list2) (head list1) then [(head list2)] ++ mergeLists comp list1 (tail list2) else
[(head list1)] ++ mergeLists comp (tail list1) list2;
id = x: x;
const = x: y: x;
}
+1
View File
@@ -1,4 +1,5 @@
#! /bin/sh -e
echo
echo substituter args: $* >&2
if test $1 = "--query"; then
+1
View File
@@ -1,4 +1,5 @@
#! /bin/sh -e
echo
echo substituter2 args: $* >&2
if test $1 = "--query"; then
+1 -1
View File
@@ -1,2 +1,2 @@
echo "\`timeout' builder entering an infinite loop"
while true ; do echo foo; sleep 1; done
while true ; do echo -n .; done
+10 -13
View File
@@ -2,23 +2,20 @@
source common.sh
drvPath=$(nix-instantiate timeout.nix)
test "$(nix-store -q --binding system "$drvPath")" = "$system"
echo "derivation is $drvPath"
failed=0
messages="`nix-store -r --timeout 2 $drvPath 2>&1 || failed=1`"
if test $failed -ne 0; then
echo "error: \`nix-store' succeeded; should have timed out" >&2
messages="`nix-build timeout.nix --timeout 2 2>&1 || failed=1`"
if [ $failed -ne 0 ]; then
echo "error: \`nix-store' succeeded; should have timed out"
exit 1
fi
if ! echo "$messages" | grep "timed out"; then
echo "error: \`nix-store' may have failed for reasons other than timeout" >&2
echo >&2
echo "output of \`nix-store' follows:" >&2
if ! echo "$messages" | grep -q "timed out"; then
echo "error: build may have failed for reasons other than timeout; output:"
echo "$messages" >&2
exit 1
fi
if nix-build timeout.nix --option build-max-log-size 100; then
echo "build should have failed"
exit 1
fi
+1 -1
View File
@@ -1 +1 @@
1.5.2
1.6