about summary refs log tree commit diff
path: root/nixpkgs/lib
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2024-03-22 16:41:59 +0100
committerAlyssa Ross <hi@alyssa.is>2024-03-22 16:41:59 +0100
commit46a88117a05c3469af5d99433af140c3de8ca088 (patch)
treed7f0557756d8f07a3081b3498c05ddc5a8ad429d /nixpkgs/lib
parente97457545cea0b2ca421da257c83d8f1ef451d85 (diff)
parenta343533bccc62400e8a9560423486a3b6c11a23b (diff)
downloadnixlib-46a88117a05c3469af5d99433af140c3de8ca088.tar
nixlib-46a88117a05c3469af5d99433af140c3de8ca088.tar.gz
nixlib-46a88117a05c3469af5d99433af140c3de8ca088.tar.bz2
nixlib-46a88117a05c3469af5d99433af140c3de8ca088.tar.lz
nixlib-46a88117a05c3469af5d99433af140c3de8ca088.tar.xz
nixlib-46a88117a05c3469af5d99433af140c3de8ca088.tar.zst
nixlib-46a88117a05c3469af5d99433af140c3de8ca088.zip
Merge commit 'a343533bccc62400e8a9560423486a3b6c11a23b'
Diffstat (limited to 'nixpkgs/lib')
-rw-r--r--nixpkgs/lib/.version1
-rw-r--r--nixpkgs/lib/asserts.nix150
-rw-r--r--nixpkgs/lib/attrsets.nix103
-rw-r--r--nixpkgs/lib/customisation.nix3
-rw-r--r--nixpkgs/lib/derivations.nix64
-rw-r--r--nixpkgs/lib/licenses.nix20
-rw-r--r--nixpkgs/lib/strings.nix27
-rw-r--r--nixpkgs/lib/tests/misc.nix36
-rw-r--r--nixpkgs/lib/tests/test-with-nix.nix6
-rw-r--r--nixpkgs/lib/trivial.nix2
10 files changed, 301 insertions, 111 deletions
diff --git a/nixpkgs/lib/.version b/nixpkgs/lib/.version
new file mode 100644
index 000000000000..420f61e8c7f6
--- /dev/null
+++ b/nixpkgs/lib/.version
@@ -0,0 +1 @@
+24.05
\ No newline at end of file
diff --git a/nixpkgs/lib/asserts.nix b/nixpkgs/lib/asserts.nix
index 8d0a621f4c1c..c7900c5d6c63 100644
--- a/nixpkgs/lib/asserts.nix
+++ b/nixpkgs/lib/asserts.nix
@@ -2,47 +2,87 @@
 
 rec {
 
-  /* Throw if pred is false, else return pred.
-     Intended to be used to augment asserts with helpful error messages.
+  /**
+    Throw if pred is false, else return pred.
+    Intended to be used to augment asserts with helpful error messages.
 
-     Example:
-       assertMsg false "nope"
-       stderr> error: nope
+    # Inputs
 
-       assert assertMsg ("foo" == "bar") "foo is not bar, silly"; ""
-       stderr> error: foo is not bar, silly
+    `pred`
 
-     Type:
-       assertMsg :: Bool -> String -> Bool
+    : Predicate that needs to succeed, otherwise `msg` is thrown
+
+    `msg`
+
+    : Message to throw in case `pred` fails
+
+    # Type
+
+    ```
+    assertMsg :: Bool -> String -> Bool
+    ```
+
+    # Examples
+    :::{.example}
+    ## `lib.asserts.assertMsg` usage example
+
+    ```nix
+    assertMsg false "nope"
+    stderr> error: nope
+    assert assertMsg ("foo" == "bar") "foo is not bar, silly"; ""
+    stderr> error: foo is not bar, silly
+    ```
+
+    :::
   */
   # TODO(Profpatsch): add tests that check stderr
   assertMsg =
-    # Predicate that needs to succeed, otherwise `msg` is thrown
     pred:
-    # Message to throw in case `pred` fails
     msg:
     pred || builtins.throw msg;
 
-  /* Specialized `assertMsg` for checking if `val` is one of the elements
-     of the list `xs`. Useful for checking enums.
+  /**
+    Specialized `assertMsg` for checking if `val` is one of the elements
+    of the list `xs`. Useful for checking enums.
+
+    # Inputs
+
+    `name`
+
+    : The name of the variable the user entered `val` into, for inclusion in the error message
+
+    `val`
+
+    : The value of what the user provided, to be compared against the values in `xs`
+
+    `xs`
+
+    : The list of valid values
+
+    # Type
 
-     Example:
-       let sslLibrary = "libressl";
-       in assertOneOf "sslLibrary" sslLibrary [ "openssl" "bearssl" ]
-       stderr> error: sslLibrary must be one of [
-       stderr>   "openssl"
-       stderr>   "bearssl"
-       stderr> ], but is: "libressl"
+    ```
+    assertOneOf :: String -> ComparableVal -> List ComparableVal -> Bool
+    ```
 
-     Type:
-       assertOneOf :: String -> ComparableVal -> List ComparableVal -> Bool
+    # Examples
+    :::{.example}
+    ## `lib.asserts.assertOneOf` usage example
+
+    ```nix
+    let sslLibrary = "libressl";
+    in assertOneOf "sslLibrary" sslLibrary [ "openssl" "bearssl" ]
+    stderr> error: sslLibrary must be one of [
+    stderr>   "openssl"
+    stderr>   "bearssl"
+    stderr> ], but is: "libressl"
+    ```
+
+    :::
   */
   assertOneOf =
-    # The name of the variable the user entered `val` into, for inclusion in the error message
     name:
-    # The value of what the user provided, to be compared against the values in `xs`
     val:
-    # The list of valid values
     xs:
     assertMsg
     (lib.elem val xs)
@@ -50,29 +90,51 @@ rec {
       lib.generators.toPretty {} xs}, but is: ${
         lib.generators.toPretty {} val}";
 
-  /* Specialized `assertMsg` for checking if every one of `vals` is one of the elements
-     of the list `xs`. Useful for checking lists of supported attributes.
-
-     Example:
-       let sslLibraries = [ "libressl" "bearssl" ];
-       in assertEachOneOf "sslLibraries" sslLibraries [ "openssl" "bearssl" ]
-       stderr> error: each element in sslLibraries must be one of [
-       stderr>   "openssl"
-       stderr>   "bearssl"
-       stderr> ], but is: [
-       stderr>   "libressl"
-       stderr>   "bearssl"
-       stderr> ]
-
-     Type:
-       assertEachOneOf :: String -> List ComparableVal -> List ComparableVal -> Bool
+  /**
+    Specialized `assertMsg` for checking if every one of `vals` is one of the elements
+    of the list `xs`. Useful for checking lists of supported attributes.
+
+    # Inputs
+
+    `name`
+
+    : The name of the variable the user entered `val` into, for inclusion in the error message
+
+    `vals`
+
+    : The list of values of what the user provided, to be compared against the values in `xs`
+
+    `xs`
+
+    : The list of valid values
+
+    # Type
+
+    ```
+    assertEachOneOf :: String -> List ComparableVal -> List ComparableVal -> Bool
+    ```
+
+    # Examples
+    :::{.example}
+    ## `lib.asserts.assertEachOneOf` usage example
+
+    ```nix
+    let sslLibraries = [ "libressl" "bearssl" ];
+    in assertEachOneOf "sslLibraries" sslLibraries [ "openssl" "bearssl" ]
+    stderr> error: each element in sslLibraries must be one of [
+    stderr>   "openssl"
+    stderr>   "bearssl"
+    stderr> ], but is: [
+    stderr>   "libressl"
+    stderr>   "bearssl"
+    stderr> ]
+    ```
+
+    :::
   */
   assertEachOneOf =
-    # The name of the variable the user entered `val` into, for inclusion in the error message
     name:
-    # The list of values of what the user provided, to be compared against the values in `xs`
     vals:
-    # The list of valid values
     xs:
     assertMsg
     (lib.all (val: lib.elem val xs) vals)
diff --git a/nixpkgs/lib/attrsets.nix b/nixpkgs/lib/attrsets.nix
index 4f7d795c397f..34054460ba76 100644
--- a/nixpkgs/lib/attrsets.nix
+++ b/nixpkgs/lib/attrsets.nix
@@ -216,8 +216,7 @@ rec {
     attrPath:
     # The nested attribute set to find the value in.
     set:
-    let errorMsg = "cannot find attribute `" + concatStringsSep "." attrPath + "'";
-    in attrByPath attrPath (abort errorMsg) set;
+    attrByPath attrPath (abort ("cannot find attribute `" + concatStringsSep "." attrPath + "'")) set;
 
   /* Map each attribute in the given set and merge them into a new attribute set.
 
@@ -680,65 +679,79 @@ rec {
   attrsToList = mapAttrsToList nameValuePair;
 
 
-  /* Like `mapAttrs`, except that it recursively applies itself to
-     the *leaf* attributes of a potentially-nested attribute set:
-     the second argument of the function will never be an attrset.
-     Also, the first argument of the argument function is a *list*
-     of the attribute names that form the path to the leaf attribute.
+  /**
+    Like `mapAttrs`, except that it recursively applies itself to the *leaf* attributes of a potentially-nested attribute set:
+    the second argument of the function will never be an attrset.
+    Also, the first argument of the mapping function is a *list* of the attribute names that form the path to the leaf attribute.
 
-     For a function that gives you control over what counts as a leaf,
-     see `mapAttrsRecursiveCond`.
+    For a function that gives you control over what counts as a leaf, see `mapAttrsRecursiveCond`.
 
-     Example:
-       mapAttrsRecursive (path: value: concatStringsSep "-" (path ++ [value]))
-         { n = { a = "A"; m = { b = "B"; c = "C"; }; }; d = "D"; }
-       => { n = { a = "n-a-A"; m = { b = "n-m-b-B"; c = "n-m-c-C"; }; }; d = "d-D"; }
+    :::{#map-attrs-recursive-example .example}
+    # Map over leaf attributes
 
-     Type:
-       mapAttrsRecursive :: ([String] -> a -> b) -> AttrSet -> AttrSet
+    ```nix
+    mapAttrsRecursive (path: value: concatStringsSep "-" (path ++ [value]))
+      { n = { a = "A"; m = { b = "B"; c = "C"; }; }; d = "D"; }
+    ```
+    evaluates to
+    ```nix
+    { n = { a = "n-a-A"; m = { b = "n-m-b-B"; c = "n-m-c-C"; }; }; d = "d-D"; }
+    ```
+    :::
+
+    # Type
+    ```
+    mapAttrsRecursive :: ([String] -> a -> b) -> AttrSet -> AttrSet
+    ```
   */
   mapAttrsRecursive =
-    # A function, given a list of attribute names and a value, returns a new value.
+    # A function that, given an attribute path as a list of strings and the corresponding attribute value, returns a new value.
     f:
-    # Set to recursively map over.
+    # Attribute set to recursively map over.
     set:
     mapAttrsRecursiveCond (as: true) f set;
 
 
-  /* Like `mapAttrsRecursive`, but it takes an additional predicate
-     function that tells it whether to recurse into an attribute
-     set.  If it returns false, `mapAttrsRecursiveCond` does not
-     recurse, but does apply the map function.  If it returns true, it
-     does recurse, and does not apply the map function.
+  /**
+    Like `mapAttrsRecursive`, but it takes an additional predicate that tells it whether to recurse into an attribute set.
+    If the predicate returns false, `mapAttrsRecursiveCond` does not recurse, but instead applies the mapping function.
+    If the predicate returns true, it does recurse, and does not apply the mapping function.
 
-     Example:
-       # To prevent recursing into derivations (which are attribute
-       # sets with the attribute "type" equal to "derivation"):
-       mapAttrsRecursiveCond
-         (as: !(as ? "type" && as.type == "derivation"))
-         (x: ... do something ...)
-         attrs
+    :::{#map-attrs-recursive-cond-example .example}
+    # Map over an leaf attributes defined by a condition
 
-     Type:
-       mapAttrsRecursiveCond :: (AttrSet -> Bool) -> ([String] -> a -> b) -> AttrSet -> AttrSet
+    Map derivations to their `name` attribute.
+    Derivatons are identified as attribute sets that contain `{ type = "derivation"; }`.
+    ```nix
+    mapAttrsRecursiveCond
+      (as: !(as ? "type" && as.type == "derivation"))
+      (x: x.name)
+      attrs
+    ```
+    :::
+
+    # Type
+    ```
+    mapAttrsRecursiveCond :: (AttrSet -> Bool) -> ([String] -> a -> b) -> AttrSet -> AttrSet
+    ```
   */
   mapAttrsRecursiveCond =
-    # A function, given the attribute set the recursion is currently at, determine if to recurse deeper into that attribute set.
+    # A function that, given the attribute set the recursion is currently at, determines if to recurse deeper into that attribute set.
     cond:
-    # A function, given a list of attribute names and a value, returns a new value.
+    # A function that, given an attribute path as a list of strings and the corresponding attribute value, returns a new value.
+    # The attribute value is either an attribute set for which `cond` returns false, or something other than an attribute set.
     f:
     # Attribute set to recursively map over.
     set:
     let
       recurse = path:
-        let
-          g =
-            name: value:
+        mapAttrs
+          (name: value:
             if isAttrs value && cond value
-              then recurse (path ++ [name]) value
-              else f (path ++ [name]) value;
-        in mapAttrs g;
-    in recurse [] set;
+            then recurse (path ++ [ name ]) value
+            else f (path ++ [ name ]) value);
+    in
+    recurse [ ] set;
 
 
   /* Generate an attribute set by mapping a function over a list of
@@ -870,10 +883,7 @@ rec {
      Type:
        zipAttrs :: [ AttrSet ] -> AttrSet
   */
-  zipAttrs =
-    # List of attribute sets to zip together.
-    sets:
-    zipAttrsWith (name: values: values) sets;
+  zipAttrs = zipAttrsWith (name: values: values);
 
   /*
     Merge a list of attribute sets together using the `//` operator.
@@ -1138,10 +1148,7 @@ rec {
    Type: chooseDevOutputs :: [Derivation] -> [String]
 
   */
-  chooseDevOutputs =
-    # List of packages to pick `dev` outputs from
-    drvs:
-    builtins.map getDev drvs;
+  chooseDevOutputs = builtins.map getDev;
 
   /* Make various Nix tools consider the contents of the resulting
      attribute set when looking for what to build, find, etc.
diff --git a/nixpkgs/lib/customisation.nix b/nixpkgs/lib/customisation.nix
index 0b5cad71fddf..7be412bac353 100644
--- a/nixpkgs/lib/customisation.nix
+++ b/nixpkgs/lib/customisation.nix
@@ -221,9 +221,10 @@ rec {
     let
       f = if isFunction fn then fn else import fn;
       auto = intersectAttrs (functionArgs f) autoArgs;
+      mirrorArgs = mirrorFunctionArgs f;
       origArgs = auto // args;
       pkgs = f origArgs;
-      mkAttrOverridable = name: _: makeOverridable (newArgs: (f newArgs).${name}) origArgs;
+      mkAttrOverridable = name: _: makeOverridable (mirrorArgs (newArgs: (f newArgs).${name})) origArgs;
     in
       if isDerivation pkgs then throw
         ("function `callPackages` was called on a *single* derivation "
diff --git a/nixpkgs/lib/derivations.nix b/nixpkgs/lib/derivations.nix
index 44b727ee31cc..6867458f9e87 100644
--- a/nixpkgs/lib/derivations.nix
+++ b/nixpkgs/lib/derivations.nix
@@ -1,7 +1,20 @@
 { lib }:
 
 let
-  inherit (lib) throwIfNot;
+  inherit (lib)
+    genAttrs
+    isString
+    throwIfNot
+    ;
+
+  showMaybeAttrPosPre = prefix: attrName: v:
+    let pos = builtins.unsafeGetAttrPos attrName v;
+    in if pos == null then "" else "${prefix}${pos.file}:${toString pos.line}:${toString pos.column}";
+
+  showMaybePackagePosPre = prefix: pkg:
+    if pkg?meta.position && isString pkg.meta.position
+    then "${prefix}${pkg.meta.position}"
+    else "";
 in
 {
   /*
@@ -64,6 +77,11 @@ in
       #
       # This can be used for adding package attributes, such as `tests`.
       passthru ? { }
+    , # Optional list of assumed outputs. Default: ["out"]
+      #
+      # This must match the set of outputs that the returned derivation has.
+      # You must use this when the derivation has multiple outputs.
+      outputs ? [ "out" ]
     }:
     let
       # These checks are strict in `drv` and some `drv` attributes, but the
@@ -71,11 +89,40 @@ in
       # Instead, the individual derivation attributes do depend on it.
       checked =
         throwIfNot (derivation.type or null == "derivation")
-          "lazySimpleDerivation: input must be a derivation."
+          "lazyDerivation: input must be a derivation."
           throwIfNot
-          (derivation.outputs == [ "out" ])
-          # Supporting multiple outputs should be a matter of inheriting more attrs.
-          "The derivation ${derivation.name or "<unknown>"} has multiple outputs. This is not supported by lazySimpleDerivation yet. Support could be added, and be useful as long as the set of outputs is known in advance, without evaluating the actual derivation."
+          # NOTE: Technically we could require our outputs to be a subset of the
+          # actual ones, or even leave them unchecked and fail on a lazy basis.
+          # However, consider the case where an output is added in the underlying
+          # derivation, such as dev. lazyDerivation would remove it and cause it
+          # to fail as a buildInputs item, without any indication as to what
+          # happened. Hence the more stringent condition. We could consider
+          # adding a flag to control this behavior if there's a valid case for it,
+          # but the documentation must have a note like this.
+          (derivation.outputs == outputs)
+          ''
+            lib.lazyDerivation: The derivation ${derivation.name or "<unknown>"} has outputs that don't match the assumed outputs.
+
+            Assumed outputs passed to lazyDerivation${showMaybeAttrPosPre ",\n    at " "outputs" args}:
+                ${lib.generators.toPretty { multiline = false; } outputs};
+
+            Actual outputs of the derivation${showMaybePackagePosPre ",\n    defined at " derivation}:
+                ${lib.generators.toPretty { multiline = false; } derivation.outputs}
+
+            If the outputs are known ahead of evaluating the derivation,
+            then update the lazyDerivation call to match the actual outputs, in the same order.
+            If lazyDerivation is passed a literal value, just change it to the actual outputs.
+            As a result it will work as before / as intended.
+
+            Otherwise, when the outputs are dynamic and can't be known ahead of time, it won't
+            be possible to add laziness, but lib.lazyDerivation may still be useful for trimming
+            the attributes.
+            If you want to keep trimming the attributes, make sure that the package is in a
+            variable (don't evaluate it twice!) and pass the variable and its outputs attribute
+            to lib.lazyDerivation. This largely defeats laziness, but keeps the trimming.
+            If none of the above works for you, replace the lib.lazyDerivation call by the
+            expression in the derivation argument.
+          ''
           derivation;
     in
     {
@@ -92,12 +139,15 @@ in
       # A fixed set of derivation values, so that `lazyDerivation` can return
       # its attrset before evaluating `derivation`.
       # This must only list attributes that are available on _all_ derivations.
-      inherit (checked) outputs out outPath outputName drvPath name system;
+      inherit (checked) outPath outputName drvPath name system;
+      inherit outputs;
 
       # The meta attribute can either be taken from the derivation, or if the
       # `lazyDerivation` caller knew a shortcut, be taken from there.
       meta = args.meta or checked.meta;
-    } // passthru;
+    }
+    // genAttrs outputs (outputName: checked.${outputName})
+    // passthru;
 
   /* Conditionally set a derivation attribute.
 
diff --git a/nixpkgs/lib/licenses.nix b/nixpkgs/lib/licenses.nix
index 39d8272f7573..30ca31ff71f2 100644
--- a/nixpkgs/lib/licenses.nix
+++ b/nixpkgs/lib/licenses.nix
@@ -412,6 +412,11 @@ in mkLicense lset) ({
     fullName = "Detection Rule License 1.0";
   };
 
+  dtoa = {
+    spdxId = "dtoa";
+    fullName = "dtoa License";
+  };
+
   eapl = {
     fullName = "EPSON AVASYS PUBLIC LICENSE";
     url = "https://avasys.jp/hp/menu000000700/hpg000000603.htm";
@@ -1066,6 +1071,11 @@ in mkLicense lset) ({
     url = "https://sources.debian.org/copyright/license/debianutils/4.9.1/";
   };
 
+  smlnj = {
+    spdxId = "SMLNJ";
+    fullName = "Standard ML of New Jersey License";
+  };
+
   sspl = {
     shortName = "SSPL";
     fullName = "Server Side Public License";
@@ -1215,6 +1225,11 @@ in mkLicense lset) ({
     url = "https://mcj.sourceforge.net/authors.html#xfig";
   };
 
+  xinetd = {
+    spdxId = "xinetd";
+    fullName = "xinetd License";
+  };
+
   zlib = {
     spdxId = "Zlib";
     fullName = "zlib License";
@@ -1229,6 +1244,11 @@ in mkLicense lset) ({
     spdxId = "ZPL-2.1";
     fullName = "Zope Public License 2.1";
   };
+
+  xskat = {
+    spdxId = "XSkat";
+    fullName = "XSkat License";
+  };
 } // {
   # TODO: remove legacy aliases
   agpl3 = {
diff --git a/nixpkgs/lib/strings.nix b/nixpkgs/lib/strings.nix
index 47ee095f1b68..32efc9bdb70e 100644
--- a/nixpkgs/lib/strings.nix
+++ b/nixpkgs/lib/strings.nix
@@ -1038,30 +1038,32 @@ rec {
        toInt "3.14"
        => error: floating point JSON numbers are not supported
   */
-  toInt = str:
+  toInt =
+    let
+      matchStripInput = match "[[:space:]]*(-?[[:digit:]]+)[[:space:]]*";
+      matchLeadingZero = match "0[[:digit:]]+";
+    in
+    str:
     let
       # RegEx: Match any leading whitespace, possibly a '-', one or more digits,
       # and finally match any trailing whitespace.
-      strippedInput = match "[[:space:]]*(-?[[:digit:]]+)[[:space:]]*" str;
+      strippedInput = matchStripInput str;
 
       # RegEx: Match a leading '0' then one or more digits.
-      isLeadingZero = match "0[[:digit:]]+" (head strippedInput) == [];
+      isLeadingZero = matchLeadingZero (head strippedInput) == [];
 
       # Attempt to parse input
       parsedInput = fromJSON (head strippedInput);
 
       generalError = "toInt: Could not convert ${escapeNixString str} to int.";
 
-      octalAmbigError = "toInt: Ambiguity in interpretation of ${escapeNixString str}"
-      + " between octal and zero padded integer.";
-
     in
       # Error on presence of non digit characters.
       if strippedInput == null
       then throw generalError
       # Error on presence of leading zero/octal ambiguity.
       else if isLeadingZero
-      then throw octalAmbigError
+      then throw "toInt: Ambiguity in interpretation of ${escapeNixString str} between octal and zero padded integer."
       # Error if parse function fails.
       else if !isInt parsedInput
       then throw generalError
@@ -1089,15 +1091,20 @@ rec {
        toIntBase10 "3.14"
        => error: floating point JSON numbers are not supported
   */
-  toIntBase10 = str:
+  toIntBase10 =
+    let
+      matchStripInput = match "[[:space:]]*0*(-?[[:digit:]]+)[[:space:]]*";
+      matchZero = match "0+";
+    in
+    str:
     let
       # RegEx: Match any leading whitespace, then match any zero padding,
       # capture possibly a '-' followed by one or more digits,
       # and finally match any trailing whitespace.
-      strippedInput = match "[[:space:]]*0*(-?[[:digit:]]+)[[:space:]]*" str;
+      strippedInput = matchStripInput str;
 
       # RegEx: Match at least one '0'.
-      isZero = match "0+" (head strippedInput) == [];
+      isZero = matchZero (head strippedInput) == [];
 
       # Attempt to parse input
       parsedInput = fromJSON (head strippedInput);
diff --git a/nixpkgs/lib/tests/misc.nix b/nixpkgs/lib/tests/misc.nix
index 193e68a96933..98d1f4e71c48 100644
--- a/nixpkgs/lib/tests/misc.nix
+++ b/nixpkgs/lib/tests/misc.nix
@@ -55,6 +55,24 @@ runTests {
     expected = { a = false; b = false; c = true; };
   };
 
+  testCallPackageWithOverridePreservesArguments =
+    let
+      f = { a ? 0, b }: {};
+      f' = callPackageWith { a = 1; b = 2; } f {};
+    in {
+      expr = functionArgs f'.override;
+      expected = functionArgs f;
+    };
+
+  testCallPackagesWithOverridePreservesArguments =
+    let
+      f = { a ? 0, b }: { nested = {}; };
+      f' = callPackagesWith { a = 1; b = 2; } f {};
+    in {
+      expr = functionArgs f'.nested.override;
+      expected = functionArgs f;
+    };
+
 # TRIVIAL
 
   testId = {
@@ -1973,6 +1991,24 @@ runTests {
     }).drvPath;
   };
 
+  testLazyDerivationMultiOutputReturnsDerivationAttrs = let
+    derivation = {
+      type = "derivation";
+      outputs = ["out" "dev"];
+      dev = "test dev";
+      out = "test out";
+      outPath = "test outPath";
+      outputName = "out";
+      drvPath = "test drvPath";
+      name = "test name";
+      system = "test system";
+      meta.position = "/hi:23";
+    };
+  in {
+    expr = lazyDerivation { inherit derivation; outputs = ["out" "dev"]; passthru.meta.position = "/hi:23"; };
+    expected = derivation;
+  };
+
   testTypeDescriptionInt = {
     expr = (with types; int).description;
     expected = "signed integer";
diff --git a/nixpkgs/lib/tests/test-with-nix.nix b/nixpkgs/lib/tests/test-with-nix.nix
index fd2e7532e697..9d66b91cab42 100644
--- a/nixpkgs/lib/tests/test-with-nix.nix
+++ b/nixpkgs/lib/tests/test-with-nix.nix
@@ -53,6 +53,12 @@ pkgs.runCommand "nixpkgs-lib-tests-nix-${nix.version}" {
   echo "Running lib/tests/modules.sh"
   bash lib/tests/modules.sh
 
+  echo "Checking lib.version"
+  nix-instantiate lib -A version --eval || {
+    echo "lib.version does not evaluate when lib is isolated from the rest of the nixpkgs tree"
+    exit 1
+  }
+
   echo "Running lib/tests/filesystem.sh"
   TEST_LIB=$PWD/lib bash lib/tests/filesystem.sh
 
diff --git a/nixpkgs/lib/trivial.nix b/nixpkgs/lib/trivial.nix
index fa499cbbf028..c197822a4f8e 100644
--- a/nixpkgs/lib/trivial.nix
+++ b/nixpkgs/lib/trivial.nix
@@ -159,7 +159,7 @@ in {
   version = release + versionSuffix;
 
   /* Returns the current nixpkgs release number as string. */
-  release = lib.strings.fileContents ../.version;
+  release = lib.strings.fileContents ./.version;
 
   /* The latest release that is supported, at the time of release branch-off,
      if applicable.