diff --git a/.mailmap b/.mailmap index d3858d78dde7..d2bf6d0e4769 100644 --- a/.mailmap +++ b/.mailmap @@ -1,3 +1,14 @@ +ajs124 +Anderson Torres Daniel Løvbrøtte Olsen +Fabian Affolter +Janne Heß +Jörg Thalheim +Martin Weinelt R. RyanTM -Sandro +Robert Hensing +Sandro Jäckel +Sandro Jäckel +superherointj <5861043+superherointj@users.noreply.github.com> +Vladimír Čunát +Vladimír Čunát diff --git a/doc/builders/images/dockertools.section.md b/doc/builders/images/dockertools.section.md index 6203b3786bfa..dfc012b80c5a 100644 --- a/doc/builders/images/dockertools.section.md +++ b/doc/builders/images/dockertools.section.md @@ -62,6 +62,8 @@ The above example will build a Docker image `redis/latest` from the given base i - `config` is used to specify the configuration of the containers that will be started off the built image in Docker. The available options are listed in the [Docker Image Specification v1.2.0](https://github.com/moby/moby/blob/master/image/spec/v1.2.md#image-json-field-descriptions). +- `architecture` is _optional_ and used to specify the image architecture, this is useful for multi-architecture builds that don't need cross compiling. If not specified it will default to `hostPlatform`. + - `diskSize` is used to specify the disk size of the VM used to build the image in megabytes. By default it's 1024 MiB. - `buildVMMemorySize` is used to specify the memory size of the VM to build the image in megabytes. By default it's 512 MiB. @@ -141,6 +143,8 @@ Create a Docker image with many of the store paths being on their own layer to i `config` _optional_ +`architecture` is _optional_ and used to specify the image architecture, this is useful for multi-architecture builds that don't need cross compiling. If not specified it will default to `hostPlatform`. + : Run-time configuration of the container. A full list of the options are available at in the [Docker Image Specification v1.2.0](https://github.com/moby/moby/blob/master/image/spec/v1.2.md#image-json-field-descriptions). *Default:* `{}` diff --git a/doc/languages-frameworks/cuelang.section.md b/doc/languages-frameworks/cuelang.section.md new file mode 100644 index 000000000000..93c94027ae29 --- /dev/null +++ b/doc/languages-frameworks/cuelang.section.md @@ -0,0 +1,93 @@ +# Cue (Cuelang) {#cuelang} + +[Cuelang](https://cuelang.org/) is a language to: + +- describe schemas and validate backward-compatibility +- generate code and schemas in various formats (e.g. JSON Schema, OpenAPI) +- do configuration akin to [Dhall Lang](https://dhall-lang.org/) +- perform data validation + +## Cuelang schema quick start + +Cuelang schemas are similar to JSON, here is a quick cheatsheet: + +- Default types includes: `null`, `string`, `bool`, `bytes`, `number`, `int`, `float`, lists as `[...T]` where `T` is a type. +- All structures, defined by: `myStructName: { }` are **open** -- they accept fields which are not specified. +- Closed structures can be built by doing `myStructName: close({ })` -- they are strict in what they accept. +- `#X` are **definitions**, referenced definitions are **recursively closed**, i.e. all its children structures are **closed**. +- `&` operator is the [unification operator](https://cuelang.org/docs/references/spec/#unification) (similar to a type-level merging operator), `|` is the [disjunction operator](https://cuelang.org/docs/references/spec/#disjunction) (similar to a type-level union operator). +- Values **are** types, i.e. `myStruct: { a: 3 }` is a valid type definition that only allows `3` as value. + +- Read to learn more about the semantics. +- Read to learn about the language specification. + +## `writeCueValidator` + +Nixpkgs provides a `pkgs.writeCueValidator` helper, which will write a validation script based on the provided Cuelang schema. + +Here is an example: +``` +pkgs.writeCueValidator + (pkgs.writeText "schema.cue" '' + #Def1: { + field1: string + } + '') + { document = "#Def1"; } +``` + +- The first parameter is the Cue schema file. +- The second paramter is an options parameter, currently, only: `document` can be passed. + +`document` : match your input data against this fragment of structure or definition, e.g. you may use the same schema file but differents documents based on the data you are validating. + +Another example, given the following `validator.nix` : +``` +{ pkgs ? import {} }: +let + genericValidator = version: + pkgs.writeCueValidator + (pkgs.writeText "schema.cue" '' + #Version1: { + field1: string + } + #Version2: #Version1 & { + field1: "unused" + }'' + ) + { document = "#Version${toString version}"; }; +in +{ + validateV1 = genericValidator 1; + validateV2 = genericValidator 2; +} +``` + +The result is a script that will validate the file you pass as the first argument against the schema you provided `writeCueValidator`. + +It can be any format that `cue vet` supports, i.e. YAML or JSON for example. + +Here is an example, named `example.json`, given the following JSON: +``` +{ "field1": "abc" } +``` + +You can run the result script (named `validate`) as the following: + +```console +$ nix-build validator.nix +$ ./result example.json +$ ./result-2 example.json +field1: conflicting values "unused" and "abc": + ./example.json:1:13 + ../../../../../../nix/store/v64dzx3vr3glpk0cq4hzmh450lrwh6sg-schema.cue:5:11 +$ sed -i 's/"abc"/3/' example.json +$ ./result example.json +field1: conflicting values 3 and string (mismatched types int and string): + ./example.json:1:13 + ../../../../../../nix/store/v64dzx3vr3glpk0cq4hzmh450lrwh6sg-schema.cue:5:11 +``` + +**Known limitations** + +* The script will enforce **concrete** values and will not accept lossy transformations (strictness). You can add these options if you need them. diff --git a/doc/languages-frameworks/index.xml b/doc/languages-frameworks/index.xml index 3d5b2f738976..7df241436ff5 100644 --- a/doc/languages-frameworks/index.xml +++ b/doc/languages-frameworks/index.xml @@ -13,6 +13,7 @@ + diff --git a/lib/generators.nix b/lib/generators.nix index b77cca75010f..c0fe69389e00 100644 --- a/lib/generators.nix +++ b/lib/generators.nix @@ -278,8 +278,11 @@ rec { mapAny 0; /* Pretty print a value, akin to `builtins.trace`. - * Should probably be a builtin as well. - */ + * Should probably be a builtin as well. + * The pretty-printed string should be suitable for rendering default values + * in the NixOS manual. In particular, it should be as close to a valid Nix expression + * as possible. + */ toPretty = { /* If this option is true, attrsets like { __pretty = fn; val = …; } will use fn to convert val to a pretty printed representation. @@ -294,20 +297,25 @@ rec { introSpace = if multiline then "\n${indent} " else " "; outroSpace = if multiline then "\n${indent}" else " "; in if isInt v then toString v - else if isFloat v then "~${toString v}" + # toString loses precision on floats, so we use toJSON instead. This isn't perfect + # as the resulting string may not parse back as a float (e.g. 42, 1e-06), but for + # pretty-printing purposes this is acceptable. + else if isFloat v then builtins.toJSON v else if isString v then let - # Separate a string into its lines - newlineSplits = filter (v: ! isList v) (builtins.split "\n" v); - # For a '' string terminated by a \n, which happens when the closing '' is on a new line - multilineResult = "''" + introSpace + concatStringsSep introSpace (lib.init newlineSplits) + outroSpace + "''"; - # For a '' string not terminated by a \n, which happens when the closing '' is not on a new line - multilineResult' = "''" + introSpace + concatStringsSep introSpace newlineSplits + "''"; - # For single lines, replace all newlines with their escaped representation - singlelineResult = "\"" + libStr.escape [ "\"" ] (concatStringsSep "\\n" newlineSplits) + "\""; - in if multiline && length newlineSplits > 1 then - if lib.last newlineSplits == "" then multilineResult else multilineResult' - else singlelineResult + lines = filter (v: ! isList v) (builtins.split "\n" v); + escapeSingleline = libStr.escape [ "\\" "\"" "\${" ]; + escapeMultiline = libStr.replaceStrings [ "\${" "''" ] [ "''\${" "'''" ]; + singlelineResult = "\"" + concatStringsSep "\\n" (map escapeSingleline lines) + "\""; + multilineResult = let + escapedLines = map escapeMultiline lines; + # The last line gets a special treatment: if it's empty, '' is on its own line at the "outer" + # indentation level. Otherwise, '' is appended to the last line. + lastLine = lib.last escapedLines; + in "''" + introSpace + concatStringsSep introSpace (lib.init escapedLines) + + (if lastLine == "" then outroSpace else introSpace + lastLine) + "''"; + in + if multiline && length lines > 1 then multilineResult else singlelineResult else if true == v then "true" else if false == v then "false" else if null == v then "null" @@ -326,11 +334,11 @@ rec { else "" else if isAttrs v then # apply pretty values if allowed - if attrNames v == [ "__pretty" "val" ] && allowPrettyValues + if allowPrettyValues && v ? __pretty && v ? val then v.__pretty v.val else if v == {} then "{ }" else if v ? type && v.type == "derivation" then - "" + "" else "{" + introSpace + libStr.concatStringsSep introSpace (libAttr.mapAttrsToList (name: value: diff --git a/lib/options.nix b/lib/options.nix index c80256c0e653..b13687576e81 100644 --- a/lib/options.nix +++ b/lib/options.nix @@ -218,7 +218,7 @@ rec { # the set generated with filterOptionSets. optionAttrSetToDocList = optionAttrSetToDocList' []; - optionAttrSetToDocList' = prefix: options: + optionAttrSetToDocList' = _: options: concatMap (opt: let docOption = rec { @@ -234,9 +234,8 @@ rec { readOnly = opt.readOnly or false; type = opt.type.description or "unspecified"; } - // optionalAttrs (opt ? example) { example = scrubOptionValue opt.example; } - // optionalAttrs (opt ? default) { default = scrubOptionValue opt.default; } - // optionalAttrs (opt ? defaultText) { default = opt.defaultText; } + // optionalAttrs (opt ? example) { example = renderOptionValue opt.example; } + // optionalAttrs (opt ? default) { default = renderOptionValue (opt.defaultText or opt.default); } // optionalAttrs (opt ? relatedPackages && opt.relatedPackages != null) { inherit (opt) relatedPackages; }; subOptions = @@ -256,6 +255,9 @@ rec { efficient: the XML representation of derivations is very large (on the order of megabytes) and is not actually used by the manual generator. + + This function was made obsolete by renderOptionValue and is kept for + compatibility with out-of-tree code. */ scrubOptionValue = x: if isDerivation x then @@ -265,6 +267,17 @@ rec { else x; + /* Ensures that the given option value (default or example) is a `_type`d string + by rendering Nix values to `literalExpression`s. + */ + renderOptionValue = v: + if v ? _type && v ? text then v + else literalExpression (lib.generators.toPretty { + multiline = true; + allowPrettyValues = true; + } v); + + /* For use in the `defaultText` and `example` option attributes. Causes the given string to be rendered verbatim in the documentation as Nix code. This is necessary for complex values, e.g. functions, or values that depend on diff --git a/lib/strings.nix b/lib/strings.nix index 96dfb779cd6f..9a4f29380d0d 100644 --- a/lib/strings.nix +++ b/lib/strings.nix @@ -510,7 +510,7 @@ rec { toUpper = replaceChars lowerChars upperChars; /* Appends string context from another string. This is an implementation - detail of Nix. + detail of Nix and should be used carefully. Strings in Nix carry an invisible `context` which is a list of strings representing store paths. If the string is later used in a derivation @@ -533,13 +533,11 @@ rec { splitString "/" "/usr/local/bin" => [ "" "usr" "local" "bin" ] */ - splitString = _sep: _s: + splitString = sep: s: let - sep = builtins.unsafeDiscardStringContext _sep; - s = builtins.unsafeDiscardStringContext _s; - splits = builtins.filter builtins.isString (builtins.split (escapeRegex sep) s); + splits = builtins.filter builtins.isString (builtins.split (escapeRegex (toString sep)) (toString s)); in - map (v: addContextFrom _sep (addContextFrom _s v)) splits; + map (addContextFrom s) splits; /* Return a string without the specified prefix, if the prefix matches. diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix index b73da4f1010d..648c05ab3572 100644 --- a/lib/tests/misc.nix +++ b/lib/tests/misc.nix @@ -727,7 +727,7 @@ runTests { float = 0.1337; bool = true; emptystring = ""; - string = ''fno"rd''; + string = "fn\${o}\"r\\d"; newlinestring = "\n"; path = /. + "/foo"; null_ = null; @@ -735,16 +735,16 @@ runTests { functionArgs = { arg ? 4, foo }: arg; list = [ 3 4 function [ false ] ]; emptylist = []; - attrs = { foo = null; "foo bar" = "baz"; }; + attrs = { foo = null; "foo b/ar" = "baz"; }; emptyattrs = {}; drv = deriv; }; expected = rec { int = "42"; - float = "~0.133700"; + float = "0.1337"; bool = "true"; emptystring = ''""''; - string = ''"fno\"rd"''; + string = ''"fn\''${o}\"r\\d"''; newlinestring = "\"\\n\""; path = "/foo"; null_ = "null"; @@ -752,9 +752,9 @@ runTests { functionArgs = ""; list = "[ 3 4 ${function} [ false ] ]"; emptylist = "[ ]"; - attrs = "{ foo = null; \"foo bar\" = \"baz\"; }"; + attrs = "{ foo = null; \"foo b/ar\" = \"baz\"; }"; emptyattrs = "{ }"; - drv = ""; + drv = ""; }; }; @@ -799,8 +799,8 @@ runTests { newlinestring = "\n"; multilinestring = '' hello - there - test + ''${there} + te'''st ''; multilinestring' = '' hello @@ -827,8 +827,8 @@ runTests { multilinestring = '' ''' hello - there - test + '''''${there} + te''''st '''''; multilinestring' = '' ''' diff --git a/nixos/doc/manual/from_md/release-notes/rl-2305.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2305.section.xml index 61daeac86a64..cc330e2f8870 100644 --- a/nixos/doc/manual/from_md/release-notes/rl-2305.section.xml +++ b/nixos/doc/manual/from_md/release-notes/rl-2305.section.xml @@ -175,6 +175,15 @@ sudo and sources the environment variables. + + + The dnsmasq service now takes configuration + via the services.dnsmasq.settings attribute + set. The option + services.dnsmasq.extraConfig will be + deprecated when NixOS 22.11 reaches end of life. + + A new virtualisation.rosetta module was diff --git a/nixos/doc/manual/release-notes/rl-2305.section.md b/nixos/doc/manual/release-notes/rl-2305.section.md index f9c76b02f891..886db43c68eb 100644 --- a/nixos/doc/manual/release-notes/rl-2305.section.md +++ b/nixos/doc/manual/release-notes/rl-2305.section.md @@ -53,6 +53,11 @@ In addition to numerous new and upgraded packages, this release has the followin - `services.mastodon` gained a tootctl wrapped named `mastodon-tootctl` similar to `nextcloud-occ` which can be executed from any user and switches to the configured mastodon user with sudo and sources the environment variables. +- The `dnsmasq` service now takes configuration via the + `services.dnsmasq.settings` attribute set. The option + `services.dnsmasq.extraConfig` will be deprecated when NixOS 22.11 reaches + end of life. + - A new `virtualisation.rosetta` module was added to allow running `x86_64` binaries through [Rosetta](https://developer.apple.com/documentation/apple-silicon/about-the-rosetta-translation-environment) inside virtualised NixOS guests on Apple silicon. This feature works by default with the [UTM](https://docs.getutm.app/) virtualisation [package](https://search.nixos.org/packages?channel=unstable&show=utm&from=0&size=1&sort=relevance&type=packages&query=utm). - Resilio sync secret keys can now be provided using a secrets file at runtime, preventing these secrets from ending up in the Nix store. diff --git a/nixos/lib/make-options-doc/default.nix b/nixos/lib/make-options-doc/default.nix index 694512115d40..dea3eec5bd6d 100644 --- a/nixos/lib/make-options-doc/default.nix +++ b/nixos/lib/make-options-doc/default.nix @@ -26,7 +26,7 @@ # If you include more than one option list into a document, you need to # provide different ids. , variablelistId ? "configuration-variable-list" - # Strig to prefix to the option XML/HTML id attributes. + # String to prefix to the option XML/HTML id attributes. , optionIdPrefix ? "opt-" , revision ? "" # Specify revision for the options # a set of options the docs we are generating will be merged into, as if by recursiveUpdate. @@ -45,28 +45,11 @@ }: let - # Make a value safe for JSON. Functions are replaced by the string "", - # derivations are replaced with an attrset - # { _type = "derivation"; name = ; }. - # We need to handle derivations specially because consumers want to know about them, - # but we can't easily use the type,name subset of keys (since type is often used as - # a module option and might cause confusion). Use _type,name instead to the same - # effect, since _type is already used by the module system. - substSpecial = x: - if lib.isDerivation x then { _type = "derivation"; name = x.name; } - else if builtins.isAttrs x then lib.mapAttrs (name: substSpecial) x - else if builtins.isList x then map substSpecial x - else if lib.isFunction x then "" - else x; - rawOpts = lib.optionAttrSetToDocList options; transformedOpts = map transformOptions rawOpts; filteredOpts = lib.filter (opt: opt.visible && !opt.internal) transformedOpts; optionsList = lib.flip map filteredOpts (opt: opt - // lib.optionalAttrs (opt ? example) { example = substSpecial opt.example; } - // lib.optionalAttrs (opt ? default) { default = substSpecial opt.default; } - // lib.optionalAttrs (opt ? type) { type = substSpecial opt.type; } // lib.optionalAttrs (opt ? relatedPackages && opt.relatedPackages != []) { relatedPackages = genRelatedPackages opt.relatedPackages opt.name; } ); diff --git a/nixos/lib/make-options-doc/options-to-docbook.xsl b/nixos/lib/make-options-doc/options-to-docbook.xsl index 0fe14a6d2d16..ac49659c681f 100644 --- a/nixos/lib/make-options-doc/options-to-docbook.xsl +++ b/nixos/lib/make-options-doc/options-to-docbook.xsl @@ -138,82 +138,6 @@ - - - '' - - '' - - - - - - - - - - - null - - - - - - - '''' - - - "" - - - - - - - - - - - - true - - - - - false - - - - - [ - - - - - ] - - - - - - - - - - { - - - = - ; - - } - - - - - (build of ) - -