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