···116116117117The [`class` argument](#module-system-lib-evalModules-param-class).
118118119119+#### `graph` {#module-system-lib-evalModules-return-value-graph}
120120+121121+Represents all the modules that took part in the evaluation.
122122+It is a list of `ModuleGraph` where `ModuleGraph` is defined as an attribute set with the following attributes:
123123+124124+- `key`: `string` for the purpose of module deduplication and `disabledModules`
125125+- `file`: `string` for the purpose of error messages and warnings
126126+- `imports`: `[ ModuleGraph ]`
127127+- `disabled`: `bool`
128128+119129## Module arguments {#module-system-module-arguments}
120130121131Module arguments are the attribute values passed to modules when they are evaluated.
···245245 };
246246 };
247247248248- merged =
249249- let
250250- collected =
251251- collectModules class (specialArgs.modulesPath or "") (regularModules ++ [ internalModule ])
252252- (
253253- {
254254- inherit
255255- lib
256256- options
257257- specialArgs
258258- ;
259259- _class = class;
260260- _prefix = prefix;
261261- config = addErrorContext "if you get an infinite recursion here, you probably reference `config` in `imports`. If you are trying to achieve a conditional import behavior dependent on `config`, consider importing unconditionally, and using `mkEnableOption` and `mkIf` to control its effect." config;
262262- }
263263- // specialArgs
264264- );
265265- in
266266- mergeModules prefix (reverseList collected);
248248+ # This function takes an empty attrset as an argument.
249249+ # It could theoretically be replaced with its body,
250250+ # but such a binding is avoided to allow for earlier grabage collection.
251251+ doCollect =
252252+ { }:
253253+ collectModules class (specialArgs.modulesPath or "") (regularModules ++ [ internalModule ]) (
254254+ {
255255+ inherit
256256+ lib
257257+ options
258258+ specialArgs
259259+ ;
260260+ _class = class;
261261+ _prefix = prefix;
262262+ config = addErrorContext "if you get an infinite recursion here, you probably reference `config` in `imports`. If you are trying to achieve a conditional import behavior dependent on `config`, consider importing unconditionally, and using `mkEnableOption` and `mkIf` to control its effect." config;
263263+ }
264264+ // specialArgs
265265+ );
266266+267267+ merged = mergeModules prefix (reverseList (doCollect { }).modules);
267268268269 options = merged.matchedOptions;
269270···359360 options = checked options;
360361 config = checked (removeAttrs config [ "_module" ]);
361362 _module = checked (config._module);
363363+ inherit (doCollect { }) graph;
362364 inherit extendModules type class;
363365 };
364366 in
365367 result;
366368367367- # collectModules :: (class: String) -> (modulesPath: String) -> (modules: [ Module ]) -> (args: Attrs) -> [ Module ]
369369+ # collectModules :: (class: String) -> (modulesPath: String) -> (modules: [ Module ]) -> (args: Attrs) -> ModulesTree
368370 #
369371 # Collects all modules recursively through `import` statements, filtering out
370372 # all modules in disabledModules.
···424426 else
425427 m: m;
426428429429+ # isDisabled :: String -> [ { disabled, file } ] -> StructuredModule -> bool
430430+ #
431431+ # Figures out whether a `StructuredModule` is disabled.
432432+ isDisabled =
433433+ modulesPath: disabledList:
434434+ let
435435+ moduleKey =
436436+ file: m:
437437+ if isString m then
438438+ if substring 0 1 m == "/" then m else toString modulesPath + "/" + m
439439+440440+ else if isConvertibleWithToString m then
441441+ if m ? key && m.key != toString m then
442442+ throw "Module `${file}` contains a disabledModules item that is an attribute set that can be converted to a string (${toString m}) but also has a `.key` attribute (${m.key}) with a different value. This makes it ambiguous which module should be disabled."
443443+ else
444444+ toString m
445445+446446+ else if m ? key then
447447+ m.key
448448+449449+ else if isAttrs m then
450450+ throw "Module `${file}` contains a disabledModules item that is an attribute set, presumably a module, that does not have a `key` attribute. This means that the module system doesn't have any means to identify the module that should be disabled. Make sure that you've put the correct value in disabledModules: a string path relative to modulesPath, a path value, or an attribute set with a `key` attribute."
451451+ else
452452+ throw "Each disabledModules item must be a path, string, or a attribute set with a key attribute, or a value supported by toString. However, one of the disabledModules items in `${toString file}` is none of that, but is of type ${typeOf m}.";
453453+454454+ disabledKeys = concatMap ({ file, disabled }: map (moduleKey file) disabled) disabledList;
455455+ in
456456+ structuredModule: elem structuredModule.key disabledKeys;
457457+427458 /**
428428- Collects all modules recursively into the form
459459+ Collects all modules recursively into a `[ StructuredModule ]` and a list of disabled modules:
429460430461 {
431462 disabled = [ <list of disabled modules> ];
···493524 modulesPath:
494525 { disabled, modules }:
495526 let
496496- moduleKey =
497497- file: m:
498498- if isString m then
499499- if substring 0 1 m == "/" then m else toString modulesPath + "/" + m
500500-501501- else if isConvertibleWithToString m then
502502- if m ? key && m.key != toString m then
503503- throw "Module `${file}` contains a disabledModules item that is an attribute set that can be converted to a string (${toString m}) but also has a `.key` attribute (${m.key}) with a different value. This makes it ambiguous which module should be disabled."
504504- else
505505- toString m
506506-507507- else if m ? key then
508508- m.key
509509-510510- else if isAttrs m then
511511- throw "Module `${file}` contains a disabledModules item that is an attribute set, presumably a module, that does not have a `key` attribute. This means that the module system doesn't have any means to identify the module that should be disabled. Make sure that you've put the correct value in disabledModules: a string path relative to modulesPath, a path value, or an attribute set with a `key` attribute."
512512- else
513513- throw "Each disabledModules item must be a path, string, or a attribute set with a key attribute, or a value supported by toString. However, one of the disabledModules items in `${toString file}` is none of that, but is of type ${typeOf m}.";
514514-515515- disabledKeys = concatMap ({ file, disabled }: map (moduleKey file) disabled) disabled;
516516- keyFilter = filter (attrs: !elem attrs.key disabledKeys);
527527+ keyFilter = filter (attrs: !isDisabled modulesPath disabled attrs);
517528 in
518529 map (attrs: attrs.module) (genericClosure {
519530 startSet = keyFilter modules;
520531 operator = attrs: keyFilter attrs.modules;
521532 });
522533534534+ toGraph =
535535+ modulesPath:
536536+ { disabled, modules }:
537537+ let
538538+ isDisabledModule = isDisabled modulesPath disabled;
539539+540540+ toModuleGraph = structuredModule: {
541541+ disabled = isDisabledModule structuredModule;
542542+ inherit (structuredModule) key;
543543+ file = structuredModule.module._file;
544544+ imports = map toModuleGraph structuredModule.modules;
545545+ };
546546+ in
547547+ map toModuleGraph (filter (x: x.key != "lib/modules.nix") modules);
523548 in
524524- modulesPath: initialModules: args:
525525- filterModules modulesPath (collectStructuredModules unknownModule "" initialModules args);
549549+ modulesPath: initialModules: args: {
550550+ modules = filterModules modulesPath (collectStructuredModules unknownModule "" initialModules args);
551551+ graph = toGraph modulesPath (collectStructuredModules unknownModule "" initialModules args);
552552+ };
526553527554 /**
528555 Wrap a module with a default location for reporting errors.
+22-1
lib/tests/modules.sh
···2020pass=0
2121fail=0
22222323+local-nix-instantiate() {
2424+ nix-instantiate --timeout 1 --eval-only --show-trace --read-write-mode --json "$@"
2525+}
2626+2327# loc
2428# prints the location of the call of to the function that calls it
2529# loc n
···5559 local attr=$1
5660 shift
5761 local script="import ./default.nix { modules = [ $* ];}"
5858- nix-instantiate --timeout 1 -E "$script" -A "$attr" --eval-only --show-trace --read-write-mode --json
6262+ local-nix-instantiate -E "$script" -A "$attr"
5963}
60646165reportFailure() {
···104108 fi
105109 return 1
106110 }
111111+}
112112+113113+checkExpression() {
114114+ local path=$1
115115+ local output
116116+ {
117117+ output="$(local-nix-instantiate --strict "$path" 2>&1)" && ((++pass))
118118+ } || {
119119+ logStartFailure
120120+ echo "$output"
121121+ ((++fail))
122122+ logFailure
123123+ logEndFailure
124124+ }
107125}
108126109127checkConfigError() {
···336354checkConfigOutput '^12$' config.value ./declare-coerced-value-unsound.nix
337355checkConfigError 'A definition for option .* is not of type .*. Definition values:\n\s*- In .*: "1000"' config.value ./declare-coerced-value-unsound.nix ./define-value-string-bigint.nix
338356checkConfigError 'toInt: Could not convert .* to int' config.value ./declare-coerced-value-unsound.nix ./define-value-string-arbitrary.nix
357357+358358+# Check `graph` attribute
359359+checkExpression './graph/test.nix'
339360340361# Check mkAliasOptionModule.
341362checkConfigOutput '^true$' config.enable ./alias-with-priority.nix
···1212 Perform OCR on a screenshot that contains text.
1313 Returns a string with all words that could be found.
1414 """
1515- variants = perform_ocr_variants_on_screenshot(screenshot_path, False)[0]
1616- if len(variants) != 1:
1717- raise MachineError(f"Received wrong number of OCR results: {len(variants)}")
1818- return variants[0]
1515+ return perform_ocr_variants_on_screenshot(screenshot_path, False)[0]
191620172118def perform_ocr_variants_on_screenshot(
···202202 # to be built eventually, we would still like to get the error early and without
203203 # having to wait while nix builds a derivation that might not be used.
204204 # See also https://github.com/NixOS/nix/issues/4629
205205- optionalAttrs (attrs ? disallowedReferences) {
206206- disallowedReferences = map unsafeDerivationToUntrackedOutpath attrs.disallowedReferences;
207207- }
208208- // optionalAttrs (attrs ? disallowedRequisites) {
209209- disallowedRequisites = map unsafeDerivationToUntrackedOutpath attrs.disallowedRequisites;
210210- }
211211- // optionalAttrs (attrs ? allowedReferences) {
212212- allowedReferences = mapNullable unsafeDerivationToUntrackedOutpath attrs.allowedReferences;
213213- }
214214- // optionalAttrs (attrs ? allowedRequisites) {
215215- allowedRequisites = mapNullable unsafeDerivationToUntrackedOutpath attrs.allowedRequisites;
205205+ {
206206+ ${if (attrs ? disallowedReferences) then "disallowedReferences" else null} =
207207+ map unsafeDerivationToUntrackedOutpath attrs.disallowedReferences;
208208+ ${if (attrs ? disallowedRequisites) then "disallowedRequisites" else null} =
209209+ map unsafeDerivationToUntrackedOutpath attrs.disallowedRequisites;
210210+ ${if (attrs ? allowedReferences) then "allowedReferences" else null} =
211211+ mapNullable unsafeDerivationToUntrackedOutpath attrs.allowedReferences;
212212+ ${if (attrs ? allowedRequisites) then "allowedRequisites" else null} =
213213+ mapNullable unsafeDerivationToUntrackedOutpath attrs.allowedRequisites;
216214 };
217215218216 makeDerivationArgument =
···478476479477 derivationArg =
480478 removeAttrs attrs removedOrReplacedAttrNames
481481- // (optionalAttrs (attrs ? name || (attrs ? pname && attrs ? version)) {
482482- name =
479479+ // {
480480+ ${if (attrs ? name || (attrs ? pname && attrs ? version)) then "name" else null} =
483481 let
484482 # Indicate the host platform of the derivation if cross compiling.
485483 # Fixed-output derivations like source tarballs shouldn't get a host
···507505 ) "The `version` attribute cannot be null.";
508506 "${attrs.pname}${staticMarker}${hostSuffix}-${attrs.version}"
509507 );
510510- })
511511- // {
508508+512509 builder = attrs.realBuilder or stdenv.shell;
513510 args =
514511 attrs.args or [
···556553 inherit doCheck doInstallCheck;
557554558555 inherit outputs;
559559- }
560560- // optionalAttrs (__contentAddressed) {
561561- inherit __contentAddressed;
562562- # Provide default values for outputHashMode and outputHashAlgo because
563563- # most people won't care about these anyways
564564- outputHashAlgo = attrs.outputHashAlgo or "sha256";
565565- outputHashMode = attrs.outputHashMode or "recursive";
566566- }
567567- // optionalAttrs (enableParallelBuilding) {
568568- inherit enableParallelBuilding;
569569- enableParallelChecking = attrs.enableParallelChecking or true;
570570- enableParallelInstalling = attrs.enableParallelInstalling or true;
571571- }
572572- // optionalAttrs (hardeningDisable != [ ] || hardeningEnable != [ ] || stdenv.hostPlatform.isMusl) {
573573- NIX_HARDENING_ENABLE = builtins.concatStringsSep " " enabledHardeningOptions;
574574- }
575575- //
556556+557557+ # When the derivations is content addressed provide default values
558558+ # for outputHashMode and outputHashAlgo because most people won't
559559+ # care about these anyways
560560+ ${if __contentAddressed then "__contentAddressed" else null} = __contentAddressed;
561561+ ${if __contentAddressed then "outputHashAlgo" else null} = attrs.outputHashAlgo or "sha256";
562562+ ${if __contentAddressed then "outputHashMode" else null} = attrs.outputHashMode or "recursive";
563563+564564+ ${if enableParallelBuilding then "enableParallelBuilding" else null} = enableParallelBuilding;
565565+ ${if enableParallelBuilding then "enableParallelChecking" else null} =
566566+ attrs.enableParallelChecking or true;
567567+ ${if enableParallelBuilding then "enableParallelInstalling" else null} =
568568+ attrs.enableParallelInstalling or true;
569569+570570+ ${
571571+ if (hardeningDisable != [ ] || hardeningEnable != [ ] || stdenv.hostPlatform.isMusl) then
572572+ "NIX_HARDENING_ENABLE"
573573+ else
574574+ null
575575+ } =
576576+ builtins.concatStringsSep " " enabledHardeningOptions;
577577+576578 # TODO: remove platform condition
577579 # Enabling this check could be a breaking change as it requires to edit nix.conf
578580 # NixOS module already sets gccarch, unsure of nix installers and other distributions
579579- optionalAttrs
580580- (
581581+ ${
582582+ if
581583 stdenv.buildPlatform ? gcc.arch
582584 && !(
583585 stdenv.buildPlatform.isAarch64
···589591 stdenv.buildPlatform.gcc.arch == "armv8-a"
590592 )
591593 )
592592- )
593593- {
594594- requiredSystemFeatures = attrs.requiredSystemFeatures or [ ] ++ [
595595- "gccarch-${stdenv.buildPlatform.gcc.arch}"
596596- ];
597597- }
594594+ then
595595+ "requiredSystemFeatures"
596596+ else
597597+ null
598598+ } =
599599+ attrs.requiredSystemFeatures or [ ] ++ [
600600+ "gccarch-${stdenv.buildPlatform.gcc.arch}"
601601+ ];
602602+ }
598603 // optionalAttrs (stdenv.buildPlatform.isDarwin) (
599604 let
600605 allDependencies = concatLists (concatLists dependencies);
+2
pkgs/top-level/aliases.nix
···588588 dtv-scan-tables_linuxtv = dtv-scan-tables; # Added 2023-03-03
589589 dtv-scan-tables_tvheadend = dtv-scan-tables; # Added 2023-03-03
590590 du-dust = dust; # Added 2024-01-19
591591+ duckstation = throw "'duckstation' has been removed due to being unmaintained"; # Added 2025-08-03
592592+ duckstation-bin = throw "'duckstation-bin' has been removed due to being unmaintained"; # Added 2025-08-03
591593 dump1090 = dump1090-fa; # Added 2024-02-12
592594 dwfv = throw "'dwfv' has been removed due to lack of upstream maintenance";
593595 dylibbundler = throw "'dylibbundler' has been renamed to/replaced by 'macdylibbundler'"; # Converted to throw 2024-10-17