diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/customisation.nix | 6 | ||||
-rw-r--r-- | lib/fixed-points.nix | 159 | ||||
-rw-r--r-- | lib/licenses.nix | 9 | ||||
-rw-r--r-- | lib/systems/inspect.nix | 6 | ||||
-rw-r--r-- | lib/tests/misc.nix | 12 | ||||
-rw-r--r-- | lib/types.nix | 22 |
6 files changed, 185 insertions, 29 deletions
diff --git a/lib/customisation.nix b/lib/customisation.nix index c233744e07ca..0b5cad71fddf 100644 --- a/lib/customisation.nix +++ b/lib/customisation.nix @@ -203,7 +203,11 @@ rec { in if missingArgs == {} then makeOverridable f allArgs - else throw "lib.customisation.callPackageWith: ${error}"; + # This needs to be an abort so it can't be caught with `builtins.tryEval`, + # which is used by nix-env and ofborg to filter out packages that don't evaluate. + # This way we're forced to fix such errors in Nixpkgs, + # which is especially relevant with allowAliases = false + else abort "lib.customisation.callPackageWith: ${error}"; /* Like callPackage, but for a function that returns an attribute diff --git a/lib/fixed-points.nix b/lib/fixed-points.nix index 3b5fdc9e8ea1..3370b55a4ab9 100644 --- a/lib/fixed-points.nix +++ b/lib/fixed-points.nix @@ -103,42 +103,155 @@ rec { else converge f x'; /* - Modify the contents of an explicitly recursive attribute set in a way that - honors `self`-references. This is accomplished with a function + Extend a function using an overlay. + + Overlays allow modifying and extending fixed-point functions, specifically ones returning attribute sets. + A fixed-point function is a function which is intended to be evaluated by passing the result of itself as the argument. + This is possible due to Nix's lazy evaluation. + + + A fixed-point function returning an attribute set has the form + + ```nix + final: { # attributes } + ``` + + where `final` refers to the lazily evaluated attribute set returned by the fixed-point function. + + An overlay to such a fixed-point function has the form ```nix - g = self: super: { foo = super.foo + " + "; } + final: prev: { # attributes } + ``` + + where `prev` refers to the result of the original function to `final`, and `final` is the result of the composition of the overlay and the original function. + + Applying an overlay is done with `extends`: + + ```nix + let + f = final: { # attributes }; + overlay = final: prev: { # attributes }; + in extends overlay f; + ``` + + To get the value of `final`, use `lib.fix`: + + ```nix + let + f = final: { # attributes }; + overlay = final: prev: { # attributes }; + g = extends overlay f; + in fix g + ``` + + :::{.example} + + # Extend a fixed-point function with an overlay + + Define a fixed-point function `f` that expects its own output as the argument `final`: + + ```nix-repl + f = final: { + # Constant value a + a = 1; + + # b depends on the final value of a, available as final.a + b = final.a + 2; + } + ``` + + Evaluate this using [`lib.fix`](#function-library-lib.fixedPoints.fix) to get the final result: + + ```nix-repl + fix f + => { a = 1; b = 3; } ``` - that has access to the unmodified input (`super`) as well as the final - non-recursive representation of the attribute set (`self`). `extends` - differs from the native `//` operator insofar as that it's applied *before* - references to `self` are resolved: + An overlay represents a modification or extension of such a fixed-point function. + Here's an example of an overlay: + ```nix-repl + overlay = final: prev: { + # Modify the previous value of a, available as prev.a + a = prev.a + 10; + + # Extend the attribute set with c, letting it depend on the final values of a and b + c = final.a + final.b; + } ``` - nix-repl> fix (extends g f) - { bar = "bar"; foo = "foo + "; foobar = "foo + bar"; } + + Use `extends overlay f` to apply the overlay to the fixed-point function `f`. + This produces a new fixed-point function `g` with the combined behavior of `f` and `overlay`: + + ```nix-repl + g = extends overlay f ``` - The name of the function is inspired by object-oriented inheritance, i.e. - think of it as an infix operator `g extends f` that mimics the syntax from - Java. It may seem counter-intuitive to have the "base class" as the second - argument, but it's nice this way if several uses of `extends` are cascaded. + The result is a function, so we can't print it directly, but it's the same as: + + ```nix-repl + g' = final: { + # The constant from f, but changed with the overlay + a = 1 + 10; - To get a better understanding how `extends` turns a function with a fix - point (the package set we start with) into a new function with a different fix - point (the desired packages set) lets just see, how `extends g f` - unfolds with `g` and `f` defined above: + # Unchanged from f + b = final.a + 2; + # Extended in the overlay + c = final.a + final.b; + } ``` - extends g f = self: let super = f self; in super // g self super; - = self: let super = { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; }; in super // g self super - = self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; } // g self { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; } - = self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; } // { foo = "foo" + " + "; } - = self: { foo = "foo + "; bar = "bar"; foobar = self.foo + self.bar; } + + Evaluate this using [`lib.fix`](#function-library-lib.fixedPoints.fix) again to get the final result: + + ```nix-repl + fix g + => { a = 11; b = 13; c = 24; } ``` + ::: + + Type: + extends :: (Attrs -> Attrs -> Attrs) # The overlay to apply to the fixed-point function + -> (Attrs -> Attrs) # A fixed-point function + -> (Attrs -> Attrs) # The resulting fixed-point function + + Example: + f = final: { a = 1; b = final.a + 2; } + + fix f + => { a = 1; b = 3; } + + fix (extends (final: prev: { a = prev.a + 10; }) f) + => { a = 11; b = 13; } + + fix (extends (final: prev: { b = final.a + 5; }) f) + => { a = 1; b = 6; } + + fix (extends (final: prev: { c = final.a + final.b; }) f) + => { a = 1; b = 3; c = 4; } + + :::{.note} + The argument to the given fixed-point function after applying an overlay will *not* refer to its own return value, but rather to the value after evaluating the overlay function. + + The given fixed-point function is called with a separate argument than if it was evaluated with `lib.fix`. + The new argument + ::: */ - extends = f: rattrs: self: let super = rattrs self; in super // f self super; + extends = + # The overlay to apply to the fixed-point function + overlay: + # The fixed-point function + f: + # Wrap with parenthesis to prevent nixdoc from rendering the `final` argument in the documentation + # The result should be thought of as a function, the argument of that function is not an argument to `extends` itself + ( + final: + let + prev = f final; + in + prev // overlay final prev + ); /* Compose two extending functions of the type expected by 'extends' diff --git a/lib/licenses.nix b/lib/licenses.nix index baf92007123d..8dc01e560746 100644 --- a/lib/licenses.nix +++ b/lib/licenses.nix @@ -104,6 +104,7 @@ in mkLicense lset) ({ }; arphicpl = { + spdxId = "Arphic-1999"; fullName = "Arphic Public License"; url = "https://www.freedesktop.org/wiki/Arphic_Public_License/"; }; @@ -236,6 +237,7 @@ in mkLicense lset) ({ }; cal10 = { + spdxId = "CAL-1.0"; fullName = "Cryptographic Autonomy License version 1.0 (CAL-1.0)"; url = "https://opensource.org/licenses/CAL-1.0"; }; @@ -429,6 +431,7 @@ in mkLicense lset) ({ }; elastic20 = { + spdxId = "Elastic-2.0"; fullName = "Elastic License 2.0"; url = "https://github.com/elastic/elasticsearch/blob/main/licenses/ELASTIC-LICENSE-2.0.txt"; free = false; @@ -598,6 +601,7 @@ in mkLicense lset) ({ # Intel's license, seems free iasl = { + spdxId = "Intel-ACPI"; fullName = "iASL"; url = "https://old.calculate-linux.org/packages/licenses/iASL"; }; @@ -609,7 +613,7 @@ in mkLicense lset) ({ imagemagick = { fullName = "ImageMagick License"; - spdxId = "imagemagick"; + spdxId = "ImageMagick"; }; imlib2 = { @@ -803,6 +807,7 @@ in mkLicense lset) ({ }; miros = { + spdxId = "MirOS"; fullName = "MirOS License"; url = "https://opensource.org/licenses/MirOS"; }; @@ -1138,6 +1143,7 @@ in mkLicense lset) ({ }; upl = { + spdxId = "UPL-1.0"; fullName = "Universal Permissive License"; url = "https://oss.oracle.com/licenses/upl/"; }; @@ -1194,6 +1200,7 @@ in mkLicense lset) ({ }; xfig = { + spdxId = "Xfig"; fullName = "xfig"; url = "https://mcj.sourceforge.net/authors.html#xfig"; }; diff --git a/lib/systems/inspect.nix b/lib/systems/inspect.nix index 073df78797c7..38ca9967cdde 100644 --- a/lib/systems/inspect.nix +++ b/lib/systems/inspect.nix @@ -62,7 +62,8 @@ rec { is32bit = { cpu = { bits = 32; }; }; is64bit = { cpu = { bits = 64; }; }; - isILP32 = map (a: { abi = { abi = a; }; }) [ "n32" "ilp32" "x32" ]; + isILP32 = [ { cpu = { family = "wasm"; bits = 32; }; } ] ++ + map (a: { abi = { abi = a; }; }) [ "n32" "ilp32" "x32" ]; isBigEndian = { cpu = { significantByte = significantBytes.bigEndian; }; }; isLittleEndian = { cpu = { significantByte = significantBytes.littleEndian; }; }; @@ -98,6 +99,9 @@ rec { { cpu = { family = "riscv"; }; } { cpu = { family = "x86"; }; } ]; + + isElf = { kernel.execFormat = execFormats.elf; }; + isMacho = { kernel.execFormat = execFormats.macho; }; }; # given two patterns, return a pattern which is their logical AND. diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix index cf7fa9f2e284..3059878ba069 100644 --- a/lib/tests/misc.nix +++ b/lib/tests/misc.nix @@ -1959,6 +1959,18 @@ runTests { expr = (with types; int).description; expected = "signed integer"; }; + testTypeDescriptionIntsPositive = { + expr = (with types; ints.positive).description; + expected = "positive integer, meaning >0"; + }; + testTypeDescriptionIntsPositiveOrEnumAuto = { + expr = (with types; either ints.positive (enum ["auto"])).description; + expected = ''positive integer, meaning >0, or value "auto" (singular enum)''; + }; + testTypeDescriptionListOfPositive = { + expr = (with types; listOf ints.positive).description; + expected = "list of (positive integer, meaning >0)"; + }; testTypeDescriptionListOfInt = { expr = (with types; listOf int).description; expected = "list of signed integer"; diff --git a/lib/types.nix b/lib/types.nix index 4378568c141f..cea63c598321 100644 --- a/lib/types.nix +++ b/lib/types.nix @@ -113,9 +113,14 @@ rec { , # Description of the type, defined recursively by embedding the wrapped type if any. description ? null # A hint for whether or not this description needs parentheses. Possible values: - # - "noun": a simple noun phrase such as "positive integer" - # - "conjunction": a phrase with a potentially ambiguous "or" connective. + # - "noun": a noun phrase + # Example description: "positive integer", + # - "conjunction": a phrase with a potentially ambiguous "or" connective + # Example description: "int or string" # - "composite": a phrase with an "of" connective + # Example description: "list of string" + # - "nonRestrictiveClause": a noun followed by a comma and a clause + # Example description: "positive integer, meaning >0" # See the `optionDescriptionPhrase` function. , descriptionClass ? null , # DO NOT USE WITHOUT KNOWING WHAT YOU ARE DOING! @@ -338,10 +343,12 @@ rec { unsigned = addCheck types.int (x: x >= 0) // { name = "unsignedInt"; description = "unsigned integer, meaning >=0"; + descriptionClass = "nonRestrictiveClause"; }; positive = addCheck types.int (x: x > 0) // { name = "positiveInt"; description = "positive integer, meaning >0"; + descriptionClass = "nonRestrictiveClause"; }; u8 = unsign 8 256; u16 = unsign 16 65536; @@ -383,10 +390,12 @@ rec { nonnegative = addCheck number (x: x >= 0) // { name = "numberNonnegative"; description = "nonnegative integer or floating point number, meaning >=0"; + descriptionClass = "nonRestrictiveClause"; }; positive = addCheck number (x: x > 0) // { name = "numberPositive"; description = "positive integer or floating point number, meaning >0"; + descriptionClass = "nonRestrictiveClause"; }; }; @@ -463,6 +472,7 @@ rec { passwdEntry = entryType: addCheck entryType (str: !(hasInfix ":" str || hasInfix "\n" str)) // { name = "passwdEntry ${entryType.name}"; description = "${optionDescriptionPhrase (class: class == "noun") entryType}, not containing newlines or colons"; + descriptionClass = "nonRestrictiveClause"; }; attrs = mkOptionType { @@ -870,7 +880,13 @@ rec { # Either value of type `t1` or `t2`. either = t1: t2: mkOptionType rec { name = "either"; - description = "${optionDescriptionPhrase (class: class == "noun" || class == "conjunction") t1} or ${optionDescriptionPhrase (class: class == "noun" || class == "conjunction" || class == "composite") t2}"; + description = + if t1.descriptionClass or null == "nonRestrictiveClause" + then + # Plain, but add comma + "${t1.description}, or ${optionDescriptionPhrase (class: class == "noun" || class == "conjunction") t2}" + else + "${optionDescriptionPhrase (class: class == "noun" || class == "conjunction") t1} or ${optionDescriptionPhrase (class: class == "noun" || class == "conjunction" || class == "composite") t2}"; descriptionClass = "conjunction"; check = x: t1.check x || t2.check x; merge = loc: defs: |