Compare commits

...

195 Commits

Author SHA1 Message Date
Eelco Dolstra
9936da6b54 * Check whether the outputName attribute works. 2012-01-04 12:45:53 +00:00
Eelco Dolstra
9d43a02382 * Let --disable-gc work. 2012-01-04 12:45:40 +00:00
Eelco Dolstra
a0477a458f * currentOutput -> outputName. "current" implies some temporal
aspect.
2012-01-04 12:00:39 +00:00
Eelco Dolstra
b79b85ad76 * Export the original input attributes of the derivation in
‘drvAttrs’.  This will simplify the implementation of functions such
  as ‘overrideDerivation’ in Nixpkgs, which need to filter out any
  added attributes such as outPath.
2012-01-04 11:56:15 +00:00
Eelco Dolstra
83647f4ef1 * Simplify the implementation of "derivation" a bit: lift out the
common attribution so that they're evaluated only once, etc.  Note
  that the default output is now the first element of the "outputs"
  attribute, rather than the first element of the sorted list of
  outputs.  This seems more user-friendly.
2012-01-04 11:04:19 +00:00
Eelco Dolstra
71f3c46cf6 * Drop the inefficient "Path" suffix in output attribute names. 2012-01-03 15:27:18 +00:00
Eelco Dolstra
921111d197 * Move the implementation of the ‘derivation’ primop into a separate
file.
2012-01-03 14:01:47 +00:00
Eelco Dolstra
6c31232e14 * Sync with the trunk. 2012-01-03 12:59:31 +00:00
Eelco Dolstra
502d94048a * Ignore missing manifest symlinks. 2012-01-03 12:59:00 +00:00
Eelco Dolstra
63227d434c * FreeBSD tar defaults to the tape device instead of stdout. 2012-01-03 12:18:41 +00:00
Eelco Dolstra
9b7df1ef00 * Forgot to add. 2012-01-03 09:19:40 +00:00
Eelco Dolstra
39d45a6b09 * Add a test for nix-channel.
* Refactor the nix-channel unpacker a bit.
2012-01-03 01:51:38 +00:00
Eelco Dolstra
dadbb51d96 * Use Nix::Config. 2012-01-03 00:47:27 +00:00
Eelco Dolstra
48cea0d01e * Refactoring: Get rid of a few subdirectories in corepkgs/, and some
other simplifications.
* Use <nix/...> to locate the corepkgs.  This allows them to be
  overriden through $NIX_PATH.
* Use bash's pipefail option in the NAR builder so that we don't need
  to create a temporary file.
2012-01-03 00:16:29 +00:00
Eelco Dolstra
93e71e6ab6 * Follow our own coding conventions. 2011-12-30 17:39:03 +00:00
Eelco Dolstra
f2d65c9c80 * Remove a redundant dot (Nicolas Pierron). 2011-12-30 17:31:58 +00:00
Eelco Dolstra
93b56acb2d * Support multiple outputs in nix-store (specifically the ‘--query’
and ‘--realise’ actions).
2011-12-30 17:25:19 +00:00
Eelco Dolstra
a71d02440b * Oops. 2011-12-30 17:13:25 +00:00
Eelco Dolstra
6f5e3326ce * Move topoSortPaths() out of gc.cc. 2011-12-30 15:02:50 +00:00
Eelco Dolstra
b1004f40f7 * Reject a build if there is a cycle among the outputs. This is
necessary because existing code assumes that the references graph is
  acyclic.
2011-12-30 14:47:14 +00:00
Eelco Dolstra
ed11b17b2e * Fix doc error. 2011-12-30 13:43:29 +00:00
Eelco Dolstra
254b3399ba * Sync with the trunk. 2011-12-30 13:08:14 +00:00
Eelco Dolstra
8c42a8c8ff * Make sure that lock files are cleaned up properly when building
through the build hook.
2011-12-25 16:38:37 +00:00
Eelco Dolstra
524fa8a4f1 * Oops. 2011-12-22 16:27:03 +00:00
Eelco Dolstra
b33da599c5 * In the garbage collector, delete invalid paths before deleting
unreachable paths.  This matters when using --max-freed etc.:
  unreachable paths could become reachable again, so it's nicer to
  keep them if there is "real" garbage to be deleted.  Also, don't use
  readDirectory() but read the Nix store and delete invalid paths in
  parallel.  This reduces GC latency on very large Nix stores.
2011-12-22 15:55:53 +00:00
Eelco Dolstra
58d974336c * Drop unnecessary call to canonPath() (nixStore is already canonical). 2011-12-22 14:33:34 +00:00
Eelco Dolstra
66c99b0cf5 * ‘--disable-shared’ is no longer supported. Fortunately it's not
needed for the coverage analysis.
2011-12-22 10:58:27 +00:00
Eelco Dolstra
2aac7cd021 * Another case of lock file permissions being too liberal. 2011-12-21 19:17:45 +00:00
Eelco Dolstra
4d728bc3e6 * Security: make sure the lock files used by build-remote.pl are not
readable to other users.  Otherwise, any user can open the lock file
  for reading and lock it, thus DoSing the remote build mechanism.
2011-12-21 19:11:58 +00:00
Eelco Dolstra
69d6f0936a * Use a lock to ensure that only one build-remote instance can copy a
closure to a given machine at the same time.  This prevents the case
  where multiple instances try to copy the same missing store path to
  the target machine, which is very wasteful.
2011-12-21 18:59:25 +00:00
Eelco Dolstra
5679041132 * The ‘foo.drvPath’ feature was already broken in read-only mode.
Since it's rarely used and fixing it is too much work right now,
  just document it.
2011-12-21 18:19:05 +00:00
Shea Levy
f8e54b7874 Make the reference cycle in the cyclic outputs test indirect 2011-12-21 17:34:44 +00:00
Shea Levy
b4cee3f816 Revert previous commit
It doesn't detect indirect references
2011-12-21 17:31:34 +00:00
Shea Levy
f3c88f297d Detect and reject mutually-referential outputs
There is probably a more efficient way to do this.
2011-12-21 17:14:28 +00:00
Eelco Dolstra
b19a0f63db * Simplify the context handling logic. 2011-12-21 15:33:30 +00:00
Eelco Dolstra
4be5a2c096 * Add a test for unsafeDiscardOutputDependency. Not really related to
multiple outputs, but good to have anyway.
2011-12-21 14:42:06 +00:00
Eelco Dolstra
179409b911 * Add a test for referring to another derivation's ‘drvPath’. This
currently fails in read-only mode.
2011-12-21 13:47:21 +00:00
Eelco Dolstra
3877619888 * Add some accidentally committed files. 2011-12-21 11:47:52 +00:00
Eelco Dolstra
edd9359beb * Doing a GC after building a derivation with cyclic outputs currently
segfaults.
2011-12-20 17:10:39 +00:00
Eelco Dolstra
1f3b0ede7d * Add a (currently failing) test that checks whether mutually
recursive outputs are properly rejected.
* Add a (also failing) test for "nix-build -A <output-name>".
2011-12-20 17:08:43 +00:00
Eelco Dolstra
46e42c92c1 * Refactor a bit so that more tests can be added. 2011-12-20 17:01:02 +00:00
Eelco Dolstra
b5363810bb * Fix the build. 2011-12-20 16:37:01 +00:00
Eelco Dolstra
194d21f9f6 * Sync with the trunk. 2011-12-16 23:33:01 +00:00
Eelco Dolstra
273b288a7e * importPath() -> importPaths(). Because of buffering of the input
stream it's now necessary for the daemon to process the entire
  sequence of exported paths, rather than letting the client do it.
2011-12-16 22:31:25 +00:00
Eelco Dolstra
8d3dfa2c17 * Avoid expensive conversions from char arrays to STL strings. 2011-12-16 21:29:46 +00:00
Eelco Dolstra
e0bd307802 * Make the import operation through the daemon much more efficient
(way fewer roundtrips) by allowing the client to send data in bigger
  chunks.
* Some refactoring.
2011-12-16 19:44:13 +00:00
Eelco Dolstra
78598d06f0 * Clean up exception handling. 2011-12-16 15:45:42 +00:00
Eelco Dolstra
5a1b9ed0aa * Refactoring: move sink/source buffering into separate classes.
* Buffer the HashSink.  This speeds up hashing a bit because it
  prevents lots of calls to the hash update functions (e.g. nix-hash
  went from 9.3s to 8.7s of user time on the closure of my
  /var/run/current-system).
2011-12-15 16:19:53 +00:00
Eelco Dolstra
a67b8ae224 * Typo. 2011-12-15 14:04:35 +00:00
Eelco Dolstra
a3e0656cbb * Buffer reads in FdSource. Together with write buffering, this
significantly cuts down the number of syscalls (e.g., for "nix-store
  -qR /var/run/current-system" via the daemon, it reduced the number
  of syscalls in the client from 29134 to 4766 and in the daemon from
  44266 to 20666).
2011-12-15 12:32:08 +00:00
Eelco Dolstra
3a48282b06 * Buffer writes in FdSink. This significantly reduces the number of
system calls / context switches when dumping a NAR and in the worker
  protocol.
2011-12-14 23:30:06 +00:00
Eelco Dolstra
893cac1402 * Remove the terminate handler, which was only really needed because
of Berkeley DB (see r8632).
2011-12-14 22:41:10 +00:00
Eelco Dolstra
23bf700196 * Oops, the daemon test wasn't actually using the daemon. 2011-12-14 22:31:31 +00:00
Eelco Dolstra
c8c0380744 * Remove unnecessary quotes. showPaths() already adds quotes. 2011-12-05 21:04:20 +00:00
Eelco Dolstra
000160f5b9 * In ‘nix-store --verify --check-contents’, repair missing hashes
rather than complain about them.
2011-12-02 17:52:18 +00:00
Eelco Dolstra
3964d95abf * nix-prefetch-url: rewritten in Perl. 2011-12-02 12:09:50 +00:00
Eelco Dolstra
92d6a5ed73 * Add some more functions to the Perl bindings. 2011-12-02 12:09:24 +00:00
Eelco Dolstra
49f59dceca * Move parseHash16or32 into libutil, and use in nix-hash. 2011-12-02 11:47:06 +00:00
Eelco Dolstra
b12b21825c * Allow '<nixexpr>' syntax to be used in nix-instantiate, nix-build
and nix-env, e.g.,

  $ nix-env -f '<nixpkgs>' -i patchelf

  or

  $ nix-build '<nixos/tests>' -A login.test
2011-12-01 16:41:43 +00:00
Eelco Dolstra
23c38a04cc * Slight improvement. 2011-12-01 13:51:05 +00:00
Eelco Dolstra
24f863d86b * When doing "nix-store --add-fixed" without "--recursive" via the Nix
daemon (which is an error), print a nicer error message than
  "Connection reset by peer" or "broken pipe".
* In the daemon, log errors that occur during request parameter
  processing.
