Compare commits

..
55 Commits
Author SHA1 Message Date
Eelco Dolstra 71a5161365 Implement buildDerivation() via the daemon 2015-09-03 12:56:59 +02:00
Eelco Dolstra 6e06a18d1b Release notes 2015-09-03 11:57:47 +02:00
Eelco Dolstra 73332fd342 Filter build-chroot-dirs entries that conflict with derivation outputs
Fixes https://github.com/NixOS/nixpkgs/issues/9504.

Note that this means we may have a non-functional /bin/sh in the
chroot while rebuilding Bash or one of its dependencies. Ideally those
packages don't rely on /bin/sh though.
2015-09-02 14:54:12 +02:00
Eelco Dolstra d711fe8f5e Remove unused variable 2015-09-02 14:46:04 +02:00
Eelco Dolstra ce97523a7c Fix readDir example
Fixes https://github.com/NixOS/nixos-homepage/issues/46.
2015-09-01 16:53:51 +02:00
Eelco Dolstra e12cf82782 Prevent .chroot from being GC'ed when using LocalStore::buildDerivation()
Fixes #616.
2015-08-24 11:13:31 +02:00
Eelco Dolstra eadb86f447 nix-collect-garbage: Revive --max-freed
Fixes #609.
2015-08-21 13:57:53 +02:00
Eelco Dolstra 1d29db2a9f Merge pull request #608 from Phant0mas/master
Remove unneeded HAVE_UNSHARE.
2015-08-19 13:35:23 +02:00
Manolis Ragkousis 26221e44eb Remove unneeded HAVE_UNSHARE.
* src/libstore/build.cc (CHROOT_ENABLED): Remove HAVE_UNSHARE.
2015-08-19 14:11:15 +03:00
Eelco Dolstra 984c5cdc50 Drop newline in error message 2015-08-07 05:32:17 +02:00
Kirill ElaginandEelco Dolstra 3b0f60e5c2 baseNameOf: Enhance basename compatibility
* If the path ends with a slash, drop it.
* If the remaining path doesn’t contain slashes, just return it.

Fixes #574.
2015-08-07 03:35:02 +02:00
Eelco Dolstra 896428c818 Fix example 2015-08-05 17:36:33 +02:00
Eelco Dolstra 34dfbd9394 Don't include <iostream> before config.h
This breaks the build on 32-bit systems.

http://hydra.nixos.org/build/24373658
2015-08-04 11:12:31 +02:00
Eelco Dolstra 30d19a2bdc Handle debug messages from runChild()
Turns out that "nix-build -vvv" with chroots enabled has been broken
for some time, because some debug message got interpreted as an error.
2015-08-03 18:04:32 +02:00
Iwan AucampandEelco Dolstra 3db950aab7 Removed unnecessary included 2015-08-03 11:48:34 +02:00
Eelco Dolstra 2bac04c5ff Fix stack consumption 2015-07-31 20:28:25 +02:00
Iwan AucampandEelco Dolstra 75837651f1 Output line number on infinite recursion 2015-07-31 20:26:44 +02:00
Eelco Dolstra 76cc8e97a2 Add sort primop 2015-07-28 18:39:39 +02:00
Eelco Dolstra 50807f3dd5 Add primop genList
This can be used to implement functions like ‘imap’ (or for that
matter, ‘map’) without the quadratic complexity incurred by calling
‘++’ repeatedly.
2015-07-28 17:28:35 +02:00
Eelco Dolstra f3dda728a4 Remove unnecessary parentheses 2015-07-26 12:07:14 +02:00
Eelco Dolstra d6d5885c15 Add replaceStrings primop
This is a generalisation of replaceChars in Nixpkgs.
2015-07-24 15:32:24 +02:00
Eelco Dolstra 2e8fd4c5cd Add concatStringsSep as a primop
This fixes the quadratic behaviour of concatStrings/concatStringsSep
in Nixpkgs.
2015-07-24 02:38:09 +02:00
Eelco Dolstra cb4320c1a0 Cleanup 2015-07-23 23:14:07 +02:00
Eelco Dolstra c8bb2371eb Optimize empty sets
This reduces the number of Bindings allocations by about 10%.
2015-07-23 23:11:08 +02:00
Eelco Dolstra 16c9935fa9 Fix fetchurl of executable file
Pointed out by @cstrahan, thanks!
2015-07-23 22:25:04 +02:00
Eelco Dolstra 19eddecc0f Merge branch 'attr-set-hh' of https://github.com/nbp/nix
Conflicts:
	src/libexpr/eval.cc
2015-07-23 22:16:01 +02:00
Eelco Dolstra b83801f8b3 Optimize small lists
The value pointers of lists with 1 or 2 elements are now stored in the
list value itself. In particular, this makes the "concatMap (x: if
cond then [(f x)] else [])" idiom cheaper.
2015-07-23 22:05:09 +02:00
Eelco Dolstra 14be783676 Add primops all and any
These are used thousands of times during NixOS evaluation, so it's
useful to speed them up.
2015-07-23 19:23:11 +02:00
Shea LevyandEelco Dolstra 39e27a04b8 Importing derivations: Add name attribute to make a valid drv 2015-07-23 17:04:07 +02:00
Shea LevyandEelco Dolstra 1ed55234d9 Allow derivations-as-srcs in the context of builtins.toFile files 2015-07-23 17:03:47 +02:00
Eelco Dolstra 61af14a921 Add foldl' primop 2015-07-23 17:03:02 +02:00
Eelco Dolstra 887bb5fa5a --version: Print some config info
Such as whether Nix is built with signed binary cache support, and the
location of the configuration file.
2015-07-23 14:38:00 +02:00
Eelco Dolstra 1993b10d11 Fix Darwin build
Turns out getgrouplist() is not POSIX.

http://hydra.nixos.org/build/23881243
2015-07-21 14:45:24 +02:00
Eelco Dolstra 0a2bee307b Make <nix/fetchurl.nix> a builtin builder
This ensures that 1) the derivation doesn't change when Nix changes;
2) the derivation closure doesn't contain Nix and its dependencies; 3)
we don't have to rely on ugly chroot hacks.
2015-07-20 04:38:46 +02:00
Eelco Dolstra eda2f36c2a Provide more detailed info about build status to hydra-queue-runner
In particular, hydra-queue-runner can now distinguish between remote
build / substitution / already-valid. For instance, if a path already
existed on the remote side, we don't want to store a log file.
2015-07-20 03:20:03 +02:00
Eelco Dolstra ccf31dbc25 nix-copy-closure: Add -v flag
And make exportPath() less spammy by default.
2015-07-20 01:52:07 +02:00
Eelco Dolstra db55940d9e Support systemd log severity prefixes
This is mostly useful for hydra-queue-runner.
2015-07-20 01:39:48 +02:00
Eelco Dolstra b3491c781c More cleanup 2015-07-20 01:16:16 +02:00
Eelco Dolstra 6bd2c7bb38 OCD: foreach -> C++11 ranged for 2015-07-17 20:13:56 +02:00
Eelco Dolstra 1511aa9f48 Allow remote builds without sending the derivation closure
Previously, to build a derivation remotely, we had to copy the entire
closure of the .drv file to the remote machine, even though we only
need the top-level derivation. This is very wasteful: the closure can
contain thousands of store paths, and in some Hydra use cases, include
source paths that are very large (e.g. Git/Mercurial checkouts).

So now there is a new operation, StoreAPI::buildDerivation(), that
performs a build from an in-memory representation of a derivation
(BasicDerivation) rather than from a on-disk .drv file. The only files
that need to be in the Nix store are the sources of the derivation
(drv.inputSrcs), and the needed output paths of the dependencies (as
described by drv.inputDrvs). "nix-store --serve" exposes this
interface.

