Fold the 'all' attribute into the listToAttrs call alongside the outputs, so commonAttrs builds from drv // listToAttrs(...) // passthru // { drvPath; outPath; } instead of four separate merges with a standalone 'all' attrset.
Also convert remaining optionalAttrs to nullable attr names in extendDerivation, overrideDerivation, and makeOverridable.
Per-derivation // merges drop from 4 to 3.
Why are we running a `flip` on arguments we can control? Why are we
using `or` on one line only to use a full if/else on the next line? Why
are we merging with {}, and why have we been doing it for three years?
THese are the questions I ask myself.
- concrete types start with uppercase: Int, String, Bool, Derivation,
etc.
- type variables start with lowercase: a, b, etc.
- list:
- use `[x]` for homogeneous lists instead of `List x` or `[ x ]`
- use `List` for heterogeneous lists (not that common in `lib`)
- attr:
- use `AttrSet` for a generic attribute set type
- use `{ key1 :: Type1; key2 :: Type2; ... }` for adding signatures
for known attribute names and types
- use `{ key1 = value1; key2 = value2; ... }` for adding attributes
with known literals
- end with an ellipsis (`...`) if the set can contain unknown
attributes
- use `{ [String] :: x }` if all the attributes has the same type `x`
- prefer `Any` over `a` if the latter is not reused
This code was more careful before
<dd435697b3>
(it didn't assume that `unsafeGetAttrPos` always returns a non-null
location). Unfortunately, `unsafeGetAttrPos` *does* return `null` when
dealing with `nix repl`:
```
nix-repl> f = {foo}: foo
nix-repl> builtins.unsafeGetAttrPos "foo" (builtins.functionArgs f)
null
```
Here's how to reproduce the issue.
*Before* this fix:
```
nix-repl> f = {foo}: foo
nix-repl> myCallPackage = lib.callPackageWith {}
nix-repl> myCallPackage f {}
error:
… while calling the 'abort' builtin
at /home/jeremy/src/github.com/NixOS/nixpkgs/lib/customisation.nix:323:7:
322| else
323| abort "lib.customisation.callPackageWith: ${error}";
| ^
324|
… while selecting an attribute
at /home/jeremy/src/github.com/NixOS/nixpkgs/lib/customisation.nix:310:14:
309| "Function called without required argument \"${arg}\" at "
310| + "${loc.file}:${toString loc.line}${prettySuggestions (getSuggestions arg)}";
| ^
311|
error: expected a set but found null: null
```
*After*:
```
nix-repl> f = {foo}: foo
nix-repl> myCallPackage = lib.callPackageWith {}
nix-repl> myCallPackage f {}
error:
… while calling the 'abort' builtin
at /home/jeremy/src/github.com/NixOS/nixpkgs/lib/customisation.nix:332:7:
331| # Inputs
332|
| ^
333| `autoArgs`
error: evaluation aborted with the following error message: 'lib.customisation.callPackageWith: Function called without required argument "foo" at <unknown location>'
```
A Cross Index, short for Cross Platform Pair Index, is the essential
shape of a splice, without the invoking the more mind bending concept
of adding variations of for these 6 pairings to an existing thing so
that it can be switched out for something else.
So the purpose of a Cross Index is to contain the result of `f`\
(which may be reified in code, or just an abstract concept):
- f "build" "build"
- f "build" "host"
- ...
Splicing on the other hand refers not just to these six variants, but
to the idea of tacking them onto one of the variants. (hostTarget,
I believe)
Cross Indexes are a necessity for making cross compilation work, but
splicing is more than necessary.
Tested with:
1. Replace the callPackageWith call by `null`, to simulate an ancient Nix
2. Run the following commands in a terminal in nixpkgs:
$ mkdir test/
$ echo '{ asdfasdfasdf }: null' >test/default.nix
$ nix repl -f .
nix-repl> callPackage ./test { }
error:
… while calling the 'abort' builtin
at /home/user/src/nixpkgs/lib/customisation.nix:312:7:
311| else
312| abort "lib.customisation.callPackageWith: ${error}";
| ^
313|
error: evaluation aborted with the following error message: 'lib.customisation.callPackageWith: Function called without required argument "asdfasdfasdf" at /home/user/src/nixpkgs/test/default.nix'
makeOverridable is very careful to ensure the arguments to the
overridden function are the same as the input function. As a result,
the arguments of hello.override are exactly the same as the original
arguments of the hello function that produced the derivation.
However, callPackagesWith calls makeOverridable with a lambda that
does not propagate the arguments. The override function for a package
instantiated with callPackagesWith will not have the original
arguments.
For example:
nix-repl> lib.functionArgs hello.override
{ callPackage = false; fetchurl = false; hello = false; lib = false; nixos = false; stdenv = false; testers = false; }
nix-repl> lib.functionArgs openssl.override
{ }
By copying the arguments onto the inner lambda before passing it to
makeOverridable, we can make callPackage and callPackages behave the
same.
nix-repl> lib.functionArgs openssl.override
{ buildPackages = false; coreutils = false; cryptodev = false; enableSSL2 = true; enableSSL3 = true; fetchurl = false; lib = false; perl = false; removeReferencesTo = false; static = true; stdenv = false; withCryptodev = true; withPerl = true; }