2011-12-01 13:48:48 +00:00
Peter Simons
be9be4c147 doc/manual/nix-env.xml: fixed "nix-env -qaA" typo 2011-12-01 08:03:30 +00:00
Peter Simons
3c7ec8fc1b doc/manual/nix-env.xml: stripped trailing whitespace 2011-12-01 08:02:37 +00:00
Eelco Dolstra
f35c4351e5 * Don't require a specific Perl version. 2011-11-29 22:15:07 +00:00
Eelco Dolstra
4d0407ba08 * Fix make check. 2011-11-29 13:38:52 +00:00
Eelco Dolstra
1749a7b0ae * download-using-manifests: use the Perl bindings. 2011-11-29 13:01:24 +00:00
Eelco Dolstra
b1eb8f4249 * Get rid of some superfluous error messages if a substituter fails.
* Say "fetch" instead of "substitute".
2011-11-29 13:00:41 +00:00
Eelco Dolstra
216440b3ff * For consistency with "nix-store -q --hash", produce hashes in
base-32.  (This affects Hydra manifests.)
2011-11-29 12:32:55 +00:00
Eelco Dolstra
1df120cb05 * Get rid of the shell in ssh calls. 2011-11-29 10:51:22 +00:00
Eelco Dolstra
784083176a * Fix race. 2011-11-25 17:04:26 +00:00
Eelco Dolstra
f3bc98b001 2011-11-23 15:39:54 +00:00
Eelco Dolstra
10e2b2b79e * Document the --include-outputs option. 2011-11-23 15:39:02 +00:00
Eelco Dolstra
d5ac78e0d6 * Add bzip2 and xz support to nix-copy-closure. 2011-11-23 15:29:58 +00:00
Eelco Dolstra
5bbd693cae * Add an API function exportPaths() that provides the functionality of
‘nix-store --export’.
* Add a Perl module that provides the functionality of
  ‘nix-copy-closure --to’.  This is used by build-remote.pl so it no
  longer needs to start a separate nix-copy-closure process.  Also, it
  uses the Perl API to do the export, so it doesn't need to start a
  separate nix-store process either.  As a result, nix-copy-closure
  and build-remote.pl should no longer fail on very large closures due
  to an "Argument list too long" error.  (Note that having very many
  dependencies in a single derivation can still fail because the
  environment can become too large.  Can't be helped though.)
2011-11-23 15:13:37 +00:00
Eelco Dolstra
ab20af3e6f * build-remote.pl: drop a hard-coded reference to /nix/etc/nix. 2011-11-23 12:21:35 +00:00
Eelco Dolstra
993fa94fb4 * Move initialisation of variables like nixConfDir from libmain to
libstore so that the Perl bindings can use it as well.  It's vital
  that the Perl bindings use the configuration file, because otherwise
  nix-copy-closure will fail with a ‘database locked’ message if the
  value of ‘use-sqlite-wal’ is changed from the default.
2011-11-22 17:28:41 +00:00
Rob Vermaas
4e1ea17052 nix: add /etc/hosts with localhost entry to chroot builds. 2011-11-21 15:19:51 +00:00
Eelco Dolstra
4de3e2a0db * Doh. 2011-11-21 13:22:34 +00:00
Eelco Dolstra
23e933b3b3 * Put back the "sys_name" variable which got removed somewhere. This
broke building on Cygwin and Solaris.
2011-11-21 12:23:48 +00:00
Eelco Dolstra
a6abade8e8 * Escape the [ and ] characters in the sed call, otherwise autoconf
will eat them.
2011-11-21 12:18:26 +00:00
Eelco Dolstra
964399c079 * "sed" on FreeBSD doesn't know the "+" operator. 2011-11-20 19:23:50 +00:00
Eelco Dolstra
b92f76374f * In the platform, canonicalise "amd64" to "x86_64". FreeBSD 8.2's
uname reports amd64.
* Drop the FreeBSD version number, e.g. "i686-freebsd" instead of
  "i686-freebsd8.2".
2011-11-18 17:25:40 +00:00
Ludovic Courtès
42164d6de4 configure: Change i*86 to i686 as has always been done. 2011-11-16 20:58:21 +00:00
Ludovic Courtès
45ec69cbdf configure: Rely on `AC_CANONICAL_HOST' to determine the Nix system name.
This should be more robust and also plays better with
cross-compilation---it uses the host name, instead of using the build
name.
2011-11-16 20:39:59 +00:00
Eelco Dolstra
f8e609c341 * nix-pull: update the Nix manifest cache if necessary. Also, don't
read the manifest just to check the version and print the number of
  paths.  This makes nix-pull very fast for the cached cache (speeding
  up nixos-rebuild without the ‘--no-pull’ or ‘--fast’ options).
2011-11-16 16:41:48 +00:00
Eelco Dolstra
d7d7910ba4 * Don't decompress the manifests in /nix/var/nix/manifest. This saves
disk space, and, since they're typically only decompressed once (to
  fill the manifest cache), doesn't make things slower.
2011-11-16 16:25:38 +00:00
Eelco Dolstra
63ee5e4d2a * Remove obsolete line. 2011-11-16 11:56:19 +00:00
Eelco Dolstra
a5952405d2 * Re-use prepared statements across insertions into the manifest cache
DB.  This speeds up creating the cache from 16.1s to 7.9s on my
  system.
2011-11-16 11:37:40 +00:00
Eelco Dolstra
c0b706213d * Boldly make SQLite WAL mode the default again. Hopefully the
intermittent problems are gone by now.  WAL mode is preferrable
  because it does way fewer fsyncs.
2011-11-07 21:11:59 +00:00
Shea Levy
3c3107da86 There's no need to mess with drvPath at all 2011-11-06 07:18:19 +00:00
Shea Levy
2ab29be70c Fix faulty reversion of my changes to unsafeDiscardOutputDependency 2011-11-06 07:03:14 +00:00
Shea Levy
ca0d47a70c Respect all outputs passed to the derivation, not just the last one 2011-11-06 06:54:05 +00:00
Shea Levy
24b65937e1 Remove the unused sCurrentOutput symbol 2011-11-06 06:28:34 +00:00
Shea Levy
3522730316 Embed output name into the context of the *OutPath attributes and extract it for input derivations
Multiple outputs test passes!
2011-11-06 06:28:30 +00:00
Shea Levy
46876ff203 Fix stupid typo in multiple outputs test 2011-11-06 06:28:25 +00:00
Shea Levy
af2e53fd48 Include all outputs of derivations in the closure of explicitly-passed derivation paths
This required adding a queryOutputDerivationNames function in the store API
2011-11-06 06:28:20 +00:00
Shea Levy
981edeab7b The 'insert output between = signs' approach was not helpful 2011-11-06 06:28:14 +00:00
Shea Levy
f883afa1a1 The nixinstantiate and nixstore env vars are no longer set in common.sh 2011-11-06 06:28:08 +00:00
Shea Levy
2721e9f56f Merge from trunk 2011-11-06 00:13:09 +00:00
Eelco Dolstra
a6a3f3a8c2 * Fix race condition in the test. 2011-11-05 21:23:01 +00:00
Eelco Dolstra
fa69ff5726 * Fix the broken reference to bunzip2 in the channel unpack script. 2011-11-05 21:06:24 +00:00
Eelco Dolstra
daed9aeac5 2011-11-03 19:22:24 +00:00
Eelco Dolstra
d7b87bebe3 * The Nix configuration file is usually /etc/nix/nix.conf. 2011-11-03 18:47:10 +00:00
Eelco Dolstra
325b5a8aee * Fix permission on /nix/store in the manual for multi-user installs
(reported by Silvio Frischknecht).
2011-11-02 19:14:54 +00:00
Eelco Dolstra
a12095d3be * In printValueAsXML, handle the case where a "type" attribute is not
a string.  This happens in the NixOS option system.
* Remove a bogus comparison of a unsigned integer with -1.
2011-10-27 19:06:23 +00:00
Eelco Dolstra
00b41e46ed * Print a consistent message. 2011-10-19 21:34:13 +00:00
Eelco Dolstra
f186a9141e * nix-copy-closure: support ‘--dry-run’ and ‘--include-outputs’. 2011-10-18 21:21:22 +00:00
Eelco Dolstra
6761757428 * Use the Store API bindings in nix-copy-closure. 2011-10-11 15:41:13 +00:00
Eelco Dolstra
d43a148204 * Add a test for nix-copy-closure. 2011-10-11 13:58:47 +00:00
Eelco Dolstra
2492914fbc * Move the remote building test from the NixOS tree to the Nix tree. 2011-10-11 13:06:59 +00:00
Eelco Dolstra
c362e4d718 * Move SSH.pm. 2011-10-11 11:45:36 +00:00
Eelco Dolstra
7d314b8c95 * Work around a race condition starting the Nix daemon. 2011-10-11 11:14:30 +00:00
Eelco Dolstra
5193db048e * Set svn:ignore. 2011-10-11 09:32:34 +00:00
Eelco Dolstra
a2a317eb0b * Distribute GeneratePatches.pm. 2011-10-11 09:31:55 +00:00
Eelco Dolstra
5090c34ee1 * Set the executable bit on scripts. 2011-10-10 22:40:17 +00:00
Eelco Dolstra
8af7d766f0 * Refactoring: remove unnecessary variables from the tests. 2011-10-10 21:32:34 +00:00
Eelco Dolstra
cd6d02c366 2011-10-10 21:30:59 +00:00
Eelco Dolstra
6fcdbcac20 * Install NixManifest.pm, NixConfig.pm and GeneratePatches.pm under
the Nix:: namespace.
2011-10-10 21:11:08 +00:00
Eelco Dolstra
659c427caa * Hopefully perl-devel contains the required headers (untested). 2011-10-10 18:58:49 +00:00
Eelco Dolstra
73fe6871c4 * Include the Nix Perl bindings in Nix itself. This will allow the
bindings to be used in Nix's own Perl scripts.

  The only downside is that Perl XS and Automake/libtool don't really
  like each other, so building is a bit tricky.
2011-10-10 18:12:40 +00:00
Shea Levy
bffe35aced Update gitignore 2011-09-19 04:36:49 +00:00
Shea Levy
6c38cc9025 Ignore everything created during build 2011-09-19 04:15:26 +00:00
Eelco Dolstra
55481c44d4 * Don't assume that we want a shared Nix store. 2011-09-17 09:53:31 +00:00
Shea Levy
e81c09edbf Remove the current output metadata from the string for unsaveDiscardOutputDependency 2011-09-16 11:31:00 +00:00
Shea Levy
bf50d6ad32 Add information about which output is active to drvPath's context
This will break things that depend on being able to just strip away an equals sign, so those have to be updated next
2011-09-16 11:30:52 +00:00
Shea Levy
ffa038f66d Add an sCurrentOutput member to EvalState 2011-09-16 11:30:44 +00:00
Shea Levy
f3e410d4bf Add a currentOutput attribute to derivations keep track of which output is active 2011-09-16 11:30:03 +00:00
Shea Levy
8f28a3ba25 Add a test for multiple outputs
This currently fails. Yay test-driven development!
2011-09-14 05:59:29 +00:00
Shea Levy
c172d16b00 First attempt at the output-as-derivation semantics
For each output, this adds a corresponding attribute to the derivation that is
the same as the derivation except for outPath, which is set to the path specific
to that output. Additionally, an "all" attribute is added that is a list of all
of the output derivations. This has to be done outside of derivationStrict as
each output is itself a derivation that contains itself (and all other outputs)
as an attribute. The derivation itself is equivalent to the first output in the
outputs list (or "out" if that list isn't set).
2011-09-14 05:59:17 +00:00
Shea Levy
0b34e57eb8 Create a branch for me to play around with finishing off the multiple outputs implementation 2011-09-14 00:41:02 +00:00
Eelco Dolstra
13114daa3e * Ouch. A store upgrade could cause a substituter to be triggered,
causing a deadlock.
2011-09-12 09:07:43 +00:00
Ludovic Courtès
281e3ed059 bootstrap: Simplify & make more robust. 2011-09-06 12:11:05 +00:00
Eelco Dolstra
e6cb3d0a0d * Added a command ‘nix-store --verify-paths PATHS’ to check whether
the contents of any of the given store paths have been modified.
  E.g.

    $ nix-store --verify-path $(nix-store -qR /var/run/current-system)
    path `/nix/store/m2smyiwbxidlprfxfz4rjlvz2c3mg58y-etc' was modified! expected hash `fc87e271c5fdf179b47939b08ad13440493805584b35e3014109d04d8436e7b8', got `20f1a47281b3c0cbe299ce47ad5ca7340b20ab34246426915fce0ee9116483aa'

  All paths are checked; the exit code is 1 if any path has been
  modified, 0 otherwise.
2011-09-06 12:06:30 +00:00
Eelco Dolstra
82710f96f7 * Add some -f flags, never hurts. 2011-09-06 12:00:11 +00:00
Eelco Dolstra
93227ff65c * Eliminate all uses of the global variable ‘store’ from libstore.
This should also fix:

    nix-instantiate: ./../boost/shared_ptr.hpp:254: T* boost::shared_ptr<T>::operator->() const [with T = nix::StoreAPI]: Assertion `px != 0' failed.

  which was caused by hashDerivationModulo() calling the ‘store’
  object (during store upgrades) before openStore() assigned it.
2011-08-31 21:11:50 +00:00
Eelco Dolstra
5bcdc7e351 * Update the cleanup script. 2011-08-27 16:59:32 +00:00
Eelco Dolstra
a95ba4cdd9 * Use last_insert_id instead of sqlite_last_insert_rowid, which you're
not really supposed to use according to the DBD::SQLite docs, and
  fails on some systems (e.g. http://hydra.nixos.org/build/1246662).
2011-08-17 14:17:19 +00:00
Eelco Dolstra
da18b11b05 * On FreeBSD, ‘touch’ is not in the test $PATH, so don't use it. 2011-08-08 14:08:38 +00:00
Eelco Dolstra
76e0029f7a * Add perl-DBD-SQLite as a dependency of the RPM builds. 2011-08-08 14:06:10 +00:00
Eelco Dolstra
d374be551d * Add DBD-SQLite as a dependency to the Debian/Ubuntu builds.
* Drop some old Fedora/Debian/Ubuntu releases.
2011-08-08 13:19:00 +00:00
Eelco Dolstra
2d663b502d * Cache the result of file evaluation (i.e, memoize evalFile()). This
prevents files from being evaluated and stored as values multiple
  times.  For instance, evaluation of the ‘system’ attribute in NixOS
  causes ‘nixpkgs/pkgs/lib/lists.nix’ to be evaluated 2019 times.

  Caching gives a modest speedup and a decent memory footprint
  reduction (e.g., from 1.44s to 1.28s, and from 81 MiB to 59 MiB with
  GC_INITIAL_HEAP_SIZE=100000 on my system).
2011-08-06 19:45:43 +00:00
Eelco Dolstra
510033e783 * Handle <path> syntax. 2011-08-06 18:54:29 +00:00
Eelco Dolstra
9d091ee99a * Handle the case where the search path element is a regular file. 2011-08-06 18:45:28 +00:00
Eelco Dolstra
00a724ebc6 * Remove a debug statement. 2011-08-06 18:24:43 +00:00
Eelco Dolstra
07340b8be7 * Add the Nix corepkgs to the end of the search path. This makes it
possible for other Nix expressions to use corepkgs (mostly useful
  for the buildenv function).
2011-08-06 18:23:38 +00:00
Eelco Dolstra
c7101dac0b * Allow redirections in search path entries. E.g. if you have a
directory

    /home/eelco/src/stdenv-updates

  that you want to use as the directory for import such as

    with (import <nixpkgs> { });

  then you can say

    $ nix-build -I nixpkgs=/home/eelco/src/stdenv-updates
2011-08-06 17:48:57 +00:00
Eelco Dolstra
1578b2261d * Add lang/dir* to the distribution. 2011-08-06 16:18:54 +00:00
Eelco Dolstra
1ecc97b6bd * Add a Nix expression search path feature. Paths between angle
brackets, e.g.

    import <nixpkgs/pkgs/lib>

  are resolved by looking them up relative to the elements listed in
  the search path.  This allows us to get rid of hacks like

    import "${builtins.getEnv "NIXPKGS_ALL"}/pkgs/lib"

  The search path can be specified through the ‘-I’ command-line flag
  and through the colon-separated ‘NIX_PATH’ environment variable,
  e.g.,

    $ nix-build -I /etc/nixos ...

  If a file is not found in the search path, an error message is
  lazily thrown.
2011-08-06 16:05:24 +00:00
Eelco Dolstra
54945a2950 * Refactoring: move parseExprFromFile() and parseExprFromString() into
the EvalState class.
2011-08-06 13:02:55 +00:00
Eelco Dolstra
c8606664ab * Don't allow derivations with fixed and non-fixed outputs. 2011-07-20 18:26:00 +00:00
Eelco Dolstra
b2027f70d9 * Fix a huuuuge security hole in the Nix daemon. It didn't check that
derivations added to the store by clients have "correct" output
  paths (meaning that the output paths are computed by hashing the
  derivation according to a certain algorithm).  This means that a
  malicious user could craft a special .drv file to build *any*
  desired path in the store with any desired contents (so long as the
  path doesn't already exist).  Then the attacker just needs to wait
  for a victim to come along and install the compromised path.

  For instance, if Alice (the attacker) knows that the latest Firefox
  derivation in Nixpkgs produces the path

    /nix/store/1a5nyfd4ajxbyy97r1fslhgrv70gj8a7-firefox-5.0.1

  then (provided this path doesn't already exist) she can craft a .drv
  file that creates that path (i.e., has it as one of its outputs),
  add it to the store using "nix-store --add", and build it with
  "nix-store -r".  So the fake .drv could write a Trojan to the
  Firefox path.  Then, if user Bob (the victim) comes along and does

    $ nix-env -i firefox
    $ firefox

  he executes the Trojan injected by Alice.

  The fix is to have the Nix daemon verify that derivation outputs are
  correct (in addValidPath()).  This required some refactoring to move
  the hash computation code to libstore.
2011-07-20 18:10:47 +00:00
Eelco Dolstra
d2bfe1b071 * Added a test that make sure that users cannot register
specially-crafted derivations that produce output paths belonging to
  other derivations.  This could be used to inject malware into the
  store.
2011-07-20 12:15:40 +00:00
Eelco Dolstra
4bdb51e621 * Refactoring. 2011-07-20 11:50:13 +00:00
Eelco Dolstra
0243eea4b9 * Create a symlink to /nix/var/nix/manifests in /nix/var/nix/gcroots
if it doesn't exist.
2011-07-20 11:47:00 +00:00
Eelco Dolstra
d329c3ea9d * Support multiple outputs. A derivation can declare multiple outputs
by setting the ‘outputs’ attribute.  For example:

    stdenv.mkDerivation {
      name = "aterm-2.5";

      src = ...;

      outputs = [ "out" "tools" "dev" ];

      configureFlags = "--bindir=$(tools)/bin --includedir=$(dev)/include";
    }

  This derivation creates three outputs, named like this:

    /nix/store/gcnqgllbh01p3d448q8q6pzn2nc2gpyl-aterm-2.5
    /nix/store/gjf1sgirwfnrlr0bdxyrwzpw2r304j02-aterm-2.5-tools
    /nix/store/hp6108bqfgxvza25nnxfs7kj88xi2vdx-aterm-2.5-dev

  That is, the symbolic name of the output is suffixed to the store
  path (except for the ‘out’ output).  Each path is passed to the
  builder through the corresponding environment variable, e.g.,
  ${tools}.

  The main reason for multiple outputs is to allow parts of a package
  to be distributed and garbage-collected separately.  For instance,
  most packages depend on Glibc for its libraries, but don't need its
  header files.  If these are separated into different store paths,
  then a package that depends on the Glibc libraries only causes the
  libraries and not the headers to be downloaded.

  The main problem with multiple outputs is that if one output exists
  while the others have been garbage-collected (or never downloaded in
  the first place), and we want to rebuild the other outputs, then
  this isn't possible because we can't clobber a valid output (it
  might be in active use).  This currently gives an error message
  like:

    error: derivation `/nix/store/1s9zw4c8qydpjyrayxamx2z7zzp5pcgh-aterm-2.5.drv' is blocked by its output paths

  There are two solutions: 1) Do the build in a chroot.  Then we don't
  need to overwrite the existing path.  2) Use hash rewriting (see the
  ASE-2005 paper).  Scary but it should work.

  This is not finished yet.  There is not yet an easy way to refer to
  non-default outputs in Nix expressions.  Also, mutually recursive
  outputs aren't detected yet and cause the garbage collector to
  crash.
2011-07-18 23:31:03 +00:00
Eelco Dolstra
d9a5959139 * Show the default for --with-store-dir (Nix/211). 2011-07-13 15:57:44 +00:00
Eelco Dolstra
d5d4dcd4c9 * Allow attribute names to be strings. Based on the
allow-arbitrary-strinsg-in-names patch by Marc Weber.
2011-07-13 15:53:24 +00:00
Eelco Dolstra
e649f3168b * Fix concurrency issues in download-using-manifests' handling of the
SQLite manifest cache.  The DBI AutoCommit feature caused every
  process to have an active transaction at all times, which could
  indefinitely block processes wanting to update the manifest cache.

* Disable fsync() in the manifest cache because we don't need
  integrity (the cache can always be recreated if it gets corrupted).
2011-07-13 14:05:54 +00:00
Eelco Dolstra
0a623a10c7 * Allow a default value in attribute selection by writing
x.y.z or default

  (as originally proposed in
  https://mail.cs.uu.nl/pipermail/nix-dev/2009-September/002989.html).

  For instance, an expression like

    stdenv.lib.attrByPath ["features" "ckSched"] false args

  can now be written as

    args.features.ckSched or false
2011-07-13 12:19:57 +00:00
Eelco Dolstra
2b9e29b1c8 * Change the right-hand side of the ‘.’ operator from an attribute to
an attribute path.  This is a refactoring to support default values.
2011-07-06 12:28:57 +00:00
Eelco Dolstra
5580f3817c * Test case. 2011-07-06 10:58:53 +00:00
Eelco Dolstra
5637037802 * In the ‘?’ operator, allow attribute paths. For instance, you can
write ‘attrs ? a.b’ to test whether ‘attrs’ has an attribute ‘a’
  containing an attribute ‘b’.  This is more convenient than ‘attrs ?
  a && attrs.a ? b’.

  Slight change in the semantics: it's no longer an error if the
  left-hand side of ‘?’ is not an attribute set.  In that case it just
  returns false.  So, ‘null ? foo’ no longer throws an error.
2011-07-06 10:58:17 +00:00
Eelco Dolstra
34f4b91820 2011-07-04 14:44:53 +00:00
Ludovic Courtès
1ea6e06445 doc: Fix typo. 2011-06-30 15:48:40 +00:00
Ludovic Courtès
5c9e9f732d Add support for the build-timeout' and --timeout' options. 2011-06-30 15:19:13 +00:00
Eelco Dolstra
9c99aa2620 2011-06-27 09:01:09 +00:00
Eelco Dolstra
e4d8148585 2011-06-27 08:04:54 +00:00
Eelco Dolstra
4891b21f34 * Use SQLite 3.7.6.2. 2011-05-03 16:17:24 +00:00
Eelco Dolstra
d94cb02bfe * nix-install-package: unset NIX_REMOTE because $NIX_MANIFESTS_DIR
doesn't work when building through the Nix daemon.  This also
  ensures an error message when the user doesn't have sufficient
  privileges to do nix-pull.
2011-04-19 10:52:35 +00:00
Eelco Dolstra
8c69dac8a1 * Handle error messages from the Nix worker containing the `%'
character.  (Nix/216)
2011-04-19 10:44:44 +00:00
Eelco Dolstra
4ba6afaf48 * nix-env -ub' (--prebuilt-only') didn't really work because it
checked too soon whether substitutes are available.  That is, it did
  so for every available package, rather than those matching installed
  packages.  This was very slow and subject to assertion failures.  So
  do the check much later.  Idem for `nix-env -qab' and `nix-env -ib'.
2011-04-11 16:27:05 +00:00
Eelco Dolstra
412914d004 * Read manifests directly into the database, rather than first reading
them into memory.  This brings memory use down to (more or less)
  O(1).  For instance, on my test case, the maximum resident size of
  download-using-manifests while filling the DB went from 142 MiB to
  11 MiB.
2011-04-11 13:16:54 +00:00
Eelco Dolstra
08c8971498 * Lock the database during updates. 2011-04-11 12:40:13 +00:00
Eelco Dolstra
b2c11b9ed0 2011-04-11 10:23:15 +00:00
Eelco Dolstra
3cbf680f5d * configure: detect whether DBD::SQLite is present. If necessary the
location to DBI and DBD::SQLite can be passed with --with-dbi and
  --with-dbd-sqlite.
2011-04-11 10:13:53 +00:00
Eelco Dolstra
83252b4ca9 * Subtle bug: if you import File::stat in one module, it affects other
modules as well.  So use symbolic field names everywhere (which is
  nicer anyway).
2011-04-11 08:21:30 +00:00
Eelco Dolstra
b1882c3ef7 * Create $manifestDir if it doesn't exist. 2011-04-11 08:06:14 +00:00
Eelco Dolstra
5591fcc529 * Cache the manifests in /nix/var/nix/manifests in a SQLite database.
This significantly speeds up the download-using-manifests
  substituter, especially if manifests are very large.  For instance,
  one "nix-build -A geeqie" operation that updated four packages using
  binary patches went from 18.5s to 1.6s.  It also significantly
  reduces memory use.

  The cache is kept in /nix/var/nix/manifests/cache.sqlite.  It's
  updated automatically when manifests are added to or removed from
  /nix/var/nix/manifests.  It might be interesting to have nix-pull
  store manifests directly in the DB, rather than storing them as
  separate flat files, but then we would need a command line interface
  to delete manifests from the DB.
2011-04-10 23:22:46 +00:00
Eelco Dolstra
1e7e4f21ba * Remove the localPaths feature in manifests since it's no longer used
and redundant anyway.
2011-04-06 09:16:22 +00:00
Eelco Dolstra
0423d0692a * Print a better error message. 2011-03-16 15:55:57 +00:00
Eelco Dolstra
48bdbbf070 * Fix a bug in the documentation (reported by Olexiy Buyanskyy,
Nix/215).
2011-03-15 13:12:59 +00:00
Eelco Dolstra
802c2651c8 2011-02-17 15:08:33 +00:00
Eelco Dolstra
e945b52a31 * nix-push: handle the case where the hash is not set in the DB. 2011-02-17 13:26:33 +00:00
Eelco Dolstra
c3cee5395b * Build for Ubuntu 10.04. 2011-02-14 14:56:02 +00:00
Florian Friesdorf
8fcaf3e9c6 make nix-mode provide 'nix-mode
this enables (require 'nix-mode)
2011-02-14 03:11:56 +00:00
Eelco Dolstra
538b7caab0 * Don't allocate a big initial GC address space on machines with
little RAM.  Even if the memory isn't actually used, it can cause
  problems with the overcommit heuristics in the kernel.  So use a VM
  space of 25% of RAM, up to 384 MB.
2011-02-10 14:31:04 +00:00
Eelco Dolstra
5a6b039802 * Don't call GC_expand_hp unless we're actually using the garbage
collector.
2011-02-09 22:59:50 +00:00
Ludovic Courtès
f1462c208b Use $BDW_GC_LIBS instead of a custom variable. 2011-02-09 21:23:13 +00:00
Eelco Dolstra
1876ab764f * A better fix. $boehmgc isn't set anywhere, we should use the flags
returned by pkg-config.
2011-02-09 14:13:09 +00:00
Eelco Dolstra
dfc4117e90 * The GC library can't be found on Solaris
(http://hydra.nixos.org/build/890714), so don't build with GC
  support for now.
2011-02-09 14:08:32 +00:00
Eelco Dolstra
d159ea1b7e * Urgh, FreeBSD doesn't have a "seq" command. 2011-02-09 14:03:16 +00:00
Eelco Dolstra
3087b3f751 * Obsolete. 2011-02-09 12:48:54 +00:00
Eelco Dolstra
eb94581d39 * Remove obsolete directory. 2011-02-09 12:43:44 +00:00
Eelco Dolstra
7bba67c401 * Remove obsolete file. 2011-02-09 12:42:15 +00:00
Eelco Dolstra
d0eda1f3e9 * Merged the SQLite branch. 2011-02-09 12:41:54 +00:00
198 changed files with 3714 additions and 2874 deletions

27
.gitignore vendored
View File

@@ -61,23 +61,11 @@
# /externals/
/externals/Makefile
/externals/Makefile.in
/externals/aterm-*
/externals/have-aterm
/externals/build-aterm
/externals/inst-aterm
/externals/bzip2-*
/externals/have-bzip2
/externals/build-bzip2
/externals/inst-bzip2
# /make/examples/aterm/
/make/examples/aterm/result*
# /make/examples/aterm/aterm/
/make/examples/aterm/aterm/*
# /make/examples/aterm/test/
/make/examples/aterm/test/*
/externals/sqlite-*
/externals/build-sqlite
# /misc/
/misc/Makefile.in
@@ -100,13 +88,16 @@
/scripts/nix-channel
/scripts/nix-build
/scripts/nix-copy-closure
/scripts/readmanifest.pm
/scripts/readconfig.pm
/scripts/nix-generate-patches
/scripts/NixConfig.pm
/scripts/NixManifest.pm
/scripts/GeneratePatches.pm
/scripts/download-using-manifests.pl
/scripts/copy-from-other-stores.pl
/scripts/generate-patches.pl
/scripts/find-runtime-roots.pl
/scripts/build-remote.pl
/scripts/nix-reduce-build
/scripts/nix-http-export.cgi
# /src/
/src/Makefile
@@ -168,6 +159,7 @@
/src/libstore/derivations-ast.cc
/src/libstore/derivations-ast.hh
/src/libstore/.libs
/src/libstore/schema.sql.hh
# /src/libutil/
/src/libutil/Makefile
@@ -242,6 +234,7 @@
/tests/config.nix
/tests/common.sh
/tests/dummy
/tests/result*
# /tests/lang/
/tests/lang/*.out

View File

@@ -1,4 +1,4 @@
SUBDIRS = externals src scripts corepkgs doc misc tests
SUBDIRS = externals src perl scripts corepkgs doc misc tests
EXTRA_DIST = substitute.mk nix.spec nix.spec.in bootstrap.sh \
nix.conf.example NEWS version
@@ -33,7 +33,7 @@ init-state:
$(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) -m 1777 -d $(DESTDIR)$(storedir)
-$(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

View File

@@ -1,149 +0,0 @@
{
ATerm library conservatively scans for GC roots
Memcheck:Cond
fun:*
fun:AT_collect_minor
}
{
ATerm library conservatively scans for GC roots
Memcheck:Cond
fun:*
fun:*
fun:AT_collect_minor
}
{
ATerm library conservatively scans for GC roots
Memcheck:Value4
fun:*
fun:AT_collect_minor
}
{
ATerm library conservatively scans for GC roots
Memcheck:Value8
fun:*
fun:AT_collect_minor
}
{
ATerm library conservatively scans for GC roots
Memcheck:Value4
fun:*
fun:*
fun:AT_collect_minor
}
{
ATerm library conservatively scans for GC roots
Memcheck:Value8
fun:*
fun:*
fun:AT_collect_minor
}
{
ATerm library conservatively scans for GC roots
Memcheck:Addr4
fun:*
fun:AT_collect_minor
}
{
ATerm library conservatively scans for GC roots
Memcheck:Addr8
fun:*
fun:AT_collect_minor
}
{
ATerm library conservatively scans for GC roots
Memcheck:Cond
fun:*
fun:AT_collect
}
{
ATerm library conservatively scans for GC roots
Memcheck:Value4
fun:*
fun:AT_collect
}
{
ATerm library conservatively scans for GC roots
Memcheck:Value8
fun:*
fun:AT_collect
}
{
ATerm library conservatively scans for GC roots
Memcheck:Addr4
fun:*
fun:AT_collect
}
{
ATerm library conservatively scans for GC roots
Memcheck:Addr8
fun:*
fun:AT_collect
}
{
ATerm library conservatively scans for GC roots
Memcheck:Value4
fun:*
fun:*
fun:AT_collect
}
{
ATerm library conservatively scans for GC roots
Memcheck:Value8
fun:*
fun:*
fun:AT_collect
}
{
ATerm library conservatively scans for GC roots
Memcheck:Cond
fun:*
fun:*
fun:AT_collect
}
{
ATerm library conservatively scans for GC roots
Memcheck:Value4
fun:*
fun:*
fun:mark_phase
}
{
ATerm library conservatively scans for GC roots
Memcheck:Cond
fun:*
fun:*
fun:mark_phase
}
{
ATerm library conservatively scans for GC roots
Memcheck:Value4
fun:*
fun:*
fun:mark_phase_young
}
{
ATerm library conservatively scans for GC roots
Memcheck:Cond
fun:*
fun:*
fun:mark_phase_young
}

View File

@@ -1,252 +0,0 @@
#! /usr/bin/perl -w -I /home/eelco/.nix-profile/lib/site_perl
use strict;
use XML::LibXML;
#use XML::Simple;
my $blacklistFN = shift @ARGV;
die unless defined $blacklistFN;
my $userEnv = shift @ARGV;
die unless defined $userEnv;
# Read the blacklist.
my $parser = XML::LibXML->new();
my $blacklist = $parser->parse_file($blacklistFN)->getDocumentElement;
#print $blacklist->toString() , "\n";
# Get all the elements of the user environment.
my $userEnvElems = `nix-store --query --references '$userEnv'`;
die "cannot query user environment elements" if $? != 0;
my @userEnvElems = split ' ', $userEnvElems;
my %storePathHashes;
sub getElemNodes {
my $node = shift;
my @elems = ();
foreach my $node ($node->getChildNodes) {
push @elems, $node if $node->nodeType == XML_ELEMENT_NODE;
}
return @elems;
}
my %referencesCache;
sub getReferences {
my $path = shift;
return $referencesCache{$path} if defined $referencesCache{$path};
my $references = `nix-store --query --references '$path'`;
die "cannot query references" if $? != 0;
$referencesCache{$path} = [split ' ', $references];
return $referencesCache{$path};
}
my %attrsCache;
sub getAttr {
my $path = shift;
my $name = shift;
my $key = "$path/$name";
return $referencesCache{$key} if defined $referencesCache{$key};
my $value = `nix-store --query --binding '$name' '$path' 2> /dev/null`;
$value = "" if $? != 0; # !!!
chomp $value;
$referencesCache{$key} = $value;
return $value;
}
sub evalCondition;
sub traverse {
my $done = shift;
my $set = shift;
my $path = shift;
my $stopCondition = shift;
return if defined $done->{$path};
$done->{$path} = 1;
$set->{$path} = 1;
# print " in $path\n";
if (!evalCondition({$path => 1}, $stopCondition)) {
# print " STOPPING in $path\n";
return;
}
# Get the requisites of the deriver.
foreach my $reference (@{getReferences $path}) {
traverse($done, $set, $reference, $stopCondition);
}
}
sub evalSet {
my $inSet = shift;
my $expr = shift;
my $name = $expr->getName;
if ($name eq "traverse") {
my $stopCondition = (getElemNodes $expr)[0];
my $done = { };
my $set = { };
foreach my $path (keys %{$inSet}) {
traverse($done, $set, $path, $stopCondition);
}
return $set;
}
else {
die "unknown element `$name'";
}
}
# Function for evaluating conditions.
sub evalCondition {
my $storePaths = shift;
my $condition = shift;
my $elemName = $condition->getName;
if ($elemName eq "containsSource") {
my $hash = $condition->attributes->getNamedItem("hash")->getValue;
foreach my $path (keys %{$storePathHashes{$hash}}) {
return 1 if defined $storePaths->{$path};
}
return 0;
}
elsif ($elemName eq "hasName") {
my $nameRE = $condition->attributes->getNamedItem("name")->getValue;
foreach my $path (keys %{$storePaths}) {
return 1 if $path =~ /$nameRE/;
}
return 0;
}
elsif ($elemName eq "hasAttr") {
my $name = $condition->attributes->getNamedItem("name")->getValue;
my $valueRE = $condition->attributes->getNamedItem("value")->getValue;
foreach my $path (keys %{$storePaths}) {
if ($path =~ /\.drv$/) {
my $value = getAttr($path, $name);
# print " $path $name $value\n";
return 1 if $value =~ /$valueRE/;
}
}
return 0;
}
elsif ($elemName eq "and") {
my $result = 1;
foreach my $node (getElemNodes $condition) {
$result &= evalCondition($storePaths, $node);
}
return $result;
}
elsif ($elemName eq "not") {
return !evalCondition($storePaths, (getElemNodes $condition)[0]);
}
elsif ($elemName eq "within") {
my @elems = getElemNodes $condition;
my $set = evalSet($storePaths, $elems[0]);
return evalCondition($set, $elems[1]);
}
elsif ($elemName eq "true") {
return 1;
}
elsif ($elemName eq "false") {
return 0;
}
else {
die "unknown element `$elemName'";
}
}
sub evalOr {
my $storePaths = shift;
my $nodes = shift;
my $result = 0;
foreach my $node (@{$nodes}) {
$result |= evalCondition($storePaths, $node);
}
return $result;
}
# Iterate over all elements, check them.
foreach my $userEnvElem (@userEnvElems) {
# Get the deriver of this path.
my $deriver = `nix-store --query --deriver '$userEnvElem'`;
die "cannot query deriver" if $? != 0;
chomp $deriver;
if ($deriver eq "unknown-deriver") {
# print " deriver unknown, cannot check sources\n";
next;
}
print "CHECKING $userEnvElem\n";
# Get the requisites of the deriver.
# my $requisites = `nix-store --query --requisites --include-outputs '$deriver'`;
# die "cannot query requisites" if $? != 0;
# my @requisites = split ' ', $requisites;
# Get the hashes of the requisites.
# my $hashes = `nix-store --query --hash @requisites`;
# die "cannot query hashes" if $? != 0;
# my @hashes = split ' ', $hashes;
# for (my $i = 0; $i < scalar @requisites; $i++) {
# die unless $i < scalar @hashes;
# my $hash = $hashes[$i];
# $storePathHashes{$hash} = {} unless defined $storePathHashes{$hash};
# my $r = $storePathHashes{$hash}; # !!! fix
# $$r{$requisites[$i]} = 1;
# }
# Evaluate each blacklist item.
foreach my $item ($blacklist->getChildrenByTagName("item")) {
my $itemId = $item->getAttributeNode("id")->getValue;
# print " CHECKING FOR $itemId\n";
my $condition = ($item->getChildrenByTagName("condition"))[0];
die unless $condition;
# Evaluate the condition.
my @elems = getElemNodes $condition;
if (evalOr({$deriver => 1}, \@elems)) {
# Oops, condition triggered.
my $reason = ($item->getChildrenByTagName("reason"))[0]->getChildNodes->to_literal;
$reason =~ s/\s+/ /g;
$reason =~ s/^\s+//g;
print " VULNERABLE TO `$itemId': $reason\n";
}
}
}

View File

@@ -1,8 +1,4 @@
#! /bin/sh -e
rm -f aclocal.m4
mkdir -p config
libtoolize --copy
aclocal
autoheader
automake --add-missing --copy
autoconf
exec autoreconf -vfi

View File

@@ -5,42 +5,42 @@ AM_INIT_AUTOMAKE([dist-bzip2 foreign])
AC_DEFINE_UNQUOTED(NIX_VERSION, ["$VERSION"], [Nix version.])
AC_CANONICAL_HOST
AC_PROG_SED
# Construct a Nix system name (like "i686-linux").
AC_CANONICAL_HOST
AC_MSG_CHECKING([for the canonical Nix system name])
cpu_name=$(uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ ' 'abcdefghijklmnopqrstuvwxyz_')
machine_name=$(uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ ' 'abcdefghijklmnopqrstuvwxyz_')
case $machine_name in
i*86)
machine_name=i686
;;
x86_64)
machine_name=x86_64
;;
ppc)
machine_name=powerpc
;;
*)
if test "$cpu_name" != "unknown"; then
machine_name=$cpu_name
fi
;;
esac
AC_ARG_WITH(system, AC_HELP_STRING([--with-system=SYSTEM],
[Platform identifier (e.g., `i686-linux').]),
[system=$withval],
[case "$host_cpu" in
i*86)
machine_name="i686";;
amd64)
machine_name="x86_64";;
*)
machine_name="$host_cpu";;
esac
sys_name=$(uname -s | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ ' 'abcdefghijklmnopqrstuvwxyz_')
case "$host_os" in
linux-gnu*)
# For backward compatibility, strip the `-gnu' part.
system="$machine_name-linux";;
*)
# Strip the version number from names such as `gnu0.3',
# `darwin10.2.0', etc.
system="$machine_name-`echo $host_os | "$SED" -e's/@<:@0-9.@:>@*$//g'`";;
esac])
sys_name=$(uname -s | tr 'A-Z ' 'a-z_')
case $sys_name in
cygwin*)
sys_name=cygwin
;;
esac
AC_ARG_WITH(system, AC_HELP_STRING([--with-system=SYSTEM],
[Platform identifier (e.g., `i686-linux').]),
system=$withval, system="${machine_name}-${sys_name}")
AC_MSG_RESULT($system)
AC_SUBST(system)
AC_DEFINE_UNQUOTED(SYSTEM, ["$system"], [platform identifier (`cpu-os')])
@@ -62,7 +62,7 @@ fi
# Solaris-specific stuff.
if test "$sys_name" = "sunos"; then
if test "$sys_name" = sunos; then
# Solaris requires -lsocket -lnsl for network functions
LIBS="-lsocket -lnsl $LIBS"
fi
@@ -171,6 +171,7 @@ AC_PATH_PROG(openssl_prog, openssl, openssl) # if not found, call openssl in $PA
AC_SUBST(openssl_prog)
AC_DEFINE_UNQUOTED(OPENSSL_PATH, ["$openssl_prog"], [Path of the OpenSSL binary])
# Test that Perl has the open/fork feature (Perl 5.8.0 and beyond).
AC_MSG_CHECKING([whether Perl is recent enough])
if ! $perl -e 'open(FOO, "-|", "true"); while (<FOO>) { print; }; close FOO or die;'; then
@@ -179,6 +180,7 @@ if ! $perl -e 'open(FOO, "-|", "true"); while (<FOO>) { print; }; close FOO or d
fi
AC_MSG_RESULT(yes)
NEED_PROG(cat, cat)
NEED_PROG(tr, tr)
AC_ARG_WITH(coreutils-bin, AC_HELP_STRING([--with-coreutils-bin=PATH],
@@ -186,6 +188,7 @@ AC_ARG_WITH(coreutils-bin, AC_HELP_STRING([--with-coreutils-bin=PATH],
coreutils=$withval, coreutils=$(dirname $cat))
AC_SUBST(coreutils)
AC_ARG_WITH(docbook-rng, AC_HELP_STRING([--with-docbook-rng=PATH],
[path of the DocBook RelaxNG schema]),
docbookrng=$withval, docbookrng=/docbook-rng-missing)
@@ -196,16 +199,19 @@ AC_ARG_WITH(docbook-xsl, AC_HELP_STRING([--with-docbook-xsl=PATH],
docbookxsl=$withval, docbookxsl=/docbook-xsl-missing)
AC_SUBST(docbookxsl)
AC_ARG_WITH(xml-flags, AC_HELP_STRING([--with-xml-flags=FLAGS],
[extra flags to be passed to xmllint and xsltproc]),
xmlflags=$withval, xmlflags=)
AC_SUBST(xmlflags)
AC_ARG_WITH(store-dir, AC_HELP_STRING([--with-store-dir=PATH],
[path of the Nix store]),
[path of the Nix store (defaults to /nix/store)]),
storedir=$withval, storedir='/nix/store')
AC_SUBST(storedir)
AC_ARG_WITH(openssl, AC_HELP_STRING([--with-openssl=PATH],
[prefix of the OpenSSL library]),
openssl=$withval, openssl=)
@@ -217,6 +223,7 @@ if test -n "$openssl"; then
AC_DEFINE(HAVE_OPENSSL, 1, [Whether to use OpenSSL.])
fi
AC_ARG_WITH(bzip2, AC_HELP_STRING([--with-bzip2=PATH],
[prefix of bzip2]),
bzip2=$withval, bzip2=)
@@ -243,11 +250,12 @@ AC_SUBST(bzip2_include)
AC_SUBST(bzip2_bin)
AC_SUBST(bzip2_bin_test)
AC_ARG_WITH(sqlite, AC_HELP_STRING([--with-sqlite=PATH],
[prefix of SQLite]),
sqlite=$withval, sqlite=)
AM_CONDITIONAL(HAVE_SQLITE, test -n "$sqlite")
SQLITE_VERSION=3070500
SQLITE_VERSION=3070900
AC_SUBST(SQLITE_VERSION)
if test -z "$sqlite"; then
sqlite_lib='${top_builddir}/externals/sqlite-autoconf-$(SQLITE_VERSION)/libsqlite3.la'
@@ -262,17 +270,37 @@ AC_SUBST(sqlite_lib)
AC_SUBST(sqlite_include)
AC_SUBST(sqlite_bin)
# Whether to use the Boehm garbage collector.
AC_ARG_ENABLE(gc, AC_HELP_STRING([--enable-gc],
[enable garbage collection in the Nix expression evaluator (requires Boehm GC)]),
gc=$enableval, gc=)
if test -n "$gc"; then
gc=$enableval, gc=no)
if test "$gc" = yes; then
PKG_CHECK_MODULES([BDW_GC], [bdw-gc])
boehmgc_lib="-L$boehmgc/lib -lgc"
CXXFLAGS="$BDW_GC_CFLAGS $CXXFLAGS"
AC_DEFINE(HAVE_BOEHMGC, 1, [Whether to use the Boehm garbage collector.])
fi
AC_SUBST(boehmgc_lib)
# Check for the required Perl dependencies (DBI and DBD::SQLite).
perlFlags="-I${libdir}/perl5/site_perl"
AC_ARG_WITH(dbi, AC_HELP_STRING([--with-dbi=PATH],
[prefix of the Perl DBI library]),
perlFlags="$perlFlags -I$withval")
AC_ARG_WITH(dbd-sqlite, AC_HELP_STRING([--with-dbd-sqlite=PATH],
[prefix of the Perl DBD::SQLite library]),
perlFlags="$perlFlags -I$withval")
AC_MSG_CHECKING([whether DBD::SQLite works])
if ! $perl $perlFlags -e 'use DBI; use DBD::SQLite;' 2>&5; then
AC_MSG_RESULT(no)
AC_MSG_FAILURE([The Perl modules DBI and/or DBD::SQLite are missing.])
fi
AC_MSG_RESULT(yes)
AC_SUBST(perlFlags)
AC_ARG_ENABLE(init-state, AC_HELP_STRING([--disable-init-state],
@@ -286,7 +314,7 @@ AC_CHECK_FUNCS([setresuid setreuid lchown])
# Nice to have, but not essential.
AC_CHECK_FUNCS([strsignal posix_fallocate nanosleep])
AC_CHECK_FUNCS([strsignal posix_fallocate nanosleep sysconf])
# This is needed if ATerm or bzip2 are static libraries,
@@ -315,11 +343,9 @@ AC_CONFIG_FILES([Makefile
src/nix-setuid-helper/Makefile
src/nix-log2xml/Makefile
src/bsdiff-4.3/Makefile
perl/Makefile
scripts/Makefile
corepkgs/Makefile
corepkgs/nar/Makefile
corepkgs/buildenv/Makefile
corepkgs/channels/Makefile
doc/Makefile
doc/manual/Makefile
misc/Makefile

View File

@@ -1 +1,11 @@
SUBDIRS = nar buildenv channels
all-local: config.nix
files = nar.nix buildenv.nix buildenv.pl unpack-channel.nix unpack-channel.sh derivation.nix
install-exec-local:
$(INSTALL) -d $(DESTDIR)$(datadir)/nix/corepkgs
$(INSTALL_DATA) config.nix $(files) $(DESTDIR)$(datadir)/nix/corepkgs
include ../substitute.mk
EXTRA_DIST = config.nix.in $(files)

View File

@@ -1,9 +1,12 @@
{system, derivations, manifest}:
with import <nix/config.nix>;
{ system, derivations, manifest }:
derivation {
name = "user-environment";
system = system;
builder = ./builder.pl;
builder = perl;
args = [ "-w" ./buildenv.pl ];
manifest = manifest;

View File

@@ -1,5 +1,3 @@
#! @perl@ -w
use strict;
use Cwd;
use IO::Handle;

View File

@@ -1,11 +0,0 @@
all-local: builder.pl
install-exec-local:
$(INSTALL) -d $(DESTDIR)$(datadir)/nix/corepkgs
$(INSTALL) -d $(DESTDIR)$(datadir)/nix/corepkgs/buildenv
$(INSTALL_DATA) $(srcdir)/default.nix $(DESTDIR)$(datadir)/nix/corepkgs/buildenv
$(INSTALL_PROGRAM) builder.pl $(DESTDIR)$(datadir)/nix/corepkgs/buildenv
include ../../substitute.mk
EXTRA_DIST = default.nix builder.pl.in

View File

@@ -1,11 +0,0 @@
all-local: unpack.sh
install-exec-local:
$(INSTALL) -d $(DESTDIR)$(datadir)/nix/corepkgs
$(INSTALL) -d $(DESTDIR)$(datadir)/nix/corepkgs/channels
$(INSTALL_DATA) $(srcdir)/unpack.nix $(DESTDIR)$(datadir)/nix/corepkgs/channels
$(INSTALL_PROGRAM) unpack.sh $(DESTDIR)$(datadir)/nix/corepkgs/channels
include ../../substitute.mk
EXTRA_DIST = unpack.nix unpack.sh.in

View File

@@ -1,7 +0,0 @@
{system, inputs}:
derivation {
name = "channels";
builder = ./unpack.sh;
inherit system inputs;
}

View File

@@ -1,35 +0,0 @@
#! @shell@ -e
# Cygwin compatibility hack: bunzip2 expects cygwin.dll in $PATH.
export PATH=@coreutils@
@coreutils@/mkdir $out
@coreutils@/mkdir $out/tmp
cd $out/tmp
inputs=($inputs)
for ((n = 0; n < ${#inputs[*]}; n += 2)); do
channelName=${inputs[n]}
channelTarball=${inputs[n+1]}
echo "unpacking channel $channelName"
@bunzip2@ < $channelTarball | @tar@ xf -
if test -e */channel-name; then
channelName="$(@coreutils@/cat */channel-name)"
fi
nr=1
attrName=$(echo $channelName | @tr@ -- '- ' '__')
dirName=$attrName
while test -e ../$dirName; do
nr=$((nr+1))
dirName=$attrName-$nr
done
@coreutils@/mv * ../$dirName # !!! hacky
done
cd ..
@coreutils@/rmdir tmp

13
corepkgs/config.nix.in Normal file
View File

@@ -0,0 +1,13 @@
let
fromEnv = var: def:
let val = builtins.getEnv var; in
if val != "" then val else def;
in {
perl = "@perl@";
shell = "@shell@";
coreutils = "@coreutils@";
bzip2 = fromEnv "NIX_BZIP2" "@bzip2@";
tar = "@tar@";
tr = "@tr@";
nixBinDir = fromEnv "NIX_BIN_DIR" "@bindir@";
}

27
corepkgs/derivation.nix Normal file
View File

@@ -0,0 +1,27 @@
/* This is the implementation of the derivation builtin function.
It's actually a wrapper around the derivationStrict primop. */
drvAttrs @ { outputs ? [ "out" ], ... }:
let
strict = derivationStrict drvAttrs;
commonAttrs = drvAttrs // (builtins.listToAttrs outputsList) //
{ all = map (x: x.value) outputsList;
inherit drvAttrs;
};
outputToAttrListElement = outputName:
{ name = outputName;
value = commonAttrs // {
outPath = builtins.getAttr outputName strict;
drvPath = strict.drvPath;
type = "derivation";
inherit outputName;
};
};
outputsList = map outputToAttrListElement outputs;
in (builtins.head outputsList).value

30
corepkgs/nar.nix Normal file
View File

@@ -0,0 +1,30 @@
with import <nix/config.nix>;
let
builder = builtins.toFile "nar.sh"
''
export PATH=${nixBinDir}:${coreutils}
echo "packing $storePath..."
mkdir $out
dst=$out/tmp.nar.bz2
set -o pipefail
nix-store --dump "$storePath" | ${bzip2} > $dst
nix-hash --flat --type $hashAlgo --base32 $dst > $out/narbz2-hash
mv $out/tmp.nar.bz2 $out/$(cat $out/narbz2-hash).nar.bz2
'';
in
{ system, storePath, hashAlgo }:
derivation {
name = "nar";
builder = shell;
args = [ "-e" builder ];
inherit system storePath hashAlgo;
}

View File

@@ -1,11 +0,0 @@
all-local: nar.sh
install-exec-local:
$(INSTALL) -d $(DESTDIR)$(datadir)/nix/corepkgs
$(INSTALL) -d $(DESTDIR)$(datadir)/nix/corepkgs/nar
$(INSTALL_DATA) $(srcdir)/nar.nix $(DESTDIR)$(datadir)/nix/corepkgs/nar
$(INSTALL_PROGRAM) nar.sh $(DESTDIR)$(datadir)/nix/corepkgs/nar
include ../../substitute.mk
EXTRA_DIST = nar.nix nar.sh.in

View File

@@ -1,7 +0,0 @@
{system, storePath, hashAlgo}:
derivation {
name = "nar";
builder = ./nar.sh;
inherit system storePath hashAlgo;
}

View File

@@ -1,12 +0,0 @@
#! @shell@ -e
echo "packing $storePath into $out..."
@coreutils@/mkdir $out
dst=$out/tmp.nar.bz2
@bindir@/nix-store --dump "$storePath" > tmp
@bzip2@ < tmp > $dst
@bindir@/nix-hash --flat --type $hashAlgo --base32 $dst > $out/narbz2-hash
@coreutils@/mv $out/tmp.nar.bz2 $out/$(@coreutils@/cat $out/narbz2-hash).nar.bz2

View File

@@ -0,0 +1,11 @@
with import <nix/config.nix>;
{ system, inputs }:
derivation {
name = "channels";
builder = shell;
args = [ "-e" ./unpack-channel.sh ];
inherit system inputs bzip2 tar tr;
PATH = "${nixBinDir}:${coreutils}";
}

View File

@@ -0,0 +1,30 @@
mkdir $out
mkdir $out/tmp
cd $out/tmp
inputs=($inputs)
for ((n = 0; n < ${#inputs[*]}; n += 2)); do
channelName=${inputs[n]}
channelTarball=${inputs[n+1]}
echo "unpacking channel $channelName"
$bzip2 -d < $channelTarball | $tar xf -
if test -e */channel-name; then
channelName="$(cat */channel-name)"
fi
nr=1
attrName=$(echo $channelName | $tr -- '- ' '__')
dirName=$attrName
while test -e ../$dirName; do
nr=$((nr+1))
dirName=$attrName-$nr
done
mv * ../$dirName # !!! hacky
done
cd ..
rmdir tmp

View File

@@ -43,10 +43,10 @@ is also available as <function>builtins.derivation</function>.</para>
<listitem><para>Return the names of the attributes in the
attribute set <replaceable>attrs</replaceable> in a sorted list.
For instance, <literal>builtins.attrNames {y = 1; x =
"foo";}</literal> evaluates to <literal>["x" "y"]</literal>.
There is no built-in function <function>attrValues</function>, but
you can easily define it yourself:
For instance, <literal>builtins.attrNames { y = 1; x = "foo";
}</literal> evaluates to <literal>[ "x" "y" ]</literal>. There is
no built-in function <function>attrValues</function>, but you can
easily define it yourself:
<programlisting>
attrValues = attrs: map (name: builtins.getAttr name attrs) (builtins.attrNames attrs);</programlisting>
@@ -442,10 +442,10 @@ x: x + 456</programlisting>
Example:
<programlisting>
builtins.listToAttrs [
{name = "foo"; value = 123;}
{name = "bar"; value = 456;}
]
builtins.listToAttrs
[ { name = "foo"; value = 123; }
{ name = "bar"; value = 456; }
]
</programlisting>
evaluates to
@@ -466,10 +466,10 @@ builtins.listToAttrs [
example,
<programlisting>
map (x: "foo" + x) ["bar" "bla" "abc"]</programlisting>
map (x: "foo" + x) [ "bar" "bla" "abc" ]</programlisting>
evaluates to <literal>["foobar" "foobla"
"fooabc"]</literal>.</para></listitem>
evaluates to <literal>[ "foobar" "foobla" "fooabc"
]</literal>.</para></listitem>
</varlistentry>
@@ -491,10 +491,10 @@ map (x: "foo" + x) ["bar" "bla" "abc"]</programlisting>
a package name and version. The package name is everything up to
but not including the first dash followed by a digit, and the
version is everything following that dash. The result is returned
in an attribute set <literal>{name, version}</literal>. Thus,
in an attribute set <literal>{ name, version }</literal>. Thus,
<literal>builtins.parseDrvName "nix-0.12pre12876"</literal>
returns <literal>{name = "nix"; version =
"0.12pre12876";}</literal>.</para></listitem>
returns <literal>{ name = "nix"; version = "0.12pre12876";
}</literal>.</para></listitem>
</varlistentry>
@@ -550,9 +550,9 @@ in config.someSetting</programlisting>
exist in <replaceable>attrs</replaceable>. For instance,
<screen>
removeAttrs { x = 1; y = 2; z = 3; } ["a" "x" "z"]</screen>
removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
evaluates to <literal>{y = 2;}</literal>.</para></listitem>
evaluates to <literal>{ y = 2; }</literal>.</para></listitem>
</varlistentry>
@@ -632,7 +632,7 @@ removeAttrs { x = 1; y = 2; z = 3; } ["a" "x" "z"]</screen>
linkend='ex-hello-builder' /> into one file:
<programlisting>
{stdenv, fetchurl, perl}:
{ stdenv, fetchurl, perl }:
stdenv.mkDerivation {
name = "hello-2.1.1";
@@ -765,12 +765,12 @@ in foo</programlisting>
using <function>toXML</function></title>
<programlisting><![CDATA[
{stdenv, fetchurl, libxslt, jira, uberwiki}:
{ stdenv, fetchurl, libxslt, jira, uberwiki }:
stdenv.mkDerivation (rec {
name = "web-server";
buildInputs = [libxslt];
buildInputs = [ libxslt ];
builder = builtins.toFile "builder.sh" "
source $stdenv/setup

View File

@@ -6,7 +6,7 @@
<para>A number of persistent settings of Nix are stored in the file
<filename><replaceable>prefix</replaceable>/etc/nix/nix.conf</filename>.
<filename><replaceable>sysconfdir</replaceable>/nix/nix.conf</filename>.
This file is a list of <literal><replaceable>name</replaceable> =
<replaceable>value</replaceable></literal> pairs, one per line.
Comments start with a <literal>#</literal> character. An example
@@ -136,6 +136,25 @@ env-keep-derivations = false
</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
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
linkend="opt-timeout">--timeout</option> command line
switch.</para>
<para>The value <literal>0</literal> means that there is no
timeout. This is also the default.</para>
</listitem>
</varlistentry>
<varlistentry xml:id="conf-build-users-group"><term><literal>build-users-group</literal></term>

View File

@@ -314,7 +314,7 @@ bit turned on (like <filename>/tmp</filename>):
<screen>
$ chgrp nixbld /nix/store
$ chmod 1777 /nix/store
$ chmod 1775 /nix/store
</screen>
</para>
@@ -323,7 +323,7 @@ $ chmod 1777 /nix/store
specifying the build users group in the <link
linkend="conf-build-users-group"><literal>build-users-group</literal>
option</link> in the <link linkend="sec-conf-file">Nix configuration
file</link> (<literal>/nix/etc/nix/nix.conf</literal>):
file</link> (usually <literal>/etc/nix/nix.conf</literal>):
<programlisting>
build-users-group = nixbld
@@ -380,7 +380,7 @@ is a special account called <literal>nix</literal>, but it can be
named anything. It should own the Nix store and database:
<screen>
$ chown -R root /nix/store /nix/var/nix</screen>
$ chown -R nix /nix/store /nix/var/nix</screen>
and of course <command>nix-worker --daemon</command> should be started
under that user, e.g.,

View File

@@ -24,8 +24,11 @@
</group>
<arg><option>--sign</option></arg>
<arg><option>--gzip</option></arg>
<arg><option>--bzip2</option></arg>
<arg><option>--xz</option></arg>
<arg><option>--include-outputs</option></arg>
<arg choice='plain'>
<arg><replaceable>user@</replaceable></arg><replaceable>machine</replaceable>
<replaceable>user@</replaceable><replaceable>machine</replaceable>
</arg>
<arg choice='plain'><replaceable>paths</replaceable></arg>
</cmdsynopsis>
@@ -84,25 +87,36 @@ those paths. If this bothers you, use
<listitem><para>Let the sending machine cryptographically sign the
dump of each path with the key in
<filename>/nix/etc/nix/signing-key.sec</filename>. If the user on
the target machine does not have direct access to the Nix store
(i.e., if the target machine has a multi-user Nix installation),
then the target machine will check the dump against
<filename>/nix/etc/nix/signing-key.pub</filename> before unpacking
it in its Nix store. This allows secure sharing of store paths
between untrusted users on two machines, provided that there is a
trust relation between the Nix installations on both machines
(namely, they have matching public/secret keys).</para></listitem>
<filename><replaceable>sysconfdir</replaceable>/nix/signing-key.sec</filename>.
If the user on the target machine does not have direct access to
the Nix store (i.e., if the target machine has a multi-user Nix
installation), then the target machine will check the dump against
<filename><replaceable>sysconfdir</replaceable>/nix/signing-key.pub</filename>
before unpacking it in its Nix store. This allows secure sharing
of store paths between untrusted users on two machines, provided
that there is a trust relation between the Nix installations on
both machines (namely, they have matching public/secret
keys).</para></listitem>
</varlistentry>
<varlistentry><term><option>--gzip</option></term>
<varlistentry><term><option>--gzip</option> / <option>--bzip2</option> / <option>--xz</option></term>
<listitem><para>Compress the dump of each path with
<command>gzip</command> before sending it.</para></listitem>
<listitem><para>Compress the dump of each path with respectively
<command>gzip</command>, <command>bzip2</command> or
<command>xz</command> before sending it. The corresponding
decompression program must be installed on the target
machine.</para></listitem>
</varlistentry>
<varlistentry><term><option>--include-outputs</option></term>
<listitem><para>Also copy the outputs of store derivations included
in the closure.</para></listitem>
</varlistentry>
</variablelist>
</refsection>

View File

@@ -2,7 +2,7 @@
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xml:id="sec-nix-env">
<refmeta>
<refentrytitle>nix-env</refentrytitle>
<manvolnum>1</manvolnum>
@@ -60,7 +60,7 @@ environments.</para>
<para><command>nix-env</command> takes exactly one
<emphasis>operation</emphasis> flag which indicates the subcommand to
be performed. These are documented below.</para>
</refsection>
@@ -78,19 +78,19 @@ linkend="sec-common-options" />.</para>
<varlistentry><term><option>--file</option></term>
<term><option>-f</option></term>
<listitem><para>Specifies the Nix expression (designated below as
the <emphasis>active Nix expression</emphasis>) used by the
<option>--install</option>, <option>--upgrade</option>, and
<option>--query --available</option> operations to obtain
derivations. The default is
<filename>~/.nix-defexpr</filename>.</para></listitem>
</varlistentry>
<varlistentry><term><option>--profile</option></term>
<term><option>-p</option></term>
<listitem><para>Specifies the profile to be used by those
operations that operate on a profile (designated below as the
<emphasis>active profile</emphasis>). A profile is sequence of
@@ -98,11 +98,11 @@ linkend="sec-common-options" />.</para>
which is the <emphasis>current generation</emphasis>. The default
profile is the target of the symbolic link
<filename>~/.nix-profile</filename> (see below).</para></listitem>
</varlistentry>
<varlistentry><term><option>--dry-run</option></term>
<listitem><para>For the <option>--install</option>,
<option>--upgrade</option>, <option>--uninstall</option>,
<option>--switch-generation</option> and
@@ -117,23 +117,23 @@ linkend="sec-common-options" />.</para>
substitute is available).</para></listitem>
</varlistentry>
<varlistentry><term><option>--system-filter</option> <replaceable>system</replaceable></term>
<listitem><para>By default, operations such as <option>--query
--available</option> only include derivations matching the current
platform. This option allows you to use derivations for the
specified platform <replaceable>system</replaceable>. The special
value <literal>*</literal> causes derivations for any platform to
be included.</para></listitem>
</varlistentry>
</variablelist>
</refsection>
<!--######################################################################-->
@@ -170,25 +170,25 @@ linkend="sec-common-options" />.</para>
this directory.</para>
</listitem>
</varlistentry>
<varlistentry><term><filename>~/.nix-profile</filename></term>
<listitem><para>A symbolic link to the user's current profile. By
default, this symlink points to
<filename><replaceable>prefix</replaceable>/var/nix/profiles/default</filename>.
The <envar>PATH</envar> environment variable should include
<filename>~/.nix-profile/bin</filename> for the user environment
to be visible to the user.</para></listitem>
</varlistentry>
</variablelist>
</refsection>
<!--######################################################################-->
@@ -214,7 +214,7 @@ linkend="sec-common-options" />.</para>
<refsection><title>Description</title>
<para>The install operation creates a new user environment, based on
the current generation of the active profile, to which a set of store
paths described by <replaceable>args</replaceable> is added. The
@@ -256,7 +256,7 @@ number of possible ways:
<emphasis>attribute paths</emphasis> that select attributes from the
top-level Nix expression. This is faster than using derivation
names and unambiguous. To find out the attribute paths of available
packages, use <literal>nix-env -qaA '*'</literal>.</para></listitem>
packages, use <literal>nix-env -qaP '*'</literal>.</para></listitem>
<listitem><para>If <option>--from-profile</option>
<replaceable>path</replaceable> is given,
@@ -306,20 +306,20 @@ number of possible ways:
<varlistentry><term><option>--preserve-installed</option></term>
<term><option>-P</option></term>
<listitem><para>Do not remove derivations with a name matching one
of the derivations being installed. Usually, trying to have two
versions of the same package installed in the same generation of a
profile will lead to an error in building the generation, due to
file name clashes between the two versions. However, this is not
the case for all packages.</para></listitem>
</varlistentry>
</variablelist>
</refsection>
<refsection xml:id='refsec-nix-env-install-examples'><title>Examples</title>
@@ -327,7 +327,7 @@ number of possible ways:
active Nix expression:
<screen>
$ nix-env --install gcc-3.3.2
$ nix-env --install gcc-3.3.2
installing `gcc-3.3.2'
uninstalling `gcc-3.1'</screen>
@@ -408,15 +408,15 @@ the following paths will be substituted:
/nix/store/8zbipvm4gp9jfqh9nnk1n3bary1a37gs-perl-XML-Parser-2.34
/nix/store/b8a2bg7gnyvvvjjibp4axg9x1hzkw36c-mono-1.1.4
<replaceable>...</replaceable></screen>
</para>
</refsection>
</refsection>
<!--######################################################################-->
<refsection xml:id="rsec-nix-env-upgrade"><title>Operation <option>--upgrade</option></title>
@@ -442,7 +442,7 @@ the following paths will be substituted:
</refsection>
<refsection><title>Description</title>
<para>The upgrade operation creates a new user environment, based on
the current generation of the active profile, in which all store paths
are replaced for which there are newer versions in the set of paths
@@ -459,47 +459,47 @@ the same symbolic name, only the one with the highest version is
installed.</para>
</refsection>
<refsection><title>Flags</title>
<variablelist>
<varlistentry><term><option>--lt</option></term>
<listitem><para>Only upgrade a derivation to newer versions. This
is the default.</para></listitem>
</varlistentry>
<varlistentry><term><option>--leq</option></term>
<listitem><para>In addition to upgrading to newer versions, also
“upgrade” to derivations that have the same version. Version are
not a unique identification of a derivation, so there may be many
derivations that have the same version. This flag may be useful
to force “synchronisation” between the installed and available
derivations.</para></listitem>
</varlistentry>
<varlistentry><term><option>--eq</option></term>
<listitem><para><emphasis>Only</emphasis> “upgrade” to derivations
that have the same version. This may not seem very useful, but it
actually is, e.g., when there is a new release of Nixpkgs and you
want to replace installed applications with the same versions
built against newer dependencies (to reduce the number of
dependencies floating around on your system).</para></listitem>
</varlistentry>
<varlistentry><term><option>--always</option></term>
<listitem><para>In addition to upgrading to newer versions, also
“upgrade” to derivations that have the same or a lower version.
I.e., derivations may actually be downgraded depending on what is
available in the active Nix expression.</para></listitem>
</varlistentry>
</variablelist>
@@ -523,10 +523,10 @@ $ nix-env --upgrade pan
$ nix-env -u '*' <lineannotation>(try to upgrade everything)</lineannotation>
upgrading `hello-2.1.2' to `hello-2.1.3'
upgrading `mozilla-1.2' to `mozilla-1.4'</screen>
upgrading `mozilla-1.2' to `mozilla-1.4'</screen>
</refsection>
<refsection xml:id="ssec-version-comparisons"><title>Versions</title>
<para>The upgrade operation determines whether a derivation
@@ -570,14 +570,14 @@ lexicographically (i.e., using case-sensitive string comparison).</para>
2.3a &lt; 2.3c
2.3pre1 &lt; 2.3c
2.3pre1 &lt; 2.3q</screen>
</para>
</refsection>
</refsection>
<!--######################################################################-->
@@ -596,14 +596,14 @@ lexicographically (i.e., using case-sensitive string comparison).</para>
</refsection>
<refsection><title>Description</title>
<para>The uninstall operation creates a new user environment, based on
the current generation of the active profile, from which the store
paths designated by the symbolic names
<replaceable>names</replaceable> are removed.</para>
</refsection>
<refsection><title>Examples</title>
<screen>
@@ -611,11 +611,11 @@ $ nix-env --uninstall gcc
$ nix-env -e '*' <lineannotation>(remove everything)</lineannotation></screen>
</refsection>
</refsection>
<!--######################################################################-->
<refsection xml:id="rsec-nix-env-set-flag"><title>Operation <option>--set-flag</option></title>
@@ -632,7 +632,7 @@ $ nix-env -e '*' <lineannotation>(remove everything)</lineannotation></screen>
</refsection>
<refsection><title>Description</title>
<para>The <option>--set-flag</option> operation allows meta attributes
of installed packages to be modified. There are several attributes
that can be usefully modified, because they affect the behaviour of
@@ -670,7 +670,7 @@ script:
</para>
</refsection>
<refsection><title>Examples</title>
<para>To prevent the currently installed Firefox from being upgraded:
@@ -716,13 +716,13 @@ $ nix-env --set-flag priority 10 gcc</screen>
</para>
</refsection>
</refsection>
<!--######################################################################-->
<refsection><title>Operation <option>--query</option></title>
<refsection><title>Synopsis</title>
@@ -738,9 +738,9 @@ $ nix-env --set-flag priority 10 gcc</screen>
<arg choice='plain'><option>--available</option></arg>
<arg choice='plain'><option>-a</option></arg>
</group>
<sbr />
<arg>
<group choice='req'>
<arg choice='plain'><option>--status</option></arg>
@@ -785,7 +785,7 @@ $ nix-env --set-flag priority 10 gcc</screen>
</arg>
<sbr />
<arg choice='plain' rep='repeat'><replaceable>names</replaceable></arg>
</cmdsynopsis>
@@ -793,7 +793,7 @@ $ nix-env --set-flag priority 10 gcc</screen>
<refsection><title>Description</title>
<para>The query operation displays information about either the store
paths that are installed in the current generation of the active
profile (<option>--installed</option>), or the derivations that are
@@ -817,23 +817,23 @@ operates.</para>
<variablelist>
<varlistentry><term><option>--installed</option></term>
<listitem><para>The query operates on the store paths that are
installed in the current generation of the active profile. This
is the default.</para></listitem>
</varlistentry>
<varlistentry><term><option>--available</option></term>
<term><option>-a</option></term>
<listitem><para>The query operates on the derivations that are
available in the active Nix expression.</para></listitem>
</varlistentry>
</variablelist>
</refsection>
@@ -874,7 +874,7 @@ user environment elements, etc. -->
<varlistentry><term><option>--status</option></term>
<term><option>-s</option></term>
<listitem><para>Print the <emphasis>status</emphasis> of the
derivation. The status consists of three characters. The first
is <literal>I</literal> or <literal>-</literal>, indicating
@@ -888,7 +888,7 @@ user environment elements, etc. -->
third is <literal>S</literal> or <literal>-</literal>, indicating
whether a substitute is available for the
derivation.</para></listitem>
</varlistentry>
<varlistentry><term><option>--attr-path</option></term>
@@ -901,17 +901,17 @@ user environment elements, etc. -->
<literal>nix-env --install</literal>.</para></listitem>
</varlistentry>
<varlistentry><term><option>--no-name</option></term>
<listitem><para>Suppress printing of the <literal>name</literal>
attribute of each derivation.</para></listitem>
</varlistentry>
<varlistentry><term><option>--compare-versions</option> /
<option>-c</option></term>
<listitem><para>Compare installed versions to available versions,
or vice versa (if <option>--available</option> is given). This is
useful for quickly seeing whether upgrades for installed
@@ -926,21 +926,21 @@ user environment elements, etc. -->
or installed.</para></listitem>
</varlistentry>
<varlistentry><term><literal>=</literal> <replaceable>version</replaceable></term>
<listitem><para>At most the same version of the package is
available or installed.</para></listitem>
</varlistentry>
<varlistentry><term><literal>></literal> <replaceable>version</replaceable></term>
<listitem><para>Only older versions of the package are
available or installed.</para></listitem>
</varlistentry>
<varlistentry><term><literal>- ?</literal></term>
<listitem><para>No version of the package is available or
@@ -951,45 +951,45 @@ user environment elements, etc. -->
</variablelist>
</para></listitem>
</varlistentry>
<varlistentry><term><option>--system</option></term>
<listitem><para>Print the <literal>system</literal> attribute of
the derivation.</para></listitem>
</varlistentry>
<varlistentry><term><option>--drv-path</option></term>
<listitem><para>Print the path of the store
derivation.</para></listitem>
</varlistentry>
<varlistentry><term><option>--out-path</option></term>
<listitem><para>Print the output path of the
derivation.</para></listitem>
</varlistentry>
<varlistentry><term><option>--description</option></term>
<listitem><para>Print a short (one-line) description of the
derivation, if available. The description is taken from the
<literal>meta.description</literal> attribute of the
derivation.</para></listitem>
</varlistentry>
<varlistentry><term><option>--meta</option></term>
<listitem><para>Print all of the meta-attributes of the
derivation. This option is only available with
<option>--xml</option>.</para></listitem>
</varlistentry>
</variablelist>
@@ -1023,7 +1023,7 @@ IP- ORBit2-2.8.3 <lineannotation>(installed and by definition present)</linea
...
<lineannotation>(show available derivations in the Nix expression <!-- !!! <filename>-->foo.nix<!-- </filename> -->)</lineannotation>
$ nix-env -f ./foo.nix -qa '*'
$ nix-env -f ./foo.nix -qa '*'
foo-1.2.3
$ nix-env -qc '*' <lineannotation>(compare installed versions to whats available)</lineannotation>
@@ -1034,7 +1034,7 @@ firefox-1.0.4 &lt; 1.0.7 <lineannotation>(a more recent version is availab
<replaceable>...</replaceable>
<lineannotation>(show info about a specific package, in XML)</lineannotation>
$ nix-env -qa --xml --description firefox
$ nix-env -qa --xml --description firefox
<![CDATA[<?xml version='1.0' encoding='utf-8'?>
<items>
<item attrPath="0.0.firefoxWrapper"
@@ -1045,8 +1045,8 @@ $ nix-env -qa --xml --description firefox
</refsection>
</refsection>
<!--######################################################################-->
@@ -1067,25 +1067,25 @@ $ nix-env -qa --xml --description firefox
<refsection><title>Description</title>
<para>This operation makes <replaceable>path</replaceable> the current
profile for the user. That is, the symlink
<filename>~/.nix-profile</filename> is made to point to
<replaceable>path</replaceable>.</para>
</refsection>
<refsection><title>Examples</title>
<screen>
$ nix-env -S ~/my-profile</screen>
</refsection>
</refsection>
<!--######################################################################-->
<refsection><title>Operation <option>--list-generations</option></title>
@@ -1101,7 +1101,7 @@ $ nix-env -S ~/my-profile</screen>
<refsection><title>Description</title>
<para>This operation print a list of all the currently existing
generations for the active profile. These may be switched to using
the <option>--switch-generation</option> operation. It also prints
@@ -1121,11 +1121,11 @@ $ nix-env --list-generations
98 2004-02-06 16:24:33 (current)</screen>
</refsection>
</refsection>
<!--######################################################################-->
<refsection><title>Operation <option>--delete-generations</option></title>
@@ -1142,7 +1142,7 @@ $ nix-env --list-generations
<refsection><title>Description</title>
<para>This operation deletes the specified generations of the current
profile. The generations can be a list of generation numbers, or the
special value <literal>old</literal> to delete all non-current
@@ -1150,7 +1150,7 @@ generations. Periodically deleting old generations is important to
make garbage collection effective.</para>
</refsection>
<refsection><title>Examples</title>
<screen>
@@ -1159,11 +1159,11 @@ $ nix-env --delete-generations 3 4 8
$ nix-env -p other_profile --delete-generations old</screen>
</refsection>
</refsection>
<!--######################################################################-->
<refsection><title>Operation <option>--switch-generation</option></title>
@@ -1183,7 +1183,7 @@ $ nix-env -p other_profile --delete-generations old</screen>
<refsection><title>Description</title>
<para>This operation makes generation number
<replaceable>generation</replaceable> the current generation of the
active profile. That is, if the
@@ -1207,11 +1207,11 @@ $ nix-env -G 42
switching from generation 50 to 42</screen>
</refsection>
</refsection>
<!--######################################################################-->
<refsection><title>Operation <option>--rollback</option></title>
@@ -1226,7 +1226,7 @@ switching from generation 50 to 42</screen>
</refsection>
<refsection><title>Description</title>
<para>This operation switches to the “previous” generation of the
active profile, that is, the highest numbered generation lower than
the current generation, if it exists. It is just a convenience
@@ -1246,9 +1246,9 @@ $ nix-env --rolback
error: no generation older than the current (91) exists</screen>
</refsection>
</refsection>
</refentry>

View File

@@ -12,7 +12,7 @@
<refnamediv>
<refname>nix-prefetch-url</refname>
<refpurpose>copy a file from a URL into the store and print its MD5 hash</refpurpose>
<refpurpose>copy a file from a URL into the store and print its hash</refpurpose>
</refnamediv>
<refsynopsisdiv>

View File

@@ -21,6 +21,10 @@
<arg><option>--max-silent-time</option></arg>
<replaceable>number</replaceable>
</arg>
<arg>
<arg><option>--timeout</option></arg>
<replaceable>number</replaceable>
</arg>
<arg><option>--keep-going</option></arg>
<arg><option>-k</option></arg>
<arg><option>--keep-failed</option></arg>

View File

@@ -132,6 +132,16 @@
</varlistentry>
<varlistentry xml:id="opt-timeout"><term><option>--timeout</option></term>
<listitem><para>Sets the maximum number of seconds that a builder
can run. The default is specified by the <link
linkend='conf-build-timeout'><literal>build-timeout</literal></link>
configuration setting. <literal>0</literal> means no
timeout.</para></listitem>
</varlistentry>
<varlistentry><term><option>--keep-going</option></term>
<term><option>-k</option></term>
@@ -254,8 +264,8 @@
expression evaluator will automatically try to call functions that
it encounters. It can automatically call functions for which every
argument has a <link linkend='ss-functions'>default value</link>
(e.g., <literal>{<replaceable>argName</replaceable> ?
<replaceable>defaultValue</replaceable>}:
(e.g., <literal>{ <replaceable>argName</replaceable> ?
<replaceable>defaultValue</replaceable> }:
<replaceable>...</replaceable></literal>). With
<option>--arg</option>, you can also call functions that have
arguments without a default value (or override a default value).

View File

@@ -22,6 +22,28 @@
option.</para>
</listitem>
<listitem>
<para>The option <option>--timeout</option> (corresponding to the
configuration setting <literal>build-timeout</literal>) allows you
to set an absolute timeout on builds — if a build runs for more than
the given number of seconds, it is terminated. This is useful for
recovering automatically from builds that are stuck in an infinite
loop but keep producing output, and for which
<literal>--max-silent-time</literal> is ineffective.</para>
</listitem>
<listitem>
<para>TODO: “or” keyword.</para>
</listitem>
<listitem>
<para>TODO: Nix expression search path (<literal>import &lt;foo/bar.nix></literal>).</para>
</listitem>
<listitem>
<para>TODO: <command>nix-store --verify-path</command> command.</para>
</listitem>
</itemizedlist>
</section>

View File

@@ -52,7 +52,7 @@ need to do three things:
<example xml:id='ex-hello-nix'><title>Nix expression for GNU Hello
(<filename>default.nix</filename>)</title>
<programlisting>
{stdenv, fetchurl, perl}: <co xml:id='ex-hello-nix-co-1' />
{ stdenv, fetchurl, perl }: <co xml:id='ex-hello-nix-co-1' />
stdenv.mkDerivation { <co xml:id='ex-hello-nix-co-2' />
name = "hello-2.1.1"; <co xml:id='ex-hello-nix-co-3' />
@@ -92,8 +92,8 @@ the single Nix expression in that directory
function that downloads files. <varname>perl</varname> is the
Perl interpreter.</para>
<para>Nix functions generally have the form <literal>{x, y, ...,
z}: e</literal> where <varname>x</varname>, <varname>y</varname>,
<para>Nix functions generally have the form <literal>{ x, y, ...,
z }: e</literal> where <varname>x</varname>, <varname>y</varname>,
etc. are the names of the expected arguments, and where
<replaceable>e</replaceable> is the body of the function. So
here, the entire remainder of the file is the body of the
@@ -114,10 +114,10 @@ the single Nix expression in that directory
<emphasis>attributes</emphasis>. An attribute set is just a list
of key/value pairs where each value is an arbitrary Nix
expression. They take the general form
<literal>{<replaceable>name1</replaceable> =
<literal>{ <replaceable>name1</replaceable> =
<replaceable>expr1</replaceable>; <replaceable>...</replaceable>
<replaceable>nameN</replaceable> =
<replaceable>exprN</replaceable>;}</literal>.</para>
<replaceable>exprN</replaceable>; }</literal>.</para>
</callout>
@@ -564,7 +564,7 @@ genericBuild <co xml:id='ex-hello-builder2-co-3' /></programlisting>
expression, like this:
<programlisting>
buildInputs = [perl];</programlisting>
buildInputs = [ perl ];</programlisting>
The <varname>perl</varname> attribute can then be removed, and the
builder becomes even shorter:
@@ -771,14 +771,14 @@ stdenv.mkDerivation {
values between square brackets. For example,
<programlisting>
[ 123 ./foo.nix "abc" (f {x=y;}) ]</programlisting>
[ 123 ./foo.nix "abc" (f { x = y; }) ]</programlisting>
defines a list of four elements, the last being the result of a call
to the function <varname>f</varname>. Note that function calls have
to be enclosed in parentheses. If they had been omitted, e.g.,
<programlisting>
[ 123 ./foo.nix "abc" f {x=y;} ]</programlisting>
[ 123 ./foo.nix "abc" f { x = y; } ]</programlisting>
the result would be a list of five elements, the fourth one being a
function and the fifth being an attribute set.</para>
@@ -891,15 +891,12 @@ propagate attributes). This can be shortened using the
<literal>inherit</literal> keyword. For instance,
<programlisting>
let
x = 123;
in
{
inherit x;
y = 456;
}</programlisting>
let x = 123; in
{ inherit x;
y = 456;
}</programlisting>
evaluates to <literal>{x = 123; y = 456;}</literal>. (Note that this
evaluates to <literal>{ x = 123; y = 456; }</literal>. (Note that this
works because <varname>x</varname> is added to the lexical scope by
the <literal>let</literal> construct.) It is also possible to inherit
attributes from another attribute set. For instance, in this fragment
@@ -960,20 +957,20 @@ in if negate true then concat "foo" "bar" else ""</programlisting>
arguments of a function); e.g.,
<programlisting>
map (concat "foo") ["bar" "bla" "abc"]</programlisting>
map (concat "foo") [ "bar" "bla" "abc" ]</programlisting>
evaluates to <literal>["foobar" "foobla"
"fooabc"]</literal>.</para></listitem>
evaluates to <literal>[ "foobar" "foobla"
"fooabc" ]</literal>.</para></listitem>
<listitem><para>An <emphasis>attribute set pattern</emphasis> of the
form <literal>{name1, name2, …, nameN}</literal>
form <literal>{ name1, name2, …, nameN }</literal>
matches an attribute set containing the listed attributes, and binds
the values of those attributes to variables in the function body.
For example, the function
<programlisting>
{x, y, z}: z + y + x</programlisting>
{ x, y, z }: z + y + x</programlisting>
can only be called with a set containing exactly the attributes
<varname>x</varname>, <varname>y</varname> and
@@ -982,7 +979,7 @@ map (concat "foo") ["bar" "bla" "abc"]</programlisting>
(<literal>...</literal>):
<programlisting>
{x, y, z, ....}: z + y + x</programlisting>
{ x, y, z, ... }: z + y + x</programlisting>
This works on any set that contains at least the three named
attributes.</para>
@@ -995,7 +992,7 @@ map (concat "foo") ["bar" "bla" "abc"]</programlisting>
<replaceable>e</replaceable> is an arbitrary expression. For example,
<programlisting>
{x, y ? "foo", z ? "bar"}: z + y + x</programlisting>
{ x, y ? "foo", z ? "bar" }: z + y + x</programlisting>
specifies a function that only requires an attribute named
<varname>x</varname>, but optionally accepts <varname>y</varname>
@@ -1007,11 +1004,11 @@ map (concat "foo") ["bar" "bla" "abc"]</programlisting>
of the <literal>@</literal>-sign. For example:
<programlisting>
args@{x, y, z, ...}: z + y + x + args.a</programlisting>
args@{ x, y, z, ... }: z + y + x + args.a</programlisting>
Here <varname>args</varname> is bound to the entire argument, which
is further matches against the pattern <literal>{x, y, z,
...}</literal>.</para></listitem>
is further matches against the pattern <literal>{ x, y, z,
... }</literal>.</para></listitem>
</itemizedlist>
@@ -1020,8 +1017,8 @@ args@{x, y, z, ...}: z + y + x + args.a</programlisting>
a name, you can bind them to an attribute, e.g.,
<programlisting>
let concat = {x, y}: x + y;
in concat {x = "foo"; y = "bar";}</programlisting>
let concat = { x, y }: x + y;
in concat { x = "foo"; y = "bar"; }</programlisting>
</para>
@@ -1142,7 +1139,7 @@ lexical scope of the expression <replaceable>e2</replaceable>. For
instance,
<programlisting>
let as = {x = "foo"; y = "bar";};
let as = { x = "foo"; y = "bar"; };
in with as; x + y</programlisting>
evaluates to <literal>"foobar"</literal> since the
@@ -1480,21 +1477,20 @@ allowedReferences = [];
references graph of their inputs. The attribute is a list of
inputs in the Nix store whose references graph the builder needs
to know. The value of this attribute should be a list of pairs
<literal>[<replaceable>name1</replaceable>
<literal>[ <replaceable>name1</replaceable>
<replaceable>path1</replaceable> <replaceable>name2</replaceable>
<replaceable>path2</replaceable>
<replaceable>...</replaceable>]</literal>. The references graph
of each <replaceable>pathN</replaceable> will be stored in a text
file <replaceable>nameN</replaceable> in the temporary build
directory. The text files have the format used by
<command>nix-store --register-validity</command> (with the deriver
fields left empty). For example, when the following derivation is
built:
<replaceable>path2</replaceable> <replaceable>...</replaceable>
]</literal>. The references graph of each
<replaceable>pathN</replaceable> will be stored in a text file
<replaceable>nameN</replaceable> in the temporary build directory.
The text files have the format used by <command>nix-store
--register-validity</command> (with the deriver fields left
empty). For example, when the following derivation is built:
<programlisting>
derivation {
...
exportReferencesGraph = ["libfoo-graph" libfoo];
exportReferencesGraph = [ "libfoo-graph" libfoo ];
};
</programlisting>
@@ -1571,14 +1567,14 @@ fetchurl {
<varname>fetchurl</varname>:
<programlisting>
{stdenv, curl}: # The <command>curl</command> program is used for downloading.
{ stdenv, curl }: # The <command>curl</command> program is used for downloading.
{url, md5}:
{ url, md5 }:
stdenv.mkDerivation {
name = baseNameOf (toString url);
builder = ./builder.sh;
buildInputs = [curl];
buildInputs = [ curl ];
# This is a fixed-output derivation; the output must be a regular
# file with MD5 hash <varname>md5</varname>.
@@ -1650,7 +1646,7 @@ stdenv.mkDerivation {
Nixpkgs has the line
<programlisting>
impureEnvVars = ["http_proxy" "https_proxy" <replaceable>...</replaceable>];
impureEnvVars = [ "http_proxy" "https_proxy" <replaceable>...</replaceable> ];
</programlisting>
to make it use the proxy server configuration specified by the

View File

@@ -23,7 +23,7 @@ build-bzip2: $(BZIP2)
install-exec-local:: build-bzip2
mkdir -p $(DESTDIR)${bzip2_bin}
$(INSTALL_PROGRAM) $(bzip2_bin_test)/bzip2 $(bzip2_bin_test)/bunzip2 $(DESTDIR)${bzip2_bin}
$(INSTALL_PROGRAM) $(bzip2_bin_test)/bzip2 $(DESTDIR)${bzip2_bin}
endif

View File

@@ -1,30 +0,0 @@
{sharedLib ? true}:
rec {
inherit (import ../../../lib) compileC makeLibrary;
sources = [
./afun.c
./aterm.c
./bafio.c
./byteio.c
./gc.c
./hash.c
./list.c
./make.c
./md5c.c
./memory.c
./tafio.c
./version.c
];
compile = main: compileC {inherit main sharedLib;};
libATerm = makeLibrary {
libraryName = "ATerm";
objects = map compile sources;
inherit sharedLib;
};
}

View File

@@ -1 +0,0 @@
import test/default.nix

View File

@@ -1,15 +0,0 @@
with (import ../../../lib);
let {
inherit (import ../aterm {}) libATerm;
compileTest = main: link {
objects = [(compileC {inherit main; localIncludePath = [ ../aterm ];})];
libraries = libATerm;
};
body = [
(compileTest ./fib.c)
(compileTest ./primes.c)
];
}

View File

@@ -1,6 +0,0 @@
[ (import ./trivial)
(import ./simple-header)
(import ./not-so-simple-header)
(import ./not-so-simple-header-auto)
(import ./aterm)
]

View File

@@ -1 +0,0 @@
#define WHAT "World"

View File

@@ -1,13 +0,0 @@
with import ../../lib;
let {
hello = link {programName = "hello"; objects = compileC {
main = ./foo/hello.c;
localIncludes = "auto";
};};
# body = findIncludes {main = ./foo/hello.c;};
body = [hello];
}

View File

@@ -1,3 +0,0 @@
#define HELLO "Hello"
#include "../../bar/hello.h"

View File

@@ -1,9 +0,0 @@
#include <stdio.h>
#include "fnord/indirect.h"
int main(int argc, char * * argv)
{
printf(HELLO " " WHAT "\n");
return 0;
}

View File

@@ -1 +0,0 @@
#define WHAT "World"

View File

@@ -1,14 +0,0 @@
let {
inherit (import ../../lib) compileC link;
hello = link {programName = "hello"; objects = compileC {
main = ./foo/hello.c;
localIncludes = [
[./foo/fnord/indirect.h "fnord/indirect.h"]
[./bar/hello.h "fnord/../../bar/hello.h"]
];
};};
body = [hello];
}

View File

@@ -1,3 +0,0 @@
#define HELLO "Hello"
#include "../../bar/hello.h"

View File

@@ -1,9 +0,0 @@
#include <stdio.h>
#include "fnord/indirect.h"
int main(int argc, char * * argv)
{
printf(HELLO " " WHAT "\n");
return 0;
}

View File

@@ -1,11 +0,0 @@
let {
inherit (import ../../lib) compileC link;
hello = link {objects = compileC {
main = ./hello.c;
localIncludes = [ [./hello.h "hello.h"] ];
};};
body = [hello];
}

View File

@@ -1,9 +0,0 @@
#include <stdio.h>
#include "hello.h"
int main(int argc, char * * argv)
{
printf("Hello " WHAT "\n");
return 0;
}

View File

@@ -1 +0,0 @@
#define WHAT "World"

View File

@@ -1,8 +0,0 @@
let {
inherit (import ../../lib) compileC link;
hello = link {objects = compileC {main = ./hello.c;};};
body = [hello];
}

View File

@@ -1,7 +0,0 @@
#include <stdio.h>
int main(int argc, char * * argv)
{
printf("Hello World\n");
return 0;
}

View File

@@ -1,73 +0,0 @@
. $stdenv/setup
mainName=$(basename $main | cut -c34-)
echo "compiling \`$mainName'..."
# Turn $localIncludes into an array.
localIncludes=($localIncludes)
# Determine how many `..' levels appear in the header file references.
# E.g., if there is some reference `../../foo.h', then we have to
# insert two extra levels in the directory structure, so that `a.c' is
# stored at `dotdot/dotdot/a.c', and a reference from it to
# `../../foo.h' resolves to `dotdot/dotdot/../../foo.h' == `foo.h'.
n=0
maxDepth=0
for ((n = 0; n < ${#localIncludes[*]}; n += 2)); do
target=${localIncludes[$((n + 1))]}
# Split the target name into path components using some IFS magic.
savedIFS="$IFS"
IFS=/
components=($target)
depth=0
for ((m = 0; m < ${#components[*]}; m++)); do
c=${components[m]}
if test "$c" = ".."; then
depth=$((depth + 1))
fi
done
IFS="$savedIFS"
if test $depth -gt $maxDepth; then
maxDepth=$depth;
fi
done
# Create the extra levels in the directory hierarchy.
prefix=
for ((n = 0; n < maxDepth; n++)); do
prefix="dotdot/$prefix"
done
# Create symlinks to the header files.
for ((n = 0; n < ${#localIncludes[*]}; n += 2)); do
source=${localIncludes[n]}
target=${localIncludes[$((n + 1))]}
# Create missing directories. We use IFS magic to split the path
# into path components.
savedIFS="$IFS"
IFS=/
components=($prefix$target)
fullPath=(.)
for ((m = 0; m < ${#components[*]} - 1; m++)); do
fullPath=("${fullPath[@]}" ${components[m]})
if ! test -d "${fullPath[*]}"; then
mkdir "${fullPath[*]}"
fi
done
IFS="$savedIFS"
ln -sf $source $prefix$target
done
# Create a symlink to the main file.
if ! test "$(readlink $prefix$mainName)" = $main; then
ln -s $main $prefix$mainName
fi
mkdir $out
test "$prefix" && cd $prefix
gcc -Wall $cFlags -c $mainName -o $out/$mainName.o

View File

@@ -1,69 +0,0 @@
rec {
# Should point at your Nixpkgs installation.
pkgPath = ./pkgs;
pkgs = import (pkgPath + /system/all-packages.nix) {};
stdenv = pkgs.stdenv;
compileC =
{ main
, localIncludes ? "auto"
, localIncludePath ? []
, cFlags ? ""
, sharedLib ? false
}:
stdenv.mkDerivation {
name = "compile-c";
builder = ./compile-c.sh;
localIncludes =
if localIncludes == "auto" then
dependencyClosure {
scanner = main:
import (findIncludes {
inherit main;
});
searchPath = localIncludePath;
startSet = [main];
}
else
localIncludes;
inherit main;
cFlags = [
cFlags
(if sharedLib then ["-fpic"] else [])
(map (p: "-I" + (relativise (dirOf main) p)) localIncludePath)
];
};
findIncludes = {main}: stdenv.mkDerivation {
name = "find-includes";
realBuilder = pkgs.perl ~ "bin/perl";
args = [ ./find-includes.pl ];
inherit main;
};
link = {objects, programName ? "program", libraries ? []}: stdenv.mkDerivation {
name = "link";
builder = ./link.sh;
inherit objects programName libraries;
};
makeLibrary = {objects, libraryName ? [], sharedLib ? false}:
# assert sharedLib -> fold (obj: x: assert obj.sharedLib && x) false objects
stdenv.mkDerivation {
name = "library";
builder = ./make-library.sh;
inherit objects libraryName sharedLib;
};
}

View File

@@ -1,21 +0,0 @@
use strict;
my $root = $ENV{"main"};
my $out = $ENV{"out"};
open OUT, ">$out" or die "$!";
print OUT "[\n";
open IN, "<$root" or die "$!";
while (<IN>) {
if (/^\#include\s+\"(.*)\"/) {
print OUT "\"$1\"\n";
}
if (/^\#include\s+\<(.*)\>/) {
print OUT "\"$1\"\n";
}
}
close IN;
print OUT "]\n";
close OUT;

View File

@@ -1,21 +0,0 @@
. $stdenv/setup
shopt -s nullglob
objs=
for i in $objects; do
obj=$(echo $i/*.o)
objs="$objs $obj"
done
libs=
for i in $libraries; do
lib=$(echo $i/*.a; echo $i/*.so)
name=$(echo $(basename $lib) | sed -e 's/^lib//' -e 's/.a$//' -e 's/.so$//')
libs="$libs -L$(dirname $lib) -l$name"
done
echo "linking object files into \`$programName'..."
mkdir $out
gcc -o $out/$programName $objs $libs

View File

@@ -1,28 +0,0 @@
. $stdenv/setup
objs=
for i in $objects; do
obj=$(echo $i/*.o)
objs="$objs $obj"
done
echo "archiving object files into library \`$libraryName'..."
ensureDir $out
if test -z "$sharedLib"; then
outPath=$out/lib${libraryName}.a
ar crs $outPath $objs
ranlib $outPath
else
outPath=$out/lib${libraryName}.so
gcc -shared -o $outPath $objs
fi

View File

@@ -67,7 +67,7 @@ The hook `nix-mode-hook' is run when Nix mode is started.
(defvar nix-keywords
'("\\<if\\>" "\\<then\\>" "\\<else\\>" "\\<assert\\>" "\\<with\\>"
"\\<let\\>" "\\<in\\>" "\\<rec\\>" "\\<inherit\\>"
"\\<let\\>" "\\<in\\>" "\\<rec\\>" "\\<inherit\\>" "\\<or\\>"
("\\<true\\>" . font-lock-builtin-face)
("\\<false\\>" . font-lock-builtin-face)
("\\<null\\>" . font-lock-builtin-face)
@@ -80,6 +80,8 @@ The hook `nix-mode-hook' is run when Nix mode is started.
. font-lock-constant-face)
("\\<\\([a-zA-Z_][a-zA-Z0-9_'\.]*\\)[ \t]*="
(1 font-lock-variable-name-face nil nil))
("<[a-zA-Z0-9._\\+-]+\\(/[a-zA-Z0-9._\\+-]+\\)*>"
. font-lock-constant-face)
("[a-zA-Z0-9._\\+-]*\\(/[a-zA-Z0-9._\\+-]+\\)+"
. font-lock-constant-face)
))
@@ -107,3 +109,5 @@ The hook `nix-mode-hook' is run when Nix mode is started.
(setq auto-mode-alist (cons '("\\.nix\\'" . nix-mode) auto-mode-alist))
(setq auto-mode-alist (cons '("\\.nix.in\\'" . nix-mode) auto-mode-alist))
(provide 'nix-mode)

View File

@@ -19,6 +19,8 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot
Prefix: /usr
Requires: /usr/bin/perl
Requires: curl
Requires: perl-DBD-SQLite
Requires: perl-devel
# Hack to make that shitty RPM scanning hack shut up.
Provides: perl(readmanifest)

7
perl/MANIFEST Normal file
View File

@@ -0,0 +1,7 @@
Changes
Makefile.PL
MANIFEST
Nix.xs
README
t/Nix.t
lib/Nix.pm

34
perl/Makefile.am Normal file
View File

@@ -0,0 +1,34 @@
perlversion := $(shell perl -e 'use Config; print $$Config{version};')
perlarchname := $(shell perl -e 'use Config; print $$Config{archname};')
perllibdir = $(libdir)/perl5/site_perl/$(perlversion)/$(perlarchname)
PERL_MODULES = lib/Nix/Store.pm lib/Nix/Manifest.pm lib/Nix/GeneratePatches.pm lib/Nix/SSH.pm lib/Nix/CopyClosure.pm lib/Nix/Config.pm.in
# Hack required by "make check".
all: $(PERL_MODULES:.in=)
mkdir -p lib/auto/Nix/Store
ln -sfn $(abs_builddir)/.libs/libNixStore.so lib/auto/Nix/Store/Store.so
install-exec-local: $(PERL_MODULES:.in=)
$(INSTALL) -d $(DESTDIR)$(perllibdir)/Nix
$(INSTALL_DATA) $(PERL_MODULES:.in=) $(DESTDIR)$(perllibdir)/Nix
$(INSTALL) -d $(DESTDIR)$(perllibdir)/auto/Nix/Store
ln -sfn $(pkglibdir)/libNixStore.so $(DESTDIR)$(perllibdir)/auto/Nix/Store/Store.so
# Awful hackery to get libtool to build Perl XS bindings.
pkglib_LTLIBRARIES = libNixStore.la
libNixStore_la_SOURCES = lib/Nix/Store.cc
libNixStore_la_LIBADD = $(top_srcdir)/src/libstore/libstore.la
AM_CXXFLAGS = \
-I$(top_srcdir)/src -I$(top_srcdir)/src/libutil -I$(top_srcdir)/src/libstore \
-I$(shell perl -e 'use Config; print $$Config{archlibexp};')/CORE
lib/Nix/Store.cc: lib/Nix/Store.xs
xsubpp $^ -output $@
EXTRA_DIST = $(PERL_MODULES) lib/Nix/Store.xs
include ../substitute.mk

27
perl/lib/Nix/Config.pm.in Normal file
View File

@@ -0,0 +1,27 @@
package Nix::Config;
$binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
$libexecDir = $ENV{"NIX_LIBEXEC_DIR"} || "@libexecdir@";
$stateDir = $ENV{"NIX_STATE_DIR"} || "@localstatedir@/nix";
$manifestDir = $ENV{"NIX_MANIFESTS_DIR"} || "@localstatedir@/nix/manifests";
$logDir = $ENV{"NIX_LOG_DIR"} || "@localstatedir@/log/nix";
$confDir = $ENV{"NIX_CONF_DIR"} || "@sysconfdir@/nix";
$bzip2 = $ENV{"NIX_BZIP2"} || "@bzip2@";
$curl = "@curl@";
sub readConfig {
my %config;
my $config = "@sysconfdir@/nix/nix.conf";
return unless -f $config;
open CONFIG, "<$config" or die "cannot open `$config'";
while (<CONFIG>) {
/^\s*([\w|-]+)\s*=\s*(.*)$/ or next;
$config{$1} = $2;
print "|$1| -> |$2|\n";
}
close CONFIG;
}
return 1;

View File

@@ -0,0 +1,46 @@
package Nix::CopyClosure;
use strict;
use Nix::Config;
use Nix::Store;
sub copyTo {
my ($sshHost, $sshOpts, $storePaths, $compressor, $decompressor, $includeOutputs, $dryRun, $sign) = @_;
$compressor = "$compressor |" if $compressor ne "";
$decompressor = "$decompressor |" if $decompressor ne "";
# Get the closure of this path.
my @closure = reverse(topoSortPaths(computeFSClosure(0, $includeOutputs,
map { followLinksToStorePath $_ } @{$storePaths})));
# Ask the remote host which paths are invalid. Because of limits
# to the command line length, do this in chunks. Eventually,
# we'll want to use --from-stdin, but we can't rely on the
# target having this option yet.
my @missing = ();
while (scalar(@closure) > 0) {
my @ps = splice(@closure, 0, 1500);
open(READ, "set -f; ssh $sshHost @{$sshOpts} nix-store --check-validity --print-invalid @ps|");
while (<READ>) {
chomp;
push @missing, $_;
}
close READ or die;
}
# Export the store paths and import them on the remote machine.
if (scalar @missing > 0) {
print STDERR "copying ", scalar @missing, " missing paths to $sshHost...\n";
#print STDERR " $_\n" foreach @missing;
unless ($dryRun) {
open SSH, "| $compressor ssh $sshHost @{$sshOpts} '$decompressor nix-store --import'" or die;
exportPaths(fileno(SSH), $sign, @missing);
close SSH or die "copying store paths to remote machine `$sshHost' failed: $?";
}
}
}
1;

View File

@@ -1,7 +1,13 @@
#! @perl@ -w -I@libexecdir@/nix
package Nix::GeneratePatches;
use strict;
use File::Temp qw(tempdir);
use File::stat;
use Nix::Config;
use Nix::Manifest;
our @ISA = qw(Exporter);
our @EXPORT = qw(generatePatches propagatePatches copyPatches);
# Some patch generations options.
@@ -202,41 +208,41 @@ sub generatePatches {
next;
}
system("@bunzip2@ < $srcNarBz2 > $tmpDir/A") == 0
system("$Nix::Config::bzip2 -d < $srcNarBz2 > $tmpDir/A") == 0
or die "cannot unpack $srcNarBz2";
if ((stat "$tmpDir/A")[7] >= $maxNarSize) {
if (stat("$tmpDir/A")->size >= $maxNarSize) {
print " skipping, source is too large\n";
next;
}
system("@bunzip2@ < $dstNarBz2 > $tmpDir/B") == 0
system("$Nix::Config::bzip2 -d < $dstNarBz2 > $tmpDir/B") == 0
or die "cannot unpack $dstNarBz2";
if ((stat "$tmpDir/B")[7] >= $maxNarSize) {
if (stat("$tmpDir/B")->size >= $maxNarSize) {
print " skipping, destination is too large\n";
next;
}
my $time1 = time();
my $res = system("ulimit -t $timeLimit; @libexecdir@/bsdiff $tmpDir/A $tmpDir/B $tmpDir/DIFF");
my $res = system("ulimit -t $timeLimit; $Nix::Config::libexecDir/bsdiff $tmpDir/A $tmpDir/B $tmpDir/DIFF");
my $time2 = time();
if ($res) {
warn "binary diff computation aborted after ", $time2 - $time1, " seconds\n";
next;
}
my $baseHash = `@bindir@/nix-hash --flat --type $hashAlgo --base32 $tmpDir/A` or die;
my $baseHash = `$Nix::Config::binDir/nix-hash --flat --type $hashAlgo --base32 $tmpDir/A` or die;
chomp $baseHash;
my $narHash = `@bindir@/nix-hash --flat --type $hashAlgo --base32 $tmpDir/B` or die;
my $narHash = `$Nix::Config::binDir/nix-hash --flat --type $hashAlgo --base32 $tmpDir/B` or die;
chomp $narHash;
my $narDiffHash = `@bindir@/nix-hash --flat --type $hashAlgo --base32 $tmpDir/DIFF` or die;
my $narDiffHash = `$Nix::Config::binDir/nix-hash --flat --type $hashAlgo --base32 $tmpDir/DIFF` or die;
chomp $narDiffHash;
my $narDiffSize = (stat "$tmpDir/DIFF")[7];
my $dstNarBz2Size = (stat $dstNarBz2)[7];
my $narDiffSize = stat("$tmpDir/DIFF")->size;
my $dstNarBz2Size = stat($dstNarBz2)->size;
print " size $narDiffSize; full size $dstNarBz2Size; ", $time2 - $time1, " seconds\n";

367
perl/lib/Nix/Manifest.pm Normal file
View File

@@ -0,0 +1,367 @@
package Nix::Manifest;
use strict;
use DBI;
use Cwd;
use File::stat;
use File::Path;
use Fcntl ':flock';
use Nix::Config;
our @ISA = qw(Exporter);
our @EXPORT = qw(readManifest writeManifest updateManifestDB addPatch);
sub addNAR {
my ($narFiles, $storePath, $info) = @_;
$$narFiles{$storePath} = []
unless defined $$narFiles{$storePath};
my $narFileList = $$narFiles{$storePath};
my $found = 0;
foreach my $narFile (@{$narFileList}) {
$found = 1 if $narFile->{url} eq $info->{url};
}
push @{$narFileList}, $info if !$found;
}
sub addPatch {
my ($patches, $storePath, $patch) = @_;
$$patches{$storePath} = []
unless defined $$patches{$storePath};
my $patchList = $$patches{$storePath};
my $found = 0;
foreach my $patch2 (@{$patchList}) {
$found = 1 if
$patch2->{url} eq $patch->{url} &&
$patch2->{basePath} eq $patch->{basePath};
}
push @{$patchList}, $patch if !$found;
return !$found;
}
sub readManifest_ {
my ($manifest, $addNAR, $addPatch) = @_;
# Decompress the manifest if necessary.
if ($manifest =~ /\.bz2$/) {
open MANIFEST, "$Nix::Config::bzip2 -d < $manifest |"
or die "cannot decompress `$manifest': $!";
} else {
open MANIFEST, "<$manifest"
or die "cannot open `$manifest': $!";
}
my $inside = 0;
my $type;
my $manifestVersion = 2;
my ($storePath, $url, $hash, $size, $basePath, $baseHash, $patchType);
my ($narHash, $narSize, $references, $deriver, $copyFrom, $system);
while (<MANIFEST>) {
chomp;
s/\#.*$//g;
next if (/^$/);
if (!$inside) {
if (/^\s*(\w*)\s*\{$/) {
$type = $1;
$type = "narfile" if $type eq "";
$inside = 1;
undef $storePath;
undef $url;
undef $hash;
undef $size;
undef $narHash;
undef $narSize;
undef $basePath;
undef $baseHash;
undef $patchType;
undef $system;
$references = "";
$deriver = "";
}
} else {
if (/^\}$/) {
$inside = 0;
if ($type eq "narfile") {
&$addNAR($storePath,
{ url => $url, hash => $hash, size => $size
, narHash => $narHash, narSize => $narSize
, references => $references
, deriver => $deriver
, system => $system
});
}
elsif ($type eq "patch") {
&$addPatch($storePath,
{ url => $url, hash => $hash, size => $size
, basePath => $basePath, baseHash => $baseHash
, narHash => $narHash, narSize => $narSize
, patchType => $patchType
});
}
}
elsif (/^\s*StorePath:\s*(\/\S+)\s*$/) { $storePath = $1; }
elsif (/^\s*CopyFrom:\s*(\/\S+)\s*$/) { $copyFrom = $1; }
elsif (/^\s*Hash:\s*(\S+)\s*$/) { $hash = $1; }
elsif (/^\s*URL:\s*(\S+)\s*$/) { $url = $1; }
elsif (/^\s*Size:\s*(\d+)\s*$/) { $size = $1; }
elsif (/^\s*BasePath:\s*(\/\S+)\s*$/) { $basePath = $1; }
elsif (/^\s*BaseHash:\s*(\S+)\s*$/) { $baseHash = $1; }
elsif (/^\s*Type:\s*(\S+)\s*$/) { $patchType = $1; }
elsif (/^\s*NarHash:\s*(\S+)\s*$/) { $narHash = $1; }
elsif (/^\s*NarSize:\s*(\d+)\s*$/) { $narSize = $1; }
elsif (/^\s*References:\s*(.*)\s*$/) { $references = $1; }
elsif (/^\s*Deriver:\s*(\S+)\s*$/) { $deriver = $1; }
elsif (/^\s*ManifestVersion:\s*(\d+)\s*$/) { $manifestVersion = $1; }
elsif (/^\s*System:\s*(\S+)\s*$/) { $system = $1; }
# Compatibility;
elsif (/^\s*NarURL:\s*(\S+)\s*$/) { $url = $1; }
elsif (/^\s*MD5:\s*(\S+)\s*$/) { $hash = "md5:$1"; }
}
}
close MANIFEST;
return $manifestVersion;
}
sub readManifest {
my ($manifest, $narFiles, $patches) = @_;
readManifest_($manifest,
sub { addNAR($narFiles, @_); },
sub { addPatch($patches, @_); } );
}
sub writeManifest {
my ($manifest, $narFiles, $patches, $noCompress) = @_;
open MANIFEST, ">$manifest.tmp"; # !!! check exclusive
print MANIFEST "version {\n";
print MANIFEST " ManifestVersion: 3\n";
print MANIFEST "}\n";
foreach my $storePath (sort (keys %{$narFiles})) {
my $narFileList = $$narFiles{$storePath};
foreach my $narFile (@{$narFileList}) {
print MANIFEST "{\n";
print MANIFEST " StorePath: $storePath\n";
print MANIFEST " NarURL: $narFile->{url}\n";
print MANIFEST " Hash: $narFile->{hash}\n" if defined $narFile->{hash};
print MANIFEST " Size: $narFile->{size}\n" if defined $narFile->{size};
print MANIFEST " NarHash: $narFile->{narHash}\n";
print MANIFEST " NarSize: $narFile->{narSize}\n" if $narFile->{narSize};
print MANIFEST " References: $narFile->{references}\n"
if defined $narFile->{references} && $narFile->{references} ne "";
print MANIFEST " Deriver: $narFile->{deriver}\n"
if defined $narFile->{deriver} && $narFile->{deriver} ne "";
print MANIFEST " System: $narFile->{system}\n" if defined $narFile->{system};
print MANIFEST "}\n";
}
}
foreach my $storePath (sort (keys %{$patches})) {
my $patchList = $$patches{$storePath};
foreach my $patch (@{$patchList}) {
print MANIFEST "patch {\n";
print MANIFEST " StorePath: $storePath\n";
print MANIFEST " NarURL: $patch->{url}\n";
print MANIFEST " Hash: $patch->{hash}\n";
print MANIFEST " Size: $patch->{size}\n";
print MANIFEST " NarHash: $patch->{narHash}\n";
print MANIFEST " NarSize: $patch->{narSize}\n" if $patch->{narSize};
print MANIFEST " BasePath: $patch->{basePath}\n";
print MANIFEST " BaseHash: $patch->{baseHash}\n";
print MANIFEST " Type: $patch->{patchType}\n";
print MANIFEST "}\n";
}
}
close MANIFEST;
rename("$manifest.tmp", $manifest)
or die "cannot rename $manifest.tmp: $!";
# Create a bzipped manifest.
unless (defined $noCompress) {
system("$Nix::Config::bzip2 < $manifest > $manifest.bz2.tmp") == 0
or die "cannot compress manifest";
rename("$manifest.bz2.tmp", "$manifest.bz2")
or die "cannot rename $manifest.bz2.tmp: $!";
}
}
sub updateManifestDB {
my $manifestDir = $Nix::Config::manifestDir;
mkpath($manifestDir);
my $dbPath = "$manifestDir/cache.sqlite";
# Open/create the database.
our $dbh = DBI->connect("dbi:SQLite:dbname=$dbPath", "", "")
or die "cannot open database `$dbPath'";
$dbh->{RaiseError} = 1;
$dbh->{PrintError} = 0;
$dbh->do("pragma foreign_keys = on");
$dbh->do("pragma synchronous = off"); # we can always reproduce the cache
$dbh->do("pragma journal_mode = truncate");
# Initialise the database schema, if necessary.
$dbh->do(<<EOF);
create table if not exists Manifests (
id integer primary key autoincrement not null,
path text unique not null,
timestamp integer not null
);
EOF
$dbh->do(<<EOF);
create table if not exists NARs (
id integer primary key autoincrement not null,
manifest integer not null,
storePath text not null,
url text not null,
hash text,
size integer,
narHash text,
narSize integer,
refs text,
deriver text,
system text,
foreign key (manifest) references Manifests(id) on delete cascade
);
EOF
$dbh->do("create index if not exists NARs_storePath on NARs(storePath)");
$dbh->do(<<EOF);
create table if not exists Patches (
id integer primary key autoincrement not null,
manifest integer not null,
storePath text not null,
basePath text not null,
baseHash text not null,
url text not null,
hash text,
size integer,
narHash text,
narSize integer,
patchType text not null,
foreign key (manifest) references Manifests(id) on delete cascade
);
EOF
$dbh->do("create index if not exists Patches_storePath on Patches(storePath)");
# Acquire an exclusive lock to ensure that only one process
# updates the DB at the same time. This isn't really necessary,
# but it prevents work duplication and lock contention in SQLite.
my $lockFile = "$manifestDir/cache.lock";
open MAINLOCK, ">>$lockFile" or die "unable to acquire lock $lockFile: $!\n";
flock(MAINLOCK, LOCK_EX) or die;
our $insertNAR = $dbh->prepare(
"insert into NARs(manifest, storePath, url, hash, size, narHash, " .
"narSize, refs, deriver, system) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") or die;
our $insertPatch = $dbh->prepare(
"insert into Patches(manifest, storePath, basePath, baseHash, url, hash, " .
"size, narHash, narSize, patchType) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
$dbh->begin_work;
# Read each manifest in $manifestDir and add it to the database,
# unless we've already done so on a previous run.
my %seen;
for my $manifestLink (glob "$manifestDir/*.nixmanifest") {
my $manifest = Cwd::abs_path($manifestLink);
next unless -f $manifest;
my $timestamp = lstat($manifest)->mtime;
$seen{$manifest} = 1;
next if scalar @{$dbh->selectcol_arrayref(
"select 1 from Manifests where path = ? and timestamp = ?",
{}, $manifest, $timestamp)} == 1;
print STDERR "caching $manifest...\n";
$dbh->do("delete from Manifests where path = ?", {}, $manifest);
$dbh->do("insert into Manifests(path, timestamp) values (?, ?)",
{}, $manifest, $timestamp);
our $id = $dbh->last_insert_id("", "", "", "");
sub addNARToDB {
my ($storePath, $narFile) = @_;
$insertNAR->execute(
$id, $storePath, $narFile->{url}, $narFile->{hash}, $narFile->{size},
$narFile->{narHash}, $narFile->{narSize}, $narFile->{references},
$narFile->{deriver}, $narFile->{system});
};
sub addPatchToDB {
my ($storePath, $patch) = @_;
$insertPatch->execute(
$id, $storePath, $patch->{basePath}, $patch->{baseHash}, $patch->{url},
$patch->{hash}, $patch->{size}, $patch->{narHash}, $patch->{narSize},
$patch->{patchType});
};
my $version = readManifest_($manifest, \&addNARToDB, \&addPatchToDB);
if ($version < 3) {
die "you have an old-style or corrupt manifest `$manifestLink'; please delete it";
}
if ($version >= 10) {
die "manifest `$manifestLink' is too new; please delete it or upgrade Nix";
}
}
# Removed cached information for removed manifests from the DB.
foreach my $manifest (@{$dbh->selectcol_arrayref("select path from Manifests")}) {
next if defined $seen{$manifest};
$dbh->do("delete from Manifests where path = ?", {}, $manifest);
}
$dbh->commit;
close MAINLOCK;
return $dbh;
}
return 1;

27
perl/lib/Nix/Store.pm Normal file
View File

@@ -0,0 +1,27 @@
package Nix::Store;
use strict;
use warnings;
require Exporter;
our @ISA = qw(Exporter);
our %EXPORT_TAGS = ( 'all' => [ qw( ) ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw(
isValidPath queryReferences queryPathInfo queryDeriver queryPathHash
topoSortPaths computeFSClosure followLinksToStorePath exportPaths
hashPath hashFile hashString
addToStore makeFixedOutputPath
);
our $VERSION = '0.15';
require XSLoader;
XSLoader::load('Nix::Store', $VERSION);
1;
__END__

218
perl/lib/Nix/Store.xs Normal file
View File

@@ -0,0 +1,218 @@
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
/* Prevent a clash between some Perl and libstdc++ macros. */
#undef do_open
#undef do_close
#include <store-api.hh>
#include <globals.hh>
#include <misc.hh>
#include <util.hh>
using namespace nix;
void doInit()
{
if (!store) {
try {
setDefaultsFromEnvironment();
store = openStore();
} catch (Error & e) {
croak(e.what());
}
}
}
MODULE = Nix::Store PACKAGE = Nix::Store
PROTOTYPES: ENABLE
void init()
CODE:
doInit();
int isValidPath(char * path)
CODE:
try {
doInit();
RETVAL = store->isValidPath(path);
} catch (Error & e) {
croak(e.what());
}
OUTPUT:
RETVAL
SV * queryReferences(char * path)
PPCODE:
try {
doInit();
PathSet paths;
store->queryReferences(path, paths);
for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i)
XPUSHs(sv_2mortal(newSVpv(i->c_str(), 0)));
} catch (Error & e) {
croak(e.what());
}
SV * queryPathHash(char * path)
PPCODE:
try {
doInit();
Hash hash = store->queryPathHash(path);
string s = "sha256:" + printHash32(hash);
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
} catch (Error & e) {
croak(e.what());
}
SV * queryDeriver(char * path)
PPCODE:
try {
doInit();
Path deriver = store->queryDeriver(path);
if (deriver == "") XSRETURN_UNDEF;
XPUSHs(sv_2mortal(newSVpv(deriver.c_str(), 0)));
} catch (Error & e) {
croak(e.what());
}
SV * queryPathInfo(char * path)
PPCODE:
try {
doInit();
ValidPathInfo info = store->queryPathInfo(path);
if (info.deriver == "")
XPUSHs(&PL_sv_undef);
else
XPUSHs(sv_2mortal(newSVpv(info.deriver.c_str(), 0)));
string s = "sha256:" + printHash(info.hash);
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
mXPUSHi(info.registrationTime);
mXPUSHi(info.narSize);
AV * arr = newAV();
for (PathSet::iterator i = info.references.begin(); i != info.references.end(); ++i)
av_push(arr, newSVpv(i->c_str(), 0));
XPUSHs(sv_2mortal(newRV((SV *) arr)));
} catch (Error & e) {
croak(e.what());
}
SV * computeFSClosure(int flipDirection, int includeOutputs, ...)
PPCODE:
try {
doInit();
PathSet paths;
for (int n = 2; n < items; ++n)
computeFSClosure(*store, SvPV_nolen(ST(n)), paths, flipDirection, includeOutputs);
for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i)
XPUSHs(sv_2mortal(newSVpv(i->c_str(), 0)));
} catch (Error & e) {
croak(e.what());
}
SV * topoSortPaths(...)
PPCODE:
try {
doInit();
PathSet paths;
for (int n = 0; n < items; ++n) paths.insert(SvPV_nolen(ST(n)));
Paths sorted = topoSortPaths(*store, paths);
for (Paths::iterator i = sorted.begin(); i != sorted.end(); ++i)
XPUSHs(sv_2mortal(newSVpv(i->c_str(), 0)));
} catch (Error & e) {
croak(e.what());
}
SV * followLinksToStorePath(char * path)
CODE:
try {
doInit();
RETVAL = newSVpv(followLinksToStorePath(path).c_str(), 0);
} catch (Error & e) {
croak(e.what());
}
OUTPUT:
RETVAL
void exportPaths(int fd, int sign, ...)
PPCODE:
try {
doInit();
Paths paths;
for (int n = 2; n < items; ++n) paths.push_back(SvPV_nolen(ST(n)));
FdSink sink(fd);
exportPaths(*store, paths, sign, sink);
} catch (Error & e) {
croak(e.what());
}
SV * hashPath(char * algo, int base32, char * path)
PPCODE:
try {
Hash h = hashPath(parseHashType(algo), path).first;
string s = base32 ? printHash32(h) : printHash(h);
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
} catch (Error & e) {
croak(e.what());
}
SV * hashFile(char * algo, int base32, char * path)
PPCODE:
try {
Hash h = hashFile(parseHashType(algo), path);
string s = base32 ? printHash32(h) : printHash(h);
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
} catch (Error & e) {
croak(e.what());
}
SV * hashString(char * algo, int base32, char * s)
PPCODE:
try {
Hash h = hashString(parseHashType(algo), s);
string s = base32 ? printHash32(h) : printHash(h);
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
} catch (Error & e) {
croak(e.what());
}
SV * addToStore(char * srcPath, int recursive, char * algo)
PPCODE:
try {
doInit();
Path path = store->addToStore(srcPath, recursive, parseHashType(algo));
XPUSHs(sv_2mortal(newSVpv(path.c_str(), 0)));
} catch (Error & e) {
croak(e.what());
}
SV * makeFixedOutputPath(int recursive, char * algo, char * hash, char * name)
PPCODE:
try {
doInit();
HashType ht = parseHashType(algo);
Path path = makeFixedOutputPath(recursive, ht,
parseHash16or32(ht, hash), name);
XPUSHs(sv_2mortal(newSVpv(path.c_str(), 0)));
} catch (Error & e) {
croak(e.what());
}

View File

@@ -1,4 +1,4 @@
{ nixpkgs ? ../nixpkgs
{ nixpkgs ? <nixpkgs>, nixos ? <nixos>
, nix ? { outPath = ./.; rev = 1234; }
, officialRelease ? false
}:
@@ -26,6 +26,8 @@ let
--with-docbook-rng=${docbook5}/xml/rng/docbook
--with-docbook-xsl=${docbook5_xsl}/xml/xsl/docbook
--with-xml-flags=--nonet
--with-dbi=${perlPackages.DBI}/lib/perl5/site_perl
--with-dbd-sqlite=${perlPackages.DBDSQLite}/lib/perl5/site_perl
'';
# Include the Bzip2 tarball in the distribution.
@@ -75,6 +77,8 @@ let
configureFlags = ''
--disable-init-state
--with-bzip2=${bzip2} --with-sqlite=${sqlite}
--with-dbi=${perlPackages.DBI}/lib/perl5/site_perl
--with-dbd-sqlite=${perlPackages.DBDSQLite}/lib/perl5/site_perl
--enable-gc
'';
};
@@ -94,8 +98,10 @@ let
];
configureFlags = ''
--disable-init-state --disable-shared
--disable-init-state
--with-bzip2=${bzip2} --with-sqlite=${sqlite}
--with-dbi=${perlPackages.DBI}/lib/perl5/site_perl
--with-dbd-sqlite=${perlPackages.DBDSQLite}/lib/perl5/site_perl
'';
lcovFilter = [ "*/boost/*" "*-tab.*" ];
@@ -107,34 +113,42 @@ let
};
rpm_fedora5i386 = makeRPM_i686 (diskImages: diskImages.fedora5i386) 10;
rpm_fedora9i386 = makeRPM_i686 (diskImages: diskImages.fedora9i386) 20;
rpm_fedora9x86_64 = makeRPM_x86_64 (diskImages: diskImages.fedora9x86_64) 20;
rpm_fedora10i386 = makeRPM_i686 (diskImages: diskImages.fedora10i386) 30;
rpm_fedora10x86_64 = makeRPM_x86_64 (diskImages: diskImages.fedora10x86_64) 30;
rpm_fedora11i386 = makeRPM_i686 (diskImages: diskImages.fedora11i386) 40;
rpm_fedora11x86_64 = makeRPM_x86_64 (diskImages: diskImages.fedora11x86_64) 40;
rpm_fedora12i386 = makeRPM_i686 (diskImages: diskImages.fedora12i386) 50;
rpm_fedora12x86_64 = makeRPM_x86_64 (diskImages: diskImages.fedora12x86_64) 50;
rpm_opensuse103i386 = makeRPM_i686 (diskImages: diskImages.opensuse103i386) 40;
rpm_opensuse110i386 = makeRPM_i686 (diskImages: diskImages.opensuse110i386) 50;
rpm_opensuse110x86_64 = makeRPM_x86_64 (diskImages: diskImages.opensuse110x86_64) 50;
rpm_fedora10i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora10i386) 20;
rpm_fedora10x86_64 = makeRPM_x86_64 (diskImageFuns: diskImageFuns.fedora10x86_64) 20;
rpm_fedora11i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora11i386) 30;
rpm_fedora11x86_64 = makeRPM_x86_64 (diskImageFuns: diskImageFuns.fedora11x86_64) 30;
rpm_fedora12i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora12i386) 40;
rpm_fedora12x86_64 = makeRPM_x86_64 (diskImageFuns: diskImageFuns.fedora12x86_64) 40;
rpm_fedora13i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora13i386) 50;
rpm_fedora13x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora13x86_64) 50;
rpm_opensuse103i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.opensuse103i386) 40;
rpm_opensuse110i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.opensuse110i386) 50;
rpm_opensuse110x86_64 = makeRPM_x86_64 (diskImageFuns: diskImageFuns.opensuse110x86_64) 50;
deb_debian40i386 = makeDeb_i686 (diskImages: diskImages.debian40i386) 40;
deb_debian40x86_64 = makeDeb_x86_64 (diskImages: diskImages.debian40x86_64) 40;
deb_debian50i386 = makeDeb_i686 (diskImages: diskImages.debian50i386) 50;
deb_debian50x86_64 = makeDeb_x86_64 (diskImages: diskImages.debian50x86_64) 50;
deb_ubuntu804i386 = makeDeb_i686 (diskImages: diskImages.ubuntu804i386) 20;
deb_ubuntu804x86_64 = makeDeb_x86_64 (diskImages: diskImages.ubuntu804x86_64) 20;
deb_ubuntu810i386 = makeDeb_i686 (diskImages: diskImages.ubuntu810i386) 30;
deb_ubuntu810x86_64 = makeDeb_x86_64 (diskImages: diskImages.ubuntu810x86_64) 30;
deb_ubuntu904i386 = makeDeb_i686 (diskImages: diskImages.ubuntu904i386) 40;
deb_ubuntu904x86_64 = makeDeb_x86_64 (diskImages: diskImages.ubuntu904x86_64) 40;
deb_ubuntu910i386 = makeDeb_i686 (diskImages: diskImages.ubuntu910i386) 50;
deb_ubuntu910x86_64 = makeDeb_x86_64 (diskImages: diskImages.ubuntu910x86_64) 50;
deb_debian50i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.debian50i386) 50;
deb_debian50x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.debian50x86_64) 50;
deb_debian60i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.debian60i386) 50;
deb_debian60x86_64 = makeDeb_x86_64 (diskImageFunsFun: diskImageFunsFun.debian60x86_64) 50;
deb_ubuntu904i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu904i386) 40;
deb_ubuntu904x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu904x86_64) 40;
deb_ubuntu910i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu910i386) 50;
deb_ubuntu910x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu910x86_64) 50;
deb_ubuntu1004i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1004i386) 50;
deb_ubuntu1004x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1004x86_64) 50;
deb_ubuntu1010i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1010i386) 50;
deb_ubuntu1010x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1010x86_64) 50;
# System tests.
tests.remote_builds = (import ./tests/remote-builds.nix rec {
inherit nixpkgs nixos; nix = build { inherit system; }; system = "x86_64-linux";
}).test;
tests.nix_copy_closure = (import ./tests/nix-copy-closure.nix rec {
inherit nixpkgs nixos; nix = build { inherit system; }; system = "x86_64-linux";
}).test;
};
@@ -149,7 +163,8 @@ let
releaseTools.rpmBuild rec {
name = "nix-rpm-${diskImage.name}";
src = jobs.tarball;
diskImage = diskImageFun vmTools.diskImages;
diskImage = (diskImageFun vmTools.diskImageFuns)
{ extraPackages = [ "perl-DBD-SQLite" "perl-devel" ]; };
memSize = 1024;
meta.schedulingPriority = prio;
};
@@ -166,11 +181,12 @@ let
releaseTools.debBuild {
name = "nix-deb";
src = jobs.tarball;
diskImage = diskImageFun vmTools.diskImages;
diskImage = (diskImageFun vmTools.diskImageFuns)
{ extraPackages = [ "libdbd-sqlite3-perl" ]; };
memSize = 1024;
meta.schedulingPriority = prio;
configureFlags = "--sysconfdir=/etc";
debRequires = [ "curl" ];
debRequires = [ "curl" "libdbd-sqlite3-perl" ];
};

View File

@@ -3,20 +3,16 @@ bin_SCRIPTS = nix-collect-garbage \
nix-install-package nix-channel nix-build \
nix-copy-closure nix-generate-patches
noinst_SCRIPTS = nix-profile.sh GeneratePatches.pm \
noinst_SCRIPTS = nix-profile.sh \
find-runtime-roots.pl build-remote.pl nix-reduce-build \
copy-from-other-stores.pl nix-http-export.cgi
nix-pull nix-push: NixManifest.pm NixConfig.pm download-using-manifests.pl
nix-pull nix-push: download-using-manifests.pl
install-exec-local: NixManifest.pm GeneratePatches.pm download-using-manifests.pl copy-from-other-stores.pl find-runtime-roots.pl
install-exec-local: download-using-manifests.pl copy-from-other-stores.pl find-runtime-roots.pl
$(INSTALL) -d $(DESTDIR)$(sysconfdir)/profile.d
$(INSTALL_PROGRAM) nix-profile.sh $(DESTDIR)$(sysconfdir)/profile.d/nix.sh
$(INSTALL) -d $(DESTDIR)$(libexecdir)/nix
$(INSTALL_DATA) NixManifest.pm $(DESTDIR)$(libexecdir)/nix
$(INSTALL_DATA) NixConfig.pm $(DESTDIR)$(libexecdir)/nix
$(INSTALL_DATA) SSH.pm $(DESTDIR)$(libexecdir)/nix
$(INSTALL_DATA) GeneratePatches.pm $(DESTDIR)$(libexecdir)/nix
$(INSTALL_PROGRAM) find-runtime-roots.pl $(DESTDIR)$(libexecdir)/nix
$(INSTALL_PROGRAM) build-remote.pl $(DESTDIR)$(libexecdir)/nix
$(INSTALL) -d $(DESTDIR)$(libexecdir)/nix/substituters
@@ -30,10 +26,6 @@ EXTRA_DIST = nix-collect-garbage.in \
nix-pull.in nix-push.in nix-profile.sh.in \
nix-prefetch-url.in nix-install-package.in \
nix-channel.in \
NixManifest.pm.in \
NixConfig.pm.in \
SSH.pm \
GeneratePatches.pm.in \
nix-build.in \
download-using-manifests.pl.in \
copy-from-other-stores.pl.in \
@@ -43,3 +35,6 @@ EXTRA_DIST = nix-collect-garbage.in \
nix-reduce-build.in \
nix-http-export.cgi.in \
nix-generate-patches.in
clean:
rm -f $(bin_SCRIPTS) $(noinst_SCRIPTS)

View File

@@ -1,17 +0,0 @@
use strict;
sub readConfig {
my %config;
my $config = "@sysconfdir@/nix/nix.conf";
return unless -f $config;
open CONFIG, "<$config" or die "cannot open `$config'";
while (<CONFIG>) {
/^\s*([\w|-]+)\s*=\s*(.*)$/ or next;
$config{$1} = $2;
print "|$1| -> |$2|\n";
}
close CONFIG;
}
return 1;

View File

@@ -1,211 +0,0 @@
use strict;
sub addPatch {
my ($patches, $storePath, $patch) = @_;
$$patches{$storePath} = []
unless defined $$patches{$storePath};
my $patchList = $$patches{$storePath};
my $found = 0;
foreach my $patch2 (@{$patchList}) {
$found = 1 if
$patch2->{url} eq $patch->{url} &&
$patch2->{basePath} eq $patch->{basePath};
}
push @{$patchList}, $patch if !$found;
return !$found;
}
sub readManifest {
my ($manifest, $narFiles, $localPaths, $patches) = @_;
open MANIFEST, "<$manifest"
or die "cannot open `$manifest': $!";
my $inside = 0;
my $type;
my $manifestVersion = 2;
my ($storePath, $url, $hash, $size, $basePath, $baseHash, $patchType);
my ($narHash, $narSize, $references, $deriver, $hashAlgo, $copyFrom, $system);
while (<MANIFEST>) {
chomp;
s/\#.*$//g;
next if (/^$/);
if (!$inside) {
if (/^\s*(\w*)\s*\{$/) {
$type = $1;
$type = "narfile" if $type eq "";
$inside = 1;
undef $storePath;
undef $url;
undef $hash;
undef $size;
undef $narHash;
undef $narSize;
undef $basePath;
undef $baseHash;
undef $patchType;
undef $system;
$references = "";
$deriver = "";
$hashAlgo = "md5";
}
} else {
if (/^\}$/) {
$inside = 0;
if ($type eq "narfile") {
$$narFiles{$storePath} = []
unless defined $$narFiles{$storePath};
my $narFileList = $$narFiles{$storePath};
my $found = 0;
foreach my $narFile (@{$narFileList}) {
$found = 1 if $narFile->{url} eq $url;
}
if (!$found) {
push @{$narFileList},
{ url => $url, hash => $hash, size => $size
, narHash => $narHash, narSize => $narSize
, references => $references
, deriver => $deriver, hashAlgo => $hashAlgo
, system => $system
};
}
}
elsif ($type eq "patch") {
addPatch $patches, $storePath,
{ url => $url, hash => $hash, size => $size
, basePath => $basePath, baseHash => $baseHash
, narHash => $narHash, narSize => $narSize
, patchType => $patchType, hashAlgo => $hashAlgo
};
}
elsif ($type eq "localPath") {
$$localPaths{$storePath} = []
unless defined $$localPaths{$storePath};
my $localPathsList = $$localPaths{$storePath};
# !!! remove duplicates
push @{$localPathsList},
{ copyFrom => $copyFrom, references => $references
, deriver => ""
};
}
}
elsif (/^\s*StorePath:\s*(\/\S+)\s*$/) { $storePath = $1; }
elsif (/^\s*CopyFrom:\s*(\/\S+)\s*$/) { $copyFrom = $1; }
elsif (/^\s*Hash:\s*(\S+)\s*$/) { $hash = $1; }
elsif (/^\s*URL:\s*(\S+)\s*$/) { $url = $1; }
elsif (/^\s*Size:\s*(\d+)\s*$/) { $size = $1; }
elsif (/^\s*SuccOf:\s*(\/\S+)\s*$/) { } # obsolete
elsif (/^\s*BasePath:\s*(\/\S+)\s*$/) { $basePath = $1; }
elsif (/^\s*BaseHash:\s*(\S+)\s*$/) { $baseHash = $1; }
elsif (/^\s*Type:\s*(\S+)\s*$/) { $patchType = $1; }
elsif (/^\s*NarHash:\s*(\S+)\s*$/) { $narHash = $1; }
elsif (/^\s*NarSize:\s*(\d+)\s*$/) { $narSize = $1; }
elsif (/^\s*References:\s*(.*)\s*$/) { $references = $1; }
elsif (/^\s*Deriver:\s*(\S+)\s*$/) { $deriver = $1; }
elsif (/^\s*ManifestVersion:\s*(\d+)\s*$/) { $manifestVersion = $1; }
elsif (/^\s*System:\s*(\S+)\s*$/) { $system = $1; }
# Compatibility;
elsif (/^\s*NarURL:\s*(\S+)\s*$/) { $url = $1; }
elsif (/^\s*MD5:\s*(\S+)\s*$/) { $hash = "md5:$1"; }
}
}
close MANIFEST;
return $manifestVersion;
}
sub writeManifest {
my ($manifest, $narFiles, $patches, $noCompress) = @_;
open MANIFEST, ">$manifest.tmp"; # !!! check exclusive
print MANIFEST "version {\n";
print MANIFEST " ManifestVersion: 3\n";
print MANIFEST "}\n";
foreach my $storePath (sort (keys %{$narFiles})) {
my $narFileList = $$narFiles{$storePath};
foreach my $narFile (@{$narFileList}) {
print MANIFEST "{\n";
print MANIFEST " StorePath: $storePath\n";
print MANIFEST " NarURL: $narFile->{url}\n";
print MANIFEST " Hash: $narFile->{hash}\n" if defined $narFile->{hash};
print MANIFEST " Size: $narFile->{size}\n" if defined $narFile->{size};
print MANIFEST " NarHash: $narFile->{narHash}\n";
print MANIFEST " NarSize: $narFile->{narSize}\n" if $narFile->{narSize};
print MANIFEST " References: $narFile->{references}\n"
if defined $narFile->{references} && $narFile->{references} ne "";
print MANIFEST " Deriver: $narFile->{deriver}\n"
if defined $narFile->{deriver} && $narFile->{deriver} ne "";
print MANIFEST " System: $narFile->{system}\n" if defined $narFile->{system};
print MANIFEST "}\n";
}
}
foreach my $storePath (sort (keys %{$patches})) {
my $patchList = $$patches{$storePath};
foreach my $patch (@{$patchList}) {
print MANIFEST "patch {\n";
print MANIFEST " StorePath: $storePath\n";
print MANIFEST " NarURL: $patch->{url}\n";
print MANIFEST " Hash: $patch->{hash}\n";
print MANIFEST " Size: $patch->{size}\n";
print MANIFEST " NarHash: $patch->{narHash}\n";
print MANIFEST " NarSize: $patch->{narSize}\n" if $patch->{narSize};
print MANIFEST " BasePath: $patch->{basePath}\n";
print MANIFEST " BaseHash: $patch->{baseHash}\n";
print MANIFEST " Type: $patch->{patchType}\n";
print MANIFEST "}\n";
}
}
close MANIFEST;
rename("$manifest.tmp", $manifest)
or die "cannot rename $manifest.tmp: $!";
# Create a bzipped manifest.
unless (defined $noCompress) {
system("@bzip2@ < $manifest > $manifest.bz2.tmp") == 0
or die "cannot compress manifest";
rename("$manifest.bz2.tmp", "$manifest.bz2")
or die "cannot rename $manifest.bz2.tmp: $!";
}
}
return 1;

View File

@@ -1,9 +1,11 @@
#! @perl@ -w -I@libexecdir@/nix
#! @perl@ -w @perlFlags@
use Fcntl ':flock';
use Fcntl qw(:DEFAULT :flock);
use English '-no_match_vars';
use IO::Handle;
use SSH qw/sshOpts openSSHConnection/;
use Nix::Config;
use Nix::SSH qw/sshOpts openSSHConnection/;
use Nix::CopyClosure;
no warnings('once');
@@ -54,7 +56,7 @@ sub openSlotLock {
my ($machine, $slot) = @_;
my $slotLockFn = "$currentLoad/" . (join '+', @{$machine->{systemTypes}}) . "-" . $machine->{hostName} . "-$slot";
my $slotLock = new IO::Handle;
open $slotLock, ">>$slotLockFn" or die;
sysopen $slotLock, "$slotLockFn", O_RDWR|O_CREAT, 0600 or die;
return $slotLock;
}
@@ -62,7 +64,7 @@ sub openSlotLock {
# Read the list of machines.
my @machines;
if (defined $conf && -e $conf) {
open CONF, "< $conf" or die;
open CONF, "<$conf" or die;
while (<CONF>) {
chomp;
s/\#.*$//g;
@@ -102,7 +104,7 @@ REQ: while (1) {
# Acquire the exclusive lock on $currentLoad/main-lock.
mkdir $currentLoad, 0777 or die unless -d $currentLoad;
my $mainLock = "$currentLoad/main-lock";
open MAINLOCK, ">>$mainLock" or die;
sysopen MAINLOCK, "$mainLock", O_RDWR|O_CREAT, 0600 or die;
flock(MAINLOCK, LOCK_EX) or die;
@@ -208,7 +210,7 @@ print STDERR "@ build-remote $drvPath $hostName\n" if $printBuildTrace;
my $maybeSign = "";
$maybeSign = "--sign" if -e "/nix/etc/nix/signing-key.sec";
$maybeSign = "--sign" if -e "$Nix::Config::confDir/signing-key.sec";
# Register the derivation as a temporary GC root. Note that $PPID is
@@ -223,9 +225,17 @@ sub removeRoots {
}
# Copy the derivation and its dependencies to the build machine.
system("NIX_SSHOPTS=\"@sshOpts\" @bindir@/nix-copy-closure $hostName $maybeSign $drvPath @inputs") == 0
or die "cannot copy inputs to $hostName: $?";
# Copy the derivation and its dependencies to the build machine. This
# is guarded by an exclusive lock per machine to prevent multiple
# build-remote instances from copying to a machine simultaneously.
# That's undesirable because we may end up with N instances uploading
# the same missing path simultaneously, causing the effective network
# bandwidth and target disk speed to be divided by N.
my $uploadLock = "$currentLoad/$hostName.upload-lock";
sysopen MAINLOCK, "$uploadLock", O_RDWR|O_CREAT, 0600 or die;
flock(MAINLOCK, LOCK_EX) or die;
Nix::CopyClosure::copyTo($hostName, [ @sshOpts ], [ $drvPath, @inputs ], "", "", 0, 0, $maybeSign ne "");
close MAINLOCK;
# Perform the build.
@@ -239,7 +249,7 @@ my $buildFlags = "--max-silent-time $maxSilentTime --fallback --add-root $rootsD
# in which case every child receives SIGHUP; however, `-tt' doesn't
# work on some platforms when connection sharing is used.)
pipe STDIN, DUMMY; # make sure we have a readable STDIN
if (system("ssh $hostName @sshOpts '(read; kill -INT -\$\$) <&0 & nix-store -r $drvPath $buildFlags > /dev/null' 2>&4") != 0) {
if (system("exec ssh $hostName @sshOpts '(read; kill -INT -\$\$) <&0 & nix-store -r $drvPath $buildFlags > /dev/null' 2>&4") != 0) {
# Note that if we get exit code 100 from `nix-store -r', it
# denotes a permanent build failure (as opposed to an SSH problem
# or a temporary Nix problem). We propagate this to the caller to
@@ -259,7 +269,7 @@ foreach my $output (@outputs) {
my $maybeSignRemote = "";
$maybeSignRemote = "--sign" if $UID != 0;
system("ssh $hostName @sshOpts 'nix-store --export $maybeSignRemote $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: $?";
}

0
scripts/copy-from-other-stores.pl.in Normal file → Executable file
View File

162
scripts/download-using-manifests.pl.in Normal file → Executable file
View File

@@ -1,48 +1,27 @@
#! @perl@ -w -I@libexecdir@/nix
#! @perl@ -w @perlFlags@
use strict;
use NixManifest;
use Nix::Config;
use Nix::Manifest;
use Nix::Store;
use POSIX qw(strftime);
use File::Temp qw(tempdir);
my $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
STDOUT->autoflush(1);
my $manifestDir = ($ENV{"NIX_MANIFESTS_DIR"} or "@localstatedir@/nix/manifests");
my $logFile = "@localstatedir@/log/nix/downloads";
my $logFile = "$Nix::Config::logDir/downloads";
# For queries, skip expensive calls to nix-hash etc. We're just
# estimating the expected download size.
my $fast = 1;
# Load all manifests.
my %narFiles;
my %localPaths;
my %patches;
for my $manifest (glob "$manifestDir/*.nixmanifest") {
my $version = readManifest($manifest, \%narFiles, \%localPaths, \%patches);
if ($version < 3) {
print STDERR "you have an old-style manifest `$manifest'; please delete it\n";
exit 1;
}
if ($version >= 10) {
print STDERR "manifest `$manifest' is too new; please delete it or upgrade Nix\n";
exit 1;
}
}
# Open the manifest cache and update it if necessary.
my $dbh = updateManifestDB();
sub isValidPath {
my $p = shift;
if ($fast) {
return -e $p;
} else {
return system("$binDir/nix-store --check-validity '$p' 2> /dev/null") == 0;
}
}
# $hashCache->{$algo}->{$path} yields the $algo-hash of $path.
my $hashCache;
sub parseHash {
@@ -111,18 +90,23 @@ sub computeSmallestDownload {
else {
# Add patch edges.
my $patchList = $patches{$u};
my $patchList = $dbh->selectall_arrayref(
"select * from Patches where storePath = ?",
{ Slice => {} }, $u);
foreach my $patch (@{$patchList}) {
if (isValidPath($patch->{basePath})) {
# !!! this should be cached
my ($baseHashAlgo, $baseHash) = parseHash $patch->{baseHash};
my $format = "--base32";
$format = "" if $baseHashAlgo eq "md5";
my $hash = $fast && $baseHashAlgo eq "sha256"
? `$binDir/nix-store -q --hash "$patch->{basePath}"`
: `$binDir/nix-hash --type '$baseHashAlgo' $format "$patch->{basePath}"`;
chomp $hash;
$hash =~ s/.*://;
my $hash = $hashCache->{$baseHashAlgo}->{$patch->{basePath}};
if (!defined $hash) {
$hash = $fast && $baseHashAlgo eq "sha256"
? queryPathHash($patch->{basePath})
: hashPath($baseHashAlgo, $baseHashAlgo ne "md5", $patch->{basePath});
$hash =~ s/.*://;
$hashCache->{$baseHashAlgo}->{$patch->{basePath}} = $hash;
}
next if $hash ne $baseHash;
}
push @queue, $patch->{basePath};
@@ -130,11 +114,15 @@ sub computeSmallestDownload {
}
# Add NAR file edges to the start node.
my $narFileList = $narFiles{$u};
my $narFileList = $dbh->selectall_arrayref(
"select * from NARs where storePath = ?",
{ Slice => {} }, $u);
foreach my $narFile (@{$narFileList}) {
# !!! how to handle files whose size is not known in advance?
# For now, assume some arbitrary size (1 MB).
addEdge \%graph, "start", $u, ($narFile->{size} || 1000000), "narfile", $narFile;
# For now, assume some arbitrary size (1 GB).
# This has the side-effect of preferring non-Hydra downloads.
addEdge \%graph, "start", $u, ($narFile->{size} || 1000000000), "narfile", $narFile;
}
}
}
@@ -161,7 +149,7 @@ sub computeSmallestDownload {
$v_->{d} = $u_->{d} + $edge->{weight};
# Store the edge; to edge->start is actually the
# predecessor.
$v_->{pred} = $edge;
$v_->{pred} = $edge;
}
}
}
@@ -189,19 +177,21 @@ if ($ARGV[0] eq "--query") {
if ($cmd eq "have") {
my $storePath = <STDIN>; chomp $storePath;
print STDOUT ((defined $narFiles{$storePath} or defined $localPaths{$storePath})
print STDOUT (
scalar @{$dbh->selectcol_arrayref("select 1 from NARs where storePath = ?", {}, $storePath)} > 0
? "1\n" : "0\n");
}
elsif ($cmd eq "info") {
my $storePath = <STDIN>; chomp $storePath;
my $infos = $dbh->selectall_arrayref(
"select * from NARs where storePath = ?",
{ Slice => {} }, $storePath);
my $info;
if (defined $narFiles{$storePath}) {
$info = @{$narFiles{$storePath}}[0];
}
elsif (defined $localPaths{$storePath}) {
$info = @{$localPaths{$storePath}}[0];
if (scalar @{$infos} > 0) {
$info = @{$infos}[0];
}
else {
print "0\n";
@@ -210,12 +200,12 @@ if ($ARGV[0] eq "--query") {
print "1\n";
print "$info->{deriver}\n";
my @references = split " ", $info->{references};
my @references = split " ", $info->{refs};
print scalar @references, "\n";
print "$_\n" foreach @references;
my @path = computeSmallestDownload $storePath;
my $downloadSize = 0;
while (scalar @path > 0) {
my $edge = pop @path;
@@ -228,7 +218,7 @@ if ($ARGV[0] eq "--query") {
$downloadSize += $edge->{info}->{size} || 0;
}
}
print "$downloadSize\n";
my $narSize = $info->{narSize} || 0;
@@ -264,20 +254,7 @@ open LOGFILE, ">>$logFile" or die "cannot open log file $logFile";
my $date = strftime ("%F %H:%M:%S UTC", gmtime (time));
print LOGFILE "$$ get $targetPath $date\n";
print "\n*** Trying to download/patch `$targetPath'\n";
# If we can copy from a local path, do that.
my $localPathList = $localPaths{$targetPath};
foreach my $localPath (@{$localPathList}) {
my $sourcePath = $localPath->{copyFrom};
if (-e $sourcePath) {
print "\n*** Step 1/1: copying from $sourcePath\n";
system("$binDir/nix-store --dump $sourcePath | $binDir/nix-store --restore $targetPath") == 0
or die "cannot copy `$sourcePath' to `$targetPath'";
exit 0;
}
}
print STDERR "\n*** Trying to download/patch `$targetPath'\n";
# Compute the shortest path.
@@ -285,6 +262,12 @@ my @path = computeSmallestDownload $targetPath;
die "don't know how to produce $targetPath\n" if scalar @path == 0;
# We don't need the manifest anymore, so close it as an optimisation:
# if we still have SQLite locks blocking other processes (we
# shouldn't), this gets rid of them.
$dbh->disconnect;
# Traverse the shortest path, perform the actions described by the
# edges.
my $curStep = 1;
@@ -294,8 +277,8 @@ sub downloadFile {
my $url = shift;
$ENV{"PRINT_PATH"} = 1;
$ENV{"QUIET"} = 1;
my ($hash, $path) = `$binDir/nix-prefetch-url '$url'`;
die "download of `$url' failed" unless $? == 0;
my ($hash, $path) = `$Nix::Config::binDir/nix-prefetch-url '$url'`;
die "download of `$url' failed" . ($! ? ": $!" : "") . "\n" unless $? == 0;
chomp $path;
return $path;
}
@@ -307,36 +290,36 @@ while (scalar @path > 0) {
my $u = $edge->{start};
my $v = $edge->{end};
print "\n*** Step $curStep/$maxStep: ";
print STDERR "\n*** Step $curStep/$maxStep: ";
if ($edge->{type} eq "present") {
print "using already present path `$v'\n";
print STDERR "using already present path `$v'\n";
print LOGFILE "$$ present $v\n";
if ($curStep < $maxStep) {
# Since this is not the last step, the path will be used
# as a base to one or more patches. So turn the base path
# into a NAR archive, to which we can apply the patch.
print " packing base path...\n";
system("$binDir/nix-store --dump $v > $tmpNar") == 0
print STDERR " packing base path...\n";
system("$Nix::Config::binDir/nix-store --dump $v > $tmpNar") == 0
or die "cannot dump `$v'";
}
}
elsif ($edge->{type} eq "patch") {
my $patch = $edge->{info};
print "applying patch `$patch->{url}' to `$u' to create `$v'\n";
print STDERR "applying patch `$patch->{url}' to `$u' to create `$v'\n";
print LOGFILE "$$ patch $patch->{url} $patch->{size} $patch->{baseHash} $u $v\n";
# Download the patch.
print " downloading patch...\n";
print STDERR " downloading patch...\n";
my $patchPath = downloadFile "$patch->{url}";
# Apply the patch to the NAR archive produced in step 1 (for
# the already present path) or a later step (for patch sequences).
print " applying patch...\n";
system("@libexecdir@/bspatch $tmpNar $tmpNar2 $patchPath") == 0
print STDERR " applying patch...\n";
system("$Nix::Config::libexecDir/bspatch $tmpNar $tmpNar2 $patchPath") == 0
or die "cannot apply patch `$patchPath' to $tmpNar";
if ($curStep < $maxStep) {
@@ -345,8 +328,8 @@ while (scalar @path > 0) {
} else {
# This was the last patch. Unpack the final NAR archive
# into the target path.
print " unpacking patched archive...\n";
system("$binDir/nix-store --restore $v < $tmpNar2") == 0
print STDERR " unpacking patched archive...\n";
system("$Nix::Config::binDir/nix-store --restore $v < $tmpNar2") == 0
or die "cannot unpack $tmpNar2 into `$v'";
}
@@ -355,23 +338,23 @@ while (scalar @path > 0) {
elsif ($edge->{type} eq "narfile") {
my $narFile = $edge->{info};
print "downloading `$narFile->{url}' into `$v'\n";
print STDERR "downloading `$narFile->{url}' into `$v'\n";
my $size = $narFile->{size} || -1;
print LOGFILE "$$ narfile $narFile->{url} $size $v\n";
# Download the archive.
print " downloading archive...\n";
print STDERR " downloading archive...\n";
my $narFilePath = downloadFile "$narFile->{url}";
if ($curStep < $maxStep) {
# The archive will be used a base to a patch.
system("@bunzip2@ < '$narFilePath' > $tmpNar") == 0
system("$Nix::Config::bzip2 -d < '$narFilePath' > $tmpNar") == 0
or die "cannot unpack `$narFilePath' into `$v'";
} else {
# Unpack the archive into the target path.
print " unpacking archive...\n";
system("@bunzip2@ < '$narFilePath' | $binDir/nix-store --restore '$v'") == 0
print STDERR " unpacking archive...\n";
system("$Nix::Config::bzip2 -d < '$narFilePath' | $Nix::Config::binDir/nix-store --restore '$v'") == 0
or die "cannot unpack `$narFilePath' into `$v'";
}
@@ -390,20 +373,15 @@ if (defined $finalNarHash) {
# The hash in the manifest can be either in base-16 or base-32.
# Handle both.
my $extraFlag =
($hashAlgo eq "sha256" && length($hash) != 64)
? "--base32" : "";
my $hash2 = hashPath($hashAlgo, $hashAlgo eq "sha256" && length($hash) != 64, $targetPath);
my $hash2 = `@bindir@/nix-hash --type $hashAlgo $extraFlag $targetPath`
or die "cannot compute hash of path `$targetPath'";
chomp $hash2;
die "hash mismatch in downloaded path $targetPath; expected $hash, got $hash2"
die "hash mismatch in downloaded path $targetPath; expected $hash, got $hash2\n"
if $hash ne $hash2;
} else {
die "cannot check integrity of the downloaded path since its hash is not known";
die "cannot check integrity of the downloaded path since its hash is not known\n";
}
print STDERR "\n";
print LOGFILE "$$ success\n";
close LOGFILE;

0
scripts/find-runtime-roots.pl.in Normal file → Executable file
View File

View File

@@ -1,2 +1,2 @@
./gc-releases.pl /data/webserver/dist/*/*/MANIFEST > dead
cat dead | xargs mv --target-directory=/data/webserver/trash/
./gc-releases.pl /data/releases/patches/all-patches $(find /data/releases -name MANIFEST) | sort > dead
cat dead | xargs -d '\n' sh -c 'find "$@" -mtime +100 -print' | xargs -d '\n' mv -v --target-directory=/data/releases/trash/

View File

@@ -1,18 +1,18 @@
#! /usr/bin/perl -w -I. -I..
#! /var/run/current-system/sw/bin/perl -w -I. -I..
use strict;
use readmanifest;
use NixManifest;
use readcache;
use File::Basename;
# Read the manifests.
my %narFiles;
my %localPaths;
my %patches;
foreach my $manifest (@ARGV) {
print STDERR "loading $manifest\n";
if (readManifest($manifest, \%narFiles, \%localPaths, \%patches, 1) < 3) {
if (readManifest($manifest, \%narFiles, \%patches, 1) < 3) {
# die "manifest `$manifest' is too old (i.e., for Nix <= 0.7)\n";
}
}
@@ -50,6 +50,9 @@ foreach my $patch (keys %patches) {
foreach my $archive (keys %readcache::archives) {
next if $archive eq "." || $archive eq "..";
if (!defined $usedFiles{$archive}) {
print $readcache::archives{$archive}, "\n";
my $file = $readcache::archives{$archive};
print "$file\n";
my $hashFile = dirname($file) . "/.hash." . basename($file);
print "$hashFile\n" if -e $hashFile;
}
}

View File

@@ -9,13 +9,13 @@ sub readDir {
opendir(DIR, "$dir") or die "cannot open `$dir': $!";
my @as = readdir DIR;
foreach my $archive (@as) {
next unless $archive =~ /^sha256_/ || $archive =~ /\.nar-bsdiff$/ || $archive =~ /\.nar\.bz2$/;
$archives{$archive} = "$dir/$archive";
}
closedir DIR;
}
readDir "/data/webserver/dist/nix-cache";
readDir "/data/webserver/dist/test-cache";
readDir "/data/webserver/dist/patches";
readDir "/data/releases/nars";
readDir "/data/releases/patches";
print STDERR scalar (keys %archives), "\n";

11
scripts/nix-build.in Normal file → Executable file
View File

@@ -1,8 +1,7 @@
#! @perl@ -w -I@libexecdir@/nix
use strict;
my $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
use Nix::Config;
my $addDrvLink = 0;
@@ -76,10 +75,10 @@ EOF
$outLink = $ARGV[$n];
}
elsif ($arg eq "--attr" or $arg eq "-A") {
elsif ($arg eq "--attr" or $arg eq "-A" or $arg eq "-I") {
$n++;
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
push @instArgs, ("--attr", $ARGV[$n]);
push @instArgs, ($arg, $ARGV[$n]);
}
elsif ($arg eq "--arg" || $arg eq "--argstr") {
@@ -156,7 +155,7 @@ foreach my $expr (@exprs) {
# Instantiate.
my @drvPaths;
# !!! would prefer the perl 5.8.0 pipe open feature here.
my $pid = open(DRVPATHS, "-|") || exec "$binDir/nix-instantiate", "--add-root", $drvLink, "--indirect", @instArgs, $expr;
my $pid = open(DRVPATHS, "-|") || exec "$Nix::Config::binDir/nix-instantiate", "--add-root", $drvLink, "--indirect", @instArgs, $expr;
while (<DRVPATHS>) {chomp; push @drvPaths, $_;}
if (!close DRVPATHS) {
die "nix-instantiate killed by signal " . ($? & 127) . "\n" if ($? & 127);
@@ -170,7 +169,7 @@ foreach my $expr (@exprs) {
# Build.
my @outPaths;
$pid = open(OUTPATHS, "-|") || exec "$binDir/nix-store", "--add-root", $outLink, "--indirect", "-r",
$pid = open(OUTPATHS, "-|") || exec "$Nix::Config::binDir/nix-store", "--add-root", $outLink, "--indirect", "-r",
@buildArgs, @drvPaths;
while (<OUTPATHS>) {chomp; push @outPaths, $_;}
if (!close OUTPATHS) {

22
scripts/nix-channel.in Normal file → Executable file
View File

@@ -1,15 +1,13 @@
#! @perl@ -w
use strict;
use Nix::Config;
my $rootsDir = "@localstatedir@/nix/gcroots";
my $stateDir = $ENV{"NIX_STATE_DIR"};
$stateDir = "@localstatedir@/nix" unless defined $stateDir;
my $manifestDir = $Nix::Config::manifestDir;
# Turn on caching in nix-prefetch-url.
my $channelCache = "$stateDir/channel-cache";
my $channelCache = "$Nix::Config::stateDir/channel-cache";
mkdir $channelCache, 0755 unless -e $channelCache;
$ENV{'NIX_DOWNLOAD_CACHE'} = $channelCache if -W $channelCache;
@@ -79,19 +77,19 @@ sub update {
readChannels;
# Create the manifests directory if it doesn't exist.
mkdir "$stateDir/manifests", 0755 unless -e "$stateDir/manifests";
mkdir $manifestDir, 0755 unless -e $manifestDir;
# Do we have write permission to the manifests directory? If not,
# then just skip pulling the manifest and just download the Nix
# expressions. If the user is a non-privileged user in a
# multi-user Nix installation, he at least gets installation from
# source.
if (-W "$stateDir/manifests") {
if (-W $manifestDir) {
# Pull cache manifests.
foreach my $url (@channels) {
#print "pulling cache manifest from `$url'\n";
system("@bindir@/nix-pull", "--skip-wrong-store", "$url/MANIFEST") == 0
system("$Nix::Config::binDir/nix-pull", "--skip-wrong-store", "$url/MANIFEST") == 0
or die "cannot pull cache manifest from `$url'";
}
@@ -110,7 +108,7 @@ sub update {
print "downloading Nix expressions from `$fullURL'...\n";
$ENV{"PRINT_PATH"} = 1;
$ENV{"QUIET"} = 1;
my ($hash, $path) = `@bindir@/nix-prefetch-url '$fullURL'`;
my ($hash, $path) = `$Nix::Config::binDir/nix-prefetch-url '$fullURL'`;
die "cannot fetch `$fullURL'" if $? != 0;
chomp $path;
$inputs .= '"' . $channelName . '"' . " " . $path . " ";
@@ -121,13 +119,13 @@ sub update {
my $userName = getpwuid($<);
die "who ARE you? go away" unless defined $userName;
my $rootFile = "$rootsDir/per-user/$userName/channels";
my $rootFile = "$Nix::Config::stateDir/gcroots/per-user/$userName/channels";
# Build the Nix expression.
print "unpacking channel Nix expressions...\n";
my $outPath = `\\
@bindir@/nix-build --out-link '$rootFile' --drv-link '$rootFile'.tmp \\
@datadir@/nix/corepkgs/channels/unpack.nix \\
$Nix::Config::binDir/nix-build --out-link '$rootFile' --drv-link '$rootFile'.tmp \\
'<nix/unpack-channel.nix>' \\
--argstr system @system@ --arg inputs '$inputs'`
or die "cannot unpack the channels";
chomp $outPath;

7
scripts/nix-collect-garbage.in Normal file → Executable file
View File

@@ -1,11 +1,10 @@
#! @perl@ -w
use strict;
use Nix::Config;
my $profilesDir = "@localstatedir@/nix/profiles";
my $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
# Process the command line arguments.
my @args = ();
@@ -36,7 +35,7 @@ sub removeOldGenerations {
$name = $dir . "/" . $name;
if (-l $name && (readlink($name) =~ /link/)) {
print STDERR "removing old generations of profile $name\n";
system("$binDir/nix-env", "-p", $name, "--delete-generations", "old");
system("$Nix::Config::binDir/nix-env", "-p", $name, "--delete-generations", "old");
}
elsif (! -l $name && -d $name) {
removeOldGenerations $name;
@@ -50,4 +49,4 @@ removeOldGenerations $profilesDir if $removeOld;
# Run the actual garbage collector.
exec "$binDir/nix-store", "--gc", @args;
exec "$Nix::Config::binDir/nix-store", "--gc", @args;

105
scripts/nix-copy-closure.in Normal file → Executable file
View File

@@ -1,13 +1,14 @@
#! @perl@ -w -I@libexecdir@/nix
#! @perl@ -w @perlFlags@
use SSH;
my $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
use Nix::SSH;
use Nix::Config;
use Nix::Store;
use Nix::CopyClosure;
if (scalar @ARGV < 1) {
print STDERR <<EOF
Usage: nix-copy-closure [--from | --to] HOSTNAME [--sign] [--gzip] PATHS...
Usage: nix-copy-closure [--from | --to] HOSTNAME [--sign] [--gzip] [--bzip2] [--xz] PATHS...
EOF
;
exit 1;
@@ -24,6 +25,10 @@ my $decompressor = "";
my $toMode = 1;
my $includeOutputs = 0;
my $dryRun = 0;
# !!! Copied from nix-pack-closure, should put this in a module.
my @storePaths = ();
@@ -35,8 +40,16 @@ while (@ARGV) {
$sign = 1;
}
elsif ($arg eq "--gzip") {
$compressor = "| gzip";
$decompressor = "gunzip |";
$compressor = "gzip";
$decompressor = "gunzip";
}
elsif ($arg eq "--bzip2") {
$compressor = "bzip2";
$decompressor = "bunzip2";
}
elsif ($arg eq "--xz") {
$compressor = "xz";
$decompressor = "xz -d";
}
elsif ($arg eq "--from") {
$toMode = 0;
@@ -44,6 +57,12 @@ while (@ARGV) {
elsif ($arg eq "--to") {
$toMode = 1;
}
elsif ($arg eq "--include-outputs") {
$includeOutputs = 1;
}
elsif ($arg eq "--dry-run") {
$dryRun = 1;
}
elsif (!defined $sshHost) {
$sshHost = $arg;
}
@@ -57,81 +76,37 @@ openSSHConnection $sshHost or die "$0: unable to start SSH\n";
if ($toMode) { # Copy TO the remote machine.
my @allStorePaths;
# Get the closure of this path.
my $pid = open(READ, "set -f; $binDir/nix-store --query --requisites @storePaths|") or die;
while (<READ>) {
chomp;
die "bad: $_" unless /^\//;
push @allStorePaths, $_;
}
close READ or die "nix-store failed: $?";
# Ask the remote host which paths are invalid.
open(READ, "set -f; ssh $sshHost @sshOpts nix-store --check-validity --print-invalid @allStorePaths|");
my @missing = ();
while (<READ>) {
chomp;
push @missing, $_;
}
close READ or die;
# Export the store paths and import them on the remote machine.
if (scalar @missing > 0) {
print STDERR "copying these missing paths:\n";
print STDERR " $_\n" foreach @missing;
my $extraOpts = "";
$extraOpts .= "--sign" if $sign == 1;
system("set -f; nix-store --export $extraOpts @missing $compressor | ssh $sshHost @sshOpts '$decompressor nix-store --import'") == 0
or die "copying store paths to remote machine `$sshHost' failed: $?";
}
Nix::CopyClosure::copyTo($sshHost, [ @sshOpts ], [ @storePaths ], $compressor, $decompressor, $includeOutputs, $dryRun, $sign);
}
else { # Copy FROM the remote machine.
# Query the closure of the given store paths on the remote
# machine. Paths are assumed to be store paths; there is no
# resolution (following of symlinks).
my $extraOpts = $includeOutputs ? "--include-outputs" : "";
my $pid = open(READ,
"set -f; ssh @sshOpts $sshHost nix-store --query --requisites @storePaths|") or die;
"set -f; ssh @sshOpts $sshHost nix-store --query --requisites $extraOpts @storePaths|") or die;
my @allStorePaths;
while (<READ>) {
chomp;
die "bad: $_" unless /^\//;
push @allStorePaths, $_;
push @missing, $_ unless isValidPath($_);
}
close READ or die "nix-store on remote machine `$sshHost' failed: $?";
# What paths are already valid locally?
open(READ, "set -f; @bindir@/nix-store --check-validity --print-invalid @allStorePaths|");
my @missing = ();
while (<READ>) {
chomp;
push @missing, $_;
}
close READ or die;
# Export the store paths on the remote machine and import them on locally.
# Export the store paths on the remote machine and import them locally.
if (scalar @missing > 0) {
print STDERR "copying these missing paths:\n";
print STDERR " $_\n" foreach @missing;
my $extraOpts = "";
$extraOpts .= "--sign" if $sign == 1;
system("set -f; ssh $sshHost @sshOpts 'nix-store --export $extraOpts @missing $compressor' | $decompressor @bindir@/nix-store --import") == 0
or die "copying store paths from remote machine `$sshHost' failed: $?";
print STDERR "copying ", scalar @missing, " missing paths from $sshHost...\n";
#print STDERR " $_\n" foreach @missing;
$compressor = "| $compressor" if $compressor ne "";
$decompressor = "$decompressor |" if $decompressor ne "";
unless ($dryRun) {
my $extraOpts = $sign ? "--sign" : "";
system("set -f; ssh $sshHost @sshOpts 'nix-store --export $extraOpts @missing $compressor' | $decompressor $Nix::Config::binDir/nix-store --import") == 0
or die "copying store paths from remote machine `$sshHost' failed: $?";
}
}
}

10
scripts/nix-generate-patches.in Normal file → Executable file
View File

@@ -1,9 +1,9 @@
#! @perl@ -w -I@libexecdir@/nix
#! @perl@ -w @perlFlags@
use strict;
use File::Temp qw(tempdir);
use NixManifest;
use GeneratePatches;
use Nix::Manifest;
use Nix::GeneratePatches;
if (scalar @ARGV != 5) {
print STDERR <<EOF;
@@ -26,10 +26,10 @@ my $srcManifest = $ARGV[3];
my $dstManifest = $ARGV[4];
my (%srcNarFiles, %srcLocalPaths, %srcPatches);
readManifest $srcManifest, \%srcNarFiles, \%srcLocalPaths, \%srcPatches;
readManifest $srcManifest, \%srcNarFiles, \%srcPatches;
my (%dstNarFiles, %dstLocalPaths, %dstPatches);
readManifest $dstManifest, \%dstNarFiles, \%dstLocalPaths, \%dstPatches;
readManifest $dstManifest, \%dstNarFiles, \%dstPatches;
my $tmpDir = tempdir("nix-generate-patches.XXXXXX", CLEANUP => 1, TMPDIR => 1)
or die "cannot create a temporary directory";

14
scripts/nix-install-package.in Normal file → Executable file
View File

@@ -2,8 +2,7 @@
use strict;
use File::Temp qw(tempdir);
my $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
use Nix::Config;
sub usageError {
@@ -61,7 +60,7 @@ if ($interactive && !defined $ENV{"NIX_HAVE_TERMINAL"}) {
$ENV{"NIX_HAVE_TERMINAL"} = "1";
$ENV{"LD_LIBRARY_PATH"} = "";
foreach my $term ("xterm", "konsole", "gnome-terminal", "xterm") {
exec($term, "-e", "$binDir/nix-install-package", @ARGV);
exec($term, "-e", "$Nix::Config::binDir/nix-install-package", @ARGV);
}
die "cannot execute `xterm'";
}
@@ -124,17 +123,20 @@ if ($interactive) {
# Store the manifest in the temporary directory so that we don't
# pollute /nix/var/nix/manifests.
# pollute /nix/var/nix/manifests. This also requires that we don't
# use the Nix daemon (because otherwise download-using-manifests won't
# see our NIX_MANIFESTS_DIRS environment variable).
$ENV{NIX_MANIFESTS_DIR} = $tmpDir;
$ENV{NIX_REMOTE} = "";
print "\nPulling manifests...\n";
system("$binDir/nix-pull", $manifestURL) == 0
system("$Nix::Config::binDir/nix-pull", $manifestURL) == 0
or barf "nix-pull failed: $?";
print "\nInstalling package...\n";
system("$binDir/nix-env", "--install", $outPath, "--force-name", $drvName, @extraNixEnvArgs) == 0
system("$Nix::Config::binDir/nix-env", "--install", $outPath, "--force-name", $drvName, @extraNixEnvArgs) == 0
or barf "nix-env failed: $?";

226
scripts/nix-prefetch-url.in Normal file → Executable file
View File

@@ -1,162 +1,128 @@
#! @shell@ -e
#! @perl@ -w @perlFlags@
url=$1
expHash=$2
use strict;
use File::Basename;
use File::Temp qw(tempdir);
use File::stat;
use Nix::Store;
use Nix::Config;
# needed to make it work on NixOS
export PATH=$PATH:@coreutils@
my $url = shift;
my $expHash = shift;
my $hashType = $ENV{'NIX_HASH_ALGO'} || "sha256";
my $cacheDir = $ENV{'NIX_DOWNLOAD_CACHE'};
hashType=$NIX_HASH_ALGO
if test -z "$hashType"; then
hashType=sha256
fi
if (!defined $url || $url eq "") {
print STDERR <<EOF
Usage: nix-prefetch-url URL [EXPECTED-HASH]
EOF
;
exit 1;
}
hashFormat=
if test "$hashType" != "md5"; then
hashFormat=--base32
fi
sub writeFile {
my ($fn, $s) = @_;
open TMP, ">$fn" or die;
print TMP "$s" or die;
close TMP or die;
}
if test -z "$url"; then
echo "syntax: nix-prefetch-url URL [EXPECTED-HASH]" >&2
exit 1
fi
sub readFile {
local $/ = undef;
my ($fn) = @_;
open TMP, "<$fn" or die;
my $s = <TMP>;
close TMP or die;
return $s;
}
my $tmpDir = tempdir("nix-prefetch-url.XXXXXX", CLEANUP => 1, TMPDIR => 1)
or die "cannot create a temporary directory";
# Hack to support the mirror:// scheme from Nixpkgs.
if ($url =~ /^mirror:\/\//) {
system("$Nix::Config::binDir/nix-build '<nixpkgs>' -A resolveMirrorURLs --argstr url '$url' -o $tmpDir/urls > /dev/null") == 0
or die "$0: nix-build failed; maybe \$NIX_PATH is not set properly\n";
my @expanded = split ' ', readFile("$tmpDir/urls");
die "$0: cannot resolve $url" unless scalar @expanded > 0;
print STDERR "$url expands to $expanded[0]\n";
$url = $expanded[0];
}
# Handle escaped characters in the URI. `+', `=' and `?' are the only
# characters that are valid in Nix store path names but have a special
# meaning in URIs.
name=$(basename "$url" | @sed@ -e 's/%2b/+/g' -e 's/%3d/=/g' -e 's/%3f/\?/g')
if test -z "$name"; then echo "invalid url"; exit 1; fi
my $name = basename $url;
die "cannot figure out file name for $url\n" if $name eq "";
$name =~ s/%2b/+/g;
$name =~ s/%3d/=/g;
$name =~ s/%3f/?/g;
my $finalPath;
my $hash;
# If the hash was given, a file with that hash may already be in the
# store.
if test -n "$expHash"; then
finalPath=$(@bindir@/nix-store --print-fixed-path "$hashType" "$expHash" "$name")
if ! @bindir@/nix-store --check-validity "$finalPath" 2> /dev/null; then
finalPath=
fi
hash=$expHash
fi
mkTempDir() {
if test -n "$tmpPath"; then return; fi
local i=0
while true; do
if test -z "$TMPDIR"; then TMPDIR=/tmp; fi
tmpPath=$TMPDIR/nix-prefetch-url-$$-$i
if mkdir "$tmpPath"; then break; fi
# !!! to bad we can't check for ENOENT in mkdir, so this check
# is slightly racy (it bombs out if somebody just removed
# $tmpPath...).
if ! test -e "$tmpPath"; then exit 1; fi
i=$((i + 1))
done
trap removeTempDir EXIT SIGINT SIGQUIT
if (defined $expHash) {
$finalPath = makeFixedOutputPath(0, $hashType, $expHash, $name);
if (isValidPath($finalPath)) { $hash = $expHash; } else { $finalPath = undef; }
}
removeTempDir() {
if test -n "$tmpPath"; then
rm -rf "$tmpPath" || true
fi
}
doDownload() {
@curl@ $cacheFlags --fail --location --max-redirs 20 --disable-epsv \
--cookie-jar $tmpPath/cookies "$url" -o $tmpFile
}
# Hack to support the mirror:// scheme from Nixpkgs.
if test "${url:0:9}" = "mirror://"; then
if test -z "$NIXPKGS_ALL"; then
echo "Resolving mirror:// URLs requires Nixpkgs. Please point \$NIXPKGS_ALL at a Nixpkgs tree." >&2
exit 1
fi
mkTempDir
nix-build "$NIXPKGS_ALL" -A resolveMirrorURLs --argstr url "$url" -o $tmpPath/urls > /dev/null
expanded=($(cat $tmpPath/urls))
if test "${#expanded[*]}" = 0; then
echo "$0: cannot resolve $url." >&2
exit 1
fi
echo "$url expands to ${expanded[*]} (using ${expanded[0]})" >&2
url="${expanded[0]}"
fi
# If we don't know the hash or a file with that hash doesn't exist,
# download the file and add it to the store.
if test -z "$finalPath"; then
mkTempDir
tmpFile=$tmpPath/$name
if (!defined $finalPath) {
my $tmpFile = "$tmpDir/$name";
# Optionally do timestamp-based caching of the download.
# Actually, the only thing that we cache in $NIX_DOWNLOAD_CACHE is
# the hash and the timestamp of the file at $url. The caching of
# the file *contents* is done in Nix store, where it can be
# garbage-collected independently.
if test -n "$NIX_DOWNLOAD_CACHE"; then
echo -n "$url" > $tmpPath/url
urlHash=$(@bindir@/nix-hash --type sha256 --base32 --flat $tmpPath/url)
echo "$url" > "$NIX_DOWNLOAD_CACHE/$urlHash.url"
cachedHashFN="$NIX_DOWNLOAD_CACHE/$urlHash.$hashType"
cachedTimestampFN="$NIX_DOWNLOAD_CACHE/$urlHash.stamp"
cacheFlags="--remote-time"
if test -e "$cachedTimestampFN" -a -e "$cachedHashFN"; then
# Only download the file if it is newer than the cached version.
cacheFlags="$cacheFlags --time-cond $cachedTimestampFN"
fi
fi
my ($cachedTimestampFN, $cachedHashFN, @cacheFlags);
if (defined $cacheDir) {
my $urlHash = hashString("sha256", 1, $url);
writeFile "$cacheDir/$urlHash.url", $url;
$cachedHashFN = "$cacheDir/$urlHash.$hashType";
$cachedTimestampFN = "$cacheDir/$urlHash.stamp";
@cacheFlags = ("--time-cond", $cachedTimestampFN) if -f $cachedHashFN && -f $cachedTimestampFN;
}
# Perform the download.
doDownload
my @curlFlags = ("curl", $url, "-o", $tmpFile, "--fail", "--location", "--max-redirs", "20", "--disable-epsv", "--cookie-jar", "$tmpDir/cookies", "--remote-time", (split " ", ($ENV{NIX_CURL_FLAGS} || "")));
(system $Nix::Config::curl @curlFlags, @cacheFlags) == 0 or die "$0: download of $url failed\n";
if test -n "$NIX_DOWNLOAD_CACHE" -a ! -e $tmpFile; then
if (defined $cacheDir && ! -e $tmpFile) {
# Curl didn't create $tmpFile, so apparently there's no newer
# file on the server.
hash=$(cat $cachedHashFN)
finalPath=$(@bindir@/nix-store --print-fixed-path "$hashType" "$hash" "$name")
if ! @bindir@/nix-store --check-validity "$finalPath" 2> /dev/null; then
echo "cached contents of \`$url' disappeared, redownloading..." >&2
finalPath=
cacheFlags="--remote-time"
doDownload
fi
fi
$hash = readFile $cachedHashFN or die;
$finalPath = makeFixedOutputPath(0, $hashType, $hash, $name);
unless (isValidPath $finalPath) {
print STDERR "cached contents of $url disappeared, redownloading...\n";
$finalPath = undef;
(system $Nix::Config::curl @curlFlags) == 0 or die "$0: download of $url failed\n";
}
}
if test -z "$finalPath"; then
# Compute the hash.
hash=$(@bindir@/nix-hash --type "$hashType" $hashFormat --flat $tmpFile)
if ! test -n "$QUIET"; then echo "hash is $hash" >&2; fi
if test -n "$NIX_DOWNLOAD_CACHE"; then
echo $hash > $cachedHashFN
touch -r $tmpFile $cachedTimestampFN
fi
# Add the downloaded file to the Nix store.
finalPath=$(@bindir@/nix-store --add-fixed "$hashType" $tmpFile)
if test -n "$expHash" -a "$expHash" != "$hash"; then
echo "hash mismatch for URL \`$url'" >&2
exit 1
fi
if (!defined $finalPath) {
fi
fi
# Compute the hash.
$hash = hashFile($hashType, $hashType ne "md5", $tmpFile);
if (defined $cacheDir) {
writeFile $cachedHashFN, $hash;
my $st = stat($tmpFile) or die;
open STAMP, ">$cachedTimestampFN" or die; close STAMP;
utime($st->atime, $st->mtime, $cachedTimestampFN) or die;
}
# Add the downloaded file to the Nix store.
$finalPath = addToStore($tmpFile, 0, $hashType);
}
if ! test -n "$QUIET"; then echo "path is $finalPath" >&2; fi
die "$0: hash mismatch for $url\n" if defined $expHash && $expHash ne $hash;
}
echo $hash
if test -n "$PRINT_PATH"; then
echo $finalPath
fi
print STDERR "path is $finalPath\n" unless $ENV{'QUIET'};
print "$hash\n";
print "$finalPath\n" if $ENV{'PRINT_PATH'};

63
scripts/nix-pull.in Normal file → Executable file
View File

@@ -1,17 +1,14 @@
#! @perl@ -w -I@libexecdir@/nix
#! @perl@ -w @perlFlags@
use strict;
use File::Temp qw(tempdir);
use NixManifest;
use Nix::Config;
use Nix::Manifest;
my $tmpDir = tempdir("nix-pull.XXXXXX", CLEANUP => 1, TMPDIR => 1)
or die "cannot create a temporary directory";
my $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
my $libexecDir = ($ENV{"NIX_LIBEXEC_DIR"} or "@libexecdir@");
my $storeDir = ($ENV{"NIX_STORE_DIR"} or "@storedir@");
my $stateDir = ($ENV{"NIX_STATE_DIR"} or "@localstatedir@/nix");
my $manifestDir = ($ENV{"NIX_MANIFESTS_DIR"} or "$stateDir/manifests");
my $manifestDir = $Nix::Config::manifestDir;
# Prevent access problems in shared-stored installations.
@@ -24,18 +21,21 @@ if (! -e $manifestDir) {
}
# Process the URLs specified on the command line.
my %narFiles;
my %localPaths;
my %patches;
# Make sure that the manifests directory is scanned for GC roots.
my $gcRootsDir = "$Nix::Config::stateDir/gcroots";
my $manifestDirLink = "$gcRootsDir/manifests";
if (! -l $manifestDirLink) {
symlink($manifestDir, $manifestDirLink) or die "cannot create symlink `$manifestDirLink'";
}
my $skipWrongStore = 0;
# Process the URLs specified on the command line.
sub downloadFile {
my $url = shift;
$ENV{"PRINT_PATH"} = 1;
$ENV{"QUIET"} = 1;
my ($dummy, $path) = `$binDir/nix-prefetch-url '$url'`;
my ($dummy, $path) = `$Nix::Config::binDir/nix-prefetch-url '$url'`;
die "cannot fetch `$url'" if $? != 0;
die "nix-prefetch-url did not return a path" unless defined $path;
chomp $path;
@@ -50,46 +50,23 @@ sub processURL {
my $manifest;
# First see if a bzipped manifest is available.
if (system("@curl@ --fail --silent --head '$url'.bz2 > /dev/null") == 0) {
if (system("$Nix::Config::curl --fail --silent --head '$url'.bz2 > /dev/null") == 0) {
print "fetching list of Nix archives at `$url.bz2'...\n";
my $bzipped = downloadFile "$url.bz2";
$manifest = "$tmpDir/MANIFEST";
system("@bunzip2@ < $bzipped > $manifest") == 0
or die "cannot decompress manifest";
$manifest = (`$binDir/nix-store --add $manifest`
or die "cannot copy $manifest to the store");
chomp $manifest;
$manifest = downloadFile "$url.bz2";
}
# Otherwise, just get the uncompressed manifest.
else {
print "obtaining list of Nix archives at `$url'...\n";
print "fetching list of Nix archives at `$url'...\n";
$manifest = downloadFile $url;
}
my $version = readManifest($manifest, \%narFiles, \%localPaths, \%patches);
die "`$url' is not a manifest or it is too old (i.e., for Nix <= 0.7)\n" if $version < 3;
die "manifest `$url' is too new\n" if $version >= 5;
if ($skipWrongStore) {
foreach my $path (keys %narFiles) {
if (substr($path, 0, length($storeDir) + 1) ne "$storeDir/") {
print STDERR "warning: manifest `$url' assumes a Nix store at a different location than $storeDir, skipping...\n";
exit 0;
}
}
}
my $baseName = "unnamed";
if ($url =~ /\/([^\/]+)\/[^\/]+$/) { # get the forelast component
$baseName = $1;
}
my $hash = `$binDir/nix-hash --flat '$manifest'`
my $hash = `$Nix::Config::binDir/nix-hash --flat '$manifest'`
or die "cannot hash `$manifest'";
chomp $hash;
@@ -122,12 +99,12 @@ sub processURL {
while (@ARGV) {
my $url = shift @ARGV;
if ($url eq "--skip-wrong-store") {
$skipWrongStore = 1;
# No-op, no longer supported.
} else {
processURL $url;
}
}
my $size = scalar (keys %narFiles) + scalar (keys %localPaths);
print "$size store paths in manifest\n";
# Update the cache.
updateManifestDB();

43
scripts/nix-push.in Normal file → Executable file
View File

@@ -1,8 +1,10 @@
#! @perl@ -w -I@libexecdir@/nix
#! @perl@ -w @perlFlags@
use strict;
use File::Temp qw(tempdir);
use NixManifest;
use File::stat;
use Nix::Config;
use Nix::Manifest;
my $hashAlgo = "sha256";
@@ -12,15 +14,10 @@ my $tmpDir = tempdir("nix-push.XXXXXX", CLEANUP => 1, TMPDIR => 1)
my $nixExpr = "$tmpDir/create-nars.nix";
my $manifest = "$tmpDir/MANIFEST";
my $curl = "@curl@ --fail --silent";
my $curl = "$Nix::Config::curl --fail --silent";
my $extraCurlFlags = ${ENV{'CURL_FLAGS'}};
$curl = "$curl $extraCurlFlags" if defined $extraCurlFlags;
my $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
my $dataDir = $ENV{"NIX_DATA_DIR"};
$dataDir = "@datadir@" unless defined $dataDir;
# Parse the command line.
my $localCopy;
@@ -80,7 +77,7 @@ foreach my $path (@ARGV) {
# Get all paths referenced by the normalisation of the given
# Nix expression.
my $pid = open(READ,
"$binDir/nix-store --query --requisites --force-realise " .
"$Nix::Config::binDir/nix-store --query --requisites --force-realise " .
"--include-outputs '$path'|") or die;
while (<READ>) {
@@ -105,8 +102,8 @@ foreach my $storePath (@storePaths) {
# Construct a Nix expression that creates a Nix archive.
my $nixexpr =
"((import $dataDir/nix/corepkgs/nar/nar.nix) " .
"{storePath = builtins.storePath \"$storePath\"; system = \"@system@\"; hashAlgo = \"$hashAlgo\";}) ";
"(import <nix/nar.nix> " .
"{ storePath = builtins.storePath \"$storePath\"; system = \"@system@\"; hashAlgo = \"$hashAlgo\"; }) ";
print NIX $nixexpr;
}
@@ -118,7 +115,7 @@ close NIX;
# Instantiate store derivations from the Nix expression.
my @storeExprs;
print STDERR "instantiating store derivations...\n";
my $pid = open(READ, "$binDir/nix-instantiate $nixExpr|")
my $pid = open(READ, "$Nix::Config::binDir/nix-instantiate $nixExpr|")
or die "cannot run nix-instantiate";
while (<READ>) {
chomp;
@@ -140,7 +137,7 @@ while (scalar @tmp > 0) {
my @tmp2 = @tmp[0..$n - 1];
@tmp = @tmp[$n..scalar @tmp - 1];
my $pid = open(READ, "$binDir/nix-store --realise @tmp2|")
my $pid = open(READ, "$Nix::Config::binDir/nix-store --realise @tmp2|")
or die "cannot run nix-store";
while (<READ>) {
chomp;
@@ -178,22 +175,32 @@ for (my $n = 0; $n < scalar @storePaths; $n++) {
(-f $narFile) or die "narfile for $storePath not found";
push @narArchives, $narFile;
my $narbz2Size = (stat $narFile)[7];
my $narbz2Size = stat($narFile)->size;
my $references = `$binDir/nix-store --query --references '$storePath'`;
my $references = `$Nix::Config::binDir/nix-store --query --references '$storePath'`;
die "cannot query references for `$storePath'" if $? != 0;
$references = join(" ", split(" ", $references));
my $deriver = `$binDir/nix-store --query --deriver '$storePath'`;
my $deriver = `$Nix::Config::binDir/nix-store --query --deriver '$storePath'`;
die "cannot query deriver for `$storePath'" if $? != 0;
chomp $deriver;
$deriver = "" if $deriver eq "unknown-deriver";
my $narHash = `$binDir/nix-store --query --hash '$storePath'`;
my $narHash = `$Nix::Config::binDir/nix-store --query --hash '$storePath'`;
die "cannot query hash for `$storePath'" if $? != 0;
chomp $narHash;
my $narSize = `$binDir/nix-store --query --size '$storePath'`;
# In some exceptional cases (such as VM tests that use the Nix
# store of the host), the database doesn't contain the hash. So
# compute it.
if ($narHash =~ /^sha256:0*$/) {
$narHash = `$Nix::Config::binDir/nix-hash --type sha256 --base32 '$storePath'`;
die "cannot hash `$storePath'" if $? != 0;
chomp $narHash;
$narHash = "sha256:$narHash";
}
my $narSize = `$Nix::Config::binDir/nix-store --query --size '$storePath'`;
die "cannot query size for `$storePath'" if $? != 0;
chomp $narSize;

0
scripts/nix-reduce-build.in Normal file → Executable file
View File

View File

@@ -6,10 +6,9 @@ use readmanifest;
for my $p (@ARGV) {
my %narFiles;
my %localPaths;
my %patches;
readManifest $p, \%narFiles, \%localPaths, \%patches;
readManifest $p, \%narFiles, \%patches;
%patches = ();

View File

@@ -1,53 +0,0 @@
#! /usr/bin/perl -w -I.
use strict;
use readmanifest;
die unless scalar @ARGV == 2;
my $cache = $ARGV[0];
my $manifest = $ARGV[1];
my %narFiles;
my %localPaths;
my %patches;
readManifest $manifest, \%narFiles, \%localPaths, \%patches;
foreach my $storePath (keys %narFiles) {
my $narFileList = $narFiles{$storePath};
foreach my $narFile (@{$narFileList}) {
if (!defined $narFile->{size} or
!defined $narFile->{narHash})
{
$narFile->{url} =~ /\/([^\/]+)$/;
die unless defined $1;
my $fn = "$cache/$1";
my @info = stat $fn or die;
$narFile->{size} = $info[7];
my $narHash;
my $hashFile = "$fn.NARHASH";
if (-e $hashFile) {
open HASH, "<$hashFile" or die;
$narHash = <HASH>;
close HASH;
} else {
print "$fn\n";
$narHash = `bunzip2 < '$fn' | nix-hash --flat /dev/stdin` or die;
open HASH, ">$hashFile" or die;
print HASH $narHash;
close HASH;
}
chomp $narHash;
$narFile->{narHash} = $narHash;
}
}
}
if (! -e "$manifest.backup") {
system "mv --reply=no '$manifest' '$manifest.backup'";
}
writeManifest $manifest, \%narFiles, \%patches;

View File

@@ -6,12 +6,12 @@ libexpr_la_SOURCES = \
names.cc
pkginclude_HEADERS = \
nixexpr.hh eval.hh parser.hh lexer-tab.hh parser-tab.hh \
nixexpr.hh eval.hh lexer-tab.hh parser-tab.hh \
get-drvs.hh attr-path.hh value-to-xml.hh common-opts.hh \
names.hh symbol-table.hh
libexpr_la_LIBADD = ../libutil/libutil.la ../libstore/libstore.la \
../boost/format/libformat.la @boehmgc_lib@
../boost/format/libformat.la @BDW_GC_LIBS@
BUILT_SOURCES = \
parser-tab.hh lexer-tab.hh parser-tab.cc lexer-tab.cc

View File

@@ -1,7 +1,6 @@
#include "common-opts.hh"
#include "../libmain/shared.hh"
#include "util.hh"
#include "parser.hh"
namespace nix {
@@ -25,7 +24,7 @@ bool parseOptionArg(const string & arg, Strings::iterator & i,
autoArgs.push_back(Attr(state.symbols.create(name), v));
if (arg == "--arg")
state.mkThunk_(*v, parseExprFromString(state, value, absPath(".")));
state.mkThunk_(*v, state.parseExprFromString(value, absPath(".")));
else
mkString(*v, value);
@@ -34,5 +33,26 @@ bool parseOptionArg(const string & arg, Strings::iterator & i,
return true;
}
bool parseSearchPathArg(const string & arg, Strings::iterator & i,
const Strings::iterator & argsEnd, EvalState & state)
{
if (arg != "-I") return false;
if (i == argsEnd) throw UsageError(format("`%1%' requires an argument") % arg);;
state.addToSearchPath(*i++);
return true;
}
Path lookupFileArg(EvalState & state, string s)
{
if (s.size() > 2 && s.at(0) == '<' && s.at(s.size() - 1) == '>') {
Path p = state.findFile(s.substr(1, s.size() - 2));
if (p == "") throw Error(format("file `%1%' was not found in the Nix search path (add it using $NIX_PATH or -I)") % p);
return p;
} else
return absPath(s);
}
}

View File

@@ -11,6 +11,11 @@ bool parseOptionArg(const string & arg, Strings::iterator & i,
const Strings::iterator & argsEnd, EvalState & state,
Bindings & autoArgs);
bool parseSearchPathArg(const string & arg, Strings::iterator & i,
const Strings::iterator & argsEnd, EvalState & state);
Path lookupFileArg(EvalState & state, string s);
}

View File

@@ -1,5 +1,4 @@
#include "eval.hh"
#include "parser.hh"
#include "hash.hh"
#include "util.hh"
#include "store-api.hh"
@@ -7,6 +6,7 @@
#include "globals.hh"
#include <cstring>
#include <unistd.h>
#if HAVE_BOEHMGC
@@ -148,9 +148,46 @@ EvalState::EvalState()
nrAttrsets = nrOpUpdates = nrOpUpdateValuesCopied = 0;
deepestStack = (char *) -1;
createBaseEnv();
allowUnsafeEquality = getEnv("NIX_NO_UNSAFE_EQ", "") == "";
#if HAVE_BOEHMGC
static bool gcInitialised = true;
if (gcInitialised) {
/* Set the initial heap size to something fairly big (25% of
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
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
allocated. This might be a problem on systems that don't
overcommit. */
if (!getenv("GC_INITIAL_HEAP_SIZE")) {
size_t maxSize = 384 * 1024 * 1024;
size_t size = 32 * 1024 * 1024;
#if HAVE_SYSCONF && defined(_SC_PAGESIZE) && defined(_SC_PHYS_PAGES)
long pageSize = sysconf(_SC_PAGESIZE);
long pages = sysconf(_SC_PHYS_PAGES);
if (pageSize != -1)
size = (pageSize * pages) / 4; // 25% of RAM
if (size > maxSize) size = maxSize;
#endif
debug(format("setting initial heap size to %1% bytes") % size);
GC_expand_hp(size);
}
gcInitialised = true;
}
#endif
/* Initialise the Nix expression search path. */
searchPathInsertionPoint = searchPath.end();
Strings paths = tokenizeString(getEnv("NIX_PATH", ""), ":");
foreach (Strings::iterator, i, paths) addToSearchPath(*i);
addToSearchPath("nix=" + nixDataDir + "/nix/corepkgs");
searchPathInsertionPoint = searchPath.begin();
createBaseEnv();
}
@@ -394,21 +431,19 @@ Value * EvalState::maybeThunk(Env & env, Expr * expr)
void EvalState::evalFile(const Path & path, Value & v)
{
startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path);
Expr * e = parseTrees[path];
if (!e) {
e = parseExprFromFile(*this, path);
parseTrees[path] = e;
}
try {
eval(e, v);
} catch (Error & e) {
addErrorPrefix(e, "while evaluating the file `%1%':\n", path);
throw;
}
FileEvalCache::iterator i = fileEvalCache.find(path);
if (i == fileEvalCache.end()) {
startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path);
Expr * e = parseExprFromFile(path);
try {
eval(e, v);
} catch (Error & e) {
addErrorPrefix(e, "while evaluating the file `%1%':\n", path);
throw;
}
fileEvalCache[path] = v;
} else
v = i->second;
}
@@ -601,33 +636,71 @@ void ExprVar::eval(EvalState & state, Env & env, Value & v)
unsigned long nrLookups = 0;
unsigned long nrLookupSize = 0;
void ExprSelect::eval(EvalState & state, Env & env, Value & v)
{
nrLookups++;
Value v2;
state.evalAttrs(env, e, v2);
nrLookupSize += v2.attrs->size();
Bindings::iterator i = v2.attrs->find(name);
if (i == v2.attrs->end())
throwEvalError("attribute `%1%' missing", name);
try {
state.forceValue(*i->value);
Value vTmp;
Pos * pos = 0;
Value * vAttrs = &vTmp;
state.eval(env, e, vTmp);
try {
foreach (AttrPath::const_iterator, i, attrPath) {
nrLookups++;
Bindings::iterator j;
if (def) {
state.forceValue(*vAttrs);
if (vAttrs->type != tAttrs ||
(j = vAttrs->attrs->find(*i)) == vAttrs->attrs->end())
{
state.eval(env, def, v);
return;
}
} else {
state.forceAttrs(*vAttrs);
if ((j = vAttrs->attrs->find(*i)) == vAttrs->attrs->end())
throwEvalError("attribute `%1%' missing", showAttrPath(attrPath));
}
vAttrs = j->value;
pos = j->pos;
}
state.forceValue(*vAttrs);
} catch (Error & e) {
addErrorPrefix(e, "while evaluating the attribute `%1%' at %2%:\n",
name, *i->pos);
if (pos)
addErrorPrefix(e, "while evaluating the attribute `%1%' at %2%:\n",
showAttrPath(attrPath), *pos);
throw;
}
v = *i->value;
v = *vAttrs;
}
void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v)
{
Value vAttrs;
state.evalAttrs(env, e, vAttrs);
mkBool(v, vAttrs.attrs->find(name) != vAttrs.attrs->end());
Value vTmp;
Value * vAttrs = &vTmp;
state.eval(env, e, vTmp);
foreach (AttrPath::const_iterator, i, attrPath) {
state.forceValue(*vAttrs);
Bindings::iterator j;
if (vAttrs->type != tAttrs ||
(j = vAttrs->attrs->find(*i)) == vAttrs->attrs->end())
{
mkBool(v, false);
return;
} else {
vAttrs = j->value;
}
}
mkBool(v, true);
}
@@ -1035,7 +1108,10 @@ bool EvalState::isDerivation(Value & v)
{
if (v.type != tAttrs) return false;
Bindings::iterator i = v.attrs->find(sType);
return i != v.attrs->end() && forceStringNoCtx(*i->value) == "derivation";
if (i == v.attrs->end()) return false;
forceValue(*i->value);
if (i->value->type != tString) return false;
return forceStringNoCtx(*i->value) == "derivation";
}
@@ -1209,7 +1285,6 @@ void EvalState::printStats()
printMsg(v, format(" number of thunks: %1%") % nrThunks);
printMsg(v, format(" number of thunks avoided: %1%") % nrAvoided);
printMsg(v, format(" number of attr lookups: %1%") % nrLookups);
printMsg(v, format(" attr lookup size: %1%") % nrLookupSize);
}

View File

@@ -188,8 +188,6 @@ void mkPath(Value & v, const char * s);
void copyContext(const Value & v, PathSet & context);
typedef std::map<Path, Hash> DrvHashes;
/* Cache for calls to addToStore(); maps source paths to the store
paths. */
typedef std::map<Path, Path> SrcToStore;
@@ -203,8 +201,6 @@ std::ostream & operator << (std::ostream & str, const Value & v);
class EvalState
{
public:
DrvHashes drvHashes; /* normalised derivation hashes */
SymbolTable symbols;
const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName,
@@ -215,17 +211,42 @@ private:
bool allowUnsafeEquality;
/* 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;
#else
typedef std::map<Path, Value> FileEvalCache;
#endif
FileEvalCache fileEvalCache;
typedef list<std::pair<string, Path> > SearchPath;
SearchPath searchPath;
SearchPath::iterator searchPathInsertionPoint;
public:
EvalState();
~EvalState();
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 string. */
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);
/* Look up a file in the search path. */
Path findFile(const string & path);
/* Evaluate an expression to normal form, storing the result in
value `v'. */
void eval(Expr * e, Value & v);
@@ -300,6 +321,9 @@ private:
friend class ExprAttrs;
friend class ExprLet;
Expr * parse(const char * text,
const Path & path, const Path & basePath);
public:
/* Do a deep equality test between two values. That is, list

View File

@@ -81,6 +81,7 @@ static Expr * unescapeStr(SymbolTable & symbols, const char * s)
ID [a-zA-Z\_][a-zA-Z0-9\_\']*
INT [0-9]+
PATH [a-zA-Z0-9\.\_\-\+]*(\/[a-zA-Z0-9\.\_\-\+]+)+
SPATH \<[a-zA-Z0-9\.\_\-\+]+(\/[a-zA-Z0-9\.\_\-\+]+)*\>
URI [a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\']+
@@ -96,6 +97,7 @@ let { return LET; }
in { return IN; }
rec { return REC; }
inherit { return INHERIT; }
or { return OR_KW; }
\.\.\. { return ELLIPSIS; }
\=\= { return EQ; }
@@ -152,6 +154,7 @@ inherit { return INHERIT; }
<IND_STRING>. return yytext[0]; /* just in case: shouldn't be reached */
{PATH} { yylval->path = strdup(yytext); return PATH; }
{SPATH} { yylval->path = strdup(yytext); return SPATH; }
{URI} { yylval->uri = strdup(yytext); return URI; }
[ \t\r\n]+ /* eat up whitespace */

View File

@@ -43,12 +43,13 @@ void ExprVar::show(std::ostream & str)
void ExprSelect::show(std::ostream & str)
{
str << "(" << *e << ")." << name;
str << "(" << *e << ")." << showAttrPath(attrPath);
if (def) str << " or " << *def;
}
void ExprOpHasAttr::show(std::ostream & str)
{
str << "(" << *e << ") ? " << name;
str << "(" << *e << ") ? " << showAttrPath(attrPath);
}
void ExprAttrs::show(std::ostream & str)
@@ -140,6 +141,17 @@ std::ostream & operator << (std::ostream & str, const Pos & pos)
}
string showAttrPath(const AttrPath & attrPath)
{
string s;
foreach (AttrPath::const_iterator, i, attrPath) {
if (!s.empty()) s += '.';
s += *i;
}
return s;
}
Pos noPos;
@@ -200,6 +212,7 @@ void ExprVar::bindVars(const StaticEnv & env)
void ExprSelect::bindVars(const StaticEnv & env)
{
e->bindVars(env);
if (def) def->bindVars(env);
}
void ExprOpHasAttr::bindVars(const StaticEnv & env)

View File

@@ -40,6 +40,12 @@ struct EvalState;
struct StaticEnv;
/* An attribute path is a sequence of attribute names. */
typedef vector<Symbol> AttrPath;
string showAttrPath(const AttrPath & attrPath);
/* Abstract syntax of Nix expressions. */
struct Expr
@@ -115,17 +121,18 @@ struct ExprVar : Expr
struct ExprSelect : Expr
{
Expr * e;
Symbol name;
ExprSelect(Expr * e, const Symbol & name) : e(e), name(name) { };
Expr * e, * def;
AttrPath attrPath;
ExprSelect(Expr * e, const AttrPath & attrPath, Expr * def) : e(e), def(def), attrPath(attrPath) { };
ExprSelect(Expr * e, const Symbol & name) : e(e), def(0) { attrPath.push_back(name); };
COMMON_METHODS
};
struct ExprOpHasAttr : Expr
{
Expr * e;
Symbol name;
ExprOpHasAttr(Expr * e, const Symbol & name) : e(e), name(name) { };
AttrPath attrPath;
ExprOpHasAttr(Expr * e, const AttrPath & attrPath) : e(e), attrPath(attrPath) { };
COMMON_METHODS
};

View File

@@ -1,21 +0,0 @@
#ifndef __PARSER_H
#define __PARSER_H
#include "eval.hh"
namespace nix {
/* Parse a Nix expression from the specified file. If `path' refers
to a directory, then "/default.nix" is appended. */
Expr * parseExprFromFile(EvalState & state, Path path);
/* Parse a Nix expression from the specified string. */
Expr * parseExprFromString(EvalState & state, const string & s, const Path & basePath);
}
#endif /* !__PARSER_H */

View File

@@ -17,19 +17,22 @@
#include "util.hh"
#include "nixexpr.hh"
#include "eval.hh"
namespace nix {
struct ParseData
{
EvalState & state;
SymbolTable & symbols;
Expr * result;
Path basePath;
Path path;
string error;
Symbol sLetBody;
ParseData(SymbolTable & symbols)
: symbols(symbols)
ParseData(EvalState & state)
: state(state)
, symbols(state.symbols)
, sLetBody(symbols.create("<let-body>"))
{ };
};
@@ -61,18 +64,7 @@ using namespace nix;
namespace nix {
static string showAttrPath(const vector<Symbol> & attrPath)
{
string s;
foreach (vector<Symbol>::const_iterator, i, attrPath) {
if (!s.empty()) s += '.';
s += *i;
}
return s;
}
static void dupAttr(const vector<Symbol> & attrPath, const Pos & pos, const Pos & prevPos)
static void dupAttr(const AttrPath & attrPath, const Pos & pos, const Pos & prevPos)
{
throw ParseError(format("attribute `%1%' at %2% already defined at %3%")
% showAttrPath(attrPath) % pos % prevPos);
@@ -81,17 +73,17 @@ static void dupAttr(const vector<Symbol> & attrPath, const Pos & pos, const Pos
static void dupAttr(Symbol attr, const Pos & pos, const Pos & prevPos)
{
vector<Symbol> attrPath; attrPath.push_back(attr);
AttrPath attrPath; attrPath.push_back(attr);
throw ParseError(format("attribute `%1%' at %2% already defined at %3%")
% showAttrPath(attrPath) % pos % prevPos);
}
static void addAttr(ExprAttrs * attrs, const vector<Symbol> & attrPath,
static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
Expr * e, const Pos & pos)
{
unsigned int n = 0;
foreach (vector<Symbol>::const_iterator, i, attrPath) {
foreach (AttrPath::const_iterator, i, attrPath) {
n++;
ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(*i);
if (j != attrs->attrs.end()) {
@@ -238,6 +230,7 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
%}
%union {
// !!! We're probably leaking stuff here.
nix::Expr * e;
nix::ExprList * list;
nix::ExprAttrs * attrs;
@@ -247,7 +240,7 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
char * id; // !!! -> Symbol
char * path;
char * uri;
std::vector<nix::Symbol> * ids;
std::vector<nix::Symbol> * attrNames;
std::vector<nix::Expr *> * string_parts;
}
@@ -257,14 +250,15 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
%type <attrs> binds
%type <formals> formals
%type <formal> formal
%type <ids> ids attrpath
%type <attrNames> attrs attrpath
%type <string_parts> string_parts ind_string_parts
%type <id> attr
%token <id> ID ATTRPATH
%token <e> STR IND_STR
%token <n> INT
%token <path> PATH
%token <path> PATH SPATH
%token <uri> URI
%token IF THEN ELSE ASSERT WITH LET IN REC INHERIT EQ NEQ AND OR IMPL
%token IF THEN ELSE ASSERT WITH LET IN REC INHERIT EQ NEQ AND OR IMPL OR_KW
%token DOLLAR_CURLY /* == ${ */
%token IND_STRING_OPEN IND_STRING_CLOSE
%token ELLIPSIS
@@ -317,7 +311,7 @@ expr_op
| expr_op OR expr_op { $$ = new ExprOpOr($1, $3); }
| expr_op IMPL expr_op { $$ = new ExprOpImpl($1, $3); }
| expr_op UPDATE expr_op { $$ = new ExprOpUpdate($1, $3); }
| expr_op '?' ID { $$ = new ExprOpHasAttr($1, data->symbols.create($3)); }
| expr_op '?' attrpath { $$ = new ExprOpHasAttr($1, *$3); }
| expr_op '+' expr_op
{ vector<Expr *> * l = new vector<Expr *>;
l->push_back($1);
@@ -335,8 +329,14 @@ expr_app
;
expr_select
: expr_select '.' ID
{ $$ = new ExprSelect($1, data->symbols.create($3)); }
: expr_simple '.' attrpath
{ $$ = new ExprSelect($1, *$3, 0); }
| expr_simple '.' attrpath OR_KW expr_select
{ $$ = new ExprSelect($1, *$3, $5); }
| /* Backwards compatibility: because Nixpkgs has a rarely used
function named or, allow stuff like map or [...]. */
expr_simple OR_KW
{ $$ = new ExprApp($1, new ExprVar(data->symbols.create("or"))); }
| expr_simple { $$ = $1; }
;
@@ -353,6 +353,20 @@ expr_simple
$$ = stripIndentation(data->symbols, *$2);
}
| PATH { $$ = new ExprPath(absPath($1, data->basePath)); }
| SPATH {
string path($1 + 1, strlen($1) - 2);
Path path2 = data->state.findFile(path);
/* The file wasn't found in the search path. However, we can't
throw an error here, because the expression might never be
evaluated. So return an expression that lazily calls
abort. */
$$ = path2 == ""
? (Expr * ) new ExprApp(
new ExprVar(data->symbols.create("throw")),
new ExprString(data->symbols.create(
(format("file `%1%' was not found in the Nix search path (add it using $NIX_PATH or -I)") % path).str())))
: (Expr * ) new ExprPath(path2);
}
| URI { $$ = new ExprString(data->symbols.create($1)); }
| '(' expr ')' { $$ = $2; }
/* Let expressions `let {..., body = ...}' are just desugared
@@ -380,35 +394,42 @@ ind_string_parts
binds
: binds attrpath '=' expr ';' { $$ = $1; addAttr($$, *$2, $4, makeCurPos(@2, data)); }
| binds INHERIT ids ';'
| binds INHERIT attrs ';'
{ $$ = $1;
foreach (vector<Symbol>::iterator, i, *$3) {
foreach (AttrPath::iterator, i, *$3) {
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);
}
}
| binds INHERIT '(' expr ')' ids ';'
| binds INHERIT '(' expr ')' attrs ';'
{ $$ = $1;
/* !!! Should ensure sharing of the expression in $4. */
foreach (vector<Symbol>::iterator, i, *$6) {
if ($$->attrs.find(*i) != $$->attrs.end())
dupAttr(*i, makeCurPos(@6, data), $$->attrs[*i].pos);
$$->attrs[*i] = ExprAttrs::AttrDef(new ExprSelect($4, *i), makeCurPos(@6, data));
}}
}
}
| { $$ = new ExprAttrs; }
;
ids
: ids ID { $$ = $1; $1->push_back(data->symbols.create($2)); /* !!! dangerous */ }
attrs
: attrs attr { $$ = $1; $1->push_back(data->symbols.create($2)); /* !!! dangerous */ }
| { $$ = new vector<Symbol>; }
;
attrpath
: attrpath '.' ID { $$ = $1; $1->push_back(data->symbols.create($3)); }
| ID { $$ = new vector<Symbol>; $$->push_back(data->symbols.create($1)); }
: attrpath '.' attr { $$ = $1; $1->push_back(data->symbols.create($3)); }
| attr { $$ = new vector<Symbol>; $$->push_back(data->symbols.create($1)); }
;
attr
: ID { $$ = $1; }
| OR_KW { $$ = "or"; }
| '"' STR '"'
{ $$ = strdup(((string) ((ExprString *) $2)->s).c_str()); delete $2; }
;
expr_list
@@ -446,11 +467,11 @@ formal
namespace nix {
static Expr * parse(EvalState & state, const char * text,
Expr * EvalState::parse(const char * text,
const Path & path, const Path & basePath)
{
yyscan_t scanner;
ParseData data(state.symbols);
ParseData data(*this);
data.basePath = basePath;
data.path = path;
@@ -462,7 +483,7 @@ static Expr * parse(EvalState & state, const char * text,
if (res) throw ParseError(data.error);
try {
data.result->bindVars(state.staticBaseEnv);
data.result->bindVars(staticBaseEnv);
} catch (Error & e) {
throw ParseError(format("%1%, in `%2%'") % e.msg() % path);
}
@@ -471,7 +492,7 @@ static Expr * parse(EvalState & state, const char * text,
}
Expr * parseExprFromFile(EvalState & state, Path path)
Expr * EvalState::parseExprFromFile(Path path)
{
assert(path[0] == '/');
@@ -489,16 +510,61 @@ Expr * parseExprFromFile(EvalState & state, Path path)
if (S_ISDIR(st.st_mode))
path = canonPath(path + "/default.nix");
/* Read and parse the input file. */
return parse(state, readFile(path).c_str(), path, dirOf(path));
/* 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 e;
}
Expr * parseExprFromString(EvalState & state,
const string & s, const Path & basePath)
Expr * EvalState::parseExprFromString(const string & s, const Path & basePath)
{
return parse(state, s.c_str(), "(string)", basePath);
return parse(s.c_str(), "(string)", basePath);
}
void EvalState::addToSearchPath(const string & s)
{
size_t pos = s.find('=');
string prefix;
Path path;
if (pos == string::npos) {
path = s;
} else {
prefix = string(s, 0, pos);
path = string(s, pos + 1);
}
path = absPath(path);
if (pathExists(path)) {
debug(format("adding path `%1%' to the search path") % path);
searchPath.insert(searchPathInsertionPoint, std::pair<string, Path>(prefix, path));
}
}
Path EvalState::findFile(const string & path)
{
foreach (SearchPath::iterator, i, searchPath) {
Path res;
if (i->first.empty())
res = i->second + "/" + path;
else {
if (path.compare(0, i->first.size(), i->first) != 0 ||
(path.size() > i->first.size() && path[i->first.size()] != '/'))
continue;
res = i->second +
(path.size() == i->first.size() ? "" : "/" + string(path, i->first.size()));
}
if (pathExists(res)) return canonPath(res);
}
return "";
}
}

View File

@@ -5,7 +5,6 @@
#include "util.hh"
#include "archive.hh"
#include "value-to-xml.hh"
#include "parser.hh"
#include "names.hh"
#include <sys/types.h>
@@ -246,63 +245,6 @@ static void prim_trace(EvalState & state, Value * * args, Value & v)
*************************************************************/
static bool isFixedOutput(const Derivation & drv)
{
return drv.outputs.size() == 1 &&
drv.outputs.begin()->first == "out" &&
drv.outputs.begin()->second.hash != "";
}
/* Returns the hash of a derivation modulo fixed-output
subderivations. A fixed-output derivation is a derivation with one
output (`out') for which an expected hash and hash algorithm are
specified (using the `outputHash' and `outputHashAlgo'
attributes). We don't want changes to such derivations to
propagate upwards through the dependency graph, changing output
paths everywhere.
For instance, if we change the url in a call to the `fetchurl'
function, we do not want to rebuild everything depending on it
(after all, (the hash of) the file being downloaded is unchanged).
So the *output paths* should not change. On the other hand, the
*derivation paths* should change to reflect the new dependency
graph.
That's what this function does: it returns a hash which is just the
hash of the derivation ATerm, except that any input derivation
paths have been replaced by the result of a recursive call to this
function, and that for fixed-output derivations we return a hash of
its output path. */
static Hash hashDerivationModulo(EvalState & state, Derivation drv)
{
/* Return a fixed hash for fixed-output derivations. */
if (isFixedOutput(drv)) {
DerivationOutputs::const_iterator i = drv.outputs.begin();
return hashString(htSHA256, "fixed:out:"
+ i->second.hashAlgo + ":"
+ i->second.hash + ":"
+ i->second.path);
}
/* For other derivations, replace the inputs paths with recursive
calls to this function.*/
DerivationInputs inputs2;
foreach (DerivationInputs::const_iterator, i, drv.inputDrvs) {
Hash h = state.drvHashes[i->first];
if (h.type == htUnknown) {
Derivation drv2 = derivationFromPath(i->first);
h = hashDerivationModulo(state, drv2);
state.drvHashes[i->first] = h;
}
inputs2[printHash(h)] = i->second;
}
drv.inputDrvs = inputs2;
return hashString(htSHA256, unparseDerivation(drv));
}
/* Construct (as a unobservable side effect) a Nix derivation
expression that performs the derivation described by the argument
set. Returns the original set extended with the following
@@ -337,6 +279,9 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
string outputHash, outputHashAlgo;
bool outputHashRecursive = false;
StringSet outputs;
outputs.insert("out");
foreach (Bindings::iterator, i, *args[0]->attrs) {
string key = i->name;
startNest(nest, lvlVomit, format("processing attribute `%1%'") % key);
@@ -368,6 +313,24 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
else if (s == "flat") outputHashRecursive = false;
else throw EvalError(format("invalid value `%1%' for `outputHashMode' attribute") % s);
}
else if (key == "outputs") {
Strings tmp = tokenizeString(s);
outputs.clear();
foreach (Strings::iterator, j, tmp) {
if (outputs.find(*j) != outputs.end())
throw EvalError(format("duplicate derivation output `%1%'") % *j);
/* !!! Check whether *j is a valid attribute
name. */
/* Derivations cannot be named drv, because
then we'd have an attribute drvPath in
the resulting set. */
if (*j == "drv")
throw EvalError(format("invalid derivation output name `drv'") % *j);
outputs.insert(*j);
}
if (outputs.empty())
throw EvalError("derivation cannot have an empty set of outputs");
}
}
} catch (Error & e) {
@@ -393,27 +356,31 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
inputs to ensure that they are available when the builder
runs. */
if (path.at(0) == '=') {
path = string(path, 1);
PathSet refs; computeFSClosure(path, refs);
/* !!! This doesn't work if readOnlyMode is set. */
PathSet refs; computeFSClosure(*store, string(path, 1), refs);
foreach (PathSet::iterator, j, refs) {
drv.inputSrcs.insert(*j);
if (isDerivation(*j))
drv.inputDrvs[*j] = singleton<StringSet>("out");
drv.inputDrvs[*j] = store->queryDerivationOutputNames(*j);
}
}
/* See prim_unsafeDiscardOutputDependency. */
bool useDrvAsSrc = false;
if (path.at(0) == '~') {
path = string(path, 1);
useDrvAsSrc = true;
else if (path.at(0) == '~')
drv.inputSrcs.insert(string(path, 1));
/* Handle derivation outputs of the form !<name>!<path>. */
else if (path.at(0) == '!') {
size_t index = path.find("!", 1);
drv.inputDrvs[string(path, index + 1)].insert(string(path, 1, index - 1));
}
assert(isStorePath(path));
/* Handle derivation contexts returned by
builtins.storePath. */
else if (isDerivation(path))
drv.inputDrvs[path] = store->queryDerivationOutputNames(path);
debug(format("derivation uses `%1%'") % path);
if (!useDrvAsSrc && isDerivation(path))
drv.inputDrvs[path] = singleton<StringSet>("out");
/* Otherwise it's a source file. */
else
drv.inputSrcs.insert(path);
}
@@ -424,69 +391,69 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
if (drv.platform == "")
throw EvalError("required attribute `system' missing");
/* If an output hash was given, check it. */
Path outPath;
if (outputHash == "")
outputHashAlgo = "";
else {
HashType ht = parseHashType(outputHashAlgo);
if (ht == htUnknown)
throw EvalError(format("unknown hash algorithm `%1%'") % outputHashAlgo);
Hash h(ht);
if (outputHash.size() == h.hashSize * 2)
/* hexadecimal representation */
h = parseHash(ht, outputHash);
else if (outputHash.size() == hashLength32(h))
/* base-32 representation */
h = parseHash32(ht, outputHash);
else
throw Error(format("hash `%1%' has wrong length for hash type `%2%'")
% outputHash % outputHashAlgo);
string s = outputHash;
outputHash = printHash(h);
outPath = makeFixedOutputPath(outputHashRecursive, ht, h, drvName);
if (outputHashRecursive) outputHashAlgo = "r:" + outputHashAlgo;
}
/* Check whether the derivation name is valid. */
checkStoreName(drvName);
if (isDerivation(drvName))
throw EvalError(format("derivation names are not allowed to end in `%1%'")
% drvExtension);
/* Construct the "masked" derivation store expression, which is
the final one except that in the list of outputs, the output
paths are empty, and the corresponding environment variables
have an empty value. This ensures that changes in the set of
output names do get reflected in the hash. */
drv.env["out"] = "";
drv.outputs["out"] = DerivationOutput("", outputHashAlgo, outputHash);
if (outputHash != "") {
/* Handle fixed-output derivations. */
if (outputs.size() != 1 || *(outputs.begin()) != "out")
throw Error("multiple outputs are not supported in fixed-output derivations");
/* Use the masked derivation expression to compute the output
path. */
if (outPath == "")
outPath = makeStorePath("output:out", hashDerivationModulo(state, drv), drvName);
HashType ht = parseHashType(outputHashAlgo);
if (ht == htUnknown)
throw EvalError(format("unknown hash algorithm `%1%'") % outputHashAlgo);
Hash h = parseHash16or32(ht, outputHash);
outputHash = printHash(h);
if (outputHashRecursive) outputHashAlgo = "r:" + outputHashAlgo;
Path outPath = makeFixedOutputPath(outputHashRecursive, ht, h, drvName);
drv.env["out"] = outPath;
drv.outputs["out"] = DerivationOutput(outPath, outputHashAlgo, outputHash);
}
/* Construct the final derivation store expression. */
drv.env["out"] = outPath;
drv.outputs["out"] =
DerivationOutput(outPath, outputHashAlgo, outputHash);
else {
/* Construct the "masked" store derivation, which is the final
one except that in the list of outputs, the output paths
are empty, and the corresponding environment variables have
an empty value. This ensures that changes in the set of
output names do get reflected in the hash. */
foreach (StringSet::iterator, i, outputs) {
drv.env[*i] = "";
drv.outputs[*i] = DerivationOutput("", "", "");
}
/* Use the masked derivation expression to compute the output
path. */
Hash h = hashDerivationModulo(*store, drv);
foreach (DerivationOutputs::iterator, i, drv.outputs)
if (i->second.path == "") {
Path outPath = makeOutputPath(i->first, h, drvName);
drv.env[i->first] = outPath;
i->second.path = outPath;
}
}
/* Write the resulting term into the Nix store directory. */
Path drvPath = writeDerivation(drv, drvName);
Path drvPath = writeDerivation(*store, drv, drvName);
printMsg(lvlChatty, format("instantiated `%1%' -> `%2%'")
% drvName % drvPath);
/* Optimisation, but required in read-only mode! because in that
case we don't actually write store expressions, so we can't
case we don't actually write store derivations, so we can't
read them later. */
state.drvHashes[drvPath] = hashDerivationModulo(state, drv);
drvHashes[drvPath] = hashDerivationModulo(*store, drv);
/* !!! assumes a single output */
state.mkAttrs(v, 2);
mkString(*state.allocAttr(v, state.sOutPath), outPath, singleton<PathSet>(drvPath));
state.mkAttrs(v, 1 + drv.outputs.size());
mkString(*state.allocAttr(v, state.sDrvPath), drvPath, singleton<PathSet>("=" + drvPath));
foreach (DerivationOutputs::iterator, i, drv.outputs) {
mkString(*state.allocAttr(v, state.symbols.create(i->first)),
i->second.path, singleton<PathSet>("!" + i->first + "!" + drvPath));
}
v.attrs->sort();
}
@@ -1077,15 +1044,6 @@ void EvalState::createBaseEnv()
addPrimOp("__getEnv", 1, prim_getEnv);
addPrimOp("__trace", 2, prim_trace);
// Derivations
addPrimOp("derivationStrict", 1, prim_derivationStrict);
/* Add a wrapper around the derivation primop that computes the
`drvPath' and `outPath' attributes lazily. */
string s = "attrs: let res = derivationStrict attrs; in attrs // { drvPath = res.drvPath; outPath = res.outPath; type = \"derivation\"; }";
mkThunk_(v, parseExprFromString(*this, s, "/"));
addConstant("derivation", v);
// Paths
addPrimOp("__toPath", 1, prim_toPath);
addPrimOp("__storePath", 1, prim_storePath);
@@ -1134,6 +1092,14 @@ void EvalState::createBaseEnv()
addPrimOp("__parseDrvName", 1, prim_parseDrvName);
addPrimOp("__compareVersions", 2, prim_compareVersions);
// Derivations
addPrimOp("derivationStrict", 1, prim_derivationStrict);
/* Add a wrapper around the derivation primop that computes the
`drvPath' and `outPath' attributes lazily. */
mkThunk_(v, parseExprFromFile(findFile("nix/derivation.nix")));
addConstant("derivation", v);
/* Now that we've added all primops, sort the `builtins' attribute
set, because attribute lookups expect it to be sorted. */
baseEnv.values[0]->attrs->sort();

View File

@@ -2,18 +2,11 @@ pkglib_LTLIBRARIES = libmain.la
libmain_la_SOURCES = shared.cc
libmain_la_LIBADD = ../libstore/libstore.la @boehmgc_lib@
libmain_la_LIBADD = ../libstore/libstore.la @BDW_GC_LIBS@
pkginclude_HEADERS = shared.hh
AM_CXXFLAGS = \
-DNIX_STORE_DIR=\"$(storedir)\" \
-DNIX_DATA_DIR=\"$(datadir)\" \
-DNIX_STATE_DIR=\"$(localstatedir)/nix\" \
-DNIX_LOG_DIR=\"$(localstatedir)/log/nix\" \
-DNIX_CONF_DIR=\"$(sysconfdir)/nix\" \
-DNIX_LIBEXEC_DIR=\"$(libexecdir)\" \
-DNIX_BIN_DIR=\"$(bindir)\" \
-DNIX_VERSION=\"$(VERSION)\" \
-I$(srcdir)/.. -I$(srcdir)/../libutil \
-I$(srcdir)/../libstore

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