Factor out the NixOS meta.maintainers module (#431450)

This commit is contained in:
Robert Hensing
2025-08-21 10:11:08 +02:00
committed by GitHub
12 changed files with 202 additions and 48 deletions

View File

@@ -30,6 +30,7 @@ let
"doc" "doc"
"lib" "lib"
"maintainers" "maintainers"
"modules"
"nixos" "nixos"
"pkgs" "pkgs"
".version" ".version"

View File

@@ -15,12 +15,43 @@
markdown-code-runner, markdown-code-runner,
roboto, roboto,
treefmt, treefmt,
nixosOptionsDoc,
}: }:
stdenvNoCC.mkDerivation ( stdenvNoCC.mkDerivation (
finalAttrs: finalAttrs:
let let
inherit (finalAttrs.finalPackage.optionsDoc) optionsJSON; inherit (finalAttrs.finalPackage.optionsDoc) optionsJSON;
inherit (finalAttrs.finalPackage) epub lib-docs pythonInterpreterTable; 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 in
{ {
name = "nixpkgs-manual"; name = "nixpkgs-manual";
@@ -49,6 +80,7 @@ stdenvNoCC.mkDerivation (
ln -s ${optionsJSON}/share/doc/nixos/options.json ./config-options.json ln -s ${optionsJSON}/share/doc/nixos/options.json ./config-options.json
ln -s ${treefmt.functionsDoc.markdown} ./packages/treefmt-functions.section.md 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 ${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 = '' buildPhase = ''

View File

@@ -11,6 +11,7 @@ lib.md
stdenv.md stdenv.md
toolchains.md toolchains.md
build-helpers.md build-helpers.md
modules/index.md
development.md development.md
contributing.md contributing.md
interoperability.md interoperability.md

View File

@@ -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

12
doc/modules/index.md Normal file
View File

@@ -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

View File

@@ -130,6 +130,15 @@
"minor-ghc-deprecation": [ "minor-ghc-deprecation": [
"index.html#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": [ "neovim": [
"index.html#neovim" "index.html#neovim"
], ],

9
modules/README.md Normal file
View File

@@ -0,0 +1,9 @@
# `<nixpkgs>/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 `<nixpkgs>/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.

View File

@@ -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
];
}

View File

@@ -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

View File

@@ -49,6 +49,7 @@ let
version = release; version = release;
revision = "release-${release}"; revision = "release-${release}";
prefix = modulesPath; prefix = modulesPath;
extraSources = [ (dirOf nixosPath) ];
}; };
in in
docs.optionsNix docs.optionsNix

View File

@@ -116,18 +116,34 @@ let
&& (t == "directory" -> baseNameOf n != "tests") && (t == "directory" -> baseNameOf n != "tests")
&& (t == "file" -> hasSuffix ".nix" n) && (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 in
pkgs.runCommand "lazy-options.json" pkgs.runCommand "lazy-options.json"
{ rec {
libPath = filter (pkgs.path + "/lib"); libPath = filter (pkgs.path + "/lib");
pkgsLibPath = filter (pkgs.path + "/pkgs/pkgs-lib"); pkgsLibPath = filter (pkgs.path + "/pkgs/pkgs-lib");
nixosPath = filter (pkgs.path + "/nixos"); nixosPath = filteredModules + "/nixos";
NIX_ABORT_ON_WARN = warningsAreErrors; NIX_ABORT_ON_WARN = warningsAreErrors;
modules = modules =
"[ " "[ "
+ concatMapStringsSep " " (p: ''"${removePrefix "${modulesPath}/" (toString p)}"'') docModules.lazy + concatMapStringsSep " " (p: ''"${removePrefix "${modulesPath}/" (toString p)}"'') docModules.lazy
+ " ]"; + " ]";
passAsFile = [ "modules" ]; passAsFile = [ "modules" ];
disallowedReferences = [
filteredModules
libPath
pkgsLibPath
];
} }
'' ''
export NIX_STORE_DIR=$TMPDIR/store export NIX_STORE_DIR=$TMPDIR/store

View File

@@ -1,39 +1,5 @@
{ lib, ... }: { lib, ... }:
let 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 <first@nixos.org>"
# "maintainer2 <second@nixos.org>" ];
# }
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 // { docFile = lib.types.path // {
# Returns tuples of # Returns tuples of
# { file = "module location"; value = <path/to/doc.xml>; } # { file = "module location"; value = <path/to/doc.xml>; }
@@ -42,20 +8,11 @@ let
in in
{ {
imports = [ ../../../modules/generic/meta-maintainers.nix ];
options = { options = {
meta = { 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 { doc = lib.mkOption {
type = docFile; type = docFile;
internal = true; internal = true;
@@ -84,5 +41,8 @@ in
}; };
}; };
meta.maintainers = lib.singleton lib.maintainers.pierron; meta.maintainers = with lib.maintainers; [
pierron
roberth
];
} }