aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/manual/src/command-ref/nix-store.md6
-rw-r--r--doc/manual/src/installation/installing-binary.md6
-rw-r--r--doc/manual/src/language/operators.md191
-rw-r--r--doc/manual/src/language/values.md7
-rw-r--r--src/libcmd/installables.cc5
-rw-r--r--src/libexpr/primops.cc2
-rw-r--r--src/libstore/build/derivation-goal.cc3
-rw-r--r--src/libstore/gc.cc84
-rw-r--r--src/libstore/local-store.cc6
-rw-r--r--src/libstore/local-store.hh24
-rw-r--r--src/libstore/lock.cc12
-rw-r--r--src/libstore/lock.hh2
-rw-r--r--src/libstore/realisation.hh10
-rw-r--r--src/libstore/remote-store.cc5
-rw-r--r--src/nix/flake.cc17
-rw-r--r--src/nix/why-depends.cc24
-rw-r--r--tests/flakes/check.sh16
-rw-r--r--tests/local.mk1
-rw-r--r--tests/why-depends.sh3
19 files changed, 282 insertions, 142 deletions
diff --git a/doc/manual/src/command-ref/nix-store.md b/doc/manual/src/command-ref/nix-store.md
index acf29e4aa..6d0e02ca5 100644
--- a/doc/manual/src/command-ref/nix-store.md
+++ b/doc/manual/src/command-ref/nix-store.md
@@ -155,6 +155,12 @@ To test whether a previously-built derivation is deterministic:
$ nix-build '<nixpkgs>' -A hello --check -K
```
+Use [`--read-log`](#operation---read-log) to show the stderr and stdout of a build:
+
+```console
+$ nix-store --read-log $(nix-instantiate ./test.nix)
+```
+
# Operation `--serve`
## Synopsis
diff --git a/doc/manual/src/installation/installing-binary.md b/doc/manual/src/installation/installing-binary.md
index a9378681d..53fdbe31a 100644
--- a/doc/manual/src/installation/installing-binary.md
+++ b/doc/manual/src/installation/installing-binary.md
@@ -120,10 +120,10 @@ sudo rm -rf /nix /etc/nix /etc/profile/nix.sh ~root/.nix-profile ~root/.nix-defe
Remove build users and their group:
```console
-for i in $(seq 30001 30032); do
- sudo userdel $i
+for i in $(seq 1 32); do
+ sudo userdel nixbld$i
done
-sudo groupdel 30000
+sudo groupdel nixbld
```
There may also be references to Nix in
diff --git a/doc/manual/src/language/operators.md b/doc/manual/src/language/operators.md
index 32398189d..797f13bd3 100644
--- a/doc/manual/src/language/operators.md
+++ b/doc/manual/src/language/operators.md
@@ -1,28 +1,167 @@
# Operators
-The table below lists the operators in the Nix language, in
-order of precedence (from strongest to weakest binding).
-
-| Name | Syntax | Associativity | Description | Precedence |
-| ------------------------ | ----------------------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
-| Select | *e* `.` *attrpath* \[ `or` *def* \] | none | Select attribute denoted by the attribute path *attrpath* from set *e*. (An attribute path is a dot-separated list of attribute names.) If the attribute doesn’t exist, return *def* if provided, otherwise abort evaluation. | 1 |
-| Application | *e1* *e2* | left | Call function *e1* with argument *e2*. | 2 |
-| Arithmetic Negation | `-` *e* | none | Arithmetic negation. | 3 |
-| Has Attribute | *e* `?` *attrpath* | none | Test whether set *e* contains the attribute denoted by *attrpath*; return `true` or `false`. | 4 |
-| List Concatenation | *e1* `++` *e2* | right | List concatenation. | 5 |
-| Multiplication | *e1* `*` *e2*, | left | Arithmetic multiplication. | 6 |
-| Division | *e1* `/` *e2* | left | Arithmetic division. | 6 |
-| Addition | *e1* `+` *e2* | left | Arithmetic addition. | 7 |
-| Subtraction | *e1* `-` *e2* | left | Arithmetic subtraction. | 7 |
-| String Concatenation | *string1* `+` *string2* | left | String concatenation. | 7 |
-| Not | `!` *e* | none | Boolean negation. | 8 |
-| Update | *e1* `//` *e2* | right | Return a set consisting of the attributes in *e1* and *e2* (with the latter taking precedence over the former in case of equally named attributes). | 9 |
-| Less Than | *e1* `<` *e2*, | none | Arithmetic/lexicographic comparison. | 10 |
-| Less Than or Equal To | *e1* `<=` *e2* | none | Arithmetic/lexicographic comparison. | 10 |
-| Greater Than | *e1* `>` *e2* | none | Arithmetic/lexicographic comparison. | 10 |
-| Greater Than or Equal To | *e1* `>=` *e2* | none | Arithmetic/lexicographic comparison. | 10 |
-| Equality | *e1* `==` *e2* | none | Equality. | 11 |
-| Inequality | *e1* `!=` *e2* | none | Inequality. | 11 |
-| Logical AND | *e1* `&&` *e2* | left | Logical AND. | 12 |
-| Logical OR | *e1* <code>&#124;&#124;</code> *e2* | left | Logical OR. | 13 |
-| Logical Implication | *e1* `->` *e2* | none | Logical implication (equivalent to <code>!e1 &#124;&#124; e2</code>). | 14 |
+| Name | Syntax | Associativity | Precedence |
+|----------------------------------------|--------------------------------------------|---------------|------------|
+| [Attribute selection] | *attrset* `.` *attrpath* \[ `or` *expr* \] | none | 1 |
+| Function application | *func* *expr* | left | 2 |
+| [Arithmetic negation][arithmetic] | `-` *number* | none | 3 |
+| [Has attribute] | *attrset* `?` *attrpath* | none | 4 |
+| List concatenation | *list* `++` *list* | right | 5 |
+| [Multiplication][arithmetic] | *number* `*` *number* | left | 6 |
+| [Division][arithmetic] | *number* `/` *number* | left | 6 |
+| [Subtraction][arithmetic] | *number* `-` *number* | left | 7 |
+| [Addition][arithmetic] | *number* `+` *number* | left | 7 |
+| [String concatenation] | *string* `+` *string* | left | 7 |
+| [Path concatenation] | *path* `+` *path* | left | 7 |
+| [Path and string concatenation] | *path* `+` *string* | left | 7 |
+| [String and path concatenation] | *string* `+` *path* | left | 7 |
+| Logical negation (`NOT`) | `!` *bool* | none | 8 |
+| [Update] | *attrset* `//` *attrset* | right | 9 |
+| [Less than][Comparison] | *expr* `<` *expr* | none | 10 |
+| [Less than or equal to][Comparison] | *expr* `<=` *expr* | none | 10 |
+| [Greater than][Comparison] | *expr* `>` *expr* | none | 10 |
+| [Greater than or equal to][Comparison] | *expr* `>=` *expr* | none | 10 |
+| [Equality] | *expr* `==` *expr* | none | 11 |
+| Inequality | *expr* `!=` *expr* | none | 11 |
+| Logical conjunction (`AND`) | *bool* `&&` *bool* | left | 12 |
+| Logical disjunction (`OR`) | *bool* `||` *bool* | left | 13 |
+| [Logical implication] | *bool* `->` *bool* | none | 14 |
+
+[string]: ./values.md#type-string
+[path]: ./values.md#type-path
+[number]: ./values.md#type-number
+[list]: ./values.md#list
+[attribute set]: ./values.md#attribute-set
+
+## Attribute selection
+
+Select the attribute denoted by attribute path *attrpath* from [attribute set] *attrset*.
+If the attribute doesn’t exist, return *value* if provided, otherwise abort evaluation.
+
+<!-- FIXME: the following should to into its own language syntax section, but that needs more work to fit in well -->
+
+An attribute path is a dot-separated list of attribute names.
+An attribute name can be an identifier or a string.
+
+> *attrpath* = *name* [ `.` *name* ]...
+> *name* = *identifier* | *string*
+> *identifier* ~ `[a-zA-Z_][a-zA-Z0-9_'-]*`
+
+[Attribute selection]: #attribute-selection
+
+## Has attribute
+
+> *attrset* `?` *attrpath*
+
+Test whether [attribute set] *attrset* contains the attribute denoted by *attrpath*.
+The result is a [Boolean] value.
+
+[Boolean]: ./values.md#type-boolean
+
+[Has attribute]: #has-attribute
+
+## Arithmetic
+
+Numbers are type-compatible:
+Pure integer operations will always return integers, whereas any operation involving at least one floating point number return a floating point number.
+
+See also [Comparison] and [Equality].
+
+The `+` operator is overloaded to also work on strings and paths.
+
+[arithmetic]: #arithmetic
+
+## String concatenation
+
+> *string* `+` *string*
+
+Concatenate two [string]s and merge their string contexts.
+
+[String concatenation]: #string-concatenation
+
+## Path concatenation
+
+> *path* `+` *path*
+
+Concatenate two [path]s.
+The result is a path.
+
+[Path concatenation]: #path-concatenation
+
+## Path and string concatenation
+
+> *path* + *string*
+
+Concatenate *[path]* with *[string]*.
+The result is a path.
+
+> **Note**
+>
+> The string must not have a string context that refers to a [store path].
+
+[Path and string concatenation]: #path-and-string-concatenation
+
+## String and path concatenation
+
+> *string* + *path*
+
+Concatenate *[string]* with *[path]*.
+The result is a string.
+
+> **Important**
+>
+> The file or directory at *path* must exist and is copied to the [store].
+> The path appears in the result as the corresponding [store path].
+
+[store path]: ../glossary.md#gloss-store-path
+[store]: ../glossary.md#gloss-store
+
+[Path and string concatenation]: #path-and-string-concatenation
+
+## Update
+
+> *attrset1* + *attrset2*
+
+Update [attribute set] *attrset1* with names and values from *attrset2*.
+
+The returned attribute set will have of all the attributes in *e1* and *e2*.
+If an attribute name is present in both, the attribute value from the former is taken.
+
+[Update]: #update
+
+## Comparison
+
+Comparison is
+
+- [arithmetic] for [number]s
+- lexicographic for [string]s and [path]s
+- item-wise lexicographic for [list]s:
+ elements at the same index in both lists are compared according to their type and skipped if they are equal.
+
+All comparison operators are implemented in terms of `<`, and the following equivalencies hold:
+
+| comparison | implementation |
+|--------------|-----------------------|
+| *a* `<=` *b* | `! (` *b* `<` *a* `)` |
+| *a* `>` *b* | *b* `<` *a* |
+| *a* `>=` *b* | `! (` *a* `<` *b* `)` |
+
+[Comparison]: #comparison-operators
+
+## Equality
+
+- [Attribute sets][attribute set] and [list]s are compared recursively, and therefore are fully evaluated.
+- Comparison of [function]s always returns `false`.
+- Numbers are type-compatible, see [arithmetic] operators.
+- Floating point numbers only differ up to a limited precision.
+
+[function]: ./constructs.md#functions
+
+[Equality]: #equality
+
+## Logical implication
+
+Equivalent to `!`*b1* `||` *b2*.
+
+[Logical implication]: #logical-implication
+
diff --git a/doc/manual/src/language/values.md b/doc/manual/src/language/values.md
index 08baa8f95..3973518ca 100644
--- a/doc/manual/src/language/values.md
+++ b/doc/manual/src/language/values.md
@@ -85,9 +85,10 @@
Numbers, which can be *integers* (like `123`) or *floating point*
(like `123.43` or `.27e13`).
- Numbers are type-compatible: pure integer operations will always
- return integers, whereas any operation involving at least one
- floating point number will have a floating point number as a result.
+ See [arithmetic] and [comparison] operators for semantics.
+
+ [arithmetic]: ./operators.md#arithmetic
+ [comparison]: ./operators.md#comparison
- <a id="type-path" href="#type-path">Path</a>
diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc
index f481a41a0..79361e94e 100644
--- a/src/libcmd/installables.cc
+++ b/src/libcmd/installables.cc
@@ -931,10 +931,7 @@ std::vector<std::pair<std::shared_ptr<Installable>, BuiltPathWithResult>> Instal
DrvOutput outputId { *outputHash, output };
auto realisation = store->queryRealisation(outputId);
if (!realisation)
- throw Error(
- "cannot operate on an output of the "
- "unbuilt derivation '%s'",
- outputId.to_string());
+ throw MissingRealisation(outputId);
outputs.insert_or_assign(output, realisation->outPath);
} else {
// If ca-derivations isn't enabled, assume that
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 9356d307e..9ef91cbc5 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -2807,7 +2807,7 @@ static RegisterPrimOp primop_map({
example,
```nix
- map (x"foo" + x) [ "bar" "bla" "abc" ]
+ map (x: "foo" + x) [ "bar" "bla" "abc" ]
```
evaluates to `[ "foobar" "foobla" "fooabc" ]`.
diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc
index 173058d1b..5e86b5269 100644
--- a/src/libstore/build/derivation-goal.cc
+++ b/src/libstore/build/derivation-goal.cc
@@ -544,7 +544,8 @@ void DerivationGoal::inputsRealised()
However, the impure derivations feature still relies on this
fragile way of doing things, because its builds do not have
a representation in the store, which is a usability problem
- in itself */
+ in itself. When implementing this logic entirely with lookups
+ make sure that they're cached. */
if (auto outPath = get(inputDrvOutputs, { depDrvPath, j })) {
worker.store.computeFSClosure(*outPath, inputPaths);
}
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index 5d91829f1..996f26a95 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -77,60 +77,73 @@ Path LocalFSStore::addPermRoot(const StorePath & storePath, const Path & _gcRoot
}
-void LocalStore::addTempRoot(const StorePath & path)
+void LocalStore::createTempRootsFile()
{
- auto state(_state.lock());
+ auto fdTempRoots(_fdTempRoots.lock());
/* Create the temporary roots file for this process. */
- if (!state->fdTempRoots) {
-
- while (1) {
- if (pathExists(fnTempRoots))
- /* It *must* be stale, since there can be no two
- processes with the same pid. */
- unlink(fnTempRoots.c_str());
+ if (*fdTempRoots) return;
- state->fdTempRoots = openLockFile(fnTempRoots, true);
+ while (1) {
+ if (pathExists(fnTempRoots))
+ /* It *must* be stale, since there can be no two
+ processes with the same pid. */
+ unlink(fnTempRoots.c_str());
- debug("acquiring write lock on '%s'", fnTempRoots);
- lockFile(state->fdTempRoots.get(), ltWrite, true);
+ *fdTempRoots = openLockFile(fnTempRoots, true);
- /* Check whether the garbage collector didn't get in our
- way. */
- struct stat st;
- if (fstat(state->fdTempRoots.get(), &st) == -1)
- throw SysError("statting '%1%'", fnTempRoots);
- if (st.st_size == 0) break;
+ debug("acquiring write lock on '%s'", fnTempRoots);
+ lockFile(fdTempRoots->get(), ltWrite, true);
- /* The garbage collector deleted this file before we could
- get a lock. (It won't delete the file after we get a
- lock.) Try again. */
- }
+ /* Check whether the garbage collector didn't get in our
+ way. */
+ struct stat st;
+ if (fstat(fdTempRoots->get(), &st) == -1)
+ throw SysError("statting '%1%'", fnTempRoots);
+ if (st.st_size == 0) break;
+ /* The garbage collector deleted this file before we could get
+ a lock. (It won't delete the file after we get a lock.)
+ Try again. */
}
+}
+
- if (!state->fdGCLock)
- state->fdGCLock = openGCLock();
+void LocalStore::addTempRoot(const StorePath & path)
+{
+ createTempRootsFile();
+
+ /* Open/create the global GC lock file. */
+ {
+ auto fdGCLock(_fdGCLock.lock());
+ if (!*fdGCLock)
+ *fdGCLock = openGCLock();
+ }
restart:
- FdLock gcLock(state->fdGCLock.get(), ltRead, false, "");
+ /* Try to acquire a shared global GC lock (non-blocking). This
+ only succeeds if the garbage collector is not currently
+ running. */
+ FdLock gcLock(_fdGCLock.lock()->get(), ltRead, false, "");
if (!gcLock.acquired) {
/* We couldn't get a shared global GC lock, so the garbage
collector is running. So we have to connect to the garbage
collector and inform it about our root. */
- if (!state->fdRootsSocket) {
+ auto fdRootsSocket(_fdRootsSocket.lock());
+
+ if (!*fdRootsSocket) {
auto socketPath = stateDir.get() + gcSocketPath;
debug("connecting to '%s'", socketPath);
- state->fdRootsSocket = createUnixDomainSocket();
+ *fdRootsSocket = createUnixDomainSocket();
try {
- nix::connect(state->fdRootsSocket.get(), socketPath);
+ nix::connect(fdRootsSocket->get(), socketPath);
} catch (SysError & e) {
/* The garbage collector may have exited, so we need to
restart. */
if (e.errNo == ECONNREFUSED) {
debug("GC socket connection refused");
- state->fdRootsSocket.close();
+ fdRootsSocket->close();
goto restart;
}
throw;
@@ -139,9 +152,9 @@ void LocalStore::addTempRoot(const StorePath & path)
try {
debug("sending GC root '%s'", printStorePath(path));
- writeFull(state->fdRootsSocket.get(), printStorePath(path) + "\n", false);
+ writeFull(fdRootsSocket->get(), printStorePath(path) + "\n", false);
char c;
- readFull(state->fdRootsSocket.get(), &c, 1);
+ readFull(fdRootsSocket->get(), &c, 1);
assert(c == '1');
debug("got ack for GC root '%s'", printStorePath(path));
} catch (SysError & e) {
@@ -149,20 +162,21 @@ void LocalStore::addTempRoot(const StorePath & path)
restart. */
if (e.errNo == EPIPE || e.errNo == ECONNRESET) {
debug("GC socket disconnected");
- state->fdRootsSocket.close();
+ fdRootsSocket->close();
goto restart;
}
throw;
} catch (EndOfFile & e) {
debug("GC socket disconnected");
- state->fdRootsSocket.close();
+ fdRootsSocket->close();
goto restart;
}
}
- /* Append the store path to the temporary roots file. */
+ /* Record the store path in the temporary roots file so it will be
+ seen by a future run of the garbage collector. */
auto s = printStorePath(path) + '\0';
- writeFull(state->fdTempRoots.get(), s);
+ writeFull(_fdTempRoots.lock()->get(), s);
}
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index 3bab10af9..be21e3ca0 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -441,9 +441,9 @@ LocalStore::~LocalStore()
}
try {
- auto state(_state.lock());
- if (state->fdTempRoots) {
- state->fdTempRoots = -1;
+ auto fdTempRoots(_fdTempRoots.lock());
+ if (*fdTempRoots) {
+ *fdTempRoots = -1;
unlink(fnTempRoots.c_str());
}
} catch (...) {
diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh
index 4579c2f62..06d36a7d5 100644
--- a/src/libstore/local-store.hh
+++ b/src/libstore/local-store.hh
@@ -59,15 +59,6 @@ private:
struct Stmts;
std::unique_ptr<Stmts> stmts;
- /* The global GC lock */
- AutoCloseFD fdGCLock;
-
- /* The file to which we write our temporary roots. */
- AutoCloseFD fdTempRoots;
-
- /* Connection to the garbage collector. */
- AutoCloseFD fdRootsSocket;
-
/* The last time we checked whether to do an auto-GC, or an
auto-GC finished. */
std::chrono::time_point<std::chrono::steady_clock> lastGCCheck;
@@ -156,6 +147,21 @@ public:
void addTempRoot(const StorePath & path) override;
+private:
+
+ void createTempRootsFile();
+
+ /* The file to which we write our temporary roots. */
+ Sync<AutoCloseFD> _fdTempRoots;
+
+ /* The global GC lock. */
+ Sync<AutoCloseFD> _fdGCLock;
+
+ /* Connection to the garbage collector. */
+ Sync<AutoCloseFD> _fdRootsSocket;
+
+public:
+
void addIndirectRoot(const Path & path) override;
private:
diff --git a/src/libstore/lock.cc b/src/libstore/lock.cc
index d02d20b4c..4fe1fcf56 100644
--- a/src/libstore/lock.cc
+++ b/src/libstore/lock.cc
@@ -123,8 +123,12 @@ struct AutoUserLock : UserLock
std::vector<gid_t> getSupplementaryGIDs() override { return {}; }
- static std::unique_ptr<UserLock> acquire(uid_t nrIds, bool useChroot)
+ static std::unique_ptr<UserLock> acquire(uid_t nrIds, bool useUserNamespace)
{
+ #if !defined(__linux__)
+ useUserNamespace = false;
+ #endif
+
settings.requireExperimentalFeature(Xp::AutoAllocateUids);
assert(settings.startId > 0);
assert(settings.uidCount % maxIdsPerBuild == 0);
@@ -157,7 +161,7 @@ struct AutoUserLock : UserLock
auto lock = std::make_unique<AutoUserLock>();
lock->fdUserLock = std::move(fd);
lock->firstUid = firstUid;
- if (useChroot)
+ if (useUserNamespace)
lock->firstGid = firstUid;
else {
struct group * gr = getgrnam(settings.buildUsersGroup.get().c_str());
@@ -174,10 +178,10 @@ struct AutoUserLock : UserLock
}
};
-std::unique_ptr<UserLock> acquireUserLock(uid_t nrIds, bool useChroot)
+std::unique_ptr<UserLock> acquireUserLock(uid_t nrIds, bool useUserNamespace)
{
if (settings.autoAllocateUids)
- return AutoUserLock::acquire(nrIds, useChroot);
+ return AutoUserLock::acquire(nrIds, useUserNamespace);
else
return SimpleUserLock::acquire();
}
diff --git a/src/libstore/lock.hh b/src/libstore/lock.hh
index 49ad86de7..7f1934510 100644
--- a/src/libstore/lock.hh
+++ b/src/libstore/lock.hh
@@ -31,7 +31,7 @@ struct UserLock
/* Acquire a user lock for a UID range of size `nrIds`. Note that this
may return nullptr if no user is available. */
-std::unique_ptr<UserLock> acquireUserLock(uid_t nrIds, bool useChroot);
+std::unique_ptr<UserLock> acquireUserLock(uid_t nrIds, bool useUserNamespace);
bool useBuildUsers();
diff --git a/src/libstore/realisation.hh b/src/libstore/realisation.hh
index 9070a6ee2..911c61909 100644
--- a/src/libstore/realisation.hh
+++ b/src/libstore/realisation.hh
@@ -93,4 +93,14 @@ struct RealisedPath {
GENERATE_CMP(RealisedPath, me->raw);
};
+class MissingRealisation : public Error
+{
+public:
+ MissingRealisation(DrvOutput & outputId)
+ : Error( "cannot operate on an output of the "
+ "unbuilt derivation '%s'",
+ outputId.to_string())
+ {}
+};
+
}
diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc
index 48cf731a8..ccf7d7e8b 100644
--- a/src/libstore/remote-store.cc
+++ b/src/libstore/remote-store.cc
@@ -879,10 +879,7 @@ std::vector<BuildResult> RemoteStore::buildPathsWithResults(
auto realisation =
queryRealisation(outputId);
if (!realisation)
- throw Error(
- "cannot operate on an output of unbuilt "
- "content-addressed derivation '%s'",
- outputId.to_string());
+ throw MissingRealisation(outputId);
res.builtOutputs.emplace(realisation->id, *realisation);
} else {
// If ca-derivations isn't enabled, assume that
diff --git a/src/nix/flake.cc b/src/nix/flake.cc
index 06fd87ef2..9b4cdf35a 100644
--- a/src/nix/flake.cc
+++ b/src/nix/flake.cc
@@ -381,23 +381,6 @@ struct CmdFlakeCheck : FlakeCommand
auto checkModule = [&](const std::string & attrPath, Value & v, const PosIdx pos) {
try {
state->forceValue(v, pos);
- if (v.isLambda()) {
- if (!v.lambda.fun->hasFormals() || !v.lambda.fun->formals->ellipsis)
- throw Error("module must match an open attribute set ('{ config, ... }')");
- } else if (v.type() == nAttrs) {
- for (auto & attr : *v.attrs)
- try {
- state->forceValue(*attr.value, attr.pos);
- } catch (Error & e) {
- e.addTrace(
- state->positions[attr.pos],
- hintfmt("while evaluating the option '%s'", state->symbols[attr.name]));
- throw;
- }
- } else
- throw Error("module must be a function or an attribute set");
- // FIXME: if we have a 'nixpkgs' input, use it to
- // check the module.
} catch (Error & e) {
e.addTrace(resolve(pos), hintfmt("while checking the NixOS module '%s'", attrPath));
reportError(e);
diff --git a/src/nix/why-depends.cc b/src/nix/why-depends.cc
index 723017497..76125e5e4 100644
--- a/src/nix/why-depends.cc
+++ b/src/nix/why-depends.cc
@@ -95,23 +95,13 @@ struct CmdWhyDepends : SourceExprCommand
* to build.
*/
auto dependency = parseInstallable(store, _dependency);
- auto derivedDependency = dependency->toDerivedPath();
- auto optDependencyPath = std::visit(overloaded {
- [](const DerivedPath::Opaque & nodrv) -> std::optional<StorePath> {
- return { nodrv.path };
- },
- [&](const DerivedPath::Built & hasdrv) -> std::optional<StorePath> {
- if (hasdrv.outputs.size() != 1) {
- throw Error("argument '%s' should evaluate to one store path", dependency->what());
- }
- auto outputMap = store->queryPartialDerivationOutputMap(hasdrv.drvPath);
- auto maybePath = outputMap.find(*hasdrv.outputs.begin());
- if (maybePath == outputMap.end()) {
- throw Error("unexpected end of iterator");
- }
- return maybePath->second;
- },
- }, derivedDependency.raw());
+ auto optDependencyPath = [&]() -> std::optional<StorePath> {
+ try {
+ return {Installable::toStorePath(getEvalStore(), store, Realise::Derivation, operateOn, dependency)};
+ } catch (MissingRealisation &) {
+ return std::nullopt;
+ }
+ }();
StorePathSet closure;
store->computeFSClosure({packagePath}, closure, false, false);
diff --git a/tests/flakes/check.sh b/tests/flakes/check.sh
index f572aa75c..278ac7fa4 100644
--- a/tests/flakes/check.sh
+++ b/tests/flakes/check.sh
@@ -41,9 +41,9 @@ nix flake check $flakeDir
cat > $flakeDir/flake.nix <<EOF
{
outputs = { self }: {
- nixosModules.foo = {
+ nixosModules.foo = assert false; {
a.b.c = 123;
- foo = assert false; true;
+ foo = true;
};
};
}
@@ -66,18 +66,6 @@ nix flake check $flakeDir
cat > $flakeDir/flake.nix <<EOF
{
outputs = { self }: {
- nixosModule = { config, pkgs }: {
- a.b.c = 123;
- };
- };
-}
-EOF
-
-(! nix flake check $flakeDir)
-
-cat > $flakeDir/flake.nix <<EOF
-{
- outputs = { self }: {
packages.system-1.default = "foo";
packages.system-2.default = "bar";
};
diff --git a/tests/local.mk b/tests/local.mk
index bba6ad9c9..2489baecf 100644
--- a/tests/local.mk
+++ b/tests/local.mk
@@ -92,6 +92,7 @@ nix_tests = \
fmt.sh \
eval-store.sh \
why-depends.sh \
+ ca/why-depends.sh \
import-derivation.sh \
ca/import-derivation.sh \
nix_path.sh \
diff --git a/tests/why-depends.sh b/tests/why-depends.sh
index c12941e76..a04d529b5 100644
--- a/tests/why-depends.sh
+++ b/tests/why-depends.sh
@@ -6,6 +6,9 @@ cp ./dependencies.nix ./dependencies.builder0.sh ./config.nix $TEST_HOME
cd $TEST_HOME
+nix why-depends --derivation --file ./dependencies.nix input2_drv input1_drv
+nix why-depends --file ./dependencies.nix input2_drv input1_drv
+
nix-build ./dependencies.nix -A input0_drv -o dep
nix-build ./dependencies.nix -o toplevel