Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71a5161365 | ||
|
|
6e06a18d1b | ||
|
|
73332fd342 | ||
|
|
d711fe8f5e | ||
|
|
ce97523a7c | ||
|
|
e12cf82782 | ||
|
|
eadb86f447 | ||
|
|
1d29db2a9f | ||
|
|
26221e44eb | ||
|
|
984c5cdc50 | ||
|
|
3b0f60e5c2 | ||
|
|
896428c818 | ||
|
|
34dfbd9394 | ||
|
|
30d19a2bdc | ||
|
|
3db950aab7 | ||
|
|
2bac04c5ff | ||
|
|
75837651f1 | ||
|
|
76cc8e97a2 | ||
|
|
50807f3dd5 | ||
|
|
f3dda728a4 | ||
|
|
d6d5885c15 | ||
|
|
2e8fd4c5cd | ||
|
|
cb4320c1a0 | ||
|
|
c8bb2371eb | ||
|
|
16c9935fa9 | ||
|
|
19eddecc0f | ||
|
|
b83801f8b3 | ||
|
|
14be783676 | ||
|
|
39e27a04b8 | ||
|
|
1ed55234d9 | ||
|
|
61af14a921 | ||
|
|
887bb5fa5a | ||
|
|
1993b10d11 | ||
|
|
0a2bee307b | ||
|
|
eda2f36c2a | ||
|
|
ccf31dbc25 | ||
|
|
db55940d9e | ||
|
|
b3491c781c | ||
|
|
6bd2c7bb38 | ||
|
|
1511aa9f48 | ||
|
|
f39979c6d3 | ||
|
|
7c9d0a5969 | ||
|
|
5845ffdf13 | ||
|
|
db21cfa688 | ||
|
|
467977f203 | ||
|
|
65e4dcd69b | ||
|
|
dd48c06bb6 | ||
|
|
9aed117395 | ||
|
|
e012c126db | ||
|
|
ff4de4cb27 | ||
|
|
2bc9c84327 | ||
|
|
ba63ec6f39 | ||
|
|
65f17cd330 | ||
|
|
0d4d92fcf9 | ||
|
|
a33b4bc01b |
@@ -12,7 +12,6 @@ in rec {
|
|||||||
tar = "@tar@";
|
tar = "@tar@";
|
||||||
tarFlags = "@tarFlags@";
|
tarFlags = "@tarFlags@";
|
||||||
tr = "@tr@";
|
tr = "@tr@";
|
||||||
curl = "@curl@";
|
|
||||||
nixBinDir = fromEnv "NIX_BIN_DIR" "@bindir@";
|
nixBinDir = fromEnv "NIX_BIN_DIR" "@bindir@";
|
||||||
nixPrefix = "@prefix@";
|
nixPrefix = "@prefix@";
|
||||||
|
|
||||||
|
|||||||
+2
-15
@@ -5,20 +5,9 @@ with import <nix/config.nix>;
|
|||||||
assert (outputHash != "" && outputHashAlgo != "")
|
assert (outputHash != "" && outputHashAlgo != "")
|
||||||
|| md5 != "" || sha1 != "" || sha256 != "";
|
|| 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 {
|
derivation {
|
||||||
name = baseNameOf (toString url);
|
name = baseNameOf (toString url);
|
||||||
builder = shell;
|
builder = "builtin:fetchurl";
|
||||||
args = [ "-e" builder ];
|
|
||||||
|
|
||||||
# New-style output content requirements.
|
# New-style output content requirements.
|
||||||
outputHashAlgo = if outputHashAlgo != "" then outputHashAlgo else
|
outputHashAlgo = if outputHashAlgo != "" then outputHashAlgo else
|
||||||
@@ -27,7 +16,7 @@ derivation {
|
|||||||
if sha256 != "" then sha256 else if sha1 != "" then sha1 else md5;
|
if sha256 != "" then sha256 else if sha1 != "" then sha1 else md5;
|
||||||
outputHashMode = if executable then "recursive" else "flat";
|
outputHashMode = if executable then "recursive" else "flat";
|
||||||
|
|
||||||
inherit system url;
|
inherit system url executable;
|
||||||
|
|
||||||
# No need to double the amount of network traffic
|
# No need to double the amount of network traffic
|
||||||
preferLocalBuild = true;
|
preferLocalBuild = true;
|
||||||
@@ -39,6 +28,4 @@ derivation {
|
|||||||
# by definition pure.
|
# by definition pure.
|
||||||
"http_proxy" "https_proxy" "ftp_proxy" "all_proxy" "no_proxy"
|
"http_proxy" "https_proxy" "ftp_proxy" "all_proxy" "no_proxy"
|
||||||
];
|
];
|
||||||
|
|
||||||
inherit chrootDeps;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
attrs @ { drvPath, outputs, ... }:
|
attrs @ { drvPath, outputs, name, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
commonAttrs = (builtins.listToAttrs outputsList) //
|
commonAttrs = (builtins.listToAttrs outputsList) //
|
||||||
{ all = map (x: x.value) outputsList;
|
{ all = map (x: x.value) outputsList;
|
||||||
inherit drvPath;
|
inherit drvPath name;
|
||||||
type = "derivation";
|
type = "derivation";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
<arg><option>--include-outputs</option></arg>
|
<arg><option>--include-outputs</option></arg>
|
||||||
<arg><option>--use-substitutes</option></arg>
|
<arg><option>--use-substitutes</option></arg>
|
||||||
<arg><option>-s</option></arg>
|
<arg><option>-s</option></arg>
|
||||||
|
<arg><option>-v</option></arg>
|
||||||
<arg choice='plain'>
|
<arg choice='plain'>
|
||||||
<replaceable>user@</replaceable><replaceable>machine</replaceable>
|
<replaceable>user@</replaceable><replaceable>machine</replaceable>
|
||||||
</arg>
|
</arg>
|
||||||
@@ -138,6 +139,12 @@ those paths. If this bothers you, use
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry><term><option>-v</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Show verbose output.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
</refsection>
|
</refsection>
|
||||||
|
|||||||
@@ -39,6 +39,28 @@ available as <function>builtins.derivation</function>.</para>
|
|||||||
</varlistentry>
|
</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>
|
<varlistentry><term><function>builtins.attrNames</function>
|
||||||
<replaceable>set</replaceable></term>
|
<replaceable>set</replaceable></term>
|
||||||
|
|
||||||
@@ -313,6 +335,19 @@ stdenv.mkDerivation {
|
|||||||
</varlistentry>
|
</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>
|
<varlistentry><term><function>builtins.fromJSON</function> <replaceable>e</replaceable></term>
|
||||||
|
|
||||||
<listitem><para>Convert a JSON string to a Nix
|
<listitem><para>Convert a JSON string to a Nix
|
||||||
@@ -329,6 +364,24 @@ builtins.fromJSON ''{"x": [1, 2, 3], "y": null}''
|
|||||||
</varlistentry>
|
</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>
|
<varlistentry><term><function>builtins.getAttr</function>
|
||||||
<replaceable>s</replaceable> <replaceable>set</replaceable></term>
|
<replaceable>s</replaceable> <replaceable>set</replaceable></term>
|
||||||
|
|
||||||
@@ -663,7 +716,7 @@ in config.someSetting</programlisting>
|
|||||||
./A</literal> will return the set
|
./A</literal> will return the set
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
{ A = "regular"; B = "directory"; }</programlisting>
|
{ B = "regular"; C = "directory"; }</programlisting>
|
||||||
|
|
||||||
The possible values for the file type are
|
The possible values for the file type are
|
||||||
<literal>"regular"</literal>, <literal>"directory"</literal>,
|
<literal>"regular"</literal>, <literal>"directory"</literal>,
|
||||||
@@ -698,6 +751,23 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</programlisting>
|
|||||||
</varlistentry>
|
</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>
|
<varlistentry><term><function>builtins.seq</function>
|
||||||
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
||||||
|
|
||||||
@@ -709,6 +779,29 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</programlisting>
|
|||||||
</varlistentry>
|
</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>
|
<varlistentry><term><function>builtins.stringLength</function>
|
||||||
<replaceable>e</replaceable></term>
|
<replaceable>e</replaceable></term>
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
</partintro>
|
</partintro>
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
<xi:include href="rl-1.10.xml" />
|
||||||
<xi:include href="rl-1.9.xml" />
|
<xi:include href="rl-1.9.xml" />
|
||||||
<xi:include href="rl-1.8.xml" />
|
<xi:include href="rl-1.8.xml" />
|
||||||
<xi:include href="rl-1.7.xml" />
|
<xi:include href="rl-1.7.xml" />
|
||||||
|
|||||||
@@ -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 doesn’t
|
||||||
|
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><nix/fetchurl.nix></literal> now
|
||||||
|
uses a <emphasis>builtin</emphasis> builder (i.e. it doesn’t
|
||||||
|
require starting an external process; the download is performed by
|
||||||
|
Nix itself). This ensures that derivation paths don’t 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>
|
||||||
@@ -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):
|
<listitem><para>In <command>nixos-rebuild</command> (on NixOS):
|
||||||
|
|
||||||
<screen>
|
<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>
|
</screen>
|
||||||
|
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
|
|||||||
@@ -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
@@ -305,7 +305,9 @@ let
|
|||||||
memSize = 1024;
|
memSize = 1024;
|
||||||
meta.schedulingPriority = 50;
|
meta.schedulingPriority = 50;
|
||||||
configureFlags = "--sysconfdir=/etc";
|
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>";
|
debMaintainer = "Eelco Dolstra <eelco.dolstra@logicblox.com>";
|
||||||
doInstallCheck = true;
|
doInstallCheck = true;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,8 +16,6 @@ binmode STDERR, ":encoding(utf8)";
|
|||||||
|
|
||||||
my $debug = defined $ENV{NIX_DEBUG_HOOK};
|
my $debug = defined $ENV{NIX_DEBUG_HOOK};
|
||||||
|
|
||||||
setVerbosity(0); # make exportPath() less verbose
|
|
||||||
|
|
||||||
|
|
||||||
# General operation:
|
# General operation:
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -105,8 +105,8 @@ sub update {
|
|||||||
my $tmpdir = tempdir( CLEANUP => 1 );
|
my $tmpdir = tempdir( CLEANUP => 1 );
|
||||||
my $filename;
|
my $filename;
|
||||||
($url, $filename) = `cd $tmpdir && $Nix::Config::curl --silent --write-out '%{url_effective}\n%{filename_effective}' -L '$url' -O`;
|
($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;
|
chomp $url;
|
||||||
|
die "$0: unable to check ‘$url’\n" if $? != 0;
|
||||||
|
|
||||||
# If the URL contains a version number, append it to the name
|
# If the URL contains a version number, append it to the name
|
||||||
# attribute (so that "nix-env -q" on the channels profile
|
# attribute (so that "nix-env -q" on the channels profile
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ my $toMode = 1;
|
|||||||
my $includeOutputs = 0;
|
my $includeOutputs = 0;
|
||||||
my $dryRun = 0;
|
my $dryRun = 0;
|
||||||
my $useSubstitutes = 0;
|
my $useSubstitutes = 0;
|
||||||
|
my $verbosity = 1;
|
||||||
|
|
||||||
|
|
||||||
# !!! Copied from nix-pack-closure, should put this in a module.
|
# !!! 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") {
|
elsif ($arg eq "--use-substitutes" || $arg eq "-s") {
|
||||||
$useSubstitutes = 1;
|
$useSubstitutes = 1;
|
||||||
}
|
}
|
||||||
|
elsif ($arg eq "-v") {
|
||||||
|
$verbosity++;
|
||||||
|
setVerbosity($verbosity);
|
||||||
|
}
|
||||||
elsif (!defined $sshHost) {
|
elsif (!defined $sshHost) {
|
||||||
$sshHost = $arg;
|
$sshHost = $arg;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ if [ -n "$HOME" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
export PATH=$NIX_LINK/bin:$NIX_LINK/sbin:$PATH
|
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.
|
# Subscribe the user to the Nixpkgs channel by default.
|
||||||
if [ ! -e $HOME/.nix-channels ]; then
|
if [ ! -e $HOME/.nix-channels ]; then
|
||||||
|
|||||||
@@ -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)
|
static void substitute(std::pair<FdSink, FdSource> & pipes, Path storePath, Path destPath)
|
||||||
{
|
{
|
||||||
writeInt(cmdDumpStorePath, pipes.first);
|
pipes.first << cmdDumpStorePath << storePath;
|
||||||
writeString(storePath, pipes.first);
|
|
||||||
pipes.first.flush();
|
pipes.first.flush();
|
||||||
restorePath(destPath, pipes.second);
|
restorePath(destPath, pipes.second);
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
@@ -58,17 +57,17 @@ static void query(std::pair<FdSink, FdSource> & pipes)
|
|||||||
string cmd = tokenized.front();
|
string cmd = tokenized.front();
|
||||||
tokenized.pop_front();
|
tokenized.pop_front();
|
||||||
if (cmd == "have") {
|
if (cmd == "have") {
|
||||||
writeInt(cmdQueryValidPaths, pipes.first);
|
pipes.first
|
||||||
writeInt(0, pipes.first); // don't lock
|
<< cmdQueryValidPaths
|
||||||
writeInt(0, pipes.first); // don't substitute
|
<< 0 // don't lock
|
||||||
writeStrings(tokenized, pipes.first);
|
<< 0 // don't substitute
|
||||||
|
<< tokenized;
|
||||||
pipes.first.flush();
|
pipes.first.flush();
|
||||||
PathSet paths = readStrings<PathSet>(pipes.second);
|
PathSet paths = readStrings<PathSet>(pipes.second);
|
||||||
foreach (PathSet::iterator, i, paths)
|
for (auto & i : paths)
|
||||||
std::cout << *i << std::endl;
|
std::cout << i << std::endl;
|
||||||
} else if (cmd == "info") {
|
} else if (cmd == "info") {
|
||||||
writeInt(cmdQueryPathInfos, pipes.first);
|
pipes.first << cmdQueryPathInfos << tokenized;
|
||||||
writeStrings(tokenized, pipes.first);
|
|
||||||
pipes.first.flush();
|
pipes.first.flush();
|
||||||
while (1) {
|
while (1) {
|
||||||
Path path = readString(pipes.second);
|
Path path = readString(pipes.second);
|
||||||
@@ -80,8 +79,8 @@ static void query(std::pair<FdSink, FdSource> & pipes)
|
|||||||
std::cout << deriver << std::endl;
|
std::cout << deriver << std::endl;
|
||||||
PathSet references = readStorePaths<PathSet>(pipes.second);
|
PathSet references = readStorePaths<PathSet>(pipes.second);
|
||||||
std::cout << references.size() << std::endl;
|
std::cout << references.size() << std::endl;
|
||||||
foreach (PathSet::iterator, i, references)
|
for (auto & i : references)
|
||||||
std::cout << *i << std::endl;
|
std::cout << i << std::endl;
|
||||||
std::cout << readLongLong(pipes.second) << std::endl;
|
std::cout << readLongLong(pipes.second) << 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);
|
std::pair<FdSink, FdSource> pipes = connect(host);
|
||||||
|
|
||||||
/* Exchange the greeting */
|
/* Exchange the greeting */
|
||||||
writeInt(SERVE_MAGIC_1, pipes.first);
|
pipes.first << SERVE_MAGIC_1;
|
||||||
pipes.first.flush();
|
pipes.first.flush();
|
||||||
unsigned int magic = readInt(pipes.second);
|
unsigned int magic = readInt(pipes.second);
|
||||||
if (magic != SERVE_MAGIC_2)
|
if (magic != SERVE_MAGIC_2)
|
||||||
throw Error("protocol mismatch");
|
throw Error("protocol mismatch");
|
||||||
readInt(pipes.second); // Server version, unused for now
|
readInt(pipes.second); // Server version, unused for now
|
||||||
writeInt(SERVE_PROTOCOL_VERSION, pipes.first);
|
pipes.first << SERVE_PROTOCOL_VERSION;
|
||||||
pipes.first.flush();
|
pipes.first.flush();
|
||||||
|
|
||||||
string arg = argv[1];
|
string arg = argv[1];
|
||||||
|
|||||||
@@ -42,11 +42,10 @@ Value * findAlongAttrPath(EvalState & state, const string & attrPath,
|
|||||||
|
|
||||||
Value * v = &vIn;
|
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;
|
enum { apAttr, apIndex } apType = apAttr;
|
||||||
string attr = *i;
|
|
||||||
unsigned int attrIndex;
|
unsigned int attrIndex;
|
||||||
if (string2Int(attr, attrIndex)) apType = apIndex;
|
if (string2Int(attr, attrIndex)) apType = apIndex;
|
||||||
|
|
||||||
@@ -77,15 +76,15 @@ Value * findAlongAttrPath(EvalState & state, const string & attrPath,
|
|||||||
|
|
||||||
else if (apType == apIndex) {
|
else if (apType == apIndex) {
|
||||||
|
|
||||||
if (v->type != tList)
|
if (!v->isList())
|
||||||
throw TypeError(
|
throw TypeError(
|
||||||
format("the expression selected by the selection path ‘%1%’ should be a list but is %2%")
|
format("the expression selected by the selection path ‘%1%’ should be a list but is %2%")
|
||||||
% attrPath % showType(*v));
|
% 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);
|
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];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -7,9 +7,9 @@
|
|||||||
|
|
||||||
namespace nix {
|
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))
|
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) {
|
if (v.type == tThunk) {
|
||||||
Env * env = v.thunk.env;
|
Env * env = v.thunk.env;
|
||||||
@@ -43,7 +43,7 @@ void EvalState::forceValue(Value & v)
|
|||||||
else if (v.type == tApp)
|
else if (v.type == tApp)
|
||||||
callFunction(*v.app.left, *v.app.right, v, noPos);
|
callFunction(*v.app.left, *v.app.right, v, noPos);
|
||||||
else if (v.type == tBlackhole)
|
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)
|
inline void EvalState::forceList(Value & v)
|
||||||
{
|
{
|
||||||
forceValue(v);
|
forceValue(v);
|
||||||
if (v.type != tList)
|
if (!v.isList())
|
||||||
throwTypeError("value is %1% while a list was expected", v);
|
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)
|
inline void EvalState::forceList(Value & v, const Pos & pos)
|
||||||
{
|
{
|
||||||
forceValue(v);
|
forceValue(v);
|
||||||
if (v.type != tList)
|
if (!v.isList())
|
||||||
throwTypeError("value is %1% while a list was expected, at %2%", v, pos);
|
throwTypeError("value is %1% while a list was expected, at %2%", v, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+118
-127
@@ -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)
|
static void printValue(std::ostream & str, std::set<const Value *> & active, const Value & v)
|
||||||
{
|
{
|
||||||
|
checkInterrupt();
|
||||||
|
|
||||||
if (active.find(&v) != active.end()) {
|
if (active.find(&v) != active.end()) {
|
||||||
str << "<CYCLE>";
|
str << "<CYCLE>";
|
||||||
return;
|
return;
|
||||||
@@ -96,8 +92,8 @@ static void printValue(std::ostream & str, std::set<const Value *> & active, con
|
|||||||
str << "{ ";
|
str << "{ ";
|
||||||
typedef std::map<string, Value *> Sorted;
|
typedef std::map<string, Value *> Sorted;
|
||||||
Sorted sorted;
|
Sorted sorted;
|
||||||
foreach (Bindings::iterator, i, *v.attrs)
|
for (auto & i : *v.attrs)
|
||||||
sorted[i->name] = i->value;
|
sorted[i.name] = i.value;
|
||||||
for (auto & i : sorted) {
|
for (auto & i : sorted) {
|
||||||
str << i.first << " = ";
|
str << i.first << " = ";
|
||||||
printValue(str, active, *i.second);
|
printValue(str, active, *i.second);
|
||||||
@@ -106,10 +102,12 @@ static void printValue(std::ostream & str, std::set<const Value *> & active, con
|
|||||||
str << "}";
|
str << "}";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case tList:
|
case tList1:
|
||||||
|
case tList2:
|
||||||
|
case tListN:
|
||||||
str << "[ ";
|
str << "[ ";
|
||||||
for (unsigned int n = 0; n < v.list.length; ++n) {
|
for (unsigned int n = 0; n < v.listSize(); ++n) {
|
||||||
printValue(str, active, *v.list.elems[n]);
|
printValue(str, active, *v.listElems()[n]);
|
||||||
str << " ";
|
str << " ";
|
||||||
}
|
}
|
||||||
str << "]";
|
str << "]";
|
||||||
@@ -155,7 +153,7 @@ string showType(const Value & v)
|
|||||||
case tPath: return "a path";
|
case tPath: return "a path";
|
||||||
case tNull: return "null";
|
case tNull: return "null";
|
||||||
case tAttrs: return "a set";
|
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 tThunk: return "a thunk";
|
||||||
case tApp: return "a function application";
|
case tApp: return "a function application";
|
||||||
case tLambda: return "a function";
|
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)
|
EvalState::EvalState(const Strings & _searchPath)
|
||||||
: sWith(symbols.create("<with>"))
|
: sWith(symbols.create("<with>"))
|
||||||
, sOutPath(symbols.create("outPath"))
|
, sOutPath(symbols.create("outPath"))
|
||||||
@@ -251,14 +261,9 @@ EvalState::EvalState(const Strings & _searchPath)
|
|||||||
, sLine(symbols.create("line"))
|
, sLine(symbols.create("line"))
|
||||||
, sColumn(symbols.create("column"))
|
, sColumn(symbols.create("column"))
|
||||||
, sFunctor(symbols.create("__functor"))
|
, sFunctor(symbols.create("__functor"))
|
||||||
, repair(false)
|
|
||||||
, baseEnv(allocEnv(128))
|
, baseEnv(allocEnv(128))
|
||||||
, staticBaseEnv(false, 0)
|
, 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";
|
countCalls = getEnv("NIX_COUNT_CALLS", "0") != "0";
|
||||||
|
|
||||||
restricted = settings.get("restrict-eval", false);
|
restricted = settings.get("restrict-eval", false);
|
||||||
@@ -266,11 +271,15 @@ EvalState::EvalState(const Strings & _searchPath)
|
|||||||
assert(gcInitialised);
|
assert(gcInitialised);
|
||||||
|
|
||||||
/* Initialise the Nix expression search path. */
|
/* 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 : _searchPath) addToSearchPath(i, true);
|
||||||
for (auto & i : paths) addToSearchPath(i);
|
for (auto & i : paths) addToSearchPath(i);
|
||||||
addToSearchPath("nix=" + settings.nixDataDir + "/nix/corepkgs");
|
addToSearchPath("nix=" + settings.nixDataDir + "/nix/corepkgs");
|
||||||
|
|
||||||
|
clearValue(vEmptySet);
|
||||||
|
vEmptySet.type = tAttrs;
|
||||||
|
vEmptySet.attrs = allocBindings(0);
|
||||||
|
|
||||||
createBaseEnv();
|
createBaseEnv();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,11 +358,6 @@ LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2))
|
|||||||
throw EvalError(format(s) % 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))
|
LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, const Pos & pos))
|
||||||
{
|
{
|
||||||
throw EvalError(format(s) % s2 % 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;
|
unsigned int n = 0;
|
||||||
v.string.context = (const char * *)
|
v.string.context = (const char * *)
|
||||||
allocBytes((context.size() + 1) * sizeof(char *));
|
allocBytes((context.size() + 1) * sizeof(char *));
|
||||||
foreach (PathSet::const_iterator, i, context)
|
for (auto & i : context)
|
||||||
v.string.context[n++] = dupString(i->c_str());
|
v.string.context[n++] = dupString(i.c_str());
|
||||||
v.string.context[n] = 0;
|
v.string.context[n] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -491,37 +495,19 @@ Env & EvalState::allocEnv(unsigned int size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Value * EvalState::allocAttr(Value & vAttrs, const Symbol & name)
|
void EvalState::mkList(Value & v, unsigned int size)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
clearValue(v);
|
clearValue(v);
|
||||||
v.type = tList;
|
if (size == 1)
|
||||||
v.list.length = length;
|
v.type = tList1;
|
||||||
v.list.elems = length ? (Value * *) allocBytes(length * sizeof(Value *)) : 0;
|
else if (size == 2)
|
||||||
nrListElems += length;
|
v.type = tList2;
|
||||||
}
|
else {
|
||||||
|
v.type = tListN;
|
||||||
|
v.bigList.size = size;
|
||||||
void EvalState::mkAttrs(Value & v, unsigned int expected)
|
v.bigList.elems = size ? (Value * *) allocBytes(size * sizeof(Value *)) : 0;
|
||||||
{
|
}
|
||||||
clearValue(v);
|
nrListElems += size;
|
||||||
v.type = tAttrs;
|
|
||||||
v.attrs = allocBindings(expected);
|
|
||||||
nrAttrsets++;
|
|
||||||
nrAttrsInAttrsets += expected;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -709,15 +695,15 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
|||||||
environment, while the inherited attributes are evaluated
|
environment, while the inherited attributes are evaluated
|
||||||
in the original environment. */
|
in the original environment. */
|
||||||
unsigned int displ = 0;
|
unsigned int displ = 0;
|
||||||
foreach (AttrDefs::iterator, i, attrs) {
|
for (auto & i : attrs) {
|
||||||
Value * vAttr;
|
Value * vAttr;
|
||||||
if (hasOverrides && !i->second.inherited) {
|
if (hasOverrides && !i.second.inherited) {
|
||||||
vAttr = state.allocValue();
|
vAttr = state.allocValue();
|
||||||
mkThunk(*vAttr, env2, i->second.e);
|
mkThunk(*vAttr, env2, i.second.e);
|
||||||
} else
|
} 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;
|
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
|
/* If the rec contains an attribute called `__overrides', then
|
||||||
@@ -748,25 +734,25 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
foreach (AttrDefs::iterator, i, attrs)
|
for (auto & i : attrs)
|
||||||
v.attrs->push_back(Attr(i->first, i->second.e->maybeThunk(state, env), &i->second.pos));
|
v.attrs->push_back(Attr(i.first, i.second.e->maybeThunk(state, env), &i.second.pos));
|
||||||
|
|
||||||
/* Dynamic attrs apply *after* rec and __overrides. */
|
/* Dynamic attrs apply *after* rec and __overrides. */
|
||||||
foreach (DynamicAttrDefs::iterator, i, dynamicAttrs) {
|
for (auto & i : dynamicAttrs) {
|
||||||
Value nameVal;
|
Value nameVal;
|
||||||
i->nameExpr->eval(state, *dynamicEnv, nameVal);
|
i.nameExpr->eval(state, *dynamicEnv, nameVal);
|
||||||
state.forceValue(nameVal);
|
state.forceValue(nameVal, i.pos);
|
||||||
if (nameVal.type == tNull)
|
if (nameVal.type == tNull)
|
||||||
continue;
|
continue;
|
||||||
state.forceStringNoCtx(nameVal);
|
state.forceStringNoCtx(nameVal);
|
||||||
Symbol nameSym = state.symbols.create(nameVal.string.s);
|
Symbol nameSym = state.symbols.create(nameVal.string.s);
|
||||||
Bindings::iterator j = v.attrs->find(nameSym);
|
Bindings::iterator j = v.attrs->find(nameSym);
|
||||||
if (j != v.attrs->end())
|
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 */
|
/* 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
|
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
|
while the inherited attributes are evaluated in the original
|
||||||
environment. */
|
environment. */
|
||||||
unsigned int displ = 0;
|
unsigned int displ = 0;
|
||||||
foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs)
|
for (auto & i : attrs->attrs)
|
||||||
env2.values[displ++] = i->second.e->maybeThunk(state, i->second.inherited ? env : env2);
|
env2.values[displ++] = i.second.e->maybeThunk(state, i.second.inherited ? env : env2);
|
||||||
|
|
||||||
body->eval(state, env2, v);
|
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)
|
void ExprList::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
state.mkList(v, elems.size());
|
state.mkList(v, elems.size());
|
||||||
for (unsigned int n = 0; n < v.list.length; ++n)
|
for (unsigned int n = 0; n < elems.size(); ++n)
|
||||||
v.list.elems[n] = elems[n]->maybeThunk(state, env);
|
v.listElems()[n] = elems[n]->maybeThunk(state, env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ExprVar::eval(EvalState & state, Env & env, Value & v)
|
void ExprVar::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
Value * v2 = state.lookupVar(&env, *this, false);
|
Value * v2 = state.lookupVar(&env, *this, false);
|
||||||
state.forceValue(*v2);
|
state.forceValue(*v2, pos);
|
||||||
v = *v2;
|
v = *v2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -835,12 +821,12 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
foreach (AttrPath::const_iterator, i, attrPath) {
|
for (auto & i : attrPath) {
|
||||||
nrLookups++;
|
nrLookups++;
|
||||||
Bindings::iterator j;
|
Bindings::iterator j;
|
||||||
Symbol name = getName(*i, state, env);
|
Symbol name = getName(i, state, env);
|
||||||
if (def) {
|
if (def) {
|
||||||
state.forceValue(*vAttrs);
|
state.forceValue(*vAttrs, pos);
|
||||||
if (vAttrs->type != tAttrs ||
|
if (vAttrs->type != tAttrs ||
|
||||||
(j = vAttrs->attrs->find(name)) == vAttrs->attrs->end())
|
(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]++;
|
if (state.countCalls && pos2) state.attrSelects[*pos2]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.forceValue(*vAttrs);
|
state.forceValue(*vAttrs, ( pos2 != NULL ? *pos2 : this->pos ) );
|
||||||
|
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
if (pos2 && pos2->file != state.sDerivationNix)
|
if (pos2 && pos2->file != state.sDerivationNix)
|
||||||
@@ -877,10 +863,10 @@ void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v)
|
|||||||
|
|
||||||
e->eval(state, env, vTmp);
|
e->eval(state, env, vTmp);
|
||||||
|
|
||||||
foreach (AttrPath::const_iterator, i, attrPath) {
|
for (auto & i : attrPath) {
|
||||||
state.forceValue(*vAttrs);
|
state.forceValue(*vAttrs);
|
||||||
Bindings::iterator j;
|
Bindings::iterator j;
|
||||||
Symbol name = getName(*i, state, env);
|
Symbol name = getName(i, state, env);
|
||||||
if (vAttrs->type != tAttrs ||
|
if (vAttrs->type != tAttrs ||
|
||||||
(j = vAttrs->attrs->find(name)) == vAttrs->attrs->end())
|
(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) {
|
if (fun.type == tAttrs) {
|
||||||
auto found = fun.attrs->find(sFunctor);
|
auto found = fun.attrs->find(sFunctor);
|
||||||
if (found != fun.attrs->end()) {
|
if (found != fun.attrs->end()) {
|
||||||
forceValue(*found->value);
|
forceValue(*found->value, pos);
|
||||||
Value * v2 = allocValue();
|
Value * v2 = allocValue();
|
||||||
callFunction(*found->value, fun, *v2, pos);
|
callFunction(*found->value, fun, *v2, pos);
|
||||||
forceValue(*v2);
|
forceValue(*v2, pos);
|
||||||
return callFunction(*v2, arg, v, 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
|
there is no matching actual argument but the formal
|
||||||
argument has a default, use the default. */
|
argument has a default, use the default. */
|
||||||
unsigned int attrsUsed = 0;
|
unsigned int attrsUsed = 0;
|
||||||
foreach (Formals::Formals_::iterator, i, lambda.formals->formals) {
|
for (auto & i : lambda.formals->formals) {
|
||||||
Bindings::iterator j = arg.attrs->find(i->name);
|
Bindings::iterator j = arg.attrs->find(i.name);
|
||||||
if (j == arg.attrs->end()) {
|
if (j == arg.attrs->end()) {
|
||||||
if (!i->def) throwTypeError("%1% called without required argument ‘%2%’, at %3%",
|
if (!i.def) throwTypeError("%1% called without required argument ‘%2%’, at %3%",
|
||||||
lambda, i->name, pos);
|
lambda, i.name, pos);
|
||||||
env2.values[displ++] = i->def->maybeThunk(*this, env2);
|
env2.values[displ++] = i.def->maybeThunk(*this, env2);
|
||||||
} else {
|
} else {
|
||||||
attrsUsed++;
|
attrsUsed++;
|
||||||
env2.values[displ++] = j->value;
|
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()) {
|
if (!lambda.formals->ellipsis && attrsUsed != arg.attrs->size()) {
|
||||||
/* Nope, so show the first unexpected argument to the
|
/* Nope, so show the first unexpected argument to the
|
||||||
user. */
|
user. */
|
||||||
foreach (Bindings::iterator, i, *arg.attrs)
|
for (auto & i : *arg.attrs)
|
||||||
if (lambda.formals->argNames.find(i->name) == lambda.formals->argNames.end())
|
if (lambda.formals->argNames.find(i.name) == lambda.formals->argNames.end())
|
||||||
throwTypeError("%1% called with unexpected argument ‘%2%’, at %3%", lambda, i->name, pos);
|
throwTypeError("%1% called with unexpected argument ‘%2%’, at %3%", lambda, i.name, pos);
|
||||||
abort(); // can't happen
|
abort(); // can't happen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1054,12 +1040,12 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
|
|||||||
Value * actualArgs = allocValue();
|
Value * actualArgs = allocValue();
|
||||||
mkAttrs(*actualArgs, fun.lambda.fun->formals->formals.size());
|
mkAttrs(*actualArgs, fun.lambda.fun->formals->formals.size());
|
||||||
|
|
||||||
foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) {
|
for (auto & i : fun.lambda.fun->formals->formals) {
|
||||||
Bindings::iterator j = args.find(i->name);
|
Bindings::iterator j = args.find(i.name);
|
||||||
if (j != args.end())
|
if (j != args.end())
|
||||||
actualArgs->attrs->push_back(*j);
|
actualArgs->attrs->push_back(*j);
|
||||||
else if (!i->def)
|
else if (!i.def)
|
||||||
throwTypeError("cannot auto-call a function that has an argument without a default value (‘%1%’)", i->name);
|
throwTypeError("cannot auto-call a function that has an argument without a default value (‘%1%’)", i.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
actualArgs->attrs->sort();
|
actualArgs->attrs->sort();
|
||||||
@@ -1187,20 +1173,21 @@ void EvalState::concatLists(Value & v, unsigned int nrLists, Value * * lists, co
|
|||||||
unsigned int len = 0;
|
unsigned int len = 0;
|
||||||
for (unsigned int n = 0; n < nrLists; ++n) {
|
for (unsigned int n = 0; n < nrLists; ++n) {
|
||||||
forceList(*lists[n], pos);
|
forceList(*lists[n], pos);
|
||||||
unsigned int l = lists[n]->list.length;
|
unsigned int l = lists[n]->listSize();
|
||||||
len += l;
|
len += l;
|
||||||
if (l) nonEmpty = lists[n];
|
if (l) nonEmpty = lists[n];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nonEmpty && len == nonEmpty->list.length) {
|
if (nonEmpty && len == nonEmpty->listSize()) {
|
||||||
v = *nonEmpty;
|
v = *nonEmpty;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mkList(v, len);
|
mkList(v, len);
|
||||||
|
auto out = v.listElems();
|
||||||
for (unsigned int n = 0, pos = 0; n < nrLists; ++n) {
|
for (unsigned int n = 0, pos = 0; n < nrLists; ++n) {
|
||||||
unsigned int l = lists[n]->list.length;
|
unsigned int l = lists[n]->listSize();
|
||||||
memcpy(v.list.elems + pos, lists[n]->list.elems, l * sizeof(Value *));
|
memcpy(out + pos, lists[n]->listElems(), l * sizeof(Value *));
|
||||||
pos += l;
|
pos += l;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1215,9 +1202,9 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
|||||||
bool first = !forceString;
|
bool first = !forceString;
|
||||||
ValueType firstType = tString;
|
ValueType firstType = tString;
|
||||||
|
|
||||||
foreach (vector<Expr *>::iterator, i, *es) {
|
for (auto & i : *es) {
|
||||||
Value vTmp;
|
Value vTmp;
|
||||||
(*i)->eval(state, env, vTmp);
|
i->eval(state, env, vTmp);
|
||||||
|
|
||||||
/* If the first element is a path, then the result will also
|
/* 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,
|
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) {
|
else if (v.isList()) {
|
||||||
for (unsigned int n = 0; n < v.list.length; ++n)
|
for (unsigned int n = 0; n < v.listSize(); ++n)
|
||||||
recurse(*v.list.elems[n]);
|
recurse(*v.listElems()[n]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1288,7 +1275,7 @@ void EvalState::forceValueDeep(Value & v)
|
|||||||
|
|
||||||
NixInt EvalState::forceInt(Value & v, const Pos & pos)
|
NixInt EvalState::forceInt(Value & v, const Pos & pos)
|
||||||
{
|
{
|
||||||
forceValue(v);
|
forceValue(v, pos);
|
||||||
if (v.type != tInt)
|
if (v.type != tInt)
|
||||||
throwTypeError("value is %1% while an integer was expected, at %2%", v, pos);
|
throwTypeError("value is %1% while an integer was expected, at %2%", v, pos);
|
||||||
return v.integer;
|
return v.integer;
|
||||||
@@ -1314,7 +1301,7 @@ void EvalState::forceFunction(Value & v, const Pos & pos)
|
|||||||
|
|
||||||
string EvalState::forceString(Value & v, const Pos & pos)
|
string EvalState::forceString(Value & v, const Pos & pos)
|
||||||
{
|
{
|
||||||
forceValue(v);
|
forceValue(v, pos);
|
||||||
if (v.type != tString) {
|
if (v.type != tString) {
|
||||||
if (pos)
|
if (pos)
|
||||||
throwTypeError("value is %1% while a string was expected, at %2%", v, 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 == tInt) return int2String(v.integer);
|
||||||
if (v.type == tNull) return "";
|
if (v.type == tNull) return "";
|
||||||
|
|
||||||
if (v.type == tList) {
|
if (v.isList()) {
|
||||||
string result;
|
string result;
|
||||||
for (unsigned int n = 0; n < v.list.length; ++n) {
|
for (unsigned int n = 0; n < v.listSize(); ++n) {
|
||||||
result += coerceToString(pos, *v.list.elems[n],
|
result += coerceToString(pos, *v.listElems()[n],
|
||||||
context, coerceMore, copyToStore);
|
context, coerceMore, copyToStore);
|
||||||
if (n < v.list.length - 1
|
if (n < v.listSize() - 1
|
||||||
/* !!! not quite correct */
|
/* !!! 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 += " ";
|
result += " ";
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -1480,10 +1467,12 @@ bool EvalState::eqValues(Value & v1, Value & v2)
|
|||||||
case tNull:
|
case tNull:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case tList:
|
case tList1:
|
||||||
if (v1.list.length != v2.list.length) return false;
|
case tList2:
|
||||||
for (unsigned int n = 0; n < v1.list.length; ++n)
|
case tListN:
|
||||||
if (!eqValues(*v1.list.elems[n], *v2.list.elems[n])) return false;
|
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;
|
return true;
|
||||||
|
|
||||||
case tAttrs: {
|
case tAttrs: {
|
||||||
@@ -1569,25 +1558,25 @@ void EvalState::printStats()
|
|||||||
printMsg(v, format("calls to %1% primops:") % primOpCalls.size());
|
printMsg(v, format("calls to %1% primops:") % primOpCalls.size());
|
||||||
typedef std::multimap<unsigned int, Symbol> PrimOpCalls_;
|
typedef std::multimap<unsigned int, Symbol> PrimOpCalls_;
|
||||||
PrimOpCalls_ primOpCalls_;
|
PrimOpCalls_ primOpCalls_;
|
||||||
foreach (PrimOpCalls::iterator, i, primOpCalls)
|
for (auto & i : primOpCalls)
|
||||||
primOpCalls_.insert(std::pair<unsigned int, Symbol>(i->second, i->first));
|
primOpCalls_.insert(std::pair<unsigned int, Symbol>(i.second, i.first));
|
||||||
foreach_reverse (PrimOpCalls_::reverse_iterator, i, primOpCalls_)
|
for (auto i = primOpCalls_.rbegin(); i != primOpCalls_.rend(); ++i)
|
||||||
printMsg(v, format("%1$10d %2%") % i->first % i->second);
|
printMsg(v, format("%1$10d %2%") % i->first % i->second);
|
||||||
|
|
||||||
printMsg(v, format("calls to %1% functions:") % functionCalls.size());
|
printMsg(v, format("calls to %1% functions:") % functionCalls.size());
|
||||||
typedef std::multimap<unsigned int, ExprLambda *> FunctionCalls_;
|
typedef std::multimap<unsigned int, ExprLambda *> FunctionCalls_;
|
||||||
FunctionCalls_ functionCalls_;
|
FunctionCalls_ functionCalls_;
|
||||||
foreach (FunctionCalls::iterator, i, functionCalls)
|
for (auto & i : functionCalls)
|
||||||
functionCalls_.insert(std::pair<unsigned int, ExprLambda *>(i->second, i->first));
|
functionCalls_.insert(std::pair<unsigned int, ExprLambda *>(i.second, i.first));
|
||||||
foreach_reverse (FunctionCalls_::reverse_iterator, i, functionCalls_)
|
for (auto i = functionCalls_.rbegin(); i != functionCalls_.rend(); ++i)
|
||||||
printMsg(v, format("%1$10d %2%") % i->first % i->second->showNamePos());
|
printMsg(v, format("%1$10d %2%") % i->first % i->second->showNamePos());
|
||||||
|
|
||||||
printMsg(v, format("evaluations of %1% attributes:") % attrSelects.size());
|
printMsg(v, format("evaluations of %1% attributes:") % attrSelects.size());
|
||||||
typedef std::multimap<unsigned int, Pos> AttrSelects_;
|
typedef std::multimap<unsigned int, Pos> AttrSelects_;
|
||||||
AttrSelects_ attrSelects_;
|
AttrSelects_ attrSelects_;
|
||||||
foreach (AttrSelects::iterator, i, attrSelects)
|
for (auto & i : attrSelects)
|
||||||
attrSelects_.insert(std::pair<unsigned int, Pos>(i->second, i->first));
|
attrSelects_.insert(std::pair<unsigned int, Pos>(i.second, i.first));
|
||||||
foreach_reverse (AttrSelects_::reverse_iterator, i, attrSelects_)
|
for (auto i = attrSelects_.rbegin(); i != attrSelects_.rend(); ++i)
|
||||||
printMsg(v, format("%1$10d %2%") % i->first % i->second);
|
printMsg(v, format("%1$10d %2%") % i->first % i->second);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1631,12 +1620,14 @@ size_t valueSize(Value & v)
|
|||||||
sz += doValue(*i.value);
|
sz += doValue(*i.value);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case tList:
|
case tList1:
|
||||||
if (seen.find(v.list.elems) == seen.end()) {
|
case tList2:
|
||||||
seen.insert(v.list.elems);
|
case tListN:
|
||||||
sz += v.list.length * sizeof(Value *);
|
if (seen.find(v.listElems()) == seen.end()) {
|
||||||
for (unsigned int n = 0; n < v.list.length; ++n)
|
seen.insert(v.listElems());
|
||||||
sz += doValue(*v.list.elems[n]);
|
sz += v.listSize() * sizeof(Value *);
|
||||||
|
for (unsigned int n = 0; n < v.listSize(); ++n)
|
||||||
|
sz += doValue(*v.listElems()[n]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case tThunk:
|
case tThunk:
|
||||||
|
|||||||
+18
-79
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "attr-set.hh"
|
||||||
#include "value.hh"
|
#include "value.hh"
|
||||||
#include "nixexpr.hh"
|
#include "nixexpr.hh"
|
||||||
#include "symbol-table.hh"
|
#include "symbol-table.hh"
|
||||||
@@ -18,70 +19,6 @@ namespace nix {
|
|||||||
class EvalState;
|
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);
|
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
|
/* If set, force copying files to the Nix store even if they
|
||||||
already exist there. */
|
already exist there. */
|
||||||
bool repair;
|
bool repair = false;
|
||||||
|
|
||||||
/* If set, don't allow access to files outside of the Nix search
|
/* If set, don't allow access to files outside of the Nix search
|
||||||
path or to environment variables. */
|
path or to environment variables. */
|
||||||
bool restricted;
|
bool restricted;
|
||||||
|
|
||||||
|
Value vEmptySet;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SrcToStore srcToStore;
|
SrcToStore srcToStore;
|
||||||
|
|
||||||
@@ -197,7 +136,7 @@ public:
|
|||||||
of the evaluation of the thunk. If `v' is a delayed function
|
of the evaluation of the thunk. If `v' is a delayed function
|
||||||
application, call the function and overwrite `v' with the
|
application, call the function and overwrite `v' with the
|
||||||
result. Otherwise, this is a no-op. */
|
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
|
/* Force a value, then recursively force list elements and
|
||||||
attributes. */
|
attributes. */
|
||||||
@@ -244,7 +183,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
unsigned int baseEnvDispl;
|
unsigned int baseEnvDispl = 0;
|
||||||
|
|
||||||
void createBaseEnv();
|
void createBaseEnv();
|
||||||
|
|
||||||
@@ -290,7 +229,7 @@ public:
|
|||||||
Bindings * allocBindings(Bindings::size_t capacity);
|
Bindings * allocBindings(Bindings::size_t capacity);
|
||||||
|
|
||||||
void mkList(Value & v, unsigned int length);
|
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 mkThunk_(Value & v, Expr * expr);
|
||||||
void mkPos(Value & v, Pos * pos);
|
void mkPos(Value & v, Pos * pos);
|
||||||
|
|
||||||
@@ -301,17 +240,17 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
unsigned long nrEnvs;
|
unsigned long nrEnvs = 0;
|
||||||
unsigned long nrValuesInEnvs;
|
unsigned long nrValuesInEnvs = 0;
|
||||||
unsigned long nrValues;
|
unsigned long nrValues = 0;
|
||||||
unsigned long nrListElems;
|
unsigned long nrListElems = 0;
|
||||||
unsigned long nrAttrsets;
|
unsigned long nrAttrsets = 0;
|
||||||
unsigned long nrAttrsInAttrsets;
|
unsigned long nrAttrsInAttrsets = 0;
|
||||||
unsigned long nrOpUpdates;
|
unsigned long nrOpUpdates = 0;
|
||||||
unsigned long nrOpUpdateValuesCopied;
|
unsigned long nrOpUpdateValuesCopied = 0;
|
||||||
unsigned long nrListConcats;
|
unsigned long nrListConcats = 0;
|
||||||
unsigned long nrPrimOpCalls;
|
unsigned long nrPrimOpCalls = 0;
|
||||||
unsigned long nrFunctionCalls;
|
unsigned long nrFunctionCalls = 0;
|
||||||
|
|
||||||
bool countCalls;
|
bool countCalls;
|
||||||
|
|
||||||
|
|||||||
+19
-19
@@ -39,9 +39,9 @@ DrvInfo::Outputs DrvInfo::queryOutputs()
|
|||||||
state->forceList(*i->value, *i->pos);
|
state->forceList(*i->value, *i->pos);
|
||||||
|
|
||||||
/* For each output... */
|
/* 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. */
|
/* 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));
|
Bindings::iterator out = attrs->find(state->symbols.create(name));
|
||||||
if (out == attrs->end()) continue; // FIXME: throw error?
|
if (out == attrs->end()) continue; // FIXME: throw error?
|
||||||
state->forceAttrs(*out->value);
|
state->forceAttrs(*out->value);
|
||||||
@@ -85,8 +85,8 @@ StringSet DrvInfo::queryMetaNames()
|
|||||||
{
|
{
|
||||||
StringSet res;
|
StringSet res;
|
||||||
if (!getMeta()) return res;
|
if (!getMeta()) return res;
|
||||||
foreach (Bindings::iterator, i, *meta)
|
for (auto & i : *meta)
|
||||||
res.insert(i->name);
|
res.insert(i.name);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,16 +94,16 @@ StringSet DrvInfo::queryMetaNames()
|
|||||||
bool DrvInfo::checkMeta(Value & v)
|
bool DrvInfo::checkMeta(Value & v)
|
||||||
{
|
{
|
||||||
state->forceValue(v);
|
state->forceValue(v);
|
||||||
if (v.type == tList) {
|
if (v.isList()) {
|
||||||
for (unsigned int n = 0; n < v.list.length; ++n)
|
for (unsigned int n = 0; n < v.listSize(); ++n)
|
||||||
if (!checkMeta(*v.list.elems[n])) return false;
|
if (!checkMeta(*v.listElems()[n])) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (v.type == tAttrs) {
|
else if (v.type == tAttrs) {
|
||||||
Bindings::iterator i = v.attrs->find(state->sOutPath);
|
Bindings::iterator i = v.attrs->find(state->sOutPath);
|
||||||
if (i != v.attrs->end()) return false;
|
if (i != v.attrs->end()) return false;
|
||||||
foreach (Bindings::iterator, i, *v.attrs)
|
for (auto & i : *v.attrs)
|
||||||
if (!checkMeta(*i->value)) return false;
|
if (!checkMeta(*i.value)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else return v.type == tInt || v.type == tBool || v.type == tString;
|
else return v.type == tInt || v.type == tBool || v.type == tString;
|
||||||
@@ -255,13 +255,13 @@ static void getDerivations(EvalState & state, Value & vIn,
|
|||||||
precedence). */
|
precedence). */
|
||||||
typedef std::map<string, Symbol> SortedSymbols;
|
typedef std::map<string, Symbol> SortedSymbols;
|
||||||
SortedSymbols attrs;
|
SortedSymbols attrs;
|
||||||
foreach (Bindings::iterator, i, *v.attrs)
|
for (auto & i : *v.attrs)
|
||||||
attrs.insert(std::pair<string, Symbol>(i->name, i->name));
|
attrs.insert(std::pair<string, Symbol>(i.name, i.name));
|
||||||
|
|
||||||
foreach (SortedSymbols::iterator, i, attrs) {
|
for (auto & i : attrs) {
|
||||||
startNest(nest, lvlDebug, format("evaluating attribute ‘%1%’") % i->first);
|
startNest(nest, lvlDebug, format("evaluating attribute ‘%1%’") % i.first);
|
||||||
string pathPrefix2 = addToPath(pathPrefix, i->first);
|
string pathPrefix2 = addToPath(pathPrefix, i.first);
|
||||||
Value & v2(*v.attrs->find(i->second)->value);
|
Value & v2(*v.attrs->find(i.second)->value);
|
||||||
if (combineChannels)
|
if (combineChannels)
|
||||||
getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
|
getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
|
||||||
else if (getDerivation(state, v2, pathPrefix2, 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) {
|
else if (v.isList()) {
|
||||||
for (unsigned int n = 0; n < v.list.length; ++n) {
|
for (unsigned int n = 0; n < v.listSize(); ++n) {
|
||||||
startNest(nest, lvlDebug,
|
startNest(nest, lvlDebug,
|
||||||
format("evaluating list element"));
|
format("evaluating list element"));
|
||||||
string pathPrefix2 = addToPath(pathPrefix, (format("%1%") % n).str());
|
string pathPrefix2 = addToPath(pathPrefix, (format("%1%") % n).str());
|
||||||
if (getDerivation(state, *v.list.elems[n], pathPrefix2, drvs, done, ignoreAssertionFailures))
|
if (getDerivation(state, *v.listElems()[n], pathPrefix2, drvs, done, ignoreAssertionFailures))
|
||||||
getDerivations(state, *v.list.elems[n], pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
|
getDerivations(state, *v.listElems()[n], pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ static void parseJSON(EvalState & state, const char * & s, Value & v)
|
|||||||
s++;
|
s++;
|
||||||
state.mkList(v, values.size());
|
state.mkList(v, values.size());
|
||||||
for (size_t n = 0; n < values.size(); ++n)
|
for (size_t n = 0; n < values.size(); ++n)
|
||||||
v.list.elems[n] = values[n];
|
v.listElems()[n] = values[n];
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (*s == '{') {
|
else if (*s == '{') {
|
||||||
|
|||||||
+20
-33
@@ -1,6 +1,9 @@
|
|||||||
%option reentrant bison-bridge bison-locations
|
%option reentrant bison-bridge bison-locations
|
||||||
%option noyywrap
|
%option noyywrap
|
||||||
%option never-interactive
|
%option never-interactive
|
||||||
|
%option stack
|
||||||
|
%option nodefault
|
||||||
|
%option nounput noyy_top_state
|
||||||
|
|
||||||
|
|
||||||
%x STRING
|
%x STRING
|
||||||
@@ -74,6 +77,9 @@ static Expr * unescapeStr(SymbolTable & symbols, const char * s)
|
|||||||
#define YY_USER_INIT initLoc(yylloc)
|
#define YY_USER_INIT initLoc(yylloc)
|
||||||
#define YY_USER_ACTION adjustLoc(yylloc, yytext, yyleng);
|
#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 INT;
|
||||||
}
|
}
|
||||||
|
|
||||||
\$\{ { return DOLLAR_CURLY; }
|
\$\{ { PUSH_STATE(INITIAL); return DOLLAR_CURLY; }
|
||||||
|
\{ { PUSH_STATE(INITIAL); return '{'; }
|
||||||
|
\} { POP_STATE(); return '}'; }
|
||||||
|
|
||||||
\" { BEGIN(STRING); return '"'; }
|
\" { PUSH_STATE(STRING); return '"'; }
|
||||||
<STRING>([^\$\"\\]|\$[^\{\"]|\\.)+ {
|
<STRING>([^\$\"\\]|\$[^\{\"\\]|\\.|\$\\.)*\$/\" |
|
||||||
/* !!! Not quite right: we want a follow restriction on
|
<STRING>([^\$\"\\]|\$[^\{\"\\]|\\.|\$\\.)+ {
|
||||||
"$", it shouldn't be followed by a "{". Right now
|
/* It is impossible to match strings ending with '$' with one
|
||||||
"$\"" will be consumed as part of a string, rather
|
regex because trailing contexts are only valid at the end
|
||||||
than a "$" followed by the string terminator.
|
of a rule. (A sane but undocumented limitation.) */
|
||||||
Disallow "$\"" for now. */
|
|
||||||
yylval->e = unescapeStr(data->symbols, yytext);
|
yylval->e = unescapeStr(data->symbols, yytext);
|
||||||
return STR;
|
return STR;
|
||||||
}
|
}
|
||||||
<STRING>\$\{ { BEGIN(INITIAL); return DOLLAR_CURLY; }
|
<STRING>\$\{ { PUSH_STATE(INITIAL); return DOLLAR_CURLY; }
|
||||||
<STRING>\" { BEGIN(INITIAL); return '"'; }
|
<STRING>\" { POP_STATE(); return '"'; }
|
||||||
<STRING>. return yytext[0]; /* just in case: shouldn't be reached */
|
<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>([^\$\']|\$[^\{\']|\'[^\'\$])+ {
|
<IND_STRING>([^\$\']|\$[^\{\']|\'[^\'\$])+ {
|
||||||
yylval->e = new ExprIndStr(yytext);
|
yylval->e = new ExprIndStr(yytext);
|
||||||
return IND_STR;
|
return IND_STR;
|
||||||
@@ -151,8 +158,8 @@ or { return OR_KW; }
|
|||||||
yylval->e = unescapeStr(data->symbols, yytext + 2);
|
yylval->e = unescapeStr(data->symbols, yytext + 2);
|
||||||
return IND_STR;
|
return IND_STR;
|
||||||
}
|
}
|
||||||
<IND_STRING>\$\{ { BEGIN(INITIAL); return DOLLAR_CURLY; }
|
<IND_STRING>\$\{ { PUSH_STATE(INITIAL); return DOLLAR_CURLY; }
|
||||||
<IND_STRING>\'\' { BEGIN(INITIAL); return IND_STRING_CLOSE; }
|
<IND_STRING>\'\' { POP_STATE(); return IND_STRING_CLOSE; }
|
||||||
<IND_STRING>\' {
|
<IND_STRING>\' {
|
||||||
yylval->e = new ExprIndStr("'");
|
yylval->e = new ExprIndStr("'");
|
||||||
return IND_STR;
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ libexpr_SOURCES := $(wildcard $(d)/*.cc) $(d)/lexer-tab.cc $(d)/parser-tab.cc
|
|||||||
|
|
||||||
libexpr_LIBS = libutil libstore libformat
|
libexpr_LIBS = libutil libstore libformat
|
||||||
|
|
||||||
libexpr_LDFLAGS = -ldl -lcurl
|
libexpr_LDFLAGS = -ldl
|
||||||
|
|
||||||
# The dependency on libgc must be propagated (i.e. meaning that
|
# The dependency on libgc must be propagated (i.e. meaning that
|
||||||
# programs/libraries that use libexpr must explicitly pass -lgc),
|
# programs/libraries that use libexpr must explicitly pass -lgc),
|
||||||
|
|||||||
@@ -98,8 +98,8 @@ int compareVersions(const string & v1, const string & v2)
|
|||||||
DrvNames drvNamesFromArgs(const Strings & opArgs)
|
DrvNames drvNamesFromArgs(const Strings & opArgs)
|
||||||
{
|
{
|
||||||
DrvNames result;
|
DrvNames result;
|
||||||
foreach (Strings::const_iterator, i, opArgs)
|
for (auto & i : opArgs)
|
||||||
result.push_back(DrvName(*i));
|
result.push_back(DrvName(i));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+46
-46
@@ -97,21 +97,21 @@ void ExprAttrs::show(std::ostream & str)
|
|||||||
{
|
{
|
||||||
if (recursive) str << "rec ";
|
if (recursive) str << "rec ";
|
||||||
str << "{ ";
|
str << "{ ";
|
||||||
foreach (AttrDefs::iterator, i, attrs)
|
for (auto & i : attrs)
|
||||||
if (i->second.inherited)
|
if (i.second.inherited)
|
||||||
str << "inherit " << i->first << " " << "; ";
|
str << "inherit " << i.first << " " << "; ";
|
||||||
else
|
else
|
||||||
str << i->first << " = " << *i->second.e << "; ";
|
str << i.first << " = " << *i.second.e << "; ";
|
||||||
foreach (DynamicAttrDefs::iterator, i, dynamicAttrs)
|
for (auto & i : dynamicAttrs)
|
||||||
str << "\"${" << *i->nameExpr << "}\" = " << *i->valueExpr << "; ";
|
str << "\"${" << *i.nameExpr << "}\" = " << *i.valueExpr << "; ";
|
||||||
str << "}";
|
str << "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExprList::show(std::ostream & str)
|
void ExprList::show(std::ostream & str)
|
||||||
{
|
{
|
||||||
str << "[ ";
|
str << "[ ";
|
||||||
foreach (vector<Expr *>::iterator, i, elems)
|
for (auto & i : elems)
|
||||||
str << "(" << **i << ") ";
|
str << "(" << *i << ") ";
|
||||||
str << "]";
|
str << "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,10 +121,10 @@ void ExprLambda::show(std::ostream & str)
|
|||||||
if (matchAttrs) {
|
if (matchAttrs) {
|
||||||
str << "{ ";
|
str << "{ ";
|
||||||
bool first = true;
|
bool first = true;
|
||||||
foreach (Formals::Formals_::iterator, i, formals->formals) {
|
for (auto & i : formals->formals) {
|
||||||
if (first) first = false; else str << ", ";
|
if (first) first = false; else str << ", ";
|
||||||
str << i->name;
|
str << i.name;
|
||||||
if (i->def) str << " ? " << *i->def;
|
if (i.def) str << " ? " << *i.def;
|
||||||
}
|
}
|
||||||
if (formals->ellipsis) {
|
if (formals->ellipsis) {
|
||||||
if (!first) str << ", ";
|
if (!first) str << ", ";
|
||||||
@@ -140,12 +140,12 @@ void ExprLambda::show(std::ostream & str)
|
|||||||
void ExprLet::show(std::ostream & str)
|
void ExprLet::show(std::ostream & str)
|
||||||
{
|
{
|
||||||
str << "(let ";
|
str << "(let ";
|
||||||
foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs)
|
for (auto & i : attrs->attrs)
|
||||||
if (i->second.inherited) {
|
if (i.second.inherited) {
|
||||||
str << "inherit " << i->first << "; ";
|
str << "inherit " << i.first << "; ";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
str << i->first << " = " << *i->second.e << "; ";
|
str << i.first << " = " << *i.second.e << "; ";
|
||||||
str << "in " << *body << ")";
|
str << "in " << *body << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,9 +173,9 @@ void ExprConcatStrings::show(std::ostream & str)
|
|||||||
{
|
{
|
||||||
bool first = true;
|
bool first = true;
|
||||||
str << "(";
|
str << "(";
|
||||||
foreach (vector<Expr *>::iterator, i, *es) {
|
for (auto & i : *es) {
|
||||||
if (first) first = false; else str << " + ";
|
if (first) first = false; else str << " + ";
|
||||||
str << **i;
|
str << *i;
|
||||||
}
|
}
|
||||||
str << ")";
|
str << ")";
|
||||||
}
|
}
|
||||||
@@ -267,17 +267,17 @@ void ExprSelect::bindVars(const StaticEnv & env)
|
|||||||
{
|
{
|
||||||
e->bindVars(env);
|
e->bindVars(env);
|
||||||
if (def) def->bindVars(env);
|
if (def) def->bindVars(env);
|
||||||
foreach (AttrPath::iterator, i, attrPath)
|
for (auto & i : attrPath)
|
||||||
if (!i->symbol.set())
|
if (!i.symbol.set())
|
||||||
i->expr->bindVars(env);
|
i.expr->bindVars(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExprOpHasAttr::bindVars(const StaticEnv & env)
|
void ExprOpHasAttr::bindVars(const StaticEnv & env)
|
||||||
{
|
{
|
||||||
e->bindVars(env);
|
e->bindVars(env);
|
||||||
foreach (AttrPath::iterator, i, attrPath)
|
for (auto & i : attrPath)
|
||||||
if (!i->symbol.set())
|
if (!i.symbol.set())
|
||||||
i->expr->bindVars(env);
|
i.expr->bindVars(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExprAttrs::bindVars(const StaticEnv & env)
|
void ExprAttrs::bindVars(const StaticEnv & env)
|
||||||
@@ -289,27 +289,27 @@ void ExprAttrs::bindVars(const StaticEnv & env)
|
|||||||
dynamicEnv = &newEnv;
|
dynamicEnv = &newEnv;
|
||||||
|
|
||||||
unsigned int displ = 0;
|
unsigned int displ = 0;
|
||||||
foreach (AttrDefs::iterator, i, attrs)
|
for (auto & i : attrs)
|
||||||
newEnv.vars[i->first] = i->second.displ = displ++;
|
newEnv.vars[i.first] = i.second.displ = displ++;
|
||||||
|
|
||||||
foreach (AttrDefs::iterator, i, attrs)
|
for (auto & i : attrs)
|
||||||
i->second.e->bindVars(i->second.inherited ? env : newEnv);
|
i.second.e->bindVars(i.second.inherited ? env : newEnv);
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
foreach (AttrDefs::iterator, i, attrs)
|
for (auto & i : attrs)
|
||||||
i->second.e->bindVars(env);
|
i.second.e->bindVars(env);
|
||||||
|
|
||||||
foreach (DynamicAttrDefs::iterator, i, dynamicAttrs) {
|
for (auto & i : dynamicAttrs) {
|
||||||
i->nameExpr->bindVars(*dynamicEnv);
|
i.nameExpr->bindVars(*dynamicEnv);
|
||||||
i->valueExpr->bindVars(*dynamicEnv);
|
i.valueExpr->bindVars(*dynamicEnv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExprList::bindVars(const StaticEnv & env)
|
void ExprList::bindVars(const StaticEnv & env)
|
||||||
{
|
{
|
||||||
foreach (vector<Expr *>::iterator, i, elems)
|
for (auto & i : elems)
|
||||||
(*i)->bindVars(env);
|
i->bindVars(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExprLambda::bindVars(const StaticEnv & 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 (!arg.empty()) newEnv.vars[arg] = displ++;
|
||||||
|
|
||||||
if (matchAttrs) {
|
if (matchAttrs) {
|
||||||
foreach (Formals::Formals_::iterator, i, formals->formals)
|
for (auto & i : formals->formals)
|
||||||
newEnv.vars[i->name] = displ++;
|
newEnv.vars[i.name] = displ++;
|
||||||
|
|
||||||
foreach (Formals::Formals_::iterator, i, formals->formals)
|
for (auto & i : formals->formals)
|
||||||
if (i->def) i->def->bindVars(newEnv);
|
if (i.def) i.def->bindVars(newEnv);
|
||||||
}
|
}
|
||||||
|
|
||||||
body->bindVars(newEnv);
|
body->bindVars(newEnv);
|
||||||
@@ -336,11 +336,11 @@ void ExprLet::bindVars(const StaticEnv & env)
|
|||||||
StaticEnv newEnv(false, &env);
|
StaticEnv newEnv(false, &env);
|
||||||
|
|
||||||
unsigned int displ = 0;
|
unsigned int displ = 0;
|
||||||
foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs)
|
for (auto & i : attrs->attrs)
|
||||||
newEnv.vars[i->first] = i->second.displ = displ++;
|
newEnv.vars[i.first] = i.second.displ = displ++;
|
||||||
|
|
||||||
foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs)
|
for (auto & i : attrs->attrs)
|
||||||
i->second.e->bindVars(i->second.inherited ? env : newEnv);
|
i.second.e->bindVars(i.second.inherited ? env : newEnv);
|
||||||
|
|
||||||
body->bindVars(newEnv);
|
body->bindVars(newEnv);
|
||||||
}
|
}
|
||||||
@@ -384,8 +384,8 @@ void ExprOpNot::bindVars(const StaticEnv & env)
|
|||||||
|
|
||||||
void ExprConcatStrings::bindVars(const StaticEnv & env)
|
void ExprConcatStrings::bindVars(const StaticEnv & env)
|
||||||
{
|
{
|
||||||
foreach (vector<Expr *>::iterator, i, *es)
|
for (auto & i : *es)
|
||||||
(*i)->bindVars(env);
|
i->bindVars(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExprPos::bindVars(const StaticEnv & env)
|
void ExprPos::bindVars(const StaticEnv & env)
|
||||||
@@ -419,8 +419,8 @@ string ExprLambda::showNamePos() const
|
|||||||
size_t SymbolTable::totalSize() const
|
size_t SymbolTable::totalSize() const
|
||||||
{
|
{
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
foreach (Symbols::const_iterator, i, symbols)
|
for (auto & i : symbols)
|
||||||
n += i->size();
|
n += i.size();
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+14
-25
@@ -136,8 +136,8 @@ static Expr * stripIndentation(const Pos & pos, SymbolTable & symbols, vector<Ex
|
|||||||
bool atStartOfLine = true; /* = seen only whitespace in the current line */
|
bool atStartOfLine = true; /* = seen only whitespace in the current line */
|
||||||
unsigned int minIndent = 1000000;
|
unsigned int minIndent = 1000000;
|
||||||
unsigned int curIndent = 0;
|
unsigned int curIndent = 0;
|
||||||
foreach (vector<Expr *>::iterator, i, es) {
|
for (auto & i : es) {
|
||||||
ExprIndStr * e = dynamic_cast<ExprIndStr *>(*i);
|
ExprIndStr * e = dynamic_cast<ExprIndStr *>(i);
|
||||||
if (!e) {
|
if (!e) {
|
||||||
/* Anti-quotations end the current start-of-line whitespace. */
|
/* Anti-quotations end the current start-of-line whitespace. */
|
||||||
if (atStartOfLine) {
|
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)
|
static inline Pos makeCurPos(const YYLTYPE & loc, ParseData * data)
|
||||||
{
|
{
|
||||||
return Pos(data->path, loc.first_line, loc.first_column);
|
return Pos(data->path, loc.first_line, loc.first_column);
|
||||||
@@ -404,25 +400,18 @@ string_parts
|
|||||||
|
|
||||||
string_parts_interpolated
|
string_parts_interpolated
|
||||||
: string_parts_interpolated STR { $$ = $1; $1->push_back($2); }
|
: string_parts_interpolated STR { $$ = $1; $1->push_back($2); }
|
||||||
| string_parts_interpolated DOLLAR_CURLY expr '}' { backToString(scanner); $$ = $1; $1->push_back($3); }
|
| string_parts_interpolated DOLLAR_CURLY expr '}' { $$ = $1; $1->push_back($3); }
|
||||||
| STR DOLLAR_CURLY expr '}'
|
| DOLLAR_CURLY expr '}' { $$ = new vector<Expr *>; $$->push_back($2); }
|
||||||
{
|
| STR DOLLAR_CURLY expr '}' {
|
||||||
backToString(scanner);
|
|
||||||
$$ = new vector<Expr *>;
|
$$ = new vector<Expr *>;
|
||||||
$$->push_back($1);
|
$$->push_back($1);
|
||||||
$$->push_back($3);
|
$$->push_back($3);
|
||||||
}
|
}
|
||||||
| DOLLAR_CURLY expr '}'
|
|
||||||
{
|
|
||||||
backToString(scanner);
|
|
||||||
$$ = new vector<Expr *>;
|
|
||||||
$$->push_back($2);
|
|
||||||
}
|
|
||||||
;
|
;
|
||||||
|
|
||||||
ind_string_parts
|
ind_string_parts
|
||||||
: ind_string_parts IND_STR { $$ = $1; $1->push_back($2); }
|
: 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 *>; }
|
| { $$ = new vector<Expr *>; }
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -430,20 +419,20 @@ binds
|
|||||||
: binds attrpath '=' expr ';' { $$ = $1; addAttr($$, *$2, $4, makeCurPos(@2, data)); }
|
: binds attrpath '=' expr ';' { $$ = $1; addAttr($$, *$2, $4, makeCurPos(@2, data)); }
|
||||||
| binds INHERIT attrs ';'
|
| binds INHERIT attrs ';'
|
||||||
{ $$ = $1;
|
{ $$ = $1;
|
||||||
foreach (AttrPath::iterator, i, *$3) {
|
for (auto & i : *$3) {
|
||||||
if ($$->attrs.find(i->symbol) != $$->attrs.end())
|
if ($$->attrs.find(i.symbol) != $$->attrs.end())
|
||||||
dupAttr(i->symbol, makeCurPos(@3, data), $$->attrs[i->symbol].pos);
|
dupAttr(i.symbol, makeCurPos(@3, data), $$->attrs[i.symbol].pos);
|
||||||
Pos pos = makeCurPos(@3, data);
|
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 ';'
|
| binds INHERIT '(' expr ')' attrs ';'
|
||||||
{ $$ = $1;
|
{ $$ = $1;
|
||||||
/* !!! Should ensure sharing of the expression in $4. */
|
/* !!! Should ensure sharing of the expression in $4. */
|
||||||
foreach (AttrPath::iterator, i, *$6) {
|
for (auto & i : *$6) {
|
||||||
if ($$->attrs.find(i->symbol) != $$->attrs.end())
|
if ($$->attrs.find(i.symbol) != $$->attrs.end())
|
||||||
dupAttr(i->symbol, makeCurPos(@6, data), $$->attrs[i->symbol].pos);
|
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));
|
$$->attrs[i.symbol] = ExprAttrs::AttrDef(new ExprSelect(CUR_POS, $4, i.symbol), makeCurPos(@6, data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| { $$ = new ExprAttrs; }
|
| { $$ = new ExprAttrs; }
|
||||||
|
|||||||
+272
-102
@@ -86,9 +86,11 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args
|
|||||||
if (isStorePath(path) && store->isValidPath(path) && isDerivation(path)) {
|
if (isStorePath(path) && store->isValidPath(path) && isDerivation(path)) {
|
||||||
Derivation drv = readDerivation(path);
|
Derivation drv = readDerivation(path);
|
||||||
Value & w = *state.allocValue();
|
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);
|
Value * v2 = state.allocAttr(w, state.sDrvPath);
|
||||||
mkString(*v2, path, singleton<PathSet>("=" + path));
|
mkString(*v2, path, singleton<PathSet>("=" + path));
|
||||||
|
v2 = state.allocAttr(w, state.sName);
|
||||||
|
mkString(*v2, drv.env["name"]);
|
||||||
Value * outputsVal =
|
Value * outputsVal =
|
||||||
state.allocAttr(w, state.symbols.create("outputs"));
|
state.allocAttr(w, state.symbols.create("outputs"));
|
||||||
state.mkList(*outputsVal, drv.outputs.size());
|
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));
|
v2 = state.allocAttr(w, state.symbols.create(o.first));
|
||||||
mkString(*v2, o.second.path,
|
mkString(*v2, o.second.path,
|
||||||
singleton<PathSet>("!" + o.first + "!" + path));
|
singleton<PathSet>("!" + o.first + "!" + path));
|
||||||
outputsVal->list.elems[outputs_index] = state.allocValue();
|
outputsVal->listElems()[outputs_index] = state.allocValue();
|
||||||
mkString(*(outputsVal->list.elems[outputs_index++]), o.first);
|
mkString(*(outputsVal->listElems()[outputs_index++]), o.first);
|
||||||
}
|
}
|
||||||
w.attrs->sort();
|
w.attrs->sort();
|
||||||
Value fun;
|
Value fun;
|
||||||
@@ -186,7 +188,7 @@ static void prim_typeOf(EvalState & state, const Pos & pos, Value * * args, Valu
|
|||||||
case tPath: t = "path"; break;
|
case tPath: t = "path"; break;
|
||||||
case tNull: t = "null"; break;
|
case tNull: t = "null"; break;
|
||||||
case tAttrs: t = "set"; break;
|
case tAttrs: t = "set"; break;
|
||||||
case tList: t = "list"; break;
|
case tList1: case tList2: case tListN: t = "list"; break;
|
||||||
case tLambda:
|
case tLambda:
|
||||||
case tPrimOp:
|
case tPrimOp:
|
||||||
case tPrimOpApp:
|
case tPrimOpApp:
|
||||||
@@ -282,8 +284,8 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
|
|||||||
state.forceList(*startSet->value, pos);
|
state.forceList(*startSet->value, pos);
|
||||||
|
|
||||||
ValueList workSet;
|
ValueList workSet;
|
||||||
for (unsigned int n = 0; n < startSet->value->list.length; ++n)
|
for (unsigned int n = 0; n < startSet->value->listSize(); ++n)
|
||||||
workSet.push_back(startSet->value->list.elems[n]);
|
workSet.push_back(startSet->value->listElems()[n]);
|
||||||
|
|
||||||
/* Get the operator. */
|
/* Get the operator. */
|
||||||
Bindings::iterator op =
|
Bindings::iterator op =
|
||||||
@@ -321,17 +323,17 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
|
|||||||
state.forceList(call, pos);
|
state.forceList(call, pos);
|
||||||
|
|
||||||
/* Add the values returned by the operator to the work set. */
|
/* Add the values returned by the operator to the work set. */
|
||||||
for (unsigned int n = 0; n < call.list.length; ++n) {
|
for (unsigned int n = 0; n < call.listSize(); ++n) {
|
||||||
state.forceValue(*call.list.elems[n]);
|
state.forceValue(*call.listElems()[n]);
|
||||||
workSet.push_back(call.list.elems[n]);
|
workSet.push_back(call.listElems()[n]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create the result list. */
|
/* Create the result list. */
|
||||||
state.mkList(v, res.size());
|
state.mkList(v, res.size());
|
||||||
unsigned int n = 0;
|
unsigned int n = 0;
|
||||||
foreach (ValueList::iterator, i, res)
|
for (auto & i : res)
|
||||||
v.list.elems[n++] = *i;
|
v.listElems()[n++] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -477,24 +479,24 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
|
|||||||
StringSet outputs;
|
StringSet outputs;
|
||||||
outputs.insert("out");
|
outputs.insert("out");
|
||||||
|
|
||||||
foreach (Bindings::iterator, i, *args[0]->attrs) {
|
for (auto & i : *args[0]->attrs) {
|
||||||
if (i->name == state.sIgnoreNulls) continue;
|
if (i.name == state.sIgnoreNulls) continue;
|
||||||
string key = i->name;
|
string key = i.name;
|
||||||
startNest(nest, lvlVomit, format("processing attribute ‘%1%’") % key);
|
startNest(nest, lvlVomit, format("processing attribute ‘%1%’") % key);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
if (ignoreNulls) {
|
if (ignoreNulls) {
|
||||||
state.forceValue(*i->value);
|
state.forceValue(*i.value);
|
||||||
if (i->value->type == tNull) continue;
|
if (i.value->type == tNull) continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The `args' attribute is special: it supplies the
|
/* The `args' attribute is special: it supplies the
|
||||||
command-line arguments to the builder. */
|
command-line arguments to the builder. */
|
||||||
if (key == "args") {
|
if (key == "args") {
|
||||||
state.forceList(*i->value, pos);
|
state.forceList(*i.value, pos);
|
||||||
for (unsigned int n = 0; n < i->value->list.length; ++n) {
|
for (unsigned int n = 0; n < i.value->listSize(); ++n) {
|
||||||
string s = state.coerceToString(posDrvName, *i->value->list.elems[n], context, true);
|
string s = state.coerceToString(posDrvName, *i.value->listElems()[n], context, true);
|
||||||
drv.args.push_back(s);
|
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
|
/* All other attributes are passed to the builder through
|
||||||
the environment. */
|
the environment. */
|
||||||
else {
|
else {
|
||||||
string s = state.coerceToString(posDrvName, *i->value, context, true);
|
string s = state.coerceToString(posDrvName, *i.value, context, true);
|
||||||
drv.env[key] = s;
|
drv.env[key] = s;
|
||||||
if (key == "builder") drv.builder = s;
|
if (key == "builder") drv.builder = s;
|
||||||
else if (i->name == state.sSystem) drv.platform = s;
|
else if (i.name == state.sSystem) drv.platform = s;
|
||||||
else if (i->name == state.sName) {
|
else if (i.name == state.sName) {
|
||||||
drvName = s;
|
drvName = s;
|
||||||
printMsg(lvlVomit, format("derivation name is ‘%1%’") % drvName);
|
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") {
|
else if (key == "outputs") {
|
||||||
Strings tmp = tokenizeString<Strings>(s);
|
Strings tmp = tokenizeString<Strings>(s);
|
||||||
outputs.clear();
|
outputs.clear();
|
||||||
foreach (Strings::iterator, j, tmp) {
|
for (auto & j : tmp) {
|
||||||
if (outputs.find(*j) != outputs.end())
|
if (outputs.find(j) != outputs.end())
|
||||||
throw EvalError(format("duplicate derivation output ‘%1%’, at %2%") % *j % posDrvName);
|
throw EvalError(format("duplicate derivation output ‘%1%’, at %2%") % j % posDrvName);
|
||||||
/* !!! Check whether *j is a valid attribute
|
/* !!! Check whether j is a valid attribute
|
||||||
name. */
|
name. */
|
||||||
/* Derivations cannot be named ‘drv’, because
|
/* Derivations cannot be named ‘drv’, because
|
||||||
then we'd have an attribute ‘drvPath’ in
|
then we'd have an attribute ‘drvPath’ in
|
||||||
the resulting set. */
|
the resulting set. */
|
||||||
if (*j == "drv")
|
if (j == "drv")
|
||||||
throw EvalError(format("invalid derivation output name ‘drv’, at %1%") % posDrvName);
|
throw EvalError(format("invalid derivation output name ‘drv’, at %1%") % posDrvName);
|
||||||
outputs.insert(*j);
|
outputs.insert(j);
|
||||||
}
|
}
|
||||||
if (outputs.empty())
|
if (outputs.empty())
|
||||||
throw EvalError(format("derivation cannot have an empty set of outputs, at %1%") % posDrvName);
|
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
|
/* Everything in the context of the strings in the derivation
|
||||||
attributes should be added as dependencies of the resulting
|
attributes should be added as dependencies of the resulting
|
||||||
derivation. */
|
derivation. */
|
||||||
foreach (PathSet::iterator, i, context) {
|
for (auto & path : context) {
|
||||||
Path path = *i;
|
|
||||||
|
|
||||||
/* Paths marked with `=' denote that the path of a derivation
|
/* Paths marked with `=' denote that the path of a derivation
|
||||||
is explicitly passed to the builder. Since that allows the
|
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) == '=') {
|
if (path.at(0) == '=') {
|
||||||
/* !!! This doesn't work if readOnlyMode is set. */
|
/* !!! This doesn't work if readOnlyMode is set. */
|
||||||
PathSet refs; computeFSClosure(*store, string(path, 1), refs);
|
PathSet refs; computeFSClosure(*store, string(path, 1), refs);
|
||||||
foreach (PathSet::iterator, j, refs) {
|
for (auto & j : refs) {
|
||||||
drv.inputSrcs.insert(*j);
|
drv.inputSrcs.insert(j);
|
||||||
if (isDerivation(*j))
|
if (isDerivation(j))
|
||||||
drv.inputDrvs[*j] = store->queryDerivationOutputNames(*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
|
are empty, and the corresponding environment variables have
|
||||||
an empty value. This ensures that changes in the set of
|
an empty value. This ensures that changes in the set of
|
||||||
output names do get reflected in the hash. */
|
output names do get reflected in the hash. */
|
||||||
foreach (StringSet::iterator, i, outputs) {
|
for (auto & i : outputs) {
|
||||||
drv.env[*i] = "";
|
drv.env[i] = "";
|
||||||
drv.outputs[*i] = DerivationOutput("", "", "");
|
drv.outputs[i] = DerivationOutput("", "", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Use the masked derivation expression to compute the output
|
/* Use the masked derivation expression to compute the output
|
||||||
path. */
|
path. */
|
||||||
Hash h = hashDerivationModulo(*store, drv);
|
Hash h = hashDerivationModulo(*store, drv);
|
||||||
|
|
||||||
foreach (DerivationOutputs::iterator, i, drv.outputs)
|
for (auto & i : drv.outputs)
|
||||||
if (i->second.path == "") {
|
if (i.second.path == "") {
|
||||||
Path outPath = makeOutputPath(i->first, h, drvName);
|
Path outPath = makeOutputPath(i.first, h, drvName);
|
||||||
drv.env[i->first] = outPath;
|
drv.env[i.first] = outPath;
|
||||||
i->second.path = 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());
|
state.mkAttrs(v, 1 + drv.outputs.size());
|
||||||
mkString(*state.allocAttr(v, state.sDrvPath), drvPath, singleton<PathSet>("=" + drvPath));
|
mkString(*state.allocAttr(v, state.sDrvPath), drvPath, singleton<PathSet>("=" + drvPath));
|
||||||
foreach (DerivationOutputs::iterator, i, drv.outputs) {
|
for (auto & i : drv.outputs) {
|
||||||
mkString(*state.allocAttr(v, state.symbols.create(i->first)),
|
mkString(*state.allocAttr(v, state.symbols.create(i.first)),
|
||||||
i->second.path, singleton<PathSet>("!" + i->first + "!" + drvPath));
|
i.second.path, singleton<PathSet>("!" + i.first + "!" + drvPath));
|
||||||
}
|
}
|
||||||
v.attrs->sort();
|
v.attrs->sort();
|
||||||
}
|
}
|
||||||
@@ -765,8 +766,8 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
|
|||||||
SearchPath searchPath;
|
SearchPath searchPath;
|
||||||
|
|
||||||
PathSet context;
|
PathSet context;
|
||||||
for (unsigned int n = 0; n < args[0]->list.length; ++n) {
|
for (unsigned int n = 0; n < args[0]->listSize(); ++n) {
|
||||||
Value & v2(*args[0]->list.elems[n]);
|
Value & v2(*args[0]->listElems()[n]);
|
||||||
state.forceAttrs(v2, pos);
|
state.forceAttrs(v2, pos);
|
||||||
|
|
||||||
string prefix;
|
string prefix;
|
||||||
@@ -871,11 +872,14 @@ static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Valu
|
|||||||
|
|
||||||
PathSet refs;
|
PathSet refs;
|
||||||
|
|
||||||
foreach (PathSet::iterator, i, context) {
|
for (auto path : context) {
|
||||||
Path path = *i;
|
|
||||||
if (path.at(0) == '=') path = string(path, 1);
|
if (path.at(0) == '=') path = string(path, 1);
|
||||||
if (isDerivation(path))
|
if (isDerivation(path)) {
|
||||||
throw EvalError(format("in ‘toFile’: the file ‘%1%’ cannot refer to derivation outputs, at %2%") % name % pos);
|
/* 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);
|
refs.insert(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -968,9 +972,9 @@ static void prim_attrNames(EvalState & state, const Pos & pos, Value * * args, V
|
|||||||
|
|
||||||
unsigned int n = 0;
|
unsigned int n = 0;
|
||||||
for (auto & i : *args[0]->attrs)
|
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; });
|
[](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;
|
unsigned int n = 0;
|
||||||
for (auto & i : *args[0]->attrs)
|
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; });
|
[](Value * v1, Value * v2) { return (string) ((Attr *) v1)->name < (string) ((Attr *) v2)->name; });
|
||||||
|
|
||||||
for (unsigned int i = 0; i < n; ++i)
|
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. */
|
/* Get the attribute names to be removed. */
|
||||||
std::set<Symbol> names;
|
std::set<Symbol> names;
|
||||||
for (unsigned int i = 0; i < args[1]->list.length; ++i) {
|
for (unsigned int i = 0; i < args[1]->listSize(); ++i) {
|
||||||
state.forceStringNoCtx(*args[1]->list.elems[i], pos);
|
state.forceStringNoCtx(*args[1]->listElems()[i], pos);
|
||||||
names.insert(state.symbols.create(args[1]->list.elems[i]->string.s));
|
names.insert(state.symbols.create(args[1]->listElems()[i]->string.s));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy all attributes not in that set. Note that we don't need
|
/* 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
|
to sort v.attrs because it's a subset of an already sorted
|
||||||
vector. */
|
vector. */
|
||||||
state.mkAttrs(v, args[0]->attrs->size());
|
state.mkAttrs(v, args[0]->attrs->size());
|
||||||
foreach (Bindings::iterator, i, *args[0]->attrs) {
|
for (auto & i : *args[0]->attrs) {
|
||||||
if (names.find(i->name) == names.end())
|
if (names.find(i.name) == names.end())
|
||||||
v.attrs->push_back(*i);
|
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.forceList(*args[0], pos);
|
||||||
|
|
||||||
state.mkAttrs(v, args[0]->list.length);
|
state.mkAttrs(v, args[0]->listSize());
|
||||||
|
|
||||||
std::set<Symbol> seen;
|
std::set<Symbol> seen;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < args[0]->list.length; ++i) {
|
for (unsigned int i = 0; i < args[0]->listSize(); ++i) {
|
||||||
Value & v2(*args[0]->list.elems[i]);
|
Value & v2(*args[0]->listElems()[i]);
|
||||||
state.forceAttrs(v2, pos);
|
state.forceAttrs(v2, pos);
|
||||||
|
|
||||||
Bindings::iterator j = v2.attrs->find(state.sName);
|
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()));
|
state.mkAttrs(v, std::min(args[0]->attrs->size(), args[1]->attrs->size()));
|
||||||
|
|
||||||
foreach (Bindings::iterator, i, *args[0]->attrs) {
|
for (auto & i : *args[0]->attrs) {
|
||||||
Bindings::iterator j = args[1]->attrs->find(i->name);
|
Bindings::iterator j = args[1]->attrs->find(i.name);
|
||||||
if (j != args[1]->attrs->end())
|
if (j != args[1]->attrs->end())
|
||||||
v.attrs->push_back(*j);
|
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));
|
Symbol attrName = state.symbols.create(state.forceStringNoCtx(*args[0], pos));
|
||||||
state.forceList(*args[1], pos);
|
state.forceList(*args[1], pos);
|
||||||
|
|
||||||
Value * res[args[1]->list.length];
|
Value * res[args[1]->listSize()];
|
||||||
unsigned int found = 0;
|
unsigned int found = 0;
|
||||||
|
|
||||||
for (unsigned int n = 0; n < args[1]->list.length; ++n) {
|
for (unsigned int n = 0; n < args[1]->listSize(); ++n) {
|
||||||
Value & v2(*args[1]->list.elems[n]);
|
Value & v2(*args[1]->listElems()[n]);
|
||||||
state.forceAttrs(v2, pos);
|
state.forceAttrs(v2, pos);
|
||||||
Bindings::iterator i = v2.attrs->find(attrName);
|
Bindings::iterator i = v2.attrs->find(attrName);
|
||||||
if (i != v2.attrs->end())
|
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);
|
state.mkList(v, found);
|
||||||
for (unsigned int n = 0; n < found; ++n)
|
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());
|
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)
|
// !!! 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();
|
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)
|
static void prim_isList(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
state.forceValue(*args[0]);
|
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)
|
static void elemAt(EvalState & state, const Pos & pos, Value & list, int n, Value & v)
|
||||||
{
|
{
|
||||||
state.forceList(list, pos);
|
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);
|
throw Error(format("list index %1% is out of bounds, at %2%") % n % pos);
|
||||||
state.forceValue(*list.list.elems[n]);
|
state.forceValue(*list.listElems()[n]);
|
||||||
v = *list.list.elems[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)
|
static void prim_tail(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
state.forceList(*args[0], pos);
|
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);
|
throw Error(format("‘tail’ called on an empty list, at %1%") % pos);
|
||||||
state.mkList(v, args[0]->list.length - 1);
|
state.mkList(v, args[0]->listSize() - 1);
|
||||||
for (unsigned int n = 0; n < v.list.length; ++n)
|
for (unsigned int n = 0; n < v.listSize(); ++n)
|
||||||
v.list.elems[n] = args[0]->list.elems[n + 1];
|
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.forceFunction(*args[0], pos);
|
||||||
state.forceList(*args[1], 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)
|
for (unsigned int n = 0; n < v.listSize(); ++n)
|
||||||
mkApp(*(v.list.elems[n] = state.allocValue()),
|
mkApp(*(v.listElems()[n] = state.allocValue()),
|
||||||
*args[0], *args[1]->list.elems[n]);
|
*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);
|
state.forceList(*args[1], pos);
|
||||||
|
|
||||||
// FIXME: putting this on the stack is risky.
|
// FIXME: putting this on the stack is risky.
|
||||||
Value * vs[args[1]->list.length];
|
Value * vs[args[1]->listSize()];
|
||||||
unsigned int k = 0;
|
unsigned int k = 0;
|
||||||
|
|
||||||
bool same = true;
|
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;
|
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))
|
if (state.forceBool(res))
|
||||||
vs[k++] = args[1]->list.elems[n];
|
vs[k++] = args[1]->listElems()[n];
|
||||||
else
|
else
|
||||||
same = false;
|
same = false;
|
||||||
}
|
}
|
||||||
@@ -1271,7 +1275,7 @@ static void prim_filter(EvalState & state, const Pos & pos, Value * * args, Valu
|
|||||||
v = *args[1];
|
v = *args[1];
|
||||||
else {
|
else {
|
||||||
state.mkList(v, k);
|
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;
|
bool res = false;
|
||||||
state.forceList(*args[1], pos);
|
state.forceList(*args[1], pos);
|
||||||
for (unsigned int n = 0; n < args[1]->list.length; ++n)
|
for (unsigned int n = 0; n < args[1]->listSize(); ++n)
|
||||||
if (state.eqValues(*args[0], *args[1]->list.elems[n])) {
|
if (state.eqValues(*args[0], *args[1]->listElems()[n])) {
|
||||||
res = true;
|
res = true;
|
||||||
break;
|
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)
|
static void prim_concatLists(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
state.forceList(*args[0], pos);
|
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)
|
static void prim_length(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
state.forceList(*args[0], pos);
|
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);
|
string s = state.coerceToString(pos, *args[0], context);
|
||||||
|
|
||||||
PathSet context2;
|
PathSet context2;
|
||||||
foreach (PathSet::iterator, i, context) {
|
for (auto & p : context)
|
||||||
Path p = *i;
|
context2.insert(p.at(0) == '=' ? "~" + string(p, 1) : p);
|
||||||
if (p.at(0) == '=') p = "~" + string(p, 1);
|
|
||||||
context2.insert(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
mkString(v, s, context2);
|
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) {
|
for (unsigned int n = 0; n < len; ++n) {
|
||||||
auto i = subs.find(n);
|
auto i = subs.find(n);
|
||||||
if (i == subs.end())
|
if (i == subs.end())
|
||||||
mkNull(*(v.list.elems[n] = state.allocValue()));
|
mkNull(*(v.listElems()[n] = state.allocValue()));
|
||||||
else
|
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
|
* Versions
|
||||||
*************************************************************/
|
*************************************************************/
|
||||||
@@ -1646,6 +1809,11 @@ void EvalState::createBaseEnv()
|
|||||||
addPrimOp("__elem", 2, prim_elem);
|
addPrimOp("__elem", 2, prim_elem);
|
||||||
addPrimOp("__concatLists", 1, prim_concatLists);
|
addPrimOp("__concatLists", 1, prim_concatLists);
|
||||||
addPrimOp("__length", 1, prim_length);
|
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
|
// Integer arithmetic
|
||||||
addPrimOp("__add", 2, prim_add);
|
addPrimOp("__add", 2, prim_add);
|
||||||
@@ -1662,6 +1830,8 @@ void EvalState::createBaseEnv()
|
|||||||
addPrimOp("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency);
|
addPrimOp("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency);
|
||||||
addPrimOp("__hashString", 2, prim_hashString);
|
addPrimOp("__hashString", 2, prim_hashString);
|
||||||
addPrimOp("__match", 2, prim_match);
|
addPrimOp("__match", 2, prim_match);
|
||||||
|
addPrimOp("__concatStringsSep", 2, prim_concatStringSep);
|
||||||
|
addPrimOp("__replaceStrings", 3, prim_replaceStrings);
|
||||||
|
|
||||||
// Versions
|
// Versions
|
||||||
addPrimOp("__parseDrvName", 1, prim_parseDrvName);
|
addPrimOp("__parseDrvName", 1, prim_parseDrvName);
|
||||||
@@ -1685,7 +1855,7 @@ void EvalState::createBaseEnv()
|
|||||||
mkList(v, searchPath.size());
|
mkList(v, searchPath.size());
|
||||||
int n = 0;
|
int n = 0;
|
||||||
for (auto & i : searchPath) {
|
for (auto & i : searchPath) {
|
||||||
v2 = v.list.elems[n++] = allocValue();
|
v2 = v.listElems()[n++] = allocValue();
|
||||||
mkAttrs(*v2, 2);
|
mkAttrs(*v2, 2);
|
||||||
mkString(*allocAttr(*v2, symbols.create("path")), i.second);
|
mkString(*allocAttr(*v2, symbols.create("path")), i.second);
|
||||||
mkString(*allocAttr(*v2, symbols.create("prefix")), i.first);
|
mkString(*allocAttr(*v2, symbols.create("prefix")), i.first);
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ namespace nix {
|
|||||||
void escapeJSON(std::ostream & str, const string & s)
|
void escapeJSON(std::ostream & str, const string & s)
|
||||||
{
|
{
|
||||||
str << "\"";
|
str << "\"";
|
||||||
foreach (string::const_iterator, i, s)
|
for (auto & i : s)
|
||||||
if (*i == '\"' || *i == '\\') str << "\\" << *i;
|
if (i == '\"' || i == '\\') str << "\\" << i;
|
||||||
else if (*i == '\n') str << "\\n";
|
else if (i == '\n') str << "\\n";
|
||||||
else if (*i == '\r') str << "\\r";
|
else if (i == '\r') str << "\\r";
|
||||||
else if (*i == '\t') str << "\\t";
|
else if (i == '\t') str << "\\t";
|
||||||
else if (*i >= 0 && *i < 32)
|
else if (i >= 0 && i < 32)
|
||||||
str << "\\u" << std::setfill('0') << std::setw(4) << std::hex << (uint16_t) *i << std::dec;
|
str << "\\u" << std::setfill('0') << std::setw(4) << std::hex << (uint16_t) i << std::dec;
|
||||||
else str << *i;
|
else str << i;
|
||||||
str << "\"";
|
str << "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,11 +59,11 @@ void printValueAsJSON(EvalState & state, bool strict,
|
|||||||
if (i == v.attrs->end()) {
|
if (i == v.attrs->end()) {
|
||||||
JSONObject json(str);
|
JSONObject json(str);
|
||||||
StringSet names;
|
StringSet names;
|
||||||
foreach (Bindings::iterator, i, *v.attrs)
|
for (auto & j : *v.attrs)
|
||||||
names.insert(i->name);
|
names.insert(j.name);
|
||||||
foreach (StringSet::iterator, i, names) {
|
for (auto & j : names) {
|
||||||
Attr & a(*v.attrs->find(state.symbols.create(*i)));
|
Attr & a(*v.attrs->find(state.symbols.create(j)));
|
||||||
json.attr(*i);
|
json.attr(j);
|
||||||
printValueAsJSON(state, strict, *a.value, str, context);
|
printValueAsJSON(state, strict, *a.value, str, context);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
@@ -71,16 +71,16 @@ void printValueAsJSON(EvalState & state, bool strict,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case tList: {
|
case tList1: case tList2: case tListN: {
|
||||||
JSONList json(str);
|
JSONList json(str);
|
||||||
for (unsigned int n = 0; n < v.list.length; ++n) {
|
for (unsigned int n = 0; n < v.listSize(); ++n) {
|
||||||
json.elem();
|
json.elem();
|
||||||
printValueAsJSON(state, strict, *v.list.elems[n], str, context);
|
printValueAsJSON(state, strict, *v.listElems()[n], str, context);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case tExternal:
|
case tExternal:
|
||||||
v.external->printValueAsJSON(state, strict, str, context);
|
v.external->printValueAsJSON(state, strict, str, context);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
+23
-23
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
static XMLAttrs singletonAttrs(const string & name, const string & value)
|
static XMLAttrs singletonAttrs(const string & name, const string & value)
|
||||||
{
|
{
|
||||||
XMLAttrs attrs;
|
XMLAttrs attrs;
|
||||||
@@ -33,17 +33,17 @@ static void showAttrs(EvalState & state, bool strict, bool location,
|
|||||||
Bindings & attrs, XMLWriter & doc, PathSet & context, PathSet & drvsSeen)
|
Bindings & attrs, XMLWriter & doc, PathSet & context, PathSet & drvsSeen)
|
||||||
{
|
{
|
||||||
StringSet names;
|
StringSet names;
|
||||||
|
|
||||||
foreach (Bindings::iterator, i, attrs)
|
for (auto & i : attrs)
|
||||||
names.insert(i->name);
|
names.insert(i.name);
|
||||||
|
|
||||||
foreach (StringSet::iterator, i, names) {
|
for (auto & i : names) {
|
||||||
Attr & a(*attrs.find(state.symbols.create(*i)));
|
Attr & a(*attrs.find(state.symbols.create(i)));
|
||||||
|
|
||||||
XMLAttrs xmlAttrs;
|
XMLAttrs xmlAttrs;
|
||||||
xmlAttrs["name"] = *i;
|
xmlAttrs["name"] = i;
|
||||||
if (location && a.pos != &noPos) posToXML(xmlAttrs, *a.pos);
|
if (location && a.pos != &noPos) posToXML(xmlAttrs, *a.pos);
|
||||||
|
|
||||||
XMLOpenElement _(doc, "attr", xmlAttrs);
|
XMLOpenElement _(doc, "attr", xmlAttrs);
|
||||||
printValueAsXML(state, strict, location,
|
printValueAsXML(state, strict, location,
|
||||||
*a.value, doc, context, drvsSeen);
|
*a.value, doc, context, drvsSeen);
|
||||||
@@ -57,7 +57,7 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
|
|||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
|
|
||||||
if (strict) state.forceValue(v);
|
if (strict) state.forceValue(v);
|
||||||
|
|
||||||
switch (v.type) {
|
switch (v.type) {
|
||||||
|
|
||||||
case tInt:
|
case tInt:
|
||||||
@@ -85,7 +85,7 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
|
|||||||
case tAttrs:
|
case tAttrs:
|
||||||
if (state.isDerivation(v)) {
|
if (state.isDerivation(v)) {
|
||||||
XMLAttrs xmlAttrs;
|
XMLAttrs xmlAttrs;
|
||||||
|
|
||||||
Bindings::iterator a = v.attrs->find(state.symbols.create("derivation"));
|
Bindings::iterator a = v.attrs->find(state.symbols.create("derivation"));
|
||||||
|
|
||||||
Path drvPath;
|
Path drvPath;
|
||||||
@@ -95,7 +95,7 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
|
|||||||
if (a->value->type == tString)
|
if (a->value->type == tString)
|
||||||
xmlAttrs["drvPath"] = drvPath = a->value->string.s;
|
xmlAttrs["drvPath"] = drvPath = a->value->string.s;
|
||||||
}
|
}
|
||||||
|
|
||||||
a = v.attrs->find(state.sOutPath);
|
a = v.attrs->find(state.sOutPath);
|
||||||
if (a != v.attrs->end()) {
|
if (a != v.attrs->end()) {
|
||||||
if (strict) state.forceValue(*a->value);
|
if (strict) state.forceValue(*a->value);
|
||||||
@@ -116,13 +116,13 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
|
|||||||
XMLOpenElement _(doc, "attrs");
|
XMLOpenElement _(doc, "attrs");
|
||||||
showAttrs(state, strict, location, *v.attrs, doc, context, drvsSeen);
|
showAttrs(state, strict, location, *v.attrs, doc, context, drvsSeen);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case tList: {
|
case tList1: case tList2: case tListN: {
|
||||||
XMLOpenElement _(doc, "list");
|
XMLOpenElement _(doc, "list");
|
||||||
for (unsigned int n = 0; n < v.list.length; ++n)
|
for (unsigned int n = 0; n < v.listSize(); ++n)
|
||||||
printValueAsXML(state, strict, location, *v.list.elems[n], doc, context, drvsSeen);
|
printValueAsXML(state, strict, location, *v.listElems()[n], doc, context, drvsSeen);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,17 +130,17 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
|
|||||||
XMLAttrs xmlAttrs;
|
XMLAttrs xmlAttrs;
|
||||||
if (location) posToXML(xmlAttrs, v.lambda.fun->pos);
|
if (location) posToXML(xmlAttrs, v.lambda.fun->pos);
|
||||||
XMLOpenElement _(doc, "function", xmlAttrs);
|
XMLOpenElement _(doc, "function", xmlAttrs);
|
||||||
|
|
||||||
if (v.lambda.fun->matchAttrs) {
|
if (v.lambda.fun->matchAttrs) {
|
||||||
XMLAttrs attrs;
|
XMLAttrs attrs;
|
||||||
if (!v.lambda.fun->arg.empty()) attrs["name"] = v.lambda.fun->arg;
|
if (!v.lambda.fun->arg.empty()) attrs["name"] = v.lambda.fun->arg;
|
||||||
if (v.lambda.fun->formals->ellipsis) attrs["ellipsis"] = "1";
|
if (v.lambda.fun->formals->ellipsis) attrs["ellipsis"] = "1";
|
||||||
XMLOpenElement _(doc, "attrspat", attrs);
|
XMLOpenElement _(doc, "attrspat", attrs);
|
||||||
foreach (Formals::Formals_::iterator, i, v.lambda.fun->formals->formals)
|
for (auto & i : v.lambda.fun->formals->formals)
|
||||||
doc.writeEmptyElement("attr", singletonAttrs("name", i->name));
|
doc.writeEmptyElement("attr", singletonAttrs("name", i.name));
|
||||||
} else
|
} else
|
||||||
doc.writeEmptyElement("varpat", singletonAttrs("name", v.lambda.fun->arg));
|
doc.writeEmptyElement("varpat", singletonAttrs("name", v.lambda.fun->arg));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,9 +166,9 @@ void printValueAsXML(EvalState & state, bool strict, bool location,
|
|||||||
{
|
{
|
||||||
XMLWriter doc(true, out);
|
XMLWriter doc(true, out);
|
||||||
XMLOpenElement root(doc, "expr");
|
XMLOpenElement root(doc, "expr");
|
||||||
PathSet drvsSeen;
|
PathSet drvsSeen;
|
||||||
printValueAsXML(state, strict, location, v, doc, context, drvsSeen);
|
printValueAsXML(state, strict, location, v, doc, context, drvsSeen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-3
@@ -12,7 +12,9 @@ typedef enum {
|
|||||||
tPath,
|
tPath,
|
||||||
tNull,
|
tNull,
|
||||||
tAttrs,
|
tAttrs,
|
||||||
tList,
|
tList1,
|
||||||
|
tList2,
|
||||||
|
tListN,
|
||||||
tThunk,
|
tThunk,
|
||||||
tApp,
|
tApp,
|
||||||
tLambda,
|
tLambda,
|
||||||
@@ -119,9 +121,10 @@ struct Value
|
|||||||
const char * path;
|
const char * path;
|
||||||
Bindings * attrs;
|
Bindings * attrs;
|
||||||
struct {
|
struct {
|
||||||
unsigned int length;
|
unsigned int size;
|
||||||
Value * * elems;
|
Value * * elems;
|
||||||
} list;
|
} bigList;
|
||||||
|
Value * smallList[2];
|
||||||
struct {
|
struct {
|
||||||
Env * env;
|
Env * env;
|
||||||
Expr * expr;
|
Expr * expr;
|
||||||
@@ -139,6 +142,26 @@ struct Value
|
|||||||
} primOpApp;
|
} primOpApp;
|
||||||
ExternalValueBase * external;
|
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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ static void setLogType(string lt)
|
|||||||
if (lt == "pretty") logType = ltPretty;
|
if (lt == "pretty") logType = ltPretty;
|
||||||
else if (lt == "escapes") logType = ltEscapes;
|
else if (lt == "escapes") logType = ltEscapes;
|
||||||
else if (lt == "flat") logType = ltFlat;
|
else if (lt == "flat") logType = ltFlat;
|
||||||
|
else if (lt == "systemd") logType = ltSystemd;
|
||||||
else throw UsageError("unknown log type");
|
else throw UsageError("unknown log type");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,6 +117,9 @@ void initNix()
|
|||||||
|
|
||||||
std::ios::sync_with_stdio(false);
|
std::ios::sync_with_stdio(false);
|
||||||
|
|
||||||
|
if (getEnv("IN_SYSTEMD") == "1")
|
||||||
|
logType = ltSystemd;
|
||||||
|
|
||||||
settings.processEnvironment();
|
settings.processEnvironment();
|
||||||
settings.loadConfFile();
|
settings.loadConfFile();
|
||||||
|
|
||||||
@@ -239,6 +243,20 @@ void parseCmdLine(int argc, char * * argv,
|
|||||||
void printVersion(const string & programName)
|
void printVersion(const string & programName)
|
||||||
{
|
{
|
||||||
std::cout << format("%1% (Nix) %2%") % programName % nixVersion << std::endl;
|
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();
|
throw Exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+429
-298
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "derivations.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
void builtinFetchurl(const BasicDerivation & drv);
|
||||||
|
|
||||||
|
}
|
||||||
+61
-20
@@ -3,6 +3,7 @@
|
|||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
#include "misc.hh"
|
#include "misc.hh"
|
||||||
|
#include "worker-protocol.hh"
|
||||||
|
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
@@ -31,8 +32,8 @@ Path writeDerivation(StoreAPI & store,
|
|||||||
{
|
{
|
||||||
PathSet references;
|
PathSet references;
|
||||||
references.insert(drv.inputSrcs.begin(), drv.inputSrcs.end());
|
references.insert(drv.inputSrcs.begin(), drv.inputSrcs.end());
|
||||||
foreach (DerivationInputs::const_iterator, i, drv.inputDrvs)
|
for (auto & i : drv.inputDrvs)
|
||||||
references.insert(i->first);
|
references.insert(i.first);
|
||||||
/* Note that the outputs of a derivation are *not* references
|
/* Note that the outputs of a derivation are *not* references
|
||||||
(that can be missing (of course) and should not necessarily be
|
(that can be missing (of course) and should not necessarily be
|
||||||
held during a garbage collection). */
|
held during a garbage collection). */
|
||||||
@@ -155,21 +156,21 @@ string unparseDerivation(const Derivation & drv)
|
|||||||
s += "Derive([";
|
s += "Derive([";
|
||||||
|
|
||||||
bool first = true;
|
bool first = true;
|
||||||
foreach (DerivationOutputs::const_iterator, i, drv.outputs) {
|
for (auto & i : drv.outputs) {
|
||||||
if (first) first = false; else s += ',';
|
if (first) first = false; else s += ',';
|
||||||
s += '('; printString(s, i->first);
|
s += '('; printString(s, i.first);
|
||||||
s += ','; printString(s, i->second.path);
|
s += ','; printString(s, i.second.path);
|
||||||
s += ','; printString(s, i->second.hashAlgo);
|
s += ','; printString(s, i.second.hashAlgo);
|
||||||
s += ','; printString(s, i->second.hash);
|
s += ','; printString(s, i.second.hash);
|
||||||
s += ')';
|
s += ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
s += "],[";
|
s += "],[";
|
||||||
first = true;
|
first = true;
|
||||||
foreach (DerivationInputs::const_iterator, i, drv.inputDrvs) {
|
for (auto & i : drv.inputDrvs) {
|
||||||
if (first) first = false; else s += ',';
|
if (first) first = false; else s += ',';
|
||||||
s += '('; printString(s, i->first);
|
s += '('; printString(s, i.first);
|
||||||
s += ','; printStrings(s, i->second.begin(), i->second.end());
|
s += ','; printStrings(s, i.second.begin(), i.second.end());
|
||||||
s += ')';
|
s += ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,10 +183,10 @@ string unparseDerivation(const Derivation & drv)
|
|||||||
|
|
||||||
s += ",[";
|
s += ",[";
|
||||||
first = true;
|
first = true;
|
||||||
foreach (StringPairs::const_iterator, i, drv.env) {
|
for (auto & i : drv.env) {
|
||||||
if (first) first = false; else s += ',';
|
if (first) first = false; else s += ',';
|
||||||
s += '('; printString(s, i->first);
|
s += '('; printString(s, i.first);
|
||||||
s += ','; printString(s, i->second);
|
s += ','; printString(s, i.second);
|
||||||
s += ')';
|
s += ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,15 +247,15 @@ Hash hashDerivationModulo(StoreAPI & store, Derivation drv)
|
|||||||
/* For other derivations, replace the inputs paths with recursive
|
/* For other derivations, replace the inputs paths with recursive
|
||||||
calls to this function.*/
|
calls to this function.*/
|
||||||
DerivationInputs inputs2;
|
DerivationInputs inputs2;
|
||||||
foreach (DerivationInputs::const_iterator, i, drv.inputDrvs) {
|
for (auto & i : drv.inputDrvs) {
|
||||||
Hash h = drvHashes[i->first];
|
Hash h = drvHashes[i.first];
|
||||||
if (h.type == htUnknown) {
|
if (h.type == htUnknown) {
|
||||||
assert(store.isValidPath(i->first));
|
assert(store.isValidPath(i.first));
|
||||||
Derivation drv2 = readDerivation(i->first);
|
Derivation drv2 = readDerivation(i.first);
|
||||||
h = hashDerivationModulo(store, drv2);
|
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;
|
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;
|
PathSet paths;
|
||||||
for (auto & i : drv.outputs)
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,15 +40,21 @@ typedef std::map<Path, StringSet> DerivationInputs;
|
|||||||
|
|
||||||
typedef std::map<string, string> StringPairs;
|
typedef std::map<string, string> StringPairs;
|
||||||
|
|
||||||
struct Derivation
|
struct BasicDerivation
|
||||||
{
|
{
|
||||||
DerivationOutputs outputs; /* keyed on symbolic IDs */
|
DerivationOutputs outputs; /* keyed on symbolic IDs */
|
||||||
DerivationInputs inputDrvs; /* inputs that are sub-derivations */
|
|
||||||
PathSet inputSrcs; /* inputs that are sources */
|
PathSet inputSrcs; /* inputs that are sources */
|
||||||
string platform;
|
string platform;
|
||||||
Path builder;
|
Path builder;
|
||||||
Strings args;
|
Strings args;
|
||||||
StringPairs env;
|
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);
|
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
@@ -350,15 +350,14 @@ static void addAdditionalRoots(StoreAPI & store, PathSet & roots)
|
|||||||
|
|
||||||
StringSet paths = tokenizeString<StringSet>(result, "\n");
|
StringSet paths = tokenizeString<StringSet>(result, "\n");
|
||||||
|
|
||||||
foreach (StringSet::iterator, i, paths) {
|
for (auto & i : paths)
|
||||||
if (isInStore(*i)) {
|
if (isInStore(i)) {
|
||||||
Path path = toStorePath(*i);
|
Path path = toStorePath(i);
|
||||||
if (roots.find(path) == roots.end() && store.isValidPath(path)) {
|
if (roots.find(path) == roots.end() && store.isValidPath(path)) {
|
||||||
debug(format("got additional root ‘%1%’") % path);
|
debug(format("got additional root ‘%1%’") % path);
|
||||||
roots.insert(path);
|
roots.insert(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -376,6 +375,7 @@ struct LocalStore::GCState
|
|||||||
bool gcKeepOutputs;
|
bool gcKeepOutputs;
|
||||||
bool gcKeepDerivations;
|
bool gcKeepDerivations;
|
||||||
unsigned long long bytesInvalidated;
|
unsigned long long bytesInvalidated;
|
||||||
|
bool moveToTrash = true;
|
||||||
Path trashDir;
|
Path trashDir;
|
||||||
bool shouldDelete;
|
bool shouldDelete;
|
||||||
GCState(GCResults & results_) : results(results_), bytesInvalidated(0) { }
|
GCState(GCResults & results_) : results(results_), bytesInvalidated(0) { }
|
||||||
@@ -407,8 +407,8 @@ void LocalStore::deletePathRecursive(GCState & state, const Path & path)
|
|||||||
if (isValidPath(path)) {
|
if (isValidPath(path)) {
|
||||||
PathSet referrers;
|
PathSet referrers;
|
||||||
queryReferrers(path, referrers);
|
queryReferrers(path, referrers);
|
||||||
foreach (PathSet::iterator, i, referrers)
|
for (auto & i : referrers)
|
||||||
if (*i != path) deletePathRecursive(state, *i);
|
if (i != path) deletePathRecursive(state, i);
|
||||||
size = queryPathInfo(path).narSize;
|
size = queryPathInfo(path).narSize;
|
||||||
invalidatePathChecked(path);
|
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
|
not holding the global GC lock) we can delete the path without
|
||||||
being afraid that the path has become alive again. Otherwise
|
being afraid that the path has become alive again. Otherwise
|
||||||
delete it right away. */
|
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:
|
// Estimate the amount freed using the narSize field. FIXME:
|
||||||
// if the path was not valid, need to determine the actual
|
// if the path was not valid, need to determine the actual
|
||||||
// size.
|
// size.
|
||||||
state.bytesInvalidated += size;
|
try {
|
||||||
if (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1)
|
if (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1)
|
||||||
throw SysError(format("making ‘%1%’ writable") % path);
|
throw SysError(format("making ‘%1%’ writable") % path);
|
||||||
Path tmp = state.trashDir + "/" + baseNameOf(path);
|
Path tmp = state.trashDir + "/" + baseNameOf(path);
|
||||||
if (rename(path.c_str(), tmp.c_str()))
|
if (rename(path.c_str(), tmp.c_str()))
|
||||||
throw SysError(format("unable to rename ‘%1%’ to ‘%2%’") % path % tmp);
|
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
|
} else
|
||||||
deleteGarbage(state, path);
|
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. */
|
don't delete the derivation if any of the outputs are alive. */
|
||||||
if (state.gcKeepDerivations && isDerivation(path)) {
|
if (state.gcKeepDerivations && isDerivation(path)) {
|
||||||
PathSet outputs = queryDerivationOutputs(path);
|
PathSet outputs = queryDerivationOutputs(path);
|
||||||
foreach (PathSet::iterator, i, outputs)
|
for (auto & i : outputs)
|
||||||
if (isValidPath(*i) && queryDeriver(*i) == path)
|
if (isValidPath(i) && queryDeriver(i) == path)
|
||||||
incoming.insert(*i);
|
incoming.insert(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If gc-keep-outputs is set, then don't delete this path if there
|
/* If gc-keep-outputs is set, then don't delete this path if there
|
||||||
are derivers of this path that are not garbage. */
|
are derivers of this path that are not garbage. */
|
||||||
if (state.gcKeepOutputs) {
|
if (state.gcKeepOutputs) {
|
||||||
PathSet derivers = queryValidDerivers(path);
|
PathSet derivers = queryValidDerivers(path);
|
||||||
foreach (PathSet::iterator, i, derivers)
|
for (auto & i : derivers)
|
||||||
incoming.insert(*i);
|
incoming.insert(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (PathSet::iterator, i, incoming)
|
for (auto & i : incoming)
|
||||||
if (*i != path)
|
if (i != path)
|
||||||
if (canReachRoot(state, visited, *i)) {
|
if (canReachRoot(state, visited, i)) {
|
||||||
state.alive.insert(path);
|
state.alive.insert(path);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -614,7 +621,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
|||||||
printMsg(lvlError, format("finding garbage collector roots..."));
|
printMsg(lvlError, format("finding garbage collector roots..."));
|
||||||
Roots rootMap = options.ignoreLiveness ? Roots() : findRoots();
|
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
|
/* Add additional roots returned by the program specified by the
|
||||||
NIX_ROOT_FINDER environment variable. This is typically used
|
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 (state.shouldDelete) {
|
||||||
if (pathExists(state.trashDir)) deleteGarbage(state, state.trashDir);
|
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
|
/* 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) {
|
if (options.action == GCOptions::gcDeleteSpecific) {
|
||||||
|
|
||||||
foreach (PathSet::iterator, i, options.pathsToDelete) {
|
for (auto & i : options.pathsToDelete) {
|
||||||
assertStorePath(*i);
|
assertStorePath(i);
|
||||||
tryToDelete(state, *i);
|
tryToDelete(state, i);
|
||||||
if (state.dead.find(*i) == state.dead.end())
|
if (state.dead.find(i) == state.dead.end())
|
||||||
throw Error(format("cannot delete path ‘%1%’ since it is still alive") % *i);
|
throw Error(format("cannot delete path ‘%1%’ since it is still alive") % i);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (options.maxFreed > 0) {
|
} else if (options.maxFreed > 0) {
|
||||||
@@ -692,8 +706,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
|||||||
vector<Path> entries_(entries.begin(), entries.end());
|
vector<Path> entries_(entries.begin(), entries.end());
|
||||||
random_shuffle(entries_.begin(), entries_.end());
|
random_shuffle(entries_.begin(), entries_.end());
|
||||||
|
|
||||||
foreach (vector<Path>::iterator, i, entries_)
|
for (auto & i : entries_)
|
||||||
tryToDelete(state, *i);
|
tryToDelete(state, i);
|
||||||
|
|
||||||
} catch (GCLimitReached & e) {
|
} catch (GCLimitReached & e) {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ Settings::Settings()
|
|||||||
buildTimeout = 0;
|
buildTimeout = 0;
|
||||||
useBuildHook = true;
|
useBuildHook = true;
|
||||||
printBuildTrace = false;
|
printBuildTrace = false;
|
||||||
reservedSize = 1024 * 1024;
|
reservedSize = 8 * 1024 * 1024;
|
||||||
fsyncMetadata = true;
|
fsyncMetadata = true;
|
||||||
useSQLiteWAL = true;
|
useSQLiteWAL = true;
|
||||||
syncBeforeRegistering = false;
|
syncBeforeRegistering = false;
|
||||||
@@ -248,12 +248,12 @@ template<class N> void Settings::_get(N & res, const string & name)
|
|||||||
string Settings::pack()
|
string Settings::pack()
|
||||||
{
|
{
|
||||||
string s;
|
string s;
|
||||||
foreach (SettingsMap::iterator, i, settings) {
|
for (auto & i : settings) {
|
||||||
if (i->first.find('\n') != string::npos ||
|
if (i.first.find('\n') != string::npos ||
|
||||||
i->first.find('=') != string::npos ||
|
i.first.find('=') != string::npos ||
|
||||||
i->second.find('\n') != string::npos)
|
i.second.find('\n') != string::npos)
|
||||||
throw Error("illegal option name/value");
|
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;
|
return s;
|
||||||
}
|
}
|
||||||
@@ -261,11 +261,11 @@ string Settings::pack()
|
|||||||
|
|
||||||
void Settings::unpack(const string & pack) {
|
void Settings::unpack(const string & pack) {
|
||||||
Strings lines = tokenizeString<Strings>(pack, "\n");
|
Strings lines = tokenizeString<Strings>(pack, "\n");
|
||||||
foreach (Strings::iterator, i, lines) {
|
for (auto & i : lines) {
|
||||||
string::size_type eq = i->find('=');
|
string::size_type eq = i.find('=');
|
||||||
if (eq == string::npos)
|
if (eq == string::npos)
|
||||||
throw Error("illegal option name/value");
|
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
@@ -289,7 +289,17 @@ LocalStore::LocalStore(bool reserveSpace)
|
|||||||
struct stat st;
|
struct stat st;
|
||||||
if (stat(reservedPath.c_str(), &st) == -1 ||
|
if (stat(reservedPath.c_str(), &st) == -1 ||
|
||||||
st.st_size != settings.reservedSize)
|
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
|
else
|
||||||
deletePath(reservedPath);
|
deletePath(reservedPath);
|
||||||
@@ -357,13 +367,13 @@ LocalStore::LocalStore(bool reserveSpace)
|
|||||||
LocalStore::~LocalStore()
|
LocalStore::~LocalStore()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
foreach (RunningSubstituters::iterator, i, runningSubstituters) {
|
for (auto & i : runningSubstituters) {
|
||||||
if (i->second.disabled) continue;
|
if (i.second.disabled) continue;
|
||||||
i->second.to.close();
|
i.second.to.close();
|
||||||
i->second.from.close();
|
i.second.from.close();
|
||||||
i->second.error.close();
|
i.second.error.close();
|
||||||
if (i->second.pid != -1)
|
if (i.second.pid != -1)
|
||||||
i->second.pid.wait(true);
|
i.second.pid.wait(true);
|
||||||
}
|
}
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
ignoreException();
|
ignoreException();
|
||||||
@@ -661,19 +671,19 @@ void LocalStore::checkDerivationOutputs(const Path & drvPath, const Derivation &
|
|||||||
|
|
||||||
else {
|
else {
|
||||||
Derivation drvCopy(drv);
|
Derivation drvCopy(drv);
|
||||||
foreach (DerivationOutputs::iterator, i, drvCopy.outputs) {
|
for (auto & i : drvCopy.outputs) {
|
||||||
i->second.path = "";
|
i.second.path = "";
|
||||||
drvCopy.env[i->first] = "";
|
drvCopy.env[i.first] = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
Hash h = hashDerivationModulo(*this, drvCopy);
|
Hash h = hashDerivationModulo(*this, drvCopy);
|
||||||
|
|
||||||
foreach (DerivationOutputs::const_iterator, i, drv.outputs) {
|
for (auto & i : drv.outputs) {
|
||||||
Path outPath = makeOutputPath(i->first, h, drvName);
|
Path outPath = makeOutputPath(i.first, h, drvName);
|
||||||
StringPairs::const_iterator j = drv.env.find(i->first);
|
StringPairs::const_iterator j = drv.env.find(i.first);
|
||||||
if (i->second.path != outPath || j == drv.env.end() || j->second != outPath)
|
if (i.second.path != outPath || j == drv.env.end() || j->second != outPath)
|
||||||
throw Error(format("derivation ‘%1%’ has incorrect output ‘%2%’, should be ‘%3%’")
|
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. */
|
registration above is undone. */
|
||||||
if (checkOutputs) checkDerivationOutputs(info.path, drv);
|
if (checkOutputs) checkDerivationOutputs(info.path, drv);
|
||||||
|
|
||||||
foreach (DerivationOutputs::iterator, i, drv.outputs) {
|
for (auto & i : drv.outputs) {
|
||||||
SQLiteStmtUse use(stmtAddDerivationOutput);
|
SQLiteStmtUse use(stmtAddDerivationOutput);
|
||||||
stmtAddDerivationOutput.bind(id);
|
stmtAddDerivationOutput.bind(id);
|
||||||
stmtAddDerivationOutput.bind(i->first);
|
stmtAddDerivationOutput.bind(i.first);
|
||||||
stmtAddDerivationOutput.bind(i->second.path);
|
stmtAddDerivationOutput.bind(i.second.path);
|
||||||
if (sqlite3_step(stmtAddDerivationOutput) != SQLITE_DONE)
|
if (sqlite3_step(stmtAddDerivationOutput) != SQLITE_DONE)
|
||||||
throwSQLiteError(db, format("adding derivation output for ‘%1%’ in database") % info.path);
|
throwSQLiteError(db, format("adding derivation output for ‘%1%’ in database") % info.path);
|
||||||
}
|
}
|
||||||
@@ -786,11 +796,11 @@ void LocalStore::clearFailedPaths(const PathSet & paths)
|
|||||||
retry_sqlite {
|
retry_sqlite {
|
||||||
SQLiteTxn txn(db);
|
SQLiteTxn txn(db);
|
||||||
|
|
||||||
foreach (PathSet::const_iterator, i, paths) {
|
for (auto & i : paths) {
|
||||||
SQLiteStmtUse use(stmtClearFailedPath);
|
SQLiteStmtUse use(stmtClearFailedPath);
|
||||||
stmtClearFailedPath.bind(*i);
|
stmtClearFailedPath.bind(i);
|
||||||
if (sqlite3_step(stmtClearFailedPath) != SQLITE_DONE)
|
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();
|
txn.commit();
|
||||||
@@ -913,8 +923,8 @@ PathSet LocalStore::queryValidPaths(const PathSet & paths)
|
|||||||
{
|
{
|
||||||
retry_sqlite {
|
retry_sqlite {
|
||||||
PathSet res;
|
PathSet res;
|
||||||
foreach (PathSet::const_iterator, i, paths)
|
for (auto & i : paths)
|
||||||
if (isValidPath_(*i)) res.insert(*i);
|
if (isValidPath_(i)) res.insert(i);
|
||||||
return res;
|
return res;
|
||||||
} end_retry_sqlite;
|
} end_retry_sqlite;
|
||||||
}
|
}
|
||||||
@@ -1202,14 +1212,14 @@ template<class T> T LocalStore::getIntLineFromSubstituter(RunningSubstituter & r
|
|||||||
PathSet LocalStore::querySubstitutablePaths(const PathSet & paths)
|
PathSet LocalStore::querySubstitutablePaths(const PathSet & paths)
|
||||||
{
|
{
|
||||||
PathSet res;
|
PathSet res;
|
||||||
foreach (Paths::iterator, i, settings.substituters) {
|
for (auto & i : settings.substituters) {
|
||||||
if (res.size() == paths.size()) break;
|
if (res.size() == paths.size()) break;
|
||||||
RunningSubstituter & run(runningSubstituters[*i]);
|
RunningSubstituter & run(runningSubstituters[i]);
|
||||||
startSubstituter(*i, run);
|
startSubstituter(i, run);
|
||||||
if (run.disabled) continue;
|
if (run.disabled) continue;
|
||||||
string s = "have ";
|
string s = "have ";
|
||||||
foreach (PathSet::const_iterator, j, paths)
|
for (auto & j : paths)
|
||||||
if (res.find(*j) == res.end()) { s += *j; s += " "; }
|
if (res.find(j) == res.end()) { s += j; s += " "; }
|
||||||
writeLine(run.to, s);
|
writeLine(run.to, s);
|
||||||
while (true) {
|
while (true) {
|
||||||
/* FIXME: we only read stderr when an error occurs, so
|
/* FIXME: we only read stderr when an error occurs, so
|
||||||
@@ -1233,8 +1243,8 @@ void LocalStore::querySubstitutablePathInfos(const Path & substituter,
|
|||||||
if (run.disabled) return;
|
if (run.disabled) return;
|
||||||
|
|
||||||
string s = "info ";
|
string s = "info ";
|
||||||
foreach (PathSet::const_iterator, i, paths)
|
for (auto & i : paths)
|
||||||
if (infos.find(*i) == infos.end()) { s += *i; s += " "; }
|
if (infos.find(i) == infos.end()) { s += i; s += " "; }
|
||||||
writeLine(run.to, s);
|
writeLine(run.to, s);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -1262,9 +1272,9 @@ void LocalStore::querySubstitutablePathInfos(const PathSet & paths,
|
|||||||
SubstitutablePathInfos & infos)
|
SubstitutablePathInfos & infos)
|
||||||
{
|
{
|
||||||
PathSet todo = paths;
|
PathSet todo = paths;
|
||||||
foreach (Paths::iterator, i, settings.substituters) {
|
for (auto & i : settings.substituters) {
|
||||||
if (todo.empty()) break;
|
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);
|
SQLiteTxn txn(db);
|
||||||
PathSet paths;
|
PathSet paths;
|
||||||
|
|
||||||
foreach (ValidPathInfos::const_iterator, i, infos) {
|
for (auto & i : infos) {
|
||||||
assert(i->hash.type == htSHA256);
|
assert(i.hash.type == htSHA256);
|
||||||
if (isValidPath_(i->path))
|
if (isValidPath_(i.path))
|
||||||
updatePathInfo(*i);
|
updatePathInfo(i);
|
||||||
else
|
else
|
||||||
addValidPath(*i, false);
|
addValidPath(i, false);
|
||||||
paths.insert(i->path);
|
paths.insert(i.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (ValidPathInfos::const_iterator, i, infos) {
|
for (auto & i : infos) {
|
||||||
unsigned long long referrer = queryValidPathId(i->path);
|
unsigned long long referrer = queryValidPathId(i.path);
|
||||||
foreach (PathSet::iterator, j, i->references)
|
for (auto & j : i.references)
|
||||||
addReference(referrer, queryValidPathId(*j));
|
addReference(referrer, queryValidPathId(j));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check that the derivation outputs are correct. We can't do
|
/* Check that the derivation outputs are correct. We can't do
|
||||||
this in addValidPath() above, because the references might
|
this in addValidPath() above, because the references might
|
||||||
not be valid yet. */
|
not be valid yet. */
|
||||||
foreach (ValidPathInfos::const_iterator, i, infos)
|
for (auto & i : infos)
|
||||||
if (isDerivation(i->path)) {
|
if (isDerivation(i.path)) {
|
||||||
// FIXME: inefficient; we already loaded the
|
// FIXME: inefficient; we already loaded the
|
||||||
// derivation in addValidPath().
|
// derivation in addValidPath().
|
||||||
Derivation drv = readDerivation(i->path);
|
Derivation drv = readDerivation(i.path);
|
||||||
checkDerivationOutputs(i->path, drv);
|
checkDerivationOutputs(i.path, drv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do a topological sort of the paths. This will throw an
|
/* 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);
|
assertStorePath(path);
|
||||||
|
|
||||||
printMsg(lvlInfo, format("exporting path ‘%1%’") % path);
|
printMsg(lvlTalkative, format("exporting path ‘%1%’") % path);
|
||||||
|
|
||||||
if (!isValidPath(path))
|
if (!isValidPath(path))
|
||||||
throw Error(format("path ‘%1%’ is not valid") % 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
|
throw Error(format("hash of path ‘%1%’ has changed from ‘%2%’ to ‘%3%’!") % path
|
||||||
% printHash(storedHash) % printHash(hash));
|
% printHash(storedHash) % printHash(hash));
|
||||||
|
|
||||||
writeInt(EXPORT_MAGIC, hashAndWriteSink);
|
|
||||||
|
|
||||||
writeString(path, hashAndWriteSink);
|
|
||||||
|
|
||||||
PathSet references;
|
PathSet references;
|
||||||
queryReferences(path, references);
|
queryReferences(path, references);
|
||||||
writeStrings(references, hashAndWriteSink);
|
|
||||||
|
|
||||||
Path deriver = queryDeriver(path);
|
hashAndWriteSink << EXPORT_MAGIC << path << references << queryDeriver(path);
|
||||||
writeString(deriver, hashAndWriteSink);
|
|
||||||
|
|
||||||
if (sign) {
|
if (sign) {
|
||||||
Hash hash = hashAndWriteSink.currentHash();
|
Hash hash = hashAndWriteSink.currentHash();
|
||||||
|
|
||||||
writeInt(1, hashAndWriteSink);
|
|
||||||
|
|
||||||
Path tmpDir = createTempDir();
|
Path tmpDir = createTempDir();
|
||||||
AutoDelete delTmp(tmpDir);
|
AutoDelete delTmp(tmpDir);
|
||||||
Path hashFile = tmpDir + "/hash";
|
Path hashFile = tmpDir + "/hash";
|
||||||
@@ -1551,10 +1553,10 @@ void LocalStore::exportPath(const Path & path, bool sign,
|
|||||||
args.push_back(hashFile);
|
args.push_back(hashFile);
|
||||||
string signature = runProgram(OPENSSL_PATH, true, args);
|
string signature = runProgram(OPENSSL_PATH, true, args);
|
||||||
|
|
||||||
writeString(signature, hashAndWriteSink);
|
hashAndWriteSink << 1 << signature;
|
||||||
|
|
||||||
} else
|
} else
|
||||||
writeInt(0, hashAndWriteSink);
|
hashAndWriteSink << 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1611,6 +1613,8 @@ Path LocalStore::importPath(bool requireSignature, Source & source)
|
|||||||
|
|
||||||
Path dstPath = readStorePath(hashAndReadSource);
|
Path dstPath = readStorePath(hashAndReadSource);
|
||||||
|
|
||||||
|
printMsg(lvlTalkative, format("importing path ‘%1%’") % dstPath);
|
||||||
|
|
||||||
PathSet references = readStorePaths<PathSet>(hashAndReadSource);
|
PathSet references = readStorePaths<PathSet>(hashAndReadSource);
|
||||||
|
|
||||||
Path deriver = readString(hashAndReadSource);
|
Path deriver = readString(hashAndReadSource);
|
||||||
@@ -1751,8 +1755,8 @@ bool LocalStore::verifyStore(bool checkContents, bool repair)
|
|||||||
|
|
||||||
PathSet validPaths2 = queryAllValidPaths(), validPaths, done;
|
PathSet validPaths2 = queryAllValidPaths(), validPaths, done;
|
||||||
|
|
||||||
foreach (PathSet::iterator, i, validPaths2)
|
for (auto & i : validPaths2)
|
||||||
verifyPath(*i, store, done, validPaths, repair, errors);
|
verifyPath(i, store, done, validPaths, repair, errors);
|
||||||
|
|
||||||
/* Release the GC lock so that checking content hashes (which can
|
/* Release the GC lock so that checking content hashes (which can
|
||||||
take ages) doesn't block the GC or builds. */
|
take ages) doesn't block the GC or builds. */
|
||||||
@@ -1764,33 +1768,33 @@ bool LocalStore::verifyStore(bool checkContents, bool repair)
|
|||||||
|
|
||||||
Hash nullHash(htSHA256);
|
Hash nullHash(htSHA256);
|
||||||
|
|
||||||
foreach (PathSet::iterator, i, validPaths) {
|
for (auto & i : validPaths) {
|
||||||
try {
|
try {
|
||||||
ValidPathInfo info = queryPathInfo(*i);
|
ValidPathInfo info = queryPathInfo(i);
|
||||||
|
|
||||||
/* Check the content hash (optionally - slow). */
|
/* Check the content hash (optionally - slow). */
|
||||||
printMsg(lvlTalkative, format("checking contents of ‘%1%’") % *i);
|
printMsg(lvlTalkative, format("checking contents of ‘%1%’") % i);
|
||||||
HashResult current = hashPath(info.hash.type, *i);
|
HashResult current = hashPath(info.hash.type, i);
|
||||||
|
|
||||||
if (info.hash != nullHash && info.hash != current.first) {
|
if (info.hash != nullHash && info.hash != current.first) {
|
||||||
printMsg(lvlError, format("path ‘%1%’ was modified! "
|
printMsg(lvlError, format("path ‘%1%’ was modified! "
|
||||||
"expected hash ‘%2%’, got ‘%3%’")
|
"expected hash ‘%2%’, got ‘%3%’")
|
||||||
% *i % printHash(info.hash) % printHash(current.first));
|
% i % printHash(info.hash) % printHash(current.first));
|
||||||
if (repair) repairPath(*i); else errors = true;
|
if (repair) repairPath(i); else errors = true;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
bool update = false;
|
bool update = false;
|
||||||
|
|
||||||
/* Fill in missing hashes. */
|
/* Fill in missing hashes. */
|
||||||
if (info.hash == nullHash) {
|
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;
|
info.hash = current.first;
|
||||||
update = true;
|
update = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill in missing narSize fields (from old stores). */
|
/* Fill in missing narSize fields (from old stores). */
|
||||||
if (info.narSize == 0) {
|
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;
|
info.narSize = current.second;
|
||||||
update = true;
|
update = true;
|
||||||
}
|
}
|
||||||
@@ -1802,7 +1806,7 @@ bool LocalStore::verifyStore(bool checkContents, bool repair)
|
|||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
/* It's possible that the path got GC'ed, so ignore
|
/* It's possible that the path got GC'ed, so ignore
|
||||||
errors on invalid paths. */
|
errors on invalid paths. */
|
||||||
if (isValidPath(*i))
|
if (isValidPath(i))
|
||||||
printMsg(lvlError, format("error: %1%") % e.msg());
|
printMsg(lvlError, format("error: %1%") % e.msg());
|
||||||
else
|
else
|
||||||
printMsg(lvlError, format("warning: %1%") % e.msg());
|
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. */
|
first, then we can invalidate this path as well. */
|
||||||
bool canInvalidate = true;
|
bool canInvalidate = true;
|
||||||
PathSet referrers; queryReferrers(path, referrers);
|
PathSet referrers; queryReferrers(path, referrers);
|
||||||
foreach (PathSet::iterator, i, referrers)
|
for (auto & i : referrers)
|
||||||
if (*i != path) {
|
if (i != path) {
|
||||||
verifyPath(*i, store, done, validPaths, repair, errors);
|
verifyPath(i, store, done, validPaths, repair, errors);
|
||||||
if (validPaths.find(*i) != validPaths.end())
|
if (validPaths.find(i) != validPaths.end())
|
||||||
canInvalidate = false;
|
canInvalidate = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1915,12 +1919,12 @@ ValidPathInfo LocalStore::queryPathInfoOld(const Path & path)
|
|||||||
/* Parse it. */
|
/* Parse it. */
|
||||||
Strings lines = tokenizeString<Strings>(info, "\n");
|
Strings lines = tokenizeString<Strings>(info, "\n");
|
||||||
|
|
||||||
foreach (Strings::iterator, i, lines) {
|
for (auto & i : lines) {
|
||||||
string::size_type p = i->find(':');
|
string::size_type p = i.find(':');
|
||||||
if (p == string::npos)
|
if (p == string::npos)
|
||||||
throw Error(format("corrupt line in ‘%1%’: %2%") % infoFile % *i);
|
throw Error(format("corrupt line in ‘%1%’: %2%") % infoFile % i);
|
||||||
string name(*i, 0, p);
|
string name(i, 0, p);
|
||||||
string value(*i, p + 2);
|
string value(i, p + 2);
|
||||||
if (name == "References") {
|
if (name == "References") {
|
||||||
Strings refs = tokenizeString<Strings>(value, " ");
|
Strings refs = tokenizeString<Strings>(value, " ");
|
||||||
res.references = PathSet(refs.begin(), refs.end());
|
res.references = PathSet(refs.begin(), refs.end());
|
||||||
@@ -1950,18 +1954,18 @@ void LocalStore::upgradeStore6()
|
|||||||
|
|
||||||
SQLiteTxn txn(db);
|
SQLiteTxn txn(db);
|
||||||
|
|
||||||
foreach (PathSet::iterator, i, validPaths) {
|
for (auto & i : validPaths) {
|
||||||
addValidPath(queryPathInfoOld(*i), false);
|
addValidPath(queryPathInfoOld(i), false);
|
||||||
std::cerr << ".";
|
std::cerr << ".";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cerr << "|";
|
std::cerr << "|";
|
||||||
|
|
||||||
foreach (PathSet::iterator, i, validPaths) {
|
for (auto & i : validPaths) {
|
||||||
ValidPathInfo info = queryPathInfoOld(*i);
|
ValidPathInfo info = queryPathInfoOld(i);
|
||||||
unsigned long long referrer = queryValidPathId(*i);
|
unsigned long long referrer = queryValidPathId(i);
|
||||||
foreach (PathSet::iterator, j, info.references)
|
for (auto & j : info.references)
|
||||||
addReference(referrer, queryValidPathId(*j));
|
addReference(referrer, queryValidPathId(j));
|
||||||
std::cerr << ".";
|
std::cerr << ".";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -151,6 +151,9 @@ public:
|
|||||||
|
|
||||||
void buildPaths(const PathSet & paths, BuildMode buildMode);
|
void buildPaths(const PathSet & paths, BuildMode buildMode);
|
||||||
|
|
||||||
|
BuildResult buildDerivation(const Path & drvPath, const BasicDerivation & drv,
|
||||||
|
BuildMode buildMode) override;
|
||||||
|
|
||||||
void ensurePath(const Path & path);
|
void ensurePath(const Path & path);
|
||||||
|
|
||||||
void addTempRoot(const Path & path);
|
void addTempRoot(const Path & path);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ libstore_SOURCES := $(wildcard $(d)/*.cc)
|
|||||||
|
|
||||||
libstore_LIBS = libutil libformat
|
libstore_LIBS = libutil libformat
|
||||||
|
|
||||||
libstore_LDFLAGS = -lsqlite3 -lbz2
|
libstore_LDFLAGS = -lsqlite3 -lbz2 -lcurl
|
||||||
|
|
||||||
ifeq ($(OS), SunOS)
|
ifeq ($(OS), SunOS)
|
||||||
libstore_LDFLAGS += -lsocket
|
libstore_LDFLAGS += -lsocket
|
||||||
|
|||||||
+43
-43
@@ -28,15 +28,15 @@ void computeFSClosure(StoreAPI & store, const Path & path,
|
|||||||
|
|
||||||
if (includeOutputs) {
|
if (includeOutputs) {
|
||||||
PathSet derivers = store.queryValidDerivers(path);
|
PathSet derivers = store.queryValidDerivers(path);
|
||||||
foreach (PathSet::iterator, i, derivers)
|
for (auto & i : derivers)
|
||||||
edges.insert(*i);
|
edges.insert(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (includeDerivers && isDerivation(path)) {
|
if (includeDerivers && isDerivation(path)) {
|
||||||
PathSet outputs = store.queryDerivationOutputs(path);
|
PathSet outputs = store.queryDerivationOutputs(path);
|
||||||
foreach (PathSet::iterator, i, outputs)
|
for (auto & i : outputs)
|
||||||
if (store.isValidPath(*i) && store.queryDeriver(*i) == path)
|
if (store.isValidPath(i) && store.queryDeriver(i) == path)
|
||||||
edges.insert(*i);
|
edges.insert(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -44,8 +44,8 @@ void computeFSClosure(StoreAPI & store, const Path & path,
|
|||||||
|
|
||||||
if (includeOutputs && isDerivation(path)) {
|
if (includeOutputs && isDerivation(path)) {
|
||||||
PathSet outputs = store.queryDerivationOutputs(path);
|
PathSet outputs = store.queryDerivationOutputs(path);
|
||||||
foreach (PathSet::iterator, i, outputs)
|
for (auto & i : outputs)
|
||||||
if (store.isValidPath(*i)) edges.insert(*i);
|
if (store.isValidPath(i)) edges.insert(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (includeDerivers) {
|
if (includeDerivers) {
|
||||||
@@ -54,15 +54,15 @@ void computeFSClosure(StoreAPI & store, const Path & path,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (PathSet::iterator, i, edges)
|
for (auto & i : edges)
|
||||||
computeFSClosure(store, *i, paths, flipDirection, includeOutputs, includeDerivers);
|
computeFSClosure(store, i, paths, flipDirection, includeOutputs, includeDerivers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Path findOutput(const Derivation & drv, string id)
|
Path findOutput(const Derivation & drv, string id)
|
||||||
{
|
{
|
||||||
foreach (DerivationOutputs::const_iterator, i, drv.outputs)
|
for (auto & i : drv.outputs)
|
||||||
if (i->first == id) return i->second.path;
|
if (i.first == id) return i.second.path;
|
||||||
throw Error(format("derivation has no output ‘%1%’") % id);
|
throw Error(format("derivation has no output ‘%1%’") % id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,36 +98,36 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
|
|||||||
|
|
||||||
PathSet query, todoDrv, todoNonDrv;
|
PathSet query, todoDrv, todoNonDrv;
|
||||||
|
|
||||||
foreach (PathSet::iterator, i, todo) {
|
for (auto & i : todo) {
|
||||||
if (done.find(*i) != done.end()) continue;
|
if (done.find(i) != done.end()) continue;
|
||||||
done.insert(*i);
|
done.insert(i);
|
||||||
|
|
||||||
DrvPathWithOutputs i2 = parseDrvPathWithOutputs(*i);
|
DrvPathWithOutputs i2 = parseDrvPathWithOutputs(i);
|
||||||
|
|
||||||
if (isDerivation(i2.first)) {
|
if (isDerivation(i2.first)) {
|
||||||
if (!store.isValidPath(i2.first)) {
|
if (!store.isValidPath(i2.first)) {
|
||||||
// FIXME: we could try to substitute p.
|
// FIXME: we could try to substitute p.
|
||||||
unknown.insert(*i);
|
unknown.insert(i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Derivation drv = derivationFromPath(store, i2.first);
|
Derivation drv = derivationFromPath(store, i2.first);
|
||||||
|
|
||||||
PathSet invalid;
|
PathSet invalid;
|
||||||
foreach (DerivationOutputs::iterator, j, drv.outputs)
|
for (auto & j : drv.outputs)
|
||||||
if (wantOutput(j->first, i2.second)
|
if (wantOutput(j.first, i2.second)
|
||||||
&& !store.isValidPath(j->second.path))
|
&& !store.isValidPath(j.second.path))
|
||||||
invalid.insert(j->second.path);
|
invalid.insert(j.second.path);
|
||||||
if (invalid.empty()) continue;
|
if (invalid.empty()) continue;
|
||||||
|
|
||||||
todoDrv.insert(*i);
|
todoDrv.insert(i);
|
||||||
if (settings.useSubstitutes && substitutesAllowed(drv))
|
if (settings.useSubstitutes && substitutesAllowed(drv))
|
||||||
query.insert(invalid.begin(), invalid.end());
|
query.insert(invalid.begin(), invalid.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
if (store.isValidPath(*i)) continue;
|
if (store.isValidPath(i)) continue;
|
||||||
query.insert(*i);
|
query.insert(i);
|
||||||
todoNonDrv.insert(*i);
|
todoNonDrv.insert(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,8 +136,8 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
|
|||||||
SubstitutablePathInfos infos;
|
SubstitutablePathInfos infos;
|
||||||
store.querySubstitutablePathInfos(query, infos);
|
store.querySubstitutablePathInfos(query, infos);
|
||||||
|
|
||||||
foreach (PathSet::iterator, i, todoDrv) {
|
for (auto & i : todoDrv) {
|
||||||
DrvPathWithOutputs i2 = parseDrvPathWithOutputs(*i);
|
DrvPathWithOutputs i2 = parseDrvPathWithOutputs(i);
|
||||||
|
|
||||||
// FIXME: cache this
|
// FIXME: cache this
|
||||||
Derivation drv = derivationFromPath(store, i2.first);
|
Derivation drv = derivationFromPath(store, i2.first);
|
||||||
@@ -145,13 +145,13 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
|
|||||||
PathSet outputs;
|
PathSet outputs;
|
||||||
bool mustBuild = false;
|
bool mustBuild = false;
|
||||||
if (settings.useSubstitutes && substitutesAllowed(drv)) {
|
if (settings.useSubstitutes && substitutesAllowed(drv)) {
|
||||||
foreach (DerivationOutputs::iterator, j, drv.outputs) {
|
for (auto & j : drv.outputs) {
|
||||||
if (!wantOutput(j->first, i2.second)) continue;
|
if (!wantOutput(j.first, i2.second)) continue;
|
||||||
if (!store.isValidPath(j->second.path)) {
|
if (!store.isValidPath(j.second.path)) {
|
||||||
if (infos.find(j->second.path) == infos.end())
|
if (infos.find(j.second.path) == infos.end())
|
||||||
mustBuild = true;
|
mustBuild = true;
|
||||||
else
|
else
|
||||||
outputs.insert(j->second.path);
|
outputs.insert(j.second.path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
@@ -160,22 +160,22 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
|
|||||||
if (mustBuild) {
|
if (mustBuild) {
|
||||||
willBuild.insert(i2.first);
|
willBuild.insert(i2.first);
|
||||||
todo.insert(drv.inputSrcs.begin(), drv.inputSrcs.end());
|
todo.insert(drv.inputSrcs.begin(), drv.inputSrcs.end());
|
||||||
foreach (DerivationInputs::iterator, j, drv.inputDrvs)
|
for (auto & j : drv.inputDrvs)
|
||||||
todo.insert(makeDrvPathWithOutputs(j->first, j->second));
|
todo.insert(makeDrvPathWithOutputs(j.first, j.second));
|
||||||
} else
|
} else
|
||||||
todoNonDrv.insert(outputs.begin(), outputs.end());
|
todoNonDrv.insert(outputs.begin(), outputs.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (PathSet::iterator, i, todoNonDrv) {
|
for (auto & i : todoNonDrv) {
|
||||||
done.insert(*i);
|
done.insert(i);
|
||||||
SubstitutablePathInfos::iterator info = infos.find(*i);
|
SubstitutablePathInfos::iterator info = infos.find(i);
|
||||||
if (info != infos.end()) {
|
if (info != infos.end()) {
|
||||||
willSubstitute.insert(*i);
|
willSubstitute.insert(i);
|
||||||
downloadSize += info->second.downloadSize;
|
downloadSize += info->second.downloadSize;
|
||||||
narSize += info->second.narSize;
|
narSize += info->second.narSize;
|
||||||
todo.insert(info->second.references.begin(), info->second.references.end());
|
todo.insert(info->second.references.begin(), info->second.references.end());
|
||||||
} else
|
} else
|
||||||
unknown.insert(*i);
|
unknown.insert(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,11 +196,11 @@ static void dfsVisit(StoreAPI & store, const PathSet & paths,
|
|||||||
if (store.isValidPath(path))
|
if (store.isValidPath(path))
|
||||||
store.queryReferences(path, references);
|
store.queryReferences(path, references);
|
||||||
|
|
||||||
foreach (PathSet::iterator, i, references)
|
for (auto & i : references)
|
||||||
/* Don't traverse into paths that don't exist. That can
|
/* Don't traverse into paths that don't exist. That can
|
||||||
happen due to substitutes for non-existent paths. */
|
happen due to substitutes for non-existent paths. */
|
||||||
if (*i != path && paths.find(*i) != paths.end())
|
if (i != path && paths.find(i) != paths.end())
|
||||||
dfsVisit(store, paths, *i, visited, sorted, parents);
|
dfsVisit(store, paths, i, visited, sorted, parents);
|
||||||
|
|
||||||
sorted.push_front(path);
|
sorted.push_front(path);
|
||||||
parents.erase(path);
|
parents.erase(path);
|
||||||
@@ -211,8 +211,8 @@ Paths topoSortPaths(StoreAPI & store, const PathSet & paths)
|
|||||||
{
|
{
|
||||||
Paths sorted;
|
Paths sorted;
|
||||||
PathSet visited, parents;
|
PathSet visited, parents;
|
||||||
foreach (PathSet::const_iterator, i, paths)
|
for (auto & i : paths)
|
||||||
dfsVisit(store, paths, *i, visited, sorted, parents);
|
dfsVisit(store, paths, i, visited, sorted, parents);
|
||||||
return sorted;
|
return sorted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,9 +32,9 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
|
|||||||
PathSet & willBuild, PathSet & willSubstitute, PathSet & unknown,
|
PathSet & willBuild, PathSet & willSubstitute, PathSet & unknown,
|
||||||
unsigned long long & downloadSize, unsigned long long & narSize);
|
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);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,8 +99,8 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa
|
|||||||
|
|
||||||
if (S_ISDIR(st.st_mode)) {
|
if (S_ISDIR(st.st_mode)) {
|
||||||
Strings names = readDirectoryIgnoringInodes(path, inodeHash);
|
Strings names = readDirectoryIgnoringInodes(path, inodeHash);
|
||||||
foreach (Strings::iterator, i, names)
|
for (auto & i : names)
|
||||||
optimisePath_(stats, path + "/" + *i, inodeHash);
|
optimisePath_(stats, path + "/" + i, inodeHash);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,11 +218,11 @@ void LocalStore::optimiseStore(OptimiseStats & stats)
|
|||||||
PathSet paths = queryAllValidPaths();
|
PathSet paths = queryAllValidPaths();
|
||||||
InodeHash inodeHash = loadInodeHash();
|
InodeHash inodeHash = loadInodeHash();
|
||||||
|
|
||||||
foreach (PathSet::iterator, i, paths) {
|
for (auto & i : paths) {
|
||||||
addTempRoot(*i);
|
addTempRoot(i);
|
||||||
if (!isValidPath(*i)) continue; /* path was GC'ed, probably */
|
if (!isValidPath(i)) continue; /* path was GC'ed, probably */
|
||||||
startNest(nest, lvlChatty, format("hashing files in ‘%1%’") % *i);
|
startNest(nest, lvlChatty, format("hashing files in ‘%1%’") % i);
|
||||||
optimisePath_(stats, *i, inodeHash);
|
optimisePath_(stats, i, inodeHash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-14
@@ -60,7 +60,7 @@ bool lockFile(int fd, LockType lockType, bool wait)
|
|||||||
while (fcntl(fd, F_SETLK, &lock) != 0) {
|
while (fcntl(fd, F_SETLK, &lock) != 0) {
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
if (errno == EACCES || errno == EAGAIN) return false;
|
if (errno == EACCES || errno == EAGAIN) return false;
|
||||||
if (errno != EINTR)
|
if (errno != EINTR)
|
||||||
throw SysError(format("acquiring/releasing lock"));
|
throw SysError(format("acquiring/releasing lock"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,7 +94,7 @@ bool PathLocks::lockPaths(const PathSet & _paths,
|
|||||||
const string & waitMsg, bool wait)
|
const string & waitMsg, bool wait)
|
||||||
{
|
{
|
||||||
assert(fds.empty());
|
assert(fds.empty());
|
||||||
|
|
||||||
/* Note that `fds' is built incrementally so that the destructor
|
/* Note that `fds' is built incrementally so that the destructor
|
||||||
will only release those locks that we have already acquired. */
|
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. */
|
the same order, thus preventing deadlocks. */
|
||||||
Paths paths(_paths.begin(), _paths.end());
|
Paths paths(_paths.begin(), _paths.end());
|
||||||
paths.sort();
|
paths.sort();
|
||||||
|
|
||||||
/* Acquire the lock for each path. */
|
/* Acquire the lock for each path. */
|
||||||
foreach (Paths::iterator, i, paths) {
|
for (auto & path : paths) {
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
Path path = *i;
|
|
||||||
Path lockPath = path + ".lock";
|
Path lockPath = path + ".lock";
|
||||||
|
|
||||||
debug(format("locking path ‘%1%’") % path);
|
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");
|
throw Error("deadlock: trying to re-acquire self-held lock");
|
||||||
|
|
||||||
AutoCloseFD fd;
|
AutoCloseFD fd;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
||||||
/* Open/create the lock file. */
|
/* Open/create the lock file. */
|
||||||
fd = openLockFile(lockPath, true);
|
fd = openLockFile(lockPath, true);
|
||||||
|
|
||||||
/* Acquire an exclusive lock. */
|
/* Acquire an exclusive lock. */
|
||||||
if (!lockFile(fd, ltWrite, false)) {
|
if (!lockFile(fd, ltWrite, false)) {
|
||||||
@@ -168,15 +167,15 @@ PathLocks::~PathLocks()
|
|||||||
|
|
||||||
void PathLocks::unlock()
|
void PathLocks::unlock()
|
||||||
{
|
{
|
||||||
foreach (list<FDPair>::iterator, i, fds) {
|
for (auto & i : fds) {
|
||||||
if (deletePaths) deleteLockFile(i->second, i->first);
|
if (deletePaths) deleteLockFile(i.second, i.first);
|
||||||
|
|
||||||
lockedPaths.erase(i->second);
|
lockedPaths.erase(i.second);
|
||||||
if (close(i->first) == -1)
|
if (close(i.first) == -1)
|
||||||
printMsg(lvlError,
|
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();
|
fds.clear();
|
||||||
@@ -195,5 +194,5 @@ bool pathIsLockedByMe(const Path & path)
|
|||||||
return lockedPaths.find(lockPath) != lockedPaths.end();
|
return lockedPaths.find(lockPath) != lockedPaths.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-10
@@ -13,7 +13,7 @@ namespace nix {
|
|||||||
static unsigned int refLength = 32; /* characters */
|
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)
|
StringSet & hashes, StringSet & seen)
|
||||||
{
|
{
|
||||||
static bool initialised = false;
|
static bool initialised = false;
|
||||||
@@ -24,7 +24,7 @@ static void search(const unsigned char * s, unsigned int len,
|
|||||||
isBase32[(unsigned char) base32Chars[i]] = true;
|
isBase32[(unsigned char) base32Chars[i]] = true;
|
||||||
initialised = true;
|
initialised = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i + refLength <= len; ) {
|
for (unsigned int i = 0; i + refLength <= len; ) {
|
||||||
int j;
|
int j;
|
||||||
bool match = true;
|
bool match = true;
|
||||||
@@ -56,7 +56,7 @@ struct RefScanSink : Sink
|
|||||||
string tail;
|
string tail;
|
||||||
|
|
||||||
RefScanSink() : hashSink(htSHA256) { }
|
RefScanSink() : hashSink(htSHA256) { }
|
||||||
|
|
||||||
void operator () (const unsigned char * data, size_t len);
|
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
|
/* For efficiency (and a higher hit rate), just search for the
|
||||||
hash part of the file name. (This assumes that all references
|
hash part of the file name. (This assumes that all references
|
||||||
have the form `HASH-bla'). */
|
have the form `HASH-bla'). */
|
||||||
foreach (PathSet::const_iterator, i, refs) {
|
for (auto & i : refs) {
|
||||||
string baseName = baseNameOf(*i);
|
string baseName = baseNameOf(i);
|
||||||
string::size_type pos = baseName.find('-');
|
string::size_type pos = baseName.find('-');
|
||||||
if (pos == string::npos)
|
if (pos == string::npos)
|
||||||
throw Error(format("bad reference ‘%1%’") % *i);
|
throw Error(format("bad reference ‘%1%’") % i);
|
||||||
string s = string(baseName, 0, pos);
|
string s = string(baseName, 0, pos);
|
||||||
assert(s.size() == refLength);
|
assert(s.size() == refLength);
|
||||||
assert(backMap.find(s) == backMap.end());
|
assert(backMap.find(s) == backMap.end());
|
||||||
// parseHash(htSHA256, s);
|
// parseHash(htSHA256, s);
|
||||||
sink.hashes.insert(s);
|
sink.hashes.insert(s);
|
||||||
backMap[s] = *i;
|
backMap[s] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Look for the hashes in the NAR dump of the path. */
|
/* 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. */
|
/* Map the hashes found back to their store paths. */
|
||||||
PathSet found;
|
PathSet found;
|
||||||
foreach (StringSet::iterator, i, sink.seen) {
|
for (auto & i : sink.seen) {
|
||||||
std::map<string, Path>::iterator j;
|
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);
|
found.insert(j->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
hash = sink.hashSink.finish();
|
hash = sink.hashSink.finish();
|
||||||
|
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+87
-111
@@ -5,6 +5,7 @@
|
|||||||
#include "archive.hh"
|
#include "archive.hh"
|
||||||
#include "affinity.hh"
|
#include "affinity.hh"
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
|
#include "derivations.hh"
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@@ -31,7 +32,7 @@ Path readStorePath(Source & from)
|
|||||||
template<class T> T readStorePaths(Source & from)
|
template<class T> T readStorePaths(Source & from)
|
||||||
{
|
{
|
||||||
T paths = readStrings<T>(from);
|
T paths = readStrings<T>(from);
|
||||||
foreach (typename T::iterator, i, paths) assertStorePath(*i);
|
for (auto & i : paths) assertStorePath(i);
|
||||||
return paths;
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +64,7 @@ void RemoteStore::openConnection(bool reserveSpace)
|
|||||||
|
|
||||||
/* Send the magic greeting, check for the reply. */
|
/* Send the magic greeting, check for the reply. */
|
||||||
try {
|
try {
|
||||||
writeInt(WORKER_MAGIC_1, to);
|
to << WORKER_MAGIC_1;
|
||||||
to.flush();
|
to.flush();
|
||||||
unsigned int magic = readInt(from);
|
unsigned int magic = readInt(from);
|
||||||
if (magic != WORKER_MAGIC_2) throw Error("protocol mismatch");
|
if (magic != WORKER_MAGIC_2) throw Error("protocol mismatch");
|
||||||
@@ -71,19 +72,18 @@ void RemoteStore::openConnection(bool reserveSpace)
|
|||||||
daemonVersion = readInt(from);
|
daemonVersion = readInt(from);
|
||||||
if (GET_PROTOCOL_MAJOR(daemonVersion) != GET_PROTOCOL_MAJOR(PROTOCOL_VERSION))
|
if (GET_PROTOCOL_MAJOR(daemonVersion) != GET_PROTOCOL_MAJOR(PROTOCOL_VERSION))
|
||||||
throw Error("Nix daemon protocol version not supported");
|
throw Error("Nix daemon protocol version not supported");
|
||||||
writeInt(PROTOCOL_VERSION, to);
|
to << PROTOCOL_VERSION;
|
||||||
|
|
||||||
if (GET_PROTOCOL_MINOR(daemonVersion) >= 14) {
|
if (GET_PROTOCOL_MINOR(daemonVersion) >= 14) {
|
||||||
int cpu = settings.lockCPU ? lockToCurrentCPU() : -1;
|
int cpu = settings.lockCPU ? lockToCurrentCPU() : -1;
|
||||||
if (cpu != -1) {
|
if (cpu != -1)
|
||||||
writeInt(1, to);
|
to << 1 << cpu;
|
||||||
writeInt(cpu, to);
|
else
|
||||||
} else
|
to << 0;
|
||||||
writeInt(0, to);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GET_PROTOCOL_MINOR(daemonVersion) >= 11)
|
if (GET_PROTOCOL_MINOR(daemonVersion) >= 11)
|
||||||
writeInt(reserveSpace, to);
|
to << reserveSpace;
|
||||||
|
|
||||||
processStderr();
|
processStderr();
|
||||||
}
|
}
|
||||||
@@ -141,35 +141,31 @@ RemoteStore::~RemoteStore()
|
|||||||
|
|
||||||
void RemoteStore::setOptions()
|
void RemoteStore::setOptions()
|
||||||
{
|
{
|
||||||
writeInt(wopSetOptions, to);
|
to << wopSetOptions
|
||||||
|
<< settings.keepFailed
|
||||||
writeInt(settings.keepFailed, to);
|
<< settings.keepGoing
|
||||||
writeInt(settings.keepGoing, to);
|
<< settings.tryFallback
|
||||||
writeInt(settings.tryFallback, to);
|
<< verbosity
|
||||||
writeInt(verbosity, to);
|
<< settings.maxBuildJobs
|
||||||
writeInt(settings.maxBuildJobs, to);
|
<< settings.maxSilentTime;
|
||||||
writeInt(settings.maxSilentTime, to);
|
|
||||||
if (GET_PROTOCOL_MINOR(daemonVersion) >= 2)
|
if (GET_PROTOCOL_MINOR(daemonVersion) >= 2)
|
||||||
writeInt(settings.useBuildHook, to);
|
to << settings.useBuildHook;
|
||||||
if (GET_PROTOCOL_MINOR(daemonVersion) >= 4) {
|
if (GET_PROTOCOL_MINOR(daemonVersion) >= 4)
|
||||||
writeInt(settings.buildVerbosity, to);
|
to << settings.buildVerbosity
|
||||||
writeInt(logType, to);
|
<< logType
|
||||||
writeInt(settings.printBuildTrace, to);
|
<< settings.printBuildTrace;
|
||||||
}
|
|
||||||
if (GET_PROTOCOL_MINOR(daemonVersion) >= 6)
|
if (GET_PROTOCOL_MINOR(daemonVersion) >= 6)
|
||||||
writeInt(settings.buildCores, to);
|
to << settings.buildCores;
|
||||||
if (GET_PROTOCOL_MINOR(daemonVersion) >= 10)
|
if (GET_PROTOCOL_MINOR(daemonVersion) >= 10)
|
||||||
writeInt(settings.useSubstitutes, to);
|
to << settings.useSubstitutes;
|
||||||
|
|
||||||
if (GET_PROTOCOL_MINOR(daemonVersion) >= 12) {
|
if (GET_PROTOCOL_MINOR(daemonVersion) >= 12) {
|
||||||
Settings::SettingsMap overrides = settings.getOverrides();
|
Settings::SettingsMap overrides = settings.getOverrides();
|
||||||
if (overrides["ssh-auth-sock"] == "")
|
if (overrides["ssh-auth-sock"] == "")
|
||||||
overrides["ssh-auth-sock"] = getEnv("SSH_AUTH_SOCK");
|
overrides["ssh-auth-sock"] = getEnv("SSH_AUTH_SOCK");
|
||||||
writeInt(overrides.size(), to);
|
to << overrides.size();
|
||||||
foreach (Settings::SettingsMap::iterator, i, overrides) {
|
for (auto & i : overrides)
|
||||||
writeString(i->first, to);
|
to << i.first << i.second;
|
||||||
writeString(i->second, to);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
processStderr();
|
processStderr();
|
||||||
@@ -179,8 +175,7 @@ void RemoteStore::setOptions()
|
|||||||
bool RemoteStore::isValidPath(const Path & path)
|
bool RemoteStore::isValidPath(const Path & path)
|
||||||
{
|
{
|
||||||
openConnection();
|
openConnection();
|
||||||
writeInt(wopIsValidPath, to);
|
to << wopIsValidPath << path;
|
||||||
writeString(path, to);
|
|
||||||
processStderr();
|
processStderr();
|
||||||
unsigned int reply = readInt(from);
|
unsigned int reply = readInt(from);
|
||||||
return reply != 0;
|
return reply != 0;
|
||||||
@@ -192,12 +187,11 @@ PathSet RemoteStore::queryValidPaths(const PathSet & paths)
|
|||||||
openConnection();
|
openConnection();
|
||||||
if (GET_PROTOCOL_MINOR(daemonVersion) < 12) {
|
if (GET_PROTOCOL_MINOR(daemonVersion) < 12) {
|
||||||
PathSet res;
|
PathSet res;
|
||||||
foreach (PathSet::const_iterator, i, paths)
|
for (auto & i : paths)
|
||||||
if (isValidPath(*i)) res.insert(*i);
|
if (isValidPath(i)) res.insert(i);
|
||||||
return res;
|
return res;
|
||||||
} else {
|
} else {
|
||||||
writeInt(wopQueryValidPaths, to);
|
to << wopQueryValidPaths << paths;
|
||||||
writeStrings(paths, to);
|
|
||||||
processStderr();
|
processStderr();
|
||||||
return readStorePaths<PathSet>(from);
|
return readStorePaths<PathSet>(from);
|
||||||
}
|
}
|
||||||
@@ -207,7 +201,7 @@ PathSet RemoteStore::queryValidPaths(const PathSet & paths)
|
|||||||
PathSet RemoteStore::queryAllValidPaths()
|
PathSet RemoteStore::queryAllValidPaths()
|
||||||
{
|
{
|
||||||
openConnection();
|
openConnection();
|
||||||
writeInt(wopQueryAllValidPaths, to);
|
to << wopQueryAllValidPaths;
|
||||||
processStderr();
|
processStderr();
|
||||||
return readStorePaths<PathSet>(from);
|
return readStorePaths<PathSet>(from);
|
||||||
}
|
}
|
||||||
@@ -218,16 +212,14 @@ PathSet RemoteStore::querySubstitutablePaths(const PathSet & paths)
|
|||||||
openConnection();
|
openConnection();
|
||||||
if (GET_PROTOCOL_MINOR(daemonVersion) < 12) {
|
if (GET_PROTOCOL_MINOR(daemonVersion) < 12) {
|
||||||
PathSet res;
|
PathSet res;
|
||||||
foreach (PathSet::const_iterator, i, paths) {
|
for (auto & i : paths) {
|
||||||
writeInt(wopHasSubstitutes, to);
|
to << wopHasSubstitutes << i;
|
||||||
writeString(*i, to);
|
|
||||||
processStderr();
|
processStderr();
|
||||||
if (readInt(from)) res.insert(*i);
|
if (readInt(from)) res.insert(i);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
} else {
|
} else {
|
||||||
writeInt(wopQuerySubstitutablePaths, to);
|
to << wopQuerySubstitutablePaths << paths;
|
||||||
writeStrings(paths, to);
|
|
||||||
processStderr();
|
processStderr();
|
||||||
return readStorePaths<PathSet>(from);
|
return readStorePaths<PathSet>(from);
|
||||||
}
|
}
|
||||||
@@ -245,10 +237,9 @@ void RemoteStore::querySubstitutablePathInfos(const PathSet & paths,
|
|||||||
|
|
||||||
if (GET_PROTOCOL_MINOR(daemonVersion) < 12) {
|
if (GET_PROTOCOL_MINOR(daemonVersion) < 12) {
|
||||||
|
|
||||||
foreach (PathSet::const_iterator, i, paths) {
|
for (auto & i : paths) {
|
||||||
SubstitutablePathInfo info;
|
SubstitutablePathInfo info;
|
||||||
writeInt(wopQuerySubstitutablePathInfo, to);
|
to << wopQuerySubstitutablePathInfo << i;
|
||||||
writeString(*i, to);
|
|
||||||
processStderr();
|
processStderr();
|
||||||
unsigned int reply = readInt(from);
|
unsigned int reply = readInt(from);
|
||||||
if (reply == 0) continue;
|
if (reply == 0) continue;
|
||||||
@@ -257,13 +248,12 @@ void RemoteStore::querySubstitutablePathInfos(const PathSet & paths,
|
|||||||
info.references = readStorePaths<PathSet>(from);
|
info.references = readStorePaths<PathSet>(from);
|
||||||
info.downloadSize = readLongLong(from);
|
info.downloadSize = readLongLong(from);
|
||||||
info.narSize = GET_PROTOCOL_MINOR(daemonVersion) >= 7 ? readLongLong(from) : 0;
|
info.narSize = GET_PROTOCOL_MINOR(daemonVersion) >= 7 ? readLongLong(from) : 0;
|
||||||
infos[*i] = info;
|
infos[i] = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
writeInt(wopQuerySubstitutablePathInfos, to);
|
to << wopQuerySubstitutablePathInfos << paths;
|
||||||
writeStrings(paths, to);
|
|
||||||
processStderr();
|
processStderr();
|
||||||
unsigned int count = readInt(from);
|
unsigned int count = readInt(from);
|
||||||
for (unsigned int n = 0; n < count; n++) {
|
for (unsigned int n = 0; n < count; n++) {
|
||||||
@@ -283,8 +273,7 @@ void RemoteStore::querySubstitutablePathInfos(const PathSet & paths,
|
|||||||
ValidPathInfo RemoteStore::queryPathInfo(const Path & path)
|
ValidPathInfo RemoteStore::queryPathInfo(const Path & path)
|
||||||
{
|
{
|
||||||
openConnection();
|
openConnection();
|
||||||
writeInt(wopQueryPathInfo, to);
|
to << wopQueryPathInfo << path;
|
||||||
writeString(path, to);
|
|
||||||
processStderr();
|
processStderr();
|
||||||
ValidPathInfo info;
|
ValidPathInfo info;
|
||||||
info.path = path;
|
info.path = path;
|
||||||
@@ -301,8 +290,7 @@ ValidPathInfo RemoteStore::queryPathInfo(const Path & path)
|
|||||||
Hash RemoteStore::queryPathHash(const Path & path)
|
Hash RemoteStore::queryPathHash(const Path & path)
|
||||||
{
|
{
|
||||||
openConnection();
|
openConnection();
|
||||||
writeInt(wopQueryPathHash, to);
|
to << wopQueryPathHash << path;
|
||||||
writeString(path, to);
|
|
||||||
processStderr();
|
processStderr();
|
||||||
string hash = readString(from);
|
string hash = readString(from);
|
||||||
return parseHash(htSHA256, hash);
|
return parseHash(htSHA256, hash);
|
||||||
@@ -313,8 +301,7 @@ void RemoteStore::queryReferences(const Path & path,
|
|||||||
PathSet & references)
|
PathSet & references)
|
||||||
{
|
{
|
||||||
openConnection();
|
openConnection();
|
||||||
writeInt(wopQueryReferences, to);
|
to << wopQueryReferences << path;
|
||||||
writeString(path, to);
|
|
||||||
processStderr();
|
processStderr();
|
||||||
PathSet references2 = readStorePaths<PathSet>(from);
|
PathSet references2 = readStorePaths<PathSet>(from);
|
||||||
references.insert(references2.begin(), references2.end());
|
references.insert(references2.begin(), references2.end());
|
||||||
@@ -325,8 +312,7 @@ void RemoteStore::queryReferrers(const Path & path,
|
|||||||
PathSet & referrers)
|
PathSet & referrers)
|
||||||
{
|
{
|
||||||
openConnection();
|
openConnection();
|
||||||
writeInt(wopQueryReferrers, to);
|
to << wopQueryReferrers << path;
|
||||||
writeString(path, to);
|
|
||||||
processStderr();
|
processStderr();
|
||||||
PathSet referrers2 = readStorePaths<PathSet>(from);
|
PathSet referrers2 = readStorePaths<PathSet>(from);
|
||||||
referrers.insert(referrers2.begin(), referrers2.end());
|
referrers.insert(referrers2.begin(), referrers2.end());
|
||||||
@@ -336,8 +322,7 @@ void RemoteStore::queryReferrers(const Path & path,
|
|||||||
Path RemoteStore::queryDeriver(const Path & path)
|
Path RemoteStore::queryDeriver(const Path & path)
|
||||||
{
|
{
|
||||||
openConnection();
|
openConnection();
|
||||||
writeInt(wopQueryDeriver, to);
|
to << wopQueryDeriver << path;
|
||||||
writeString(path, to);
|
|
||||||
processStderr();
|
processStderr();
|
||||||
Path drvPath = readString(from);
|
Path drvPath = readString(from);
|
||||||
if (drvPath != "") assertStorePath(drvPath);
|
if (drvPath != "") assertStorePath(drvPath);
|
||||||
@@ -348,8 +333,7 @@ Path RemoteStore::queryDeriver(const Path & path)
|
|||||||
PathSet RemoteStore::queryValidDerivers(const Path & path)
|
PathSet RemoteStore::queryValidDerivers(const Path & path)
|
||||||
{
|
{
|
||||||
openConnection();
|
openConnection();
|
||||||
writeInt(wopQueryValidDerivers, to);
|
to << wopQueryValidDerivers << path;
|
||||||
writeString(path, to);
|
|
||||||
processStderr();
|
processStderr();
|
||||||
return readStorePaths<PathSet>(from);
|
return readStorePaths<PathSet>(from);
|
||||||
}
|
}
|
||||||
@@ -358,8 +342,7 @@ PathSet RemoteStore::queryValidDerivers(const Path & path)
|
|||||||
PathSet RemoteStore::queryDerivationOutputs(const Path & path)
|
PathSet RemoteStore::queryDerivationOutputs(const Path & path)
|
||||||
{
|
{
|
||||||
openConnection();
|
openConnection();
|
||||||
writeInt(wopQueryDerivationOutputs, to);
|
to << wopQueryDerivationOutputs << path;
|
||||||
writeString(path, to);
|
|
||||||
processStderr();
|
processStderr();
|
||||||
return readStorePaths<PathSet>(from);
|
return readStorePaths<PathSet>(from);
|
||||||
}
|
}
|
||||||
@@ -368,8 +351,7 @@ PathSet RemoteStore::queryDerivationOutputs(const Path & path)
|
|||||||
PathSet RemoteStore::queryDerivationOutputNames(const Path & path)
|
PathSet RemoteStore::queryDerivationOutputNames(const Path & path)
|
||||||
{
|
{
|
||||||
openConnection();
|
openConnection();
|
||||||
writeInt(wopQueryDerivationOutputNames, to);
|
to << wopQueryDerivationOutputNames << path;
|
||||||
writeString(path, to);
|
|
||||||
processStderr();
|
processStderr();
|
||||||
return readStrings<PathSet>(from);
|
return readStrings<PathSet>(from);
|
||||||
}
|
}
|
||||||
@@ -378,8 +360,7 @@ PathSet RemoteStore::queryDerivationOutputNames(const Path & path)
|
|||||||
Path RemoteStore::queryPathFromHashPart(const string & hashPart)
|
Path RemoteStore::queryPathFromHashPart(const string & hashPart)
|
||||||
{
|
{
|
||||||
openConnection();
|
openConnection();
|
||||||
writeInt(wopQueryPathFromHashPart, to);
|
to << wopQueryPathFromHashPart << hashPart;
|
||||||
writeString(hashPart, to);
|
|
||||||
processStderr();
|
processStderr();
|
||||||
Path path = readString(from);
|
Path path = readString(from);
|
||||||
if (!path.empty()) assertStorePath(path);
|
if (!path.empty()) assertStorePath(path);
|
||||||
@@ -396,12 +377,10 @@ Path RemoteStore::addToStore(const string & name, const Path & _srcPath,
|
|||||||
|
|
||||||
Path srcPath(absPath(_srcPath));
|
Path srcPath(absPath(_srcPath));
|
||||||
|
|
||||||
writeInt(wopAddToStore, to);
|
to << wopAddToStore << name
|
||||||
writeString(name, to);
|
<< ((hashAlgo == htSHA256 && recursive) ? 0 : 1) /* backwards compatibility hack */
|
||||||
/* backwards compatibility hack */
|
<< (recursive ? 1 : 0)
|
||||||
writeInt((hashAlgo == htSHA256 && recursive) ? 0 : 1, to);
|
<< printHashType(hashAlgo);
|
||||||
writeInt(recursive ? 1 : 0, to);
|
|
||||||
writeString(printHashType(hashAlgo), to);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
to.written = 0;
|
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");
|
if (repair) throw Error("repairing is not supported when building through the Nix daemon");
|
||||||
|
|
||||||
openConnection();
|
openConnection();
|
||||||
writeInt(wopAddTextToStore, to);
|
to << wopAddTextToStore << name << s << references;
|
||||||
writeString(name, to);
|
|
||||||
writeString(s, to);
|
|
||||||
writeStrings(references, to);
|
|
||||||
|
|
||||||
processStderr();
|
processStderr();
|
||||||
return readStorePath(from);
|
return readStorePath(from);
|
||||||
@@ -443,9 +419,7 @@ void RemoteStore::exportPath(const Path & path, bool sign,
|
|||||||
Sink & sink)
|
Sink & sink)
|
||||||
{
|
{
|
||||||
openConnection();
|
openConnection();
|
||||||
writeInt(wopExportPath, to);
|
to << wopExportPath << path << (sign ? 1 : 0);
|
||||||
writeString(path, to);
|
|
||||||
writeInt(sign ? 1 : 0, to);
|
|
||||||
processStderr(&sink); /* sink receives the actual data */
|
processStderr(&sink); /* sink receives the actual data */
|
||||||
readInt(from);
|
readInt(from);
|
||||||
}
|
}
|
||||||
@@ -454,7 +428,7 @@ void RemoteStore::exportPath(const Path & path, bool sign,
|
|||||||
Paths RemoteStore::importPaths(bool requireSignature, Source & source)
|
Paths RemoteStore::importPaths(bool requireSignature, Source & source)
|
||||||
{
|
{
|
||||||
openConnection();
|
openConnection();
|
||||||
writeInt(wopImportPaths, to);
|
to << wopImportPaths;
|
||||||
/* We ignore requireSignature, since the worker forces it to true
|
/* We ignore requireSignature, since the worker forces it to true
|
||||||
anyway. */
|
anyway. */
|
||||||
processStderr(0, &source);
|
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");
|
if (buildMode != bmNormal) throw Error("repairing or checking is not supported when building through the Nix daemon");
|
||||||
openConnection();
|
openConnection();
|
||||||
writeInt(wopBuildPaths, to);
|
to << wopBuildPaths;
|
||||||
if (GET_PROTOCOL_MINOR(daemonVersion) >= 13)
|
if (GET_PROTOCOL_MINOR(daemonVersion) >= 13)
|
||||||
writeStrings(drvPaths, to);
|
to << drvPaths;
|
||||||
else {
|
else {
|
||||||
/* For backwards compatibility with old daemons, strip output
|
/* For backwards compatibility with old daemons, strip output
|
||||||
identifiers. */
|
identifiers. */
|
||||||
PathSet drvPaths2;
|
PathSet drvPaths2;
|
||||||
foreach (PathSet::const_iterator, i, drvPaths)
|
for (auto & i : drvPaths)
|
||||||
drvPaths2.insert(string(*i, 0, i->find('!')));
|
drvPaths2.insert(string(i, 0, i.find('!')));
|
||||||
writeStrings(drvPaths2, to);
|
to << drvPaths2;
|
||||||
}
|
}
|
||||||
processStderr();
|
processStderr();
|
||||||
readInt(from);
|
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)
|
void RemoteStore::ensurePath(const Path & path)
|
||||||
{
|
{
|
||||||
openConnection();
|
openConnection();
|
||||||
writeInt(wopEnsurePath, to);
|
to << wopEnsurePath << path;
|
||||||
writeString(path, to);
|
|
||||||
processStderr();
|
processStderr();
|
||||||
readInt(from);
|
readInt(from);
|
||||||
}
|
}
|
||||||
@@ -495,8 +482,7 @@ void RemoteStore::ensurePath(const Path & path)
|
|||||||
void RemoteStore::addTempRoot(const Path & path)
|
void RemoteStore::addTempRoot(const Path & path)
|
||||||
{
|
{
|
||||||
openConnection();
|
openConnection();
|
||||||
writeInt(wopAddTempRoot, to);
|
to << wopAddTempRoot << path;
|
||||||
writeString(path, to);
|
|
||||||
processStderr();
|
processStderr();
|
||||||
readInt(from);
|
readInt(from);
|
||||||
}
|
}
|
||||||
@@ -505,8 +491,7 @@ void RemoteStore::addTempRoot(const Path & path)
|
|||||||
void RemoteStore::addIndirectRoot(const Path & path)
|
void RemoteStore::addIndirectRoot(const Path & path)
|
||||||
{
|
{
|
||||||
openConnection();
|
openConnection();
|
||||||
writeInt(wopAddIndirectRoot, to);
|
to << wopAddIndirectRoot << path;
|
||||||
writeString(path, to);
|
|
||||||
processStderr();
|
processStderr();
|
||||||
readInt(from);
|
readInt(from);
|
||||||
}
|
}
|
||||||
@@ -515,7 +500,7 @@ void RemoteStore::addIndirectRoot(const Path & path)
|
|||||||
void RemoteStore::syncWithGC()
|
void RemoteStore::syncWithGC()
|
||||||
{
|
{
|
||||||
openConnection();
|
openConnection();
|
||||||
writeInt(wopSyncWithGC, to);
|
to << wopSyncWithGC;
|
||||||
processStderr();
|
processStderr();
|
||||||
readInt(from);
|
readInt(from);
|
||||||
}
|
}
|
||||||
@@ -524,7 +509,7 @@ void RemoteStore::syncWithGC()
|
|||||||
Roots RemoteStore::findRoots()
|
Roots RemoteStore::findRoots()
|
||||||
{
|
{
|
||||||
openConnection();
|
openConnection();
|
||||||
writeInt(wopFindRoots, to);
|
to << wopFindRoots;
|
||||||
processStderr();
|
processStderr();
|
||||||
unsigned int count = readInt(from);
|
unsigned int count = readInt(from);
|
||||||
Roots result;
|
Roots result;
|
||||||
@@ -541,17 +526,11 @@ void RemoteStore::collectGarbage(const GCOptions & options, GCResults & results)
|
|||||||
{
|
{
|
||||||
openConnection(false);
|
openConnection(false);
|
||||||
|
|
||||||
writeInt(wopCollectGarbage, to);
|
to << wopCollectGarbage << options.action << options.pathsToDelete << options.ignoreLiveness
|
||||||
writeInt(options.action, to);
|
<< options.maxFreed << 0;
|
||||||
writeStrings(options.pathsToDelete, to);
|
if (GET_PROTOCOL_MINOR(daemonVersion) >= 5)
|
||||||
writeInt(options.ignoreLiveness, to);
|
|
||||||
writeLongLong(options.maxFreed, to);
|
|
||||||
writeInt(0, to);
|
|
||||||
if (GET_PROTOCOL_MINOR(daemonVersion) >= 5) {
|
|
||||||
/* removed options */
|
/* removed options */
|
||||||
writeInt(0, to);
|
to << 0 << 0;
|
||||||
writeInt(0, to);
|
|
||||||
}
|
|
||||||
|
|
||||||
processStderr();
|
processStderr();
|
||||||
|
|
||||||
@@ -564,7 +543,7 @@ void RemoteStore::collectGarbage(const GCOptions & options, GCResults & results)
|
|||||||
PathSet RemoteStore::queryFailedPaths()
|
PathSet RemoteStore::queryFailedPaths()
|
||||||
{
|
{
|
||||||
openConnection();
|
openConnection();
|
||||||
writeInt(wopQueryFailedPaths, to);
|
to << wopQueryFailedPaths;
|
||||||
processStderr();
|
processStderr();
|
||||||
return readStorePaths<PathSet>(from);
|
return readStorePaths<PathSet>(from);
|
||||||
}
|
}
|
||||||
@@ -573,8 +552,7 @@ PathSet RemoteStore::queryFailedPaths()
|
|||||||
void RemoteStore::clearFailedPaths(const PathSet & paths)
|
void RemoteStore::clearFailedPaths(const PathSet & paths)
|
||||||
{
|
{
|
||||||
openConnection();
|
openConnection();
|
||||||
writeInt(wopClearFailedPaths, to);
|
to << wopClearFailedPaths << paths;
|
||||||
writeStrings(paths, to);
|
|
||||||
processStderr();
|
processStderr();
|
||||||
readInt(from);
|
readInt(from);
|
||||||
}
|
}
|
||||||
@@ -582,7 +560,7 @@ void RemoteStore::clearFailedPaths(const PathSet & paths)
|
|||||||
void RemoteStore::optimiseStore()
|
void RemoteStore::optimiseStore()
|
||||||
{
|
{
|
||||||
openConnection();
|
openConnection();
|
||||||
writeInt(wopOptimiseStore, to);
|
to << wopOptimiseStore;
|
||||||
processStderr();
|
processStderr();
|
||||||
readInt(from);
|
readInt(from);
|
||||||
}
|
}
|
||||||
@@ -590,9 +568,7 @@ void RemoteStore::optimiseStore()
|
|||||||
bool RemoteStore::verifyStore(bool checkContents, bool repair)
|
bool RemoteStore::verifyStore(bool checkContents, bool repair)
|
||||||
{
|
{
|
||||||
openConnection();
|
openConnection();
|
||||||
writeInt(wopVerifyStore, to);
|
to << wopVerifyStore << checkContents << repair;
|
||||||
writeInt(checkContents, to);
|
|
||||||
writeInt(repair, to);
|
|
||||||
processStderr();
|
processStderr();
|
||||||
return readInt(from) != 0;
|
return readInt(from) != 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,6 +67,9 @@ public:
|
|||||||
|
|
||||||
void buildPaths(const PathSet & paths, BuildMode buildMode);
|
void buildPaths(const PathSet & paths, BuildMode buildMode);
|
||||||
|
|
||||||
|
BuildResult buildDerivation(const Path & drvPath, const BasicDerivation & drv,
|
||||||
|
BuildMode buildMode) override;
|
||||||
|
|
||||||
void ensurePath(const Path & path);
|
void ensurePath(const Path & path);
|
||||||
|
|
||||||
void addTempRoot(const Path & path);
|
void addTempRoot(const Path & path);
|
||||||
|
|||||||
+24
-34
@@ -2,20 +2,10 @@
|
|||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
|
|
||||||
#include <climits>
|
|
||||||
|
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
GCOptions::GCOptions()
|
|
||||||
{
|
|
||||||
action = gcDeleteDead;
|
|
||||||
ignoreLiveness = false;
|
|
||||||
maxFreed = ULLONG_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool isInStore(const Path & path)
|
bool isInStore(const Path & path)
|
||||||
{
|
{
|
||||||
return isInDir(path, settings.nixStore);
|
return isInDir(path, settings.nixStore);
|
||||||
@@ -82,14 +72,14 @@ void checkStoreName(const string & name)
|
|||||||
reasons (e.g., "." and ".."). */
|
reasons (e.g., "." and ".."). */
|
||||||
if (string(name, 0, 1) == ".")
|
if (string(name, 0, 1) == ".")
|
||||||
throw Error(format("illegal name: ‘%1%’") % name);
|
throw Error(format("illegal name: ‘%1%’") % name);
|
||||||
foreach (string::const_iterator, i, name)
|
for (auto & i : name)
|
||||||
if (!((*i >= 'A' && *i <= 'Z') ||
|
if (!((i >= 'A' && i <= 'Z') ||
|
||||||
(*i >= 'a' && *i <= 'z') ||
|
(i >= 'a' && i <= 'z') ||
|
||||||
(*i >= '0' && *i <= '9') ||
|
(i >= '0' && i <= '9') ||
|
||||||
validChars.find(*i) != string::npos))
|
validChars.find(i) != string::npos))
|
||||||
{
|
{
|
||||||
throw Error(format("invalid character ‘%1%’ in name ‘%2%’")
|
throw Error(format("invalid character ‘%1%’ in name ‘%2%’")
|
||||||
% *i % name);
|
% i % name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,22 +91,22 @@ void checkStoreName(const string & name)
|
|||||||
where
|
where
|
||||||
|
|
||||||
<store> = the location of the Nix store, usually /nix/store
|
<store> = the location of the Nix store, usually /nix/store
|
||||||
|
|
||||||
<name> = a human readable name for the path, typically obtained
|
<name> = a human readable name for the path, typically obtained
|
||||||
from the name attribute of the derivation, or the name of the
|
from the name attribute of the derivation, or the name of the
|
||||||
source file from which the store path is created. For derivation
|
source file from which the store path is created. For derivation
|
||||||
outputs other than the default "out" output, the string "-<id>"
|
outputs other than the default "out" output, the string "-<id>"
|
||||||
is suffixed to <name>.
|
is suffixed to <name>.
|
||||||
|
|
||||||
<h> = base-32 representation of the first 160 bits of a SHA-256
|
<h> = base-32 representation of the first 160 bits of a SHA-256
|
||||||
hash of <s>; the hash part of the store name
|
hash of <s>; the hash part of the store name
|
||||||
|
|
||||||
<s> = the string "<type>:sha256:<h2>:<store>:<name>";
|
<s> = the string "<type>:sha256:<h2>:<store>:<name>";
|
||||||
note that it includes the location of the store as well as the
|
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
|
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
|
in the hash (e.g. you won't get /nix/store/<h>-name1 and
|
||||||
/nix/store/<h>-name2 with equal hash parts).
|
/nix/store/<h>-name2 with equal hash parts).
|
||||||
|
|
||||||
<type> = one of:
|
<type> = one of:
|
||||||
"text:<r1>:<r2>:...<rN>"
|
"text:<r1>:<r2>:...<rN>"
|
||||||
for plain text files written to the store using
|
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
|
hacky, but we can't put them in `s' since that would be
|
||||||
ambiguous. */
|
ambiguous. */
|
||||||
string type = "text";
|
string type = "text";
|
||||||
foreach (PathSet::const_iterator, i, references) {
|
for (auto & i : references) {
|
||||||
type += ":";
|
type += ":";
|
||||||
type += *i;
|
type += i;
|
||||||
}
|
}
|
||||||
return makeStorePath(type, hash, name);
|
return makeStorePath(type, hash, name);
|
||||||
}
|
}
|
||||||
@@ -234,11 +224,11 @@ string StoreAPI::makeValidityRegistration(const PathSet & paths,
|
|||||||
bool showDerivers, bool showHash)
|
bool showDerivers, bool showHash)
|
||||||
{
|
{
|
||||||
string s = "";
|
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) {
|
if (showHash) {
|
||||||
s += printHash(info.hash) + "\n";
|
s += printHash(info.hash) + "\n";
|
||||||
@@ -250,8 +240,8 @@ string StoreAPI::makeValidityRegistration(const PathSet & paths,
|
|||||||
|
|
||||||
s += (format("%1%\n") % info.references.size()).str();
|
s += (format("%1%\n") % info.references.size()).str();
|
||||||
|
|
||||||
foreach (PathSet::iterator, j, info.references)
|
for (auto & j : info.references)
|
||||||
s += *j + "\n";
|
s += j + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
@@ -286,9 +276,9 @@ ValidPathInfo decodeValidPathInfo(std::istream & str, bool hashGiven)
|
|||||||
string showPaths(const PathSet & paths)
|
string showPaths(const PathSet & paths)
|
||||||
{
|
{
|
||||||
string s;
|
string s;
|
||||||
foreach (PathSet::const_iterator, i, paths) {
|
for (auto & i : paths) {
|
||||||
if (s.size() != 0) s += ", ";
|
if (s.size() != 0) s += ", ";
|
||||||
s += "‘" + *i + "’";
|
s += "‘" + i + "’";
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@@ -297,11 +287,11 @@ string showPaths(const PathSet & paths)
|
|||||||
void exportPaths(StoreAPI & store, const Paths & paths,
|
void exportPaths(StoreAPI & store, const Paths & paths,
|
||||||
bool sign, Sink & sink)
|
bool sign, Sink & sink)
|
||||||
{
|
{
|
||||||
foreach (Paths::const_iterator, i, paths) {
|
for (auto & i : paths) {
|
||||||
writeInt(1, sink);
|
sink << 1;
|
||||||
store.exportPath(*i, sign, sink);
|
store.exportPath(i, sign, sink);
|
||||||
}
|
}
|
||||||
writeInt(0, sink);
|
sink << 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "serialise.hh"
|
#include "serialise.hh"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <limits>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@@ -36,21 +37,19 @@ struct GCOptions
|
|||||||
gcDeleteSpecific,
|
gcDeleteSpecific,
|
||||||
} GCAction;
|
} GCAction;
|
||||||
|
|
||||||
GCAction action;
|
GCAction action{gcDeleteDead};
|
||||||
|
|
||||||
/* If `ignoreLiveness' is set, then reachability from the roots is
|
/* If `ignoreLiveness' is set, then reachability from the roots is
|
||||||
ignored (dangerous!). However, the paths must still be
|
ignored (dangerous!). However, the paths must still be
|
||||||
unreferenced *within* the store (i.e., there can be no other
|
unreferenced *within* the store (i.e., there can be no other
|
||||||
store paths that depend on them). */
|
store paths that depend on them). */
|
||||||
bool ignoreLiveness;
|
bool ignoreLiveness{false};
|
||||||
|
|
||||||
/* For `gcDeleteSpecific', the paths to delete. */
|
/* For `gcDeleteSpecific', the paths to delete. */
|
||||||
PathSet pathsToDelete;
|
PathSet pathsToDelete;
|
||||||
|
|
||||||
/* Stop after at least `maxFreed' bytes have been freed. */
|
/* Stop after at least `maxFreed' bytes have been freed. */
|
||||||
unsigned long long maxFreed;
|
unsigned long long maxFreed{std::numeric_limits<unsigned long long>::max()};
|
||||||
|
|
||||||
GCOptions();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -100,6 +99,32 @@ typedef list<ValidPathInfo> ValidPathInfos;
|
|||||||
enum BuildMode { bmNormal, bmRepair, bmCheck };
|
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
|
class StoreAPI
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -194,6 +219,12 @@ public:
|
|||||||
not derivations, substitute them. */
|
not derivations, substitute them. */
|
||||||
virtual void buildPaths(const PathSet & paths, BuildMode buildMode = bmNormal) = 0;
|
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
|
/* 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
|
may be made valid by running a substitute (if defined for the
|
||||||
path). */
|
path). */
|
||||||
|
|||||||
@@ -43,7 +43,8 @@ typedef enum {
|
|||||||
wopQuerySubstitutablePaths = 32,
|
wopQuerySubstitutablePaths = 32,
|
||||||
wopQueryValidDerivers = 33,
|
wopQueryValidDerivers = 33,
|
||||||
wopOptimiseStore = 34,
|
wopOptimiseStore = 34,
|
||||||
wopVerifyStore = 35
|
wopVerifyStore = 35,
|
||||||
|
wopBuildDerivation = 36,
|
||||||
} WorkerOp;
|
} WorkerOp;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+12
-25
@@ -39,8 +39,7 @@ PathFilter defaultPathFilter;
|
|||||||
static void dumpContents(const Path & path, size_t size,
|
static void dumpContents(const Path & path, size_t size,
|
||||||
Sink & sink)
|
Sink & sink)
|
||||||
{
|
{
|
||||||
writeString("contents", sink);
|
sink << "contents" << size;
|
||||||
writeLongLong(size, sink);
|
|
||||||
|
|
||||||
AutoCloseFD fd = open(path.c_str(), O_RDONLY);
|
AutoCloseFD fd = open(path.c_str(), O_RDONLY);
|
||||||
if (fd == -1) throw SysError(format("opening file ‘%1%’") % path);
|
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))
|
if (lstat(path.c_str(), &st))
|
||||||
throw SysError(format("getting attributes of path ‘%1%’") % path);
|
throw SysError(format("getting attributes of path ‘%1%’") % path);
|
||||||
|
|
||||||
writeString("(", sink);
|
sink << "(";
|
||||||
|
|
||||||
if (S_ISREG(st.st_mode)) {
|
if (S_ISREG(st.st_mode)) {
|
||||||
writeString("type", sink);
|
sink << "type" << "regular";
|
||||||
writeString("regular", sink);
|
if (st.st_mode & S_IXUSR)
|
||||||
if (st.st_mode & S_IXUSR) {
|
sink << "executable" << "";
|
||||||
writeString("executable", sink);
|
|
||||||
writeString("", sink);
|
|
||||||
}
|
|
||||||
dumpContents(path, (size_t) st.st_size, sink);
|
dumpContents(path, (size_t) st.st_size, sink);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (S_ISDIR(st.st_mode)) {
|
else if (S_ISDIR(st.st_mode)) {
|
||||||
writeString("type", sink);
|
sink << "type" << "directory";
|
||||||
writeString("directory", sink);
|
|
||||||
|
|
||||||
/* If we're on a case-insensitive system like Mac OS X, undo
|
/* If we're on a case-insensitive system like Mac OS X, undo
|
||||||
the case hack applied by restorePath(). */
|
the case hack applied by restorePath(). */
|
||||||
@@ -101,32 +96,24 @@ static void dump(const Path & path, Sink & sink, PathFilter & filter)
|
|||||||
|
|
||||||
for (auto & i : unhacked)
|
for (auto & i : unhacked)
|
||||||
if (filter(path + "/" + i.first)) {
|
if (filter(path + "/" + i.first)) {
|
||||||
writeString("entry", sink);
|
sink << "entry" << "(" << "name" << i.first << "node";
|
||||||
writeString("(", sink);
|
|
||||||
writeString("name", sink);
|
|
||||||
writeString(i.first, sink);
|
|
||||||
writeString("node", sink);
|
|
||||||
dump(path + "/" + i.second, sink, filter);
|
dump(path + "/" + i.second, sink, filter);
|
||||||
writeString(")", sink);
|
sink << ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (S_ISLNK(st.st_mode)) {
|
else if (S_ISLNK(st.st_mode))
|
||||||
writeString("type", sink);
|
sink << "type" << "symlink" << "target" << readLink(path);
|
||||||
writeString("symlink", sink);
|
|
||||||
writeString("target", sink);
|
|
||||||
writeString(readLink(path), sink);
|
|
||||||
}
|
|
||||||
|
|
||||||
else throw Error(format("file ‘%1%’ has an unsupported type") % path);
|
else throw Error(format("file ‘%1%’ has an unsupported type") % path);
|
||||||
|
|
||||||
writeString(")", sink);
|
sink << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void dumpPath(const Path & path, Sink & sink, PathFilter & filter)
|
void dumpPath(const Path & path, Sink & sink, PathFilter & filter)
|
||||||
{
|
{
|
||||||
writeString(archiveVersion1, sink);
|
sink << archiveVersion1;
|
||||||
dump(path, sink, filter);
|
dump(path, sink, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+35
-39
@@ -16,11 +16,11 @@ BufferedSink::~BufferedSink()
|
|||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void BufferedSink::operator () (const unsigned char * data, size_t len)
|
void BufferedSink::operator () (const unsigned char * data, size_t len)
|
||||||
{
|
{
|
||||||
if (!buffer) buffer = new unsigned char[bufSize];
|
if (!buffer) buffer = new unsigned char[bufSize];
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
/* Optimisation: bypass the buffer if the data exceeds the
|
/* Optimisation: bypass the buffer if the data exceeds the
|
||||||
buffer size. */
|
buffer size. */
|
||||||
@@ -96,7 +96,7 @@ size_t BufferedSource::read(unsigned char * data, size_t len)
|
|||||||
if (!buffer) buffer = new unsigned char[bufSize];
|
if (!buffer) buffer = new unsigned char[bufSize];
|
||||||
|
|
||||||
if (!bufPosIn) bufPosIn = readUnbuffered(buffer, bufSize);
|
if (!bufPosIn) bufPosIn = readUnbuffered(buffer, bufSize);
|
||||||
|
|
||||||
/* Copy out the data in the buffer. */
|
/* Copy out the data in the buffer. */
|
||||||
size_t n = len > bufPosIn - bufPosOut ? bufPosIn - bufPosOut : len;
|
size_t n = len > bufPosIn - bufPosOut ? bufPosIn - bufPosOut : len;
|
||||||
memcpy(data, buffer + bufPosOut, n);
|
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)
|
void writeString(const unsigned char * buf, size_t len, Sink & sink)
|
||||||
{
|
{
|
||||||
writeInt(len, sink);
|
sink << len;
|
||||||
sink(buf, len);
|
sink(buf, len);
|
||||||
writePadding(len, sink);
|
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);
|
writeString((const unsigned char *) s.data(), s.size(), sink);
|
||||||
|
return sink;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<class T> void writeStrings(const T & ss, Sink & sink)
|
template<class T> void writeStrings(const T & ss, Sink & sink)
|
||||||
{
|
{
|
||||||
writeInt(ss.size(), sink);
|
sink << ss.size();
|
||||||
foreach (typename T::const_iterator, i, ss)
|
for (auto & i : ss)
|
||||||
writeString(*i, sink);
|
sink << i;
|
||||||
}
|
}
|
||||||
|
|
||||||
template void writeStrings(const Paths & ss, Sink & sink);
|
Sink & operator << (Sink & sink, const Strings & s)
|
||||||
template void writeStrings(const PathSet & ss, Sink & sink);
|
{
|
||||||
|
writeStrings(s, sink);
|
||||||
|
return sink;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sink & operator << (Sink & sink, const StringSet & s)
|
||||||
|
{
|
||||||
|
writeStrings(s, sink);
|
||||||
|
return sink;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void readPadding(size_t len, Source & source)
|
void readPadding(size_t len, Source & source)
|
||||||
@@ -247,7 +230,7 @@ size_t readString(unsigned char * buf, size_t max, Source & source)
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
string readString(Source & source)
|
string readString(Source & source)
|
||||||
{
|
{
|
||||||
size_t len = readInt(source);
|
size_t len = readInt(source);
|
||||||
@@ -258,7 +241,20 @@ string readString(Source & source)
|
|||||||
return string((char *) buf, len);
|
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)
|
template<class T> T readStrings(Source & source)
|
||||||
{
|
{
|
||||||
unsigned int count = readInt(source);
|
unsigned int count = readInt(source);
|
||||||
|
|||||||
+32
-12
@@ -1,13 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "types.hh"
|
#include "types.hh"
|
||||||
|
#include "util.hh"
|
||||||
|
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
/* Abstract destination of binary data. */
|
/* Abstract destination of binary data. */
|
||||||
struct Sink
|
struct Sink
|
||||||
{
|
{
|
||||||
virtual ~Sink() { }
|
virtual ~Sink() { }
|
||||||
virtual void operator () (const unsigned char * data, size_t len) = 0;
|
virtual void operator () (const unsigned char * data, size_t len) = 0;
|
||||||
@@ -25,9 +26,9 @@ struct BufferedSink : Sink
|
|||||||
~BufferedSink();
|
~BufferedSink();
|
||||||
|
|
||||||
void operator () (const unsigned char * data, size_t len);
|
void operator () (const unsigned char * data, size_t len);
|
||||||
|
|
||||||
void flush();
|
void flush();
|
||||||
|
|
||||||
virtual void write(const unsigned char * data, size_t len) = 0;
|
virtual void write(const unsigned char * data, size_t len) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -36,7 +37,7 @@ struct BufferedSink : Sink
|
|||||||
struct Source
|
struct Source
|
||||||
{
|
{
|
||||||
virtual ~Source() { }
|
virtual ~Source() { }
|
||||||
|
|
||||||
/* Store exactly ‘len’ bytes in the buffer pointed to by ‘data’.
|
/* Store exactly ‘len’ bytes in the buffer pointed to by ‘data’.
|
||||||
It blocks until all the requested data is available, or throws
|
It blocks until all the requested data is available, or throws
|
||||||
an error if it is not going to be available. */
|
an error if it is not going to be available. */
|
||||||
@@ -58,9 +59,9 @@ struct BufferedSource : Source
|
|||||||
BufferedSource(size_t bufSize = 32 * 1024)
|
BufferedSource(size_t bufSize = 32 * 1024)
|
||||||
: bufSize(bufSize), bufPosIn(0), bufPosOut(0), buffer(0) { }
|
: bufSize(bufSize), bufPosIn(0), bufPosOut(0), buffer(0) { }
|
||||||
~BufferedSource();
|
~BufferedSource();
|
||||||
|
|
||||||
size_t read(unsigned char * data, size_t len);
|
size_t read(unsigned char * data, size_t len);
|
||||||
|
|
||||||
/* Underlying read call, to be overridden. */
|
/* Underlying read call, to be overridden. */
|
||||||
virtual size_t readUnbuffered(unsigned char * data, size_t len) = 0;
|
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() : fd(-1), warn(false), written(0) { }
|
||||||
FdSink(int fd) : fd(fd), warn(false), written(0) { }
|
FdSink(int fd) : fd(fd), warn(false), written(0) { }
|
||||||
~FdSink();
|
~FdSink();
|
||||||
|
|
||||||
void write(const unsigned char * data, size_t len);
|
void write(const unsigned char * data, size_t len);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -107,16 +108,32 @@ struct StringSource : Source
|
|||||||
const string & s;
|
const string & s;
|
||||||
size_t pos;
|
size_t pos;
|
||||||
StringSource(const string & _s) : s(_s), pos(0) { }
|
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 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 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);
|
void readPadding(size_t len, Source & source);
|
||||||
unsigned int readInt(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);
|
string readString(Source & source);
|
||||||
template<class T> T readStrings(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)
|
MakeError(SerialisationError, Error)
|
||||||
|
|
||||||
|
|||||||
+42
-7
@@ -149,10 +149,19 @@ Path dirOf(const Path & path)
|
|||||||
|
|
||||||
string baseNameOf(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)
|
if (pos == string::npos)
|
||||||
throw Error(format("invalid file name ‘%1%’") % path);
|
pos = 0;
|
||||||
return string(path, pos + 1);
|
else
|
||||||
|
pos += 1;
|
||||||
|
return string(path, pos, last - pos + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -477,12 +486,24 @@ void printMsg_(Verbosity level, const FormatOrString & fs)
|
|||||||
{
|
{
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
if (level > verbosity) return;
|
if (level > verbosity) return;
|
||||||
|
|
||||||
string prefix;
|
string prefix;
|
||||||
if (logType == ltPretty)
|
if (logType == ltPretty)
|
||||||
for (int i = 0; i < nestingLevel; i++)
|
for (int i = 0; i < nestingLevel; i++)
|
||||||
prefix += "| ";
|
prefix += "| ";
|
||||||
else if (logType == ltEscapes && level != lvlInfo)
|
else if (logType == ltEscapes && level != lvlInfo)
|
||||||
prefix = "\033[" + escVerbosity(level) + "s";
|
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();
|
string s = (format("%1%%2%\n") % prefix % fs.s).str();
|
||||||
if (!isatty(STDERR_FILENO)) s = filterANSIEscapes(s);
|
if (!isatty(STDERR_FILENO)) s = filterANSIEscapes(s);
|
||||||
writeToStderr(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 concatStringsSep(const string & sep, const Strings & ss)
|
||||||
{
|
{
|
||||||
string s;
|
string s;
|
||||||
foreach (Strings::const_iterator, i, ss) {
|
for (auto & i : ss) {
|
||||||
if (s.size() != 0) s += sep;
|
if (s.size() != 0) s += sep;
|
||||||
s += *i;
|
s += i;
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@@ -1071,9 +1092,9 @@ string concatStringsSep(const string & sep, const Strings & ss)
|
|||||||
string concatStringsSep(const string & sep, const StringSet & ss)
|
string concatStringsSep(const string & sep, const StringSet & ss)
|
||||||
{
|
{
|
||||||
string s;
|
string s;
|
||||||
foreach (StringSet::const_iterator, i, ss) {
|
for (auto & i : ss) {
|
||||||
if (s.size() != 0) s += sep;
|
if (s.size() != 0) s += sep;
|
||||||
s += *i;
|
s += i;
|
||||||
}
|
}
|
||||||
return s;
|
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)
|
string statusToString(int status)
|
||||||
{
|
{
|
||||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
||||||
|
|||||||
+7
-8
@@ -15,13 +15,6 @@
|
|||||||
namespace nix {
|
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. */
|
/* Return an environment variable. */
|
||||||
string getEnv(const string & key, const string & def = "");
|
string getEnv(const string & key, const string & def = "");
|
||||||
|
|
||||||
@@ -129,7 +122,8 @@ T singleton(const A & a)
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
ltPretty, /* nice, nested output */
|
ltPretty, /* nice, nested output */
|
||||||
ltEscapes, /* nesting indicated using escape codes (for log2xml) */
|
ltEscapes, /* nesting indicated using escape codes (for log2xml) */
|
||||||
ltFlat /* no nesting */
|
ltFlat, /* no nesting */
|
||||||
|
ltSystemd, /* use systemd severity prefixes */
|
||||||
} LogType;
|
} LogType;
|
||||||
|
|
||||||
extern LogType logType;
|
extern LogType logType;
|
||||||
@@ -341,6 +335,11 @@ string chomp(const string & s);
|
|||||||
string trim(const string & s, const string & whitespace = " \n\r\t");
|
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
|
/* Convert the exit status of a child as returned by wait() into an
|
||||||
error string. */
|
error string. */
|
||||||
string statusToString(int status);
|
string statusToString(int status);
|
||||||
|
|||||||
@@ -73,10 +73,10 @@ void XMLWriter::writeEmptyElement(const string & name,
|
|||||||
|
|
||||||
void XMLWriter::writeAttrs(const XMLAttrs & attrs)
|
void XMLWriter::writeAttrs(const XMLAttrs & attrs)
|
||||||
{
|
{
|
||||||
for (XMLAttrs::const_iterator i = attrs.begin(); i != attrs.end(); ++i) {
|
for (auto & i : attrs) {
|
||||||
output << " " << i->first << "=\"";
|
output << " " << i.first << "=\"";
|
||||||
for (unsigned int j = 0; j < i->second.size(); ++j) {
|
for (unsigned int j = 0; j < i.second.size(); ++j) {
|
||||||
char c = i->second[j];
|
char c = i.second[j];
|
||||||
if (c == '"') output << """;
|
if (c == '"') output << """;
|
||||||
else if (c == '<') output << "<";
|
else if (c == '<') output << "<";
|
||||||
else if (c == '>') output << ">";
|
else if (c == '>') output << ">";
|
||||||
|
|||||||
@@ -28,7 +28,12 @@ void removeOldGenerations(std::string dir)
|
|||||||
auto type = i.type == DT_UNKNOWN ? getFileType(path) : i.type;
|
auto type = i.type == DT_UNKNOWN ? getFileType(path) : i.type;
|
||||||
|
|
||||||
if (type == DT_LNK && canWrite) {
|
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) {
|
if (link.find("link") != string::npos) {
|
||||||
printMsg(lvlInfo, format("removing old generations of profile %1%") % path);
|
printMsg(lvlInfo, format("removing old generations of profile %1%") % path);
|
||||||
if (deleteOlderThan != "")
|
if (deleteOlderThan != "")
|
||||||
@@ -45,11 +50,12 @@ void removeOldGenerations(std::string dir)
|
|||||||
int main(int argc, char * * argv)
|
int main(int argc, char * * argv)
|
||||||
{
|
{
|
||||||
bool removeOld = false;
|
bool removeOld = false;
|
||||||
Strings extraArgs;
|
|
||||||
|
|
||||||
return handleExceptions(argv[0], [&]() {
|
return handleExceptions(argv[0], [&]() {
|
||||||
initNix();
|
initNix();
|
||||||
|
|
||||||
|
GCOptions options;
|
||||||
|
|
||||||
parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) {
|
parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) {
|
||||||
if (*arg == "--help")
|
if (*arg == "--help")
|
||||||
showManPage("nix-collect-garbage");
|
showManPage("nix-collect-garbage");
|
||||||
@@ -61,8 +67,12 @@ int main(int argc, char * * argv)
|
|||||||
deleteOlderThan = getArg(*arg, arg, end);
|
deleteOlderThan = getArg(*arg, arg, end);
|
||||||
}
|
}
|
||||||
else if (*arg == "--dry-run") dryRun = true;
|
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
|
else
|
||||||
extraArgs.push_back(*arg);
|
return false;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -72,7 +82,6 @@ int main(int argc, char * * argv)
|
|||||||
// Run the actual garbage collector.
|
// Run the actual garbage collector.
|
||||||
if (!dryRun) {
|
if (!dryRun) {
|
||||||
store = openStore(false);
|
store = openStore(false);
|
||||||
GCOptions options;
|
|
||||||
options.action = GCOptions::gcDeleteDead;
|
options.action = GCOptions::gcDeleteDead;
|
||||||
GCResults results;
|
GCResults results;
|
||||||
PrintFreed freed(true, results);
|
PrintFreed freed(true, results);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "affinity.hh"
|
#include "affinity.hh"
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "monitor-fd.hh"
|
#include "monitor-fd.hh"
|
||||||
|
#include "derivations.hh"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
@@ -43,7 +44,7 @@ static void tunnelStderr(const unsigned char * buf, size_t count)
|
|||||||
{
|
{
|
||||||
if (canSendStderr) {
|
if (canSendStderr) {
|
||||||
try {
|
try {
|
||||||
writeInt(STDERR_NEXT, to);
|
to << STDERR_NEXT;
|
||||||
writeString(buf, count, to);
|
writeString(buf, count, to);
|
||||||
to.flush();
|
to.flush();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
@@ -72,11 +73,10 @@ static void stopWork(bool success = true, const string & msg = "", unsigned int
|
|||||||
canSendStderr = false;
|
canSendStderr = false;
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
writeInt(STDERR_LAST, to);
|
to << STDERR_LAST;
|
||||||
else {
|
else {
|
||||||
writeInt(STDERR_ERROR, to);
|
to << STDERR_ERROR << msg;
|
||||||
writeString(msg, to);
|
if (status != 0) to << status;
|
||||||
if (status != 0) writeInt(status, to);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ struct TunnelSink : Sink
|
|||||||
TunnelSink(Sink & to) : to(to) { }
|
TunnelSink(Sink & to) : to(to) { }
|
||||||
virtual void operator () (const unsigned char * data, size_t len)
|
virtual void operator () (const unsigned char * data, size_t len)
|
||||||
{
|
{
|
||||||
writeInt(STDERR_WRITE, to);
|
to << STDERR_WRITE;
|
||||||
writeString(data, len, to);
|
writeString(data, len, to);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -99,8 +99,7 @@ struct TunnelSource : BufferedSource
|
|||||||
TunnelSource(Source & from) : from(from) { }
|
TunnelSource(Source & from) : from(from) { }
|
||||||
size_t readUnbuffered(unsigned char * data, size_t len)
|
size_t readUnbuffered(unsigned char * data, size_t len)
|
||||||
{
|
{
|
||||||
writeInt(STDERR_READ, to);
|
to << STDERR_READ << len;
|
||||||
writeInt(len, to);
|
|
||||||
to.flush();
|
to.flush();
|
||||||
size_t n = readString(data, len, from);
|
size_t n = readString(data, len, from);
|
||||||
if (n == 0) throw EndOfFile("unexpected end-of-file");
|
if (n == 0) throw EndOfFile("unexpected end-of-file");
|
||||||
@@ -166,7 +165,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
assertStorePath(path);
|
assertStorePath(path);
|
||||||
bool result = store->isValidPath(path);
|
bool result = store->isValidPath(path);
|
||||||
stopWork();
|
stopWork();
|
||||||
writeInt(result, to);
|
to << result;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +174,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
startWork();
|
startWork();
|
||||||
PathSet res = store->queryValidPaths(paths);
|
PathSet res = store->queryValidPaths(paths);
|
||||||
stopWork();
|
stopWork();
|
||||||
writeStrings(res, to);
|
to << res;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,7 +183,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
startWork();
|
startWork();
|
||||||
PathSet res = store->querySubstitutablePaths(singleton<PathSet>(path));
|
PathSet res = store->querySubstitutablePaths(singleton<PathSet>(path));
|
||||||
stopWork();
|
stopWork();
|
||||||
writeInt(res.find(path) != res.end(), to);
|
to << (res.find(path) != res.end());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +192,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
startWork();
|
startWork();
|
||||||
PathSet res = store->querySubstitutablePaths(paths);
|
PathSet res = store->querySubstitutablePaths(paths);
|
||||||
stopWork();
|
stopWork();
|
||||||
writeStrings(res, to);
|
to << res;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,7 +201,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
startWork();
|
startWork();
|
||||||
Hash hash = store->queryPathHash(path);
|
Hash hash = store->queryPathHash(path);
|
||||||
stopWork();
|
stopWork();
|
||||||
writeString(printHash(hash), to);
|
to << printHash(hash);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +220,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
paths = store->queryValidDerivers(path);
|
paths = store->queryValidDerivers(path);
|
||||||
else paths = store->queryDerivationOutputs(path);
|
else paths = store->queryDerivationOutputs(path);
|
||||||
stopWork();
|
stopWork();
|
||||||
writeStrings(paths, to);
|
to << paths;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,7 +230,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
StringSet names;
|
StringSet names;
|
||||||
names = store->queryDerivationOutputNames(path);
|
names = store->queryDerivationOutputNames(path);
|
||||||
stopWork();
|
stopWork();
|
||||||
writeStrings(names, to);
|
to << names;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,7 +239,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
startWork();
|
startWork();
|
||||||
Path deriver = store->queryDeriver(path);
|
Path deriver = store->queryDeriver(path);
|
||||||
stopWork();
|
stopWork();
|
||||||
writeString(deriver, to);
|
to << deriver;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,7 +248,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
startWork();
|
startWork();
|
||||||
Path path = store->queryPathFromHashPart(hashPart);
|
Path path = store->queryPathFromHashPart(hashPart);
|
||||||
stopWork();
|
stopWork();
|
||||||
writeString(path, to);
|
to << path;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,7 +282,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
->addToStoreFromDump(recursive ? savedNAR.s : savedRegular.s, baseName, recursive, hashAlgo);
|
->addToStoreFromDump(recursive ? savedNAR.s : savedRegular.s, baseName, recursive, hashAlgo);
|
||||||
stopWork();
|
stopWork();
|
||||||
|
|
||||||
writeString(path, to);
|
to << path;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,7 +293,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
startWork();
|
startWork();
|
||||||
Path path = store->addTextToStore(suffix, s, refs);
|
Path path = store->addTextToStore(suffix, s, refs);
|
||||||
stopWork();
|
stopWork();
|
||||||
writeString(path, to);
|
to << path;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,7 +304,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
TunnelSink sink(to);
|
TunnelSink sink(to);
|
||||||
store->exportPath(path, sign, sink);
|
store->exportPath(path, sign, sink);
|
||||||
stopWork();
|
stopWork();
|
||||||
writeInt(1, to);
|
to << 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,7 +313,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
TunnelSource source(from);
|
TunnelSource source(from);
|
||||||
Paths paths = store->importPaths(!trusted, source);
|
Paths paths = store->importPaths(!trusted, source);
|
||||||
stopWork();
|
stopWork();
|
||||||
writeStrings(paths, to);
|
to << paths;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,7 +322,21 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
startWork();
|
startWork();
|
||||||
store->buildPaths(drvs);
|
store->buildPaths(drvs);
|
||||||
stopWork();
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,7 +345,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
startWork();
|
startWork();
|
||||||
store->ensurePath(path);
|
store->ensurePath(path);
|
||||||
stopWork();
|
stopWork();
|
||||||
writeInt(1, to);
|
to << 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,7 +354,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
startWork();
|
startWork();
|
||||||
store->addTempRoot(path);
|
store->addTempRoot(path);
|
||||||
stopWork();
|
stopWork();
|
||||||
writeInt(1, to);
|
to << 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,7 +363,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
startWork();
|
startWork();
|
||||||
store->addIndirectRoot(path);
|
store->addIndirectRoot(path);
|
||||||
stopWork();
|
stopWork();
|
||||||
writeInt(1, to);
|
to << 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,7 +371,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
startWork();
|
startWork();
|
||||||
store->syncWithGC();
|
store->syncWithGC();
|
||||||
stopWork();
|
stopWork();
|
||||||
writeInt(1, to);
|
to << 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -366,11 +379,9 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
startWork();
|
startWork();
|
||||||
Roots roots = store->findRoots();
|
Roots roots = store->findRoots();
|
||||||
stopWork();
|
stopWork();
|
||||||
writeInt(roots.size(), to);
|
to << roots.size();
|
||||||
for (Roots::iterator i = roots.begin(); i != roots.end(); ++i) {
|
for (auto & i : roots)
|
||||||
writeString(i->first, to);
|
to << i.first << i.second;
|
||||||
writeString(i->second, to);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,9 +406,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
store->collectGarbage(options, results);
|
store->collectGarbage(options, results);
|
||||||
stopWork();
|
stopWork();
|
||||||
|
|
||||||
writeStrings(results.paths, to);
|
to << results.paths << results.bytesFreed << 0 /* obsolete */;
|
||||||
writeLongLong(results.bytesFreed, to);
|
|
||||||
writeLongLong(0, to); // obsolete
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -445,14 +454,11 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
stopWork();
|
stopWork();
|
||||||
SubstitutablePathInfos::iterator i = infos.find(path);
|
SubstitutablePathInfos::iterator i = infos.find(path);
|
||||||
if (i == infos.end())
|
if (i == infos.end())
|
||||||
writeInt(0, to);
|
to << 0;
|
||||||
else {
|
else {
|
||||||
writeInt(1, to);
|
to << 1 << i->second.deriver << i->second.references << i->second.downloadSize;
|
||||||
writeString(i->second.deriver, to);
|
|
||||||
writeStrings(i->second.references, to);
|
|
||||||
writeLongLong(i->second.downloadSize, to);
|
|
||||||
if (GET_PROTOCOL_MINOR(clientVersion) >= 7)
|
if (GET_PROTOCOL_MINOR(clientVersion) >= 7)
|
||||||
writeLongLong(i->second.narSize, to);
|
to << i->second.narSize;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -463,13 +469,10 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
SubstitutablePathInfos infos;
|
SubstitutablePathInfos infos;
|
||||||
store->querySubstitutablePathInfos(paths, infos);
|
store->querySubstitutablePathInfos(paths, infos);
|
||||||
stopWork();
|
stopWork();
|
||||||
writeInt(infos.size(), to);
|
to << infos.size();
|
||||||
foreach (SubstitutablePathInfos::iterator, i, infos) {
|
for (auto & i : infos) {
|
||||||
writeString(i->first, to);
|
to << i.first << i.second.deriver << i.second.references
|
||||||
writeString(i->second.deriver, to);
|
<< i.second.downloadSize << i.second.narSize;
|
||||||
writeStrings(i->second.references, to);
|
|
||||||
writeLongLong(i->second.downloadSize, to);
|
|
||||||
writeLongLong(i->second.narSize, to);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -478,7 +481,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
startWork();
|
startWork();
|
||||||
PathSet paths = store->queryAllValidPaths();
|
PathSet paths = store->queryAllValidPaths();
|
||||||
stopWork();
|
stopWork();
|
||||||
writeStrings(paths, to);
|
to << paths;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -486,7 +489,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
startWork();
|
startWork();
|
||||||
PathSet paths = store->queryFailedPaths();
|
PathSet paths = store->queryFailedPaths();
|
||||||
stopWork();
|
stopWork();
|
||||||
writeStrings(paths, to);
|
to << paths;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,7 +498,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
startWork();
|
startWork();
|
||||||
store->clearFailedPaths(paths);
|
store->clearFailedPaths(paths);
|
||||||
stopWork();
|
stopWork();
|
||||||
writeInt(1, to);
|
to << 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,11 +507,8 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
startWork();
|
startWork();
|
||||||
ValidPathInfo info = store->queryPathInfo(path);
|
ValidPathInfo info = store->queryPathInfo(path);
|
||||||
stopWork();
|
stopWork();
|
||||||
writeString(info.deriver, to);
|
to << info.deriver << printHash(info.hash) << info.references
|
||||||
writeString(printHash(info.hash), to);
|
<< info.registrationTime << info.narSize;
|
||||||
writeStrings(info.references, to);
|
|
||||||
writeInt(info.registrationTime, to);
|
|
||||||
writeLongLong(info.narSize, to);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -516,7 +516,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
startWork();
|
startWork();
|
||||||
store->optimiseStore();
|
store->optimiseStore();
|
||||||
stopWork();
|
stopWork();
|
||||||
writeInt(1, to);
|
to << 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case wopVerifyStore: {
|
case wopVerifyStore: {
|
||||||
@@ -527,7 +527,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||||||
throw Error("you are not privileged to repair paths");
|
throw Error("you are not privileged to repair paths");
|
||||||
bool errors = store->verifyStore(checkContents, repair);
|
bool errors = store->verifyStore(checkContents, repair);
|
||||||
stopWork();
|
stopWork();
|
||||||
writeInt(errors, to);
|
to << errors;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -547,8 +547,7 @@ static void processConnection(bool trusted)
|
|||||||
/* Exchange the greeting. */
|
/* Exchange the greeting. */
|
||||||
unsigned int magic = readInt(from);
|
unsigned int magic = readInt(from);
|
||||||
if (magic != WORKER_MAGIC_1) throw Error("protocol mismatch");
|
if (magic != WORKER_MAGIC_1) throw Error("protocol mismatch");
|
||||||
writeInt(WORKER_MAGIC_2, to);
|
to << WORKER_MAGIC_2 << PROTOCOL_VERSION;
|
||||||
writeInt(PROTOCOL_VERSION, to);
|
|
||||||
to.flush();
|
to.flush();
|
||||||
unsigned int clientVersion = readInt(from);
|
unsigned int clientVersion = readInt(from);
|
||||||
|
|
||||||
|
|||||||
+140
-136
@@ -232,9 +232,9 @@ static bool isPrebuilt(EvalState & state, DrvInfo & elem)
|
|||||||
static void checkSelectorUse(DrvNames & selectors)
|
static void checkSelectorUse(DrvNames & selectors)
|
||||||
{
|
{
|
||||||
/* Check that all selectors have been used. */
|
/* Check that all selectors have been used. */
|
||||||
foreach (DrvNames::iterator, i, selectors)
|
for (auto & i : selectors)
|
||||||
if (i->hits == 0 && i->fullName != "*")
|
if (i.hits == 0 && i.fullName != "*")
|
||||||
throw Error(format("selector ‘%1%’ matches no derivations") % 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;
|
DrvInfos elems;
|
||||||
set<unsigned int> done;
|
set<unsigned int> done;
|
||||||
|
|
||||||
foreach (DrvNames::iterator, i, selectors) {
|
for (auto & i : selectors) {
|
||||||
typedef list<std::pair<DrvInfo, unsigned int> > Matches;
|
typedef list<std::pair<DrvInfo, unsigned int> > Matches;
|
||||||
Matches matches;
|
Matches matches;
|
||||||
unsigned int n = 0;
|
unsigned int n = 0;
|
||||||
@@ -256,8 +256,8 @@ static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems,
|
|||||||
j != allElems.end(); ++j, ++n)
|
j != allElems.end(); ++j, ++n)
|
||||||
{
|
{
|
||||||
DrvName drvName(j->name);
|
DrvName drvName(j->name);
|
||||||
if (i->matches(drvName)) {
|
if (i.matches(drvName)) {
|
||||||
i->hits++;
|
i.hits++;
|
||||||
matches.push_back(std::pair<DrvInfo, unsigned int>(*j, n));
|
matches.push_back(std::pair<DrvInfo, unsigned int>(*j, n));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -276,47 +276,47 @@ static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems,
|
|||||||
Newest newest;
|
Newest newest;
|
||||||
StringSet multiple;
|
StringSet multiple;
|
||||||
|
|
||||||
for (Matches::iterator j = matches.begin(); j != matches.end(); ++j) {
|
for (auto & j : matches) {
|
||||||
DrvName drvName(j->first.name);
|
DrvName drvName(j.first.name);
|
||||||
int d = 1;
|
int d = 1;
|
||||||
|
|
||||||
Newest::iterator k = newest.find(drvName.name);
|
Newest::iterator k = newest.find(drvName.name);
|
||||||
|
|
||||||
if (k != newest.end()) {
|
if (k != newest.end()) {
|
||||||
d = j->first.system == k->second.first.system ? 0 :
|
d = j.first.system == k->second.first.system ? 0 :
|
||||||
j->first.system == settings.thisSystem ? 1 :
|
j.first.system == settings.thisSystem ? 1 :
|
||||||
k->second.first.system == settings.thisSystem ? -1 : 0;
|
k->second.first.system == settings.thisSystem ? -1 : 0;
|
||||||
if (d == 0)
|
if (d == 0)
|
||||||
d = comparePriorities(state, j->first, k->second.first);
|
d = comparePriorities(state, j.first, k->second.first);
|
||||||
if (d == 0)
|
if (d == 0)
|
||||||
d = compareVersions(drvName.version, DrvName(k->second.first.name).version);
|
d = compareVersions(drvName.version, DrvName(k->second.first.name).version);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (d > 0) {
|
if (d > 0) {
|
||||||
newest.erase(drvName.name);
|
newest.erase(drvName.name);
|
||||||
newest.insert(Newest::value_type(drvName.name, *j));
|
newest.insert(Newest::value_type(drvName.name, j));
|
||||||
multiple.erase(j->first.name);
|
multiple.erase(j.first.name);
|
||||||
} else if (d == 0) {
|
} else if (d == 0) {
|
||||||
multiple.insert(j->first.name);
|
multiple.insert(j.first.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
matches.clear();
|
matches.clear();
|
||||||
for (Newest::iterator j = newest.begin(); j != newest.end(); ++j) {
|
for (auto & j : newest) {
|
||||||
if (multiple.find(j->second.first.name) != multiple.end())
|
if (multiple.find(j.second.first.name) != multiple.end())
|
||||||
printMsg(lvlInfo,
|
printMsg(lvlInfo,
|
||||||
format("warning: there are multiple derivations named ‘%1%’; using the first one")
|
format("warning: there are multiple derivations named ‘%1%’; using the first one")
|
||||||
% j->second.first.name);
|
% j.second.first.name);
|
||||||
matches.push_back(j->second);
|
matches.push_back(j.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Insert only those elements in the final list that we
|
/* Insert only those elements in the final list that we
|
||||||
haven't inserted before. */
|
haven't inserted before. */
|
||||||
for (Matches::iterator j = matches.begin(); j != matches.end(); ++j)
|
for (auto & j : matches)
|
||||||
if (done.find(j->second) == done.end()) {
|
if (done.find(j.second) == done.end()) {
|
||||||
done.insert(j->second);
|
done.insert(j.second);
|
||||||
elems.push_back(j->first);
|
elems.push_back(j.first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,8 +370,8 @@ static void queryInstSources(EvalState & state,
|
|||||||
Value vArg;
|
Value vArg;
|
||||||
loadSourceExpr(state, instSource.nixExprPath, vArg);
|
loadSourceExpr(state, instSource.nixExprPath, vArg);
|
||||||
|
|
||||||
foreach (Strings::const_iterator, i, args) {
|
for (auto & i : args) {
|
||||||
Expr * eFun = state.parseExprFromString(*i, absPath("."));
|
Expr * eFun = state.parseExprFromString(i, absPath("."));
|
||||||
Value vFun, vTmp;
|
Value vFun, vTmp;
|
||||||
state.eval(eFun, vFun);
|
state.eval(eFun, vFun);
|
||||||
mkApp(vTmp, vFun, vArg);
|
mkApp(vTmp, vFun, vArg);
|
||||||
@@ -386,8 +386,8 @@ static void queryInstSources(EvalState & state,
|
|||||||
derivations). */
|
derivations). */
|
||||||
case srcStorePaths: {
|
case srcStorePaths: {
|
||||||
|
|
||||||
foreach (Strings::const_iterator, i, args) {
|
for (auto & i : args) {
|
||||||
Path path = followLinksToStorePath(*i);
|
Path path = followLinksToStorePath(i);
|
||||||
|
|
||||||
string name = baseNameOf(path);
|
string name = baseNameOf(path);
|
||||||
string::size_type dash = name.find('-');
|
string::size_type dash = name.find('-');
|
||||||
@@ -424,8 +424,8 @@ static void queryInstSources(EvalState & state,
|
|||||||
case srcAttrPath: {
|
case srcAttrPath: {
|
||||||
Value vRoot;
|
Value vRoot;
|
||||||
loadSourceExpr(state, instSource.nixExprPath, vRoot);
|
loadSourceExpr(state, instSource.nixExprPath, vRoot);
|
||||||
foreach (Strings::const_iterator, i, args) {
|
for (auto & i : args) {
|
||||||
Value & v(*findAlongAttrPath(state, *i, *instSource.autoArgs, vRoot));
|
Value & v(*findAlongAttrPath(state, i, *instSource.autoArgs, vRoot));
|
||||||
getDerivations(state, v, "", *instSource.autoArgs, elems, true);
|
getDerivations(state, v, "", *instSource.autoArgs, elems, true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -437,12 +437,12 @@ static void queryInstSources(EvalState & state,
|
|||||||
static void printMissing(EvalState & state, DrvInfos & elems)
|
static void printMissing(EvalState & state, DrvInfos & elems)
|
||||||
{
|
{
|
||||||
PathSet targets;
|
PathSet targets;
|
||||||
foreach (DrvInfos::iterator, i, elems) {
|
for (auto & i : elems) {
|
||||||
Path drvPath = i->queryDrvPath();
|
Path drvPath = i.queryDrvPath();
|
||||||
if (drvPath != "")
|
if (drvPath != "")
|
||||||
targets.insert(drvPath);
|
targets.insert(drvPath);
|
||||||
else
|
else
|
||||||
targets.insert(i->queryOutPath());
|
targets.insert(i.queryOutPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
printMissing(*store, targets);
|
printMissing(*store, targets);
|
||||||
@@ -465,19 +465,19 @@ static void installDerivations(Globals & globals,
|
|||||||
queryInstSources(*globals.state, globals.instSource, args, newElemsTmp, true);
|
queryInstSources(*globals.state, globals.instSource, args, newElemsTmp, true);
|
||||||
|
|
||||||
/* If --prebuilt-only is given, filter out source-only packages. */
|
/* If --prebuilt-only is given, filter out source-only packages. */
|
||||||
foreach (DrvInfos::iterator, i, newElemsTmp)
|
for (auto & i : newElemsTmp)
|
||||||
if (!globals.prebuiltOnly || isPrebuilt(*globals.state, *i))
|
if (!globals.prebuiltOnly || isPrebuilt(*globals.state, i))
|
||||||
newElems.push_back(*i);
|
newElems.push_back(i);
|
||||||
|
|
||||||
StringSet newNames;
|
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
|
/* `forceName' is a hack to get package names right in some
|
||||||
one-click installs, namely those where the name used in the
|
one-click installs, namely those where the name used in the
|
||||||
path is not the one we want (e.g., `java-front' versus
|
path is not the one we want (e.g., `java-front' versus
|
||||||
`java-front-0.9pre15899'). */
|
`java-front-0.9pre15899'). */
|
||||||
if (globals.forceName != "")
|
if (globals.forceName != "")
|
||||||
i->name = globals.forceName;
|
i.name = globals.forceName;
|
||||||
newNames.insert(DrvName(i->name).name);
|
newNames.insert(DrvName(i.name).name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -491,18 +491,18 @@ static void installDerivations(Globals & globals,
|
|||||||
if (!globals.removeAll) {
|
if (!globals.removeAll) {
|
||||||
DrvInfos installedElems = queryInstalled(*globals.state, profile);
|
DrvInfos installedElems = queryInstalled(*globals.state, profile);
|
||||||
|
|
||||||
foreach (DrvInfos::iterator, i, installedElems) {
|
for (auto & i : installedElems) {
|
||||||
DrvName drvName(i->name);
|
DrvName drvName(i.name);
|
||||||
if (!globals.preserveInstalled &&
|
if (!globals.preserveInstalled &&
|
||||||
newNames.find(drvName.name) != newNames.end() &&
|
newNames.find(drvName.name) != newNames.end() &&
|
||||||
!keep(*i))
|
!keep(i))
|
||||||
printMsg(lvlInfo, format("replacing old ‘%1%’") % i->name);
|
printMsg(lvlInfo, format("replacing old ‘%1%’") % i.name);
|
||||||
else
|
else
|
||||||
allElems.push_back(*i);
|
allElems.push_back(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (DrvInfos::iterator, i, newElems)
|
for (auto & i : newElems)
|
||||||
printMsg(lvlInfo, format("installing ‘%1%’") % i->name);
|
printMsg(lvlInfo, format("installing ‘%1%’") % i.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
printMissing(*globals.state, newElems);
|
printMissing(*globals.state, newElems);
|
||||||
@@ -555,13 +555,13 @@ static void upgradeDerivations(Globals & globals,
|
|||||||
|
|
||||||
/* Go through all installed derivations. */
|
/* Go through all installed derivations. */
|
||||||
DrvInfos newElems;
|
DrvInfos newElems;
|
||||||
foreach (DrvInfos::iterator, i, installedElems) {
|
for (auto & i : installedElems) {
|
||||||
DrvName drvName(i->name);
|
DrvName drvName(i.name);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
if (keep(*i)) {
|
if (keep(i)) {
|
||||||
newElems.push_back(*i);
|
newElems.push_back(i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,10 +573,10 @@ static void upgradeDerivations(Globals & globals,
|
|||||||
take the one with the highest version. */
|
take the one with the highest version. */
|
||||||
DrvInfos::iterator bestElem = availElems.end();
|
DrvInfos::iterator bestElem = availElems.end();
|
||||||
DrvName bestName;
|
DrvName bestName;
|
||||||
foreach (DrvInfos::iterator, j, availElems) {
|
for (auto j = availElems.begin(); j != availElems.end(); ++j) {
|
||||||
DrvName newName(j->name);
|
DrvName newName(j->name);
|
||||||
if (newName.name == drvName.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 (d == 0) d = compareVersions(drvName.version, newName.version);
|
||||||
if ((upgradeType == utLt && d < 0) ||
|
if ((upgradeType == utLt && d < 0) ||
|
||||||
(upgradeType == utLeq && d <= 0) ||
|
(upgradeType == utLeq && d <= 0) ||
|
||||||
@@ -597,17 +597,17 @@ static void upgradeDerivations(Globals & globals,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (bestElem != availElems.end() &&
|
if (bestElem != availElems.end() &&
|
||||||
i->queryOutPath() !=
|
i.queryOutPath() !=
|
||||||
bestElem->queryOutPath())
|
bestElem->queryOutPath())
|
||||||
{
|
{
|
||||||
printMsg(lvlInfo,
|
printMsg(lvlInfo,
|
||||||
format("upgrading ‘%1%’ to ‘%2%’")
|
format("upgrading ‘%1%’ to ‘%2%’")
|
||||||
% i->name % bestElem->name);
|
% i.name % bestElem->name);
|
||||||
newElems.push_back(*bestElem);
|
newElems.push_back(*bestElem);
|
||||||
} else newElems.push_back(*i);
|
} else newElems.push_back(i);
|
||||||
|
|
||||||
} catch (Error & e) {
|
} 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;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -666,13 +666,13 @@ static void opSetFlag(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
DrvInfos installedElems = queryInstalled(*globals.state, globals.profile);
|
DrvInfos installedElems = queryInstalled(*globals.state, globals.profile);
|
||||||
|
|
||||||
/* Update all matching derivations. */
|
/* Update all matching derivations. */
|
||||||
foreach (DrvInfos::iterator, i, installedElems) {
|
for (auto & i : installedElems) {
|
||||||
DrvName drvName(i->name);
|
DrvName drvName(i.name);
|
||||||
foreach (DrvNames::iterator, j, selectors)
|
for (auto & j : selectors)
|
||||||
if (j->matches(drvName)) {
|
if (j.matches(drvName)) {
|
||||||
printMsg(lvlInfo, format("setting flag on ‘%1%’") % i->name);
|
printMsg(lvlInfo, format("setting flag on ‘%1%’") % i.name);
|
||||||
j->hits++;
|
j.hits++;
|
||||||
setMetaFlag(*globals.state, *i, flagName, flagValue);
|
setMetaFlag(*globals.state, i, flagName, flagValue);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -732,20 +732,20 @@ static void uninstallDerivations(Globals & globals, Strings & selectors,
|
|||||||
DrvInfos installedElems = queryInstalled(*globals.state, profile);
|
DrvInfos installedElems = queryInstalled(*globals.state, profile);
|
||||||
DrvInfos newElems;
|
DrvInfos newElems;
|
||||||
|
|
||||||
foreach (DrvInfos::iterator, i, installedElems) {
|
for (auto & i : installedElems) {
|
||||||
DrvName drvName(i->name);
|
DrvName drvName(i.name);
|
||||||
bool found = false;
|
bool found = false;
|
||||||
foreach (Strings::iterator, j, selectors)
|
for (auto & j : selectors)
|
||||||
/* !!! the repeated calls to followLinksToStorePath()
|
/* !!! the repeated calls to followLinksToStorePath()
|
||||||
are expensive, should pre-compute them. */
|
are expensive, should pre-compute them. */
|
||||||
if ((isPath(*j) && i->queryOutPath() == followLinksToStorePath(*j))
|
if ((isPath(j) && i.queryOutPath() == followLinksToStorePath(j))
|
||||||
|| DrvName(*j).matches(drvName))
|
|| DrvName(j).matches(drvName))
|
||||||
{
|
{
|
||||||
printMsg(lvlInfo, format("uninstalling ‘%1%’") % i->name);
|
printMsg(lvlInfo, format("uninstalling ‘%1%’") % i.name);
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!found) newElems.push_back(*i);
|
if (!found) newElems.push_back(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (globals.dryRun) return;
|
if (globals.dryRun) return;
|
||||||
@@ -788,18 +788,18 @@ void printTable(Table & table)
|
|||||||
vector<unsigned int> widths;
|
vector<unsigned int> widths;
|
||||||
widths.resize(nrColumns);
|
widths.resize(nrColumns);
|
||||||
|
|
||||||
foreach (Table::iterator, i, table) {
|
for (auto & i : table) {
|
||||||
assert(i->size() == nrColumns);
|
assert(i.size() == nrColumns);
|
||||||
Strings::iterator j;
|
Strings::iterator j;
|
||||||
unsigned int column;
|
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();
|
if (j->size() > widths[column]) widths[column] = j->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Table::iterator, i, table) {
|
for (auto & i : table) {
|
||||||
Strings::iterator j;
|
Strings::iterator j;
|
||||||
unsigned int column;
|
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;
|
string s = *j;
|
||||||
replace(s.begin(), s.end(), '\n', ' ');
|
replace(s.begin(), s.end(), '\n', ' ');
|
||||||
cout << s;
|
cout << s;
|
||||||
@@ -828,8 +828,8 @@ static VersionDiff compareVersionAgainstSet(
|
|||||||
VersionDiff diff = cvUnavail;
|
VersionDiff diff = cvUnavail;
|
||||||
version = "?";
|
version = "?";
|
||||||
|
|
||||||
for (DrvInfos::const_iterator i = elems.begin(); i != elems.end(); ++i) {
|
for (auto & i : elems) {
|
||||||
DrvName name2(i->name);
|
DrvName name2(i.name);
|
||||||
if (name.name == name2.name) {
|
if (name.name == name2.name) {
|
||||||
int d = compareVersions(name.version, name2.version);
|
int d = compareVersions(name.version, name2.version);
|
||||||
if (d < 0) {
|
if (d < 0) {
|
||||||
@@ -855,21 +855,21 @@ static VersionDiff compareVersionAgainstSet(
|
|||||||
static void queryJSON(Globals & globals, vector<DrvInfo> & elems)
|
static void queryJSON(Globals & globals, vector<DrvInfo> & elems)
|
||||||
{
|
{
|
||||||
JSONObject topObj(cout);
|
JSONObject topObj(cout);
|
||||||
foreach (vector<DrvInfo>::iterator, i, elems) {
|
for (auto & i : elems) {
|
||||||
topObj.attr(i->attrPath);
|
topObj.attr(i.attrPath);
|
||||||
JSONObject pkgObj(cout);
|
JSONObject pkgObj(cout);
|
||||||
|
|
||||||
pkgObj.attr("name", i->name);
|
pkgObj.attr("name", i.name);
|
||||||
pkgObj.attr("system", i->system);
|
pkgObj.attr("system", i.system);
|
||||||
|
|
||||||
pkgObj.attr("meta");
|
pkgObj.attr("meta");
|
||||||
JSONObject metaObj(cout);
|
JSONObject metaObj(cout);
|
||||||
StringSet metaNames = i->queryMetaNames();
|
StringSet metaNames = i.queryMetaNames();
|
||||||
foreach (StringSet::iterator, j, metaNames) {
|
for (auto & j : metaNames) {
|
||||||
metaObj.attr(*j);
|
metaObj.attr(j);
|
||||||
Value * v = i->queryMeta(*j);
|
Value * v = i.queryMeta(j);
|
||||||
if (!v) {
|
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";
|
cout << "null";
|
||||||
} else {
|
} else {
|
||||||
PathSet context;
|
PathSet context;
|
||||||
@@ -944,8 +944,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
/* Sort them by name. */
|
/* Sort them by name. */
|
||||||
/* !!! */
|
/* !!! */
|
||||||
vector<DrvInfo> elems;
|
vector<DrvInfo> elems;
|
||||||
for (DrvInfos::iterator i = elems_.begin(); i != elems_.end(); ++i)
|
for (auto & i : elems_) elems.push_back(i);
|
||||||
elems.push_back(*i);
|
|
||||||
sort(elems.begin(), elems.end(), cmpElemByName);
|
sort(elems.begin(), elems.end(), cmpElemByName);
|
||||||
|
|
||||||
|
|
||||||
@@ -954,9 +953,8 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
PathSet installed; /* installed paths */
|
PathSet installed; /* installed paths */
|
||||||
|
|
||||||
if (printStatus) {
|
if (printStatus) {
|
||||||
for (DrvInfos::iterator i = installedElems.begin();
|
for (auto & i : installedElems)
|
||||||
i != installedElems.end(); ++i)
|
installed.insert(i.queryOutPath());
|
||||||
installed.insert(i->queryOutPath());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -964,12 +962,12 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
PathSet validPaths, substitutablePaths;
|
PathSet validPaths, substitutablePaths;
|
||||||
if (printStatus || globals.prebuiltOnly) {
|
if (printStatus || globals.prebuiltOnly) {
|
||||||
PathSet paths;
|
PathSet paths;
|
||||||
foreach (vector<DrvInfo>::iterator, i, elems)
|
for (auto & i : elems)
|
||||||
try {
|
try {
|
||||||
paths.insert(i->queryOutPath());
|
paths.insert(i.queryOutPath());
|
||||||
} catch (AssertionError & e) {
|
} 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);
|
||||||
i->setFailed();
|
i.setFailed();
|
||||||
}
|
}
|
||||||
validPaths = store->queryValidPaths(paths);
|
validPaths = store->queryValidPaths(paths);
|
||||||
substitutablePaths = store->querySubstitutablePaths(paths);
|
substitutablePaths = store->querySubstitutablePaths(paths);
|
||||||
@@ -990,15 +988,15 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
XMLWriter xml(true, *(xmlOutput ? &cout : &dummy));
|
XMLWriter xml(true, *(xmlOutput ? &cout : &dummy));
|
||||||
XMLOpenElement xmlRoot(xml, "items");
|
XMLOpenElement xmlRoot(xml, "items");
|
||||||
|
|
||||||
foreach (vector<DrvInfo>::iterator, i, elems) {
|
for (auto & i : elems) {
|
||||||
try {
|
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 &&
|
if (globals.prebuiltOnly &&
|
||||||
validPaths.find(i->queryOutPath()) == validPaths.end() &&
|
validPaths.find(i.queryOutPath()) == validPaths.end() &&
|
||||||
substitutablePaths.find(i->queryOutPath()) == substitutablePaths.end())
|
substitutablePaths.find(i.queryOutPath()) == substitutablePaths.end())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* For table output. */
|
/* For table output. */
|
||||||
@@ -1008,7 +1006,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
XMLAttrs attrs;
|
XMLAttrs attrs;
|
||||||
|
|
||||||
if (printStatus) {
|
if (printStatus) {
|
||||||
Path outPath = i->queryOutPath();
|
Path outPath = i.queryOutPath();
|
||||||
bool hasSubs = substitutablePaths.find(outPath) != substitutablePaths.end();
|
bool hasSubs = substitutablePaths.find(outPath) != substitutablePaths.end();
|
||||||
bool isInstalled = installed.find(outPath) != installed.end();
|
bool isInstalled = installed.find(outPath) != installed.end();
|
||||||
bool isValid = validPaths.find(outPath) != validPaths.end();
|
bool isValid = validPaths.find(outPath) != validPaths.end();
|
||||||
@@ -1024,14 +1022,14 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (xmlOutput)
|
if (xmlOutput)
|
||||||
attrs["attrPath"] = i->attrPath;
|
attrs["attrPath"] = i.attrPath;
|
||||||
else if (printAttrPath)
|
else if (printAttrPath)
|
||||||
columns.push_back(i->attrPath);
|
columns.push_back(i.attrPath);
|
||||||
|
|
||||||
if (xmlOutput)
|
if (xmlOutput)
|
||||||
attrs["name"] = i->name;
|
attrs["name"] = i.name;
|
||||||
else if (printName)
|
else if (printName)
|
||||||
columns.push_back(i->name);
|
columns.push_back(i.name);
|
||||||
|
|
||||||
if (compareVersions) {
|
if (compareVersions) {
|
||||||
/* Compare this element against the versions of the
|
/* 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. !!!
|
elements, or the set of installed elements. !!!
|
||||||
This is O(N * M), should be O(N * lg M). */
|
This is O(N * M), should be O(N * lg M). */
|
||||||
string version;
|
string version;
|
||||||
VersionDiff diff = compareVersionAgainstSet(*i, otherElems, version);
|
VersionDiff diff = compareVersionAgainstSet(i, otherElems, version);
|
||||||
|
|
||||||
char ch;
|
char ch;
|
||||||
switch (diff) {
|
switch (diff) {
|
||||||
@@ -1064,13 +1062,13 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (xmlOutput) {
|
if (xmlOutput) {
|
||||||
if (i->system != "") attrs["system"] = i->system;
|
if (i.system != "") attrs["system"] = i.system;
|
||||||
}
|
}
|
||||||
else if (printSystem)
|
else if (printSystem)
|
||||||
columns.push_back(i->system);
|
columns.push_back(i.system);
|
||||||
|
|
||||||
if (printDrvPath) {
|
if (printDrvPath) {
|
||||||
string drvPath = i->queryDrvPath();
|
string drvPath = i.queryDrvPath();
|
||||||
if (xmlOutput) {
|
if (xmlOutput) {
|
||||||
if (drvPath != "") attrs["drvPath"] = drvPath;
|
if (drvPath != "") attrs["drvPath"] = drvPath;
|
||||||
} else
|
} else
|
||||||
@@ -1078,18 +1076,18 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (printOutPath && !xmlOutput) {
|
if (printOutPath && !xmlOutput) {
|
||||||
DrvInfo::Outputs outputs = i->queryOutputs();
|
DrvInfo::Outputs outputs = i.queryOutputs();
|
||||||
string s;
|
string s;
|
||||||
foreach (DrvInfo::Outputs::iterator, j, outputs) {
|
for (auto & j : outputs) {
|
||||||
if (!s.empty()) s += ';';
|
if (!s.empty()) s += ';';
|
||||||
if (j->first != "out") { s += j->first; s += "="; }
|
if (j.first != "out") { s += j.first; s += "="; }
|
||||||
s += j->second;
|
s += j.second;
|
||||||
}
|
}
|
||||||
columns.push_back(s);
|
columns.push_back(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (printDescription) {
|
if (printDescription) {
|
||||||
string descr = i->queryMetaString("description");
|
string descr = i.queryMetaString("description");
|
||||||
if (xmlOutput) {
|
if (xmlOutput) {
|
||||||
if (descr != "") attrs["description"] = descr;
|
if (descr != "") attrs["description"] = descr;
|
||||||
} else
|
} else
|
||||||
@@ -1100,22 +1098,22 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
if (printOutPath || printMeta) {
|
if (printOutPath || printMeta) {
|
||||||
XMLOpenElement item(xml, "item", attrs);
|
XMLOpenElement item(xml, "item", attrs);
|
||||||
if (printOutPath) {
|
if (printOutPath) {
|
||||||
DrvInfo::Outputs outputs = i->queryOutputs();
|
DrvInfo::Outputs outputs = i.queryOutputs();
|
||||||
foreach (DrvInfo::Outputs::iterator, j, outputs) {
|
for (auto & j : outputs) {
|
||||||
XMLAttrs attrs2;
|
XMLAttrs attrs2;
|
||||||
attrs2["name"] = j->first;
|
attrs2["name"] = j.first;
|
||||||
attrs2["path"] = j->second;
|
attrs2["path"] = j.second;
|
||||||
xml.writeEmptyElement("output", attrs2);
|
xml.writeEmptyElement("output", attrs2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (printMeta) {
|
if (printMeta) {
|
||||||
StringSet metaNames = i->queryMetaNames();
|
StringSet metaNames = i.queryMetaNames();
|
||||||
foreach (StringSet::iterator, j, metaNames) {
|
for (auto & j : metaNames) {
|
||||||
XMLAttrs attrs2;
|
XMLAttrs attrs2;
|
||||||
attrs2["name"] = *j;
|
attrs2["name"] = j;
|
||||||
Value * v = i->queryMeta(*j);
|
Value * v = i.queryMeta(j);
|
||||||
if (!v)
|
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 {
|
else {
|
||||||
if (v->type == tString) {
|
if (v->type == tString) {
|
||||||
attrs2["type"] = "string";
|
attrs2["type"] = "string";
|
||||||
@@ -1129,13 +1127,13 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
attrs2["type"] = "bool";
|
attrs2["type"] = "bool";
|
||||||
attrs2["value"] = v->boolean ? "true" : "false";
|
attrs2["value"] = v->boolean ? "true" : "false";
|
||||||
xml.writeEmptyElement("meta", attrs2);
|
xml.writeEmptyElement("meta", attrs2);
|
||||||
} else if (v->type == tList) {
|
} else if (v->isList()) {
|
||||||
attrs2["type"] = "strings";
|
attrs2["type"] = "strings";
|
||||||
XMLOpenElement m(xml, "meta", attrs2);
|
XMLOpenElement m(xml, "meta", attrs2);
|
||||||
for (unsigned int j = 0; j < v->list.length; ++j) {
|
for (unsigned int j = 0; j < v->listSize(); ++j) {
|
||||||
if (v->list.elems[j]->type != tString) continue;
|
if (v->listElems()[j]->type != tString) continue;
|
||||||
XMLAttrs attrs3;
|
XMLAttrs attrs3;
|
||||||
attrs3["value"] = v->list.elems[j]->string.s;
|
attrs3["value"] = v->listElems()[j]->string.s;
|
||||||
xml.writeEmptyElement("string", attrs3);
|
xml.writeEmptyElement("string", attrs3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1150,9 +1148,9 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
cout.flush();
|
cout.flush();
|
||||||
|
|
||||||
} catch (AssertionError & e) {
|
} 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) {
|
} 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;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1187,10 +1185,10 @@ static void switchGeneration(Globals & globals, int dstGen)
|
|||||||
Generations gens = findGenerations(globals.profile, curGen);
|
Generations gens = findGenerations(globals.profile, curGen);
|
||||||
|
|
||||||
Generation dst;
|
Generation dst;
|
||||||
for (Generations::iterator i = gens.begin(); i != gens.end(); ++i)
|
for (auto & i : gens)
|
||||||
if ((dstGen == prevGen && i->number < curGen) ||
|
if ((dstGen == prevGen && i.number < curGen) ||
|
||||||
(dstGen >= 0 && i->number == dstGen))
|
(dstGen >= 0 && i.number == dstGen))
|
||||||
dst = *i;
|
dst = i;
|
||||||
|
|
||||||
if (!dst) {
|
if (!dst) {
|
||||||
if (dstGen == prevGen)
|
if (dstGen == prevGen)
|
||||||
@@ -1250,14 +1248,14 @@ static void opListGenerations(Globals & globals, Strings opFlags, Strings opArgs
|
|||||||
|
|
||||||
RunPager pager;
|
RunPager pager;
|
||||||
|
|
||||||
for (Generations::iterator i = gens.begin(); i != gens.end(); ++i) {
|
for (auto & i : gens) {
|
||||||
tm t;
|
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")
|
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_year + 1900) % (t.tm_mon + 1) % t.tm_mday
|
||||||
% t.tm_hour % t.tm_min % t.tm_sec
|
% 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)
|
int main(int argc, char * * argv)
|
||||||
{
|
{
|
||||||
return handleExceptions(argv[0], [&]() {
|
return handleExceptions(argv[0], [&]() {
|
||||||
@@ -1313,7 +1317,7 @@ int main(int argc, char * * argv)
|
|||||||
if (*arg == "--help")
|
if (*arg == "--help")
|
||||||
showManPage("nix-env");
|
showManPage("nix-env");
|
||||||
else if (*arg == "--version")
|
else if (*arg == "--version")
|
||||||
printVersion("nix-env");
|
op = opVersion;
|
||||||
else if (*arg == "--install" || *arg == "-i")
|
else if (*arg == "--install" || *arg == "-i")
|
||||||
op = opInstall;
|
op = opInstall;
|
||||||
else if (parseAutoArgs(arg, end, autoArgs_))
|
else if (parseAutoArgs(arg, end, autoArgs_))
|
||||||
|
|||||||
+23
-23
@@ -33,9 +33,9 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
|||||||
/* Build the components in the user environment, if they don't
|
/* Build the components in the user environment, if they don't
|
||||||
exist already. */
|
exist already. */
|
||||||
PathSet drvsToBuild;
|
PathSet drvsToBuild;
|
||||||
foreach (DrvInfos::iterator, i, elems)
|
for (auto & i : elems)
|
||||||
if (i->queryDrvPath() != "")
|
if (i.queryDrvPath() != "")
|
||||||
drvsToBuild.insert(i->queryDrvPath());
|
drvsToBuild.insert(i.queryDrvPath());
|
||||||
|
|
||||||
debug(format("building user environment dependencies"));
|
debug(format("building user environment dependencies"));
|
||||||
store->buildPaths(drvsToBuild, state.repair ? bmRepair : bmNormal);
|
store->buildPaths(drvsToBuild, state.repair ? bmRepair : bmNormal);
|
||||||
@@ -45,51 +45,51 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
|||||||
Value manifest;
|
Value manifest;
|
||||||
state.mkList(manifest, elems.size());
|
state.mkList(manifest, elems.size());
|
||||||
unsigned int n = 0;
|
unsigned int n = 0;
|
||||||
foreach (DrvInfos::iterator, i, elems) {
|
for (auto & i : elems) {
|
||||||
/* Create a pseudo-derivation containing the name, system,
|
/* Create a pseudo-derivation containing the name, system,
|
||||||
output paths, and optionally the derivation path, as well
|
output paths, and optionally the derivation path, as well
|
||||||
as the meta attributes. */
|
as the meta attributes. */
|
||||||
Path drvPath = keepDerivations ? i->queryDrvPath() : "";
|
Path drvPath = keepDerivations ? i.queryDrvPath() : "";
|
||||||
|
|
||||||
Value & v(*state.allocValue());
|
Value & v(*state.allocValue());
|
||||||
manifest.list.elems[n++] = &v;
|
manifest.listElems()[n++] = &v;
|
||||||
state.mkAttrs(v, 16);
|
state.mkAttrs(v, 16);
|
||||||
|
|
||||||
mkString(*state.allocAttr(v, state.sType), "derivation");
|
mkString(*state.allocAttr(v, state.sType), "derivation");
|
||||||
mkString(*state.allocAttr(v, state.sName), i->name);
|
mkString(*state.allocAttr(v, state.sName), i.name);
|
||||||
if (!i->system.empty())
|
if (!i.system.empty())
|
||||||
mkString(*state.allocAttr(v, state.sSystem), i->system);
|
mkString(*state.allocAttr(v, state.sSystem), i.system);
|
||||||
mkString(*state.allocAttr(v, state.sOutPath), i->queryOutPath());
|
mkString(*state.allocAttr(v, state.sOutPath), i.queryOutPath());
|
||||||
if (drvPath != "")
|
if (drvPath != "")
|
||||||
mkString(*state.allocAttr(v, state.sDrvPath), i->queryDrvPath());
|
mkString(*state.allocAttr(v, state.sDrvPath), i.queryDrvPath());
|
||||||
|
|
||||||
// Copy each output.
|
// Copy each output.
|
||||||
DrvInfo::Outputs outputs = i->queryOutputs();
|
DrvInfo::Outputs outputs = i.queryOutputs();
|
||||||
Value & vOutputs = *state.allocAttr(v, state.sOutputs);
|
Value & vOutputs = *state.allocAttr(v, state.sOutputs);
|
||||||
state.mkList(vOutputs, outputs.size());
|
state.mkList(vOutputs, outputs.size());
|
||||||
unsigned int m = 0;
|
unsigned int m = 0;
|
||||||
foreach (DrvInfo::Outputs::iterator, j, outputs) {
|
for (auto & j : outputs) {
|
||||||
mkString(*(vOutputs.list.elems[m++] = state.allocValue()), j->first);
|
mkString(*(vOutputs.listElems()[m++] = state.allocValue()), j.first);
|
||||||
Value & vOutputs = *state.allocAttr(v, state.symbols.create(j->first));
|
Value & vOutputs = *state.allocAttr(v, state.symbols.create(j.first));
|
||||||
state.mkAttrs(vOutputs, 2);
|
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.,
|
/* This is only necessary when installing store paths, e.g.,
|
||||||
`nix-env -i /nix/store/abcd...-foo'. */
|
`nix-env -i /nix/store/abcd...-foo'. */
|
||||||
store->addTempRoot(j->second);
|
store->addTempRoot(j.second);
|
||||||
store->ensurePath(j->second);
|
store->ensurePath(j.second);
|
||||||
|
|
||||||
references.insert(j->second);
|
references.insert(j.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the meta attributes.
|
// Copy the meta attributes.
|
||||||
Value & vMeta = *state.allocAttr(v, state.sMeta);
|
Value & vMeta = *state.allocAttr(v, state.sMeta);
|
||||||
state.mkAttrs(vMeta, 16);
|
state.mkAttrs(vMeta, 16);
|
||||||
StringSet metaNames = i->queryMetaNames();
|
StringSet metaNames = i.queryMetaNames();
|
||||||
foreach (StringSet::iterator, j, metaNames) {
|
for (auto & j : metaNames) {
|
||||||
Value * v = i->queryMeta(*j);
|
Value * v = i.queryMeta(j);
|
||||||
if (!v) continue;
|
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();
|
vMeta.attrs->sort();
|
||||||
v.attrs->sort();
|
v.attrs->sort();
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ void processExpr(EvalState & state, const Strings & attrPaths,
|
|||||||
Value vRoot;
|
Value vRoot;
|
||||||
state.eval(e, vRoot);
|
state.eval(e, vRoot);
|
||||||
|
|
||||||
foreach (Strings::const_iterator, i, attrPaths) {
|
for (auto & i : attrPaths) {
|
||||||
Value & v(*findAlongAttrPath(state, *i, autoArgs, vRoot));
|
Value & v(*findAlongAttrPath(state, i, autoArgs, vRoot));
|
||||||
state.forceValue(v);
|
state.forceValue(v);
|
||||||
|
|
||||||
PathSet context;
|
PathSet context;
|
||||||
@@ -67,11 +67,11 @@ void processExpr(EvalState & state, const Strings & attrPaths,
|
|||||||
} else {
|
} else {
|
||||||
DrvInfos drvs;
|
DrvInfos drvs;
|
||||||
getDerivations(state, v, "", autoArgs, drvs, false);
|
getDerivations(state, v, "", autoArgs, drvs, false);
|
||||||
foreach (DrvInfos::iterator, i, drvs) {
|
for (auto & i : drvs) {
|
||||||
Path drvPath = i->queryDrvPath();
|
Path drvPath = i.queryDrvPath();
|
||||||
|
|
||||||
/* What output do we want? */
|
/* What output do we want? */
|
||||||
string outputName = i->queryOutputName();
|
string outputName = i.queryOutputName();
|
||||||
if (outputName == "")
|
if (outputName == "")
|
||||||
throw Error(format("derivation ‘%1%’ lacks an ‘outputName’ attribute ") % drvPath);
|
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 (attrPaths.empty()) attrPaths.push_back("");
|
||||||
|
|
||||||
if (findFile) {
|
if (findFile) {
|
||||||
foreach (Strings::iterator, i, files) {
|
for (auto & i : files) {
|
||||||
Path p = state.findFile(*i);
|
Path p = state.findFile(i);
|
||||||
if (p == "") throw Error(format("unable to find ‘%1%’") % *i);
|
if (p == "") throw Error(format("unable to find ‘%1%’") % i);
|
||||||
std::cout << p << std::endl;
|
std::cout << p << std::endl;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|||||||
+189
-172
@@ -69,13 +69,13 @@ static PathSet realisePath(Path path, bool build = true)
|
|||||||
rootNr++;
|
rootNr++;
|
||||||
|
|
||||||
if (p.second.empty())
|
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;
|
PathSet outputs;
|
||||||
foreach (StringSet::iterator, j, p.second) {
|
for (auto & j : p.second) {
|
||||||
DerivationOutputs::iterator i = drv.outputs.find(*j);
|
DerivationOutputs::iterator i = drv.outputs.find(j);
|
||||||
if (i == drv.outputs.end())
|
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;
|
Path outPath = i->second.path;
|
||||||
if (gcRoot == "")
|
if (gcRoot == "")
|
||||||
printGCWarning();
|
printGCWarning();
|
||||||
@@ -113,16 +113,16 @@ static void opRealise(Strings opFlags, Strings opArgs)
|
|||||||
BuildMode buildMode = bmNormal;
|
BuildMode buildMode = bmNormal;
|
||||||
bool ignoreUnknown = false;
|
bool ignoreUnknown = false;
|
||||||
|
|
||||||
foreach (Strings::iterator, i, opFlags)
|
for (auto & i : opFlags)
|
||||||
if (*i == "--dry-run") dryRun = true;
|
if (i == "--dry-run") dryRun = true;
|
||||||
else if (*i == "--repair") buildMode = bmRepair;
|
else if (i == "--repair") buildMode = bmRepair;
|
||||||
else if (*i == "--check") buildMode = bmCheck;
|
else if (i == "--check") buildMode = bmCheck;
|
||||||
else if (*i == "--ignore-unknown") ignoreUnknown = true;
|
else if (i == "--ignore-unknown") ignoreUnknown = true;
|
||||||
else throw UsageError(format("unknown flag ‘%1%’") % *i);
|
else throw UsageError(format("unknown flag ‘%1%’") % i);
|
||||||
|
|
||||||
Paths paths;
|
Paths paths;
|
||||||
foreach (Strings::iterator, i, opArgs) {
|
for (auto & i : opArgs) {
|
||||||
DrvPathWithOutputs p = parseDrvPathWithOutputs(*i);
|
DrvPathWithOutputs p = parseDrvPathWithOutputs(i);
|
||||||
paths.push_back(makeDrvPathWithOutputs(followLinksToStorePath(p.first), p.second));
|
paths.push_back(makeDrvPathWithOutputs(followLinksToStorePath(p.first), p.second));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,8 +133,8 @@ static void opRealise(Strings opFlags, Strings opArgs)
|
|||||||
|
|
||||||
if (ignoreUnknown) {
|
if (ignoreUnknown) {
|
||||||
Paths paths2;
|
Paths paths2;
|
||||||
foreach (Paths::iterator, i, paths)
|
for (auto & i : paths)
|
||||||
if (unknown.find(*i) == unknown.end()) paths2.push_back(*i);
|
if (unknown.find(i) == unknown.end()) paths2.push_back(i);
|
||||||
paths = paths2;
|
paths = paths2;
|
||||||
unknown = PathSet();
|
unknown = PathSet();
|
||||||
}
|
}
|
||||||
@@ -148,11 +148,11 @@ static void opRealise(Strings opFlags, Strings opArgs)
|
|||||||
store->buildPaths(PathSet(paths.begin(), paths.end()), buildMode);
|
store->buildPaths(PathSet(paths.begin(), paths.end()), buildMode);
|
||||||
|
|
||||||
if (!ignoreUnknown)
|
if (!ignoreUnknown)
|
||||||
foreach (Paths::iterator, i, paths) {
|
for (auto & i : paths) {
|
||||||
PathSet paths = realisePath(*i, false);
|
PathSet paths = realisePath(i, false);
|
||||||
if (!noOutput)
|
if (!noOutput)
|
||||||
foreach (PathSet::iterator, j, paths)
|
for (auto & j : paths)
|
||||||
cout << format("%1%\n") % *j;
|
cout << format("%1%\n") % j;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,10 +173,9 @@ static void opAddFixed(Strings opFlags, Strings opArgs)
|
|||||||
{
|
{
|
||||||
bool recursive = false;
|
bool recursive = false;
|
||||||
|
|
||||||
for (Strings::iterator i = opFlags.begin();
|
for (auto & i : opFlags)
|
||||||
i != opFlags.end(); ++i)
|
if (i == "--recursive") recursive = true;
|
||||||
if (*i == "--recursive") recursive = true;
|
else throw UsageError(format("unknown flag ‘%1%’") % i);
|
||||||
else throw UsageError(format("unknown flag ‘%1%’") % *i);
|
|
||||||
|
|
||||||
if (opArgs.empty())
|
if (opArgs.empty())
|
||||||
throw UsageError("first argument must be hash algorithm");
|
throw UsageError("first argument must be hash algorithm");
|
||||||
@@ -194,10 +193,9 @@ static void opPrintFixedPath(Strings opFlags, Strings opArgs)
|
|||||||
{
|
{
|
||||||
bool recursive = false;
|
bool recursive = false;
|
||||||
|
|
||||||
for (Strings::iterator i = opFlags.begin();
|
for (auto i : opFlags)
|
||||||
i != opFlags.end(); ++i)
|
if (i == "--recursive") recursive = true;
|
||||||
if (*i == "--recursive") recursive = true;
|
else throw UsageError(format("unknown flag ‘%1%’") % i);
|
||||||
else throw UsageError(format("unknown flag ‘%1%’") % *i);
|
|
||||||
|
|
||||||
if (opArgs.size() != 3)
|
if (opArgs.size() != 3)
|
||||||
throw UsageError(format("‘--print-fixed-path’ requires three arguments"));
|
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)) {
|
if (useOutput && isDerivation(storePath)) {
|
||||||
Derivation drv = derivationFromPath(*store, storePath);
|
Derivation drv = derivationFromPath(*store, storePath);
|
||||||
PathSet outputs;
|
PathSet outputs;
|
||||||
foreach (DerivationOutputs::iterator, i, drv.outputs)
|
for (auto & i : drv.outputs)
|
||||||
outputs.insert(i->second.path);
|
outputs.insert(i.second.path);
|
||||||
return outputs;
|
return outputs;
|
||||||
}
|
}
|
||||||
else return singleton<PathSet>(storePath);
|
else return singleton<PathSet>(storePath);
|
||||||
@@ -257,8 +255,8 @@ static void printTree(const Path & path,
|
|||||||
Paths sorted = topoSortPaths(*store, references);
|
Paths sorted = topoSortPaths(*store, references);
|
||||||
reverse(sorted.begin(), sorted.end());
|
reverse(sorted.begin(), sorted.end());
|
||||||
|
|
||||||
foreach (Paths::iterator, i, sorted) {
|
for (auto i = sorted.begin(); i != sorted.end(); ++i) {
|
||||||
Paths::iterator j = i; ++j;
|
auto j = i; ++j;
|
||||||
printTree(*i, tailPad + treeConn,
|
printTree(*i, tailPad + treeConn,
|
||||||
j == sorted.end() ? tailPad + treeNull : tailPad + treeLine,
|
j == sorted.end() ? tailPad + treeNull : tailPad + treeLine,
|
||||||
done);
|
done);
|
||||||
@@ -279,34 +277,34 @@ static void opQuery(Strings opFlags, Strings opArgs)
|
|||||||
bool forceRealise = false;
|
bool forceRealise = false;
|
||||||
string bindingName;
|
string bindingName;
|
||||||
|
|
||||||
foreach (Strings::iterator, i, opFlags) {
|
for (auto & i : opFlags) {
|
||||||
QueryType prev = query;
|
QueryType prev = query;
|
||||||
if (*i == "--outputs") query = qOutputs;
|
if (i == "--outputs") query = qOutputs;
|
||||||
else if (*i == "--requisites" || *i == "-R") query = qRequisites;
|
else if (i == "--requisites" || i == "-R") query = qRequisites;
|
||||||
else if (*i == "--references") query = qReferences;
|
else if (i == "--references") query = qReferences;
|
||||||
else if (*i == "--referrers" || *i == "--referers") query = qReferrers;
|
else if (i == "--referrers" || i == "--referers") query = qReferrers;
|
||||||
else if (*i == "--referrers-closure" || *i == "--referers-closure") query = qReferrersClosure;
|
else if (i == "--referrers-closure" || i == "--referers-closure") query = qReferrersClosure;
|
||||||
else if (*i == "--deriver" || *i == "-d") query = qDeriver;
|
else if (i == "--deriver" || i == "-d") query = qDeriver;
|
||||||
else if (*i == "--binding" || *i == "-b") {
|
else if (i == "--binding" || i == "-b") {
|
||||||
if (opArgs.size() == 0)
|
if (opArgs.size() == 0)
|
||||||
throw UsageError("expected binding name");
|
throw UsageError("expected binding name");
|
||||||
bindingName = opArgs.front();
|
bindingName = opArgs.front();
|
||||||
opArgs.pop_front();
|
opArgs.pop_front();
|
||||||
query = qBinding;
|
query = qBinding;
|
||||||
}
|
}
|
||||||
else if (*i == "--hash") query = qHash;
|
else if (i == "--hash") query = qHash;
|
||||||
else if (*i == "--size") query = qSize;
|
else if (i == "--size") query = qSize;
|
||||||
else if (*i == "--tree") query = qTree;
|
else if (i == "--tree") query = qTree;
|
||||||
else if (*i == "--graph") query = qGraph;
|
else if (i == "--graph") query = qGraph;
|
||||||
else if (*i == "--xml") query = qXml;
|
else if (i == "--xml") query = qXml;
|
||||||
else if (*i == "--resolve") query = qResolve;
|
else if (i == "--resolve") query = qResolve;
|
||||||
else if (*i == "--roots") query = qRoots;
|
else if (i == "--roots") query = qRoots;
|
||||||
else if (*i == "--use-output" || *i == "-u") useOutput = true;
|
else if (i == "--use-output" || i == "-u") useOutput = true;
|
||||||
else if (*i == "--force-realise" || *i == "--force-realize" || *i == "-f") forceRealise = true;
|
else if (i == "--force-realise" || i == "--force-realize" || i == "-f") forceRealise = true;
|
||||||
else if (*i == "--include-outputs") includeOutputs = true;
|
else if (i == "--include-outputs") includeOutputs = true;
|
||||||
else throw UsageError(format("unknown flag ‘%1%’") % *i);
|
else throw UsageError(format("unknown flag ‘%1%’") % i);
|
||||||
if (prev != qDefault && prev != query)
|
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;
|
if (query == qDefault) query = qOutputs;
|
||||||
@@ -316,12 +314,12 @@ static void opQuery(Strings opFlags, Strings opArgs)
|
|||||||
switch (query) {
|
switch (query) {
|
||||||
|
|
||||||
case qOutputs: {
|
case qOutputs: {
|
||||||
foreach (Strings::iterator, i, opArgs) {
|
for (auto & i : opArgs) {
|
||||||
*i = followLinksToStorePath(*i);
|
i = followLinksToStorePath(i);
|
||||||
if (forceRealise) realisePath(*i);
|
if (forceRealise) realisePath(i);
|
||||||
Derivation drv = derivationFromPath(*store, *i);
|
Derivation drv = derivationFromPath(*store, i);
|
||||||
foreach (DerivationOutputs::iterator, j, drv.outputs)
|
for (auto & j : drv.outputs)
|
||||||
cout << format("%1%\n") % j->second.path;
|
cout << format("%1%\n") % j.second.path;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -331,13 +329,13 @@ static void opQuery(Strings opFlags, Strings opArgs)
|
|||||||
case qReferrers:
|
case qReferrers:
|
||||||
case qReferrersClosure: {
|
case qReferrersClosure: {
|
||||||
PathSet paths;
|
PathSet paths;
|
||||||
foreach (Strings::iterator, i, opArgs) {
|
for (auto & i : opArgs) {
|
||||||
PathSet ps = maybeUseOutputs(followLinksToStorePath(*i), useOutput, forceRealise);
|
PathSet ps = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise);
|
||||||
foreach (PathSet::iterator, j, ps) {
|
for (auto & j : ps) {
|
||||||
if (query == qRequisites) computeFSClosure(*store, *j, paths, false, includeOutputs);
|
if (query == qRequisites) computeFSClosure(*store, j, paths, false, includeOutputs);
|
||||||
else if (query == qReferences) store->queryReferences(*j, paths);
|
else if (query == qReferences) store->queryReferences(j, paths);
|
||||||
else if (query == qReferrers) store->queryReferrers(*j, paths);
|
else if (query == qReferrers) store->queryReferrers(j, paths);
|
||||||
else if (query == qReferrersClosure) computeFSClosure(*store, *j, paths, true);
|
else if (query == qReferrersClosure) computeFSClosure(*store, j, paths, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Paths sorted = topoSortPaths(*store, paths);
|
Paths sorted = topoSortPaths(*store, paths);
|
||||||
@@ -348,16 +346,16 @@ static void opQuery(Strings opFlags, Strings opArgs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
case qDeriver:
|
case qDeriver:
|
||||||
foreach (Strings::iterator, i, opArgs) {
|
for (auto & i : opArgs) {
|
||||||
Path deriver = store->queryDeriver(followLinksToStorePath(*i));
|
Path deriver = store->queryDeriver(followLinksToStorePath(i));
|
||||||
cout << format("%1%\n") %
|
cout << format("%1%\n") %
|
||||||
(deriver == "" ? "unknown-deriver" : deriver);
|
(deriver == "" ? "unknown-deriver" : deriver);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case qBinding:
|
case qBinding:
|
||||||
foreach (Strings::iterator, i, opArgs) {
|
for (auto & i : opArgs) {
|
||||||
Path path = useDeriver(followLinksToStorePath(*i));
|
Path path = useDeriver(followLinksToStorePath(i));
|
||||||
Derivation drv = derivationFromPath(*store, path);
|
Derivation drv = derivationFromPath(*store, path);
|
||||||
StringPairs::iterator j = drv.env.find(bindingName);
|
StringPairs::iterator j = drv.env.find(bindingName);
|
||||||
if (j == drv.env.end())
|
if (j == drv.env.end())
|
||||||
@@ -369,10 +367,10 @@ static void opQuery(Strings opFlags, Strings opArgs)
|
|||||||
|
|
||||||
case qHash:
|
case qHash:
|
||||||
case qSize:
|
case qSize:
|
||||||
foreach (Strings::iterator, i, opArgs) {
|
for (auto & i : opArgs) {
|
||||||
PathSet paths = maybeUseOutputs(followLinksToStorePath(*i), useOutput, forceRealise);
|
PathSet paths = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise);
|
||||||
foreach (PathSet::iterator, j, paths) {
|
for (auto & j : paths) {
|
||||||
ValidPathInfo info = store->queryPathInfo(*j);
|
ValidPathInfo info = store->queryPathInfo(j);
|
||||||
if (query == qHash) {
|
if (query == qHash) {
|
||||||
assert(info.hash.type == htSHA256);
|
assert(info.hash.type == htSHA256);
|
||||||
cout << format("sha256:%1%\n") % printHash32(info.hash);
|
cout << format("sha256:%1%\n") % printHash32(info.hash);
|
||||||
@@ -384,15 +382,15 @@ static void opQuery(Strings opFlags, Strings opArgs)
|
|||||||
|
|
||||||
case qTree: {
|
case qTree: {
|
||||||
PathSet done;
|
PathSet done;
|
||||||
foreach (Strings::iterator, i, opArgs)
|
for (auto & i : opArgs)
|
||||||
printTree(followLinksToStorePath(*i), "", "", done);
|
printTree(followLinksToStorePath(i), "", "", done);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case qGraph: {
|
case qGraph: {
|
||||||
PathSet roots;
|
PathSet roots;
|
||||||
foreach (Strings::iterator, i, opArgs) {
|
for (auto & i : opArgs) {
|
||||||
PathSet paths = maybeUseOutputs(followLinksToStorePath(*i), useOutput, forceRealise);
|
PathSet paths = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise);
|
||||||
roots.insert(paths.begin(), paths.end());
|
roots.insert(paths.begin(), paths.end());
|
||||||
}
|
}
|
||||||
printDotGraph(roots);
|
printDotGraph(roots);
|
||||||
@@ -401,8 +399,8 @@ static void opQuery(Strings opFlags, Strings opArgs)
|
|||||||
|
|
||||||
case qXml: {
|
case qXml: {
|
||||||
PathSet roots;
|
PathSet roots;
|
||||||
foreach (Strings::iterator, i, opArgs) {
|
for (auto & i : opArgs) {
|
||||||
PathSet paths = maybeUseOutputs(followLinksToStorePath(*i), useOutput, forceRealise);
|
PathSet paths = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise);
|
||||||
roots.insert(paths.begin(), paths.end());
|
roots.insert(paths.begin(), paths.end());
|
||||||
}
|
}
|
||||||
printXmlGraph(roots);
|
printXmlGraph(roots);
|
||||||
@@ -410,23 +408,23 @@ static void opQuery(Strings opFlags, Strings opArgs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
case qResolve: {
|
case qResolve: {
|
||||||
foreach (Strings::iterator, i, opArgs)
|
for (auto & i : opArgs)
|
||||||
cout << format("%1%\n") % followLinksToStorePath(*i);
|
cout << format("%1%\n") % followLinksToStorePath(i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case qRoots: {
|
case qRoots: {
|
||||||
PathSet referrers;
|
PathSet referrers;
|
||||||
foreach (Strings::iterator, i, opArgs) {
|
for (auto & i : opArgs) {
|
||||||
PathSet paths = maybeUseOutputs(followLinksToStorePath(*i), useOutput, forceRealise);
|
PathSet paths = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise);
|
||||||
foreach (PathSet::iterator, j, paths)
|
for (auto & j : paths)
|
||||||
computeFSClosure(*store, *j, referrers, true,
|
computeFSClosure(*store, j, referrers, true,
|
||||||
settings.gcKeepOutputs, settings.gcKeepDerivations);
|
settings.gcKeepOutputs, settings.gcKeepDerivations);
|
||||||
}
|
}
|
||||||
Roots roots = store->findRoots();
|
Roots roots = store->findRoots();
|
||||||
foreach (Roots::iterator, i, roots)
|
for (auto & i : roots)
|
||||||
if (referrers.find(i->second) != referrers.end())
|
if (referrers.find(i.second) != referrers.end())
|
||||||
cout << format("%1%\n") % i->first;
|
cout << format("%1%\n") % i.first;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -439,8 +437,8 @@ static void opQuery(Strings opFlags, Strings opArgs)
|
|||||||
static string shellEscape(const string & s)
|
static string shellEscape(const string & s)
|
||||||
{
|
{
|
||||||
string r;
|
string r;
|
||||||
foreach (string::const_iterator, i, s)
|
for (auto & i : s)
|
||||||
if (*i == '\'') r += "'\\''"; else r += *i;
|
if (i == '\'') r += "'\\''"; else r += i;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -455,15 +453,17 @@ static void opPrintEnv(Strings opFlags, Strings opArgs)
|
|||||||
|
|
||||||
/* Print each environment variable in the derivation in a format
|
/* Print each environment variable in the derivation in a format
|
||||||
that can be sourced by the shell. */
|
that can be sourced by the shell. */
|
||||||
foreach (StringPairs::iterator, i, drv.env)
|
for (auto & i : drv.env)
|
||||||
cout << format("export %1%; %1%='%2%'\n") % i->first % shellEscape(i->second);
|
cout << format("export %1%; %1%='%2%'\n") % i.first % shellEscape(i.second);
|
||||||
|
|
||||||
/* Also output the arguments. This doesn't preserve whitespace in
|
/* Also output the arguments. This doesn't preserve whitespace in
|
||||||
arguments. */
|
arguments. */
|
||||||
cout << "export _args; _args='";
|
cout << "export _args; _args='";
|
||||||
foreach (Strings::iterator, i, drv.args) {
|
bool first = true;
|
||||||
if (i != drv.args.begin()) cout << ' ';
|
for (auto & i : drv.args) {
|
||||||
cout << shellEscape(*i);
|
if (!first) cout << ' ';
|
||||||
|
first = false;
|
||||||
|
cout << shellEscape(i);
|
||||||
}
|
}
|
||||||
cout << "'\n";
|
cout << "'\n";
|
||||||
}
|
}
|
||||||
@@ -475,8 +475,8 @@ static void opReadLog(Strings opFlags, Strings opArgs)
|
|||||||
|
|
||||||
RunPager pager;
|
RunPager pager;
|
||||||
|
|
||||||
foreach (Strings::iterator, i, opArgs) {
|
for (auto & i : opArgs) {
|
||||||
Path path = useDeriver(followLinksToStorePath(*i));
|
Path path = useDeriver(followLinksToStorePath(i));
|
||||||
|
|
||||||
string baseName = baseNameOf(path);
|
string baseName = baseNameOf(path);
|
||||||
bool found = false;
|
bool found = false;
|
||||||
@@ -547,8 +547,8 @@ static void opDumpDB(Strings opFlags, Strings opArgs)
|
|||||||
if (!opArgs.empty())
|
if (!opArgs.empty())
|
||||||
throw UsageError("no arguments expected");
|
throw UsageError("no arguments expected");
|
||||||
PathSet validPaths = store->queryAllValidPaths();
|
PathSet validPaths = store->queryAllValidPaths();
|
||||||
foreach (PathSet::iterator, i, validPaths)
|
for (auto & i : validPaths)
|
||||||
cout << store->makeValidityRegistration(singleton<PathSet>(*i), true, true);
|
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 reregister = false; // !!! maybe this should be the default
|
||||||
bool hashGiven = false;
|
bool hashGiven = false;
|
||||||
|
|
||||||
for (Strings::iterator i = opFlags.begin();
|
for (auto & i : opFlags)
|
||||||
i != opFlags.end(); ++i)
|
if (i == "--reregister") reregister = true;
|
||||||
if (*i == "--reregister") reregister = true;
|
else if (i == "--hash-given") hashGiven = true;
|
||||||
else if (*i == "--hash-given") hashGiven = true;
|
else throw UsageError(format("unknown flag ‘%1%’") % i);
|
||||||
else throw UsageError(format("unknown flag ‘%1%’") % *i);
|
|
||||||
|
|
||||||
if (!opArgs.empty()) throw UsageError("no arguments expected");
|
if (!opArgs.empty()) throw UsageError("no arguments expected");
|
||||||
|
|
||||||
@@ -606,15 +605,12 @@ static void opCheckValidity(Strings opFlags, Strings opArgs)
|
|||||||
{
|
{
|
||||||
bool printInvalid = false;
|
bool printInvalid = false;
|
||||||
|
|
||||||
for (Strings::iterator i = opFlags.begin();
|
for (auto & i : opFlags)
|
||||||
i != opFlags.end(); ++i)
|
if (i == "--print-invalid") printInvalid = true;
|
||||||
if (*i == "--print-invalid") printInvalid = true;
|
else throw UsageError(format("unknown flag ‘%1%’") % i);
|
||||||
else throw UsageError(format("unknown flag ‘%1%’") % *i);
|
|
||||||
|
|
||||||
for (Strings::iterator i = opArgs.begin();
|
for (auto & i : opArgs) {
|
||||||
i != opArgs.end(); ++i)
|
Path path = followLinksToStorePath(i);
|
||||||
{
|
|
||||||
Path path = followLinksToStorePath(*i);
|
|
||||||
if (!store->isValidPath(path)) {
|
if (!store->isValidPath(path)) {
|
||||||
if (printInvalid)
|
if (printInvalid)
|
||||||
cout << format("%1%\n") % path;
|
cout << format("%1%\n") % path;
|
||||||
@@ -634,7 +630,7 @@ static void opGC(Strings opFlags, Strings opArgs)
|
|||||||
GCResults results;
|
GCResults results;
|
||||||
|
|
||||||
/* Do what? */
|
/* Do what? */
|
||||||
foreach (Strings::iterator, i, opFlags)
|
for (auto i = opFlags.begin(); i != opFlags.end(); ++i)
|
||||||
if (*i == "--print-roots") printRoots = true;
|
if (*i == "--print-roots") printRoots = true;
|
||||||
else if (*i == "--print-live") options.action = GCOptions::gcReturnLive;
|
else if (*i == "--print-live") options.action = GCOptions::gcReturnLive;
|
||||||
else if (*i == "--print-dead") options.action = GCOptions::gcReturnDead;
|
else if (*i == "--print-dead") options.action = GCOptions::gcReturnDead;
|
||||||
@@ -649,8 +645,8 @@ static void opGC(Strings opFlags, Strings opArgs)
|
|||||||
|
|
||||||
if (printRoots) {
|
if (printRoots) {
|
||||||
Roots roots = store->findRoots();
|
Roots roots = store->findRoots();
|
||||||
foreach (Roots::iterator, i, roots)
|
for (auto & i : roots)
|
||||||
cout << i->first << " -> " << i->second << std::endl;
|
cout << i.first << " -> " << i.second << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
@@ -658,8 +654,8 @@ static void opGC(Strings opFlags, Strings opArgs)
|
|||||||
store->collectGarbage(options, results);
|
store->collectGarbage(options, results);
|
||||||
|
|
||||||
if (options.action != GCOptions::gcDeleteDead)
|
if (options.action != GCOptions::gcDeleteDead)
|
||||||
foreach (PathSet::iterator, i, results.paths)
|
for (auto & i : results.paths)
|
||||||
cout << *i << std::endl;
|
cout << i << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -672,12 +668,12 @@ static void opDelete(Strings opFlags, Strings opArgs)
|
|||||||
GCOptions options;
|
GCOptions options;
|
||||||
options.action = GCOptions::gcDeleteSpecific;
|
options.action = GCOptions::gcDeleteSpecific;
|
||||||
|
|
||||||
foreach (Strings::iterator, i, opFlags)
|
for (auto & i : opFlags)
|
||||||
if (*i == "--ignore-liveness") options.ignoreLiveness = true;
|
if (i == "--ignore-liveness") options.ignoreLiveness = true;
|
||||||
else throw UsageError(format("unknown flag ‘%1%’") % *i);
|
else throw UsageError(format("unknown flag ‘%1%’") % i);
|
||||||
|
|
||||||
foreach (Strings::iterator, i, opArgs)
|
for (auto & i : opArgs)
|
||||||
options.pathsToDelete.insert(followLinksToStorePath(*i));
|
options.pathsToDelete.insert(followLinksToStorePath(i));
|
||||||
|
|
||||||
GCResults results;
|
GCResults results;
|
||||||
PrintFreed freed(true, results);
|
PrintFreed freed(true, results);
|
||||||
@@ -713,10 +709,9 @@ static void opRestore(Strings opFlags, Strings opArgs)
|
|||||||
static void opExport(Strings opFlags, Strings opArgs)
|
static void opExport(Strings opFlags, Strings opArgs)
|
||||||
{
|
{
|
||||||
bool sign = false;
|
bool sign = false;
|
||||||
for (Strings::iterator i = opFlags.begin();
|
for (auto & i : opFlags)
|
||||||
i != opFlags.end(); ++i)
|
if (i == "--sign") sign = true;
|
||||||
if (*i == "--sign") sign = true;
|
else throw UsageError(format("unknown flag ‘%1%’") % i);
|
||||||
else throw UsageError(format("unknown flag ‘%1%’") % *i);
|
|
||||||
|
|
||||||
FdSink sink(STDOUT_FILENO);
|
FdSink sink(STDOUT_FILENO);
|
||||||
Paths sorted = topoSortPaths(*store, PathSet(opArgs.begin(), opArgs.end()));
|
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)
|
static void opImport(Strings opFlags, Strings opArgs)
|
||||||
{
|
{
|
||||||
bool requireSignature = false;
|
bool requireSignature = false;
|
||||||
foreach (Strings::iterator, i, opFlags)
|
for (auto & i : opFlags)
|
||||||
if (*i == "--require-signature") requireSignature = true;
|
if (i == "--require-signature") requireSignature = true;
|
||||||
else throw UsageError(format("unknown flag ‘%1%’") % *i);
|
else throw UsageError(format("unknown flag ‘%1%’") % i);
|
||||||
|
|
||||||
if (!opArgs.empty()) throw UsageError("no arguments expected");
|
if (!opArgs.empty()) throw UsageError("no arguments expected");
|
||||||
|
|
||||||
FdSource source(STDIN_FILENO);
|
FdSource source(STDIN_FILENO);
|
||||||
Paths paths = store->importPaths(requireSignature, source);
|
Paths paths = store->importPaths(requireSignature, source);
|
||||||
|
|
||||||
foreach (Paths::iterator, i, paths)
|
for (auto & i : paths)
|
||||||
cout << format("%1%\n") % *i << std::flush;
|
cout << format("%1%\n") % i << std::flush;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -762,11 +757,10 @@ static void opVerify(Strings opFlags, Strings opArgs)
|
|||||||
bool checkContents = false;
|
bool checkContents = false;
|
||||||
bool repair = false;
|
bool repair = false;
|
||||||
|
|
||||||
for (Strings::iterator i = opFlags.begin();
|
for (auto & i : opFlags)
|
||||||
i != opFlags.end(); ++i)
|
if (i == "--check-contents") checkContents = true;
|
||||||
if (*i == "--check-contents") checkContents = true;
|
else if (i == "--repair") repair = true;
|
||||||
else if (*i == "--repair") repair = true;
|
else throw UsageError(format("unknown flag ‘%1%’") % i);
|
||||||
else throw UsageError(format("unknown flag ‘%1%’") % *i);
|
|
||||||
|
|
||||||
if (store->verifyStore(checkContents, repair)) {
|
if (store->verifyStore(checkContents, repair)) {
|
||||||
printMsg(lvlError, "warning: not all errors were fixed");
|
printMsg(lvlError, "warning: not all errors were fixed");
|
||||||
@@ -783,8 +777,8 @@ static void opVerifyPath(Strings opFlags, Strings opArgs)
|
|||||||
|
|
||||||
int status = 0;
|
int status = 0;
|
||||||
|
|
||||||
foreach (Strings::iterator, i, opArgs) {
|
for (auto & i : opArgs) {
|
||||||
Path path = followLinksToStorePath(*i);
|
Path path = followLinksToStorePath(i);
|
||||||
printMsg(lvlTalkative, format("checking path ‘%1%’...") % path);
|
printMsg(lvlTalkative, format("checking path ‘%1%’...") % path);
|
||||||
ValidPathInfo info = store->queryPathInfo(path);
|
ValidPathInfo info = store->queryPathInfo(path);
|
||||||
HashResult current = hashPath(info.hash.type, path);
|
HashResult current = hashPath(info.hash.type, path);
|
||||||
@@ -807,8 +801,8 @@ static void opRepairPath(Strings opFlags, Strings opArgs)
|
|||||||
if (!opFlags.empty())
|
if (!opFlags.empty())
|
||||||
throw UsageError("no flags expected");
|
throw UsageError("no flags expected");
|
||||||
|
|
||||||
foreach (Strings::iterator, i, opArgs) {
|
for (auto & i : opArgs) {
|
||||||
Path path = followLinksToStorePath(*i);
|
Path path = followLinksToStorePath(i);
|
||||||
ensureLocalStore().repairPath(path);
|
ensureLocalStore().repairPath(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -828,8 +822,8 @@ static void opQueryFailedPaths(Strings opFlags, Strings opArgs)
|
|||||||
if (!opArgs.empty() || !opFlags.empty())
|
if (!opArgs.empty() || !opFlags.empty())
|
||||||
throw UsageError("no arguments expected");
|
throw UsageError("no arguments expected");
|
||||||
PathSet failed = store->queryFailedPaths();
|
PathSet failed = store->queryFailedPaths();
|
||||||
foreach (PathSet::iterator, i, failed)
|
for (auto & i : failed)
|
||||||
cout << format("%1%\n") % *i;
|
cout << format("%1%\n") % i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -845,9 +839,9 @@ static void opClearFailedPaths(Strings opFlags, Strings opArgs)
|
|||||||
static void opServe(Strings opFlags, Strings opArgs)
|
static void opServe(Strings opFlags, Strings opArgs)
|
||||||
{
|
{
|
||||||
bool writeAllowed = false;
|
bool writeAllowed = false;
|
||||||
foreach (Strings::iterator, i, opFlags)
|
for (auto & i : opFlags)
|
||||||
if (*i == "--write") writeAllowed = true;
|
if (i == "--write") writeAllowed = true;
|
||||||
else throw UsageError(format("unknown flag ‘%1%’") % *i);
|
else throw UsageError(format("unknown flag ‘%1%’") % i);
|
||||||
|
|
||||||
if (!opArgs.empty()) throw UsageError("no arguments expected");
|
if (!opArgs.empty()) throw UsageError("no arguments expected");
|
||||||
|
|
||||||
@@ -857,11 +851,20 @@ static void opServe(Strings opFlags, Strings opArgs)
|
|||||||
/* Exchange the greeting. */
|
/* Exchange the greeting. */
|
||||||
unsigned int magic = readInt(in);
|
unsigned int magic = readInt(in);
|
||||||
if (magic != SERVE_MAGIC_1) throw Error("protocol mismatch");
|
if (magic != SERVE_MAGIC_1) throw Error("protocol mismatch");
|
||||||
writeInt(SERVE_MAGIC_2, out);
|
out << SERVE_MAGIC_2 << SERVE_PROTOCOL_VERSION;
|
||||||
writeInt(SERVE_PROTOCOL_VERSION, out);
|
|
||||||
out.flush();
|
out.flush();
|
||||||
readInt(in); // Client version, unused for now
|
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) {
|
while (true) {
|
||||||
ServeCommand cmd;
|
ServeCommand cmd;
|
||||||
try {
|
try {
|
||||||
@@ -902,25 +905,23 @@ static void opServe(Strings opFlags, Strings opArgs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writeStrings(store->queryValidPaths(paths), out);
|
out << store->queryValidPaths(paths);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case cmdQueryPathInfos: {
|
case cmdQueryPathInfos: {
|
||||||
PathSet paths = readStorePaths<PathSet>(in);
|
PathSet paths = readStorePaths<PathSet>(in);
|
||||||
// !!! Maybe we want a queryPathInfos?
|
// !!! Maybe we want a queryPathInfos?
|
||||||
foreach (PathSet::iterator, i, paths) {
|
for (auto & i : paths) {
|
||||||
if (!store->isValidPath(*i))
|
if (!store->isValidPath(i))
|
||||||
continue;
|
continue;
|
||||||
ValidPathInfo info = store->queryPathInfo(*i);
|
ValidPathInfo info = store->queryPathInfo(i);
|
||||||
writeString(info.path, out);
|
out << info.path << info.deriver << info.references;
|
||||||
writeString(info.deriver, out);
|
|
||||||
writeStrings(info.references, out);
|
|
||||||
// !!! Maybe we want compression?
|
// !!! Maybe we want compression?
|
||||||
writeLongLong(info.narSize, out); // downloadSize
|
out << info.narSize // downloadSize
|
||||||
writeLongLong(info.narSize, out);
|
<< info.narSize;
|
||||||
}
|
}
|
||||||
writeString("", out);
|
out << "";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -931,7 +932,7 @@ static void opServe(Strings opFlags, Strings opArgs)
|
|||||||
case cmdImportPaths: {
|
case cmdImportPaths: {
|
||||||
if (!writeAllowed) throw Error("importing paths is not allowed");
|
if (!writeAllowed) throw Error("importing paths is not allowed");
|
||||||
store->importPaths(false, in);
|
store->importPaths(false, in);
|
||||||
writeInt(1, out); // indicate success
|
out << 1; // indicate success
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -943,39 +944,49 @@ static void opServe(Strings opFlags, Strings opArgs)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case cmdBuildPaths: {
|
case cmdBuildPaths: { /* Used by build-remote.pl. */
|
||||||
|
|
||||||
/* Used by build-remote.pl. */
|
|
||||||
if (!writeAllowed) throw Error("building paths is not allowed");
|
if (!writeAllowed) throw Error("building paths is not allowed");
|
||||||
PathSet paths = readStorePaths<PathSet>(in);
|
PathSet paths = readStorePaths<PathSet>(in);
|
||||||
|
|
||||||
// FIXME: changing options here doesn't work if we're
|
getBuildSettings();
|
||||||
// building through the daemon.
|
|
||||||
verbosity = lvlError;
|
|
||||||
settings.keepLog = false;
|
|
||||||
settings.useSubstitutes = false;
|
|
||||||
settings.maxSilentTime = readInt(in);
|
|
||||||
settings.buildTimeout = readInt(in);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
MonitorFdHup monitor(in.fd);
|
MonitorFdHup monitor(in.fd);
|
||||||
store->buildPaths(paths);
|
store->buildPaths(paths);
|
||||||
writeInt(0, out);
|
out << 0;
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
assert(e.status);
|
assert(e.status);
|
||||||
writeInt(e.status, out);
|
out << e.status << e.msg();
|
||||||
writeString(e.msg(), out);
|
|
||||||
}
|
}
|
||||||
break;
|
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: {
|
case cmdQueryClosure: {
|
||||||
bool includeOutputs = readInt(in);
|
bool includeOutputs = readInt(in);
|
||||||
PathSet paths = readStorePaths<PathSet>(in);
|
PathSet paths = readStorePaths<PathSet>(in);
|
||||||
PathSet closure;
|
PathSet closure;
|
||||||
for (auto & i : paths)
|
for (auto & i : paths)
|
||||||
computeFSClosure(*store, i, closure, false, includeOutputs);
|
computeFSClosure(*store, i, closure, false, includeOutputs);
|
||||||
writeStrings(closure, out);
|
out << closure;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -990,8 +1001,8 @@ static void opServe(Strings opFlags, Strings opArgs)
|
|||||||
|
|
||||||
static void opGenerateBinaryCacheKey(Strings opFlags, Strings opArgs)
|
static void opGenerateBinaryCacheKey(Strings opFlags, Strings opArgs)
|
||||||
{
|
{
|
||||||
foreach (Strings::iterator, i, opFlags)
|
for (auto & i : opFlags)
|
||||||
throw UsageError(format("unknown flag ‘%1%’") % *i);
|
throw UsageError(format("unknown flag ‘%1%’") % i);
|
||||||
|
|
||||||
if (opArgs.size() != 3) throw UsageError("three arguments expected");
|
if (opArgs.size() != 3) throw UsageError("three arguments expected");
|
||||||
auto i = opArgs.begin();
|
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
|
/* Scan the arguments; find the operation, set global flags, put all
|
||||||
other flags in a list, and put all other arguments in another
|
other flags in a list, and put all other arguments in another
|
||||||
list. */
|
list. */
|
||||||
@@ -1033,7 +1050,7 @@ int main(int argc, char * * argv)
|
|||||||
if (*arg == "--help")
|
if (*arg == "--help")
|
||||||
showManPage("nix-store");
|
showManPage("nix-store");
|
||||||
else if (*arg == "--version")
|
else if (*arg == "--version")
|
||||||
printVersion("nix-store");
|
op = opVersion;
|
||||||
else if (*arg == "--realise" || *arg == "--realize" || *arg == "-r")
|
else if (*arg == "--realise" || *arg == "--realize" || *arg == "-r")
|
||||||
op = opRealise;
|
op = opRealise;
|
||||||
else if (*arg == "--add" || *arg == "-A")
|
else if (*arg == "--add" || *arg == "-A")
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace nix {
|
|||||||
#define SERVE_MAGIC_1 0x390c9deb
|
#define SERVE_MAGIC_1 0x390c9deb
|
||||||
#define SERVE_MAGIC_2 0x5452eecb
|
#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_MAJOR(x) ((x) & 0xff00)
|
||||||
#define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff)
|
#define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff)
|
||||||
|
|
||||||
@@ -17,6 +17,7 @@ typedef enum {
|
|||||||
cmdExportPaths = 5,
|
cmdExportPaths = 5,
|
||||||
cmdBuildPaths = 6,
|
cmdBuildPaths = 6,
|
||||||
cmdQueryClosure = 7,
|
cmdQueryClosure = 7,
|
||||||
|
cmdBuildDerivation = 8,
|
||||||
} ServeCommand;
|
} ServeCommand;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
[ false false true true true true false true ]
|
||||||
@@ -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 ", " [])
|
||||||
|
]
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
[ "faabar" "fbar" "fubar" "faboor" "fubar" ]
|
||||||
@@ -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")
|
||||||
|
]
|
||||||
@@ -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"; } ] ]
|
||||||
@@ -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 @@
|
|||||||
"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$\"$\"$"
|
||||||
|
|||||||
@@ -8,3 +8,5 @@ of
|
|||||||
line"
|
line"
|
||||||
+ "foo${if true then "b${"a" + "r"}" else "xyzzy"}blaat"
|
+ "foo${if true then "b${"a" + "r"}" else "xyzzy"}blaat"
|
||||||
+ "foo$bar"
|
+ "foo$bar"
|
||||||
|
+ "$\"$\""
|
||||||
|
+ "$"
|
||||||
|
|||||||
+4
-4
@@ -17,7 +17,7 @@ rec {
|
|||||||
then fold (x: y: (flatten x) ++ y) [] x
|
then fold (x: y: (flatten x) ++ y) [] x
|
||||||
else [x];
|
else [x];
|
||||||
|
|
||||||
sum = fold (x: y: add x y) 0;
|
sum = foldl' (x: y: add x y) 0;
|
||||||
|
|
||||||
hasSuffix = ext: fileName:
|
hasSuffix = ext: fileName:
|
||||||
let lenFileName = stringLength fileName;
|
let lenFileName = stringLength fileName;
|
||||||
@@ -54,8 +54,8 @@ rec {
|
|||||||
const = x: y: x;
|
const = x: y: x;
|
||||||
|
|
||||||
range = first: last:
|
range = first: last:
|
||||||
if builtins.lessThan last first
|
if first > last
|
||||||
then []
|
then []
|
||||||
else [first] ++ range (builtins.add first 1) last;
|
else genList (n: first + n) (last - first + 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,3 +14,6 @@ nix-env --version | grep "$version"
|
|||||||
# Usage errors.
|
# Usage errors.
|
||||||
nix-env --foo 2>&1 | grep "no operation"
|
nix-env --foo 2>&1 | grep "no operation"
|
||||||
nix-env -q --foo 2>&1 | grep "unknown flag"
|
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$"
|
||||||
|
|||||||
Reference in New Issue
Block a user