From d1d1ae7a3b97059af09dd5a5dde2e37ada0fddac Mon Sep 17 00:00:00 2001 From: Noah Snelson Date: Mon, 27 Mar 2023 17:12:49 -0700 Subject: [PATCH 01/11] Documentation: list experimental features in manual Lists all current experimental features in the `nix.conf` manual. --- src/libutil/config.hh | 2 +- src/libutil/experimental-features.cc | 91 +++++++++++++++++++++++----- src/libutil/experimental-features.hh | 5 +- 3 files changed, 81 insertions(+), 17 deletions(-) diff --git a/src/libutil/config.hh b/src/libutil/config.hh index 748d6043b..59a766034 100644 --- a/src/libutil/config.hh +++ b/src/libutil/config.hh @@ -367,7 +367,7 @@ extern GlobalConfig globalConfig; struct ExperimentalFeatureSettings : Config { Setting> experimentalFeatures{this, {}, "experimental-features", - "Experimental Nix features to enable."}; + getExperimentalFeaturesList()}; /** * Check whether the given experimental feature is enabled. diff --git a/src/libutil/experimental-features.cc b/src/libutil/experimental-features.cc index 58d762ebb..fc8590674 100644 --- a/src/libutil/experimental-features.cc +++ b/src/libutil/experimental-features.cc @@ -5,18 +5,61 @@ namespace nix { -std::map stringifiedXpFeatures = { - { Xp::CaDerivations, "ca-derivations" }, - { Xp::ImpureDerivations, "impure-derivations" }, - { Xp::Flakes, "flakes" }, - { Xp::NixCommand, "nix-command" }, - { Xp::RecursiveNix, "recursive-nix" }, - { Xp::NoUrlLiterals, "no-url-literals" }, - { Xp::FetchClosure, "fetch-closure" }, - { Xp::ReplFlake, "repl-flake" }, - { Xp::AutoAllocateUids, "auto-allocate-uids" }, - { Xp::Cgroups, "cgroups" }, - { Xp::DiscardReferences, "discard-references" }, +std::map> stringifiedXpFeatures = { + { Xp::CaDerivations, {"ca-derivations", R"( + Allows derivations to be content-addressed in order to prevent rebuilds + when changes to the derivation do not result in changes to the + derivation's output. See + [__contentAddressed](../language/advanced-attributes.md#adv-attr-__contentAddressed) + for more info. + )"} }, + { Xp::ImpureDerivations, {"impure-derivations", R"( + Allows derivations to produce non-fixed outputs by setting the `__impure` + derivation attribute to `true`. See [these release + notes](../release-notes/rl-2.8.md) for an example. + )"} }, + { Xp::Flakes, {"flakes", R"( + Allows for derivations to be packaged in flakes. See the manual entry for + [`nix flake`](../command-ref/new-cli/nix3-flake.md) or this [detailed + introduction](https://www.tweag.io/blog/2020-05-25-flakes/) for more info. + )"} }, + { Xp::NixCommand, {"nix-command", R"( + Allows the usage of the new `nix` CLI subcommands, such as `nix build`, `nix + develop`, `nix run`, etc. See the manual for + [`nix`](../command-ref/new-cli/nix.md) for more info. + )"} }, + { Xp::RecursiveNix, {"recursive-nix", R"( + Allow Nix derivations to call Nix in order to recursively build derivations. + See [this + commit](https://github.com/edolstra/nix/commit/1a27aa7d64ffe6fc36cfca4d82bdf51c4d8cf717) + for more info. + )"} }, + { Xp::NoUrlLiterals, {"no-url-literals", R"( + Disallows unquoted URLs as part of the Nix language syntax. See [RFC + 45](https://github.com/NixOS/rfcs/pull/45) for more info. + )"} }, + { Xp::FetchClosure, {"fetch-closure", R"( + Enables the use of the `fetchClosure` function in the standard library. See + the docs for [`fetchClosure`](../language/builtins.md#builtins-fetchClosure) + for more info. + )"} }, + { Xp::ReplFlake, {"repl-flake", R"( + Allows the user to enter a Nix REPL within a flake, e.g. `nix repl nixpkgs` + or `nix repl .#foo`. + )"} }, + { Xp::AutoAllocateUids, {"auto-allocate-uids", R"( + Allows Nix to automatically pick UIDs for builds, rather than creating + `nixbld*` user accounts. See [here](#conf-auto-allocate-uids) for more info. + )"} }, + { Xp::Cgroups, {"cgroups", R"( + Allows Nix to execute builds inside cgroups. See + [`use-cgroups`](#conf-use-cgroups) for more info. + )"} }, + { Xp::DiscardReferences, {"discard-references", R"( + Enables the use of the `unsafeDiscardReferences` attribute in derivations + that use structured attributes. This disables scanning of outputs for + runtime dependencies. + )"} }, }; const std::optional parseExperimentalFeature(const std::string_view & name) @@ -26,8 +69,11 @@ const std::optional parseExperimentalFeature(const std::str static auto reverseXpMap = []() { auto reverseXpMap = std::make_unique(); - for (auto & [feature, name] : stringifiedXpFeatures) + std::string_view name; + for (auto & [feature, featureStringPair] : stringifiedXpFeatures) { + name = featureStringPair.first; (*reverseXpMap)[name] = feature; + } return reverseXpMap; }(); @@ -41,7 +87,24 @@ std::string_view showExperimentalFeature(const ExperimentalFeature feature) { const auto ret = get(stringifiedXpFeatures, feature); assert(ret); - return *ret; + return ret->first; +} + +std::string getExperimentalFeaturesList() { + std::string experimentalFeaturesList = R"( + Experimental Nix features to enable. + Current experimental features are the following: + +)"; + + std::string experimentalFeatureString; + for (auto& [feature, featureStringPair] : stringifiedXpFeatures) { + experimentalFeatureString = " - `" + featureStringPair.first + "`\n"; + experimentalFeatureString += featureStringPair.second + "\n\n"; + experimentalFeaturesList += experimentalFeatureString; + } + + return experimentalFeaturesList; } std::set parseFeatures(const std::set & rawFeatures) diff --git a/src/libutil/experimental-features.hh b/src/libutil/experimental-features.hh index ac372e03e..1f1852705 100644 --- a/src/libutil/experimental-features.hh +++ b/src/libutil/experimental-features.hh @@ -10,8 +10,8 @@ namespace nix { /** * The list of available experimental features. * - * If you update this, don’t forget to also change the map defining their - * string representation in the corresponding `.cc` file. + * If you update this, don’t forget to also change the map defining their string + * representation and documentation in the corresponding `.cc` file as well. **/ enum struct ExperimentalFeature { @@ -36,6 +36,7 @@ using Xp = ExperimentalFeature; const std::optional parseExperimentalFeature( const std::string_view & name); std::string_view showExperimentalFeature(const ExperimentalFeature); +std::string getExperimentalFeaturesList(); std::ostream & operator<<( std::ostream & str, From 2585bcaa500f874871d8ac34a83fca638770b78f Mon Sep 17 00:00:00 2001 From: John Ericson Date: Sun, 2 Apr 2023 18:11:16 -0400 Subject: [PATCH 02/11] Rework a few things with the experimental features list - Use struct not `std::pair`, designated initializers - Use `constexpr` array that we can index by enum tag - It no longer segfaults; not sure why. --- src/libutil/experimental-features.cc | 209 +++++++++++++++++---------- src/libutil/experimental-features.hh | 5 +- src/libutil/util.hh | 10 +- 3 files changed, 142 insertions(+), 82 deletions(-) diff --git a/src/libutil/experimental-features.cc b/src/libutil/experimental-features.cc index fc8590674..305b0cb11 100644 --- a/src/libutil/experimental-features.cc +++ b/src/libutil/experimental-features.cc @@ -5,75 +5,131 @@ namespace nix { -std::map> stringifiedXpFeatures = { - { Xp::CaDerivations, {"ca-derivations", R"( - Allows derivations to be content-addressed in order to prevent rebuilds - when changes to the derivation do not result in changes to the - derivation's output. See - [__contentAddressed](../language/advanced-attributes.md#adv-attr-__contentAddressed) - for more info. - )"} }, - { Xp::ImpureDerivations, {"impure-derivations", R"( - Allows derivations to produce non-fixed outputs by setting the `__impure` - derivation attribute to `true`. See [these release - notes](../release-notes/rl-2.8.md) for an example. - )"} }, - { Xp::Flakes, {"flakes", R"( - Allows for derivations to be packaged in flakes. See the manual entry for - [`nix flake`](../command-ref/new-cli/nix3-flake.md) or this [detailed - introduction](https://www.tweag.io/blog/2020-05-25-flakes/) for more info. - )"} }, - { Xp::NixCommand, {"nix-command", R"( - Allows the usage of the new `nix` CLI subcommands, such as `nix build`, `nix - develop`, `nix run`, etc. See the manual for - [`nix`](../command-ref/new-cli/nix.md) for more info. - )"} }, - { Xp::RecursiveNix, {"recursive-nix", R"( - Allow Nix derivations to call Nix in order to recursively build derivations. - See [this - commit](https://github.com/edolstra/nix/commit/1a27aa7d64ffe6fc36cfca4d82bdf51c4d8cf717) - for more info. - )"} }, - { Xp::NoUrlLiterals, {"no-url-literals", R"( - Disallows unquoted URLs as part of the Nix language syntax. See [RFC - 45](https://github.com/NixOS/rfcs/pull/45) for more info. - )"} }, - { Xp::FetchClosure, {"fetch-closure", R"( - Enables the use of the `fetchClosure` function in the standard library. See - the docs for [`fetchClosure`](../language/builtins.md#builtins-fetchClosure) - for more info. - )"} }, - { Xp::ReplFlake, {"repl-flake", R"( - Allows the user to enter a Nix REPL within a flake, e.g. `nix repl nixpkgs` - or `nix repl .#foo`. - )"} }, - { Xp::AutoAllocateUids, {"auto-allocate-uids", R"( - Allows Nix to automatically pick UIDs for builds, rather than creating - `nixbld*` user accounts. See [here](#conf-auto-allocate-uids) for more info. - )"} }, - { Xp::Cgroups, {"cgroups", R"( - Allows Nix to execute builds inside cgroups. See - [`use-cgroups`](#conf-use-cgroups) for more info. - )"} }, - { Xp::DiscardReferences, {"discard-references", R"( - Enables the use of the `unsafeDiscardReferences` attribute in derivations - that use structured attributes. This disables scanning of outputs for - runtime dependencies. - )"} }, +struct ExperimentalFeatureDetails +{ + ExperimentalFeature tag; + std::string_view name; + std::string_view description; }; +constexpr std::array xpFeatureDetails = {{ + { + .tag = Xp::CaDerivations, + .name = "ca-derivations", + .description = R"( + Allows derivations to be content-addressed in order to prevent rebuilds + when changes to the derivation do not result in changes to the + derivation's output. See + [__contentAddressed](../language/advanced-attributes.md#adv-attr-__contentAddressed) + for more info. + )", + }, + { + .tag = Xp::ImpureDerivations, + .name = "impure-derivations", + .description = R"( + Allows derivations to produce non-fixed outputs by setting the `__impure` + derivation attribute to `true`. See [these release + notes](../release-notes/rl-2.8.md) for an example. + )", + }, + { + .tag = Xp::Flakes, + .name = "flakes", + .description = R"( + Allows for derivations to be packaged in flakes. See the manual entry for + [`nix flake`](../command-ref/new-cli/nix3-flake.md) or this [detailed + introduction](https://www.tweag.io/blog/2020-05-25-flakes/) for more info. + )", + }, + { + .tag = Xp::NixCommand, + .name = "nix-command", + .description = R"( + Allows the usage of the new `nix` CLI subcommands, such as `nix build`, `nix + develop`, `nix run`, etc. See the manual for + [`nix`](../command-ref/new-cli/nix.md) for more info. + )", + }, + { + .tag = Xp::RecursiveNix, + .name = "recursive-nix", + .description = R"( + Allow Nix derivations to call Nix in order to recursively build derivations. + See [this + commit](https://github.com/edolstra/nix/commit/1a27aa7d64ffe6fc36cfca4d82bdf51c4d8cf717) + for more info. + )", + }, + { + .tag = Xp::NoUrlLiterals, + .name = "no-url-literals", + .description = R"( + Disallows unquoted URLs as part of the Nix language syntax. See [RFC + 45](https://github.com/NixOS/rfcs/pull/45) for more info. + )", + }, + { + .tag = Xp::FetchClosure, + .name = "fetch-closure", + .description = R"( + Enables the use of the `fetchClosure` function in the standard library. See + the docs for [`fetchClosure`](../language/builtins.md#builtins-fetchClosure) + for more info. + )", + }, + { + .tag = Xp::ReplFlake, + .name = "repl-flake", + .description = R"( + Allows the user to enter a Nix REPL within a flake, e.g. `nix repl nixpkgs` + or `nix repl .#foo`. + )", + }, + { + .tag = Xp::AutoAllocateUids, + .name = "auto-allocate-uids", + .description = R"( + Allows Nix to automatically pick UIDs for builds, rather than creating + `nixbld*` user accounts. See [here](#conf-auto-allocate-uids) for more info. + )", + }, + { + .tag = Xp::Cgroups, + .name = "cgroups", + .description = R"( + Allows Nix to execute builds inside cgroups. See + [`use-cgroups`](#conf-use-cgroups) for more info. + )", + }, + { + .tag = Xp::DiscardReferences, + .name = "discard-references", + .description = R"( + Enables the use of the `unsafeDiscardReferences` attribute in derivations + that use structured attributes. This disables scanning of outputs for + runtime dependencies. + )", + }, +}}; + +static_assert( + []() constexpr { + for (auto [index, feature] : enumerate(xpFeatureDetails)) + if (index != (size_t)feature.tag) + return false; + return true; + }(), + "array order does not match enum tag order"); + const std::optional parseExperimentalFeature(const std::string_view & name) { using ReverseXpMap = std::map; - static auto reverseXpMap = []() - { + static std::unique_ptr reverseXpMap = [](){ auto reverseXpMap = std::make_unique(); - std::string_view name; - for (auto & [feature, featureStringPair] : stringifiedXpFeatures) { - name = featureStringPair.first; - (*reverseXpMap)[name] = feature; - } + for (auto & xpFeature : xpFeatureDetails) + (*reverseXpMap)[xpFeature.name] = xpFeature.tag; return reverseXpMap; }(); @@ -83,25 +139,29 @@ const std::optional parseExperimentalFeature(const std::str return std::nullopt; } -std::string_view showExperimentalFeature(const ExperimentalFeature feature) +std::string_view showExperimentalFeature(const ExperimentalFeature tag) { - const auto ret = get(stringifiedXpFeatures, feature); - assert(ret); - return ret->first; + assert((size_t)tag < xpFeatureDetails.size()); + return xpFeatureDetails[(size_t)tag].name; } std::string getExperimentalFeaturesList() { std::string experimentalFeaturesList = R"( - Experimental Nix features to enable. - Current experimental features are the following: + Experimental Nix features to enable. + Current experimental features are the following: )"; - std::string experimentalFeatureString; - for (auto& [feature, featureStringPair] : stringifiedXpFeatures) { - experimentalFeatureString = " - `" + featureStringPair.first + "`\n"; - experimentalFeatureString += featureStringPair.second + "\n\n"; - experimentalFeaturesList += experimentalFeatureString; + for (auto & xpFeature : xpFeatureDetails) { + experimentalFeaturesList += std::string {} + /* length of this first string must be 12, matching the indent of + the descriptions in the xpFeatureDetails literal. FIXME compute + markdown in a less hacky way. */ + + " - " + + "`" + xpFeature.name + "`" + + "\n" + + xpFeature.description + + "\n\n"; } return experimentalFeaturesList; @@ -110,10 +170,9 @@ std::string getExperimentalFeaturesList() { std::set parseFeatures(const std::set & rawFeatures) { std::set res; - for (auto & rawFeature : rawFeatures) { + for (auto & rawFeature : rawFeatures) if (auto feature = parseExperimentalFeature(rawFeature)) res.insert(*feature); - } return res; } diff --git a/src/libutil/experimental-features.hh b/src/libutil/experimental-features.hh index 7c2f872c5..650fa6533 100644 --- a/src/libutil/experimental-features.hh +++ b/src/libutil/experimental-features.hh @@ -11,8 +11,9 @@ namespace nix { /** * The list of available experimental features. * - * If you update this, don’t forget to also change the map defining their string - * representation and documentation in the corresponding `.cc` file as well. + * If you update this, don’t forget to also change the map defining + * their string representation and documentation in the corresponding + * `.cc` file as well. */ enum struct ExperimentalFeature { diff --git a/src/libutil/util.hh b/src/libutil/util.hh index 6c2706cc1..94c9efb74 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -730,16 +730,16 @@ constexpr auto enumerate(T && iterable) { size_t i; TIter iter; - bool operator != (const iterator & other) const { return iter != other.iter; } - void operator ++ () { ++i; ++iter; } - auto operator * () const { return std::tie(i, *iter); } + constexpr bool operator != (const iterator & other) const { return iter != other.iter; } + constexpr void operator ++ () { ++i; ++iter; } + constexpr auto operator * () const { return std::tie(i, *iter); } }; struct iterable_wrapper { T iterable; - auto begin() { return iterator{ 0, std::begin(iterable) }; } - auto end() { return iterator{ 0, std::end(iterable) }; } + constexpr auto begin() { return iterator{ 0, std::begin(iterable) }; } + constexpr auto end() { return iterator{ 0, std::end(iterable) }; } }; return iterable_wrapper{ std::forward(iterable) }; From 32d72b1696c085d17c82c9f9b02f31ac32aa148f Mon Sep 17 00:00:00 2001 From: John Ericson Date: Sun, 2 Apr 2023 18:57:46 -0400 Subject: [PATCH 03/11] Add more API docs to `experimental-features.hh` --- src/libutil/experimental-features.hh | 33 +++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/libutil/experimental-features.hh b/src/libutil/experimental-features.hh index 650fa6533..3c479dbd9 100644 --- a/src/libutil/experimental-features.hh +++ b/src/libutil/experimental-features.hh @@ -35,27 +35,54 @@ enum struct ExperimentalFeature */ using Xp = ExperimentalFeature; +/** + * Parse an experimental feature (enum value) from its name. Experimental + * feature flag names are hyphenated and do not contain spaces. + */ const std::optional parseExperimentalFeature( const std::string_view & name); + +/** + * Show the name of an experimental feature. This is the opposite of + * parseExperimentalFeature(). + */ std::string_view showExperimentalFeature(const ExperimentalFeature); + +/** + * Compute the documentation of all experimental features. + * + * This a markdown bulleted list where each item is first (a) the + * experimental feature flag name in backticks, and then (b) the + * description of the experimental feature. + */ std::string getExperimentalFeaturesList(); +/** + * Shorthand for `str << showExperimentalFeature(feature)`. + */ std::ostream & operator<<( std::ostream & str, const ExperimentalFeature & feature); /** - * Parse a set of strings to the corresponding set of experimental features, - * ignoring (but warning for) any unkwown feature. + * Parse a set of strings to the corresponding set of experimental + * features, ignoring (but warning for) any unknown feature. */ std::set parseFeatures(const std::set &); +/** + * An experimental feature was required for some (experimental) + * operation, but was not enabled. + */ class MissingExperimentalFeature : public Error { public: + /** + * The experimental feature that was required but not enabled. + */ ExperimentalFeature missingFeature; - MissingExperimentalFeature(ExperimentalFeature); + MissingExperimentalFeature(ExperimentalFeature missingFeature); }; /** From bdeeffff967a513b6a35165bb476d24491a03e23 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Tue, 4 Apr 2023 19:16:10 -0400 Subject: [PATCH 04/11] Apply suggestions from code review Co-authored-by: Valentin Gagarin --- src/libutil/experimental-features.cc | 41 ++++++++++++++-------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/libutil/experimental-features.cc b/src/libutil/experimental-features.cc index 305b0cb11..a64e9715a 100644 --- a/src/libutil/experimental-features.cc +++ b/src/libutil/experimental-features.cc @@ -17,11 +17,11 @@ constexpr std::array xpFeatureDetails = {{ .tag = Xp::CaDerivations, .name = "ca-derivations", .description = R"( - Allows derivations to be content-addressed in order to prevent rebuilds + Allow derivations to be content-addressed in order to prevent rebuilds when changes to the derivation do not result in changes to the derivation's output. See - [__contentAddressed](../language/advanced-attributes.md#adv-attr-__contentAddressed) - for more info. + [__contentAddressed](@docroot@/language/advanced-attributes.md#adv-attr-__contentAddressed) + for details. )", }, { @@ -37,18 +37,16 @@ constexpr std::array xpFeatureDetails = {{ .tag = Xp::Flakes, .name = "flakes", .description = R"( - Allows for derivations to be packaged in flakes. See the manual entry for - [`nix flake`](../command-ref/new-cli/nix3-flake.md) or this [detailed - introduction](https://www.tweag.io/blog/2020-05-25-flakes/) for more info. + Enable flakes. See the manual entry for + [`nix flake`](../command-ref/new-cli/nix3-flake.md) for details. )", }, { .tag = Xp::NixCommand, .name = "nix-command", .description = R"( - Allows the usage of the new `nix` CLI subcommands, such as `nix build`, `nix - develop`, `nix run`, etc. See the manual for - [`nix`](../command-ref/new-cli/nix.md) for more info. + Enable the new `nix` subcommands. See the manual on + [`nix`](@docroot@/command-ref/new-cli/nix.md) for details. )", }, { @@ -73,17 +71,14 @@ constexpr std::array xpFeatureDetails = {{ .tag = Xp::FetchClosure, .name = "fetch-closure", .description = R"( - Enables the use of the `fetchClosure` function in the standard library. See - the docs for [`fetchClosure`](../language/builtins.md#builtins-fetchClosure) - for more info. + Enable the use of the [`fetchClosure`](@docroot@/language/builtins.md#builtins-fetchClosure) built-in function in the Nix language. )", }, { .tag = Xp::ReplFlake, .name = "repl-flake", .description = R"( - Allows the user to enter a Nix REPL within a flake, e.g. `nix repl nixpkgs` - or `nix repl .#foo`. + Allow passing [installables](@docroot@/command-ref/new-cli/nix.md#installables) to `nix repl`, making its interface consistent with the other experimental commands. )", }, { @@ -91,7 +86,7 @@ constexpr std::array xpFeatureDetails = {{ .name = "auto-allocate-uids", .description = R"( Allows Nix to automatically pick UIDs for builds, rather than creating - `nixbld*` user accounts. See [here](#conf-auto-allocate-uids) for more info. + `nixbld*` user accounts. See the [`auto-allocate-uids`](#conf-auto-allocate-uids) setting for details. )", }, { @@ -99,15 +94,15 @@ constexpr std::array xpFeatureDetails = {{ .name = "cgroups", .description = R"( Allows Nix to execute builds inside cgroups. See - [`use-cgroups`](#conf-use-cgroups) for more info. + the [`use-cgroups`](#conf-use-cgroups) setting for details. )", }, { .tag = Xp::DiscardReferences, .name = "discard-references", .description = R"( - Enables the use of the `unsafeDiscardReferences` attribute in derivations - that use structured attributes. This disables scanning of outputs for + Allow the use of the [`unsafeDiscardReferences`](@docroot@/language/advanced-attributes.html#adv-attr-unsafeDiscardReferences) attribute in derivations + that use [structured attributes](@docroot@/language/advanced-attributes.html#adv-attr-structuredAttrs). This disables scanning of outputs for runtime dependencies. )", }, @@ -147,8 +142,14 @@ std::string_view showExperimentalFeature(const ExperimentalFeature tag) std::string getExperimentalFeaturesList() { std::string experimentalFeaturesList = R"( - Experimental Nix features to enable. - Current experimental features are the following: + Experimental features that can be enabled. + + Example: + + ``` + experimental-features = nix-command flakes + + Experimental features available: )"; From 53d0836347ea262884658036f97bf19ecbdc5c26 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Tue, 4 Apr 2023 22:57:11 -0400 Subject: [PATCH 05/11] Assemble experimental feature docs outside of Nix itself Instead of constructing a markdown list in C++ (which involved all sorts of nasty string literals), export some JSON and assemble it with the manual build system. Besides following the precedent set with other dumped data, this is a better separate of content and presentation; if we decide for example we want to display this information in a different way, or in a different section of the manual, it will become much easier to do so. --- .gitignore | 2 ++ doc/manual/generate-xp-features.nix | 11 ++++++++++ doc/manual/local.mk | 13 +++++++++-- doc/manual/utils.nix | 6 +++--- src/libutil/config.hh | 17 +++++++++++++-- src/libutil/experimental-features.cc | 32 ++++++---------------------- src/libutil/experimental-features.hh | 6 ++---- src/nix/main.cc | 5 +++++ 8 files changed, 55 insertions(+), 37 deletions(-) create mode 100644 doc/manual/generate-xp-features.nix diff --git a/.gitignore b/.gitignore index e326966d6..53442751f 100644 --- a/.gitignore +++ b/.gitignore @@ -19,9 +19,11 @@ perl/Makefile.config /doc/manual/nix.json /doc/manual/conf-file.json /doc/manual/builtins.json +/doc/manual/xp-features.json /doc/manual/src/SUMMARY.md /doc/manual/src/command-ref/new-cli /doc/manual/src/command-ref/conf-file.md +/doc/manual/src/command-ref/experimental-features.md /doc/manual/src/language/builtins.md # /scripts/ diff --git a/doc/manual/generate-xp-features.nix b/doc/manual/generate-xp-features.nix new file mode 100644 index 000000000..db1ba6092 --- /dev/null +++ b/doc/manual/generate-xp-features.nix @@ -0,0 +1,11 @@ +with builtins; +with import ./utils.nix; + +let + showExperimentalFeature = name: doc: + squash '' + - [`${name}`](#xp-feature-${name}) + + ${indent " " doc} + ''; +in xps: indent " " (concatStringsSep "\n" (attrValues (mapAttrs showExperimentalFeature xps))) diff --git a/doc/manual/local.mk b/doc/manual/local.mk index df941d460..0d4b9d640 100644 --- a/doc/manual/local.mk +++ b/doc/manual/local.mk @@ -88,12 +88,12 @@ $(d)/src/SUMMARY.md: $(d)/src/SUMMARY.md.in $(d)/src/command-ref/new-cli @cp $< $@ @$(call process-includes,$@,$@) -$(d)/src/command-ref/new-cli: $(d)/nix.json $(d)/generate-manpage.nix $(bindir)/nix +$(d)/src/command-ref/new-cli: $(d)/nix.json $(d)/utils.nix $(d)/generate-manpage.nix $(bindir)/nix @rm -rf $@ $@.tmp $(trace-gen) $(nix-eval) --write-to $@.tmp --expr 'import doc/manual/generate-manpage.nix (builtins.readFile $<)' @mv $@.tmp $@ -$(d)/src/command-ref/conf-file.md: $(d)/conf-file.json $(d)/utils.nix $(d)/src/command-ref/conf-file-prefix.md $(bindir)/nix +$(d)/src/command-ref/conf-file.md: $(d)/conf-file.json $(d)/utils.nix $(d)/src/command-ref/conf-file-prefix.md $(d)/src/command-ref/experimental-features.md $(bindir)/nix @cat doc/manual/src/command-ref/conf-file-prefix.md > $@.tmp $(trace-gen) $(nix-eval) --expr '(import doc/manual/utils.nix).showSettings { useAnchors = true; } (builtins.fromJSON (builtins.readFile $<))' >> $@.tmp; @mv $@.tmp $@ @@ -106,6 +106,15 @@ $(d)/conf-file.json: $(bindir)/nix $(trace-gen) $(dummy-env) $(bindir)/nix show-config --json --experimental-features nix-command > $@.tmp @mv $@.tmp $@ +$(d)/src/command-ref/experimental-features.md: $(d)/xp-features.json $(d)/utils.nix $(d)/generate-xp-features.nix $(bindir)/nix + @rm -rf $@ $@.tmp + $(trace-gen) $(nix-eval) --write-to $@.tmp --expr 'import doc/manual/generate-xp-features.nix (builtins.fromJSON (builtins.readFile $<))' + @mv $@.tmp $@ + +$(d)/xp-features.json: $(bindir)/nix + $(trace-gen) $(dummy-env) NIX_PATH=nix/corepkgs=corepkgs $(bindir)/nix __dump-xp-features > $@.tmp + @mv $@.tmp $@ + $(d)/src/language/builtins.md: $(d)/builtins.json $(d)/generate-builtins.nix $(d)/src/language/builtins-prefix.md $(bindir)/nix @cat doc/manual/src/language/builtins-prefix.md > $@.tmp $(trace-gen) $(nix-eval) --expr 'import doc/manual/generate-builtins.nix (builtins.fromJSON (builtins.readFile $<))' >> $@.tmp; diff --git a/doc/manual/utils.nix b/doc/manual/utils.nix index 5eacce0dd..f78e6bb02 100644 --- a/doc/manual/utils.nix +++ b/doc/manual/utils.nix @@ -74,10 +74,10 @@ rec { if aliases == [] then "" else "**Deprecated alias:** ${(concatStringsSep ", " (map (s: "`${s}`") aliases))}"; - indent = prefix: s: - concatStringsSep "\n" (map (x: if x == "" then x else "${prefix}${x}") (splitLines s)); - in result; + indent = prefix: s: + concatStringsSep "\n" (map (x: if x == "" then x else "${prefix}${x}") (splitLines s)); + showSettings = args: settingsInfo: concatStrings (attrValues (mapAttrs (showSetting args) settingsInfo)); } diff --git a/src/libutil/config.hh b/src/libutil/config.hh index a001056f7..8b0fe6555 100644 --- a/src/libutil/config.hh +++ b/src/libutil/config.hh @@ -371,8 +371,21 @@ extern GlobalConfig globalConfig; struct ExperimentalFeatureSettings : Config { - Setting> experimentalFeatures{this, {}, "experimental-features", - getExperimentalFeaturesList()}; + Setting> experimentalFeatures{ + this, {}, "experimental-features", + R"( + Experimental features that are enabled. + + Example: + + ``` + experimental-features = nix-command flakes + ``` + + Experimental features available: + + {{#include experimental-features.md}} + )"}; /** * Check whether the given experimental feature is enabled. diff --git a/src/libutil/experimental-features.cc b/src/libutil/experimental-features.cc index a64e9715a..010ab1d68 100644 --- a/src/libutil/experimental-features.cc +++ b/src/libutil/experimental-features.cc @@ -140,32 +140,12 @@ std::string_view showExperimentalFeature(const ExperimentalFeature tag) return xpFeatureDetails[(size_t)tag].name; } -std::string getExperimentalFeaturesList() { - std::string experimentalFeaturesList = R"( - Experimental features that can be enabled. - - Example: - - ``` - experimental-features = nix-command flakes - - Experimental features available: - -)"; - - for (auto & xpFeature : xpFeatureDetails) { - experimentalFeaturesList += std::string {} - /* length of this first string must be 12, matching the indent of - the descriptions in the xpFeatureDetails literal. FIXME compute - markdown in a less hacky way. */ - + " - " - + "`" + xpFeature.name + "`" - + "\n" - + xpFeature.description - + "\n\n"; - } - - return experimentalFeaturesList; +nlohmann::json documentExperimentalFeatures() { + StringMap res; + for (auto & xpFeature : xpFeatureDetails) + res[std::string { xpFeature.name }] = + trim(stripIndentation(xpFeature.description)); + return (nlohmann::json) res; } std::set parseFeatures(const std::set & rawFeatures) diff --git a/src/libutil/experimental-features.hh b/src/libutil/experimental-features.hh index 3c479dbd9..8ef66263a 100644 --- a/src/libutil/experimental-features.hh +++ b/src/libutil/experimental-features.hh @@ -51,11 +51,9 @@ std::string_view showExperimentalFeature(const ExperimentalFeature); /** * Compute the documentation of all experimental features. * - * This a markdown bulleted list where each item is first (a) the - * experimental feature flag name in backticks, and then (b) the - * description of the experimental feature. + * See `doc/manual` for how this information is used. */ -std::string getExperimentalFeaturesList(); +nlohmann::json documentExperimentalFeatures(); /** * Shorthand for `str << showExperimentalFeature(feature)`. diff --git a/src/nix/main.cc b/src/nix/main.cc index 4d4164333..62b1f98d1 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -374,6 +374,11 @@ void mainWrapped(int argc, char * * argv) return; } + if (argc == 2 && std::string(argv[1]) == "__dump-xp-features") { + logger->cout(documentExperimentalFeatures().dump()); + return; + } + Finally printCompletions([&]() { if (completions) { From 8a7790f46aaf608bd7ed4ec6042b99bd36d7118e Mon Sep 17 00:00:00 2001 From: Noah Snelson Date: Wed, 5 Apr 2023 20:10:11 -0700 Subject: [PATCH 06/11] Expand documentation for `experimental-features` Adds examples and additional information to the `impure-derivations`, `recursive-nix`, and `no-url-literals` experimental feature documentation. --- src/libutil/experimental-features.cc | 111 +++++++++++++++++++++++---- 1 file changed, 97 insertions(+), 14 deletions(-) diff --git a/src/libutil/experimental-features.cc b/src/libutil/experimental-features.cc index 010ab1d68..b7879ff69 100644 --- a/src/libutil/experimental-features.cc +++ b/src/libutil/experimental-features.cc @@ -17,9 +17,9 @@ constexpr std::array xpFeatureDetails = {{ .tag = Xp::CaDerivations, .name = "ca-derivations", .description = R"( - Allow derivations to be content-addressed in order to prevent rebuilds - when changes to the derivation do not result in changes to the - derivation's output. See + Allow derivations to be content-addressed in order to prevent + rebuilds when changes to the derivation do not result in changes to + the derivation's output. See [__contentAddressed](@docroot@/language/advanced-attributes.md#adv-attr-__contentAddressed) for details. )", @@ -28,17 +28,36 @@ constexpr std::array xpFeatureDetails = {{ .tag = Xp::ImpureDerivations, .name = "impure-derivations", .description = R"( - Allows derivations to produce non-fixed outputs by setting the `__impure` - derivation attribute to `true`. See [these release - notes](../release-notes/rl-2.8.md) for an example. + Allow derivations to produce non-fixed outputs by setting the + `__impure` derivation attribute to `true`. An impure derivation can + have differing outputs each time it is built. + + Example: + + ``` + derivation { + name = "impure"; + builder = /bin/sh; + __impure = true; # mark this derivation as impure + args = [ "-c" "read -n 10 random < /dev/random; echo $random > $out" ]; + system = builtins.currentSystem; + } + ``` + + Each time this derivation is built, it can produce a different + output (as the builder outputs random bytes to `$out`). Impure + derivations also have access to the network, and only fixed-output + or other impure derivations can rely on impure derivations. Finally, + an impure derivation cannot also be + [content-addressed](#xp-feature-ca-derivations). )", }, { .tag = Xp::Flakes, .name = "flakes", .description = R"( - Enable flakes. See the manual entry for - [`nix flake`](../command-ref/new-cli/nix3-flake.md) for details. + Enable flakes. See the manual entry for [`nix + flake`](../command-ref/new-cli/nix3-flake.md) for details. )", }, { @@ -53,18 +72,82 @@ constexpr std::array xpFeatureDetails = {{ .tag = Xp::RecursiveNix, .name = "recursive-nix", .description = R"( - Allow Nix derivations to call Nix in order to recursively build derivations. - See [this - commit](https://github.com/edolstra/nix/commit/1a27aa7d64ffe6fc36cfca4d82bdf51c4d8cf717) - for more info. + Allow derivation builders to call Nix, and thus build derivations + recursively. + + Example: + + ``` + with import {}; + + runCommand "foo" + { + buildInputs = [ nix jq ]; + NIX_PATH = "nixpkgs=${}"; + } + '' + hello=$(nix-build -E '(import {}).hello.overrideDerivation (args: { name = "recursive-hello"; })') + + mkdir -p $out/bin + ln -s $hello/bin/hello $out/bin/hello + '' + ``` + + An important restriction on recursive builders is disallowing + arbitrary substitutions. For example, running + + ``` + nix-store -r /nix/store/kmwd1hq55akdb9sc7l3finr175dajlby-hello-2.10 + ``` + + in the above `runCommand` script would be disallowed, as this could + lead to derivations with hidden dependencies or breaking + reproducibility by relying on the current state of the Nix store. An + exception would be if + `/nix/store/kmwd1hq55akdb9sc7l3finr175dajlby-hello-2.10` were + already in the build inputs or built by a previous recursive Nix + call. )", }, { .tag = Xp::NoUrlLiterals, .name = "no-url-literals", .description = R"( - Disallows unquoted URLs as part of the Nix language syntax. See [RFC - 45](https://github.com/NixOS/rfcs/pull/45) for more info. + Disallow unquoted URLs as part of the Nix language syntax. The Nix + language allows for URL literals, like so: + + ``` + $ nix repl + Welcome to Nix 2.15.0. Type :? for help. + + nix-repl> http://foo + "http://foo" + ``` + + But enabling this experimental feature will cause the Nix parser to + throw an error when encountering a URL literal: + + ``` + $ nix repl --extra-experimental-features 'no-url-literals' + Welcome to Nix 2.15.0. Type :? for help. + + nix-repl> http://foo + error: URL literals are disabled + + at «string»:1:1: + + 1| http://bar + | ^ + + ``` + + While this is currently an experimental feature, unquoted URLs are + being deprecated and their usage is discouraged. + + The reason is that, as opposed to path literals, URLs have no + special properties that distinguish them from regular strings, URLs + containing parameters have to be quoted anyway, and unquoted URLs + may confuse external tooling. )", }, { From e399cb49c245de909417cfbe39a4c64fe0632653 Mon Sep 17 00:00:00 2001 From: Noah Snelson Date: Thu, 6 Apr 2023 15:02:19 -0700 Subject: [PATCH 07/11] Fix typo in `no-url-literals` experimental feature docs Co-authored-by: Valentin Gagarin --- src/libutil/experimental-features.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libutil/experimental-features.cc b/src/libutil/experimental-features.cc index b7879ff69..aa3367639 100644 --- a/src/libutil/experimental-features.cc +++ b/src/libutil/experimental-features.cc @@ -136,7 +136,7 @@ constexpr std::array xpFeatureDetails = {{ at «string»:1:1: - 1| http://bar + 1| http://foo | ^ ``` From 6c4049b38a2e694d904b4bc4f3525efe68f2f611 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Thu, 6 Apr 2023 11:37:02 -0400 Subject: [PATCH 08/11] Link the new general documentation on xp features on the setting --- src/libutil/config.hh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libutil/config.hh b/src/libutil/config.hh index 8b0fe6555..b21f8a422 100644 --- a/src/libutil/config.hh +++ b/src/libutil/config.hh @@ -385,6 +385,8 @@ struct ExperimentalFeatureSettings : Config { Experimental features available: {{#include experimental-features.md}} + + Experimental features are [further documented](@docroot@/contributing/experimental-features.md) in the contribution guide. )"}; /** From bc192a95ef4c777d9ca0ad025e0fb2b7f18879f7 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Thu, 6 Apr 2023 12:24:11 -0400 Subject: [PATCH 09/11] Describe active experimental features in the contributing guide They are put in the manual separate pages under the new overarching description of experimental features. The settings page just lists the valid experimental feature names (so people know what a valid setting entry looks like), with links to those pages. It doesn't attempt to describe each experimental feature as that is too much information for the configuration settings section. --- .gitignore | 3 ++- doc/manual/generate-xp-features-shortlist.nix | 9 ++++++++ doc/manual/generate-xp-features.nix | 22 ++++++++++++++----- doc/manual/local.mk | 14 ++++++++---- doc/manual/src/SUMMARY.md.in | 1 + doc/manual/utils.nix | 3 +++ src/libutil/config.hh | 2 +- src/libutil/experimental-features.cc | 2 +- 8 files changed, 43 insertions(+), 13 deletions(-) create mode 100644 doc/manual/generate-xp-features-shortlist.nix diff --git a/.gitignore b/.gitignore index 53442751f..ffaf52be8 100644 --- a/.gitignore +++ b/.gitignore @@ -23,7 +23,8 @@ perl/Makefile.config /doc/manual/src/SUMMARY.md /doc/manual/src/command-ref/new-cli /doc/manual/src/command-ref/conf-file.md -/doc/manual/src/command-ref/experimental-features.md +/doc/manual/src/command-ref/experimental-features-shortlist.md +/doc/manual/src/contributing/experimental-features /doc/manual/src/language/builtins.md # /scripts/ diff --git a/doc/manual/generate-xp-features-shortlist.nix b/doc/manual/generate-xp-features-shortlist.nix new file mode 100644 index 000000000..b2095bc27 --- /dev/null +++ b/doc/manual/generate-xp-features-shortlist.nix @@ -0,0 +1,9 @@ +with builtins; +with import ./utils.nix; + +let + showExperimentalFeature = name: doc: + '' + - [`${name}`](@docroot@/contributing/experimental-features/${name}.md) + ''; +in xps: indent " " (concatStrings (attrValues (mapAttrs showExperimentalFeature xps))) diff --git a/doc/manual/generate-xp-features.nix b/doc/manual/generate-xp-features.nix index db1ba6092..ff64edcf7 100644 --- a/doc/manual/generate-xp-features.nix +++ b/doc/manual/generate-xp-features.nix @@ -1,11 +1,21 @@ +xps: + with builtins; with import ./utils.nix; let - showExperimentalFeature = name: doc: - squash '' - - [`${name}`](#xp-feature-${name}) + makePage = { name, value }: + { + name = "${name}.md"; + inherit value; + feature = name; + }; - ${indent " " doc} - ''; -in xps: indent " " (concatStringsSep "\n" (attrValues (mapAttrs showExperimentalFeature xps))) + featurePages = map makePage (attrsToList xps); + + tableOfContents = let + showEntry = page: + " - [${page.feature}](contributing/experimental-features/${page.name})"; + in concatStringsSep "\n" (map showEntry featurePages) + "\n"; + +in (listToAttrs featurePages) // { "SUMMARY.md" = tableOfContents; } diff --git a/doc/manual/local.mk b/doc/manual/local.mk index 0d4b9d640..ae55ae4a9 100644 --- a/doc/manual/local.mk +++ b/doc/manual/local.mk @@ -81,10 +81,11 @@ $(d)/%.8: $(d)/src/command-ref/%.md $(d)/nix.conf.5: $(d)/src/command-ref/conf-file.md @printf "Title: %s\n\n" "$$(basename $@ .5)" > $^.tmp @cat $^ >> $^.tmp + @$(call process-includes,$^,$^.tmp) $(trace-gen) lowdown -sT man --nroff-nolinks -M section=5 $^.tmp -o $@ @rm $^.tmp -$(d)/src/SUMMARY.md: $(d)/src/SUMMARY.md.in $(d)/src/command-ref/new-cli +$(d)/src/SUMMARY.md: $(d)/src/SUMMARY.md.in $(d)/src/command-ref/new-cli $(d)/src/contributing/experimental-features @cp $< $@ @$(call process-includes,$@,$@) @@ -93,7 +94,7 @@ $(d)/src/command-ref/new-cli: $(d)/nix.json $(d)/utils.nix $(d)/generate-manpage $(trace-gen) $(nix-eval) --write-to $@.tmp --expr 'import doc/manual/generate-manpage.nix (builtins.readFile $<)' @mv $@.tmp $@ -$(d)/src/command-ref/conf-file.md: $(d)/conf-file.json $(d)/utils.nix $(d)/src/command-ref/conf-file-prefix.md $(d)/src/command-ref/experimental-features.md $(bindir)/nix +$(d)/src/command-ref/conf-file.md: $(d)/conf-file.json $(d)/utils.nix $(d)/src/command-ref/conf-file-prefix.md $(d)/src/command-ref/experimental-features-shortlist.md $(bindir)/nix @cat doc/manual/src/command-ref/conf-file-prefix.md > $@.tmp $(trace-gen) $(nix-eval) --expr '(import doc/manual/utils.nix).showSettings { useAnchors = true; } (builtins.fromJSON (builtins.readFile $<))' >> $@.tmp; @mv $@.tmp $@ @@ -106,11 +107,16 @@ $(d)/conf-file.json: $(bindir)/nix $(trace-gen) $(dummy-env) $(bindir)/nix show-config --json --experimental-features nix-command > $@.tmp @mv $@.tmp $@ -$(d)/src/command-ref/experimental-features.md: $(d)/xp-features.json $(d)/utils.nix $(d)/generate-xp-features.nix $(bindir)/nix +$(d)/src/contributing/experimental-features: $(d)/xp-features.json $(d)/utils.nix $(d)/generate-xp-features.nix $(bindir)/nix @rm -rf $@ $@.tmp $(trace-gen) $(nix-eval) --write-to $@.tmp --expr 'import doc/manual/generate-xp-features.nix (builtins.fromJSON (builtins.readFile $<))' @mv $@.tmp $@ +$(d)/src/command-ref/experimental-features-shortlist.md: $(d)/xp-features.json $(d)/utils.nix $(d)/generate-xp-features-shortlist.nix $(bindir)/nix + @rm -rf $@ $@.tmp + $(trace-gen) $(nix-eval) --write-to $@.tmp --expr 'import doc/manual/generate-xp-features-shortlist.nix (builtins.fromJSON (builtins.readFile $<))' + @mv $@.tmp $@ + $(d)/xp-features.json: $(bindir)/nix $(trace-gen) $(dummy-env) NIX_PATH=nix/corepkgs=corepkgs $(bindir)/nix __dump-xp-features > $@.tmp @mv $@.tmp $@ @@ -154,7 +160,7 @@ doc/manual/generated/man1/nix3-manpages: $(d)/src/command-ref/new-cli done @touch $@ -$(docdir)/manual/index.html: $(MANUAL_SRCS) $(d)/book.toml $(d)/anchors.jq $(d)/custom.css $(d)/src/SUMMARY.md $(d)/src/command-ref/new-cli $(d)/src/command-ref/conf-file.md $(d)/src/language/builtins.md +$(docdir)/manual/index.html: $(MANUAL_SRCS) $(d)/book.toml $(d)/anchors.jq $(d)/custom.css $(d)/src/SUMMARY.md $(d)/src/command-ref/new-cli $(d)/src/contributing/experimental-features $(d)/src/command-ref/conf-file.md $(d)/src/language/builtins.md $(trace-gen) \ tmp="$$(mktemp -d)"; \ cp -r doc/manual "$$tmp"; \ diff --git a/doc/manual/src/SUMMARY.md.in b/doc/manual/src/SUMMARY.md.in index 5bf274550..298644044 100644 --- a/doc/manual/src/SUMMARY.md.in +++ b/doc/manual/src/SUMMARY.md.in @@ -96,6 +96,7 @@ - [Contributing](contributing/contributing.md) - [Hacking](contributing/hacking.md) - [Experimental Features](contributing/experimental-features.md) +{{#include ./contributing/experimental-features/SUMMARY.md}} - [CLI guideline](contributing/cli-guideline.md) - [Release Notes](release-notes/release-notes.md) - [Release X.Y (202?-??-??)](release-notes/rl-next.md) diff --git a/doc/manual/utils.nix b/doc/manual/utils.nix index f78e6bb02..82544935a 100644 --- a/doc/manual/utils.nix +++ b/doc/manual/utils.nix @@ -5,6 +5,9 @@ rec { concatStrings = concatStringsSep ""; + attrsToList = a: + map (name: { inherit name; value = a.${name}; }) (builtins.attrNames a); + replaceStringsRec = from: to: string: # recursively replace occurrences of `from` with `to` within `string` # example: diff --git a/src/libutil/config.hh b/src/libutil/config.hh index b21f8a422..6baba0167 100644 --- a/src/libutil/config.hh +++ b/src/libutil/config.hh @@ -384,7 +384,7 @@ struct ExperimentalFeatureSettings : Config { Experimental features available: - {{#include experimental-features.md}} + {{#include experimental-features-shortlist.md}} Experimental features are [further documented](@docroot@/contributing/experimental-features.md) in the contribution guide. )"}; diff --git a/src/libutil/experimental-features.cc b/src/libutil/experimental-features.cc index aa3367639..1cd0dbb79 100644 --- a/src/libutil/experimental-features.cc +++ b/src/libutil/experimental-features.cc @@ -57,7 +57,7 @@ constexpr std::array xpFeatureDetails = {{ .name = "flakes", .description = R"( Enable flakes. See the manual entry for [`nix - flake`](../command-ref/new-cli/nix3-flake.md) for details. + flake`](@docroot@/command-ref/new-cli/nix3-flake.md) for details. )", }, { From 73eb6a2a578c85fe4a9399bdc20b4ff943fb49b4 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Sun, 9 Apr 2023 11:01:23 -0400 Subject: [PATCH 10/11] Single page for experimental feature descriptions As requested by @fricklerhandwerk. --- .gitignore | 2 +- doc/manual/generate-xp-features-shortlist.nix | 2 +- doc/manual/generate-xp-features.nix | 22 +++++-------------- doc/manual/local.mk | 6 ++--- doc/manual/src/SUMMARY.md.in | 1 - .../src/contributing/experimental-features.md | 4 ++++ 6 files changed, 15 insertions(+), 22 deletions(-) diff --git a/.gitignore b/.gitignore index ffaf52be8..8ceff4ef2 100644 --- a/.gitignore +++ b/.gitignore @@ -24,7 +24,7 @@ perl/Makefile.config /doc/manual/src/command-ref/new-cli /doc/manual/src/command-ref/conf-file.md /doc/manual/src/command-ref/experimental-features-shortlist.md -/doc/manual/src/contributing/experimental-features +/doc/manual/src/contributing/experimental-feature-descriptions.md /doc/manual/src/language/builtins.md # /scripts/ diff --git a/doc/manual/generate-xp-features-shortlist.nix b/doc/manual/generate-xp-features-shortlist.nix index b2095bc27..30e211c96 100644 --- a/doc/manual/generate-xp-features-shortlist.nix +++ b/doc/manual/generate-xp-features-shortlist.nix @@ -4,6 +4,6 @@ with import ./utils.nix; let showExperimentalFeature = name: doc: '' - - [`${name}`](@docroot@/contributing/experimental-features/${name}.md) + - [`${name}`](@docroot@/contributing/experimental-features.md#xp-feature-${name}) ''; in xps: indent " " (concatStrings (attrValues (mapAttrs showExperimentalFeature xps))) diff --git a/doc/manual/generate-xp-features.nix b/doc/manual/generate-xp-features.nix index ff64edcf7..adb94355c 100644 --- a/doc/manual/generate-xp-features.nix +++ b/doc/manual/generate-xp-features.nix @@ -1,21 +1,11 @@ -xps: - with builtins; with import ./utils.nix; let - makePage = { name, value }: - { - name = "${name}.md"; - inherit value; - feature = name; - }; + showExperimentalFeature = name: doc: + squash '' + ## [`${name}`]{#xp-feature-${name}} - featurePages = map makePage (attrsToList xps); - - tableOfContents = let - showEntry = page: - " - [${page.feature}](contributing/experimental-features/${page.name})"; - in concatStringsSep "\n" (map showEntry featurePages) + "\n"; - -in (listToAttrs featurePages) // { "SUMMARY.md" = tableOfContents; } + ${doc} + ''; +in xps: (concatStringsSep "\n" (attrValues (mapAttrs showExperimentalFeature xps))) diff --git a/doc/manual/local.mk b/doc/manual/local.mk index ae55ae4a9..63e7e61e4 100644 --- a/doc/manual/local.mk +++ b/doc/manual/local.mk @@ -85,7 +85,7 @@ $(d)/nix.conf.5: $(d)/src/command-ref/conf-file.md $(trace-gen) lowdown -sT man --nroff-nolinks -M section=5 $^.tmp -o $@ @rm $^.tmp -$(d)/src/SUMMARY.md: $(d)/src/SUMMARY.md.in $(d)/src/command-ref/new-cli $(d)/src/contributing/experimental-features +$(d)/src/SUMMARY.md: $(d)/src/SUMMARY.md.in $(d)/src/command-ref/new-cli $(d)/src/contributing/experimental-feature-descriptions.md @cp $< $@ @$(call process-includes,$@,$@) @@ -107,7 +107,7 @@ $(d)/conf-file.json: $(bindir)/nix $(trace-gen) $(dummy-env) $(bindir)/nix show-config --json --experimental-features nix-command > $@.tmp @mv $@.tmp $@ -$(d)/src/contributing/experimental-features: $(d)/xp-features.json $(d)/utils.nix $(d)/generate-xp-features.nix $(bindir)/nix +$(d)/src/contributing/experimental-feature-descriptions.md: $(d)/xp-features.json $(d)/utils.nix $(d)/generate-xp-features.nix $(bindir)/nix @rm -rf $@ $@.tmp $(trace-gen) $(nix-eval) --write-to $@.tmp --expr 'import doc/manual/generate-xp-features.nix (builtins.fromJSON (builtins.readFile $<))' @mv $@.tmp $@ @@ -160,7 +160,7 @@ doc/manual/generated/man1/nix3-manpages: $(d)/src/command-ref/new-cli done @touch $@ -$(docdir)/manual/index.html: $(MANUAL_SRCS) $(d)/book.toml $(d)/anchors.jq $(d)/custom.css $(d)/src/SUMMARY.md $(d)/src/command-ref/new-cli $(d)/src/contributing/experimental-features $(d)/src/command-ref/conf-file.md $(d)/src/language/builtins.md +$(docdir)/manual/index.html: $(MANUAL_SRCS) $(d)/book.toml $(d)/anchors.jq $(d)/custom.css $(d)/src/SUMMARY.md $(d)/src/command-ref/new-cli $(d)/src/contributing/experimental-feature-descriptions.md $(d)/src/command-ref/conf-file.md $(d)/src/language/builtins.md $(trace-gen) \ tmp="$$(mktemp -d)"; \ cp -r doc/manual "$$tmp"; \ diff --git a/doc/manual/src/SUMMARY.md.in b/doc/manual/src/SUMMARY.md.in index 298644044..5bf274550 100644 --- a/doc/manual/src/SUMMARY.md.in +++ b/doc/manual/src/SUMMARY.md.in @@ -96,7 +96,6 @@ - [Contributing](contributing/contributing.md) - [Hacking](contributing/hacking.md) - [Experimental Features](contributing/experimental-features.md) -{{#include ./contributing/experimental-features/SUMMARY.md}} - [CLI guideline](contributing/cli-guideline.md) - [Release Notes](release-notes/release-notes.md) - [Release X.Y (202?-??-??)](release-notes/rl-next.md) diff --git a/doc/manual/src/contributing/experimental-features.md b/doc/manual/src/contributing/experimental-features.md index f1db22751..ad5cffa91 100644 --- a/doc/manual/src/contributing/experimental-features.md +++ b/doc/manual/src/contributing/experimental-features.md @@ -89,3 +89,7 @@ However they serve different purposes: It is primarily an issue of *design* and *communication*, targeting the broader community. This means that experimental features and RFCs are orthogonal mechanisms, and can be used independently or together as needed. + +# Currently available experimental features + +{{#include ./experimental-feature-descriptions.md}} From deb7f4b466574c12a8384f1c76df0141c6f7ca69 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 11 Apr 2023 11:29:35 +0200 Subject: [PATCH 11/11] Nitpicks --- src/libutil/config.hh | 4 ++-- src/libutil/experimental-features.cc | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/libutil/config.hh b/src/libutil/config.hh index 6baba0167..162626791 100644 --- a/src/libutil/config.hh +++ b/src/libutil/config.hh @@ -382,11 +382,11 @@ struct ExperimentalFeatureSettings : Config { experimental-features = nix-command flakes ``` - Experimental features available: + The following experimental features are available: {{#include experimental-features-shortlist.md}} - Experimental features are [further documented](@docroot@/contributing/experimental-features.md) in the contribution guide. + Experimental features are [further documented in the manual](@docroot@/contributing/experimental-features.md). )"}; /** diff --git a/src/libutil/experimental-features.cc b/src/libutil/experimental-features.cc index 1cd0dbb79..5b4418714 100644 --- a/src/libutil/experimental-features.cc +++ b/src/libutil/experimental-features.cc @@ -204,7 +204,7 @@ const std::optional parseExperimentalFeature(const std::str { using ReverseXpMap = std::map; - static std::unique_ptr reverseXpMap = [](){ + static std::unique_ptr reverseXpMap = []() { auto reverseXpMap = std::make_unique(); for (auto & xpFeature : xpFeatureDetails) (*reverseXpMap)[xpFeature.name] = xpFeature.tag; @@ -223,7 +223,8 @@ std::string_view showExperimentalFeature(const ExperimentalFeature tag) return xpFeatureDetails[(size_t)tag].name; } -nlohmann::json documentExperimentalFeatures() { +nlohmann::json documentExperimentalFeatures() +{ StringMap res; for (auto & xpFeature : xpFeatureDetails) res[std::string { xpFeature.name }] =