diff --git a/ci/eval/default.nix b/ci/eval/default.nix index 2b7f59ae6b43..363804cce716 100644 --- a/ci/eval/default.nix +++ b/ci/eval/default.nix @@ -30,6 +30,7 @@ let "doc" "lib" "maintainers" + "modules" "nixos" "pkgs" ".version" diff --git a/doc/doc-support/package.nix b/doc/doc-support/package.nix index 8ed6865a1c90..8e5651864d48 100644 --- a/doc/doc-support/package.nix +++ b/doc/doc-support/package.nix @@ -15,12 +15,43 @@ markdown-code-runner, roboto, treefmt, + nixosOptionsDoc, }: stdenvNoCC.mkDerivation ( finalAttrs: let inherit (finalAttrs.finalPackage.optionsDoc) optionsJSON; inherit (finalAttrs.finalPackage) epub lib-docs pythonInterpreterTable; + + # Make anything from lib (the module system internals) invisible + hide-lib = + opt: + opt + // { + visible = if lib.all (decl: decl == "lib/modules.nix") opt.declarations then false else opt.visible; + }; + + toURL = + decl: + let + declStr = toString decl; + root = toString (../..); + subpath = lib.removePrefix "/" (lib.removePrefix root declStr); + in + if lib.hasPrefix root declStr then + { + url = "https://github.com/NixOS/nixpkgs/blob/master/${subpath}"; + name = "nixpkgs/${subpath}"; + } + else + decl; + + mapURLs = opt: opt // { declarations = map toURL opt.declarations; }; + + docs.generic.meta-maintainers = nixosOptionsDoc { + inherit (lib.evalModules { modules = [ ../../modules/generic/meta-maintainers.nix ]; }) options; + transformOptions = opt: hide-lib (mapURLs opt); + }; in { name = "nixpkgs-manual"; @@ -49,6 +80,7 @@ stdenvNoCC.mkDerivation ( ln -s ${optionsJSON}/share/doc/nixos/options.json ./config-options.json ln -s ${treefmt.functionsDoc.markdown} ./packages/treefmt-functions.section.md ln -s ${treefmt.optionsDoc.optionsJSON}/share/doc/nixos/options.json ./treefmt-options.json + ln -s ${docs.generic.meta-maintainers.optionsJSON}/share/doc/nixos/options.json ./options-modules-generic-meta-maintainers.json ''; buildPhase = '' diff --git a/doc/manual.md.in b/doc/manual.md.in index 160c6eaead3c..8d75d0fe459e 100644 --- a/doc/manual.md.in +++ b/doc/manual.md.in @@ -11,6 +11,7 @@ lib.md stdenv.md toolchains.md build-helpers.md +modules/index.md development.md contributing.md interoperability.md diff --git a/doc/modules/generic.chapter.md b/doc/modules/generic.chapter.md new file mode 100644 index 000000000000..2a14812160e0 --- /dev/null +++ b/doc/modules/generic.chapter.md @@ -0,0 +1,16 @@ + +# Generic {#modules-generic} + +Generic modules can be imported to extend configurations of any [class]. + +## `meta-maintainers.nix` {#modules-generic-meta-maintainers} + +The options below become available when using `imports = [ (nixpkgs + "/modules/generic/meta-maintainers.nix") ];`. + +```{=include=} options +id-prefix: opt-modules-generic-meta-maintainers- +list-id: configuration-variable-list +source: ../options-modules-generic-meta-maintainers.json +``` + +[class]: https://nixos.org/manual/nixpkgs/unstable/#module-system-lib-evalModules-param-class diff --git a/doc/modules/index.md b/doc/modules/index.md new file mode 100644 index 000000000000..af4897f11d6d --- /dev/null +++ b/doc/modules/index.md @@ -0,0 +1,12 @@ +# Modules {#modules} + +The Nixpkgs repository provides [Module System] modules for various purposes. + +The following sections are organized by [module class]. + +```{=include=} chapters +generic.chapter.md +``` + +[Module System]: https://nixos.org/manual/nixpkgs/unstable/#module-system +[module class]: https://nixos.org/manual/nixpkgs/unstable/#module-system-lib-evalModules-param-class diff --git a/doc/redirects.json b/doc/redirects.json index 8210470b5bcb..685e93538f85 100644 --- a/doc/redirects.json +++ b/doc/redirects.json @@ -130,6 +130,15 @@ "minor-ghc-deprecation": [ "index.html#minor-ghc-deprecation" ], + "modules": [ + "index.html#modules" + ], + "modules-generic": [ + "index.html#modules-generic" + ], + "modules-generic-meta-maintainers": [ + "index.html#modules-generic-meta-maintainers" + ], "neovim": [ "index.html#neovim" ], diff --git a/modules/README.md b/modules/README.md new file mode 100644 index 000000000000..777ab9839949 --- /dev/null +++ b/modules/README.md @@ -0,0 +1,9 @@ +# `/modules` + +This directory hosts subdirectories representing each module [class](https://nixos.org/manual/nixpkgs/stable/#module-system-lib-evalModules-param-class) for which the `nixpkgs` repository has user-importable modules. + +Exceptions: +- `_class = "nixos";` modules go in the `/nixos/modules` tree +- modules whose only purpose is to test code in this repository + +The emphasis is on _importable_ modules, i.e. ones that aren't inherent to and built into the Module System application. diff --git a/modules/generic/meta-maintainers.nix b/modules/generic/meta-maintainers.nix new file mode 100644 index 000000000000..fb66174cf621 --- /dev/null +++ b/modules/generic/meta-maintainers.nix @@ -0,0 +1,63 @@ +# Test: +# ./meta-maintainers/test.nix +{ lib, ... }: +let + inherit (lib) + mkOption + mkOptionType + types + ; + + maintainer = mkOptionType { + name = "maintainer"; + check = email: lib.elem email (lib.attrValues lib.maintainers); + merge = loc: defs: { + # lib.last: Perhaps this could be merged instead, if "at most once per module" + # is a problem (see option description). + ${(lib.last defs).file} = (lib.last defs).value; + }; + }; + + listOfMaintainers = types.listOf maintainer // { + merge = + loc: defs: + lib.zipAttrs ( + lib.flatten ( + lib.imap1 ( + n: def: + lib.imap1 ( + m: def': + maintainer.merge (loc ++ [ "[${toString n}-${toString m}]" ]) [ + { + inherit (def) file; + value = def'; + } + ] + ) def.value + ) defs + ) + ); + }; +in +{ + _class = null; # not specific to NixOS + options = { + meta = { + maintainers = mkOption { + type = listOfMaintainers; + default = [ ]; + example = lib.literalExpression ''[ lib.maintainers.alice lib.maintainers.bob ]''; + description = '' + List of maintainers of each module. + This option should be defined at most once per module. + + The option value is not a list of maintainers, but an attribute set that maps module file names to lists of maintainers. + ''; + }; + }; + }; + meta.maintainers = with lib.maintainers; [ + pierron + roberth + ]; +} diff --git a/modules/generic/meta-maintainers/test.nix b/modules/generic/meta-maintainers/test.nix new file mode 100644 index 000000000000..73a431c34327 --- /dev/null +++ b/modules/generic/meta-maintainers/test.nix @@ -0,0 +1,34 @@ +# Run: +# $ nix-instantiate --eval 'modules/generic/meta-maintainers/test.nix' +# +# Expected output: +# { } +# +# Debugging: +# drop .test from the end of this file, then use nix repl on it +rec { + lib = import ../../../lib; + + example = lib.evalModules { + modules = [ + ../meta-maintainers.nix + { + _file = "eelco.nix"; + meta.maintainers = [ lib.maintainers.eelco ]; + } + ]; + }; + + test = + assert + example.config.meta.maintainers == { + ${toString ../meta-maintainers.nix} = [ + lib.maintainers.pierron + lib.maintainers.roberth + ]; + "eelco.nix" = [ lib.maintainers.eelco ]; + }; + { }; + +} +.test diff --git a/nixos/lib/eval-cacheable-options.nix b/nixos/lib/eval-cacheable-options.nix index 73cf5eda32ec..9641d8d8d422 100644 --- a/nixos/lib/eval-cacheable-options.nix +++ b/nixos/lib/eval-cacheable-options.nix @@ -49,6 +49,7 @@ let version = release; revision = "release-${release}"; prefix = modulesPath; + extraSources = [ (dirOf nixosPath) ]; }; in docs.optionsNix diff --git a/nixos/modules/misc/documentation.nix b/nixos/modules/misc/documentation.nix index 3a60ae3286d2..7dd2a481004a 100644 --- a/nixos/modules/misc/documentation.nix +++ b/nixos/modules/misc/documentation.nix @@ -116,18 +116,34 @@ let && (t == "directory" -> baseNameOf n != "tests") && (t == "file" -> hasSuffix ".nix" n) ); + prefixRegex = "^" + lib.strings.escapeRegex (toString pkgs.path) + "($|/(modules|nixos)($|/.*))"; + filteredModules = builtins.path { + name = "source"; + inherit (pkgs) path; + filter = + n: t: + builtins.match prefixRegex n != null + && cleanSourceFilter n t + && (t == "directory" -> baseNameOf n != "tests") + && (t == "file" -> hasSuffix ".nix" n); + }; in pkgs.runCommand "lazy-options.json" - { + rec { libPath = filter (pkgs.path + "/lib"); pkgsLibPath = filter (pkgs.path + "/pkgs/pkgs-lib"); - nixosPath = filter (pkgs.path + "/nixos"); + nixosPath = filteredModules + "/nixos"; NIX_ABORT_ON_WARN = warningsAreErrors; modules = "[ " + concatMapStringsSep " " (p: ''"${removePrefix "${modulesPath}/" (toString p)}"'') docModules.lazy + " ]"; passAsFile = [ "modules" ]; + disallowedReferences = [ + filteredModules + libPath + pkgsLibPath + ]; } '' export NIX_STORE_DIR=$TMPDIR/store diff --git a/nixos/modules/misc/meta.nix b/nixos/modules/misc/meta.nix index 1e75a84452f8..20a2c99904d1 100644 --- a/nixos/modules/misc/meta.nix +++ b/nixos/modules/misc/meta.nix @@ -1,39 +1,5 @@ { lib, ... }: let - maintainer = lib.mkOptionType { - name = "maintainer"; - check = email: lib.elem email (lib.attrValues lib.maintainers); - merge = - loc: defs: - lib.listToAttrs (lib.singleton (lib.nameValuePair (lib.last defs).file (lib.last defs).value)); - }; - - listOfMaintainers = lib.types.listOf maintainer // { - # Returns list of - # { "module-file" = [ - # "maintainer1 " - # "maintainer2 " ]; - # } - merge = - loc: defs: - lib.zipAttrs ( - lib.flatten ( - lib.imap1 ( - n: def: - lib.imap1 ( - m: def': - maintainer.merge (loc ++ [ "[${toString n}-${toString m}]" ]) [ - { - inherit (def) file; - value = def'; - } - ] - ) def.value - ) defs - ) - ); - }; - docFile = lib.types.path // { # Returns tuples of # { file = "module location"; value = ; } @@ -42,20 +8,11 @@ let in { + imports = [ ../../../modules/generic/meta-maintainers.nix ]; + options = { meta = { - maintainers = lib.mkOption { - type = listOfMaintainers; - internal = true; - default = [ ]; - example = lib.literalExpression ''[ lib.maintainers.all ]''; - description = '' - List of maintainers of each module. This option should be defined at - most once per module. - ''; - }; - doc = lib.mkOption { type = docFile; internal = true; @@ -84,5 +41,8 @@ in }; }; - meta.maintainers = lib.singleton lib.maintainers.pierron; + meta.maintainers = with lib.maintainers; [ + pierron + roberth + ]; }