Compare commits

...
578 Commits
Author SHA1 Message Date
Eelco Dolstra 8d6418d46e Fix building without a garbage collector
http://hydra.nixos.org/build/6695350
2013-10-28 22:51:12 +01:00
Eelco Dolstra dec2f19502 Fix a segfault in genericClosure
It kept temporary data in STL containers that were not scanned by
Boehm GC, so Nix programs using genericClosure could randomly crash if
the garbage collector kicked in at a bad time.

Also make it a bit more efficient by copying points to values rather
than values.
2013-10-28 18:52:26 +01:00
Eelco Dolstra 6123144933 Drop Cygwin and Solaris builds 2013-10-28 11:56:37 +00:00
Eelco Dolstra 1dacd427cd Update release notes, set version for 1.6.1 release 2013-10-28 11:56:21 +00:00
Eelco Dolstra ea6bf0c21f Slightly optimize listToAttrs 2013-10-28 07:34:44 +01:00
Eelco Dolstra 36e67ff16b Undocument obsolete form of "let" 2013-10-24 22:06:39 +02:00
Eelco Dolstra fba17a9043 Doc fix 2013-10-24 22:05:58 +02:00
Eelco Dolstra 2d9bb56e55 Fix segfault on Darwin
Ever since SQLite in Nixpkgs was updated to 3.8.0.2, Nix has randomly
segfaulted on Darwin:

  http://hydra.nixos.org/build/6175515
  http://hydra.nixos.org/build/6611038

It turns out that this is because the binary cache substituter somehow
ends up loading two versions of SQLite: the one in Nixpkgs and the
other from /usr/lib/libsqlite3.dylib.  It's not exactly clear why the
latter is loaded, but it appears to be because WWW::Curl indirectly loads
/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation,
which in turn seems to load /usr/lib/libsqlite3.dylib.  This leads to
a segfault when Perl exits:

  #0  0x00000001010375f4 in sqlite3_finalize ()
  #1  0x000000010125806e in sqlite_st_destroy ()
  #2  0x000000010124bc30 in XS_DBD__SQLite__st_DESTROY ()
  #3  0x00000001001c8155 in XS_DBI_dispatch ()
  ...
  #14 0x0000000100023224 in perl_destruct ()
  #15 0x0000000100000d6a in main ()
  ...

The workaround is to explicitly load DBD::SQLite before WWW::Curl.
2013-10-24 19:15:52 +02:00
Eelco Dolstra 5bc41d78ff Rename "attribute sets" to "sets"
We don't have any other kind of sets so calling them attribute sets is
unnecessarily verbose.
2013-10-24 16:41:04 +02:00
Eelco Dolstra 9e4bb20455 Manual: Fix broken URLs
Fixes #172.
2013-10-24 16:02:08 +02:00
Eelco Dolstra dc341811d6 Add rpm_fedora19i386 to the release-critical builds 2013-10-24 15:54:23 +02:00
Eelco Dolstra 69befd33a9 Remove unnecessary call to forceStringNoCtx 2013-10-24 03:08:34 +02:00
Eelco Dolstra a5684e09d3 Document typeOf 2013-10-24 02:56:00 +02:00
Eelco Dolstra 411a3461dc Add a test of the type primops 2013-10-24 02:51:28 +02:00
Eelco Dolstra 05d02f798f Add a typeOf primop
We already have some primops for determining the type of a value, such
as isString, but they're incomplete: for instance, there is no isPath.
Rather than adding more isBla functions, the generic typeOf function
returns a string representing the type of the argument (e.g. "int").
2013-10-24 02:49:13 +02:00
Eelco Dolstra 6da92d96ae Document NIX_SHOW_STATS and NIX_COUNT_CALLS 2013-10-24 02:22:24 +02:00
Eelco Dolstra 543d8a5942 Don't require NIX_SHOW_STATS for NIX_COUNT_CALLS 2013-10-24 02:20:54 +02:00
Eelco Dolstra fe95650487 Memoize evalFile() lookups under both the original and resolved name
Previously we only used the resolved name, causing repeated resolution
(e.g. /dir to /dir/default.nix).
2013-10-23 11:19:01 +00:00
Eelco Dolstra 3139481822 Add an aggregate job
Also, build for Ubuntu 13.10 and Fedora 19.
2013-10-23 11:52:25 +02:00
Eelco Dolstra c086183843 For auto roots, show the intermediate link
I.e. "nix-store -q --roots" will now show (for example)

  /home/eelco/Dev/nixpkgs/result

rather than

  /nix/var/nix/gcroots/auto/53222qsppi12s2hkap8dm2lg8xhhyk6v
2013-10-22 11:39:10 +02:00
Eelco Dolstra 4f4a14453a Don't set $PS1 in non-interactive shells
Shouldn't really matter, but you never know.
2013-10-18 14:51:25 +02:00
Shea LevyandEelco Dolstra 4ea034a5c5 nix-shell: Play nicely with non-interactive shells
nix-shell with the --command flag might be used non-interactively, but
if bash starts non-interactively (i.e. with stdin or stderr not a
terminal), it won't source the script given in --rcfile. However, in
that case it *will* source the script found in $BASH_ENV, so we can use
that instead.

Also, don't source ~/.bashrc in a non-interactive shell (detectable by
checking the PS1 env var)

Signed-off-by: Shea Levy <shea@shealevy.com>
2013-10-18 14:34:46 +02:00
Eelco Dolstra 792fd51f41 Fold two stack trace messages in derivations
Combined with the previous changes, stack traces involving derivations
are now much less verbose, since something like

  while evaluating the builtin function `getAttr':
  while evaluating the builtin function `derivationStrict':
  while instantiating the derivation named `gtk+-2.24.20' at `/home/eelco/Dev/nixpkgs/pkgs/development/libraries/gtk+/2.x.nix:11:3':
  while evaluating the derivation attribute `propagatedNativeBuildInputs' at `/home/eelco/Dev/nixpkgs/pkgs/stdenv/generic/default.nix:78:17':
  while evaluating the attribute `outPath' at `/nix/store/212ngf4ph63mp6p1np2bapkfikpakfv7-nix-1.6/share/nix/corepkgs/derivation.nix:18:9':
  ...

now reads

  while evaluating the attribute `propagatedNativeBuildInputs' of the derivation `gtk+-2.24.20' at `/home/eelco/Dev/nixpkgs/pkgs/development/libraries/gtk+/2.x.nix:11:3':
  ...
2013-10-17 11:57:25 +02:00
Eelco Dolstra f440558acc Don't show <nix/derivation.nix> in stack traces
Messages like

  while evaluating the attribute `outPath' at `/nix/store/212ngf4ph63mp6p1np2bapkfikpakfv7-nix-1.6/share/nix/corepkgs/derivation.nix:18:9':

are redundant, because Nix already shows that it's evaluating a derivation:

  while instantiating the derivation named `firefox-24.0' at `/home/eelco/Dev/nixpkgs/pkgs/applications/networking/browsers/firefox/default.nix:131:5':
  while evaluating the derivation attribute `nativeBuildInputs' at `/home/eelco/Dev/nixpkgs/pkgs/stdenv/generic/default.nix:76:17':
2013-10-17 11:47:38 +02:00
Eelco Dolstra bb659bad81 Nix 1.6.1 release notes 2013-10-17 11:40:20 +02:00
Eelco Dolstra f6a8e7f4c2 Fix test 2013-10-17 11:18:37 +02:00
Eelco Dolstra b08f4b0da9 Test string semantics a bit more 2013-10-17 01:12:43 +02:00
goblinandEelco Dolstra d7625b5c2d two typos 2013-10-17 00:59:19 +02:00
Eelco Dolstra b8034e5581 Ensure proper type checking/coercion of "${expr}"
Now we only rewrite "${expr}" to expr if expr is a string literal.
2013-10-17 00:57:24 +02:00
Eelco Dolstra 9d8a80375d Add a test for type correctness of antiquotes
Antiquotes should evaluate to strings or paths.  This is usually
checked, except in the case where the antiquote makes up the entire
string, as in "${expr}".  This is optimised to expr, which discards
the runtime type checks / coercions.
2013-10-17 00:51:07 +02:00
Eelco Dolstra d6a7aa8f48 Revert the behaviour of antiquoted paths to pre-Nix 1.6
Commit 159e621d1a accidentally changed
the behaviour of antiquoted paths, e.g.

  "${/foo}/bar"

used to evaluate to "/nix/store/<hash>-foo/bar" (where /foo gets
copied to the store), but in Nix 1.6 it evaluates to "/foo/bar".  This
is inconsistent, since

  " ${/foo}/bar"

evaluates to " /nix/store/<hash>-foo/bar".  So revert to the old
behaviour.
2013-10-17 00:39:59 +02:00
Eelco Dolstra b8571d68c4 Add a regression test for correct path antiquotation behavior
This broke in Nix 1.6.
2013-10-16 23:29:11 +02:00
Eelco Dolstra a737f51fd9 Retry all SQLite operations
To deal with SQLITE_PROTOCOL, we also need to retry read-only
operations.
2013-10-16 15:58:20 +02:00
Eelco Dolstra ff02f5336c Fix a race in registerFailedPath()
Registering the path as failed can fail if another process does the
same thing after the call to hasPathFailed().  This is extremely
unlikely though.
2013-10-16 14:55:53 +02:00
Eelco Dolstra 4bd5282573 Convenience macros for retrying a SQLite transaction 2013-10-16 14:46:35 +02:00
Eelco Dolstra bce14d0f61 Don't wrap read-only queries in a transaction
There is no risk of getting an inconsistent result here: if the ID
returned by queryValidPathId() is deleted from the database
concurrently, subsequent queries involving that ID will simply fail
(since IDs are never reused).
2013-10-16 14:36:53 +02:00
Eelco Dolstra 7cdefdbe73 Print a distinct warning for SQLITE_PROTOCOL 2013-10-16 14:27:36 +02:00
Eelco Dolstra d05bf04444 Treat SQLITE_PROTOCOL as SQLITE_BUSY
In the Hydra build farm we fairly regularly get SQLITE_PROTOCOL errors
(e.g., "querying path in database: locking protocol").  The docs for
this error code say that it "is returned if some other process is
messing with file locks and has violated the file locking protocol
that SQLite uses on its rollback journal files."  However, the SQLite
source code reveals that this error can also occur under high load:

  if( cnt>5 ){
    int nDelay = 1;                      /* Pause time in microseconds */
    if( cnt>100 ){
      VVA_ONLY( pWal->lockError = 1; )
      return SQLITE_PROTOCOL;
    }
    if( cnt>=10 ) nDelay = (cnt-9)*238;  /* Max delay 21ms. Total delay 996ms */
    sqlite3OsSleep(pWal->pVfs, nDelay);
  }

i.e. if certain locks cannot be not acquired, SQLite will retry a
number of times before giving up and returing SQLITE_PROTOCOL.  The
comments say:

  Circumstances that cause a RETRY should only last for the briefest
  instances of time.  No I/O or other system calls are done while the
  locks are held, so the locks should not be held for very long. But
  if we are unlucky, another process that is holding a lock might get
  paged out or take a page-fault that is time-consuming to resolve,
  during the few nanoseconds that it is holding the lock.  In that case,
  it might take longer than normal for the lock to free.
  ...
  The total delay time before giving up is less than 1 second.

On a heavily loaded machine like lucifer (the main Hydra server),
which often has dozens of processes waiting for I/O, it seems to me
that a page fault could easily take more than a second to resolve.
So, let's treat SQLITE_PROTOCOL as SQLITE_BUSY and retry the
transaction.

Issue NixOS/hydra#14.
2013-10-16 14:19:59 +02:00
Eelco Dolstra c1994fecf9 nix-shell: Fix bash completion
Nixpkgs's stdenv setup script sets the "nullglob" option, but doing so
breaks Bash completion on NixOS (when ‘programs.bash.enableCompletion’
is set) and on Ubuntu.  So clear that flag afterwards.  Of course,
this may break stdenv functions in subtle ways...
2013-10-14 15:28:43 +02:00
Eelco Dolstra 672c3acc71 Adjust to the NixOS/Nixpkgs merge 2013-10-11 10:57:23 +02:00
Eelco Dolstra 7bdb85453d printStats(): Print the size of the symbol table in bytes 2013-10-08 15:37:08 +02:00
Eelco Dolstra 9deb822180 Deduplicate filenames in Pos
This saves ~4 MiB of RAM for NixOS system instantiation, and ~18 MiB
for "nix-env -qa".
2013-10-08 15:36:10 +02:00
Eelco Dolstra b1e3b1a4ac Treat undefined variable errors consistently
Previously, a undefined variable inside a "with" caused an EvalError
(which can be caught), while outside, it caused a ParseError (which
cannot be caught).  Now both cause an UndefinedVarError (which cannot
be caught).
2013-10-08 14:45:36 +02:00
Eelco Dolstra 6b47de580f Show the exact position of undefined variables
In particular, undefined variable errors in a "with" previously didn't
show *any* position information, so this should help a lot in those
cases.
2013-10-08 14:40:51 +02:00
Eelco Dolstra a5e0f64db3 Remove some unused functions 2013-10-08 12:30:23 +00:00
Eelco Dolstra 221a2daf34 Merge VarRef into ExprVar 2013-10-08 14:24:53 +02:00
Eelco Dolstra 176c666f36 Don't show calls to primops in stack traces
Since they don't have location information, they just give you crap
like:

  while evaluating the builtin function `getAttr':
  while evaluating the builtin function `derivationStrict':
  ...
2013-10-07 18:02:32 +02:00
Eelco Dolstra c945f015de Fix segfault in nix-repl / hydra-eval-jobs
If a "with" attribute set fails to evaluate, we have to make sure its
Env record remains unchanged.  Otherwise, repeated evaluation gives a
segfault:

  nix-repl> :a with 0; { a = x; b = x; }
  Added 2 variables.

  nix-repl> a
  error: value is an integer while an attribute set was expected

  nix-repl> b
  Segmentation fault
2013-10-02 15:24:45 +02:00
Eelco Dolstra 28e0742966 Report OOM errors better 2013-10-02 14:34:36 +02:00
Eelco Dolstra a5fb4b5b7c Fix typo 2013-10-02 14:22:49 +02:00
Eelco Dolstra faaae44f2e build-remote.pl: Don't use substituters on the remote
It's kinda pointless to check substituters on the remote side, since
we just checked them locally.
2013-09-18 14:04:03 +02:00
Eelco Dolstra f53574ebd6 RestoreSink: Slightly reduce the number of concurrent FDs 2013-09-17 12:06:59 +00:00
Eelco Dolstra d5529f5b85 Version was called 1.6, not 1.6.0 2013-09-10 17:48:11 +02:00
Eelco Dolstra b072fc04a7 Bump version number 2013-09-10 17:41:49 +02:00
Eelco Dolstra fecad91b67 Update release notes 2013-09-10 11:21:30 +02:00
Eelco Dolstra 0220da3e10 Remove stray debug line 2013-09-06 17:20:19 +02:00
Eelco Dolstra 936f9d45ba Don't apply the CPU affinity hack to nix-shell (and other Perl programs)
As discovered by Todd Veldhuizen, the shell started by nix-shell has
its affinity set to a single CPU.  This is because nix-shell connects
to the Nix daemon, which causes the affinity hack to be applied.  So
we turn this off for Perl programs.
2013-09-06 16:36:56 +02:00
Domen KožarandEelco Dolstra 4b83830d0c typo 2013-09-06 15:18:07 +02:00
Eelco Dolstra 5904262640 nix-shell: Support a .drv as argument
Fixes #161.
2013-09-06 14:58:05 +02:00
Eelco Dolstra 2c1ecf8e81 nix-env -i: Add a flag ‘--remove-all’ / ‘-r’
This is equivalent to running ‘nix-env -e '*'’ first, except that it
happens in a single transaction.  Thus, ‘nix-env -i pkgs...’ replaces
the profile with the specified set of packages.

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

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

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

  $ nix-env -f profile.nix -ir

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

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

  nix-env -qa

is equivalent to

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  error: stack overflow (possible infinite recursion)

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

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

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

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

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

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

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

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

while evaluating `concatMapStrings' at `/nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs/pkgs/lib/strings.nix:18:25':
...
2013-05-16 19:08:02 +02:00
Eelco Dolstra 1b3a03f161 Show which function argument was unexpected
Fixes #116.
2013-05-16 17:56:14 +02:00
Eelco Dolstra 229567293c Shut up a compiler warning 2013-05-16 17:48:19 +02:00
Eelco Dolstra a4cb62ac25 download-from-binary-cache.pl: Get rid of an uninitialized value warning
Reported by Pablo Costa.
2013-05-15 15:47:05 +02:00
Eelco Dolstra 31a551a60f Bump version 2013-05-13 23:50:31 +02:00
Eelco Dolstra 6e85d1b5ba Bump release date 2013-05-13 16:52:08 +02:00
Eelco Dolstra 3a0cc43ac8 build-remote.pl: Properly close the SSH connection between attempts 2013-05-10 02:38:50 +02:00
Eelco Dolstra be0b9dda31 build-remote.pl: Pass /dev/null as SSH's stdin
Otherwise it will set the parent's stdin to non-blocking mode, causing
the subsequent read of the set of inputs/outputs to fail randomly.
That's insane.
2013-05-10 02:32:13 +02:00
Eelco Dolstra 78206f06ec build-remote.pl: Allow a machine to refuse a build
Before selecting a machine, build-remote.pl will try to run the
command "nix-builds-inhibited" on the machine.  If this command exists
and returns a 0 exit code, then the machine won't be used.  It's up to
the user to provide this command, but it would typically be a script
that checks whether there is enough disk space and whether the load is
not too high.
2013-05-10 01:09:46 +02:00
Eelco Dolstra 2ee9da9e22 In trace messages, don't print the output path
This doesn't work if there is no output named "out".  Hydra didn't use
it anyway.
2013-05-10 00:24:33 +02:00
Eelco Dolstra 6eba05613a Communicate build timeouts to Hydra 2013-05-09 18:39:04 +02:00
Eelco Dolstra 7a03cbf09d build-remote.pl: Create one process fewer on the remote side 2013-05-09 17:30:07 +02:00
Eelco Dolstra 69b8f9980f build-remote.pl: Enforce timeouts locally
Don't pass --timeout / --max-silent-time to the remote builder.
Instead, let the local Nix process terminate the build if it exceeds a
timeout.  The remote builder will be killed as a side-effect.  This
gives better error reporting (since the timeout message from the
remote side wasn't properly propagated) and handles non-Nix problems
like SSH hangs.
2013-05-09 17:17:17 +02:00
Eelco Dolstra e93acab852 Build Fedora 18 RPMs 2013-05-08 14:41:35 +02:00
Eelco Dolstra 806970349b Update release date 2013-05-07 15:46:25 +02:00
Eelco Dolstra ea019e9a26 Add option ‘extra-binary-caches’
This allows providing additional binary caches, useful in scripts like
Hydra's build reproduction scripts, in particular because untrusted
caches are ignored.
2013-05-07 15:37:28 +02:00
Eelco Dolstra cc837e2458 Build Debian 7.0 debs 2013-05-07 11:21:30 +02:00
Eelco Dolstra 28034bfa49 Build Ubuntu 13.04 debs 2013-05-03 14:14:46 +02:00
Eelco Dolstra 93f4fa8a15 Update release notes 2013-05-03 11:28:32 +02:00
Eelco Dolstra c51b6a893c nix-copy-closure: Show a proper error message if no host name is given 2013-05-03 11:12:11 +02:00
Lluís Batlle i RossellandEelco Dolstra e6c44d166a Fixing the pv position regarding compression
Problem noticed by niksnut.
2013-05-03 11:08:51 +02:00
Lluís Batlle i RossellandEelco Dolstra 7391533ea5 Fixing the pv reference; I didn't mean to change it 2013-05-03 11:08:51 +02:00
Lluís Batlle i RossellandEelco Dolstra 5cc2fc46ec Adding ETA support to the --show-progress in nix-copy-closure
Based on https://github.com/NixOS/nix/pull/6 from shlevy
2013-05-03 11:08:51 +02:00
Eelco Dolstra 3628b61ce0 Nix 1.5.2 release notes 2013-05-01 13:31:33 +02:00
Eelco Dolstra 470553bd05 Don't let stderr writes in substituters cause a deadlock 2013-05-01 13:21:39 +02:00
Eelco Dolstra 4ddd077bfa find-runtime-roots.pl: Don't hardcode /nix/store 2013-04-26 12:15:54 +02:00
Eelco Dolstra 0374d94437 addAdditionalRoots(): Check each path only once 2013-04-26 12:07:25 +02:00
Eelco Dolstra 00f698eb8b find-runtime-roots.pl: Search process environments for roots
For instance, this prevents paths from being deleted that are in use
by a "nix-build --run-env" session.
2013-04-26 12:06:39 +02:00
Eelco Dolstra 938092a213 find-runtime-roots.pl: Use Nix::Utils::readFile 2013-04-26 11:44:19 +02:00
Eelco Dolstra 772b70952f Fix --timeout
I'm not sure if it has ever worked correctly.  The line "lastWait =
after;" seems to mean that the timer was reset every time a build
produced log output.

Note that the timeout is now per build, as documented ("the maximum
number of seconds that a builder can run").
2013-04-23 18:04:59 +02:00
Eelco Dolstra f9974f856e Show that --timeout doesn't work if the build produces log output 2013-04-23 17:16:29 +02:00
Eelco Dolstra 6955d41f2b nix-build: Respect --timeout 2013-04-23 17:16:01 +02:00
Eelco Dolstra 934cf2d1f4 Nix daemon: respect build timeout from the client 2013-04-23 16:59:06 +02:00
Eelco Dolstra 08d96ffad0 Fix --fallback with the binary cache substituter
Reported by Peter Simons.
2013-04-23 12:45:01 +02:00
Eelco Dolstra a9b4e26b5c Test whether --fallback works if NARS have disappeared from the binary cache 2013-04-23 12:44:01 +02:00
Eelco Dolstra c642441beb Test NAR info caching 2013-04-23 12:43:28 +02:00
Eelco Dolstra 05420e7883 Manual: Add a missing step to the build instructions
Reported by Johan Grande.
2013-04-09 17:57:48 +02:00
Eelco Dolstra 258897c265 Complain if /homeless-shelter exists 2013-04-04 11:16:26 +02:00
Eelco Dolstra 239841787b Fix evaluation of the VM tests 2013-03-25 21:59:11 +01:00
Shea LevyandEelco Dolstra cc63db1dd5 makeStoreWritable: Ask forgiveness, not permission
It is surprisingly impossible to check if a mountpoint is a bind mount
on Linux, and in my previous commit I forgot to check if /nix/store was
even a mountpoint at all. statvfs.f_flag is not populated with MS_BIND
(and even if it were, my check was wrong in the previous commit).

Luckily, the semantics of mount with MS_REMOUNT | MS_BIND make both
checks unnecessary: if /nix/store is not a mountpoint, then mount will
fail with EINVAL, and if /nix/store is not a bind-mount, then it will
not be made writable. Thus, if /nix/store is not a mountpoint, we fail
immediately (since we don't know how to make it writable), and if
/nix/store IS a mountpoint but not a bind-mount, we fail at first write
(see below for why we can't check and fail immediately).

Note that, due to what is IMO buggy behavior in Linux, calling mount
with MS_REMOUNT | MS_BIND on a non-bind readonly mount makes the
mountpoint appear writable in two places: In the sixth (but not the
10th!) column of mountinfo, and in the f_flags member of struct statfs.
All other syscalls behave as if the mount point were still readonly (at
least for Linux 3.9-rc1, but I don't think this has changed recently or
is expected to soon). My preferred semantics would be for MS_REMOUNT |
MS_BIND to fail on a non-bind mount, as it doesn't make sense to remount
a non bind-mount as a bind mount.
2013-03-25 19:00:16 +01:00
Shea LevyandEelco Dolstra 2c9cf50746 makeStoreWritable: Use statvfs instead of /proc/self/mountinfo to find out if /nix/store is a read-only bind mount
/nix/store could be a read-only bind mount even if it is / in its own filesystem, so checking the 4th field in mountinfo is insufficient.

Signed-off-by: Shea Levy <shea@shealevy.com>
2013-03-25 19:00:16 +01:00
Eelco Dolstra c3fc60d936 Fix evaluation 2013-03-18 21:49:42 +01:00
Eelco Dolstra f72ed36025 Bump version number 2013-03-15 14:21:05 +01:00
Eelco Dolstra 78d777ca15 Remove the "system" jobset input 2013-03-15 13:18:49 +01:00
Eelco Dolstra a68ebf8e37 Require Bison 2.6 2013-03-14 18:33:15 +01:00
Eelco Dolstra 804709706c Fix building against Bison 2.6 2013-03-14 18:31:08 +01:00
Eelco Dolstra c56bc3d81c Make sure that thunks are restored properly if an exception occurs
Fixes Hydra bug #67.
2013-03-14 17:21:13 +01:00
Eelco Dolstra 4b07476848 Prevent config.h from being clobbered 2013-03-08 01:27:04 +01:00
Eelco Dolstra bdd4646338 Revert "Prevent config.h from being clobbered"
This reverts commit 28bba8c44f.
2013-03-08 01:24:59 +01:00
Eelco Dolstra e73d9e9488 Fix annoying Perl 5.16 warnings
I.e.

Subroutine Nix::Store::isValidPath redefined at /nix/store/clfzsf6gi7qh5i9c0vks1ifjam47rijn-perl-5.16.2/lib/perl5/5.16.2/XSLoader.pm line 92.

and so on.
2013-03-08 00:27:32 +01:00
Eelco Dolstra 28bba8c44f Prevent config.h from being clobbered 2013-03-07 23:55:55 +01:00
Eelco Dolstra 8057a192e3 Handle systems without lutimes() or lchown() 2013-02-28 19:55:09 +01:00
Eelco Dolstra 9fa1bee575 Update release notes
Also use a point release version number as suggested by several
people.
2013-02-28 19:36:02 +01:00
Eelco Dolstra f45c731cd7 Handle symlinks properly
Now it's really brown paper bag time...
2013-02-28 14:51:08 +01:00
Eelco Dolstra 88936411bc Bump version number 2013-02-28 13:03:53 +01:00
Eelco Dolstra 0111ba98ea Handle hard links to other files in the output 2013-02-27 17:18:41 +01:00
Eelco Dolstra b008674e46 Refactoring: Split off the non-recursive canonicalisePathMetaData()
Also, change the file mode before changing the owner.  This prevents a
slight time window in which a setuid binary would be setuid root.
2013-02-27 16:42:19 +01:00
Eelco Dolstra 826dc0d07d Remove outdated file 2013-02-26 14:32:48 +01:00
Eelco Dolstra 97c6009c47 Bump version number 2013-02-26 14:32:14 +01:00
Eelco Dolstra ca9c02dff1 Update release notes 2013-02-26 13:23:09 +01:00
Eelco Dolstra 5526a282b5 Security: Don't allow builders to change permissions on files they don't own
It turns out that in multi-user Nix, a builder may be able to do

  ln /etc/shadow $out/foo

Afterwards, canonicalisePathMetaData() will be applied to $out/foo,
causing /etc/shadow's mode to be set to 444 (readable by everybody but
writable by nobody).  That's obviously Very Bad.

Fortunately, this fails in NixOS's default configuration because
/nix/store is a bind mount, so "ln" will fail with "Invalid
cross-device link".  It also fails if hard-link restrictions are
enabled, so a workaround is:

  echo 1 > /proc/sys/fs/protected_hardlinks

The solution is to check that all files in $out are owned by the build
user.  This means that innocuous operations like "ln
${pkgs.foo}/some-file $out/" are now rejected, but that already failed
in chroot builds anyway.
2013-02-26 02:30:19 +01:00
Eelco Dolstra dadf7a5b46 build-remote: Use the --quiet flag
‘--option verbosity 0’ doesn't actually do anything.
2013-02-19 16:56:31 +01:00
Ludovic CourtèsandEelco Dolstra 3e067ac11c Add `Settings::nixDaemonSocketFile'. 2013-02-19 10:19:18 +01:00
Ludovic CourtèsandEelco Dolstra 5ea138dc4b Enable chroot support on old glibc versions. 2013-02-19 10:19:11 +01:00
Eelco Dolstra 79a3ba7fa3 Document ‘hashString’ 2013-02-08 20:04:14 +01:00
Eelco Dolstra 5f18cd2e84 Make "${./path} ..." evaluate to a string, not a path
Wacky string coercion semantics caused expressions like

  exec = "${./my-script} params...";

to evaluate to a path (‘/path/my-script params’), because
anti-quotations are desuged to string concatenation:

  exec = ./my-script + " params...";

By constrast, adding a space at the start would yield a string as
expected:

  exec = " ${./my-script} params...";

Now the first example also evaluates to a string.
2013-02-08 20:04:04 +01:00
Eelco Dolstra 52172607cf Rename "hash" to "hashString" and handle SHA-1 2013-02-08 19:36:23 +01:00
Marc WeberandEelco Dolstra 01a5ea9914 experimental/hash
adding primop function calculating hash of a string

Signed-off-by: Marc Weber <marco-oweber@gmx.de>
2013-02-08 19:26:34 +01:00
Eelco Dolstra 8add116acd Nix::Store::derivationFromPath: Return derivation outputs 2013-02-05 16:02:57 +01:00
Eelco Dolstra d6143801fd Support the colonies 2013-01-30 18:50:58 +01:00
Eelco Dolstra 9842077cb2 Improve -I description
Issue #88.
2013-01-24 13:00:44 +01:00
Eelco Dolstra 5e9c3da412 Only warn about SQLite being busy once
No need to get annoying.
2013-01-23 16:45:10 +01:00
Eelco Dolstra 99ed558a93 Correctly handle missing logs 2013-01-22 22:07:25 +01:00
Eelco Dolstra 1943b60ad8 Fix the VM tests 2013-01-21 22:36:23 +01:00
Eelco Dolstra 96fbbbde55 build-remote.pl: Don't keep build logs on the build slave 2013-01-21 22:26:25 +01:00
Shea LevyandEelco Dolstra d6fd6d8aff corepkgs/fetchurl: Enable making the downloaded file executable 2013-01-21 10:20:52 +01:00
Eelco Dolstra 536c85ea49 Store build logs in /nix/var/log/nix/drvs/<XX>
...where <XX> is the first two characters of the derivation.
Otherwise /nix/var/log/nix/drvs may become so large that we run into
all sorts of weird filesystem limits/inefficiences.  For instance,
ext3/ext4 filesystems will barf with "ext4_dx_add_entry:1551:
Directory index full!" once you hit a few million files.
2013-01-17 15:47:26 +01:00
Eelco Dolstra 66fa9e6a4d Bump version number to 1.4 2013-01-07 14:48:44 +01:00
Eelco Dolstra e42df686f3 Delete a left-over trash directory before doing a GC 2013-01-05 00:13:29 +01:00
Eelco Dolstra 92926be2fe Fix "0 store paths deleted" message 2013-01-04 15:17:19 +01:00
Eelco Dolstra b424d29d1b Open the database after removing immutable bits 2013-01-03 13:29:17 +01:00
Eelco Dolstra 3007f57377 Remove tabs 2013-01-03 13:00:46 +01:00
Eelco Dolstra def5160b61 Clear any immutable bits in the Nix store
Doing this once makes subsequent operations like garbage collecting
more efficient since we don't have to call makeMutable() first.
2013-01-03 12:59:23 +01:00
Eelco Dolstra 0a4e90395c Urgggh
http://hydra.nixos.org/build/3661100
2013-01-02 23:52:15 +01:00
Eelco Dolstra f12492c66d Manual: Fix "nix-store --export" example 2013-01-02 22:36:08 +01:00
Eelco Dolstra aebea2e489 Reinstate the http://nixos.org/binary-cache default for the binary-caches setting 2013-01-02 22:16:37 +01:00
Eelco Dolstra 649bb60617 Use sysconfdir=/etc 2013-01-02 22:12:19 +01:00
Eelco Dolstra 42d6f640c1 Update release notes 2013-01-02 13:00:55 +01:00
Eelco Dolstra 299141ecbd If a substitute closure is incomplete, build dependencies, then retry the substituter
Issue #77.
2013-01-02 12:38:28 +01:00
Eelco Dolstra 1b3a78a459 Automatically fall back if the references of a substitute are not substitutable
Fixes #77.
2013-01-02 12:00:26 +01:00
Eelco Dolstra 82248abd8f Add a test for incomplete closures in the binary cache
Issue #77.
2013-01-02 11:45:23 +01:00
Eelco Dolstra 12f9129f60 nix-build: Support talking to old daemons
Fixes #76.
2012-12-29 23:21:46 +01:00
Eelco Dolstra b7629778ef Allow mounting a path in a different location in the chroot
Fixes #24.
2012-12-29 23:04:02 +01:00
Eelco Dolstra 68dcbb187e download-from-binary-cache: Use the channels of the calling user rather than root
This should make live easier for single-user (non-daemon)
installations.  Note that when the daemon is used, the "calling user"
is root so we're not using any untrusted caches.
2012-12-21 15:00:07 +01:00
Eelco Dolstra 5ee7d8fbab Typo fix 2012-12-21 00:18:59 +01:00
Eelco Dolstra 2754a07ead nix-store -q --roots: Respect the gc-keep-outputs/gc-keep-derivations settings
So if a path is not garbage solely because it's reachable from a root
due to the gc-keep-outputs or gc-keep-derivations settings, ‘nix-store
-q --roots’ now shows that root.
2012-12-20 18:41:44 +01:00
Eelco Dolstra 06f62defe6 Yet another rewrite of the garbage collector
But this time it's *obviously* correct!  No more segfaults due to
infinite recursions for sure, etc.

Also, move directories to /nix/store/trash instead of renaming them to
/nix/store/bla-gc-<pid>.  Then we can just delete /nix/store/trash at
the end.
2012-12-20 17:32:15 +01:00
Eelco Dolstra 9c29a2ed35 Give a better error message if writeFile fails due to permission issues 2012-12-20 12:22:13 +01:00
Eelco Dolstra e775d4d84f If gc-keep-derivations is set, only keep the actual deriver
This prevents zillions of derivations from being kept, and fixes an
infinite recursion in the garbage collector (due to an obscure cycle
that can occur with fixed-output derivations).
2012-12-19 15:33:09 +01:00
Eelco Dolstra fbf0b2fa45 Kill the build hook rather than shutting it down cleanly
Waiting for the hook to shut down cleanly sometimes seems to lead to
hangs.
2012-12-19 11:47:42 +01:00
Eelco Dolstra 228ea7c2f9 Revert brain fart
This reverts commit cc511fd65b.
2012-12-18 20:43:47 +01:00
Eelco Dolstra cc511fd65b Check for potential infinite select() loops when building 2012-12-18 18:50:05 +01:00
Stuart PernsteinerandEelco Dolstra a9045c727f fix use-after-free bug in mkString(Value&, Symbol&) 2012-12-13 11:13:20 +01:00
Eelco Dolstra 9fa12fc201 Allow setting the profile location using $NIX_PROFILE
Fixes #69.
2012-12-12 16:01:46 +01:00
Eelco Dolstra 3ad53e43c8 Debian package: Add dependency on libwww-curl-perl
Fixes issue #70.
2012-12-11 16:50:21 +01:00
Eelco Dolstra 772778c0ec On SQLITE_BUSY, wait a random amount of time
If all contending processes wait a fixed amount of time (100 ms),
there is a good probability that they'll just collide again.
2012-12-11 11:49:42 +01:00
Eelco Dolstra e087bfef5f Bump version number 2012-12-07 13:14:04 +01:00
Eelco Dolstra a6ce6d9e7c Fix manual generation
Grmbl.
2012-12-06 16:55:57 +01:00
Eelco Dolstra 8cc19ed089 Set a long SQLite timeout in the binary cache substituter 2012-12-06 11:43:34 +01:00
Eelco Dolstra 52edef3495 Fix RPM build
http://hydra.nixos.org/build/3436627
2012-12-05 23:25:40 +01:00
Eelco Dolstra 8d100dbef1 Add a dependency on xz-utils 2012-12-05 12:18:07 +01:00
Eelco Dolstra 5c487761c4 Add a dependency on xz 2012-12-05 12:17:12 +01:00
Eelco Dolstra 3631dc6b2f Typo 2012-12-05 12:15:06 +01:00
Eelco Dolstra aa61bc7472 Fix RPM build
http://hydra.nixos.org/build/3436511
2012-12-05 12:05:43 +01:00
Eelco Dolstra 0f96966a44 Add release date 2012-12-05 11:03:06 +01:00
Eelco Dolstra 566afa1e9c Support xz compression of nixexprs.tar in channels 2012-12-05 11:02:44 +01:00
Eelco Dolstra 444b03a36f Produce an xz-compressed tarball
Footnote: doing "make dist-gzip dist-xz" doesn't work with Automake;
you have to do "make dist-gzip; dist-xz".  That's because the dist-*
targets delete the temporary distdir at the end.
2012-12-05 10:23:53 +01:00
Eelco Dolstra d5a01d0f9d Build Debs for Ubuntu 12.10 2012-12-05 09:54:41 +01:00
Eelco Dolstra a7b4aaa2c3 Updated release notes 2012-12-04 17:41:51 +01:00
Eelco Dolstra 3100b29fc5 Tiny optimisation in the filter primop 2012-12-04 17:22:20 +01:00
Eelco Dolstra 094a08f839 Document new primops 2012-12-04 17:15:32 +01:00
Florian FriesdorfandEelco Dolstra 4387d19359 nix-channel --update needs bzip2 2012-12-04 16:35:27 +01:00
Eelco Dolstra 24d5875514 Document multiple output support 2012-12-04 16:03:56 +01:00
Eelco Dolstra b215b23e9e Test priorities 2012-12-04 14:47:50 +01:00
Eelco Dolstra 56d29dcd62 buildenv.pl: Create symlinks in priority order
This reduces unnecessary symlink/unlink steps.
2012-12-04 14:45:32 +01:00
Eelco Dolstra 2d5e8e267b Add a test for ‘nix-env --set-flag active ...’ 2012-12-04 14:30:34 +01:00
Eelco Dolstra 5ad89398d1 nix-env: Install all outputs of a derivation
If you explicitly install a package, presumably you want all of it.
So symlink all outputs in the user environment.
2012-12-04 14:20:36 +01:00
Eelco Dolstra 21c2d8d102 Test the ‘--prebuilt-only’ flag 2012-12-03 21:02:06 +01:00
Eelco Dolstra d62fc71b85 Fix the ‘--prebuilt-only’ flag 2012-12-03 21:01:41 +01:00
Eelco Dolstra 4bb4d5479a Whitespace 2012-12-03 18:19:49 +01:00
Eelco Dolstra 8eed07cda4 nix-env -q --out-path: Support multiple outputs
We now print all output paths of a package, e.g.

  openssl-1.0.0i  bin=/nix/store/gq2mvh0wb9l90djvsagln3aqywqmr6vl-openssl-1.0.0i-bin;man=/nix/store/7zwf5r5hsdarl3n86dasvb4chm2xzw9n-openssl-1.0.0i-man;/nix/store/cj7xvk7fjp9q887359j75pw3pzjfmqf1-openssl-1.0.0i

or (in XML mode)

  <item attrPath="openssl" name="openssl-1.0.0i" system="x86_64-linux">
    <output name="bin" path="/nix/store/gq2mvh0wb9l90djvsagln3aqywqmr6vl-openssl-1.0.0i-bin" />
    <output name="man" path="/nix/store/7zwf5r5hsdarl3n86dasvb4chm2xzw9n-openssl-1.0.0i-man" />
    <output name="out" path="/nix/store/cj7xvk7fjp9q887359j75pw3pzjfmqf1-openssl-1.0.0i" />
  </item>
2012-11-28 13:49:44 +01:00
Eelco Dolstra 6c98e6a5de Optionally ignore null-valued derivation attributes
This allows adding attributes like

  attr = if stdenv.system == "bla" then something else null;

without changing the resulting derivation on non-<bla> platforms.

We once considered adding a special "ignore" value for this purpose,
but using null seems more elegant.
2012-11-27 15:01:32 +01:00
Eelco Dolstra 8b8ee53bc7 Add builtin constants ‘langVersion’ and ‘nixVersion’
The integer constant ‘langVersion’ denotes the current language
version.  It gets increased every time a language feature is
added/changed/removed.  It's currently 1.

The string constant ‘nixVersion’ contains the current Nix version,
e.g. "1.2pre2980_9de6bc5".
2012-11-27 13:29:55 +01:00
Eelco Dolstra 5943f41b8b queryMissing(): Handle partially valid derivations 2012-11-26 18:25:12 +01:00
Eelco Dolstra 08964d7328 Undo accidental debug change 2012-11-26 17:57:14 +01:00
Eelco Dolstra 69c88f5028 Fix the multiple-outputs test 2012-11-26 17:46:45 +01:00
Eelco Dolstra 408a7bfac1 nix-instantiate: Fix read-only evaluation 2012-11-26 17:41:10 +01:00
Eelco Dolstra 8d8d47abd2 Only substitute wanted outputs of a derivation
If a derivation has multiple outputs, then we only want to download
those outputs that are actuallty needed.  So if we do "nix-build -A
openssl.man", then only the "man" output should be downloaded.
Likewise if another package depends on ${openssl.man}.

The tricky part is that different derivations can depend on different
outputs of a given derivation, so we may need to restart the
corresponding derivation goal if that happens.
2012-11-26 17:15:09 +01:00
Eelco Dolstra 46a369ad95 Make "nix-build -A <derivation>.<output>" do the right thing
For example, given a derivation with outputs "out", "man" and "bin":

  $ nix-build -A pkg

produces ./result pointing to the "out" output;

  $ nix-build -A pkg.man

produces ./result-man pointing to the "man" output;

  $ nix-build -A pkg.all

produces ./result, ./result-man and ./result-bin;

  $ nix-build -A pkg.all -A pkg2

produces ./result, ./result-man, ./result-bin and ./result-2.
2012-11-26 15:39:10 +01:00
Eelco Dolstra a3d6585c5a nix-copy-closure: Add flag ‘--use-substitutes’ 2012-11-23 16:20:16 +01:00
Eelco Dolstra 9de6bc5d05 nix-store -r: Add ‘--ignore-unknown’ flag
This flag causes paths that do not have a known substitute to be
quietly ignored.  This is mostly useful for Charon, allowing it to
speed up deployment by letting a machine use substitutes for all
substitutable paths, instead of uploading them.  The latter is
frequently faster, e.g. if the target machine has a fast Internet
connection while the source machine is on a slow ADSL line.
2012-11-20 00:27:25 +01:00
Eelco Dolstra bf3725da2a nix-store -r: Don't quietly ignore missing paths 2012-11-19 23:51:56 +01:00
Eelco Dolstra 17dc306aa3 Revert "prim_toPath: Actually make the string a path"
This reverts commit 2980d1fba9.  It
causes a regression in NixOS evaluation:

string `/nix/store/ya3s5gmj3b28170fpbjhgsk8wzymkpa1-pommed-1.39/etc/pommed.conf' cannot refer to other paths
2012-11-15 23:04:34 +01:00
Eelco Dolstra f794465ca8 Disable use of vfork()
vfork() is just too weird.  For instance, in this build:

  http://hydra.nixos.org/build/3330487

the value fromHook.writeSide becomes corrupted in the parent, even
though the child only reads from it.  At -O0 the problem goes away.
Probably the child is overriding some spilled temporary variable.

If I get bored I may implement using posix_spawn() instead.
2012-11-15 19:35:18 +01:00
Eelco Dolstra 8541d27fce Don't use std::cerr in a few places
Slightly scared of using std::cerr in a vforked process...
2012-11-15 15:01:02 +01:00
Eelco Dolstra 3acc8adcad Add some debug code 2012-11-15 13:55:02 +01:00
Eelco Dolstra ea89df2b76 Use vfork() instead of fork() if available
Hopefully this reduces the chance of hitting ‘unable to fork: Cannot
allocate memory’ errors.  vfork() is used for everything except
starting builders.
2012-11-09 18:00:33 +01:00
Eelco Dolstra 48c19c4633 Remove definition of non-existant function 2012-11-09 17:59:41 +01:00
Eelco Dolstra 198dbe7fa1 Remove some redundant close() calls
They are unnecessary because we set the close-on-exec flag.
2012-11-09 16:58:51 +01:00
Eelco Dolstra 10dcee99ed Remove the quickExit function 2012-11-09 16:42:10 +01:00
Eelco Dolstra 4c9e3fa641 Remove a Darwin hack that should no longer be needed 2012-11-09 16:35:42 +01:00
Eelco Dolstra 182e15b661 Manual: Don't use a store path in our closure
http://hydra.nixos.org/build/3313227
2012-11-09 16:30:15 +01:00
Eelco Dolstra 88164325fa Fix a segfault when auto-calling a "a@{...}" function
Since the called function can return its argument attribute set
(e.g. "a"), the latter should not be allocated on the stack.

Reported by Shea.
2012-11-09 15:09:31 +01:00
Eelco Dolstra f581ce0b0c Don't start copy-from-other-stores if $NIX_OTHER_STORES is unset
Slight optimisation.
2012-11-09 14:58:10 +01:00
Eelco Dolstra 91ef4d9a81 Remove unnecessary call to closeMostFDs()
We have close-on-exec on all FDs now, and there is no security risk in
passing open FDs to substituters anyway.
2012-11-09 14:43:47 +01:00
Eelco Dolstra a9a8baaccb Use a shorter Nixpkgs channel URL 2012-11-09 13:33:35 +01:00
Eelco Dolstra c31ebc50aa Update release notes 2012-11-09 13:33:24 +01:00
Eelco Dolstra e28b683324 download-from-binary-cache: Try next cache if downloading a NAR fails 2012-11-06 17:55:53 +01:00
Eelco Dolstra bbc107ef1e Process binary caches in order of priority
Binary caches can now specify a priority in their nix-cache-info file.
The binary cache substituter checks caches in order of priority.  This
is to ensure that fast, static caches like nixos.org/binary-cache are
processed before slow, dynamic caches like hydra.nixos.org.
2012-11-06 17:45:20 +01:00
Eelco Dolstra 3a95e1a17c Update nix-push manpage and document the binary cache format 2012-11-06 15:49:53 +01:00
Eelco Dolstra 82951e5582 nix-push: Handle pushing a symlink 2012-11-06 13:53:53 +01:00
Eelco Dolstra 620e92e880 Add an option ‘use-binary-caches’
This allows disabling the use of binary caches, e.g.

  $ nix-build ... --option use-binary-caches false

Note that

  $ nix-build ... --option binary-caches ''

does not disable all binary caches, since the caches defined by
channels will still be used.
2012-11-06 13:44:59 +01:00
Eelco Dolstra df27db712d Fix "Not an ARRAY reference" error
It's a mystery why this error is not triggered in the build farm
(e.g. http://hydra.nixos.org/build/3265602).  Ah well.
2012-11-06 13:43:46 +01:00
Shea LevyandEelco Dolstra d0fc615af6 canonicalizePathMetaData: Fall-back to utimes if lutimes fails due to ENOSYS 2012-11-06 11:29:59 +01:00
Eelco Dolstra 4c34d384e6 If hashes do not match, print them in base-32 for SHA-1/SHA-256
Fixes #57.
2012-10-23 18:05:50 +02:00
Eelco Dolstra a28b4445a4 nix-prefetch-url: Improve option handling 2012-10-23 18:04:11 +02:00
Shea LevyandEelco Dolstra 2980d1fba9 prim_toPath: Actually make the string a path 2012-10-23 16:39:35 +02:00
Eelco Dolstra dde6486eab nix-push: Add a flag ‘--manifest-path’ to write the manifest to another directory 2012-10-18 10:36:16 -04:00
Eelco Dolstra c8daeba303 nix-push: Add ‘--link’ flag
If ‘--link’ is given, nix-push will create hard links to the NAR files
in the store, rather than copying them.  This is faster and requires
less disk space.  However, it doesn't work if the store is on a
different file system.
2012-10-17 17:01:23 -04:00
Eelco Dolstra 167e36a5c3 nix-push: Only generate and copy a NAR if it doesn't already exist
This prevents unnecessary and slow rebuilds of NARs that already exist
in the binary cache.
2012-10-17 16:58:05 -04:00
Eelco Dolstra ac238d619c Typo
Reported by Shea.
2012-10-12 10:21:04 -04:00
Eelco Dolstra 600daf972f download-from-binary-cache: Remove duplicate entries in trustedURLs 2012-10-11 14:21:22 -04:00
Eelco Dolstra e345182055 Shorten the names of temporary build directories 2012-10-11 14:03:06 -04:00
Mats Erik AnderssonandEelco Dolstra ecedd9c50c Out-of-tree building of perl modules. 2012-10-10 10:28:33 -04:00
Eelco Dolstra 70f75be199 getDerivation(): Don't always quietly ignore assertion failure
Ignoring assertion failures makes some sense for nix-env -qa, but not
for nix-instantiate/nix-build or hydra-eval-jobs.
2012-10-04 15:22:25 -04:00
Eelco Dolstra ad328bea15 XML writer: flush after newlines
This is useful for hydra-eval-jobs.
2012-10-04 14:07:36 -04:00
Eelco Dolstra bfaa5635de Manual: Don't use a store path that actually exists
http://hydra.nixos.org/build/3124130
2012-10-04 13:37:30 -04:00
Eelco Dolstra 904f50412c nix-store --verify: Continue on errors 2012-10-04 10:20:23 -04:00
Eelco Dolstra 90b8a34f82 Fix regular expression
http://hydra.nixos.org/build/3123177
2012-10-04 09:46:10 -04:00
Eelco Dolstra d1de836938 Fix the tarball build 2012-10-03 21:01:03 -04:00
Eelco Dolstra f766e146f4 Fix the test 2012-10-03 18:01:35 -04:00
Eelco Dolstra e35d6f78dc Rename nix-worker to nix-daemon 2012-10-03 17:59:23 -04:00
Eelco Dolstra 522ecab9b8 Drop support for running nix-worker in "slave" mode
AFAIK nobody uses this, setuid binaries are evil, and there is no good
reason why people can't just run the daemon.
2012-10-03 17:30:45 -04:00
Eelco Dolstra 7586095504 Remove bin2c 2012-10-03 16:59:28 -04:00
Eelco Dolstra a562d544d8 When ‘--help’ is given, just run ‘man’ to show the manual page
I.e. do what git does.  I'm too lazy to keep the builtin help text up
to date :-)

Also add ‘--help’ to various commands that lacked it
(e.g. nix-collect-garbage).
2012-10-03 16:40:09 -04:00
Eelco Dolstra 9c41c66c5b Document ‘--repair’ 2012-10-03 15:53:25 -04:00
Eelco Dolstra 2bbc4a214e nix-env: Support ‘--repair’ flag 2012-10-03 15:35:42 -04:00
Eelco Dolstra 2e90a5a2a7 nix-build: Support ‘--repair’ flag 2012-10-03 15:14:02 -04:00
Eelco Dolstra 0a7084567f Add a ‘--repair’ flag to nix-instantiate
This allows repairing corrupted derivations and other source files.
2012-10-03 15:09:18 -04:00
Eelco Dolstra a807edfae8 Handle repairing paths that are in build-chroot-dirs 2012-10-03 11:20:16 -04:00
Eelco Dolstra a3f205b249 When repairing a derivation, check and repair the entire output closure
If we find a corrupted path in the output closure, we rebuild the
derivation that produced that particular path.
2012-10-03 10:38:09 -04:00
Eelco Dolstra 2001895f3d Add a --repair flag to ‘nix-store -r’ to repair derivation outputs
With this flag, if any valid derivation output is missing or corrupt,
it will be recreated by using a substitute if available, or by
rebuilding the derivation.  The latter may use hash rewriting if
chroots are not available.
2012-10-02 17:13:46 -04:00
Eelco Dolstra cf46f19444 nix-store -r: Get rid of an unnecessary call to buildPaths/ensurePaths 2012-10-02 16:00:09 -04:00
Eelco Dolstra 8e3a7bd712 nix-store --verify: Add an option ‘--repair’ to repair all missing/corrupt paths
Also, return a non-zero exit code if errors remain after
verifying/repairing.
2012-10-02 15:12:56 -04:00
Eelco Dolstra 9958bd6992 Add operation ‘nix-store --repair-path’
This operation allows fixing corrupted or accidentally deleted store
paths by redownloading them using substituters, if available.

Since the corrupted path cannot be replaced atomically, there is a
very small time window (one system call) during which neither the old
(corrupted) nor the new (repaired) contents are available.  So
repairing should be used with some care on critical packages like
Glibc.
2012-10-02 14:08:59 -04:00
Eelco Dolstra e666e1156f Handle octal escapes in /proc/self/mountinfo 2012-09-28 21:39:30 -04:00
Eelco Dolstra f406288cc7 Print a more descriptive error message if setting up the build environment fails 2012-09-28 21:37:02 -04:00
Eelco Dolstra 95c74eae26 Allow dashes in identifiers
In Nixpkgs, the attribute in all-packages.nix corresponding to a
package is usually equal to the package name.  However, this doesn't
work if the package contains a dash, which is fairly common.  The
convention is to replace the dash with an underscore (e.g. "dbus-lib"
becomes "dbus_glib"), but that's annoying.  So now dashes are valid in
variable / attribute names, allowing you to write:

  dbus-glib = callPackage ../development/libraries/dbus-glib { };

and

  buildInputs = [ dbus-glib ];

Since we don't have a negation or subtraction operation in Nix, this
is unambiguous.
2012-09-27 15:49:20 -04:00
Eelco Dolstra f46612be96 Add "on Linux" qualifier 2012-09-25 16:30:37 -04:00
Eelco Dolstra d534f137f0 Make the store writable before creating /nix/store/.links 2012-09-25 16:30:08 -04:00
Eelco Dolstra 0f358ca5b6 Document that Nix requires GNU Make
Fixes #44.
2012-09-25 16:17:30 -04:00
Eelco Dolstra cb6651e878 Update release notes 2012-09-25 16:04:50 -04:00
Eelco Dolstra e464b0247d Merge branch 'readonly-store' 2012-09-25 15:38:00 -04:00
Eelco Dolstra 28bf183d2d Include <sys/types.h> for off_t
Reported by "gio" on IRC.
2012-09-25 13:00:19 -04:00
Eelco Dolstra c1f91570b3 Style fix 2012-09-21 15:02:33 -04:00
Eelco Dolstra 20582e9ae3 Support xz compression in the download-using-manifests substituter 2012-09-19 17:33:42 -04:00
Eelco Dolstra b9c2b4d5b4 Remove setting of the immutable bit
Using the immutable bit is problematic, especially in conjunction with
store optimisation.  For instance, if the garbage collector deletes a
file, it has to clear its immutable bit, but if the file has
additional hard links, we can't set the bit afterwards because we
don't know the remaining paths.

So now that we support having the entire Nix store as a read-only
mount, we may as well drop the immutable bit.  Unfortunately, we have
to keep the code to clear the immutable bit for backwards
compatibility.
2012-09-19 16:17:54 -04:00
Eelco Dolstra b9124a5c33 Support having /nix/store as a read-only bind mount
It turns out that the immutable bit doesn't work all that well.  A
better way is to make the entire Nix store a read-only bind mount,
i.e. by doing

  $ mount --bind /nix/store /nix/store
  $ mount -o remount,ro,bind /nix/store

(This would typically done in an early boot script, before anything
from /nix/store is used.)

Since Nix needs to be able to write to the Nix store, it now detects
if /nix/store is a read-only bind mount and then makes it writable in
a private mount namespace.
2012-09-19 15:45:29 -04:00
Eelco Dolstra 76e88871b2 Templatise tokenizeString() 2012-09-19 15:43:23 -04:00
Eelco Dolstra 00092b2d35 Keep build directory if not all expected outputs were produced
Fixes issue #123 in Nixpkgs.
2012-09-18 10:11:42 -04:00
Eelco Dolstra b674665765 Test whether GNU tar understands --warning=no-timestamp
http://hydra.nixos.org/build/3031618
2012-09-14 10:18:27 -04:00
Eelco Dolstra 09eb230900 Fix test
http://hydra.nixos.org/build/3031382
2012-09-14 09:39:54 -04:00
Eelco Dolstra 983220bcd4 nix-collect-garbage: Support --dry-run 2012-09-13 18:09:20 -04:00
Eelco Dolstra 9fd9dedf12 nix-env --delete-generations: Support --dry-run flag
Fixes #43.
2012-09-13 18:05:04 -04:00
Eelco Dolstra 1bda006b74 Add a test for nix-profile.sh 2012-09-13 17:58:14 -04:00
Eelco Dolstra aac14222f5 nix-profile.sh: Revert to single-user version
Commit 6a214f3e06 copied most of the Nix
shell initialisation code from NixOS to nix-profile.sh; however, that
code assumes a multi-user install and is Linux-specific (e.g. it calls
the "stat" command).  So go back to the simple single-user version.

Fixes #49.
2012-09-13 17:48:19 -04:00
Eelco Dolstra 54fe8e0773 Remove double Fedora release suffix 2012-09-13 17:23:12 -04:00
Eelco Dolstra 47ae3ce2ca Put a time-to-live on negative binary cache lookups
Negative lookups are purged from the DB after a day, at most once per
day.  However, for non-"have" lookups (e.g. all except "nix-env
-qas"), negative lookups are ignored after one hour.  This is to
ensure that you don't have to wait a day for an operation like
"nix-env -i" to start using new binaries in the cache.

Should probably make this configurable.
2012-09-13 16:39:16 -04:00
Eelco Dolstra e03a8a1c92 Doh 2012-09-13 14:58:56 -04:00
Eelco Dolstra 8fbe96cb31 RemoteStore::connectToDaemon(): Set close-on-exec flag
This ensures that "nix-build --run-env" doesn't keep a connection to
the worker open, preventing it from exiting.
2012-09-13 14:46:37 -04:00
Eelco Dolstra e6e495649c Vacuum the SQLite DB after running the garbage collector 2012-09-13 14:33:41 -04:00
Eelco Dolstra 2923b55f9d Delete paths in a component in topologically sorted order
The outputs of a derivation can refer to each other (even though they
cannot have cycles), so they have to be deleted in the right order.

http://hydra.nixos.org/build/3026118
2012-09-13 13:08:27 -04:00
Eelco Dolstra 31114ec3a5 Fix the store optimisation test
http://hydra.nixos.org/build/3026118
2012-09-13 12:54:23 -04:00
Eelco Dolstra c845c0ccad nix-channel: Add option to force fetching of manifests 2012-09-13 12:11:40 -04:00
Eelco Dolstra b14717ab90 Delete manifests in "nix-channel --remove" or when a binary cache is available 2012-09-13 11:35:46 -04:00
Eelco Dolstra 6c4ac29917 Disable auto store optimisation for now
I've seen operations like "nix-store --import" take much longer on one
system.  So default to off until I've investigated this a bit further.
2012-09-13 10:28:20 -04:00
Eelco Dolstra e56f71edaf In startBuilder(), only print the new paths we're building 2012-09-13 10:06:24 -04:00
Eelco Dolstra 4fca02077c Handle gc-keep-outputs and gc-keep-derivations both enabled
If the options gc-keep-outputs and gc-keep-derivations are both
enabled, you can get a cycle in the liveness graph.  There was a hack
to handle this, but it didn't work with multiple-output derivations,
causing the garbage collector to fail with errors like ‘error: cannot
delete path `...' because it is in use by `...'’.  The garbage
collector now handles strongly connected components in the liveness
graph as a unit and decides whether to delete all or none of the paths
in an SCC.
2012-09-12 18:49:35 -04:00
Eelco Dolstra 479e9172b3 Build hook: Pass the timeout to the remote builder
Note that this will only work if the client has a very recent Nix
version (post 15e1b2c223), otherwise the
--option flag will just be ignored.

Fixes #50.
2012-09-12 12:18:14 -04:00
Eelco Dolstra 4ba47205c6 Fix test failure on Darwin
Apparently our DBD::SQLite links against /usr/lib/libsqlite3.dylib,
which is an old version that doesn't respect foreign key constraints.
So manifests/cache.sqlite doesn't get updated properly when a manifest
disappears.  We should fix our DBD::SQLite, but in the meantime this
will fix the test.

http://hydra.nixos.org/build/3017959
2012-09-12 11:29:10 -04:00
Eelco Dolstra 6762424e24 Compatibility fix for WWW::Curl < 4.14
Older versions of WWW::Curl don't support scalar references for
CURLOPT_WRITEDATA directly.

http://hydra.nixos.org/build/3017188
2012-09-12 10:41:17 -04:00
Eelco Dolstra d4c3b6327f Don't put results symlinks in the tests directory 2012-09-11 19:14:15 -04:00
Eelco Dolstra 1f7901ec3b Test hash rewriting 2012-09-11 19:10:11 -04:00
Eelco Dolstra 5e2ffd0b8a Fix "non-zero padding" error
Probably it's not a good idea to pass a temporary object to
StringSource.
2012-09-11 19:09:01 -04:00
Eelco Dolstra 8cf672091e Support building a derivation if some outputs are already valid (non-chroot case)
This uses scary hash rewriting.

Fixes #21.
2012-09-11 18:39:22 -04:00
Eelco Dolstra 9dbda2b3fe Remove debug line 2012-09-11 17:05:35 -04:00
Eelco Dolstra a2785b7391 Support building a derivation if some outputs are already valid
This handles the chroot and build hook cases, which are easy.
Supporting the non-chroot-build case will require more work (hash
rewriting!).

Issue #21.
2012-09-11 16:59:59 -04:00
Eelco Dolstra 295027f533 Include config.h before any other header
"config.h" must be included first, because otherwise the compiler
might not see the right value of _FILE_OFFSET_BITS.  We've had this
before; see 705868a8a9.  In this case,
GCC would compute a different address for ‘settings.useSubstitutes’ in
misc.cc because of the off_t in ‘settings’.

Reverts 3854fc9b42.

http://hydra.nixos.org/build/3016700
2012-09-11 14:45:42 -04:00
Eelco Dolstra d3004c78d9 Don't use -warning=no-timestamp unless we have GNU tar
http://hydra.nixos.org/build/2998485
2012-09-11 13:07:22 -04:00
Shea LevyandEelco Dolstra 360056e174 Document importing from a directory in the import documentation 2012-08-29 18:07:51 -04:00
Eelco Dolstra f7b650d234 Make "nix-instantiate -" interruptible 2012-08-28 11:47:26 -04:00
Eelco Dolstra 15e1b2c223 Merge branch 'no-manifests' 2012-08-27 14:34:51 -04:00
Eelco Dolstra 9e2fc6951c Disable the binary cache substituter by default for now 2012-08-27 14:20:14 -04:00
Eelco Dolstra cfd968dd94 Fix stupid type error in calling std::max 2012-08-27 14:17:13 -04:00
Eelco Dolstra f3077fd88d Add libwww-curl-perl to the Debian/Ubuntu images 2012-08-27 13:45:53 -04:00
Eelco Dolstra cc8641815b Add WWW::Curl to the RPM dependencies 2012-08-27 11:47:49 -04:00
Eelco Dolstra 2688fb73f1 Add perl-WWW-Curl to the RPM image 2012-08-27 11:47:04 -04:00
Eelco Dolstra 8207359227 Whitespace 2012-08-27 11:28:48 -04:00
Eelco Dolstra 8b8fe6139e Drop dependency on List::MoreUtils 2012-08-27 11:28:34 -04:00
Eelco Dolstra babe54bf97 Add missing file 2012-08-27 11:11:30 -04:00
Eelco Dolstra e94806d030 Merge branch 'master' into no-manifests 2012-08-27 11:09:07 -04:00
Eelco Dolstra a9e6752bbd Include the output name in the GC root link
Output names are now appended to resulting GC symlinks, e.g. by
nix-build.  For backwards compatibility, if the output is named "out",
nothing is appended.  E.g. doing "nix-build -A foo" on a derivation
that produces outputs "out", "bin" and "dev" will produce symlinks
"./result", "./result-bin" and "./result-dev", respectively.
2012-08-24 16:58:11 -04:00
Eelco Dolstra 4aa1e5c554 Receive reserveSpace before calling startWork()
Otherwise we can get a SIGPOLL.  Reported by Ludovic.
2012-08-22 10:58:24 -04:00
Eelco Dolstra d950cfe70b Check if MS_PRIVATE is defined
http://hydra.nixos.org/build/2955671
2012-08-20 15:55:49 -04:00
Eelco Dolstra 56e30e161c In the chroot, make all mounted filesystems private
This is required on systemd, which mounts filesystems as "shared"
subtrees.  Changes to shared trees in a private mount namespace are
propagated to the outside world, which is bad.
2012-08-20 15:27:30 -04:00
Eelco Dolstra f0eab0636b Don't bind-mount /proc since we mount our own 2012-08-20 15:27:00 -04:00
Eelco Dolstra 862c4c5ec5 Fix 1755 permission on temporary directories left behind by ‘-K’ 2012-08-19 16:32:42 -04:00
Eelco Dolstra 767101824a Avoid concatenating lists of one string 2012-08-13 15:10:29 -04:00
Eelco Dolstra e5c589d271 Don't allocate empty lists
This saves about 4 MB when evaluating a NixOS system configuration.
2012-08-13 15:02:09 -04:00
Eelco Dolstra 3e89ef597c Optimise concatenating a list to an empty list
More precisely, in concatLists, if all lists except one are empty,
then just return the non-empty list.  This reduces the number of list
element allocations by 32% when evaluating a NixOS system
configuration.
2012-08-13 14:58:54 -04:00
Eelco Dolstra 9c2d63084b Add a primop ‘elemAt’ to get an element from a list 2012-08-13 13:46:42 -04:00
Eelco Dolstra 198d0338be Add a primop ‘concatLists’
This can serve as a generic efficient list builder.  For instance, the
function ‘catAttrs’ in Nixpkgs can be rewritten from

  attr: l: fold (s: l: if hasAttr attr s then [(getAttr attr s)] ++ l else l) [] l

to

  attr: l: builtins.concatLists (map (s: if hasAttr attr s then [(getAttr attr s)] else []) l)

Statistics before:

  time elapsed: 1.08683
  size of a value: 24
  environments allocated: 1384376 (35809568 bytes)
  list elements: 6946783 (55574264 bytes)
  list concatenations: 37434
  values allocated: 1760440 (42250560 bytes)
  attribute sets allocated: 392040
  right-biased unions: 186334
  values copied in right-biased unions: 591137
  symbols in symbol table: 18273
  number of thunks: 1297673
  number of thunks avoided: 1380759
  number of attr lookups: 430802
  number of primop calls: 628912
  number of function calls: 1333544

Statistics after (including new catAttrs):

  time elapsed: 0.959854
  size of a value: 24
  environments allocated: 1010198 (26829296 bytes)
  list elements: 1984878 (15879024 bytes)
  list concatenations: 30488
  values allocated: 1589760 (38154240 bytes)
  attribute sets allocated: 392040
  right-biased unions: 186334
  values copied in right-biased unions: 591137
  symbols in symbol table: 18274
  number of thunks: 1040925
  number of thunks avoided: 1038428
  number of attr lookups: 438419
  number of primop calls: 474844
  number of function calls: 959366
2012-08-13 01:53:10 -04:00
Eelco Dolstra b9e5b908ed Provide an efficient implementation of ‘elem’
The one in Nixpkgs is O(n^2), this one is O(n).  Big reduction in the
number of list allocations.

Statistics before (on a NixOS system config):

  time elapsed: 1.17982
  size of a value: 24
  environments allocated: 1543334 (39624560 bytes)
  list elements: 9612638 (76901104 bytes)
  list concatenations: 37434
  values allocated: 1854933 (44518392 bytes)
  attribute sets allocated: 392040
  right-biased unions: 186334
  values copied in right-biased unions: 591137
  symbols in symbol table: 18272
  number of thunks: 1392467
  number of thunks avoided: 1507311
  number of attr lookups: 430801
  number of primop calls: 691600
  number of function calls: 1492502

Statistics after:

  time elapsed: 1.08683
  size of a value: 24
  environments allocated: 1384376 (35809568 bytes)
  list elements: 6946783 (55574264 bytes)
  list concatenations: 37434
  values allocated: 1760440 (42250560 bytes)
  attribute sets allocated: 392040
  right-biased unions: 186334
  values copied in right-biased unions: 591137
  symbols in symbol table: 18273
  number of thunks: 1297673
  number of thunks avoided: 1380759
  number of attr lookups: 430802
  number of primop calls: 628912
  number of function calls: 1333544
2012-08-13 01:05:35 -04:00
Eelco Dolstra 4ccd48ce24 Add a "filter" primop
Evaluation of a NixOS configuration spends quite a lot of time in the
"filter" function in Nixpkgs.  As implemented in Nixpkgs, this is a
O(n^2) operation, so it's a good candidate for providing a more
efficient (i.e. primop) implementation.  Using it gives a ~10% speed
increase and a significant reduction in the number of evaluations.

Statistics before (on a NixOS system config):

  time elapsed: 1.3258
  size of a value: 24
  environments allocated: 1980939 (50127080 bytes)
  list elements: 14679308 (117434464 bytes)
  list concatenations: 50828
  values allocated: 2098938 (50374512 bytes)
  attribute sets allocated: 392040
  right-biased unions: 186334
  values copied in right-biased unions: 591137
  symbols in symbol table: 18271
  number of thunks: 1645752
  number of thunks avoided: 1921196
  number of attr lookups: 430798
  number of primop calls: 838807
  number of function calls: 1930107

Statistics after:

  time elapsed: 1.17982
  size of a value: 24
  environments allocated: 1543334 (39624560 bytes)
  list elements: 9612638 (76901104 bytes)
  list concatenations: 37434
  values allocated: 1854933 (44518392 bytes)
  attribute sets allocated: 392040
  right-biased unions: 186334
  values copied in right-biased unions: 591137
  symbols in symbol table: 18272
  number of thunks: 1392467
  number of thunks avoided: 1507311
  number of attr lookups: 430801
  number of primop calls: 691600
  number of function calls: 1492502
2012-08-13 00:28:08 -04:00
Eelco Dolstra 62f72eb9e1 Add some more evaluations stats 2012-08-12 23:41:48 -04:00
Eelco Dolstra e82767910c Add some basic profiling support to the evaluator
Setting the environment variable NIX_COUNT_CALLS to 1 enables some
basic profiling in the evaluator.  It will count calls to functions
and primops as well as evaluations of attributes.

For example, to see where evaluation of a NixOS configuration spends
its time:

$ NIX_SHOW_STATS=1 NIX_COUNT_CALLS=1 ./src/nix-instantiate/nix-instantiate '<nixos>' -A system --readonly-mode
...
calls to 39 primops:
    239532 head
    233962 tail
    191252 hasAttr
...
calls to 1595 functions:
    224157 `/nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs/pkgs/lib/lists.nix:17:19'
    221767 `/nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs/pkgs/lib/lists.nix:17:14'
    221767 `/nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs/pkgs/lib/lists.nix:17:10'
...
evaluations of 7088 attributes:
    167377 undefined position
    132459 `/nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs/pkgs/lib/attrsets.nix:119:41'
     47322 `/nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs/pkgs/lib/attrsets.nix:13:21'
...
2012-08-12 23:29:28 -04:00
Eelco Dolstra 325d1cfebf Don't warn about maximum link count exceeded on 0-byte files 2012-08-07 16:22:54 -04:00
Eelco Dolstra d025142f52 Handle amount of disk space saved by hard linking being negative
Fixes bogus messages like "currently hard linking saves
17592186044416.00 MiB".
2012-08-05 21:45:27 -04:00
Eelco Dolstra b6c989b801 Fix race condition when two processes create a hard link to a file in .links
This is a problem because one process may set the immutable bit before
the second process has created its link.

Addressed random Hydra failures such as:

error: cannot rename `/nix/store/.tmp-link-17397-1804289383' to
`/nix/store/rsvzm574rlfip3830ac7kmaa028bzl6h-nixos-0.1pre-git/upstart-interface-version':
Operation not permitted
2012-08-05 21:41:44 -04:00
Eelco Dolstra 108e14bb18 Fix race condition when two processes create the same link in /nix/store/.links 2012-08-05 18:17:55 -04:00
Eelco Dolstra 6763084ae5 Count bytes freed deleting unused links 2012-08-01 22:43:03 -04:00
Eelco Dolstra 01d56c1eec Drop the block count in the garbage collector 2012-08-01 22:34:46 -04:00
Eelco Dolstra 967d066d8e nix-store --gc: Make ‘--max-freed 0’ do the right thing
That is, delete almost nothing (it will still remove unused links from
/nix/store/.links).
2012-08-01 19:14:58 -04:00
Eelco Dolstra 1df702d347 removeUnusedLinks(): Print stats on disk space saved by hard linking 2012-08-01 19:01:50 -04:00
Eelco Dolstra 9c2decaa19 Merge branch 'master' into no-manifests 2012-08-01 18:03:49 -04:00
Eelco Dolstra 5170c5691a nix-channel: Use binary caches advertised by channels
Channels can now advertise a binary cache by creating a file
<channel-url>/binary-cache-url.  The channel unpacker puts these in
its "binary-caches" subdirectory.  Thus, the URLS of the binary caches
for the channels added by root appear in
/nix/var/nix/profiles/per-user/eelco/channels/binary-caches/*.  The
binary cache substituter reads these and adds them to the list of
binary caches.
2012-08-01 17:56:11 -04:00
Eelco Dolstra 79bba3782c Doh 2012-08-01 17:21:47 -04:00
Eelco Dolstra ca94b38371 nix-env: Ignore manifest.nix when recursing into ~/.nix-defexpr
Channels are implemented using a profile now, and profiles contain a
manifest.nix file.  This should be ignored to prevent bogus packages
from showing up in nix-env.
2012-08-01 17:17:07 -04:00
Eelco Dolstra 46f852cda0 Use a GNU tar flag to shut up warnings about implausibly old timestamp 2012-08-01 16:42:51 -04:00
Eelco Dolstra afa7e01878 Inline unpack-channel.sh 2012-08-01 16:34:17 -04:00
Eelco Dolstra 234ce610e0 Doh 2012-08-01 16:09:47 -04:00
Eelco Dolstra 7b10562370 Make ‘nix-store --optimise’ interruptible 2012-08-01 16:06:49 -04:00
Eelco Dolstra 8a25d787d7 download-from-binary-cache: Remove duplicate URLs 2012-08-01 11:33:15 -04:00
Eelco Dolstra c770a2422a Report substituter errors to clients of the Nix daemon 2012-08-01 11:19:24 -04:00
Eelco Dolstra 4d1b64f118 Allow daemon users to override ‘binary-caches’
For security reasons, daemon users can only specify caches that appear
in the ‘binary-caches’ and ‘trusted-binary-caches’ options in
nix.conf.
2012-07-31 18:56:22 -04:00
Eelco Dolstra eb7849e3a2 Prevent an injection attack in passing untrusted options to substituters 2012-07-31 18:50:32 -04:00
Eelco Dolstra 90d9c58d4d Pass all --option flags to the daemon 2012-07-31 18:19:44 -04:00
Eelco Dolstra 89a8207029 Add an option ‘build-fallback’ (equivalent to the --fallback flag) 2012-07-31 17:56:02 -04:00
Eelco Dolstra 157170059d Manual: Remove reference to non-existent -I option 2012-07-30 22:29:42 -04:00
Eelco Dolstra 97421eb5ec Refactor settings processing
Put all Nix configuration flags in a Settings object.
2012-07-30 19:55:41 -04:00
Eelco Dolstra d50d7a2874 Whitespace 2012-07-30 17:13:25 -04:00
Eelco Dolstra 9cd63d2244 Do some validation of URLs 2012-07-30 17:09:36 -04:00
Eelco Dolstra f3eb29c653 Fix the test 2012-07-30 17:09:13 -04:00
Eelco Dolstra 9de6d10d11 Get rid of $NIX_BINARY_CACHES
You can use ‘--option binary-caches URLs’ instead.
2012-07-30 16:39:31 -04:00
Eelco Dolstra ab42bf1dab nix-install-package: Support binary caches
The .nixpkg file format is extended to optionally include the URL of a
binary cache, which will be used in preference to the manifest URL
(which can be set to a non-existent value).
2012-07-30 16:11:02 -04:00
Eelco Dolstra d059bf48e4 Pass configuration settings to the substituters
Previously substituters could read nix.conf themselves, but this
didn't take --option flags into account.
2012-07-30 16:09:54 -04:00
Eelco Dolstra f9613da180 Remove unused variables 2012-07-30 15:43:37 -04:00
Eelco Dolstra 6183cf2f19 Fix whitespace 2012-07-30 15:42:18 -04:00
Eelco Dolstra f15083c10a Document the --option flag
Pointed out by Daniel Santa Cruz on IRC.
2012-07-29 14:37:40 -04:00
Eelco Dolstra 66a3ac6a56 Allow a binary cache to declare that it doesn't support "nix-env -qas"
Querying all substitutable paths via "nix-env -qas" is potentially
hard on a server, since it involves sending thousands of HEAD
requests.  So a binary cache must now have a meta-info file named
"nix-cache-info" that specifies whether the server wants this.  It
also specifies the store prefix so that we don't send useless queries
to a binary cache for a different store prefix.
2012-07-27 18:16:05 -04:00
Eelco Dolstra 6ecf4f13f6 Use "set -x" in the tests to see where a test fails 2012-07-27 14:33:01 -04:00
Eelco Dolstra e6ab52cdd1 Test "nix-env -qas" with the binary cache substituter 2012-07-27 14:15:03 -04:00
Eelco Dolstra 73acb8b836 Let build.cc verify the expected hash of a substituter's output
Since SubstitutionGoal::finished() in build.cc computes the hash
anyway, we can prevent the inefficiency of computing the hash twice by
letting the substituter tell Nix about the expected hash, which can
then verify it.
2012-07-27 12:16:02 -04:00
Eelco Dolstra fbf59d95f6 Remove more tabs 2012-07-27 10:56:33 -04:00
Eelco Dolstra 3a8f841612 download-using-manifests: Don't use nix-prefetch-url
Instead call curl directly and pipe it into ‘nix-store --restore’.
This saves I/O and prevents creating garbage in the Nix store.
2012-07-27 10:47:36 -04:00
Eelco Dolstra b4ea83249b Remove trailing whitespace / tabs 2012-07-27 09:59:18 -04:00
Eelco Dolstra 7f8e805c8e download-from-binary-cache: Only use the default cache for /nix/store 2012-07-27 09:57:42 -04:00
Eelco Dolstra 67c6f3eded nix-push: Support generating a manifest again
This makes all the tests succeed.  Woohoo!
2012-07-26 18:28:12 -04:00
Eelco Dolstra 50395b71a9 Fix the substituter tests 2012-07-26 17:36:07 -04:00
Eelco Dolstra e3ce54ccee nix-push: Remove the upload feature 2012-07-26 17:13:38 -04:00
Eelco Dolstra 609586a16d Add a test for the binary cache substituter 2012-07-26 17:13:14 -04:00
Eelco Dolstra 7861260a5f Clear NIX_STORE when running the tests 2012-07-26 17:12:42 -04:00
Eelco Dolstra 7892ad15ab download-from-binary-cache: Support file://
The file:// URI schema requires checking for errors in a more general
way.  Also, don't cache file:// lookups.
2012-07-26 17:11:11 -04:00
Eelco Dolstra dbce685e91 Add some .gitignore entries 2012-07-26 17:10:28 -04:00
Eelco Dolstra 8c79100839 Merge branch 'master' into no-manifests 2012-07-26 15:14:33 -04:00
Eelco Dolstra 3a4623afbb Set permissions on temporary build directories to 0700
Fixes #39.
2012-07-26 15:04:40 -04:00
Eelco Dolstra 2605f4f4e6 nix-profile.sh: Don't set NIX_REMOTE on single user installations
Commit 6a214f3e06 reused the NixOS
environment initialisation for nix-profile.sh, but this is
inappropriate on systems that don't have multi-user support enabled.
2012-07-25 17:06:09 -04:00
Eelco Dolstra 477b0fbeca Subscribe to the Nixpkgs rather than NixOS channel 2012-07-25 16:56:56 -04:00
Shea LevyandEelco Dolstra f5954e2d94 prim_import: When importing .drvs, allocate the intermediate attrset on the heap just in case it escapes the stack frame. 2012-07-25 09:30:17 -04:00
Shea LevyandEelco Dolstra 1ef2d5765b Turn tests back on 2012-07-25 09:30:17 -04:00
Shea LevyandEelco Dolstra b1112bbef1 import: If the path is a valid .drv file, parse it and generate a derivation attrset.
The generated attrset has drvPath and outPath with the right string context, type 'derivation', outputName with
the right name, all with a list of outputs, and an attribute for each output.

I see three uses for this (though certainly there may be more):

* Using derivations generated by something besides nix-instantiate (e.g. guix)

* Allowing packages provided by channels to be used in nix expressions. If a channel installed a valid deriver
  for each package it provides into the store, then those could be imported and used as dependencies or installed
  in environment.systemPackages, for example.

* Enable hydra to be consistent in how it treats inputs that are outputs of another build. Right now, if an
  input is passed as an argument to the job, it is passed as a derivation, but if it is accessed via NIX_PATH
  (i.e. through the <> syntax), then it is a path that can be imported. This is problematic because the build
  being depended upon may have been built with non-obvious arguments passed to its jobset file. With this
  feature, hydra can just set the name of that input to the path to its drv file in NIX_PATH
2012-07-25 09:30:17 -04:00
Shea LevyandEelco Dolstra 566a30c007 Disable tests temporarily 2012-07-25 09:30:17 -04:00
Eelco Dolstra e98c029717 Handle platforms that don't support linking to a symlink
E.g. Darwin doesn't allow this.
2012-07-23 18:42:18 -04:00
Eelco Dolstra fd63c8bfcd Unlink the right file 2012-07-23 18:06:37 -04:00
Eelco Dolstra 0f65793f94 Add a test for Nix store optimisation 2012-07-23 17:40:23 -04:00
Eelco Dolstra 680ab6f83d Garbage collect unused links in /nix/store/.links
Incremental optimisation requires creating links in /nix/store/.links
to all files in the store.  However, this means that if we delete a
store path, no files are actually deleted because links in
/nix/store/.links still exists.  So we need to check /nix/store/.links
for files with a link count of 1 and delete them.
2012-07-23 17:14:16 -04:00
Eelco Dolstra 6193105710 Automatically optimise the Nix store when a new path is added
Auto-optimisation is enabled by default.  It can be turned off by
setting auto-optimise-store to false in nix.conf.
2012-07-23 17:14:15 -04:00
Eelco Dolstra 564fb7d9fa optimiseStore(): Use a content-addressed file store in /nix/store/.links
optimiseStore() now creates persistent, content-addressed hard links
in /nix/store/.links.  For instance, if it encounters a file P with
hash H, it will create a hard link

  P' = /nix/store/.link/<H>

to P if P' doesn't already exist; if P' exist, then P is replaced by a
hard link to P'.  This is better than the previous in-memory map,
because it had the tendency to unnecessarily replace hard links with a
hard link to whatever happened to be the first file with a given hash
it encountered.  It also allows on-the-fly, incremental optimisation.
2012-07-23 17:14:15 -04:00
Eelco Dolstra ed59bf7a18 nix-build: Support the ‘-’ argument to build an expression from stdin 2012-07-23 17:11:12 -04:00
Eelco Dolstra 6852289c46 Use lutimes() if available to canonicalise the timestamp of symlinks
Also use utimes() instead of utime() if lutimes() is not available.
2012-07-23 16:52:25 -04:00
Eelco Dolstra 1832ab71db Bump version 2012-07-18 17:17:23 -04:00
Eelco Dolstra 98193bb440 Remove RPM builds that don't evaluate 2012-07-18 16:50:56 -04:00
Eelco Dolstra b7fd2c2822 Use "#pragma once" to prevent repeated header file inclusion 2012-07-18 14:59:03 -04:00
Eelco Dolstra 58337e0e61 Set release date 2012-07-18 11:51:27 -04:00
Eelco Dolstra aa115e22df download-from-binary-cache: Print correct URL 2012-07-18 11:01:17 -04:00
Eelco Dolstra fe241ece29 Merge branch 'master' into no-manifests 2012-07-18 10:47:59 -04:00
Eelco Dolstra ccc52adfb2 Add function queryPathFromHashPart()
To implement binary caches efficiently, Hydra needs to be able to map
the hash part of a store path (e.g. "gbg...zr7") to the full store
path (e.g. "/nix/store/gbg...kzr7-subversion-1.7.5").  (The binary
cache mechanism uses hash parts as a key for looking up store paths to
ensure privacy.)  However, doing a search in the Nix store for
/nix/store/<hash>* is expensive since it requires reading the entire
directory.  queryPathFromHashPart() prevents this by doing a cheap
database lookup.
2012-07-17 18:55:39 -04:00
Eelco Dolstra 220818f758 queryPathInfo(): return hash in base-32 if desired
Cherry-picked from the no-manifests branch.
2012-07-17 16:55:45 -04:00
Eelco Dolstra a6f348599c Print some debug output 2012-07-17 16:19:40 -04:00
Eelco Dolstra 3a9fdf2747 Return an exit code of 100 for cached failed builds
Exit code 100 should be returned for all permanent failures.  This
includes cached failures.

Fixes #34.
2012-07-17 15:55:30 -04:00
Eelco Dolstra 1217204c81 Remove dead code 2012-07-17 14:07:52 -04:00
Eelco Dolstra 51d71ad3d7 Manual: Don't claim we support Cygwin 2012-07-17 11:49:47 -04:00
Eelco Dolstra 6c01fb4d68 Update Nix 1.1 release notes 2012-07-17 10:06:20 -04:00
Eelco Dolstra 53b24f3518 Allow disabling log compression 2012-07-17 09:40:12 -04:00
Eelco Dolstra a7a43adb79 builtins.storePath: resolve symlinks
Needed for Charon/Hydra interaction.
2012-07-12 18:25:01 -04:00
Eelco Dolstra 04559a0d45 Merge branch 'master' of github.com:NixOS/nix into no-manifests 2012-07-11 18:53:27 -04:00
Eelco Dolstra e4d6bcb6cd Update release notes 2012-07-11 18:52:23 -04:00
Eelco Dolstra f2bdc87595 Update the other substituters 2012-07-11 18:52:09 -04:00
Eelco Dolstra 15c15da482 Add some missing --version switches 2012-07-11 18:07:41 -04:00
Eelco Dolstra d287b62b64 Set the User-Agent header to "Nix/<version>" 2012-07-11 18:05:30 -04:00
Eelco Dolstra b74d92755d download-from-binary-cache: Use HEAD requests if possible
In "nix-env -qas", we don't need the substitute info, we just need to
know if it exists.  This can be done using a HTTP HEAD request, which
saves bandwidth.

Note however that curl currently has a bug that prevents it from
reusing HTTP connections if HEAD requests return a 404:

https://sourceforge.net/tracker/?func=detail&aid=3542731&group_id=976&atid=100976

Without the patch attached to the issue, using HEAD is actually quite
a bit slower than GET.
2012-07-11 17:53:20 -04:00
Eelco Dolstra 09a6321aeb Replace hasSubstitutes() with querySubstitutablePaths()
querySubstitutablePaths() takes a set of paths, so this greatly
reduces daemon <-> client latency.
2012-07-11 17:52:18 -04:00
Eelco Dolstra 58ef4d9a95 Add a function queryValidPaths()
queryValidPaths() combines multiple calls to isValidPath() in one.
This matters when using the Nix daemon because it reduces latency.
For instance, on "nix-env -qas \*" it reduces execution time from 5.7s
to 4.7s (which is indistinguishable from the non-daemon case).
2012-07-11 11:08:47 -04:00
Eelco Dolstra 667d5f1936 Rename queryValidPaths() to queryAllValidPaths() 2012-07-11 10:49:04 -04:00
Eelco Dolstra eb3036da87 Implement querySubstitutablePathInfos() in the daemon
Also removed querySubstitutablePathInfo().
2012-07-11 10:43:24 -04:00
Eelco Dolstra 6586414bc7 nix-env: Determine which paths have substitutes in parallel 2012-07-11 10:14:06 -04:00
Eelco Dolstra 5ee8944155 Cleanup 2012-07-11 10:13:16 -04:00
Eelco Dolstra eae802459d Pass --insecure to curl so that https works 2012-07-09 15:49:20 -04:00
Eelco Dolstra 2dd3117c27 Inline fetchurl.sh 2012-07-09 15:48:55 -04:00
Eelco Dolstra 51f9f9924b Add a test for the fetchurl function 2012-07-09 15:41:43 -04:00
Shea LevyandEelco Dolstra 035aa11403 Remove obsolete comment 2012-07-09 15:29:49 -04:00
Shea LevyandEelco Dolstra a2865f6b3d corepkgs/fetchurl: Build locally and outside of the chroot 2012-07-09 15:29:49 -04:00
Shea LevyandEelco Dolstra 53f52c2111 corepkgs/fetchurl: the 'system' argument can be optional 2012-07-09 15:29:49 -04:00
Shea LevyandEelco Dolstra 543bf742c9 corepkgs: distribute fetchurl files 2012-07-09 15:29:49 -04:00
Shea LevyandEelco Dolstra f863673a90 corepkgs/fetchurl: Call the shell directly instead of using the shebang 2012-07-09 15:29:49 -04:00
Shea LevyandEelco Dolstra a994eb92a4 corepkgs/fetchurl.sh: Use config.nix's curl 2012-07-09 15:29:49 -04:00
Shea LevyandEelco Dolstra 9d94a28bed The fetchurl builder is now fetchurl.sh 2012-07-09 15:29:49 -04:00
Shea LevyandEelco Dolstra fd2630e1f7 Remove old fetchurl makefile 2012-07-09 15:29:49 -04:00
Shea LevyandEelco Dolstra 6450f5699f Move fetchurl files out of their subdirectory 2012-07-09 15:29:49 -04:00
Shea LevyandEelco Dolstra 40c01ec467 corepkgs/config.nix.in: We'll need curl 2012-07-09 15:29:49 -04:00
Shea LevyandEelco Dolstra c4df747267 Resurrect old corepkgs fetchurl 2012-07-09 15:29:49 -04:00
Eelco Dolstra 27f0c34390 Really fix RPM builds 2012-07-09 13:16:09 -04:00
Eelco Dolstra ae72be1b8b Add WWW::Curl as a dependency 2012-07-09 13:11:37 -04:00
Eelco Dolstra a560124cdf Fix RPM builds
http://hydra.nixos.org/build/2784908
2012-07-09 11:58:12 -04:00
Eelco Dolstra 087dee6e1b Get rid of nix.conf.example
No need to duplicate the nix.conf manpage.
2012-07-09 11:56:55 -04:00
Eelco Dolstra 5755a5c354 Install a nix.conf manpage 2012-07-09 11:33:38 -04:00
Eelco Dolstra 099125435f download-from-binary-cache: add nix.conf options 2012-07-09 10:57:28 -04:00
Eelco Dolstra 98a423b75a prim_import(): prefetch substitute info in parallel using queryMissing() 2012-07-09 09:59:34 -04:00
Eelco Dolstra 425cc612ad build.cc: Don't use hasSubstitute()
Instead make a single call to querySubstitutablePathInfo() per
derivation output.  This is faster and prevents having to implement
the "have" function in the binary cache substituter.
2012-07-08 18:39:24 -04:00
Eelco Dolstra 400e556b34 Cleanup 2012-07-08 18:39:07 -04:00
Eelco Dolstra 11800e6198 download-from-binary-cache: parallelise fetching of NAR info files
Getting substitute information using the binary cache substituter has
non-trivial latency overhead.  A package or NixOS system configuration
can have hundreds of dependencies, and in the worst case (when the
local info cache is empty) we have to do a separate HTTP request for
each of these.  If the ping time to the server is t, getting N info
files will take tN seconds; e.g., with a ping time of 0.1s to
nixos.org, sequentially downloading 1000 info files (a typical NixOS
config) will take at least 100 seconds.

To fix this problem, the binary cache substituter can now perform
requests in parallel.  This required changing the substituter
interface to support a function querySubstitutablePathInfos() that
queries multiple paths at the same time, and rewriting queryMissing()
to take advantage of parallelism.  (Due to local caching,
parallelising queryMissing() is sufficient for most use cases, since
it's almost always called before building a derivation and thus fills
the local info cache.)

For example, parallelism speeds up querying all 1056 paths in a
particular NixOS system configuration from 116s to 2.6s.  It works so
well because the eccentricity of the top-level derivation in the
dependency graph is only 9.  So we only need 10 round-trips (when
using an unlimited number of parallel connections) to get everything.

Currently we do a maximum of 150 parallel connections to the server.
Thus it's important that the binary cache server (e.g. nixos.org) has
a high connection limit.  Alternatively we could use HTTP pipelining,
but WWW::Curl doesn't support it and libcurl has a hard-coded limit of
5 requests per pipeline.
2012-07-06 19:08:20 -04:00
Eelco Dolstra cd94665f38 download-from-binary-cache: use WWW::Curl
Using WWW::Curl rather than running an external curl process for every
NAR info file halves the time it takes to get info thanks to libcurl's
support for persistent HTTP connections.  (We save a roundtrip per
file.)  But the real gain will come from using parallel and/or
pipelined requests.
2012-07-06 00:30:40 -04:00
Eelco Dolstra ae60643c15 download-from-binary-cache: do negative NAR info caching
I.e. if a NAR info file does *not* exist, we record it in the cache DB
so that we don't retry it later.
2012-07-03 18:54:46 -04:00
Eelco Dolstra 89380c03e9 download-from-binary-cache: in queries, preferred cached info 2012-07-03 18:35:39 -04:00
Eelco Dolstra 2a8e5c8b11 download-from-binary-cache: strip trailing / from URLs 2012-07-03 17:47:01 -04:00
Eelco Dolstra d694c599e2 download-from-binary-cache: cache binary cache info in a SQLite DB 2012-07-03 17:29:33 -04:00
Eelco Dolstra 8319b1ab9f download-from-binary-cache: Verify NAR hashes 2012-07-02 18:53:04 -04:00
Eelco Dolstra cf49472d60 nix-push: Always generate base-32 hashes 2012-07-02 18:05:57 -04:00
Eelco Dolstra 6ec7460af1 Binary caches: use a better key
Use the hash part of the store path as a key rather than a hash of the
store path.  This is enough to get the desired privacy property.
2012-07-02 12:42:58 -04:00
Eelco Dolstra 6b1e671ac6 Fix xz compression 2012-07-01 21:57:25 -04:00
Eelco Dolstra 440adfbdd1 Add an environment variable $NIX_BINARY_CACHES specifying URLs of binary caches 2012-07-01 21:55:36 -04:00
Eelco Dolstra f4190c38ba Allow both bzip2 and xz compression 2012-07-01 18:46:38 -04:00
Eelco Dolstra 000132cbd1 nix-push: Don't pollute the current directory with result symlink 2012-06-29 18:30:28 -04:00
Eelco Dolstra 37f7098464 First attempt at the manifest-less substituter 2012-06-29 18:28:52 -04:00
Eelco Dolstra 91b8814f0d Doh 2012-06-29 17:16:00 -04:00
Eelco Dolstra 4911a10a4e Use XZ compression in binary caches
XZ compresses significantly better than bzip2.  Here are the
compression ratios and execution times (using 4 cores in parallel) on
my /var/run/current-system (3.1 GiB):

  bzip2: total compressed size 849.56 MiB, 30.8% [2m08]
  xz -6: total compressed size 641.84 MiB, 23.4% [6m53]
  xz -7: total compressed size 621.82 MiB, 22.6% [7m19]
  xz -8: total compressed size 599.33 MiB, 21.8% [7m18]
  xz -9: total compressed size 588.18 MiB, 21.4% [7m40]

Note that compression takes much longer.  More importantly, however,
decompression is much faster:

  bzip2: 1m47.274s
  xz -6: 0m55.446s
  xz -7: 0m54.119s
  xz -8: 0m52.388s
  xz -9: 0m51.842s

The only downside to using -9 is that decompression takes a fair
amount (~65 MB) of memory.
2012-06-29 15:24:52 -04:00
Eelco Dolstra 49cd7387ad nix-push: create a manifest-less binary cache
Manifests are a huge pain, since users need to run nix-pull directly
or indirectly to obtain them.  They tend to be large and lag behind
the available binaries; also, the downloaded manifests in
/nix/var/nix/manifest need to be in sync with the Nixpkgs sources.  So
we want to get rid of them.

The idea of manifest-free operation works as follows.  Nix is
configured with a set of URIs of binary caches, e.g.

  http://nixos.org/binary-cache

Whenever Nix needs a store path X, it checks each binary cache for the
existence of a file <CACHE-URI>/<SHA-256 hash of X>.narinfo, e.g.

  http://nixos.org/binary-cache/bi1gh9...ia17.narinfo

The .narinfo file contains the necessary information about the store
path that was formerly kept in the manifest, i.e., (relative) URI of
the compressed NAR, references, size, hash, etc.  For example:

  StorePath: /nix/store/xqp4l88cr9bxv01jinkz861mnc9p7qfi-neon-0.29.6
  URL: 1bjxbg52l32wj8ww47sw9f4qz0r8n5vs71l93lcbgk2506v3cpfd.nar.bz2
  CompressedHash: sha256:1bjxbg52l32wj8ww47sw9f4qz0r8n5vs71l93lcbgk2506v3cpfd
  CompressedSize: 202542
  NarHash: sha256:1af26536781e6134ab84201b33408759fc59b36cc5530f57c0663f67b588e15f
  NarSize: 700440
  References: 043zrsanirjh8nbc5vqpjn93hhrf107f-bash-4.2-p24 cj7a81wsm1ijwwpkks3725661h3263p5-glibc-2.13 ...
  Deriver: 4idz1bgi58h3pazxr3akrw4fsr6zrf3r-neon-0.29.6.drv
  System: x86_64-linux

Nix then knows that it needs to download

  http://nixos.org/binary-cache/1bjxbg52l32wj8ww47sw9f4qz0r8n5vs71l93lcbgk2506v3cpfd.nar.bz2

to substitute the store path.

Note that the store directory is omitted from the References and
Deriver fields to save space, and that the URL can be relative to the
binary cache prefix.

This patch just makes nix-push create binary caches in this format.
The next step is to make a substituter that supports them.
2012-06-28 17:19:32 -04:00
Eelco Dolstra 1aba0bf0fa nix-store -r: do substitutions in parallel
I.e. when multiple non-derivation arguments are passed to ‘nix-store
-r’ to be substituted, do them in parallel.
2012-06-27 16:58:15 -04:00
Eelco Dolstra 42f5a2fc29 Mount an empty /dev/shm tmpfs in the chroot
This ensures that whatever the builder writes in /dev/shm is
automatically cleaned up.
2012-06-27 09:52:27 -04:00
Eelco Dolstra 3ee208516f Check the return code of the clone() call 2012-06-27 09:52:06 -04:00
Eelco Dolstra 1db38ae81b When using chroots, use a private PID namespace
In a private PID namespace, processes have PIDs that are separate from
the rest of the system.  The initial child gets PID 1.  Processes in
the chroot cannot see processes outside of the chroot.  This improves
isolation between builds.  However, processes on the outside can see
processes in the chroot and send signals to them (if they have
appropriate rights).

Since the builder gets PID 1, it serves as the reaper for zombies in
the chroot.  This might turn out to be a problem.  In that case we'll
need to have a small PID 1 process that sits in a loop calling wait().
2012-06-25 15:45:16 -04:00
Eelco Dolstra 5489086456 Use a private UTS namespace to provide a deterministic host/domain name to builders
In chroot builds, set the host name to "localhost" and the domain name
to "(none)" (the latter being the kernel's default).  This improves
determinism a bit further.

P.S. I have to idea what UTS stands for.
2012-06-25 14:12:17 -04:00
Eelco Dolstra 8da6772ed4 Update release notes 2012-06-23 14:59:13 -04:00
Eelco Dolstra 723a68c826 Improve error message 2012-06-23 00:57:14 -04:00
Eelco Dolstra 7ffa523fd1 In chroot builds, use a private SysV IPC namespace
This improves isolation a bit further, and it's just one extra flag in
the unshare() call.

P.S. It would be very cool to use CLONE_NEWPID (to put the builder in
a private PID namespace) as well, but that's slightly more risky since
having a builder start as PID 1 may cause problems.
2012-06-23 00:51:40 -04:00
Eelco Dolstra df716c98d2 In chroot builds, use a private network namespace
On Linux it's possible to run a process in its own network namespace,
meaning that it gets its own set of network interfaces, disjunct from
the rest of the system.  We use this to completely remove network
access to chroot builds, except that they get a private loopback
interface.  This means that:

- Builders cannot connect to the outside network or to other processes
  on the same machine, except processes within the same build.

- Vice versa, other processes cannot connect to processes in a chroot
  build, and open ports/connections do not show up in "netstat".

- If two concurrent builders try to listen on the same port (e.g. as
  part of a test), they no longer conflict with each other.

This was inspired by the "PrivateNetwork" flag in systemd.
2012-06-23 00:28:35 -04:00
Eelco Dolstra 2f3f413e91 Support socket-based, on-demand activation of the Nix daemon with systemd
Systemd can start the Nix daemon on demand when the Nix daemon socket
is first accessed.  This is signalled through the LISTEN_FDS
environment variable, so all we need to do is check for that and then
use file descriptor 3 as the listen socket instead of creating one
ourselves.
2012-06-18 23:01:46 -04:00
Eelco Dolstra 02fb6323e0 Add Emacs to the disk image 2012-05-31 09:50:58 -04:00
Michel Alexandre SalimandEelco Dolstra 221626e715 fixes to nix-worker systemd service descriptor: - remove commented-out lines - register the file for distribution in Makefile.am 2012-05-31 08:59:36 -04:00
Michel Alexandre SalimandEelco Dolstra a7ed1f67ee On systems with SystemD, install the service descriptor for nix-worker, and enable and start it 2012-05-31 08:59:36 -04:00
Michel Alexandre SalimandEelco Dolstra 8922346305 Major spec update: - Fix license field - Split into subpackages - Update build dependencies - Configure users and groups for multi-user mode - Fix installation location of Perl modules 2012-05-31 08:59:36 -04:00
Michel Alexandre SalimandEelco Dolstra 6a214f3e06 Update nix profile: - incorporate NixOS's configuration so that nix is usable by normal users - install as a data file, not a program file 2012-05-31 08:59:36 -04:00
Michel Alexandre SalimandEelco Dolstra d0308073c3 - only enable deprecated spec sections when building on systems with older RPM versions - move tests to dedicated %check section - use standard build macros 2012-05-31 08:59:36 -04:00
Michel Alexandre SalimandEelco Dolstra e545a7f9a8 - replace %define with %global 2012-05-31 08:59:36 -04:00
Eelco Dolstra f5398d374b Compress build logs on the fly using bzip2 2012-05-30 10:12:29 -04:00
Eelco Dolstra 881beb170d "nix-store -l": support compressed logs 2012-05-30 00:00:02 -04:00
Eelco Dolstra 4bc4da331a Reserve some disk space for the garbage collector
We can't open a SQLite database if the disk is full.  Since this
prevents the garbage collector from running when it's most needed, we
reserve some dummy space that we can free just before doing a garbage
collection.  This actually revives some old code from the Berkeley DB
days.

Fixes #27.
2012-05-29 22:59:12 -04:00
Eelco Dolstra 2c26985835 Add option ‘build-keep-log’ to enable/disable writing of build logs
Fixes #26.
2012-05-29 16:42:05 -04:00
Eelco Dolstra 8058dab26e Clean up the installation section; document the generic binary tarballs 2012-05-24 12:04:07 -04:00
Eelco Dolstra 0301525e6c Fix owner/group in tar invocation 2012-05-22 19:40:40 -04:00
Eelco Dolstra 6814b1dfa1 Generate binary tarballs for installing Nix
For several platforms we don't currently have "native" Nix packages
(e.g. Mac OS X and FreeBSD).  This provides the next best thing: a
tarball containing the closure of Nix, plus a simple script
"nix-finish-install" that initialises the Nix database, registers the
paths in the closure as valid, and runs "nix-env -i /path/to/nix" to
initialise the user profile.

The tarball must be unpacked in the root directory.  It creates
/nix/store/... and /usr/bin/nix-finish-install.  Typical installation
is as follows:

  $ cd /
  $ tar xvf /path/to/nix-1.1pre1234_abcdef-x86_64-linux.tar.bz2
  $ nix-finish-install
  (if necessary add ~/.nix-profile/etc/profile.d/nix.sh to the shell
  login scripts)

After this, /usr/bin/nix-finish-install can be deleted, if desired.

The downside to the binary tarball is that it's pretty big (~55 MiB
for x86_64-linux).
2012-05-22 18:36:54 -04:00
Eelco Dolstra 591aab7e21 Remove $FONTCONFIG_FILE hack from nix-profile.sh
It's no longer needed because Nixpkgs' fontconfig uses
/etc/fonts/fonts.conf as a default, just like other distributions.
2012-05-22 14:00:08 -04:00
Eelco Dolstra e071f87dc5 Add an experimental nix-make file
To use it, just do (e.g.) "nix-build build.nix -A nix_env".
2012-05-21 09:43:01 -04:00
Eelco Dolstra cac9eb39fe Bump version number 2012-05-12 00:07:08 -04:00
216 changed files with 9767 additions and 5150 deletions
+6 -15
View File
@@ -35,8 +35,11 @@ Makefile.in
# /doc/manual/
/doc/manual/manual.html
/doc/manual/manual.xmli
/doc/manual/manual.pdf
/doc/manual/manual.is-valid
/doc/manual/*.1
/doc/manual/*.5
/doc/manual/*.8
/doc/manual/images
/doc/manual/version.txt
@@ -60,14 +63,12 @@ Makefile.in
/scripts/GeneratePatches.pm
/scripts/download-using-manifests.pl
/scripts/copy-from-other-stores.pl
/scripts/download-from-binary-cache.pl
/scripts/find-runtime-roots.pl
/scripts/build-remote.pl
/scripts/nix-reduce-build
/scripts/nix-http-export.cgi
# /src/bin2c/
/src/bin2c/bin2c
# /src/bsdiff-4.3/
/src/bsdiff-4.3/bsdiff
/src/bsdiff-4.3/bspatch
@@ -78,26 +79,19 @@ Makefile.in
/src/libexpr/parser-tab.cc
/src/libexpr/parser-tab.hh
/src/libexpr/parser-tab.output
/src/libexpr/nixexpr-ast.hh
/src/libexpr/nixexpr-ast.cc
/src/libexpr/nix.tbl
# /src/libstore/
/src/libstore/derivations-ast.cc
/src/libstore/derivations-ast.hh
/src/libstore/schema.sql.hh
# /src/nix-env/
/src/nix-env/nix-env
/src/nix-env/help.txt.hh
# /src/nix-hash/
/src/nix-hash/nix-hash
/src/nix-hash/help.txt.hh
# /src/nix-instantiate/
/src/nix-instantiate/nix-instantiate
/src/nix-instantiate/help.txt.hh
# /src/nix-log2xml/
/src/nix-log2xml/nix-log2xml
@@ -108,15 +102,12 @@ Makefile.in
# /src/nix-setuid-helper/
/src/nix-setuid-helper/nix-setuid-helper
/src/nix-setuid-helper/help.txt.hh
# /src/nix-store/
/src/nix-store/help.txt.hh
/src/nix-store/nix-store
# /src/nix-worker/
/src/nix-worker/nix-worker
/src/nix-worker/help.txt.hh
# /src/nix-daemon/
/src/nix-daemon/nix-daemon
# /tests/
/tests/test-tmp
+1 -7
View File
@@ -1,6 +1,6 @@
SUBDIRS = src perl scripts corepkgs doc misc tests
EXTRA_DIST = substitute.mk nix.spec nix.spec.in bootstrap.sh \
nix.conf.example NEWS version
NEWS version misc/systemd/nix-daemon.service
pkginclude_HEADERS = config.h
@@ -10,10 +10,6 @@ nix.spec: nix.spec.in
install-data-local: init-state
$(INSTALL) -d $(DESTDIR)$(sysconfdir)/nix
$(INSTALL_DATA) $(srcdir)/nix.conf.example $(DESTDIR)$(sysconfdir)/nix
if ! test -e $(DESTDIR)$(sysconfdir)/nix/nix.conf; then \
$(INSTALL_DATA) $(srcdir)/nix.conf.example $(DESTDIR)$(sysconfdir)/nix/nix.conf; \
fi
$(INSTALL) -d $(DESTDIR)$(docdir)
$(INSTALL_DATA) README $(DESTDIR)$(docdir)/
@@ -31,11 +27,9 @@ init-state:
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/profiles
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/gcroots
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/temproots
ln -sfn $(localstatedir)/nix/profiles $(DESTDIR)$(localstatedir)/nix/gcroots/profiles
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/userpool
-$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(storedir)
$(INSTALL) $(INIT_FLAGS) $(GROUP_WRITABLE) -d $(DESTDIR)$(localstatedir)/nix/manifests
ln -sfn $(localstatedir)/nix/manifests $(DESTDIR)$(localstatedir)/nix/gcroots/manifests
else
+169
View File
@@ -0,0 +1,169 @@
with import <nix-make/lib>;
with pkgs;
rec {
bin2c = link {
objects = [ (compileC { main = ./src/bin2c/bin2c.c; }) ];
programName = "bin2c";
};
bsdiff = link {
objects = [ (compileC { main = ./src/bsdiff-4.3/bsdiff.c; buildInputs = [ pkgs.bzip2 ]; }) ];
programName = "bsdiff";
buildInputs = [ pkgs.bzip2 ];
flags = "-lbz2";
};
bspatch = link {
objects = [ (compileC { main = ./src/bsdiff-4.3/bspatch.c; buildInputs = [ pkgs.bzip2 ]; }) ];
programName = "bspatch";
buildInputs = [ pkgs.bzip2 ];
flags = "-lbz2";
};
libformat = makeLibrary {
objects =
map (fn: compileC {
main = fn;
localIncludePath = [ ./src ];
})
[ ./src/boost/format/format_implementation.cc
./src/boost/format/free_funcs.cc
./src/boost/format/parsing.cc
];
libraryName = "format";
};
libutil = makeLibrary {
objects =
map (fn: compileC {
main = fn;
localIncludePath = [ ./src/libutil ./src ./. ];
buildInputs = [ pkgs.openssl ];
})
[ ./src/libutil/util.cc
./src/libutil/hash.cc
./src/libutil/serialise.cc
./src/libutil/archive.cc
./src/libutil/xml-writer.cc
./src/libutil/immutable.cc
];
libraryName = "util";
};
libstore = makeLibrary {
objects =
map (fn: compileC {
main = fn;
localIncludePath = [ ./src/libstore ./src/libutil ./src ./. ];
buildInputs = [ pkgs.sqlite ];
cFlags = "-DNIX_STORE_DIR=\"/nix/store\" -DNIX_DATA_DIR=\"/home/eelco/Dev/nix/inst/share\" -DNIX_STATE_DIR=\"/nix/var/nix\" -DNIX_LOG_DIR=\"/foo\" -DNIX_CONF_DIR=\"/foo\" -DNIX_LIBEXEC_DIR=\"/foo\" -DNIX_BIN_DIR=\"/home/eelco/Dev/nix/inst/bin\"";
})
[ ./src/libstore/store-api.cc
./src/libstore/local-store.cc
./src/libstore/remote-store.cc
./src/libstore/derivations.cc
./src/libstore/build.cc
./src/libstore/misc.cc
./src/libstore/globals.cc
./src/libstore/references.cc
./src/libstore/pathlocks.cc
./src/libstore/gc.cc
./src/libstore/optimise-store.cc
];
libraryName = "store";
};
libmain = makeLibrary {
objects =
map (fn: compileC {
main = fn;
localIncludePath = [ ./src/libmain ./src/libstore ./src/libutil ./src ./. ];
})
[ ./src/libmain/shared.cc ];
libraryName = "main";
};
nix_hash = link {
objects =
map (fn: compileC {
main = fn;
localIncludePath = [ ./src/nix-hash ./src/libmain ./src/libstore ./src/libutil ./src ./. ];
})
[ ./src/nix-hash/nix-hash.cc
];
libraries = [ libformat libutil libstore libmain ];
buildInputs = [ pkgs.openssl pkgs.sqlite ];
flags = "-lssl -lsqlite3 -lstdc++";
programName = "nix-hash";
};
nix_store = link {
objects =
map (fn: compileC {
main = fn;
localIncludePath = [ ./src/nix-store ./src/libmain ./src/libstore ./src/libutil ./src ./. ];
})
[ ./src/nix-store/nix-store.cc
./src/nix-store/dotgraph.cc
./src/nix-store/xmlgraph.cc
];
libraries = [ libformat libutil libstore libmain ];
buildInputs = [ pkgs.openssl pkgs.sqlite ];
flags = "-lssl -lsqlite3 -lstdc++";
programName = "nix-store";
};
libexpr = makeLibrary {
objects =
map (fn: compileC {
main = fn;
localIncludePath = [ ./src/libexpr ./src/libstore ./src/libutil ./src ./. ];
})
[ ./src/libexpr/nixexpr.cc
./src/libexpr/eval.cc
./src/libexpr/primops.cc
./src/libexpr/lexer-tab.cc
./src/libexpr/parser-tab.cc
./src/libexpr/get-drvs.cc
./src/libexpr/attr-path.cc
./src/libexpr/value-to-xml.cc
./src/libexpr/common-opts.cc
./src/libexpr/names.cc
];
libraryName = "expr";
};
nix_instantiate = link {
objects =
map (fn: compileC {
main = fn;
localIncludePath = [ ./src/nix-instantiate ./src/libexpr ./src/libmain ./src/libstore ./src/libutil ./src ./. ];
})
[ ./src/nix-instantiate/nix-instantiate.cc ];
libraries = [ libformat libutil libstore libmain libexpr ];
buildInputs = [ pkgs.openssl pkgs.sqlite ];
flags = "-lssl -lsqlite3 -lstdc++";
programName = "nix-instantiate";
};
nix_env = link {
objects =
map (fn: compileC {
main = fn;
localIncludePath = [ ./src/nix-env ./src/libexpr ./src/libmain ./src/libstore ./src/libutil ./src ./. ];
})
[ ./src/nix-env/nix-env.cc
./src/nix-env/profiles.cc
./src/nix-env/user-env.cc
];
libraries = [ libformat libutil libstore libmain libexpr ];
buildInputs = [ pkgs.openssl pkgs.sqlite ];
flags = "-lssl -lsqlite3 -lstdc++";
programName = "nix-env";
};
all = [ bsdiff bspatch nix_hash nix_store nix_instantiate nix_env ];
}
+59 -9
View File
@@ -25,12 +25,12 @@ AC_ARG_WITH(system, AC_HELP_STRING([--with-system=SYSTEM],
case "$host_os" in
linux-gnu*)
# For backward compatibility, strip the `-gnu' part.
system="$machine_name-linux";;
# 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'`";;
system="$machine_name-`echo $host_os | "$SED" -e's/@<:@0-9.@:>@*$//g'`";;
esac])
sys_name=$(uname -s | tr 'A-Z ' 'a-z_')
@@ -40,7 +40,7 @@ case $sys_name in
sys_name=cygwin
;;
esac
AC_MSG_RESULT($system)
AC_SUBST(system)
AC_DEFINE_UNQUOTED(SYSTEM, ["$system"], [platform identifier (`cpu-os')])
@@ -68,6 +68,8 @@ if test "$sys_name" = sunos; then
fi
CFLAGS=${CFLAGS:--g -O3 -Wall}
CXXFLAGS=${CXXFLAGS:--g -O3 -Wall}
AC_PROG_CC
AC_PROG_CXX
@@ -106,6 +108,7 @@ AC_LANG_POP(C++)
# Check for chroot support (requires chroot() and bind mounts).
AC_CHECK_FUNCS([chroot])
AC_CHECK_FUNCS([unshare])
AC_CHECK_FUNCS([statvfs])
AC_CHECK_HEADERS([sched.h])
AC_CHECK_HEADERS([sys/param.h])
AC_CHECK_HEADERS([sys/mount.h], [], [],
@@ -115,6 +118,31 @@ AC_CHECK_HEADERS([sys/mount.h], [], [],
])
# Check for vfork.
#AC_FUNC_FORK()
# Check for lutimes, optionally used for changing the mtime of
# symlinks.
AC_CHECK_FUNCS([lutimes])
# Check for sched_setaffinity.
AC_CHECK_FUNCS([sched_setaffinity])
# Check whether the store optimiser can optimise symlinks.
AC_MSG_CHECKING([whether it is possible to create a link to a symlink])
ln -s bla tmp_link
if ln tmp_link tmp_link2 2> /dev/null; then
AC_MSG_RESULT(yes)
AC_DEFINE(CAN_LINK_SYMLINK, 1, [Whether link() works on symlinks.])
else
AC_MSG_RESULT(no)
fi
rm -f tmp_link tmp_link2
# Check for <locale>.
AC_LANG_PUSH(C++)
AC_CHECK_HEADERS([locale])
@@ -161,9 +189,10 @@ NEED_PROG(perl, perl)
NEED_PROG(sed, sed)
NEED_PROG(tar, tar)
NEED_PROG(bzip2, bzip2)
NEED_PROG(gzip, gzip)
NEED_PROG(xz, xz)
AC_PATH_PROG(dot, dot)
AC_PATH_PROG(dblatex, dblatex)
AC_PATH_PROG(gzip, gzip)
AC_PATH_PROG(pv, pv, pv)
@@ -249,7 +278,7 @@ if test "$gc" = yes; then
fi
# Check for the required Perl dependencies (DBI and DBD::SQLite).
# Check for the required Perl dependencies (DBI, DBD::SQLite and WWW::Curl).
perlFlags="-I$perllibdir"
AC_ARG_WITH(dbi, AC_HELP_STRING([--with-dbi=PATH],
@@ -260,13 +289,24 @@ AC_ARG_WITH(dbd-sqlite, AC_HELP_STRING([--with-dbd-sqlite=PATH],
[prefix of the Perl DBD::SQLite library]),
perlFlags="$perlFlags -I$withval")
AC_ARG_WITH(www-curl, AC_HELP_STRING([--with-www-curl=PATH],
[prefix of the Perl WWW::Curl 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_MSG_CHECKING([whether WWW::Curl works])
if ! $perl $perlFlags -e 'use WWW::Curl;' 2>&5; then
AC_MSG_RESULT(no)
AC_MSG_FAILURE([The Perl module WWW::Curl is missing.])
fi
AC_MSG_RESULT(yes)
AC_SUBST(perlFlags)
@@ -310,10 +350,20 @@ eval dynlib_suffix=$shrext_cmds
AC_SUBST(dynlib_suffix)
# Do we have GNU tar?
AC_MSG_CHECKING([if you have a recent GNU tar])
if $tar --version 2> /dev/null | grep -q GNU && tar cvf /dev/null --warning=no-timestamp ./config.log > /dev/null; then
AC_MSG_RESULT(yes)
tarFlags="--warning=no-timestamp"
else
AC_MSG_RESULT(no)
fi
AC_SUBST(tarFlags)
AM_CONFIG_HEADER([config.h])
AC_CONFIG_FILES([Makefile
src/Makefile
src/bin2c/Makefile
src/boost/Makefile
src/boost/format/Makefile
src/libutil/Makefile
@@ -324,7 +374,7 @@ AC_CONFIG_FILES([Makefile
src/libexpr/Makefile
src/nix-instantiate/Makefile
src/nix-env/Makefile
src/nix-worker/Makefile
src/nix-daemon/Makefile
src/nix-setuid-helper/Makefile
src/nix-log2xml/Makefile
src/bsdiff-4.3/Makefile
+2 -1
View File
@@ -1,6 +1,7 @@
all-local: config.nix
files = nar.nix buildenv.nix buildenv.pl unpack-channel.nix unpack-channel.sh derivation.nix
files = nar.nix buildenv.nix buildenv.pl unpack-channel.nix derivation.nix fetchurl.nix \
imported-drv-to-derivation.nix
install-exec-local:
$(INSTALL) -d $(DESTDIR)$(datadir)/nix/corepkgs
+9 -5
View File
@@ -2,18 +2,22 @@ with import <nix/config.nix>;
{ derivations, manifest }:
derivation {
derivation {
name = "user-environment";
system = builtins.currentSystem;
builder = perl;
args = [ "-w" ./buildenv.pl ];
manifest = manifest;
# !!! grmbl, need structured data for passing this in a clean way.
paths = derivations;
active = map (x: if x ? meta && x.meta ? active then x.meta.active else "true") derivations;
priority = map (x: if x ? meta && x.meta ? priority then x.meta.priority else "5") derivations;
derivations =
map (d:
[ (d.meta.active or "true")
(d.meta.priority or 5)
(builtins.length d.outputs)
] ++ map (output: builtins.getAttr output d) d.outputs)
derivations;
# Building user environments remotely just causes huge amounts of
# network traffic, so don't do that.
+26 -27
View File
@@ -36,19 +36,16 @@ sub createLinks {
if ($srcFile =~ /\/propagated-build-inputs$/ ||
$srcFile =~ /\/nix-support$/ ||
$srcFile =~ /\/perllocal.pod$/ ||
$srcFile =~ /\/easy-install.pth$/ ||
$srcFile =~ /\/site.py$/ ||
$srcFile =~ /\/site.pyc$/ ||
$srcFile =~ /\/info\/dir$/ ||
$srcFile =~ /\/log$/)
{
# Do nothing.
}
}
elsif (-d $srcFile) {
lstat $dstFile;
if (-d _) {
createLinks($srcFile, $dstFile, $priority);
}
@@ -56,10 +53,10 @@ sub createLinks {
elsif (-l _) {
my $target = readlink $dstFile or die;
if (!-d $target) {
die "collission between directory `$srcFile' and non-directory `$target'";
die "collision between directory `$srcFile' and non-directory `$target'";
}
unlink $dstFile or die "error unlinking `$dstFile': $!";
mkdir $dstFile, 0755 ||
mkdir $dstFile, 0755 ||
die "error creating directory `$dstFile': $!";
createLinks($target, $dstFile, $priorities{$dstFile});
createLinks($srcFile, $dstFile, $priority);
@@ -78,15 +75,15 @@ sub createLinks {
if (-l $dstFile) {
my $target = readlink $dstFile;
my $prevPriority = $priorities{$dstFile};
die ( "Collission between `$srcFile' and `$target'. "
. "Suggested solution: use `nix-env --set-flag "
die ( "collision between `$srcFile' and `$target'; "
. "use `nix-env --set-flag "
. "priority NUMBER PKGNAME' to change the priority of "
. "one of the conflicting packages.\n" )
. "one of the conflicting packages\n" )
if $prevPriority == $priority;
next if $prevPriority < $priority;
unlink $dstFile or die;
}
symlink($srcFile, $dstFile) ||
die "error creating link `$dstFile': $!";
$priorities{$dstFile} = $priority;
@@ -125,27 +122,29 @@ sub addPkg {
# Convert the stuff we get from the environment back into a coherent
# data type.
my @paths = split ' ', $ENV{"paths"};
my @active = split ' ', $ENV{"active"};
my @priority = split ' ', $ENV{"priority"};
die if scalar @paths != scalar @active;
die if scalar @paths != scalar @priority;
my %pkgs;
for (my $n = 0; $n < scalar @paths; $n++) {
$pkgs{$paths[$n]} =
{ active => $active[$n]
, priority => $priority[$n] };
my @pkgs;
my @derivations = split ' ', $ENV{"derivations"};
while (scalar @derivations) {
my $active = shift @derivations;
my $priority = shift @derivations;
my $outputs = shift @derivations;
for (my $n = 0; $n < $outputs; $n++) {
my $path = shift @derivations;
push @pkgs,
{ path => $path
, active => $active ne "false"
, priority => int($priority) };
}
}
# Symlink to the packages that have been installed explicitly by the
# user.
foreach my $pkg (sort (keys %pkgs)) {
# user. Process in priority order to reduce unnecessary
# symlink/unlink steps.
@pkgs = sort { $a->{priority} <=> $b->{priority} || $a->{path} cmp $b->{path} } @pkgs;
foreach my $pkg (@pkgs) {
#print $pkg, " ", $pkgs{$pkg}->{priority}, "\n";
addPkg($pkg, $pkgs{$pkg}->{priority}) if $pkgs{$pkg}->{active} ne "false";
addPkg($pkg->{path}, $pkg->{priority}) if $pkg->{active};
}
+5 -1
View File
@@ -6,8 +6,12 @@ in {
perl = "@perl@";
shell = "@shell@";
coreutils = "@coreutils@";
bzip2 = fromEnv "NIX_BZIP2" "@bzip2@";
bzip2 = "@bzip2@";
gzip = "@gzip@";
xz = "@xz@";
tar = "@tar@";
tarFlags = "@tarFlags@";
tr = "@tr@";
curl = "@curl@";
nixBinDir = fromEnv "NIX_BIN_DIR" "@bindir@";
}
+3 -3
View File
@@ -6,7 +6,7 @@ drvAttrs @ { outputs ? [ "out" ], ... }:
let
strict = derivationStrict drvAttrs;
commonAttrs = drvAttrs // (builtins.listToAttrs outputsList) //
{ all = map (x: x.value) outputsList;
inherit drvAttrs;
@@ -21,7 +21,7 @@ let
inherit outputName;
};
};
outputsList = map outputToAttrListElement outputs;
in (builtins.head outputsList).value
+37
View File
@@ -0,0 +1,37 @@
with import <nix/config.nix>;
{system ? builtins.currentSystem, url, outputHash ? "", outputHashAlgo ? "", md5 ? "", sha1 ? "", sha256 ? "", executable ? false}:
assert (outputHash != "" && outputHashAlgo != "")
|| md5 != "" || sha1 != "" || sha256 != "";
let
builder = builtins.toFile "fetchurl.sh"
(''
echo "downloading $url into $out"
${curl} --fail --location --max-redirs 20 --insecure "$url" > "$out"
'' + (if executable then "${coreutils}/chmod +x $out" else ""));
in
derivation {
name = baseNameOf (toString url);
builder = shell;
args = [ "-e" builder ];
# New-style output content requirements.
outputHashAlgo = if outputHashAlgo != "" then outputHashAlgo else
if sha256 != "" then "sha256" else if sha1 != "" then "sha1" else "md5";
outputHash = if outputHash != "" then outputHash else
if sha256 != "" then sha256 else if sha1 != "" then sha1 else md5;
outputHashMode = if executable then "recursive" else "flat";
inherit system url;
# No need to double the amount of network traffic
preferLocalBuild = true;
# Don't build in a chroot because Nix's dependencies may not be there.
__noChroot = true;
}
+21
View File
@@ -0,0 +1,21 @@
attrs @ { drvPath, outputs, ... }:
let
commonAttrs = (builtins.listToAttrs outputsList) //
{ all = map (x: x.value) outputsList;
inherit drvPath;
type = "derivation";
};
outputToAttrListElement = outputName:
{ name = outputName;
value = commonAttrs // {
outPath = builtins.getAttr outputName attrs;
inherit outputName;
};
};
outputsList = map outputToAttrListElement outputs;
in (builtins.head outputsList).value
+21 -6
View File
@@ -6,29 +6,44 @@ let
''
export PATH=${nixBinDir}:${coreutils}
if [ $compressionType = xz ]; then
ext=.xz
compressor="| ${xz} -7"
elif [ $compressionType = bzip2 ]; then
ext=.bz2
compressor="| ${bzip2}"
else
ext=
compressor=
fi
echo "packing $storePath..."
mkdir $out
dst=$out/tmp.nar.bz2
dst=$out/tmp.nar$ext
set -o pipefail
nix-store --dump "$storePath" | ${bzip2} > $dst
eval "nix-store --dump \"$storePath\" $compressor > $dst"
nix-hash --flat --type $hashAlgo --base32 $dst > $out/narbz2-hash
hash=$(nix-hash --flat --type $hashAlgo --base32 $dst)
echo -n $hash > $out/nar-compressed-hash
mv $out/tmp.nar.bz2 $out/$(cat $out/narbz2-hash).nar.bz2
mv $dst $out/$hash.nar$ext
'';
in
{ storePath, hashAlgo }:
{ storePath, hashAlgo, compressionType }:
derivation {
name = "nar";
system = builtins.currentSystem;
builder = shell;
args = [ "-e" builder ];
inherit storePath hashAlgo;
inherit storePath hashAlgo compressionType;
# Don't build in a chroot because Nix's dependencies may not be there.
__noChroot = true;
# Remote machines may not have ${nixBinDir} or ${coreutils} in the same prefixes
preferLocalBuild = true;
}
+29 -4
View File
@@ -1,14 +1,39 @@
with import <nix/config.nix>;
{ name, channelName, src }:
let
builder = builtins.toFile "unpack-channel.sh"
''
mkdir $out
cd $out
xzpat="\.xz\$"
gzpat="\.gz\$"
if [[ "$src" =~ $xzpat ]]; then
${xz} -d < $src | ${tar} xf - ${tarFlags}
elif [[ "$src" =~ $gzpat ]]; then
${gzip} -d < $src | ${tar} xf - ${tarFlags}
else
${bzip2} -d < $src | ${tar} xf - ${tarFlags}
fi
mv * $out/$channelName
if [ -n "$binaryCacheURL" ]; then
mkdir $out/binary-caches
echo -n "$binaryCacheURL" > $out/binary-caches/$channelName
fi
'';
in
{ name, channelName, src, binaryCacheURL ? "" }:
derivation {
system = builtins.currentSystem;
builder = shell;
args = [ "-e" ./unpack-channel.sh ];
inherit name channelName src bzip2 tar tr;
args = [ "-e" builder ];
inherit name channelName src binaryCacheURL;
PATH = "${nixBinDir}:${coreutils}";
# No point in doing this remotely.
preferLocalBuild = true;
-4
View File
@@ -1,4 +0,0 @@
mkdir $out
cd $out
$bzip2 -d < $src | $tar xf -
mv * $out/$channelName
Executable
+17
View File
@@ -0,0 +1,17 @@
#! /bin/sh
if [ -e tests/test-tmp ]; then
chmod -R u+w tests/test-tmp
rm -rf tests/test-tmp
fi
s=$(type -p nix-shell)
exec $s release.nix -A tarball --command "
export NIX_REMOTE=daemon
export NIX_PATH='$NIX_PATH'
export NIX_BUILD_SHELL=$(type -p bash)
export c=\$configureFlags
exec $s release.nix -A build.x86_64-linux --exclude tarball --command '
configureFlags+=\" \$c --prefix=$(pwd)/inst --sysconfdir=$(pwd)/inst/etc\"
return
'" \
"$@"
-33
View File
@@ -1,33 +0,0 @@
To produce a `stable' release from the trunk:
-1. Update the release notes; make sure that the release date is
correct.
0. Make sure that the trunk builds in the release supervisor.
1. Branch the trunk, e.g., `svn cp .../trunk
.../branches/0.5-release'.
2. Switch to the branch, e.g., `svn switch .../branches/0.5-release'.
3. In `configure.ac', change `STABLE=0' into `STABLE=1' and commit.
4. In the release supervisor, add a one-time job to build
`.../branches/0.5-release'.
5. Make sure that the release succeeds.
6. Move the branch to a tag, e.g., `svn mv .../branches/0.5-release
.../tags/0.5'.
Note that the branch should not be used for maintenance; it should
be deleted after the release has been created. A maintenance
branch (e.g., `.../branches/0.5') should be created from the
original revision of the trunk (since maintenance releases should
also be tested first; hence, we cannot have `STABLE=1'). The same
procedure can then be followed to produce maintenance releases;
just substitute `.../branches/VERSION' for the trunk.
7. Switch back to the trunk.
8. Bump the version number in `configure.ac' (in AC_INIT).
+4 -2
View File
@@ -16,12 +16,14 @@ dblatex_opts = \
# Note: we use GIF for now, since the PNGs shipped with Docbook aren't
# transparent.
man1_MANS = nix-env.1 nix-build.1 nix-store.1 nix-instantiate.1 \
man1_MANS = nix-env.1 nix-build.1 nix-shell.1 nix-store.1 nix-instantiate.1 \
nix-collect-garbage.1 nix-push.1 nix-pull.1 \
nix-prefetch-url.1 nix-channel.1 \
nix-install-package.1 nix-hash.1 nix-copy-closure.1
man8_MANS = nix-worker.8
man5_MANS = nix.conf.5
man8_MANS = nix-daemon.8
FIGURES = figures/user-environments.png
+167 -98
View File
@@ -12,14 +12,14 @@ such as <function>derivation</function>, are always in scope of every
Nix expression; you can just access them right away. But to prevent
polluting the namespace too much, most built-ins are not in scope.
Instead, you can access them through the <varname>builtins</varname>
built-in value, which is an attribute set that contains all built-in
functions and values. For instance, <function>derivation</function>
is also available as <function>builtins.derivation</function>.</para>
built-in value, which is a set that contains all built-in functions
and values. For instance, <function>derivation</function> is also
available as <function>builtins.derivation</function>.</para>
<variablelist>
<varlistentry><term><function>abort</function> <replaceable>s</replaceable></term>
<listitem><para>Abort Nix expression evaluation, print error
@@ -27,7 +27,7 @@ is also available as <function>builtins.derivation</function>.</para>
</varlistentry>
<varlistentry><term><function>builtins.add</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
@@ -37,25 +37,25 @@ is also available as <function>builtins.derivation</function>.</para>
</varlistentry>
<varlistentry><term><function>builtins.attrNames</function>
<replaceable>attrs</replaceable></term>
<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:
<varlistentry><term><function>builtins.attrNames</function>
<replaceable>set</replaceable></term>
<listitem><para>Return the names of the attributes in the set
<replaceable>set</replaceable> in 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:
<programlisting>
attrValues = attrs: map (name: builtins.getAttr name attrs) (builtins.attrNames attrs);</programlisting>
attrValues = set: map (name: builtins.getAttr name set) (builtins.attrNames set);</programlisting>
</para></listitem>
</varlistentry>
<varlistentry><term><function>baseNameOf</function> <replaceable>s</replaceable></term>
<listitem><para>Return the <emphasis>base name</emphasis> of the
@@ -65,11 +65,11 @@ attrValues = attrs: map (name: builtins.getAttr name attrs) (builtins.attrNames
</varlistentry>
<varlistentry><term><varname>builtins</varname></term>
<listitem><para>The attribute set <varname>builtins</varname>
contains all the built-in functions and values. You can use
<listitem><para>The set <varname>builtins</varname> contains all
the built-in functions and values. You can use
<varname>builtins</varname> to test for the availability of
features in the Nix installation, e.g.,
@@ -82,7 +82,7 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
</varlistentry>
<varlistentry><term><function>builtins.compareVersions</function>
<replaceable>s1</replaceable> <replaceable>s2</replaceable></term>
@@ -99,7 +99,16 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
</varlistentry>
<varlistentry><term><function>builtins.concatLists</function>
<replaceable>lists</replaceable></term>
<listitem><para>Concatenate a list of lists into a single
list.</para></listitem>
</varlistentry>
<varlistentry
xml:id='builtin-currentSystem'><term><varname>builtins.currentSystem</varname></term>
@@ -124,7 +133,7 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
</varlistentry>
-->
<!--
<varlistentry><term><function>dependencyClosure</function></term>
@@ -133,7 +142,7 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
</varlistentry>
-->
<varlistentry><term><function>derivation</function>
<replaceable>attrs</replaceable></term>
@@ -152,7 +161,7 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
</varlistentry>
<varlistentry><term><function>builtins.div</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
@@ -162,7 +171,40 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
</varlistentry>
<varlistentry><term><function>builtins.elem</function>
<replaceable>x</replaceable> <replaceable>xs</replaceable></term>
<listitem><para>Return <literal>true</literal> if a value equal to
<replaceable>x</replaceable> occurs in the list
<replaceable>xs</replaceable>, and <literal>false</literal>
otherwise.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.elemAt</function>
<replaceable>xs</replaceable> <replaceable>n</replaceable></term>
<listitem><para>Return element <replaceable>n</replaceable> from
the list <replaceable>xs</replaceable>. Elements are counted
starting from 0. A fatal error occurs in the index is out of
bounds.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.filter</function>
<replaceable>f</replaceable> <replaceable>xs</replaceable></term>
<listitem><para>Return a list consisting of the elements of
<replaceable>xs</replaceable> for which the function
<replaceable>f</replaceable> returns
<literal>true</literal>.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.filterSource</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
@@ -214,20 +256,20 @@ stdenv.mkDerivation {
</varlistentry>
<varlistentry><term><function>builtins.getAttr</function>
<replaceable>s</replaceable> <replaceable>attrs</replaceable></term>
<replaceable>s</replaceable> <replaceable>set</replaceable></term>
<listitem><para><function>getAttr</function> returns the attribute
named <replaceable>s</replaceable> from the attribute set
<replaceable>attrs</replaceable>. Evaluation aborts if the
named <replaceable>s</replaceable> from
<replaceable>set</replaceable>. Evaluation aborts if the
attribute doesnt exist. This is a dynamic version of the
<literal>.</literal> operator, since <replaceable>s</replaceable>
is an expression rather than an identifier.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.getEnv</function>
<replaceable>s</replaceable></term>
@@ -245,21 +287,33 @@ stdenv.mkDerivation {
</varlistentry>
<varlistentry><term><function>builtins.hasAttr</function>
<replaceable>s</replaceable> <replaceable>attrs</replaceable></term>
<replaceable>s</replaceable> <replaceable>set</replaceable></term>
<listitem><para><function>hasAttr</function> returns
<literal>true</literal> if the attribute set
<replaceable>attrs</replaceable> has an attribute named
<replaceable>s</replaceable>, and <literal>false</literal>
otherwise. This is a dynamic version of the <literal>?</literal>
operator, since <replaceable>s</replaceable> is an expression
rather than an identifier.</para></listitem>
<literal>true</literal> if <replaceable>set</replaceable> has an
attribute named <replaceable>s</replaceable>, and
<literal>false</literal> otherwise. This is a dynamic version of
the <literal>?</literal> operator, since
<replaceable>s</replaceable> is an expression rather than an
identifier.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.hashString</function>
<replaceable>type</replaceable> <replaceable>s</replaceable></term>
<listitem><para>Return a base-16 representation of the
cryptographic hash of string <replaceable>s</replaceable>. The
hash algorithm specified by <replaceable>type</replaceable> must
be one of <literal>"md5"</literal>, <literal>"sha1"</literal> or
<literal>"sha256"</literal>.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.head</function>
<replaceable>list</replaceable></term>
@@ -270,17 +324,19 @@ stdenv.mkDerivation {
</varlistentry>
<varlistentry><term><function>import</function>
<replaceable>path</replaceable></term>
<listitem><para>Load, parse and return the Nix expression in the
file <replaceable>path</replaceable>. Evaluation aborts if the
file doesnt exist or contains an incorrect Nix
expression. <function>import</function> implements Nixs module
system: you can put any Nix expression (such as an attribute set
or a function) in a separate file, and use it from Nix expressions
in other files.</para>
file <replaceable>path</replaceable>. If <replaceable>path
</replaceable> is a directory, the file <filename>default.nix
</filename> in that directory is loaded. Evaluation aborts if the
file doesnt exist or contains an incorrect Nix expression.
<function>import</function> implements Nixs module system: you
can put any Nix expression (such as a set or a function) in a
separate file, and use it from Nix expressions in other
files.</para>
<para>A Nix expression loaded by <function>import</function> must
not contain any <emphasis>free variables</emphasis> (identifiers
@@ -288,7 +344,7 @@ stdenv.mkDerivation {
built-in). Therefore, it cannot refer to variables that are in
scope at the call site. For instance, if you have a calling
expression
<programlisting>
rec {
x = 123;
@@ -323,27 +379,27 @@ x: x + 456</programlisting>
</varlistentry>
<varlistentry><term><function>builtins.intersectAttrs</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<listitem><para>Return an attribute set consisting of the
attributes in the set <replaceable>e2</replaceable> that also
exist in the set <replaceable>e1</replaceable>.</para></listitem>
<listitem><para>Return a set consisting of the attributes in the
set <replaceable>e2</replaceable> that also exist in the set
<replaceable>e1</replaceable>.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.isAttrs</function>
<replaceable>e</replaceable></term>
<listitem><para>Return <literal>true</literal> if
<replaceable>e</replaceable> evaluates to an attribute set, and
<replaceable>e</replaceable> evaluates to a set, and
<literal>false</literal> otherwise.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.isList</function>
<replaceable>e</replaceable></term>
@@ -353,7 +409,7 @@ x: x + 456</programlisting>
</varlistentry>
<varlistentry><term><function>builtins.isFunction</function>
<replaceable>e</replaceable></term>
@@ -363,7 +419,7 @@ x: x + 456</programlisting>
</varlistentry>
<varlistentry><term><function>builtins.isString</function>
<replaceable>e</replaceable></term>
@@ -373,17 +429,17 @@ x: x + 456</programlisting>
</varlistentry>
<varlistentry><term><function>builtins.isInt</function>
<replaceable>e</replaceable></term>
<listitem><para>Return <literal>true</literal> if
<replaceable>e</replaceable> evaluates to a int, and
<replaceable>e</replaceable> evaluates to an int, and
<literal>false</literal> otherwise.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.isBool</function>
<replaceable>e</replaceable></term>
@@ -393,7 +449,7 @@ x: x + 456</programlisting>
</varlistentry>
<varlistentry><term><function>isNull</function>
<replaceable>e</replaceable></term>
@@ -403,12 +459,12 @@ x: x + 456</programlisting>
<warning><para>This function is <emphasis>deprecated</emphasis>;
just write <literal>e == null</literal> instead.</para></warning>
</listitem>
</varlistentry>
<varlistentry><term><function>builtins.length</function>
<replaceable>e</replaceable></term>
@@ -417,7 +473,7 @@ x: x + 456</programlisting>
</varlistentry>
<varlistentry><term><function>builtins.lessThan</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
@@ -430,13 +486,13 @@ x: x + 456</programlisting>
</varlistentry>
<varlistentry><term><function>builtins.listToAttrs</function>
<replaceable>e</replaceable></term>
<listitem><para>Construct an attribute set from a list specifying
the names and values of each attribute. Each element of the list
should be an attribute set consisting of a string-valued attribute
<listitem><para>Construct a set from a list specifying the names
and values of each attribute. Each element of the list should be
a set consisting of a string-valued attribute
<varname>name</varname> specifying the name of the attribute, and
an attribute <varname>value</varname> specifying its value.
Example:
@@ -457,7 +513,7 @@ builtins.listToAttrs
</para></listitem>
</varlistentry>
<varlistentry><term><function>map</function>
<replaceable>f</replaceable> <replaceable>list</replaceable></term>
@@ -470,10 +526,10 @@ map (x: "foo" + x) [ "bar" "bla" "abc" ]</programlisting>
evaluates to <literal>[ "foobar" "foobla" "fooabc"
]</literal>.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.mul</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
@@ -483,7 +539,7 @@ map (x: "foo" + x) [ "bar" "bla" "abc" ]</programlisting>
</varlistentry>
<varlistentry><term><function>builtins.parseDrvName</function>
<replaceable>s</replaceable></term>
@@ -491,14 +547,14 @@ 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 a set <literal>{ name, version }</literal>. Thus,
<literal>builtins.parseDrvName "nix-0.12pre12876"</literal>
returns <literal>{ name = "nix"; version = "0.12pre12876";
}</literal>.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.pathExists</function>
<replaceable>path</replaceable></term>
@@ -531,7 +587,7 @@ in config.someSetting</programlisting>
</varlistentry>
-->
<varlistentry><term><function>builtins.readFile</function>
<replaceable>path</replaceable></term>
@@ -539,15 +595,15 @@ in config.someSetting</programlisting>
<replaceable>path</replaceable> as a string.</para></listitem>
</varlistentry>
<varlistentry><term><function>removeAttrs</function>
<replaceable>attrs</replaceable> <replaceable>list</replaceable></term>
<replaceable>set</replaceable> <replaceable>list</replaceable></term>
<listitem><para>Remove the attributes listed in
<replaceable>list</replaceable> from the attribute set
<replaceable>attrs</replaceable>. The attributes dont have to
exist in <replaceable>attrs</replaceable>. For instance,
<replaceable>list</replaceable> from
<replaceable>set</replaceable>. The attributes dont have to
exist in <replaceable>set</replaceable>. For instance,
<screen>
removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
@@ -556,7 +612,7 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
</varlistentry>
<varlistentry><term><function>builtins.stringLength</function>
<replaceable>e</replaceable></term>
@@ -566,7 +622,7 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
</varlistentry>
<varlistentry><term><function>builtins.sub</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
@@ -576,7 +632,7 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
</varlistentry>
<varlistentry><term><function>builtins.substring</function>
<replaceable>start</replaceable> <replaceable>len</replaceable>
<replaceable>s</replaceable></term>
@@ -594,7 +650,7 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
</varlistentry>
<varlistentry><term><function>builtins.tail</function>
<replaceable>list</replaceable></term>
@@ -604,7 +660,7 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
</varlistentry>
<varlistentry><term><function>throw</function>
<replaceable>s</replaceable></term>
@@ -618,7 +674,7 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
</varlistentry>
<varlistentry
xml:id='builtin-toFile'><term><function>builtins.toFile</function>
<replaceable>name</replaceable> <replaceable>s</replaceable></term>
@@ -636,7 +692,7 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
stdenv.mkDerivation {
name = "hello-2.1.1";
builder = builtins.toFile "builder.sh" "
source $stdenv/setup
@@ -655,7 +711,7 @@ stdenv.mkDerivation {
};
inherit perl;
}</programlisting>
</para>
<para>It is even possible for one file to refer to another, e.g.,
@@ -693,7 +749,7 @@ in foo</programlisting>
</varlistentry>
<varlistentry><term><function>builtins.toPath</function> <replaceable>s</replaceable></term>
<listitem><para>Convert the string value
@@ -706,7 +762,7 @@ in foo</programlisting>
</varlistentry>
<varlistentry><term><function>toString</function> <replaceable>e</replaceable></term>
<listitem><para>Convert the expression
@@ -718,7 +774,7 @@ in foo</programlisting>
</varlistentry>
<varlistentry xml:id='builtin-toXML'><term><function>builtins.toXML</function> <replaceable>e</replaceable></term>
<listitem><para>Return a string containing an XML representation
@@ -736,7 +792,7 @@ in foo</programlisting>
servlet container</link>. A servlet container contains a number
of servlets (<filename>*.war</filename> files) each exported under
a specific URI prefix. So the servlet configuration is a list of
attribute sets containing the <varname>path</varname> and
sets containing the <varname>path</varname> and
<varname>war</varname> of the servlet (<xref
linkend='ex-toxml-co-servlets' />). This kind of information is
difficult to communicate with the normal method of passing
@@ -763,7 +819,7 @@ in foo</programlisting>
<example xml:id='ex-toxml'><title>Passing information to a builder
using <function>toXML</function></title>
<programlisting><![CDATA[
{ stdenv, fetchurl, libxslt, jira, uberwiki }:
@@ -771,7 +827,7 @@ stdenv.mkDerivation (rec {
name = "web-server";
buildInputs = [ libxslt ];
builder = builtins.toFile "builder.sh" "
source $stdenv/setup
mkdir $out
@@ -804,7 +860,7 @@ stdenv.mkDerivation (rec {
<example xml:id='ex-toxml-result'><title>XML representation produced by
<function>toXML</function></title>
<programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
<expr>
<list>
@@ -833,7 +889,7 @@ stdenv.mkDerivation (rec {
</varlistentry>
<varlistentry><term><function>builtins.trace</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
@@ -844,7 +900,20 @@ stdenv.mkDerivation (rec {
</varlistentry>
<varlistentry><term><function>builtins.typeOf</function>
<replaceable>e</replaceable></term>
<listitem><para>Return a string representing the type of the value
<replaceable>e</replaceable>, namely <literal>"int"</literal>,
<literal>"bool"</literal>, <literal>"string"</literal>,
<literal>"path"</literal>, <literal>"null"</literal>,
<literal>"set"</literal>, <literal>"list"</literal> or
<literal>"lambda"</literal>.</para></listitem>
</varlistentry>
</variablelist>
+197 -52
View File
@@ -1,38 +1,50 @@
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xml:id="sec-conf-file">
<refentry xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xml:id="sec-conf-file">
<title>Nix configuration file</title>
<refmeta>
<refentrytitle>nix.conf</refentrytitle>
<manvolnum>5</manvolnum>
<refmiscinfo class="source">Nix</refmiscinfo>
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
</refmeta>
<refnamediv>
<refname>nix.conf</refname>
<refpurpose>Nix configuration file</refpurpose>
</refnamediv>
<refsection><title>Description</title>
<para>A number of persistent settings of Nix are stored in the file
<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
configuration file is shown in <xref linkend="ex-nix-conf" />.</para>
<example xml:id='ex-nix-conf'><title>Nix configuration file</title>
Comments start with a <literal>#</literal> character. Here is an example
configuration file:</para>
<programlisting>
gc-keep-outputs = true # Nice for developers
gc-keep-derivations = true # Idem
env-keep-derivations = false
</programlisting>
</example>
<para>The following variables are currently available:
<para>You can override settings using the <option>--option</option>
flag, e.g. <literal>--option gc-keep-outputs false</literal>.</para>
<para>The following settings are currently available:
<variablelist>
<varlistentry xml:id="conf-gc-keep-outputs"><term><literal>gc-keep-outputs</literal></term>
<listitem><para>If <literal>true</literal>, the garbage collector
will keep the outputs of non-garbage derivations. If
<literal>false</literal> (default), outputs will be deleted unless
they are GC roots themselves (or reachable from other roots).</para>
<para>In general, outputs must be registered as roots separately.
However, even if the output of a derivation is registered as a
root, the collector will still delete store paths that are used
@@ -41,7 +53,7 @@ env-keep-derivations = false
this option to <literal>true</literal>.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-gc-keep-derivations"><term><literal>gc-keep-derivations</literal></term>
@@ -59,7 +71,7 @@ env-keep-derivations = false
</varlistentry>
<varlistentry><term><literal>env-keep-derivations</literal></term>
<listitem><para>If <literal>false</literal> (default), derivations
@@ -83,14 +95,14 @@ env-keep-derivations = false
</varlistentry>
<varlistentry xml:id="conf-build-max-jobs"><term><literal>build-max-jobs</literal></term>
<listitem><para>This option defines the maximum number of jobs
that Nix will try to build in parallel. The default is
<literal>1</literal>. You should generally set it to the number
of CPUs in your system (e.g., <literal>2</literal> on a Athlon 64
X2). It can be overriden using the <option
of CPUs in your system (e.g., <literal>2</literal> on an Athlon 64
X2). It can be overridden using the <option
linkend='opt-max-jobs'>--max-jobs</option> (<option>-j</option>)
command line switch.</para></listitem>
@@ -107,7 +119,7 @@ env-keep-derivations = false
<varname>enableParallelBuilding</varname> is set to
<literal>true</literal>, the builder passes the
<option>-j<replaceable>N</replaceable></option> flag to GNU Make.
It can be overriden using the <option
It can be overridden using the <option
linkend='opt-cores'>--cores</option> command line switch and
defaults to <literal>1</literal>. The value <literal>0</literal>
means that the builder should use all available CPU cores in the
@@ -122,10 +134,10 @@ env-keep-derivations = false
<para>This option defines the maximum number of seconds that a
builder can go without producing any data on standard output or
standard error. This is useful (for instance in a automated
standard error. This is useful (for instance in an automated
build system) to catch builds that are stuck in an infinite
loop, or to catch remote builds that are hanging due to network
problems. It can be overriden using the <option
problems. It can be overridden using the <option
linkend="opt-max-silent-time">--max-silent-time</option> command
line switch.</para>
@@ -136,15 +148,16 @@ 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
builder can run. This is useful (for instance in an automated
build system) to catch builds that are stuck in an infinite loop
but keep writing to their standard output or standard error. It
can be overriden using the <option
can be overridden using the <option
linkend="opt-timeout">--timeout</option> command line
switch.</para>
@@ -156,6 +169,20 @@ env-keep-derivations = false
</varlistentry>
<varlistentry xml:id="conf-build-max-log-size"><term><literal>build-max-log-size</literal></term>
<listitem>
<para>This option defines the maximum number of bytes that a
builder can write to its stdout/stderr. If the builder exceeds
this limit, its killed. A value of <literal>0</literal> (the
default) means that there is no limit.</para>
</listitem>
</varlistentry>
<varlistentry xml:id="conf-build-users-group"><term><literal>build-users-group</literal></term>
<listitem><para>This options specifies the Unix group containing
@@ -189,10 +216,8 @@ env-keep-derivations = false
under the uid of the Nix process (that is, the uid of the caller
if <envar>NIX_REMOTE</envar> is empty, the uid under which the Nix
daemon runs if <envar>NIX_REMOTE</envar> is
<literal>daemon</literal>, or the uid that owns the setuid
<command>nix-worker</command> program if <envar>NIX_REMOTE</envar>
is <literal>slave</literal>). Obviously, this should not be used
in multi-user settings with untrusted users.</para>
<literal>daemon</literal>). Obviously, this should not be used in
multi-user settings with untrusted users.</para>
</listitem>
@@ -224,7 +249,27 @@ env-keep-derivations = false
</varlistentry>
<varlistentry xml:id="conf-build-chroot-dirs"><term><literal>build-chroot-dirs</literal></term>
<listitem><para>When builds are performed in a chroot environment,
Nix will mount some directories from the normal file system
hierarchy inside the chroot. These are the Nix store, the
temporary build directory (usually
<filename>/tmp/nix-build-<replaceable>drvname</replaceable>-<replaceable>number</replaceable></filename>),
the <literal>/proc</literal> filesystem, and the directories
listed here. The default is <literal>/dev /dev/pts</literal>,
since these contain files needed by many builds (such as
<filename>/dev/null</filename>). You can use the syntax
<literal><replaceable>target</replaceable>=<replaceable>source</replaceable></literal>
to mount a path in a different location in the chroot; for
instance, <literal>/bin=/nix-bin</literal> will mount the
directory <literal>/nix-bin</literal> as <literal>/bin</literal>
inside the chroot.</para></listitem>
</varlistentry>
<varlistentry><term><literal>build-use-substitutes</literal></term>
<listitem><para>If set to <literal>true</literal> (default), Nix
@@ -233,34 +278,17 @@ env-keep-derivations = false
</varlistentry>
<varlistentry xml:id="conf-build-chroot-dirs"><term><literal>build-chroot-dirs</literal></term>
<listitem><para>When builds are performed in a chroot environment,
Nix will mount (using <command>mount --bind</command> on Linux)
some directories from the normal file system hierarchy inside the
chroot. These are the Nix store, the temporary build directory
(usually
<filename>/tmp/nix-<replaceable>pid</replaceable>-<replaceable>number</replaceable></filename>)
and the directories listed here. The default is <literal>dev
/proc</literal>. Files in <filename>/dev</filename> (such as
<filename>/dev/null</filename>) are needed by many builds, and
some files in <filename>/proc</filename> may also be needed
occasionally.</para>
<varlistentry><term><literal>build-fallback</literal></term>
<para>The value used on NixOS is
<programlisting>
build-use-chroot = /dev /proc /bin</programlisting>
to make the <filename>/bin/sh</filename> symlink available (which
is still needed by many builders).</para>
</listitem>
<listitem><para>If set to <literal>true</literal>, Nix will fall
back to building from source if a binary substitute fails. This
is equivalent to the <option>--fallback</option> flag. The
default is <literal>false</literal>.</para></listitem>
</varlistentry>
<varlistentry><term><literal>build-cache-failures</literal></term>
<listitem><para>If set to <literal>true</literal>, Nix will
@@ -276,6 +304,108 @@ build-use-chroot = /dev /proc /bin</programlisting>
</varlistentry>
<varlistentry><term><literal>build-keep-log</literal></term>
<listitem><para>If set to <literal>true</literal> (the default),
Nix will write the build log of a derivation (i.e. the standard
output and error of its builder) to the directory
<filename>/nix/var/log/nix/drvs</filename>. The build log can be
retrieved using the command <command>nix-store -l
<replaceable>path</replaceable></command>.</para></listitem>
</varlistentry>
<varlistentry><term><literal>build-compress-log</literal></term>
<listitem><para>If set to <literal>true</literal> (the default),
build logs written to <filename>/nix/var/log/nix/drvs</filename>
will be compressed on the fly using bzip2. Otherwise, they will
not be compressed.</para></listitem>
</varlistentry>
<varlistentry><term><literal>use-binary-caches</literal></term>
<listitem><para>If set to <literal>true</literal> (the default),
Nix will check the binary caches specified by
<option>binary-caches</option> and related options to obtain
binary substitutes.</para></listitem>
</varlistentry>
<varlistentry><term><literal>binary-caches</literal></term>
<listitem><para>A list of URLs of binary caches, separated by
whitespace. The default is
<literal>http://cache.nixos.org</literal>.</para></listitem>
</varlistentry>
<varlistentry><term><literal>binary-caches-files</literal></term>
<listitem><para>A list of names of files that will be read to
obtain additional binary cache URLs. The default is
<literal>/nix/var/nix/profiles/per-user/<replaceable>username</replaceable>/channels/binary-caches/*</literal>.
Note that when youre using the Nix daemon,
<replaceable>username</replaceable> is always equal to
<literal>root</literal>, so Nix will only use the binary caches
provided by the channels installed by root. Do not set this
option to read files created by untrusted users!</para></listitem>
</varlistentry>
<varlistentry><term><literal>trusted-binary-caches</literal></term>
<listitem><para>A list of URLs of binary caches, separated by
whitespace. These are not used by default, but can be enabled by
users of the Nix daemon by specifying <literal>--option
binary-caches <replaceable>urls</replaceable></literal> on the
command line. Unprivileged users are only allowed to pass a
subset of the URLs listed in <literal>binary-caches</literal> and
<literal>trusted-binary-caches</literal>.</para></listitem>
</varlistentry>
<varlistentry><term><literal>extra-binary-caches</literal></term>
<listitem><para>Additional binary caches appended to those
specified in <option>binary-caches</option> and
<option>binary-caches-files</option>. When used by unprivileged
users, untrusted binary caches (i.e. those not listed in
<option>trusted-binary-caches</option>) are silently
ignored.</para></listitem>
</varlistentry>
<varlistentry><term><literal>binary-caches-parallel-connections</literal></term>
<listitem><para>The maximum number of parallel HTTP connections
used by the binary cache substituter to get NAR info files. This
number should be high to minimise latency. It defaults to
150.</para></listitem>
</varlistentry>
<varlistentry><term><literal>force-manifest</literal></term>
<listitem><para>If this option is set to <literal>false</literal>
(default) and a Nix channel provides both a manifest and a binary
cache, only the binary cache will be used. If set to
<literal>true</literal>, the manifest will be fetched as well.
This is useful if you want to use binary patches (which are
currently not supported by binary caches).</para></listitem>
</varlistentry>
<varlistentry><term><literal>system</literal></term>
<listitem><para>This option specifies the canonical Nix system
@@ -306,10 +436,25 @@ build-use-chroot = /dev /proc /bin</programlisting>
<literal>true</literal>.</para></listitem>
</varlistentry>
<varlistentry><term><literal>auto-optimise-store</literal></term>
<listitem><para>If set to <literal>true</literal>, Nix
automatically detects files in the store that have identical
contents, and replaces them with hard links to a single copy.
This saves disk space. If set to <literal>false</literal> (the
default), you can still run <command>nix-store
--optimise</command> to get rid of duplicate
files.</para></listitem>
</varlistentry>
</variablelist>
</para>
</refsection>
</section>
</refentry>
+22 -4
View File
@@ -283,7 +283,7 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
<listitem><para>This variable should be set to
<literal>daemon</literal> if you want to use the Nix daemon to
executed Nix operations, which is necessary in <link
execute Nix operations. This is necessary in <link
linkend="ssec-multi-user">multi-user Nix installations</link>.
Otherwise, it should be left unset.</para></listitem>
@@ -293,7 +293,7 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
<varlistentry xml:id="envar-other-stores"><term><envar>NIX_OTHER_STORES</envar></term>
<listitem><para>This variable contains the paths of remote Nix
installations from whichs paths can be copied, separated by colons.
installations from which packages can be copied, separated by colons.
<phrase condition="manual">See <xref linkend="sec-sharing-packages"
/> for details.</phrase> Each path should be the
<filename>/nix</filename> directory of a remote Nix installation
@@ -304,14 +304,32 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
<literal>/var/run/nix/remote-stores</literal>.</para>
<para>Note that if youre building through the <link
linkend="sec-nix-worker">Nix daemon</link>, the only setting for
linkend="sec-nix-daemon">Nix daemon</link>, the only setting for
this variable that matters is the one that the
<command>nix-worker</command> process uses. So if you want to
<command>nix-daemon</command> process uses. So if you want to
change it, you have to restart the daemon.</para></listitem>
</varlistentry>
<varlistentry><term><envar>NIX_SHOW_STATS</envar></term>
<listitem><para>If set to <literal>1</literal>, Nix will print some
evaluation statistics, such as the number of values
allocated.</para></listitem>
</varlistentry>
<varlistentry><term><envar>NIX_COUNT_CALLS</envar></term>
<listitem><para>If set to <literal>1</literal>, Nix will print how
often functions were called during Nix expression evaluation. This
is useful for profiling your Nix expressions.</para></listitem>
</varlistentry>
<varlistentry><term><envar>GC_INITIAL_HEAP_SIZE</envar></term>
<listitem><para>If Nix has been configured to use the Boehm garbage
Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 83 KiB

+12
View File
@@ -160,6 +160,18 @@
</glossentry>
<glossentry xml:id="gloss-nar"><glossterm>NAR</glossterm>
<glossdef><para>A <emphasis>N</emphasis>ix
<emphasis>AR</emphasis>chive. This is a serialisation of a path in
the Nix store. It can contain regular files, directories and
symbolic links. NARs are generated and unpacked using
<command>nix-store --dump</command> and <command>nix-store
--restore</command>.</para></glossdef>
</glossentry>
</glosslist>
+41
View File
@@ -0,0 +1,41 @@
<appendix xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xml:id="chap-hacking">
<title>Hacking</title>
<para>This section provides some notes on how to hack on Nix. To get
the latest version of Nix from GitHub:
<screen>
$ git clone git://github.com/NixOS/nix.git
$ cd hydra
</screen>
</para>
<para>To build it and its dependencies:
<screen>
$ nix-build release.nix -A build.x86_64-linux
</screen>
</para>
<para>To build all dependencies and start a shell in which all
environment variables are set up so that those dependencies can be
found:
<screen>
$ ./dev-shell
</screen>
To build Nix itself in this shell:
<screen>
[nix-shell]$ ./bootstrap
[nix-shell]$ configurePhase
[nix-shell]$ make
</screen>
To test it:
<screen>
[nix-shell]$ make install
[nix-shell]$ make installcheck
</screen>
</para>
</appendix>
+157 -103
View File
@@ -40,11 +40,156 @@ platforms as well.</para>
</section>
<section><title>Obtaining Nix</title>
<section><title>Installing a binary distribution</title>
<para>The easiest way to obtain Nix is to download a <link
xlink:href="http://nixos.org/">source distribution</link>. RPMs
for Red Hat, SuSE, and Fedora Core are also available.</para>
<para>The easiest way to install Nix is to use a binary package.
Binary packages of the latest stable release are available for Fedora,
Debian, Ubuntu, Mac OS X and various other systems from the <link
xlink:href="http://nixos.org/nix/download.html">Nix homepage</link>.
You can also get builds of the latest development release from our
<link
xlink:href="http://hydra.nixos.org/job/nix/trunk/release/latest-finished#tabs-constituents">continuous
build system</link>.</para>
<para>For Fedora, RPM packages are available. These can be installed
or upgraded using <command>rpm -U</command>. For example,
<screen>
$ rpm -U nix-1.0-1.i386.rpm</screen>
</para>
<para>For Debian and Ubuntu, you can download a Deb package and
install it like this:
<screen>
$ dpkg -i nix_1.0-1_amd64.deb</screen>
</para>
<para>For other platforms, including Mac OS X (Darwin), FreeBSD and
other Linux distributions, you can download a binary tarball. It
contains Nix and all its dependencies. You should unpack it in the
root directory, then run <command>nix-finish-install</command>:
<screen>
$ cd /
$ tar xfj nix-1.1-x86_64-darwin.tar.bz2
$ nix-finish-install
</screen>
After this you can delete
<filename>/usr/bin/nix-finish-install</filename>.</para>
<para>If you plan to use Nix from a single non-root user account, its
probably convenient to change the ownership of the entire Nix store
and database to that user account. In that case, install as follows:
<screen>
alice$ cd /
alice$ sudo tar xfj nix-1.1-x86_64-darwin.tar.bz2
alice$ sudo chown -R alice /nix
alice$ nix-finish-install
</screen>
</para>
<para>Nix can be uninstalled using <command>rpm -e nix</command> or
<command>dpkg -r nix</command> on RPM- and Dpkg-based systems,
respectively. After this you should manually remove the Nix store and
other auxiliary data, if desired:
<screen>
$ rm -rf /nix</screen>
</para>
</section>
<section><title>Installing Nix from source</title>
<para>If no binary package is available, you can download and compile
a source distribution.</para>
<section><title>Prerequisites</title>
<itemizedlist>
<listitem><para>GNU Make.</para></listitem>
<listitem><para>A fairly recent version of GCC/G++. Version 2.95
and higher should work. Clang will also work.</para></listitem>
<listitem><para>Perl 5.8 or higher.</para></listitem>
<listitem><para><command>pkg-config</command> to locate
dependencies. If your distribution does not provide it, you can get
it from <link
xlink:href="http://www.freedesktop.org/wiki/Software/pkg-config"
/>.</para></listitem>
<listitem><para>The bzip2 compressor program and the
<literal>libbz2</literal> library. Thus you must have bzip2
installed, including development headers and libraries. If your
distribution does not provide these, you can obtain bzip2 from <link
xlink:href="http://www.bzip.org/"/>.</para></listitem>
<listitem><para>The SQLite embedded database library, version 3.6.19
or higher. If your distribution does not provide it, please install
it from <link xlink:href="http://www.sqlite.org/" />.</para></listitem>
<listitem><para>The Perl DBI and DBD::SQLite libraries, which are
available from <link
xlink:href="http://search.cpan.org/">CPAN</link> if your
distribution does not provide them.</para></listitem>
<listitem><para>The <link
xlink:href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/">Boehm
garbage collector</link> to reduce the evaluators memory
consumption (optional). To enable it, install
<literal>pkgconfig</literal> and the Boehm garbage collector, and
pass the flag <option>--enable-gc</option> to
<command>configure</command>.</para></listitem>
<listitem><para>The <command>xmllint</command> and
<command>xsltproc</command> programs to build this manual and the
man-pages. These are part of the <literal>libxml2</literal> and
<literal>libxslt</literal> packages, respectively. You also need
the <link
xlink:href="http://docbook.sourceforge.net/projects/xsl/">DocBook
XSL stylesheets</link> and optionally the <link
xlink:href="http://www.docbook.org/schemas/5x"> DocBook 5.0 RELAX NG
schemas</link>. Note that these are only required if you modify the
manual sources or when you are building from the Git
repository.</para></listitem>
<listitem><para>Recent versions of Bison and Flex to build the
parser. (This is because Nix needs GLR support in Bison and
reentrancy support in Flex.) For Bison, you need version 2.6, which
can be obtained from the <link
xlink:href="ftp://alpha.gnu.org/pub/gnu/bison">GNU FTP
server</link>. For Flex, you need version 2.5.35, which is
available on <link
xlink:href="http://lex.sourceforge.net/">SourceForge</link>.
Slightly older versions may also work, but ancient versions like the
ubiquitous 2.5.4a won't. Note that these are only required if you
modify the parser or when you are building from the Git
repository.</para></listitem>
</itemizedlist>
</section>
<section><title>Obtaining a source distribution</title>
<para>The source tarball of the most recent stable release can be
downloaded from the <link
xlink:href="http://nixos.org/nix/download.html">Nix homepage</link>.
You can also grab the <link
xlink:href="http://hydra.nixos.org/job/nix/trunk/release/latest-finished#tabs-constituents">most
recent development release</link>.</para>
<para>Alternatively, the most recent sources of Nix can be obtained
from its <link
@@ -63,71 +208,6 @@ repository.</para>
</section>
<section><title>Prerequisites</title>
<para><emphasis>The following prerequisites only apply when you build
from source</emphasis>. Binary releases (e.g., RPMs) have no
prerequisites.</para>
<para>A fairly recent version of GCC/G++ is required. Version 2.95
and higher should work. Clang will also work.</para>
<para>Nix requires Perl, version 5.8 or higher.</para>
<para>Nix requires <command>pkg-config</command> to locate its
dependencies. If your distribution does not provide it, you can get
it from <link
xlink:href="http://www.freedesktop.org/wiki/Software/pkg-config"
/>.</para>
<para>Nix requires the bzip2 compressor program and the
<literal>libbz2</literal> library. Thus you must have bzip2
installed, including development headers and libraries. If your
distribution does not provide these, you can obtain bzip2 from <link
xlink:href="http://www.bzip.org/"/>.</para>
<para>Nix requires the SQLite embedded database library, version
3.6.19 or higher. If your distribution does not provide it, please
install it from <link xlink:href="http://www.sqlite.org/" />.</para>
<para>Nix requires the Perl DBI and DBD::SQLite libraries, which are
available from <link xlink:href="http://search.cpan.org/">CPAN</link>
if your distribution does not provide them.</para>
<para>Nix can optionally use the <link
xlink:href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/">Boehm
garbage collector</link> to reduce the evaluators memory consumption.
To enable it, install <literal>pkgconfig</literal> and the Boehm
garbage collector, and pass the flag <option>--enable-gc</option> to
<command>configure</command>.</para>
<para>To build this manual and the man-pages you need the
<command>xmllint</command> and <command>xsltproc</command> programs,
which are part of the <literal>libxml2</literal> and
<literal>libxslt</literal> packages, respectively. You also need the
<link
xlink:href="http://docbook.sourceforge.net/projects/xsl/">DocBook XSL
stylesheets</link> and optionally the <link
xlink:href="http://www.docbook.org/schemas/5x"> DocBook 5.0 RELAX NG
schemas</link>. Note that these are only required if you modify the
manual sources or when you are building from the Git
repository.</para>
<para>To build the parser, very <emphasis>recent</emphasis> versions
of Bison and Flex are required. (This is because Nix needs GLR
support in Bison and reentrancy support in Flex.) For Bison, you need
version 2.3 or higher (1.875 does <emphasis>not</emphasis> work),
which can be obtained from the <link
xlink:href="ftp://alpha.gnu.org/pub/gnu/bison">GNU FTP server</link>.
For Flex, you need version 2.5.33, which is available on <link
xlink:href="http://lex.sourceforge.net/">SourceForge</link>. Slightly
older versions may also work, but ancient versions like the ubiquitous
2.5.4a won't. Note that these are only required if you modify the
parser or when you are building from the Git repository.</para>
</section>
<section><title>Building Nix from source</title>
<para>After unpacking or checking out the Nix sources, issue the
@@ -138,7 +218,8 @@ $ ./configure <replaceable>options...</replaceable>
$ make
$ make install</screen>
</para>
Nix requires GNU Make so you may need to invoke
<command>gmake</command> instead.</para>
<para>When building from the Git repository, these should be preceded
by the command:
@@ -180,33 +261,6 @@ options.</para>
</section>
<section><title>Installing a binary distribution</title>
<para>RPM and Deb packages of Nix for a number of different versions
of Fedora, openSUSE, Debian and Ubuntu can be downloaded from <link
xlink:href="http://nixos.org/" />. Once downloaded, the RPMs can be
installed or upgraded using <command>rpm -U</command>. For example,
<screen>
$ rpm -U nix-0.13pre18104-1.i386.rpm</screen>
Likewise, for a Deb package:
<screen>
$ dpkg -i nix_0.13pre18104-1_amd64.deb</screen>
</para>
<para>Nix can be uninstalled using <command>rpm -e nix</command> or
<command>dpkg -r nix</command>. After this you should manually remove
the Nix store and other auxiliary data, if desired:
<screen>
$ rm -rf /nix/store
$ rm -rf /nix/var</screen>
</para>
</section>
@@ -357,11 +411,11 @@ $ chown -R root /nix/store /nix/var/nix</screen>
</para>
<para>The <link linkend="sec-nix-worker">Nix daemon</link> should be
<para>The <link linkend="sec-nix-daemon">Nix daemon</link> should be
started as follows (as <literal>root</literal>):
<screen>
$ nix-worker --daemon</screen>
$ nix-daemon</screen>
Youll want to put that line somewhere in your systems boot
scripts.</para>
@@ -395,11 +449,11 @@ named anything. It should own the Nix store and database:
<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.,
and of course <command>nix-daemon</command> should be started under
that user, e.g.,
<screen>
$ su - nix -c "exec /nix/bin/nix-worker --daemon"</screen>
$ su - nix -c "exec /nix/bin/nix-daemon"</screen>
</para>
@@ -484,7 +538,7 @@ a symbolic link to the current <emphasis>user environment</emphasis>
installed packages). The simplest way to set the required environment
variables is to include the file
<filename><replaceable>prefix</replaceable>/etc/profile.d/nix.sh</filename>
in your <filename>~/.bashrc</filename> (or similar), like this:</para>
in your <filename>~/.profile</filename> (or similar), like this:</para>
<screen>
source <replaceable>prefix</replaceable>/etc/profile.d/nix.sh</screen>
+1 -1
View File
@@ -225,7 +225,7 @@ href="docs/papers.html#servicecm">SCM-12 paper</a>.</para>
<simplesect><title>Portability</title>
<para>Nix should run on most Unix systems, including Linux, FreeBSD and
Mac OS X. It is also supported on Windows using Cygwin.</para>
Mac OS X.<!-- It is also supported on Windows using Cygwin.--></para>
</simplesect>
+15 -9
View File
@@ -19,15 +19,15 @@
</author>
<copyright>
<year>2004-2012</year>
<year>2004-2013</year>
<holder>Eelco Dolstra</holder>
</copyright>
<date>May 2012</date>
<date>July 2013</date>
</info>
<xi:include href="introduction.xml" />
<xi:include href="quick-start.xml" />
<xi:include href="installation.xml" />
@@ -40,18 +40,18 @@
<title>Command Reference</title>
<xi:include href="opt-common.xml" />
<xi:include href="env-common.xml" />
<xi:include href="conf-file.xml" />
<section>
<title>Main commands</title>
<xi:include href="nix-env.xml" />
<xi:include href="nix-instantiate.xml" />
<xi:include href="nix-store.xml" />
</section>
<section>
<title>Utilities</title>
<xi:include href="nix-build.xml" />
<xi:include href="nix-shell.xml" />
<xi:include href="nix-channel.xml" />
<xi:include href="nix-collect-garbage.xml" />
<xi:include href="nix-copy-closure.xml" />
@@ -60,7 +60,12 @@
<xi:include href="nix-prefetch-url.xml" />
<xi:include href="nix-pull.xml" />
<xi:include href="nix-push.xml" />
<xi:include href="nix-worker.xml" />
<xi:include href="nix-daemon.xml" />
</section>
<section>
<title>Files</title>
<xi:include href="conf-file.xml" />
</section>
</appendix>
@@ -68,11 +73,12 @@
<xi:include href="troubleshooting.xml" />
<!-- <xi:include href="bugs.xml" /> -->
<xi:include href="glossary.xml" />
<xi:include href="hacking.xml" />
<appendix>
<title>Nix Release Notes</title>
<xi:include href="release-notes.xml"
xpointer="xmlns(x=http://docbook.org/ns/docbook)xpointer(x:article/x:section)" />
</appendix>
</book>
+25 -52
View File
@@ -38,11 +38,6 @@
</group>
<replaceable>outlink</replaceable>
</arg>
<arg>
<option>--run-env</option>
<arg><option>--command</option> <replaceable>cmd</replaceable></arg>
<arg><option>--exclude</option> <replaceable>regexp</replaceable></arg>
</arg>
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
@@ -75,13 +70,6 @@ a root of the Nix garbage collector. This root disappears
automatically when the <filename>result</filename> symlink is deleted
or renamed. So dont rename the symlink.</para></warning>
<para>The subcommand <command>nix-build --run-env</command> will build
the dependencies of the derivation, but not the derivation itself. It
will then start an interactive shell in which all environment
variables defined by the derivation have been set to their
corresponding values. This is useful for reproducing the environment
of a derivation for development.</para>
</refsection>
@@ -96,7 +84,7 @@ also <xref linkend="sec-common-options" />.</phrase></para>
<variablelist>
<varlistentry><term><option>--drv-link</option> <replaceable>drvlink</replaceable></term>
<listitem><para>Add a symlink named
<replaceable>drvlink</replaceable> to the store derivation
produced by <command>nix-instantiate</command>. The derivation is
@@ -108,14 +96,14 @@ also <xref linkend="sec-common-options" />.</phrase></para>
</varlistentry>
<varlistentry><term><option>--add-drv-link</option></term>
<listitem><para>Shorthand for <option>--drv-link</option>
<filename>./derivation</filename>.</para></listitem>
</varlistentry>
<varlistentry><term><option>--no-out-link</option></term>
<listitem><para>Do not create a symlink to the output path. Note
that as a result the output does not become a root of the garbage
collector, and so might be deleted by <command>nix-store
@@ -125,7 +113,7 @@ also <xref linkend="sec-common-options" />.</phrase></para>
<varlistentry xml:id='opt-out-link'><term><option>--out-link</option> /
<option>-o</option> <replaceable>outlink</replaceable></term>
<listitem><para>Change the name of the symlink to the output path
created from <filename>result</filename> to
<replaceable>outlink</replaceable>.</para></listitem>
@@ -134,32 +122,12 @@ also <xref linkend="sec-common-options" />.</phrase></para>
</variablelist>
<para>The following common options are supported:</para>
<variablelist condition="manpage">
<xi:include href="opt-common.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(//db:variablelist[@xml:id='opt-common']/*)" />
</variablelist>
<para>The following options apply to <command>nix-build --run-env</command>.</para>
<variablelist>
<varlistentry><term><option>--command</option> <replaceable>cmd</replaceable></term>
<listitem><para>In the environment of the derivation, executeq the
command <replaceable>cmd</replaceable> instead of the default
interactive shell.</para></listitem>
</varlistentry>
<varlistentry><term><option>--exclude</option> <replaceable>regexp</replaceable></term>
<listitem><para>Do not build any dependencies whose store path
matches the regular expression <replaceable>regexp</replaceable>.
This option may be specified multiple times.</para></listitem>
</varlistentry>
</variablelist>
</refsection>
@@ -176,20 +144,25 @@ lrwxrwxrwx <replaceable>...</replaceable> result -> /nix/store/d18hyl92g30l...
$ ls ./result/bin/
firefox firefox-config</screen>
<para>To build the dependencies of the package Pan, and start an
interactive shell in which to build it:
<para>If a derivation has multiple outputs,
<command>nix-build</command> will build the default (first) output.
You can also build all outputs:
<screen>
$ nix-build '&lt;nixpkgs>' --run-env -A pan
$ tar xf $src
$ cd pan-*
$ ./configure
$ make
$ ./pan/gui/pan
$ nix-build '&lt;nixpkgs>' -A openssl.all
</screen>
</para>
This will create a symlink for each output named
<filename>result-<replaceable>outputname</replaceable></filename>.
The suffix is omitted if the output name is <literal>out</literal>.
So if <literal>openssl</literal> has outputs <literal>out</literal>,
<literal>bin</literal> and <literal>man</literal>,
<command>nix-build</command> will create symlinks
<literal>result</literal>, <literal>result-bin</literal> and
<literal>result-man</literal>. Its also possible to build a specific
output:
<screen>
$ nix-build '&lt;nixpkgs>' -A openssl.man
</screen>
This will create a symlink <literal>result-man</literal>.</para>
</refsection>
@@ -201,6 +174,6 @@ $ ./pan/gui/pan
</variablelist>
</refsection>
</refentry>
+1 -1
View File
@@ -103,7 +103,7 @@ respectively.</para>
<para>To subscribe to the Nixpkgs channel and install the GNU Hello package:</para>
<screen>
$ nix-channel --add http://nixos.org/releases/nixpkgs/channels/nixpkgs-unstable
$ nix-channel --add http://nixos.org/channels/nixpkgs-unstable
$ nix-channel --update
$ nix-env -iA nixpkgs.hello</screen>
+1
View File
@@ -26,6 +26,7 @@
<arg choice='plain'><option>--print-dead</option></arg>
<arg choice='plain'><option>--delete</option></arg>
</group>
<arg><option>--dry-run</option></arg>
</cmdsynopsis>
</refsynopsisdiv>
+20 -6
View File
@@ -28,6 +28,8 @@
<arg><option>--xz</option></arg>
<arg><option>--show-progress</option></arg>
<arg><option>--include-outputs</option></arg>
<arg><option>--use-substitutes</option></arg>
<arg><option>-s</option></arg>
<arg choice='plain'>
<replaceable>user@</replaceable><replaceable>machine</replaceable>
</arg>
@@ -65,7 +67,7 @@ those paths. If this bothers you, use
<refsection><title>Options</title>
<variablelist>
<varlistentry><term><option>--to</option></term>
<listitem><para>Copy the closure of
@@ -119,10 +121,22 @@ those paths. If this bothers you, use
</varlistentry>
<varlistentry><term><option>--include-outputs</option></term>
<listitem><para>Also copy the outputs of store derivations included
in the closure.</para></listitem>
<listitem><para>Also copy the outputs of store derivations
included in the closure.</para></listitem>
</varlistentry>
<varlistentry><term><option>--use-substitutes</option> / <option>-s</option></term>
<listitem><para>Attempt to download missing paths on the target
machine using Nixs substitute mechanism. Any paths that cannot
be substituted on the target are still copied normally from the
source. This is useful, for instance, if the connection between
the source and target machine is slow, but the connection between
the target machine and <literal>nixos.org</literal> (the default
binary cache server) is fast.</para></listitem>
</varlistentry>
</variablelist>
@@ -140,7 +154,7 @@ those paths. If this bothers you, use
<command>ssh</command> on the command line.</para></listitem>
</varlistentry>
</variablelist>
</refsection>
@@ -1,24 +1,23 @@
<refentry xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xml:id="sec-nix-worker">
xml:id="sec-nix-daemon">
<refmeta>
<refentrytitle>nix-worker</refentrytitle>
<refentrytitle>nix-daemon</refentrytitle>
<manvolnum>8</manvolnum>
<refmiscinfo class="source">Nix</refmiscinfo>
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
</refmeta>
<refnamediv>
<refname>nix-worker</refname>
<refname>nix-daemon</refname>
<refpurpose>Nix multi-user support daemon</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>nix-worker</command>
<arg choice="plain"><option>--daemon</option></arg>
<command>nix-daemon</command>
</cmdsynopsis>
</refsynopsisdiv>
+37 -14
View File
@@ -93,11 +93,10 @@ also <xref linkend="sec-common-options" />.</phrase></para>
<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
<emphasis>active profile</emphasis>). A profile is a sequence of
user environments called <emphasis>generations</emphasis>, one of
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>
which is the <emphasis>current
generation</emphasis>.</para></listitem>
</varlistentry>
@@ -105,7 +104,8 @@ also <xref linkend="sec-common-options" />.</phrase></para>
<listitem><para>For the <option>--install</option>,
<option>--upgrade</option>, <option>--uninstall</option>,
<option>--switch-generation</option> and
<option>--switch-generation</option>,
<option>--delete-generations</option> and
<option>--rollback</option> operations, this flag will cause
<command>nix-env</command> to print what
<emphasis>would</emphasis> be done if this flag had not been
@@ -153,11 +153,10 @@ also <xref linkend="sec-common-options" />.</phrase></para>
default.</para>
<para>The Nix expressions in this directory are combined into a
single attribute set, with each file as an attribute that has the
name of the file. Thus, if <filename>~/.nix-defexpr</filename>
contains two files, <filename>foo</filename> and
<filename>bar</filename>, then the default Nix expression will
essentially be
single set, with each file as an attribute that has the name of
the file. Thus, if <filename>~/.nix-defexpr</filename> contains
two files, <filename>foo</filename> and <filename>bar</filename>,
then the default Nix expression will essentially be
<programlisting>
{
@@ -209,6 +208,10 @@ also <xref linkend="sec-common-options" />.</phrase></para>
<arg choice='plain'><option>--preserve-installed</option></arg>
<arg choice='plain'><option>-P</option></arg>
</group>
<group choice='opt'>
<arg choice='plain'><option>--remove-all</option></arg>
<arg choice='plain'><option>-r</option></arg>
</group>
<arg choice='plain' rep='repeat'><replaceable>args</replaceable></arg>
</cmdsynopsis>
@@ -272,7 +275,7 @@ number of possible ways:
linkend="ss-functions">functions</link> that are called with the
active Nix expression as their single argument. The derivations
returned by those function calls are installed. This allows
derivations to be specified in a unambiguous way, which is necessary
derivations to be specified in an unambiguous way, which is necessary
if there are multiple derivations with the same
name.</para></listitem>
@@ -318,6 +321,16 @@ number of possible ways:
</varlistentry>
<varlistentry><term><option>--remove-all</option></term>
<term><option>-r</option></term>
<listitem><para>Remove all previously installed packages first.
This is equivalent to running <literal>nix-env -e '*'</literal>
first, except that everything happens in a single
transaction.</para></listitem>
</varlistentry>
</variablelist>
</refsection>
@@ -391,7 +404,7 @@ $ nix-env -f ./foo.nix -i -E \
I.e., this evaluates to <literal>(f: (f {system =
"i686-linux";}).subversionWithJava) (import ./foo.nix)</literal>, thus
selecting the <literal>subversionWithJava</literal> attribute from the
attribute set returned by calling the function defined in
set returned by calling the function defined in
<filename>./foo.nix</filename>.</para>
<para>A dry-run tells you which paths will be downloaded or built from
@@ -692,7 +705,7 @@ firefox-2.0.0.9 <lineannotation>(the current one)</lineannotation>
$ nix-env --preserve-installed -i firefox-2.0.0.11
installing `firefox-2.0.0.11'
building path(s) `/nix/store/myy0y59q3ig70dgq37jqwg1j0rsapzsl-user-environment'
Collission between `/nix/store/<replaceable>...</replaceable>-firefox-2.0.0.11/bin/firefox'
collision between `/nix/store/<replaceable>...</replaceable>-firefox-2.0.0.11/bin/firefox'
and `/nix/store/<replaceable>...</replaceable>-firefox-2.0.0.9/bin/firefox'.
<lineannotation>(i.e., cant have two active at the same time)</lineannotation>
@@ -1244,7 +1257,7 @@ wrapper around <option>--list-generations</option> and
$ nix-env --rollback
switching from generation 92 to 91
$ nix-env --rolback
$ nix-env --rollback
error: no generation older than the current (91) exists</screen>
</refsection>
@@ -1255,6 +1268,16 @@ error: no generation older than the current (91) exists</screen>
<refsection condition="manpage"><title>Environment variables</title>
<variablelist>
<varlistentry><term><envar>NIX_PROFILE</envar></term>
<listitem><para>Location of the Nix profile. Defaults to the
target of the symlink <filename>~/.nix-profile</filename>, if it
exists, or <filename>/nix/var/nix/profiles/default</filename>
otherwise.</para></listitem>
</varlistentry>
<xi:include href="env-common.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(//db:variablelist[@xml:id='env-common']/*)" />
</variablelist>
+3 -2
View File
@@ -91,8 +91,9 @@ cryptographic hash as <literal>nix-store --dump
<varlistentry><term><option>--type</option> <replaceable>hashAlgo</replaceable></term>
<listitem><para>Specify a cryptographic hash, which can be one of
<literal>md5</literal>, <literal>sha1</literal>, and
<listitem><para>Use the specified cryptographic hash algorithm,
which can be one of <literal>md5</literal>,
<literal>sha1</literal>, and
<literal>sha256</literal>.</para></listitem>
</varlistentry>
+19 -5
View File
@@ -18,6 +18,7 @@
<refsynopsisdiv>
<cmdsynopsis>
<command>nix-prefetch-url</command>
<arg><option>--type</option> <replaceable>hashAlgo</replaceable></arg>
<arg choice='plain'><replaceable>url</replaceable></arg>
<arg><replaceable>hash</replaceable></arg>
</cmdsynopsis>
@@ -45,11 +46,6 @@ download it again when you build your Nix expression. Since
as <command>nix-prefetch-url</command>, the redundant download can be
avoided.</para>
<para>The environment variable <envar>NIX_HASH_ALGO</envar> specifies
which hash algorithm to use. It can be either <literal>md5</literal>,
<literal>sha1</literal>, or <literal>sha256</literal>. The default is
<literal>sha256</literal>.</para>
<para>If <replaceable>hash</replaceable> is specified, then a download
is not performed if the Nix store already contains a file with the
same hash and base name. Otherwise, the file is downloaded, and an
@@ -63,6 +59,24 @@ of the downloaded file in the Nix store is also printed.</para>
</refsection>
<refsection><title>Options</title>
<variablelist>
<varlistentry><term><option>--type</option> <replaceable>hashAlgo</replaceable></term>
<listitem><para>Use the specified cryptographic hash algorithm,
which can be one of <literal>md5</literal>,
<literal>sha1</literal>, and
<literal>sha256</literal>.</para></listitem>
</varlistentry>
</variablelist>
</refsection>
<refsection><title>Examples</title>
<screen>
+345 -76
View File
@@ -12,24 +12,20 @@
<refnamediv>
<refname>nix-push</refname>
<refpurpose>push store paths onto a network cache</refpurpose>
<refpurpose>generate a binary cache</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>nix-push</command>
<group choice='req'>
<arg choice='req'>
<arg choice='plain'><replaceable>archivesPutURL</replaceable></arg>
<arg choice='plain'><replaceable>archivesGetURL</replaceable></arg>
<arg choice='plain'><replaceable>manifestPutURL</replaceable></arg>
</arg>
<arg choice='req'>
<arg choice='plain'><option>--copy</option></arg>
<arg choice='plain'><replaceable>archivesDir</replaceable></arg>
<arg choice='plain'><replaceable>manifestFile</replaceable></arg>
</arg>
</group>
<arg choice='plain'><option>--dest</option> <replaceable>dest-dir</replaceable></arg>
<arg><option>--bzip2</option></arg>
<arg><option>--none</option></arg>
<arg><option>--force</option></arg>
<arg><option>--link</option></arg>
<arg><option>--manifest</option></arg>
<arg><option>--manifest-path</option> <replaceable>filename</replaceable></arg>
<arg><option>--url-prefix</option> <replaceable>url</replaceable></arg>
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
@@ -37,93 +33,366 @@
<refsection><title>Description</title>
<para>The command <command>nix-push</command> builds a set of store
paths (if necessary), and then packages and uploads all store paths in
the resulting closures to a server. A network cache thus populated
can subsequently be used to speed up software deployment on other
machines using the <command>nix-pull</command> command.</para>
<para>The command <command>nix-push</command> produces a
<emphasis>binary cache</emphasis>, a directory containing compressed
Nix archives (NARs) plus some metadata of the closure of the specified
store paths. This directory can then be made available through a web
server to other Nix installations, allowing them to skip building from
source and instead download binaries from the cache
automatically.</para>
<para><command>nix-push</command> performs the following actions.
<orderedlist>
<listitem><para>Each path in <replaceable>paths</replaceable> is
realised (using <link
linkend='rsec-nix-store-realise'><literal>nix-store
--realise</literal></link>).</para></listitem>
built (using <link
linkend='rsec-nix-store-realise'><command>nix-store
--realise</command></link>).</para></listitem>
<listitem><para>All paths in the closure of the store expressions
stored in <replaceable>paths</replaceable> are determined (using
<literal>nix-store --query --requisites
--include-outputs</literal>). It should be noted that since the
<option>--include-outputs</option> flag is used, you get a combined
source/binary distribution.</para></listitem>
<listitem><para>All paths in the closure of
<replaceable>paths</replaceable> are determined (using
<command>nix-store --query --requisites
--include-outputs</command>). Note that since the
<option>--include-outputs</option> flag is used, if
<replaceable>paths</replaceable> includes a store derivation, you
get a combined source/binary distribution (e.g., source tarballs
will be included).</para></listitem>
<listitem><para>All store paths determined in the previous step are
packaged and compressed into a <command>bzip</command>ped NAR
archive (extension <filename>.nar.bz2</filename>).</para></listitem>
packaged into a NAR (using <command>nix-store --dump</command>) and
compressed using <command>xz</command> or <command>bzip2</command>.
The resulting files have the extension <filename>.nar.xz</filename>
or <filename>.nar.bz2</filename>. Also for each store path, Nix
generates a file with extension <filename>.narinfo</filename>
containing metadata such as the references, cryptographic hash and
size of each path.</para></listitem>
<listitem><para>A <emphasis>manifest</emphasis> is created that
contains information on the store paths, their eventual URLs in the
cache, and cryptographic hashes of the contents of the NAR
archives.</para></listitem>
<listitem><para>Optionally, a single <emphasis>manifest</emphasis>
file is created that contains the same metadata as the
<filename>.narinfo</filename> files. This is for compatibility with
Nix versions prior to 1.2 (see <command>nix-pull</command> for
details).</para></listitem>
<listitem><para>Each store path is uploaded to the remote directory
specified by <replaceable>archivesPutURL</replaceable>. HTTP PUT
requests are used to do this. However, before a file
<varname>x</varname> is uploaded to
<literal><replaceable>archivesPutURL</replaceable>/</literal><varname>x</varname>,
<command>nix-push</command> first determines whether this upload is
unnecessary by issuing a HTTP HEAD request on
<literal><replaceable>archivesGetURL</replaceable>/</literal><varname>x</varname>.
This allows a cache to be shared between many partially overlapping
<command>nix-push</command> invocations. (We use two URLs because
the upload URL typically refers to a CGI script, while the download
URL just refers to a file system directory on the
server.)</para></listitem>
<listitem><para>A file named <option>nix-cache-info</option> is
placed in the destination directory. The existence of this file
marks the directory as a binary cache.</para></listitem>
<listitem><para>The manifest is uploaded using an HTTP PUT request
to <replaceable>manifestPutURL</replaceable>. The corresponding
URL to download the manifest can then be used by
<command>nix-pull</command>.</para></listitem>
</orderedlist>
</para>
<!--
<para>TODO: <option>- -copy</option></para>
-->
</refsection>
<refsection><title>Options</title>
<variablelist>
<varlistentry><term><option>--dest</option> <replaceable>dest-dir</replaceable></term>
<listitem><para>Set the destination directory to
<replaceable>dir</replaceable>, which is created if it does not
exist. This flag is required.</para></listitem>
</varlistentry>
<varlistentry><term><option>--bzip2</option></term>
<listitem><para>Compress NARs using <command>bzip2</command>
instead of <command>xz -9</command>. The latter compresses about
30% better on typical archives, decompresses about twice as fast,
but compresses a lot slower and is not supported by Nix prior to
version 1.2.</para></listitem>
</varlistentry>
<varlistentry><term><option>--none</option></term>
<listitem><para>Do not compress NARs.</para></listitem>
</varlistentry>
<varlistentry><term><option>--force</option></term>
<listitem><para>Overwrite <filename>.narinfo</filename> files if
they already exist.</para></listitem>
</varlistentry>
<varlistentry><term><option>--link</option></term>
<listitem><para>By default, NARs are generated in the Nix store
and then copied to <replaceable>dest-dir</replaceable>. If this
option is given, hard links are used instead. This only works if
<replaceable>dest-dir</replaceable> is on the same filesystem as
the Nix store.</para></listitem>
</varlistentry>
<varlistentry><term><option>--manifest</option></term>
<listitem><para>Force the generation of a manifest suitable for
use by <command>nix-pull</command>. The manifest is stored as
<filename><replaceable>dest-dir</replaceable>/MANIFEST</filename>.</para></listitem>
</varlistentry>
<varlistentry><term><option>--manifest-path</option> <replaceable>filename</replaceable></term>
<listitem><para>Like <option>--manifest</option>, but store the
manifest in <replaceable>filename</replaceable>.</para></listitem>
</varlistentry>
<varlistentry><term><option>--url-prefix</option> <replaceable>url</replaceable></term>
<listitem><para>Manifests are expected to contain the absolute
URLs of NARs. For generating these URLs, the prefix
<replaceable>url</replaceable> is used. It defaults to
<uri>file://<replaceable>dest-dir</replaceable></uri>.</para></listitem>
</varlistentry>
</variablelist>
</refsection>
<refsection><title>Examples</title>
<para>To upload files there typically is some CGI script on the server
side. This script should be be protected with a password. The
following example uploads the store paths resulting from building the
Nix expressions in <filename>foo.nix</filename>, passing appropriate
authentication information:
<screen>
$ nix-push \
http://foo@bar:server.domain/cgi-bin/upload.pl/cache \
http://server.domain/cache \
http://foo@bar:server.domain/cgi-bin/upload.pl/MANIFEST \
$(nix-instantiate foo.nix)</screen>
<para>To add the closure of Thunderbird to a binary cache:
This will push both sources and binaries (and any build-time
dependencies used in the build, such as compilers).</para>
<para>If we just want to push binaries, not sources and build-time
dependencies, we can do:
<screen>
$ nix-push <replaceable>urls</replaceable> $(nix-store -r $(nix-instantiate foo.nix))</screen>
$ nix-push --dest /tmp/cache $(nix-build -A thunderbird)
</screen>
Assuming that <filename>/tmp/cache</filename> is exported by a web
server as <uri>http://example.org/cache</uri>, you can then use this
cache on another machine to speed up the installation of Thunderbird:
<screen>
$ nix-build -A thunderbird --option binary-caches http://example.org/cache
</screen>
Alternatively, you could add <literal>binary-caches =
http://example.org/cache</literal> to
<filename>nix.conf</filename>.</para>
<para>To also include build-time dependencies (such as source
tarballs):
<screen>
$ nix-push --dest /tmp/cache $(nix-instantiate -A thunderbird)
</screen>
</para>
<para>To generate a manifest suitable for <command>nix-pull</command>:
<screen>
$ nix-push --dest /tmp/cache $(nix-build -A thunderbird) --manifest
</screen>
On another machine you can then do:
<screen>
$ nix-pull http://example.org/cache
</screen>
to cause the binaries to be used by subsequent Nix operations.</para>
</refsection>
<refsection><title>Binary cache format and operation</title>
<para>A binary cache with URL <replaceable>url</replaceable> only
denotes a valid binary cache if the file
<uri><replaceable>url</replaceable>/nix-cache-info</uri> exists. If
this file does not exist (or cannot be downloaded), the cache is
ignored. If it does exist, it must be a text file containing cache
properties. Heres an example:
<screen>
StoreDir: /nix/store
WantMassQuery: 1
Priority: 10
</screen>
The properties that are currently supported are:
<variablelist>
<varlistentry><term><literal>StoreDir</literal></term>
<listitem><para>The path of the Nix store to which this binary
cache applies. Binaries are not relocatable — a binary built for
<filename>/nix/store</filename> wont generally work in
<filename>/home/alice/store</filename> — so to prevent binaries
from being used in a wrong store, a binary cache is only used if
its <literal>StoreDir</literal> matches the local Nix
configuration. The default is
<filename>/nix/store</filename>.</para></listitem>
</varlistentry>
<varlistentry><term><literal>WantMassQuery</literal></term>
<listitem><para>Query operations such as <command>nix-env
-qas</command> can cause thousands of cache queries, and thus
thousands of HTTP requests, to determine which packages are
available in binary form. While these requests are small, not
every server may appreciate a potential onslaught of queries. If
<literal>WantMassQuery</literal> is set to <literal>0</literal>
(default), “mass queries” such as <command>nix-env -qas</command>
will skip this cache. Thus a package may appear not to have a
binary substitute. However, the binary will still be used when
you actually install the package. If
<literal>WantMassQuery</literal> is set to <literal>1</literal>,
mass queries will use this cache.</para></listitem>
</varlistentry>
<varlistentry><term><literal>Priority</literal></term>
<listitem><para>Each binary cache has a priority (defaulting to
50). Binary caches are checked for binaries in order of ascending
priority; thus a higher number denotes a lower priority. The
binary cache <uri>http://cache.nixos.org</uri> has priority
40.</para></listitem>
</varlistentry>
</variablelist>
</para>
<para>Every time Nix needs to build some store path
<replaceable>p</replaceable>, it will check each configured binary
cache to see if it has a NAR file for <replaceable>p</replaceable>,
until it finds one. If no cache has a NAR, Nix will fall back to
building the path from source (if applicable). To see if a cache with
URL <replaceable>url</replaceable> has a binary for
<replaceable>p</replaceable>, Nix fetches
<replaceable>url/h</replaceable>, where <replaceable>h</replaceable>
is the hash part of <replaceable>p</replaceable>. Thus, if we have a
cache <uri>http://cache.nixos.org</uri> and we want to obtain
the store path
<screen>
/nix/store/a8922c0h87iilxzzvwn2hmv8x210aqb9-glibc-2.7
</screen>
then Nix will attempt to fetch
<screen>
http://cache.nixos.org/a8922c0h87iilxzzvwn2hmv8x210aqb9.narinfo
</screen>
(Commands such as <command>nix-env -qas</command> will issue an HTTP
HEAD request, since it only needs to know if the
<filename>.narinfo</filename> file exists.) The
<filename>.narinfo</filename> file is a simple text file that looks
like this:
<screen>
StorePath: /nix/store/a8922c0h87iilxzzvwn2hmv8x210aqb9-glibc-2.7
URL: nar/0zzjpdz46mdn74v09m053yczlz4am038g8r74iy8w43gx8801h70.nar.bz2
Compression: bzip2
FileHash: sha256:0zzjpdz46mdn74v09m053yczlz4am038g8r74iy8w43gx8801h70
FileSize: 24473768
NarHash: sha256:0s491y1h9hxj5ghiizlxk7ax6jwbha00zwn7lpyd5xg5bhf60vzg
NarSize: 109521136
References: 2ma2k0ys8knh4an48n28vigcmc2z8773-linux-headers-2.6.23.16 ...
Deriver: 7akyyc87ka32xwmqza9dvyg5pwx3j212-glibc-2.7.drv
</screen>
The fields are as follows:
<variablelist>
<varlistentry><term><literal>StorePath</literal></term>
<listitem><para>The full store path, including the name part
(e.g., <literal>glibc-2.7</literal>). It must match the
requested store path.</para></listitem>
</varlistentry>
<varlistentry><term><literal>URL</literal></term>
<listitem><para>The URL of the NAR, relative to the binary cache
URL.</para></listitem>
</varlistentry>
<varlistentry><term><literal>Compression</literal></term>
<listitem><para>The compression method; either
<literal>xz</literal> or
<literal>bzip2</literal>.</para></listitem>
</varlistentry>
<varlistentry><term><literal>FileHash</literal></term>
<listitem><para>The SHA-256 hash of the compressed
NAR.</para></listitem>
</varlistentry>
<varlistentry><term><literal>FileSize</literal></term>
<listitem><para>The size of the compressed NAR.</para></listitem>
</varlistentry>
<varlistentry><term><literal>NarHash</literal></term>
<listitem><para>The SHA-256 hash of the uncompressed NAR. This is
equal to the hash of the store path as returned by
<command>nix-store -q --hash
<replaceable>p</replaceable></command>.</para></listitem>
</varlistentry>
<varlistentry><term><literal>NarSize</literal></term>
<listitem><para>The size of the uncompressed NAR.</para></listitem>
</varlistentry>
<varlistentry><term><literal>References</literal></term>
<listitem><para>The references of the store path, without the Nix
store prefix.</para></listitem>
</varlistentry>
<varlistentry><term><literal>Deriver</literal></term>
<listitem><para>The deriver of the store path, without the Nix
store prefix. This field is optional.</para></listitem>
</varlistentry>
<varlistentry><term><literal>System</literal></term>
<listitem><para>The Nix platform type of this binary, if known.
This field is optional.</para></listitem>
</varlistentry>
</variablelist>
</para>
<para>Thus, in our example, after recursively ensuring that the
references exist (e.g.,
<filename>/nix/store/2ma2k0ys8knh4an48n28vigcmc2z8773-linux-headers-2.6.23.16</filename>),
Nix will fetch <screen>
http://cache.nixos.org/nar/0zzjpdz46mdn74v09m053yczlz4am038g8r74iy8w43gx8801h70.nar.bz2
</screen> and decompress and unpack it to
<filename>/nix/store/a8922c0h87iilxzzvwn2hmv8x210aqb9-glibc-2.7</filename>.</para>
</refsection>
</refentry>
+142
View File
@@ -0,0 +1,142 @@
<refentry xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xml:id="sec-nix-shell">
<refmeta>
<refentrytitle>nix-shell</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo class="source">Nix</refmiscinfo>
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
</refmeta>
<refnamediv>
<refname>nix-shell</refname>
<refpurpose>start an interactive shell based on a Nix expression</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>nix-shell</command>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="opt-common-syn.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(/db:nop/*)" />
<arg><option>--arg</option> <replaceable>name</replaceable> <replaceable>value</replaceable></arg>
<arg><option>--argstr</option> <replaceable>name</replaceable> <replaceable>value</replaceable></arg>
<arg>
<group choice='req'>
<arg choice='plain'><option>--attr</option></arg>
<arg choice='plain'><option>-A</option></arg>
</group>
<replaceable>attrPath</replaceable>
</arg>
<arg><option>--command</option> <replaceable>cmd</replaceable></arg>
<arg><option>--exclude</option> <replaceable>regexp</replaceable></arg>
<arg><option>--pure</option></arg>
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsection><title>Description</title>
<para>The command <command>nix-shell</command> will build
the dependencies of the specified derivation, but not the derivation
itself. It will then start an interactive shell in which all
environment variables defined by the derivation have been set to their
corresponding values, and the script <literal>$stdenv/setup</literal>
has been sourced. This is useful for reproducing the environment of a
derivation for development.</para>
</refsection>
<refsection><title>Options</title>
<para>All options not listed here are passed to <command>nix-store
--realise</command>, except for <option>--arg</option> and
<option>--attr</option> / <option>-A</option> which are passed to
<command>nix-instantiate</command>. <phrase condition="manual">See
also <xref linkend="sec-common-options" />.</phrase></para>
<variablelist>
<varlistentry><term><option>--command</option> <replaceable>cmd</replaceable></term>
<listitem><para>In the environment of the derivation, run the
shell command <replaceable>cmd</replaceable> instead of starting
an interactive shell. However, if you end the shell command with
<literal>return</literal>, you still get an interactive shell.
This can be useful for doing any additional
initialisation.</para></listitem>
</varlistentry>
<varlistentry><term><option>--exclude</option> <replaceable>regexp</replaceable></term>
<listitem><para>Do not build any dependencies whose store path
matches the regular expression <replaceable>regexp</replaceable>.
This option may be specified multiple times.</para></listitem>
</varlistentry>
<varlistentry><term><option>--pure</option></term>
<listitem><para>If this flag is specified, the environment is
almost entirely cleared before the interactive shell is started,
so you get an environment that more closely corresponds to the
“real” Nix build. A few variables, in particular
<envar>HOME</envar>, <envar>USER</envar> and
<envar>DISPLAY</envar>, are retained. Note that
<filename>~/.bashrc</filename> and (depending on your Bash
installation) <filename>/etc/bashrc</filename> are still sourced,
so any variables set there will affect the interactive
shell.</para></listitem>
</varlistentry>
</variablelist>
<para>The following common options are supported:</para>
<variablelist condition="manpage">
<xi:include href="opt-common.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(//db:variablelist[@xml:id='opt-common']/*)" />
</variablelist>
</refsection>
<refsection><title>Examples</title>
<para>To build the dependencies of the package Pan, and start an
interactive shell in which to build it:
<screen>
$ nix-shell '&lt;nixpkgs>' -A pan
$ unpackPhase
$ cd pan-*
$ configurePhase
$ buildPhase
$ ./pan/gui/pan
</screen>
To clear the environment first, and do some additional automatic
initialisation of the interactive shell:
<screen>
$ nix-shell '&lt;nixpkgs>' -A pan --pure \
--command 'export NIX_DEBUG=1; export NIX_CORES=8; return'
</screen>
</para>
</refsection>
<refsection condition="manpage"><title>Environment variables</title>
<variablelist>
<xi:include href="env-common.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(//db:variablelist[@xml:id='env-common']/*)" />
</variablelist>
</refsection>
</refentry>
+84 -11
View File
@@ -164,7 +164,7 @@ the specified store paths. Realisation is a somewhat overloaded term:
exist in the file system). If the path is already valid, we are
done immediately. Otherwise, the path and any missing paths in its
closure may be produced through substitutes. If there are no
(succesful) subsitutes, realisation fails.</para></listitem>
(successful) subsitutes, realisation fails.</para></listitem>
</itemizedlist>
@@ -174,10 +174,26 @@ the specified store paths. Realisation is a somewhat overloaded term:
output. (For non-derivations argument, the argument itself is
printed.)</para>
<para>If the <option>--dry-run</option> option is used, then
<command>nix-store</command> will print on standard error a
description of what packages would be built or downloaded, and then
quit.</para>
<para>The following flags are available:</para>
<variablelist>
<varlistentry><term><option>--dry-run</option></term>
<listitem><para>Print on standard error a description of what
packages would be built or downloaded, without actually performing
the operation.</para></listitem>
</varlistentry>
<varlistentry><term><option>--ignore-unknown</option></term>
<listitem><para>If a non-derivation path does not have a
substitute, then silently ignore it.</para></listitem>
</varlistentry>
</variablelist>
</refsection>
@@ -773,6 +789,7 @@ $ nix-store --add ./foo.c
<command>nix-store</command>
<arg choice='plain'><option>--verify</option></arg>
<arg><option>--check-contents</option></arg>
<arg><option>--repair</option></arg>
</cmdsynopsis>
</refsection>
@@ -785,7 +802,7 @@ automatically repaired. Inconsistencies are generally the result of
the Nix store or database being modified by non-Nix tools, or of bugs
in Nix itself.</para>
<para>There is one option:
<para>This operation has the following options:
<variablelist>
@@ -800,6 +817,16 @@ in Nix itself.</para>
</varlistentry>
<varlistentry><term><option>--repair</option></term>
<listitem><para>If any valid path is missing from the store, or
(if <option>--check-contents</option> is given) the contents of a
valid path has been modified, then try to repair the path by
redownloading it. See <command>nix-store --repair-path</command>
for details.</para></listitem>
</varlistentry>
</variablelist>
</para>
@@ -825,7 +852,7 @@ in Nix itself.</para>
<refsection><title>Description</title>
<para>The operation <option>--verify-paths</option> compares the
<para>The operation <option>--verify-path</option> compares the
contents of the given store paths to their cryptographic hashes stored
in Nixs database. For every changed path, it prints a warning
message. The exit status is 0 if no path has changed, and 1
@@ -848,6 +875,52 @@ $ nix-store --verify-path $(nix-store -qR $(which svn))
</refsection>
<!--######################################################################-->
<refsection><title>Operation <option>--repair-path</option></title>
<refsection>
<title>Synopsis</title>
<cmdsynopsis>
<command>nix-store</command>
<arg choice='plain'><option>--repair-path</option></arg>
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
</cmdsynopsis>
</refsection>
<refsection><title>Description</title>
<para>The operation <option>--repair-path</option> attempts to
“repair” the specified paths by redownloading them using the available
substituters. If no substitutes are available, then repair is not
possible.</para>
<warning><para>During repair, there is a very small time window during
which the old path (if it exists) is moved out of the way and replaced
with the new path. If repair is interrupted in between, then the
system may be left in a broken state (e.g., if the path contains a
critical system component like the GNU C Library).</para></warning>
</refsection>
<refsection><title>Example</title>
<screen>
$ nix-store --verify-path /nix/store/dj7a81wsm1ijwwpkks3725661h3263p5-glibc-2.13
path `/nix/store/dj7a81wsm1ijwwpkks3725661h3263p5-glibc-2.13' was modified!
expected hash `2db57715ae90b7e31ff1f2ecb8c12ec1cc43da920efcbe3b22763f36a1861588',
got `481c5aa5483ebc97c20457bb8bca24deea56550d3985cda0027f67fe54b808e4'
$ nix-store --repair-path /nix/store/dj7a81wsm1ijwwpkks3725661h3263p5-glibc-2.13
fetching path `/nix/store/d7a81wsm1ijwwpkks3725661h3263p5-glibc-2.13'...
</screen>
</refsection>
</refsection>
<!--######################################################################-->
<refsection xml:id='refsec-nix-store-dump'><title>Operation <option>--dump</option></title>
@@ -1169,9 +1242,9 @@ variable <envar>_args</envar>.</para>
$ nix-store --print-env $(nix-instantiate '&lt;nixpkgs>' -A firefox)
<replaceable></replaceable>
export src; src='/nix/store/plpj7qrwcz94z2psh6fchsi7s8yihc7k-firefox-12.0.source.tar.bz2'
export stdenv; stdenv='/nix/store/7c8asx3yfrg5dg1gzhzyq2236zfgibnm-stdenv'
export stdenv; stdenv='/nix/store/7c8asx3yfrg5dg1gzhzyq2236zfgibnn-stdenv'
export system; system='x86_64-linux'
export _args; _args='-e /nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh'
export _args; _args='-e /nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25c-default-builder.sh'
</screen>
</refsection>
@@ -1246,8 +1319,8 @@ paths.</para>
<refsection><title>Example</title>
<screen>
$ nix-store --clear-failed-path /nix/store/000zi5dcla86l92jn1g997jb06sidm7x-perl-PerlMagick-6.59
$ nix-store --clear-failed-path *
$ nix-store --clear-failed-paths /nix/store/000zi5dcla86l92jn1g997jb06sidm7x-perl-PerlMagick-6.59
$ nix-store --clear-failed-paths *
</screen>
</refsection>
+5
View File
@@ -37,6 +37,11 @@
<option>-I</option>
<replaceable>path</replaceable>
</arg>
<arg>
<option>--option</option>
<replaceable>name</replaceable>
<replaceable>value</replaceable>
</arg>
<sbr />
</nop>
+29 -7
View File
@@ -181,7 +181,7 @@
from, say, a network repository. If the repository is down, the
realisation of the derivation will fail. When this option is
specified, Nix will build the derivation instead. Thus,
installation from binaries falls back on nstallation from source.
installation from binaries falls back on installation from source.
This option is not the default since it is generally not desirable
for a transient failure in obtaining the substitutes to lead to a
full build from source (with the related consumption of
@@ -236,7 +236,7 @@
interpreted by the <command>nix-log2xml</command> tool in the
Nix source distribution. The resulting XML file can be fed into
the <command>log2html.xsl</command> stylesheet to create an HTML
file that can be browsed interactively, using Javascript to
file that can be browsed interactively, using JavaScript to
expand and collapse parts of the output.</para></listitem>
</varlistentry>
@@ -337,20 +337,42 @@
<listitem><para>Causes Nix to print out a stack trace in case of Nix
expression evaluation errors.</para></listitem>
</varlistentry>
<varlistentry><term><option>-I</option> <replaceable>path</replaceable></term>
<listitem><para>Add a path to the Nix expression search path. See
the <envar>NIX_PATH</envar> environment variable for details. Paths
added through <option>-I</option> take precedence over
<envar>NIX_PATH</envar>.</para></listitem>
<listitem><para>Add a path to the Nix expression search path. This
option may be given multiple times. See the <envar>NIX_PATH</envar>
environment variable for information on the semantics of the Nix
search path. Paths added through <option>-I</option> take
precedence over <envar>NIX_PATH</envar>.</para></listitem>
</varlistentry>
<varlistentry><term><option>--option</option> <replaceable>name</replaceable> <replaceable>value</replaceable></term>
<listitem><para>Set the Nix configuration option
<replaceable>name</replaceable> to <replaceable>value</replaceable>.
This overrides settings in the Nix configuration file (see
<citerefentry><refentrytitle>nix.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>).</para></listitem>
</varlistentry>
<varlistentry><term><option>--repair</option></term>
<listitem><para>Fix corrupted or missing store paths by
redownloading or rebuilding them. Note that this is slow because it
requires computing a cryptographic hash of the contents of every
path in the closure of the build. Also note the warning under
<command>nix-store --repair-path</command>.</para></listitem>
</varlistentry>
</variablelist>
+6 -21
View File
@@ -129,7 +129,7 @@ downloading binaries from <systemitem
class='fqdomainname'>nixos.org</systemitem>, instead of building
them from source. This might still take a while since all
dependencies must be downloaded, but on a reasonably fast connection
such as an DSL line its on the order of a few minutes.</para>
such as a DSL line its on the order of a few minutes.</para>
<para>Naturally, packages can also be uninstalled:
@@ -175,21 +175,6 @@ upgrading `coreutils-5.0' to `coreutils-5.2.1'</screen>
</para>
<para>If you grow bored of specifying the Nix expressions using
<parameter>-f</parameter> all the time, you can set a default
location:
<screen>
$ nix-env -I nixpkgs-<replaceable>version</replaceable></screen>
After this you can just say, for instance, <literal>nix-env -u
'*'</literal>.<footnote><para>Setting a default using
<parameter>-I</parameter> currently clashes with using Nix channels,
since <literal>nix-channel --update</literal> calls <literal>nix-env
-I</literal> to set the default to the Nix expressions it downloaded
from the channel, replacing whatever default you had
set.</para></footnote></para>
</section>
@@ -240,7 +225,7 @@ uses is to create directory trees of symlinks to
themselves (though automatically generated by
<command>nix-env</command>), so they too reside in the Nix store. For
instance, in <xref linkend='fig-user-environments' /> the user
environment <filename>/nix/store/5mq2jcn36ldl...-user-env</filename>
environment <filename>/nix/store/0c1p5z4kda11...-user-env</filename>
contains a symlink to just Subversion 1.1.2 (arrows in the figure
indicate symlinks). This would be what we would obtain if we had done
@@ -458,7 +443,7 @@ URL.</para>
<command>nix-channel --add</command>, e.g.,
<screen>
$ nix-channel --add http://nixos.org/releases/nixpkgs/channels/nixpkgs-unstable</screen>
$ nix-channel --add http://nixos.org/channels/nixpkgs-unstable</screen>
subscribes you to a channel that always contains that latest version
of the Nix Packages collection. (Instead of
@@ -553,7 +538,7 @@ dependencies) to a file, and then unpack that file into another Nix
store. For example,
<screen>
$ nix-store --export $(type -p firefox) > firefox.closure</screen>
$ nix-store --export $(nix-store -qR $(type -p firefox)) > firefox.closure</screen>
writes the closure of Firefox to a file. You can then copy this file
to another machine and install the closure:
@@ -567,7 +552,7 @@ another command, e.g. to copy and install a closure directly to/on
another machine:
<screen>
$ nix-store --export $(type -p firefox) | bzip2 | \
$ nix-store --export $(nix-store -qR $(type -p firefox)) | bzip2 | \
ssh alice@itchy.example.org "bunzip2 | nix-store --import"</screen>
But note that <command>nix-copy-closure</command> is generally more
@@ -598,7 +583,7 @@ $ nix-env -i firefox</screen>
and Nix has to build a path that it sees is already present in
<filename>/mnt/nix</filename>, then it will just copy from there
instead of building it from source.</para>
</section>
+6 -5
View File
@@ -14,9 +14,10 @@ to the following chapters.</para>
<listitem><para>Download a source tarball or RPM or Debian/Ubuntu
package from <link xlink:href='http://nixos.org/'/>. Build source
distributions using the regular sequence:
<screen>
$ tar xvfj nix-<replaceable>version</replaceable>.tar.bz2
$ cd nix-<replaceable>version</replaceable>
$ ./configure
$ make
$ make install <lineannotation>(as root)</lineannotation></screen>
@@ -35,13 +36,13 @@ changed using
<listitem><para>You should add
<filename><replaceable>prefix</replaceable>/etc/profile.d/nix.sh</filename>
to your <filename>~/.bashrc</filename> (or some other login
to your <filename>~/.profile</filename> (or some other login
file).</para></listitem>
<listitem><para>Subscribe to the Nix Packages channel.
<screen>
$ nix-channel --add http://nixos.org/releases/nixpkgs/channels/nixpkgs-unstable</screen>
$ nix-channel --add http://nixos.org/channels/nixpkgs-unstable</screen>
</para></listitem>
@@ -69,7 +70,7 @@ libxslt-1.1.0
</para></listitem>
<listitem><para>Install some packages from the channel:
<screen>
$ nix-env -i hello firefox <replaceable>...</replaceable> </screen>
@@ -87,7 +88,7 @@ $ firefox
<lineannotation>(read Slashdot or something)</lineannotation></screen>
</para></listitem>
<listitem><para>Uninstall a package:
<screen>
+580 -4
View File
@@ -5,6 +5,582 @@
<title>Nix Release Notes</title>
<!--==================================================================-->
<section xml:id="ssec-relnotes-1.6.1"><title>Release 1.6.1 (October 28, 2013)</title>
<para>This is primarily a bug fix release. Changes of interest
are:</para>
<itemizedlist>
<listitem>
<para>Nix 1.6 accidentally changed the semantics of antiquoted
paths in strings, such as <literal>"${/foo}/bar"</literal>. This
release reverts to the Nix 1.5.3 behaviour.</para>
</listitem>
<listitem>
<para>Previously, Nix optimised expressions such as
<literal>"${<replaceable>expr</replaceable>}"</literal> to
<replaceable>expr</replaceable>. Thus it neither checked whether
<replaceable>expr</replaceable> could be coerced to a string, nor
applied such coercions. This meant that
<literal>"${123}"</literal> evaluatued to <literal>123</literal>,
and <literal>"${./foo}"</literal> evaluated to
<literal>./foo</literal> (even though
<literal>"${./foo} "</literal> evaluates to
<literal>"/nix/store/<replaceable>hash</replaceable>-foo "</literal>).
Nix now checks the type of antiquoted expressions and
applies coercions.</para>
</listitem>
<listitem>
<para>Nix now shows the exact position of undefined variables. In
particular, undefined variable errors in a <literal>with</literal>
previously didn't show <emphasis>any</emphasis> position
information, so this makes it a lot easier to fix such
errors.</para>
</listitem>
<listitem>
<para>Undefined variables are now treated consistently.
Previously, the <function>tryEval</function> function would catch
undefined variables inside a <literal>with</literal> but not
outside. Now <function>tryEval</function> never catches undefined
variables.</para>
</listitem>
<listitem>
<para>Bash completion in <command>nix-shell</command> now works
correctly.</para>
</listitem>
<listitem>
<para>Stack traces are less verbose: they no longer show calls to
builtin functions and only show a single line for each derivation
on the call stack.</para>
</listitem>
<listitem>
<para>New built-in function: <function>builtins.typeOf</function>,
which returns the type of its argument as a string.</para>
</listitem>
</itemizedlist>
</section>
<!--==================================================================-->
<section xml:id="ssec-relnotes-1.6.0"><title>Release 1.6 (September 10, 2013)</title>
<para>In addition to the usual bug fixes, this release has several new
features:</para>
<itemizedlist>
<listitem>
<para>The command <command>nix-build --run-env</command> has been
renamed to <command>nix-shell</command>.</para>
</listitem>
<listitem>
<para><command>nix-shell</command> now sources
<filename>$stdenv/setup</filename> <emphasis>inside</emphasis> the
interactive shell, rather than in a parent shell. This ensures
that shell functions defined by <literal>stdenv</literal> can be
used in the interactive shell.</para>
</listitem>
<listitem>
<para><command>nix-shell</command> has a new flag
<option>--pure</option> to clear the environment, so you get an
environment that more closely corresponds to the “real” Nix build.
</para>
</listitem>
<listitem>
<para><command>nix-shell</command> now sets the shell prompt
(<envar>PS1</envar>) to ensure that Nix shells are distinguishable
from your regular shells.</para>
</listitem>
<listitem>
<para><command>nix-env</command> no longer requires a
<literal>*</literal> argument to match all packages, so
<literal>nix-env -qa</literal> is equivalent to <literal>nix-env
-qa '*'</literal>.</para>
</listitem>
<listitem>
<para><command>nix-env -i</command> has a new flag
<option>--remove-all</option> (<option>-r</option>) to remove all
previous packages from the profile. This makes it easier to do
declarative package management similar to NixOSs
<option>environment.systemPackages</option>. For instance, if you
have a specification <filename>my-packages.nix</filename> like this:
<programlisting>
with import &lt;nixpkgs> {};
[ thunderbird
geeqie
...
]
</programlisting>
then after any change to this file, you can run:
<screen>
$ nix-env -f my-packages.nix -ir
</screen>
to update your profile to match the specification.</para>
</listitem>
<listitem>
<para>The <literal>with</literal> language construct is now more
lazy. It only evaluates its argument if a variable might actually
refer to an attribute in the argument. For instance, this now
works:
<programlisting>
let
pkgs = with pkgs; { foo = "old"; bar = foo; } // overrides;
overrides = { foo = "new"; };
in pkgs.bar
</programlisting>
This evaluates to <literal>"new"</literal>, while previously it
gave an “infinite recursion” error.</para>
</listitem>
<listitem>
<para>Nix now has proper integer arithmetic operators. For
instance, you can write <literal>x + y</literal> instead of
<literal>builtins.add x y</literal>, or <literal>x &lt;
y</literal> instead of <literal>builtins.lessThan x y</literal>.
The comparison operators also work on strings.</para>
</listitem>
<listitem>
<para>On 64-bit systems, Nix integers are now 64 bits rather than
32 bits.</para>
</listitem>
<listitem>
<para>When using the Nix daemon, the <command>nix-daemon</command>
worker process now runs on the same CPU as the client, on systems
that support setting CPU affinity. This gives a significant speedup
on some systems.</para>
</listitem>
<listitem>
<para>If a stack overflow occurs in the Nix evaluator, you now get
a proper error message (rather than “Segmentation fault”) on some
systems.</para>
</listitem>
<listitem>
<para>In addition to directories, you can now bind-mount regular
files in chroots through the (now misnamed) option
<option>build-chroot-dirs</option>.</para>
</listitem>
</itemizedlist>
<para>This release has contributions from Domen Kožar, Eelco Dolstra,
Florian Friesdorf, Gergely Risko, Ivan Kozik, Ludovic Courtès and Shea
Levy.</para>
</section>
<!--==================================================================-->
<section xml:id="ssec-relnotes-1.5.3"><title>Release 1.5.3 (June 17, 2013)</title>
<para>This is primarily a bug fix release. The following changes are
noteworthy:</para>
<itemizedlist>
<listitem>
<para>Yet another security bug involving hard links to files
outside the store was fixed. This bug only affected multi-user
installations that do not have hard link restrictions
enabled. (NixOS is thus not vulnerable.)</para>
</listitem>
<listitem>
<para>The default binary cache URL has changed from
<uri>http://nixos.org/binary-cache</uri> to
<uri>http://cache.nixos.org</uri>. The latter is hosted on Amazon
CloudFront (courtesy of <link
xlink:href="http://www.logicblox.com/">LogicBlox</link>) and
should provide better performance for users in both Europe and
North America.</para>
</listitem>
<listitem>
<para>The binary cache substituter now prints a warning message if
fetching information from the cache takes more than five seconds.
Thus network or server problems no longer make Nix appear to just
hang.</para>
</listitem>
<listitem>
<para>Stack traces now show function names, e.g.
<screen>
while evaluating `concatMapStrings' at `<replaceable>...</replaceable>/nixpkgs/pkgs/lib/strings.nix:18:25':
</screen>
Also, if a function is called with an unexpected argument, Nix
now shows the name of the argument.
</para>
</listitem>
</itemizedlist>
</section>
<!--==================================================================-->
<section xml:id="ssec-relnotes-1.5.2"><title>Release 1.5.2 (May 13, 2013)</title>
<para>This is primarily a bug fix release. It has contributions from
Eelco Dolstra, Lluís Batlle i Rossell and Shea Levy.</para>
</section>
<!--==================================================================-->
<section xml:id="ssec-relnotes-1.5.1"><title>Release 1.5.1 (February 28, 2013)</title>
<para>The bug fix to the bug fix had a bug itself, of course. But
this time it will work for sure!</para>
</section>
<!--==================================================================-->
<section xml:id="ssec-relnotes-1.5"><title>Release 1.5 (February 27, 2013)</title>
<para>This is a brown paper bag release to fix a regression introduced
by the hard link security fix in 1.4.</para>
</section>
<!--==================================================================-->
<section xml:id="ssec-relnotes-1.4"><title>Release 1.4 (February 26, 2013)</title>
<para>This release fixes a security bug in multi-user operation. It
was possible for derivations to cause the mode of files outside of the
Nix store to be changed to 444 (read-only but world-readable) by
creating hard links to those files (<link
xlink:href="https://github.com/NixOS/nix/commit/5526a282b5b44e9296e61e07d7d2626a79141ac4">details</link>).</para>
<para>There are also the following improvements:</para>
<itemizedlist>
<listitem><para>New built-in function:
<function>builtins.hashString</function>.</para></listitem>
<listitem><para>Build logs are now stored in
<filename>/nix/var/log/nix/drvs/<replaceable>XX</replaceable>/</filename>,
where <replaceable>XX</replaceable> is the first two characters of
the derivation. This is useful on machines that keep a lot of build
logs (such as Hydra servers).</para></listitem>
<listitem><para>The function <function>corepkgs/fetchurl</function>
can now make the downloaded file executable. This will allow
getting rid of all bootstrap binaries in the Nixpkgs source
tree.</para></listitem>
<listitem><para>Language change: The expression <literal>"${./path}
..."</literal> now evaluates to a string instead of a
path.</para></listitem>
</itemizedlist>
</section>
<!--==================================================================-->
<section xml:id="ssec-relnotes-1.3"><title>Release 1.3 (January 4, 2013)</title>
<para>This is primarily a bug fix release. When this version is first
run on Linux, it removes any immutable bits from the Nix store and
increases the schema version of the Nix store. (The previous release
removed support for setting the immutable bit; this release clears any
remaining immutable bits to make certain operations more
efficient.)</para>
<para>This release has contributions from Eelco Dolstra and Stuart
Pernsteiner.</para>
</section>
<!--==================================================================-->
<section xml:id="ssec-relnotes-1.2"><title>Release 1.2 (December 6, 2012)</title>
<para>This release has the following improvements and changes:</para>
<itemizedlist>
<listitem>
<para>Nix has a new binary substituter mechanism: the
<emphasis>binary cache</emphasis>. A binary cache contains
pre-built binaries of Nix packages. Whenever Nix wants to build a
missing Nix store path, it will check a set of binary caches to
see if any of them has a pre-built binary of that path. The
configuration setting <option>binary-caches</option> contains a
list of URLs of binary caches. For instance, doing
<screen>
$ nix-env -i thunderbird --option binary-caches http://cache.nixos.org
</screen>
will install Thunderbird and its dependencies, using the available
pre-built binaries in <uri>http://cache.nixos.org</uri>.
The main advantage over the old “manifest”-based method of getting
pre-built binaries is that you dont have to worry about your
manifest being in sync with the Nix expressions youre installing
from; i.e., you dont need to run <command>nix-pull</command> to
update your manifest. Its also more scalable because you dont
need to redownload a giant manifest file every time.
</para>
<para>A Nix channel can provide a binary cache URL that will be
used automatically if you subscribe to that channel. If you use
the Nixpkgs or NixOS channels
(<uri>http://nixos.org/channels</uri>) you automatically get the
cache <uri>http://cache.nixos.org</uri>.</para>
<para>Binary caches are created using <command>nix-push</command>.
For details on the operation and format of binary caches, see the
<command>nix-push</command> manpage. More details are provided in
<link xlink:href="http://lists.science.uu.nl/pipermail/nix-dev/2012-September/009826.html">this
nix-dev posting</link>.</para>
</listitem>
<listitem>
<para>Multiple output support should now be usable. A derivation
can declare that it wants to produce multiple store paths by
saying something like
<programlisting>
outputs = [ "lib" "headers" "doc" ];
</programlisting>
This will cause Nix to pass the intended store path of each output
to the builder through the environment variables
<literal>lib</literal>, <literal>headers</literal> and
<literal>doc</literal>. Other packages can refer to a specific
output by referring to
<literal><replaceable>pkg</replaceable>.<replaceable>output</replaceable></literal>,
e.g.
<programlisting>
buildInputs = [ pkg.lib pkg.headers ];
</programlisting>
If you install a package with multiple outputs using
<command>nix-env</command>, each output path will be symlinked
into the user environment.</para>
</listitem>
<listitem>
<para>Dashes are now valid as part of identifiers and attribute
names.</para>
</listitem>
<listitem>
<para>The new operation <command>nix-store --repair-path</command>
allows corrupted or missing store paths to be repaired by
redownloading them. <command>nix-store --verify --check-contents
--repair</command> will scan and repair all paths in the Nix
store. Similarly, <command>nix-env</command>,
<command>nix-build</command>, <command>nix-instantiate</command>
and <command>nix-store --realise</command> have a
<option>--repair</option> flag to detect and fix bad paths by
rebuilding or redownloading them.</para>
</listitem>
<listitem>
<para>Nix no longer sets the immutable bit on files in the Nix
store. Instead, the recommended way to guard the Nix store
against accidental modification on Linux is to make it a read-only
bind mount, like this:
<screen>
$ mount --bind /nix/store /nix/store
$ mount -o remount,ro,bind /nix/store
</screen>
Nix will automatically make <filename>/nix/store</filename>
writable as needed (using a private mount namespace) to allow
modifications.</para>
</listitem>
<listitem>
<para>Store optimisation (replacing identical files in the store
with hard links) can now be done automatically every time a path
is added to the store. This is enabled by setting the
configuration option <literal>auto-optimise-store</literal> to
<literal>true</literal> (disabled by default).</para>
</listitem>
<listitem>
<para>Nix now supports <command>xz</command> compression for NARs
in addition to <command>bzip2</command>. It compresses about 30%
better on typical archives and decompresses about twice as
fast.</para>
</listitem>
<listitem>
<para>Basic Nix expression evaluation profiling: setting the
environment variable <envar>NIX_COUNT_CALLS</envar> to
<literal>1</literal> will cause Nix to print how many times each
primop or function was executed.</para>
</listitem>
<listitem>
<para>New primops: <varname>concatLists</varname>,
<varname>elem</varname>, <varname>elemAt</varname> and
<varname>filter</varname>.</para>
</listitem>
<listitem>
<para>The command <command>nix-copy-closure</command> has a new
flag <option>--use-substitutes</option> (<option>-s</option>) to
download missing paths on the target machine using the substitute
mechanism.</para>
</listitem>
<listitem>
<para>The command <command>nix-worker</command> has been renamed
to <command>nix-daemon</command>. Support for running the Nix
worker in “slave” mode has been removed.</para>
</listitem>
<listitem>
<para>The <option>--help</option> flag of every Nix command now
invokes <command>man</command>.</para>
</listitem>
<listitem>
<para>Chroot builds are now supported on systemd machines.</para>
</listitem>
</itemizedlist>
<para>This release has contributions from Eelco Dolstra, Florian
Friesdorf, Mats Erik Andersson and Shea Levy.</para>
</section>
<!--==================================================================-->
<section xml:id="ssec-relnotes-1.1"><title>Release 1.1 (July 18, 2012)</title>
<para>This release has the following improvements:</para>
<itemizedlist>
<listitem>
<para>On Linux, when doing a chroot build, Nix now uses various
namespace features provided by the Linux kernel to improve
build isolation. Namely:
<itemizedlist>
<listitem><para>The private network namespace ensures that
builders cannot talk to the outside world (or vice versa): each
build only sees a private loopback interface. This also means
that two concurrent builds can listen on the same port (e.g. as
part of a test) without conflicting with each
other.</para></listitem>
<listitem><para>The PID namespace causes each build to start as
PID 1. Processes outside of the chroot are not visible to those
on the inside. On the other hand, processes inside the chroot
<emphasis>are</emphasis> visible from the outside (though with
different PIDs).</para></listitem>
<listitem><para>The IPC namespace prevents the builder from
communicating with outside processes using SysV IPC mechanisms
(shared memory, message queues, semaphores). It also ensures
that all IPC objects are destroyed when the builder
exits.</para></listitem>
<listitem><para>The UTS namespace ensures that builders see a
hostname of <literal>localhost</literal> rather than the actual
hostname.</para></listitem>
<listitem><para>The private mount namespace was already used by
Nix to ensure that the bind-mounts used to set up the chroot are
cleaned up automatically.</para></listitem>
</itemizedlist>
</para>
</listitem>
<listitem>
<para>Build logs are now compressed using
<command>bzip2</command>. The command <command>nix-store
-l</command> decompresses them on the fly. This can be disabled
by setting the option <literal>build-compress-log</literal> to
<literal>false</literal>.</para>
</listitem>
<listitem>
<para>The creation of build logs in
<filename>/nix/var/log/nix/drvs</filename> can be disabled by
setting the new option <literal>build-keep-log</literal> to
<literal>false</literal>. This is useful, for instance, for Hydra
build machines.</para>
</listitem>
<listitem>
<para>Nix now reserves some space in
<filename>/nix/var/nix/db/reserved</filename> to ensure that the
garbage collector can run successfully if the disk is full. This
is necessary because SQLite transactions fail if the disk is
full.</para>
</listitem>
<listitem>
<para>Added a basic <function>fetchurl</function> function. This
is not intended to replace the <function>fetchurl</function> in
Nixpkgs, but is useful for bootstrapping; e.g., it will allow us
to get rid of the bootstrap binaries in the Nixpkgs source tree
and download them instead. You can use it by doing
<literal>import &lt;nix/fetchurl.nix> { url =
<replaceable>url</replaceable>; sha256 =
"<replaceable>hash</replaceable>"; }</literal>. (Shea Levy)</para>
</listitem>
<listitem>
<para>Improved RPM spec file. (Michel Alexandre Salim)</para>
</listitem>
<listitem>
<para>Support for on-demand socket-based activation in the Nix
daemon with <command>systemd</command>.</para>
</listitem>
<listitem>
<para>Added a manpage for
<citerefentry><refentrytitle>nix.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
</listitem>
<listitem>
<para>When using the Nix daemon, the <option>-s</option> flag in
<command>nix-env -qa</command> is now much faster.</para>
</listitem>
</itemizedlist>
</section>
<!--==================================================================-->
@@ -936,7 +1512,7 @@ irreversible.</para></warning>
</para></listitem>
<listitem><para>You can now unambigously specify which derivation to
<listitem><para>You can now unambiguously specify which derivation to
build or install in <command>nix-env</command>,
<command>nix-instantiate</command> and <command>nix-build</command>
using the <option>--attr</option> / <option>-A</option> flags, which
@@ -1076,7 +1652,7 @@ irreversible.</para></warning>
<itemizedlist>
<listitem><para>Make sure that the garbage collector can run
succesfully when the disk is full
successfully when the disk is full
(<literal>NIX-18</literal>).</para></listitem>
<listitem><para><command>nix-env</command> now locks the profile
@@ -1431,7 +2007,7 @@ $ nix-env -f .../i686-linux.nix -i -E 'x: x.firefoxWrapper'</screen>
</itemizedlist></para></listitem>
<listitem><para>A hash of the contents of a store path is now stored
in the database after a succesful build. This allows you to check
in the database after a successful build. This allows you to check
whether store paths have been tampered with: <command>nix-store
--verify --check-contents</command>.</para></listitem>
@@ -1595,7 +2171,7 @@ $ nix-env -f .../i686-linux.nix -i -E 'x: x.firefoxWrapper'</screen>
<itemizedlist>
<listitem><para>Derivations for other platforms are filtered out
(which can be overriden using
(which can be overridden using
<option>--system-filter</option>).</para></listitem>
<listitem><para><option>--install</option> by default now
+2 -2
View File
@@ -17,7 +17,7 @@ bug tracker</link> for a list of currently known issues.</para>
$ nix-env -i docbook-xml
...
adding /nix/store/s5hyxgm62gk2...-docbook-xml-4.2
collission between `/nix/store/s5hyxgm62gk2...-docbook-xml-4.2/xml/dtd/docbook/calstblx.dtd'
collision between `/nix/store/s5hyxgm62gk2...-docbook-xml-4.2/xml/dtd/docbook/calstblx.dtd'
and `/nix/store/06h377hr4b33...-docbook-xml-4.3/xml/dtd/docbook/calstblx.dtd'
at /nix/store/...-builder.pl line 62.</screen>
@@ -68,7 +68,7 @@ in <filename>/nix/store</filename>, as can be seen using <command>ls
$ ls -l /nix/store
drwxrwxrwt 32000 nix nix 4620288 Sep 8 15:08 store</screen>
The <literal>ext2</literal> file system is limited to a inode link
The <literal>ext2</literal> file system is limited to an inode link
count of 32,000 (each subdirectory increasing the count by one).
Furthermore, the <literal>st_nlink</literal> field of the
<function>stat</function> system call is a 16-bit value.</para>
+146 -119
View File
@@ -15,7 +15,7 @@ on to a more in-depth look at the Nix expression language.</para>
For more extensive information on adding packages to the Nix Packages
collection (such as functions in the standard environment and coding
conventions), please consult <link
xlink:href="http://hydra.nixos.org/job/nixpkgs/trunk/tarball/latest/download-by-type/doc/manual">its
xlink:href="http://nixos.org/nixpkgs/manual/">its
manual</link>.</para></note>
@@ -106,7 +106,7 @@ the single Nix expression in that directory
here, the entire remainder of the file is the body of the
function; when given the required arguments, the body should
describe how to build an instance of the Hello package.</para>
</callout>
<callout arearefs='ex-hello-nix-co-2'>
@@ -118,10 +118,10 @@ the single Nix expression in that directory
<varname>stdenv.mkDerivation</varname>.
<varname>mkDerivation</varname> is a function provided by
<varname>stdenv</varname> that builds a package from a set of
<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> =
<emphasis>attributes</emphasis>. A set is just a list of
key/value pairs where each key is a string and each value is an
arbitrary Nix expression. They take the general form <literal>{
<replaceable>name1</replaceable> =
<replaceable>expr1</replaceable>; <replaceable>...</replaceable>
<replaceable>nameN</replaceable> =
<replaceable>exprN</replaceable>; }</literal>.</para>
@@ -190,7 +190,7 @@ perl = perl;</programlisting>
with the same name happen to be in scope.</para>
</callout>
</calloutlist>
</para>
@@ -301,7 +301,7 @@ steps:</para>
(<literal>make install</literal>).</para>
</callout>
</calloutlist>
<para>If you are wondering about the absence of error checking on the
@@ -321,7 +321,7 @@ error check.</para>
...
rec { <co xml:id='ex-hello-composition-co-1' />
hello = import ../applications/misc/hello/ex-1 <co xml:id='ex-hello-composition-co-2' /> { <co xml:id='ex-hello-composition-co-3' />
inherit fetchurl stdenv perl;
};
@@ -330,10 +330,10 @@ rec { <co xml:id='ex-hello-composition-co-1' />
inherit fetchurl stdenv;
};
fetchurl = import ../build-support/fetchurl {
fetchurl = import ../build-support/fetchurl {
inherit stdenv; ...
};
stdenv = ...;
}
@@ -384,9 +384,9 @@ some fragments of
<para>This is where the actual composition takes place. Here we
<emphasis>call</emphasis> the function imported from
<filename>../applications/misc/hello/ex-1</filename> with an
attribute set containing the things that the function expects,
namely <varname>fetchurl</varname>, <varname>stdenv</varname>, and
<filename>../applications/misc/hello/ex-1</filename> with a set
containing the things that the function expects, namely
<varname>fetchurl</varname>, <varname>stdenv</varname>, and
<varname>perl</varname>. We use inherit again to use the
attributes defined in the surrounding scope (we could also have
written <literal>fetchurl = fetchurl;</literal>, etc.).</para>
@@ -476,8 +476,8 @@ that the path denoted by <envar>out</envar> is now
will see that the path is already valid and finish immediately. If a
build fails, either because it returns a non-zero exit code, because
Nix or the builder are killed, or because the machine crashes, then
the output path will not be registered as valid. If you try to build
the derivation again, Nix will remove the output path if it exists
the output paths will not be registered as valid. If you try to build
the derivation again, Nix will remove the output paths if they exist
(e.g., because the builder died half-way through <literal>make
install</literal>) and try again. Note that there is no
<quote>negative caching</quote>: Nix doesn't remember that a build
@@ -543,7 +543,7 @@ genericBuild <co xml:id='ex-hello-builder2-co-3' /></programlisting>
<calloutlist>
<callout arearefs='ex-hello-builder2-co-1'>
<para>The <envar>buildInputs</envar> variable tells
<filename>setup</filename> to use the indicated packages as
<quote>inputs</quote>. This means that if a package provides a
@@ -568,7 +568,7 @@ genericBuild <co xml:id='ex-hello-builder2-co-3' /></programlisting>
the file <literal>$stdenv/setup</literal>.</para>
</callout>
<callout arearefs='ex-hello-builder2-co-3'>
<para>The final step calls the shell function
@@ -580,7 +580,7 @@ genericBuild <co xml:id='ex-hello-builder2-co-3' /></programlisting>
see <xref linkend='sec-standard-environment' />.</para>
</callout>
</calloutlist>
<para>Discerning readers will note that the
@@ -617,7 +617,7 @@ Laziness means that arguments to functions are evaluated only when
they are needed. Functional means that functions are
<quote>normal</quote> values that can be passed around and manipulated
in interesting ways. The language is not a full-featured, general
purpose language. It's main job is to describe packages,
purpose language. Its main job is to describe packages,
compositions of packages, and the variability within
packages.</para>
@@ -701,10 +701,10 @@ configureFlags = "
number of spaces equal to the minimal indentation of the string as
a whole (disregarding the indentation of empty lines). For
instance, the first and second line are indented two space, while
the third line is indented three spaces. Thus, two spaces are
the third line is indented four spaces. Thus, two spaces are
stripped from each line, so the resulting string is
<programlisting>
<programlisting>
"This is the first line.\nThis is the second line.\n This is the third line.\n"</programlisting>
</para>
@@ -714,19 +714,19 @@ configureFlags = "
text on the initial line.</para>
<para>Antiquotation
(<literal>${<replaceable>expr</replaceable>}}</literal>) is
(<literal>${<replaceable>expr</replaceable>}</literal>) is
supported in indented strings.</para>
<para>Since <literal>${</literal> and <literal>''</literal> have
special meaning in indented strings, you need a way to quote them.
<literal>${</literal> can be escaped by prefixing it with
<literal>''</literal>, i.e., <literal>''${</literal>.
<literal>''</literal> can be escaped by prefixing it with
<literal>'</literal>, i.e., <literal>'''</literal>. Finally,
linefeed, carriage-return and tab characters can be writted as
<literal>''\n</literal>, <literal>''\r</literal>,
<literal>''\t</literal>.</para>
<literal>''</literal> (that is, two single quotes), i.e.,
<literal>''${</literal>. <literal>''</literal> can be escaped by
prefixing it with <literal>'</literal>, i.e.,
<literal>'''</literal>. Finally, linefeed, carriage-return and
tab characters can be written as <literal>''\n</literal>,
<literal>''\r</literal>, <literal>''\t</literal>.</para>
<para>Indented strings are primarily useful in that they allow
multi-line string literals to follow the indentation of the
enclosing Nix expression, and that less escaping is typically
@@ -745,7 +745,7 @@ stdenv.mkDerivation {
${if enableBar then "cp bar $out/bin" else ""}
'';
<replaceable>...</replaceable>
}
}
</programlisting>
</para>
@@ -775,13 +775,13 @@ stdenv.mkDerivation {
absolute at parse time relative to the directory of the Nix
expression that contained it. For instance, if a Nix expression in
<filename>/foo/bar/bla.nix</filename> refers to
<filename>../xyzzy/fnord.nix</filename>, the absolutised path is
<filename>../xyzzy/fnord.nix</filename>, the absolute path is
<filename>/foo/xyzzy/fnord.nix</filename>.</para></listitem>
<listitem><para><emphasis>Booleans</emphasis> with values
<literal>true</literal> and
<literal>false</literal>.</para></listitem>
</itemizedlist>
</para>
@@ -805,20 +805,21 @@ to be enclosed in parentheses. If they had been omitted, e.g.,
[ 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>
function and the fifth being a set.</para>
</simplesect>
<simplesect><title>Attribute sets</title>
<simplesect><title>Sets</title>
<para>Attribute sets are really the core of the language, since
ultimately it's all about creating derivations, which are really just
<para>Sets are really the core of the language, since ultimately the
Nix language is all about creating derivations, which are really just
sets of attributes to be passed to build scripts.</para>
<para>Attribute sets are just a list of name/value pairs enclosed in
curly brackets, where each value is an arbitrary expression terminated
by a semicolon. For example:
<para>Sets are just a list of name/value pairs (called
<emphasis>attributes</emphasis>) enclosed in curly brackets, where
each value is an arbitrary expression terminated by a semicolon. For
example:
<programlisting>
{ x = 123;
@@ -826,12 +827,12 @@ by a semicolon. For example:
y = f { bla = 456; };
}</programlisting>
This defines an attribute set with attributes named
<varname>x</varname>, <varname>test</varname>, <varname>y</varname>.
The order of the attributes is irrelevant. An attribute name may only
occur once.</para>
This defines a set with attributes named <varname>x</varname>,
<varname>text</varname>, <varname>y</varname>. The order of the
attributes is irrelevant. An attribute name may only occur
once.</para>
<para>Attributes can be selected from an attribute set using the
<para>Attributes can be selected from a set using the
<literal>.</literal> operator. For instance,
<programlisting>
@@ -864,10 +865,10 @@ This will evaluate to <literal>123</literal>.</para>
<section><title>Language constructs</title>
<simplesect><title>Recursive attribute sets</title>
<simplesect><title>Recursive sets</title>
<para>Recursive attribute sets are just normal attribute sets, but the
attributes can refer to each other. For example,
<para>Recursive sets are just normal sets, but the attributes can
refer to each other. For example,
<programlisting>
rec {
@@ -880,11 +881,11 @@ evaluates to <literal>123</literal>. Note that without
<literal>rec</literal> the binding <literal>x = y;</literal> would
refer to the variable <varname>y</varname> in the surrounding scope,
if one exists, and would be invalid if no such variable exists. That
is, in a normal (non-recursive) attribute set, attributes are not
added to the lexical scope; in a recursive set, they are.</para>
is, in a normal (non-recursive) set, attributes are not added to the
lexical scope; in a recursive set, they are.</para>
<para>Recursive attribute sets of course introduce the danger of
infinite recursion. For example,
<para>Recursive sets of course introduce the danger of infinite
recursion. For example,
<programlisting>
rec {
@@ -901,8 +902,8 @@ encountered</quote>).</para></footnote>.</para>
<simplesect><title>Let-expressions</title>
<para>A let-expression allows you define local
variables for an expression. For instance,
<para>A let-expression allows you define local variables for an
expression. For instance,
<programlisting>
let
@@ -914,32 +915,26 @@ evaluates to <literal>"foobar"</literal>.
</para>
<note><para>There is also an obsolete form of let-expression,
<literal>let { <replaceable>attrs</replaceable> }</literal>, which is
translated to <literal>rec { <replaceable>attrs</replaceable>
}.body</literal>. That is, the body of the let-expression is the
<literal>body</literal> attribute of the attribute set.</para></note>
</simplesect>
<simplesect><title>Inheriting attributes</title>
<para>When defining an attribute set it is often convenient to copy
variables from the surrounding lexical scope (e.g., when you want to
propagate attributes). This can be shortened using the
<para>When defining a set it is often convenient to copy variables
from the surrounding lexical scope (e.g., when you want to propagate
attributes). This can be shortened using the
<literal>inherit</literal> keyword. For instance,
<programlisting>
let x = 123; in
let x = 123; in
{ inherit x;
y = 456;
}</programlisting>
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
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 set. For instance, in this fragment
from <filename>all-packages.nix</filename>,
<programlisting>
@@ -958,13 +953,12 @@ from <filename>all-packages.nix</filename>,
libjpg = ...;
...</programlisting>
the attribute set used in the function call to the function defined in
the set used in the function call to the function defined in
<filename>../tools/graphics/graphviz</filename> inherits a number of
variables from the surrounding scope (<varname>fetchurl</varname>
... <varname>yacc</varname>), but also inherits
<varname>libXaw</varname> (the X Athena Widgets) from the
<varname>xlibs</varname> (X11 client-side libraries) attribute
set.</para>
<varname>xlibs</varname> (X11 client-side libraries) set.</para>
</simplesect>
@@ -982,7 +976,7 @@ argument. There are three kinds of patterns:</para>
<itemizedlist>
<listitem><para>If a pattern is a single identifier, then the
function matches any argument. Example:
@@ -1002,12 +996,12 @@ map (concat "foo") [ "bar" "bla" "abc" ]</programlisting>
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>
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
<listitem><para>A <emphasis>set pattern</emphasis> of the form
<literal>{ name1, name2, …, nameN }</literal> matches a 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>
@@ -1016,7 +1010,7 @@ map (concat "foo") [ "bar" "bla" "abc" ]</programlisting>
<varname>x</varname>, <varname>y</varname> and
<varname>z</varname>. No other attributes are allowed. If you want
to allow additional arguments, you can use an ellipsis
(<literal>...</literal>):
(<literal>...</literal>):
<programlisting>
{ x, y, z, ... }: z + y + x</programlisting>
@@ -1164,7 +1158,7 @@ used in the Nix expression for Subversion.</para>
</calloutlist>
</simplesect>
<simplesect><title>With-expressions</title>
@@ -1174,9 +1168,8 @@ used in the Nix expression for Subversion.</para>
<programlisting>
with <replaceable>e1</replaceable>; <replaceable>e2</replaceable></programlisting>
introduces the attribute set <replaceable>e1</replaceable> into the
lexical scope of the expression <replaceable>e2</replaceable>. For
instance,
introduces the set <replaceable>e1</replaceable> into the lexical
scope of the expression <replaceable>e2</replaceable>. For instance,
<programlisting>
let as = { x = "foo"; y = "bar"; };
@@ -1235,7 +1228,7 @@ weakest binding).</para>
</entry>
<entry>none</entry>
<entry>Select attribute denoted by the attribute path
<replaceable>attrpath</replaceable> from attribute set
<replaceable>attrpath</replaceable> from set
<replaceable>e</replaceable>. (An attribute path is a
dot-separated list of attribute names.) If the attribute
doesnt exist, return <replaceable>def</replaceable> if
@@ -1251,8 +1244,8 @@ weakest binding).</para>
<entry><replaceable>e</replaceable> <literal>?</literal>
<replaceable>attrpath</replaceable></entry>
<entry>none</entry>
<entry>Test whether attribute set <replaceable>e</replaceable>
contains the attribute denoted by <replaceable>attrpath</replaceable>;
<entry>Test whether set <replaceable>e</replaceable> contains
the attribute denoted by <replaceable>attrpath</replaceable>;
return <literal>true</literal> or
<literal>false</literal>.</entry>
</row>
@@ -1275,10 +1268,11 @@ weakest binding).</para>
<entry><replaceable>e1</replaceable> <literal>//</literal>
<replaceable>e2</replaceable></entry>
<entry>right</entry>
<entry>Return an attribute set consisting of the attributes in
<entry>Return a set consisting of the attributes in
<replaceable>e1</replaceable> and
<replaceable>e2</replaceable> (with the latter taking
precedence over the former in case of equally named attributes).</entry>
precedence over the former in case of equally named
attributes).</entry>
</row>
<row>
<entry><replaceable>e1</replaceable> <literal>==</literal>
@@ -1322,9 +1316,9 @@ weakest binding).</para>
<section xml:id="ssec-derivation"><title>Derivations</title>
<para>The most important built-in function is
<function>derivation</function>, which is used to describe a
single derivation (a build action). It takes as input an attribute
set, the attributes of which specify the inputs of the build.</para>
<function>derivation</function>, which is used to describe a single
derivation (a build action). It takes as input a set, the attributes
of which specify the inputs of the build.</para>
<itemizedlist>
@@ -1343,7 +1337,7 @@ set, the attributes of which specify the inputs of the build.</para>
<listitem><para>There must be an attribute named
<varname>name</varname> whose value must be a string. This is used
as a symbolic name for the package by <command>nix-env</command>,
and it is appended to the hash in the output path of the
and it is appended to the output paths of the
derivation.</para></listitem>
<listitem><para>There must be an attribute named
@@ -1358,7 +1352,7 @@ set, the attributes of which specify the inputs of the build.</para>
<itemizedlist>
<listitem><para>Strings, URIs, and integers are just passed
<listitem><para>Strings and integers are just passed
verbatim.</para></listitem>
<listitem><para>A <emphasis>path</emphasis> (e.g.,
@@ -1369,8 +1363,8 @@ set, the attributes of which specify the inputs of the build.</para>
should reside in the Nix store.</para></listitem>
<listitem><para>A <emphasis>derivation</emphasis> causes that
derivation to be built prior to the present derivation; the
output path is put in the environment
derivation to be built prior to the present derivation; its
default output path is put in the environment
variable.</para></listitem>
<listitem><para>Lists of the previous types are also allowed.
@@ -1389,14 +1383,48 @@ set, the attributes of which specify the inputs of the build.</para>
specifies command-line arguments to be passed to the builder. It
should be a list.</para></listitem>
<listitem><para>The optional attribute <varname>outputs</varname>
specifies a list of symbolic outputs of the derivation. By default,
a derivation produces a single output path, denoted as
<literal>out</literal>. However, derivations can produce multiple
output paths. This is useful because it allows outputs to be
downloaded or garbage-collected separately. For instance, imagine a
library package that provides a dynamic library, header files, and
documentation. A program that links against the library doesnt
need the header files and documentation at runtime, and it doesnt
need the documentation at build time. Thus, the library package
could specify:
<programlisting>
outputs = [ "lib" "headers" "doc" ];
</programlisting>
This will cause Nix to pass environment variables
<literal>lib</literal>, <literal>headers</literal> and
<literal>doc</literal> to the builder containing the intended store
paths of each output. The builder would typically do something like
<programlisting>
./configure --libdir=$lib/lib --includedir=$headers/include --docdir=$doc/share/doc
</programlisting>
for an Autoconf-style package. You can refer to each output of a
derivation by selecting it as an attribute, e.g.
<programlisting>
buildInputs = [ pkg.lib pkg.headers ];
</programlisting>
The first element of <varname>output</varname> determines the
<emphasis>default output</emphasis>. Thus, you could also write
<programlisting>
buildInputs = [ pkg pkg.headers ];
</programlisting>
since <literal>pkg</literal> is equivalent to
<literal>pkg.lib</literal>.</para></listitem>
</itemizedlist>
<para>(Note that <function>mkDerivation</function> in the standard
<para>The function <function>mkDerivation</function> in the standard
environment is a wrapper around <function>derivation</function> that
adds a default value for <varname>system</varname> and always uses
Bash as the builder, to which the supplied builder is passed as a
command-line argument. See <xref linkend='sec-standard-environment'
/>.)</para>
/>.</para>
<para>The builder is executed as follows:
@@ -1440,17 +1468,19 @@ command-line argument. See <xref linkend='sec-standard-environment'
top-level Nix store directory (typically,
<filename>/nix/store</filename>).</para></listitem>
<listitem><para><envar>out</envar> is set to point to the output
path of the derivation, which is a subdirectory of the Nix store.
The output path is a concatenation of the cryptographic hash of
all build inputs, and the <varname>name</varname>
attribute.</para></listitem>
<listitem><para>For each output declared in
<varname>outputs</varname>, the corresponding environment variable
is set to point to the intended path in the Nix store for that
output. Each output path is a concatenation of the cryptographic
hash of all build inputs, the <varname>name</varname> attribute
and the output name. (The output name is omitted if its
<literal>out</literal>.)</para></listitem>
</itemizedlist>
</para></listitem>
<listitem><para>If the output path already exists, it is removed.
<listitem><para>If an output path already exists, it is removed.
Also, locks are acquired to prevent multiple Nix instances from
performing the same build at the same time.</para></listitem>
@@ -1464,14 +1494,11 @@ command-line argument. See <xref linkend='sec-standard-environment'
<listitem><para>The temporary directory is removed (unless the
<option>-K</option> option was specified).</para></listitem>
<listitem><para>If the build was successful, Nix scans the output
for references to the paths of the inputs. These so-called
<emphasis>retained dependencies</emphasis> could be used when the
output of the derivation is used (e.g., when it's executed or used
as input to another derivation), so if we deploy the derivation, we
should copy the retained dependencies as well. The scan is
performed by looking for the hash parts of file names of the
inputs.</para></listitem>
<listitem><para>If the build was successful, Nix scans each output
path for references to input paths by looking for the hash parts of
the input paths. Since these are potential runtime dependencies,
Nix registers them as dependencies of the output
paths.</para></listitem>
<listitem><para>After the build, Nix sets the last-modified
timestamp on all files in the build result to 1 (00:00:01 1/1/1970
@@ -1497,7 +1524,7 @@ attributes.</para>
<variablelist>
<varlistentry><term><varname>allowedReferences</varname></term>
<listitem><para>The optional attribute
<varname>allowedReferences</varname> specifies a list of legal
references (dependencies) of the output of the builder. For
@@ -1515,7 +1542,7 @@ allowedReferences = [];
</varlistentry>
<varlistentry><term><varname>exportReferencesGraph</varname></term>
<listitem><para>This attribute allows builders access to the
@@ -1626,7 +1653,7 @@ stdenv.mkDerivation {
outputHashMode = "flat";
outputHashAlgo = "md5";
outputHash = md5;
inherit url;
}
</programlisting>
@@ -1655,7 +1682,7 @@ stdenv.mkDerivation {
<para>This is the default.</para></listitem>
</varlistentry>
<varlistentry><term><literal>"recursive"</literal></term>
<listitem><para>The hash is computed over the NAR archive dump
@@ -1676,10 +1703,10 @@ stdenv.mkDerivation {
linkend="sec-nix-hash"><command>nix-hash</command> command</link>
for information about converting to and from base-32
notation.)</para></listitem>
</varlistentry>
<varlistentry><term><varname>impureEnvVars</varname></term>
<listitem><para>This attribute allows you to specify a list of
@@ -1706,7 +1733,7 @@ impureEnvVars = [ "http_proxy" "https_proxy" <replaceable>...</replaceable> ];
</varlistentry>
<varlistentry><term><varname>preferLocalBuild</varname></term>
<listitem><para>If this attribute is set to
+1 -1
View File
@@ -78,7 +78,7 @@ The hook `nix-mode-hook' is run when Nix mode is started.
("\\<isNull\\>" . font-lock-builtin-face)
("[a-zA-Z][a-zA-Z0-9\\+-\\.]*:[a-zA-Z0-9%/\\?:@&=\\+\\$,_\\.!~\\*'-]+"
. font-lock-constant-face)
("\\<\\([a-zA-Z_][a-zA-Z0-9_'\.]*\\)[ \t]*="
("\\<\\([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)
+10
View File
@@ -0,0 +1,10 @@
[Unit]
Description=Helper daemon for managing secure, multi-user Nix stores
After=syslog.target
[Service]
Type=simple
ExecStart=/usr/bin/nix-daemon
[Install]
WantedBy=multi-user.target
-181
View File
@@ -1,181 +0,0 @@
### Option `gc-keep-outputs'
#
# If `true', the garbage collector will keep the outputs of
# non-garbage derivations. If `false' (default), outputs will be
# deleted unless they are GC roots themselves (or reachable from other
# roots).
#
# In general, outputs must be registered as roots separately.
# However, even if the output of a derivation is registered as a root,
# the collector will still delete store paths that are used only at
# build time (e.g., the C compiler, or source tarballs downloaded from
# the network). To prevent it from doing so, set this option to
# `true'.
#gc-keep-outputs = false
### Option `gc-keep-derivations'
#
# If `true' (default), the garbage collector will keep the derivations
# from which non-garbage store paths were built. If `false', they
# will be deleted unless explicitly registered as a root (or reachable
# from other roots).
#
# Keeping derivation around is useful for querying and traceability
# (e.g., it allows you to ask with what dependencies or options a
# store path was built), so by default this option is on. Turn it off
# to safe a bit of disk space (or a lot if `gc-keep-outputs' is also
# turned on).
#gc-keep-derivations = true
### Option `env-keep-derivations'
#
# If `false' (default), derivations are not stored in Nix user
# environments. That is, the derivation any build-time-only
# dependencies may be garbage-collected.
#
# If `true', when you add a Nix derivation to a user environment, the
# path of the derivation is stored in the user environment. Thus, the
# derivation will not be garbage-collected until the user environment
# generation is deleted (`nix-env --delete-generations'). To prevent
# build-time-only dependencies from being collected, you should also
# turn on `gc-keep-outputs'.
#
# The difference between this option and `gc-keep-derivations' is that
# this one is `sticky': it applies to any user environment created
# while this option was enabled, while `gc-keep-derivations' only
# applies at the moment the garbage collector is run.
#env-keep-derivations = false
### Option `build-max-jobs'
#
# This option defines the maximum number of jobs that Nix will try to
# build in parallel. The default is 1. You should generally set it
# to the number of CPUs in your system (e.g., 2 on a Athlon 64 X2).
# It can be overriden using the `--max-jobs' / `-j' command line
# switch.
#build-max-jobs = 1
### Option `build-cores'
#
# This option defines the number of CPU cores to utilize in parallel
# within a build job, i.e. by passing an appropriate `-jN' flag to GNU
# Make. The default is 1, meaning that parallel building within jobs
# is disabled. Passing the special value `0' causes Nix to try and
# auto-detect the number of available cores on the local host. This
# setting can be overridden using the `--cores' command line switch.
#build-cores = 1
### Option `build-max-silent-time'
#
# This option defines the maximum number of seconds that a builder can
# go without producing any data on standard output or standard error.
# This is useful (for instance in a automated build system) to catch
# builds that are stuck in an infinite loop, or to catch remote builds
# that are hanging due to network problems. It can be overriden using
# the `--max-silent-time' command line switch.
#
# The value 0 means that there is no timeout. This is also the
# default.
#
# Example:
# build-max-silent-time = 600 # = 10 minutes
#build-max-silent-time = 0
### Option `build-users-group'
#
# This options specifies the Unix group containing the Nix build user
# accounts. In multi-user Nix installations, builds should not
# be performed by the Nix account since that would allow users to
# arbitrarily modify the Nix store and database by supplying specially
# crafted builders; and they cannot be performed by the calling user
# since that would allow him/her to influence the build result.
#
# Therefore, if this option is non-empty and specifies a valid group,
# builds will be performed under the user accounts that are a member
# of the group specified here (as listed in /etc/group). Those user
# accounts should not be used for any other purpose!
#
# Nix will never run two builds under the same user account at the
# same time. This is to prevent an obvious security hole: a malicious
# user writing a Nix expression that modifies the build result of a
# legitimate Nix expression being built by another user. Therefore it
# is good to have as many Nix build user accounts as you can spare.
# (Remember: uids are cheap.)
#
# The build users should have permission to create files in the Nix
# store, but not delete them. Therefore, /nix/store should be owned
# by the Nix account, its group should be the group specified here,
# and its mode should be 1775.
#
# If the build users group is empty, builds will be performed under
# the uid of the Nix process (that is, the uid of the caller if
# $NIX_REMOTE is empty, the uid under which the Nix daemon runs if
# $NIX_REMOTE is `daemon', or the uid that owns the setuid nix-worker
# program if $NIX_REMOTE is `slave'). Obviously, this should not be
# used in multi-user settings with untrusted users.
#
# The default is empty.
#
# Example:
# build-users-group = nix-builders
#build-users-group =
### Option `build-use-chroot'
#
# If set to `true', builds will be performed in a chroot environment,
# i.e., the build will be isolated from the normal file system
# hierarchy and will only see the Nix store, the temporary build
# directory, and the directories configured with the
# `build-chroot-dirs' option (such as /proc and /dev). This is useful
# to prevent undeclared dependencies on files in directories such as
# /usr/bin.
#
# The use of a chroot requires that Nix is run as root (but you can
# still use the "build users" feature to perform builds under
# different users than root). Currently, chroot builds only work on
# Linux because Nix uses "bind mounts" to make the Nix store and other
# directories available inside the chroot.
#
# The default is `false'.
#
# Example:
# build-use-chroot = true
#build-use-chroot = false
### Option `build-chroot-dirs'
#
# When builds are performed in a chroot environment, Nix will mount
# (using `mount --bind' on Linux) some directories from the normal
# file system hierarchy inside the chroot. These are the Nix store,
# the temporary build directory (usually /tmp/nix-<pid>-<number>) and
# the directories listed here. The default is "/dev /dev/pts /proc".
# Files in /dev (such as /dev/null) are needed by many builds, and
# some files in /proc may also be needed occasionally.
#
# Example:
# build-use-chroot = /dev /proc /bin
#build-chroot-dirs = /dev /dev/pts /proc
### Option `build-cache-failure'
#
# If this option is enabled, Nix will do negative caching; that is, it
# will remember failed builds, and won't attempt to try to build them
# again if you ask for it. Negative caching is disabled by default
# because Nix cannot distinguish between permanent build errors (e.g.,
# a syntax error in a source file) and transient build errors (e.g., a
# full disk), as they both cause the builder to return a non-zero exit
# code. You can clear the cache by doing `rm -f
# /nix/var/nix/db/failed/*'.
#
# Example:
# build-cache-failure = true
#build-cache-failure = false
+177 -51
View File
@@ -1,29 +1,29 @@
%define enable_setuid ""
%define nix_user "nix"
%define nix_group "nix"
# If set, the Nix user and group will be created by the RPM
# pre-install script.
%define nix_user_uid ""
%define nix_group_gid ""
%global nixbld_user "nix-builder-"
%global nixbld_group "nix-builders"
Summary: The Nix software deployment system
Name: nix
Version: @version@
Release: 1
License: GPL
Group: Software Deployment
Release: 2%{?dist}
License: LGPLv2+
%if 0%{?rhel}
Group: Applications/System
%endif
URL: http://nixos.org/
Source0: %{name}-@version@.tar.bz2
BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot
Prefix: /usr
Source0: %{name}-%{version}.tar.gz
%if 0%{?el5}
BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
%endif
BuildRequires: perl(DBD::SQLite)
BuildRequires: perl(DBI)
BuildRequires: perl(WWW::Curl)
BuildRequires: perl(ExtUtils::ParseXS)
Requires: /usr/bin/perl
Requires: curl
Requires: perl-DBD-SQLite
Requires: perl-devel
Requires: bzip2
Requires: bzip2-libs
Requires: sqlite
Requires: gzip
Requires: xz
BuildRequires: bzip2-devel
BuildRequires: sqlite-devel
@@ -31,7 +31,6 @@ BuildRequires: sqlite-devel
Provides: perl(Nix::SSH)
%description
Nix is a purely functional package manager. It allows multiple
versions of a package to be installed side-by-side, ensures that
dependency specifications are complete, supports atomic upgrades and
@@ -39,52 +38,179 @@ rollbacks, allows non-root users to install software, and has many
other features. It is the basis of the NixOS Linux distribution, but
it can be used equally well under other Unix systems.
%package devel
Summary: Development files for %{name}
%if 0%{?rhel}
Group: Development/Libraries
%endif
Requires: %{name}%{?_isa} = %{version}-%{release}
%description devel
The %{name}-devel package contains libraries and header files for
developing applications that use %{name}.
%package doc
Summary: Documentation files for %{name}
%if 0%{?rhel}
Group: Documentation
%endif
BuildArch: noarch
Requires: %{name} = %{version}-%{release}
%description doc
The %{name}-doc package contains documentation files for %{name}.
%package -n emacs-%{name}
Summary: Nix mode for Emacs
%if 0%{?rhel}
Group: Applications/Editors
%endif
BuildArch: noarch
BuildRequires: emacs
Requires: emacs(bin) >= %{_emacs_version}
%description -n emacs-%{name}
This package provides a major mode for editing Nix expressions.
%package -n emacs-%{name}-el
Summary: Elisp source files for emacs-%{name}
%if 0%{?rhel}
Group: Applications/Editors
%endif
BuildArch: noarch
Requires: emacs-%{name} = %{version}-%{release}
%description -n emacs-%{name}-el
This package contains the elisp source file for the Nix major mode for
GNU Emacs. You do not need to install this package to run Nix. Install
the emacs-%{name} package to edit Nix expressions with GNU Emacs.
%prep
%setup -q
# Install Perl modules to vendor_perl
# configure.ac need to be changed to make this global; however, this will
# also affect NixOS. Use discretion.
%{__sed} -i 's|perl5/site_perl/$perlversion/$perlarchname|perl5/vendor_perl|' \
configure
%build
extraFlags=
if test -n "%{enable_setuid}"; then
extraFlags="$extraFlags --enable-setuid"
if test -n "%{nix_user}"; then
extraFlags="$extraFlags --with-nix-user=%{nix_user}"
fi
if test -n "%{nix_group}"; then
extraFlags="$extraFlags --with-nix-group=%{nix_group}"
fi
fi
./configure --prefix=%{_prefix} --sysconfdir=/etc $extraFlags
make
make check
# - override docdir so large documentation files are owned by the
# -doc subpackage
# - set localstatedir by hand to the preferred nix value
%configure --localstatedir=/nix/var \
--docdir=%{_defaultdocdir}/%{name}-doc-%{version} \
$extraFlags
make %{?_smp_flags}
%{_emacs_bytecompile} misc/emacs/nix-mode.el
%install
%if 0%{?el5}
rm -rf $RPM_BUILD_ROOT
%endif
make DESTDIR=$RPM_BUILD_ROOT install
rm $RPM_BUILD_ROOT/etc/nix/nix.conf
strip $RPM_BUILD_ROOT/%{_prefix}/bin/* || true
find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';'
# Fix symlink: we want to link to the versioned soname, not to the
# unversioned one that'd be put in -devel
pushd $RPM_BUILD_ROOT%{perl_vendorarch}/auto/Nix/Store
ln -sf %{_libdir}/nix/libNixStore.so.0 Store.so
popd
# Specify build users group
echo "build-users-group = %{nixbld_group}" > $RPM_BUILD_ROOT%{_sysconfdir}/nix/nix.conf
# make per-user directories
for d in profiles gcroots;
do
mkdir $RPM_BUILD_ROOT/nix/var/nix/$d/per-user
chmod 1777 $RPM_BUILD_ROOT/nix/var/nix/$d/per-user
done
# fix permission of nix profile
# (until this is fixed in the relevant Makefile)
chmod -x $RPM_BUILD_ROOT%{_sysconfdir}/profile.d/nix.sh
# systemd not available on RHEL yet
%if ! 0%{?rhel}
# install systemd service descriptor
mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/systemd/system
cp -p misc/systemd/nix-daemon.service \
$RPM_BUILD_ROOT%{_prefix}/lib/systemd/system/
%endif
# Copy the byte-compiled mode file by hand
cp -p misc/emacs/nix-mode.elc $RPM_BUILD_ROOT%{_emacs_sitelispdir}/
# we ship this file in the base package
rm $RPM_BUILD_ROOT%{_defaultdocdir}/%{name}-doc-%{version}/README
%check
make check
%clean
rm -rf $RPM_BUILD_ROOT
%pre
if test -n "%{nix_group_gid}"; then
/usr/sbin/groupadd -g %{nix_group_gid} %{nix_group} || true
fi
if test -n "%{nix_user_uid}"; then
/usr/sbin/useradd -c "Nix" -u %{nix_user_uid} \
-s /sbin/nologin -r -d /var/empty %{nix_user} \
-g %{nix_group} || true
fi
getent group %{nixbld_group} >/dev/null || groupadd -r %{nixbld_group}
for i in $(seq 10);
do
getent passwd %{nixbld_user}$i >/dev/null || \
useradd -r -g %{nixbld_group} -G %{nixbld_group} -d /var/empty \
-s %{_sbindir}/nologin \
-c "Nix build user $i" %{nixbld_user}$i
done
%post
chgrp %{nixbld_group} /nix/store
chmod 1775 /nix/store
%if ! 0%{?rhel}
# Enable and start Nix worker
systemctl enable nix-daemon.service
systemctl start nix-daemon.service
%endif
%files
#%defattr(-,root,root)
%{_prefix}/bin
%{_prefix}/lib
%{_prefix}/libexec
%{_prefix}/include
%{_prefix}/share
/etc/profile.d/nix.sh
/nix/var
/nix/store
%config
/etc/nix
%doc COPYING AUTHORS README
%{_bindir}/nix-*
%dir %{_libdir}/nix
%{_libdir}/nix/*.so.*
%{perl_vendorarch}/*
%exclude %dir %{perl_vendorarch}/auto/
%{_prefix}/libexec/*
%if ! 0%{?rhel}
%{_prefix}/lib/systemd/system/nix-daemon.service
%endif
%{_datadir}/emacs/site-lisp/nix-mode.el
%{_datadir}/nix
%{_mandir}/man1/*.1*
%{_mandir}/man5/*.5*
%{_mandir}/man8/*.8*
%config(noreplace) %{_sysconfdir}/profile.d/nix.sh
/nix
%dir %{_sysconfdir}/nix
%config(noreplace) %{_sysconfdir}/nix/nix.conf
%files devel
%{_includedir}/nix
%{_libdir}/nix/*.so
%files doc
%docdir %{_defaultdocdir}/%{name}-doc-%{version}
%{_defaultdocdir}/%{name}-doc-%{version}
%files -n emacs-%{name}
%{_emacs_sitelispdir}/*.elc
#{_emacs_sitestartdir}/*.el
%files -n emacs-%{name}-el
%{_emacs_sitelispdir}/*.el
+2 -1
View File
@@ -1,4 +1,4 @@
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
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 lib/Nix/Utils.pm
all: $(PERL_MODULES:.in=)
@@ -26,6 +26,7 @@ AM_CXXFLAGS = \
-D_FILE_OFFSET_BITS=64
lib/Nix/Store.cc: lib/Nix/Store.xs
$(INSTALL) -d lib/Nix
xsubpp $^ -output $@
else
+17 -5
View File
@@ -1,27 +1,39 @@
package Nix::Config;
$version = "@version@";
$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";
$storeDir = $ENV{"NIX_STORE_DIR"} || "@storedir@";
$bzip2 = $ENV{"NIX_BZIP2"} || "@bzip2@";
$bzip2 = "@bzip2@";
$xz = "@xz@";
$curl = "@curl@";
$useBindings = "@perlbindings@" eq "yes";
%config = ();
sub readConfig {
my %config;
my $config = "@sysconfdir@/nix/nix.conf";
if (defined $ENV{'_NIX_OPTIONS'}) {
foreach my $s (split '\n', $ENV{'_NIX_OPTIONS'}) {
my ($n, $v) = split '=', $s, 2;
$config{$n} = $v;
}
return;
}
my $config = "$confDir/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;
}
+17 -6
View File
@@ -3,39 +3,50 @@ package Nix::CopyClosure;
use strict;
use Nix::Config;
use Nix::Store;
use List::Util qw(sum);
sub copyTo {
my ($sshHost, $sshOpts, $storePaths, $compressor, $decompressor, $includeOutputs, $dryRun, $sign, $progressViewer) = @_;
$compressor = "$compressor |" if $compressor ne "";
$decompressor = "$decompressor |" if $decompressor ne "";
$progressViewer = "$progressViewer |" if $progressViewer ne "";
my ($sshHost, $sshOpts, $storePaths, $compressor, $decompressor,
$includeOutputs, $dryRun, $sign, $progressViewer, $useSubstitutes) = @_;
# Get the closure of this path.
my @closure = reverse(topoSortPaths(computeFSClosure(0, $includeOutputs,
map { followLinksToStorePath $_ } @{$storePaths})));
# Optionally use substitutes on the remote host.
if (!$dryRun && $useSubstitutes) {
system "ssh $sshHost @{$sshOpts} nix-store -r --ignore-unknown @closure";
# Ignore exit status because this is just an optimisation.
}
# 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 = ();
my $missingSize = 0;
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, $_;
my ($deriver, $narHash, $time, $narSize, $refs) = queryPathInfo($_, 1);
$missingSize += $narSize;
}
close READ or die;
}
$compressor = "$compressor |" if $compressor ne "";
$decompressor = "$decompressor |" if $decompressor ne "";
$progressViewer = "$progressViewer -s $missingSize |" if $progressViewer ne "";
# 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";
unless ($dryRun) {
open SSH, "| $compressor $progressViewer ssh $sshHost @{$sshOpts} '$decompressor nix-store --import' > /dev/null" or die;
open SSH, "| $progressViewer $compressor ssh $sshHost @{$sshOpts} '$decompressor nix-store --import' > /dev/null" or die;
exportPaths(fileno(SSH), $sign, @missing);
close SSH or die "copying store paths to remote machine `$sshHost' failed: $?";
}
+94 -28
View File
@@ -2,6 +2,7 @@ package Nix::Manifest;
use strict;
use DBI;
use DBD::SQLite;
use Cwd;
use File::stat;
use File::Path;
@@ -9,12 +10,12 @@ use Fcntl ':flock';
use Nix::Config;
our @ISA = qw(Exporter);
our @EXPORT = qw(readManifest writeManifest updateManifestDB addPatch);
our @EXPORT = qw(readManifest writeManifest updateManifestDB addPatch deleteOldManifests parseNARInfo);
sub addNAR {
my ($narFiles, $storePath, $info) = @_;
$$narFiles{$storePath} = []
unless defined $$narFiles{$storePath};
@@ -24,7 +25,7 @@ sub addNAR {
foreach my $narFile (@{$narFileList}) {
$found = 1 if $narFile->{url} eq $info->{url};
}
push @{$narFileList}, $info if !$found;
}
@@ -43,7 +44,7 @@ sub addPatch {
$patch2->{url} eq $patch->{url} &&
$patch2->{basePath} eq $patch->{basePath};
}
push @{$patchList}, $patch if !$found;
return !$found;
@@ -68,7 +69,7 @@ sub readManifest_ {
my $manifestVersion = 2;
my ($storePath, $url, $hash, $size, $basePath, $baseHash, $patchType);
my ($narHash, $narSize, $references, $deriver, $copyFrom, $system);
my ($narHash, $narSize, $references, $deriver, $copyFrom, $system, $compressionType);
while (<MANIFEST>) {
chomp;
@@ -93,10 +94,11 @@ sub readManifest_ {
undef $system;
$references = "";
$deriver = "";
}
$compressionType = "bzip2";
}
} else {
if (/^\}$/) {
$inside = 0;
@@ -107,6 +109,7 @@ sub readManifest_ {
, references => $references
, deriver => $deriver
, system => $system
, compressionType => $compressionType
});
}
@@ -120,11 +123,12 @@ sub readManifest_ {
}
}
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*Compression:\s*(\S+)\s*$/) { $compressionType = $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; }
@@ -172,6 +176,7 @@ sub writeManifest {
print MANIFEST "{\n";
print MANIFEST " StorePath: $storePath\n";
print MANIFEST " NarURL: $narFile->{url}\n";
print MANIFEST " Compression: $narFile->{compressionType}\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";
@@ -184,7 +189,7 @@ sub writeManifest {
print MANIFEST "}\n";
}
}
foreach my $storePath (sort (keys %{$patches})) {
my $patchList = $$patches{$storePath};
foreach my $patch (@{$patchList}) {
@@ -201,8 +206,8 @@ sub writeManifest {
print MANIFEST "}\n";
}
}
close MANIFEST;
rename("$manifest.tmp", $manifest)
@@ -211,11 +216,11 @@ sub writeManifest {
# Create a bzipped manifest.
unless (defined $noCompress) {
system("$Nix::Config::bzip2 < $manifest > $manifest.bz2.tmp") == 0
or die "cannot compress manifest";
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: $!";
rename("$manifest.bz2.tmp", "$manifest.bz2")
or die "cannot rename $manifest.bz2.tmp: $!";
}
}
@@ -223,9 +228,13 @@ sub writeManifest {
sub updateManifestDB {
my $manifestDir = $Nix::Config::manifestDir;
my @manifests = glob "$manifestDir/*.nixmanifest";
return undef if scalar @manifests == 0;
mkpath($manifestDir);
my $dbPath = "$manifestDir/cache.sqlite";
unlink "$manifestDir/cache.sqlite"; # remove obsolete cache
my $dbPath = "$manifestDir/cache-v2.sqlite";
# Open/create the database.
our $dbh = DBI->connect("dbi:SQLite:dbname=$dbPath", "", "")
@@ -245,13 +254,14 @@ sub updateManifestDB {
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,
compressionType text not null,
hash text,
size integer,
narHash text,
@@ -292,8 +302,8 @@ EOF
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;
"insert into NARs(manifest, storePath, url, compressionType, hash, size, narHash, " .
"narSize, refs, deriver, system) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") or die;
our $insertPatch = $dbh->prepare(
"insert into Patches(manifest, storePath, basePath, baseHash, url, hash, " .
@@ -304,8 +314,8 @@ EOF
# 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") {
for my $manifestLink (@manifests) {
my $manifest = Cwd::abs_path($manifestLink);
next unless -f $manifest;
my $timestamp = lstat($manifest)->mtime;
@@ -316,9 +326,9 @@ EOF
{}, $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);
@@ -327,11 +337,11 @@ EOF
sub addNARToDB {
my ($storePath, $narFile) = @_;
$insertNAR->execute(
$id, $storePath, $narFile->{url}, $narFile->{hash}, $narFile->{size},
$narFile->{narHash}, $narFile->{narSize}, $narFile->{references},
$id, $storePath, $narFile->{url}, $narFile->{compressionType}, $narFile->{hash},
$narFile->{size}, $narFile->{narHash}, $narFile->{narSize}, $narFile->{references},
$narFile->{deriver}, $narFile->{system});
};
sub addPatchToDB {
my ($storePath, $patch) = @_;
$insertPatch->execute(
@@ -341,7 +351,7 @@ EOF
};
my $version = readManifest_($manifest, \&addNARToDB, \&addPatchToDB);
if ($version < 3) {
die "you have an old-style or corrupt manifest `$manifestLink'; please delete it\n";
}
@@ -364,4 +374,60 @@ EOF
}
# Delete all old manifests downloaded from a given URL.
sub deleteOldManifests {
my ($url, $curUrlFile) = @_;
for my $urlFile (glob "$Nix::Config::manifestDir/*.url") {
next if defined $curUrlFile && $urlFile eq $curUrlFile;
open URL, "<$urlFile" or die;
my $url2 = <URL>;
chomp $url2;
close URL;
next unless $url eq $url2;
my $base = $urlFile; $base =~ s/.url$//;
unlink "${base}.url";
unlink "${base}.nixmanifest";
}
}
# Parse a NAR info file.
sub parseNARInfo {
my ($storePath, $content) = @_;
my ($storePath2, $url, $fileHash, $fileSize, $narHash, $narSize, $deriver, $system);
my $compression = "bzip2";
my @refs;
foreach my $line (split "\n", $content) {
return undef unless $line =~ /^(.*): (.*)$/;
if ($1 eq "StorePath") { $storePath2 = $2; }
elsif ($1 eq "URL") { $url = $2; }
elsif ($1 eq "Compression") { $compression = $2; }
elsif ($1 eq "FileHash") { $fileHash = $2; }
elsif ($1 eq "FileSize") { $fileSize = int($2); }
elsif ($1 eq "NarHash") { $narHash = $2; }
elsif ($1 eq "NarSize") { $narSize = int($2); }
elsif ($1 eq "References") { @refs = split / /, $2; }
elsif ($1 eq "Deriver") { $deriver = $2; }
elsif ($1 eq "System") { $system = $2; }
}
return undef if $storePath ne $storePath2 || !defined $url || !defined $narHash;
return
{ url => $url
, compression => $compression
, fileHash => $fileHash
, fileSize => $fileSize
, narHash => $narHash
, narSize => $narSize
, refs => [ @refs ]
, deriver => $deriver
, system => $system
};
}
return 1;
+1
View File
@@ -44,6 +44,7 @@ sub closeSSHConnection {
if ($sshStarted) {
system("ssh $sshHost @sshOpts -O exit 2> /dev/null") == 0
or warn "unable to stop SSH master: $?";
$sshStarted = 0;
}
}
+18 -17
View File
@@ -14,6 +14,7 @@ our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw(
isValidPath queryReferences queryPathInfo queryDeriver queryPathHash
queryPathFromHashPart
topoSortPaths computeFSClosure followLinksToStorePath exportPaths
hashPath hashFile hashString
addToStore makeFixedOutputPath
@@ -41,50 +42,50 @@ if ($Nix::Config::useBindings) {
use File::Temp;
use Fcntl qw/F_SETFD/;
sub hashFile {
*hashFile = sub {
my ($algo, $base32, $path) = @_;
my $res = backtick("$Nix::Config::binDir/nix-hash", "--flat", $path, "--type", $algo, $base32 ? "--base32" : ());
chomp $res;
return $res;
}
sub hashPath {
};
*hashPath = sub {
my ($algo, $base32, $path) = @_;
my $res = backtick("$Nix::Config::binDir/nix-hash", $path, "--type", $algo, $base32 ? "--base32" : ());
chomp $res;
return $res;
}
sub hashString {
};
*hashString = sub {
my ($algo, $base32, $s) = @_;
my $fh = File::Temp->new();
print $fh $s;
my $res = backtick("$Nix::Config::binDir/nix-hash", $fh->filename, "--type", $algo, $base32 ? "--base32" : ());
chomp $res;
return $res;
}
sub addToStore {
};
*addToStore = sub {
my ($srcPath, $recursive, $algo) = @_;
die "not implemented" if $recursive || $algo ne "sha256";
my $res = backtick("$Nix::Config::binDir/nix-store", "--add", $srcPath);
chomp $res;
return $res;
}
sub isValidPath {
};
*isValidPath = sub {
my ($path) = @_;
my $res = backtick("$Nix::Config::binDir/nix-store", "--check-validity", "--print-invalid", $path);
chomp $res;
return $res ne $path;
}
sub queryPathHash {
};
*queryPathHash = sub {
my ($path) = @_;
my $res = backtick("$Nix::Config::binDir/nix-store", "--query", "--hash", $path);
chomp $res;
return $res;
}
};
}
1;
+27 -12
View File
@@ -15,11 +15,12 @@
using namespace nix;
void doInit()
void doInit()
{
if (!store) {
try {
setDefaultsFromEnvironment();
settings.processEnvironment();
settings.lockCPU = false;
store = openStore();
} catch (Error & e) {
croak(e.what());
@@ -86,7 +87,7 @@ SV * queryDeriver(char * path)
}
SV * queryPathInfo(char * path)
SV * queryPathInfo(char * path, int base32)
PPCODE:
try {
doInit();
@@ -95,7 +96,7 @@ SV * queryPathInfo(char * path)
XPUSHs(&PL_sv_undef);
else
XPUSHs(sv_2mortal(newSVpv(info.deriver.c_str(), 0)));
string s = "sha256:" + printHash(info.hash);
string s = "sha256:" + (base32 ? printHash32(info.hash) : printHash(info.hash));
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
mXPUSHi(info.registrationTime);
mXPUSHi(info.narSize);
@@ -108,6 +109,17 @@ SV * queryPathInfo(char * path)
}
SV * queryPathFromHashPart(char * hashPart)
PPCODE:
try {
doInit();
Path path = store->queryPathFromHashPart(hashPart);
XPUSHs(sv_2mortal(newSVpv(path.c_str(), 0)));
} catch (Error & e) {
croak(e.what());
}
SV * computeFSClosure(int flipDirection, int includeOutputs, ...)
PPCODE:
try {
@@ -226,32 +238,35 @@ SV * derivationFromPath(char * drvPath)
doInit();
Derivation drv = derivationFromPath(*store, drvPath);
hash = newHV();
/* TODO: handle drv.outputs */
HV * outputs = newHV();
for (DerivationOutputs::iterator i = drv.outputs.begin(); i != drv.outputs.end(); ++i)
hv_store(outputs, i->first.c_str(), i->first.size(), newSVpv(i->second.path.c_str(), 0), 0);
hv_stores(hash, "outputs", newRV((SV *) outputs));
AV * inputDrvs = newAV();
for (DerivationInputs::iterator i = drv.inputDrvs.begin(); i != drv.inputDrvs.end(); ++i)
av_push(inputDrvs, newSVpv(i->first.c_str(), 0)); // !!! ignores i->second
hv_stores(hash, "inputDrvs", newRV((SV *) inputDrvs));
AV * inputSrcs = newAV();
for (PathSet::iterator i = drv.inputSrcs.begin(); i != drv.inputSrcs.end(); ++i)
av_push(inputSrcs, newSVpv(i->c_str(), 0));
hv_stores(hash, "inputSrcs", newRV((SV *) inputSrcs));
hv_stores(hash, "platform", newSVpv(drv.platform.c_str(), 0));
hv_stores(hash, "builder", newSVpv(drv.builder.c_str(), 0));
AV * args = newAV();
for (Strings::iterator i = drv.args.begin(); i != drv.args.end(); ++i)
av_push(args, newSVpv(i->c_str(), 0));
hv_stores(hash, "args", newRV((SV *) args));
HV * env = newHV();
for (StringPairs::iterator i = drv.env.begin(); i != drv.env.end(); ++i)
hv_store(env, i->first.c_str(), i->first.size(), newSVpv(i->second.c_str(), 0), 0);
hv_stores(hash, "env", newRV((SV *) env));
RETVAL = newRV_noinc((SV *)hash);
} catch (Error & e) {
croak(e.what());
+38
View File
@@ -0,0 +1,38 @@
package Nix::Utils;
our @ISA = qw(Exporter);
our @EXPORT = qw(checkURL uniq writeFile readFile);
$urlRE = "(?: [a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*]+ )";
sub checkURL {
my ($url) = @_;
die "invalid URL $url\n" unless $url =~ /^ $urlRE $ /x;
}
sub uniq {
my %seen;
my @res;
foreach my $name (@_) {
next if $seen{$name};
$seen{$name} = 1;
push @res, $name;
}
return @res;
}
sub writeFile {
my ($fn, $s) = @_;
open TMP, ">$fn" or die "cannot create file `$fn': $!";
print TMP "$s" or die;
close TMP or die;
}
sub readFile {
local $/ = undef;
my ($fn) = @_;
open TMP, "<$fn" or die "cannot open file `$fn': $!";
my $s = <TMP>;
close TMP or die;
return $s;
}
+120 -33
View File
@@ -1,15 +1,19 @@
{ nixpkgs ? <nixpkgs>
, nix ? { outPath = ./.; revCount = 1234; shortRev = "abcdef"; }
{ nix ? { outPath = ./.; revCount = 1234; shortRev = "abcdef"; }
, officialRelease ? false
}:
let
pkgs = import <nixpkgs> {};
systems = [ "x86_64-linux" "i686-linux" "x86_64-darwin" "x86_64-freebsd" "i686-freebsd" ];
jobs = rec {
tarball =
with import nixpkgs {};
with pkgs;
releaseTools.sourceTarball {
name = "nix-tarball";
@@ -19,7 +23,7 @@ let
inherit officialRelease;
buildInputs =
[ curl bison25 flex2535 perl libxml2 libxslt w3m bzip2
[ curl bison flex2535 perl libxml2 libxslt w3m bzip2
tetex dblatex nukeReferences pkgconfig sqlite git
];
@@ -29,6 +33,7 @@ let
--with-xml-flags=--nonet
--with-dbi=${perlPackages.DBI}/${perl.libPrefix}
--with-dbd-sqlite=${perlPackages.DBDSQLite}/${perl.libPrefix}
--with-www-curl=${perlPackages.WWWCurl}/${perl.libPrefix}
'';
postUnpack = ''
@@ -41,9 +46,18 @@ let
export VARTEXFONTS=$TMPDIR/texfonts
'';
distPhase =
''
runHook preDist
make dist-gzip
make dist-xz
mkdir -p $out/tarballs
cp *.tar.* $out/tarballs
'';
preDist = ''
make -C doc/manual install prefix=$out
make -C doc/manual manual.pdf prefix=$out
cp doc/manual/manual.pdf $out/manual.pdf
@@ -54,7 +68,7 @@ let
# to Windows and Macs, so there should be no Linux binaries
# in the closure).
nuke-refs $out/manual.pdf
echo "doc manual $out/share/doc/nix/manual" >> $out/nix-support/hydra-build-products
echo "doc-pdf manual $out/manual.pdf" >> $out/nix-support/hydra-build-products
echo "doc release-notes $out/share/doc/nix/release-notes" >> $out/nix-support/hydra-build-products
@@ -62,10 +76,9 @@ let
};
build =
{ system ? "i686-linux" }:
build = pkgs.lib.genAttrs systems (system:
with import nixpkgs { inherit system; };
with import <nixpkgs> { inherit system; };
releaseTools.nixBuild {
name = "nix";
@@ -77,15 +90,54 @@ let
--disable-init-state
--with-dbi=${perlPackages.DBI}/${perl.libPrefix}
--with-dbd-sqlite=${perlPackages.DBDSQLite}/${perl.libPrefix}
--with-www-curl=${perlPackages.WWWCurl}/${perl.libPrefix}
--enable-gc
--sysconfdir=/etc
'';
enableParallelBuilding = true;
makeFlags = "profiledir=$(out)/etc/profile.d";
installFlags = "sysconfdir=$(out)/etc";
doInstallCheck = true;
};
});
binaryTarball = pkgs.lib.genAttrs systems (system:
with import <nixpkgs> { inherit system; };
let
toplevel = builtins.getAttr system jobs.build;
version = toplevel.src.version;
in
runCommand "nix-binary-tarball-${version}"
{ exportReferencesGraph = [ "closure" toplevel ];
buildInputs = [ perl ];
meta.description = "Distribution-independent Nix bootstrap binaries for ${system}";
}
''
storePaths=$(perl ${pathsFromGraph} ./closure)
printRegistration=1 perl ${pathsFromGraph} ./closure > $TMPDIR/reginfo
substitute ${./scripts/install-nix-from-closure.sh} $TMPDIR/install \
--subst-var-by nix ${toplevel} --subst-var-by regInfo /nix/store/reginfo
chmod +x $TMPDIR/install
fn=$out/nix-${version}-${system}.tar.bz2
mkdir -p $out/nix-support
echo "file binary-dist $fn" >> $out/nix-support/hydra-build-products
tar cvfj $fn \
--owner=0 --group=0 --absolute-names \
--transform "s,$TMPDIR/install,/usr/bin/nix-finish-install," \
--transform "s,$TMPDIR/reginfo,/nix/store/reginfo," \
$TMPDIR/install $TMPDIR/reginfo $storePaths
'');
coverage =
with import nixpkgs { system = "x86_64-linux"; };
with import <nixpkgs> { system = "x86_64-linux"; };
releaseTools.coverageAnalysis {
name = "nix-build";
@@ -101,12 +153,13 @@ let
--disable-init-state
--with-dbi=${perlPackages.DBI}/${perl.libPrefix}
--with-dbd-sqlite=${perlPackages.DBDSQLite}/${perl.libPrefix}
--with-www-curl=${perlPackages.WWWCurl}/${perl.libPrefix}
'';
dontInstall = false;
doInstallCheck = true;
lcovFilter = [ "*/boost/*" "*-tab.*" ];
# We call `dot', and even though we just use it to
@@ -115,55 +168,89 @@ let
FONTCONFIG_FILE = texFunctions.fontsConf;
};
rpm_fedora13i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora13i386) 50;
rpm_fedora13x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora13x86_64) 50;
rpm_fedora16i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora16i386) 50;
rpm_fedora16x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora16x86_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;
rpm_fedora18i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora18i386) 60;
rpm_fedora18x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora18x86_64) 60;
rpm_fedora19i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora19i386) 70;
rpm_fedora19x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora19x86_64) 70;
deb_debian60i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.debian60i386) 50;
deb_debian60x86_64 = makeDeb_x86_64 (diskImageFunsFun: diskImageFunsFun.debian60x86_64) 50;
deb_ubuntu1004i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1004i386) 50;
deb_ubuntu1004x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1004x86_64) 50;
deb_debian7i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.debian7i386) 60;
deb_debian7x86_64 = makeDeb_x86_64 (diskImageFunsFun: diskImageFunsFun.debian7x86_64) 60;
deb_ubuntu1010i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1010i386) 50;
deb_ubuntu1010x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1010x86_64) 50;
deb_ubuntu1110i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1110i386) 60;
deb_ubuntu1110x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1110x86_64) 60;
deb_ubuntu1204i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1204i386) 60;
deb_ubuntu1204x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1204x86_64) 60;
deb_ubuntu1210i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1210i386) 70;
deb_ubuntu1210x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1210x86_64) 70;
deb_ubuntu1304i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1304i386) 80;
deb_ubuntu1304x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1304x86_64) 80;
deb_ubuntu1310i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1310i386) 90;
deb_ubuntu1310x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1310x86_64) 90;
# System tests.
tests.remote_builds = (import ./tests/remote-builds.nix rec {
nix = build { inherit system; }; system = "x86_64-linux";
nix = build.x86_64-linux; system = "x86_64-linux";
}).test;
tests.nix_copy_closure = (import ./tests/nix-copy-closure.nix rec {
nix = build { inherit system; }; system = "x86_64-linux";
nix = build.x86_64-linux; system = "x86_64-linux";
}).test;
# Aggregate job containing the release-critical jobs.
release = pkgs.releaseTools.aggregate {
name = "nix-${tarball.version}";
meta.description = "Release-critical builds";
constituents =
[ tarball
build.i686-freebsd
build.i686-linux
build.x86_64-darwin
build.x86_64-freebsd
build.x86_64-linux
binaryTarball.i686-freebsd
binaryTarball.i686-linux
binaryTarball.x86_64-darwin
binaryTarball.x86_64-freebsd
binaryTarball.x86_64-linux
deb_debian7i386
deb_debian7x86_64
deb_ubuntu1304i386
deb_ubuntu1304x86_64
deb_ubuntu1310i386
deb_ubuntu1310x86_64
rpm_fedora19i386
rpm_fedora19x86_64
tests.remote_builds
tests.nix_copy_closure
];
};
};
makeRPM_i686 = makeRPM "i686-linux";
makeRPM_x86_64 = makeRPM "x86_64-linux";
makeRPM =
makeRPM =
system: diskImageFun: prio:
with import nixpkgs { inherit system; };
with import <nixpkgs> { inherit system; };
releaseTools.rpmBuild rec {
name = "nix-rpm-${diskImage.name}";
name = "nix-rpm";
src = jobs.tarball;
diskImage = (diskImageFun vmTools.diskImageFuns)
{ extraPackages = [ "perl-DBD-SQLite" "perl-devel" "sqlite" "sqlite-devel" "bzip2-devel" ]; };
{ extraPackages = [ "perl-DBD-SQLite" "perl-devel" "sqlite" "sqlite-devel" "bzip2-devel" "emacs" "perl-WWW-Curl" ]; };
memSize = 1024;
meta.schedulingPriority = prio;
postRPMInstall = "cd /tmp/rpmout/BUILD/nix-* && make installcheck";
@@ -172,21 +259,21 @@ let
makeDeb_i686 = makeDeb "i686-linux";
makeDeb_x86_64 = makeDeb "x86_64-linux";
makeDeb =
system: diskImageFun: prio:
with import nixpkgs { inherit system; };
with import <nixpkgs> { inherit system; };
releaseTools.debBuild {
name = "nix-deb";
src = jobs.tarball;
diskImage = (diskImageFun vmTools.diskImageFuns)
{ extraPackages = [ "libdbd-sqlite3-perl" "libsqlite3-dev" "libbz2-dev" ]; };
{ extraPackages = [ "libdbd-sqlite3-perl" "libsqlite3-dev" "libbz2-dev" "libwww-curl-perl" ]; };
memSize = 1024;
meta.schedulingPriority = prio;
configureFlags = "--sysconfdir=/etc";
debRequires = [ "curl" "libdbd-sqlite3-perl" "libsqlite3-0" "libbz2-1.0" ];
debRequires = [ "curl" "libdbd-sqlite3-perl" "libsqlite3-0" "libbz2-1.0" "bzip2" "xz-utils" "libwww-curl-perl" ];
doInstallCheck = true;
};
+7 -6
View File
@@ -7,18 +7,18 @@ 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: download-using-manifests.pl
profiledir = $(sysconfdir)/profile.d
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-exec-local: download-using-manifests.pl copy-from-other-stores.pl download-from-binary-cache.pl find-runtime-roots.pl
$(INSTALL) -d $(DESTDIR)$(profiledir)
$(INSTALL_DATA) nix-profile.sh $(DESTDIR)$(profiledir)/nix.sh
$(INSTALL) -d $(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
$(INSTALL_PROGRAM) download-using-manifests.pl $(DESTDIR)$(libexecdir)/nix/substituters
$(INSTALL_PROGRAM) copy-from-other-stores.pl $(DESTDIR)$(libexecdir)/nix/substituters
$(INSTALL_PROGRAM) download-using-manifests.pl copy-from-other-stores.pl download-from-binary-cache.pl $(DESTDIR)$(libexecdir)/nix/substituters
$(INSTALL) -d $(DESTDIR)$(sysconfdir)/nix
ln -sf nix-build $(DESTDIR)$(bindir)/nix-shell
include ../substitute.mk
@@ -29,6 +29,7 @@ EXTRA_DIST = nix-collect-garbage.in \
nix-build.in \
download-using-manifests.pl.in \
copy-from-other-stores.pl.in \
download-from-binary-cache.pl.in \
nix-copy-closure.in \
find-runtime-roots.pl.in \
build-remote.pl.in \
+28 -23
View File
@@ -6,6 +6,7 @@ use IO::Handle;
use Nix::Config;
use Nix::SSH qw/sshOpts openSSHConnection/;
use Nix::CopyClosure;
use Nix::Store;
no warnings('once');
@@ -18,7 +19,7 @@ no warnings('once');
# less than the maximum load for that machine, we try to get an
# exclusive lock on $currentLoad/$machine-$slot (without blocking).
# If we get such a lock, we send "accept" to the caller. Otherwise,
# we send "postpone" and exit.
# we send "postpone" and exit.
# - We release the exclusive lock on $currentLoad/main-lock.
# - We perform the build on $neededSystem.
# - We release the exclusive lock on $currentLoad/$machine-$slot.
@@ -45,8 +46,7 @@ sub all { $_ || return 0 for @_; 1 }
# Initialisation.
my $loadIncreased = 0;
my ($localSystem, $maxSilentTime, $printBuildTrace) = @ARGV;
$maxSilentTime = 0 unless defined $maxSilentTime;
my ($localSystem, $maxSilentTime, $printBuildTrace, $buildTimeout) = @ARGV;
my $currentLoad = $ENV{"NIX_CURRENT_LOAD"};
my $conf = $ENV{"NIX_REMOTE_SYSTEMS"};
@@ -102,14 +102,14 @@ REQ: while (1) {
sendReply "decline";
next;
}
# Acquire the exclusive lock on $currentLoad/main-lock.
mkdir $currentLoad, 0777 or die unless -d $currentLoad;
my $mainLock = "$currentLoad/main-lock";
sysopen MAINLOCK, "$mainLock", O_RDWR|O_CREAT, 0600 or die;
flock(MAINLOCK, LOCK_EX) or die;
while (1) {
# Find all machine that can execute this build, i.e., that
# support builds for the given platform and features, and are
@@ -141,7 +141,7 @@ REQ: while (1) {
close $slotLock;
$slot++;
}
push @available, { machine => $cur, load => $load, free => $free }
if $load < $cur->{maxJobs};
}
@@ -160,7 +160,7 @@ REQ: while (1) {
if ($rightType && !$canBuildLocally) {
sendReply "postpone";
} else {
sendReply "decline";
sendReply "decline";
}
close MAINLOCK;
next REQ;
@@ -182,9 +182,9 @@ REQ: while (1) {
# Select the best available machine and lock a free slot.
my $selected = $available[0];
my $selected = $available[0];
my $machine = $selected->{machine};
$slotLock = openSlotLock($machine, $selected->{free});
flock($slotLock, LOCK_EX | LOCK_NB) or die;
utime undef, undef, $slotLock;
@@ -195,9 +195,13 @@ REQ: while (1) {
# Connect to the selected machine.
@sshOpts = ("-i", $machine->{sshKeys}, "-x");
$hostName = $machine->{hostName};
last REQ if openSSHConnection $hostName;
warn "unable to open SSH connection to $hostName, trying other available machines...\n";
if (openSSHConnection($hostName)) {
last REQ if system("ssh $hostName @sshOpts nix-builds-inhibited < /dev/null > /dev/null 2>&1") != 0;
warn "machine `$hostName' is refusing builds, trying other available machines...\n";
closeSSHConnection;
} else {
warn "unable to open SSH connection to `$hostName', trying other available machines...\n";
}
$machine->{enabled} = 0;
}
}
@@ -209,7 +213,6 @@ my @inputs = split /\s/, readline(STDIN);
my @outputs = split /\s/, readline(STDIN);
print STDERR "building `$drvPath' on `$hostName'\n";
print STDERR "@ build-remote $drvPath $hostName\n" if $printBuildTrace;
@@ -257,7 +260,10 @@ close UPLOADLOCK;
# Perform the build.
my $buildFlags = "--max-silent-time $maxSilentTime --fallback --add-root $rootsDir/\$PPID.out --option verbosity 0";
my $buildFlags =
"--max-silent-time $maxSilentTime --option build-timeout $buildTimeout"
. " --fallback --add-root $rootsDir/\$PPID.out --quiet"
. " --option build-keep-log false --option build-use-substitutes false";
# We let the remote side kill its process group when the connection is
# closed unexpectedly. This is necessary to ensure that no processes
@@ -266,8 +272,9 @@ my $buildFlags = "--max-silent-time $maxSilentTime --fallback --add-root $rootsD
# is interrupted unless the `-tt' flag is used to force a pseudo-tty,
# in which case every child receives SIGHUP; however, `-tt' doesn't
# work on some platforms when connection sharing is used.)
print STDERR "building `$drvPath' on `$hostName'\n";
pipe STDIN, DUMMY; # make sure we have a readable STDIN
if (system("exec ssh $hostName @sshOpts '(read; kill -INT -\$\$) <&0 & nix-store -r $drvPath $buildFlags > /dev/null' 2>&4") != 0) {
if (system("exec ssh $hostName @sshOpts '(read; kill -INT -\$\$) <&0 & exec nix-store -r $drvPath $buildFlags > /dev/null' 2>&4") != 0) {
# Note that if we get exit code 100 from `nix-store -r', it
# denotes a permanent build failure (as opposed to an SSH problem
# or a temporary Nix problem). We propagate this to the caller to
@@ -283,13 +290,11 @@ if (system("exec ssh $hostName @sshOpts '(read; kill -INT -\$\$) <&0 & nix-store
# Copy the output from the build machine.
foreach my $output (@outputs) {
my $maybeSignRemote = "";
$maybeSignRemote = "--sign" if $UID != 0;
system("exec ssh $hostName @sshOpts 'nix-store --export $maybeSignRemote $output'" .
"| NIX_HELD_LOCKS=$output @bindir@/nix-store --import > /dev/null") == 0
or die "cannot copy $output from $hostName: $?";
my @outputs2 = grep { !isValidPath($_) } @outputs;
if (scalar @outputs2 > 0) {
system("exec ssh $hostName @sshOpts 'nix-store --export @outputs2'" .
"| NIX_HELD_LOCKS='@outputs2' @bindir@/nix-store --import > /dev/null") == 0
or die("cannot copy paths " . join(", ", @outputs) . " from `$hostName': $?");
}
+40 -32
View File
@@ -16,6 +16,9 @@ foreach my $dir (@remoteStoresAll) {
push @remoteStores, glob($dir);
}
exit if scalar @remoteStores == 0;
print "\n";
$ENV{"NIX_REMOTE"} = "";
@@ -27,7 +30,7 @@ sub findStorePath {
next unless -e $sourcePath || -l $sourcePath;
$ENV{"NIX_DB_DIR"} = "$store/var/nix/db";
return ($store, $sourcePath) if
system("@bindir@/nix-store --check-validity $storePath") == 0;
system("$binDir/nix-store --check-validity $storePath") == 0;
}
return undef;
}
@@ -36,42 +39,45 @@ sub findStorePath {
if ($ARGV[0] eq "--query") {
while (<STDIN>) {
my $cmd = $_; chomp $cmd;
chomp;
my ($cmd, @args) = split " ", $_;
if ($cmd eq "have") {
my $storePath = <STDIN>; chomp $storePath;
print STDOUT (defined findStorePath($storePath) ? "1\n" : "0\n");
foreach my $storePath (@args) {
print "$storePath\n" if defined findStorePath($storePath);
}
print "\n";
}
elsif ($cmd eq "info") {
my $storePath = <STDIN>; chomp $storePath;
my ($store, $sourcePath) = findStorePath($storePath);
if (!defined $store) {
foreach my $storePath (@args) {
my ($store, $sourcePath) = findStorePath($storePath);
next unless defined $store;
$ENV{"NIX_DB_DIR"} = "$store/var/nix/db";
my $deriver = `$binDir/nix-store --query --deriver $storePath`;
die "cannot query deriver of `$storePath'" if $? != 0;
chomp $deriver;
$deriver = "" if $deriver eq "unknown-deriver";
my @references = split "\n",
`$binDir/nix-store --query --references $storePath`;
die "cannot query references of `$storePath'" if $? != 0;
my $narSize = `$binDir/nix-store --query --size $storePath`;
die "cannot query size of `$storePath'" if $? != 0;
chomp $narSize;
print "$storePath\n";
print "$deriver\n";
print scalar @references, "\n";
print "$_\n" foreach @references;
print "0\n";
next; # not an error
print "$narSize\n";
}
print "1\n";
$ENV{"NIX_DB_DIR"} = "$store/var/nix/db";
my $deriver = `@bindir@/nix-store --query --deriver $storePath`;
die "cannot query deriver of `$storePath'" if $? != 0;
chomp $deriver;
$deriver = "" if $deriver eq "unknown-deriver";
my @references = split "\n",
`@bindir@/nix-store --query --references $storePath`;
die "cannot query references of `$storePath'" if $? != 0;
my $narSize = `@bindir@/nix-store --query --size $storePath`;
die "cannot query size of `$storePath'" if $? != 0;
chomp $narSize;
print "$deriver\n";
print scalar @references, "\n";
print "$_\n" foreach @references;
print "$narSize\n";
print "$narSize\n";
print "\n";
}
else { die "unknown command `$cmd'"; }
@@ -80,13 +86,15 @@ if ($ARGV[0] eq "--query") {
elsif ($ARGV[0] eq "--substitute") {
die unless scalar @ARGV == 2;
die unless scalar @ARGV == 3;
my $storePath = $ARGV[1];
my $destPath = $ARGV[2];
my ($store, $sourcePath) = findStorePath $storePath;
die unless $store;
print "\n*** Copying `$storePath' from `$sourcePath'\n\n";
system("$binDir/nix-store --dump $sourcePath | $binDir/nix-store --restore $storePath") == 0
print STDERR "\n*** Copying `$storePath' from `$sourcePath'\n\n";
system("$binDir/nix-store --dump $sourcePath | $binDir/nix-store --restore $destPath") == 0
or die "cannot copy `$sourcePath' to `$storePath'";
print "\n"; # no hash to verify
}
+589
View File
@@ -0,0 +1,589 @@
#! @perl@ -w @perlFlags@
use DBI;
use DBD::SQLite;
use File::Basename;
use IO::Select;
use Nix::Config;
use Nix::Store;
use Nix::Utils;
use Nix::Manifest;
use WWW::Curl::Easy;
use WWW::Curl::Multi;
use strict;
Nix::Config::readConfig;
my @caches;
my $gotCaches = 0;
my $maxParallelRequests = int($Nix::Config::config{"binary-caches-parallel-connections"} // 150);
$maxParallelRequests = 1 if $maxParallelRequests < 1;
my $ttlNegative = 24 * 3600; # when to purge negative lookups from the database
my $ttlNegativeUse = 3600; # how long negative lookups are valid for non-"have" lookups
my $didExpiration = 0;
my $showAfter = 5; # show that we're waiting for a request after this many seconds
my $debug = ($Nix::Config::config{"debug-subst"} // "") eq 1 || ($Nix::Config::config{"untrusted-debug-subst"} // "") eq 1;
my $cacheFileURLs = ($ENV{"_NIX_CACHE_FILE_URLS"} // "") eq 1; # for testing
my ($dbh, $queryCache, $insertNAR, $queryNAR, $insertNARExistence, $queryNARExistence, $expireNARExistence);
my $curlm = WWW::Curl::Multi->new;
my $activeRequests = 0;
my $curlIdCount = 1;
my %requests;
my %scheduled;
my $caBundle = $ENV{"CURL_CA_BUNDLE"} // $ENV{"OPENSSL_X509_CERT_FILE"};
my $userName = getpwuid($<) or die "cannot figure out user name";
sub addRequest {
my ($storePath, $url, $head) = @_;
my $curl = WWW::Curl::Easy->new;
my $curlId = $curlIdCount++;
$requests{$curlId} = { storePath => $storePath, url => $url, handle => $curl, content => "", type => $head ? "HEAD" : "GET"
, shown => 0, started => time() };
$curl->setopt(CURLOPT_PRIVATE, $curlId);
$curl->setopt(CURLOPT_URL, $url);
open (my $fh, ">", \$requests{$curlId}->{content});
$curl->setopt(CURLOPT_WRITEDATA, $fh);
$curl->setopt(CURLOPT_FOLLOWLOCATION, 1);
$curl->setopt(CURLOPT_CAINFO, $caBundle) if defined $caBundle;
$curl->setopt(CURLOPT_USERAGENT, "Nix/$Nix::Config::version");
$curl->setopt(CURLOPT_NOBODY, 1) if $head;
$curl->setopt(CURLOPT_FAILONERROR, 1);
$curl->setopt(CURLOPT_TIMEOUT, int($ENV{"NIX_CONNECT_TIMEOUT"} // 0));
if ($activeRequests >= $maxParallelRequests) {
$scheduled{$curlId} = 1;
} else {
$curlm->add_handle($curl);
$activeRequests++;
}
return $requests{$curlId};
}
sub processRequests {
while ($activeRequests) {
my ($rfds, $wfds, $efds) = $curlm->fdset();
#print STDERR "R = @{$rfds}, W = @{$wfds}, E = @{$efds}\n";
# Sleep until we can read or write some data.
if (scalar @{$rfds} + scalar @{$wfds} + scalar @{$efds} > 0) {
IO::Select->select(IO::Select->new(@{$rfds}), IO::Select->new(@{$wfds}), IO::Select->new(@{$efds}), 1.0);
}
if ($curlm->perform() != $activeRequests) {
while (my ($id, $result) = $curlm->info_read) {
if ($id) {
my $request = $requests{$id} or die;
my $handle = $request->{handle};
$request->{result} = $result;
$request->{httpStatus} = $handle->getinfo(CURLINFO_RESPONSE_CODE);
print STDERR "$request->{type} on $request->{url} [$request->{result}, $request->{httpStatus}]\n" if $debug;
$activeRequests--;
delete $request->{handle};
if (scalar(keys %scheduled) > 0) {
my $id2 = (keys %scheduled)[0];
$curlm->add_handle($requests{$id2}->{handle});
$activeRequests++;
delete $scheduled{$id2};
}
}
}
}
my $time = time();
while (my ($key, $request) = each %requests) {
next unless defined $request->{handle};
next if $request->{shown};
if ($time > $request->{started} + $showAfter) {
print STDERR "still waiting for $request->{url} after $showAfter seconds...\n";
$request->{shown} = 1;
}
}
}
}
sub initCache {
my $dbPath = "$Nix::Config::stateDir/binary-cache-v2.sqlite";
unlink "$Nix::Config::stateDir/binary-cache-v1.sqlite";
# Open/create the database.
$dbh = DBI->connect("dbi:SQLite:dbname=$dbPath", "", "")
or die "cannot open database `$dbPath'";
$dbh->{RaiseError} = 1;
$dbh->{PrintError} = 0;
$dbh->sqlite_busy_timeout(60 * 60 * 1000);
$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 BinaryCaches (
id integer primary key autoincrement not null,
url text unique not null,
timestamp integer not null,
storeDir text not null,
wantMassQuery integer not null,
priority integer not null
);
EOF
$dbh->do(<<EOF);
create table if not exists NARs (
cache integer not null,
storePath text not null,
url text not null,
compression text not null,
fileHash text,
fileSize integer,
narHash text,
narSize integer,
refs text,
deriver text,
system text,
timestamp integer not null,
primary key (cache, storePath),
foreign key (cache) references BinaryCaches(id) on delete cascade
);
EOF
$dbh->do(<<EOF);
create table if not exists NARExistence (
cache integer not null,
storePath text not null,
exist integer not null,
timestamp integer not null,
primary key (cache, storePath),
foreign key (cache) references BinaryCaches(id) on delete cascade
);
EOF
$dbh->do("create index if not exists NARExistenceByExistTimestamp on NARExistence (exist, timestamp)");
$queryCache = $dbh->prepare("select id, storeDir, wantMassQuery, priority from BinaryCaches where url = ?") or die;
$insertNAR = $dbh->prepare(
"insert or replace into NARs(cache, storePath, url, compression, fileHash, fileSize, narHash, " .
"narSize, refs, deriver, system, timestamp) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") or die;
$queryNAR = $dbh->prepare("select * from NARs where cache = ? and storePath = ?") or die;
$insertNARExistence = $dbh->prepare(
"insert or replace into NARExistence(cache, storePath, exist, timestamp) values (?, ?, ?, ?)") or die;
$queryNARExistence = $dbh->prepare("select exist, timestamp from NARExistence where cache = ? and storePath = ?") or die;
$expireNARExistence = $dbh->prepare("delete from NARExistence where exist = ? and timestamp < ?") or die;
}
sub getAvailableCaches {
return if $gotCaches;
$gotCaches = 1;
sub strToList {
my ($s) = @_;
return map { s/\/+$//; $_ } split(/ /, $s);
}
my @urls = strToList($Nix::Config::config{"binary-caches"} //
($Nix::Config::storeDir eq "/nix/store" ? "http://cache.nixos.org" : ""));
my $urlsFiles = $Nix::Config::config{"binary-cache-files"}
// "$Nix::Config::stateDir/profiles/per-user/$userName/channels/binary-caches/*";
foreach my $urlFile (glob $urlsFiles) {
next unless -f $urlFile;
open FILE, "<$urlFile" or die "cannot open $urlFile\n";
my $url = <FILE>; chomp $url;
close FILE;
push @urls, strToList($url);
}
push @urls, strToList($Nix::Config::config{"extra-binary-caches"} // "");
# Allow Nix daemon users to override the binary caches to a subset
# of those listed in the config file. Note that untrusted-*
# denotes options passed by the client.
my @trustedUrls = uniq(@urls, strToList($Nix::Config::config{"trusted-binary-caches"} // ""));
if (defined $Nix::Config::config{"untrusted-binary-caches"}) {
my @untrustedUrls = strToList $Nix::Config::config{"untrusted-binary-caches"};
@urls = ();
foreach my $url (@untrustedUrls) {
die "binary cache $url is not trusted (please add it to trusted-binary-caches [@trustedUrls] in $Nix::Config::confDir/nix.conf)\n"
unless scalar(grep { $url eq $_ } @trustedUrls) > 0;
push @urls, $url;
}
}
my @untrustedUrls = strToList $Nix::Config::config{"untrusted-extra-binary-caches"} // "";
foreach my $url (@untrustedUrls) {
next unless scalar(grep { $url eq $_ } @trustedUrls) > 0;
push @urls, $url;
}
foreach my $url (uniq @urls) {
# FIXME: not atomic.
$queryCache->execute($url);
my $res = $queryCache->fetchrow_hashref();
if (defined $res) {
next if $res->{storeDir} ne $Nix::Config::storeDir;
push @caches, { id => $res->{id}, url => $url, wantMassQuery => $res->{wantMassQuery}, priority => $res->{priority} };
next;
}
# Get the cache info file.
my $request = addRequest(undef, $url . "/nix-cache-info");
processRequests;
if ($request->{result} != 0) {
print STDERR "could not download $request->{url} (" .
($request->{result} != 0 ? "Curl error $request->{result}" : "HTTP status $request->{httpStatus}") . ")\n";
next;
}
my $storeDir = "/nix/store";
my $wantMassQuery = 0;
my $priority = 50;
foreach my $line (split "\n", $request->{content}) {
unless ($line =~ /^(.*): (.*)$/) {
print STDERR "bad cache info file $request->{url}\n";
return undef;
}
if ($1 eq "StoreDir") { $storeDir = $2; }
elsif ($1 eq "WantMassQuery") { $wantMassQuery = int($2); }
elsif ($1 eq "Priority") { $priority = int($2); }
}
$dbh->do("insert or replace into BinaryCaches(url, timestamp, storeDir, wantMassQuery, priority) values (?, ?, ?, ?, ?)",
{}, $url, time(), $storeDir, $wantMassQuery, $priority);
$queryCache->execute($url);
$res = $queryCache->fetchrow_hashref() or die;
next if $storeDir ne $Nix::Config::storeDir;
push @caches, { id => $res->{id}, url => $url, wantMassQuery => $wantMassQuery, priority => $priority };
}
@caches = sort { $a->{priority} <=> $b->{priority} } @caches;
expireNegative();
}
sub shouldCache {
my ($url) = @_;
return $cacheFileURLs || $url !~ /^file:/;
}
sub processNARInfo {
my ($storePath, $cache, $request) = @_;
if ($request->{result} != 0) {
if ($request->{result} != 37 && $request->{httpStatus} != 404 && $request->{httpStatus} != 403) {
print STDERR "could not download $request->{url} (" .
($request->{result} != 0 ? "Curl error $request->{result}" : "HTTP status $request->{httpStatus}") . ")\n";
} else {
$insertNARExistence->execute($cache->{id}, basename($storePath), 0, time())
if shouldCache $request->{url};
}
return undef;
}
my $narInfo = parseNARInfo($storePath, $request->{content});
return undef unless defined $narInfo;
# Cache the result.
$insertNAR->execute(
$cache->{id}, basename($storePath), $narInfo->{url}, $narInfo->{compression},
$narInfo->{fileHash}, $narInfo->{fileSize}, $narInfo->{narHash}, $narInfo->{narSize},
join(" ", @{$narInfo->{refs}}), $narInfo->{deriver}, $narInfo->{system}, time())
if shouldCache $request->{url};
return $narInfo;
}
sub getCachedInfoFrom {
my ($storePath, $cache) = @_;
$queryNAR->execute($cache->{id}, basename($storePath));
my $res = $queryNAR->fetchrow_hashref();
return undef unless defined $res;
return
{ url => $res->{url}
, compression => $res->{compression}
, fileHash => $res->{fileHash}
, fileSize => $res->{fileSize}
, narHash => $res->{narHash}
, narSize => $res->{narSize}
, refs => [ split " ", $res->{refs} ]
, deriver => $res->{deriver}
} if defined $res;
}
sub negativeHit {
my ($storePath, $cache) = @_;
$queryNARExistence->execute($cache->{id}, basename($storePath));
my $res = $queryNARExistence->fetchrow_hashref();
return defined $res && $res->{exist} == 0 && time() - $res->{timestamp} < $ttlNegativeUse;
}
sub positiveHit {
my ($storePath, $cache) = @_;
return 1 if defined getCachedInfoFrom($storePath, $cache);
$queryNARExistence->execute($cache->{id}, basename($storePath));
my $res = $queryNARExistence->fetchrow_hashref();
return defined $res && $res->{exist} == 1;
}
sub expireNegative {
return if $didExpiration;
$didExpiration = 1;
my $time = time();
# Round up to the next multiple of the TTL to ensure that we do
# expiration only once per time interval. E.g. if $ttlNegative ==
# 3600, we expire entries at most once per hour. This is
# presumably faster than expiring a few entries per request (and
# thus doing a transaction).
my $limit = (int($time / $ttlNegative) - 1) * $ttlNegative;
$expireNARExistence->execute($limit, 0);
print STDERR "expired ", $expireNARExistence->rows, " negative entries\n" if $debug;
}
sub printInfo {
my ($storePath, $info) = @_;
print "$storePath\n";
print $info->{deriver} ? "$Nix::Config::storeDir/$info->{deriver}" : "", "\n";
print scalar @{$info->{refs}}, "\n";
print "$Nix::Config::storeDir/$_\n" foreach @{$info->{refs}};
print $info->{fileSize} || 0, "\n";
print $info->{narSize} || 0, "\n";
}
sub infoUrl {
my ($binaryCacheUrl, $storePath) = @_;
my $pathHash = substr(basename($storePath), 0, 32);
my $infoUrl = "$binaryCacheUrl/$pathHash.narinfo";
}
sub printInfoParallel {
my @paths = @_;
# First print all paths for which we have cached info.
my @left;
foreach my $storePath (@paths) {
my $found = 0;
foreach my $cache (@caches) {
my $info = getCachedInfoFrom($storePath, $cache);
if (defined $info) {
printInfo($storePath, $info);
$found = 1;
last;
}
}
push @left, $storePath if !$found;
}
return if scalar @left == 0;
foreach my $cache (@caches) {
my @left2;
%requests = ();
foreach my $storePath (@left) {
if (negativeHit($storePath, $cache)) {
push @left2, $storePath;
next;
}
addRequest($storePath, infoUrl($cache->{url}, $storePath));
}
processRequests;
foreach my $request (values %requests) {
my $info = processNARInfo($request->{storePath}, $cache, $request);
if (defined $info) {
printInfo($request->{storePath}, $info);
} else {
push @left2, $request->{storePath};
}
}
@left = @left2;
}
}
sub printSubstitutablePaths {
my @paths = @_;
# First look for paths that have cached info.
my @left;
foreach my $storePath (@paths) {
my $found = 0;
foreach my $cache (@caches) {
next unless $cache->{wantMassQuery};
if (positiveHit($storePath, $cache)) {
print "$storePath\n";
$found = 1;
last;
}
}
push @left, $storePath if !$found;
}
return if scalar @left == 0;
# For remaining paths, do HEAD requests.
foreach my $cache (@caches) {
next unless $cache->{wantMassQuery};
my @left2;
%requests = ();
foreach my $storePath (@left) {
if (negativeHit($storePath, $cache)) {
push @left2, $storePath;
next;
}
addRequest($storePath, infoUrl($cache->{url}, $storePath), 1);
}
processRequests;
foreach my $request (values %requests) {
if ($request->{result} != 0) {
if ($request->{result} != 37 && $request->{httpStatus} != 404 && $request->{httpStatus} != 403) {
print STDERR "could not check $request->{url} (" .
($request->{result} != 0 ? "Curl error $request->{result}" : "HTTP status $request->{httpStatus}") . ")\n";
} else {
$insertNARExistence->execute($cache->{id}, basename($request->{storePath}), 0, time())
if shouldCache $request->{url};
}
push @left2, $request->{storePath};
} else {
$insertNARExistence->execute($cache->{id}, basename($request->{storePath}), 1, time())
if shouldCache $request->{url};
print "$request->{storePath}\n";
}
}
@left = @left2;
}
}
sub downloadBinary {
my ($storePath, $destPath) = @_;
foreach my $cache (@caches) {
my $info = getCachedInfoFrom($storePath, $cache);
unless (defined $info) {
next if negativeHit($storePath, $cache);
my $request = addRequest($storePath, infoUrl($cache->{url}, $storePath));
processRequests;
$info = processNARInfo($storePath, $cache, $request);
}
next unless defined $info;
my $decompressor;
if ($info->{compression} eq "bzip2") { $decompressor = "| $Nix::Config::bzip2 -d"; }
elsif ($info->{compression} eq "xz") { $decompressor = "| $Nix::Config::xz -d"; }
elsif ($info->{compression} eq "none") { $decompressor = ""; }
else {
print STDERR "unknown compression method $info->{compression}\n";
next;
}
my $url = "$cache->{url}/$info->{url}"; # FIXME: handle non-relative URLs
print STDERR "\n*** Downloading $url to $storePath...\n";
checkURL $url;
if (system("$Nix::Config::curl --fail --location --insecure '$url' $decompressor | $Nix::Config::binDir/nix-store --restore $destPath") != 0) {
warn "download of `$url' failed" . ($! ? ": $!" : "") . "\n";
next;
}
# Tell Nix about the expected hash so it can verify it.
print "$info->{narHash}\n";
print STDERR "\n";
return;
}
print STDERR "could not download $storePath from any binary cache\n";
exit 1;
}
# Bail out right away if binary caches are disabled.
exit 0 if
($Nix::Config::config{"use-binary-caches"} // "true") eq "false" ||
($Nix::Config::config{"untrusted-use-binary-caches"} // "true") eq "false";
print "\n";
flush STDOUT;
initCache();
if ($ARGV[0] eq "--query") {
while (<STDIN>) {
getAvailableCaches;
chomp;
my ($cmd, @args) = split " ", $_;
if ($cmd eq "have") {
print STDERR "checking binary caches for existence of @args\n" if $debug;
printSubstitutablePaths(@args);
print "\n";
}
elsif ($cmd eq "info") {
print STDERR "checking binary caches for info on @args\n" if $debug;
printInfoParallel(@args);
print "\n";
}
else { die "unknown command `$cmd'"; }
flush STDOUT;
}
}
elsif ($ARGV[0] eq "--substitute") {
my $storePath = $ARGV[1] or die;
my $destPath = $ARGV[2] or die;
getAvailableCaches;
downloadBinary($storePath, $destPath);
}
else {
die;
}
+74 -84
View File
@@ -4,6 +4,7 @@ use strict;
use Nix::Config;
use Nix::Manifest;
use Nix::Store;
use Nix::Utils;
use POSIX qw(strftime);
use File::Temp qw(tempdir);
@@ -15,9 +16,14 @@ my $logFile = "$Nix::Config::logDir/downloads";
# estimating the expected download size.
my $fast = 1;
# --insecure is fine because Nix verifies the hash of the result.
my $curl = "$Nix::Config::curl --fail --location --insecure";
# Open the manifest cache and update it if necessary.
my $dbh = updateManifestDB();
exit 0 unless defined $dbh; # exit if there are no manifests
print "\n";
# $hashCache->{$algo}->{$path} yields the $algo-hash of $path.
@@ -38,7 +44,7 @@ sub parseHash {
# given path.
sub computeSmallestDownload {
my $targetPath = shift;
# Build a graph of all store paths that might contribute to the
# construction of $targetPath, and the special node "start". The
# edges are either patch operations, or downloads of full NAR
@@ -93,7 +99,7 @@ sub computeSmallestDownload {
my $patchList = $dbh->selectall_arrayref(
"select * from Patches where storePath = ?",
{ Slice => {} }, $u);
foreach my $patch (@{$patchList}) {
if (isValidPath($patch->{basePath})) {
my ($baseHashAlgo, $baseHash) = parseHash $patch->{baseHash};
@@ -106,7 +112,7 @@ sub computeSmallestDownload {
$hash =~ s/.*://;
$hashCache->{$baseHashAlgo}->{$patch->{basePath}} = $hash;
}
next if $hash ne $baseHash;
}
push @queue, $patch->{basePath};
@@ -117,7 +123,7 @@ sub computeSmallestDownload {
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 GB).
@@ -173,58 +179,56 @@ sub computeSmallestDownload {
if ($ARGV[0] eq "--query") {
while (<STDIN>) {
my $cmd = $_; chomp $cmd;
chomp;
my ($cmd, @args) = split " ", $_;
if ($cmd eq "have") {
my $storePath = <STDIN>; chomp $storePath;
print STDOUT (
scalar @{$dbh->selectcol_arrayref("select 1 from NARs where storePath = ?", {}, $storePath)} > 0
? "1\n" : "0\n");
foreach my $storePath (@args) {
print "$storePath\n" if scalar @{$dbh->selectcol_arrayref("select 1 from NARs where storePath = ?", {}, $storePath)} > 0;
}
print "\n";
}
elsif ($cmd eq "info") {
my $storePath = <STDIN>; chomp $storePath;
foreach my $storePath (@args) {
my $infos = $dbh->selectall_arrayref(
"select * from NARs where storePath = ?",
{ Slice => {} }, $storePath);
my $info;
if (scalar @{$infos} > 0) {
$info = @{$infos}[0];
}
else {
print "0\n";
next; # not an error
}
my $infos = $dbh->selectall_arrayref(
"select * from NARs where storePath = ?",
{ Slice => {} }, $storePath);
print "1\n";
print "$info->{deriver}\n";
my @references = split " ", $info->{refs};
print scalar @references, "\n";
print "$_\n" foreach @references;
next unless scalar @{$infos} > 0;
my $info = @{$infos}[0];
my @path = computeSmallestDownload $storePath;
print "$storePath\n";
print "$info->{deriver}\n";
my @references = split " ", $info->{refs};
print scalar @references, "\n";
print "$_\n" foreach @references;
my $downloadSize = 0;
while (scalar @path > 0) {
my $edge = pop @path;
my $u = $edge->{start};
my $v = $edge->{end};
if ($edge->{type} eq "patch") {
$downloadSize += $edge->{info}->{size} || 0;
}
elsif ($edge->{type} eq "narfile") {
$downloadSize += $edge->{info}->{size} || 0;
my @path = computeSmallestDownload $storePath;
my $downloadSize = 0;
while (scalar @path > 0) {
my $edge = pop @path;
my $u = $edge->{start};
my $v = $edge->{end};
if ($edge->{type} eq "patch") {
$downloadSize += $edge->{info}->{size} || 0;
}
elsif ($edge->{type} eq "narfile") {
$downloadSize += $edge->{info}->{size} || 0;
}
}
print "$downloadSize\n";
my $narSize = $info->{narSize} || 0;
print "$narSize\n";
}
print "$downloadSize\n";
my $narSize = $info->{narSize} || 0;
print "$narSize\n";
print "\n";
}
else { die "unknown command `$cmd'"; }
}
@@ -236,8 +240,9 @@ elsif ($ARGV[0] ne "--substitute") {
}
die unless scalar @ARGV == 2;
die unless scalar @ARGV == 3;
my $targetPath = $ARGV[1];
my $destPath = $ARGV[2];
$fast = 0;
@@ -273,16 +278,6 @@ $dbh->disconnect;
my $curStep = 1;
my $maxStep = scalar @path;
sub downloadFile {
my $url = shift;
$ENV{"PRINT_PATH"} = 1;
$ENV{"QUIET"} = 1;
my ($hash, $path) = `$Nix::Config::binDir/nix-prefetch-url '$url'`;
die "download of `$url' failed" . ($! ? ": $!" : "") . "\n" unless $? == 0;
chomp $path;
return $path;
}
my $finalNarHash;
while (scalar @path > 0) {
@@ -314,13 +309,16 @@ while (scalar @path > 0) {
# Download the patch.
print STDERR " downloading patch...\n";
my $patchPath = downloadFile "$patch->{url}";
my $patchPath = "$tmpDir/patch";
checkURL $patch->{url};
system("$curl '$patch->{url}' -o $patchPath") == 0
or die "cannot download patch `$patch->{url}'\n";
# Apply the patch to the NAR archive produced in step 1 (for
# the already present path) or a later step (for patch sequences).
print STDERR " applying patch...\n";
system("$Nix::Config::libexecDir/bspatch $tmpNar $tmpNar2 $patchPath") == 0
or die "cannot apply patch `$patchPath' to $tmpNar";
or die "cannot apply patch `$patchPath' to $tmpNar\n";
if ($curStep < $maxStep) {
# The archive will be used as the base of the next patch.
@@ -329,8 +327,8 @@ while (scalar @path > 0) {
# This was the last patch. Unpack the final NAR archive
# into the target path.
print STDERR " unpacking patched archive...\n";
system("$Nix::Config::binDir/nix-store --restore $v < $tmpNar2") == 0
or die "cannot unpack $tmpNar2 into `$v'";
system("$Nix::Config::binDir/nix-store --restore $destPath < $tmpNar2") == 0
or die "cannot unpack $tmpNar2 to `$v'\n";
}
$finalNarHash = $patch->{narHash};
@@ -338,24 +336,27 @@ while (scalar @path > 0) {
elsif ($edge->{type} eq "narfile") {
my $narFile = $edge->{info};
print STDERR "downloading `$narFile->{url}' into `$v'\n";
print STDERR "downloading `$narFile->{url}' to `$v'\n";
my $size = $narFile->{size} || -1;
print LOGFILE "$$ narfile $narFile->{url} $size $v\n";
# Download the archive.
print STDERR " downloading archive...\n";
my $narFilePath = downloadFile "$narFile->{url}";
checkURL $narFile->{url};
my $decompressor =
$narFile->{compressionType} eq "bzip2" ? "| $Nix::Config::bzip2 -d" :
$narFile->{compressionType} eq "xz" ? "| $Nix::Config::xz -d" :
$narFile->{compressionType} eq "none" ? "" :
die "unknown compression type `$narFile->{compressionType}'";
if ($curStep < $maxStep) {
# The archive will be used a base to a patch.
system("$Nix::Config::bzip2 -d < '$narFilePath' > $tmpNar") == 0
or die "cannot unpack `$narFilePath' into `$v'";
system("$curl '$narFile->{url}' $decompressor > $tmpNar") == 0
or die "cannot download and unpack `$narFile->{url}' to `$v'\n";
} else {
# Unpack the archive into the target path.
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'";
# Unpack the archive to the target path.
system("$curl '$narFile->{url}' $decompressor | $Nix::Config::binDir/nix-store --restore '$destPath'") == 0
or die "cannot download and unpack `$narFile->{url}' to `$v'\n";
}
$finalNarHash = $narFile->{narHash};
@@ -365,21 +366,10 @@ while (scalar @path > 0) {
}
# Make sure that the hash declared in the manifest matches what we
# downloaded and unpacked.
if (defined $finalNarHash) {
my ($hashAlgo, $hash) = parseHash $finalNarHash;
# The hash in the manifest can be either in base-16 or base-32.
# Handle both.
my $hash2 = hashPath($hashAlgo, $hashAlgo eq "sha256" && length($hash) != 64, $targetPath);
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\n";
}
# Tell Nix about the expected hash so it can verify it.
die "cannot check integrity of the downloaded path since its hash is not known\n"
unless defined $finalNarHash;
print "$finalNarHash\n";
print STDERR "\n";
+23 -19
View File
@@ -1,22 +1,22 @@
#! @perl@ -w
#! @perl@ -w @perlFlags@
use strict;
my $procDir = "/proc";
use Nix::Utils;
use Nix::Config;
sub readProc {
return unless -d $procDir;
return unless -d "/proc";
opendir DIR, "/proc" or return;
opendir DIR, $procDir or return;
foreach my $name (readdir DIR) {
next unless $name =~ /^\d+$/;
my $process = "$procDir/$name";
my $process = "/proc/$name";
#print STDERR "=== $process\n";
my $target;
print "$target\n" if $target = readlink "$process/exe";
print "$target\n" if $target = readlink "$process/cwd";
@@ -36,6 +36,13 @@ sub readProc {
}
close MAP;
}
# Get all store paths that appear in the environment of this process.
eval {
my $env = Nix::Utils::readFile "$process/environ";
my @matches = $env =~ /\Q$Nix::Config::storeDir\E\/[0-9a-z]+[0-9a-zA-Z\+\-\._\?=]*/g;
print "$_\n" foreach @matches;
}
}
closedir DIR;
@@ -58,18 +65,15 @@ readProc;
lsof;
sub readFile {
my $path = shift;
if (-e $path) {
if (open FILE, "$path") {
while (<FILE>) {
print;
}
close FILE;
}
sub printFile {
my ($fn) = @_;
if (-e $fn) {
print Nix::Utils::readFile($fn), "\n";
}
}
# This is rather NixOS-specific, so it probably shouldn't be here.
readFile "/proc/sys/kernel/modprobe";
readFile "/proc/sys/kernel/fbsplash";
printFile "/proc/sys/kernel/modprobe";
printFile "/proc/sys/kernel/fbsplash";
printFile "/proc/sys/kernel/poweroff_cmd";
+34
View File
@@ -0,0 +1,34 @@
#! /bin/sh -e
nix=@nix@
regInfo=@regInfo@
if ! $nix/bin/nix-store --load-db < $regInfo; then
echo "$0: unable to register valid paths"
exit 1
fi
. @nix@/etc/profile.d/nix.sh
if ! $nix/bin/nix-env -i @nix@; then
echo "$0: unable to install Nix into your default profile"
exit 1
fi
# Add nix.sh to the shell's profile.d directory.
p=$NIX_LINK/etc/profile.d/nix.sh
if [ -w /etc/profile.d ]; then
ln -s $p /etc/profile.d/
elif [ -w /usr/local/etc/profile.d ]; then
ln -s $p /usr/local/etc/profile.d/
else
cat <<EOF
Installation finished. To ensure that the necessary environment
variables are set, please add the line
source $p
to your shell profile (e.g. ~/.profile).
EOF
fi
+92 -50
View File
@@ -3,23 +3,27 @@
use strict;
use Nix::Config;
use Nix::Store;
use Nix::Utils;
use File::Temp qw(tempdir);
my $dryRun = 0;
my $verbose = 0;
my $runEnv = 0;
my $runEnv = $0 =~ /nix-shell$/;
my $pure = 0;
my @instArgs = ();
my @buildArgs = ();
my @exprs = ();
my $shell = $ENV{SHELL} || "/bin/sh";
my $envCommand = "p=\$PATH; source \$stdenv/setup; PATH=\$PATH:\$p; exec $shell";
my $envCommand = ""; # interactive shell
my @envExclude = ();
my $myName = $runEnv ? "nix-shell" : "nix-build";
my $tmpDir = tempdir("nix-build.XXXXXX", CLEANUP => 1, TMPDIR => 1)
my $tmpDir = tempdir("$myName.XXXXXX", CLEANUP => 1, TMPDIR => 1)
or die "cannot create a temporary directory";
my $outLink = "./result";
@@ -33,29 +37,12 @@ for (my $n = 0; $n < scalar @ARGV; $n++) {
my $arg = $ARGV[$n];
if ($arg eq "--help") {
print STDERR <<EOF;
Usage: nix-build [OPTION]... [FILE]...
exec "man $myName" or die;
}
`nix-build' builds the given Nix expressions (which
default to ./default.nix if none are given). A symlink called
`result' is placed in the current directory.
Flags:
--add-drv-link: create a symlink `derivation' to the store derivation
--drv-link NAME: create symlink NAME instead of `derivation'
--no-out-link: do not create the `result' symlink
--out-link / -o NAME: create symlink NAME instead of `result'
--attr / -A ATTR: select a specific attribute from the Nix expression
--run-env: build dependencies of the specified derivation, then start a
shell with the environment of the derivation
--command: command to run with `--run-env'
--exclude: regexp specifying dependencies to be excluded by `--run-env'
Any additional flags are passed to `nix-store'.
EOF
elsif ($arg eq "--version") {
print "$myName (Nix) $Nix::Config::version\n";
exit 0;
# '` hack
}
elsif ($arg eq "--add-drv-link") {
@@ -104,7 +91,7 @@ EOF
$n += 2;
}
elsif ($arg eq "--max-jobs" or $arg eq "-j" or $arg eq "--max-silent-time" or $arg eq "--log-type" or $arg eq "--cores") {
elsif ($arg eq "--max-jobs" or $arg eq "-j" or $arg eq "--max-silent-time" or $arg eq "--log-type" or $arg eq "--cores" or $arg eq "--timeout") {
$n++;
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
push @buildArgs, ($arg, $ARGV[$n]);
@@ -114,30 +101,34 @@ EOF
push @buildArgs, "--dry-run";
$dryRun = 1;
}
elsif ($arg eq "--show-trace") {
push @instArgs, $arg;
}
elsif ($arg eq "-") {
@exprs = ("-");
}
elsif ($arg eq "--verbose" or substr($arg, 0, 2) eq "-v") {
push @buildArgs, $arg;
push @instArgs, $arg;
$verbose = 1;
}
elsif ($arg eq "--quiet") {
elsif ($arg eq "--quiet" || $arg eq "--repair") {
push @buildArgs, $arg;
push @instArgs, $arg;
}
elsif ($arg eq "--run-env") {
elsif ($arg eq "--run-env") { # obsolete
$runEnv = 1;
}
elsif ($arg eq "--command") {
$n++;
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
$envCommand = $ARGV[$n];
$envCommand = "$ARGV[$n]\nexit $!";
}
elsif ($arg eq "--exclude") {
@@ -146,6 +137,10 @@ EOF
push @envExclude, $ARGV[$n];
}
elsif ($arg eq "--pure") {
$pure = 1;
}
elsif (substr($arg, 0, 1) eq "-") {
push @buildArgs, $arg;
}
@@ -162,17 +157,22 @@ foreach my $expr (@exprs) {
# Instantiate.
my @drvPaths;
# !!! would prefer the perl 5.8.0 pipe open feature here.
my $pid = open(DRVPATHS, "-|") || exec "$Nix::Config::binDir/nix-instantiate", "--add-root", $drvLink, "--indirect", @instArgs, $expr;
while (<DRVPATHS>) {chomp; push @drvPaths, $_;}
if (!close DRVPATHS) {
die "nix-instantiate killed by signal " . ($? & 127) . "\n" if ($? & 127);
exit 1;
if ($expr !~ /^\/.*\.drv$/) {
# !!! would prefer the perl 5.8.0 pipe open feature here.
my $pid = open(DRVPATHS, "-|") || exec "$Nix::Config::binDir/nix-instantiate", "--add-root", $drvLink, "--indirect", @instArgs, $expr;
while (<DRVPATHS>) {chomp; push @drvPaths, $_;}
if (!close DRVPATHS) {
die "nix-instantiate killed by signal " . ($? & 127) . "\n" if ($? & 127);
exit 1;
}
} else {
push @drvPaths, $expr;
}
if ($runEnv) {
die "$0: --run-env requires a single derivation\n" if scalar @drvPaths != 1;
my $drvPath = readlink $drvPaths[0] or die "cannot read symlink `$drvPaths[0]'";
die "$0: a single derivation is required\n" if scalar @drvPaths != 1;
my $drvPath = $drvPaths[0];
$drvPath = readlink $drvPath or die "cannot read symlink `$drvPath'" if -l $drvPath;
my $drv = derivationFromPath($drvPath);
# Build or fetch all dependencies of the derivation.
@@ -181,28 +181,70 @@ foreach my $expr (@exprs) {
or die "$0: failed to build all dependencies\n";
# Set the environment.
$ENV{'NIX_BUILD_TOP'} = $ENV{'TMPDIR'} || "/tmp";
foreach (keys %{$drv->{env}}) {
$ENV{$_} = $drv->{env}->{$_};
if ($pure) {
foreach my $name (keys %ENV) {
next if $name eq "HOME" || $name eq "USER" || $name eq "LOGNAME" || $name eq "DISPLAY" || $name eq "PATH";
delete $ENV{$name};
}
# NixOS hack: prevent /etc/bashrc from sourcing /etc/profile.
$ENV{'__ETC_PROFILE_SOURCED'} = 1;
}
$ENV{'NIX_BUILD_TOP'} = $ENV{'TMPDIR'} = $ENV{'TEMPDIR'} = $ENV{'TMP'} = $ENV{'TEMP'} = $ENV{'TMPDIR'} // "/tmp";
$ENV{'NIX_STORE'} = $Nix::Config::storeDir;
$ENV{$_} = $drv->{env}->{$_} foreach keys %{$drv->{env}};
$ENV{'IN_NIX_SHELL'} = 1;
# Run a shell using the derivation's environment. For
# convenience, source $stdenv/setup to setup additional
# environment variables. Also don't lose the current $PATH
# directories.
exec($ENV{SHELL}, "-c", $envCommand);
# environment variables and shell functions. Also don't lose
# the current $PATH directories.
my $rcfile = "$tmpDir/rc";
writeFile(
$rcfile,
'unset BASH_ENV; ' .
'[ -n "$PS1" ] && [ -e ~/.bashrc ] && source ~/.bashrc; ' .
($pure ? '' : 'p=$PATH; ' ) .
'dontAddDisableDepTrack=1; ' .
'[ -e $stdenv/setup ] && source $stdenv/setup; ' .
($pure ? '' : 'PATH=$PATH:$p; ') .
'set +e; ' .
'[ -n "$PS1" ] && PS1="\n\[\033[1;32m\][nix-shell:\w]$\[\033[0m\] "; ' .
'unset NIX_ENFORCE_PURITY; ' .
'shopt -u nullglob; ' .
$envCommand);
$ENV{BASH_ENV} = $rcfile;
exec($ENV{NIX_BUILD_SHELL} // "bash", "--rcfile", $rcfile);
die;
}
# Ugly hackery to make "nix-build -A foo.all" produce symlinks
# ./result, ./result-dev, and so on, rather than ./result,
# ./result-2-dev, and so on. This combines multiple derivation
# paths into one "/nix/store/drv-path!out1,out2,..." argument.
my $prevDrvPath = "";
my @drvPaths2;
foreach my $drvPath (@drvPaths) {
my $target = readlink $drvPath or die "cannot read symlink `$drvPath'";
my $p = $drvPath; my $output = "out";
if ($drvPath =~ /(.*)!(.*)/) {
$p = $1; $output = $2;
} else {
$p = $drvPath;
}
my $target = readlink $p or die "cannot read symlink `$p'";
print STDERR "derivation is $target\n" if $verbose;
if ($target eq $prevDrvPath) {
push @drvPaths2, (pop @drvPaths2) . "," . $output;
} else {
push @drvPaths2, $target . "!" . $output;
$prevDrvPath = $target;
}
}
# Build.
my @outPaths;
$pid = open(OUTPATHS, "-|") || exec "$Nix::Config::binDir/nix-store", "--add-root", $outLink, "--indirect", "-r",
@buildArgs, @drvPaths;
my $pid = open(OUTPATHS, "-|") || exec "$Nix::Config::binDir/nix-store", "--add-root", $outLink, "--indirect", "-r",
@buildArgs, @drvPaths2;
while (<OUTPATHS>) {chomp; push @outPaths, $_;}
if (!close OUTPATHS) {
die "nix-store killed by signal " . ($? & 127) . "\n" if ($? & 127);
+46 -37
View File
@@ -4,6 +4,9 @@ use strict;
use File::Basename;
use File::Path qw(mkpath);
use Nix::Config;
use Nix::Manifest;
Nix::Config::readConfig;
my $manifestDir = $Nix::Config::manifestDir;
@@ -22,7 +25,7 @@ my $nixDefExpr = "$home/.nix-defexpr";
my $userName = getpwuid($<) or die "cannot figure out user name";
my $profile = "$Nix::Config::stateDir/profiles/per-user/$userName/channels";
mkpath(dirname $profile, 0, 0755);
my %channels;
@@ -65,11 +68,13 @@ sub addChannel {
sub removeChannel {
my ($name) = @_;
readChannels;
my $url = $channels{$name};
deleteOldManifests($url . "/MANIFEST", undef) if defined $url;
delete $channels{$name};
writeChannels;
system("$Nix::Config::binDir/nix-env --profile '$profile' -e '$name'") == 0
or die "cannot remove channel `$name'";
or die "cannot remove channel `$name'\n";
}
@@ -77,20 +82,14 @@ sub removeChannel {
# channels.
sub update {
my @channelNames = @_;
readChannels;
# Create the manifests directory if it doesn't exist.
mkdir $manifestDir, 0755 unless -e $manifestDir;
# Do we have write permission to the manifests directory?
die "$0: you do not have write permission to `$manifestDir'!\n" unless -W $manifestDir;
# Download each channel.
my $exprs = "";
foreach my $name (keys %channels) {
next if scalar @channelNames > 0 && ! grep { $_ eq $name } @{channelNames};
my $url = $channels{$name};
my $origUrl = "$url/MANIFEST";
@@ -101,17 +100,34 @@ sub update {
die "$0: unable to check `$url'\n" if $? != 0;
$headers =~ s/\r//g;
$url = $1 if $headers =~ /^Location:\s*(.*)\s*$/m;
# Pull the channel manifest.
$ENV{'NIX_ORIG_URL'} = $origUrl;
system("$Nix::Config::binDir/nix-pull", "--skip-wrong-store", "$url/MANIFEST") == 0
or die "cannot pull manifest from `$url'\n";
# Check if the channel advertises a binary cache.
my $binaryCacheURL = `$Nix::Config::curl --silent '$url'/binary-cache-url`;
my $extraAttrs = "";
my $getManifest = ($Nix::Config::config{"force-manifest"} // "false") eq "true";
if ($? == 0 && $binaryCacheURL ne "") {
$extraAttrs .= "binaryCacheURL = \"$binaryCacheURL\"; ";
deleteOldManifests($origUrl, undef);
} else {
$getManifest = 1;
}
if ($getManifest) {
# No binary cache, so pull the channel manifest.
mkdir $manifestDir, 0755 unless -e $manifestDir;
die "$0: you do not have write permission to `$manifestDir'!\n" unless -W $manifestDir;
$ENV{'NIX_ORIG_URL'} = $origUrl;
system("$Nix::Config::binDir/nix-pull", "--skip-wrong-store", "$url/MANIFEST") == 0
or die "cannot pull manifest from `$url'\n";
}
# Download the channel tarball.
my $fullURL = "$url/nixexprs.tar.bz2";
my $fullURL = "$url/nixexprs.tar.xz";
system("$Nix::Config::curl --fail --silent --head '$fullURL' > /dev/null") == 0 or
$fullURL = "$url/nixexprs.tar.bz2";
print STDERR "downloading Nix expressions from `$fullURL'...\n";
my ($hash, $path) = `PRINT_PATH=1 QUIET=1 $Nix::Config::binDir/nix-prefetch-url '$fullURL'`;
die "cannot fetch `$fullURL'" if $? != 0;
die "cannot fetch `$fullURL'\n" if $? != 0;
chomp $path;
# If the URL contains a version number, append it to the name
@@ -120,7 +136,7 @@ sub update {
my $cname = $name;
$cname .= $1 if basename($url) =~ /(-\d.*)$/;
$exprs .= "'f: f { name = \"$cname\"; channelName = \"$name\"; src = builtins.storePath \"$path\"; }' ";
$exprs .= "'f: f { name = \"$cname\"; channelName = \"$name\"; src = builtins.storePath \"$path\"; $extraAttrs }' ";
}
# Unpack the channel tarballs into the Nix store and install them
@@ -139,26 +155,14 @@ sub update {
}
sub usageError {
print STDERR <<EOF;
Usage:
nix-channel --add URL [CHANNEL-NAME]
nix-channel --remove CHANNEL-NAME
nix-channel --list
nix-channel --update [CHANNEL-NAME...]
EOF
exit 1;
}
usageError if scalar @ARGV == 0;
die "$0: argument expected\n" if scalar @ARGV == 0;
while (scalar @ARGV) {
my $arg = shift @ARGV;
if ($arg eq "--add") {
usageError if scalar @ARGV < 1 || scalar @ARGV > 2;
die "$0: `--add' requires one or two arguments\n" if scalar @ARGV < 1 || scalar @ARGV > 2;
my $url = shift @ARGV;
my $name = shift @ARGV;
unless (defined $name) {
@@ -171,13 +175,13 @@ while (scalar @ARGV) {
}
if ($arg eq "--remove") {
usageError if scalar @ARGV != 1;
die "$0: `--remove' requires one argument\n" if scalar @ARGV != 1;
removeChannel(shift @ARGV);
last;
}
if ($arg eq "--list") {
usageError if scalar @ARGV != 0;
die "$0: `--list' requires one argument\n" if scalar @ARGV != 0;
readChannels;
foreach my $name (keys %channels) {
print "$name $channels{$name}\n";
@@ -189,12 +193,17 @@ while (scalar @ARGV) {
update(@ARGV);
last;
}
elsif ($arg eq "--help") {
usageError;
exec "man nix-channel" or die;
}
elsif ($arg eq "--version") {
print "nix-channel (Nix) $Nix::Config::version\n";
exit 0;
}
else {
die "unknown argument `$arg'; try `--help'";
die "unknown argument `$arg'; try `--help'\n";
}
}
+8 -3
View File
@@ -9,10 +9,15 @@ my $profilesDir = "@localstatedir@/nix/profiles";
# Process the command line arguments.
my @args = ();
my $removeOld = 0;
my $dryRun = 0;
for my $arg (@ARGV) {
if ($arg eq "--delete-old" || $arg eq "-d") {
$removeOld = 1;
} elsif ($arg eq "--dry-run") {
$dryRun = 1;
} elsif ($arg eq "--help") {
exec "man nix-collect-garbage" or die;
} else {
push @args, $arg;
}
@@ -35,13 +40,13 @@ sub removeOldGenerations {
$name = $dir . "/" . $name;
if (-l $name && (readlink($name) =~ /link/)) {
print STDERR "removing old generations of profile $name\n";
system("$Nix::Config::binDir/nix-env", "-p", $name, "--delete-generations", "old");
system("$Nix::Config::binDir/nix-env", "-p", $name, "--delete-generations", "old", $dryRun ? "--dry-run" : ());
}
elsif (! -l $name && -d $name) {
removeOldGenerations $name;
}
}
closedir $dh or die;
}
@@ -49,4 +54,4 @@ removeOldGenerations $profilesDir if $removeOld;
# Run the actual garbage collector.
exec "$Nix::Config::binDir/nix-store", "--gc", @args;
exec "$Nix::Config::binDir/nix-store", "--gc", @args unless $dryRun;
+28 -14
View File
@@ -4,6 +4,7 @@ use Nix::SSH;
use Nix::Config;
use Nix::Store;
use Nix::CopyClosure;
use List::Util qw(sum);
if (scalar @ARGV < 1) {
@@ -17,19 +18,14 @@ EOF
# Get the target host.
my $sshHost;
my $sign = 0;
my $compressor = "";
my $decompressor = "";
my $progressViewer = "";
my $toMode = 1;
my $includeOutputs = 0;
my $dryRun = 0;
my $useSubstitutes = 0;
# !!! Copied from nix-pack-closure, should put this in a module.
@@ -37,8 +33,11 @@ my @storePaths = ();
while (@ARGV) {
my $arg = shift @ARGV;
if ($arg eq "--sign") {
if ($arg eq "--help") {
exec "man nix-copy-closure" or die;
}
elsif ($arg eq "--sign") {
$sign = 1;
}
elsif ($arg eq "--gzip") {
@@ -68,6 +67,9 @@ while (@ARGV) {
elsif ($arg eq "--dry-run") {
$dryRun = 1;
}
elsif ($arg eq "--use-substitutes" || $arg eq "-s") {
$useSubstitutes = 1;
}
elsif (!defined $sshHost) {
$sshHost = $arg;
}
@@ -76,12 +78,16 @@ while (@ARGV) {
}
}
die "$0: you did not specify a host name\n" unless defined $sshHost;
openSSHConnection $sshHost or die "$0: unable to start SSH\n";
if ($toMode) { # Copy TO the remote machine.
Nix::CopyClosure::copyTo($sshHost, [ @sshOpts ], [ @storePaths ], $compressor, $decompressor, $includeOutputs, $dryRun, $sign, $progressViewer);
Nix::CopyClosure::copyTo(
$sshHost, [ @sshOpts ], [ @storePaths ], $compressor, $decompressor,
$includeOutputs, $dryRun, $sign, $progressViewer, $useSubstitutes);
}
else { # Copy FROM the remote machine.
@@ -92,7 +98,7 @@ else { # Copy FROM the remote machine.
my $extraOpts = $includeOutputs ? "--include-outputs" : "";
my $pid = open(READ,
"set -f; ssh @sshOpts $sshHost nix-store --query --requisites $extraOpts @storePaths|") or die;
while (<READ>) {
chomp;
die "bad: $_" unless /^\//;
@@ -101,15 +107,23 @@ else { # Copy FROM the remote machine.
close READ or die "nix-store on remote machine `$sshHost' failed: $?";
my $missingSize = 0;
if ($progressViewer ne "") {
$missingSize = sum (split ' ', `set -f; ssh @sshOpts $sshHost nix-store -q --size @missing`) or die;
}
# Export the store paths on the remote machine and import them locally.
if (scalar @missing > 0) {
print STDERR "copying ", scalar @missing, " missing paths from $sshHost...\n";
$compressor = "| $compressor" if $compressor ne "";
$decompressor = "$decompressor |" if $decompressor ne "";
$progressViewer = "$progressViewer |" if $progressViewer ne "";
unless ($dryRun) {
if ($useSubstitutes) {
system "$Nix::Config::binDir/nix-store -r --ignore-unknown @missing";
}
$compressor = "| $compressor" if $compressor ne "";
$decompressor = "$decompressor |" if $decompressor ne "";
$progressViewer = "$progressViewer -s $missingSize |" if $progressViewer ne "";
my $extraOpts = $sign ? "--sign" : "";
system("set -f; ssh $sshHost @sshOpts 'nix-store --export $extraOpts @missing $compressor' | $progressViewer $decompressor $Nix::Config::binDir/nix-store --import > /dev/null") == 0
system("set -f; ssh $sshHost @sshOpts 'nix-store --export $extraOpts @missing $compressor' | $decompressor $progressViewer $Nix::Config::binDir/nix-store --import > /dev/null") == 0
or die "copying store paths from remote machine `$sshHost' failed: $?";
}
}
+24 -32
View File
@@ -3,27 +3,11 @@
use strict;
use File::Temp qw(tempdir);
use Nix::Config;
sub usageError {
print STDERR <<EOF;
Usage: nix-install-package (FILE | --url URL)
Install a Nix Package (.nixpkg) either directly from FILE or by
downloading it from URL.
Flags:
--profile / -p LINK: install into the specified profile
--non-interactive: don't run inside a new terminal
EOF
; # '
exit 1;
}
use Nix::Utils;
# Parse the command line arguments.
my @args = @ARGV;
usageError if scalar @args == 0;
my $source;
my $fromURL = 0;
@@ -33,14 +17,14 @@ my $interactive = 1;
while (scalar @args) {
my $arg = shift @args;
if ($arg eq "--help") {
usageError;
exec "man nix-install-package" or die;
}
elsif ($arg eq "--url") {
$fromURL = 1;
}
elsif ($arg eq "--profile" || $arg eq "-p") {
my $profile = shift @args;
usageError if !defined $profile;
die "$0: `--profile' requires an argument\n" if !defined $profile;
push @extraNixEnvArgs, "-p", $profile;
}
elsif ($arg eq "--non-interactive") {
@@ -51,7 +35,7 @@ while (scalar @args) {
}
}
usageError unless defined $source;
die "$0: please specify a .nixpkg file or URL\n" unless defined $source;
# Re-execute in a terminal, if necessary, so that if we're executed
@@ -72,7 +56,7 @@ my $tmpDir = tempdir("nix-install-package.XXXXXX", CLEANUP => 1, TMPDIR => 1)
sub barf {
my $msg = shift;
print "$msg\n";
print "\nInstallation failed: $msg\n";
<STDIN> if $interactive;
exit 1;
}
@@ -92,7 +76,6 @@ open PKGFILE, "<$pkgFile" or barf "cannot open `$pkgFile': $!";
my $contents = <PKGFILE>;
close PKGFILE;
my $urlRE = "(?: [a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\']+ )";
my $nameRE = "(?: [A-Za-z0-9\+\-\.\_\?\=]+ )"; # see checkStoreName()
my $systemRE = "(?: [A-Za-z0-9\+\-\_]+ )";
my $pathRE = "(?: \/ [\/A-Za-z0-9\+\-\.\_\?\=]* )";
@@ -101,7 +84,7 @@ my $pathRE = "(?: \/ [\/A-Za-z0-9\+\-\.\_\?\=]* )";
# store path. We'll let nix-env do that.
$contents =~
/ ^ \s* (\S+) \s+ ($urlRE) \s+ ($nameRE) \s+ ($systemRE) \s+ ($pathRE) \s+ ($pathRE) /x
/ ^ \s* (\S+) \s+ ($Nix::Utils::urlRE) \s+ ($nameRE) \s+ ($systemRE) \s+ ($pathRE) \s+ ($pathRE) ( \s+ ($Nix::Utils::urlRE) )? /x
or barf "invalid package contents";
my $version = $1;
my $manifestURL = $2;
@@ -109,6 +92,7 @@ my $drvName = $3;
my $system = $4;
my $drvPath = $5;
my $outPath = $6;
my $binaryCacheURL = $8;
barf "invalid package version `$version'" unless $version eq "NIXPKG1";
@@ -122,17 +106,25 @@ if ($interactive) {
}
# Store the manifest in the temporary directory so that we don't
# 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} = "";
if (defined $binaryCacheURL) {
push @extraNixEnvArgs, "--option", "binary-caches", $binaryCacheURL;
print "\nPulling manifests...\n";
system("$Nix::Config::binDir/nix-pull", $manifestURL) == 0
or barf "nix-pull failed: $?";
} else {
# Store the manifest in the temporary directory so that we don't
# 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("$Nix::Config::binDir/nix-pull", $manifestURL) == 0
or barf "nix-pull failed: $?";
}
print "\nInstalling package...\n";
+21 -19
View File
@@ -6,12 +6,30 @@ use File::Temp qw(tempdir);
use File::stat;
use Nix::Store;
use Nix::Config;
use Nix::Utils;
my $url = shift;
my $expHash = shift;
my $hashType = $ENV{'NIX_HASH_ALGO'} || "sha256";
my $hashType = $ENV{'NIX_HASH_ALGO'} || "sha256"; # obsolete
my $cacheDir = $ENV{'NIX_DOWNLOAD_CACHE'};
my @args;
my $arg;
while ($arg = shift) {
if ($arg eq "--help") {
exec "man nix-prefetch-url" or die;
} elsif ($arg eq "--type") {
$hashType = shift;
die "$0: `$arg' requires an argument\n" unless defined $hashType;
} elsif (substr($arg, 0, 1) eq "-") {
die "$0: unknown flag `$arg'\n";
} else {
push @args, $arg;
}
}
my $url = $args[0];
my $expHash = $args[1];
if (!defined $url || $url eq "") {
print STDERR <<EOF
Usage: nix-prefetch-url URL [EXPECTED-HASH]
@@ -20,22 +38,6 @@ EOF
exit 1;
}
sub writeFile {
my ($fn, $s) = @_;
open TMP, ">$fn" or die;
print TMP "$s" or die;
close TMP or die;
}
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";
+7 -8
View File
@@ -1,18 +1,17 @@
if test -n "$HOME"; then
NIX_LINK="$HOME/.nix-profile"
if ! test -L "$NIX_LINK"; then
# Set the default profile.
if ! [ -L "$NIX_LINK" ]; then
echo "creating $NIX_LINK" >&2
_NIX_DEF_LINK=@localstatedir@/nix/profiles/default
@coreutils@/ln -s "$_NIX_DEF_LINK" "$NIX_LINK"
fi
# Subscribe the root user to the Nixpkgs channel by default.
if [ ! -e $HOME/.nix-channels ]; then
echo "http://nixos.org/channels/nixpkgs-unstable nixpkgs" > $HOME/.nix-channels
fi
export PATH=$NIX_LINK/bin:$PATH
fi
# This is a quick hack to make fontconfig-based packages in Nixpkgs
# work out of the box on non-NixOS systems. Of course, we should
# really fix fontconfig...
if test -z "$FONTCONFIG_FILE" -a -e /etc/fonts/fonts.conf; then
export FONTCONFIG_FILE=/etc/fonts/fonts.conf
fi
+6 -15
View File
@@ -76,31 +76,22 @@ sub processURL {
open URL, ">$urlFile" or die "cannot create `$urlFile'";
print URL $origUrl;
close URL;
my $finalPath = "$manifestDir/$baseName-$hash.nixmanifest";
unlink $finalPath if -e $finalPath;
symlink("$manifest", "$finalPath")
or die "cannot link `$finalPath to `$manifest'";
# Delete all old manifests downloaded from this URL.
for my $urlFile2 (glob "$manifestDir/*.url") {
next if $urlFile eq $urlFile2;
open URL, "<$urlFile2" or die;
my $url2 = <URL>;
chomp $url2;
close URL;
next unless $origUrl eq $url2;
my $base = $urlFile2; $base =~ s/.url$//;
unlink "${base}.url";
unlink "${base}.nixmanifest";
}
deleteOldManifests($origUrl, $urlFile);
}
while (@ARGV) {
my $url = shift @ARGV;
if ($url eq "--skip-wrong-store") {
if ($url eq "--help") {
exec "man nix-pull" or die;
} elsif ($url eq "--skip-wrong-store") {
# No-op, no longer supported.
} else {
processURL $url;
+189 -195
View File
@@ -1,85 +1,85 @@
#! @perl@ -w @perlFlags@
use strict;
use File::Basename;
use File::Temp qw(tempdir);
use File::Path qw(mkpath);
use File::stat;
use File::Copy;
use Nix::Config;
use Nix::Store;
use Nix::Manifest;
my $hashAlgo = "sha256";
use Nix::Utils;
my $tmpDir = tempdir("nix-push.XXXXXX", CLEANUP => 1, TMPDIR => 1)
or die "cannot create a temporary directory";
my $nixExpr = "$tmpDir/create-nars.nix";
my $manifest = "$tmpDir/MANIFEST";
my $curl = "$Nix::Config::curl --fail --silent";
my $extraCurlFlags = ${ENV{'CURL_FLAGS'}};
$curl = "$curl $extraCurlFlags" if defined $extraCurlFlags;
# Parse the command line.
my $localCopy;
my $localArchivesDir;
my $localManifestFile;
my $compressionType = "xz";
my $force = 0;
my $destDir;
my $writeManifest = 0;
my $manifestPath;
my $archivesURL;
my $link = 0;
my @roots;
my $targetArchivesUrl;
for (my $n = 0; $n < scalar @ARGV; $n++) {
my $arg = $ARGV[$n];
my $archivesPutURL;
my $archivesGetURL;
my $manifestPutURL;
sub showSyntax {
print STDERR <<EOF
Usage: nix-push --copy ARCHIVES_DIR MANIFEST_FILE PATHS...
or: nix-push ARCHIVES_PUT_URL ARCHIVES_GET_URL MANIFEST_PUT_URL PATHS...
`nix-push' copies or uploads the closure of PATHS to the given
destination.
EOF
; # `
exit 1;
}
showSyntax if scalar @ARGV < 1;
if ($ARGV[0] eq "--copy") {
showSyntax if scalar @ARGV < 3;
$localCopy = 1;
shift @ARGV;
$localArchivesDir = shift @ARGV;
$localManifestFile = shift @ARGV;
if ($ARGV[0] eq "--target") {
shift @ARGV;
$targetArchivesUrl = shift @ARGV;
}
else {
$targetArchivesUrl = "file://$localArchivesDir";
if ($arg eq "--help") {
exec "man nix-push" or die;
} elsif ($arg eq "--bzip2") {
$compressionType = "bzip2";
} elsif ($arg eq "--none") {
$compressionType = "none";
} elsif ($arg eq "--force") {
$force = 1;
} elsif ($arg eq "--dest") {
$n++;
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
$destDir = $ARGV[$n];
mkpath($destDir, 0, 0755);
} elsif ($arg eq "--manifest") {
$writeManifest = 1;
} elsif ($arg eq "--manifest-path") {
$n++;
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
$manifestPath = $ARGV[$n];
$writeManifest = 1;
mkpath(dirname($manifestPath), 0, 0755);
} elsif ($arg eq "--url-prefix") {
$n++;
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
$archivesURL = $ARGV[$n];
} elsif ($arg eq "--link") {
$link = 1;
} elsif (substr($arg, 0, 1) eq "-") {
die "$0: unknown flag `$arg'\n";
} else {
push @roots, $arg;
}
}
else {
showSyntax if scalar @ARGV < 3;
$localCopy = 0;
$archivesPutURL = shift @ARGV;
$archivesGetURL = shift @ARGV;
$manifestPutURL = shift @ARGV;
}
die "$0: please specify a destination directory\n" if !defined $destDir;
$archivesURL = "file://$destDir" unless defined $archivesURL;
# From the given store paths, determine the set of requisite store
# paths, i.e, the paths required to realise them.
my %storePaths;
foreach my $path (@ARGV) {
die unless $path =~ /^\//;
# Get all paths referenced by the normalisation of the given
foreach my $path (@roots) {
# Get all paths referenced by the normalisation of the given
# Nix expression.
my $pid = open(READ,
"$Nix::Config::binDir/nix-store --query --requisites --force-realise " .
"--include-outputs '$path'|") or die;
while (<READ>) {
chomp;
die "bad: $_" unless /^\//;
@@ -92,19 +92,50 @@ foreach my $path (@ARGV) {
my @storePaths = keys %storePaths;
# For each path, create a Nix expression that turns the path into
# a Nix archive.
# Don't create archives for files that are already in the binary cache.
my @storePaths2;
my %narFiles;
foreach my $storePath (@storePaths) {
my $pathHash = substr(basename($storePath), 0, 32);
my $narInfoFile = "$destDir/$pathHash.narinfo";
if (-e $narInfoFile) {
my $narInfo = parseNARInfo($storePath, readFile($narInfoFile));
my $narFile = "$destDir/$narInfo->{url}";
if (-e $narFile) {
print STDERR "skipping existing $storePath\n";
# Add the NAR info to $narFiles if we're writing a
# manifest.
$narFiles{$storePath} = [
{ url => ("$archivesURL/" . basename $narInfo->{url})
, hash => $narInfo->{fileHash}
, size => $narInfo->{fileSize}
, compressionType => $narInfo->{compression}
, narHash => $narInfo->{narHash}
, narSize => $narInfo->{narSize}
, references => join(" ", map { "$Nix::Config::storeDir/$_" } @{$narInfo->{refs}})
, deriver => $narInfo->{deriver} ? "$Nix::Config::storeDir/$narInfo->{deriver}" : undef
}
] if $writeManifest;
next;
}
}
push @storePaths2, $storePath;
}
# Create a list of Nix derivations that turn each path into a Nix
# archive.
open NIX, ">$nixExpr";
print NIX "[";
foreach my $storePath (@storePaths) {
foreach my $storePath (@storePaths2) {
die unless ($storePath =~ /\/[0-9a-z]{32}[^\"\\\$]*$/);
# Construct a Nix expression that creates a Nix archive.
my $nixexpr =
my $nixexpr =
"(import <nix/nar.nix> " .
"{ storePath = builtins.storePath \"$storePath\"; hashAlgo = \"$hashAlgo\"; }) ";
"{ storePath = builtins.storePath \"$storePath\"; hashAlgo = \"sha256\"; compressionType = \"$compressionType\"; }) ";
print NIX $nixexpr;
}
@@ -112,172 +143,135 @@ print NIX "]";
close NIX;
# Instantiate store derivations from the Nix expression.
my @storeExprs;
print STDERR "instantiating store derivations...\n";
my $pid = open(READ, "$Nix::Config::binDir/nix-instantiate $nixExpr|")
or die "cannot run nix-instantiate";
# Build the Nix expression.
print STDERR "building compressed archives...\n";
my @narPaths;
my $pid = open(READ, "$Nix::Config::binDir/nix-build $nixExpr -o $tmpDir/result |")
or die "cannot run nix-build";
while (<READ>) {
chomp;
die unless /^\//;
push @storeExprs, $_;
push @narPaths, $_;
}
close READ or die "nix-instantiate failed: $?";
close READ or die "nix-build failed: $?";
# Build the derivations.
print STDERR "creating archives...\n";
my @narPaths;
my @tmp = @storeExprs;
while (scalar @tmp > 0) {
my $n = scalar @tmp;
if ($n > 256) { $n = 256 };
my @tmp2 = @tmp[0..$n - 1];
@tmp = @tmp[$n..scalar @tmp - 1];
my $pid = open(READ, "$Nix::Config::binDir/nix-store --realise @tmp2|")
or die "cannot run nix-store";
while (<READ>) {
chomp;
die unless (/^\//);
push @narPaths, "$_";
}
close READ or die "nix-store failed: $?";
# Write the cache info file.
my $cacheInfoFile = "$destDir/nix-cache-info";
if (! -e $cacheInfoFile) {
open FILE, ">$cacheInfoFile" or die "cannot create $cacheInfoFile: $!";
print FILE "StoreDir: $Nix::Config::storeDir\n";
print FILE "WantMassQuery: 0\n"; # by default, don't hit this cache for "nix-env -qas"
close FILE;
}
# Create the manifest.
print STDERR "creating manifest...\n";
# Copy the archives and the corresponding NAR info files.
print STDERR "copying archives...\n";
my %narFiles;
my %patches;
my $totalNarSize = 0;
my $totalCompressedSize = 0;
my @narArchives;
for (my $n = 0; $n < scalar @storePaths; $n++) {
my $storePath = $storePaths[$n];
for (my $n = 0; $n < scalar @storePaths2; $n++) {
my $storePath = $storePaths2[$n];
my $narDir = $narPaths[$n];
$storePath =~ /\/([^\/]*)$/;
my $basename = $1;
defined $basename or die;
my $baseName = basename $storePath;
open HASH, "$narDir/narbz2-hash" or die "cannot open narbz2-hash";
my $narbz2Hash = <HASH>;
chomp $narbz2Hash;
$narbz2Hash =~ /^[0-9a-z]+$/ or die "invalid hash";
close HASH;
my $narName = "$narbz2Hash.nar.bz2";
my $narFile = "$narDir/$narName";
(-f $narFile) or die "narfile for $storePath not found";
push @narArchives, $narFile;
my $narbz2Size = stat($narFile)->size;
my $references = `$Nix::Config::binDir/nix-store --query --references '$storePath'`;
die "cannot query references for `$storePath'" if $? != 0;
$references = join(" ", split(" ", $references));
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 = `$Nix::Config::binDir/nix-store --query --hash '$storePath'`;
die "cannot query hash for `$storePath'" if $? != 0;
chomp $narHash;
# Get info about the store path.
my ($deriver, $narHash, $time, $narSize, $refs) = queryPathInfo($storePath, 1);
# 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;
my $nar = "$tmpDir/nar";
system("$Nix::Config::binDir/nix-store --dump $storePath > $nar") == 0
or die "cannot dump $storePath\n";
$narHash = `$Nix::Config::binDir/nix-hash --type sha256 --base32 --flat $nar`;
die "cannot hash `$nar'" if $? != 0;
chomp $narHash;
$narHash = "sha256:$narHash";
$narSize = stat("$nar")->size;
unlink $nar or die;
}
my $narSize = `$Nix::Config::binDir/nix-store --query --size '$storePath'`;
die "cannot query size for `$storePath'" if $? != 0;
chomp $narSize;
$totalNarSize += $narSize;
my $url;
if ($localCopy) {
$url = "$targetArchivesUrl/$narName";
} else {
$url = "$archivesGetURL/$narName";
# Get info about the compressed NAR.
open HASH, "$narDir/nar-compressed-hash" or die "cannot open nar-compressed-hash";
my $compressedHash = <HASH>;
chomp $compressedHash;
$compressedHash =~ /^[0-9a-z]+$/ or die "invalid hash";
close HASH;
my $narName = "$compressedHash.nar" . ($compressionType eq "xz" ? ".xz" : $compressionType eq "bzip2" ? ".bz2" : "");
my $narFile = "$narDir/$narName";
(-f $narFile) or die "NAR file for $storePath not found";
my $compressedSize = stat($narFile)->size;
$totalCompressedSize += $compressedSize;
printf STDERR "%s [%.2f MiB, %.1f%%]\n", $storePath,
$compressedSize / (1024 * 1024), $compressedSize / $narSize * 100;
# Copy the compressed NAR.
my $dst = "$destDir/$narName";
if (! -f $dst) {
my $tmp = "$destDir/.tmp.$$.$narName";
if ($link) {
link($narFile, $tmp) or die "cannot link $tmp to $narFile: $!\n";
} else {
copy($narFile, $tmp) or die "cannot copy $narFile to $tmp: $!\n";
}
rename($tmp, $dst) or die "cannot rename $tmp to $dst: $!\n";
}
# Write the info file.
my $info;
$info .= "StorePath: $storePath\n";
$info .= "URL: $narName\n";
$info .= "Compression: $compressionType\n";
$info .= "FileHash: sha256:$compressedHash\n";
$info .= "FileSize: $compressedSize\n";
$info .= "NarHash: $narHash\n";
$info .= "NarSize: $narSize\n";
$info .= "References: " . join(" ", map { basename $_ } @{$refs}) . "\n";
if (defined $deriver) {
$info .= "Deriver: " . basename $deriver . "\n";
if (isValidPath($deriver)) {
my $drv = derivationFromPath($deriver);
$info .= "System: $drv->{platform}\n";
}
}
my $pathHash = substr(basename($storePath), 0, 32);
$dst = "$destDir/$pathHash.narinfo";
if ($force || ! -f $dst) {
my $tmp = "$destDir/.tmp.$$.$pathHash.narinfo";
open INFO, ">$tmp" or die;
print INFO "$info" or die;
close INFO or die;
rename($tmp, $dst) or die "cannot rename $tmp to $dst: $!\n";
}
$narFiles{$storePath} = [
{ url => $url
, hash => "$hashAlgo:$narbz2Hash"
, size => $narbz2Size
{ url => "$archivesURL/$narName"
, hash => "sha256:$compressedHash"
, size => $compressedSize
, compressionType => $compressionType
, narHash => "$narHash"
, narSize => $narSize
, references => $references
, references => join(" ", @{$refs})
, deriver => $deriver
}
];
] if $writeManifest;
}
writeManifest $manifest, \%narFiles, \%patches;
printf STDERR "total compressed size %.2f MiB, %.1f%%\n",
$totalCompressedSize / (1024 * 1024), $totalCompressedSize / ($totalNarSize || 1) * 100;
sub copyFile {
my $src = shift;
my $dst = shift;
my $tmp = "$dst.tmp.$$";
system("@coreutils@/cp", $src, $tmp) == 0 or die "cannot copy file";
rename($tmp, $dst) or die "cannot rename file: $!";
}
# Upload/copy the archives.
print STDERR "uploading/copying archives...\n";
sub archiveExists {
my $name = shift;
print STDERR " HEAD on $archivesGetURL/$name\n";
return system("$curl --head $archivesGetURL/$name > /dev/null") == 0;
}
foreach my $narArchive (@narArchives) {
$narArchive =~ /\/([^\/]*)$/;
my $basename = $1;
if ($localCopy) {
# Since nix-push creates $dst atomically, if it exists we
# don't have to copy again.
my $dst = "$localArchivesDir/$basename";
if (! -f "$localArchivesDir/$basename") {
print STDERR " $narArchive\n";
copyFile $narArchive, $dst;
}
}
else {
if (!archiveExists("$basename")) {
print STDERR " $narArchive\n";
system("$curl --show-error --upload-file " .
"'$narArchive' '$archivesPutURL/$basename' > /dev/null") == 0 or
die "curl failed on $narArchive: $?";
}
}
}
# Upload the manifest.
print STDERR "uploading manifest...\n";
if ($localCopy) {
copyFile $manifest, $localManifestFile;
copyFile "$manifest.bz2", "$localManifestFile.bz2";
} else {
system("$curl --show-error --upload-file " .
"'$manifest' '$manifestPutURL' > /dev/null") == 0 or
die "curl failed on $manifest: $?";
system("$curl --show-error --upload-file " .
"'$manifest'.bz2 '$manifestPutURL'.bz2 > /dev/null") == 0 or
die "curl failed on $manifest: $?";
}
# Optionally write a manifest.
writeManifest($manifestPath // "$destDir/MANIFEST", \%narFiles, \()) if $writeManifest;
+2 -2
View File
@@ -1,3 +1,3 @@
SUBDIRS = bin2c boost libutil libstore libmain nix-store nix-hash \
libexpr nix-instantiate nix-env nix-worker nix-setuid-helper \
SUBDIRS = boost libutil libstore libmain nix-store nix-hash \
libexpr nix-instantiate nix-env nix-daemon nix-setuid-helper \
nix-log2xml bsdiff-4.3
-6
View File
@@ -1,6 +0,0 @@
noinst_PROGRAMS = bin2c
bin2c_SOURCES = bin2c.c
bin2c$(EXEEXT): bin2c.c
$(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) -o bin2c bin2c.c
-23
View File
@@ -1,23 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
void print(const char *format, ...)
{
va_list ap;
va_start(ap, format);
if (vprintf(format, ap) < 0) abort();
va_end(ap);
}
int main(int argc, char * * argv)
{
int c;
if (argc != 2) abort();
print("static unsigned char %s[] = { ", argv[1]);
while ((c = getchar()) != EOF) {
print("0x%02x, ", (unsigned char) c);
}
print("0 };\n");
return 0;
}
+26 -26
View File
@@ -6,19 +6,18 @@
namespace nix {
// !!! Shouldn't we return a pointer to a Value?
void findAlongAttrPath(EvalState & state, const string & attrPath,
Bindings & autoArgs, Expr * e, Value & v)
Value * findAlongAttrPath(EvalState & state, const string & attrPath,
Bindings & autoArgs, Value & vIn)
{
Strings tokens = tokenizeString(attrPath, ".");
Strings tokens = tokenizeString<Strings>(attrPath, ".");
Error attrError =
Error(format("attribute selection path `%1%' does not match expression") % attrPath);
string curPath;
state.mkThunk_(v, e);
Value * v = &vIn;
foreach (Strings::iterator, i, tokens) {
if (!curPath.empty()) curPath += ".";
@@ -27,47 +26,48 @@ void findAlongAttrPath(EvalState & state, const string & attrPath,
/* Is *i an index (integer) or a normal attribute name? */
enum { apAttr, apIndex } apType = apAttr;
string attr = *i;
int attrIndex = -1;
unsigned int attrIndex;
if (string2Int(attr, attrIndex)) apType = apIndex;
/* Evaluate the expression. */
Value vTmp;
state.autoCallFunction(autoArgs, v, vTmp);
v = vTmp;
state.forceValue(v);
Value * vNew = state.allocValue();
state.autoCallFunction(autoArgs, *v, *vNew);
v = vNew;
state.forceValue(*v);
/* It should evaluate to either an attribute set or an
expression, according to what is specified in the
attrPath. */
/* It should evaluate to either a set or an expression,
according to what is specified in the attrPath. */
if (apType == apAttr) {
if (v.type != tAttrs)
if (v->type != tAttrs)
throw TypeError(
format("the expression selected by the selection path `%1%' should be an attribute set but is %2%")
% curPath % showType(v));
format("the expression selected by the selection path `%1%' should be a set but is %2%")
% curPath % showType(*v));
Bindings::iterator a = v.attrs->find(state.symbols.create(attr));
if (a == v.attrs->end())
Bindings::iterator a = v->attrs->find(state.symbols.create(attr));
if (a == v->attrs->end())
throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath);
v = *a->value;
v = &*a->value;
}
else if (apType == apIndex) {
if (v.type != tList)
if (v->type != tList)
throw TypeError(
format("the expression selected by the selection path `%1%' should be a list but is %2%")
% curPath % showType(v));
% curPath % showType(*v));
if (attrIndex >= v.list.length)
if (attrIndex >= v->list.length)
throw Error(format("list index %1% in selection path `%2%' is out of range") % attrIndex % curPath);
v = *v.list.elems[attrIndex];
v = v->list.elems[attrIndex];
}
}
return v;
}
}
+3 -10
View File
@@ -1,20 +1,13 @@
#ifndef __ATTR_PATH_H
#define __ATTR_PATH_H
#pragma once
#include "eval.hh"
#include <string>
#include <map>
namespace nix {
void findAlongAttrPath(EvalState & state, const string & attrPath,
Bindings & autoArgs, Expr * e, Value & v);
Value * findAlongAttrPath(EvalState & state, const string & attrPath,
Bindings & autoArgs, Value & vIn);
}
#endif /* !__ATTR_PATH_H */
+1 -6
View File
@@ -1,9 +1,7 @@
#ifndef __COMMON_OPTS_H
#define __COMMON_OPTS_H
#pragma once
#include "eval.hh"
namespace nix {
/* Some common option parsing between nix-env and nix-instantiate. */
@@ -17,6 +15,3 @@ bool parseSearchPathArg(const string & arg, Strings::iterator & i,
Path lookupFileArg(EvalState & state, string s);
}
#endif /* !__COMMON_OPTS_H */
+8 -10
View File
@@ -1,5 +1,4 @@
#ifndef __EVAL_INLINE_H
#define __EVAL_INLINE_H
#pragma once
#include "eval.hh"
@@ -8,7 +7,6 @@
namespace nix {
LocalNoInlineNoReturn(void throwEvalError(const char * s))
{
throw EvalError(s);
@@ -23,13 +21,16 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s2))
void EvalState::forceValue(Value & v)
{
if (v.type == tThunk) {
ValueType saved = v.type;
Env * env = v.thunk.env;
Expr * expr = v.thunk.expr;
try {
v.type = tBlackhole;
//checkInterrupt();
v.thunk.expr->eval(*this, *v.thunk.env, v);
expr->eval(*this, *env, v);
} catch (Error & e) {
v.type = saved;
v.type = tThunk;
v.thunk.env = env;
v.thunk.expr = expr;
throw;
}
}
@@ -44,7 +45,7 @@ inline void EvalState::forceAttrs(Value & v)
{
forceValue(v);
if (v.type != tAttrs)
throwTypeError("value is %1% while an attribute set was expected", showType(v));
throwTypeError("value is %1% while a set was expected", showType(v));
}
@@ -55,7 +56,4 @@ inline void EvalState::forceList(Value & v)
throwTypeError("value is %1% while a list was expected", showType(v));
}
}
#endif /* !__EVAL_INLINE_H */
+236 -161
View File
@@ -44,7 +44,7 @@ void Bindings::sort()
{
std::sort(begin(), end());
}
std::ostream & operator << (std::ostream & str, const Value & v)
{
@@ -116,7 +116,7 @@ string showType(const Value & v)
case tString: return "a string";
case tPath: return "a path";
case tNull: return "null";
case tAttrs: return "an attribute set";
case tAttrs: return "a set";
case tList: return "a list";
case tThunk: return "a thunk";
case tApp: return "a function application";
@@ -136,16 +136,21 @@ EvalState::EvalState()
, sType(symbols.create("type"))
, sMeta(symbols.create("meta"))
, sName(symbols.create("name"))
, sValue(symbols.create("value"))
, sSystem(symbols.create("system"))
, sOverrides(symbols.create("__overrides"))
, sOutputs(symbols.create("outputs"))
, sOutputName(symbols.create("outputName"))
, sIgnoreNulls(symbols.create("__ignoreNulls"))
, repair(false)
, baseEnv(allocEnv(128))
, baseEnvDispl(0)
, staticBaseEnv(false, 0)
, baseEnvDispl(0)
{
nrEnvs = nrValuesInEnvs = nrValues = nrListElems = 0;
nrEvaluated = recursionDepth = maxRecursionDepth = 0;
nrAttrsets = nrOpUpdates = nrOpUpdateValuesCopied = 0;
deepestStack = (char *) -1;
nrListConcats = nrPrimOpCalls = nrFunctionCalls = 0;
countCalls = getEnv("NIX_COUNT_CALLS", "0") != "0";
#if HAVE_BOEHMGC
static bool gcInitialised = true;
@@ -154,7 +159,7 @@ EvalState::EvalState()
physical RAM, up to a maximum of 384 MiB) so that in most
cases we don't need to garbage collect at all. (Collection
has a fairly significant overhead.) The heap size can be
overriden through libgc's GC_INITIAL_HEAP_SIZE environment
overridden through libgc's GC_INITIAL_HEAP_SIZE environment
variable. We should probably also provide a nix.conf
setting for this. Note that GC_expand_hp() causes a lot of
virtual, but not physical (resident) memory to be
@@ -179,9 +184,9 @@ EvalState::EvalState()
/* Initialise the Nix expression search path. */
searchPathInsertionPoint = searchPath.end();
Strings paths = tokenizeString(getEnv("NIX_PATH", ""), ":");
Strings paths = tokenizeString<Strings>(getEnv("NIX_PATH", ""), ":");
foreach (Strings::iterator, i, paths) addToSearchPath(*i);
addToSearchPath("nix=" + nixDataDir + "/nix/corepkgs");
addToSearchPath("nix=" + settings.nixDataDir + "/nix/corepkgs");
searchPathInsertionPoint = searchPath.begin();
createBaseEnv();
@@ -190,7 +195,6 @@ EvalState::EvalState()
EvalState::~EvalState()
{
assert(recursionDepth == 0);
}
@@ -219,6 +223,12 @@ void EvalState::addPrimOp(const string & name,
}
void EvalState::getBuiltin(const string & name, Value & v)
{
v = *baseEnv.values[0]->attrs->find(symbols.create(name))->value;
}
/* Every "format" object (even temporary) takes up a few hundred bytes
of stack space, which is a real killer in the recursive
evaluator. So here are some helper functions for throwing
@@ -239,14 +249,9 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s))
throw TypeError(s);
}
LocalNoInlineNoReturn(void throwTypeError(const char * s, const Pos & pos, const string & s2))
LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s1, const string & s2))
{
throw TypeError(format(s) % pos % s2);
}
LocalNoInlineNoReturn(void throwTypeError(const char * s, const Pos & pos))
{
throw TypeError(format(s) % pos);
throw TypeError(format(s) % s1 % s2);
}
LocalNoInlineNoReturn(void throwAssertionError(const char * s, const Pos & pos))
@@ -254,16 +259,16 @@ LocalNoInlineNoReturn(void throwAssertionError(const char * s, const Pos & pos))
throw AssertionError(format(s) % pos);
}
LocalNoInlineNoReturn(void throwUndefinedVarError(const char * s, const string & s1, const Pos & pos))
{
throw UndefinedVarError(format(s) % s1 % pos);
}
LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2))
{
e.addPrefix(format(s) % s2);
}
LocalNoInline(void addErrorPrefix(Error & e, const char * s, const Pos & pos))
{
e.addPrefix(format(s) % pos);
}
LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2, const Pos & pos))
{
e.addPrefix(format(s) % s2 % pos);
@@ -283,7 +288,7 @@ void mkString(Value & v, const string & s, const PathSet & context)
unsigned int n = 0;
v.string.context = (const char * *)
GC_MALLOC((context.size() + 1) * sizeof(char *));
foreach (PathSet::const_iterator, i, context)
foreach (PathSet::const_iterator, i, context)
v.string.context[n++] = GC_STRDUP(i->c_str());
v.string.context[n] = 0;
}
@@ -296,21 +301,29 @@ void mkPath(Value & v, const char * s)
}
inline Value * EvalState::lookupVar(Env * env, const VarRef & var)
inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
{
for (unsigned int l = var.level; l; --l, env = env->up) ;
if (var.fromWith) {
while (1) {
Bindings::iterator j = env->values[0]->attrs->find(var.name);
if (j != env->values[0]->attrs->end())
return j->value;
if (env->prevWith == 0)
throwEvalError("undefined variable `%1%'", var.name);
for (unsigned int l = env->prevWith; l; --l, env = env->up) ;
if (!var.fromWith) return env->values[var.displ];
while (1) {
if (!env->haveWithAttrs) {
if (noEval) return 0;
Value * v = allocValue();
evalAttrs(*env->up, (Expr *) env->values[0], *v);
env->values[0] = v;
env->haveWithAttrs = true;
}
} else
return env->values[var.displ];
Bindings::iterator j = env->values[0]->attrs->find(var.name);
if (j != env->values[0]->attrs->end()) {
if (countCalls && j->pos) attrSelects[*j->pos]++;
return j->value;
}
if (!env->prevWith)
throwUndefinedVarError("undefined variable `%1%' at %2%", var.name, var.pos);
for (unsigned int l = env->prevWith; l; --l, env = env->up) ;
}
}
@@ -327,10 +340,10 @@ Env & EvalState::allocEnv(unsigned int size)
nrValuesInEnvs += size;
Env * env = (Env *) GC_MALLOC(sizeof(Env) + size * sizeof(Value *));
/* Clear the values because maybeThunk() expects this. */
/* Clear the values because maybeThunk() and lookupVar fromWith expects this. */
for (unsigned i = 0; i < size; ++i)
env->values[i] = 0;
return *env;
}
@@ -342,12 +355,12 @@ Value * EvalState::allocAttr(Value & vAttrs, const Symbol & name)
return v;
}
void EvalState::mkList(Value & v, unsigned int length)
{
v.type = tList;
v.list.length = length;
v.list.elems = (Value * *) GC_MALLOC(length * sizeof(Value *));
v.list.elems = length ? (Value * *) GC_MALLOC(length * sizeof(Value *)) : 0;
nrListElems += length;
}
@@ -395,7 +408,7 @@ unsigned long nrAvoided = 0;
Value * ExprVar::maybeThunk(EvalState & state, Env & env)
{
Value * v = state.lookupVar(&env, info);
Value * v = state.lookupVar(&env, *this, true);
/* The value might not be initialised in the environment yet.
In that case, ignore it. */
if (v) { nrAvoided++; return v; }
@@ -424,19 +437,35 @@ Value * ExprPath::maybeThunk(EvalState & state, Env & env)
void EvalState::evalFile(const Path & path, Value & v)
{
FileEvalCache::iterator i = fileEvalCache.find(path);
if (i == fileEvalCache.end()) {
startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path);
Expr * e = parseExprFromFile(path);
try {
eval(e, v);
} catch (Error & e) {
addErrorPrefix(e, "while evaluating the file `%1%':\n", path);
throw;
}
fileEvalCache[path] = v;
} else
FileEvalCache::iterator i;
if ((i = fileEvalCache.find(path)) != fileEvalCache.end()) {
v = i->second;
return;
}
Path path2 = resolveExprPath(path);
if ((i = fileEvalCache.find(path2)) != fileEvalCache.end()) {
v = i->second;
return;
}
startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path2);
Expr * e = parseExprFromFile(path2);
try {
eval(e, v);
} catch (Error & e) {
addErrorPrefix(e, "while evaluating the file `%1%':\n", path2);
throw;
}
fileEvalCache[path2] = v;
if (path != path2) fileEvalCache[path] = v;
}
void EvalState::resetFileCache()
{
fileEvalCache.clear();
}
@@ -460,7 +489,7 @@ inline void EvalState::evalAttrs(Env & env, Expr * e, Value & v)
{
e->eval(*this, env, v);
if (v.type != tAttrs)
throwTypeError("value is %1% while an attribute set was expected", showType(v));
throwTypeError("value is %1% while a set was expected", showType(v));
}
@@ -505,23 +534,17 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
environment, while the inherited attributes are evaluated
in the original environment. */
unsigned int displ = 0;
foreach (AttrDefs::iterator, i, attrs)
if (i->second.inherited) {
/* !!! handle overrides? */
Value * vAttr = state.lookupVar(&env, i->second.var);
env2.values[displ++] = vAttr;
v.attrs->push_back(Attr(i->first, vAttr, &i->second.pos));
} else {
Value * vAttr;
if (hasOverrides) {
vAttr = state.allocValue();
mkThunk(*vAttr, env2, i->second.e);
} else
vAttr = i->second.e->maybeThunk(state, env2);
env2.values[displ++] = vAttr;
v.attrs->push_back(Attr(i->first, vAttr, &i->second.pos));
}
foreach (AttrDefs::iterator, i, attrs) {
Value * vAttr;
if (hasOverrides && !i->second.inherited) {
vAttr = state.allocValue();
mkThunk(*vAttr, env2, i->second.e);
} else
vAttr = i->second.e->maybeThunk(state, i->second.inherited ? env : env2);
env2.values[displ++] = vAttr;
v.attrs->push_back(Attr(i->first, vAttr, &i->second.pos));
}
/* If the rec contains an attribute called `__overrides', then
evaluate it, and add the attributes in that set to the rec.
This allows overriding of recursive attributes, which is
@@ -547,10 +570,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
else {
foreach (AttrDefs::iterator, i, attrs)
if (i->second.inherited)
v.attrs->push_back(Attr(i->first, state.lookupVar(&env, i->second.var), &i->second.pos));
else
v.attrs->push_back(Attr(i->first, i->second.e->maybeThunk(state, env), &i->second.pos));
v.attrs->push_back(Attr(i->first, i->second.e->maybeThunk(state, env), &i->second.pos));
}
}
@@ -567,10 +587,7 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v)
environment. */
unsigned int displ = 0;
foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs)
if (i->second.inherited)
env2.values[displ++] = state.lookupVar(&env, i->second.var);
else
env2.values[displ++] = i->second.e->maybeThunk(state, env2);
env2.values[displ++] = i->second.e->maybeThunk(state, i->second.inherited ? env : env2);
body->eval(state, env2, v);
}
@@ -586,7 +603,7 @@ void ExprList::eval(EvalState & state, Env & env, Value & v)
void ExprVar::eval(EvalState & state, Env & env, Value & v)
{
Value * v2 = state.lookupVar(&env, info);
Value * v2 = state.lookupVar(&env, *this, false);
state.forceValue(*v2);
v = *v2;
}
@@ -603,7 +620,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
e->eval(state, env, vTmp);
try {
foreach (AttrPath::const_iterator, i, attrPath) {
nrLookups++;
Bindings::iterator j;
@@ -622,17 +639,18 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
}
vAttrs = j->value;
pos = j->pos;
if (state.countCalls && pos) state.attrSelects[*pos]++;
}
state.forceValue(*vAttrs);
} catch (Error & e) {
if (pos)
if (pos && pos->file != state.sDerivationNix)
addErrorPrefix(e, "while evaluating the attribute `%1%' at %2%:\n",
showAttrPath(attrPath), *pos);
throw;
}
v = *vAttrs;
}
@@ -656,7 +674,7 @@ void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v)
vAttrs = j->value;
}
}
mkBool(v, true);
}
@@ -691,10 +709,10 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
assert(primOp->type == tPrimOp);
unsigned int arity = primOp->primOp->arity;
unsigned int argsLeft = arity - argsDone;
if (argsLeft == 1) {
/* We have all the arguments, so call the primop. */
/* Put all the arguments in an array. */
Value * vArgs[arity];
unsigned int n = arity - 1;
@@ -703,12 +721,9 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
vArgs[n--] = arg->primOpApp.right;
/* And call the primop. */
try {
primOp->primOp->fun(*this, vArgs, v);
} catch (Error & e) {
addErrorPrefix(e, "while evaluating the builtin function `%1%':\n", primOp->primOp->name);
throw;
}
nrPrimOpCalls++;
if (countCalls) primOpCalls[primOp->primOp->name]++;
primOp->primOp->fun(*this, vArgs, v);
} else {
v.type = tPrimOpApp;
v.primOpApp.left = allocValue();
@@ -717,9 +732,9 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
}
return;
}
if (fun.type != tLambda)
throwTypeError("attempt to call something which is neither a function nor a primop (built-in operation) but %1%",
throwTypeError("attempt to call something which is not a function but %1%",
showType(fun));
unsigned int size =
@@ -735,7 +750,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
else {
forceAttrs(arg);
if (!fun.lambda.fun->arg.empty())
env2.values[displ++] = &arg;
@@ -746,8 +761,8 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) {
Bindings::iterator j = arg.attrs->find(i->name);
if (j == arg.attrs->end()) {
if (!i->def) throwTypeError("function at %1% called without required argument `%2%'",
fun.lambda.fun->pos, i->name);
if (!i->def) throwTypeError("%1% called without required argument `%2%'",
fun.lambda.fun->showNamePos(), i->name);
env2.values[displ++] = i->def->maybeThunk(*this, env2);
} else {
attrsUsed++;
@@ -756,17 +771,24 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
}
/* Check that each actual argument is listed as a formal
argument (unless the attribute match specifies a `...').
TODO: show the names of the expected/unexpected
arguments. */
if (!fun.lambda.fun->formals->ellipsis && attrsUsed != arg.attrs->size())
throwTypeError("function at %1% called with unexpected argument", fun.lambda.fun->pos);
argument (unless the attribute match specifies a `...'). */
if (!fun.lambda.fun->formals->ellipsis && attrsUsed != arg.attrs->size()) {
/* Nope, so show the first unexpected argument to the
user. */
foreach (Bindings::iterator, i, *arg.attrs)
if (fun.lambda.fun->formals->argNames.find(i->name) == fun.lambda.fun->formals->argNames.end())
throwTypeError("%1% called with unexpected argument `%2%'", fun.lambda.fun->showNamePos(), i->name);
abort(); // can't happen
}
}
nrFunctionCalls++;
if (countCalls) functionCalls[fun.lambda.fun]++;
try {
fun.lambda.fun->body->eval(*this, env2, v);
} catch (Error & e) {
addErrorPrefix(e, "while evaluating the function at %1%:\n", fun.lambda.fun->pos);
addErrorPrefix(e, "while evaluating %1%:\n", fun.lambda.fun->showNamePos());
throw;
}
}
@@ -781,20 +803,20 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
return;
}
Value actualArgs;
mkAttrs(actualArgs, fun.lambda.fun->formals->formals.size());
Value * actualArgs = allocValue();
mkAttrs(*actualArgs, fun.lambda.fun->formals->formals.size());
foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) {
Bindings::iterator j = args.find(i->name);
if (j != args.end())
actualArgs.attrs->push_back(*j);
actualArgs->attrs->push_back(*j);
else if (!i->def)
throwTypeError("cannot auto-call a function that has an argument without a default value (`%1%')", i->name);
}
actualArgs.attrs->sort();
actualArgs->attrs->sort();
callFunction(fun, actualArgs, res);
callFunction(fun, *actualArgs, res);
}
@@ -803,9 +825,8 @@ void ExprWith::eval(EvalState & state, Env & env, Value & v)
Env & env2(state.allocEnv(1));
env2.up = &env;
env2.prevWith = prevWith;
env2.values[0] = state.allocValue();
state.evalAttrs(env, attrs, *env2.values[0]);
env2.haveWithAttrs = false;
env2.values[0] = (Value *) attrs;
body->eval(state, env2, v);
}
@@ -816,7 +837,7 @@ void ExprIf::eval(EvalState & state, Env & env, Value & v)
(state.evalBool(env, cond) ? then : else_)->eval(state, env, v);
}
void ExprAssert::eval(EvalState & state, Env & env, Value & v)
{
if (!state.evalBool(env, cond))
@@ -824,7 +845,7 @@ void ExprAssert::eval(EvalState & state, Env & env, Value & v)
body->eval(state, env, v);
}
void ExprOpNot::eval(EvalState & state, Env & env, Value & v)
{
mkBool(v, !state.evalBool(env, e));
@@ -878,9 +899,8 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
state.mkAttrs(v, v1.attrs->size() + v2.attrs->size());
/* Merge the attribute sets, preferring values from the second
set. Make sure to keep the resulting vector in sorted
order. */
/* Merge the sets, preferring values from the second set. Make
sure to keep the resulting vector in sorted order. */
Bindings::iterator i = v1.attrs->begin();
Bindings::iterator j = v2.attrs->begin();
@@ -897,7 +917,7 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
while (i != v1.attrs->end()) v.attrs->push_back(*i++);
while (j != v2.attrs->end()) v.attrs->push_back(*j++);
state.nrOpUpdateValuesCopied += v.attrs->size();
}
@@ -905,14 +925,36 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v)
{
Value v1; e1->eval(state, env, v1);
state.forceList(v1);
Value v2; e2->eval(state, env, v2);
state.forceList(v2);
state.mkList(v, v1.list.length + v2.list.length);
for (unsigned int n = 0; n < v1.list.length; ++n)
v.list.elems[n] = v1.list.elems[n];
for (unsigned int n = 0; n < v2.list.length; ++n)
v.list.elems[n + v1.list.length] = v2.list.elems[n];
Value * lists[2] = { &v1, &v2 };
state.concatLists(v, 2, lists);
}
void EvalState::concatLists(Value & v, unsigned int nrLists, Value * * lists)
{
nrListConcats++;
Value * nonEmpty = 0;
unsigned int len = 0;
for (unsigned int n = 0; n < nrLists; ++n) {
forceList(*lists[n]);
unsigned int l = lists[n]->list.length;
len += l;
if (l) nonEmpty = lists[n];
}
if (nonEmpty && len == nonEmpty->list.length) {
v = *nonEmpty;
return;
}
mkList(v, len);
for (unsigned int n = 0, pos = 0; n < nrLists; ++n) {
unsigned int l = lists[n]->list.length;
memcpy(v.list.elems + pos, lists[n]->list.elems, l * sizeof(Value *));
pos += l;
}
}
@@ -920,31 +962,39 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
{
PathSet context;
std::ostringstream s;
bool first = true, isPath = false;
Value vStr;
NixInt n = 0;
bool first = !forceString;
ValueType firstType = tString;
foreach (vector<Expr *>::iterator, i, *es) {
(*i)->eval(state, env, vStr);
Value vTmp;
(*i)->eval(state, env, vTmp);
/* If the first element is a path, then the result will also
be a path, we don't copy anything (yet - that's done later,
since paths are copied when they are used in a derivation),
and none of the strings are allowed to have contexts. */
if (first) {
isPath = vStr.type == tPath;
firstType = vTmp.type;
first = false;
}
s << state.coerceToString(vStr, context, false, !isPath);
}
if (isPath && !context.empty())
throwEvalError("a string that refers to a store path cannot be appended to a path, in `%1%'", s.str());
if (isPath)
if (firstType == tInt) {
if (vTmp.type != tInt)
throwEvalError("cannot add %1% to an integer", showType(vTmp));
n += vTmp.integer;
} else
s << state.coerceToString(vTmp, context, false, firstType == tString);
}
if (firstType == tInt)
mkInt(v, n);
else if (firstType == tPath) {
if (!context.empty())
throwEvalError("a string that refers to a store path cannot be appended to a path, in `%1%'", s.str());
mkPath(v, s.str().c_str());
else
} else
mkString(v, s.str(), context);
}
@@ -952,12 +1002,12 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
void EvalState::strictForceValue(Value & v)
{
forceValue(v);
if (v.type == tAttrs) {
foreach (Bindings::iterator, i, *v.attrs)
strictForceValue(*i->value);
}
else if (v.type == tList) {
for (unsigned int n = 0; n < v.list.length; ++n)
strictForceValue(*v.list.elems[n]);
@@ -965,7 +1015,7 @@ void EvalState::strictForceValue(Value & v)
}
int EvalState::forceInt(Value & v)
NixInt EvalState::forceInt(Value & v)
{
forceValue(v);
if (v.type != tInt)
@@ -1003,7 +1053,7 @@ string EvalState::forceString(Value & v)
void copyContext(const Value & v, PathSet & context)
{
if (v.string.context)
for (const char * * p = v.string.context; *p; ++p)
for (const char * * p = v.string.context; *p; ++p)
context.insert(*p);
}
@@ -1033,7 +1083,7 @@ bool EvalState::isDerivation(Value & v)
if (i == v.attrs->end()) return false;
forceValue(*i->value);
if (i->value->type != tString) return false;
return forceStringNoCtx(*i->value) == "derivation";
return strcmp(i->value->string.s, "derivation") == 0;
}
@@ -1053,7 +1103,7 @@ string EvalState::coerceToString(Value & v, PathSet & context,
Path path(canonPath(v.path));
if (!copyToStore) return path;
if (nix::isDerivation(path))
throwEvalError("file names are not allowed to end in `%1%'", drvExtension);
@@ -1061,9 +1111,9 @@ string EvalState::coerceToString(Value & v, PathSet & context,
if (srcToStore[path] != "")
dstPath = srcToStore[path];
else {
dstPath = readOnlyMode
dstPath = settings.readOnlyMode
? computeStorePathForPath(path).first
: store->addToStore(path);
: store->addToStore(path, true, htSHA256, defaultPathFilter, repair);
srcToStore[path] = dstPath;
printMsg(lvlChatty, format("copied source `%1%' -> `%2%'")
% path % dstPath);
@@ -1075,8 +1125,7 @@ string EvalState::coerceToString(Value & v, PathSet & context,
if (v.type == tAttrs) {
Bindings::iterator i = v.attrs->find(sOutPath);
if (i == v.attrs->end())
throwTypeError("cannot coerce an attribute set (except a derivation) to a string");
if (i == v.attrs->end()) throwTypeError("cannot coerce a set to a string");
return coerceToString(*i->value, context, coerceMore, copyToStore);
}
@@ -1102,7 +1151,7 @@ string EvalState::coerceToString(Value & v, PathSet & context,
return result;
}
}
throwTypeError("cannot coerce %1% to a string", showType(v));
}
@@ -1122,9 +1171,8 @@ bool EvalState::eqValues(Value & v1, Value & v2)
forceValue(v2);
/* !!! Hack to support some old broken code that relies on pointer
equality tests between attribute sets. (Specifically,
builderDefs calls uniqList on a list of attribute sets.) Will
remove this eventually. */
equality tests between sets. (Specifically, builderDefs calls
uniqList on a list of sets.) Will remove this eventually. */
if (&v1 == &v2) return true;
if (v1.type != v2.type) return false;
@@ -1162,8 +1210,8 @@ bool EvalState::eqValues(Value & v1, Value & v2)
return true;
case tAttrs: {
/* If both attribute sets denote a derivation (type =
"derivation"), then compare their outPaths. */
/* If both sets denote a derivation (type = "derivation"),
then compare their outPaths. */
if (isDerivation(v1) && isDerivation(v2)) {
Bindings::iterator i = v1.attrs->find(sOutPath);
Bindings::iterator j = v2.attrs->find(sOutPath);
@@ -1178,7 +1226,7 @@ bool EvalState::eqValues(Value & v1, Value & v2)
for (i = v1.attrs->begin(), j = v2.attrs->begin(); i != v1.attrs->end(); ++i, ++j)
if (i->name != j->name || !eqValues(*i->value, *j->value))
return false;
return true;
}
@@ -1206,25 +1254,52 @@ void EvalState::printStats()
printMsg(v, format(" time elapsed: %1%") % cpuTime);
printMsg(v, format(" size of a value: %1%") % sizeof(Value));
printMsg(v, format(" expressions evaluated: %1%") % nrEvaluated);
char x;
printMsg(v, format(" stack space used: %1% bytes") % (&x - deepestStack));
printMsg(v, format(" max eval() nesting depth: %1%") % maxRecursionDepth);
printMsg(v, format(" stack space per eval() level: %1% bytes")
% ((&x - deepestStack) / (float) maxRecursionDepth));
printMsg(v, format(" environments allocated: %1% (%2% bytes)")
% nrEnvs % (nrEnvs * sizeof(Env) + nrValuesInEnvs * sizeof(Value *)));
printMsg(v, format(" list elements: %1% (%2% bytes)")
% nrListElems % (nrListElems * sizeof(Value *)));
printMsg(v, format(" list concatenations: %1%") % nrListConcats);
printMsg(v, format(" values allocated: %1% (%2% bytes)")
% nrValues % (nrValues * sizeof(Value)));
printMsg(v, format(" attribute sets allocated: %1%") % nrAttrsets);
printMsg(v, format(" sets allocated: %1%") % nrAttrsets);
printMsg(v, format(" right-biased unions: %1%") % nrOpUpdates);
printMsg(v, format(" values copied in right-biased unions: %1%") % nrOpUpdateValuesCopied);
printMsg(v, format(" symbols in symbol table: %1%") % symbols.size());
printMsg(v, format(" size of symbol table: %1%") % symbols.totalSize());
printMsg(v, format(" number of thunks: %1%") % nrThunks);
printMsg(v, format(" number of thunks avoided: %1%") % nrAvoided);
printMsg(v, format(" number of attr lookups: %1%") % nrLookups);
printMsg(v, format(" number of primop calls: %1%") % nrPrimOpCalls);
printMsg(v, format(" number of function calls: %1%") % nrFunctionCalls);
if (countCalls) {
v = lvlInfo;
printMsg(v, format("calls to %1% primops:") % primOpCalls.size());
typedef std::multimap<unsigned int, Symbol> PrimOpCalls_;
PrimOpCalls_ primOpCalls_;
foreach (PrimOpCalls::iterator, i, primOpCalls)
primOpCalls_.insert(std::pair<unsigned int, Symbol>(i->second, i->first));
foreach_reverse (PrimOpCalls_::reverse_iterator, i, primOpCalls_)
printMsg(v, format("%1$10d %2%") % i->first % i->second);
printMsg(v, format("calls to %1% functions:") % functionCalls.size());
typedef std::multimap<unsigned int, ExprLambda *> FunctionCalls_;
FunctionCalls_ functionCalls_;
foreach (FunctionCalls::iterator, i, functionCalls)
functionCalls_.insert(std::pair<unsigned int, ExprLambda *>(i->second, i->first));
foreach_reverse (FunctionCalls_::reverse_iterator, i, functionCalls_)
printMsg(v, format("%1$10d %2%") % i->first % i->second->showNamePos());
printMsg(v, format("evaluations of %1% attributes:") % attrSelects.size());
typedef std::multimap<unsigned int, Pos> AttrSelects_;
AttrSelects_ attrSelects_;
foreach (AttrSelects::iterator, i, attrSelects)
attrSelects_.insert(std::pair<unsigned int, Pos>(i->second, i->first));
foreach_reverse (AttrSelects_::reverse_iterator, i, attrSelects_)
printMsg(v, format("%1$10d %2%") % i->first % i->second);
}
}
+65 -42
View File
@@ -1,5 +1,4 @@
#ifndef __EVAL_H
#define __EVAL_H
#pragma once
#include "value.hh"
#include "nixexpr.hh"
@@ -20,8 +19,8 @@ class EvalState;
struct Attr;
/* Attribute sets are represented as a vector of attributes, sorted by
symbol (i.e. pointer to the attribute name in the symbol table). */
/* Sets are represented as a vector of attributes, sorted by symbol
(i.e. pointer to the attribute name in the symbol table). */
#if HAVE_BOEHMGC
typedef std::vector<Attr, gc_allocator<Attr> > BindingsBase;
#else
@@ -53,7 +52,8 @@ struct PrimOp
struct Env
{
Env * up;
unsigned int prevWith; // nr of levels up to next `with' environment
unsigned short prevWith; // nr of levels up to next `with' environment
bool haveWithAttrs;
Value * values[0];
};
@@ -88,19 +88,21 @@ struct EvalState;
std::ostream & operator << (std::ostream & str, const Value & v);
class EvalState
class EvalState
{
public:
SymbolTable symbols;
const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName,
sSystem, sOverrides;
const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName, sValue,
sSystem, sOverrides, sOutputs, sOutputName, sIgnoreNulls;
Symbol sDerivationNix;
/* If set, force copying files to the Nix store even if they
already exist there. */
bool repair;
private:
SrcToStore srcToStore;
/* A cache from path names to parse trees. */
std::map<Path, Expr *> parseTrees;
SrcToStore srcToStore;
/* A cache from path names to values. */
#if HAVE_BOEHMGC
@@ -115,23 +117,25 @@ private:
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 file. */
Expr * parseExprFromFile(const Path & path);
/* Parse a Nix expression from the specified string. */
Expr * parseExprFromString(const string & s, const Path & basePath, StaticEnv & staticEnv);
Expr * parseExprFromString(const string & s, const Path & basePath);
/* Evaluate an expression read from the given file to normal
form. */
void evalFile(const Path & path, Value & v);
void resetFileCache();
/* Look up a file in the search path. */
Path findFile(const string & path);
@@ -155,7 +159,7 @@ public:
void strictForceValue(Value & v);
/* Force `v', and then verify that it has the expected type. */
int forceInt(Value & v);
NixInt forceInt(Value & v);
bool forceBool(Value & v);
inline void forceAttrs(Value & v);
inline void forceList(Value & v);
@@ -171,7 +175,7 @@ public:
/* String coercion. Converts strings, paths and derivations to a
string. If `coerceMore' is set, also converts nulls, integers,
booleans and lists to a string. If `copyToStore' is set,
referenced paths are copied to the Nix store as a side effect.q */
referenced paths are copied to the Nix store as a side effect. */
string coerceToString(Value & v, PathSet & context,
bool coerceMore = false, bool copyToStore = true);
@@ -180,39 +184,43 @@ public:
path. Nothing is copied to the store. */
Path coerceToPath(Value & v, PathSet & context);
private:
public:
/* The base environment, containing the builtin functions and
values. */
Env & baseEnv;
unsigned int baseEnvDispl;
public:
/* The same, but used during parsing to resolve variables. */
StaticEnv staticBaseEnv; // !!! should be private
private:
unsigned int baseEnvDispl;
void createBaseEnv();
void addConstant(const string & name, Value & v);
void addPrimOp(const string & name,
unsigned int arity, PrimOpFun primOp);
inline Value * lookupVar(Env * env, const VarRef & var);
public:
void getBuiltin(const string & name, Value & v);
private:
inline Value * lookupVar(Env * env, const ExprVar & var, bool noEval);
friend class ExprVar;
friend class ExprAttrs;
friend class ExprLet;
Expr * parse(const char * text,
const Path & path, const Path & basePath);
Expr * parse(const char * text, const Path & path,
const Path & basePath, StaticEnv & staticEnv);
public:
/* Do a deep equality test between two values. That is, list
elements and attributes are compared recursively. */
bool eqValues(Value & v1, Value & v2);
@@ -222,7 +230,7 @@ public:
/* Automatically call a function for which each argument has a
default value or has a binding in the `args' map. */
void autoCallFunction(Bindings & args, Value & fun, Value & res);
/* Allocation primitives. */
Value * allocValue();
Env & allocEnv(unsigned int size);
@@ -233,25 +241,39 @@ public:
void mkAttrs(Value & v, unsigned int expected);
void mkThunk_(Value & v, Expr * expr);
void concatLists(Value & v, unsigned int nrLists, Value * * lists);
/* Print statistics. */
void printStats();
private:
unsigned long nrEnvs;
unsigned long nrValuesInEnvs;
unsigned long nrValues;
unsigned long nrListElems;
unsigned long nrEvaluated;
unsigned long nrAttrsets;
unsigned long nrOpUpdates;
unsigned long nrOpUpdateValuesCopied;
unsigned int recursionDepth;
unsigned int maxRecursionDepth;
char * deepestStack; /* for measuring stack usage */
friend class RecursionCounter;
unsigned long nrListConcats;
unsigned long nrPrimOpCalls;
unsigned long nrFunctionCalls;
bool countCalls;
typedef std::map<Symbol, unsigned int> PrimOpCalls;
PrimOpCalls primOpCalls;
typedef std::map<ExprLambda *, unsigned int> FunctionCalls;
FunctionCalls functionCalls;
typedef std::map<Pos, unsigned int> AttrSelects;
AttrSelects attrSelects;
friend class ExprOpUpdate;
friend class ExprOpConcatLists;
friend class ExprSelect;
friend void prim_getAttr(EvalState & state, Value * * args, Value & v);
};
@@ -259,7 +281,8 @@ private:
string showType(const Value & v);
/* If `path' refers to a directory, then append "/default.nix". */
Path resolveExprPath(Path path);
}
#endif /* !__EVAL_H */
+73 -30
View File
@@ -28,12 +28,53 @@ string DrvInfo::queryOutPath(EvalState & state) const
}
DrvInfo::Outputs DrvInfo::queryOutputs(EvalState & state)
{
if (outputs.empty()) {
/* Get the outputs list. */
Bindings::iterator i = attrs->find(state.sOutputs);
if (i == attrs->end())
outputs["out"] = queryOutPath(state);
else {
state.forceList(*i->value);
/* For each output... */
for (unsigned int j = 0; j < i->value->list.length; ++j) {
/* Evaluate the corresponding set. */
string name = state.forceStringNoCtx(*i->value->list.elems[j]);
Bindings::iterator out = attrs->find(state.symbols.create(name));
if (out == attrs->end()) continue; // FIXME: throw error?
state.forceAttrs(*out->value);
/* And evaluate its outPath attribute. */
Bindings::iterator outPath = out->value->attrs->find(state.sOutPath);
if (outPath == out->value->attrs->end()) continue; // FIXME: throw error?
PathSet context;
outputs[name] = state.coerceToPath(*outPath->value, context);
}
}
}
return outputs;
}
string DrvInfo::queryOutputName(EvalState & state) const
{
if (outputName == "" && attrs) {
Bindings::iterator i = attrs->find(state.sOutputName);
(string &) outputName = i != attrs->end() ? state.forceStringNoCtx(*i->value) : "";
}
return outputName;
}
MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const
{
if (metaInfoRead) return meta;
(bool &) metaInfoRead = true;
Bindings::iterator a = attrs->find(state.sMeta);
if (a == attrs->end()) return meta; /* fine, empty meta information */
@@ -78,25 +119,25 @@ void DrvInfo::setMetaInfo(const MetaInfo & meta)
typedef set<Bindings *> Done;
/* Evaluate value `v'. If it evaluates to an attribute set of type
`derivation', then put information about it in `drvs' (unless it's
already in `doneExprs'). The result boolean indicates whether it
makes sense for the caller to recursively search for derivations in
`v'. */
/* Evaluate value `v'. If it evaluates to a set of type `derivation',
then put information about it in `drvs' (unless it's already in
`doneExprs'). The result boolean indicates whether it makes sense
for the caller to recursively search for derivations in `v'. */
static bool getDerivation(EvalState & state, Value & v,
const string & attrPath, DrvInfos & drvs, Done & done)
const string & attrPath, DrvInfos & drvs, Done & done,
bool ignoreAssertionFailures)
{
try {
state.forceValue(v);
if (!state.isDerivation(v)) return true;
/* Remove spurious duplicates (e.g., an attribute set like
`rec { x = derivation {...}; y = x;}'. */
/* Remove spurious duplicates (e.g., a set like `rec { x =
derivation {...}; y = x;}'. */
if (done.find(v.attrs) != done.end()) return false;
done.insert(v.attrs);
DrvInfo drv;
Bindings::iterator i = v.attrs->find(state.sName);
/* !!! We really would like to have a decent back trace here. */
if (i == v.attrs->end()) throw TypeError("derivation name missing");
@@ -114,18 +155,20 @@ static bool getDerivation(EvalState & state, Value & v,
drvs.push_back(drv);
return false;
} catch (AssertionError & e) {
return false;
if (ignoreAssertionFailures) return false;
throw;
}
}
bool getDerivation(EvalState & state, Value & v, DrvInfo & drv)
bool getDerivation(EvalState & state, Value & v, DrvInfo & drv,
bool ignoreAssertionFailures)
{
Done done;
DrvInfos drvs;
getDerivation(state, v, "", drvs, done);
getDerivation(state, v, "", drvs, done, ignoreAssertionFailures);
if (drvs.size() != 1) return false;
drv = drvs.front();
return true;
@@ -140,15 +183,16 @@ static string addToPath(const string & s1, const string & s2)
static void getDerivations(EvalState & state, Value & vIn,
const string & pathPrefix, Bindings & autoArgs,
DrvInfos & drvs, Done & done)
DrvInfos & drvs, Done & done,
bool ignoreAssertionFailures)
{
Value v;
state.autoCallFunction(autoArgs, vIn, v);
/* Process the expression. */
DrvInfo drv;
if (!getDerivation(state, v, pathPrefix, drvs, done)) ;
if (!getDerivation(state, v, pathPrefix, drvs, done, ignoreAssertionFailures)) ;
else if (v.type == tAttrs) {
@@ -171,16 +215,15 @@ static void getDerivations(EvalState & state, Value & vIn,
string pathPrefix2 = addToPath(pathPrefix, i->first);
Value & v2(*v.attrs->find(i->second)->value);
if (combineChannels)
getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done);
else if (getDerivation(state, v2, pathPrefix2, drvs, done)) {
/* If the value of this attribute is itself an
attribute set, should we recurse into it? => Only
if it has a `recurseForDerivations = true'
attribute. */
getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
else if (getDerivation(state, v2, pathPrefix2, drvs, done, ignoreAssertionFailures)) {
/* If the value of this attribute is itself a set,
should we recurse into it? => Only if it has a
`recurseForDerivations = true' attribute. */
if (v2.type == tAttrs) {
Bindings::iterator j = v2.attrs->find(state.symbols.create("recurseForDerivations"));
if (j != v2.attrs->end() && state.forceBool(*j->value))
getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done);
getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
}
}
}
@@ -191,8 +234,8 @@ static void getDerivations(EvalState & state, Value & vIn,
startNest(nest, lvlDebug,
format("evaluating list element"));
string pathPrefix2 = addToPath(pathPrefix, (format("%1%") % n).str());
if (getDerivation(state, *v.list.elems[n], pathPrefix2, drvs, done))
getDerivations(state, *v.list.elems[n], pathPrefix2, autoArgs, drvs, done);
if (getDerivation(state, *v.list.elems[n], pathPrefix2, drvs, done, ignoreAssertionFailures))
getDerivations(state, *v.list.elems[n], pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
}
}
@@ -201,11 +244,11 @@ static void getDerivations(EvalState & state, Value & vIn,
void getDerivations(EvalState & state, Value & v, const string & pathPrefix,
Bindings & autoArgs, DrvInfos & drvs)
Bindings & autoArgs, DrvInfos & drvs, bool ignoreAssertionFailures)
{
Done done;
getDerivations(state, v, pathPrefix, autoArgs, drvs, done);
getDerivations(state, v, pathPrefix, autoArgs, drvs, done, ignoreAssertionFailures);
}
}
+21 -11
View File
@@ -1,5 +1,4 @@
#ifndef __GET_DRVS_H
#define __GET_DRVS_H
#pragma once
#include "eval.hh"
@@ -26,13 +25,20 @@ typedef std::map<string, MetaValue> MetaInfo;
struct DrvInfo
{
public:
typedef std::map<string, Path> Outputs;
private:
string drvPath;
string outPath;
string outputName;
Outputs outputs;
bool metaInfoRead;
MetaInfo meta;
bool failed; // set if we get an AssertionError
public:
string name;
string attrPath; /* path towards the derivation */
@@ -41,10 +47,12 @@ public:
/* !!! make this private */
Bindings * attrs;
DrvInfo() : metaInfoRead(false), attrs(0) { };
DrvInfo() : metaInfoRead(false), failed(false), attrs(0) { };
string queryDrvPath(EvalState & state) const;
string queryOutPath(EvalState & state) const;
string queryOutputName(EvalState & state) const;
Outputs queryOutputs(EvalState & state);
MetaInfo queryMetaInfo(EvalState & state) const;
MetaValue queryMetaInfo(EvalState & state, const string & name) const;
@@ -52,13 +60,16 @@ public:
{
drvPath = s;
}
void setOutPath(const string & s)
{
outPath = s;
}
void setMetaInfo(const MetaInfo & meta);
void setFailed() { failed = true; };
bool hasFailed() { return failed; };
};
@@ -71,13 +82,12 @@ typedef list<DrvInfo> DrvInfos;
/* If value `v' denotes a derivation, store information about the
derivation in `drv' and return true. Otherwise, return false. */
bool getDerivation(EvalState & state, Value & v, DrvInfo & drv);
bool getDerivation(EvalState & state, Value & v, DrvInfo & drv,
bool ignoreAssertionFailures);
void getDerivations(EvalState & state, Value & v, const string & pathPrefix,
Bindings & autoArgs, DrvInfos & drvs);
Bindings & autoArgs, DrvInfos & drvs,
bool ignoreAssertionFailures);
}
#endif /* !__GET_DRVS_H */
+12 -9
View File
@@ -9,21 +9,20 @@
%{
#include "nixexpr.hh"
#define BISON_HEADER_HACK
#include "parser-tab.hh"
using namespace nix;
namespace nix {
static void initLoc(YYLTYPE * loc)
{
loc->first_line = loc->last_line = 1;
loc->first_column = loc->last_column = 1;
}
static void adjustLoc(YYLTYPE * loc, const char * s, size_t len)
{
loc->first_line = loc->last_line;
@@ -35,7 +34,7 @@ static void adjustLoc(YYLTYPE * loc, const char * s, size_t len)
if (*s == '\n') /* cr/lf */
s++;
/* fall through */
case '\n':
case '\n':
++loc->last_line;
loc->last_column = 1;
break;
@@ -69,7 +68,7 @@ static Expr * unescapeStr(SymbolTable & symbols, const char * s)
return new ExprString(symbols.create(t));
}
}
#define YY_USER_INIT initLoc(yylloc)
@@ -78,7 +77,7 @@ static Expr * unescapeStr(SymbolTable & symbols, const char * s)
%}
ID [a-zA-Z\_][a-zA-Z0-9\_\']*
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\.\_\-\+]+)*\>
@@ -102,6 +101,8 @@ or { return OR_KW; }
\=\= { return EQ; }
\!\= { return NEQ; }
\<\= { return LEQ; }
\>\= { return GEQ; }
\&\& { return AND; }
\|\| { return OR; }
\-\> { return IMPL; }
@@ -109,8 +110,10 @@ or { return OR_KW; }
\+\+ { return CONCAT; }
{ID} { yylval->id = strdup(yytext); return ID; }
{INT} { int n = atoi(yytext); /* !!! overflow */
yylval->n = n;
{INT} { errno = 0;
yylval->n = strtol(yytext, 0, 10);
if (errno != 0)
throw ParseError(format("invalid integer `%1%'") % yytext);
return INT;
}
@@ -168,7 +171,7 @@ or { return OR_KW; }
namespace nix {
/* Horrible, disgusting hack: allow the parser to set the scanner
start condition back to STRING. Necessary in interpolations like
"foo${expr}bar"; after the close brace we have to go back to the
+4 -5
View File
@@ -55,7 +55,7 @@ static string nextComponent(string::const_iterator & p,
else
while (p != end && (!isdigit(*p) && *p != '.' && *p != '-'))
s += *p++;
return s;
}
@@ -80,7 +80,7 @@ int compareVersions(const string & v1, const string & v2)
{
string::const_iterator p1 = v1.begin();
string::const_iterator p2 = v2.begin();
while (p1 != v1.end() || p2 != v2.end()) {
string c1 = nextComponent(p1, v1.end());
string c2 = nextComponent(p2, v2.end());
@@ -95,11 +95,10 @@ int compareVersions(const string & v1, const string & v2)
DrvNames drvNamesFromArgs(const Strings & opArgs)
{
DrvNames result;
for (Strings::const_iterator i = opArgs.begin();
i != opArgs.end(); ++i)
foreach (Strings::const_iterator, i, opArgs)
result.push_back(DrvName(*i));
return result;
}
}
+1 -10
View File
@@ -1,12 +1,9 @@
#ifndef __NAMES_H
#define __NAMES_H
#pragma once
#include "types.hh"
namespace nix {
struct DrvName
{
string fullName;
@@ -19,15 +16,9 @@ struct DrvName
bool matches(DrvName & n);
};
typedef list<DrvName> DrvNames;
int compareVersions(const string & v1, const string & v2);
DrvNames drvNamesFromArgs(const Strings & opArgs);
}
#endif /* !__NAMES_H */
+47 -23
View File
@@ -38,7 +38,7 @@ void ExprPath::show(std::ostream & str)
void ExprVar::show(std::ostream & str)
{
str << info.name;
str << name;
}
void ExprSelect::show(std::ostream & str)
@@ -174,7 +174,7 @@ void ExprPath::bindVars(const StaticEnv & env)
{
}
void VarRef::bind(const StaticEnv & env)
void ExprVar::bindVars(const StaticEnv & env)
{
/* Check whether the variable appears in the environment. If so,
set its level and displacement. */
@@ -198,17 +198,12 @@ void VarRef::bind(const StaticEnv & env)
/* Otherwise, the variable must be obtained from the nearest
enclosing `with'. If there is no `with', then we can issue an
"undefined variable" error now. */
if (withLevel == -1) throw EvalError(format("undefined variable `%1%'") % name);
if (withLevel == -1) throw UndefinedVarError(format("undefined variable `%1%' at %2%") % name % pos);
fromWith = true;
this->level = withLevel;
}
void ExprVar::bindVars(const StaticEnv & env)
{
info.bind(env);
}
void ExprSelect::bindVars(const StaticEnv & env)
{
e->bindVars(env);
@@ -224,20 +219,18 @@ void ExprAttrs::bindVars(const StaticEnv & env)
{
if (recursive) {
StaticEnv newEnv(false, &env);
unsigned int displ = 0;
foreach (AttrDefs::iterator, i, attrs)
newEnv.vars[i->first] = i->second.displ = displ++;
foreach (AttrDefs::iterator, i, attrs)
if (i->second.inherited) i->second.var.bind(env);
else i->second.e->bindVars(newEnv);
i->second.e->bindVars(i->second.inherited ? env : newEnv);
}
else
foreach (AttrDefs::iterator, i, attrs)
if (i->second.inherited) i->second.var.bind(env);
else i->second.e->bindVars(env);
i->second.e->bindVars(env);
}
void ExprList::bindVars(const StaticEnv & env)
@@ -249,9 +242,9 @@ void ExprList::bindVars(const StaticEnv & env)
void ExprLambda::bindVars(const StaticEnv & env)
{
StaticEnv newEnv(false, &env);
unsigned int displ = 0;
if (!arg.empty()) newEnv.vars[arg] = displ++;
if (matchAttrs) {
@@ -268,15 +261,14 @@ void ExprLambda::bindVars(const StaticEnv & env)
void ExprLet::bindVars(const StaticEnv & env)
{
StaticEnv newEnv(false, &env);
unsigned int displ = 0;
foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs)
newEnv.vars[i->first] = i->second.displ = displ++;
foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs)
if (i->second.inherited) i->second.var.bind(env);
else i->second.e->bindVars(newEnv);
i->second.e->bindVars(i->second.inherited ? env : newEnv);
body->bindVars(newEnv);
}
@@ -293,8 +285,8 @@ void ExprWith::bindVars(const StaticEnv & env)
prevWith = level;
break;
}
attrs->bindVars(env);
attrs->bindVars(env);
StaticEnv newEnv(true, &env);
body->bindVars(newEnv);
}
@@ -324,4 +316,36 @@ void ExprConcatStrings::bindVars(const StaticEnv & env)
}
/* Storing function names. */
void Expr::setName(Symbol & name)
{
}
void ExprLambda::setName(Symbol & name)
{
this->name = name;
body->setName(name);
}
string ExprLambda::showNamePos()
{
return (format("%1% at %2%") % (name.set() ? "`" + (string) name + "'" : "an anonymous function") % pos).str();
}
/* Symbol table. */
size_t SymbolTable::totalSize() const
{
size_t n = 0;
foreach (Symbols::const_iterator, i, symbols)
n += i->size();
return n;
}
}
+32 -27
View File
@@ -1,5 +1,4 @@
#ifndef __NIXEXPR_H
#define __NIXEXPR_H
#pragma once
#include "value.hh"
#include "symbol-table.hh"
@@ -17,17 +16,29 @@ MakeError(ThrownError, AssertionError)
MakeError(Abort, EvalError)
MakeError(TypeError, EvalError)
MakeError(ImportError, EvalError) // error building an imported derivation
MakeError(UndefinedVarError, Error)
/* Position objects. */
struct Pos
{
string file;
Symbol file;
unsigned int line, column;
Pos() : line(0), column(0) { };
Pos(const string & file, unsigned int line, unsigned int column)
Pos(const Symbol & file, unsigned int line, unsigned int column)
: file(file), line(line), column(column) { };
bool operator < (const Pos & p2) const
{
if (!line) return p2.line;
if (!p2.line) return false;
int d = ((string) file).compare((string) p2.file);
if (d < 0) return true;
if (d > 0) return false;
if (line < p2.line) return true;
if (line > p2.line) return false;
return column < p2.column;
}
};
extern Pos noPos;
@@ -55,6 +66,7 @@ struct Expr
virtual void bindVars(const StaticEnv & env);
virtual void eval(EvalState & state, Env & env, Value & v);
virtual Value * maybeThunk(EvalState & state, Env & env);
virtual void setName(Symbol & name);
};
std::ostream & operator << (std::ostream & str, Expr & e);
@@ -66,9 +78,9 @@ std::ostream & operator << (std::ostream & str, Expr & e);
struct ExprInt : Expr
{
int n;
NixInt n;
Value v;
ExprInt(int n) : n(n) { mkInt(v, n); };
ExprInt(NixInt n) : n(n) { mkInt(v, n); };
COMMON_METHODS
Value * maybeThunk(EvalState & state, Env & env);
};
@@ -98,32 +110,25 @@ struct ExprPath : Expr
Value * maybeThunk(EvalState & state, Env & env);
};
struct VarRef
struct ExprVar : Expr
{
Pos pos;
Symbol name;
/* Whether the variable comes from an environment (e.g. a rec, let
or function argument) or from a "with". */
bool fromWith;
/* In the former case, the value is obtained by going `level'
levels up from the current environment and getting the
`displ'th value in that environment. In the latter case, the
value is obtained by getting the attribute named `name' from
the attribute set stored in the environment that is `level'
levels up from the current one.*/
the set stored in the environment that is `level' levels up
from the current one.*/
unsigned int level;
unsigned int displ;
VarRef() { };
VarRef(const Symbol & name) : name(name) { };
void bind(const StaticEnv & env);
};
struct ExprVar : Expr
{
VarRef info;
ExprVar(const Symbol & name) : info(name) { };
ExprVar(const Pos & pos, const Symbol & name) : pos(pos), name(name) { };
COMMON_METHODS
Value * maybeThunk(EvalState & state, Env & env);
};
@@ -150,12 +155,10 @@ struct ExprAttrs : Expr
bool recursive;
struct AttrDef {
bool inherited;
Expr * e; // if not inherited
VarRef var; // if inherited
Expr * e;
Pos pos;
unsigned int displ; // displacement
AttrDef(Expr * e, const Pos & pos) : inherited(false), e(e), pos(pos) { };
AttrDef(const Symbol & name, const Pos & pos) : inherited(true), var(name), pos(pos) { };
AttrDef(Expr * e, const Pos & pos, bool inherited=false) : inherited(inherited), e(e), pos(pos) { };
AttrDef() { };
};
typedef std::map<Symbol, AttrDef> AttrDefs;
@@ -189,6 +192,7 @@ struct Formals
struct ExprLambda : Expr
{
Pos pos;
Symbol name;
Symbol arg;
bool matchAttrs;
Formals * formals;
@@ -200,6 +204,8 @@ struct ExprLambda : Expr
throw ParseError(format("duplicate formal function argument `%1%' at %2%")
% arg % pos);
};
void setName(Symbol & name);
string showNamePos();
COMMON_METHODS
};
@@ -269,8 +275,10 @@ MakeBinOp(OpConcatLists, "++")
struct ExprConcatStrings : Expr
{
bool forceString;
vector<Expr *> * es;
ExprConcatStrings(vector<Expr *> * es) : es(es) { };
ExprConcatStrings(bool forceString, vector<Expr *> * es)
: forceString(forceString), es(es) { };
COMMON_METHODS
};
@@ -290,6 +298,3 @@ struct StaticEnv
}
#endif /* !__NIXEXPR_H */
+65 -53
View File
@@ -4,32 +4,32 @@
%error-verbose
%defines
/* %no-lines */
%parse-param { yyscan_t scanner }
%parse-param { ParseData * data }
%lex-param { yyscan_t scanner }
%lex-param { ParseData * data }
%parse-param { void * scanner }
%parse-param { nix::ParseData * data }
%lex-param { void * scanner }
%lex-param { nix::ParseData * data }
%expect 1
%expect-rr 1
%code requires {
#ifndef BISON_HEADER
#define BISON_HEADER
#include "util.hh"
#include "nixexpr.hh"
#include "eval.hh"
namespace nix {
struct ParseData
struct ParseData
{
EvalState & state;
SymbolTable & symbols;
Expr * result;
Path basePath;
Path path;
Symbol path;
string error;
Symbol sLetBody;
ParseData(EvalState & state)
@@ -38,7 +38,7 @@ namespace nix {
, sLetBody(symbols.create("<let-body>"))
{ };
};
}
#define YY_DECL int yylex \
@@ -52,7 +52,6 @@ namespace nix {
#include "parser-tab.hh"
#include "lexer-tab.hh"
#define YYSTYPE YYSTYPE // workaround a bug in Bison 2.4
#include <stdio.h>
#include <stdlib.h>
@@ -64,14 +63,14 @@ using namespace nix;
namespace nix {
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);
}
static void dupAttr(Symbol attr, const Pos & pos, const Pos & prevPos)
{
@@ -79,7 +78,7 @@ static void dupAttr(Symbol attr, const Pos & pos, const Pos & prevPos)
throw ParseError(format("attribute `%1%' at %2% already defined at %3%")
% showAttrPath(attrPath) % pos % prevPos);
}
static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
Expr * e, const Pos & pos)
@@ -105,6 +104,7 @@ static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
}
}
}
e->setName(attrPath.back());
}
@@ -121,7 +121,7 @@ static void addFormal(const Pos & pos, Formals * formals, const Formal & formal)
static Expr * stripIndentation(SymbolTable & symbols, vector<Expr *> & es)
{
if (es.empty()) return new ExprString(symbols.create(""));
/* Figure out the minimum indentation. Note that by design
whitespace-only final lines are not taken into account. (So
the " " in "\n ''" is ignored, but the " " in "\n foo''" is.) */
@@ -170,7 +170,7 @@ static Expr * stripIndentation(SymbolTable & symbols, vector<Expr *> & es)
es2->push_back(*i);
continue;
}
string s2;
for (unsigned int j = 0; j < e->s.size(); ++j) {
if (atStartOfLine) {
@@ -203,7 +203,8 @@ static Expr * stripIndentation(SymbolTable & symbols, vector<Expr *> & es)
es2->push_back(new ExprString(symbols.create(s2)));
}
return new ExprConcatStrings(es2);
/* If this is a single string, then don't do a concatenation. */
return es2->size() == 1 && dynamic_cast<ExprString *>((*es2)[0]) ? (*es2)[0] : new ExprConcatStrings(true, es2);
}
@@ -232,13 +233,13 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
%}
%union {
// !!! We're probably leaking stuff here.
// !!! We're probably leaking stuff here.
nix::Expr * e;
nix::ExprList * list;
nix::ExprAttrs * attrs;
nix::Formals * formals;
nix::Formal * formal;
int n;
nix::NixInt n;
char * id; // !!! -> Symbol
char * path;
char * uri;
@@ -269,12 +270,15 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
%left OR
%left AND
%nonassoc EQ NEQ
%left '<' '>' LEQ GEQ
%right UPDATE
%left NEG
%left '+'
%left NOT
%left '+' '-'
%left '*' '/'
%right CONCAT
%nonassoc '?'
%nonassoc '~'
%nonassoc NEGATE
%%
@@ -306,9 +310,14 @@ expr_if
;
expr_op
: '!' expr_op %prec NEG { $$ = new ExprOpNot($2); }
: '!' expr_op %prec NOT { $$ = new ExprOpNot($2); }
| '-' expr_op %prec NEGATE { $$ = new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__sub")), new ExprInt(0)), $2); }
| expr_op EQ expr_op { $$ = new ExprOpEq($1, $3); }
| expr_op NEQ expr_op { $$ = new ExprOpNEq($1, $3); }
| expr_op '<' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__lessThan")), $1), $3); }
| expr_op LEQ expr_op { $$ = new ExprOpNot(new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__lessThan")), $3), $1)); }
| expr_op '>' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__lessThan")), $3), $1); }
| expr_op GEQ expr_op { $$ = new ExprOpNot(new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__lessThan")), $1), $3)); }
| expr_op AND expr_op { $$ = new ExprOpAnd($1, $3); }
| expr_op OR expr_op { $$ = new ExprOpOr($1, $3); }
| expr_op IMPL expr_op { $$ = new ExprOpImpl($1, $3); }
@@ -318,8 +327,11 @@ expr_op
{ vector<Expr *> * l = new vector<Expr *>;
l->push_back($1);
l->push_back($3);
$$ = new ExprConcatStrings(l);
$$ = new ExprConcatStrings(false, l);
}
| expr_op '-' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__sub")), $1), $3); }
| expr_op '*' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__mul")), $1), $3); }
| expr_op '/' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__div")), $1), $3); }
| expr_op CONCAT expr_op { $$ = new ExprOpConcatLists($1, $3); }
| expr_app
;
@@ -338,18 +350,18 @@ expr_select
| /* 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"))); }
{ $$ = new ExprApp($1, new ExprVar(CUR_POS, data->symbols.create("or"))); }
| expr_simple { $$ = $1; }
;
expr_simple
: ID { $$ = new ExprVar(data->symbols.create($1)); }
: ID { $$ = new ExprVar(CUR_POS, data->symbols.create($1)); }
| INT { $$ = new ExprInt($1); }
| '"' string_parts '"' {
/* For efficiency, and to simplify parse trees a bit. */
if ($2->empty()) $$ = new ExprString(data->symbols.create(""));
else if ($2->size() == 1) $$ = $2->front();
else $$ = new ExprConcatStrings($2);
else if ($2->size() == 1 && dynamic_cast<ExprString *>($2->front())) $$ = $2->front();
else $$ = new ExprConcatStrings(true, $2);
}
| IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE {
$$ = stripIndentation(data->symbols, *$2);
@@ -361,10 +373,10 @@ expr_simple
/* 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. */
throw. */
$$ = path2 == ""
? (Expr * ) new ExprApp(
new ExprVar(data->symbols.create("throw")),
new ExprVar(noPos, 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);
@@ -402,7 +414,7 @@ binds
if ($$->attrs.find(*i) != $$->attrs.end())
dupAttr(*i, makeCurPos(@3, data), $$->attrs[*i].pos);
Pos pos = makeCurPos(@3, data);
$$->attrs[*i] = ExprAttrs::AttrDef(*i, pos);
$$->attrs[*i] = ExprAttrs::AttrDef(new ExprVar(CUR_POS, *i), pos, true);
}
}
| binds INHERIT '(' expr ')' attrs ';'
@@ -454,7 +466,7 @@ formal
: ID { $$ = new Formal(data->symbols.create($1), 0); }
| ID '?' expr { $$ = new Formal(data->symbols.create($1), $3); }
;
%%
@@ -467,34 +479,30 @@ formal
namespace nix {
Expr * EvalState::parse(const char * text,
const Path & path, const Path & basePath)
const Path & path, const Path & basePath, StaticEnv & staticEnv)
{
yyscan_t scanner;
ParseData data(*this);
data.basePath = basePath;
data.path = path;
data.path = data.symbols.create(path);
yylex_init(&scanner);
yy_scan_string(text, scanner);
int res = yyparse(scanner, &data);
yylex_destroy(scanner);
if (res) throw ParseError(data.error);
try {
data.result->bindVars(staticBaseEnv);
} catch (Error & e) {
throw ParseError(format("%1%, in `%2%'") % e.msg() % path);
}
data.result->bindVars(staticEnv);
return data.result;
}
Expr * EvalState::parseExprFromFile(Path path)
Path resolveExprPath(Path path)
{
assert(path[0] == '/');
@@ -512,21 +520,25 @@ Expr * EvalState::parseExprFromFile(Path path)
if (S_ISDIR(st.st_mode))
path = canonPath(path + "/default.nix");
/* Read and parse the input file, unless it's already in the parse
tree cache. */
Expr * e = parseTrees[path];
if (!e) {
e = parse(readFile(path).c_str(), path, dirOf(path));
parseTrees[path] = e;
}
return path;
}
return e;
Expr * EvalState::parseExprFromFile(const Path & path)
{
return parse(readFile(path).c_str(), path, dirOf(path), staticBaseEnv);
}
Expr * EvalState::parseExprFromString(const string & s, const Path & basePath, StaticEnv & staticEnv)
{
return parse(s.c_str(), "(string)", basePath, staticEnv);
}
Expr * EvalState::parseExprFromString(const string & s, const Path & basePath)
{
return parse(s.c_str(), "(string)", basePath);
return parseExprFromString(s, basePath, staticBaseEnv);
}
@@ -541,7 +553,7 @@ void EvalState::addToSearchPath(const string & s)
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);
@@ -554,7 +566,7 @@ Path EvalState::findFile(const string & path)
{
foreach (SearchPath::iterator, i, searchPath) {
Path res;
if (i->first.empty())
if (i->first.empty())
res = i->second + "/" + path;
else {
if (path.compare(0, i->first.size(), i->first) != 0 ||
+269 -89
View File
@@ -37,7 +37,7 @@ std::pair<string, string> decodeContext(const string & s)
/* Load and evaluate an expression from path specified by the
argument. */
argument. */
static void prim_import(EvalState & state, Value * * args, Value & v)
{
PathSet context;
@@ -51,15 +51,68 @@ static void prim_import(EvalState & state, Value * * args, Value & v)
% path % ctx);
if (isDerivation(ctx))
try {
/* For performance, prefetch all substitute info. */
PathSet willBuild, willSubstitute, unknown;
unsigned long long downloadSize, narSize;
queryMissing(*store, singleton<PathSet>(ctx),
willBuild, willSubstitute, unknown, downloadSize, narSize);
/* !!! If using a substitute, we only need to fetch
the selected output of this derivation. */
store->buildDerivations(singleton<PathSet>(ctx));
store->buildPaths(singleton<PathSet>(ctx));
} catch (Error & e) {
throw ImportError(e.msg());
}
}
state.evalFile(path, v);
if (isStorePath(path) && store->isValidPath(path) && isDerivation(path)) {
Derivation drv = parseDerivation(readFile(path));
Value & w = *state.allocValue();
state.mkAttrs(w, 1 + drv.outputs.size());
mkString(*state.allocAttr(w, state.sDrvPath), path, singleton<PathSet>("=" + path));
state.mkList(*state.allocAttr(w, state.symbols.create("outputs")), drv.outputs.size());
unsigned int outputs_index = 0;
Value * outputsVal = w.attrs->find(state.symbols.create("outputs"))->value;
foreach (DerivationOutputs::iterator, i, drv.outputs) {
mkString(*state.allocAttr(w, state.symbols.create(i->first)),
i->second.path, singleton<PathSet>("!" + i->first + "!" + path));
mkString(*(outputsVal->list.elems[outputs_index++] = state.allocValue()),
i->first);
}
w.attrs->sort();
Value fun;
state.evalFile(state.findFile("nix/imported-drv-to-derivation.nix"), fun);
state.forceFunction(fun);
mkApp(v, fun, w);
state.forceAttrs(v);
} else {
state.evalFile(path, v);
}
}
/* Return a string representing the type of the expression. */
static void prim_typeOf(EvalState & state, Value * * args, Value & v)
{
state.forceValue(*args[0]);
string t;
switch (args[0]->type) {
case tInt: t = "int"; break;
case tBool: t = "bool"; break;
case tString: t = "string"; break;
case tPath: t = "path"; break;
case tNull: t = "null"; break;
case tAttrs: t = "set"; break;
case tList: t = "list"; break;
case tLambda:
case tPrimOp:
case tPrimOpApp:
t = "lambda";
break;
default: abort();
}
mkString(v, state.symbols.create(t));
}
@@ -79,7 +132,7 @@ static void prim_isFunction(EvalState & state, Value * * args, Value & v)
}
/* Determine whether the argument is an Int. */
/* Determine whether the argument is an integer. */
static void prim_isInt(EvalState & state, Value * * args, Value & v)
{
state.forceValue(*args[0]);
@@ -87,7 +140,7 @@ static void prim_isInt(EvalState & state, Value * * args, Value & v)
}
/* Determine whether the argument is an String. */
/* Determine whether the argument is a string. */
static void prim_isString(EvalState & state, Value * * args, Value & v)
{
state.forceValue(*args[0]);
@@ -95,7 +148,7 @@ static void prim_isString(EvalState & state, Value * * args, Value & v)
}
/* Determine whether the argument is an Bool. */
/* Determine whether the argument is a Boolean. */
static void prim_isBool(EvalState & state, Value * * args, Value & v)
{
state.forceValue(*args[0]);
@@ -105,24 +158,31 @@ static void prim_isBool(EvalState & state, Value * * args, Value & v)
struct CompareValues
{
bool operator () (const Value & v1, const Value & v2) const
bool operator () (const Value * v1, const Value * v2) const
{
if (v1.type != v2.type)
if (v1->type != v2->type)
throw EvalError("cannot compare values of different types");
switch (v1.type) {
switch (v1->type) {
case tInt:
return v1.integer < v2.integer;
return v1->integer < v2->integer;
case tString:
return strcmp(v1.string.s, v2.string.s) < 0;
return strcmp(v1->string.s, v2->string.s) < 0;
case tPath:
return strcmp(v1.path, v2.path) < 0;
return strcmp(v1->path, v2->path) < 0;
default:
throw EvalError(format("cannot compare %1% with %2%") % showType(v1) % showType(v2));
throw EvalError(format("cannot compare %1% with %2%") % showType(*v1) % showType(*v2));
}
}
};
#if HAVE_BOEHMGC
typedef list<Value *, gc_allocator<Value *> > ValueList;
#else
typedef list<Value *> ValueList;
#endif
static void prim_genericClosure(EvalState & state, Value * * args, Value & v)
{
startNest(nest, lvlDebug, "finding dependencies");
@@ -136,7 +196,7 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v)
throw EvalError("attribute `startSet' required");
state.forceList(*startSet->value);
list<Value *> workSet;
ValueList workSet;
for (unsigned int n = 0; n < startSet->value->list.length; ++n)
workSet.push_back(startSet->value->list.elems[n]);
@@ -150,11 +210,13 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v)
/* Construct the closure by applying the operator to element of
`workSet', adding the result to `workSet', continuing until
no new elements are found. */
list<Value> res;
set<Value, CompareValues> doneKeys; // !!! use Value *?
ValueList res;
// `doneKeys' doesn't need to be a GC root, because its values are
// reachable from res.
set<Value *, CompareValues> doneKeys;
while (!workSet.empty()) {
Value * e = *(workSet.begin());
workSet.pop_front();
Value * e = *(workSet.begin());
workSet.pop_front();
state.forceAttrs(*e);
@@ -164,10 +226,10 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v)
throw EvalError("attribute `key' required");
state.forceValue(*key->value);
if (doneKeys.find(*key->value) != doneKeys.end()) continue;
doneKeys.insert(*key->value);
res.push_back(*e);
if (doneKeys.find(key->value) != doneKeys.end()) continue;
doneKeys.insert(key->value);
res.push_back(e);
/* Call the `operator' function with `e' as argument. */
Value call;
mkApp(call, *op->value, *e);
@@ -183,8 +245,8 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v)
/* Create the result list. */
state.mkList(v, res.size());
unsigned int n = 0;
foreach (list<Value>::iterator, i, res)
*(v.list.elems[n++] = state.allocValue()) = *i;
foreach (ValueList::iterator, i, res)
v.list.elems[n++] = *i;
}
@@ -217,17 +279,17 @@ static void prim_addErrorContext(EvalState & state, Value * * args, Value & v)
}
/* Try evaluating the argument. Success => {success=true; value=something;},
/* Try evaluating the argument. Success => {success=true; value=something;},
* else => {success=false; value=false;} */
static void prim_tryEval(EvalState & state, Value * * args, Value & v)
{
state.mkAttrs(v, 2);
try {
state.forceValue(*args[0]);
v.attrs->push_back(Attr(state.symbols.create("value"), args[0]));
v.attrs->push_back(Attr(state.sValue, args[0]));
mkBool(*state.allocAttr(v, state.symbols.create("success")), true);
} catch (AssertionError & e) {
mkBool(*state.allocAttr(v, state.symbols.create("value")), false);
mkBool(*state.allocAttr(v, state.sValue), false);
mkBool(*state.allocAttr(v, state.symbols.create("success")), false);
}
v.attrs->sort();
@@ -280,16 +342,22 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
throw EvalError("required attribute `name' missing");
string drvName;
Pos & posDrvName(*attr->pos);
try {
try {
drvName = state.forceStringNoCtx(*attr->value);
} catch (Error & e) {
e.addPrefix(format("while evaluating the derivation attribute `name' at %1%:\n") % posDrvName);
throw;
}
/* Check whether null attributes should be ignored. */
bool ignoreNulls = false;
attr = args[0]->attrs->find(state.sIgnoreNulls);
if (attr != args[0]->attrs->end())
ignoreNulls = state.forceBool(*attr->value);
/* Build the derivation expression by processing the attributes. */
Derivation drv;
PathSet context;
string outputHash, outputHashAlgo;
@@ -299,11 +367,17 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
outputs.insert("out");
foreach (Bindings::iterator, i, *args[0]->attrs) {
if (i->name == state.sIgnoreNulls) continue;
string key = i->name;
startNest(nest, lvlVomit, format("processing attribute `%1%'") % key);
try {
if (ignoreNulls) {
state.forceValue(*i->value);
if (i->value->type == tNull) continue;
}
/* The `args' attribute is special: it supplies the
command-line arguments to the builder. */
if (key == "args") {
@@ -328,12 +402,12 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
else if (key == "outputHash") outputHash = s;
else if (key == "outputHashAlgo") outputHashAlgo = s;
else if (key == "outputHashMode") {
if (s == "recursive") outputHashRecursive = true;
if (s == "recursive") outputHashRecursive = true;
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);
Strings tmp = tokenizeString<Strings>(s);
outputs.clear();
foreach (Strings::iterator, j, tmp) {
if (outputs.find(*j) != outputs.end())
@@ -353,20 +427,18 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
}
} catch (Error & e) {
e.addPrefix(format("while evaluating the derivation attribute `%1%' at %2%:\n")
% key % *i->pos);
e.addPrefix(format("while instantiating the derivation named `%1%' at %2%:\n")
% drvName % posDrvName);
e.addPrefix(format("while evaluating the attribute `%1%' of the derivation `%2%' at %3%:\n")
% key % drvName % posDrvName);
throw;
}
}
/* Everything in the context of the strings in the derivation
attributes should be added as dependencies of the resulting
derivation. */
foreach (PathSet::iterator, i, context) {
Path path = *i;
/* Paths marked with `=' denote that the path of a derivation
is explicitly passed to the builder. Since that allows the
builder to gain access to every path in the dependency
@@ -403,7 +475,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
else
drv.inputSrcs.insert(path);
}
/* Do we have all required attributes? */
if (drv.builder == "")
throw EvalError("required attribute `builder' missing");
@@ -420,14 +492,14 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
/* Handle fixed-output derivations. */
if (outputs.size() != 1 || *(outputs.begin()) != "out")
throw Error("multiple outputs are not supported in fixed-output derivations");
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);
@@ -447,7 +519,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
/* 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);
@@ -457,7 +529,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
}
/* Write the resulting term into the Nix store directory. */
Path drvPath = writeDerivation(*store, drv, drvName);
Path drvPath = writeDerivation(*store, drv, drvName, state.repair);
printMsg(lvlChatty, format("instantiated `%1%' -> `%2%'")
% drvName % drvPath);
@@ -502,7 +574,11 @@ static void prim_toPath(EvalState & state, Value * * args, Value & v)
static void prim_storePath(EvalState & state, Value * * args, Value & v)
{
PathSet context;
Path path = canonPath(state.coerceToPath(*args[0], context));
Path path = state.coerceToPath(*args[0], context);
/* Resolve symlinks in path, unless path itself is a symlink
directly in the store. The latter condition is necessary so
e.g. nix-push does the right thing. */
if (!isStorePath(path)) path = canonPath(path, true);
if (!isInStore(path))
throw EvalError(format("path `%1%' is not in the Nix store") % path);
Path path2 = toStorePath(path);
@@ -588,10 +664,10 @@ static void prim_toFile(EvalState & state, Value * * args, Value & v)
throw EvalError(format("in `toFile': the file `%1%' cannot refer to derivation outputs") % name);
refs.insert(path);
}
Path storePath = readOnlyMode
Path storePath = settings.readOnlyMode
? computeStorePathForText(name, contents, refs)
: store->addTextToStore(name, contents, refs);
: store->addTextToStore(name, contents, refs, state.repair);
/* Note: we don't need to add `context' to the context of the
result, since `storePath' itself has references to the paths
@@ -605,7 +681,7 @@ struct FilterFromExpr : PathFilter
{
EvalState & state;
Value & filter;
FilterFromExpr(EvalState & state, Value & filter)
: state(state), filter(filter)
{
@@ -626,12 +702,12 @@ struct FilterFromExpr : PathFilter
state.callFunction(filter, arg1, fun2);
Value arg2;
mkString(arg2,
mkString(arg2,
S_ISREG(st.st_mode) ? "regular" :
S_ISDIR(st.st_mode) ? "directory" :
S_ISLNK(st.st_mode) ? "symlink" :
"unknown" /* not supported, will fail! */);
Value res;
state.callFunction(fun2, arg2, res);
@@ -653,21 +729,21 @@ static void prim_filterSource(EvalState & state, Value * * args, Value & v)
FilterFromExpr filter(state, *args[0]);
Path dstPath = readOnlyMode
Path dstPath = settings.readOnlyMode
? computeStorePathForPath(path, true, htSHA256, filter).first
: store->addToStore(path, true, htSHA256, filter);
: store->addToStore(path, true, htSHA256, filter, state.repair);
mkString(v, dstPath, singleton<PathSet>(dstPath));
}
/*************************************************************
* Attribute sets
* Sets
*************************************************************/
/* Return the names of the attributes in an attribute set as a sorted
list of strings. */
/* Return the names of the attributes in a set as a sorted list of
strings. */
static void prim_attrNames(EvalState & state, Value * * args, Value & v)
{
state.forceAttrs(*args[0]);
@@ -685,7 +761,7 @@ static void prim_attrNames(EvalState & state, Value * * args, Value & v)
/* Dynamic version of the `.' operator. */
static void prim_getAttr(EvalState & state, Value * * args, Value & v)
void prim_getAttr(EvalState & state, Value * * args, Value & v)
{
string attr = state.forceStringNoCtx(*args[0]);
state.forceAttrs(*args[1]);
@@ -694,6 +770,7 @@ static void prim_getAttr(EvalState & state, Value * * args, Value & v)
if (i == args[1]->attrs->end())
throw EvalError(format("attribute `%1%' missing") % attr);
// !!! add to stack trace?
if (state.countCalls && i->pos) state.attrSelects[*i->pos]++;
state.forceValue(*i->value);
v = *i->value;
}
@@ -708,7 +785,7 @@ static void prim_hasAttr(EvalState & state, Value * * args, Value & v)
}
/* Determine whether the argument is an attribute set. */
/* Determine whether the argument is a set. */
static void prim_isAttrs(EvalState & state, Value * * args, Value & v)
{
state.forceValue(*args[0]);
@@ -739,10 +816,11 @@ static void prim_removeAttrs(EvalState & state, Value * * args, Value & v)
}
/* Builds an attribute set from a list specifying (name, value)
pairs. To be precise, a list [{name = "name1"; value = value1;}
... {name = "nameN"; value = valueN;}] is transformed to {name1 =
value1; ... nameN = valueN;}. */
/* Builds a set from a list specifying (name, value) pairs. To be
precise, a list [{name = "name1"; value = value1;} ... {name =
"nameN"; value = valueN;}] is transformed to {name1 = value1;
... nameN = valueN;}. In case of duplicate occurences of the same
name, the first takes precedence. */
static void prim_listToAttrs(EvalState & state, Value * * args, Value & v)
{
state.forceList(*args[0]);
@@ -754,36 +832,35 @@ static void prim_listToAttrs(EvalState & state, Value * * args, Value & v)
for (unsigned int i = 0; i < args[0]->list.length; ++i) {
Value & v2(*args[0]->list.elems[i]);
state.forceAttrs(v2);
Bindings::iterator j = v2.attrs->find(state.sName);
if (j == v2.attrs->end())
throw TypeError("`name' attribute missing in a call to `listToAttrs'");
string name = state.forceStringNoCtx(*j->value);
Bindings::iterator j2 = v2.attrs->find(state.symbols.create("value"));
if (j2 == v2.attrs->end())
throw TypeError("`value' attribute missing in a call to `listToAttrs'");
Symbol sym = state.symbols.create(name);
if (seen.find(sym) == seen.end()) {
Bindings::iterator j2 = v2.attrs->find(state.symbols.create(state.sValue));
if (j2 == v2.attrs->end())
throw TypeError("`value' attribute missing in a call to `listToAttrs'");
v.attrs->push_back(Attr(sym, j2->value, j2->pos));
seen.insert(sym);
}
/* !!! Throw an error if `name' already exists? */
}
v.attrs->sort();
}
/* Return the right-biased intersection of two attribute sets as1 and
as2, i.e. a set that contains every attribute from as2 that is also
a member of as1. */
/* Return the right-biased intersection of two sets as1 and as2,
i.e. a set that contains every attribute from as2 that is also a
member of as1. */
static void prim_intersectAttrs(EvalState & state, Value * * args, Value & v)
{
state.forceAttrs(*args[0]);
state.forceAttrs(*args[1]);
state.mkAttrs(v, std::min(args[0]->attrs->size(), args[1]->attrs->size()));
foreach (Bindings::iterator, i, *args[0]->attrs) {
@@ -839,19 +916,33 @@ static void prim_isList(EvalState & state, Value * * args, Value & v)
}
static void elemAt(EvalState & state, Value & list, int n, Value & v)
{
state.forceList(list);
if (n < 0 || n >= list.list.length)
throw Error(format("list index %1% is out of bounds") % n);
state.forceValue(*list.list.elems[n]);
v = *list.list.elems[n];
}
/* Return the n-1'th element of a list. */
static void prim_elemAt(EvalState & state, Value * * args, Value & v)
{
elemAt(state, *args[0], state.forceInt(*args[1]), v);
}
/* Return the first element of a list. */
static void prim_head(EvalState & state, Value * * args, Value & v)
{
state.forceList(*args[0]);
if (args[0]->list.length == 0)
throw Error("`head' called on an empty list");
state.forceValue(*args[0]->list.elems[0]);
v = *args[0]->list.elems[0];
elemAt(state, *args[0], 0, v);
}
/* Return a list consisting of everything but the the first element of
a list. */
a list. Warning: this function takes O(n) time, so you probably
don't want to use it! */
static void prim_tail(EvalState & state, Value * * args, Value & v)
{
state.forceList(*args[0]);
@@ -872,11 +963,64 @@ static void prim_map(EvalState & state, Value * * args, Value & v)
state.mkList(v, args[1]->list.length);
for (unsigned int n = 0; n < v.list.length; ++n)
mkApp(*(v.list.elems[n] = state.allocValue()),
mkApp(*(v.list.elems[n] = state.allocValue()),
*args[0], *args[1]->list.elems[n]);
}
/* Filter a list using a predicate; that is, return a list containing
every element from the list for which the predicate function
returns true. */
static void prim_filter(EvalState & state, Value * * args, Value & v)
{
state.forceFunction(*args[0]);
state.forceList(*args[1]);
// FIXME: putting this on the stack is risky.
Value * vs[args[1]->list.length];
unsigned int k = 0;
bool same = true;
for (unsigned int n = 0; n < args[1]->list.length; ++n) {
Value res;
state.callFunction(*args[0], *args[1]->list.elems[n], res);
if (state.forceBool(res))
vs[k++] = args[1]->list.elems[n];
else
same = false;
}
if (same)
v = *args[1];
else {
state.mkList(v, k);
for (unsigned int n = 0; n < k; ++n) v.list.elems[n] = vs[n];
}
}
/* Return true if a list contains a given element. */
static void prim_elem(EvalState & state, Value * * args, Value & v)
{
bool res = false;
state.forceList(*args[1]);
for (unsigned int n = 0; n < args[1]->list.length; ++n)
if (state.eqValues(*args[0], *args[1]->list.elems[n])) {
res = true;
break;
}
mkBool(v, res);
}
/* Concatenate a list of lists. */
static void prim_concatLists(EvalState & state, Value * * args, Value & v)
{
state.forceList(*args[0]);
state.concatLists(v, args[0]->list.length, args[0]->list.elems);
}
/* Return the length of a list. This is an O(1) time operation. */
static void prim_length(EvalState & state, Value * * args, Value & v)
{
@@ -910,7 +1054,7 @@ static void prim_mul(EvalState & state, Value * * args, Value & v)
static void prim_div(EvalState & state, Value * * args, Value & v)
{
int i2 = state.forceInt(*args[1]);
NixInt i2 = state.forceInt(*args[1]);
if (i2 == 0) throw EvalError("division by zero");
mkInt(v, state.forceInt(*args[0]) / i2);
}
@@ -918,7 +1062,10 @@ static void prim_div(EvalState & state, Value * * args, Value & v)
static void prim_lessThan(EvalState & state, Value * * args, Value & v)
{
mkBool(v, state.forceInt(*args[0]) < state.forceInt(*args[1]));
state.forceValue(*args[0]);
state.forceValue(*args[1]);
CompareValues comp;
mkBool(v, comp(args[0], args[1]));
}
@@ -988,11 +1135,26 @@ static void prim_unsafeDiscardOutputDependency(EvalState & state, Value * * args
if (p.at(0) == '=') p = "~" + string(p, 1);
context2.insert(p);
}
mkString(v, s, context2);
}
/* Return the cryptographic hash of a string in base-16. */
static void prim_hashString(EvalState & state, Value * * args, Value & v)
{
string type = state.forceStringNoCtx(*args[0]);
HashType ht = parseHashType(type);
if (ht == htUnknown)
throw Error(format("unknown hash type `%1%'") % type);
PathSet context; // discarded
string s = state.forceString(*args[1], context);
mkString(v, printHash(hashString(ht, s)), context);
};
/*************************************************************
* Versions
*************************************************************/
@@ -1035,21 +1197,32 @@ void EvalState::createBaseEnv()
mkBool(v, true);
addConstant("true", v);
mkBool(v, false);
addConstant("false", v);
v.type = tNull;
addConstant("null", v);
mkInt(v, time(0));
addConstant("__currentTime", v);
mkString(v, thisSystem.c_str());
mkString(v, settings.thisSystem.c_str());
addConstant("__currentSystem", v);
mkString(v, nixVersion.c_str());
addConstant("__nixVersion", v);
/* Language version. This should be increased every time a new
language feature gets added. It's not necessary to increase it
when primops get added, because you can just use `builtins ?
primOp' to check. */
mkInt(v, 1);
addConstant("__langVersion", v);
// Miscellaneous
addPrimOp("import", 1, prim_import);
addPrimOp("__typeOf", 1, prim_typeOf);
addPrimOp("isNull", 1, prim_isNull);
addPrimOp("__isFunction", 1, prim_isFunction);
addPrimOp("__isString", 1, prim_isString);
@@ -1076,7 +1249,7 @@ void EvalState::createBaseEnv()
addPrimOp("__toFile", 2, prim_toFile);
addPrimOp("__filterSource", 2, prim_filterSource);
// Attribute sets
// Sets
addPrimOp("__attrNames", 1, prim_attrNames);
addPrimOp("__getAttr", 2, prim_getAttr);
addPrimOp("__hasAttr", 2, prim_hasAttr);
@@ -1088,11 +1261,15 @@ void EvalState::createBaseEnv()
// Lists
addPrimOp("__isList", 1, prim_isList);
addPrimOp("__elemAt", 2, prim_elemAt);
addPrimOp("__head", 1, prim_head);
addPrimOp("__tail", 1, prim_tail);
addPrimOp("map", 2, prim_map);
addPrimOp("__filter", 2, prim_filter);
addPrimOp("__elem", 2, prim_elem);
addPrimOp("__concatLists", 1, prim_concatLists);
addPrimOp("__length", 1, prim_length);
// Integer arithmetic
addPrimOp("__add", 2, prim_add);
addPrimOp("__sub", 2, prim_sub);
@@ -1106,6 +1283,7 @@ void EvalState::createBaseEnv()
addPrimOp("__stringLength", 1, prim_stringLength);
addPrimOp("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext);
addPrimOp("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency);
addPrimOp("__hashString", 2, prim_hashString);
// Versions
addPrimOp("__parseDrvName", 1, prim_parseDrvName);
@@ -1116,11 +1294,13 @@ void EvalState::createBaseEnv()
/* Add a wrapper around the derivation primop that computes the
`drvPath' and `outPath' attributes lazily. */
mkThunk_(v, parseExprFromFile(findFile("nix/derivation.nix")));
string path = findFile("nix/derivation.nix");
sDerivationNix = symbols.create(path);
evalFile(path, v);
addConstant("derivation", v);
/* Now that we've added all primops, sort the `builtins' attribute
set, because attribute lookups expect it to be sorted. */
/* Now that we've added all primops, sort the `builtins' set,
because attribute lookups expect it to be sorted. */
baseEnv.values[0]->attrs->sort();
}
+16 -13
View File
@@ -1,5 +1,4 @@
#ifndef __SYMBOL_TABLE_H
#define __SYMBOL_TABLE_H
#pragma once
#include "config.h"
@@ -14,11 +13,10 @@
namespace nix {
/* Symbol table used by the parser and evaluator to represent and look
up identifiers and attribute sets efficiently.
SymbolTable::create() converts a string into a symbol. Symbols
have the property that they can be compared efficiently (using a
pointer equality test), because the symbol table stores only one
copy of each string. */
up identifiers and attributes efficiently. SymbolTable::create()
converts a string into a symbol. Symbols have the property that
they can be compared efficiently (using a pointer equality test),
because the symbol table stores only one copy of each string. */
class Symbol
{
@@ -29,17 +27,17 @@ private:
public:
Symbol() : s(0) { };
bool operator == (const Symbol & s2) const
{
return s == s2.s;
}
bool operator != (const Symbol & s2) const
{
return s != s2.s;
}
bool operator < (const Symbol & s2) const
{
return s < s2.s;
@@ -50,6 +48,11 @@ public:
return *s;
}
bool set() const
{
return s;
}
bool empty() const
{
return s->empty();
@@ -67,7 +70,7 @@ inline std::ostream & operator << (std::ostream & str, const Symbol & sym)
class SymbolTable
{
private:
#if HAVE_TR1_UNORDERED_SET
#if HAVE_TR1_UNORDERED_SET
typedef std::tr1::unordered_set<string> Symbols;
#else
typedef std::set<string> Symbols;
@@ -85,8 +88,8 @@ public:
{
return symbols.size();
}
size_t totalSize() const;
};
}
#endif /* !__SYMBOL_TABLE_H */
+1 -4
View File
@@ -1,5 +1,4 @@
#ifndef __VALUE_TO_XML_H
#define __VALUE_TO_XML_H
#pragma once
#include "nixexpr.hh"
#include "eval.hh"
@@ -13,5 +12,3 @@ void printValueAsXML(EvalState & state, bool strict, bool location,
Value & v, std::ostream & out, PathSet & context);
}
#endif /* !__VALUE_TO_XML_H */
+13 -13
View File
@@ -1,5 +1,4 @@
#ifndef __VALUE_H
#define __VALUE_H
#pragma once
#include "symbol-table.hh"
@@ -32,17 +31,20 @@ struct PrimOp;
struct Symbol;
typedef long NixInt;
struct Value
{
ValueType type;
union
union
{
int integer;
NixInt integer;
bool boolean;
/* Strings in the evaluator carry a so-called `context' (the
ATermList) which is a list of strings representing store
paths. This is to allow users to write things like
/* Strings in the evaluator carry a so-called `context' which
is a list of strings representing store paths. This is to
allow users to write things like
"--with-freetype2-library=" + freetype + "/lib"
@@ -64,7 +66,7 @@ struct Value
const char * s;
const char * * context; // must be in sorted order
} string;
const char * path;
Bindings * attrs;
struct {
@@ -98,7 +100,7 @@ static inline void clearValue(Value & v)
}
static inline void mkInt(Value & v, int n)
static inline void mkInt(Value & v, NixInt n)
{
clearValue(v);
v.type = tInt;
@@ -132,7 +134,7 @@ static inline void mkStringNoCopy(Value & v, const char * s)
static inline void mkString(Value & v, const Symbol & s)
{
mkStringNoCopy(v, ((string) s).c_str());
mkStringNoCopy(v, ((const string &) s).c_str());
}
@@ -151,5 +153,3 @@ void mkPath(Value & v, const char * s);
}
#endif /* !__VALUE_H */
+1 -2
View File
@@ -1,12 +1,11 @@
pkglib_LTLIBRARIES = libmain.la
libmain_la_SOURCES = shared.cc
libmain_la_SOURCES = shared.cc stack.cc
libmain_la_LIBADD = ../libstore/libstore.la @BDW_GC_LIBS@
pkginclude_HEADERS = shared.hh
AM_CXXFLAGS = \
-DNIX_VERSION=\"$(VERSION)\" \
-I$(srcdir)/.. -I$(srcdir)/../libutil \
-I$(srcdir)/../libstore
+67 -95
View File
@@ -10,8 +10,10 @@
#include <cctype>
#include <exception>
#include <sys/time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>
#if HAVE_BOEHMGC
#include <gc/gc.h>
@@ -33,20 +35,10 @@ static void sigintHandler(int signo)
}
Path makeRootName(const Path & gcRoot, int & counter)
{
counter++;
if (counter == 1)
return gcRoot;
else
return (format("%1%-%2%") % gcRoot % counter).str();
}
void printGCWarning()
{
static bool haveWarned = false;
warnOnce(haveWarned,
warnOnce(haveWarned,
"you did not specify `--add-root'; "
"the result might be removed by the garbage collector");
}
@@ -57,7 +49,14 @@ void printMissing(StoreAPI & store, const PathSet & paths)
unsigned long long downloadSize, narSize;
PathSet willBuild, willSubstitute, unknown;
queryMissing(store, paths, willBuild, willSubstitute, unknown, downloadSize, narSize);
printMissing(willBuild, willSubstitute, unknown, downloadSize, narSize);
}
void printMissing(const PathSet & willBuild,
const PathSet & willSubstitute, const PathSet & unknown,
unsigned long long downloadSize, unsigned long long narSize)
{
if (!willBuild.empty()) {
printMsg(lvlInfo, format("these derivations will be built:"));
foreach (PathSet::iterator, i, willBuild)
@@ -74,7 +73,7 @@ void printMissing(StoreAPI & store, const PathSet & paths)
if (!unknown.empty()) {
printMsg(lvlInfo, format("don't know how to build these paths%1%:")
% (readOnlyMode ? " (may be caused by read-only store access)" : ""));
% (settings.readOnlyMode ? " (may be caused by read-only store access)" : ""));
foreach (PathSet::iterator, i, unknown)
printMsg(lvlInfo, format(" %1%") % *i);
}
@@ -93,12 +92,25 @@ static void setLogType(string lt)
static bool showTrace = false;
string getArg(const string & opt,
Strings::iterator & i, const Strings::iterator & end)
{
++i;
if (i == end) throw UsageError(format("`%1%' requires an argument") % opt);
return *i;
}
void detectStackOverflow();
/* Initialize and reorder arguments, then call the actual argument
processor. */
static void initAndRun(int argc, char * * argv)
{
setDefaultsFromEnvironment();
settings.processEnvironment();
settings.loadConfFile();
/* Catch SIGINT. */
struct sigaction act;
act.sa_handler = sigintHandler;
@@ -123,12 +135,19 @@ static void initAndRun(int argc, char * * argv)
if (sigaction(SIGCHLD, &act, 0))
throw SysError("resetting SIGCHLD");
/* Register a SIGSEGV handler to detect stack overflows. */
detectStackOverflow();
/* There is no privacy in the Nix system ;-) At least not for
now. In particular, store objects should be readable by
everybody. This prevents nasty surprises when using a shared
store (with the setuid() hack). */
everybody. */
umask(0022);
/* Initialise the PRNG. */
struct timeval tv;
gettimeofday(&tv, 0);
srandom(tv.tv_usec);
/* Process the NIX_LOG_TYPE environment variable. */
string lt = getEnv("NIX_LOG_TYPE");
if (lt != "") setLogType(lt);
@@ -137,7 +156,7 @@ static void initAndRun(int argc, char * * argv)
Strings args, remaining;
while (argc--) args.push_back(*argv++);
args.erase(args.begin());
/* Expand compound dash options (i.e., `-qlf' -> `-q -l -f'), and
ignore options for the ATerm library. */
for (Strings::iterator i = args.begin(); i != args.end(); ++i) {
@@ -156,46 +175,44 @@ static void initAndRun(int argc, char * * argv)
remaining.clear();
/* Process default options. */
int verbosityDelta = 0;
for (Strings::iterator i = args.begin(); i != args.end(); ++i) {
string arg = *i;
if (arg == "--verbose" || arg == "-v") verbosityDelta++;
else if (arg == "--quiet") verbosityDelta--;
if (arg == "--verbose" || arg == "-v") verbosity = (Verbosity) (verbosity + 1);
else if (arg == "--quiet") verbosity = verbosity > lvlError ? (Verbosity) (verbosity - 1) : lvlError;
else if (arg == "--log-type") {
++i;
if (i == args.end()) throw UsageError("`--log-type' requires an argument");
setLogType(*i);
string s = getArg(arg, i, args.end());
setLogType(s);
}
else if (arg == "--no-build-output" || arg == "-Q")
buildVerbosity = lvlVomit;
settings.buildVerbosity = lvlVomit;
else if (arg == "--print-build-trace")
printBuildTrace = true;
settings.printBuildTrace = true;
else if (arg == "--help") {
printHelp();
return;
}
else if (arg == "--version") {
std::cout << format("%1% (Nix) %2%") % programId % NIX_VERSION << std::endl;
std::cout << format("%1% (Nix) %2%") % programId % nixVersion << std::endl;
return;
}
else if (arg == "--keep-failed" || arg == "-K")
keepFailed = true;
settings.keepFailed = true;
else if (arg == "--keep-going" || arg == "-k")
keepGoing = true;
settings.keepGoing = true;
else if (arg == "--fallback")
tryFallback = true;
settings.set("build-fallback", "true");
else if (arg == "--max-jobs" || arg == "-j")
maxBuildJobs = getIntArg<unsigned int>(arg, i, args.end());
settings.set("build-max-jobs", getArg(arg, i, args.end()));
else if (arg == "--cores")
buildCores = getIntArg<unsigned int>(arg, i, args.end());
settings.set("build-cores", getArg(arg, i, args.end()));
else if (arg == "--readonly-mode")
readOnlyMode = true;
settings.readOnlyMode = true;
else if (arg == "--max-silent-time")
maxSilentTime = getIntArg<unsigned int>(arg, i, args.end());
settings.set("build-max-silent-time", getArg(arg, i, args.end()));
else if (arg == "--timeout")
buildTimeout = getIntArg<unsigned int>(arg, i, args.end());
settings.set("build-timeout", getArg(arg, i, args.end()));
else if (arg == "--no-build-hook")
useBuildHook = false;
settings.useBuildHook = false;
else if (arg == "--show-trace")
showTrace = true;
else if (arg == "--option") {
@@ -203,14 +220,13 @@ static void initAndRun(int argc, char * * argv)
string name = *i;
++i; if (i == args.end()) throw UsageError("`--option' requires two arguments");
string value = *i;
overrideSetting(name, tokenizeString(value));
settings.set(name, value);
}
else remaining.push_back(arg);
}
verbosityDelta += queryIntSetting("verbosity", lvlInfo);
verbosity = (Verbosity) (verbosityDelta < 0 ? 0 : verbosityDelta);
settings.update();
run(remaining);
/* Close the Nix database. */
@@ -218,56 +234,6 @@ static void initAndRun(int argc, char * * argv)
}
bool setuidMode = false;
static void setuidInit()
{
/* Don't do anything if this is not a setuid binary. */
if (getuid() == geteuid() && getgid() == getegid()) return;
uid_t nixUid = geteuid();
gid_t nixGid = getegid();
setuidCleanup();
/* Don't trust the current directory. */
if (chdir("/") == -1) abort();
/* Set the real (and preferably also the save) uid/gid to the
effective uid/gid. This matters mostly when we're not using
build-users (bad!), since some builders (like Perl) complain
when real != effective.
On systems where setresuid is unavailable, we can't drop the
saved uid/gid. This means that we could go back to the
original real uid (i.e., the uid of the caller). That's not
really a problem, except maybe when we execute a builder and
we're not using build-users. In that case, the builder may be
able to switch to the uid of the caller and possibly do bad
stuff. But note that when not using build-users, the builder
could also modify the Nix executables (say, replace them by a
Trojan horse), so the problem is already there. */
#if HAVE_SETRESUID
if (setresuid(nixUid, nixUid, nixUid)) abort();
if (setresgid(nixGid, nixGid, nixGid)) abort();
#elif HAVE_SETREUID
/* Note: doesn't set saved uid/gid! */
fprintf(stderr, "warning: cannot set saved uid\n");
if (setreuid(nixUid, nixUid)) abort();
if (setregid(nixGid, nixGid)) abort();
#else
/* Note: doesn't set real and saved uid/gid! */
fprintf(stderr, "warning: cannot set real and saved uids\n");
if (setuid(nixUid)) abort();
if (setgid(nixGid)) abort();
#endif
setuidMode = true;
}
/* Called when the Boehm GC runs out of memory. */
static void * oomHandler(size_t requested)
{
@@ -276,6 +242,14 @@ static void * oomHandler(size_t requested)
}
void showManPage(const string & name)
{
string cmd = "man " + name;
if (system(cmd.c_str()) != 0)
throw Error(format("command `%1%' failed") % cmd);
}
int exitCode = 0;
char * * argvSaved = 0;
@@ -290,11 +264,6 @@ int main(int argc, char * * argv)
argvSaved = argv;
/* If we're setuid, then we need to take some security precautions
right away. */
if (argc == 0) abort();
setuidInit();
/* Turn on buffering for cerr. */
#if HAVE_PUBSETBUF
std::cerr.rdbuf()->pubsetbuf(buf, sizeof(buf));
@@ -323,7 +292,7 @@ int main(int argc, char * * argv)
throw;
}
} catch (UsageError & e) {
printMsg(lvlError,
printMsg(lvlError,
format(
"error: %1%\n"
"Try `%2% --help' for more information.")
@@ -334,6 +303,9 @@ int main(int argc, char * * argv)
if (e.prefix() != "" && !showTrace)
printMsg(lvlError, "(use `--show-trace' to show detailed location information)");
return e.status;
} catch (std::bad_alloc & e) {
printMsg(lvlError, "error: out of memory");
return 1;
} catch (std::exception & e) {
printMsg(lvlError, format("error: %1%") % e.what());
return 1;
+7 -8
View File
@@ -1,5 +1,4 @@
#ifndef __SHARED_H
#define __SHARED_H
#pragma once
#include "util.hh"
@@ -27,11 +26,14 @@ MakeError(UsageError, nix::Error);
class StoreAPI;
/* Ugh. No better place to put this. */
Path makeRootName(const Path & gcRoot, int & counter);
void printGCWarning();
void printMissing(StoreAPI & store, const PathSet & paths);
void printMissing(const PathSet & willBuild,
const PathSet & willSubstitute, const PathSet & unknown,
unsigned long long downloadSize, unsigned long long narSize);
template<class N> N getIntArg(const string & opt,
Strings::iterator & i, const Strings::iterator & end)
{
@@ -43,8 +45,8 @@ template<class N> N getIntArg(const string & opt,
return n;
}
/* Whether we're running setuid. */
extern bool setuidMode;
/* Show the manual page for the specified program. */
void showManPage(const string & name);
extern volatile ::sig_atomic_t blockInt;
@@ -54,6 +56,3 @@ extern int exitCode;
extern char * * argvSaved;
}
#endif /* !__SHARED_H */
+72
View File
@@ -0,0 +1,72 @@
#include "config.h"
#include "types.hh"
#include <cstring>
#include <cstddef>
#include <cstdlib>
#include <unistd.h>
#include <signal.h>
namespace nix {
static void sigsegvHandler(int signo, siginfo_t * info, void * ctx)
{
/* Detect stack overflows by comparing the faulting address with
the stack pointer. Unfortunately, getting the stack pointer is
not portable. */
bool haveSP = true;
char * sp;
#if defined(__x86_64__) && defined(REG_RSP)
sp = (char *) ((ucontext *) ctx)->uc_mcontext.gregs[REG_RSP];
#elif defined(REG_ESP)
sp = (char *) ((ucontext *) ctx)->uc_mcontext.gregs[REG_ESP];
#else
haveSP = false;
#endif
if (haveSP) {
ptrdiff_t diff = (char *) info->si_addr - sp;
if (diff < 0) diff = -diff;
if (diff < 4096) {
char msg[] = "error: stack overflow (possible infinite recursion)\n";
write(2, msg, strlen(msg));
_exit(1); // maybe abort instead?
}
}
/* Restore default behaviour (i.e. segfault and dump core). */
struct sigaction act;
sigfillset(&act.sa_mask);
act.sa_handler = SIG_DFL;
act.sa_flags = 0;
if (sigaction(SIGSEGV, &act, 0)) abort();
}
void detectStackOverflow()
{
#if defined(SA_SIGINFO) && defined (SA_ONSTACK)
/* Install a SIGSEGV handler to detect stack overflows. This
requires an alternative stack, otherwise the signal cannot be
delivered when we're out of stack space. */
stack_t stack;
stack.ss_size = 4096 * 4 + MINSIGSTKSZ;
stack.ss_sp = new char[stack.ss_size];
if (!stack.ss_sp) throw Error("cannot allocate alternative stack");
stack.ss_flags = 0;
if (sigaltstack(&stack, 0) == -1) throw SysError("cannot set alternative stack");
struct sigaction act;
sigfillset(&act.sa_mask);
act.sa_sigaction = sigsegvHandler;
act.sa_flags = SA_SIGINFO | SA_ONSTACK;
if (sigaction(SIGSEGV, &act, 0))
throw SysError("resetting SIGCHLD");
#endif
}
}
+3 -2
View File
@@ -10,7 +10,7 @@ pkginclude_HEADERS = \
globals.hh references.hh pathlocks.hh \
worker-protocol.hh
libstore_la_LIBADD = ../libutil/libutil.la ../boost/format/libformat.la @SQLITE3_LIBS@
libstore_la_LIBADD = ../libutil/libutil.la ../boost/format/libformat.la @SQLITE3_LIBS@ -lbz2
EXTRA_DIST = schema.sql
@@ -23,10 +23,11 @@ AM_CXXFLAGS = -Wall \
-DNIX_CONF_DIR=\"$(sysconfdir)/nix\" \
-DNIX_LIBEXEC_DIR=\"$(libexecdir)\" \
-DNIX_BIN_DIR=\"$(bindir)\" \
-DNIX_VERSION=\"$(VERSION)\" \
-I$(srcdir)/.. -I$(srcdir)/../libutil \
-I$(srcdir)/../libstore
local-store.lo: schema.sql.hh
%.sql.hh: %.sql
../bin2c/bin2c schema < $< > $@ || (rm $@ && exit 1)
sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $< > $@ || (rm $@ && exit 1)
+1069 -571
View File
File diff suppressed because it is too large Load Diff

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