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) };