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