Note that this is a privileged operation, because you can construct a
derivation that builds any store path whatsoever. Fixing this will
require changing the hashing scheme (i.e., the output paths should be
computed from the other fields in BasicDerivation, allowing them to be
verified without access to other derivations). However, this would be
quite nice because it would allow .drv-free building (e.g. "nix-env
-i" wouldn't have to write any .drv files to disk).

Fixes #173.
2015-07-17 17:57:40 +02:00
Eelco Dolstra f39979c6d3 Make printValue() interruptible
Fixes #572.
2015-07-17 11:33:39 +02:00
Eelco Dolstra 7c9d0a5969 nix-collect-garbage: Handle ENOENT
Don't barf trying to read a link that just got deleted.

Fixes #575.
2015-07-17 11:24:25 +02:00
Jaka HudoklinandEelco Dolstra 5845ffdf13 Add Dockerfile 2015-07-17 11:06:50 +02:00
Nicolas B. Pierron db21cfa688 Move attribute set data structures into their own header file.
This modification moves Attr and Bindings structures into their own header
file which is dedicated to the attribute set representation. The goal of to
isolate pieces of code which are related to the attribute set
representation. Thus future modifications of the attribute set
representation will only have to modify these files, and not every other
file across the evaluator.
2015-07-14 19:23:17 +02:00
Guillaume Maudoux 467977f203 Fix the parsing of "$"'s in strings. 2015-07-03 14:09:58 +02:00
Guillaume Maudoux 65e4dcd69b Fix the hack that resets the scanner state. 2015-07-03 13:53:36 +02:00
Eelco Dolstra dd48c06bb6 Typo 2015-07-02 00:30:16 +02:00
Ludovic CourtèsandEelco Dolstra 9aed117395 Preserve supplementary groups of build users
The following patch is an attempt to address this bug (see
<http://bugs.gnu.org/18994>) by preserving the supplementary groups of
build users in the build environment.

In practice, I would expect that supplementary groups would contain only
one or two groups: the build users group, and possibly the “kvm” group.

[Changed &at(0) to data() and removed tabs - Eelco]
2015-07-01 14:57:48 +02:00
Eelco Dolstra e012c126db Revert "add the manpath to the installer"
This reverts commit 76f985b92d. We
shouldn't mess with $MANPATH, because on some "man" implementations
(like NixOS'), the default value on $MANPATH is derived from $PATH. So
if you set $MANPATH, you lose the default locations.
2015-07-01 13:04:15 +02:00
Eelco Dolstra ff4de4cb27 GC: Handle ENOSPC creating/moving to the trash directory
Issue #564.
2015-06-30 21:41:26 +02:00
Eelco Dolstra 2bc9c84327 Use posix_fallocate to create /nix/var/nix/db/reserved 2015-06-22 15:54:55 +02:00
Eelco Dolstra ba63ec6f39 Make /nix/var/nix/db/reserved bigger
Issue #564.
2015-06-22 15:47:40 +02:00
Eelco Dolstra 65f17cd330 Support URLs in $NIX_PATH
This didn't work (despite claims in the manual), because the colon in
"http://" was parsed as a element separator. So handle "://"
specially.
2015-06-17 16:20:11 +02:00
Eelco Dolstra 0d4d92fcf9 Debian package: Declare runtime dependency on libsodium13
Fixes #558.
2015-06-17 10:33:51 +02:00
Eelco Dolstra a33b4bc01b Bump 2015-06-15 10:22:35 +02:00
81 changed files with 2494 additions and 1707 deletions
-1
View File
@@ -12,7 +12,6 @@ in rec {
tar = "@tar@";
tarFlags = "@tarFlags@";
tr = "@tr@";
curl = "@curl@";
nixBinDir = fromEnv "NIX_BIN_DIR" "@bindir@";
nixPrefix = "@prefix@";
+2 -15
View File
@@ -5,20 +5,9 @@ with import <nix/config.nix>;
assert (outputHash != "" && outputHashAlgo != "")
|| md5 != "" || sha1 != "" || sha256 != "";
let
builder = builtins.toFile "fetchurl.sh"
(''
echo "downloading $url into $out"
${curl} --fail --location --max-redirs 20 --insecure "$url" > "$out"
'' + (if executable then "${coreutils}/chmod +x $out" else ""));
in
derivation {
name = baseNameOf (toString url);
builder = shell;
args = [ "-e" builder ];
builder = "builtin:fetchurl";
# New-style output content requirements.
outputHashAlgo = if outputHashAlgo != "" then outputHashAlgo else
@@ -27,7 +16,7 @@ derivation {
if sha256 != "" then sha256 else if sha1 != "" then sha1 else md5;
outputHashMode = if executable then "recursive" else "flat";
inherit system url;
inherit system url executable;
# No need to double the amount of network traffic
preferLocalBuild = true;
@@ -39,6 +28,4 @@ derivation {
# by definition pure.
"http_proxy" "https_proxy" "ftp_proxy" "all_proxy" "no_proxy"
];
inherit chrootDeps;
}
+2 -2
View File
@@ -1,10 +1,10 @@
attrs @ { drvPath, outputs, ... }:
attrs @ { drvPath, outputs, name, ... }:
let
commonAttrs = (builtins.listToAttrs outputsList) //
{ all = map (x: x.value) outputsList;
inherit drvPath;
inherit drvPath name;
type = "derivation";
};
@@ -30,6 +30,7 @@
<arg><option>--include-outputs</option></arg>
<arg><option>--use-substitutes</option></arg>
<arg><option>-s</option></arg>
<arg><option>-v</option></arg>
<arg choice='plain'>
<replaceable>user@</replaceable><replaceable>machine</replaceable>
</arg>
@@ -138,6 +139,12 @@ those paths. If this bothers you, use
</varlistentry>
<varlistentry><term><option>-v</option></term>
<listitem><para>Show verbose output.</para></listitem>
</varlistentry>
</variablelist>
</refsection>
+94 -1
View File
@@ -39,6 +39,28 @@ available as <function>builtins.derivation</function>.</para>
</varlistentry>
<varlistentry><term><function>builtins.all</function>
<replaceable>pred</replaceable> <replaceable>list</replaceable></term>
<listitem><para>Return <literal>true</literal> if the function
<replaceable>pred</replaceable> returns <literal>true</literal>
for all elements of <replaceable>list</replaceable>,
and <literal>false</literal> otherwise.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.any</function>
<replaceable>pred</replaceable> <replaceable>list</replaceable></term>
<listitem><para>Return <literal>true</literal> if the function
<replaceable>pred</replaceable> returns <literal>true</literal>
for at least one element of <replaceable>list</replaceable>,
and <literal>false</literal> otherwise.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.attrNames</function>
<replaceable>set</replaceable></term>
@@ -313,6 +335,19 @@ stdenv.mkDerivation {
</varlistentry>
<varlistentry><term><function>builtins.foldl</function>
<replaceable>op</replaceable> <replaceable>nul</replaceable> <replaceable>list</replaceable></term>
<listitem><para>Reduce a list by applying a binary operator, from
left to right, e.g. <literal>foldl op nul [x0 x1 x2 ...] = op (op
(op nul x0) x1) x2) ...</literal>. The operator is applied
strictly, i.e., its arguments are evaluated first. For example,
<literal>foldl (x: y: x + y) 0 [1 2 3]</literal> evaluates to
6.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.fromJSON</function> <replaceable>e</replaceable></term>
<listitem><para>Convert a JSON string to a Nix
@@ -329,6 +364,24 @@ builtins.fromJSON ''{"x": [1, 2, 3], "y": null}''
</varlistentry>
<varlistentry><term><function>builtins.genList</function>
<replaceable>generator</replaceable> <replaceable>length</replaceable></term>
<listitem><para>Generate list of size
<replaceable>length</replaceable>, with each element
<replaceable>i></replaceable> equal to the value returned by
<replaceable>generator</replaceable> <literal>i</literal>. For
example,
<programlisting>
builtins.genList (x: x * x) 5
</programlisting>
returns the list <literal>[ 0 1 4 9 16 ]</literal>.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.getAttr</function>
<replaceable>s</replaceable> <replaceable>set</replaceable></term>
@@ -663,7 +716,7 @@ in config.someSetting</programlisting>
./A</literal> will return the set
<programlisting>
{ A = "regular"; B = "directory"; }</programlisting>
{ B = "regular"; C = "directory"; }</programlisting>
The possible values for the file type are
<literal>"regular"</literal>, <literal>"directory"</literal>,
@@ -698,6 +751,23 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</programlisting>
</varlistentry>
<varlistentry><term><function>builtins.replaceStrings</function>
<replaceable>from</replaceable> <replaceable>to</replaceable> <replaceable>s</replaceable></term>
<listitem><para>Given string <replaceable>s</replaceable>, replace
every occurrence of the strings in <replaceable>from</replaceable>
with the corresponding string in
<replaceable>to</replaceable>. For example,
<programlisting>
builtins.replaceStrings ["oo" "a"] ["a" "i"] "foobar"
</programlisting>
evaluates to <literal>"fabir"</literal>.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.seq</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
@@ -709,6 +779,29 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</programlisting>
</varlistentry>
<varlistentry><term><function>builtins.sort</function>
<replaceable>comparator</replaceable> <replaceable>list</replaceable></term>
<listitem><para>Return <replaceable>list</replaceable> in sorted
order. It repeatedly calls the function
<replaceable>comparator</replaceable> with two elements. The
comparator should return <literal>true</literal> if the first
element is less than the second, and <literal>false</literal>
otherwise. For example,
<programlisting>
builtins.sort builtins.lessThan [ 483 249 526 147 42 77 ]
</programlisting>
produces the list <literal>[ 42 77 147 249 483 526
]</literal>.</para>
<para>This is a stable sort: it preserves the relative order of
elements deemed equal by the comparator.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.stringLength</function>
<replaceable>e</replaceable></term>
@@ -12,6 +12,7 @@
</partintro>
-->
<xi:include href="rl-1.10.xml" />
<xi:include href="rl-1.9.xml" />
<xi:include href="rl-1.8.xml" />
<xi:include href="rl-1.7.xml" />
+64
View File
@@ -0,0 +1,64 @@
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="ssec-relnotes-1.10">
<title>Release 1.10 (September 3, 2015)</title>
<para>This is primarily a bug fix release. It also has a number of new
features:</para>
<itemizedlist>
<listitem>
<para>A number of builtin functions have been added to reduce
Nixpkgs/NixOS evaluation time and memory consumption:
<function>all</function>,
<function>any</function>,
<function>concatStringsSep</function>,
<function>foldl</function>,
<function>genList</function>,
<function>replaceStrings</function>,
<function>sort</function>.
</para>
</listitem>
<listitem>
<para>The garbage collector is more robust when the disk is full.</para>
</listitem>
<listitem>
<para>Nix supports a new API for building derivations that doesnt
require a <literal>.drv</literal> file to be present on disk; it
only requires an in-memory representation of the derivation. This
is used by the Hydra continuous build system to make remote builds
more efficient.</para>
</listitem>
<listitem>
<para>The function <literal>&lt;nix/fetchurl.nix></literal> now
uses a <emphasis>builtin</emphasis> builder (i.e. it doesnt
require starting an external process; the download is performed by
Nix itself). This ensures that derivation paths dont change when
Nix is upgraded, and obviates the need for ugly hacks to support
chroot execution.</para>
</listitem>
<listitem>
<para><option>--version -v</option> now prints some configuration
information, in particular what compile-time optional features are
enabled, and the paths of various directories.</para>
</listitem>
<listitem>
<para>Build users have their supplementary groups set correctly.</para>
</listitem>
</itemizedlist>
<para>This release has contributions from Eelco Dolstra, Guillaume
Maudoux, Iwan Aucamp, Jaka Hudoklin, Kirill Elagin, Ludovic Courtès,
Manolis Ragkousis, Nicolas B. Pierron and Shea Levy.</para>
</section>
+1 -1
View File
@@ -75,7 +75,7 @@ $ nix-shell -p pan -I nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/
<listitem><para>In <command>nixos-rebuild</command> (on NixOS):
<screen>
$ nixos-rebuild test -I nixpkgs=nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/nixos-unstable.tar.gz
$ nixos-rebuild test -I nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/nixos-unstable.tar.gz
</screen>
</para></listitem>
+23
View File
@@ -0,0 +1,23 @@
FROM busybox
RUN set -x \
&& wget -O- http://nixos.org/releases/nix/nix-1.9/nix-1.9-x86_64-linux.tar.bz2 | \
bzcat - | tar xf - \
&& echo "nixbld:x:30000:nixbld1,nixbld10,nixbld2,nixbld3,nixbld4,nixbld5,nixbld6,nixbld7,nixbld8,nixbld9" >> /etc/group \
&& for i in $(seq 1 9); do echo "nixbld$i:x:3000$i:30000:::" >> /etc/passwd; done \
&& sed -i 's/\$HOME\/\.nix-profile\/etc\/ssl\/certs\/ca-bundle\.crt/\$HOME\/\.nix-profile\/etc\/ca-bundle\.crt/g' nix-1.9-x86_64-linux/install \
&& mkdir -m 0755 /nix && USER=root sh nix-1.9-x86_64-linux/install \
&& echo ". /root/.nix-profile/etc/profile.d/nix.sh" >> /etc/profile \
&& rm -r /nix-1.9-x86_64-linux
ONBUILD ENV \
ENV=/etc/profile \
PATH=/root/.nix-profile/bin:/root/.nix-profile/sbin:/bin:/sbin:/usr/bin:/usr/sbin \
GIT_SSL_CAINFO=/root/.nix-profile/etc/ca-bundle.crt \
SSL_CERT_FILE=/root/.nix-profile/etc/ca-bundle.crt
ENV \
ENV=/etc/profile \
PATH=/root/.nix-profile/bin:/root/.nix-profile/sbin:/bin:/sbin:/usr/bin:/usr/sbin \
GIT_SSL_CAINFO=/root/.nix-profile/etc/ca-bundle.crt \
SSL_CERT_FILE=/root/.nix-profile/etc/ca-bundle.crt
+3 -1
View File
@@ -305,7 +305,9 @@ let
memSize = 1024;
meta.schedulingPriority = 50;
configureFlags = "--sysconfdir=/etc";
debRequires = [ "curl" "libdbd-sqlite3-perl" "libsqlite3-0" "libbz2-1.0" "bzip2" "xz-utils" "libwww-curl-perl" ];
debRequires =
[ "curl" "libdbd-sqlite3-perl" "libsqlite3-0" "libbz2-1.0" "bzip2" "xz-utils" "libwww-curl-perl" ]
++ lib.optionals (lib.elem "libsodium-dev" extraPackages) [ "libsodium13" ] ;
debMaintainer = "Eelco Dolstra <eelco.dolstra@logicblox.com>";
doInstallCheck = true;
};
-2
View File
@@ -16,8 +16,6 @@ binmode STDERR, ":encoding(utf8)";
my $debug = defined $ENV{NIX_DEBUG_HOOK};
setVerbosity(0); # make exportPath() less verbose
# General operation:
#
+1 -1
View File
@@ -105,8 +105,8 @@ sub update {
my $tmpdir = tempdir( CLEANUP => 1 );
my $filename;
($url, $filename) = `cd $tmpdir && $Nix::Config::curl --silent --write-out '%{url_effective}\n%{filename_effective}' -L '$url' -O`;
die "$0: unable to check $url\n" if $? != 0;
chomp $url;
die "$0: unable to check $url\n" if $? != 0;
# If the URL contains a version number, append it to the name
# attribute (so that "nix-env -q" on the channels profile
+5
View File
@@ -25,6 +25,7 @@ my $toMode = 1;
my $includeOutputs = 0;
my $dryRun = 0;
my $useSubstitutes = 0;
my $verbosity = 1;
# !!! Copied from nix-pack-closure, should put this in a module.
@@ -61,6 +62,10 @@ while (@ARGV) {
elsif ($arg eq "--use-substitutes" || $arg eq "-s") {
$useSubstitutes = 1;
}
elsif ($arg eq "-v") {
$verbosity++;
setVerbosity($verbosity);
}
elsif (!defined $sshHost) {
$sshHost = $arg;
}
-1
View File
@@ -9,7 +9,6 @@ if [ -n "$HOME" ]; then
fi
export PATH=$NIX_LINK/bin:$NIX_LINK/sbin:$PATH
export MANPATH=$NIX_LINK/share/man:$MANPATH
# Subscribe the user to the Nixpkgs channel by default.
if [ ! -e $HOME/.nix-channels ]; then
+13 -14
View File
@@ -43,8 +43,7 @@ static std::pair<FdSink, FdSource> connect(const string & conn)
static void substitute(std::pair<FdSink, FdSource> & pipes, Path storePath, Path destPath)
{
writeInt(cmdDumpStorePath, pipes.first);
writeString(storePath, pipes.first);
pipes.first << cmdDumpStorePath << storePath;
pipes.first.flush();
restorePath(destPath, pipes.second);
std::cout << std::endl;
@@ -58,17 +57,17 @@ static void query(std::pair<FdSink, FdSource> & pipes)
string cmd = tokenized.front();
tokenized.pop_front();
if (cmd == "have") {
writeInt(cmdQueryValidPaths, pipes.first);
writeInt(0, pipes.first); // don't lock
writeInt(0, pipes.first); // don't substitute
writeStrings(tokenized, pipes.first);
pipes.first
<< cmdQueryValidPaths
<< 0 // don't lock
<< 0 // don't substitute
<< tokenized;
pipes.first.flush();
PathSet paths = readStrings<PathSet>(pipes.second);
foreach (PathSet::iterator, i, paths)
std::cout << *i << std::endl;
for (auto & i : paths)
std::cout << i << std::endl;
} else if (cmd == "info") {
writeInt(cmdQueryPathInfos, pipes.first);
writeStrings(tokenized, pipes.first);
pipes.first << cmdQueryPathInfos << tokenized;
pipes.first.flush();
while (1) {
Path path = readString(pipes.second);
@@ -80,8 +79,8 @@ static void query(std::pair<FdSink, FdSource> & pipes)
std::cout << deriver << std::endl;
PathSet references = readStorePaths<PathSet>(pipes.second);
std::cout << references.size() << std::endl;
foreach (PathSet::iterator, i, references)
std::cout << *i << std::endl;
for (auto & i : references)
std::cout << i << std::endl;
std::cout << readLongLong(pipes.second) << std::endl;
std::cout << readLongLong(pipes.second) << std::endl;
}
@@ -116,13 +115,13 @@ int main(int argc, char * * argv)
std::pair<FdSink, FdSource> pipes = connect(host);
/* Exchange the greeting */
writeInt(SERVE_MAGIC_1, pipes.first);
pipes.first << SERVE_MAGIC_1;
pipes.first.flush();
unsigned int magic = readInt(pipes.second);
if (magic != SERVE_MAGIC_2)
throw Error("protocol mismatch");
readInt(pipes.second); // Server version, unused for now
writeInt(SERVE_PROTOCOL_VERSION, pipes.first);
pipes.first << SERVE_PROTOCOL_VERSION;
pipes.first.flush();
string arg = argv[1];
+5 -6
View File
@@ -42,11 +42,10 @@ Value * findAlongAttrPath(EvalState & state, const string & attrPath,
Value * v = &vIn;
foreach (Strings::iterator, i, tokens) {
for (auto & attr : tokens) {
/* Is *i an index (integer) or a normal attribute name? */
/* Is i an index (integer) or a normal attribute name? */
enum { apAttr, apIndex } apType = apAttr;
string attr = *i;
unsigned int attrIndex;
if (string2Int(attr, attrIndex)) apType = apIndex;
@@ -77,15 +76,15 @@ Value * findAlongAttrPath(EvalState & state, const string & attrPath,
else if (apType == apIndex) {
if (v->type != tList)
if (!v->isList())
throw TypeError(
format("the expression selected by the selection path %1% should be a list but is %2%")
% attrPath % showType(*v));
if (attrIndex >= v->list.length)
if (attrIndex >= v->listSize())
throw Error(format("list index %1% in selection path %2% is out of range") % attrIndex % attrPath);
v = v->list.elems[attrIndex];
v = v->listElems()[attrIndex];
}
}
+63
View File
@@ -0,0 +1,63 @@
#include "attr-set.hh"
#include "eval.hh"
#include <algorithm>
namespace nix {
static void * allocBytes(size_t n)
{
void * p;
#if HAVE_BOEHMGC
p = GC_malloc(n);
#else
p = malloc(n);
#endif
if (!p) throw std::bad_alloc();
return p;
}
/* Allocate a new array of attributes for an attribute set with a specific
capacity. The space is implicitly reserved after the Bindings
structure. */
Bindings * EvalState::allocBindings(Bindings::size_t capacity)
{
return new (allocBytes(sizeof(Bindings) + sizeof(Attr) * capacity)) Bindings(capacity);
}
void EvalState::mkAttrs(Value & v, unsigned int capacity)
{
if (capacity == 0) {
v = vEmptySet;
return;
}
clearValue(v);
v.type = tAttrs;
v.attrs = allocBindings(capacity);
nrAttrsets++;
nrAttrsInAttrsets += capacity;
}
/* Create a new attribute named 'name' on an existing attribute set stored
in 'vAttrs' and return the newly allocated Value which is associated with
this attribute. */
Value * EvalState::allocAttr(Value & vAttrs, const Symbol & name)
{
Value * v = allocValue();
vAttrs.attrs->push_back(Attr(name, v));
return v;
}
void Bindings::sort()
{
std::sort(begin(), end());
}
}
+82
View File
@@ -0,0 +1,82 @@
#pragma once
#include "nixexpr.hh"
#include "symbol-table.hh"
#include <algorithm>
namespace nix {
class EvalState;
struct Value;
/* Map one attribute name to its value. */
struct Attr
{
Symbol name;
Value * value;
Pos * pos;
Attr(Symbol name, Value * value, Pos * pos = &noPos)
: name(name), value(value), pos(pos) { };
Attr() : pos(&noPos) { };
bool operator < (const Attr & a) const
{
return name < a.name;
}
};
/* Bindings contains all the attributes of an attribute set. It is defined
by its size and its capacity, the capacity being the number of Attr
elements allocated after this structure, while the size corresponds to
the number of elements already inserted in this structure. */
class Bindings
{
public:
typedef uint32_t size_t;
private:
size_t size_, capacity_;
Attr attrs[0];
Bindings(size_t capacity) : size_(0), capacity_(capacity) { }
Bindings(const Bindings & bindings) = delete;
public:
size_t size() const { return size_; }
bool empty() const { return !size_; }
typedef Attr * iterator;
void push_back(const Attr & attr)
{
assert(size_ < capacity_);
attrs[size_++] = attr;
}
iterator find(const Symbol & name)
{
Attr key(name, 0);
iterator i = std::lower_bound(begin(), end(), key);
if (i != end() && i->name == name) return i;
return end();
}
iterator begin() { return &attrs[0]; }
iterator end() { return &attrs[size_]; }
Attr & operator[](size_t pos)
{
return attrs[pos];
}
void sort();
size_t capacity() { return capacity_; }
friend class EvalState;
};
}
+6 -6
View File
@@ -7,9 +7,9 @@
namespace nix {
LocalNoInlineNoReturn(void throwEvalError(const char * s))
LocalNoInlineNoReturn(void throwEvalError(const char * s, const Pos & pos))
{
throw EvalError(s);
throw EvalError(format(s) % pos);
}
LocalNoInlineNoReturn(void throwTypeError(const char * s, const Value & v))
@@ -24,7 +24,7 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s, const Value & v, const
}
void EvalState::forceValue(Value & v)
void EvalState::forceValue(Value & v, const Pos & pos)
{
if (v.type == tThunk) {
Env * env = v.thunk.env;
@@ -43,7 +43,7 @@ void EvalState::forceValue(Value & v)
else if (v.type == tApp)
callFunction(*v.app.left, *v.app.right, v, noPos);
else if (v.type == tBlackhole)
throwEvalError("infinite recursion encountered");
throwEvalError("infinite recursion encountered, at %1%", pos);
}
@@ -66,7 +66,7 @@ inline void EvalState::forceAttrs(Value & v, const Pos & pos)
inline void EvalState::forceList(Value & v)
{
forceValue(v);
if (v.type != tList)
if (!v.isList())
throwTypeError("value is %1% while a list was expected", v);
}
@@ -74,7 +74,7 @@ inline void EvalState::forceList(Value & v)
inline void EvalState::forceList(Value & v, const Pos & pos)
{
forceValue(v);
if (v.type != tList)
if (!v.isList())
throwTypeError("value is %1% while a list was expected, at %2%", v, pos);
}
+118 -127
View File
@@ -55,14 +55,10 @@ static void * allocBytes(size_t n)
}
void Bindings::sort()
{
std::sort(begin(), end());
}
static void printValue(std::ostream & str, std::set<const Value *> & active, const Value & v)
{
checkInterrupt();
if (active.find(&v) != active.end()) {
str << "<CYCLE>";
return;
@@ -96,8 +92,8 @@ static void printValue(std::ostream & str, std::set<const Value *> & active, con
str << "{ ";
typedef std::map<string, Value *> Sorted;
Sorted sorted;
foreach (Bindings::iterator, i, *v.attrs)
sorted[i->name] = i->value;
for (auto & i : *v.attrs)
sorted[i.name] = i.value;
for (auto & i : sorted) {
str << i.first << " = ";
printValue(str, active, *i.second);
@@ -106,10 +102,12 @@ static void printValue(std::ostream & str, std::set<const Value *> & active, con
str << "}";
break;
}
case tList:
case tList1:
case tList2:
case tListN:
str << "[ ";
for (unsigned int n = 0; n < v.list.length; ++n) {
printValue(str, active, *v.list.elems[n]);
for (unsigned int n = 0; n < v.listSize(); ++n) {
printValue(str, active, *v.listElems()[n]);
str << " ";
}
str << "]";
@@ -155,7 +153,7 @@ string showType(const Value & v)
case tPath: return "a path";
case tNull: return "null";
case tAttrs: return "a set";
case tList: return "a list";
case tList1: case tList2: case tListN: return "a list";
case tThunk: return "a thunk";
case tApp: return "a function application";
case tLambda: return "a function";
@@ -234,6 +232,18 @@ void initGC()
}
/* Very hacky way to parse $NIX_PATH, which is colon-separated, but
can contain URLs (e.g. "nixpkgs=https://bla...:foo=https://"). */
static Strings parseNixPath(const string & in)
{
string marker = "\001//";
auto res = tokenizeString<Strings>(replaceStrings(in, "://", marker), ":");
for (auto & s : res)
s = replaceStrings(s, marker, "://");
return res;
}
EvalState::EvalState(const Strings & _searchPath)
: sWith(symbols.create("<with>"))
, sOutPath(symbols.create("outPath"))
@@ -251,14 +261,9 @@ EvalState::EvalState(const Strings & _searchPath)
, sLine(symbols.create("line"))
, sColumn(symbols.create("column"))
, sFunctor(symbols.create("__functor"))
, repair(false)
, baseEnv(allocEnv(128))
, staticBaseEnv(false, 0)
, baseEnvDispl(0)
{
nrEnvs = nrValuesInEnvs = nrValues = nrListElems = 0;
nrAttrsets = nrAttrsInAttrsets = nrOpUpdates = nrOpUpdateValuesCopied = 0;
nrListConcats = nrPrimOpCalls = nrFunctionCalls = 0;
countCalls = getEnv("NIX_COUNT_CALLS", "0") != "0";
restricted = settings.get("restrict-eval", false);
@@ -266,11 +271,15 @@ EvalState::EvalState(const Strings & _searchPath)
assert(gcInitialised);
/* Initialise the Nix expression search path. */
Strings paths = tokenizeString<Strings>(getEnv("NIX_PATH", ""), ":");
Strings paths = parseNixPath(getEnv("NIX_PATH", ""));
for (auto & i : _searchPath) addToSearchPath(i, true);
for (auto & i : paths) addToSearchPath(i);
addToSearchPath("nix=" + settings.nixDataDir + "/nix/corepkgs");
clearValue(vEmptySet);
vEmptySet.type = tAttrs;
vEmptySet.attrs = allocBindings(0);
createBaseEnv();
}
@@ -349,11 +358,6 @@ LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2))
throw EvalError(format(s) % s2);
}
LocalNoInlineNoReturn(void throwEvalError(const char * s, const Pos & pos))
{
throw EvalError(format(s) % pos);
}
LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, const Pos & pos))
{
throw EvalError(format(s) % s2 % pos);
@@ -428,8 +432,8 @@ void mkString(Value & v, const string & s, const PathSet & context)
unsigned int n = 0;
v.string.context = (const char * *)
allocBytes((context.size() + 1) * sizeof(char *));
foreach (PathSet::const_iterator, i, context)
v.string.context[n++] = dupString(i->c_str());
for (auto & i : context)
v.string.context[n++] = dupString(i.c_str());
v.string.context[n] = 0;
}
}
@@ -491,37 +495,19 @@ Env & EvalState::allocEnv(unsigned int size)
}
Value * EvalState::allocAttr(Value & vAttrs, const Symbol & name)
{
Value * v = allocValue();
vAttrs.attrs->push_back(Attr(name, v));
return v;
}
Bindings * EvalState::allocBindings(Bindings::size_t capacity)
{
return new (allocBytes(sizeof(Bindings) + sizeof(Attr) * capacity)) Bindings(capacity);
}
void EvalState::mkList(Value & v, unsigned int length)
void EvalState::mkList(Value & v, unsigned int size)
{
clearValue(v);
v.type = tList;
v.list.length = length;
v.list.elems = length ? (Value * *) allocBytes(length * sizeof(Value *)) : 0;
nrListElems += length;
}
void EvalState::mkAttrs(Value & v, unsigned int expected)
{
clearValue(v);
v.type = tAttrs;
v.attrs = allocBindings(expected);
nrAttrsets++;
nrAttrsInAttrsets += expected;
if (size == 1)
v.type = tList1;
else if (size == 2)
v.type = tList2;
else {
v.type = tListN;
v.bigList.size = size;
v.bigList.elems = size ? (Value * *) allocBytes(size * sizeof(Value *)) : 0;
}
nrListElems += size;
}
@@ -709,15 +695,15 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
environment, while the inherited attributes are evaluated
in the original environment. */
unsigned int displ = 0;
foreach (AttrDefs::iterator, i, attrs) {
for (auto & i : attrs) {
Value * vAttr;
if (hasOverrides && !i->second.inherited) {
if (hasOverrides && !i.second.inherited) {
vAttr = state.allocValue();
mkThunk(*vAttr, env2, i->second.e);
mkThunk(*vAttr, env2, i.second.e);
} else
vAttr = i->second.e->maybeThunk(state, i->second.inherited ? env : env2);
vAttr = i.second.e->maybeThunk(state, i.second.inherited ? env : env2);
env2.values[displ++] = vAttr;
v.attrs->push_back(Attr(i->first, vAttr, &i->second.pos));
v.attrs->push_back(Attr(i.first, vAttr, &i.second.pos));
}
/* If the rec contains an attribute called `__overrides', then
@@ -748,25 +734,25 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
}
else
foreach (AttrDefs::iterator, i, attrs)
v.attrs->push_back(Attr(i->first, i->second.e->maybeThunk(state, env), &i->second.pos));
for (auto & i : attrs)
v.attrs->push_back(Attr(i.first, i.second.e->maybeThunk(state, env), &i.second.pos));
/* Dynamic attrs apply *after* rec and __overrides. */
foreach (DynamicAttrDefs::iterator, i, dynamicAttrs) {
for (auto & i : dynamicAttrs) {
Value nameVal;
i->nameExpr->eval(state, *dynamicEnv, nameVal);
state.forceValue(nameVal);
i.nameExpr->eval(state, *dynamicEnv, nameVal);
state.forceValue(nameVal, i.pos);
if (nameVal.type == tNull)
continue;
state.forceStringNoCtx(nameVal);
Symbol nameSym = state.symbols.create(nameVal.string.s);
Bindings::iterator j = v.attrs->find(nameSym);
if (j != v.attrs->end())
throwEvalError("dynamic attribute %1% at %2% already defined at %3%", nameSym, i->pos, *j->pos);
throwEvalError("dynamic attribute %1% at %2% already defined at %3%", nameSym, i.pos, *j->pos);
i->valueExpr->setName(nameSym);
i.valueExpr->setName(nameSym);
/* Keep sorted order so find can catch duplicates */
v.attrs->push_back(Attr(nameSym, i->valueExpr->maybeThunk(state, *dynamicEnv), &i->pos));
v.attrs->push_back(Attr(nameSym, i.valueExpr->maybeThunk(state, *dynamicEnv), &i.pos));
v.attrs->sort(); // FIXME: inefficient
}
}
@@ -783,8 +769,8 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v)
while the inherited attributes are evaluated in the original
environment. */
unsigned int displ = 0;
foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs)
env2.values[displ++] = i->second.e->maybeThunk(state, i->second.inherited ? env : env2);
for (auto & i : attrs->attrs)
env2.values[displ++] = i.second.e->maybeThunk(state, i.second.inherited ? env : env2);
body->eval(state, env2, v);
}
@@ -793,15 +779,15 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v)
void ExprList::eval(EvalState & state, Env & env, Value & v)
{
state.mkList(v, elems.size());
for (unsigned int n = 0; n < v.list.length; ++n)
v.list.elems[n] = elems[n]->maybeThunk(state, env);
for (unsigned int n = 0; n < elems.size(); ++n)
v.listElems()[n] = elems[n]->maybeThunk(state, env);
}
void ExprVar::eval(EvalState & state, Env & env, Value & v)
{
Value * v2 = state.lookupVar(&env, *this, false);
state.forceValue(*v2);
state.forceValue(*v2, pos);
v = *v2;
}
@@ -835,12 +821,12 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
try {
foreach (AttrPath::const_iterator, i, attrPath) {
for (auto & i : attrPath) {
nrLookups++;
Bindings::iterator j;
Symbol name = getName(*i, state, env);
Symbol name = getName(i, state, env);
if (def) {
state.forceValue(*vAttrs);
state.forceValue(*vAttrs, pos);
if (vAttrs->type != tAttrs ||
(j = vAttrs->attrs->find(name)) == vAttrs->attrs->end())
{
@@ -857,7 +843,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
if (state.countCalls && pos2) state.attrSelects[*pos2]++;
}
state.forceValue(*vAttrs);
state.forceValue(*vAttrs, ( pos2 != NULL ? *pos2 : this->pos ) );
} catch (Error & e) {
if (pos2 && pos2->file != state.sDerivationNix)
@@ -877,10 +863,10 @@ void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v)
e->eval(state, env, vTmp);
foreach (AttrPath::const_iterator, i, attrPath) {
for (auto & i : attrPath) {
state.forceValue(*vAttrs);
Bindings::iterator j;
Symbol name = getName(*i, state, env);
Symbol name = getName(i, state, env);
if (vAttrs->type != tAttrs ||
(j = vAttrs->attrs->find(name)) == vAttrs->attrs->end())
{
@@ -959,10 +945,10 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po
if (fun.type == tAttrs) {
auto found = fun.attrs->find(sFunctor);
if (found != fun.attrs->end()) {
forceValue(*found->value);
forceValue(*found->value, pos);
Value * v2 = allocValue();
callFunction(*found->value, fun, *v2, pos);
forceValue(*v2);
forceValue(*v2, pos);
return callFunction(*v2, arg, v, pos);
}
}
@@ -993,12 +979,12 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po
there is no matching actual argument but the formal
argument has a default, use the default. */
unsigned int attrsUsed = 0;
foreach (Formals::Formals_::iterator, i, lambda.formals->formals) {
Bindings::iterator j = arg.attrs->find(i->name);
for (auto & i : lambda.formals->formals) {
Bindings::iterator j = arg.attrs->find(i.name);
if (j == arg.attrs->end()) {
if (!i->def) throwTypeError("%1% called without required argument %2%, at %3%",
lambda, i->name, pos);
env2.values[displ++] = i->def->maybeThunk(*this, env2);
if (!i.def) throwTypeError("%1% called without required argument %2%, at %3%",
lambda, i.name, pos);
env2.values[displ++] = i.def->maybeThunk(*this, env2);
} else {
attrsUsed++;
env2.values[displ++] = j->value;
@@ -1010,9 +996,9 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po
if (!lambda.formals->ellipsis && attrsUsed != arg.attrs->size()) {
/* Nope, so show the first unexpected argument to the
user. */
foreach (Bindings::iterator, i, *arg.attrs)
if (lambda.formals->argNames.find(i->name) == lambda.formals->argNames.end())
throwTypeError("%1% called with unexpected argument %2%, at %3%", lambda, i->name, pos);
for (auto & i : *arg.attrs)
if (lambda.formals->argNames.find(i.name) == lambda.formals->argNames.end())
throwTypeError("%1% called with unexpected argument %2%, at %3%", lambda, i.name, pos);
abort(); // can't happen
}
}
@@ -1054,12 +1040,12 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
Value * actualArgs = allocValue();
mkAttrs(*actualArgs, fun.lambda.fun->formals->formals.size());
foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) {
Bindings::iterator j = args.find(i->name);
for (auto & i : fun.lambda.fun->formals->formals) {
Bindings::iterator j = args.find(i.name);
if (j != args.end())
actualArgs->attrs->push_back(*j);
else if (!i->def)
throwTypeError("cannot auto-call a function that has an argument without a default value (%1%)", i->name);
else if (!i.def)
throwTypeError("cannot auto-call a function that has an argument without a default value (%1%)", i.name);
}
actualArgs->attrs->sort();
@@ -1187,20 +1173,21 @@ void EvalState::concatLists(Value & v, unsigned int nrLists, Value * * lists, co
unsigned int len = 0;
for (unsigned int n = 0; n < nrLists; ++n) {
forceList(*lists[n], pos);
unsigned int l = lists[n]->list.length;
unsigned int l = lists[n]->listSize();
len += l;
if (l) nonEmpty = lists[n];
}
if (nonEmpty && len == nonEmpty->list.length) {
if (nonEmpty && len == nonEmpty->listSize()) {
v = *nonEmpty;
return;
}
mkList(v, len);
auto out = v.listElems();
for (unsigned int n = 0, pos = 0; n < nrLists; ++n) {
unsigned int l = lists[n]->list.length;
memcpy(v.list.elems + pos, lists[n]->list.elems, l * sizeof(Value *));
unsigned int l = lists[n]->listSize();
memcpy(out + pos, lists[n]->listElems(), l * sizeof(Value *));
pos += l;
}
}
@@ -1215,9 +1202,9 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
bool first = !forceString;
ValueType firstType = tString;
foreach (vector<Expr *>::iterator, i, *es) {
for (auto & i : *es) {
Value vTmp;
(*i)->eval(state, env, vTmp);
i->eval(state, env, vTmp);
/* If the first element is a path, then the result will also
be a path, we don't copy anything (yet - that's done later,
@@ -1276,9 +1263,9 @@ void EvalState::forceValueDeep(Value & v)
}
}
else if (v.type == tList) {
for (unsigned int n = 0; n < v.list.length; ++n)
recurse(*v.list.elems[n]);
else if (v.isList()) {
for (unsigned int n = 0; n < v.listSize(); ++n)
recurse(*v.listElems()[n]);
}
};
@@ -1288,7 +1275,7 @@ void EvalState::forceValueDeep(Value & v)
NixInt EvalState::forceInt(Value & v, const Pos & pos)
{
forceValue(v);
forceValue(v, pos);
if (v.type != tInt)
throwTypeError("value is %1% while an integer was expected, at %2%", v, pos);
return v.integer;
@@ -1314,7 +1301,7 @@ void EvalState::forceFunction(Value & v, const Pos & pos)
string EvalState::forceString(Value & v, const Pos & pos)
{
forceValue(v);
forceValue(v, pos);
if (v.type != tString) {
if (pos)
throwTypeError("value is %1% while a string was expected, at %2%", v, pos);
@@ -1402,14 +1389,14 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
if (v.type == tInt) return int2String(v.integer);
if (v.type == tNull) return "";
if (v.type == tList) {
if (v.isList()) {
string result;
for (unsigned int n = 0; n < v.list.length; ++n) {
result += coerceToString(pos, *v.list.elems[n],
for (unsigned int n = 0; n < v.listSize(); ++n) {
result += coerceToString(pos, *v.listElems()[n],
context, coerceMore, copyToStore);
if (n < v.list.length - 1
if (n < v.listSize() - 1
/* !!! not quite correct */
&& (v.list.elems[n]->type != tList || v.list.elems[n]->list.length != 0))
&& (!v.listElems()[n]->isList() || v.listElems()[n]->listSize() != 0))
result += " ";
}
return result;
@@ -1480,10 +1467,12 @@ bool EvalState::eqValues(Value & v1, Value & v2)
case tNull:
return true;
case tList:
if (v1.list.length != v2.list.length) return false;
for (unsigned int n = 0; n < v1.list.length; ++n)
if (!eqValues(*v1.list.elems[n], *v2.list.elems[n])) return false;
case tList1:
case tList2:
case tListN:
if (v1.listSize() != v2.listSize()) return false;
for (unsigned int n = 0; n < v1.listSize(); ++n)
if (!eqValues(*v1.listElems()[n], *v2.listElems()[n])) return false;
return true;
case tAttrs: {
@@ -1569,25 +1558,25 @@ void EvalState::printStats()
printMsg(v, format("calls to %1% primops:") % primOpCalls.size());
typedef std::multimap<unsigned int, Symbol> PrimOpCalls_;
PrimOpCalls_ primOpCalls_;
foreach (PrimOpCalls::iterator, i, primOpCalls)
primOpCalls_.insert(std::pair<unsigned int, Symbol>(i->second, i->first));
foreach_reverse (PrimOpCalls_::reverse_iterator, i, primOpCalls_)
for (auto & i : primOpCalls)
primOpCalls_.insert(std::pair<unsigned int, Symbol>(i.second, i.first));
for (auto i = primOpCalls_.rbegin(); i != primOpCalls_.rend(); ++i)
printMsg(v, format("%1$10d %2%") % i->first % i->second);
printMsg(v, format("calls to %1% functions:") % functionCalls.size());
typedef std::multimap<unsigned int, ExprLambda *> FunctionCalls_;
FunctionCalls_ functionCalls_;
foreach (FunctionCalls::iterator, i, functionCalls)
functionCalls_.insert(std::pair<unsigned int, ExprLambda *>(i->second, i->first));
foreach_reverse (FunctionCalls_::reverse_iterator, i, functionCalls_)
for (auto & i : functionCalls)
functionCalls_.insert(std::pair<unsigned int, ExprLambda *>(i.second, i.first));
for (auto i = functionCalls_.rbegin(); i != functionCalls_.rend(); ++i)
printMsg(v, format("%1$10d %2%") % i->first % i->second->showNamePos());
printMsg(v, format("evaluations of %1% attributes:") % attrSelects.size());
typedef std::multimap<unsigned int, Pos> AttrSelects_;
AttrSelects_ attrSelects_;
foreach (AttrSelects::iterator, i, attrSelects)
attrSelects_.insert(std::pair<unsigned int, Pos>(i->second, i->first));
foreach_reverse (AttrSelects_::reverse_iterator, i, attrSelects_)
for (auto & i : attrSelects)
attrSelects_.insert(std::pair<unsigned int, Pos>(i.second, i.first));
for (auto i = attrSelects_.rbegin(); i != attrSelects_.rend(); ++i)
printMsg(v, format("%1$10d %2%") % i->first % i->second);
}
@@ -1631,12 +1620,14 @@ size_t valueSize(Value & v)
sz += doValue(*i.value);
}
break;
case tList:
if (seen.find(v.list.elems) == seen.end()) {
seen.insert(v.list.elems);
sz += v.list.length * sizeof(Value *);
for (unsigned int n = 0; n < v.list.length; ++n)
sz += doValue(*v.list.elems[n]);
case tList1:
case tList2:
case tListN:
if (seen.find(v.listElems()) == seen.end()) {
seen.insert(v.listElems());
sz += v.listSize() * sizeof(Value *);
for (unsigned int n = 0; n < v.listSize(); ++n)
sz += doValue(*v.listElems()[n]);
}
break;
case tThunk:
+18 -79
View File
@@ -1,5 +1,6 @@
#pragma once
#include "attr-set.hh"
#include "value.hh"
#include "nixexpr.hh"
#include "symbol-table.hh"
@@ -18,70 +19,6 @@ namespace nix {
class EvalState;
struct Attr
{
Symbol name;
Value * value;
Pos * pos;
Attr(Symbol name, Value * value, Pos * pos = &noPos)
: name(name), value(value), pos(pos) { };
Attr() : pos(&noPos) { };
bool operator < (const Attr & a) const
{
return name < a.name;
}
};
class Bindings
{
public:
typedef uint32_t size_t;
private:
size_t size_, capacity_;
Attr attrs[0];
Bindings(size_t capacity) : size_(0), capacity_(capacity) { }
Bindings(const Bindings & bindings) = delete;
public:
size_t size() const { return size_; }
bool empty() const { return !size_; }
typedef Attr * iterator;
void push_back(const Attr & attr)
{
assert(size_ < capacity_);
attrs[size_++] = attr;
}
iterator find(const Symbol & name)
{
Attr key(name, 0);
iterator i = std::lower_bound(begin(), end(), key);
if (i != end() && i->name == name) return i;
return end();
}
iterator begin() { return &attrs[0]; }
iterator end() { return &attrs[size_]; }
Attr & operator[](size_t pos)
{
return attrs[pos];
}
void sort();
size_t capacity() { return capacity_; }
friend class EvalState;
};
typedef void (* PrimOpFun) (EvalState & state, const Pos & pos, Value * * args, Value & v);
@@ -137,12 +74,14 @@ public:
/* If set, force copying files to the Nix store even if they
already exist there. */
bool repair;
bool repair = false;
/* If set, don't allow access to files outside of the Nix search
path or to environment variables. */
bool restricted;
Value vEmptySet;
private:
SrcToStore srcToStore;
@@ -197,7 +136,7 @@ public:
of the evaluation of the thunk. If `v' is a delayed function
application, call the function and overwrite `v' with the
result. Otherwise, this is a no-op. */
inline void forceValue(Value & v);
inline void forceValue(Value & v, const Pos & pos = noPos);
/* Force a value, then recursively force list elements and
attributes. */
@@ -244,7 +183,7 @@ public:
private:
unsigned int baseEnvDispl;
unsigned int baseEnvDispl = 0;
void createBaseEnv();
@@ -290,7 +229,7 @@ public:
Bindings * allocBindings(Bindings::size_t capacity);
void mkList(Value & v, unsigned int length);
void mkAttrs(Value & v, unsigned int expected);
void mkAttrs(Value & v, unsigned int capacity);
void mkThunk_(Value & v, Expr * expr);
void mkPos(Value & v, Pos * pos);
@@ -301,17 +240,17 @@ public:
private:
unsigned long nrEnvs;
unsigned long nrValuesInEnvs;
unsigned long nrValues;
unsigned long nrListElems;
unsigned long nrAttrsets;
unsigned long nrAttrsInAttrsets;
unsigned long nrOpUpdates;
unsigned long nrOpUpdateValuesCopied;
unsigned long nrListConcats;
unsigned long nrPrimOpCalls;
unsigned long nrFunctionCalls;
unsigned long nrEnvs = 0;
unsigned long nrValuesInEnvs = 0;
unsigned long nrValues = 0;
unsigned long nrListElems = 0;
unsigned long nrAttrsets = 0;
unsigned long nrAttrsInAttrsets = 0;
unsigned long nrOpUpdates = 0;
unsigned long nrOpUpdateValuesCopied = 0;
unsigned long nrListConcats = 0;
unsigned long nrPrimOpCalls = 0;
unsigned long nrFunctionCalls = 0;
bool countCalls;
+19 -19
View File
@@ -39,9 +39,9 @@ DrvInfo::Outputs DrvInfo::queryOutputs()
state->forceList(*i->value, *i->pos);
/* For each output... */
for (unsigned int j = 0; j < i->value->list.length; ++j) {
for (unsigned int j = 0; j < i->value->listSize(); ++j) {
/* Evaluate the corresponding set. */
string name = state->forceStringNoCtx(*i->value->list.elems[j], *i->pos);
string name = state->forceStringNoCtx(*i->value->listElems()[j], *i->pos);
Bindings::iterator out = attrs->find(state->symbols.create(name));
if (out == attrs->end()) continue; // FIXME: throw error?
state->forceAttrs(*out->value);
@@ -85,8 +85,8 @@ StringSet DrvInfo::queryMetaNames()
{
StringSet res;
if (!getMeta()) return res;
foreach (Bindings::iterator, i, *meta)
res.insert(i->name);
for (auto & i : *meta)
res.insert(i.name);
return res;
}
@@ -94,16 +94,16 @@ StringSet DrvInfo::queryMetaNames()
bool DrvInfo::checkMeta(Value & v)
{
state->forceValue(v);
if (v.type == tList) {
for (unsigned int n = 0; n < v.list.length; ++n)
if (!checkMeta(*v.list.elems[n])) return false;
if (v.isList()) {
for (unsigned int n = 0; n < v.listSize(); ++n)
if (!checkMeta(*v.listElems()[n])) return false;
return true;
}
else if (v.type == tAttrs) {
Bindings::iterator i = v.attrs->find(state->sOutPath);
if (i != v.attrs->end()) return false;
foreach (Bindings::iterator, i, *v.attrs)
if (!checkMeta(*i->value)) return false;
for (auto & i : *v.attrs)
if (!checkMeta(*i.value)) return false;
return true;
}
else return v.type == tInt || v.type == tBool || v.type == tString;
@@ -255,13 +255,13 @@ static void getDerivations(EvalState & state, Value & vIn,
precedence). */
typedef std::map<string, Symbol> SortedSymbols;
SortedSymbols attrs;
foreach (Bindings::iterator, i, *v.attrs)
attrs.insert(std::pair<string, Symbol>(i->name, i->name));
for (auto & i : *v.attrs)
attrs.insert(std::pair<string, Symbol>(i.name, i.name));
foreach (SortedSymbols::iterator, i, attrs) {
startNest(nest, lvlDebug, format("evaluating attribute %1%") % i->first);
string pathPrefix2 = addToPath(pathPrefix, i->first);
Value & v2(*v.attrs->find(i->second)->value);
for (auto & i : attrs) {
startNest(nest, lvlDebug, format("evaluating attribute %1%") % i.first);
string pathPrefix2 = addToPath(pathPrefix, i.first);
Value & v2(*v.attrs->find(i.second)->value);
if (combineChannels)
getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
else if (getDerivation(state, v2, pathPrefix2, drvs, done, ignoreAssertionFailures)) {
@@ -277,13 +277,13 @@ static void getDerivations(EvalState & state, Value & vIn,
}
}
else if (v.type == tList) {
for (unsigned int n = 0; n < v.list.length; ++n) {
else if (v.isList()) {
for (unsigned int n = 0; n < v.listSize(); ++n) {
startNest(nest, lvlDebug,
format("evaluating list element"));
string pathPrefix2 = addToPath(pathPrefix, (format("%1%") % n).str());
if (getDerivation(state, *v.list.elems[n], pathPrefix2, drvs, done, ignoreAssertionFailures))
getDerivations(state, *v.list.elems[n], pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
if (getDerivation(state, *v.listElems()[n], pathPrefix2, drvs, done, ignoreAssertionFailures))
getDerivations(state, *v.listElems()[n], pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
}
}
+1 -1
View File
@@ -73,7 +73,7 @@ static void parseJSON(EvalState & state, const char * & s, Value & v)
s++;
state.mkList(v, values.size());
for (size_t n = 0; n < values.size(); ++n)
v.list.elems[n] = values[n];
v.listElems()[n] = values[n];
}
else if (*s == '{') {
+20 -33
View File
@@ -1,6 +1,9 @@
%option reentrant bison-bridge bison-locations
%option noyywrap
%option never-interactive
%option stack
%option nodefault
%option nounput noyy_top_state
%x STRING
@@ -74,6 +77,9 @@ static Expr * unescapeStr(SymbolTable & symbols, const char * s)
#define YY_USER_INIT initLoc(yylloc)
#define YY_USER_ACTION adjustLoc(yylloc, yytext, yyleng);
#define PUSH_STATE(state) yy_push_state(state, yyscanner)
#define POP_STATE() yy_pop_state(yyscanner)
%}
@@ -118,23 +124,24 @@ or { return OR_KW; }
return INT;
}
\$\{ { return DOLLAR_CURLY; }
\$\{ { PUSH_STATE(INITIAL); return DOLLAR_CURLY; }
\{ { PUSH_STATE(INITIAL); return '{'; }
\} { POP_STATE(); return '}'; }
\" { BEGIN(STRING); return '"'; }
<STRING>([^\$\"\\]|\$[^\{\"]|\\.)+ {
/* !!! Not quite right: we want a follow restriction on
"$", it shouldn't be followed by a "{". Right now
"$\"" will be consumed as part of a string, rather
than a "$" followed by the string terminator.
Disallow "$\"" for now. */
\" { PUSH_STATE(STRING); return '"'; }
<STRING>([^\$\"\\]|\$[^\{\"\\]|\\.|\$\\.)*\$/\" |
<STRING>([^\$\"\\]|\$[^\{\"\\]|\\.|\$\\.)+ {
/* It is impossible to match strings ending with '$' with one
regex because trailing contexts are only valid at the end
of a rule. (A sane but undocumented limitation.) */
yylval->e = unescapeStr(data->symbols, yytext);
return STR;
}
<STRING>\$\{ { BEGIN(INITIAL); return DOLLAR_CURLY; }
<STRING>\" { BEGIN(INITIAL); return '"'; }
<STRING>\$\{ { PUSH_STATE(INITIAL); return DOLLAR_CURLY; }
<STRING>\" { POP_STATE(); return '"'; }
<STRING>. return yytext[0]; /* just in case: shouldn't be reached */
\'\'(\ *\n)? { BEGIN(IND_STRING); return IND_STRING_OPEN; }
\'\'(\ *\n)? { PUSH_STATE(IND_STRING); return IND_STRING_OPEN; }
<IND_STRING>([^\$\']|\$[^\{\']|\'[^\'\$])+ {
yylval->e = new ExprIndStr(yytext);
return IND_STR;
@@ -151,8 +158,8 @@ or { return OR_KW; }
yylval->e = unescapeStr(data->symbols, yytext + 2);
return IND_STR;
}
<IND_STRING>\$\{ { BEGIN(INITIAL); return DOLLAR_CURLY; }
<IND_STRING>\'\' { BEGIN(INITIAL); return IND_STRING_CLOSE; }
<IND_STRING>\$\{ { PUSH_STATE(INITIAL); return DOLLAR_CURLY; }
<IND_STRING>\'\' { POP_STATE(); return IND_STRING_CLOSE; }
<IND_STRING>\' {
yylval->e = new ExprIndStr("'");
return IND_STR;
@@ -173,23 +180,3 @@ or { return OR_KW; }
%%
namespace nix {
/* Horrible, disgusting hack: allow the parser to set the scanner
start condition back to STRING. Necessary in interpolations like
"foo${expr}bar"; after the close brace we have to go back to the
STRING state. */
void backToString(yyscan_t scanner)
{
struct yyguts_t * yyg = (struct yyguts_t *) scanner;
BEGIN(STRING);
}
void backToIndString(yyscan_t scanner)
{
struct yyguts_t * yyg = (struct yyguts_t *) scanner;
BEGIN(IND_STRING);
}
}
+1 -1
View File
@@ -8,7 +8,7 @@ libexpr_SOURCES := $(wildcard $(d)/*.cc) $(d)/lexer-tab.cc $(d)/parser-tab.cc
libexpr_LIBS = libutil libstore libformat
libexpr_LDFLAGS = -ldl -lcurl
libexpr_LDFLAGS = -ldl
# The dependency on libgc must be propagated (i.e. meaning that
# programs/libraries that use libexpr must explicitly pass -lgc),
+2 -2
View File
@@ -98,8 +98,8 @@ int compareVersions(const string & v1, const string & v2)
DrvNames drvNamesFromArgs(const Strings & opArgs)
{
DrvNames result;
foreach (Strings::const_iterator, i, opArgs)
result.push_back(DrvName(*i));
for (auto & i : opArgs)
result.push_back(DrvName(i));
return result;
}
+46 -46
View File
@@ -97,21 +97,21 @@ void ExprAttrs::show(std::ostream & str)
{
if (recursive) str << "rec ";
str << "{ ";
foreach (AttrDefs::iterator, i, attrs)
if (i->second.inherited)
str << "inherit " << i->first << " " << "; ";
for (auto & i : attrs)
if (i.second.inherited)
str << "inherit " << i.first << " " << "; ";
else
str << i->first << " = " << *i->second.e << "; ";
foreach (DynamicAttrDefs::iterator, i, dynamicAttrs)
str << "\"${" << *i->nameExpr << "}\" = " << *i->valueExpr << "; ";
str << i.first << " = " << *i.second.e << "; ";
for (auto & i : dynamicAttrs)
str << "\"${" << *i.nameExpr << "}\" = " << *i.valueExpr << "; ";
str << "}";
}
void ExprList::show(std::ostream & str)
{
str << "[ ";
foreach (vector<Expr *>::iterator, i, elems)
str << "(" << **i << ") ";
for (auto & i : elems)
str << "(" << *i << ") ";
str << "]";
}
@@ -121,10 +121,10 @@ void ExprLambda::show(std::ostream & str)
if (matchAttrs) {
str << "{ ";
bool first = true;
foreach (Formals::Formals_::iterator, i, formals->formals) {
for (auto & i : formals->formals) {
if (first) first = false; else str << ", ";
str << i->name;
if (i->def) str << " ? " << *i->def;
str << i.name;
if (i.def) str << " ? " << *i.def;
}
if (formals->ellipsis) {
if (!first) str << ", ";
@@ -140,12 +140,12 @@ void ExprLambda::show(std::ostream & str)
void ExprLet::show(std::ostream & str)
{
str << "(let ";
foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs)
if (i->second.inherited) {
str << "inherit " << i->first << "; ";
for (auto & i : attrs->attrs)
if (i.second.inherited) {
str << "inherit " << i.first << "; ";
}
else
str << i->first << " = " << *i->second.e << "; ";
str << i.first << " = " << *i.second.e << "; ";
str << "in " << *body << ")";
}
@@ -173,9 +173,9 @@ void ExprConcatStrings::show(std::ostream & str)
{
bool first = true;
str << "(";
foreach (vector<Expr *>::iterator, i, *es) {
for (auto & i : *es) {
if (first) first = false; else str << " + ";
str << **i;
str << *i;
}
str << ")";
}
@@ -267,17 +267,17 @@ void ExprSelect::bindVars(const StaticEnv & env)
{
e->bindVars(env);
if (def) def->bindVars(env);
foreach (AttrPath::iterator, i, attrPath)
if (!i->symbol.set())
i->expr->bindVars(env);
for (auto & i : attrPath)
if (!i.symbol.set())
i.expr->bindVars(env);
}
void ExprOpHasAttr::bindVars(const StaticEnv & env)
{
e->bindVars(env);
foreach (AttrPath::iterator, i, attrPath)
if (!i->symbol.set())
i->expr->bindVars(env);
for (auto & i : attrPath)
if (!i.symbol.set())
i.expr->bindVars(env);
}
void ExprAttrs::bindVars(const StaticEnv & env)
@@ -289,27 +289,27 @@ void ExprAttrs::bindVars(const StaticEnv & env)
dynamicEnv = &newEnv;
unsigned int displ = 0;
foreach (AttrDefs::iterator, i, attrs)
newEnv.vars[i->first] = i->second.displ = displ++;
for (auto & i : attrs)
newEnv.vars[i.first] = i.second.displ = displ++;
foreach (AttrDefs::iterator, i, attrs)
i->second.e->bindVars(i->second.inherited ? env : newEnv);
for (auto & i : attrs)
i.second.e->bindVars(i.second.inherited ? env : newEnv);
}
else
foreach (AttrDefs::iterator, i, attrs)
i->second.e->bindVars(env);
for (auto & i : attrs)
i.second.e->bindVars(env);
foreach (DynamicAttrDefs::iterator, i, dynamicAttrs) {
i->nameExpr->bindVars(*dynamicEnv);
i->valueExpr->bindVars(*dynamicEnv);
for (auto & i : dynamicAttrs) {
i.nameExpr->bindVars(*dynamicEnv);
i.valueExpr->bindVars(*dynamicEnv);
}
}
void ExprList::bindVars(const StaticEnv & env)
{
foreach (vector<Expr *>::iterator, i, elems)
(*i)->bindVars(env);
for (auto & i : elems)
i->bindVars(env);
}
void ExprLambda::bindVars(const StaticEnv & env)
@@ -321,11 +321,11 @@ void ExprLambda::bindVars(const StaticEnv & env)
if (!arg.empty()) newEnv.vars[arg] = displ++;
if (matchAttrs) {
foreach (Formals::Formals_::iterator, i, formals->formals)
newEnv.vars[i->name] = displ++;
for (auto & i : formals->formals)
newEnv.vars[i.name] = displ++;
foreach (Formals::Formals_::iterator, i, formals->formals)
if (i->def) i->def->bindVars(newEnv);
for (auto & i : formals->formals)
if (i.def) i.def->bindVars(newEnv);
}
body->bindVars(newEnv);
@@ -336,11 +336,11 @@ void ExprLet::bindVars(const StaticEnv & env)
StaticEnv newEnv(false, &env);
unsigned int displ = 0;
foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs)
newEnv.vars[i->first] = i->second.displ = displ++;
for (auto & i : attrs->attrs)
newEnv.vars[i.first] = i.second.displ = displ++;
foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs)
i->second.e->bindVars(i->second.inherited ? env : newEnv);
for (auto & i : attrs->attrs)
i.second.e->bindVars(i.second.inherited ? env : newEnv);
body->bindVars(newEnv);
}
@@ -384,8 +384,8 @@ void ExprOpNot::bindVars(const StaticEnv & env)
void ExprConcatStrings::bindVars(const StaticEnv & env)
{
foreach (vector<Expr *>::iterator, i, *es)
(*i)->bindVars(env);
for (auto & i : *es)
i->bindVars(env);
}
void ExprPos::bindVars(const StaticEnv & env)
@@ -419,8 +419,8 @@ string ExprLambda::showNamePos() const
size_t SymbolTable::totalSize() const
{
size_t n = 0;
foreach (Symbols::const_iterator, i, symbols)
n += i->size();
for (auto & i : symbols)
n += i.size();
return n;
}
+14 -25
View File
@@ -136,8 +136,8 @@ static Expr * stripIndentation(const Pos & pos, SymbolTable & symbols, vector<Ex
bool atStartOfLine = true; /* = seen only whitespace in the current line */
unsigned int minIndent = 1000000;
unsigned int curIndent = 0;
foreach (vector<Expr *>::iterator, i, es) {
ExprIndStr * e = dynamic_cast<ExprIndStr *>(*i);
for (auto & i : es) {
ExprIndStr * e = dynamic_cast<ExprIndStr *>(i);
if (!e) {
/* Anti-quotations end the current start-of-line whitespace. */
if (atStartOfLine) {
@@ -216,10 +216,6 @@ static Expr * stripIndentation(const Pos & pos, SymbolTable & symbols, vector<Ex
}
void backToString(yyscan_t scanner);
void backToIndString(yyscan_t scanner);
static inline Pos makeCurPos(const YYLTYPE & loc, ParseData * data)
{
return Pos(data->path, loc.first_line, loc.first_column);
@@ -404,25 +400,18 @@ string_parts
string_parts_interpolated
: string_parts_interpolated STR { $$ = $1; $1->push_back($2); }
| string_parts_interpolated DOLLAR_CURLY expr '}' { backToString(scanner); $$ = $1; $1->push_back($3); }
| STR DOLLAR_CURLY expr '}'
{
backToString(scanner);
| string_parts_interpolated DOLLAR_CURLY expr '}' { $$ = $1; $1->push_back($3); }
| DOLLAR_CURLY expr '}' { $$ = new vector<Expr *>; $$->push_back($2); }
| STR DOLLAR_CURLY expr '}' {
$$ = new vector<Expr *>;
$$->push_back($1);
$$->push_back($3);
}
| DOLLAR_CURLY expr '}'
{
backToString(scanner);
$$ = new vector<Expr *>;
$$->push_back($2);
}
;
ind_string_parts
: ind_string_parts IND_STR { $$ = $1; $1->push_back($2); }
| ind_string_parts DOLLAR_CURLY expr '}' { backToIndString(scanner); $$ = $1; $1->push_back($3); }
| ind_string_parts DOLLAR_CURLY expr '}' { $$ = $1; $1->push_back($3); }
| { $$ = new vector<Expr *>; }
;
@@ -430,20 +419,20 @@ binds
: binds attrpath '=' expr ';' { $$ = $1; addAttr($$, *$2, $4, makeCurPos(@2, data)); }
| binds INHERIT attrs ';'
{ $$ = $1;
foreach (AttrPath::iterator, i, *$3) {
if ($$->attrs.find(i->symbol) != $$->attrs.end())
dupAttr(i->symbol, makeCurPos(@3, data), $$->attrs[i->symbol].pos);
for (auto & i : *$3) {
if ($$->attrs.find(i.symbol) != $$->attrs.end())
dupAttr(i.symbol, makeCurPos(@3, data), $$->attrs[i.symbol].pos);
Pos pos = makeCurPos(@3, data);
$$->attrs[i->symbol] = ExprAttrs::AttrDef(new ExprVar(CUR_POS, i->symbol), pos, true);
$$->attrs[i.symbol] = ExprAttrs::AttrDef(new ExprVar(CUR_POS, i.symbol), pos, true);
}
}
| binds INHERIT '(' expr ')' attrs ';'
{ $$ = $1;
/* !!! Should ensure sharing of the expression in $4. */
foreach (AttrPath::iterator, i, *$6) {
if ($$->attrs.find(i->symbol) != $$->attrs.end())
dupAttr(i->symbol, makeCurPos(@6, data), $$->attrs[i->symbol].pos);
$$->attrs[i->symbol] = ExprAttrs::AttrDef(new ExprSelect(CUR_POS, $4, i->symbol), makeCurPos(@6, data));
for (auto & i : *$6) {
if ($$->attrs.find(i.symbol) != $$->attrs.end())
dupAttr(i.symbol, makeCurPos(@6, data), $$->attrs[i.symbol].pos);
$$->attrs[i.symbol] = ExprAttrs::AttrDef(new ExprSelect(CUR_POS, $4, i.symbol), makeCurPos(@6, data));
}
}
| { $$ = new ExprAttrs; }
+272 -102
View File
@@ -86,9 +86,11 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args
if (isStorePath(path) && store->isValidPath(path) && isDerivation(path)) {
Derivation drv = readDerivation(path);
Value & w = *state.allocValue();
state.mkAttrs(w, 2 + drv.outputs.size());
state.mkAttrs(w, 3 + drv.outputs.size());
Value * v2 = state.allocAttr(w, state.sDrvPath);
mkString(*v2, path, singleton<PathSet>("=" + path));
v2 = state.allocAttr(w, state.sName);
mkString(*v2, drv.env["name"]);
Value * outputsVal =
state.allocAttr(w, state.symbols.create("outputs"));
state.mkList(*outputsVal, drv.outputs.size());
@@ -98,8 +100,8 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args
v2 = state.allocAttr(w, state.symbols.create(o.first));
mkString(*v2, o.second.path,
singleton<PathSet>("!" + o.first + "!" + path));
outputsVal->list.elems[outputs_index] = state.allocValue();
mkString(*(outputsVal->list.elems[outputs_index++]), o.first);
outputsVal->listElems()[outputs_index] = state.allocValue();
mkString(*(outputsVal->listElems()[outputs_index++]), o.first);
}
w.attrs->sort();
Value fun;
@@ -186,7 +188,7 @@ static void prim_typeOf(EvalState & state, const Pos & pos, Value * * args, Valu
case tPath: t = "path"; break;
case tNull: t = "null"; break;
case tAttrs: t = "set"; break;
case tList: t = "list"; break;
case tList1: case tList2: case tListN: t = "list"; break;
case tLambda:
case tPrimOp:
case tPrimOpApp:
@@ -282,8 +284,8 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
state.forceList(*startSet->value, pos);
ValueList workSet;
for (unsigned int n = 0; n < startSet->value->list.length; ++n)
workSet.push_back(startSet->value->list.elems[n]);
for (unsigned int n = 0; n < startSet->value->listSize(); ++n)
workSet.push_back(startSet->value->listElems()[n]);
/* Get the operator. */
Bindings::iterator op =
@@ -321,17 +323,17 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
state.forceList(call, pos);
/* Add the values returned by the operator to the work set. */
for (unsigned int n = 0; n < call.list.length; ++n) {
state.forceValue(*call.list.elems[n]);
workSet.push_back(call.list.elems[n]);
for (unsigned int n = 0; n < call.listSize(); ++n) {
state.forceValue(*call.listElems()[n]);
workSet.push_back(call.listElems()[n]);
}
}
/* Create the result list. */
state.mkList(v, res.size());
unsigned int n = 0;
foreach (ValueList::iterator, i, res)
v.list.elems[n++] = *i;
for (auto & i : res)
v.listElems()[n++] = i;
}
@@ -477,24 +479,24 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
StringSet outputs;
outputs.insert("out");
foreach (Bindings::iterator, i, *args[0]->attrs) {
if (i->name == state.sIgnoreNulls) continue;
string key = i->name;
for (auto & i : *args[0]->attrs) {
if (i.name == state.sIgnoreNulls) continue;
string key = i.name;
startNest(nest, lvlVomit, format("processing attribute %1%") % key);
try {
if (ignoreNulls) {
state.forceValue(*i->value);
if (i->value->type == tNull) continue;
state.forceValue(*i.value);
if (i.value->type == tNull) continue;
}
/* The `args' attribute is special: it supplies the
command-line arguments to the builder. */
if (key == "args") {
state.forceList(*i->value, pos);
for (unsigned int n = 0; n < i->value->list.length; ++n) {
string s = state.coerceToString(posDrvName, *i->value->list.elems[n], context, true);
state.forceList(*i.value, pos);
for (unsigned int n = 0; n < i.value->listSize(); ++n) {
string s = state.coerceToString(posDrvName, *i.value->listElems()[n], context, true);
drv.args.push_back(s);
}
}
@@ -502,11 +504,11 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
/* All other attributes are passed to the builder through
the environment. */
else {
string s = state.coerceToString(posDrvName, *i->value, context, true);
string s = state.coerceToString(posDrvName, *i.value, context, true);
drv.env[key] = s;
if (key == "builder") drv.builder = s;
else if (i->name == state.sSystem) drv.platform = s;
else if (i->name == state.sName) {
else if (i.name == state.sSystem) drv.platform = s;
else if (i.name == state.sName) {
drvName = s;
printMsg(lvlVomit, format("derivation name is %1%") % drvName);
}
@@ -520,17 +522,17 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
else if (key == "outputs") {
Strings tmp = tokenizeString<Strings>(s);
outputs.clear();
foreach (Strings::iterator, j, tmp) {
if (outputs.find(*j) != outputs.end())
throw EvalError(format("duplicate derivation output %1%, at %2%") % *j % posDrvName);
/* !!! Check whether *j is a valid attribute
for (auto & j : tmp) {
if (outputs.find(j) != outputs.end())
throw EvalError(format("duplicate derivation output %1%, at %2%") % j % posDrvName);
/* !!! Check whether j is a valid attribute
name. */
/* Derivations cannot be named drv, because
then we'd have an attribute drvPath in
the resulting set. */
if (*j == "drv")
if (j == "drv")
throw EvalError(format("invalid derivation output name drv, at %1%") % posDrvName);
outputs.insert(*j);
outputs.insert(j);
}
if (outputs.empty())
throw EvalError(format("derivation cannot have an empty set of outputs, at %1%") % posDrvName);
@@ -547,8 +549,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
/* Everything in the context of the strings in the derivation
attributes should be added as dependencies of the resulting
derivation. */
foreach (PathSet::iterator, i, context) {
Path path = *i;
for (auto & path : context) {
/* Paths marked with `=' denote that the path of a derivation
is explicitly passed to the builder. Since that allows the
@@ -560,10 +561,10 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
if (path.at(0) == '=') {
/* !!! This doesn't work if readOnlyMode is set. */
PathSet refs; computeFSClosure(*store, string(path, 1), refs);
foreach (PathSet::iterator, j, refs) {
drv.inputSrcs.insert(*j);
if (isDerivation(*j))
drv.inputDrvs[*j] = store->queryDerivationOutputNames(*j);
for (auto & j : refs) {
drv.inputSrcs.insert(j);
if (isDerivation(j))
drv.inputDrvs[j] = store->queryDerivationOutputNames(j);
}
}
@@ -622,20 +623,20 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
are empty, and the corresponding environment variables have
an empty value. This ensures that changes in the set of
output names do get reflected in the hash. */
foreach (StringSet::iterator, i, outputs) {
drv.env[*i] = "";
drv.outputs[*i] = DerivationOutput("", "", "");
for (auto & i : outputs) {
drv.env[i] = "";
drv.outputs[i] = DerivationOutput("", "", "");
}
/* Use the masked derivation expression to compute the output
path. */
Hash h = hashDerivationModulo(*store, drv);
foreach (DerivationOutputs::iterator, i, drv.outputs)
if (i->second.path == "") {
Path outPath = makeOutputPath(i->first, h, drvName);
drv.env[i->first] = outPath;
i->second.path = outPath;
for (auto & i : drv.outputs)
if (i.second.path == "") {
Path outPath = makeOutputPath(i.first, h, drvName);
drv.env[i.first] = outPath;
i.second.path = outPath;
}
}
@@ -652,9 +653,9 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
state.mkAttrs(v, 1 + drv.outputs.size());
mkString(*state.allocAttr(v, state.sDrvPath), drvPath, singleton<PathSet>("=" + drvPath));
foreach (DerivationOutputs::iterator, i, drv.outputs) {
mkString(*state.allocAttr(v, state.symbols.create(i->first)),
i->second.path, singleton<PathSet>("!" + i->first + "!" + drvPath));
for (auto & i : drv.outputs) {
mkString(*state.allocAttr(v, state.symbols.create(i.first)),
i.second.path, singleton<PathSet>("!" + i.first + "!" + drvPath));
}
v.attrs->sort();
}
@@ -765,8 +766,8 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
SearchPath searchPath;
PathSet context;
for (unsigned int n = 0; n < args[0]->list.length; ++n) {
Value & v2(*args[0]->list.elems[n]);
for (unsigned int n = 0; n < args[0]->listSize(); ++n) {
Value & v2(*args[0]->listElems()[n]);
state.forceAttrs(v2, pos);
string prefix;
@@ -871,11 +872,14 @@ static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Valu
PathSet refs;
foreach (PathSet::iterator, i, context) {
Path path = *i;
for (auto path : context) {
if (path.at(0) == '=') path = string(path, 1);
if (isDerivation(path))
throw EvalError(format("in toFile: the file %1% cannot refer to derivation outputs, at %2%") % name % pos);
if (isDerivation(path)) {
/* See prim_unsafeDiscardOutputDependency. */
if (path.at(0) != '~')
throw EvalError(format("in toFile: the file %1% cannot refer to derivation outputs, at %2%") % name % pos);
path = string(path, 1);
}
refs.insert(path);
}
@@ -968,9 +972,9 @@ static void prim_attrNames(EvalState & state, const Pos & pos, Value * * args, V
unsigned int n = 0;
for (auto & i : *args[0]->attrs)
mkString(*(v.list.elems[n++] = state.allocValue()), i.name);
mkString(*(v.listElems()[n++] = state.allocValue()), i.name);
std::sort(v.list.elems, v.list.elems + n,
std::sort(v.listElems(), v.listElems() + n,
[](Value * v1, Value * v2) { return strcmp(v1->string.s, v2->string.s) < 0; });
}
@@ -985,13 +989,13 @@ static void prim_attrValues(EvalState & state, const Pos & pos, Value * * args,
unsigned int n = 0;
for (auto & i : *args[0]->attrs)
v.list.elems[n++] = (Value *) &i;
v.listElems()[n++] = (Value *) &i;
std::sort(v.list.elems, v.list.elems + n,
std::sort(v.listElems(), v.listElems() + n,
[](Value * v1, Value * v2) { return (string) ((Attr *) v1)->name < (string) ((Attr *) v2)->name; });
for (unsigned int i = 0; i < n; ++i)
v.list.elems[i] = ((Attr *) v.list.elems[i])->value;
v.listElems()[i] = ((Attr *) v.listElems()[i])->value;
}
@@ -1048,18 +1052,18 @@ static void prim_removeAttrs(EvalState & state, const Pos & pos, Value * * args,
/* Get the attribute names to be removed. */
std::set<Symbol> names;
for (unsigned int i = 0; i < args[1]->list.length; ++i) {
state.forceStringNoCtx(*args[1]->list.elems[i], pos);
names.insert(state.symbols.create(args[1]->list.elems[i]->string.s));
for (unsigned int i = 0; i < args[1]->listSize(); ++i) {
state.forceStringNoCtx(*args[1]->listElems()[i], pos);
names.insert(state.symbols.create(args[1]->listElems()[i]->string.s));
}
/* Copy all attributes not in that set. Note that we don't need
to sort v.attrs because it's a subset of an already sorted
vector. */
state.mkAttrs(v, args[0]->attrs->size());
foreach (Bindings::iterator, i, *args[0]->attrs) {
if (names.find(i->name) == names.end())
v.attrs->push_back(*i);
for (auto & i : *args[0]->attrs) {
if (names.find(i.name) == names.end())
v.attrs->push_back(i);
}
}
@@ -1073,12 +1077,12 @@ static void prim_listToAttrs(EvalState & state, const Pos & pos, Value * * args,
{
state.forceList(*args[0], pos);
state.mkAttrs(v, args[0]->list.length);
state.mkAttrs(v, args[0]->listSize());
std::set<Symbol> seen;
for (unsigned int i = 0; i < args[0]->list.length; ++i) {
Value & v2(*args[0]->list.elems[i]);
for (unsigned int i = 0; i < args[0]->listSize(); ++i) {
Value & v2(*args[0]->listElems()[i]);
state.forceAttrs(v2, pos);
Bindings::iterator j = v2.attrs->find(state.sName);
@@ -1111,8 +1115,8 @@ static void prim_intersectAttrs(EvalState & state, const Pos & pos, Value * * ar
state.mkAttrs(v, std::min(args[0]->attrs->size(), args[1]->attrs->size()));
foreach (Bindings::iterator, i, *args[0]->attrs) {
Bindings::iterator j = args[1]->attrs->find(i->name);
for (auto & i : *args[0]->attrs) {
Bindings::iterator j = args[1]->attrs->find(i.name);
if (j != args[1]->attrs->end())
v.attrs->push_back(*j);
}
@@ -1131,11 +1135,11 @@ static void prim_catAttrs(EvalState & state, const Pos & pos, Value * * args, Va
Symbol attrName = state.symbols.create(state.forceStringNoCtx(*args[0], pos));
state.forceList(*args[1], pos);
Value * res[args[1]->list.length];
Value * res[args[1]->listSize()];
unsigned int found = 0;
for (unsigned int n = 0; n < args[1]->list.length; ++n) {
Value & v2(*args[1]->list.elems[n]);
for (unsigned int n = 0; n < args[1]->listSize(); ++n) {
Value & v2(*args[1]->listElems()[n]);
state.forceAttrs(v2, pos);
Bindings::iterator i = v2.attrs->find(attrName);
if (i != v2.attrs->end())
@@ -1144,7 +1148,7 @@ static void prim_catAttrs(EvalState & state, const Pos & pos, Value * * args, Va
state.mkList(v, found);
for (unsigned int n = 0; n < found; ++n)
v.list.elems[n] = res[n];
v.listElems()[n] = res[n];
}
@@ -1173,9 +1177,9 @@ static void prim_functionArgs(EvalState & state, const Pos & pos, Value * * args
}
state.mkAttrs(v, args[0]->lambda.fun->formals->formals.size());
foreach (Formals::Formals_::iterator, i, args[0]->lambda.fun->formals->formals)
for (auto & i : args[0]->lambda.fun->formals->formals)
// !!! should optimise booleans (allocate only once)
mkBool(*state.allocAttr(v, i->name), i->def);
mkBool(*state.allocAttr(v, i.name), i.def);
v.attrs->sort();
}
@@ -1189,17 +1193,17 @@ static void prim_functionArgs(EvalState & state, const Pos & pos, Value * * args
static void prim_isList(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceValue(*args[0]);
mkBool(v, args[0]->type == tList);
mkBool(v, args[0]->isList());
}
static void elemAt(EvalState & state, const Pos & pos, Value & list, int n, Value & v)
{
state.forceList(list, pos);
if (n < 0 || (unsigned int) n >= list.list.length)
if (n < 0 || (unsigned int) n >= list.listSize())
throw Error(format("list index %1% is out of bounds, at %2%") % n % pos);
state.forceValue(*list.list.elems[n]);
v = *list.list.elems[n];
state.forceValue(*list.listElems()[n]);
v = *list.listElems()[n];
}
@@ -1223,11 +1227,11 @@ static void prim_head(EvalState & state, const Pos & pos, Value * * args, Value
static void prim_tail(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceList(*args[0], pos);
if (args[0]->list.length == 0)
if (args[0]->listSize() == 0)
throw Error(format("tail called on an empty list, at %1%") % pos);
state.mkList(v, args[0]->list.length - 1);
for (unsigned int n = 0; n < v.list.length; ++n)
v.list.elems[n] = args[0]->list.elems[n + 1];
state.mkList(v, args[0]->listSize() - 1);
for (unsigned int n = 0; n < v.listSize(); ++n)
v.listElems()[n] = args[0]->listElems()[n + 1];
}
@@ -1237,11 +1241,11 @@ static void prim_map(EvalState & state, const Pos & pos, Value * * args, Value &
state.forceFunction(*args[0], pos);
state.forceList(*args[1], pos);
state.mkList(v, args[1]->list.length);
state.mkList(v, args[1]->listSize());
for (unsigned int n = 0; n < v.list.length; ++n)
mkApp(*(v.list.elems[n] = state.allocValue()),
*args[0], *args[1]->list.elems[n]);
for (unsigned int n = 0; n < v.listSize(); ++n)
mkApp(*(v.listElems()[n] = state.allocValue()),
*args[0], *args[1]->listElems()[n]);
}
@@ -1254,15 +1258,15 @@ static void prim_filter(EvalState & state, const Pos & pos, Value * * args, Valu
state.forceList(*args[1], pos);
// FIXME: putting this on the stack is risky.
Value * vs[args[1]->list.length];
Value * vs[args[1]->listSize()];
unsigned int k = 0;
bool same = true;
for (unsigned int n = 0; n < args[1]->list.length; ++n) {
for (unsigned int n = 0; n < args[1]->listSize(); ++n) {
Value res;
state.callFunction(*args[0], *args[1]->list.elems[n], res, noPos);
state.callFunction(*args[0], *args[1]->listElems()[n], res, noPos);
if (state.forceBool(res))
vs[k++] = args[1]->list.elems[n];
vs[k++] = args[1]->listElems()[n];
else
same = false;
}
@@ -1271,7 +1275,7 @@ static void prim_filter(EvalState & state, const Pos & pos, Value * * args, Valu
v = *args[1];
else {
state.mkList(v, k);
for (unsigned int n = 0; n < k; ++n) v.list.elems[n] = vs[n];
for (unsigned int n = 0; n < k; ++n) v.listElems()[n] = vs[n];
}
}
@@ -1281,8 +1285,8 @@ static void prim_elem(EvalState & state, const Pos & pos, Value * * args, Value
{
bool res = false;
state.forceList(*args[1], pos);
for (unsigned int n = 0; n < args[1]->list.length; ++n)
if (state.eqValues(*args[0], *args[1]->list.elems[n])) {
for (unsigned int n = 0; n < args[1]->listSize(); ++n)
if (state.eqValues(*args[0], *args[1]->listElems()[n])) {
res = true;
break;
}
@@ -1294,7 +1298,7 @@ static void prim_elem(EvalState & state, const Pos & pos, Value * * args, Value
static void prim_concatLists(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceList(*args[0], pos);
state.concatLists(v, args[0]->list.length, args[0]->list.elems, pos);
state.concatLists(v, args[0]->listSize(), args[0]->listElems(), pos);
}
@@ -1302,7 +1306,114 @@ static void prim_concatLists(EvalState & state, const Pos & pos, Value * * args,
static void prim_length(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceList(*args[0], pos);
mkInt(v, args[0]->list.length);
mkInt(v, args[0]->listSize());
}
/* Reduce a list by applying a binary operator, from left to
right. The operator is applied strictly. */
static void prim_foldlStrict(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceFunction(*args[0], pos);
state.forceList(*args[2], pos);
Value * vCur = args[1];
if (args[2]->listSize())
for (unsigned int n = 0; n < args[2]->listSize(); ++n) {
Value vTmp;
state.callFunction(*args[0], *vCur, vTmp, pos);
vCur = n == args[2]->listSize() - 1 ? &v : state.allocValue();
state.callFunction(vTmp, *args[2]->listElems()[n], *vCur, pos);
}
else
v = *vCur;
state.forceValue(v);
}
static void anyOrAll(bool any, EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceFunction(*args[0], pos);
state.forceList(*args[1], pos);
Value vTmp;
for (unsigned int n = 0; n < args[1]->listSize(); ++n) {
state.callFunction(*args[0], *args[1]->listElems()[n], vTmp, pos);
bool res = state.forceBool(vTmp);
if (res == any) {
mkBool(v, any);
return;
}
}
mkBool(v, !any);
}
static void prim_any(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
anyOrAll(true, state, pos, args, v);
}
static void prim_all(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
anyOrAll(false, state, pos, args, v);
}
static void prim_genList(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceFunction(*args[0], pos);
auto len = state.forceInt(*args[1], pos);
if (len < 0)
throw EvalError(format("cannot create list of size %1%, at %2%") % len % pos);
state.mkList(v, len);
for (unsigned int n = 0; n < len; ++n) {
Value * arg = state.allocValue();
mkInt(*arg, n);
mkApp(*(v.listElems()[n] = state.allocValue()), *args[0], *arg);
}
}
static void prim_lessThan(EvalState & state, const Pos & pos, Value * * args, Value & v);
static void prim_sort(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceFunction(*args[0], pos);
state.forceList(*args[1], pos);
auto len = args[1]->listSize();
state.mkList(v, len);
for (unsigned int n = 0; n < len; ++n) {
state.forceValue(*args[1]->listElems()[n]);
v.listElems()[n] = args[1]->listElems()[n];
}
auto comparator = [&](Value * a, Value * b) {
/* Optimization: if the comparator is lessThan, bypass
callFunction. */
if (args[0]->type == tPrimOp && args[0]->primOp->fun == prim_lessThan)
return CompareValues()(a, b);
Value vTmp1, vTmp2;
state.callFunction(*args[0], *a, vTmp1, pos);
state.callFunction(vTmp1, *b, vTmp2, pos);
return state.forceBool(vTmp2);
};
/* FIXME: std::sort can segfault if the comparator is not a strict
weak ordering. What to do? std::stable_sort() seems more
resilient, but no guarantees... */
std::stable_sort(v.listElems(), v.listElems() + len, comparator);
}
@@ -1407,11 +1518,8 @@ static void prim_unsafeDiscardOutputDependency(EvalState & state, const Pos & po
string s = state.coerceToString(pos, *args[0], context);
PathSet context2;
foreach (PathSet::iterator, i, context) {
Path p = *i;
if (p.at(0) == '=') p = "~" + string(p, 1);
context2.insert(p);
}
for (auto & p : context)
context2.insert(p.at(0) == '=' ? "~" + string(p, 1) : p);
mkString(v, s, context2);
}
@@ -1452,13 +1560,68 @@ static void prim_match(EvalState & state, const Pos & pos, Value * * args, Value
for (unsigned int n = 0; n < len; ++n) {
auto i = subs.find(n);
if (i == subs.end())
mkNull(*(v.list.elems[n] = state.allocValue()));
mkNull(*(v.listElems()[n] = state.allocValue()));
else
mkString(*(v.list.elems[n] = state.allocValue()), i->second);
mkString(*(v.listElems()[n] = state.allocValue()), i->second);
}
}
static void prim_concatStringSep(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
auto sep = state.forceString(*args[0], context, pos);
state.forceList(*args[1], pos);
string res;
res.reserve((args[1]->listSize() + 32) * sep.size());
bool first = true;
for (unsigned int n = 0; n < args[1]->listSize(); ++n) {
if (first) first = false; else res += sep;
res += state.coerceToString(pos, *args[1]->listElems()[n], context);
}
mkString(v, res, context);
}
static void prim_replaceStrings(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceList(*args[0], pos);
state.forceList(*args[1], pos);
if (args[0]->listSize() != args[1]->listSize())
throw EvalError(format("from and to arguments to replaceStrings have different lengths, at %1%") % pos);
Strings from;
for (unsigned int n = 0; n < args[0]->listSize(); ++n)
from.push_back(state.forceStringNoCtx(*args[0]->listElems()[n], pos));
Strings to;
for (unsigned int n = 0; n < args[1]->listSize(); ++n)
to.push_back(state.forceStringNoCtx(*args[1]->listElems()[n], pos));
PathSet context;
auto s = state.forceString(*args[2], context, pos);
string res;
for (size_t p = 0; p < s.size(); ) {
bool found = false;
for (auto i = from.begin(), j = to.begin(); i != from.end(); ++i, ++j)
if (s.compare(p, i->size(), *i) == 0) {
found = true;
p += i->size();
res += *j;
break;
}
if (!found) res += s[p++];
}
mkString(v, res, context);
}
/*************************************************************
* Versions
*************************************************************/
@@ -1646,6 +1809,11 @@ void EvalState::createBaseEnv()
addPrimOp("__elem", 2, prim_elem);
addPrimOp("__concatLists", 1, prim_concatLists);
addPrimOp("__length", 1, prim_length);
addPrimOp("__foldl'", 3, prim_foldlStrict);
addPrimOp("__any", 2, prim_any);
addPrimOp("__all", 2, prim_all);
addPrimOp("__genList", 2, prim_genList);
addPrimOp("__sort", 2, prim_sort);
// Integer arithmetic
addPrimOp("__add", 2, prim_add);
@@ -1662,6 +1830,8 @@ void EvalState::createBaseEnv()
addPrimOp("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency);
addPrimOp("__hashString", 2, prim_hashString);
addPrimOp("__match", 2, prim_match);
addPrimOp("__concatStringsSep", 2, prim_concatStringSep);
addPrimOp("__replaceStrings", 3, prim_replaceStrings);
// Versions
addPrimOp("__parseDrvName", 1, prim_parseDrvName);
@@ -1685,7 +1855,7 @@ void EvalState::createBaseEnv()
mkList(v, searchPath.size());
int n = 0;
for (auto & i : searchPath) {
v2 = v.list.elems[n++] = allocValue();
v2 = v.listElems()[n++] = allocValue();
mkAttrs(*v2, 2);
mkString(*allocAttr(*v2, symbols.create("path")), i.second);
mkString(*allocAttr(*v2, symbols.create("prefix")), i.first);
+17 -17
View File
@@ -12,14 +12,14 @@ namespace nix {
void escapeJSON(std::ostream & str, const string & s)
{
str << "\"";
foreach (string::const_iterator, i, s)
if (*i == '\"' || *i == '\\') str << "\\" << *i;
else if (*i == '\n') str << "\\n";
else if (*i == '\r') str << "\\r";
else if (*i == '\t') str << "\\t";
else if (*i >= 0 && *i < 32)
str << "\\u" << std::setfill('0') << std::setw(4) << std::hex << (uint16_t) *i << std::dec;
else str << *i;
for (auto & i : s)
if (i == '\"' || i == '\\') str << "\\" << i;
else if (i == '\n') str << "\\n";
else if (i == '\r') str << "\\r";
else if (i == '\t') str << "\\t";
else if (i >= 0 && i < 32)
str << "\\u" << std::setfill('0') << std::setw(4) << std::hex << (uint16_t) i << std::dec;
else str << i;
str << "\"";
}
@@ -59,11 +59,11 @@ void printValueAsJSON(EvalState & state, bool strict,
if (i == v.attrs->end()) {
JSONObject json(str);
StringSet names;
foreach (Bindings::iterator, i, *v.attrs)
names.insert(i->name);
foreach (StringSet::iterator, i, names) {
Attr & a(*v.attrs->find(state.symbols.create(*i)));
json.attr(*i);
for (auto & j : *v.attrs)
names.insert(j.name);
for (auto & j : names) {
Attr & a(*v.attrs->find(state.symbols.create(j)));
json.attr(j);
printValueAsJSON(state, strict, *a.value, str, context);
}
} else
@@ -71,16 +71,16 @@ void printValueAsJSON(EvalState & state, bool strict,
break;
}
case tList: {
case tList1: case tList2: case tListN: {
JSONList json(str);
for (unsigned int n = 0; n < v.list.length; ++n) {
for (unsigned int n = 0; n < v.listSize(); ++n) {
json.elem();
printValueAsJSON(state, strict, *v.list.elems[n], str, context);
printValueAsJSON(state, strict, *v.listElems()[n], str, context);
}
break;
}
case tExternal:
case tExternal:
v.external->printValueAsJSON(state, strict, str, context);
break;
+23 -23
View File
@@ -8,7 +8,7 @@
namespace nix {
static XMLAttrs singletonAttrs(const string & name, const string & value)
{
XMLAttrs attrs;
@@ -33,17 +33,17 @@ static void showAttrs(EvalState & state, bool strict, bool location,
Bindings & attrs, XMLWriter & doc, PathSet & context, PathSet & drvsSeen)
{
StringSet names;
foreach (Bindings::iterator, i, attrs)
names.insert(i->name);
foreach (StringSet::iterator, i, names) {
Attr & a(*attrs.find(state.symbols.create(*i)));
for (auto & i : attrs)
names.insert(i.name);
for (auto & i : names) {
Attr & a(*attrs.find(state.symbols.create(i)));
XMLAttrs xmlAttrs;
xmlAttrs["name"] = *i;
xmlAttrs["name"] = i;
if (location && a.pos != &noPos) posToXML(xmlAttrs, *a.pos);
XMLOpenElement _(doc, "attr", xmlAttrs);
printValueAsXML(state, strict, location,
*a.value, doc, context, drvsSeen);
@@ -57,7 +57,7 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
checkInterrupt();
if (strict) state.forceValue(v);
switch (v.type) {
case tInt:
@@ -85,7 +85,7 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
case tAttrs:
if (state.isDerivation(v)) {
XMLAttrs xmlAttrs;
Bindings::iterator a = v.attrs->find(state.symbols.create("derivation"));
Path drvPath;
@@ -95,7 +95,7 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
if (a->value->type == tString)
xmlAttrs["drvPath"] = drvPath = a->value->string.s;
}
a = v.attrs->find(state.sOutPath);
if (a != v.attrs->end()) {
if (strict) state.forceValue(*a->value);
@@ -116,13 +116,13 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
XMLOpenElement _(doc, "attrs");
showAttrs(state, strict, location, *v.attrs, doc, context, drvsSeen);
}
break;
case tList: {
case tList1: case tList2: case tListN: {
XMLOpenElement _(doc, "list");
for (unsigned int n = 0; n < v.list.length; ++n)
printValueAsXML(state, strict, location, *v.list.elems[n], doc, context, drvsSeen);
for (unsigned int n = 0; n < v.listSize(); ++n)
printValueAsXML(state, strict, location, *v.listElems()[n], doc, context, drvsSeen);
break;
}
@@ -130,17 +130,17 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
XMLAttrs xmlAttrs;
if (location) posToXML(xmlAttrs, v.lambda.fun->pos);
XMLOpenElement _(doc, "function", xmlAttrs);
if (v.lambda.fun->matchAttrs) {
XMLAttrs attrs;
if (!v.lambda.fun->arg.empty()) attrs["name"] = v.lambda.fun->arg;
if (v.lambda.fun->formals->ellipsis) attrs["ellipsis"] = "1";
XMLOpenElement _(doc, "attrspat", attrs);
foreach (Formals::Formals_::iterator, i, v.lambda.fun->formals->formals)
doc.writeEmptyElement("attr", singletonAttrs("name", i->name));
for (auto & i : v.lambda.fun->formals->formals)
doc.writeEmptyElement("attr", singletonAttrs("name", i.name));
} else
doc.writeEmptyElement("varpat", singletonAttrs("name", v.lambda.fun->arg));
break;
}
@@ -166,9 +166,9 @@ void printValueAsXML(EvalState & state, bool strict, bool location,
{
XMLWriter doc(true, out);
XMLOpenElement root(doc, "expr");
PathSet drvsSeen;
PathSet drvsSeen;
printValueAsXML(state, strict, location, v, doc, context, drvsSeen);
}
}
+26 -3
View File
@@ -12,7 +12,9 @@ typedef enum {
tPath,
tNull,
tAttrs,
tList,
tList1,
tList2,
tListN,
tThunk,
tApp,
tLambda,
@@ -119,9 +121,10 @@ struct Value
const char * path;
Bindings * attrs;
struct {
unsigned int length;
unsigned int size;
Value * * elems;
} list;
} bigList;
Value * smallList[2];
struct {
Env * env;
Expr * expr;
@@ -139,6 +142,26 @@ struct Value
} primOpApp;
ExternalValueBase * external;
};
bool isList() const
{
return type == tList1 || type == tList2 || type == tListN;
}
Value * * listElems()
{
return type == tList1 || type == tList2 ? smallList : bigList.elems;
}
const Value * const * listElems() const
{
return type == tList1 || type == tList2 ? smallList : bigList.elems;
}
unsigned int listSize() const
{
return type == tList1 ? 1 : type == tList2 ? 2 : bigList.size;
}
};
+18
View File
@@ -90,6 +90,7 @@ static void setLogType(string lt)
if (lt == "pretty") logType = ltPretty;
else if (lt == "escapes") logType = ltEscapes;
else if (lt == "flat") logType = ltFlat;
else if (lt == "systemd") logType = ltSystemd;
else throw UsageError("unknown log type");
}
@@ -116,6 +117,9 @@ void initNix()
std::ios::sync_with_stdio(false);
if (getEnv("IN_SYSTEMD") == "1")
logType = ltSystemd;
settings.processEnvironment();
settings.loadConfFile();
@@ -239,6 +243,20 @@ void parseCmdLine(int argc, char * * argv,
void printVersion(const string & programName)
{
std::cout << format("%1% (Nix) %2%") % programName % nixVersion << std::endl;
if (verbosity > lvlInfo) {
Strings cfg;
#if HAVE_BOEHMGC
cfg.push_back("gc");
#endif
#if HAVE_SODIUM
cfg.push_back("signed-caches");
#endif
std::cout << "Features: " << concatStringsSep(", ", cfg) << "\n";
std::cout << "Configuration file: " << settings.nixConfDir + "/nix.conf" << "\n";
std::cout << "Store directory: " << settings.nixStore << "\n";
std::cout << "State directory: " << settings.nixStateDir << "\n";
std::cout << "Database directory: " << settings.nixDBPath << "\n";
}
throw Exit();
}
+429 -298
View File
File diff suppressed because it is too large Load Diff
+24
View File
@@ -0,0 +1,24 @@
#include "builtins.hh"
#include "download.hh"
namespace nix {
void builtinFetchurl(const BasicDerivation & drv)
{
auto url = drv.env.find("url");
if (url == drv.env.end()) throw Error("attribute url missing");
printMsg(lvlInfo, format("downloading %1%...") % url->second);
auto data = downloadFile(url->second); // FIXME: show progress
auto out = drv.env.find("out");
if (out == drv.env.end()) throw Error("attribute url missing");
writeFile(out->second, data.data);
auto executable = drv.env.find("executable");
if (executable != drv.env.end() && executable->second == "1") {
if (chmod(out->second.c_str(), 0755) == -1)
throw SysError(format("making %1% executable") % out->second);
}
}
}
+9
View File
@@ -0,0 +1,9 @@
#pragma once
#include "derivations.hh"
namespace nix {
void builtinFetchurl(const BasicDerivation & drv);
}
+61 -20
View File
@@ -3,6 +3,7 @@
#include "globals.hh"
#include "util.hh"
#include "misc.hh"
#include "worker-protocol.hh"
namespace nix {
@@ -31,8 +32,8 @@ Path writeDerivation(StoreAPI & store,
{
PathSet references;
references.insert(drv.inputSrcs.begin(), drv.inputSrcs.end());
foreach (DerivationInputs::const_iterator, i, drv.inputDrvs)
references.insert(i->first);
for (auto & i : drv.inputDrvs)
references.insert(i.first);
/* Note that the outputs of a derivation are *not* references
(that can be missing (of course) and should not necessarily be
held during a garbage collection). */
@@ -155,21 +156,21 @@ string unparseDerivation(const Derivation & drv)
s += "Derive([";
bool first = true;
foreach (DerivationOutputs::const_iterator, i, drv.outputs) {
for (auto & i : drv.outputs) {
if (first) first = false; else s += ',';
s += '('; printString(s, i->first);
s += ','; printString(s, i->second.path);
s += ','; printString(s, i->second.hashAlgo);
s += ','; printString(s, i->second.hash);
s += '('; printString(s, i.first);
s += ','; printString(s, i.second.path);
s += ','; printString(s, i.second.hashAlgo);
s += ','; printString(s, i.second.hash);
s += ')';
}
s += "],[";
first = true;
foreach (DerivationInputs::const_iterator, i, drv.inputDrvs) {
for (auto & i : drv.inputDrvs) {
if (first) first = false; else s += ',';
s += '('; printString(s, i->first);
s += ','; printStrings(s, i->second.begin(), i->second.end());
s += '('; printString(s, i.first);
s += ','; printStrings(s, i.second.begin(), i.second.end());
s += ')';
}
@@ -182,10 +183,10 @@ string unparseDerivation(const Derivation & drv)
s += ",[";
first = true;
foreach (StringPairs::const_iterator, i, drv.env) {
for (auto & i : drv.env) {
if (first) first = false; else s += ',';
s += '('; printString(s, i->first);
s += ','; printString(s, i->second);
s += '('; printString(s, i.first);
s += ','; printString(s, i.second);
s += ')';
}
@@ -246,15 +247,15 @@ Hash hashDerivationModulo(StoreAPI & store, Derivation drv)
/* For other derivations, replace the inputs paths with recursive
calls to this function.*/
DerivationInputs inputs2;
foreach (DerivationInputs::const_iterator, i, drv.inputDrvs) {
Hash h = drvHashes[i->first];
for (auto & i : drv.inputDrvs) {
Hash h = drvHashes[i.first];
if (h.type == htUnknown) {
assert(store.isValidPath(i->first));
Derivation drv2 = readDerivation(i->first);
assert(store.isValidPath(i.first));
Derivation drv2 = readDerivation(i.first);
h = hashDerivationModulo(store, drv2);
drvHashes[i->first] = h;
drvHashes[i.first] = h;
}
inputs2[printHash(h)] = i->second;
inputs2[printHash(h)] = i.second;
}
drv.inputDrvs = inputs2;
@@ -285,7 +286,7 @@ bool wantOutput(const string & output, const std::set<string> & wanted)
}
PathSet outputPaths(const Derivation & drv)
PathSet outputPaths(const BasicDerivation & drv)
{
PathSet paths;
for (auto & i : drv.outputs)
@@ -294,4 +295,44 @@ PathSet outputPaths(const Derivation & drv)
}
Source & operator >> (Source & in, BasicDerivation & drv)
{
drv.outputs.clear();
auto nr = readInt(in);
for (unsigned int n = 0; n < nr; n++) {
auto name = readString(in);
DerivationOutput o;
in >> o.path >> o.hashAlgo >> o.hash;
assertStorePath(o.path);
drv.outputs[name] = o;
}
drv.inputSrcs = readStorePaths<PathSet>(in);
in >> drv.platform >> drv.builder;
drv.args = readStrings<Strings>(in);
nr = readInt(in);
for (unsigned int n = 0; n < nr; n++) {
auto key = readString(in);
auto value = readString(in);
drv.env[key] = value;
}
return in;
}
Sink & operator << (Sink & out, const BasicDerivation & drv)
{
out << drv.outputs.size();
for (auto & i : drv.outputs)
out << i.first << i.second.path << i.second.hashAlgo << i.second.hash;
out << drv.inputSrcs << drv.platform << drv.builder << drv.args;
out << drv.env.size();
for (auto & i : drv.env)
out << i.first << i.second;
return out;
}
}
+15 -3
View File
@@ -40,15 +40,21 @@ typedef std::map<Path, StringSet> DerivationInputs;
typedef std::map<string, string> StringPairs;
struct Derivation
struct BasicDerivation
{
DerivationOutputs outputs; /* keyed on symbolic IDs */
DerivationInputs inputDrvs; /* inputs that are sub-derivations */
PathSet inputSrcs; /* inputs that are sources */
string platform;
Path builder;
Strings args;
StringPairs env;
virtual ~BasicDerivation() { };
};
struct Derivation : BasicDerivation
{
DerivationInputs inputDrvs; /* inputs that are sub-derivations */
};
@@ -89,6 +95,12 @@ Path makeDrvPathWithOutputs(const Path & drvPath, const std::set<string> & outpu
bool wantOutput(const string & output, const std::set<string> & wanted);
PathSet outputPaths(const Derivation & drv);
PathSet outputPaths(const BasicDerivation & drv);
struct Source;
struct Sink;
Source & operator >> (Source & in, BasicDerivation & drv);
Sink & operator << (Sink & out, const BasicDerivation & drv);
}
+44 -30
View File
@@ -350,15 +350,14 @@ static void addAdditionalRoots(StoreAPI & store, PathSet & roots)
StringSet paths = tokenizeString<StringSet>(result, "\n");
foreach (StringSet::iterator, i, paths) {
if (isInStore(*i)) {
Path path = toStorePath(*i);
for (auto & i : paths)
if (isInStore(i)) {
Path path = toStorePath(i);
if (roots.find(path) == roots.end() && store.isValidPath(path)) {
debug(format("got additional root %1%") % path);
roots.insert(path);
}
}
}
}
@@ -376,6 +375,7 @@ struct LocalStore::GCState
bool gcKeepOutputs;
bool gcKeepDerivations;
unsigned long long bytesInvalidated;
bool moveToTrash = true;
Path trashDir;
bool shouldDelete;
GCState(GCResults & results_) : results(results_), bytesInvalidated(0) { }
@@ -407,8 +407,8 @@ void LocalStore::deletePathRecursive(GCState & state, const Path & path)
if (isValidPath(path)) {
PathSet referrers;
queryReferrers(path, referrers);
foreach (PathSet::iterator, i, referrers)
if (*i != path) deletePathRecursive(state, *i);
for (auto & i : referrers)
if (i != path) deletePathRecursive(state, i);
size = queryPathInfo(path).narSize;
invalidatePathChecked(path);
}
@@ -428,16 +428,23 @@ void LocalStore::deletePathRecursive(GCState & state, const Path & path)
not holding the global GC lock) we can delete the path without
being afraid that the path has become alive again. Otherwise
delete it right away. */
if (S_ISDIR(st.st_mode)) {
if (state.moveToTrash && S_ISDIR(st.st_mode)) {
// Estimate the amount freed using the narSize field. FIXME:
// if the path was not valid, need to determine the actual
// size.
state.bytesInvalidated += size;
if (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1)
throw SysError(format("making %1% writable") % path);
Path tmp = state.trashDir + "/" + baseNameOf(path);
if (rename(path.c_str(), tmp.c_str()))
throw SysError(format("unable to rename %1% to %2%") % path % tmp);
try {
if (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1)
throw SysError(format("making %1% writable") % path);
Path tmp = state.trashDir + "/" + baseNameOf(path);
if (rename(path.c_str(), tmp.c_str()))
throw SysError(format("unable to rename %1% to %2%") % path % tmp);
state.bytesInvalidated += size;
} catch (SysError & e) {
if (e.errNo == ENOSPC) {
printMsg(lvlInfo, format("note: can't create move %1%: %2%") % path % e.msg());
deleteGarbage(state, path);
}
}
} else
deleteGarbage(state, path);
@@ -479,22 +486,22 @@ bool LocalStore::canReachRoot(GCState & state, PathSet & visited, const Path & p
don't delete the derivation if any of the outputs are alive. */
if (state.gcKeepDerivations && isDerivation(path)) {
PathSet outputs = queryDerivationOutputs(path);
foreach (PathSet::iterator, i, outputs)
if (isValidPath(*i) && queryDeriver(*i) == path)
incoming.insert(*i);
for (auto & i : outputs)
if (isValidPath(i) && queryDeriver(i) == path)
incoming.insert(i);
}
/* If gc-keep-outputs is set, then don't delete this path if there
are derivers of this path that are not garbage. */
if (state.gcKeepOutputs) {
PathSet derivers = queryValidDerivers(path);
foreach (PathSet::iterator, i, derivers)
incoming.insert(*i);
for (auto & i : derivers)
incoming.insert(i);
}
foreach (PathSet::iterator, i, incoming)
if (*i != path)
if (canReachRoot(state, visited, *i)) {
for (auto & i : incoming)
if (i != path)
if (canReachRoot(state, visited, i)) {
state.alive.insert(path);
return true;
}
@@ -614,7 +621,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
printMsg(lvlError, format("finding garbage collector roots..."));
Roots rootMap = options.ignoreLiveness ? Roots() : findRoots();
foreach (Roots::iterator, i, rootMap) state.roots.insert(i->second);
for (auto & i : rootMap) state.roots.insert(i.second);
/* Add additional roots returned by the program specified by the
NIX_ROOT_FINDER environment variable. This is typically used
@@ -636,7 +643,14 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
if (state.shouldDelete) {
if (pathExists(state.trashDir)) deleteGarbage(state, state.trashDir);
createDirs(state.trashDir);
try {
createDirs(state.trashDir);
} catch (SysError & e) {
if (e.errNo == ENOSPC) {
printMsg(lvlInfo, format("note: can't create trash directory: %1%") % e.msg());
state.moveToTrash = false;
}
}
}
/* Now either delete all garbage paths, or just the specified
@@ -644,11 +658,11 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
if (options.action == GCOptions::gcDeleteSpecific) {
foreach (PathSet::iterator, i, options.pathsToDelete) {
assertStorePath(*i);
tryToDelete(state, *i);
if (state.dead.find(*i) == state.dead.end())
throw Error(format("cannot delete path %1% since it is still alive") % *i);
for (auto & i : options.pathsToDelete) {
assertStorePath(i);
tryToDelete(state, i);
if (state.dead.find(i) == state.dead.end())
throw Error(format("cannot delete path %1% since it is still alive") % i);
}
} else if (options.maxFreed > 0) {
@@ -692,8 +706,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
vector<Path> entries_(entries.begin(), entries.end());
random_shuffle(entries_.begin(), entries_.end());
foreach (vector<Path>::iterator, i, entries_)
tryToDelete(state, *i);
for (auto & i : entries_)
tryToDelete(state, i);
} catch (GCLimitReached & e) {
}
+9 -9
View File
@@ -41,7 +41,7 @@ Settings::Settings()
buildTimeout = 0;
useBuildHook = true;
printBuildTrace = false;
reservedSize = 1024 * 1024;
reservedSize = 8 * 1024 * 1024;
fsyncMetadata = true;
useSQLiteWAL = true;
syncBeforeRegistering = false;
@@ -248,12 +248,12 @@ template<class N> void Settings::_get(N & res, const string & name)
string Settings::pack()
{
string s;
foreach (SettingsMap::iterator, i, settings) {
if (i->first.find('\n') != string::npos ||
i->first.find('=') != string::npos ||
i->second.find('\n') != string::npos)
for (auto & i : settings) {
if (i.first.find('\n') != string::npos ||
i.first.find('=') != string::npos ||
i.second.find('\n') != string::npos)
throw Error("illegal option name/value");
s += i->first; s += '='; s += i->second; s += '\n';
s += i.first; s += '='; s += i.second; s += '\n';
}
return s;
}
@@ -261,11 +261,11 @@ string Settings::pack()
void Settings::unpack(const string & pack) {
Strings lines = tokenizeString<Strings>(pack, "\n");
foreach (Strings::iterator, i, lines) {
string::size_type eq = i->find('=');
for (auto & i : lines) {
string::size_type eq = i.find('=');
if (eq == string::npos)
throw Error("illegal option name/value");
set(i->substr(0, eq), i->substr(eq + 1));
set(i.substr(0, eq), i.substr(eq + 1));
}
}
+90 -86
View File
@@ -289,7 +289,17 @@ LocalStore::LocalStore(bool reserveSpace)
struct stat st;
if (stat(reservedPath.c_str(), &st) == -1 ||
st.st_size != settings.reservedSize)
writeFile(reservedPath, string(settings.reservedSize, 'X'));
{
AutoCloseFD fd = open(reservedPath.c_str(), O_WRONLY | O_CREAT, 0600);
int res = -1;
#if HAVE_POSIX_FALLOCATE
res = posix_fallocate(fd, 0, settings.reservedSize);
#endif
if (res == -1) {
writeFull(fd, string(settings.reservedSize, 'X'));
ftruncate(fd, settings.reservedSize);
}
}
}
else
deletePath(reservedPath);
@@ -357,13 +367,13 @@ LocalStore::LocalStore(bool reserveSpace)
LocalStore::~LocalStore()
{
try {
foreach (RunningSubstituters::iterator, i, runningSubstituters) {
if (i->second.disabled) continue;
i->second.to.close();
i->second.from.close();
i->second.error.close();
if (i->second.pid != -1)
i->second.pid.wait(true);
for (auto & i : runningSubstituters) {
if (i.second.disabled) continue;
i.second.to.close();
i.second.from.close();
i.second.error.close();
if (i.second.pid != -1)
i.second.pid.wait(true);
}
} catch (...) {
ignoreException();
@@ -661,19 +671,19 @@ void LocalStore::checkDerivationOutputs(const Path & drvPath, const Derivation &
else {
Derivation drvCopy(drv);
foreach (DerivationOutputs::iterator, i, drvCopy.outputs) {
i->second.path = "";
drvCopy.env[i->first] = "";
for (auto & i : drvCopy.outputs) {
i.second.path = "";
drvCopy.env[i.first] = "";
}
Hash h = hashDerivationModulo(*this, drvCopy);
foreach (DerivationOutputs::const_iterator, i, drv.outputs) {
Path outPath = makeOutputPath(i->first, h, drvName);
StringPairs::const_iterator j = drv.env.find(i->first);
if (i->second.path != outPath || j == drv.env.end() || j->second != outPath)
for (auto & i : drv.outputs) {
Path outPath = makeOutputPath(i.first, h, drvName);
StringPairs::const_iterator j = drv.env.find(i.first);
if (i.second.path != outPath || j == drv.env.end() || j->second != outPath)
throw Error(format("derivation %1% has incorrect output %2%, should be %3%")
% drvPath % i->second.path % outPath);
% drvPath % i.second.path % outPath);
}
}
}
@@ -711,11 +721,11 @@ unsigned long long LocalStore::addValidPath(const ValidPathInfo & info, bool che
registration above is undone. */
if (checkOutputs) checkDerivationOutputs(info.path, drv);
foreach (DerivationOutputs::iterator, i, drv.outputs) {
for (auto & i : drv.outputs) {
SQLiteStmtUse use(stmtAddDerivationOutput);
stmtAddDerivationOutput.bind(id);
stmtAddDerivationOutput.bind(i->first);
stmtAddDerivationOutput.bind(i->second.path);
stmtAddDerivationOutput.bind(i.first);
stmtAddDerivationOutput.bind(i.second.path);
if (sqlite3_step(stmtAddDerivationOutput) != SQLITE_DONE)
throwSQLiteError(db, format("adding derivation output for %1% in database") % info.path);
}
@@ -786,11 +796,11 @@ void LocalStore::clearFailedPaths(const PathSet & paths)
retry_sqlite {
SQLiteTxn txn(db);
foreach (PathSet::const_iterator, i, paths) {
for (auto & i : paths) {
SQLiteStmtUse use(stmtClearFailedPath);
stmtClearFailedPath.bind(*i);
stmtClearFailedPath.bind(i);
if (sqlite3_step(stmtClearFailedPath) != SQLITE_DONE)
throwSQLiteError(db, format("clearing failed path %1% in database") % *i);
throwSQLiteError(db, format("clearing failed path %1% in database") % i);
}
txn.commit();
@@ -913,8 +923,8 @@ PathSet LocalStore::queryValidPaths(const PathSet & paths)
{
retry_sqlite {
PathSet res;
foreach (PathSet::const_iterator, i, paths)
if (isValidPath_(*i)) res.insert(*i);
for (auto & i : paths)
if (isValidPath_(i)) res.insert(i);
return res;
} end_retry_sqlite;
}
@@ -1202,14 +1212,14 @@ template<class T> T LocalStore::getIntLineFromSubstituter(RunningSubstituter & r
PathSet LocalStore::querySubstitutablePaths(const PathSet & paths)
{
PathSet res;
foreach (Paths::iterator, i, settings.substituters) {
for (auto & i : settings.substituters) {
if (res.size() == paths.size()) break;
RunningSubstituter & run(runningSubstituters[*i]);
startSubstituter(*i, run);
RunningSubstituter & run(runningSubstituters[i]);
startSubstituter(i, run);
if (run.disabled) continue;
string s = "have ";
foreach (PathSet::const_iterator, j, paths)
if (res.find(*j) == res.end()) { s += *j; s += " "; }
for (auto & j : paths)
if (res.find(j) == res.end()) { s += j; s += " "; }
writeLine(run.to, s);
while (true) {
/* FIXME: we only read stderr when an error occurs, so
@@ -1233,8 +1243,8 @@ void LocalStore::querySubstitutablePathInfos(const Path & substituter,
if (run.disabled) return;
string s = "info ";
foreach (PathSet::const_iterator, i, paths)
if (infos.find(*i) == infos.end()) { s += *i; s += " "; }
for (auto & i : paths)
if (infos.find(i) == infos.end()) { s += i; s += " "; }
writeLine(run.to, s);
while (true) {
@@ -1262,9 +1272,9 @@ void LocalStore::querySubstitutablePathInfos(const PathSet & paths,
SubstitutablePathInfos & infos)
{
PathSet todo = paths;
foreach (Paths::iterator, i, settings.substituters) {
for (auto & i : settings.substituters) {
if (todo.empty()) break;
querySubstitutablePathInfos(*i, todo, infos);
querySubstitutablePathInfos(i, todo, infos);
}
}
@@ -1294,30 +1304,30 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos)
SQLiteTxn txn(db);
PathSet paths;
foreach (ValidPathInfos::const_iterator, i, infos) {
assert(i->hash.type == htSHA256);
if (isValidPath_(i->path))
updatePathInfo(*i);
for (auto & i : infos) {
assert(i.hash.type == htSHA256);
if (isValidPath_(i.path))
updatePathInfo(i);
else
addValidPath(*i, false);
paths.insert(i->path);
addValidPath(i, false);
paths.insert(i.path);
}
foreach (ValidPathInfos::const_iterator, i, infos) {
unsigned long long referrer = queryValidPathId(i->path);
foreach (PathSet::iterator, j, i->references)
addReference(referrer, queryValidPathId(*j));
for (auto & i : infos) {
unsigned long long referrer = queryValidPathId(i.path);
for (auto & j : i.references)
addReference(referrer, queryValidPathId(j));
}
/* Check that the derivation outputs are correct. We can't do
this in addValidPath() above, because the references might
not be valid yet. */
foreach (ValidPathInfos::const_iterator, i, infos)
if (isDerivation(i->path)) {
for (auto & i : infos)
if (isDerivation(i.path)) {
// FIXME: inefficient; we already loaded the
// derivation in addValidPath().
Derivation drv = readDerivation(i->path);
checkDerivationOutputs(i->path, drv);
Derivation drv = readDerivation(i.path);
checkDerivationOutputs(i.path, drv);
}
/* Do a topological sort of the paths. This will throw an
@@ -1500,7 +1510,7 @@ void LocalStore::exportPath(const Path & path, bool sign,
{
assertStorePath(path);
printMsg(lvlInfo, format("exporting path %1%") % path);
printMsg(lvlTalkative, format("exporting path %1%") % path);
if (!isValidPath(path))
throw Error(format("path %1% is not valid") % path);
@@ -1518,22 +1528,14 @@ void LocalStore::exportPath(const Path & path, bool sign,
throw Error(format("hash of path %1% has changed from %2% to %3%!") % path
% printHash(storedHash) % printHash(hash));
writeInt(EXPORT_MAGIC, hashAndWriteSink);
writeString(path, hashAndWriteSink);
PathSet references;
queryReferences(path, references);
writeStrings(references, hashAndWriteSink);
Path deriver = queryDeriver(path);
writeString(deriver, hashAndWriteSink);
hashAndWriteSink << EXPORT_MAGIC << path << references << queryDeriver(path);
if (sign) {
Hash hash = hashAndWriteSink.currentHash();
writeInt(1, hashAndWriteSink);
Path tmpDir = createTempDir();
AutoDelete delTmp(tmpDir);
Path hashFile = tmpDir + "/hash";
@@ -1551,10 +1553,10 @@ void LocalStore::exportPath(const Path & path, bool sign,
args.push_back(hashFile);
string signature = runProgram(OPENSSL_PATH, true, args);
writeString(signature, hashAndWriteSink);
hashAndWriteSink << 1 << signature;
} else
writeInt(0, hashAndWriteSink);
hashAndWriteSink << 0;
}
@@ -1611,6 +1613,8 @@ Path LocalStore::importPath(bool requireSignature, Source & source)
Path dstPath = readStorePath(hashAndReadSource);
printMsg(lvlTalkative, format("importing path %1%") % dstPath);
PathSet references = readStorePaths<PathSet>(hashAndReadSource);
Path deriver = readString(hashAndReadSource);
@@ -1751,8 +1755,8 @@ bool LocalStore::verifyStore(bool checkContents, bool repair)
PathSet validPaths2 = queryAllValidPaths(), validPaths, done;
foreach (PathSet::iterator, i, validPaths2)
verifyPath(*i, store, done, validPaths, repair, errors);
for (auto & i : validPaths2)
verifyPath(i, store, done, validPaths, repair, errors);
/* Release the GC lock so that checking content hashes (which can
take ages) doesn't block the GC or builds. */
@@ -1764,33 +1768,33 @@ bool LocalStore::verifyStore(bool checkContents, bool repair)
Hash nullHash(htSHA256);
foreach (PathSet::iterator, i, validPaths) {
for (auto & i : validPaths) {
try {
ValidPathInfo info = queryPathInfo(*i);
ValidPathInfo info = queryPathInfo(i);
/* Check the content hash (optionally - slow). */
printMsg(lvlTalkative, format("checking contents of %1%") % *i);
HashResult current = hashPath(info.hash.type, *i);
printMsg(lvlTalkative, format("checking contents of %1%") % i);
HashResult current = hashPath(info.hash.type, i);
if (info.hash != nullHash && info.hash != current.first) {
printMsg(lvlError, format("path %1% was modified! "
"expected hash %2%, got %3%")
% *i % printHash(info.hash) % printHash(current.first));
if (repair) repairPath(*i); else errors = true;
% i % printHash(info.hash) % printHash(current.first));
if (repair) repairPath(i); else errors = true;
} else {
bool update = false;
/* Fill in missing hashes. */
if (info.hash == nullHash) {
printMsg(lvlError, format("fixing missing hash on %1%") % *i);
printMsg(lvlError, format("fixing missing hash on %1%") % i);
info.hash = current.first;
update = true;
}
/* Fill in missing narSize fields (from old stores). */
if (info.narSize == 0) {
printMsg(lvlError, format("updating size field on %1% to %2%") % *i % current.second);
printMsg(lvlError, format("updating size field on %1% to %2%") % i % current.second);
info.narSize = current.second;
update = true;
}
@@ -1802,7 +1806,7 @@ bool LocalStore::verifyStore(bool checkContents, bool repair)
} catch (Error & e) {
/* It's possible that the path got GC'ed, so ignore
errors on invalid paths. */
if (isValidPath(*i))
if (isValidPath(i))
printMsg(lvlError, format("error: %1%") % e.msg());
else
printMsg(lvlError, format("warning: %1%") % e.msg());
@@ -1834,10 +1838,10 @@ void LocalStore::verifyPath(const Path & path, const PathSet & store,
first, then we can invalidate this path as well. */
bool canInvalidate = true;
PathSet referrers; queryReferrers(path, referrers);
foreach (PathSet::iterator, i, referrers)
if (*i != path) {
verifyPath(*i, store, done, validPaths, repair, errors);
if (validPaths.find(*i) != validPaths.end())
for (auto & i : referrers)
if (i != path) {
verifyPath(i, store, done, validPaths, repair, errors);
if (validPaths.find(i) != validPaths.end())
canInvalidate = false;
}
@@ -1915,12 +1919,12 @@ ValidPathInfo LocalStore::queryPathInfoOld(const Path & path)
/* Parse it. */
Strings lines = tokenizeString<Strings>(info, "\n");
foreach (Strings::iterator, i, lines) {
string::size_type p = i->find(':');
for (auto & i : lines) {
string::size_type p = i.find(':');
if (p == string::npos)
throw Error(format("corrupt line in %1%: %2%") % infoFile % *i);
string name(*i, 0, p);
string value(*i, p + 2);
throw Error(format("corrupt line in %1%: %2%") % infoFile % i);
string name(i, 0, p);
string value(i, p + 2);
if (name == "References") {
Strings refs = tokenizeString<Strings>(value, " ");
res.references = PathSet(refs.begin(), refs.end());
@@ -1950,18 +1954,18 @@ void LocalStore::upgradeStore6()
SQLiteTxn txn(db);
foreach (PathSet::iterator, i, validPaths) {
addValidPath(queryPathInfoOld(*i), false);
for (auto & i : validPaths) {
addValidPath(queryPathInfoOld(i), false);
std::cerr << ".";
}
std::cerr << "|";
foreach (PathSet::iterator, i, validPaths) {
ValidPathInfo info = queryPathInfoOld(*i);
unsigned long long referrer = queryValidPathId(*i);
foreach (PathSet::iterator, j, info.references)
addReference(referrer, queryValidPathId(*j));
for (auto & i : validPaths) {
ValidPathInfo info = queryPathInfoOld(i);
unsigned long long referrer = queryValidPathId(i);
for (auto & j : info.references)
addReference(referrer, queryValidPathId(j));
std::cerr << ".";
}
+3
View File
@@ -151,6 +151,9 @@ public:
void buildPaths(const PathSet & paths, BuildMode buildMode);
BuildResult buildDerivation(const Path & drvPath, const BasicDerivation & drv,
BuildMode buildMode) override;
void ensurePath(const Path & path);
void addTempRoot(const Path & path);
+1 -1
View File
@@ -8,7 +8,7 @@ libstore_SOURCES := $(wildcard $(d)/*.cc)
libstore_LIBS = libutil libformat
libstore_LDFLAGS = -lsqlite3 -lbz2
libstore_LDFLAGS = -lsqlite3 -lbz2 -lcurl
ifeq ($(OS), SunOS)
libstore_LDFLAGS += -lsocket
+43 -43
View File
@@ -28,15 +28,15 @@ void computeFSClosure(StoreAPI & store, const Path & path,
if (includeOutputs) {
PathSet derivers = store.queryValidDerivers(path);
foreach (PathSet::iterator, i, derivers)
edges.insert(*i);
for (auto & i : derivers)
edges.insert(i);
}
if (includeDerivers && isDerivation(path)) {
PathSet outputs = store.queryDerivationOutputs(path);
foreach (PathSet::iterator, i, outputs)
if (store.isValidPath(*i) && store.queryDeriver(*i) == path)
edges.insert(*i);
for (auto & i : outputs)
if (store.isValidPath(i) && store.queryDeriver(i) == path)
edges.insert(i);
}
} else {
@@ -44,8 +44,8 @@ void computeFSClosure(StoreAPI & store, const Path & path,
if (includeOutputs && isDerivation(path)) {
PathSet outputs = store.queryDerivationOutputs(path);
foreach (PathSet::iterator, i, outputs)
if (store.isValidPath(*i)) edges.insert(*i);
for (auto & i : outputs)
if (store.isValidPath(i)) edges.insert(i);
}
if (includeDerivers) {
@@ -54,15 +54,15 @@ void computeFSClosure(StoreAPI & store, const Path & path,
}
}
foreach (PathSet::iterator, i, edges)
computeFSClosure(store, *i, paths, flipDirection, includeOutputs, includeDerivers);
for (auto & i : edges)
computeFSClosure(store, i, paths, flipDirection, includeOutputs, includeDerivers);
}
Path findOutput(const Derivation & drv, string id)
{
foreach (DerivationOutputs::const_iterator, i, drv.outputs)
if (i->first == id) return i->second.path;
for (auto & i : drv.outputs)
if (i.first == id) return i.second.path;
throw Error(format("derivation has no output %1%") % id);
}
@@ -98,36 +98,36 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
PathSet query, todoDrv, todoNonDrv;
foreach (PathSet::iterator, i, todo) {
if (done.find(*i) != done.end()) continue;
done.insert(*i);
for (auto & i : todo) {
if (done.find(i) != done.end()) continue;
done.insert(i);
DrvPathWithOutputs i2 = parseDrvPathWithOutputs(*i);
DrvPathWithOutputs i2 = parseDrvPathWithOutputs(i);
if (isDerivation(i2.first)) {
if (!store.isValidPath(i2.first)) {
// FIXME: we could try to substitute p.
unknown.insert(*i);
unknown.insert(i);
continue;
}
Derivation drv = derivationFromPath(store, i2.first);
PathSet invalid;
foreach (DerivationOutputs::iterator, j, drv.outputs)
if (wantOutput(j->first, i2.second)
&& !store.isValidPath(j->second.path))
invalid.insert(j->second.path);
for (auto & j : drv.outputs)
if (wantOutput(j.first, i2.second)
&& !store.isValidPath(j.second.path))
invalid.insert(j.second.path);
if (invalid.empty()) continue;
todoDrv.insert(*i);
todoDrv.insert(i);
if (settings.useSubstitutes && substitutesAllowed(drv))
query.insert(invalid.begin(), invalid.end());
}
else {
if (store.isValidPath(*i)) continue;
query.insert(*i);
todoNonDrv.insert(*i);
if (store.isValidPath(i)) continue;
query.insert(i);
todoNonDrv.insert(i);
}
}
@@ -136,8 +136,8 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
SubstitutablePathInfos infos;
store.querySubstitutablePathInfos(query, infos);
foreach (PathSet::iterator, i, todoDrv) {
DrvPathWithOutputs i2 = parseDrvPathWithOutputs(*i);
for (auto & i : todoDrv) {
DrvPathWithOutputs i2 = parseDrvPathWithOutputs(i);
// FIXME: cache this
Derivation drv = derivationFromPath(store, i2.first);
@@ -145,13 +145,13 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
PathSet outputs;
bool mustBuild = false;
if (settings.useSubstitutes && substitutesAllowed(drv)) {
foreach (DerivationOutputs::iterator, j, drv.outputs) {
if (!wantOutput(j->first, i2.second)) continue;
if (!store.isValidPath(j->second.path)) {
if (infos.find(j->second.path) == infos.end())
for (auto & j : drv.outputs) {
if (!wantOutput(j.first, i2.second)) continue;
if (!store.isValidPath(j.second.path)) {
if (infos.find(j.second.path) == infos.end())
mustBuild = true;
else
outputs.insert(j->second.path);
outputs.insert(j.second.path);
}
}
} else
@@ -160,22 +160,22 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
if (mustBuild) {
willBuild.insert(i2.first);
todo.insert(drv.inputSrcs.begin(), drv.inputSrcs.end());
foreach (DerivationInputs::iterator, j, drv.inputDrvs)
todo.insert(makeDrvPathWithOutputs(j->first, j->second));
for (auto & j : drv.inputDrvs)
todo.insert(makeDrvPathWithOutputs(j.first, j.second));
} else
todoNonDrv.insert(outputs.begin(), outputs.end());
}
foreach (PathSet::iterator, i, todoNonDrv) {
done.insert(*i);
SubstitutablePathInfos::iterator info = infos.find(*i);
for (auto & i : todoNonDrv) {
done.insert(i);
SubstitutablePathInfos::iterator info = infos.find(i);
if (info != infos.end()) {
willSubstitute.insert(*i);
willSubstitute.insert(i);
downloadSize += info->second.downloadSize;
narSize += info->second.narSize;
todo.insert(info->second.references.begin(), info->second.references.end());
} else
unknown.insert(*i);
unknown.insert(i);
}
}
}
@@ -196,11 +196,11 @@ static void dfsVisit(StoreAPI & store, const PathSet & paths,
if (store.isValidPath(path))
store.queryReferences(path, references);
foreach (PathSet::iterator, i, references)
for (auto & i : references)
/* Don't traverse into paths that don't exist. That can
happen due to substitutes for non-existent paths. */
if (*i != path && paths.find(*i) != paths.end())
dfsVisit(store, paths, *i, visited, sorted, parents);
if (i != path && paths.find(i) != paths.end())
dfsVisit(store, paths, i, visited, sorted, parents);
sorted.push_front(path);
parents.erase(path);
@@ -211,8 +211,8 @@ Paths topoSortPaths(StoreAPI & store, const PathSet & paths)
{
Paths sorted;
PathSet visited, parents;
foreach (PathSet::const_iterator, i, paths)
dfsVisit(store, paths, *i, visited, sorted, parents);
for (auto & i : paths)
dfsVisit(store, paths, i, visited, sorted, parents);
return sorted;
}
+2 -2
View File
@@ -32,9 +32,9 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
PathSet & willBuild, PathSet & willSubstitute, PathSet & unknown,
unsigned long long & downloadSize, unsigned long long & narSize);
bool willBuildLocally(const Derivation & drv);
bool willBuildLocally(const BasicDerivation & drv);
bool substitutesAllowed(const Derivation & drv);
bool substitutesAllowed(const BasicDerivation & drv);
}
+7 -7
View File
@@ -99,8 +99,8 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa
if (S_ISDIR(st.st_mode)) {
Strings names = readDirectoryIgnoringInodes(path, inodeHash);
foreach (Strings::iterator, i, names)
optimisePath_(stats, path + "/" + *i, inodeHash);
for (auto & i : names)
optimisePath_(stats, path + "/" + i, inodeHash);
return;
}
@@ -218,11 +218,11 @@ void LocalStore::optimiseStore(OptimiseStats & stats)
PathSet paths = queryAllValidPaths();
InodeHash inodeHash = loadInodeHash();
foreach (PathSet::iterator, i, paths) {
addTempRoot(*i);
if (!isValidPath(*i)) continue; /* path was GC'ed, probably */
startNest(nest, lvlChatty, format("hashing files in %1%") % *i);
optimisePath_(stats, *i, inodeHash);
for (auto & i : paths) {
addTempRoot(i);
if (!isValidPath(i)) continue; /* path was GC'ed, probably */
startNest(nest, lvlChatty, format("hashing files in %1%") % i);
optimisePath_(stats, i, inodeHash);
}
}
+13 -14
View File
@@ -60,7 +60,7 @@ bool lockFile(int fd, LockType lockType, bool wait)
while (fcntl(fd, F_SETLK, &lock) != 0) {
checkInterrupt();
if (errno == EACCES || errno == EAGAIN) return false;
if (errno != EINTR)
if (errno != EINTR)
throw SysError(format("acquiring/releasing lock"));
}
}
@@ -94,7 +94,7 @@ bool PathLocks::lockPaths(const PathSet & _paths,
const string & waitMsg, bool wait)
{
assert(fds.empty());
/* Note that `fds' is built incrementally so that the destructor
will only release those locks that we have already acquired. */
@@ -102,11 +102,10 @@ bool PathLocks::lockPaths(const PathSet & _paths,
the same order, thus preventing deadlocks. */
Paths paths(_paths.begin(), _paths.end());
paths.sort();
/* Acquire the lock for each path. */
foreach (Paths::iterator, i, paths) {
for (auto & path : paths) {
checkInterrupt();
Path path = *i;
Path lockPath = path + ".lock";
debug(format("locking path %1%") % path);
@@ -115,11 +114,11 @@ bool PathLocks::lockPaths(const PathSet & _paths,
throw Error("deadlock: trying to re-acquire self-held lock");
AutoCloseFD fd;
while (1) {
/* Open/create the lock file. */
fd = openLockFile(lockPath, true);
fd = openLockFile(lockPath, true);
/* Acquire an exclusive lock. */
if (!lockFile(fd, ltWrite, false)) {
@@ -168,15 +167,15 @@ PathLocks::~PathLocks()
void PathLocks::unlock()
{
foreach (list<FDPair>::iterator, i, fds) {
if (deletePaths) deleteLockFile(i->second, i->first);
for (auto & i : fds) {
if (deletePaths) deleteLockFile(i.second, i.first);
lockedPaths.erase(i->second);
if (close(i->first) == -1)
lockedPaths.erase(i.second);
if (close(i.first) == -1)
printMsg(lvlError,
format("error (ignored): cannot close lock file on %1%") % i->second);
format("error (ignored): cannot close lock file on %1%") % i.second);
debug(format("lock released on %1%") % i->second);
debug(format("lock released on %1%") % i.second);
}
fds.clear();
@@ -195,5 +194,5 @@ bool pathIsLockedByMe(const Path & path)
return lockedPaths.find(lockPath) != lockedPaths.end();
}
}
+10 -10
View File
@@ -13,7 +13,7 @@ namespace nix {
static unsigned int refLength = 32; /* characters */
static void search(const unsigned char * s, unsigned int len,
static void search(const unsigned char * s, unsigned int len,
StringSet & hashes, StringSet & seen)
{
static bool initialised = false;
@@ -24,7 +24,7 @@ static void search(const unsigned char * s, unsigned int len,
isBase32[(unsigned char) base32Chars[i]] = true;
initialised = true;
}
for (unsigned int i = 0; i + refLength <= len; ) {
int j;
bool match = true;
@@ -56,7 +56,7 @@ struct RefScanSink : Sink
string tail;
RefScanSink() : hashSink(htSHA256) { }
void operator () (const unsigned char * data, size_t len);
};
@@ -89,17 +89,17 @@ PathSet scanForReferences(const string & path,
/* For efficiency (and a higher hit rate), just search for the
hash part of the file name. (This assumes that all references
have the form `HASH-bla'). */
foreach (PathSet::const_iterator, i, refs) {
string baseName = baseNameOf(*i);
for (auto & i : refs) {
string baseName = baseNameOf(i);
string::size_type pos = baseName.find('-');
if (pos == string::npos)
throw Error(format("bad reference %1%") % *i);
throw Error(format("bad reference %1%") % i);
string s = string(baseName, 0, pos);
assert(s.size() == refLength);
assert(backMap.find(s) == backMap.end());
// parseHash(htSHA256, s);
sink.hashes.insert(s);
backMap[s] = *i;
backMap[s] = i;
}
/* Look for the hashes in the NAR dump of the path. */
@@ -107,14 +107,14 @@ PathSet scanForReferences(const string & path,
/* Map the hashes found back to their store paths. */
PathSet found;
foreach (StringSet::iterator, i, sink.seen) {
for (auto & i : sink.seen) {
std::map<string, Path>::iterator j;
if ((j = backMap.find(*i)) == backMap.end()) abort();
if ((j = backMap.find(i)) == backMap.end()) abort();
found.insert(j->second);
}
hash = sink.hashSink.finish();
return found;
}
+87 -111
View File
@@ -5,6 +5,7 @@
#include "archive.hh"
#include "affinity.hh"
#include "globals.hh"
#include "derivations.hh"
#include <sys/types.h>
#include <sys/stat.h>
@@ -31,7 +32,7 @@ Path readStorePath(Source & from)
template<class T> T readStorePaths(Source & from)
{
T paths = readStrings<T>(from);
foreach (typename T::iterator, i, paths) assertStorePath(*i);
for (auto & i : paths) assertStorePath(i);
return paths;
}
@@ -63,7 +64,7 @@ void RemoteStore::openConnection(bool reserveSpace)
/* Send the magic greeting, check for the reply. */
try {
writeInt(WORKER_MAGIC_1, to);
to << WORKER_MAGIC_1;
to.flush();
unsigned int magic = readInt(from);
if (magic != WORKER_MAGIC_2) throw Error("protocol mismatch");
@@ -71,19 +72,18 @@ void RemoteStore::openConnection(bool reserveSpace)
daemonVersion = readInt(from);
if (GET_PROTOCOL_MAJOR(daemonVersion) != GET_PROTOCOL_MAJOR(PROTOCOL_VERSION))
throw Error("Nix daemon protocol version not supported");
writeInt(PROTOCOL_VERSION, to);
to << PROTOCOL_VERSION;
if (GET_PROTOCOL_MINOR(daemonVersion) >= 14) {
int cpu = settings.lockCPU ? lockToCurrentCPU() : -1;
if (cpu != -1) {
writeInt(1, to);
writeInt(cpu, to);
} else
writeInt(0, to);
if (cpu != -1)
to << 1 << cpu;
else
to << 0;
}
if (GET_PROTOCOL_MINOR(daemonVersion) >= 11)
writeInt(reserveSpace, to);
to << reserveSpace;
processStderr();
}
@@ -141,35 +141,31 @@ RemoteStore::~RemoteStore()
void RemoteStore::setOptions()
{
writeInt(wopSetOptions, to);
writeInt(settings.keepFailed, to);
writeInt(settings.keepGoing, to);
writeInt(settings.tryFallback, to);
writeInt(verbosity, to);
writeInt(settings.maxBuildJobs, to);
writeInt(settings.maxSilentTime, to);
to << wopSetOptions
<< settings.keepFailed
<< settings.keepGoing
<< settings.tryFallback
<< verbosity
<< settings.maxBuildJobs
<< settings.maxSilentTime;
if (GET_PROTOCOL_MINOR(daemonVersion) >= 2)
writeInt(settings.useBuildHook, to);
if (GET_PROTOCOL_MINOR(daemonVersion) >= 4) {
writeInt(settings.buildVerbosity, to);
writeInt(logType, to);
writeInt(settings.printBuildTrace, to);
}
to << settings.useBuildHook;
if (GET_PROTOCOL_MINOR(daemonVersion) >= 4)
to << settings.buildVerbosity
<< logType
<< settings.printBuildTrace;
if (GET_PROTOCOL_MINOR(daemonVersion) >= 6)
writeInt(settings.buildCores, to);
to << settings.buildCores;
if (GET_PROTOCOL_MINOR(daemonVersion) >= 10)
writeInt(settings.useSubstitutes, to);
to << settings.useSubstitutes;
if (GET_PROTOCOL_MINOR(daemonVersion) >= 12) {
Settings::SettingsMap overrides = settings.getOverrides();
if (overrides["ssh-auth-sock"] == "")
overrides["ssh-auth-sock"] = getEnv("SSH_AUTH_SOCK");
writeInt(overrides.size(), to);
foreach (Settings::SettingsMap::iterator, i, overrides) {
writeString(i->first, to);
writeString(i->second, to);
}
to << overrides.size();
for (auto & i : overrides)
to << i.first << i.second;
}
processStderr();
@@ -179,8 +175,7 @@ void RemoteStore::setOptions()
bool RemoteStore::isValidPath(const Path & path)
{
openConnection();
writeInt(wopIsValidPath, to);
writeString(path, to);
to << wopIsValidPath << path;
processStderr();
unsigned int reply = readInt(from);
return reply != 0;
@@ -192,12 +187,11 @@ PathSet RemoteStore::queryValidPaths(const PathSet & paths)
openConnection();
if (GET_PROTOCOL_MINOR(daemonVersion) < 12) {
PathSet res;
foreach (PathSet::const_iterator, i, paths)
if (isValidPath(*i)) res.insert(*i);
for (auto & i : paths)
if (isValidPath(i)) res.insert(i);
return res;
} else {
writeInt(wopQueryValidPaths, to);
writeStrings(paths, to);
to << wopQueryValidPaths << paths;
processStderr();
return readStorePaths<PathSet>(from);
}
@@ -207,7 +201,7 @@ PathSet RemoteStore::queryValidPaths(const PathSet & paths)
PathSet RemoteStore::queryAllValidPaths()
{
openConnection();
writeInt(wopQueryAllValidPaths, to);
to << wopQueryAllValidPaths;
processStderr();
return readStorePaths<PathSet>(from);
}
@@ -218,16 +212,14 @@ PathSet RemoteStore::querySubstitutablePaths(const PathSet & paths)
openConnection();
if (GET_PROTOCOL_MINOR(daemonVersion) < 12) {
PathSet res;
foreach (PathSet::const_iterator, i, paths) {
writeInt(wopHasSubstitutes, to);
writeString(*i, to);
for (auto & i : paths) {
to << wopHasSubstitutes << i;
processStderr();
if (readInt(from)) res.insert(*i);
if (readInt(from)) res.insert(i);
}
return res;
} else {
writeInt(wopQuerySubstitutablePaths, to);
writeStrings(paths, to);
to << wopQuerySubstitutablePaths << paths;
processStderr();
return readStorePaths<PathSet>(from);
}
@@ -245,10 +237,9 @@ void RemoteStore::querySubstitutablePathInfos(const PathSet & paths,
if (GET_PROTOCOL_MINOR(daemonVersion) < 12) {
foreach (PathSet::const_iterator, i, paths) {
for (auto & i : paths) {
SubstitutablePathInfo info;
writeInt(wopQuerySubstitutablePathInfo, to);
writeString(*i, to);
to << wopQuerySubstitutablePathInfo << i;
processStderr();
unsigned int reply = readInt(from);
if (reply == 0) continue;
@@ -257,13 +248,12 @@ void RemoteStore::querySubstitutablePathInfos(const PathSet & paths,
info.references = readStorePaths<PathSet>(from);
info.downloadSize = readLongLong(from);
info.narSize = GET_PROTOCOL_MINOR(daemonVersion) >= 7 ? readLongLong(from) : 0;
infos[*i] = info;
infos[i] = info;
}
} else {
writeInt(wopQuerySubstitutablePathInfos, to);
writeStrings(paths, to);
to << wopQuerySubstitutablePathInfos << paths;
processStderr();
unsigned int count = readInt(from);
for (unsigned int n = 0; n < count; n++) {
@@ -283,8 +273,7 @@ void RemoteStore::querySubstitutablePathInfos(const PathSet & paths,
ValidPathInfo RemoteStore::queryPathInfo(const Path & path)
{
openConnection();
writeInt(wopQueryPathInfo, to);
writeString(path, to);
to << wopQueryPathInfo << path;
processStderr();
ValidPathInfo info;
info.path = path;
@@ -301,8 +290,7 @@ ValidPathInfo RemoteStore::queryPathInfo(const Path & path)
Hash RemoteStore::queryPathHash(const Path & path)
{
openConnection();
writeInt(wopQueryPathHash, to);
writeString(path, to);
to << wopQueryPathHash << path;
processStderr();
string hash = readString(from);
return parseHash(htSHA256, hash);
@@ -313,8 +301,7 @@ void RemoteStore::queryReferences(const Path & path,
PathSet & references)
{
openConnection();
writeInt(wopQueryReferences, to);
writeString(path, to);
to << wopQueryReferences << path;
processStderr();
PathSet references2 = readStorePaths<PathSet>(from);
references.insert(references2.begin(), references2.end());
@@ -325,8 +312,7 @@ void RemoteStore::queryReferrers(const Path & path,
PathSet & referrers)
{
openConnection();
writeInt(wopQueryReferrers, to);
writeString(path, to);
to << wopQueryReferrers << path;
processStderr();
PathSet referrers2 = readStorePaths<PathSet>(from);
referrers.insert(referrers2.begin(), referrers2.end());
@@ -336,8 +322,7 @@ void RemoteStore::queryReferrers(const Path & path,
Path RemoteStore::queryDeriver(const Path & path)
{
openConnection();
writeInt(wopQueryDeriver, to);
writeString(path, to);
to << wopQueryDeriver << path;
processStderr();
Path drvPath = readString(from);
if (drvPath != "") assertStorePath(drvPath);
@@ -348,8 +333,7 @@ Path RemoteStore::queryDeriver(const Path & path)
PathSet RemoteStore::queryValidDerivers(const Path & path)
{
openConnection();
writeInt(wopQueryValidDerivers, to);
writeString(path, to);
to << wopQueryValidDerivers << path;
processStderr();
return readStorePaths<PathSet>(from);
}
@@ -358,8 +342,7 @@ PathSet RemoteStore::queryValidDerivers(const Path & path)
PathSet RemoteStore::queryDerivationOutputs(const Path & path)
{
openConnection();
writeInt(wopQueryDerivationOutputs, to);
writeString(path, to);
to << wopQueryDerivationOutputs << path;
processStderr();
return readStorePaths<PathSet>(from);
}
@@ -368,8 +351,7 @@ PathSet RemoteStore::queryDerivationOutputs(const Path & path)
PathSet RemoteStore::queryDerivationOutputNames(const Path & path)
{
openConnection();
writeInt(wopQueryDerivationOutputNames, to);
writeString(path, to);
to << wopQueryDerivationOutputNames << path;
processStderr();
return readStrings<PathSet>(from);
}
@@ -378,8 +360,7 @@ PathSet RemoteStore::queryDerivationOutputNames(const Path & path)
Path RemoteStore::queryPathFromHashPart(const string & hashPart)
{
openConnection();
writeInt(wopQueryPathFromHashPart, to);
writeString(hashPart, to);
to << wopQueryPathFromHashPart << hashPart;
processStderr();
Path path = readString(from);
if (!path.empty()) assertStorePath(path);
@@ -396,12 +377,10 @@ Path RemoteStore::addToStore(const string & name, const Path & _srcPath,
Path srcPath(absPath(_srcPath));
writeInt(wopAddToStore, to);
writeString(name, to);
/* backwards compatibility hack */
writeInt((hashAlgo == htSHA256 && recursive) ? 0 : 1, to);
writeInt(recursive ? 1 : 0, to);
writeString(printHashType(hashAlgo), to);
to << wopAddToStore << name
<< ((hashAlgo == htSHA256 && recursive) ? 0 : 1) /* backwards compatibility hack */
<< (recursive ? 1 : 0)
<< printHashType(hashAlgo);
try {
to.written = 0;
@@ -429,10 +408,7 @@ Path RemoteStore::addTextToStore(const string & name, const string & s,
if (repair) throw Error("repairing is not supported when building through the Nix daemon");
openConnection();
writeInt(wopAddTextToStore, to);
writeString(name, to);
writeString(s, to);
writeStrings(references, to);
to << wopAddTextToStore << name << s << references;
processStderr();
return readStorePath(from);
@@ -443,9 +419,7 @@ void RemoteStore::exportPath(const Path & path, bool sign,
Sink & sink)
{
openConnection();
writeInt(wopExportPath, to);
writeString(path, to);
writeInt(sign ? 1 : 0, to);
to << wopExportPath << path << (sign ? 1 : 0);
processStderr(&sink); /* sink receives the actual data */
readInt(from);
}
@@ -454,7 +428,7 @@ void RemoteStore::exportPath(const Path & path, bool sign,
Paths RemoteStore::importPaths(bool requireSignature, Source & source)
{
openConnection();
writeInt(wopImportPaths, to);
to << wopImportPaths;
/* We ignore requireSignature, since the worker forces it to true
anyway. */
processStderr(0, &source);
@@ -466,27 +440,40 @@ void RemoteStore::buildPaths(const PathSet & drvPaths, BuildMode buildMode)
{
if (buildMode != bmNormal) throw Error("repairing or checking is not supported when building through the Nix daemon");
openConnection();
writeInt(wopBuildPaths, to);
to << wopBuildPaths;
if (GET_PROTOCOL_MINOR(daemonVersion) >= 13)
writeStrings(drvPaths, to);
to << drvPaths;
else {
/* For backwards compatibility with old daemons, strip output
identifiers. */
PathSet drvPaths2;
foreach (PathSet::const_iterator, i, drvPaths)
drvPaths2.insert(string(*i, 0, i->find('!')));
writeStrings(drvPaths2, to);
for (auto & i : drvPaths)
drvPaths2.insert(string(i, 0, i.find('!')));
to << drvPaths2;
}
processStderr();
readInt(from);
}
BuildResult RemoteStore::buildDerivation(const Path & drvPath, const BasicDerivation & drv,
BuildMode buildMode)
{
openConnection();
to << wopBuildDerivation << drvPath << drv << buildMode;
processStderr();
BuildResult res;
unsigned int status;
from >> status >> res.errorMsg;
res.status = (BuildResult::Status) status;
return res;
}
void RemoteStore::ensurePath(const Path & path)
{
openConnection();
writeInt(wopEnsurePath, to);
writeString(path, to);
to << wopEnsurePath << path;
processStderr();
readInt(from);
}
@@ -495,8 +482,7 @@ void RemoteStore::ensurePath(const Path & path)
void RemoteStore::addTempRoot(const Path & path)
{
openConnection();
writeInt(wopAddTempRoot, to);
writeString(path, to);
to << wopAddTempRoot << path;
processStderr();
readInt(from);
}
@@ -505,8 +491,7 @@ void RemoteStore::addTempRoot(const Path & path)
void RemoteStore::addIndirectRoot(const Path & path)
{
openConnection();
writeInt(wopAddIndirectRoot, to);
writeString(path, to);
to << wopAddIndirectRoot << path;
processStderr();
readInt(from);
}
@@ -515,7 +500,7 @@ void RemoteStore::addIndirectRoot(const Path & path)
void RemoteStore::syncWithGC()
{
openConnection();
writeInt(wopSyncWithGC, to);
to << wopSyncWithGC;
processStderr();
readInt(from);
}
@@ -524,7 +509,7 @@ void RemoteStore::syncWithGC()
Roots RemoteStore::findRoots()
{
openConnection();
writeInt(wopFindRoots, to);
to << wopFindRoots;
processStderr();
unsigned int count = readInt(from);
Roots result;
@@ -541,17 +526,11 @@ void RemoteStore::collectGarbage(const GCOptions & options, GCResults & results)
{
openConnection(false);
writeInt(wopCollectGarbage, to);
writeInt(options.action, to);
writeStrings(options.pathsToDelete, to);
writeInt(options.ignoreLiveness, to);
writeLongLong(options.maxFreed, to);
writeInt(0, to);
if (GET_PROTOCOL_MINOR(daemonVersion) >= 5) {
to << wopCollectGarbage << options.action << options.pathsToDelete << options.ignoreLiveness
<< options.maxFreed << 0;
if (GET_PROTOCOL_MINOR(daemonVersion) >= 5)
/* removed options */
writeInt(0, to);
writeInt(0, to);
}
to << 0 << 0;
processStderr();
@@ -564,7 +543,7 @@ void RemoteStore::collectGarbage(const GCOptions & options, GCResults & results)
PathSet RemoteStore::queryFailedPaths()
{
openConnection();
writeInt(wopQueryFailedPaths, to);
to << wopQueryFailedPaths;
processStderr();
return readStorePaths<PathSet>(from);
}
@@ -573,8 +552,7 @@ PathSet RemoteStore::queryFailedPaths()
void RemoteStore::clearFailedPaths(const PathSet & paths)
{
openConnection();
writeInt(wopClearFailedPaths, to);
writeStrings(paths, to);
to << wopClearFailedPaths << paths;
processStderr();
readInt(from);
}
@@ -582,7 +560,7 @@ void RemoteStore::clearFailedPaths(const PathSet & paths)
void RemoteStore::optimiseStore()
{
openConnection();
writeInt(wopOptimiseStore, to);
to << wopOptimiseStore;
processStderr();
readInt(from);
}
@@ -590,9 +568,7 @@ void RemoteStore::optimiseStore()
bool RemoteStore::verifyStore(bool checkContents, bool repair)
{
openConnection();
writeInt(wopVerifyStore, to);
writeInt(checkContents, to);
writeInt(repair, to);
to << wopVerifyStore << checkContents << repair;
processStderr();
return readInt(from) != 0;
}
+3
View File
@@ -67,6 +67,9 @@ public:
void buildPaths(const PathSet & paths, BuildMode buildMode);
BuildResult buildDerivation(const Path & drvPath, const BasicDerivation & drv,
BuildMode buildMode) override;
void ensurePath(const Path & path);
void addTempRoot(const Path & path);
+24 -34
View File
@@ -2,20 +2,10 @@
#include "globals.hh"
#include "util.hh"
#include <climits>
namespace nix {
GCOptions::GCOptions()
{
action = gcDeleteDead;
ignoreLiveness = false;
maxFreed = ULLONG_MAX;
}
bool isInStore(const Path & path)
{
return isInDir(path, settings.nixStore);
@@ -82,14 +72,14 @@ void checkStoreName(const string & name)
reasons (e.g., "." and ".."). */
if (string(name, 0, 1) == ".")
throw Error(format("illegal name: %1%") % name);
foreach (string::const_iterator, i, name)
if (!((*i >= 'A' && *i <= 'Z') ||
(*i >= 'a' && *i <= 'z') ||
(*i >= '0' && *i <= '9') ||
validChars.find(*i) != string::npos))
for (auto & i : name)
if (!((i >= 'A' && i <= 'Z') ||
(i >= 'a' && i <= 'z') ||
(i >= '0' && i <= '9') ||
validChars.find(i) != string::npos))
{
throw Error(format("invalid character %1% in name %2%")
% *i % name);
% i % name);
}
}
@@ -101,22 +91,22 @@ void checkStoreName(const string & name)
where
<store> = the location of the Nix store, usually /nix/store
<name> = a human readable name for the path, typically obtained
from the name attribute of the derivation, or the name of the
source file from which the store path is created. For derivation
outputs other than the default "out" output, the string "-<id>"
is suffixed to <name>.
<h> = base-32 representation of the first 160 bits of a SHA-256
hash of <s>; the hash part of the store name
<s> = the string "<type>:sha256:<h2>:<store>:<name>";
note that it includes the location of the store as well as the
name to make sure that changes to either of those are reflected
in the hash (e.g. you won't get /nix/store/<h>-name1 and
/nix/store/<h>-name2 with equal hash parts).
<type> = one of:
"text:<r1>:<r2>:...<rN>"
for plain text files written to the store using
@@ -219,9 +209,9 @@ Path computeStorePathForText(const string & name, const string & s,
hacky, but we can't put them in `s' since that would be
ambiguous. */
string type = "text";
foreach (PathSet::const_iterator, i, references) {
for (auto & i : references) {
type += ":";
type += *i;
type += i;
}
return makeStorePath(type, hash, name);
}
@@ -234,11 +224,11 @@ string StoreAPI::makeValidityRegistration(const PathSet & paths,
bool showDerivers, bool showHash)
{
string s = "";
foreach (PathSet::iterator, i, paths) {
s += *i + "\n";
ValidPathInfo info = queryPathInfo(*i);
for (auto & i : paths) {
s += i + "\n";
ValidPathInfo info = queryPathInfo(i);
if (showHash) {
s += printHash(info.hash) + "\n";
@@ -250,8 +240,8 @@ string StoreAPI::makeValidityRegistration(const PathSet & paths,
s += (format("%1%\n") % info.references.size()).str();
foreach (PathSet::iterator, j, info.references)
s += *j + "\n";
for (auto & j : info.references)
s += j + "\n";
}
return s;
@@ -286,9 +276,9 @@ ValidPathInfo decodeValidPathInfo(std::istream & str, bool hashGiven)
string showPaths(const PathSet & paths)
{
string s;
foreach (PathSet::const_iterator, i, paths) {
for (auto & i : paths) {
if (s.size() != 0) s += ", ";
s += "" + *i + "";
s += "" + i + "";
}
return s;
}
@@ -297,11 +287,11 @@ string showPaths(const PathSet & paths)
void exportPaths(StoreAPI & store, const Paths & paths,
bool sign, Sink & sink)
{
foreach (Paths::const_iterator, i, paths) {
writeInt(1, sink);
store.exportPath(*i, sign, sink);
for (auto & i : paths) {
sink << 1;
store.exportPath(i, sign, sink);
}
writeInt(0, sink);
sink << 0;
}
+36 -5
View File
@@ -4,6 +4,7 @@
#include "serialise.hh"
#include <string>
#include <limits>
#include <map>
#include <memory>
@@ -36,21 +37,19 @@ struct GCOptions
gcDeleteSpecific,
} GCAction;
GCAction action;
GCAction action{gcDeleteDead};
/* If `ignoreLiveness' is set, then reachability from the roots is
ignored (dangerous!). However, the paths must still be
unreferenced *within* the store (i.e., there can be no other
store paths that depend on them). */
bool ignoreLiveness;
bool ignoreLiveness{false};
/* For `gcDeleteSpecific', the paths to delete. */
PathSet pathsToDelete;
/* Stop after at least `maxFreed' bytes have been freed. */
unsigned long long maxFreed;
GCOptions();
unsigned long long maxFreed{std::numeric_limits<unsigned long long>::max()};
};
@@ -100,6 +99,32 @@ typedef list<ValidPathInfo> ValidPathInfos;
enum BuildMode { bmNormal, bmRepair, bmCheck };
struct BuildResult
{
enum Status {
Built = 0,
Substituted,
AlreadyValid,
PermanentFailure,
InputRejected,
OutputRejected,
TransientFailure, // possibly transient
CachedFailure,
TimedOut,
MiscFailure,
DependencyFailed
} status = MiscFailure;
std::string errorMsg;
//time_t startTime = 0, stopTime = 0;
bool success() {
return status == Built || status == Substituted || status == AlreadyValid;
}
};
struct BasicDerivation;
class StoreAPI
{
public:
@@ -194,6 +219,12 @@ public:
not derivations, substitute them. */
virtual void buildPaths(const PathSet & paths, BuildMode buildMode = bmNormal) = 0;
/* Build a single non-materialized derivation (i.e. not from an
on-disk .drv file). Note that drvPath is only used for
informational purposes. */
virtual BuildResult buildDerivation(const Path & drvPath, const BasicDerivation & drv,
BuildMode buildMode = bmNormal) = 0;
/* 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). */
+2 -1
View File
@@ -43,7 +43,8 @@ typedef enum {
wopQuerySubstitutablePaths = 32,
wopQueryValidDerivers = 33,
wopOptimiseStore = 34,
wopVerifyStore = 35
wopVerifyStore = 35,
wopBuildDerivation = 36,
} WorkerOp;
+12 -25
View File
@@ -39,8 +39,7 @@ PathFilter defaultPathFilter;
static void dumpContents(const Path & path, size_t size,
Sink & sink)
{
writeString("contents", sink);
writeLongLong(size, sink);
sink << "contents" << size;
AutoCloseFD fd = open(path.c_str(), O_RDONLY);
if (fd == -1) throw SysError(format("opening file %1%") % path);
@@ -65,21 +64,17 @@ static void dump(const Path & path, Sink & sink, PathFilter & filter)
if (lstat(path.c_str(), &st))
throw SysError(format("getting attributes of path %1%") % path);
writeString("(", sink);
sink << "(";
if (S_ISREG(st.st_mode)) {
writeString("type", sink);
writeString("regular", sink);
if (st.st_mode & S_IXUSR) {
writeString("executable", sink);
writeString("", sink);
}
sink << "type" << "regular";
if (st.st_mode & S_IXUSR)
sink << "executable" << "";
dumpContents(path, (size_t) st.st_size, sink);
}
else if (S_ISDIR(st.st_mode)) {
writeString("type", sink);
writeString("directory", sink);
sink << "type" << "directory";
/* If we're on a case-insensitive system like Mac OS X, undo
the case hack applied by restorePath(). */
@@ -101,32 +96,24 @@ static void dump(const Path & path, Sink & sink, PathFilter & filter)
for (auto & i : unhacked)
if (filter(path + "/" + i.first)) {
writeString("entry", sink);
writeString("(", sink);
writeString("name", sink);
writeString(i.first, sink);
writeString("node", sink);
sink << "entry" << "(" << "name" << i.first << "node";
dump(path + "/" + i.second, sink, filter);
writeString(")", sink);
sink << ")";
}
}
else if (S_ISLNK(st.st_mode)) {
writeString("type", sink);
writeString("symlink", sink);
writeString("target", sink);
writeString(readLink(path), sink);
}
else if (S_ISLNK(st.st_mode))
sink << "type" << "symlink" << "target" << readLink(path);
else throw Error(format("file %1% has an unsupported type") % path);
writeString(")", sink);
sink << ")";
}
void dumpPath(const Path & path, Sink & sink, PathFilter & filter)
{
writeString(archiveVersion1, sink);
sink << archiveVersion1;
dump(path, sink, filter);
}
+35 -39
View File
@@ -16,11 +16,11 @@ BufferedSink::~BufferedSink()
delete[] buffer;
}
void BufferedSink::operator () (const unsigned char * data, size_t len)
{
if (!buffer) buffer = new unsigned char[bufSize];
while (len) {
/* Optimisation: bypass the buffer if the data exceeds the
buffer size. */
@@ -96,7 +96,7 @@ size_t BufferedSource::read(unsigned char * data, size_t len)
if (!buffer) buffer = new unsigned char[bufSize];
if (!bufPosIn) bufPosIn = readUnbuffered(buffer, bufSize);
/* Copy out the data in the buffer. */
size_t n = len > bufPosIn - bufPosOut ? bufPosIn - bufPosOut : len;
memcpy(data, buffer + bufPosOut, n);
@@ -144,56 +144,39 @@ void writePadding(size_t len, Sink & sink)
}
void writeInt(unsigned int n, Sink & sink)
{
unsigned char buf[8];
memset(buf, 0, sizeof(buf));
buf[0] = n & 0xff;
buf[1] = (n >> 8) & 0xff;
buf[2] = (n >> 16) & 0xff;
buf[3] = (n >> 24) & 0xff;
sink(buf, sizeof(buf));
}
void writeLongLong(unsigned long long n, Sink & sink)
{
unsigned char buf[8];
buf[0] = n & 0xff;
buf[1] = (n >> 8) & 0xff;
buf[2] = (n >> 16) & 0xff;
buf[3] = (n >> 24) & 0xff;
buf[4] = (n >> 32) & 0xff;
buf[5] = (n >> 40) & 0xff;
buf[6] = (n >> 48) & 0xff;
buf[7] = (n >> 56) & 0xff;
sink(buf, sizeof(buf));
}
void writeString(const unsigned char * buf, size_t len, Sink & sink)
{
writeInt(len, sink);
sink << len;
sink(buf, len);
writePadding(len, sink);
}
void writeString(const string & s, Sink & sink)
Sink & operator << (Sink & sink, const string & s)
{
writeString((const unsigned char *) s.data(), s.size(), sink);
return sink;
}
template<class T> void writeStrings(const T & ss, Sink & sink)
{
writeInt(ss.size(), sink);
foreach (typename T::const_iterator, i, ss)
writeString(*i, sink);
sink << ss.size();
for (auto & i : ss)
sink << i;
}
template void writeStrings(const Paths & ss, Sink & sink);
template void writeStrings(const PathSet & ss, Sink & sink);
Sink & operator << (Sink & sink, const Strings & s)
{
writeStrings(s, sink);
return sink;
}
Sink & operator << (Sink & sink, const StringSet & s)
{
writeStrings(s, sink);
return sink;
}
void readPadding(size_t len, Source & source)
@@ -247,7 +230,7 @@ size_t readString(unsigned char * buf, size_t max, Source & source)
return len;
}
string readString(Source & source)
{
size_t len = readInt(source);
@@ -258,7 +241,20 @@ string readString(Source & source)
return string((char *) buf, len);
}
Source & operator >> (Source & in, string & s)
{
s = readString(in);
return in;
}
Source & operator >> (Source & in, unsigned int & n)
{
n = readInt(in);
return in;
}
template<class T> T readStrings(Source & source)
{
unsigned int count = readInt(source);
+32 -12
View File
@@ -1,13 +1,14 @@
#pragma once
#include "types.hh"
#include "util.hh"
namespace nix {
/* Abstract destination of binary data. */
struct Sink
struct Sink
{
virtual ~Sink() { }
virtual void operator () (const unsigned char * data, size_t len) = 0;
@@ -25,9 +26,9 @@ struct BufferedSink : Sink
~BufferedSink();
void operator () (const unsigned char * data, size_t len);
void flush();
virtual void write(const unsigned char * data, size_t len) = 0;
};
@@ -36,7 +37,7 @@ struct BufferedSink : Sink
struct Source
{
virtual ~Source() { }
/* Store exactly len bytes in the buffer pointed to by data.
It blocks until all the requested data is available, or throws
an error if it is not going to be available. */
@@ -58,9 +59,9 @@ struct BufferedSource : Source
BufferedSource(size_t bufSize = 32 * 1024)
: bufSize(bufSize), bufPosIn(0), bufPosOut(0), buffer(0) { }
~BufferedSource();
size_t read(unsigned char * data, size_t len);
/* Underlying read call, to be overridden. */
virtual size_t readUnbuffered(unsigned char * data, size_t len) = 0;
@@ -78,7 +79,7 @@ struct FdSink : BufferedSink
FdSink() : fd(-1), warn(false), written(0) { }
FdSink(int fd) : fd(fd), warn(false), written(0) { }
~FdSink();
void write(const unsigned char * data, size_t len);
};
@@ -107,16 +108,32 @@ struct StringSource : Source
const string & s;
size_t pos;
StringSource(const string & _s) : s(_s), pos(0) { }
size_t read(unsigned char * data, size_t len);
size_t read(unsigned char * data, size_t len);
};
void writePadding(size_t len, Sink & sink);
void writeInt(unsigned int n, Sink & sink);
void writeLongLong(unsigned long long n, Sink & sink);
void writeString(const unsigned char * buf, size_t len, Sink & sink);
void writeString(const string & s, Sink & sink);
template<class T> void writeStrings(const T & ss, Sink & sink);
inline Sink & operator << (Sink & sink, uint64_t n)
{
unsigned char buf[8];
buf[0] = n & 0xff;
buf[1] = (n >> 8) & 0xff;
buf[2] = (n >> 16) & 0xff;
buf[3] = (n >> 24) & 0xff;
buf[4] = (n >> 32) & 0xff;
buf[5] = (n >> 40) & 0xff;
buf[6] = (n >> 48) & 0xff;
buf[7] = (n >> 56) & 0xff;
sink(buf, sizeof(buf));
return sink;
}
Sink & operator << (Sink & sink, const string & s);
Sink & operator << (Sink & sink, const Strings & s);
Sink & operator << (Sink & sink, const StringSet & s);
void readPadding(size_t len, Source & source);
unsigned int readInt(Source & source);
@@ -125,6 +142,9 @@ size_t readString(unsigned char * buf, size_t max, Source & source);
string readString(Source & source);
template<class T> T readStrings(Source & source);
Source & operator >> (Source & in, string & s);
Source & operator >> (Source & in, unsigned int & n);
MakeError(SerialisationError, Error)
+42 -7
View File
@@ -149,10 +149,19 @@ Path dirOf(const Path & path)
string baseNameOf(const Path & path)
{
Path::size_type pos = path.rfind('/');
if (path.empty())
return string("");
Path::size_type last = path.length() - 1;
if (path[last] == '/' && last > 0)
last -= 1;
Path::size_type pos = path.rfind('/', last);
if (pos == string::npos)
throw Error(format("invalid file name %1%") % path);
return string(path, pos + 1);
pos = 0;
else
pos += 1;
return string(path, pos, last - pos + 1);
}
@@ -477,12 +486,24 @@ void printMsg_(Verbosity level, const FormatOrString & fs)
{
checkInterrupt();
if (level > verbosity) return;
string prefix;
if (logType == ltPretty)
for (int i = 0; i < nestingLevel; i++)
prefix += "| ";
else if (logType == ltEscapes && level != lvlInfo)
prefix = "\033[" + escVerbosity(level) + "s";
else if (logType == ltSystemd) {
char c;
switch (level) {
case lvlError: c = '3'; break;
case lvlInfo: c = '5'; break;
case lvlTalkative: case lvlChatty: c = '6'; break;
default: c = '7';
}
prefix = string("<") + c + ">";
}
string s = (format("%1%%2%\n") % prefix % fs.s).str();
if (!isatty(STDERR_FILENO)) s = filterANSIEscapes(s);
writeToStderr(s);
@@ -1060,9 +1081,9 @@ template vector<string> tokenizeString(const string & s, const string & separato
string concatStringsSep(const string & sep, const Strings & ss)
{
string s;
foreach (Strings::const_iterator, i, ss) {
for (auto & i : ss) {
if (s.size() != 0) s += sep;
s += *i;
s += i;
}
return s;
}
@@ -1071,9 +1092,9 @@ string concatStringsSep(const string & sep, const Strings & ss)
string concatStringsSep(const string & sep, const StringSet & ss)
{
string s;
foreach (StringSet::const_iterator, i, ss) {
for (auto & i : ss) {
if (s.size() != 0) s += sep;
s += *i;
s += i;
}
return s;
}
@@ -1095,6 +1116,20 @@ string trim(const string & s, const string & whitespace)
}
string replaceStrings(const std::string & s,
const std::string & from, const std::string & to)
{
if (from.empty()) return s;
string res = s;
size_t pos = 0;
while ((pos = res.find(from, pos)) != std::string::npos) {
res.replace(pos, from.size(), to);
pos += to.size();
}
return res;
}
string statusToString(int status)
{
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+7 -8
View File
@@ -15,13 +15,6 @@
namespace nix {
#define foreach(it_type, it, collection) \
for (it_type it = (collection).begin(); it != (collection).end(); ++it)
#define foreach_reverse(it_type, it, collection) \
for (it_type it = (collection).rbegin(); it != (collection).rend(); ++it)
/* Return an environment variable. */
string getEnv(const string & key, const string & def = "");
@@ -129,7 +122,8 @@ T singleton(const A & a)
typedef enum {
ltPretty, /* nice, nested output */
ltEscapes, /* nesting indicated using escape codes (for log2xml) */
ltFlat /* no nesting */
ltFlat, /* no nesting */
ltSystemd, /* use systemd severity prefixes */
} LogType;
extern LogType logType;
@@ -341,6 +335,11 @@ string chomp(const string & s);
string trim(const string & s, const string & whitespace = " \n\r\t");
/* Replace all occurrences of a string inside another string. */
string replaceStrings(const std::string & s,
const std::string & from, const std::string & to);
/* Convert the exit status of a child as returned by wait() into an
error string. */
string statusToString(int status);
+4 -4
View File
@@ -73,10 +73,10 @@ void XMLWriter::writeEmptyElement(const string & name,
void XMLWriter::writeAttrs(const XMLAttrs & attrs)
{
for (XMLAttrs::const_iterator i = attrs.begin(); i != attrs.end(); ++i) {
output << " " << i->first << "=\"";
for (unsigned int j = 0; j < i->second.size(); ++j) {
char c = i->second[j];
for (auto & i : attrs) {
output << " " << i.first << "=\"";
for (unsigned int j = 0; j < i.second.size(); ++j) {
char c = i.second[j];
if (c == '"') output << "&quot;";
else if (c == '<') output << "&lt;";
else if (c == '>') output << "&gt;";
+13 -4
View File
@@ -28,7 +28,12 @@ void removeOldGenerations(std::string dir)
auto type = i.type == DT_UNKNOWN ? getFileType(path) : i.type;
if (type == DT_LNK && canWrite) {
auto link = readLink(path);
std::string link;
try {
link = readLink(path);
} catch (SysError & e) {
if (e.errNo == ENOENT) continue;
}
if (link.find("link") != string::npos) {
printMsg(lvlInfo, format("removing old generations of profile %1%") % path);
if (deleteOlderThan != "")
@@ -45,11 +50,12 @@ void removeOldGenerations(std::string dir)
int main(int argc, char * * argv)
{
bool removeOld = false;
Strings extraArgs;
return handleExceptions(argv[0], [&]() {
initNix();
GCOptions options;
parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) {
if (*arg == "--help")
showManPage("nix-collect-garbage");
@@ -61,8 +67,12 @@ int main(int argc, char * * argv)
deleteOlderThan = getArg(*arg, arg, end);
}
else if (*arg == "--dry-run") dryRun = true;
else if (*arg == "--max-freed") {
long long maxFreed = getIntArg<long long>(*arg, arg, end, true);
options.maxFreed = maxFreed >= 0 ? maxFreed : 0;
}
else
extraArgs.push_back(*arg);
return false;
return true;
});
@@ -72,7 +82,6 @@ int main(int argc, char * * argv)
// Run the actual garbage collector.
if (!dryRun) {
store = openStore(false);
GCOptions options;
options.action = GCOptions::gcDeleteDead;
GCResults results;
PrintFreed freed(true, results);
+58 -59
View File
@@ -7,6 +7,7 @@
#include "affinity.hh"
#include "globals.hh"
#include "monitor-fd.hh"
#include "derivations.hh"
#include <algorithm>
@@ -43,7 +44,7 @@ static void tunnelStderr(const unsigned char * buf, size_t count)
{
if (canSendStderr) {
try {
writeInt(STDERR_NEXT, to);
to << STDERR_NEXT;
writeString(buf, count, to);
to.flush();
} catch (...) {
@@ -72,11 +73,10 @@ static void stopWork(bool success = true, const string & msg = "", unsigned int
canSendStderr = false;
if (success)
writeInt(STDERR_LAST, to);
to << STDERR_LAST;
else {
writeInt(STDERR_ERROR, to);
writeString(msg, to);
if (status != 0) writeInt(status, to);
to << STDERR_ERROR << msg;
if (status != 0) to << status;
}
}
@@ -87,7 +87,7 @@ struct TunnelSink : Sink
TunnelSink(Sink & to) : to(to) { }
virtual void operator () (const unsigned char * data, size_t len)
{
writeInt(STDERR_WRITE, to);
to << STDERR_WRITE;
writeString(data, len, to);
}
};
@@ -99,8 +99,7 @@ struct TunnelSource : BufferedSource
TunnelSource(Source & from) : from(from) { }
size_t readUnbuffered(unsigned char * data, size_t len)
{
writeInt(STDERR_READ, to);
writeInt(len, to);
to << STDERR_READ << len;
to.flush();
size_t n = readString(data, len, from);
if (n == 0) throw EndOfFile("unexpected end-of-file");
@@ -166,7 +165,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
assertStorePath(path);
bool result = store->isValidPath(path);
stopWork();
writeInt(result, to);
to << result;
break;
}
@@ -175,7 +174,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
startWork();
PathSet res = store->queryValidPaths(paths);
stopWork();
writeStrings(res, to);
to << res;
break;
}
@@ -184,7 +183,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
startWork();
PathSet res = store->querySubstitutablePaths(singleton<PathSet>(path));
stopWork();
writeInt(res.find(path) != res.end(), to);
to << (res.find(path) != res.end());
break;
}
@@ -193,7 +192,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
startWork();
PathSet res = store->querySubstitutablePaths(paths);
stopWork();
writeStrings(res, to);
to << res;
break;
}
@@ -202,7 +201,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
startWork();
Hash hash = store->queryPathHash(path);
stopWork();
writeString(printHash(hash), to);
to << printHash(hash);
break;
}
@@ -221,7 +220,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
paths = store->queryValidDerivers(path);
else paths = store->queryDerivationOutputs(path);
stopWork();
writeStrings(paths, to);
to << paths;
break;
}
@@ -231,7 +230,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
StringSet names;
names = store->queryDerivationOutputNames(path);
stopWork();
writeStrings(names, to);
to << names;
break;
}
@@ -240,7 +239,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
startWork();
Path deriver = store->queryDeriver(path);
stopWork();
writeString(deriver, to);
to << deriver;
break;
}
@@ -249,7 +248,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
startWork();
Path path = store->queryPathFromHashPart(hashPart);
stopWork();
writeString(path, to);
to << path;
break;
}
@@ -283,7 +282,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
->addToStoreFromDump(recursive ? savedNAR.s : savedRegular.s, baseName, recursive, hashAlgo);
stopWork();
writeString(path, to);
to << path;
break;
}
@@ -294,7 +293,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
startWork();
Path path = store->addTextToStore(suffix, s, refs);
stopWork();
writeString(path, to);
to << path;
break;
}
@@ -305,7 +304,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
TunnelSink sink(to);
store->exportPath(path, sign, sink);
stopWork();
writeInt(1, to);
to << 1;
break;
}
@@ -314,7 +313,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
TunnelSource source(from);
Paths paths = store->importPaths(!trusted, source);
stopWork();
writeStrings(paths, to);
to << paths;
break;
}
@@ -323,7 +322,21 @@ static void performOp(bool trusted, unsigned int clientVersion,
startWork();
store->buildPaths(drvs);
stopWork();
writeInt(1, to);
to << 1;
break;
}
case wopBuildDerivation: {
Path drvPath = readStorePath(from);
BasicDerivation drv;
from >> drv;
BuildMode buildMode = (BuildMode) readInt(from);
startWork();
if (!trusted)
throw Error("you are not privileged to build derivations");
auto res = store->buildDerivation(drvPath, drv, buildMode);
stopWork();
to << res.status << res.errorMsg;
break;
}
@@ -332,7 +345,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
startWork();
store->ensurePath(path);
stopWork();
writeInt(1, to);
to << 1;
break;
}
@@ -341,7 +354,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
startWork();
store->addTempRoot(path);
stopWork();
writeInt(1, to);
to << 1;
break;
}
@@ -350,7 +363,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
startWork();
store->addIndirectRoot(path);
stopWork();
writeInt(1, to);
to << 1;
break;
}
@@ -358,7 +371,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
startWork();
store->syncWithGC();
stopWork();
writeInt(1, to);
to << 1;
break;
}
@@ -366,11 +379,9 @@ static void performOp(bool trusted, unsigned int clientVersion,
startWork();
Roots roots = store->findRoots();
stopWork();
writeInt(roots.size(), to);
for (Roots::iterator i = roots.begin(); i != roots.end(); ++i) {
writeString(i->first, to);
writeString(i->second, to);
}
to << roots.size();
for (auto & i : roots)
to << i.first << i.second;
break;
}
@@ -395,9 +406,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
store->collectGarbage(options, results);
stopWork();
writeStrings(results.paths, to);
writeLongLong(results.bytesFreed, to);
writeLongLong(0, to); // obsolete
to << results.paths << results.bytesFreed << 0 /* obsolete */;
break;
}
@@ -445,14 +454,11 @@ static void performOp(bool trusted, unsigned int clientVersion,
stopWork();
SubstitutablePathInfos::iterator i = infos.find(path);
if (i == infos.end())
writeInt(0, to);
to << 0;
else {
writeInt(1, to);
writeString(i->second.deriver, to);
writeStrings(i->second.references, to);
writeLongLong(i->second.downloadSize, to);
to << 1 << i->second.deriver << i->second.references << i->second.downloadSize;
if (GET_PROTOCOL_MINOR(clientVersion) >= 7)
writeLongLong(i->second.narSize, to);
to << i->second.narSize;
}
break;
}
@@ -463,13 +469,10 @@ static void performOp(bool trusted, unsigned int clientVersion,
SubstitutablePathInfos infos;
store->querySubstitutablePathInfos(paths, infos);
stopWork();
writeInt(infos.size(), to);
foreach (SubstitutablePathInfos::iterator, i, infos) {
writeString(i->first, to);
writeString(i->second.deriver, to);
writeStrings(i->second.references, to);
writeLongLong(i->second.downloadSize, to);
writeLongLong(i->second.narSize, to);
to << infos.size();
for (auto & i : infos) {
to << i.first << i.second.deriver << i.second.references
<< i.second.downloadSize << i.second.narSize;
}
break;
}
@@ -478,7 +481,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
startWork();
PathSet paths = store->queryAllValidPaths();
stopWork();
writeStrings(paths, to);
to << paths;
break;
}
@@ -486,7 +489,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
startWork();
PathSet paths = store->queryFailedPaths();
stopWork();
writeStrings(paths, to);
to << paths;
break;
}
@@ -495,7 +498,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
startWork();
store->clearFailedPaths(paths);
stopWork();
writeInt(1, to);
to << 1;
break;
}
@@ -504,11 +507,8 @@ static void performOp(bool trusted, unsigned int clientVersion,
startWork();
ValidPathInfo info = store->queryPathInfo(path);
stopWork();
writeString(info.deriver, to);
writeString(printHash(info.hash), to);
writeStrings(info.references, to);
writeInt(info.registrationTime, to);
writeLongLong(info.narSize, to);
to << info.deriver << printHash(info.hash) << info.references
<< info.registrationTime << info.narSize;
break;
}
@@ -516,7 +516,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
startWork();
store->optimiseStore();
stopWork();
writeInt(1, to);
to << 1;
break;
case wopVerifyStore: {
@@ -527,7 +527,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
throw Error("you are not privileged to repair paths");
bool errors = store->verifyStore(checkContents, repair);
stopWork();
writeInt(errors, to);
to << errors;
break;
}
@@ -547,8 +547,7 @@ static void processConnection(bool trusted)
/* Exchange the greeting. */
unsigned int magic = readInt(from);
if (magic != WORKER_MAGIC_1) throw Error("protocol mismatch");
writeInt(WORKER_MAGIC_2, to);
writeInt(PROTOCOL_VERSION, to);
to << WORKER_MAGIC_2 << PROTOCOL_VERSION;
to.flush();
unsigned int clientVersion = readInt(from);
+140 -136
View File
@@ -232,9 +232,9 @@ static bool isPrebuilt(EvalState & state, DrvInfo & elem)
static void checkSelectorUse(DrvNames & selectors)
{
/* Check that all selectors have been used. */
foreach (DrvNames::iterator, i, selectors)
if (i->hits == 0 && i->fullName != "*")
throw Error(format("selector %1% matches no derivations") % i->fullName);
for (auto & i : selectors)
if (i.hits == 0 && i.fullName != "*")
throw Error(format("selector %1% matches no derivations") % i.fullName);
}
@@ -248,7 +248,7 @@ static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems,
DrvInfos elems;
set<unsigned int> done;
foreach (DrvNames::iterator, i, selectors) {
for (auto & i : selectors) {
typedef list<std::pair<DrvInfo, unsigned int> > Matches;
Matches matches;
unsigned int n = 0;
@@ -256,8 +256,8 @@ static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems,
j != allElems.end(); ++j, ++n)
{
DrvName drvName(j->name);
if (i->matches(drvName)) {
i->hits++;
if (i.matches(drvName)) {
i.hits++;
matches.push_back(std::pair<DrvInfo, unsigned int>(*j, n));
}
}
@@ -276,47 +276,47 @@ static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems,
Newest newest;
StringSet multiple;
for (Matches::iterator j = matches.begin(); j != matches.end(); ++j) {
DrvName drvName(j->first.name);
for (auto & j : matches) {
DrvName drvName(j.first.name);
int d = 1;
Newest::iterator k = newest.find(drvName.name);
if (k != newest.end()) {
d = j->first.system == k->second.first.system ? 0 :
j->first.system == settings.thisSystem ? 1 :
d = j.first.system == k->second.first.system ? 0 :
j.first.system == settings.thisSystem ? 1 :
k->second.first.system == settings.thisSystem ? -1 : 0;
if (d == 0)
d = comparePriorities(state, j->first, k->second.first);
d = comparePriorities(state, j.first, k->second.first);
if (d == 0)
d = compareVersions(drvName.version, DrvName(k->second.first.name).version);
}
if (d > 0) {
newest.erase(drvName.name);
newest.insert(Newest::value_type(drvName.name, *j));
multiple.erase(j->first.name);
newest.insert(Newest::value_type(drvName.name, j));
multiple.erase(j.first.name);
} else if (d == 0) {
multiple.insert(j->first.name);
multiple.insert(j.first.name);
}
}
matches.clear();
for (Newest::iterator j = newest.begin(); j != newest.end(); ++j) {
if (multiple.find(j->second.first.name) != multiple.end())
for (auto & j : newest) {
if (multiple.find(j.second.first.name) != multiple.end())
printMsg(lvlInfo,
format("warning: there are multiple derivations named %1%; using the first one")
% j->second.first.name);
matches.push_back(j->second);
% j.second.first.name);
matches.push_back(j.second);
}
}
/* Insert only those elements in the final list that we
haven't inserted before. */
for (Matches::iterator j = matches.begin(); j != matches.end(); ++j)
if (done.find(j->second) == done.end()) {
done.insert(j->second);
elems.push_back(j->first);
for (auto & j : matches)
if (done.find(j.second) == done.end()) {
done.insert(j.second);
elems.push_back(j.first);
}
}
@@ -370,8 +370,8 @@ static void queryInstSources(EvalState & state,
Value vArg;
loadSourceExpr(state, instSource.nixExprPath, vArg);
foreach (Strings::const_iterator, i, args) {
Expr * eFun = state.parseExprFromString(*i, absPath("."));
for (auto & i : args) {
Expr * eFun = state.parseExprFromString(i, absPath("."));
Value vFun, vTmp;
state.eval(eFun, vFun);
mkApp(vTmp, vFun, vArg);
@@ -386,8 +386,8 @@ static void queryInstSources(EvalState & state,
derivations). */
case srcStorePaths: {
foreach (Strings::const_iterator, i, args) {
Path path = followLinksToStorePath(*i);
for (auto & i : args) {
Path path = followLinksToStorePath(i);
string name = baseNameOf(path);
string::size_type dash = name.find('-');
@@ -424,8 +424,8 @@ static void queryInstSources(EvalState & state,
case srcAttrPath: {
Value vRoot;
loadSourceExpr(state, instSource.nixExprPath, vRoot);
foreach (Strings::const_iterator, i, args) {
Value & v(*findAlongAttrPath(state, *i, *instSource.autoArgs, vRoot));
for (auto & i : args) {
Value & v(*findAlongAttrPath(state, i, *instSource.autoArgs, vRoot));
getDerivations(state, v, "", *instSource.autoArgs, elems, true);
}
break;
@@ -437,12 +437,12 @@ static void queryInstSources(EvalState & state,
static void printMissing(EvalState & state, DrvInfos & elems)
{
PathSet targets;
foreach (DrvInfos::iterator, i, elems) {
Path drvPath = i->queryDrvPath();
for (auto & i : elems) {
Path drvPath = i.queryDrvPath();
if (drvPath != "")
targets.insert(drvPath);
else
targets.insert(i->queryOutPath());
targets.insert(i.queryOutPath());
}
printMissing(*store, targets);
@@ -465,19 +465,19 @@ static void installDerivations(Globals & globals,
queryInstSources(*globals.state, globals.instSource, args, newElemsTmp, true);
/* If --prebuilt-only is given, filter out source-only packages. */
foreach (DrvInfos::iterator, i, newElemsTmp)
if (!globals.prebuiltOnly || isPrebuilt(*globals.state, *i))
newElems.push_back(*i);
for (auto & i : newElemsTmp)
if (!globals.prebuiltOnly || isPrebuilt(*globals.state, i))
newElems.push_back(i);
StringSet newNames;
for (DrvInfos::iterator i = newElems.begin(); i != newElems.end(); ++i) {
for (auto & i : newElems) {
/* `forceName' is a hack to get package names right in some
one-click installs, namely those where the name used in the
path is not the one we want (e.g., `java-front' versus
`java-front-0.9pre15899'). */
if (globals.forceName != "")
i->name = globals.forceName;
newNames.insert(DrvName(i->name).name);
i.name = globals.forceName;
newNames.insert(DrvName(i.name).name);
}
@@ -491,18 +491,18 @@ static void installDerivations(Globals & globals,
if (!globals.removeAll) {
DrvInfos installedElems = queryInstalled(*globals.state, profile);
foreach (DrvInfos::iterator, i, installedElems) {
DrvName drvName(i->name);
for (auto & i : installedElems) {
DrvName drvName(i.name);
if (!globals.preserveInstalled &&
newNames.find(drvName.name) != newNames.end() &&
!keep(*i))
printMsg(lvlInfo, format("replacing old %1%") % i->name);
!keep(i))
printMsg(lvlInfo, format("replacing old %1%") % i.name);
else
allElems.push_back(*i);
allElems.push_back(i);
}
foreach (DrvInfos::iterator, i, newElems)
printMsg(lvlInfo, format("installing %1%") % i->name);
for (auto & i : newElems)
printMsg(lvlInfo, format("installing %1%") % i.name);
}
printMissing(*globals.state, newElems);
@@ -555,13 +555,13 @@ static void upgradeDerivations(Globals & globals,
/* Go through all installed derivations. */
DrvInfos newElems;
foreach (DrvInfos::iterator, i, installedElems) {
DrvName drvName(i->name);
for (auto & i : installedElems) {
DrvName drvName(i.name);
try {
if (keep(*i)) {
newElems.push_back(*i);
if (keep(i)) {
newElems.push_back(i);
continue;
}
@@ -573,10 +573,10 @@ static void upgradeDerivations(Globals & globals,
take the one with the highest version. */
DrvInfos::iterator bestElem = availElems.end();
DrvName bestName;
foreach (DrvInfos::iterator, j, availElems) {
for (auto j = availElems.begin(); j != availElems.end(); ++j) {
DrvName newName(j->name);
if (newName.name == drvName.name) {
int d = comparePriorities(*globals.state, *i, *j);
int d = comparePriorities(*globals.state, i, *j);
if (d == 0) d = compareVersions(drvName.version, newName.version);
if ((upgradeType == utLt && d < 0) ||
(upgradeType == utLeq && d <= 0) ||
@@ -597,17 +597,17 @@ static void upgradeDerivations(Globals & globals,
}
if (bestElem != availElems.end() &&
i->queryOutPath() !=
i.queryOutPath() !=
bestElem->queryOutPath())
{
printMsg(lvlInfo,
format("upgrading %1% to %2%")
% i->name % bestElem->name);
% i.name % bestElem->name);
newElems.push_back(*bestElem);
} else newElems.push_back(*i);
} else newElems.push_back(i);
} catch (Error & e) {
e.addPrefix(format("while trying to find an upgrade for %1%:\n") % i->name);
e.addPrefix(format("while trying to find an upgrade for %1%:\n") % i.name);
throw;
}
}
@@ -666,13 +666,13 @@ static void opSetFlag(Globals & globals, Strings opFlags, Strings opArgs)
DrvInfos installedElems = queryInstalled(*globals.state, globals.profile);
/* Update all matching derivations. */
foreach (DrvInfos::iterator, i, installedElems) {
DrvName drvName(i->name);
foreach (DrvNames::iterator, j, selectors)
if (j->matches(drvName)) {
printMsg(lvlInfo, format("setting flag on %1%") % i->name);
j->hits++;
setMetaFlag(*globals.state, *i, flagName, flagValue);
for (auto & i : installedElems) {
DrvName drvName(i.name);
for (auto & j : selectors)
if (j.matches(drvName)) {
printMsg(lvlInfo, format("setting flag on %1%") % i.name);
j.hits++;
setMetaFlag(*globals.state, i, flagName, flagValue);
break;
}
}
@@ -732,20 +732,20 @@ static void uninstallDerivations(Globals & globals, Strings & selectors,
DrvInfos installedElems = queryInstalled(*globals.state, profile);
DrvInfos newElems;
foreach (DrvInfos::iterator, i, installedElems) {
DrvName drvName(i->name);
for (auto & i : installedElems) {
DrvName drvName(i.name);
bool found = false;
foreach (Strings::iterator, j, selectors)
for (auto & j : selectors)
/* !!! the repeated calls to followLinksToStorePath()
are expensive, should pre-compute them. */
if ((isPath(*j) && i->queryOutPath() == followLinksToStorePath(*j))
|| DrvName(*j).matches(drvName))
if ((isPath(j) && i.queryOutPath() == followLinksToStorePath(j))
|| DrvName(j).matches(drvName))
{
printMsg(lvlInfo, format("uninstalling %1%") % i->name);
printMsg(lvlInfo, format("uninstalling %1%") % i.name);
found = true;
break;
}
if (!found) newElems.push_back(*i);
if (!found) newElems.push_back(i);
}
if (globals.dryRun) return;
@@ -788,18 +788,18 @@ void printTable(Table & table)
vector<unsigned int> widths;
widths.resize(nrColumns);
foreach (Table::iterator, i, table) {
assert(i->size() == nrColumns);
for (auto & i : table) {
assert(i.size() == nrColumns);
Strings::iterator j;
unsigned int column;
for (j = i->begin(), column = 0; j != i->end(); ++j, ++column)
for (j = i.begin(), column = 0; j != i.end(); ++j, ++column)
if (j->size() > widths[column]) widths[column] = j->size();
}
foreach (Table::iterator, i, table) {
for (auto & i : table) {
Strings::iterator j;
unsigned int column;
for (j = i->begin(), column = 0; j != i->end(); ++j, ++column) {
for (j = i.begin(), column = 0; j != i.end(); ++j, ++column) {
string s = *j;
replace(s.begin(), s.end(), '\n', ' ');
cout << s;
@@ -828,8 +828,8 @@ static VersionDiff compareVersionAgainstSet(
VersionDiff diff = cvUnavail;
version = "?";
for (DrvInfos::const_iterator i = elems.begin(); i != elems.end(); ++i) {
DrvName name2(i->name);
for (auto & i : elems) {
DrvName name2(i.name);
if (name.name == name2.name) {
int d = compareVersions(name.version, name2.version);
if (d < 0) {
@@ -855,21 +855,21 @@ static VersionDiff compareVersionAgainstSet(
static void queryJSON(Globals & globals, vector<DrvInfo> & elems)
{
JSONObject topObj(cout);
foreach (vector<DrvInfo>::iterator, i, elems) {
topObj.attr(i->attrPath);
for (auto & i : elems) {
topObj.attr(i.attrPath);
JSONObject pkgObj(cout);
pkgObj.attr("name", i->name);
pkgObj.attr("system", i->system);
pkgObj.attr("name", i.name);
pkgObj.attr("system", i.system);
pkgObj.attr("meta");
JSONObject metaObj(cout);
StringSet metaNames = i->queryMetaNames();
foreach (StringSet::iterator, j, metaNames) {
metaObj.attr(*j);
Value * v = i->queryMeta(*j);
StringSet metaNames = i.queryMetaNames();
for (auto & j : metaNames) {
metaObj.attr(j);
Value * v = i.queryMeta(j);
if (!v) {
printMsg(lvlError, format("derivation %1% has invalid meta attribute %2%") % i->name % *j);
printMsg(lvlError, format("derivation %1% has invalid meta attribute %2%") % i.name % j);
cout << "null";
} else {
PathSet context;
@@ -944,8 +944,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
/* Sort them by name. */
/* !!! */
vector<DrvInfo> elems;
for (DrvInfos::iterator i = elems_.begin(); i != elems_.end(); ++i)
elems.push_back(*i);
for (auto & i : elems_) elems.push_back(i);
sort(elems.begin(), elems.end(), cmpElemByName);
@@ -954,9 +953,8 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
PathSet installed; /* installed paths */
if (printStatus) {
for (DrvInfos::iterator i = installedElems.begin();
i != installedElems.end(); ++i)
installed.insert(i->queryOutPath());
for (auto & i : installedElems)
installed.insert(i.queryOutPath());
}
@@ -964,12 +962,12 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
PathSet validPaths, substitutablePaths;
if (printStatus || globals.prebuiltOnly) {
PathSet paths;
foreach (vector<DrvInfo>::iterator, i, elems)
for (auto & i : elems)
try {
paths.insert(i->queryOutPath());
paths.insert(i.queryOutPath());
} catch (AssertionError & e) {
printMsg(lvlTalkative, format("skipping derivation named %1% which gives an assertion failure") % i->name);
i->setFailed();
printMsg(lvlTalkative, format("skipping derivation named %1% which gives an assertion failure") % i.name);
i.setFailed();
}
validPaths = store->queryValidPaths(paths);
substitutablePaths = store->querySubstitutablePaths(paths);
@@ -990,15 +988,15 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
XMLWriter xml(true, *(xmlOutput ? &cout : &dummy));
XMLOpenElement xmlRoot(xml, "items");
foreach (vector<DrvInfo>::iterator, i, elems) {
for (auto & i : elems) {
try {
if (i->hasFailed()) continue;
if (i.hasFailed()) continue;
startNest(nest, lvlDebug, format("outputting query result %1%") % i->attrPath);
startNest(nest, lvlDebug, format("outputting query result %1%") % i.attrPath);
if (globals.prebuiltOnly &&
validPaths.find(i->queryOutPath()) == validPaths.end() &&
substitutablePaths.find(i->queryOutPath()) == substitutablePaths.end())
validPaths.find(i.queryOutPath()) == validPaths.end() &&
substitutablePaths.find(i.queryOutPath()) == substitutablePaths.end())
continue;
/* For table output. */
@@ -1008,7 +1006,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
XMLAttrs attrs;
if (printStatus) {
Path outPath = i->queryOutPath();
Path outPath = i.queryOutPath();
bool hasSubs = substitutablePaths.find(outPath) != substitutablePaths.end();
bool isInstalled = installed.find(outPath) != installed.end();
bool isValid = validPaths.find(outPath) != validPaths.end();
@@ -1024,14 +1022,14 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
}
if (xmlOutput)
attrs["attrPath"] = i->attrPath;
attrs["attrPath"] = i.attrPath;
else if (printAttrPath)
columns.push_back(i->attrPath);
columns.push_back(i.attrPath);
if (xmlOutput)
attrs["name"] = i->name;
attrs["name"] = i.name;
else if (printName)
columns.push_back(i->name);
columns.push_back(i.name);
if (compareVersions) {
/* Compare this element against the versions of the
@@ -1039,7 +1037,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
elements, or the set of installed elements. !!!
This is O(N * M), should be O(N * lg M). */
string version;
VersionDiff diff = compareVersionAgainstSet(*i, otherElems, version);
VersionDiff diff = compareVersionAgainstSet(i, otherElems, version);
char ch;
switch (diff) {
@@ -1064,13 +1062,13 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
}
if (xmlOutput) {
if (i->system != "") attrs["system"] = i->system;
if (i.system != "") attrs["system"] = i.system;
}
else if (printSystem)
columns.push_back(i->system);
columns.push_back(i.system);
if (printDrvPath) {
string drvPath = i->queryDrvPath();
string drvPath = i.queryDrvPath();
if (xmlOutput) {
if (drvPath != "") attrs["drvPath"] = drvPath;
} else
@@ -1078,18 +1076,18 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
}
if (printOutPath && !xmlOutput) {
DrvInfo::Outputs outputs = i->queryOutputs();
DrvInfo::Outputs outputs = i.queryOutputs();
string s;
foreach (DrvInfo::Outputs::iterator, j, outputs) {
for (auto & j : outputs) {
if (!s.empty()) s += ';';
if (j->first != "out") { s += j->first; s += "="; }
s += j->second;
if (j.first != "out") { s += j.first; s += "="; }
s += j.second;
}
columns.push_back(s);
}
if (printDescription) {
string descr = i->queryMetaString("description");
string descr = i.queryMetaString("description");
if (xmlOutput) {
if (descr != "") attrs["description"] = descr;
} else
@@ -1100,22 +1098,22 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
if (printOutPath || printMeta) {
XMLOpenElement item(xml, "item", attrs);
if (printOutPath) {
DrvInfo::Outputs outputs = i->queryOutputs();
foreach (DrvInfo::Outputs::iterator, j, outputs) {
DrvInfo::Outputs outputs = i.queryOutputs();
for (auto & j : outputs) {
XMLAttrs attrs2;
attrs2["name"] = j->first;
attrs2["path"] = j->second;
attrs2["name"] = j.first;
attrs2["path"] = j.second;
xml.writeEmptyElement("output", attrs2);
}
}
if (printMeta) {
StringSet metaNames = i->queryMetaNames();
foreach (StringSet::iterator, j, metaNames) {
StringSet metaNames = i.queryMetaNames();
for (auto & j : metaNames) {
XMLAttrs attrs2;
attrs2["name"] = *j;
Value * v = i->queryMeta(*j);
attrs2["name"] = j;
Value * v = i.queryMeta(j);
if (!v)
printMsg(lvlError, format("derivation %1% has invalid meta attribute %2%") % i->name % *j);
printMsg(lvlError, format("derivation %1% has invalid meta attribute %2%") % i.name % j);
else {
if (v->type == tString) {
attrs2["type"] = "string";
@@ -1129,13 +1127,13 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
attrs2["type"] = "bool";
attrs2["value"] = v->boolean ? "true" : "false";
xml.writeEmptyElement("meta", attrs2);
} else if (v->type == tList) {
} else if (v->isList()) {
attrs2["type"] = "strings";
XMLOpenElement m(xml, "meta", attrs2);
for (unsigned int j = 0; j < v->list.length; ++j) {
if (v->list.elems[j]->type != tString) continue;
for (unsigned int j = 0; j < v->listSize(); ++j) {
if (v->listElems()[j]->type != tString) continue;
XMLAttrs attrs3;
attrs3["value"] = v->list.elems[j]->string.s;
attrs3["value"] = v->listElems()[j]->string.s;
xml.writeEmptyElement("string", attrs3);
}
}
@@ -1150,9 +1148,9 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
cout.flush();
} catch (AssertionError & e) {
printMsg(lvlTalkative, format("skipping derivation named %1% which gives an assertion failure") % i->name);
printMsg(lvlTalkative, format("skipping derivation named %1% which gives an assertion failure") % i.name);
} catch (Error & e) {
e.addPrefix(format("while querying the derivation named %1%:\n") % i->name);
e.addPrefix(format("while querying the derivation named %1%:\n") % i.name);
throw;
}
}
@@ -1187,10 +1185,10 @@ static void switchGeneration(Globals & globals, int dstGen)
Generations gens = findGenerations(globals.profile, curGen);
Generation dst;
for (Generations::iterator i = gens.begin(); i != gens.end(); ++i)
if ((dstGen == prevGen && i->number < curGen) ||
(dstGen >= 0 && i->number == dstGen))
dst = *i;
for (auto & i : gens)
if ((dstGen == prevGen && i.number < curGen) ||
(dstGen >= 0 && i.number == dstGen))
dst = i;
if (!dst) {
if (dstGen == prevGen)
@@ -1250,14 +1248,14 @@ static void opListGenerations(Globals & globals, Strings opFlags, Strings opArgs
RunPager pager;
for (Generations::iterator i = gens.begin(); i != gens.end(); ++i) {
for (auto & i : gens) {
tm t;
if (!localtime_r(&i->creationTime, &t)) throw Error("cannot convert time");
if (!localtime_r(&i.creationTime, &t)) throw Error("cannot convert time");
cout << format("%|4| %|4|-%|02|-%|02| %|02|:%|02|:%|02| %||\n")
% i->number
% i.number
% (t.tm_year + 1900) % (t.tm_mon + 1) % t.tm_mday
% t.tm_hour % t.tm_min % t.tm_sec
% (i->number == curGen ? "(current)" : "");
% (i.number == curGen ? "(current)" : "");
}
}
@@ -1284,6 +1282,12 @@ static void opDeleteGenerations(Globals & globals, Strings opFlags, Strings opAr
}
static void opVersion(Globals & globals, Strings opFlags, Strings opArgs)
{
printVersion("nix-env");
}
int main(int argc, char * * argv)
{
return handleExceptions(argv[0], [&]() {
@@ -1313,7 +1317,7 @@ int main(int argc, char * * argv)
if (*arg == "--help")
showManPage("nix-env");
else if (*arg == "--version")
printVersion("nix-env");
op = opVersion;
else if (*arg == "--install" || *arg == "-i")
op = opInstall;
else if (parseAutoArgs(arg, end, autoArgs_))
+23 -23
View File
@@ -33,9 +33,9 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
/* Build the components in the user environment, if they don't
exist already. */
PathSet drvsToBuild;
foreach (DrvInfos::iterator, i, elems)
if (i->queryDrvPath() != "")
drvsToBuild.insert(i->queryDrvPath());
for (auto & i : elems)
if (i.queryDrvPath() != "")
drvsToBuild.insert(i.queryDrvPath());
debug(format("building user environment dependencies"));
store->buildPaths(drvsToBuild, state.repair ? bmRepair : bmNormal);
@@ -45,51 +45,51 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
Value manifest;
state.mkList(manifest, elems.size());
unsigned int n = 0;
foreach (DrvInfos::iterator, i, elems) {
for (auto & i : elems) {
/* Create a pseudo-derivation containing the name, system,
output paths, and optionally the derivation path, as well
as the meta attributes. */
Path drvPath = keepDerivations ? i->queryDrvPath() : "";
Path drvPath = keepDerivations ? i.queryDrvPath() : "";
Value & v(*state.allocValue());
manifest.list.elems[n++] = &v;
manifest.listElems()[n++] = &v;
state.mkAttrs(v, 16);
mkString(*state.allocAttr(v, state.sType), "derivation");
mkString(*state.allocAttr(v, state.sName), i->name);
if (!i->system.empty())
mkString(*state.allocAttr(v, state.sSystem), i->system);
mkString(*state.allocAttr(v, state.sOutPath), i->queryOutPath());
mkString(*state.allocAttr(v, state.sName), i.name);
if (!i.system.empty())
mkString(*state.allocAttr(v, state.sSystem), i.system);
mkString(*state.allocAttr(v, state.sOutPath), i.queryOutPath());
if (drvPath != "")
mkString(*state.allocAttr(v, state.sDrvPath), i->queryDrvPath());
mkString(*state.allocAttr(v, state.sDrvPath), i.queryDrvPath());
// Copy each output.
DrvInfo::Outputs outputs = i->queryOutputs();
DrvInfo::Outputs outputs = i.queryOutputs();
Value & vOutputs = *state.allocAttr(v, state.sOutputs);
state.mkList(vOutputs, outputs.size());
unsigned int m = 0;
foreach (DrvInfo::Outputs::iterator, j, outputs) {
mkString(*(vOutputs.list.elems[m++] = state.allocValue()), j->first);
Value & vOutputs = *state.allocAttr(v, state.symbols.create(j->first));
for (auto & j : outputs) {
mkString(*(vOutputs.listElems()[m++] = state.allocValue()), j.first);
Value & vOutputs = *state.allocAttr(v, state.symbols.create(j.first));
state.mkAttrs(vOutputs, 2);
mkString(*state.allocAttr(vOutputs, state.sOutPath), j->second);
mkString(*state.allocAttr(vOutputs, state.sOutPath), j.second);
/* This is only necessary when installing store paths, e.g.,
`nix-env -i /nix/store/abcd...-foo'. */
store->addTempRoot(j->second);
store->ensurePath(j->second);
store->addTempRoot(j.second);
store->ensurePath(j.second);
references.insert(j->second);
references.insert(j.second);
}
// Copy the meta attributes.
Value & vMeta = *state.allocAttr(v, state.sMeta);
state.mkAttrs(vMeta, 16);
StringSet metaNames = i->queryMetaNames();
foreach (StringSet::iterator, j, metaNames) {
Value * v = i->queryMeta(*j);
StringSet metaNames = i.queryMetaNames();
for (auto & j : metaNames) {
Value * v = i.queryMeta(j);
if (!v) continue;
vMeta.attrs->push_back(Attr(state.symbols.create(*j), v));
vMeta.attrs->push_back(Attr(state.symbols.create(j), v));
}
vMeta.attrs->sort();
v.attrs->sort();
+8 -8
View File
@@ -45,8 +45,8 @@ void processExpr(EvalState & state, const Strings & attrPaths,
Value vRoot;
state.eval(e, vRoot);
foreach (Strings::const_iterator, i, attrPaths) {
Value & v(*findAlongAttrPath(state, *i, autoArgs, vRoot));
for (auto & i : attrPaths) {
Value & v(*findAlongAttrPath(state, i, autoArgs, vRoot));
state.forceValue(v);
PathSet context;
@@ -67,11 +67,11 @@ void processExpr(EvalState & state, const Strings & attrPaths,
} else {
DrvInfos drvs;
getDerivations(state, v, "", autoArgs, drvs, false);
foreach (DrvInfos::iterator, i, drvs) {
Path drvPath = i->queryDrvPath();
for (auto & i : drvs) {
Path drvPath = i.queryDrvPath();
/* What output do we want? */
string outputName = i->queryOutputName();
string outputName = i.queryOutputName();
if (outputName == "")
throw Error(format("derivation %1% lacks an outputName attribute ") % drvPath);
@@ -168,9 +168,9 @@ int main(int argc, char * * argv)
if (attrPaths.empty()) attrPaths.push_back("");
if (findFile) {
foreach (Strings::iterator, i, files) {
Path p = state.findFile(*i);
if (p == "") throw Error(format("unable to find %1%") % *i);
for (auto & i : files) {
Path p = state.findFile(i);
if (p == "") throw Error(format("unable to find %1%") % i);
std::cout << p << std::endl;
}
return;
+189 -172
View File
@@ -69,13 +69,13 @@ static PathSet realisePath(Path path, bool build = true)
rootNr++;
if (p.second.empty())
foreach (DerivationOutputs::iterator, i, drv.outputs) p.second.insert(i->first);
for (auto & i : drv.outputs) p.second.insert(i.first);
PathSet outputs;
foreach (StringSet::iterator, j, p.second) {
DerivationOutputs::iterator i = drv.outputs.find(*j);
for (auto & j : p.second) {
DerivationOutputs::iterator i = drv.outputs.find(j);
if (i == drv.outputs.end())
throw Error(format("derivation %1% does not have an output named %2%") % p.first % *j);
throw Error(format("derivation %1% does not have an output named %2%") % p.first % j);
Path outPath = i->second.path;
if (gcRoot == "")
printGCWarning();
@@ -113,16 +113,16 @@ static void opRealise(Strings opFlags, Strings opArgs)
BuildMode buildMode = bmNormal;
bool ignoreUnknown = false;
foreach (Strings::iterator, i, opFlags)
if (*i == "--dry-run") dryRun = true;
else if (*i == "--repair") buildMode = bmRepair;
else if (*i == "--check") buildMode = bmCheck;
else if (*i == "--ignore-unknown") ignoreUnknown = true;
else throw UsageError(format("unknown flag %1%") % *i);
for (auto & i : opFlags)
if (i == "--dry-run") dryRun = true;
else if (i == "--repair") buildMode = bmRepair;
else if (i == "--check") buildMode = bmCheck;
else if (i == "--ignore-unknown") ignoreUnknown = true;
else throw UsageError(format("unknown flag %1%") % i);
Paths paths;
foreach (Strings::iterator, i, opArgs) {
DrvPathWithOutputs p = parseDrvPathWithOutputs(*i);
for (auto & i : opArgs) {
DrvPathWithOutputs p = parseDrvPathWithOutputs(i);
paths.push_back(makeDrvPathWithOutputs(followLinksToStorePath(p.first), p.second));
}
@@ -133,8 +133,8 @@ static void opRealise(Strings opFlags, Strings opArgs)
if (ignoreUnknown) {
Paths paths2;
foreach (Paths::iterator, i, paths)
if (unknown.find(*i) == unknown.end()) paths2.push_back(*i);
for (auto & i : paths)
if (unknown.find(i) == unknown.end()) paths2.push_back(i);
paths = paths2;
unknown = PathSet();
}
@@ -148,11 +148,11 @@ static void opRealise(Strings opFlags, Strings opArgs)
store->buildPaths(PathSet(paths.begin(), paths.end()), buildMode);
if (!ignoreUnknown)
foreach (Paths::iterator, i, paths) {
PathSet paths = realisePath(*i, false);
for (auto & i : paths) {
PathSet paths = realisePath(i, false);
if (!noOutput)
foreach (PathSet::iterator, j, paths)
cout << format("%1%\n") % *j;
for (auto & j : paths)
cout << format("%1%\n") % j;
}
}
@@ -173,10 +173,9 @@ static void opAddFixed(Strings opFlags, Strings opArgs)
{
bool recursive = false;
for (Strings::iterator i = opFlags.begin();
i != opFlags.end(); ++i)
if (*i == "--recursive") recursive = true;
else throw UsageError(format("unknown flag %1%") % *i);
for (auto & i : opFlags)
if (i == "--recursive") recursive = true;
else throw UsageError(format("unknown flag %1%") % i);
if (opArgs.empty())
throw UsageError("first argument must be hash algorithm");
@@ -194,10 +193,9 @@ static void opPrintFixedPath(Strings opFlags, Strings opArgs)
{
bool recursive = false;
for (Strings::iterator i = opFlags.begin();
i != opFlags.end(); ++i)
if (*i == "--recursive") recursive = true;
else throw UsageError(format("unknown flag %1%") % *i);
for (auto i : opFlags)
if (i == "--recursive") recursive = true;
else throw UsageError(format("unknown flag %1%") % i);
if (opArgs.size() != 3)
throw UsageError(format("--print-fixed-path requires three arguments"));
@@ -219,8 +217,8 @@ static PathSet maybeUseOutputs(const Path & storePath, bool useOutput, bool forc
if (useOutput && isDerivation(storePath)) {
Derivation drv = derivationFromPath(*store, storePath);
PathSet outputs;
foreach (DerivationOutputs::iterator, i, drv.outputs)
outputs.insert(i->second.path);
for (auto & i : drv.outputs)
outputs.insert(i.second.path);
return outputs;
}
else return singleton<PathSet>(storePath);
@@ -257,8 +255,8 @@ static void printTree(const Path & path,
Paths sorted = topoSortPaths(*store, references);
reverse(sorted.begin(), sorted.end());
foreach (Paths::iterator, i, sorted) {
Paths::iterator j = i; ++j;
for (auto i = sorted.begin(); i != sorted.end(); ++i) {
auto j = i; ++j;
printTree(*i, tailPad + treeConn,
j == sorted.end() ? tailPad + treeNull : tailPad + treeLine,
done);
@@ -279,34 +277,34 @@ static void opQuery(Strings opFlags, Strings opArgs)
bool forceRealise = false;
string bindingName;
foreach (Strings::iterator, i, opFlags) {
for (auto & i : opFlags) {
QueryType prev = query;
if (*i == "--outputs") query = qOutputs;
else if (*i == "--requisites" || *i == "-R") query = qRequisites;
else if (*i == "--references") query = qReferences;
else if (*i == "--referrers" || *i == "--referers") query = qReferrers;
else if (*i == "--referrers-closure" || *i == "--referers-closure") query = qReferrersClosure;
else if (*i == "--deriver" || *i == "-d") query = qDeriver;
else if (*i == "--binding" || *i == "-b") {
if (i == "--outputs") query = qOutputs;
else if (i == "--requisites" || i == "-R") query = qRequisites;
else if (i == "--references") query = qReferences;
else if (i == "--referrers" || i == "--referers") query = qReferrers;
else if (i == "--referrers-closure" || i == "--referers-closure") query = qReferrersClosure;
else if (i == "--deriver" || i == "-d") query = qDeriver;
else if (i == "--binding" || i == "-b") {
if (opArgs.size() == 0)
throw UsageError("expected binding name");
bindingName = opArgs.front();
opArgs.pop_front();
query = qBinding;
}
else if (*i == "--hash") query = qHash;
else if (*i == "--size") query = qSize;
else if (*i == "--tree") query = qTree;
else if (*i == "--graph") query = qGraph;
else if (*i == "--xml") query = qXml;
else if (*i == "--resolve") query = qResolve;
else if (*i == "--roots") query = qRoots;
else if (*i == "--use-output" || *i == "-u") useOutput = true;
else if (*i == "--force-realise" || *i == "--force-realize" || *i == "-f") forceRealise = true;
else if (*i == "--include-outputs") includeOutputs = true;
else throw UsageError(format("unknown flag %1%") % *i);
else if (i == "--hash") query = qHash;
else if (i == "--size") query = qSize;
else if (i == "--tree") query = qTree;
else if (i == "--graph") query = qGraph;
else if (i == "--xml") query = qXml;
else if (i == "--resolve") query = qResolve;
else if (i == "--roots") query = qRoots;
else if (i == "--use-output" || i == "-u") useOutput = true;
else if (i == "--force-realise" || i == "--force-realize" || i == "-f") forceRealise = true;
else if (i == "--include-outputs") includeOutputs = true;
else throw UsageError(format("unknown flag %1%") % i);
if (prev != qDefault && prev != query)
throw UsageError(format("query type %1% conflicts with earlier flag") % *i);
throw UsageError(format("query type %1% conflicts with earlier flag") % i);
}
if (query == qDefault) query = qOutputs;
@@ -316,12 +314,12 @@ static void opQuery(Strings opFlags, Strings opArgs)
switch (query) {
case qOutputs: {
foreach (Strings::iterator, i, opArgs) {
*i = followLinksToStorePath(*i);
if (forceRealise) realisePath(*i);
Derivation drv = derivationFromPath(*store, *i);
foreach (DerivationOutputs::iterator, j, drv.outputs)
cout << format("%1%\n") % j->second.path;
for (auto & i : opArgs) {
i = followLinksToStorePath(i);
if (forceRealise) realisePath(i);
Derivation drv = derivationFromPath(*store, i);
for (auto & j : drv.outputs)
cout << format("%1%\n") % j.second.path;
}
break;
}
@@ -331,13 +329,13 @@ static void opQuery(Strings opFlags, Strings opArgs)
case qReferrers:
case qReferrersClosure: {
PathSet paths;
foreach (Strings::iterator, i, opArgs) {
PathSet ps = maybeUseOutputs(followLinksToStorePath(*i), useOutput, forceRealise);
foreach (PathSet::iterator, j, ps) {
if (query == qRequisites) computeFSClosure(*store, *j, paths, false, includeOutputs);
else if (query == qReferences) store->queryReferences(*j, paths);
else if (query == qReferrers) store->queryReferrers(*j, paths);
else if (query == qReferrersClosure) computeFSClosure(*store, *j, paths, true);
for (auto & i : opArgs) {
PathSet ps = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise);
for (auto & j : ps) {
if (query == qRequisites) computeFSClosure(*store, j, paths, false, includeOutputs);
else if (query == qReferences) store->queryReferences(j, paths);
else if (query == qReferrers) store->queryReferrers(j, paths);
else if (query == qReferrersClosure) computeFSClosure(*store, j, paths, true);
}
}
Paths sorted = topoSortPaths(*store, paths);
@@ -348,16 +346,16 @@ static void opQuery(Strings opFlags, Strings opArgs)
}
case qDeriver:
foreach (Strings::iterator, i, opArgs) {
Path deriver = store->queryDeriver(followLinksToStorePath(*i));
for (auto & i : opArgs) {
Path deriver = store->queryDeriver(followLinksToStorePath(i));
cout << format("%1%\n") %
(deriver == "" ? "unknown-deriver" : deriver);
}
break;
case qBinding:
foreach (Strings::iterator, i, opArgs) {
Path path = useDeriver(followLinksToStorePath(*i));
for (auto & i : opArgs) {
Path path = useDeriver(followLinksToStorePath(i));
Derivation drv = derivationFromPath(*store, path);
StringPairs::iterator j = drv.env.find(bindingName);
if (j == drv.env.end())
@@ -369,10 +367,10 @@ static void opQuery(Strings opFlags, Strings opArgs)
case qHash:
case qSize:
foreach (Strings::iterator, i, opArgs) {
PathSet paths = maybeUseOutputs(followLinksToStorePath(*i), useOutput, forceRealise);
foreach (PathSet::iterator, j, paths) {
ValidPathInfo info = store->queryPathInfo(*j);
for (auto & i : opArgs) {
PathSet paths = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise);
for (auto & j : paths) {
ValidPathInfo info = store->queryPathInfo(j);
if (query == qHash) {
assert(info.hash.type == htSHA256);
cout << format("sha256:%1%\n") % printHash32(info.hash);
@@ -384,15 +382,15 @@ static void opQuery(Strings opFlags, Strings opArgs)
case qTree: {
PathSet done;
foreach (Strings::iterator, i, opArgs)
printTree(followLinksToStorePath(*i), "", "", done);
for (auto & i : opArgs)
printTree(followLinksToStorePath(i), "", "", done);
break;
}
case qGraph: {
PathSet roots;
foreach (Strings::iterator, i, opArgs) {
PathSet paths = maybeUseOutputs(followLinksToStorePath(*i), useOutput, forceRealise);
for (auto & i : opArgs) {
PathSet paths = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise);
roots.insert(paths.begin(), paths.end());
}
printDotGraph(roots);
@@ -401,8 +399,8 @@ static void opQuery(Strings opFlags, Strings opArgs)
case qXml: {
PathSet roots;
foreach (Strings::iterator, i, opArgs) {
PathSet paths = maybeUseOutputs(followLinksToStorePath(*i), useOutput, forceRealise);
for (auto & i : opArgs) {
PathSet paths = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise);
roots.insert(paths.begin(), paths.end());
}
printXmlGraph(roots);
@@ -410,23 +408,23 @@ static void opQuery(Strings opFlags, Strings opArgs)
}
case qResolve: {
foreach (Strings::iterator, i, opArgs)
cout << format("%1%\n") % followLinksToStorePath(*i);
for (auto & i : opArgs)
cout << format("%1%\n") % followLinksToStorePath(i);
break;
}
case qRoots: {
PathSet referrers;
foreach (Strings::iterator, i, opArgs) {
PathSet paths = maybeUseOutputs(followLinksToStorePath(*i), useOutput, forceRealise);
foreach (PathSet::iterator, j, paths)
computeFSClosure(*store, *j, referrers, true,
for (auto & i : opArgs) {
PathSet paths = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise);
for (auto & j : paths)
computeFSClosure(*store, j, referrers, true,
settings.gcKeepOutputs, settings.gcKeepDerivations);
}
Roots roots = store->findRoots();
foreach (Roots::iterator, i, roots)
if (referrers.find(i->second) != referrers.end())
cout << format("%1%\n") % i->first;
for (auto & i : roots)
if (referrers.find(i.second) != referrers.end())
cout << format("%1%\n") % i.first;
break;
}
@@ -439,8 +437,8 @@ static void opQuery(Strings opFlags, Strings opArgs)
static string shellEscape(const string & s)
{
string r;
foreach (string::const_iterator, i, s)
if (*i == '\'') r += "'\\''"; else r += *i;
for (auto & i : s)
if (i == '\'') r += "'\\''"; else r += i;
return r;
}
@@ -455,15 +453,17 @@ static void opPrintEnv(Strings opFlags, Strings opArgs)
/* Print each environment variable in the derivation in a format
that can be sourced by the shell. */
foreach (StringPairs::iterator, i, drv.env)
cout << format("export %1%; %1%='%2%'\n") % i->first % shellEscape(i->second);
for (auto & i : drv.env)
cout << format("export %1%; %1%='%2%'\n") % i.first % shellEscape(i.second);
/* Also output the arguments. This doesn't preserve whitespace in
arguments. */
cout << "export _args; _args='";
foreach (Strings::iterator, i, drv.args) {
if (i != drv.args.begin()) cout << ' ';
cout << shellEscape(*i);
bool first = true;
for (auto & i : drv.args) {
if (!first) cout << ' ';
first = false;
cout << shellEscape(i);
}
cout << "'\n";
}
@@ -475,8 +475,8 @@ static void opReadLog(Strings opFlags, Strings opArgs)
RunPager pager;
foreach (Strings::iterator, i, opArgs) {
Path path = useDeriver(followLinksToStorePath(*i));
for (auto & i : opArgs) {
Path path = useDeriver(followLinksToStorePath(i));
string baseName = baseNameOf(path);
bool found = false;
@@ -547,8 +547,8 @@ static void opDumpDB(Strings opFlags, Strings opArgs)
if (!opArgs.empty())
throw UsageError("no arguments expected");
PathSet validPaths = store->queryAllValidPaths();
foreach (PathSet::iterator, i, validPaths)
cout << store->makeValidityRegistration(singleton<PathSet>(*i), true, true);
for (auto & i : validPaths)
cout << store->makeValidityRegistration(singleton<PathSet>(i), true, true);
}
@@ -590,11 +590,10 @@ static void opRegisterValidity(Strings opFlags, Strings opArgs)
bool reregister = false; // !!! maybe this should be the default
bool hashGiven = false;
for (Strings::iterator i = opFlags.begin();
i != opFlags.end(); ++i)
if (*i == "--reregister") reregister = true;
else if (*i == "--hash-given") hashGiven = true;
else throw UsageError(format("unknown flag %1%") % *i);
for (auto & i : opFlags)
if (i == "--reregister") reregister = true;
else if (i == "--hash-given") hashGiven = true;
else throw UsageError(format("unknown flag %1%") % i);
if (!opArgs.empty()) throw UsageError("no arguments expected");
@@ -606,15 +605,12 @@ static void opCheckValidity(Strings opFlags, Strings opArgs)
{
bool printInvalid = false;
for (Strings::iterator i = opFlags.begin();
i != opFlags.end(); ++i)
if (*i == "--print-invalid") printInvalid = true;
else throw UsageError(format("unknown flag %1%") % *i);
for (auto & i : opFlags)
if (i == "--print-invalid") printInvalid = true;
else throw UsageError(format("unknown flag %1%") % i);
for (Strings::iterator i = opArgs.begin();
i != opArgs.end(); ++i)
{
Path path = followLinksToStorePath(*i);
for (auto & i : opArgs) {
Path path = followLinksToStorePath(i);
if (!store->isValidPath(path)) {
if (printInvalid)
cout << format("%1%\n") % path;
@@ -634,7 +630,7 @@ static void opGC(Strings opFlags, Strings opArgs)
GCResults results;
/* Do what? */
foreach (Strings::iterator, i, opFlags)
for (auto i = opFlags.begin(); i != opFlags.end(); ++i)
if (*i == "--print-roots") printRoots = true;
else if (*i == "--print-live") options.action = GCOptions::gcReturnLive;
else if (*i == "--print-dead") options.action = GCOptions::gcReturnDead;
@@ -649,8 +645,8 @@ static void opGC(Strings opFlags, Strings opArgs)
if (printRoots) {
Roots roots = store->findRoots();
foreach (Roots::iterator, i, roots)
cout << i->first << " -> " << i->second << std::endl;
for (auto & i : roots)
cout << i.first << " -> " << i.second << std::endl;
}
else {
@@ -658,8 +654,8 @@ static void opGC(Strings opFlags, Strings opArgs)
store->collectGarbage(options, results);
if (options.action != GCOptions::gcDeleteDead)
foreach (PathSet::iterator, i, results.paths)
cout << *i << std::endl;
for (auto & i : results.paths)
cout << i << std::endl;
}
}
@@ -672,12 +668,12 @@ static void opDelete(Strings opFlags, Strings opArgs)
GCOptions options;
options.action = GCOptions::gcDeleteSpecific;
foreach (Strings::iterator, i, opFlags)
if (*i == "--ignore-liveness") options.ignoreLiveness = true;
else throw UsageError(format("unknown flag %1%") % *i);
for (auto & i : opFlags)
if (i == "--ignore-liveness") options.ignoreLiveness = true;
else throw UsageError(format("unknown flag %1%") % i);
foreach (Strings::iterator, i, opArgs)
options.pathsToDelete.insert(followLinksToStorePath(*i));
for (auto & i : opArgs)
options.pathsToDelete.insert(followLinksToStorePath(i));
GCResults results;
PrintFreed freed(true, results);
@@ -713,10 +709,9 @@ static void opRestore(Strings opFlags, Strings opArgs)
static void opExport(Strings opFlags, Strings opArgs)
{
bool sign = false;
for (Strings::iterator i = opFlags.begin();
i != opFlags.end(); ++i)
if (*i == "--sign") sign = true;
else throw UsageError(format("unknown flag %1%") % *i);
for (auto & i : opFlags)
if (i == "--sign") sign = true;
else throw UsageError(format("unknown flag %1%") % i);
FdSink sink(STDOUT_FILENO);
Paths sorted = topoSortPaths(*store, PathSet(opArgs.begin(), opArgs.end()));
@@ -728,17 +723,17 @@ static void opExport(Strings opFlags, Strings opArgs)
static void opImport(Strings opFlags, Strings opArgs)
{
bool requireSignature = false;
foreach (Strings::iterator, i, opFlags)
if (*i == "--require-signature") requireSignature = true;
else throw UsageError(format("unknown flag %1%") % *i);
for (auto & i : opFlags)
if (i == "--require-signature") requireSignature = true;
else throw UsageError(format("unknown flag %1%") % i);
if (!opArgs.empty()) throw UsageError("no arguments expected");
FdSource source(STDIN_FILENO);
Paths paths = store->importPaths(requireSignature, source);
foreach (Paths::iterator, i, paths)
cout << format("%1%\n") % *i << std::flush;
for (auto & i : paths)
cout << format("%1%\n") % i << std::flush;
}
@@ -762,11 +757,10 @@ static void opVerify(Strings opFlags, Strings opArgs)
bool checkContents = false;
bool repair = false;
for (Strings::iterator i = opFlags.begin();
i != opFlags.end(); ++i)
if (*i == "--check-contents") checkContents = true;
else if (*i == "--repair") repair = true;
else throw UsageError(format("unknown flag %1%") % *i);
for (auto & i : opFlags)
if (i == "--check-contents") checkContents = true;
else if (i == "--repair") repair = true;
else throw UsageError(format("unknown flag %1%") % i);
if (store->verifyStore(checkContents, repair)) {
printMsg(lvlError, "warning: not all errors were fixed");
@@ -783,8 +777,8 @@ static void opVerifyPath(Strings opFlags, Strings opArgs)
int status = 0;
foreach (Strings::iterator, i, opArgs) {
Path path = followLinksToStorePath(*i);
for (auto & i : opArgs) {
Path path = followLinksToStorePath(i);
printMsg(lvlTalkative, format("checking path %1%...") % path);
ValidPathInfo info = store->queryPathInfo(path);
HashResult current = hashPath(info.hash.type, path);
@@ -807,8 +801,8 @@ static void opRepairPath(Strings opFlags, Strings opArgs)
if (!opFlags.empty())
throw UsageError("no flags expected");
foreach (Strings::iterator, i, opArgs) {
Path path = followLinksToStorePath(*i);
for (auto & i : opArgs) {
Path path = followLinksToStorePath(i);
ensureLocalStore().repairPath(path);
}
}
@@ -828,8 +822,8 @@ static void opQueryFailedPaths(Strings opFlags, Strings opArgs)
if (!opArgs.empty() || !opFlags.empty())
throw UsageError("no arguments expected");
PathSet failed = store->queryFailedPaths();
foreach (PathSet::iterator, i, failed)
cout << format("%1%\n") % *i;
for (auto & i : failed)
cout << format("%1%\n") % i;
}
@@ -845,9 +839,9 @@ static void opClearFailedPaths(Strings opFlags, Strings opArgs)
static void opServe(Strings opFlags, Strings opArgs)
{
bool writeAllowed = false;
foreach (Strings::iterator, i, opFlags)
if (*i == "--write") writeAllowed = true;
else throw UsageError(format("unknown flag %1%") % *i);
for (auto & i : opFlags)
if (i == "--write") writeAllowed = true;
else throw UsageError(format("unknown flag %1%") % i);
if (!opArgs.empty()) throw UsageError("no arguments expected");
@@ -857,11 +851,20 @@ static void opServe(Strings opFlags, Strings opArgs)
/* Exchange the greeting. */
unsigned int magic = readInt(in);
if (magic != SERVE_MAGIC_1) throw Error("protocol mismatch");
writeInt(SERVE_MAGIC_2, out);
writeInt(SERVE_PROTOCOL_VERSION, out);
out << SERVE_MAGIC_2 << SERVE_PROTOCOL_VERSION;
out.flush();
readInt(in); // Client version, unused for now
auto getBuildSettings = [&]() {
// FIXME: changing options here doesn't work if we're
// building through the daemon.
verbosity = lvlError;
settings.keepLog = false;
settings.useSubstitutes = false;
settings.maxSilentTime = readInt(in);
settings.buildTimeout = readInt(in);
};
while (true) {
ServeCommand cmd;
try {
@@ -902,25 +905,23 @@ static void opServe(Strings opFlags, Strings opArgs)
}
}
writeStrings(store->queryValidPaths(paths), out);
out << store->queryValidPaths(paths);
break;
}
case cmdQueryPathInfos: {
PathSet paths = readStorePaths<PathSet>(in);
// !!! Maybe we want a queryPathInfos?
foreach (PathSet::iterator, i, paths) {
if (!store->isValidPath(*i))
for (auto & i : paths) {
if (!store->isValidPath(i))
continue;
ValidPathInfo info = store->queryPathInfo(*i);
writeString(info.path, out);
writeString(info.deriver, out);
writeStrings(info.references, out);
ValidPathInfo info = store->queryPathInfo(i);
out << info.path << info.deriver << info.references;
// !!! Maybe we want compression?
writeLongLong(info.narSize, out); // downloadSize
writeLongLong(info.narSize, out);
out << info.narSize // downloadSize
<< info.narSize;
}
writeString("", out);
out << "";
break;
}
@@ -931,7 +932,7 @@ static void opServe(Strings opFlags, Strings opArgs)
case cmdImportPaths: {
if (!writeAllowed) throw Error("importing paths is not allowed");
store->importPaths(false, in);
writeInt(1, out); // indicate success
out << 1; // indicate success
break;
}
@@ -943,39 +944,49 @@ static void opServe(Strings opFlags, Strings opArgs)
break;
}
case cmdBuildPaths: {
case cmdBuildPaths: { /* Used by build-remote.pl. */
/* Used by build-remote.pl. */
if (!writeAllowed) throw Error("building paths is not allowed");
PathSet paths = readStorePaths<PathSet>(in);
// FIXME: changing options here doesn't work if we're
// building through the daemon.
verbosity = lvlError;
settings.keepLog = false;
settings.useSubstitutes = false;
settings.maxSilentTime = readInt(in);
settings.buildTimeout = readInt(in);
getBuildSettings();
try {
MonitorFdHup monitor(in.fd);
store->buildPaths(paths);
writeInt(0, out);
out << 0;
} catch (Error & e) {
assert(e.status);
writeInt(e.status, out);
writeString(e.msg(), out);
out << e.status << e.msg();
}
break;
}
case cmdBuildDerivation: { /* Used by hydra-queue-runner. */
if (!writeAllowed) throw Error("building paths is not allowed");
Path drvPath = readStorePath(in); // informational only
BasicDerivation drv;
in >> drv;
getBuildSettings();
MonitorFdHup monitor(in.fd);
auto status = store->buildDerivation(drvPath, drv);
out << status.status << status.errorMsg;
break;
}
case cmdQueryClosure: {
bool includeOutputs = readInt(in);
PathSet paths = readStorePaths<PathSet>(in);
PathSet closure;
for (auto & i : paths)
computeFSClosure(*store, i, closure, false, includeOutputs);
writeStrings(closure, out);
out << closure;
break;
}
@@ -990,8 +1001,8 @@ static void opServe(Strings opFlags, Strings opArgs)
static void opGenerateBinaryCacheKey(Strings opFlags, Strings opArgs)
{
foreach (Strings::iterator, i, opFlags)
throw UsageError(format("unknown flag %1%") % *i);
for (auto & i : opFlags)
throw UsageError(format("unknown flag %1%") % i);
if (opArgs.size() != 3) throw UsageError("three arguments expected");
auto i = opArgs.begin();
@@ -1016,6 +1027,12 @@ static void opGenerateBinaryCacheKey(Strings opFlags, Strings opArgs)
}
static void opVersion(Strings opFlags, Strings opArgs)
{
printVersion("nix-store");
}
/* Scan the arguments; find the operation, set global flags, put all
other flags in a list, and put all other arguments in another
list. */
@@ -1033,7 +1050,7 @@ int main(int argc, char * * argv)
if (*arg == "--help")
showManPage("nix-store");
else if (*arg == "--version")
printVersion("nix-store");
op = opVersion;
else if (*arg == "--realise" || *arg == "--realize" || *arg == "-r")
op = opRealise;
else if (*arg == "--add" || *arg == "-A")
+2 -1
View File
@@ -5,7 +5,7 @@ namespace nix {
#define SERVE_MAGIC_1 0x390c9deb
#define SERVE_MAGIC_2 0x5452eecb
#define SERVE_PROTOCOL_VERSION 0x200
#define SERVE_PROTOCOL_VERSION 0x201
#define GET_PROTOCOL_MAJOR(x) ((x) & 0xff00)
#define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff)
@@ -17,6 +17,7 @@ typedef enum {
cmdExportPaths = 5,
cmdBuildPaths = 6,
cmdQueryClosure = 7,
cmdBuildDerivation = 8,
} ServeCommand;
}
+1
View File
@@ -0,0 +1 @@
[ false false true true true true false true ]
+11
View File
@@ -0,0 +1,11 @@
with builtins;
[ (any (x: x == 1) [])
(any (x: x == 1) [2 3 4])
(any (x: x == 1) [1 2 3 4])
(any (x: x == 1) [4 3 2 1])
(all (x: x == 1) [])
(all (x: x == 1) [1])
(all (x: x == 1) [1 2 3])
(all (x: x == 1) [1 1 1])
]
@@ -0,0 +1 @@
[ "" "foobarxyzzy" "foo, bar, xyzzy" "foo" "" ]
@@ -0,0 +1,8 @@
with builtins;
[ (concatStringsSep "" [])
(concatStringsSep "" ["foo" "bar" "xyzzy"])
(concatStringsSep ", " ["foo" "bar" "xyzzy"])
(concatStringsSep ", " ["foo"])
(concatStringsSep ", " [])
]
+1
View File
@@ -0,0 +1 @@
[ "faabar" "fbar" "fubar" "faboor" "fubar" ]
+8
View File
@@ -0,0 +1,8 @@
with builtins;
[ (replaceStrings ["o"] ["a"] "foobar")
(replaceStrings ["o"] [""] "foobar")
(replaceStrings ["oo"] ["u"] "foobar")
(replaceStrings ["oo" "a"] ["a" "oo"] "foobar")
(replaceStrings ["oo" "oo"] ["u" "i"] "foobar")
]
+1
View File
@@ -0,0 +1 @@
[ [ 42 77 147 249 483 526 ] [ 526 483 249 147 77 42 ] [ "bar" "fnord" "foo" "xyzzy" ] [ { key = 1; value = "foo"; } { key = 1; value = "fnord"; } { key = 2; value = "bar"; } ] ]
+8
View File
@@ -0,0 +1,8 @@
with builtins;
[ (sort lessThan [ 483 249 526 147 42 77 ])
(sort (x: y: y < x) [ 483 249 526 147 42 77 ])
(sort lessThan [ "foo" "bar" "xyzzy" "fnord" ])
(sort (x: y: x.key < y.key)
[ { key = 1; value = "foo"; } { key = 2; value = "bar"; } { key = 1; value = "fnord"; } ])
]
+1 -1
View File
@@ -1 +1 @@
"foobar/a/b/c/d/foo/xyzzy/foo.txt/../foo/x/yescape: \"quote\" \n \\end\nof\nlinefoobarblaatfoo$bar"
"foobar/a/b/c/d/foo/xyzzy/foo.txt/../foo/x/yescape: \"quote\" \n \\end\nof\nlinefoobarblaatfoo$bar$\"$\"$"
+2
View File
@@ -8,3 +8,5 @@ of
line"
+ "foo${if true then "b${"a" + "r"}" else "xyzzy"}blaat"
+ "foo$bar"
+ "$\"$\""
+ "$"
+4 -4
View File
@@ -17,7 +17,7 @@ rec {
then fold (x: y: (flatten x) ++ y) [] x
else [x];
sum = fold (x: y: add x y) 0;
sum = foldl' (x: y: add x y) 0;
hasSuffix = ext: fileName:
let lenFileName = stringLength fileName;
@@ -54,8 +54,8 @@ rec {
const = x: y: x;
range = first: last:
if builtins.lessThan last first
then []
else [first] ++ range (builtins.add first 1) last;
if first > last
then []
else genList (n: first + n) (last - first + 1);
}
+3
View File
@@ -14,3 +14,6 @@ nix-env --version | grep "$version"
# Usage errors.
nix-env --foo 2>&1 | grep "no operation"
nix-env -q --foo 2>&1 | grep "unknown flag"
# Eval Errors.
nix-instantiate --eval -E 'let a = {} // a; in a.foo' 2>&1 | grep "infinite recursion encountered, at (string):1:15$"
+1 -1
View File
@@ -1 +1 @@
1.9
1.10