diff --git a/lib/modules.nix b/lib/modules.nix index 6d9dc0e3ad3..017c9255246 100644 --- a/lib/modules.nix +++ b/lib/modules.nix @@ -155,8 +155,14 @@ rec { let # Process mkOverride properties, adding in the default # value specified in the option declaration (if any). - defsFinal = filterOverrides + defsFinal' = filterOverrides ((if opt ? default then [{ file = head opt.declarations; value = mkOptionDefault opt.default; }] else []) ++ defs); + # Sort mkOrder properties. + defsFinal = + # Avoid sorting if we don't have to. + if any (def: def.value._type or "" == "order") defsFinal' + then sortProperties defsFinal' + else defsFinal'; files = map (def: def.file) defsFinal; # Type-check the remaining definitions, and merge them if # possible. @@ -180,7 +186,7 @@ rec { }; /* Given a config set, expand mkMerge properties, and push down the - mkIf properties into the children. The result is a list of + other properties into the children. The result is a list of config sets that do not have properties at top-level. For example, @@ -201,7 +207,7 @@ rec { map (mapAttrs (n: v: mkIf cfg.condition v)) (pushDownProperties cfg.content) else if cfg._type or "" == "override" then map (mapAttrs (n: v: mkOverride cfg.priority v)) (pushDownProperties cfg.content) - else + else # FIXME: handle mkOrder? [ cfg ]; /* Given a config value, expand mkMerge properties, and discharge @@ -253,6 +259,19 @@ rec { strip = def: if def.value._type or "" == "override" then def // { value = def.value.content; } else def; in concatMap (def: if getPrio def == highestPrio then [(strip def)] else []) defs; + /* Sort a list of properties. The sort priority of a property is + 1000 by default, but can be overriden by wrapping the property + using mkOrder. */ + sortProperties = defs: + let + strip = def: + if def.value._type or "" == "order" + then def // { value = def.value.content; inherit (def.value) priority; } + else def; + defs' = map strip defs; + compare = a: b: (a.priority or 1000) < (b.priority or 1000); + in sort compare defs'; + /* Hack for backward compatibility: convert options of type optionSet to configOf. FIXME: remove eventually. */ fixupOptionType = loc: opt: @@ -302,8 +321,13 @@ rec { mkFixStrictness = id; # obsolete, no-op - # FIXME: Add mkOrder back in. It's not currently used anywhere in - # NixOS, but it should be useful. + mkOrder = priority: content: + { _type = "order"; + inherit priority content; + }; + + mkBefore = mkOrder 500; + mkAfter = mkOrder 1500; /* Compatibility. */ diff --git a/nixos/doc/manual/configuration.xml b/nixos/doc/manual/configuration.xml index 307719d2cd2..246ab11587a 100644 --- a/nixos/doc/manual/configuration.xml +++ b/nixos/doc/manual/configuration.xml @@ -443,8 +443,20 @@ Note that both configuration.nix and define an option, NixOS will try to merge the definitions. In the case of , that’s easy: the lists of -packages can simply be concatenated. For other types of options, a -merge may not be possible: for instance, if two modules define +packages can simply be concatenated. The value in +configuration.nix is merged last, so for +list-type options, it will appear at the end of the merged list. If +you want it to appear first, you can use mkBefore: + + +boot.kernelModules = mkBefore [ "kvm-intel" ]; + + +This causes the kvm-intel kernel module to be +loaded before any other kernel modules. + +For other types of options, a merge may not be possible. For +instance, if two modules define , nixos-rebuild will give an error: