Compare commits

..

48 Commits
secure ... 0.9

Author SHA1 Message Date
Eelco Dolstra
2b3366f0a8 * Tagged 0.9 release. 2005-09-16 13:46:11 +00:00
Eelco Dolstra
1243732a80 * Mark as stable. 2005-09-16 11:30:17 +00:00
Eelco Dolstra
882d569077 * 0.9 release branch. 2005-09-16 11:29:14 +00:00
Eelco Dolstra
db1a4227a3 * Updated release notes. 2005-09-16 11:28:29 +00:00
Eelco Dolstra
c28b8eb699 * svn:ignores.
* Add missing file to dist.
2005-09-16 10:35:48 +00:00
Eelco Dolstra
6f044ab39c * svn:ignore. 2005-09-16 09:05:54 +00:00
Eelco Dolstra
d34fa9a6cc * Remove dead file. 2005-09-16 09:05:18 +00:00
Eelco Dolstra
846b53bde4 * Set the current directory to something well-defined. Might help in
setuid installations.
2005-09-16 09:03:24 +00:00
Eelco Dolstra
5c0770ac84 * Include the release notes in the manual. 2005-09-16 08:47:34 +00:00
Eelco Dolstra
1b62c2eba3 * Force release notes in ASCII, not UTF-8. 2005-09-15 20:29:08 +00:00
Eelco Dolstra
d1d0271996 * Check for w3m. 2005-09-15 15:21:57 +00:00
Eelco Dolstra
7f384d9c1b * Use a proper temporary directory. 2005-09-15 15:21:35 +00:00
Eelco Dolstra
896c0b92f3 * This is not a GNU project :-P 2005-09-15 09:18:21 +00:00
Eelco Dolstra
5818e8eeaf * Remove dead code. 2005-09-14 18:51:02 +00:00
Eelco Dolstra
025086edea * Release notes in Docbook; ASCII release notes (i.e., the `NEWS'
file) is now generated from that using `w3m' and some XSL hackery.
2005-09-14 18:50:45 +00:00
Eelco Dolstra
ed1db42915 * List concatenation must be right-associative for efficiency. 2005-09-14 11:41:59 +00:00
Eelco Dolstra
deb75bb414 * Remove debugging code. 2005-09-13 15:54:36 +00:00
Eelco Dolstra
116e939d57 * More debugging. 2005-09-13 14:07:22 +00:00
Eelco Dolstra
55b84357a1 * Debugging. 2005-09-13 13:17:14 +00:00
Eelco Dolstra
cf2bb91ec8 * Missing #include. 2005-09-13 13:17:01 +00:00
Eelco Dolstra
699073c337 * Release notes. 2005-09-13 10:57:24 +00:00
Eelco Dolstra
cb44aa03b8 * Use aterm 2.4. 2005-09-01 20:48:18 +00:00
Eelco Dolstra
2bcd65ecf6 * `nix-env -e' corrupts memory due to incorrect use of iterators.
Reported by Rob Vermaas.
2005-09-01 18:14:04 +00:00
Eelco Dolstra
e1a6fb7870 * `dependencyClosure' now allows a search path, e.g.,
dependencyClosure { ... searchPath = [ ../foo ../bar ]; ... }

* Primop `dirOf' to return the directory part of a path (e.g., dirOf
  /a/b/c == /a/b).

* Primop `relativise' (according to Webster that's a real word!) that
  given paths A and B returns a string representing path B relative
  path to A; e.g., relativise /a/b/c a/b/x/y => "../x/y".
2005-08-14 14:00:39 +00:00
Eelco Dolstra
08c53923db * A primitive operation `dependencyClosure' to do automatic dependency
determination (e.g., finding the header files dependencies of a C
  file) in Nix low-level builds automatically.

  For instance, in the function `compileC' in make/lib/default.nix, we
  find the header file dependencies of C file `main' as follows:

    localIncludes =
      dependencyClosure {
        scanner = file:
          import (findIncludes {
            inherit file;
          });
        startSet = [main];
      };

  The function works by "growing" the set of dependencies, starting
  with the set `startSet', and calling the function `scanner' for each
  file to get its dependencies (which should yield a list of strings
  representing relative paths).  For instance, when `scanner' is
  called on a file `foo.c' that includes the line

    #include "../bar/fnord.h"

  then `scanner' should yield ["../bar/fnord.h"].  This list of
  dependencies is absolutised relative to the including file and added
  to the set of dependencies.  The process continues until no more
  dependencies are found (hence its a closure).

  `dependencyClosure' yields a list that contains in alternation a
  dependency, and its relative path to the directory of the start
  file, e.g.,

    [ /bla/bla/foo.c
      "foo.c"
      /bla/bar/fnord.h
      "../bar/fnord.h"
    ]

  These relative paths are necessary for the builder that compiles
  foo.c to reconstruct the relative directory structure expected by
  foo.c.

  The advantage of `dependencyClosure' over the old approach (using
  the impure `__currentTime') is that it's completely pure, and more
  efficient because it only rescans for dependencies (i.e., by
  building the derivations yielded by `scanner') if sources have
  actually changed.  The old approach rescanned every time.
2005-08-14 12:38:47 +00:00
Eelco Dolstra
714b7256cd * Cleanup; sync with thesis. 2005-08-14 10:19:55 +00:00
Eelco Dolstra
0399365675 * nix-hash: option `--truncate' to truncate the hash to 160 bits. Hmm,
kind of ad hoc ;-)
2005-08-14 10:09:56 +00:00
Eelco Dolstra
2fd22c6360 * Add .libs to svn:ignore. Commit 3500 ;-) 2005-08-01 13:39:56 +00:00
Eelco Dolstra
c680f835c9 * Escape ASCII characters < 32 to Unicode FFFD (REPLACEMENT CHARACTER)
so that we don't produce un-wellformed XML.
2005-08-01 13:39:19 +00:00
Eelco Dolstra
f450c8ea2f * Oops. XSL stylesheet to mark errors. 2005-08-01 13:24:04 +00:00
Eelco Dolstra
800a6ff845 * Mark error lines in red, and expand subtrees containing errors
automatically.
2005-08-01 13:23:43 +00:00
Eelco Dolstra
78c72bf10e * channels -> channels-v3, catamaran -> nix.cs.uu.nl. 2005-08-01 07:30:35 +00:00
Eelco Dolstra
991a130b1e * Added a list concatenation operator:
[1 2 3] ++ [4 5 6] => [1 2 3 4 5 6]
2005-07-25 15:05:34 +00:00
Eelco Dolstra
e6899794ae * Add $prefix/lib to the RPM. 2005-07-25 10:10:24 +00:00
Eelco Dolstra
33efb52e02 * Hack to get around the libtool wrapper script around nix-store not
working when PATH is unset.
2005-07-25 07:25:18 +00:00
Eelco Dolstra
3fae65d4cc * Adhockery. 2005-07-22 20:37:39 +00:00
Eelco Dolstra
4c20a08293 * Build dynamic libraries. 2005-07-22 14:52:45 +00:00
Eelco Dolstra
1a67154d41 * Release notes. 2005-07-19 12:00:38 +00:00
Eelco Dolstra
0f827cc607 * Prevent repeated wrapping of closed terms
(closed(closed(closed(...)))) since this reduces performance by
  producing bigger terms and killing caching (which incidentally also
  prevents useful infinite recursion detection).
2005-07-19 11:48:05 +00:00
Eelco Dolstra
2135e7c041 * Wat cleanups. 2005-07-16 23:19:20 +00:00
Eelco Dolstra
6f82a78de7 * Define paths using regexps, as is done in the Flex definition. 2005-07-16 21:38:15 +00:00
Eelco Dolstra
6f91f02f75 * Make the rejects a bit more compact.
* Add lexical restrictions for keywords.
2005-07-16 20:43:58 +00:00
Eelco Dolstra
9590009a74 * Fix ambiguity. 2005-07-16 15:41:27 +00:00
Eelco Dolstra
f797cb5855 * Revive and update the SDF grammar for Nix expressions. 2005-07-16 14:07:35 +00:00
Eelco Dolstra
a5ceb5bc0b * nix-build: default to `./default.nix' if no paths are specified.
So when using Nix as a build tool, you can just say `nix-build' and
  it will build the top-level derivation defined in `default.nix'.
2005-07-13 17:39:10 +00:00
Eelco Dolstra
d4879b4dfe * Add curl to the RPM dependencies. Should fix NIX-11. 2005-07-12 16:08:10 +00:00
Eelco Dolstra
22d3587f3b * In nix-instantiate, at top-level, call functions that have arguments
with default values automatically.  I.e., e -> e {}.

  This feature makes convenience expressions such as
  pkgs/system/i686-linux.nix in Nixpkgs obsolete, since we can just do

  $ nix-instantiate ./pkgs/system/all-packages.nix

  since all-packages.nix takes a single argument (system) that has a
  default value (__thisSystem).
2005-07-12 16:06:25 +00:00
Eelco Dolstra
928a7c06dc * Don't create patches for archives >= 150 MB because bsdiff can't
handle it.  It crashed on the 234 MB tetex archive.  Probably we
  will never be able to handle archives of that size on 32-bit
  machines (because bsdiff does everything in memory requiring
  max(17*n,9*n+m)+O(1) bytes, so the address space simply isn't
  there).
2005-06-18 14:20:24 +00:00
74 changed files with 1431 additions and 1384 deletions

View File

@@ -1,6 +1,6 @@
SUBDIRS = externals src scripts corepkgs doc misc tests
EXTRA_DIST = substitute.mk nix.spec nix.spec.in bootstrap.sh \
svn-revision nix.conf.example
svn-revision nix.conf.example NEWS
include ./substitute.mk
@@ -45,3 +45,8 @@ endif
svn-revision:
svnversion . > svn-revision
all-local: NEWS
NEWS:
cp doc/manual/NEWS.txt NEWS

261
NEWS
View File

@@ -1,261 +0,0 @@
Version 0.9
* Unpacking of patch sequences is much faster now by not doing
redundant unpacking and repacking of intermediate paths.
Version 0.8 (April 11, 2005)
NOTE: the hashing scheme in Nix 0.8 changed (as detailed below). As a
result, `nix-pull' manifests and channels built for Nix 0.7 and below
will now work anymore. However, the Nix expression language has not
changed, so you can still build from source. Also, existing user
environments continue to work. Nix 0.8 will automatically upgrade the
database schema of previous installations when it is first run.
If you get the error message
you have an old-style manifest `/nix/var/nix/manifests/[...]';
please delete it
you should delete previously downloaded manifests:
$ rm /nix/var/nix/manifests/*
If `nix-channel' gives the error message
manifest `http://catamaran.labs.cs.uu.nl/dist/nix/channels/[channel]/MANIFEST'
is too old (i.e., for Nix <= 0.7)
then you should unsubscribe from the offending channel (`nix-channel
--remove URL'; leave out `/MANIFEST'), and subscribe to the same URL,
with `channels' replaced by `channels-v3' (e.g.,
http://catamaran.labs.cs.uu.nl/dist/nix/channels-v3/nixpkgs-unstable).
Nix 0.8 has the following improvements:
* The cryptographic hashes used in store paths are now 160 bits long,
but encoded in base-32 so that they are still only 32 characters
long (e.g., /nix/store/csw87wag8bqlqk7ipllbwypb14xainap-atk-1.9.0).
(This is actually a 160 bit truncation of a SHA-256 hash.)
* Big cleanups and simplifications of the basic store semantics. The
notion of "closure store expressions" is gone (and so is the notion
of "successors"); the file system references of a store path are now
just stored in the database.
For instance, given any store path, you can query its closure:
$ nix-store -qR $(which firefox)
... lots of paths ...
Also, Nix now remembers for each store path the derivation that
built it (the "deriver"):
$ nix-store -qR $(which firefox)
/nix/store/4b0jx7vq80l9aqcnkszxhymsf1ffa5jd-firefox-1.0.1.drv
So to see the build-time dependencies, you can do
$ nix-store -qR $(nix-store -qd $(which firefox))
or, in a nicer format:
$ nix-store -q --tree $(nix-store -qd $(which firefox))
File system references are also stored in reverse. For instance,
you can query all paths that directly or indirectly use a certain
Glibc:
$ nix-store -q --referers-closure \
/nix/store/8lz9yc6zgmc0vlqmn2ipcpkjlmbi51vv-glibc-2.3.4
* The concept of fixed-output derivations has been formalised.
Previously, functions such as `fetchurl' in Nixpkgs used a hack
(namely, explicitly specifying a store path hash) to prevent changes
to, say, the URL of the file from propagating upwards through the
dependency graph, causing rebuilds of everything. This can now be
done cleanly by specifying the `outputHash' and `outputHashAlgo'
attributes. Nix itself checks that the content of the output has
the specified hash. (This is important for maintaining certain
invariants necessary for future work on secure shared stores.)
* One-click installation :-) It is now possible to install any
top-level component in Nixpkgs directly, through the web - see,
e.g., http://catamaran.labs.cs.uu.nl/dist/nixpkgs-0.8/. All you
have to do is associate `/nix/bin/nix-install-package' with the MIME
type `application/nix-package' (or the extension `.nixpkg'), and
clicking on a package link will cause it to be installed, with all
appropriate dependencies. If you just want to install some specific
application, this is easier than subscribing to a channel.
* `nix-store -r PATHS' now builds all the derivations PATHS in
parallel. Previously it did them sequentially (though exploiting
possible parallelism between subderivations). This is nice for
build farms.
* `nix-channel' has new operations `--list' and `--remove'.
* New ways of installing components into user environments:
- Copy from another user environment:
$ nix-env -i --from-profile .../other-profile firefox
- Install a store derivation directly (bypassing the Nix expression
language entirely):
$ nix-env -i /nix/store/z58v41v21xd3...-aterm-2.3.1.drv
(This is used to implement `nix-install-package', which is
therefore immune to evolution in the Nix expression language.)
- Install an already built store path directly:
$ nix-env -i /nix/store/hsyj5pbn0d9i...-aterm-2.3.1
- Install the result of a Nix expression specified as a command-line
argument:
$ nix-env -f .../i686-linux.nix -i -E 'x: x.firefoxWrapper'
The difference with the normal installation mode is that `-E' does
not use the `name' attributes of derivations. Therefore, this can
be used to disambiguate multiple derivations with the same name.
* A hash of the contents of a store path is now stored in the database
after a succesful build. This allows you to check whether store
paths have been tampered with: `nix-store --verify --check-contents'.
* Implemented a concurrent garbage collector. It is now always safe
to run the garbage collector, even if other Nix operations are
happening simultaneously.
However, there can still be GC races if you use `nix-instantiate'
and `nix-store -r' directly to build things. To prevent races, use
the `--add-root' flag of those commands.
* The garbage collector now finally deletes paths in the right order
(i.e., topologically sorted under the `references' relation), thus
making it safe to interrupt the collector without risking a store
that violates the closure invariant.
* Likewise, the substitute mechanism now downloads files in the right
order, thus preserving the closure invariant at all times.
* The result of `nix-build' is now registered as a root of the garbage
collector. If the `./result' link is deleted, the GC root
disappears automatically.
* The behaviour of the garbage collector can be changed globally by
setting options in `/nix/etc/nix/nix.conf'.
- `gc-keep-derivations' specifies whether deriver links should be
followed when searching for live paths.
- `gc-keep-outputs' specifies whether outputs of derivations should
be followed when searching for live paths.
- `env-keep-derivations' specifies whether user environments should
store the paths of derivations when they are added (thus keeping
the derivations alive).
* New `nix-env' query flags `--drv-path' and `--out-path'.
* `fetchurl' allows SHA-1 and SHA-256 in addition to MD5. Just
specify the attribute `sha1' or `sha256' instead of `md5'.
* Manual updates.
Version 0.7 (January 12, 2005)
* Binary patching. When upgrading components using pre-built binaries
(through nix-pull / nix-channel), Nix can automatically download and
apply binary patches to already installed components instead of full
downloads. Patching is "smart": if there is a *sequence* of patches
to an installed component, Nix will use it. Patches are currently
generated automatically between Nixpkgs (pre-)releases.
* Simplifications to the substitute mechanism.
* Nix-pull now stores downloaded manifests in /nix/var/nix/manifests.
* Metadata on files in the Nix store is canonicalised after builds:
the last-modified timestamp is set to 0 (00:00:00 1/1/1970), the
mode is set to 0444 or 0555 (readable and possibly executable by
all; setuid/setgid bits are dropped), and the group is set to the
default. This ensures that the result of a build and an
installation through a substitute is the same; and that timestamp
dependencies are revealed.
Version 0.6 (November 14, 2004)
Major changes include the following:
* Rewrite of the normalisation engine.
* Multiple builds can now be performed in parallel (option `-j').
* Distributed builds. Nix can now call a shell script to forward
builds to Nix installations on remote machines, which may or may
not be of the same platform type.
* Option `--fallback' allows recovery from broken substitutes.
* Option `--keep-going' causes building of other (unaffected)
derivations to continue if one failed.
* Improvements to the garbage collector (i.e., it should actually work
now).
* Setuid Nix installations allow a Nix store to be shared among
multiple users.
* Substitute registration is much faster now.
* A utility `nix-build' to build a Nix expression and create a symlink
to the result int the current directory; useful for testing Nix
derivations.
* Manual updates.
* `nix-env' changes:
* Derivations for other platforms are filtered out (which can be
overriden using `--system-filter').
* `--install' by default now uninstall previous derivations with the
same name.
* `--upgrade' allows upgrading to a specific version.
* New operation `--delete-generations' to remove profile
generations (necessary for effective garbage collection).
* Nicer output (sorted, columnised).
* More sensible verbosity levels all around (builder output is now
shown always, unless `-Q' is given).
* Nix expression language changes:
* New language construct: `with E1; E2' brings all attributes
defined in the attribute set E1 in scope in E2.
* Added a `map' function.
* Various new operators (e.g., string concatenation).
* Expression evaluation is much faster.
* An Emacs mode for editing Nix expressions (with syntax highlighting
and indentation) has been added.
* Many bug fixes.
Version 0.5 and earlier
Please refer to the Subversion commit log messages.

View File

@@ -1,4 +1,6 @@
#! /bin/sh -e
mkdir -p config
libtoolize --copy
aclocal
autoheader
automake --add-missing --copy

View File

@@ -1,11 +1,11 @@
AC_INIT(nix, "0.9")
AC_CONFIG_SRCDIR(README)
AC_CONFIG_AUX_DIR(config)
AM_INIT_AUTOMAKE([dist-bzip2])
AM_INIT_AUTOMAKE([dist-bzip2 foreign])
# Change to `1' to produce a `stable' release (i.e., the `preREVISION'
# suffix is not added).
STABLE=0
STABLE=1
# Put the revision number in the version.
if test "$STABLE" != "1"; then
@@ -48,6 +48,10 @@ AC_PROG_CC
AC_PROG_CXX
AC_PROG_RANLIB
# We are going to use libtool.
AC_DISABLE_STATIC
AC_PROG_LIBTOOL
# Check for pubsetbuf.
AC_MSG_CHECKING([for pubsetbuf])
AC_LANG_PUSH(C++)
@@ -78,6 +82,7 @@ NEED_PROG(bunzip2, bunzip2)
NEED_PROG(shell, sh)
AC_PATH_PROG(xmllint, xmllint, false)
AC_PATH_PROG(xsltproc, xsltproc, false)
AC_PATH_PROG(w3m, w3m, false)
AC_PATH_PROG(flex, flex, false)
AC_PATH_PROG(bison, bison, false)
NEED_PROG(perl, perl)

View File

@@ -26,6 +26,7 @@ sub createLinks {
if ($srcFile =~ /\/propagated-build-inputs$/ ||
$srcFile =~ /\/nix-support$/ ||
$srcFile =~ /\/perllocal.pod$/ ||
$srcFile =~ /\/info\/dir$/ ||
$srcFile =~ /\/log$/)
{
# Do nothing.

View File

@@ -20,7 +20,7 @@ MANUAL_SRCS = manual.xml introduction.xml installation.xml \
$(man1_MANS:.1=.xml) \
troubleshooting.xml bugs.xml opt-common.xml opt-common-syn.xml \
env-common.xml quick-start.xml nix-lang-ref.xml glossary.xml \
conf-file.xml \
conf-file.xml release-notes.xml \
style.css images
manual.is-valid: $(MANUAL_SRCS) version.txt
@@ -37,7 +37,25 @@ manual.html: $(MANUAL_SRCS) manual.is-valid images
$(XSLTPROC) --nonet --xinclude --output manual.html \
$(docbookxsl)/html/docbook.xsl manual.xml
all-local: manual.html
NEWS_OPTS = \
--stringparam generate.toc "article nop" \
--stringparam section.autolabel.max.depth 0 \
--stringparam header.rule 0
NEWS.html: release-notes.xml
$(XSLTPROC) --nonet --xinclude --output $@ $(NEWS_OPTS) \
$(docbookxsl)/html/docbook.xsl release-notes.xml
NEWS.txt: release-notes.xml
$(XSLTPROC) --nonet --xinclude quote-literals.xsl release-notes.xml | \
$(XSLTPROC) --nonet --output $@.tmp.html $(NEWS_OPTS) \
$(docbookxsl)/html/docbook.xsl -
LANG=en_US $(w3m) -dump $@.tmp.html > $@
rm $@.tmp.html
all-local: manual.html NEWS.html NEWS.txt
install-data-local: manual.html
$(INSTALL) -d $(DESTDIR)$(datadir)/nix/manual
@@ -54,7 +72,7 @@ images:
cp $(docbookxsl)/images/callouts/*.png images/callouts
chmod +w -R images
KEEP = manual.html manual.is-valid version.txt $(MANS)
KEEP = manual.html manual.is-valid version.txt $(MANS) NEWS.html NEWS.txt
EXTRA_DIST = $(MANUAL_SRCS) $(FIGURES) $(KEEP)

View File

@@ -130,8 +130,8 @@ collection. It also discusses some advanced topics, such as setting
up a Nix-based build farm, and doing service deployment using
Nix.</para>
<note><para>Some background information on Nix can be found in three
papers. The ICSE 2004 paper <ulink
<note><para>Some background information on Nix can be found in a
number of papers. The ICSE 2004 paper <ulink
url='http://www.cs.uu.nl/~eelco/pubs/immdsd-icse2004-final.pdf'><citetitle>Imposing
a Memory Management Discipline on Software
Deployment</citetitle></ulink> discusses the hashing mechanism used to
@@ -144,7 +144,10 @@ Deployment</citetitle></ulink> gives a more general discussion of Nix
from a system-administration perspective. The CBSE 2005 paper <ulink
url='http://www.cs.uu.nl/~eelco/pubs/eupfcdm-cbse2005-final.pdf'><citetitle>Efficient
Upgrading in a Purely Functional Component Deployment Model
</citetitle></ulink> is about transparent patch deployment in
Nix.</para></note>
</citetitle></ulink> is about transparent patch deployment in Nix.
Finally, the SCM-12 paper <ulink
url='http://www.cs.uu.nl/~eelco/pubs/servicecm-scm12-final.pdf'>
Service Configuration Management</ulink> shows how services (e.g., web
servers) can be deployed and managed through Nix.</para></note>
</chapter>

View File

@@ -80,4 +80,9 @@
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="bugs.xml" />
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="glossary.xml" />
<appendix>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="release-notes.xml"
xpointer="xpointer(article/*)" />
</appendix>
</book>

View File

@@ -25,6 +25,10 @@ to multiple derivations, multiple sequentially numbered symlinks are
created (<filename>result</filename>, <filename>result-2</filename>,
and so on).</para>
<para>If no <replaceable>paths</replaceable> are specified, then
<command>nix-build</command> will use <filename>default.nix</filename>
in the current directory, if it exists.</para>
<note><para><command>nix-build</command> is essentially a wrapper
around <link
linkend="sec-nix-instantiate"><command>nix-instantiate</command></link>

View File

@@ -36,7 +36,7 @@
<title>Examples</title>
<screen>
$ nix-pull http://catamaran.labs.cs.uu.nl/dist/nix/nixpkgs-0.5pre753/MANIFEST</screen>
$ nix-pull http://nix.cs.uu.nl/dist/nix/nixpkgs-0.5pre753/MANIFEST</screen>
</refsection>

View File

@@ -32,8 +32,8 @@ components ranging from basic development stuff such as GCC and Glibc,
to end-user applications like Mozilla Firefox. (Nix is however not
tied to the Nix Package collection; you could write your own Nix
expressions based on it, or completely new ones.) You can download
the latest version from <ulink
url='http://catamaran.labs.cs.uu.nl/dist/nix' />.</para>
the latest version from <ulink url='http://nix.cs.uu.nl/dist/nix'
/>.</para>
<para>Assuming that you have downloaded and unpacked a release of Nix
Packages, you can view the set of available components in the release:
@@ -97,16 +97,15 @@ available somewhere. This is done using the
containing a <emphasis>manifest</emphasis> describing what binaries
are available. This URL should correspond to the Nix Packages release
that youre using. For instance, if you obtained a release from
<ulink
url='http://catamaran.labs.cs.uu.nl/dist/nix/nixpkgs-0.6pre1554/' />,
then you should do:
<ulink url='http://nix.cs.uu.nl/dist/nix/nixpkgs-0.6pre1554/' />, then
you should do:
<screen>
$ nix-pull http://catamaran.labs.cs.uu.nl/dist/nix/nixpkgs-0.6pre1554/MANIFEST</screen>
$ nix-pull http://nix.cs.uu.nl/dist/nix/nixpkgs-0.6pre1554/MANIFEST</screen>
If you then issue the installation command, it should start
downloading binaries from <systemitem
class='fqdomainname'>catamaran.labs.cs.uu.nl</systemitem>, instead of
class='fqdomainname'>nix.cs.uu.nl</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>
@@ -176,7 +175,7 @@ set.</para></footnote></para>
<sect1 id="sec-profiles"><title>Profiles</title>
<para>Profiles and user environments are Nixs mechanism for
implementing the ability to allow differens users to have different
implementing the ability to allow different users to have different
configurations, and to do atomic upgrades and rollbacks. To
understand how they work, its useful to know a bit about how Nix
works. In Nix, components are stored in unique locations in the
@@ -425,7 +424,7 @@ URL.</para>
<command>nix-channel --add</command>, e.g.,
<screen>
$ nix-channel --add http://catamaran.labs.cs.uu.nl/dist/nix/channels/nixpkgs-unstable</screen>
$ nix-channel --add http://nix.cs.uu.nl/dist/nix/channels-v3/nixpkgs-unstable</screen>
subscribes you to a channel that always contains that latest version
of the Nix Packages collection. (Instead of

View File

@@ -27,7 +27,7 @@ file).</para></listitem>
<listitem><para>Subscribe to the Nix Packages channel.
<screen>
$ nix-channel --add http://catamaran.labs.cs.uu.nl/dist/nix/channels/nixpkgs-unstable</screen>
$ nix-channel --add http://nix.cs.uu.nl/dist/nix/channels-v3/nixpkgs-unstable</screen>
</para></listitem>

View File

@@ -0,0 +1,40 @@
<?xml version="1.0"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="str">
<xsl:output method="xml"/>
<xsl:template match="function|command|literal|varname|filename|option|quote">`<xsl:apply-templates/>'</xsl:template>
<xsl:template match="token"><xsl:text> </xsl:text><xsl:apply-templates /><xsl:text>
</xsl:text></xsl:template>
<xsl:template match="screen|programlisting">
<screen><xsl:apply-templates select="str:split(., '&#xA;')" /></screen>
</xsl:template>
<xsl:template match="section[following::section]">
<section>
<xsl:apply-templates />
<screen><xsl:text>
</xsl:text></screen>
</section>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{name(.)}" namespace="{namespace-uri(.)}">
<xsl:copy-of select="namespace::*" />
<xsl:for-each select="@*">
<xsl:attribute name="{name(.)}" namespace="{namespace-uri(.)}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:for-each>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>

View File

@@ -0,0 +1,523 @@
<?xml version="1.0"?>
<!DOCTYPE book
PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.docbook.org/xml/4.3/docbook-xml-4.3.zip"
[
]>
<article><title>Nix Release Notes</title>
<section><title>Release 0.9 (September 16, 2005)</title>
<para>NOTE: this version of Nix uses Berkeley DB 4.3 instead of 4.2.
The database is upgraded automatically, but you should be careful not
to use old versions of Nix that still use Berkeley DB 4.2. In
particular, if you use a Nix installed through Nix, you should run
<screen>
$ nix-store --clear-substitutes</screen>
first.</para>
<itemizedlist>
<listitem><para>Unpacking of patch sequences is much faster now
since we no longer do redundant unpacking and repacking of
intermediate paths.</para></listitem>
<listitem><para>Nix now uses Berkeley DB 4.3.</para></listitem>
<listitem><para>The <function>derivation</function> primitive is
lazier. Attributes of dependent derivations can mutually refer to
each other (as long as there are no data dependencies on the
<varname>outPath</varname> and <varname>drvPath</varname> attributes
computed by <function>derivation</function>).</para>
<para>For example, the expression <literal>derivation
attrs</literal> now evaluates to (essentially)
<programlisting>
attrs // {
type = "derivation";
outPath = derivation! attrs;
drvPath = derivation! attrs;
}</programlisting>
where <function>derivation!</function> is a primop that does the
actual derivation instantiation (i.e., it does what
<function>derivation</function> used to do). The advantage is that
it allows commands such as <command>nix-env -qa</command> and
<command>nix-env -i</command> to be much faster since they no longer
need to instantiate all derivations, just the
<varname>name</varname> attribute.</para>
<para>Also, it allows derivations to cyclically reference each
other, for example,
<programlisting>
webServer = derivation {
...
hostName = "svn.cs.uu.nl";
services = [svnService];
};
&#x20;
svnService = derivation {
...
hostName = webServer.hostName;
};</programlisting>
Previously, this would yield a black hole (infinite recursion).</para>
</listitem>
<listitem><para><command>nix-build</command> now defaults to using
<filename>./default.nix</filename> if no Nix expression is
specified.</para></listitem>
<listitem><para><command>nix-instantiate</command>, when applied to
a Nix expression that evaluates to a function, will call the
function automatically if all its arguments have
defaults.</para></listitem>
<listitem><para>Nix now uses libtool to build dynamic libraries.
This reduces the size of executables.</para></listitem>
<listitem><para>A new list concatenation operator
<literal>++</literal>. For example, <literal>[1 2 3] ++ [4 5
6]</literal> evaluates to <literal>[1 2 3 4 5
6]</literal>.</para></listitem>
<listitem><para>Some currently undocumented primops to support
low-level build management using Nix (i.e., using Nix as a Make
replacement). See the commit messages for <literal>r3578</literal>
and <literal>r3580</literal>.</para></listitem>
<listitem><para>Various bug fixes and performance
improvements.</para></listitem>
</itemizedlist>
</section>
<section><title>Release 0.8.1 (April 13, 2005)</title>
<para>This is a bug fix release.</para>
<itemizedlist>
<listitem><para>Patch downloading was broken.</para></listitem>
<listitem><para>The garbage collector would not delete paths that
had references from invalid (but substitutable)
paths.</para></listitem>
</itemizedlist>
</section>
<section><title>Release 0.8 (April 11, 2005)</title>
<para>NOTE: the hashing scheme in Nix 0.8 changed (as detailed below).
As a result, <command>nix-pull</command> manifests and channels built
for Nix 0.7 and below will now work anymore. However, the Nix
expression language has not changed, so you can still build from
source. Also, existing user environments continue to work. Nix 0.8
will automatically upgrade the database schema of previous
installations when it is first run.</para>
<para>If you get the error message
<screen>
you have an old-style manifest `/nix/var/nix/manifests/[...]'; please
delete it</screen>
you should delete previously downloaded manifests:
<screen>
$ rm /nix/var/nix/manifests/*</screen>
If <command>nix-channel</command> gives the error message
<screen>
manifest `http://catamaran.labs.cs.uu.nl/dist/nix/channels/[channel]/MANIFEST'
is too old (i.e., for Nix &lt;= 0.7)</screen>
then you should unsubscribe from the offending channel
(<command>nix-channel --remove
<replaceable>URL</replaceable></command>; leave out
<literal>/MANIFEST</literal>), and subscribe to the same URL, with
<literal>channels</literal> replaced by <literal>channels-v3</literal>
(e.g.,
http://catamaran.labs.cs.uu.nl/dist/nix/channels-v3/nixpkgs-unstable).</para>
<para>Nix 0.8 has the following improvements:
<itemizedlist>
<listitem><para>The cryptographic hashes used in store paths are now
160 bits long, but encoded in base-32 so that they are still only 32
characters long (e.g.,
/nix/store/csw87wag8bqlqk7ipllbwypb14xainap-atk-1.9.0). (This is
actually a 160 bit truncation of a SHA-256 hash.)</para></listitem>
<listitem><para>Big cleanups and simplifications of the basic store
semantics. The notion of "closure store expressions" is gone (and
so is the notion of "successors"); the file system references of a
store path are now just stored in the database.</para>
<para>For instance, given any store path, you can query its closure:
<screen>
$ nix-store -qR $(which firefox)
... lots of paths ...</screen>
Also, Nix now remembers for each store path the derivation that
built it (the "deriver"):
<screen>
$ nix-store -qR $(which firefox)
/nix/store/4b0jx7vq80l9aqcnkszxhymsf1ffa5jd-firefox-1.0.1.drv</screen>
So to see the build-time dependencies, you can do
<screen>
$ nix-store -qR $(nix-store -qd $(which firefox))</screen>
or, in a nicer format:
<screen>
$ nix-store -q --tree $(nix-store -qd $(which firefox))</screen>
</para>
<para>File system references are also stored in reverse. For
instance, you can query all paths that directly or indirectly use a
certain Glibc:
<screen>
$ nix-store -q --referers-closure \
/nix/store/8lz9yc6zgmc0vlqmn2ipcpkjlmbi51vv-glibc-2.3.4</screen>
</para>
</listitem>
<listitem><para>The concept of fixed-output derivations has been
formalised. Previously, functions such as
<function>fetchurl</function> in Nixpkgs used a hack (namely,
explicitly specifying a store path hash) to prevent changes to, say,
the URL of the file from propagating upwards through the dependency
graph, causing rebuilds of everything. This can now be done cleanly
by specifying the <varname>outputHash</varname> and
<varname>outputHashAlgo</varname> attributes. Nix itself checks
that the content of the output has the specified hash. (This is
important for maintaining certain invariants necessary for future
work on secure shared stores.)</para></listitem>
<listitem><para>One-click installation :-) It is now possible to
install any top-level component in Nixpkgs directly, through the web
- see, e.g., http://catamaran.labs.cs.uu.nl/dist/nixpkgs-0.8/. All
you have to do is associate
<filename>/nix/bin/nix-install-package</filename> with the MIME type
<literal>application/nix-package</literal> (or the extension
<filename>.nixpkg</filename>), and clicking on a package link will
cause it to be installed, with all appropriate dependencies. If you
just want to install some specific application, this is easier than
subscribing to a channel.</para></listitem>
<listitem><para><command>nix-store -r
<replaceable>PATHS</replaceable></command> now builds all the
derivations PATHS in parallel. Previously it did them sequentially
(though exploiting possible parallelism between subderivations).
This is nice for build farms.</para></listitem>
<listitem><para><command>nix-channel</command> has new operations
<option>--list</option> and
<option>--remove</option>.</para></listitem>
<listitem><para>New ways of installing components into user
environments:
<itemizedlist>
<listitem><para>Copy from another user environment:
<screen>
$ nix-env -i --from-profile .../other-profile firefox</screen>
</para></listitem>
<listitem><para>Install a store derivation directly (bypassing the
Nix expression language entirely):
<screen>
$ nix-env -i /nix/store/z58v41v21xd3...-aterm-2.3.1.drv</screen>
(This is used to implement <command>nix-install-package</command>,
which is therefore immune to evolution in the Nix expression
language.)</para></listitem>
<listitem><para>Install an already built store path directly:
<screen>
$ nix-env -i /nix/store/hsyj5pbn0d9i...-aterm-2.3.1</screen>
</para></listitem>
<listitem><para>Install the result of a Nix expression specified
as a command-line argument:
<screen>
$ nix-env -f .../i686-linux.nix -i -E 'x: x.firefoxWrapper'</screen>
The difference with the normal installation mode is that
<option>-E</option> does not use the <varname>name</varname>
attributes of derivations. Therefore, this can be used to
disambiguate multiple derivations with the same
name.</para></listitem>
</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
whether store paths have been tampered with: <command>nix-store
--verify --check-contents</command>.</para></listitem>
<listitem>
<para>Implemented a concurrent garbage collector. It is now
always safe to run the garbage collector, even if other Nix
operations are happening simultaneously.</para>
<para>However, there can still be GC races if you use
<command>nix-instantiate</command> and <command>nix-store
--realise</command> directly to build things. To prevent races,
use the <option>--add-root</option> flag of those commands.</para>
</listitem>
<listitem><para>The garbage collector now finally deletes paths in
the right order (i.e., topologically sorted under the
<quote>references</quote> relation), thus making it safe to
interrupt the collector without risking a store that violates the
closure invariant.</para></listitem>
<listitem><para>Likewise, the substitute mechanism now downloads
files in the right order, thus preserving the closure invariant at
all times.</para></listitem>
<listitem><para>The result of <command>nix-build</command> is now
registered as a root of the garbage collector. If the
<filename>./result</filename> link is deleted, the GC root
disappears automatically.</para></listitem>
<listitem>
<para>The behaviour of the garbage collector can be changed
globally by setting options in
<filename>/nix/etc/nix/nix.conf</filename>.
<itemizedlist>
<listitem><para><literal>gc-keep-derivations</literal> specifies
whether deriver links should be followed when searching for live
paths.</para></listitem>
<listitem><para><literal>gc-keep-outputs</literal> specifies
whether outputs of derivations should be followed when searching
for live paths.</para></listitem>
<listitem><para><literal>env-keep-derivations</literal>
specifies whether user environments should store the paths of
derivations when they are added (thus keeping the derivations
alive).</para></listitem>
</itemizedlist>
</para></listitem>
<listitem><para>New <command>nix-env</command> query flags
<option>--drv-path</option> and
<option>--out-path</option>.</para></listitem>
<listitem><para><command>fetchurl</command> allows SHA-1 and SHA-256
in addition to MD5. Just specify the attribute
<varname>sha1</varname> or <varname>sha256</varname> instead of
<varname>md5</varname>.</para></listitem>
<listitem><para>Manual updates.</para></listitem>
</itemizedlist>
</para>
</section>
<section><title>Release 0.7 (January 12, 2005)</title>
<itemizedlist>
<listitem><para>Binary patching. When upgrading components using
pre-built binaries (through nix-pull / nix-channel), Nix can
automatically download and apply binary patches to already installed
components instead of full downloads. Patching is "smart": if there
is a *sequence* of patches to an installed component, Nix will use
it. Patches are currently generated automatically between Nixpkgs
(pre-)releases.</para></listitem>
<listitem><para>Simplifications to the substitute
mechanism.</para></listitem>
<listitem><para>Nix-pull now stores downloaded manifests in
/nix/var/nix/manifests.</para></listitem>
<listitem><para>Metadata on files in the Nix store is canonicalised
after builds: the last-modified timestamp is set to 0 (00:00:00
1/1/1970), the mode is set to 0444 or 0555 (readable and possibly
executable by all; setuid/setgid bits are dropped), and the group is
set to the default. This ensures that the result of a build and an
installation through a substitute is the same; and that timestamp
dependencies are revealed.</para></listitem>
</itemizedlist>
</section>
<section><title>Release 0.6 (November 14, 2004)</title>
<itemizedlist>
<listitem>
<para>Rewrite of the normalisation engine.
<itemizedlist>
<listitem><para>Multiple builds can now be performed in parallel
(option <option>-j</option>).</para></listitem>
<listitem><para>Distributed builds. Nix can now call a shell
script to forward builds to Nix installations on remote
machines, which may or may not be of the same platform
type.</para></listitem>
<listitem><para>Option <option>--fallback</option> allows
recovery from broken substitutes.</para></listitem>
<listitem><para>Option <option>--keep-going</option> causes
building of other (unaffected) derivations to continue if one
failed.</para></listitem>
</itemizedlist>
</para>
</listitem>
<listitem><para>Improvements to the garbage collector (i.e., it
should actually work now).</para></listitem>
<listitem><para>Setuid Nix installations allow a Nix store to be
shared among multiple users.</para></listitem>
<listitem><para>Substitute registration is much faster
now.</para></listitem>
<listitem><para>A utility <command>nix-build</command> to build a
Nix expression and create a symlink to the result int the current
directory; useful for testing Nix derivations.</para></listitem>
<listitem><para>Manual updates.</para></listitem>
<listitem>
<para><command>nix-env</command> changes:
<itemizedlist>
<listitem><para>Derivations for other platforms are filtered out
(which can be overriden using
<option>--system-filter</option>).</para></listitem>
<listitem><para><option>--install</option> by default now
uninstall previous derivations with the same
name.</para></listitem>
<listitem><para><option>--upgrade</option> allows upgrading to a
specific version.</para></listitem>
<listitem><para>New operation
<option>--delete-generations</option> to remove profile
generations (necessary for effective garbage
collection).</para></listitem>
<listitem><para>Nicer output (sorted,
columnised).</para></listitem>
</itemizedlist>
</para>
</listitem>
<listitem><para>More sensible verbosity levels all around (builder
output is now shown always, unless <option>-Q</option> is
given).</para></listitem>
<listitem>
<para>Nix expression language changes:
<itemizedlist>
<listitem><para>New language construct: <literal>with
<replaceable>E1</replaceable>;
<replaceable>E2</replaceable></literal> brings all attributes
defined in the attribute set <replaceable>E1</replaceable> in
scope in <replaceable>E2</replaceable>.</para></listitem>
<listitem><para>Added a <function>map</function>
function.</para></listitem>
<listitem><para>Various new operators (e.g., string
concatenation).</para></listitem>
</itemizedlist>
</para>
</listitem>
<listitem><para>Expression evaluation is much
faster.</para></listitem>
<listitem><para>An Emacs mode for editing Nix expressions (with
syntax highlighting and indentation) has been
added.</para></listitem>
<listitem><para>Many bug fixes.</para></listitem>
</itemizedlist>
</section>
<section><title>Release 0.5 and earlier</title>
<para>Please refer to the Subversion commit log messages.</para>
</section>
</article>

View File

@@ -1046,6 +1046,11 @@ weakest binding).</para>
contains an attribute named
<replaceable>id</replaceable>.</entry>
</row>
<row>
<entry><replaceable>e1</replaceable> ++ <replaceable>e2</replaceable></entry>
<entry>right</entry>
<entry>List concatenation.</entry>
</row>
<row>
<entry><replaceable>e1</replaceable> + <replaceable>e2</replaceable></entry>
<entry>left</entry>

View File

@@ -34,12 +34,12 @@ endif
# CWI ATerm
ATERM = aterm-2.3.1
ATERM = aterm-2.4
$(ATERM).tar.gz:
@echo "Nix requires the CWI ATerm library to build."
@echo "Please download version 2.3.1 from"
@echo " http://www.cwi.nl/projects/MetaEnv/aterm/aterm-2.3.1.tar.gz"
@echo "Please download version 2.4 from"
@echo " http://www.cwi.nl/projects/MetaEnv/aterm/aterm-2.4.tar.gz"
@echo "and place it in the externals/ directory."
false

View File

@@ -19,11 +19,7 @@ rec {
./version.c
];
compile = fn: compileC {
main = fn;
localIncludes = "auto";
forSharedLib = sharedLib;
};
compile = main: compileC {inherit main sharedLib;};
libATerm = makeLibrary {
libraryName = "ATerm";

View File

@@ -1,18 +1,15 @@
with (import ../../../lib);
let {
inherit (import ../../../lib) compileC link;
inherit (import ../aterm {}) libATerm;
compile = fn: compileC {
main = fn;
localIncludes = "auto";
cFlags = "-I../aterm";
compileTest = main: link {
objects = [(compileC {inherit main; localIncludePath = [ ../aterm ];})];
libraries = libATerm;
};
fib = link {objects = compile ./fib.c; libraries = libATerm;};
primes = link {objects = compile ./primes.c; libraries = libATerm;};
body = [fib primes];
body = [
(compileTest ./fib.c)
(compileTest ./primes.c)
];
}

View File

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

View File

@@ -8,46 +8,55 @@ rec {
stdenv = pkgs.stdenv;
compileC = {main, localIncludes ? [], cFlags ? "", forSharedLib ? false}:
compileC =
{ main
, localIncludes ? "auto"
, localIncludePath ? []
, cFlags ? ""
, sharedLib ? false
}:
stdenv.mkDerivation {
name = "compile-c";
builder = ./compile-c.sh;
localIncludes =
if localIncludes == "auto" then
import (findIncludes {
main = toString main;
hack = __currentTime;
inherit cFlags;
})
dependencyClosure {
scanner = main:
import (findIncludes {
inherit main;
});
searchPath = localIncludePath;
startSet = [main];
}
else
localIncludes;
inherit main;
cFlags = [
cFlags
(if forSharedLib then ["-fpic"] else [])
(if sharedLib then ["-fpic"] else [])
(map (p: "-I" + (relativise (dirOf main) p)) localIncludePath)
];
};
/*
runCommand = {command}: {
name = "run-command";
builder = ./run-command.sh;
inherit command;
};
*/
findIncludes = {main, hack, cFlags ? ""}: stdenv.mkDerivation {
name = "find-includes";
builder = ./find-includes.sh;
inherit main hack cFlags;
};
findIncludes = {main}: stdenv.mkDerivation {
name = "find-includes";
realBuilder = pkgs.perl ~ "bin/perl";
args = [ ./find-includes.pl ];
inherit main;
};
link = {objects, programName ? "program", libraries ? []}: stdenv.mkDerivation {
name = "link";
builder = ./link.sh;
inherit objects programName libraries;
};
makeLibrary = {objects, libraryName ? [], sharedLib ? false}:
# assert sharedLib -> fold (obj: x: assert obj.sharedLib && x) false objects
stdenv.mkDerivation {
@@ -56,4 +65,5 @@ rec {
inherit objects libraryName sharedLib;
};
}

21
make/lib/find-includes.pl Normal file
View File

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

View File

@@ -1,20 +0,0 @@
. $stdenv/setup
echo "finding includes of \`$(basename $main)'..."
makefile=$NIX_BUILD_TOP/makefile
mainDir=$(dirname $main)
(cd $mainDir && gcc $cFlags -MM $(basename $main) -MF $makefile) || false
echo "[" >$out
while read line; do
line=$(echo "$line" | sed 's/.*://')
for i in $line; do
fullPath=$(readlink -f $mainDir/$i)
echo " [ $fullPath \"$i\" ]" >>$out
done
done < $makefile
echo "]" >>$out

View File

@@ -19,6 +19,7 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot
%define _prefix /nix
Prefix: %{_prefix}
Requires: /usr/bin/perl
Requires: curl
# Hack to make that shitty RPM scanning hack shut up.
Provides: perl(readmanifest)
@@ -66,6 +67,7 @@ fi
%files
#%defattr(-,root,root)
%{_prefix}/bin
%{_prefix}/lib
%{_prefix}/libexec
%{_prefix}/var
%{_prefix}/share

View File

@@ -2,6 +2,7 @@
use strict;
use readmanifest;
use POSIX qw(tmpnam);
my $manifestDir = "@localstatedir@/nix/manifests";
my $logFile = "@localstatedir@/log/nix/downloads";
@@ -9,6 +10,19 @@ my $logFile = "@localstatedir@/log/nix/downloads";
open LOGFILE, ">>$logFile" or die "cannot open log file $logFile";
# Create a temporary directory.
my $tmpDir;
do { $tmpDir = tmpnam(); }
until mkdir $tmpDir, 0700;
chdir $tmpDir or die "cannot change to `$tmpDir': $!";
my $tmpNar = "$tmpDir/nar";
my $tmpNar2 = "$tmpDir/nar2";
END { unlink $tmpNar; unlink $tmpNar2; rmdir $tmpDir; }
# Check the arguments.
die unless scalar @ARGV == 1;
my $targetPath = $ARGV[0];
@@ -217,7 +231,7 @@ while (scalar @path > 0) {
# as a base to one or more patches. So turn the base path
# into a NAR archive, to which we can apply the patch.
print " packing base path...\n";
system "@bindir@/nix-store --dump $v > /tmp/nar";
system "@bindir@/nix-store --dump $v > $tmpNar";
die "cannot dump `$v'" if ($? != 0);
}
}
@@ -235,18 +249,18 @@ while (scalar @path > 0) {
# Apply the patch to the NAR archive produced in step 1 (for
# the already present path) or a later step (for patch sequences).
print " applying patch...\n";
system "@libexecdir@/bspatch /tmp/nar /tmp/nar2 $patchPath";
die "cannot apply patch `$patchPath' to /tmp/nar" if ($? != 0);
system "@libexecdir@/bspatch $tmpNar $tmpNar2 $patchPath";
die "cannot apply patch `$patchPath' to $tmpNar" if ($? != 0);
if ($curStep < $maxStep) {
# The archive will be used as the base of the next patch.
rename "/tmp/nar2", "/tmp/nar" or die "cannot rename NAR archive: $!";
rename "$tmpNar2", "$tmpNar" or die "cannot rename NAR archive: $!";
} else {
# This was the last patch. Unpack the final NAR archive
# into the target path.
print " unpacking patched archive...\n";
system "@bindir@/nix-store --restore $v < /tmp/nar2";
die "cannot unpack /tmp/nar2 into `$v'" if ($? != 0);
system "@bindir@/nix-store --restore $v < $tmpNar2";
die "cannot unpack $tmpNar2 into `$v'" if ($? != 0);
}
}
@@ -262,7 +276,7 @@ while (scalar @path > 0) {
if ($curStep < $maxStep) {
# The archive will be used a base to a patch.
system "@bunzip2@ < '$narFilePath' > /tmp/nar";
system "@bunzip2@ < '$narFilePath' > $tmpNar";
} else {
# Unpack the archive into the target path.
print " unpacking archive...\n";

View File

@@ -277,13 +277,25 @@ foreach my $p (keys %dstOutPaths) {
my $srcNarBz2 = getNarBz2 \%srcNarFiles, $closest;
my $dstNarBz2 = getNarBz2 \%dstNarFiles, $p;
my $maxNarSize = 150 * 1024 * 1024;
system("@bunzip2@ < $srcNarBz2 > $tmpdir/A") == 0
or die "cannot unpack $srcNarBz2";
if ((stat "$tmpdir/A")[7] >= $maxNarSize) {
print " skipping, source is too large\n";
next;
}
system("@bunzip2@ < $dstNarBz2 > $tmpdir/B") == 0
or die "cannot unpack $dstNarBz2";
if ((stat "$tmpdir/B")[7] >= $maxNarSize) {
print " skipping, destination is too large\n";
next;
}
system("@libexecdir@/bsdiff $tmpdir/A $tmpdir/B $tmpdir/DIFF") == 0
or die "cannot compute binary diff";

View File

@@ -2,11 +2,6 @@
nixExpr=$1
if test -z "$nixExpr"; then
echo "syntax: $0 NIX-EXPR..." >&2
exit 1
fi
extraArgs=
addDrvLink=0
addOutLink=1
@@ -16,9 +11,15 @@ trap 'rm -f ./.nix-build-tmp-*' EXIT
# Process the arguments.
exprs=
for i in "$@"; do
case "$i" in
--help)
echo "syntax: $0 [NIX-EXPR...]" >&2
exit 0
;;
--add-drv-link)
addDrvLink=1
;;
@@ -32,28 +33,37 @@ for i in "$@"; do
;;
*)
# Instantiate the Nix expression.
prefix=
if test "$addDrvLink" = 0; then prefix=.nix-build-tmp-; fi
storeExprs=$(@bindir@/nix-instantiate \
--add-root ./${prefix}derivation --indirect \
"$i")
for j in $storeExprs; do
echo "store expression is $(readlink "$j")" >&2
done
# Build the resulting store derivation.
prefix=
if test "$addOutLink" = 0; then prefix=.nix-build-tmp-; fi
outPaths=$(@bindir@/nix-store \
--add-root ./${prefix}result --indirect \
-rv $extraArgs $storeExprs)
for j in $outPaths; do
echo "$(readlink "$j")"
done
exprs="$exprs $i"
;;
esac
done
if test -z "$exprs"; then
exprs="./default.nix"
fi
# Process the specified Nix expressions.
for i in $exprs; do
# Instantiate the Nix expression.
prefix=
if test "$addDrvLink" = 0; then prefix=.nix-build-tmp-; fi
storeExprs=$(@bindir@/nix-instantiate \
--add-root ./${prefix}derivation --indirect \
"$i")
for j in $storeExprs; do
echo "store expression is $(readlink "$j")" >&2
done
# Build the resulting store derivation.
prefix=
if test "$addOutLink" = 0; then prefix=.nix-build-tmp-; fi
outPaths=$(@bindir@/nix-store \
--add-root ./${prefix}result --indirect \
-rv $extraArgs $storeExprs)
for j in $outPaths; do
echo "$(readlink "$j")"
done
done

View File

@@ -1,2 +0,0 @@
# A list of URLs from where `nix-pull' obtain Nix archives if
# no URL is specified on the command line.

View File

@@ -1,6 +1,6 @@
noinst_LIBRARIES = libformat.a
lib_LTLIBRARIES = libformat.la
libformat_a_SOURCES = format_implementation.cc free_funcs.cc \
libformat_la_SOURCES = format_implementation.cc free_funcs.cc \
parsing.cc exceptions.hpp feed_args.hpp format_class.hpp \
format_fwd.hpp group.hpp internals.hpp internals_fwd.hpp \
macros_default.hpp

View File

@@ -1,6 +1,6 @@
noinst_LIBRARIES = libexpr.a
lib_LTLIBRARIES = libexpr.la
libexpr_a_SOURCES = nixexpr.cc nixexpr.hh parser.cc parser.hh \
libexpr_la_SOURCES = nixexpr.cc nixexpr.hh parser.cc parser.hh \
eval.cc eval.hh primops.cc \
lexer-tab.c lexer-tab.h parser-tab.c parser-tab.h \
nixexpr-ast.hh
@@ -33,3 +33,11 @@ nixexpr.cc nixexpr.hh: nixexpr-ast.hh
CLEANFILES =
# SDF stuff (not built by default).
nix.tbl: nix.sdf
sdf2table -m Nix -s -i nix.sdf -o nix.tbl
test.ast: test.nix nix.tbl
sglri -p nix.tbl -i test.nix -o test.ast

View File

@@ -140,6 +140,15 @@ bool evalBool(EvalState & state, Expr e)
}
ATermList evalList(EvalState & state, Expr e)
{
e = evalExpr(state, e);
ATermList list;
if (!matchList(e, list)) throw Error("list expected");
return list;
}
Expr evalExpr2(EvalState & state, Expr e)
{
Expr e1, e2, e3, e4;
@@ -336,6 +345,13 @@ Expr evalExpr2(EvalState & state, Expr e)
else throw Error("wrong argument types in `+' operator");
}
/* List concatenation. */
if (matchOpConcat(e, e1, e2)) {
ATermList l1 = evalList(state, e1);
ATermList l2 = evalList(state, e2);
return makeList(ATconcat(l1, l2));
}
/* Barf. */
throw badTerm("invalid expression", e);
}

View File

@@ -46,6 +46,7 @@ Expr evalFile(EvalState & state, const Path & path);
/* Specific results. */
string evalString(EvalState & state, Expr e);
Path evalPath(EvalState & state, Expr e);
ATermList evalList(EvalState & state, Expr e);
/* Print statistics. */
void printEvalStats(EvalState & state);

View File

@@ -59,6 +59,7 @@ inherit { return INHERIT; }
\|\| { return OR; }
\-\> { return IMPL; }
\/\/ { return UPDATE; }
\+\+ { return CONCAT; }
{ID} { yylval->t = ATmake("<str>", yytext); return ID; /* !!! alloc */ }
{INT} { int n = atoi(yytext); /* !!! overflow */

129
src/libexpr/nix.sdf Normal file
View File

@@ -0,0 +1,129 @@
definition
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Top level syntax.
module Nix
imports Nix-Exprs Nix-Layout
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Expressions.
module Nix-Exprs
imports Nix-Lexicals
exports
sorts Expr Formal Bind ExprList
context-free start-symbols Expr
context-free syntax
Id | Int | Str | Uri | Path -> Expr {cons("Var")}
"(" Expr ")" -> Expr {bracket}
Expr Expr -> Expr {cons("Call"), left}
Id ":" Expr -> Expr {cons("Function1")}
"{" {Formal ","}* "}" ":" Expr -> Expr {cons("Function")}
Id -> Formal {cons("NoDefFormal")}
Id "?" Expr -> Formal {cons("DefFormal")}
"assert" Expr ";" Expr -> Expr {cons("Assert")}
"with" Expr ";" Expr -> Expr {cons("With")}
"rec" "{" Bind* "}" -> Expr {cons("Rec")}
"let" "{" Bind* "}" -> Expr {cons("LetRec")}
"{" Bind* "}" -> Expr {cons("Attrs")}
Id "=" Expr ";" -> Bind {cons("Bind")}
"inherit" ("(" Expr ")")? Id* ";" -> Bind {cons("Inherit")}
"[" ExprList "]" -> Expr {cons("List")}
"" -> ExprList {cons("ExprNil")}
Expr ExprList -> ExprList {cons("ExprCons")}
Expr "." Id -> Expr {cons("Select")}
"if" Expr "then" Expr "else" Expr -> Expr {cons("If")}
Expr "==" Expr -> Expr {cons("OpEq"), non-assoc}
Expr "!=" Expr -> Expr {cons("OpNEq"), non-assoc}
"!" Expr -> Expr {cons("OpNot")}
Expr "&&" Expr -> Expr {cons("OpAnd"), right}
Expr "||" Expr -> Expr {cons("OpOr"), right}
Expr "->" Expr -> Expr {cons("OpImpl"), right}
Expr "//" Expr -> Expr {cons("OpUpdate"), right}
Expr "~" Expr -> Expr {cons("SubPath"), non-assoc}
Expr "?" Id -> Expr {cons("OpHasAttr")}
Expr "+" Expr -> Expr {cons("OpPlus"), left}
context-free priorities
Expr "." Id -> Expr
> Expr ExprList -> ExprList
> Expr Expr -> Expr
> Expr "~" Expr -> Expr
> Expr "?" Id -> Expr
> Expr "+" Expr -> Expr
> "!" Expr -> Expr
> Expr "//" Expr -> Expr
> Expr "==" Expr -> Expr
> Expr "!=" Expr -> Expr
> Expr "&&" Expr -> Expr
> Expr "||" Expr -> Expr
> Expr "->" Expr -> Expr
> "if" Expr "then" Expr "else" Expr -> Expr
> "assert" Expr ";" Expr -> Expr
> "with" Expr ";" Expr -> Expr
> Id ":" Expr -> Expr
> "{" {Formal ","}* "}" ":" Expr -> Expr
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Lexical syntax.
module Nix-Lexicals
exports
sorts Id Int Str Path Uri
lexical syntax
[a-zA-Z\_][a-zA-Z0-9\_\']* -> Id
"rec" | "let" | "if" | "then" | "else" | "assert" | "with" | "inherit" -> Id {reject}
[0-9]+ -> Int
"\"" ~[\n\"]* "\"" -> Str
[a-zA-Z0-9\.\_\-\+]* ("/"[a-zA-Z0-9\.\_\-\+]+)+ -> Path
[a-zA-Z] [a-zA-Z0-9\+\-\.]* ":" [a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\']* -> Uri
lexical restrictions
Id -/- [a-zA-Z0-9\_\']
Int -/- [0-9]
Path -/- [a-zA-Z0-9\.\_\-\+\/]
Uri -/- [a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\']
"rec" "let" "if" "then" "else" "assert" "with" "inherit" -/- [A-Za-z0-9\_\']
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Layout.
module Nix-Layout
exports
sorts HashComment Asterisk Comment
lexical syntax
[\ \t\n] -> LAYOUT
HashComment -> LAYOUT
Comment -> LAYOUT
"#" ~[\n]* -> HashComment
"/*" ( ~[\*] | Asterisk )* "*/" -> Comment
[\*] -> Asterisk
lexical restrictions
Asterisk -/- [\/]
HashComment -/- ~[\n]
context-free restrictions
LAYOUT? -/- [\ \t\n]

View File

@@ -18,6 +18,7 @@ OpUpdate | Expr Expr | Expr |
SubPath | Expr Expr | Expr |
OpHasAttr | Expr string | Expr |
OpPlus | Expr Expr | Expr |
OpConcat | Expr Expr | Expr |
Call | Expr Expr | Expr |
Select | Expr string | Expr |
Var | string | Expr |

View File

@@ -233,7 +233,12 @@ Expr substitute(const ATermMap & subs, Expr e)
if (matchVar(e, name)) {
Expr sub = subs.get(name);
return sub ? makeClosed(sub) : e;
Expr wrapped;
/* Add a "closed" wrapper around terms that aren't already
closed. The check is necessary to prevent repeated
wrapping, e.g., closed(closed(closed(...))), which kills
caching. */
return sub ? (matchClosed(sub, wrapped) ? sub : makeClosed(sub)) : e;
}
/* In case of a function, filter out all variables bound by this

View File

@@ -64,6 +64,7 @@ static Pos makeCurPos(YYLTYPE * loc, void * data)
%right UPDATE
%left NEG
%left '+'
%right CONCAT
%nonassoc '?'
%nonassoc '~'
@@ -102,6 +103,7 @@ expr_op
| expr_op '~' expr_op { $$ = makeSubPath($1, $3); }
| expr_op '?' ID { $$ = makeOpHasAttr($1, $3); }
| expr_op '+' expr_op { $$ = makeOpPlus($1, $3); }
| expr_op CONCAT expr_op { $$ = makeOpConcat($1, $3); }
| expr_app
;

View File

@@ -1,7 +1,8 @@
#include <algorithm>
#include "build.hh"
#include "eval.hh"
#include "globals.hh"
#include "misc.hh"
#include "nixexpr-ast.hh"
@@ -72,8 +73,8 @@ static Hash hashDerivationModulo(EvalState & state, Derivation drv)
{
return hashString(htSHA256, "fixed:out:"
+ i->second.hashAlgo + ":"
+ i->second.hash /* !!! + ":"
+ i->second.path */);
+ i->second.hash + ":"
+ i->second.path);
}
}
@@ -320,10 +321,8 @@ static Expr primDerivationStrict(EvalState & state, const ATermVector & args)
/* Use the masked derivation expression to compute the output
path. */
/* XXX */
Path outPath;
PathHash outPathHash;
makeStorePath(hashDerivationModulo(state, drv), drvName, outPath, outPathHash);
Path outPath = makeStorePath("output:out",
hashDerivationModulo(state, drv), drvName);
/* Construct the final derivation store expression. */
drv.env["out"] = outPath;
@@ -375,6 +374,14 @@ static Expr primBaseNameOf(EvalState & state, const ATermVector & args)
}
/* Return the directory of the given path, i.e., everything before the
last slash. */
static Expr primDirOf(EvalState & state, const ATermVector & args)
{
return makePath(toATerm(dirOf(evalPath(state, args[0]))));
}
/* Convert the argument (which can be a path or a uri) to a string. */
static Expr primToString(EvalState & state, const ATermVector & args)
{
@@ -413,21 +420,161 @@ static Expr primIsNull(EvalState & state, const ATermVector & args)
}
static Path findDependency(Path dir, string dep)
{
if (dep[0] == '/') throw Error(
format("illegal absolute dependency `%1%'") % dep);
Path p = canonPath(dir + "/" + dep);
if (pathExists(p))
return p;
else
return "";
}
/* Make path `p' relative to directory `pivot'. E.g.,
relativise("/a/b/c", "a/b/x/y") => "../x/y". Both input paths
should be in absolute canonical form. */
static string relativise(Path pivot, Path p)
{
assert(pivot.size() > 0 && pivot[0] == '/');
assert(p.size() > 0 && p[0] == '/');
if (pivot == p) return ".";
/* `p' is in `pivot'? */
Path pivot2 = pivot + "/";
if (p.substr(0, pivot2.size()) == pivot2) {
return p.substr(pivot2.size());
}
/* Otherwise, `p' is in a parent of `pivot'. Find up till which
path component `p' and `pivot' match, and add an appropriate
number of `..' components. */
unsigned int i = 1;
while (1) {
unsigned int j = pivot.find('/', i);
if (j == string::npos) break;
j++;
if (pivot.substr(0, j) != p.substr(0, j)) break;
i = j;
}
string prefix;
unsigned int slashes = count(pivot.begin() + i, pivot.end(), '/') + 1;
while (slashes--) {
prefix += "../";
}
return prefix + p.substr(i);
}
static Expr primDependencyClosure(EvalState & state, const ATermVector & args)
{
startNest(nest, lvlDebug, "finding dependencies");
Expr attrs = evalExpr(state, args[0]);
/* Get the start set. */
Expr startSet = queryAttr(attrs, "startSet");
if (!startSet) throw Error("attribute `startSet' required");
ATermList startSet2 = evalList(state, startSet);
Path pivot;
PathSet workSet;
for (ATermIterator i(startSet2); i; ++i) {
Path p = evalPath(state, *i);
workSet.insert(p);
pivot = dirOf(p);
}
/* Get the search path. */
PathSet searchPath;
Expr e = queryAttr(attrs, "searchPath");
if (e) {
ATermList list = evalList(state, e);
for (ATermIterator i(list); i; ++i) {
Path p = evalPath(state, *i);
searchPath.insert(p);
}
}
Expr scanner = queryAttr(attrs, "scanner");
if (!scanner) throw Error("attribute `scanner' required");
/* Construct the dependency closure by querying the dependency of
each path in `workSet', adding the dependencies to
`workSet'. */
PathSet doneSet;
while (!workSet.empty()) {
Path path = *(workSet.begin());
workSet.erase(path);
if (doneSet.find(path) != doneSet.end()) continue;
doneSet.insert(path);
try {
/* Call the `scanner' function with `path' as argument. */
debug(format("finding dependencies in `%1%'") % path);
ATermList deps = evalList(state, makeCall(scanner, makePath(toATerm(path))));
/* Try to find the dependencies relative to the `path'. */
for (ATermIterator i(deps); i; ++i) {
string s = evalString(state, *i);
Path dep = findDependency(dirOf(path), s);
if (dep == "") {
for (PathSet::iterator j = searchPath.begin();
j != searchPath.end(); ++j)
{
dep = findDependency(*j, s);
if (dep != "") break;
}
}
if (dep == "")
debug(format("did NOT find dependency `%1%'") % s);
else {
debug(format("found dependency `%1%'") % dep);
workSet.insert(dep);
}
}
} catch (Error & e) {
throw Error(format("while finding dependencies in `%1%':\n%2%")
% path % e.msg());
}
}
/* Return a list of the dependencies we've just found. */
ATermList deps = ATempty;
for (PathSet::iterator i = doneSet.begin(); i != doneSet.end(); ++i) {
deps = ATinsert(deps, makeStr(toATerm(relativise(pivot, *i))));
deps = ATinsert(deps, makePath(toATerm(*i)));
}
debug(format("dependency list is `%1%'") % makeList(deps));
return makeList(deps);
}
/* Apply a function to every element of a list. */
static Expr primMap(EvalState & state, const ATermVector & args)
{
Expr fun = evalExpr(state, args[0]);
Expr list = evalExpr(state, args[1]);
ATermList list = evalList(state, args[1]);
ATermList list2;
if (!matchList(list, list2))
throw Error("`map' expects a list as its second argument");
ATermList res = ATempty;
for (ATermIterator i(list); i; ++i)
res = ATinsert(res, makeCall(fun, *i));
ATermList list3 = ATempty;
for (ATermIterator i(list2); i; ++i)
list3 = ATinsert(list3, makeCall(fun, *i));
return makeList(ATreverse(list3));
return makeList(ATreverse(res));
}
@@ -452,9 +599,7 @@ static Expr primRemoveAttrs(EvalState & state, const ATermVector & args)
ATermMap attrs;
queryAllAttrs(evalExpr(state, args[0]), attrs, true);
ATermList list;
if (!matchList(evalExpr(state, args[1]), list))
throw Error("`removeAttrs' expects a list as its second argument");
ATermList list = evalList(state, args[1]);
for (ATermIterator i(list); i; ++i)
/* It's not an error for *i not to exist. */
@@ -464,6 +609,14 @@ static Expr primRemoveAttrs(EvalState & state, const ATermVector & args)
}
static Expr primRelativise(EvalState & state, const ATermVector & args)
{
Path pivot = evalPath(state, args[0]);
Path path = evalPath(state, args[1]);
return makeStr(toATerm(relativise(pivot, path)));
}
void EvalState::addPrimOps()
{
addPrimOp("true", 0, primTrue);
@@ -476,11 +629,12 @@ void EvalState::addPrimOps()
addPrimOp("derivation!", 1, primDerivationStrict);
addPrimOp("derivation", 1, primDerivationLazy);
addPrimOp("baseNameOf", 1, primBaseNameOf);
addPrimOp("dirOf", 1, primDirOf);
addPrimOp("toString", 1, primToString);
addPrimOp("isNull", 1, primIsNull);
addPrimOp("dependencyClosure", 1, primDependencyClosure);
addPrimOp("map", 2, primMap);
addPrimOp("removeAttrs", 2, primRemoveAttrs);
addPrimOp("relativise", 2, primRelativise);
}

View File

@@ -1,6 +1,6 @@
noinst_LIBRARIES = libmain.a
lib_LTLIBRARIES = libmain.la
libmain_a_SOURCES = shared.cc shared.hh
libmain_la_SOURCES = shared.cc shared.hh
AM_CXXFLAGS = \
-DNIX_STORE_DIR=\"$(storedir)\" \

View File

@@ -139,21 +139,6 @@ static void initAndRun(int argc, char * * argv)
/* ATerm stuff. !!! find a better place to put this */
initDerivationsHelpers();
/* Random number generator needed by makeRandomStorePath(); !!!
improve. */
srand(time(0));
/* Set the trust ID to the user name. */
currentTrustId = getEnv("NIX_USER_ID"); /* !!! dangerous? */
if (currentTrustId == "") {
SwitchToOriginalUser sw;
uid_t uid = geteuid();
struct passwd * pw = getpwuid(uid);
if (!pw) throw Error(format("unknown user ID %1%, go away") % uid);
currentTrustId = pw->pw_name;
}
printMsg(lvlError, format("trust ID is `%1%'") % currentTrustId);
/* Put the arguments in a vector. */
Strings args, remaining;

View File

@@ -1,8 +1,8 @@
noinst_LIBRARIES = libstore.a
lib_LTLIBRARIES = libstore.la
libstore_a_SOURCES = \
libstore_la_SOURCES = \
store.cc store.hh derivations.cc derivations.hh \
build.cc build.hh misc.cc misc.hh \
build.cc misc.cc build.hh \
globals.cc globals.hh db.cc db.hh \
references.cc references.hh pathlocks.cc pathlocks.hh \
gc.cc gc.hh derivations-ast.hh
@@ -15,4 +15,4 @@ AM_CXXFLAGS = -Wall \
derivations-ast.cc derivations-ast.hh: ../aterm-helper.pl derivations-ast.def
$(perl) ../aterm-helper.pl derivations-ast.hh derivations-ast.cc < derivations-ast.def
derivations.cc store.cc: derivations-ast.hh
derivations.cc store.cc: derivations-ast.hh

View File

@@ -14,7 +14,6 @@
#include "pathlocks.hh"
#include "globals.hh"
#include "gc.hh"
#include "misc.hh"
/* !!! TODO derivationFromPath shouldn't be used here */
@@ -315,16 +314,6 @@ private:
/* The remainder is state held during the build. */
/* The map of output equivalence classes to temporary output
paths. */
typedef map<OutputEqClass, Path> OutputMap;
OutputMap tmpOutputs;
/* The hash rewrite map that rewrites output equivalences occuring
in the command-line arguments and environment variables to the
actual paths to be used. */
HashRewrites rewrites;
/* Locks on the output paths. */
PathLocks outputLocks;
@@ -410,8 +399,7 @@ private:
void writeLog(int fd, const unsigned char * buf, size_t count);
/* Return the set of (in)valid paths. */
typedef set<OutputEqClass> OutputEqClasses;
OutputEqClasses checkOutputValidity(bool returnValid);
PathSet checkPathValidity(bool returnValid);
};
@@ -475,15 +463,12 @@ void DerivationGoal::haveStoreExpr()
/* Get the derivation. */
drv = derivationFromPath(drvPath);
#if 0
for (DerivationOutputs::iterator i = drv.outputs.begin();
i != drv.outputs.end(); ++i)
addTempRoot(i->second.path);
#endif
/* Check for what output path equivalence classes we do not
already have valid, trusted output paths. */
OutputEqClasses invalidOutputs = checkOutputValidity(false);
/* Check what outputs paths are not already valid. */
PathSet invalidOutputs = checkPathValidity(false);
/* If they are all valid, then we're done. */
if (invalidOutputs.size() == 0) {
@@ -491,7 +476,6 @@ void DerivationGoal::haveStoreExpr()
return;
}
#if 0
/* We are first going to try to create the invalid output paths
through substitutes. If that doesn't work, we'll build
them. */
@@ -501,7 +485,6 @@ void DerivationGoal::haveStoreExpr()
substitutes. */
if (querySubstitutes(noTxn, *i).size() > 0)
addWaitee(worker.makeSubstitutionGoal(*i));
#endif
if (waitees.empty()) /* to prevent hang (no wake-up event) */
outputsSubstituted();
@@ -519,7 +502,7 @@ void DerivationGoal::outputsSubstituted()
nrFailed = 0;
if (checkOutputValidity(false).size() == 0) {
if (checkPathValidity(false).size() == 0) {
amDone(true);
return;
}
@@ -664,7 +647,6 @@ void DerivationGoal::buildDone()
}
#if 0
static string readLine(int fd)
{
string s;
@@ -704,27 +686,33 @@ static void drain(int fd)
else writeFull(STDERR_FILENO, buffer, rd);
}
}
#endif
#if 0
PathSet outputPaths(const DerivationOutputs & outputs)
{
PathSet paths;
/* XXX */
for (DerivationOutputs::const_iterator i = outputs.begin();
i != outputs.end(); ++i)
paths.insert(i->second.path);
return paths;
}
#endif
string showPaths(const PathSet & paths)
{
string s;
for (PathSet::const_iterator i = paths.begin();
i != paths.end(); ++i)
{
if (s.size() != 0) s += ", ";
s += "`" + *i + "'";
}
return s;
}
DerivationGoal::HookReply DerivationGoal::tryBuildHook()
{
return rpDecline;
#if 0
Path buildHook = getEnv("NIX_BUILD_HOOK");
if (buildHook == "") return rpDecline;
buildHook = absPath(buildHook);
@@ -873,7 +861,6 @@ DerivationGoal::HookReply DerivationGoal::tryBuildHook()
}
else throw Error(format("bad hook reply `%1%'") % reply);
#endif
}
@@ -894,42 +881,11 @@ void DerivationGoal::terminateBuildHook()
bool DerivationGoal::prepareBuild()
{
/* We direct each output of the derivation to a temporary location
in the Nix store. Afterwards, we move the outputs to their
final, content-addressed location. */
for (DerivationOutputs::iterator i = drv.outputs.begin();
i != drv.outputs.end(); ++i)
{
Path tmpPath = makeRandomStorePath(namePartOf(i->second.eqClass));
printMsg(lvlError, format("mapping output id `%1%', class `%2%' to `%3%'")
% i->first % i->second.eqClass % tmpPath);
assert(i->second.eqClass.size() == tmpPath.size());
debug(format("building path `%1%'") % tmpPath);
tmpOutputs[i->second.eqClass] = tmpPath;
/* This is a referenceable path. Make a note of that for when
we are scanning for references in the output. */
allPaths.insert(tmpPath);
/* The environment variables and command-line arguments of the
builder refer to the output path equivalence class. Cause
those references to be rewritten to the temporary
locations. */
rewrites[hashPartOf(i->second.eqClass)] = hashPartOf(tmpPath);
}
/* Obtain locks on all output paths. The locks are automatically
released when we exit this function or Nix crashes. */
/* !!! BUG: this could block, which is not allowed. */
#if 0
/* !!! acquire lock on the derivation or something? or on a
pseudo-path representing the output equivalence class? */
outputLocks.lockPaths(outputPaths(drv.outputs));
#endif
#if 0
/* Now check again whether the outputs are valid. This is because
another process may have started building in parallel. After
it has finished and released the locks, we can (and should)
@@ -951,7 +907,17 @@ bool DerivationGoal::prepareBuild()
format("derivation `%1%' is blocked by its output paths")
% drvPath);
}
#endif
/* Gather information necessary for computing the closure and/or
running the build hook. */
/* The outputs are referenceable paths. */
for (DerivationOutputs::iterator i = drv.outputs.begin();
i != drv.outputs.end(); ++i)
{
debug(format("building path `%1%'") % i->second.path);
allPaths.insert(i->second.path);
}
/* Determine the full set of input paths. */
@@ -964,22 +930,14 @@ bool DerivationGoal::prepareBuild()
that are specified as inputs. */
assert(isValidPath(i->first));
Derivation inDrv = derivationFromPath(i->first);
for (StringSet::iterator j = i->second.begin();
j != i->second.end(); ++j)
{
OutputEqClass eqClass = findOutputEqClass(inDrv, *j);
PathSet inputs = findTrustedEqClassMembers(eqClass, currentTrustId);
if (inputs.size() == 0)
/* !!! shouldn't happen, except for garbage
collection? */
throw Error(format("output `%1%' of derivation `%2%' is missing!")
% *j % i->first);
for (PathSet::iterator k = inputs.begin(); k != inputs.end(); ++k) {
rewrites[hashPartOf(eqClass)] = hashPartOf(*k);
computeFSClosure(*k, inputPaths);
}
}
if (inDrv.outputs.find(*j) != inDrv.outputs.end())
computeFSClosure(inDrv.outputs[*j].path, inputPaths);
else
throw Error(
format("derivation `%1%' requires non-existent output `%2%' from input derivation `%3%'")
% drvPath % *j % i->first);
}
/* Second, the input sources. */
@@ -987,31 +945,7 @@ bool DerivationGoal::prepareBuild()
i != drv.inputSrcs.end(); ++i)
computeFSClosure(*i, inputPaths);
/* There might be equivalence class collisions now. That is,
different input closures might contain different paths from the
*same* output path equivalence class. We should pick one from
each, and rewrite dependent paths. */
Replacements replacements;
inputPaths = consolidatePaths(inputPaths, false, replacements);
HashRewrites rewrites2;
for (Replacements::iterator i = replacements.begin();
i != replacements.end(); ++i)
{
printMsg(lvlError, format("HASH REWRITE %1% %2%")
% hashPartOf(i->first).toString() % hashPartOf(i->second).toString());
rewrites2[hashPartOf(i->first)] = hashPartOf(i->second);
}
for (HashRewrites::iterator i = rewrites.begin();
i != rewrites.end(); ++i)
rewrites[i->first] = PathHash(rewriteHashes(i->second.toString(), rewrites2));
/* !!! remove, debug only */
Replacements dummy;
consolidatePaths(inputPaths, true, dummy);
printMsg(lvlError, format("added input paths %1%") % showPaths(inputPaths)); /* !!! */
debug(format("added input paths %1%") % showPaths(inputPaths));
allPaths.insert(inputPaths.begin(), inputPaths.end());
@@ -1022,7 +956,7 @@ bool DerivationGoal::prepareBuild()
void DerivationGoal::startBuilder()
{
startNest(nest, lvlInfo,
format("building derivation `%1%'") % drvPath)
format("building path(s) %1%") % showPaths(outputPaths(drv.outputs)))
/* Right platform? */
if (drv.platform != thisSystem)
@@ -1032,7 +966,6 @@ void DerivationGoal::startBuilder()
/* If any of the outputs already exist but are not registered,
delete them. */
#if 0
for (DerivationOutputs::iterator i = drv.outputs.begin();
i != drv.outputs.end(); ++i)
{
@@ -1044,7 +977,6 @@ void DerivationGoal::startBuilder()
deletePath(path);
}
}
#endif
/* Construct the environment passed to the builder. */
typedef map<string, string> Environment;
@@ -1072,7 +1004,7 @@ void DerivationGoal::startBuilder()
/* Add all bindings specified in the derivation. */
for (StringPairs::iterator i = drv.env.begin();
i != drv.env.end(); ++i)
env[i->first] = rewriteHashes(i->second, rewrites);
env[i->first] = i->second;
/* Create a temporary directory where the build will take
place. */
@@ -1095,8 +1027,8 @@ void DerivationGoal::startBuilder()
env["NIX_OUTPUT_CHECKED"] = "1";
/* Run the builder. */
string builder = rewriteHashes(drv.builder, rewrites);
printMsg(lvlChatty, format("executing builder `%1%'") % builder);
printMsg(lvlChatty, format("executing builder `%1%'") %
drv.builder);
/* Create the log file and pipe. */
openLogFile();
@@ -1122,22 +1054,22 @@ void DerivationGoal::startBuilder()
/* Fill in the arguments. */
Strings args(drv.args);
args.push_front(baseNameOf(builder));
args.push_front(baseNameOf(drv.builder));
const char * * argArr = strings2CharPtrs(args);
/* Fill in the environment. */
Strings envStrs;
for (Environment::const_iterator i = env.begin();
i != env.end(); ++i)
envStrs.push_back(i->first + "=" +
rewriteHashes(i->second, rewrites));
envStrs.push_back(i->first + "=" + i->second);
const char * * envArr = strings2CharPtrs(envStrs);
/* Execute the program. This should not return. */
execve(builder.c_str(),
execve(drv.builder.c_str(),
(char * *) argArr, (char * *) envArr);
throw SysError(format("executing `%1%'") % builder);
throw SysError(format("executing `%1%'")
% drv.builder);
} catch (exception & e) {
cerr << format("build error: %1%\n") % e.what();
@@ -1157,17 +1089,23 @@ void DerivationGoal::computeClosure()
{
map<Path, PathSet> allReferences;
map<Path, Hash> contentHashes;
/* Check whether the output paths were created, and grep each
output path to determine what other paths it references. Also make all
output paths read-only. */
for (DerivationOutputs::iterator i = drv.outputs.begin();
i != drv.outputs.end(); ++i)
{
Path path = tmpOutputs[i->second.eqClass];
Path path = i->second.path;
if (!pathExists(path)) {
throw BuildError(
format("builder for `%1%' failed to produce output path `%2%'")
% drvPath % path);
}
startNest(nest, lvlTalkative,
format("scanning for references inside `%1%'") % path);
/* Check that fixed-output derivations produced the right
outputs (i.e., the content hash should match the specified
hash). */
@@ -1205,51 +1143,62 @@ void DerivationGoal::computeClosure()
% path % algo % printHash(h) % printHash(h2));
}
/* For this output path, find the references to other paths
contained in it. */
PathSet referenced;
canonicalisePathMetaData(path);
/* For this output path, find the references to other paths contained
in it. */
PathSet references;
if (!pathExists(path + "/nix-support/no-scan")) {
Paths referenced2 = filterReferences(path,
Paths references2;
references2 = filterReferences(path,
Paths(allPaths.begin(), allPaths.end()));
referenced = PathSet(referenced2.begin(), referenced2.end());
references = PathSet(references2.begin(), references2.end());
/* For debugging, print out the referenced and
unreferenced paths. */
PathSet unreferenced;
insert_iterator<PathSet> ins(unreferenced, unreferenced.begin());
set_difference(
inputPaths.begin(), inputPaths.end(),
referenced.begin(), referenced.end(), ins);
printMsg(lvlError, format("unreferenced inputs: %1%") % showPaths(unreferenced));
printMsg(lvlError, format("referenced inputs: %1%") % showPaths(referenced));
for (PathSet::iterator i = inputPaths.begin();
i != inputPaths.end(); ++i)
{
PathSet::iterator j = references.find(*i);
if (j == references.end())
debug(format("unreferenced input: `%1%'") % *i);
else
debug(format("referenced input: `%1%'") % *i);
}
}
/* Rewrite each output to a name matching its content hash.
I.e., enforce the hash invariant: the hash part of a store
path matches the contents at that path.
allReferences[path] = references;
This also registers the final output path as valid, and
sets it references. */
Path finalPath = addToStore(path,
hashPartOf(path), namePartOf(path),
referenced);
printMsg(lvlError, format("produced final path `%1%'") % finalPath);
/* Register the fact that this output path is a member of some
output path equivalence class (for a certain user, at
least). This is how subsequent derivations will be able to
find it. */
Transaction txn;
createStoreTransaction(txn);
addOutputEqMember(txn, i->second.eqClass, currentTrustId, finalPath);
txn.commit();
/* Get rid of the temporary output. !!! optimise all this by
*moving* the temporary output to the new location and
applying rewrites in situ. */
deletePath(path);
/* Hash the contents of the path. The hash is stored in the
database so that we can verify later on whether nobody has
messed with the store. !!! inefficient: it would be nice
if we could combine this with filterReferences(). */
contentHashes[path] = hashPath(htSHA256, path);
}
/* Register each output path as valid, and register the sets of
paths referenced by each of them. This is wrapped in one
database transaction to ensure that if we crash, either
everything is registered or nothing is. This is for
recoverability: unregistered paths in the store can be deleted
arbitrarily, while registered paths can only be deleted by
running the garbage collector.
The reason that we do the transaction here and not on the fly
while we are scanning (above) is so that we don't hold database
locks for too long. */
Transaction txn;
createStoreTransaction(txn);
for (DerivationOutputs::iterator i = drv.outputs.begin();
i != drv.outputs.end(); ++i)
{
registerValidPath(txn, i->second.path,
contentHashes[i->second.path],
allReferences[i->second.path],
drvPath);
}
txn.commit();
/* It is now safe to delete the lock files, since all future
lockers will see that the output paths are valid; they will not
create new lock files with the same names as the old (unlinked)
@@ -1329,19 +1278,16 @@ void DerivationGoal::writeLog(int fd,
}
DerivationGoal::OutputEqClasses DerivationGoal::checkOutputValidity(bool returnValid)
PathSet DerivationGoal::checkPathValidity(bool returnValid)
{
OutputEqClasses result;
PathSet result;
for (DerivationOutputs::iterator i = drv.outputs.begin();
i != drv.outputs.end(); ++i)
{
PathSet paths = findTrustedEqClassMembers(i->second.eqClass, currentTrustId);
if (paths.size() > 0) {
if (returnValid) result.insert(i->second.eqClass);
if (isValidPath(i->second.path)) {
if (returnValid) result.insert(i->second.path);
} else {
if (!returnValid) result.insert(i->second.eqClass);
if (!returnValid) result.insert(i->second.path);
}
}
return result;
}
@@ -1356,13 +1302,11 @@ private:
/* The store path that should be realised through a substitute. */
Path storePath;
#if 0
/* The remaining substitutes for this path. */
Substitutes subs;
/* The current substitute. */
Substitute sub;
#endif
/* Outgoing references for this path. */
PathSet references;
@@ -1431,12 +1375,10 @@ void SubstitutionGoal::init()
return;
}
#if 0
/* Read the substitutes. */
subs = querySubstitutes(noTxn, storePath);
#endif
/* To maintain the closure invariant, we first have to realise the
/* To maintain the closure invairant, we first have to realise the
paths referenced by this one. */
queryReferences(noTxn, storePath, references);
@@ -1472,7 +1414,7 @@ void SubstitutionGoal::tryNext()
{
trace("trying next substitute");
if (true /* !!! subs.size() == 0 */) {
if (subs.size() == 0) {
/* None left. Terminate this goal and let someone else deal
with it. */
printMsg(lvlError,
@@ -1481,10 +1423,8 @@ void SubstitutionGoal::tryNext()
amDone(false);
return;
}
#if 0
sub = subs.front();
subs.pop_front();
#endif
/* Wait until we can run the substitute program. */
state = &SubstitutionGoal::tryToRun;
@@ -1494,7 +1434,6 @@ void SubstitutionGoal::tryNext()
void SubstitutionGoal::tryToRun()
{
#if 0
trace("trying to run");
/* Make sure that we are allowed to start a build. */
@@ -1566,13 +1505,11 @@ void SubstitutionGoal::tryToRun()
pid, logPipe.readSide, true);
state = &SubstitutionGoal::finished;
#endif
}
void SubstitutionGoal::finished()
{
#if 0
trace("substitute finished");
/* Since we got an EOF on the logger pipe, the substitute is
@@ -1629,7 +1566,6 @@ void SubstitutionGoal::finished()
format("substitution of path `%1%' succeeded") % storePath);
amDone();
#endif
}

View File

@@ -3,7 +3,6 @@
#include "derivations.hh"
/* Ensure that the output paths of the derivation are valid. If they
are already valid, this is a no-op. Otherwise, validity can
be reached in two ways. First, if the output paths have
@@ -12,10 +11,26 @@
sub-derivations. */
void buildDerivations(const PathSet & drvPaths);
/* Ensure that a path is valid. If it is not currently valid, it may
be made valid by running a substitute (if defined for the path). */
void ensurePath(const Path & storePath);
/* Read a derivation, after ensuring its existence through
ensurePath(). */
Derivation derivationFromPath(const Path & drvPath);
/* Place in `paths' the set of all store paths in the file system
closure of `storePath'; that is, all paths than can be directly or
indirectly reached from it. `paths' is not cleared. If
`flipDirection' is true, the set of paths that can reach
`storePath' is returned; that is, the closures under the `referers'
relation instead of the `references' relation is returned. */
void computeFSClosure(const Path & storePath,
PathSet & paths, bool flipDirection = false);
/* Return the path corresponding to the output identifier `id' in the
given derivation. */
Path findOutput(const Derivation & drv, string id);
#endif /* !__BUILD_H */

View File

@@ -62,12 +62,12 @@ Derivation parseDerivation(ATerm t)
throwBadDrv(t);
for (ATermIterator i(outs); i; ++i) {
ATerm id, eqClass, hashAlgo, hash;
if (!matchDerivationOutput(*i, id, eqClass, hashAlgo, hash))
ATerm id, path, hashAlgo, hash;
if (!matchDerivationOutput(*i, id, path, hashAlgo, hash))
throwBadDrv(t);
DerivationOutput out;
out.eqClass = aterm2String(eqClass);
// !!! checkPath(out.path);
out.path = aterm2String(path);
checkPath(out.path);
out.hashAlgo = aterm2String(hashAlgo);
out.hash = aterm2String(hash);
drv.outputs[aterm2String(id)] = out;
@@ -125,7 +125,7 @@ ATerm unparseDerivation(const Derivation & drv)
outputs = ATinsert(outputs,
makeDerivationOutput(
toATerm(i->first),
toATerm(i->second.eqClass),
toATerm(i->second.path),
toATerm(i->second.hashAlgo),
toATerm(i->second.hash)));

View File

@@ -13,15 +13,15 @@ const string drvExtension = ".drv";
struct DerivationOutput
{
OutputEqClass eqClass;
Path path;
string hashAlgo; /* hash used for expected hash computation */
string hash; /* expected hash, may be null */
DerivationOutput()
{
}
DerivationOutput(OutputEqClass eqClass, string hashAlgo, string hash)
DerivationOutput(Path path, string hashAlgo, string hash)
{
this->eqClass = eqClass;
this->path = path;
this->hashAlgo = hashAlgo;
this->hash = hash;
}

View File

@@ -2,7 +2,6 @@
#include "gc.hh"
#include "build.hh"
#include "pathlocks.hh"
#include "misc.hh"
#include <boost/shared_ptr.hpp>
@@ -339,14 +338,12 @@ void collectGarbage(GCAction action, PathSet & result)
for (PathSet::iterator i = livePaths.begin();
i != livePaths.end(); ++i)
{
#if 0
/* Note that the deriver need not be valid (e.g., if we
previously ran the collector with `gcKeepDerivations'
turned off). */
Path deriver = queryDeriver(noTxn, *i);
if (deriver != "" && isValidPath(deriver))
computeFSClosure(deriver, livePaths);
#endif
}
}
@@ -356,13 +353,10 @@ void collectGarbage(GCAction action, PathSet & result)
i != livePaths.end(); ++i)
if (isDerivation(*i)) {
Derivation drv = derivationFromPath(*i);
assert(0);
#if 0
for (DerivationOutputs::iterator j = drv.outputs.begin();
j != drv.outputs.end(); ++j)
if (isValidPath(j->second.path))
computeFSClosure(j->second.path, livePaths);
#endif
}
}

View File

@@ -22,8 +22,6 @@ unsigned int maxBuildJobs = 1;
bool readOnlyMode = false;
string currentTrustId;
static bool settingsRead = false;

View File

@@ -52,10 +52,6 @@ extern unsigned int maxBuildJobs;
database. */
extern bool readOnlyMode;
/* Current trust ID. !!! Of course, this shouldn't be a global
variable. */
extern string currentTrustId;
string querySetting(const string & name, const string & def);

View File

@@ -1,6 +1,4 @@
#include "build.hh"
#include "misc.hh"
#include "globals.hh"
Derivation derivationFromPath(const Path & drvPath)
@@ -31,224 +29,10 @@ void computeFSClosure(const Path & storePath,
}
OutputEqClass findOutputEqClass(const Derivation & drv, const string & id)
Path findOutput(const Derivation & drv, string id)
{
DerivationOutputs::const_iterator i = drv.outputs.find(id);
if (i == drv.outputs.end())
throw Error(format("derivation has no output `%1%'") % id);
return i->second.eqClass;
}
PathSet findTrustedEqClassMembers(const OutputEqClass & eqClass,
const TrustId & trustId)
{
OutputEqMembers members;
queryOutputEqMembers(noTxn, eqClass, members);
PathSet result;
for (OutputEqMembers::iterator j = members.begin(); j != members.end(); ++j)
if (j->trustId == trustId || j->trustId == "root") result.insert(j->path);
return result;
}
Path findTrustedEqClassMember(const OutputEqClass & eqClass,
const TrustId & trustId)
{
PathSet paths = findTrustedEqClassMembers(eqClass, trustId);
if (paths.size() == 0)
throw Error(format("no output path in equivalence class `%1%' is known") % eqClass);
return *(paths.begin());
}
typedef map<OutputEqClass, PathSet> ClassMap;
typedef map<OutputEqClass, Path> FinalClassMap;
static void findBestRewrite(const ClassMap::const_iterator & pos,
const ClassMap::const_iterator & end,
const PathSet & selection, const PathSet & unselection,
unsigned int & bestCost, PathSet & bestSelection)
{
if (pos != end) {
for (PathSet::iterator i = pos->second.begin();
i != pos->second.end(); ++i)
{
PathSet selection2(selection);
selection2.insert(*i);
PathSet unselection2(unselection);
for (PathSet::iterator j = pos->second.begin();
j != pos->second.end(); ++j)
if (i != j) unselection2.insert(*j);
ClassMap::const_iterator j = pos; ++j;
findBestRewrite(j, end, selection2, unselection2,
bestCost, bestSelection);
}
return;
}
PathSet badPaths;
for (PathSet::iterator i = selection.begin();
i != selection.end(); ++i)
{
PathSet closure;
computeFSClosure(*i, closure);
for (PathSet::iterator j = closure.begin();
j != closure.end(); ++j)
if (unselection.find(*j) != unselection.end())
badPaths.insert(*i);
}
// printMsg(lvlError, format("cost %1% %2%") % badPaths.size() % showPaths(badPaths));
if (badPaths.size() < bestCost) {
bestCost = badPaths.size();
bestSelection = selection;
}
}
static Path maybeRewrite(const Path & path, const PathSet & selection,
const FinalClassMap & finalClassMap, const PathSet & sources,
Replacements & replacements,
unsigned int & nrRewrites)
{
startNest(nest, lvlError, format("considering rewriting `%1%'") % path);
assert(selection.find(path) != selection.end());
if (replacements.find(path) != replacements.end()) return replacements[path];
PathSet references;
queryReferences(noTxn, path, references);
HashRewrites rewrites;
PathSet newReferences;
for (PathSet::iterator i = references.begin(); i != references.end(); ++i) {
if (*i == path || sources.find(*i) != sources.end()) {
newReferences.insert(*i);
continue; /* ignore self-references */
}
OutputEqClasses classes;
queryOutputEqClasses(noTxn, *i, classes);
assert(classes.size() > 0);
FinalClassMap::const_iterator j = finalClassMap.find(*(classes.begin()));
assert(j != finalClassMap.end());
Path newPath = maybeRewrite(j->second, selection,
finalClassMap, sources, replacements, nrRewrites);
if (*i != newPath)
rewrites[hashPartOf(*i)] = hashPartOf(newPath);
newReferences.insert(newPath);
}
if (rewrites.size() == 0) {
replacements[path] = path;
return path;
}
printMsg(lvlError, format("rewriting `%1%'") % path);
Path newPath = addToStore(path,
hashPartOf(path), namePartOf(path),
references, rewrites);
/* !!! we don't know which eqClass `path' is in! That is to say,
we don't know which one is intended here. */
OutputEqClasses classes;
queryOutputEqClasses(noTxn, path, classes);
for (PathSet::iterator i = classes.begin(); i != classes.end(); ++i) {
Transaction txn;
createStoreTransaction(txn);
addOutputEqMember(txn, *i, currentTrustId, newPath);
txn.commit();
}
nrRewrites++;
printMsg(lvlError, format("rewrote `%1%' to `%2%'") % path % newPath);
replacements[path] = newPath;
return newPath;
}
PathSet consolidatePaths(const PathSet & paths, bool checkOnly,
Replacements & replacements)
{
printMsg(lvlError, format("consolidating"));
ClassMap classMap;
PathSet sources;
for (PathSet::const_iterator i = paths.begin(); i != paths.end(); ++i) {
OutputEqClasses classes;
queryOutputEqClasses(noTxn, *i, classes);
if (classes.size() == 0)
sources.insert(*i);
else
for (OutputEqClasses::iterator j = classes.begin(); j != classes.end(); ++j)
classMap[*j].insert(*i);
}
printMsg(lvlError, format("found %1% sources %2%") % sources.size() % showPaths(sources));
bool conflict = false;
for (ClassMap::iterator i = classMap.begin(); i != classMap.end(); ++i)
if (i->second.size() >= 2) {
printMsg(lvlError, format("conflict in eq class `%1%'") % i->first);
conflict = true;
}
if (!conflict) return paths;
assert(!checkOnly);
/* !!! exponential-time algorithm! */
const unsigned int infinity = 1000000;
unsigned int bestCost = infinity;
PathSet bestSelection;
findBestRewrite(classMap.begin(), classMap.end(),
PathSet(), PathSet(), bestCost, bestSelection);
assert(bestCost != infinity);
printMsg(lvlError, format("cheapest selection %1% %2%")
% bestCost % showPaths(bestSelection));
FinalClassMap finalClassMap;
for (ClassMap::iterator i = classMap.begin(); i != classMap.end(); ++i)
for (PathSet::const_iterator j = i->second.begin(); j != i->second.end(); ++j)
if (bestSelection.find(*j) != bestSelection.end())
finalClassMap[i->first] = *j;
PathSet newPaths;
unsigned int nrRewrites = 0;
replacements.clear();
for (PathSet::iterator i = bestSelection.begin();
i != bestSelection.end(); ++i)
newPaths.insert(maybeRewrite(*i, bestSelection, finalClassMap,
sources, replacements, nrRewrites));
newPaths.insert(sources.begin(), sources.end());
assert(nrRewrites == bestCost);
assert(newPaths.size() < paths.size());
return newPaths;
for (DerivationOutputs::const_iterator i = drv.outputs.begin();
i != drv.outputs.end(); ++i)
if (i->first == id) return i->second.path;
throw Error(format("derivation has no output `%1%'") % id);
}

View File

@@ -1,47 +0,0 @@
#ifndef __MISC_H
#define __MISC_H
#include "derivations.hh"
#include "store.hh"
/* Read a derivation, after ensuring its existence through
ensurePath(). */
Derivation derivationFromPath(const Path & drvPath);
/* Place in `paths' the set of all store paths in the file system
closure of `storePath'; that is, all paths than can be directly or
indirectly reached from it. `paths' is not cleared. If
`flipDirection' is true, the set of paths that can reach
`storePath' is returned; that is, the closures under the `referers'
relation instead of the `references' relation is returned. */
void computeFSClosure(const Path & storePath,
PathSet & paths, bool flipDirection = false);
/* Return the output equivalence class denoted by `id' in the
derivation `drv'. */
OutputEqClass findOutputEqClass(const Derivation & drv,
const string & id);
/* Return anll trusted path (wrt to the given trust ID) in the given
output path equivalence class, or an empty set if no such paths
currently exist. */
PathSet findTrustedEqClassMembers(const OutputEqClass & eqClass,
const TrustId & trustId);
/* Like `findTrustedEqClassMembers', but returns an arbitrary trusted
path, or throws an exception if no such path currently exists. */
Path findTrustedEqClassMember(const OutputEqClass & eqClass,
const TrustId & trustId);
typedef map<Path, Path> Replacements;
PathSet consolidatePaths(const PathSet & paths, bool checkOnly,
Replacements & replacements);
#endif /* !__MISC_H */

View File

@@ -39,21 +39,6 @@ static TableId dbReferences = 0;
This table is just the reverse mapping of dbReferences. */
static TableId dbReferers = 0;
/* dbEquivalences :: OutputEqClass -> [(TrustId, Path)]
Lists the output paths that have been produced for each extension
class; i.e., the extension of an extension class. */
static TableId dbEquivalences = 0;
/* dbEquivalenceClasses :: Path -> [OutputEqClass]
!!! should be [(TrustId, OutputEqClass)] ?
Lists for each output path the extension classes that it is in. */
static TableId dbEquivalenceClasses = 0;
#if 0
/* dbSubstitutes :: Path -> [[Path]]
Each pair $(p, subs)$ tells Nix that it can use any of the
@@ -76,16 +61,13 @@ static TableId dbSubstitutes = 0;
only be multiple such paths for fixed-output derivations (i.e.,
derivations specifying an expected hash). */
static TableId dbDerivers = 0;
#endif
#if 0
bool Substitute::operator == (const Substitute & sub) const
{
return program == sub.program
&& args == sub.args;
}
#endif
static void upgradeStore();
@@ -105,12 +87,8 @@ void openDB()
dbValidPaths = nixDB.openTable("validpaths");
dbReferences = nixDB.openTable("references");
dbReferers = nixDB.openTable("referers");
#if 0
dbSubstitutes = nixDB.openTable("substitutes");
dbDerivers = nixDB.openTable("derivers");
#endif
dbEquivalences = nixDB.openTable("equivalences");
dbEquivalenceClasses = nixDB.openTable("equivalence-classes");
int curSchema = 0;
Path schemaFN = nixDBPath + "/schema";
@@ -143,60 +121,6 @@ void createStoreTransaction(Transaction & txn)
}
/* Path hashes. */
const unsigned int pathHashLen = 32; /* characters */
const string nullPathHashRef(pathHashLen, 0);
PathHash::PathHash()
{
rep = nullPathHashRef;
}
PathHash::PathHash(const Hash & h)
{
assert(h.type == htSHA256);
rep = printHash32(compressHash(h, 20));
}
PathHash::PathHash(const string & h)
{
/* !!! hacky; check whether this is a valid 160 bit hash */
assert(h.size() == pathHashLen);
parseHash32(htSHA1, h);
rep = h;
}
string PathHash::toString() const
{
return rep;
}
bool PathHash::isNull() const
{
return rep == nullPathHashRef;
}
bool PathHash::operator ==(const PathHash & hash2) const
{
return rep == hash2.rep;
}
bool PathHash::operator <(const PathHash & hash2) const
{
return rep < hash2.rep;
}
/* Path copying. */
struct CopySink : DumpSink
@@ -243,14 +167,12 @@ void copyPath(const Path & src, const Path & dst)
}
bool isInStore(const Path & path)
{
return path[0] == '/'
&& string(path, 0, nixStore.size()) == nixStore
&& path.size() >= nixStore.size() + 2
&& path[nixStore.size()] == '/'
&& path[nixStore.size() + 1 + pathHashLen] == '-';
&& path[nixStore.size()] == '/';
}
@@ -280,20 +202,6 @@ Path toStorePath(const Path & path)
}
PathHash hashPartOf(const Path & path)
{
assertStorePath(path);
return PathHash(string(path, nixStore.size() + 1, pathHashLen));
}
string namePartOf(const Path & path)
{
assertStorePath(path);
return string(path, nixStore.size() + 1 + pathHashLen + 1);
}
void checkStoreName(const string & name)
{
string validChars = "+-._?=";
@@ -367,16 +275,14 @@ bool isValidPath(const Path & path)
}
#if 0
static Substitutes readSubstitutes(const Transaction & txn,
const Path & srcPath);
#endif
static bool isRealisablePath(const Transaction & txn, const Path & path)
{
return isValidPathTxn(txn, path)
/* !!! || readSubstitutes(txn, path).size() > 0 */;
|| readSubstitutes(txn, path).size() > 0;
}
@@ -450,73 +356,6 @@ void queryReferers(const Transaction & txn,
}
void addOutputEqMember(const Transaction & txn,
const OutputEqClass & eqClass, const TrustId & trustId,
const Path & path)
{
OutputEqMembers members;
queryOutputEqMembers(txn, eqClass, members);
for (OutputEqMembers::iterator i = members.begin();
i != members.end(); ++i)
if (i->trustId == trustId && i->path == path) return;
OutputEqMember member;
member.trustId = trustId;
member.path = path;
members.push_back(member);
Strings ss;
for (OutputEqMembers::iterator i = members.begin();
i != members.end(); ++i)
{
Strings ss2;
ss2.push_back(i->trustId);
ss2.push_back(i->path);
ss.push_back(packStrings(ss2));
}
nixDB.setStrings(txn, dbEquivalences, eqClass, ss);
OutputEqClasses classes;
queryOutputEqClasses(txn, path, classes);
classes.insert(eqClass);
nixDB.setStrings(txn, dbEquivalenceClasses, path,
Strings(classes.begin(), classes.end()));
}
void queryOutputEqMembers(const Transaction & txn,
const OutputEqClass & eqClass, OutputEqMembers & members)
{
Strings ss;
nixDB.queryStrings(txn, dbEquivalences, eqClass, ss);
for (Strings::iterator i = ss.begin(); i != ss.end(); ++i) {
Strings ss2 = unpackStrings(*i);
if (ss2.size() != 2) continue;
Strings::iterator j = ss2.begin();
OutputEqMember member;
member.trustId = *j++;
member.path = *j++;
members.push_back(member);
}
}
void queryOutputEqClasses(const Transaction & txn,
const Path & path, OutputEqClasses & classes)
{
Strings ss;
nixDB.queryStrings(txn, dbEquivalenceClasses, path, ss);
classes.insert(ss.begin(), ss.end());
}
#if 0
void setDeriver(const Transaction & txn, const Path & storePath,
const Path & deriver)
{
@@ -539,10 +378,8 @@ Path queryDeriver(const Transaction & txn, const Path & storePath)
else
return "";
}
#endif
#if 0
const int substituteVersion = 2;
@@ -651,7 +488,6 @@ void clearSubstitutes()
txn.commit();
}
#endif
static void setHash(const Transaction & txn, const Path & storePath,
@@ -727,9 +563,7 @@ void registerValidPaths(const Transaction & txn,
throw Error(format("cannot register path `%1%' as valid, since its reference `%2%' is invalid")
% i->path % *j);
#if 0
setDeriver(txn, i->path, i->deriver);
#endif
}
}
@@ -744,39 +578,30 @@ static void invalidatePath(Transaction & txn, const Path & path)
inverse `referers' entries, and the `derivers' entry; but only
if there are no substitutes for this path. This maintains the
cleanup invariant. */
if (1 /*querySubstitutes(txn, path).size() == 0 !!! */) {
if (querySubstitutes(txn, path).size() == 0) {
setReferences(txn, path, PathSet());
// !!! nixDB.delPair(txn, dbDerivers, path);
nixDB.delPair(txn, dbDerivers, path);
}
nixDB.delPair(txn, dbValidPaths, path);
}
void makeStorePath(const Hash & contentHash, const string & suffix,
Path & path, PathHash & pathHash)
Path makeStorePath(const string & type,
const Hash & hash, const string & suffix)
{
/* e.g., "source:sha256:1abc...:/nix/store:foo.tar.gz" */
string s = type + ":sha256:" + printHash(hash) + ":"
+ nixStore + ":" + suffix;
checkStoreName(suffix);
/* e.g., "sha256:1abc...:foo.tar.gz" */
string s = "sha256:" + printHash(contentHash) + ":" + suffix;
pathHash = PathHash(hashString(htSHA256, s));
path = nixStore + "/" + pathHash.toString() + "-" + suffix;
return nixStore + "/"
+ printHash32(compressHash(hashString(htSHA256, s), 20))
+ "-" + suffix;
}
Path makeRandomStorePath(const string & suffix)
{
Hash hash(htSHA256);
for (unsigned int i = 0; i < hash.hashSize; ++i)
hash.hash[i] = rand() % 256; // !!! improve
return nixStore + "/" + PathHash(hash).toString() + "-" + suffix;
}
#if 0
Path makeFixedOutputPath(bool recursive,
string hashAlgo, Hash hash, string name)
{
@@ -787,99 +612,37 @@ Path makeFixedOutputPath(bool recursive,
+ "");
return makeStorePath("output:out", h, name);
}
#endif
typedef map<PathHash, PathHash> HashRewrites;
string rewriteHashes(string s, const HashRewrites & rewrites,
vector<int> & positions)
static Path _addToStore(bool fixed, bool recursive,
string hashAlgo, const Path & _srcPath)
{
for (HashRewrites::const_iterator i = rewrites.begin();
i != rewrites.end(); ++i)
Path srcPath(absPath(_srcPath));
debug(format("adding `%1%' to the store") % srcPath);
Hash h(htSHA256);
{
string from = i->first.toString(), to = i->second.toString();
assert(from.size() == to.size());
unsigned int j = 0;
while ((j = s.find(from, j)) != string::npos) {
debug(format("rewriting @ %1%") % j);
positions.push_back(j);
s.replace(j, to.size(), to);
j += to.size();
}
SwitchToOriginalUser sw;
h = hashPath(htSHA256, srcPath);
}
return s;
}
string baseName = baseNameOf(srcPath);
string rewriteHashes(const string & s, const HashRewrites & rewrites)
{
vector<int> dummy;
return rewriteHashes(s, rewrites, dummy);
}
static Hash hashModulo(string s, const PathHash & modulus)
{
vector<int> positions;
if (!modulus.isNull()) {
/* Zero out occurences of `modulus'. */
HashRewrites rewrites;
rewrites[modulus] = PathHash(); /* = null hash */
s = rewriteHashes(s, rewrites, positions);
}
string positionPrefix;
for (vector<int>::iterator i = positions.begin();
i != positions.end(); ++i)
positionPrefix += (format("|%1%") % *i).str();
positionPrefix += "||";
debug(format("positions %1%") % positionPrefix);
return hashString(htSHA256, positionPrefix + s);
}
static PathSet rewriteReferences(const PathSet & references,
const HashRewrites & rewrites)
{
PathSet result;
for (PathSet::const_iterator i = references.begin(); i != references.end(); ++i)
result.insert(rewriteHashes(*i, rewrites));
return result;
}
static Path _addToStore(const string & suffix, string dump,
const PathHash & selfHash, const PathSet & references)
{
/* Hash the contents, modulo the previous hash reference (if it
had one). */
Hash contentHash = hashModulo(dump, selfHash);
/* Construct the new store path. */
Path dstPath;
PathHash pathHash;
makeStorePath(contentHash, suffix, dstPath, pathHash);
if (fixed) {
/* If the contents had a previous hash reference, rewrite those
references to the new hash. */
HashRewrites rewrites;
if (!selfHash.isNull()) {
rewrites[selfHash] = pathHash;
vector<int> positions;
dump = rewriteHashes(dump, rewrites, positions);
/* !!! debug code, remove */
PathHash contentHash2 = hashModulo(dump, pathHash);
assert(contentHash2 == contentHash);
HashType ht(parseHashType(hashAlgo));
Hash h2(ht);
{
SwitchToOriginalUser sw;
h2 = recursive ? hashPath(ht, srcPath) : hashFile(ht, srcPath);
}
dstPath = makeFixedOutputPath(recursive, hashAlgo, h2, baseName);
}
else dstPath = makeStorePath("source", h, baseName);
if (!readOnlyMode) addTempRoot(dstPath);
@@ -896,18 +659,17 @@ static Path _addToStore(const string & suffix, string dump,
if (pathExists(dstPath)) deletePath(dstPath);
CopySource source(dump);
restorePath(dstPath, source);
copyPath(srcPath, dstPath);
Hash h2 = hashPath(htSHA256, dstPath);
if (h != h2)
throw Error(format("contents of `%1%' changed while copying it to `%2%' (%3% -> %4%)")
% srcPath % dstPath % printHash(h) % printHash(h2));
canonicalisePathMetaData(dstPath);
/* Set the references for the new path. Of course, any
hash rewrites have to be applied to the references,
too. */
PathSet references2 = rewriteReferences(references, rewrites);
Transaction txn(nixDB);
registerValidPath(txn, dstPath, contentHash, references2, "");
registerValidPath(txn, dstPath, h, PathSet(), "");
txn.commit();
}
@@ -918,41 +680,51 @@ static Path _addToStore(const string & suffix, string dump,
}
Path addToStore(const Path & _srcPath, const PathHash & selfHash,
const string & suffix, const PathSet & references, const HashRewrites & rewrites)
Path addToStore(const Path & srcPath)
{
Path srcPath(absPath(_srcPath));
debug(format("adding `%1%' to the store") % srcPath);
CopySink sink;
{
SwitchToOriginalUser sw;
dumpPath(srcPath, sink);
}
if (rewrites.size() != 0) sink.s = rewriteHashes(sink.s, rewrites);
return _addToStore(suffix == "" ? baseNameOf(srcPath) : suffix,
sink.s, selfHash,
rewriteReferences(references, rewrites));
return _addToStore(false, false, "", srcPath);
}
#if 0
Path addToStoreFixed(bool recursive, string hashAlgo, const Path & srcPath)
{
return _addToStore(true, recursive, hashAlgo, srcPath);
}
#endif
Path addTextToStore(const string & suffix, const string & s,
const PathSet & references)
{
CopySink sink;
makeSingletonArchive(s, sink);
Hash hash = hashString(htSHA256, s);
Path dstPath = makeStorePath("text", hash, suffix);
return _addToStore(suffix, sink.s, PathHash(), references);
if (!readOnlyMode) addTempRoot(dstPath);
if (!readOnlyMode && !isValidPath(dstPath)) {
PathSet lockPaths;
lockPaths.insert(dstPath);
PathLocks outputLock(lockPaths);
if (!isValidPath(dstPath)) {
if (pathExists(dstPath)) deletePath(dstPath);
writeStringToFile(dstPath, s);
canonicalisePathMetaData(dstPath);
Transaction txn(nixDB);
registerValidPath(txn, dstPath,
hashPath(htSHA256, dstPath), references, "");
txn.commit();
}
outputLock.setDeletion(true);
}
return dstPath;
}
@@ -979,7 +751,6 @@ void deleteFromStore(const Path & _path)
void verifyStore(bool checkContents)
{
#if 0
Transaction txn(nixDB);
Paths paths;
@@ -1120,7 +891,6 @@ void verifyStore(bool checkContents)
}
txn.commit();
#endif
}
@@ -1132,7 +902,6 @@ void verifyStore(bool checkContents)
static void upgradeStore()
{
printMsg(lvlError, "upgrading Nix store to new schema (this may take a while)...");
#if 0
Transaction txn(nixDB);
@@ -1213,5 +982,4 @@ static void upgradeStore()
/* !!! maybe this transaction is way too big */
txn.commit();
#endif
}

View File

@@ -12,27 +12,6 @@ using namespace std;
const int nixSchemaVersion = 2;
/* Path hashes are the hash components of store paths, e.g., the
`zvhgns772jpj68l40mq1jb74wpfsf0ma' in
`/nix/store/zvhgns772jpj68l40mq1jb74wpfsf0ma-glibc'. These are
truncated SHA-256 hashes of the path contents, */
struct PathHash
{
private:
string rep;
public:
PathHash();
PathHash(const Hash & h);
PathHash(const string & h);
string toString() const;
bool PathHash::isNull() const;
bool operator ==(const PathHash & hash2) const;
bool operator <(const PathHash & hash2) const;
};
#if 0
/* A substitute is a program invocation that constructs some store
path (typically by fetching it from somewhere, e.g., from the
network). */
@@ -53,39 +32,6 @@ struct Substitute
};
typedef list<Substitute> Substitutes;
#endif
/* A trust identifier, which is a name of an entity involved in a
trust relation. Right now this is just a user ID (e.g.,
`root'). */
typedef string TrustId;
/* An output path equivalence class. They represent outputs of
derivations. That is, a derivation can have several outputs (e.g.,
`out', `lib', `man', etc.), each of which maps to a output path
equivalence class. They can map to a number of concrete paths,
depending on what users built the derivation.
Equivalence classes are actually "placeholder" store paths that
never get built. They do occur in derivations however in
command-line arguments and environment variables, but get
substituted with concrete paths when we actually build. */
typedef Path OutputEqClass;
typedef set<OutputEqClass> OutputEqClasses;
/* A member of an output path equivalence class, i.e., a store path
that has been produced by a certain derivation. */
struct OutputEqMember
{
TrustId trustId;
Path path;
};
typedef list<OutputEqMember> OutputEqMembers;
/* Open the database environment. */
@@ -97,12 +43,9 @@ void initDB();
/* Get a transaction object. */
void createStoreTransaction(Transaction & txn);
/* Copy a path recursively. */
void copyPath(const Path & src, const Path & dst);
#if 0
/* Register a substitute. */
void registerSubstitute(const Transaction & txn,
const Path & srcPath, const Substitute & sub);
@@ -112,8 +55,6 @@ Substitutes querySubstitutes(const Transaction & txn, const Path & srcPath);
/* Deregister all substitutes. */
void clearSubstitutes();
#endif
/* Register the validity of a path, i.e., that `path' exists, that the
paths referenced by it exists, and in the case of an output path of
@@ -138,7 +79,6 @@ typedef list<ValidPathInfo> ValidPathInfos;
void registerValidPaths(const Transaction & txn,
const ValidPathInfos & infos);
/* Throw an exception if `path' is not directly in the Nix store. */
void assertStorePath(const Path & path);
@@ -151,11 +91,6 @@ void checkStoreName(const string & name);
/nix/store/abcd-foo/bar => /nix/store/abcd-foo. */
Path toStorePath(const Path & path);
PathHash hashPartOf(const Path & path);
string namePartOf(const Path & path);
/* "Fix", or canonicalise, the meta-data of the files in a store path
after it has been built. In particular:
- the last modification date on each file is set to 0 (i.e.,
@@ -170,7 +105,6 @@ void canonicalisePathMetaData(const Path & path);
bool isValidPathTxn(const Transaction & txn, const Path & path);
bool isValidPath(const Path & path);
/* Queries the hash of a valid path. */
Hash queryPathHash(const Path & path);
@@ -189,17 +123,6 @@ void queryReferences(const Transaction & txn,
void queryReferers(const Transaction & txn,
const Path & storePath, PathSet & referers);
void addOutputEqMember(const Transaction & txn,
const OutputEqClass & eqClass, const TrustId & trustId,
const Path & path);
void queryOutputEqMembers(const Transaction & txn,
const OutputEqClass & eqClass, OutputEqMembers & members);
void queryOutputEqClasses(const Transaction & txn,
const Path & path, OutputEqClasses & classes);
#if 0
/* Sets the deriver of a store path. Use with care! */
void setDeriver(const Transaction & txn, const Path & storePath,
const Path & deriver);
@@ -207,48 +130,27 @@ void setDeriver(const Transaction & txn, const Path & storePath,
/* Query the deriver of a store path. Return the empty string if no
deriver has been set. */
Path queryDeriver(const Transaction & txn, const Path & storePath);
#endif
/* Constructs a unique store path name. */
void makeStorePath(const Hash & contentHash, const string & suffix,
Path & path, PathHash & pathHash);
/* Constructs a random store path name. Only to be used for temporary
build outputs, since these will violate the hash invariant. */
Path makeRandomStorePath(const string & suffix);
/* Hash rewriting. */
typedef map<PathHash, PathHash> HashRewrites;
string rewriteHashes(string s, const HashRewrites & rewrites,
vector<int> & positions);
string rewriteHashes(const string & s, const HashRewrites & rewrites);
Path makeStorePath(const string & type,
const Hash & hash, const string & suffix);
/* Copy the contents of a path to the store and register the validity
the resulting path. The resulting path is returned. */
Path addToStore(const Path & srcPath, const PathHash & selfHash = PathHash(),
const string & suffix = "", const PathSet & references = PathSet(),
const HashRewrites & rewrites = HashRewrites());
Path addToStore(const Path & srcPath);
#if 0
/* Like addToStore(), but for pre-adding the outputs of fixed-output
derivations. */
Path addToStoreFixed(bool recursive, string hashAlgo, const Path & srcPath);
Path makeFixedOutputPath(bool recursive,
string hashAlgo, Hash hash, string name);
#endif
/* Like addToStore, but the contents written to the output path is a
regular file containing the given string. */
Path addTextToStore(const string & suffix, const string & s,
const PathSet & references);
/* Delete a value from the nixStore directory. */
void deleteFromStore(const Path & path);

3
src/libstore/test-builder-1.sh Executable file
View File

@@ -0,0 +1,3 @@
#! /bin/sh
echo "Hello World" > $out

View File

@@ -1,6 +1,6 @@
noinst_LIBRARIES = libutil.a
lib_LTLIBRARIES = libutil.la
libutil_a_SOURCES = util.cc util.hh hash.cc hash.hh \
libutil_la_SOURCES = util.cc util.hh hash.cc hash.hh \
archive.cc archive.hh aterm.cc aterm.hh \
md5.c md5.h sha1.c sha1.h sha256.c sha256.h md32_common.h

View File

@@ -140,26 +140,6 @@ void dumpPath(const Path & path, DumpSink & sink)
}
void makeSingletonArchive(const string & contents, DumpSink & sink)
{
/* !!! hacky; have to keep this synchronised with dumpPath(). It
would be better to parameterise dumpPath() with a file system
"traverser". */
writeString(archiveVersion1, sink);
writeString("(", sink);
writeString("type", sink);
writeString("regular", sink);
unsigned int size = contents.size();
writeString("contents", sink);
writeInt(size, sink);
sink((const unsigned char *) contents.c_str(), size);
writePadding(size, sink);
writeString(")", sink);
}
static Error badArchive(string s)
{
return Error("bad archive: " + s);

View File

@@ -48,10 +48,6 @@ struct DumpSink
void dumpPath(const Path & path, DumpSink & sink);
/* Make an archive consisting of a single non-executable regular
file, with specified string contents. */
void makeSingletonArchive(const string & contents, DumpSink & sink);
struct RestoreSource
{

View File

@@ -357,19 +357,6 @@ void printMsg_(Verbosity level, const format & f)
}
string showPaths(const PathSet & paths)
{
string s;
for (PathSet::const_iterator i = paths.begin();
i != paths.end(); ++i)
{
if (s.size() != 0) s += ", ";
s += "`" + *i + "'";
}
return s;
}
void readFull(int fd, unsigned char * buf, size_t count)
{
while (count) {

View File

@@ -173,8 +173,6 @@ void printMsg_(Verbosity level, const format & f);
#define debug(f) printMsg(lvlDebug, f)
string showPaths(const PathSet & paths);
/* Wrappers arount read()/write() that read/write exactly the
requested number of bytes. */

View File

@@ -23,12 +23,14 @@
</html>
</xsl:template>
<xsl:template match="nest">
<!-- The tree should be collapsed by default if all children are
unimportant or if the header is unimportant. -->
<xsl:variable name="collapsed"
select="count(.//line[not(@priority = 3)]) = 0 or ./head[@priority = 3]" />
<!-- <xsl:variable name="collapsed"
select="count(.//line[not(@priority = 3)]) = 0 or ./head[@priority = 3]" /> -->
<xsl:variable name="collapsed" select="count(.//*[@error]) = 0"/>
<xsl:variable name="style"><xsl:if test="$collapsed">display: none;</xsl:if></xsl:variable>
<xsl:variable name="arg"><xsl:choose><xsl:when test="$collapsed">true</xsl:when><xsl:otherwise>false</xsl:otherwise></xsl:choose></xsl:variable>
@@ -52,13 +54,18 @@
</xsl:for-each>
</ul>
</xsl:template>
<xsl:template match="head|line">
<code>
<xsl:if test="@error">
<xsl:attribute name="class">error</xsl:attribute>
</xsl:if>
<xsl:apply-templates/>
</code>
</xsl:template>
<xsl:template match="storeref">
<em class='storeref'>
<span class='popup'><xsl:apply-templates/></span>

View File

@@ -117,10 +117,11 @@ void Decoder::finishLine()
if (priority != 1) cout << " priority='" << priority << "'";
cout << ">";
for (int i = 0; i < line.size(); i++) {
for (unsigned int i = 0; i < line.size(); i++) {
if (line[i] == '<') cout << "&lt;";
else if (line[i] == '&') cout << "&amp;";
else if (line[i] < 32 && line[i] != 9) cout << "&#xfffd;";
else if (i + sz + 33 < line.size() &&
string(line, i, sz) == storeDir &&
line[i + sz + 32] == '-')

View File

@@ -78,4 +78,9 @@ em.storeref:hover span.popup {
.showTree, .hideTree {
font-family: monospace;
font-size: larger;
}
.error {
color: #ff0000;
font-weight: bold;
}

View File

@@ -0,0 +1,24 @@
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="line">
<line>
<xsl:if test="contains(text(), ' *** ') or
contains(text(), 'LaTeX Error') or
contains(text(), 'FAIL:') or
contains(text(), ' error: ') or
true">
<xsl:attribute name="error"></xsl:attribute>
</xsl:if>
<xsl:apply-templates select="@*|node()"/>
</line>
</xsl:template>
</xsl:stylesheet>

View File

@@ -2,9 +2,9 @@ bin_PROGRAMS = nix-env
nix_env_SOURCES = main.cc names.cc names.hh \
profiles.cc profiles.hh help.txt
nix_env_LDADD = ../libmain/libmain.a ../libexpr/libexpr.a \
../libstore/libstore.a ../libutil/libutil.a \
../boost/format/libformat.a ${bdb_lib} ${aterm_lib}
nix_env_LDADD = ../libmain/libmain.la ../libexpr/libexpr.la \
../libstore/libstore.la ../libutil/libutil.la \
../boost/format/libformat.la ${bdb_lib} ${aterm_lib}
main.o: help.txt.hh

View File

@@ -3,7 +3,6 @@
#include "globals.hh"
#include "build.hh"
#include "gc.hh"
#include "misc.hh"
#include "shared.hh"
#include "parser.hh"
#include "eval.hh"
@@ -384,6 +383,7 @@ static void queryInstSources(EvalState & state,
(import ./foo.nix)' = `(import ./foo.nix).bar'. */
case srcNixExprs: {
Expr e1 = parseExprFromFile(state,
absPath(instSource.nixExprPath));
@@ -416,10 +416,7 @@ static void queryInstSources(EvalState & state,
if (isDerivation(*i)) {
elem.setDrvPath(*i);
elem.setOutPath(
/* XXX check this; may not give a result */
findTrustedEqClassMember(
findOutputEqClass(derivationFromPath(*i), "out"), currentTrustId));
elem.setOutPath(findOutput(derivationFromPath(*i), "out"));
if (name.size() >= drvExtension.size() &&
string(name, name.size() - drvExtension.size()) == drvExtension)
name = string(name, 0, name.size() - drvExtension.size());
@@ -587,23 +584,27 @@ static void uninstallDerivations(Globals & globals, DrvNames & selectors,
Path & profile)
{
UserEnvElems installedElems = queryInstalled(globals.state, profile);
UserEnvElems newElems;
for (UserEnvElems::iterator i = installedElems.begin();
i != installedElems.end(); ++i)
{
DrvName drvName(i->second.name);
bool found = false;
for (DrvNames::iterator j = selectors.begin();
j != selectors.end(); ++j)
if (j->matches(drvName)) {
printMsg(lvlInfo,
format("uninstalling `%1%'") % i->second.name);
installedElems.erase(i);
found = true;
break;
}
if (!found) newElems.insert(*i);
}
if (globals.dryRun) return;
createUserEnv(globals.state, installedElems,
createUserEnv(globals.state, newElems,
profile, globals.keepDerivations);
}
@@ -738,14 +739,12 @@ static void opQuery(Globals & globals,
Strings columns;
if (printStatus) {
#if 0
Substitutes subs = querySubstitutes(noTxn, i->queryDrvPath(globals.state));
#endif
columns.push_back(
(string) (installed.find(i->queryOutPath(globals.state))
!= installed.end() ? "I" : "-")
+ (isValidPath(i->queryOutPath(globals.state)) ? "P" : "-")
+ (/* XXX subs.size() > 0 */ false ? "S" : "-"));
+ (subs.size() > 0 ? "S" : "-"));
}
if (printName) columns.push_back(i->name);

View File

@@ -1,8 +1,8 @@
bin_PROGRAMS = nix-hash
nix_hash_SOURCES = nix-hash.cc help.txt
nix_hash_LDADD = ../libmain/libmain.a ../libstore/libstore.a ../libutil/libutil.a \
../boost/format/libformat.a ${bdb_lib} ${aterm_lib}
nix_hash_LDADD = ../libmain/libmain.la ../libstore/libstore.la ../libutil/libutil.la \
../boost/format/libformat.la ${bdb_lib} ${aterm_lib}
nix-hash.o: help.txt.hh

View File

@@ -6,3 +6,4 @@ files.
--flat: compute hash of regular file contents, not metadata
--base32: print hash in base-32 instead of hexadecimal
--type HASH: use hash algorithm HASH ("md5" (default), "sha1", "sha256")
--truncate: truncate the hash to 160 bits

View File

@@ -16,12 +16,14 @@ void run(Strings args)
HashType ht = htMD5;
bool flat = false;
bool base32 = false;
bool truncate = false;
for (Strings::iterator i = args.begin();
i != args.end(); i++)
{
if (*i == "--flat") flat = true;
else if (*i == "--base32") base32 = true;
else if (*i == "--truncate") truncate = true;
else if (*i == "--type") {
++i;
if (i == args.end()) throw UsageError("`--type' requires an argument");
@@ -31,6 +33,7 @@ void run(Strings args)
}
else {
Hash h = flat ? hashFile(ht, *i) : hashPath(ht, *i);
if (truncate && h.hashSize > 20) h = compressHash(h, 20);
cout << format("%1%\n") %
(base32 ? printHash32(h) : printHash(h));
}

View File

@@ -1,9 +1,9 @@
bin_PROGRAMS = nix-instantiate
nix_instantiate_SOURCES = main.cc help.txt
nix_instantiate_LDADD = ../libmain/libmain.a ../libexpr/libexpr.a \
../libstore/libstore.a ../libutil/libutil.a \
../boost/format/libformat.a ${bdb_lib} ${aterm_lib}
nix_instantiate_LDADD = ../libmain/libmain.la ../libexpr/libexpr.la \
../libstore/libstore.la ../libutil/libutil.la \
../boost/format/libformat.la ${bdb_lib} ${aterm_lib}
main.o: help.txt.hh

View File

@@ -73,6 +73,23 @@ static void printDrvPaths(EvalState & state, Expr e)
return;
}
ATermList formals;
ATerm body, pos;
if (matchFunction(e, formals, body, pos)) {
for (ATermIterator i(formals); i; ++i) {
Expr name, def;
if (matchNoDefFormal(*i, name))
throw Error(format("expression evaluates to a function with no-default arguments (`%1%')")
% aterm2String(name));
else if (!matchDefFormal(*i, name, def))
abort(); /* can't happen */
}
printDrvPaths(state, evalExpr(state,
makeCall(e, makeAttrs(ATermMap()))));
return;
}
throw Error("expression does not evaluate to one or more derivations");
}

View File

@@ -1,8 +1,8 @@
bin_PROGRAMS = nix-store
nix_store_SOURCES = main.cc dotgraph.cc dotgraph.hh help.txt
nix_store_LDADD = ../libmain/libmain.a ../libstore/libstore.a ../libutil/libutil.a \
../boost/format/libformat.a ${bdb_lib} ${aterm_lib}
nix_store_LDADD = ../libmain/libmain.la ../libstore/libstore.la ../libutil/libutil.la \
../boost/format/libformat.la ${bdb_lib} ${aterm_lib}
main.o: help.txt.hh

View File

@@ -4,7 +4,6 @@
#include "globals.hh"
#include "build.hh"
#include "gc.hh"
#include "misc.hh"
#include "archive.hh"
#include "shared.hh"
#include "dotgraph.hh"
@@ -46,8 +45,7 @@ static Path realisePath(const Path & path)
PathSet paths;
paths.insert(path);
buildDerivations(paths);
Path outPath = findTrustedEqClassMember(
findOutputEqClass(derivationFromPath(path), "out"), currentTrustId);
Path outPath = findOutput(derivationFromPath(path), "out");
if (gcRoot == "")
printGCWarning();
@@ -98,7 +96,6 @@ static void opAdd(Strings opFlags, Strings opArgs)
}
#if 0
/* Preload the output of a fixed-output derivation into the Nix
store. */
static void opAddFixed(Strings opFlags, Strings opArgs)
@@ -144,7 +141,6 @@ static void opPrintFixedPath(Strings opFlags, Strings opArgs)
cout << format("%1%\n") %
makeFixedOutputPath(recursive, hashAlgo, h, name);
}
#endif
/* Place in `paths' the set of paths that are required to `realise'
@@ -169,8 +165,6 @@ static void storePathRequisites(const Path & storePath,
computeFSClosure(storePath, paths);
if (includeOutputs) {
assert(0);
#if 0
for (PathSet::iterator i = paths.begin();
i != paths.end(); ++i)
if (isDerivation(*i)) {
@@ -180,7 +174,6 @@ static void storePathRequisites(const Path & storePath,
if (isValidPath(j->second.path))
computeFSClosure(j->second.path, paths);
}
#endif
}
}
@@ -190,8 +183,7 @@ static Path maybeUseOutput(const Path & storePath, bool useOutput, bool forceRea
if (forceRealise) realisePath(storePath);
if (useOutput && isDerivation(storePath)) {
Derivation drv = derivationFromPath(storePath);
return findTrustedEqClassMember(
findOutputEqClass(drv, "out"), currentTrustId);
return findOutput(drv, "out");
}
else return storePath;
}
@@ -321,9 +313,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
*i = fixPath(*i);
if (forceRealise) realisePath(*i);
Derivation drv = derivationFromPath(*i);
cout << format("%1%\n") % findTrustedEqClassMember(
findOutputEqClass(drv, "out"),
currentTrustId);
cout << format("%1%\n") % findOutput(drv, "out");
}
break;
}
@@ -348,7 +338,6 @@ static void opQuery(Strings opFlags, Strings opArgs)
}
case qDeriver:
#if 0
for (Strings::iterator i = opArgs.begin();
i != opArgs.end(); ++i)
{
@@ -356,8 +345,6 @@ static void opQuery(Strings opFlags, Strings opArgs)
cout << format("%1%\n") %
(deriver == "" ? "unknown-deriver" : deriver);
}
#endif
assert(0);
break;
case qBinding:
@@ -408,7 +395,6 @@ static void opQuery(Strings opFlags, Strings opArgs)
}
#if 0
static void opRegisterSubstitutes(Strings opFlags, Strings opArgs)
{
if (!opFlags.empty()) throw UsageError("unknown flag");
@@ -455,7 +441,6 @@ static void opClearSubstitutes(Strings opFlags, Strings opArgs)
clearSubstitutes();
}
#endif
static void opRegisterValidity(Strings opFlags, Strings opArgs)
@@ -617,20 +602,16 @@ void run(Strings args)
op = opRealise;
else if (arg == "--add" || arg == "-A")
op = opAdd;
#if 0
else if (arg == "--add-fixed")
op = opAddFixed;
else if (arg == "--print-fixed-path")
op = opPrintFixedPath;
#endif
else if (arg == "--query" || arg == "-q")
op = opQuery;
#if 0
else if (arg == "--register-substitutes")
op = opRegisterSubstitutes;
else if (arg == "--clear-substitutes")
op = opClearSubstitutes;
#endif
else if (arg == "--register-validity")
op = opRegisterValidity;
else if (arg == "--check-validity")

View File

@@ -40,7 +40,6 @@ gc-concurrent.sh: gc-concurrent.nix gc-concurrent2.nix
TESTS = init.sh hash.sh lang.sh simple.sh dependencies.sh locking.sh parallel.sh \
build-hook.sh substitutes.sh substitutes2.sh fallback.sh nix-push.sh gc.sh \
gc-concurrent.sh verify.sh nix-pull.sh
#TESTS = init.sh gc.sh
XFAIL_TESTS =

View File

@@ -56,6 +56,11 @@ for i in \
chmod +x $i
done
# Another ugly hack.
sed "s|^$|PATH=$PATH|" < $NIX_DATA_DIR/nix/corepkgs/nar/nar.sh > tmp
chmod +x tmp
mv tmp $NIX_DATA_DIR/nix/corepkgs/nar/nar.sh
# Initialise the database.
$TOP/src/nix-store/nix-store --init

View File

@@ -0,0 +1 @@
List([Int(1),Int(2),Int(3),Int(4),Int(5),Int(6),Int(7),Int(8),Int(9)])

View File

@@ -0,0 +1 @@
[1 2 3] ++ [4 5 6] ++ [7 8 9]