diff --git a/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
index 1e425248be0fc..cdc23ad888b18 100644
--- a/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
+++ b/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
@@ -163,6 +163,20 @@
~100MB for python itself).
+
+
+ documentation.man has been refactored to
+ support choosing a man implementation other than GNU’s
+ man-db. For this,
+ documentation.man.manualPages has been
+ renamed to
+ documentation.man.man-db.manualPages. If
+ you want to use the new alternative man implementation
+ mandoc, add
+ documentation.man = { enable = true; man-db.enable = false; mandoc.enable = true; }
+ to your configuration.
+
+
diff --git a/nixos/doc/manual/release-notes/rl-2205.section.md b/nixos/doc/manual/release-notes/rl-2205.section.md
index ca89732fa801d..27ebceab2ec9a 100644
--- a/nixos/doc/manual/release-notes/rl-2205.section.md
+++ b/nixos/doc/manual/release-notes/rl-2205.section.md
@@ -60,6 +60,8 @@ In addition to numerous new and upgraded packages, this release has the followin
This has the added benefit to reduce the closure size of `ipython` from ~400MB to ~160MB
(including ~100MB for python itself).
+- `documentation.man` has been refactored to support choosing a man implementation other than GNU's `man-db`. For this, `documentation.man.manualPages` has been renamed to `documentation.man.man-db.manualPages`. If you want to use the new alternative man implementation `mandoc`, add `documentation.man = { enable = true; man-db.enable = false; mandoc.enable = true; }` to your configuration.
+
## Other Notable Changes {#sec-release-22.05-notable-changes}
- The option [services.redis.servers](#opt-services.redis.servers) was added
diff --git a/nixos/modules/misc/documentation.nix b/nixos/modules/misc/documentation.nix
index 64b1c15086fc8..bb294addccd96 100644
--- a/nixos/modules/misc/documentation.nix
+++ b/nixos/modules/misc/documentation.nix
@@ -74,10 +74,6 @@ let
];
};
- # list of man outputs currently active intended for use as default values
- # for man-related options, thus "man" is included unconditionally.
- activeManOutputs = [ "man" ] ++ lib.optionals cfg.dev.enable [ "devman" ];
-
in
{
@@ -107,8 +103,8 @@ in
type = types.bool;
default = true;
description = ''
- Whether to install manual pages and the man command.
- This also includes "man" outputs.
+ Whether to install manual pages.
+ This also includes man outputs.
'';
};
@@ -116,27 +112,18 @@ in
type = types.bool;
default = false;
description = ''
- Whether to generate the manual page index caches using
- mandb(8). This allows searching for a page or
- keyword using utilities like apropos(1).
- '';
- };
-
- man.manualPages = mkOption {
- type = types.path;
- default = pkgs.buildEnv {
- name = "man-paths";
- paths = config.environment.systemPackages;
- pathsToLink = [ "/share/man" ];
- extraOutputsToInstall = activeManOutputs;
- ignoreCollisions = true;
- };
- defaultText = literalDocBook "all man pages in ";
- description = ''
- The manual pages to generate caches for if
- is enabled. Must be a path to a directory with man pages under
- /share/man; see the source for an example.
- Advanced users can make this a content-addressed derivation to save a few rebuilds.
+ Whether to generate the manual page index caches.
+ This allows searching for a page or
+ keyword using utilities like
+
+ apropos
+ 1
+
+ and the -k option of
+
+ man
+ 1
+ .
'';
};
@@ -220,30 +207,22 @@ in
};
config = mkIf cfg.enable (mkMerge [
+ {
+ assertions = [
+ {
+ assertion = !(cfg.man.man-db.enable && cfg.man.mandoc.enable);
+ message = ''
+ man-db and mandoc can't be used as the default man page viewer at the same time!
+ '';
+ }
+ ];
+ }
+ # The actual implementation for this lives in man-db.nix or mandoc.nix,
+ # depending on which backend is active.
(mkIf cfg.man.enable {
- environment.systemPackages = [ pkgs.man-db ];
environment.pathsToLink = [ "/share/man" ];
- environment.extraOutputsToInstall = activeManOutputs;
- environment.etc."man_db.conf".text =
- let
- manualCache = pkgs.runCommandLocal "man-cache" { } ''
- echo "MANDB_MAP ${cfg.man.manualPages}/share/man $out" > man.conf
- ${pkgs.man-db}/bin/mandb -C man.conf -psc >/dev/null 2>&1
- '';
- in
- ''
- # Manual pages paths for NixOS
- MANPATH_MAP /run/current-system/sw/bin /run/current-system/sw/share/man
- MANPATH_MAP /run/wrappers/bin /run/current-system/sw/share/man
-
- ${optionalString cfg.man.generateCaches ''
- # Generated manual pages cache for NixOS (immutable)
- MANDB_MAP /run/current-system/sw/share/man ${manualCache}
- ''}
- # Manual pages caches for NixOS
- MANDB_MAP /run/current-system/sw/share/man /var/cache/man/nixos
- '';
+ environment.extraOutputsToInstall = [ "man" ] ++ optional cfg.dev.enable "devman";
})
(mkIf cfg.info.enable {
diff --git a/nixos/modules/misc/man-db.nix b/nixos/modules/misc/man-db.nix
new file mode 100644
index 0000000000000..8bd329bc4e0c3
--- /dev/null
+++ b/nixos/modules/misc/man-db.nix
@@ -0,0 +1,73 @@
+{ config, pkgs, lib, ... }:
+
+let
+ cfg = config.documentation.man.man-db;
+in
+
+{
+ options = {
+ documentation.man.man-db = {
+ enable = lib.mkEnableOption "man-db as the default man page viewer" // {
+ default = config.documentation.man.enable;
+ defaultText = lib.literalExpression "config.documentation.man.enable";
+ example = false;
+ };
+
+ manualPages = lib.mkOption {
+ type = lib.types.path;
+ default = pkgs.buildEnv {
+ name = "man-paths";
+ paths = config.environment.systemPackages;
+ pathsToLink = [ "/share/man" ];
+ extraOutputsToInstall = [ "man" ]
+ ++ lib.optionals config.documentation.dev.enable [ "devman" ];
+ ignoreCollisions = true;
+ };
+ defaultText = lib.literalDocBook "all man pages in ";
+ description = ''
+ The manual pages to generate caches for if
+ is enabled. Must be a path to a directory with man pages under
+ /share/man; see the source for an example.
+ Advanced users can make this a content-addressed derivation to save a few rebuilds.
+ '';
+ };
+
+ package = lib.mkOption {
+ type = lib.types.package;
+ default = pkgs.man-db;
+ defaultText = lib.literalExpression "pkgs.man-db";
+ description = ''
+ The man-db derivation to use. Useful to override
+ configuration options used for the package.
+ '';
+ };
+ };
+ };
+
+ imports = [
+ (lib.mkRenamedOptionModule [ "documentation" "man" "manualPages" ] [ "documentation" "man" "man-db" "manualPages" ])
+ ];
+
+ config = lib.mkIf cfg.enable {
+ environment.systemPackages = [ cfg.package ];
+ environment.etc."man_db.conf".text =
+ let
+ manualCache = pkgs.runCommandLocal "man-cache" { } ''
+ echo "MANDB_MAP ${cfg.manualPages}/share/man $out" > man.conf
+ ${cfg.package}/bin/mandb -C man.conf -psc >/dev/null 2>&1
+ '';
+ in
+ ''
+ # Manual pages paths for NixOS
+ MANPATH_MAP /run/current-system/sw/bin /run/current-system/sw/share/man
+ MANPATH_MAP /run/wrappers/bin /run/current-system/sw/share/man
+
+ ${lib.optionalString config.documentation.man.generateCaches ''
+ # Generated manual pages cache for NixOS (immutable)
+ MANDB_MAP /run/current-system/sw/share/man ${manualCache}
+ ''}
+ # Manual pages caches for NixOS
+ MANDB_MAP /run/current-system/sw/share/man /var/cache/man/nixos
+ '';
+ };
+}
diff --git a/nixos/modules/misc/mandoc.nix b/nixos/modules/misc/mandoc.nix
new file mode 100644
index 0000000000000..3da60f2f8e65f
--- /dev/null
+++ b/nixos/modules/misc/mandoc.nix
@@ -0,0 +1,61 @@
+{ config, lib, pkgs, ... }:
+
+let
+ makewhatis = "${lib.getBin cfg.package}/bin/makewhatis";
+
+ cfg = config.documentation.man.mandoc;
+
+in {
+ meta.maintainers = [ lib.maintainers.sternenseemann ];
+
+ options = {
+ documentation.man.mandoc = {
+ enable = lib.mkEnableOption "mandoc as the default man page viewer";
+
+ manPath = lib.mkOption {
+ type = with lib.types; listOf str;
+ default = [ "share/man" ];
+ example = lib.literalExpression "[ \"share/man\" \"share/man/fr\" ]";
+ description = ''
+ Change the manpath, i. e. the directories where
+ man1
+ looks for section-specific directories of man pages.
+ You only need to change this setting if you want extra man pages
+ (e. g. in non-english languages). All values must be strings that
+ are a valid path from the target prefix (without including it).
+ The first value given takes priority.
+ '';
+ };
+
+ package = lib.mkOption {
+ type = lib.types.package;
+ default = pkgs.mandoc;
+ defaultText = lib.literalExpression "pkgs.mandoc";
+ description = ''
+ The mandoc derivation to use. Useful to override
+ configuration options used for the package.
+ '';
+ };
+ };
+ };
+
+ config = lib.mkIf cfg.enable {
+ environment = {
+ systemPackages = [ cfg.package ];
+
+ # tell mandoc about man pages
+ etc."man.conf".text = lib.concatMapStrings (path: ''
+ manpath /run/current-system/sw/${path}
+ '') cfg.manPath;
+
+ # create mandoc.db for whatis(1), apropos(1) and man(1) -k
+ # TODO(@sternenseemman): fix symlinked directories not getting indexed,
+ # see: https://inbox.vuxu.org/mandoc-tech/20210906171231.GF83680@athene.usta.de/T/#e85f773c1781e3fef85562b2794f9cad7b2909a3c
+ extraSetup = lib.mkIf config.documentation.man.generateCaches ''
+ ${makewhatis} -T utf8 ${
+ lib.concatMapStringsSep " " (path: "\"$out/${path}\"") cfg.manPath
+ }
+ '';
+ };
+ };
+}
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 55de017350248..33c13e3855c0c 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -108,6 +108,8 @@
./misc/lib.nix
./misc/label.nix
./misc/locate.nix
+ ./misc/man-db.nix
+ ./misc/mandoc.nix
./misc/meta.nix
./misc/nixpkgs.nix
./misc/passthru.nix
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index 09cd26a766925..ab9ade1124a7a 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -255,6 +255,7 @@ in
magnetico = handleTest ./magnetico.nix {};
mailcatcher = handleTest ./mailcatcher.nix {};
mailhog = handleTest ./mailhog.nix {};
+ man = handleTest ./man.nix {};
mariadb-galera-mariabackup = handleTest ./mysql/mariadb-galera-mariabackup.nix {};
mariadb-galera-rsync = handleTest ./mysql/mariadb-galera-rsync.nix {};
matomo = handleTest ./matomo.nix {};
diff --git a/nixos/tests/man.nix b/nixos/tests/man.nix
new file mode 100644
index 0000000000000..1ff5af4e80591
--- /dev/null
+++ b/nixos/tests/man.nix
@@ -0,0 +1,100 @@
+
+import ./make-test-python.nix ({ pkgs, lib, ... }: let
+ manImplementations = [
+ "mandoc"
+ "man-db"
+ ];
+
+ machineNames = builtins.map machineSafe manImplementations;
+
+ makeConfig = useImpl: {
+ # Note: mandoc currently can't index symlinked section directories.
+ # So if a man section comes from one package exclusively (e. g.
+ # 1p from man-pages-posix and 2 from man-pages), it isn't searchable.
+ environment.systemPackages = [
+ pkgs.man-pages
+ pkgs.openssl
+ pkgs.libunwind
+ ];
+
+ documentation = {
+ enable = true;
+ nixos.enable = lib.mkForce true;
+ dev.enable = true;
+ man = {
+ enable = true;
+ generateCaches = true;
+ } // lib.listToAttrs (builtins.map (impl: {
+ name = impl;
+ value = {
+ enable = useImpl == impl;
+ };
+ }) manImplementations);
+ };
+ };
+
+ machineSafe = builtins.replaceStrings [ "-" ] [ "_" ];
+in {
+ name = "man";
+ meta.maintainers = [ lib.maintainers.sternenseemann ];
+
+ nodes = lib.listToAttrs (builtins.map (i: {
+ name = machineSafe i;
+ value = makeConfig i;
+ }) manImplementations);
+
+ testScript = ''
+ import re
+ start_all()
+
+ def match_man_k(page, section, haystack):
+ """
+ Check if the man page {page}({section}) occurs in
+ the output of `man -k` given as haystack. Note:
+ This is not super reliable, e. g. it can't deal
+ with man pages that are in multiple sections.
+ """
+
+ for line in haystack.split("\n"):
+ # man -k can look like this:
+ # page(3) - bla
+ # page (3) - bla
+ # pagea, pageb (3, 3P) - foo
+ # pagea, pageb, pagec(3) - bar
+ pages = line.split("(")[0]
+ sections = re.search("\\([a-zA-Z1-9, ]+\\)", line)
+ if sections is None:
+ continue
+ else:
+ sections = sections.group(0)[1:-1]
+
+ if page in pages and f'{section}' in sections:
+ return True
+
+ return False
+
+ '' + lib.concatMapStrings (machine: ''
+ with subtest("Test direct man page lookups in ${machine}"):
+ # man works
+ ${machine}.succeed("man man > /dev/null")
+ # devman works
+ ${machine}.succeed("man 3 libunwind > /dev/null")
+ # NixOS configuration man page is installed
+ ${machine}.succeed("man configuration.nix > /dev/null")
+
+ with subtest("Test generateCaches via man -k in ${machine}"):
+ expected = [
+ ("openssl", "ssl", 3),
+ ("unwind", "libunwind", 3),
+ ("user", "useradd", 8),
+ ("user", "userdel", 8),
+ ("mem", "free", 3),
+ ("mem", "free", 1),
+ ]
+
+ for (keyword, page, section) in expected:
+ matches = ${machine}.succeed(f"man -k {keyword}")
+ if not match_man_k(page, section, matches):
+ raise Exception(f"{page}({section}) missing in matches: {matches}")
+ '') machineNames;
+})
diff --git a/pkgs/tools/misc/man-db/default.nix b/pkgs/tools/misc/man-db/default.nix
index f1739cbd50dd2..d495c912f5996 100644
--- a/pkgs/tools/misc/man-db/default.nix
+++ b/pkgs/tools/misc/man-db/default.nix
@@ -1,4 +1,4 @@
-{ lib, stdenv, fetchurl, pkg-config, libpipeline, db, groff, libiconv, makeWrapper, buildPackages }:
+{ lib, stdenv, fetchurl, pkg-config, libpipeline, db, groff, libiconv, makeWrapper, buildPackages, nixosTests }:
stdenv.mkDerivation rec {
pname = "man-db";
@@ -73,6 +73,10 @@ stdenv.mkDerivation rec {
doCheck = !stdenv.hostPlatform.isMusl /* iconv binary */ && !stdenv.hostPlatform.isDarwin;
+ passthru.tests = {
+ nixos = nixosTests.man;
+ };
+
meta = with lib; {
homepage = "http://man-db.nongnu.org";
description = "An implementation of the standard Unix documentation system accessed using the man command";
diff --git a/pkgs/tools/misc/mandoc/default.nix b/pkgs/tools/misc/mandoc/default.nix
index 1771f6515bc41..2d974b8af63dd 100644
--- a/pkgs/tools/misc/mandoc/default.nix
+++ b/pkgs/tools/misc/mandoc/default.nix
@@ -1,4 +1,4 @@
-{ lib, stdenv, fetchurl, zlib, perl }:
+{ lib, stdenv, fetchurl, zlib, perl, nixosTests }:
let
# check if we can execute binaries for the host platform on the build platform
@@ -62,6 +62,10 @@ stdenv.mkDerivation rec {
checkInputs = [ perl ];
preCheck = "patchShebangs --build regress/regress.pl";
+ passthru.tests = {
+ nixos = nixosTests.man;
+ };
+
meta = with lib; {
homepage = "https://mandoc.bsd.lv/";
description = "suite of tools compiling mdoc and man";