at 23.11-pre 13 kB view raw
1{ config, options, lib, pkgs, utils, modules, baseModules, extraModules, modulesPath, specialArgs, ... }: 2 3with lib; 4 5let 6 7 cfg = config.documentation; 8 allOpts = options; 9 10 canCacheDocs = m: 11 let 12 f = import m; 13 instance = f (mapAttrs (n: _: abort "evaluating ${n} for `meta` failed") (functionArgs f)); 14 in 15 cfg.nixos.options.splitBuild 16 && builtins.isPath m 17 && isFunction f 18 && instance ? options 19 && instance.meta.buildDocsInSandbox or true; 20 21 docModules = 22 let 23 p = partition canCacheDocs (baseModules ++ cfg.nixos.extraModules); 24 in 25 { 26 lazy = p.right; 27 eager = p.wrong ++ optionals cfg.nixos.includeAllModules (extraModules ++ modules); 28 }; 29 30 manual = import ../../doc/manual rec { 31 inherit pkgs config; 32 version = config.system.nixos.release; 33 revision = "release-${version}"; 34 extraSources = cfg.nixos.extraModuleSources; 35 options = 36 let 37 scrubbedEval = evalModules { 38 modules = [ { 39 _module.check = false; 40 } ] ++ docModules.eager; 41 class = "nixos"; 42 specialArgs = specialArgs // { 43 pkgs = scrubDerivations "pkgs" pkgs; 44 # allow access to arbitrary options for eager modules, eg for getting 45 # option types from lazy modules 46 options = allOpts; 47 inherit modulesPath utils; 48 }; 49 }; 50 scrubDerivations = namePrefix: pkgSet: mapAttrs 51 (name: value: 52 let 53 wholeName = "${namePrefix}.${name}"; 54 guard = lib.warn "Attempt to evaluate package ${wholeName} in option documentation; this is not supported and will eventually be an error. Use `mkPackageOption{,MD}` or `literalExpression` instead."; 55 in if isAttrs value then 56 scrubDerivations wholeName value 57 // optionalAttrs (isDerivation value) { 58 outPath = guard "\${${wholeName}}"; 59 drvPath = guard drvPath; 60 } 61 else value 62 ) 63 pkgSet; 64 in scrubbedEval.options; 65 66 baseOptionsJSON = 67 let 68 filter = 69 builtins.filterSource 70 (n: t: 71 cleanSourceFilter n t 72 && (t == "directory" -> baseNameOf n != "tests") 73 && (t == "file" -> hasSuffix ".nix" n) 74 ); 75 in 76 pkgs.runCommand "lazy-options.json" { 77 libPath = filter (pkgs.path + "/lib"); 78 pkgsLibPath = filter (pkgs.path + "/pkgs/pkgs-lib"); 79 nixosPath = filter (pkgs.path + "/nixos"); 80 modules = map (p: ''"${removePrefix "${modulesPath}/" (toString p)}"'') docModules.lazy; 81 } '' 82 export NIX_STORE_DIR=$TMPDIR/store 83 export NIX_STATE_DIR=$TMPDIR/state 84 ${pkgs.buildPackages.nix}/bin/nix-instantiate \ 85 --show-trace \ 86 --eval --json --strict \ 87 --argstr libPath "$libPath" \ 88 --argstr pkgsLibPath "$pkgsLibPath" \ 89 --argstr nixosPath "$nixosPath" \ 90 --arg modules "[ $modules ]" \ 91 --argstr stateVersion "${options.system.stateVersion.default}" \ 92 --argstr release "${config.system.nixos.release}" \ 93 $nixosPath/lib/eval-cacheable-options.nix > $out \ 94 || { 95 echo -en "\e[1;31m" 96 echo 'Cacheable portion of option doc build failed.' 97 echo 'Usually this means that an option attribute that ends up in documentation (eg' \ 98 '`default` or `description`) depends on the restricted module arguments' \ 99 '`config` or `pkgs`.' 100 echo 101 echo 'Rebuild your configuration with `--show-trace` to find the offending' \ 102 'location. Remove the references to restricted arguments (eg by escaping' \ 103 'their antiquotations or adding a `defaultText`) or disable the sandboxed' \ 104 'build for the failing module by setting `meta.buildDocsInSandbox = false`.' 105 echo -en "\e[0m" 106 exit 1 107 } >&2 108 ''; 109 110 inherit (cfg.nixos.options) warningsAreErrors allowDocBook; 111 }; 112 113 114 nixos-help = let 115 helpScript = pkgs.writeShellScriptBin "nixos-help" '' 116 # Finds first executable browser in a colon-separated list. 117 # (see how xdg-open defines BROWSER) 118 browser="$( 119 IFS=: ; for b in $BROWSER; do 120 [ -n "$(type -P "$b" || true)" ] && echo "$b" && break 121 done 122 )" 123 if [ -z "$browser" ]; then 124 browser="$(type -P xdg-open || true)" 125 if [ -z "$browser" ]; then 126 browser="${pkgs.w3m-nographics}/bin/w3m" 127 fi 128 fi 129 exec "$browser" ${manual.manualHTMLIndex} 130 ''; 131 132 desktopItem = pkgs.makeDesktopItem { 133 name = "nixos-manual"; 134 desktopName = "NixOS Manual"; 135 genericName = "System Manual"; 136 comment = "View NixOS documentation in a web browser"; 137 icon = "nix-snowflake"; 138 exec = "nixos-help"; 139 categories = ["System"]; 140 }; 141 142 in pkgs.symlinkJoin { 143 name = "nixos-help"; 144 paths = [ 145 helpScript 146 desktopItem 147 ]; 148 }; 149 150in 151 152{ 153 imports = [ 154 ./man-db.nix 155 ./mandoc.nix 156 ./assertions.nix 157 ./meta.nix 158 ../config/system-path.nix 159 ../system/etc/etc.nix 160 (mkRenamedOptionModule [ "programs" "info" "enable" ] [ "documentation" "info" "enable" ]) 161 (mkRenamedOptionModule [ "programs" "man" "enable" ] [ "documentation" "man" "enable" ]) 162 (mkRenamedOptionModule [ "services" "nixosManual" "enable" ] [ "documentation" "nixos" "enable" ]) 163 ]; 164 165 options = { 166 167 documentation = { 168 169 enable = mkOption { 170 type = types.bool; 171 default = true; 172 description = lib.mdDoc '' 173 Whether to install documentation of packages from 174 {option}`environment.systemPackages` into the generated system path. 175 176 See "Multiple-output packages" chapter in the nixpkgs manual for more info. 177 ''; 178 # which is at ../../../doc/multiple-output.chapter.md 179 }; 180 181 man.enable = mkOption { 182 type = types.bool; 183 default = true; 184 description = lib.mdDoc '' 185 Whether to install manual pages. 186 This also includes `man` outputs. 187 ''; 188 }; 189 190 man.generateCaches = mkOption { 191 type = types.bool; 192 default = false; 193 description = mdDoc '' 194 Whether to generate the manual page index caches. 195 This allows searching for a page or 196 keyword using utilities like {manpage}`apropos(1)` 197 and the `-k` option of 198 {manpage}`man(1)`. 199 ''; 200 }; 201 202 info.enable = mkOption { 203 type = types.bool; 204 default = true; 205 description = lib.mdDoc '' 206 Whether to install info pages and the {command}`info` command. 207 This also includes "info" outputs. 208 ''; 209 }; 210 211 doc.enable = mkOption { 212 type = types.bool; 213 default = true; 214 description = lib.mdDoc '' 215 Whether to install documentation distributed in packages' `/share/doc`. 216 Usually plain text and/or HTML. 217 This also includes "doc" outputs. 218 ''; 219 }; 220 221 dev.enable = mkOption { 222 type = types.bool; 223 default = false; 224 description = mdDoc '' 225 Whether to install documentation targeted at developers. 226 * This includes man pages targeted at developers if {option}`documentation.man.enable` is 227 set (this also includes "devman" outputs). 228 * This includes info pages targeted at developers if {option}`documentation.info.enable` 229 is set (this also includes "devinfo" outputs). 230 * This includes other pages targeted at developers if {option}`documentation.doc.enable` 231 is set (this also includes "devdoc" outputs). 232 ''; 233 }; 234 235 nixos.enable = mkOption { 236 type = types.bool; 237 default = true; 238 description = lib.mdDoc '' 239 Whether to install NixOS's own documentation. 240 241 - This includes man pages like 242 {manpage}`configuration.nix(5)` if {option}`documentation.man.enable` is 243 set. 244 - This includes the HTML manual and the {command}`nixos-help` command if 245 {option}`documentation.doc.enable` is set. 246 ''; 247 }; 248 249 nixos.extraModules = mkOption { 250 type = types.listOf types.raw; 251 default = []; 252 description = lib.mdDoc '' 253 Modules for which to show options even when not imported. 254 ''; 255 }; 256 257 nixos.options.splitBuild = mkOption { 258 type = types.bool; 259 default = true; 260 description = lib.mdDoc '' 261 Whether to split the option docs build into a cacheable and an uncacheable part. 262 Splitting the build can substantially decrease the amount of time needed to build 263 the manual, but some user modules may be incompatible with this splitting. 264 ''; 265 }; 266 267 nixos.options.allowDocBook = mkOption { 268 type = types.bool; 269 default = true; 270 description = lib.mdDoc '' 271 Whether to allow DocBook option docs. When set to `false` all option using 272 DocBook documentation will cause a manual build error; additionally a new 273 renderer may be used. 274 275 ::: {.note} 276 The `false` setting for this option is not yet fully supported. While it 277 should work fine and produce the same output as the previous toolchain 278 using DocBook it may not work in all circumstances. Whether markdown option 279 documentation is allowed is independent of this option. 280 ::: 281 ''; 282 }; 283 284 nixos.options.warningsAreErrors = mkOption { 285 type = types.bool; 286 default = true; 287 description = lib.mdDoc '' 288 Treat warning emitted during the option documentation build (eg for missing option 289 descriptions) as errors. 290 ''; 291 }; 292 293 nixos.includeAllModules = mkOption { 294 type = types.bool; 295 default = false; 296 description = lib.mdDoc '' 297 Whether the generated NixOS's documentation should include documentation for all 298 the options from all the NixOS modules included in the current 299 `configuration.nix`. Disabling this will make the manual 300 generator to ignore options defined outside of `baseModules`. 301 ''; 302 }; 303 304 nixos.extraModuleSources = mkOption { 305 type = types.listOf (types.either types.path types.str); 306 default = [ ]; 307 description = lib.mdDoc '' 308 Which extra NixOS module paths the generated NixOS's documentation should strip 309 from options. 310 ''; 311 example = literalExpression '' 312 # e.g. with options from modules in ''${pkgs.customModules}/nix: 313 [ pkgs.customModules ] 314 ''; 315 }; 316 317 }; 318 319 }; 320 321 config = mkIf cfg.enable (mkMerge [ 322 { 323 assertions = [ 324 { 325 assertion = !(cfg.man.man-db.enable && cfg.man.mandoc.enable); 326 message = '' 327 man-db and mandoc can't be used as the default man page viewer at the same time! 328 ''; 329 } 330 ]; 331 } 332 333 # The actual implementation for this lives in man-db.nix or mandoc.nix, 334 # depending on which backend is active. 335 (mkIf cfg.man.enable { 336 environment.pathsToLink = [ "/share/man" ]; 337 environment.extraOutputsToInstall = [ "man" ] ++ optional cfg.dev.enable "devman"; 338 }) 339 340 (mkIf cfg.info.enable { 341 environment.systemPackages = [ pkgs.texinfoInteractive ]; 342 environment.pathsToLink = [ "/share/info" ]; 343 environment.extraOutputsToInstall = [ "info" ] ++ optional cfg.dev.enable "devinfo"; 344 environment.extraSetup = '' 345 if [ -w $out/share/info ]; then 346 shopt -s nullglob 347 for i in $out/share/info/*.info $out/share/info/*.info.gz; do 348 ${pkgs.buildPackages.texinfo}/bin/install-info $i $out/share/info/dir 349 done 350 fi 351 ''; 352 }) 353 354 (mkIf cfg.doc.enable { 355 environment.pathsToLink = [ "/share/doc" ]; 356 environment.extraOutputsToInstall = [ "doc" ] ++ optional cfg.dev.enable "devdoc"; 357 }) 358 359 (mkIf cfg.nixos.enable { 360 system.build.manual = manual; 361 362 system.activationScripts.check-manual-docbook = '' 363 if [[ $(cat ${manual.optionsUsedDocbook}) = 1 ]]; then 364 echo -e "\e[31;1mwarning\e[0m: This configuration contains option documentation in docbook." \ 365 "Support for docbook is deprecated and will be removed after NixOS 23.05." \ 366 "See nix-store --read-log ${builtins.unsafeDiscardStringContext manual.optionsJSON.drvPath}" 367 fi 368 ''; 369 370 environment.systemPackages = [] 371 ++ optional cfg.man.enable manual.manpages 372 ++ optionals cfg.doc.enable [ manual.manualHTML nixos-help ]; 373 }) 374 375 ]); 376 377}