diff options
author | Katharina Fey <kookie@spacekookie.de> | 2020-01-12 01:00:12 +0000 |
---|---|---|
committer | Katharina Fey <kookie@spacekookie.de> | 2020-01-12 01:00:12 +0000 |
commit | eeaf5d25d5f6ae7ae1f5bf8a3dee4559693f8147 (patch) | |
tree | afc41ca8dde96b41089ca324533084aef570322f /nixpkgs/lib | |
parent | 63c4c4dda49dc69e5812faa7ef8406180998f3ae (diff) | |
parent | e4134747f5666bcab8680aff67fa3b63384f9a0f (diff) |
Merge commit 'e4134747f5666bcab8680aff67fa3b63384f9a0f'
Diffstat (limited to 'nixpkgs/lib')
40 files changed, 389 insertions, 191 deletions
diff --git a/nixpkgs/lib/default.nix b/nixpkgs/lib/default.nix index 8af53152586..9f7a088d792 100644 --- a/nixpkgs/lib/default.nix +++ b/nixpkgs/lib/default.nix @@ -101,8 +101,8 @@ let cleanSource sourceByRegex sourceFilesBySuffices commitIdFromGitRepo cleanSourceWith pathHasContext canCleanSource; - inherit (modules) evalModules closeModules unifyModuleSyntax - applyIfFunction unpackSubmodule packSubmodule mergeModules + inherit (modules) evalModules unifyModuleSyntax + applyIfFunction mergeModules mergeModules' mergeOptionDecls evalOptionValue mergeDefinitions pushDownProperties dischargeProperties filterOverrides sortProperties fixupOptionType mkIf mkAssert mkMerge mkOverride @@ -110,7 +110,7 @@ let mkFixStrictness mkOrder mkBefore mkAfter mkAliasDefinitions mkAliasAndWrapDefinitions fixMergeModules mkRemovedOptionModule mkRenamedOptionModule mkMergedOptionModule mkChangedOptionModule - mkAliasOptionModule doRename filterModules; + mkAliasOptionModule doRename; inherit (options) isOption mkEnableOption mkSinkUndeclaredOptions mergeDefaultOption mergeOneOption mergeEqualOption getValues getFiles optionAttrSetToDocList optionAttrSetToDocList' diff --git a/nixpkgs/lib/modules.nix b/nixpkgs/lib/modules.nix index 44db77b5d1c..38d6ac8cd91 100644 --- a/nixpkgs/lib/modules.nix +++ b/nixpkgs/lib/modules.nix @@ -59,9 +59,12 @@ rec { }; }; - closed = closeModules (modules ++ [ internalModule ]) ({ inherit config options lib; } // specialArgs); + collected = collectModules + (specialArgs.modulesPath or "") + (modules ++ [ internalModule ]) + ({ inherit config options lib; } // specialArgs); - options = mergeModules prefix (reverseList (filterModules (specialArgs.modulesPath or "") closed)); + options = mergeModules prefix (reverseList collected); # Traverse options and extract the option values into the final # config set. At the same time, check whether all option @@ -87,58 +90,103 @@ rec { result = { inherit options config; }; in result; + # collectModules :: (modulesPath: String) -> (modules: [ Module ]) -> (args: Attrs) -> [ Module ] + # + # Collects all modules recursively through `import` statements, filtering out + # all modules in disabledModules. + collectModules = let - # Filter disabled modules. Modules can be disabled allowing - # their implementation to be replaced. - filterModules = modulesPath: modules: - let - moduleKey = m: if isString m then toString modulesPath + "/" + m else toString m; - disabledKeys = map moduleKey (concatMap (m: m.disabledModules) modules); - in - filter (m: !(elem m.key disabledKeys)) modules; + # Like unifyModuleSyntax, but also imports paths and calls functions if necessary + loadModule = args: fallbackFile: fallbackKey: m: + if isFunction m || isAttrs m then + unifyModuleSyntax fallbackFile fallbackKey (applyIfFunction fallbackKey m args) + else unifyModuleSyntax (toString m) (toString m) (applyIfFunction (toString m) (import m) args); - /* Close a set of modules under the āimportsā relation. */ - closeModules = modules: args: - let - toClosureList = file: parentKey: imap1 (n: x: - if isAttrs x || isFunction x then - let key = "${parentKey}:anon-${toString n}"; in - unifyModuleSyntax file key (unpackSubmodule (applyIfFunction key) x args) - else - let file = toString x; key = toString x; in - unifyModuleSyntax file key (applyIfFunction key (import x) args)); - in - builtins.genericClosure { - startSet = toClosureList unknownModule "" modules; - operator = m: toClosureList m.file m.key m.imports; - }; + /* + Collects all modules recursively into the form + + { + disabled = [ <list of disabled modules> ]; + # All modules of the main module list + modules = [ + { + key = <key1>; + module = <module for key1>; + # All modules imported by the module for key1 + modules = [ + { + key = <key1-1>; + module = <module for key1-1>; + # All modules imported by the module for key1-1 + modules = [ ... ]; + } + ... + ]; + } + ... + ]; + } + */ + collectStructuredModules = + let + collectResults = modules: { + disabled = concatLists (catAttrs "disabled" modules); + inherit modules; + }; + in parentFile: parentKey: initialModules: args: collectResults (imap1 (n: x: + let + module = loadModule args parentFile "${parentKey}:anon-${toString n}" x; + collectedImports = collectStructuredModules module._file module.key module.imports args; + in { + key = module.key; + module = module; + modules = collectedImports.modules; + disabled = module.disabledModules ++ collectedImports.disabled; + }) initialModules); + + # filterModules :: String -> { disabled, modules } -> [ Module ] + # + # Filters a structure as emitted by collectStructuredModules by removing all disabled + # modules recursively. It returns the final list of unique-by-key modules + filterModules = modulesPath: { disabled, modules }: + let + moduleKey = m: if isString m then toString modulesPath + "/" + m else toString m; + disabledKeys = listToAttrs (map (k: nameValuePair (moduleKey k) null) disabled); + keyFilter = filter (attrs: ! disabledKeys ? ${attrs.key}); + in map (attrs: attrs.module) (builtins.genericClosure { + startSet = keyFilter modules; + operator = attrs: keyFilter attrs.modules; + }); + + in modulesPath: initialModules: args: + filterModules modulesPath (collectStructuredModules unknownModule "" initialModules args); /* Massage a module into canonical form, that is, a set consisting of āoptionsā, āconfigā and āimportsā attributes. */ unifyModuleSyntax = file: key: m: - let metaSet = if m ? meta - then { meta = m.meta; } - else {}; + let addMeta = config: if m ? meta + then mkMerge [ config { meta = m.meta; } ] + else config; in if m ? config || m ? options then let badAttrs = removeAttrs m ["_file" "key" "disabledModules" "imports" "options" "config" "meta"]; in if badAttrs != {} then - throw "Module `${key}' has an unsupported attribute `${head (attrNames badAttrs)}'. This is caused by assignments to the top-level attributes `config' or `options'." + throw "Module `${key}' has an unsupported attribute `${head (attrNames badAttrs)}'. This is caused by introducing a top-level `config' or `options' attribute. Add configuration attributes immediately on the top level instead, or move all of them (namely: ${toString (attrNames badAttrs)}) into the explicit `config' attribute." else - { file = m._file or file; + { _file = m._file or file; key = toString m.key or key; disabledModules = m.disabledModules or []; imports = m.imports or []; options = m.options or {}; - config = mkMerge [ (m.config or {}) metaSet ]; + config = addMeta (m.config or {}); } else - { file = m._file or file; + { _file = m._file or file; key = toString m.key or key; disabledModules = m.disabledModules or []; imports = m.require or [] ++ m.imports or []; options = {}; - config = mkMerge [ (removeAttrs m ["_file" "key" "disabledModules" "require" "imports"]) metaSet ]; + config = addMeta (removeAttrs m ["_file" "key" "disabledModules" "require" "imports"]); }; applyIfFunction = key: f: args@{ config, options, lib, ... }: if isFunction f then @@ -171,17 +219,6 @@ rec { else f; - /* We have to pack and unpack submodules. We cannot wrap the expected - result of the function as we would no longer be able to list the arguments - of the submodule. (see applyIfFunction) */ - unpackSubmodule = unpack: m: args: - if isType "submodule" m then - { _file = m.file; } // (unpack m.submodule args) - else unpack m args; - - packSubmodule = file: m: - { _type = "submodule"; file = file; submodule = m; }; - /* Merge a list of modules. This will recurse over the option declarations in all modules, combining them into a single set. At the same time, for each option declaration, it will merge the @@ -189,7 +226,7 @@ rec { in the āvalueā attribute of each option. */ mergeModules = prefix: modules: mergeModules' prefix modules - (concatMap (m: map (config: { inherit (m) file; inherit config; }) (pushDownProperties m.config)) modules); + (concatMap (m: map (config: { file = m._file; inherit config; }) (pushDownProperties m.config)) modules); mergeModules' = prefix: options: configs: let @@ -223,7 +260,7 @@ rec { ) {} modules; # an attrset 'name' => list of submodules that declare ānameā. declsByName = byName "options" (module: option: - [{ inherit (module) file; options = option; }] + [{ inherit (module) _file; options = option; }] ) options; # an attrset 'name' => list of submodules that define ānameā. defnsByName = byName "config" (module: value: @@ -250,7 +287,7 @@ rec { firstOption = findFirst (m: isOption m.options) "" decls; firstNonOption = findFirst (m: !isOption m.options) "" decls; in - throw "The option `${showOption loc}' in `${firstOption.file}' is a prefix of options in `${firstNonOption.file}'." + throw "The option `${showOption loc}' in `${firstOption._file}' is a prefix of options in `${firstNonOption._file}'." else mergeModules' loc decls defns )) @@ -267,7 +304,14 @@ rec { 'opts' is a list of modules. Each module has an options attribute which correspond to the definition of 'loc' in 'opt.file'. */ - mergeOptionDecls = loc: opts: + mergeOptionDecls = + let + packSubmodule = file: m: + { _file = file; imports = [ m ]; }; + coerceOption = file: opt: + if isFunction opt then packSubmodule file opt + else packSubmodule file { options = opt; }; + in loc: opts: foldl' (res: opt: let t = res.type; t' = opt.options.type; @@ -284,7 +328,7 @@ rec { bothHave "apply" || (bothHave "type" && (! typesMergeable)) then - throw "The option `${showOption loc}' in `${opt.file}' is already declared in ${showFiles res.declarations}." + throw "The option `${showOption loc}' in `${opt._file}' is already declared in ${showFiles res.declarations}." else let /* Add the modules of the current option to the list of modules @@ -293,16 +337,14 @@ rec { current option declaration as the file use for the submodule. If the submodule defines any filename, then we ignore the enclosing option file. */ options' = toList opt.options.options; - coerceOption = file: opt: - if isFunction opt then packSubmodule file opt - else packSubmodule file { options = opt; }; + getSubModules = opt.options.type.getSubModules or null; submodules = - if getSubModules != null then map (packSubmodule opt.file) getSubModules ++ res.options - else if opt.options ? options then map (coerceOption opt.file) options' ++ res.options + if getSubModules != null then map (packSubmodule opt._file) getSubModules ++ res.options + else if opt.options ? options then map (coerceOption opt._file) options' ++ res.options else res.options; in opt.options // res // - { declarations = res.declarations ++ [opt.file]; + { declarations = res.declarations ++ [opt._file]; options = submodules; } // typeSet ) { inherit loc; declarations = []; options = []; } opts; diff --git a/nixpkgs/lib/systems/doubles.nix b/nixpkgs/lib/systems/doubles.nix index 700c895b3ab..96e602d0e16 100644 --- a/nixpkgs/lib/systems/doubles.nix +++ b/nixpkgs/lib/systems/doubles.nix @@ -27,6 +27,8 @@ let "riscv32-linux" "riscv64-linux" "aarch64-none" "avr-none" "arm-none" "i686-none" "x86_64-none" "powerpc-none" "msp430-none" "riscv64-none" "riscv32-none" "vc4-none" + + "js-ghcjs" ]; allParsed = map parse.mkSystemFromString all; @@ -46,6 +48,7 @@ in { mips = filterDoubles predicates.isMips; riscv = filterDoubles predicates.isRiscV; vc4 = filterDoubles predicates.isVc4; + js = filterDoubles predicates.isJavaScript; cygwin = filterDoubles predicates.isCygwin; darwin = filterDoubles predicates.isDarwin; diff --git a/nixpkgs/lib/tests/modules.sh b/nixpkgs/lib/tests/modules.sh index cf344122cf4..2997fb1ada1 100755 --- a/nixpkgs/lib/tests/modules.sh +++ b/nixpkgs/lib/tests/modules.sh @@ -87,36 +87,36 @@ checkConfigOutput "false" "$@" ./define-force-enable.nix checkConfigOutput "false" "$@" ./define-enable-force.nix # Check mkForce with option and submodules. -checkConfigError 'attribute .*foo.* .* not found' config.loaOfSub.foo.enable ./declare-loaOfSub-any-enable.nix -checkConfigOutput 'false' config.loaOfSub.foo.enable ./declare-loaOfSub-any-enable.nix ./define-loaOfSub-foo.nix -set -- config.loaOfSub.foo.enable ./declare-loaOfSub-any-enable.nix ./define-loaOfSub-foo-enable.nix +checkConfigError 'attribute .*foo.* .* not found' config.attrsOfSub.foo.enable ./declare-attrsOfSub-any-enable.nix +checkConfigOutput 'false' config.attrsOfSub.foo.enable ./declare-attrsOfSub-any-enable.nix ./define-attrsOfSub-foo.nix +set -- config.attrsOfSub.foo.enable ./declare-attrsOfSub-any-enable.nix ./define-attrsOfSub-foo-enable.nix checkConfigOutput 'true' "$@" -checkConfigOutput 'false' "$@" ./define-force-loaOfSub-foo-enable.nix -checkConfigOutput 'false' "$@" ./define-loaOfSub-force-foo-enable.nix -checkConfigOutput 'false' "$@" ./define-loaOfSub-foo-force-enable.nix -checkConfigOutput 'false' "$@" ./define-loaOfSub-foo-enable-force.nix +checkConfigOutput 'false' "$@" ./define-force-attrsOfSub-foo-enable.nix +checkConfigOutput 'false' "$@" ./define-attrsOfSub-force-foo-enable.nix +checkConfigOutput 'false' "$@" ./define-attrsOfSub-foo-force-enable.nix +checkConfigOutput 'false' "$@" ./define-attrsOfSub-foo-enable-force.nix # Check overriding effect of mkForce on submodule definitions. -checkConfigError 'attribute .*bar.* .* not found' config.loaOfSub.bar.enable ./declare-loaOfSub-any-enable.nix ./define-loaOfSub-foo.nix -checkConfigOutput 'false' config.loaOfSub.bar.enable ./declare-loaOfSub-any-enable.nix ./define-loaOfSub-foo.nix ./define-loaOfSub-bar.nix -set -- config.loaOfSub.bar.enable ./declare-loaOfSub-any-enable.nix ./define-loaOfSub-foo.nix ./define-loaOfSub-bar-enable.nix +checkConfigError 'attribute .*bar.* .* not found' config.attrsOfSub.bar.enable ./declare-attrsOfSub-any-enable.nix ./define-attrsOfSub-foo.nix +checkConfigOutput 'false' config.attrsOfSub.bar.enable ./declare-attrsOfSub-any-enable.nix ./define-attrsOfSub-foo.nix ./define-attrsOfSub-bar.nix +set -- config.attrsOfSub.bar.enable ./declare-attrsOfSub-any-enable.nix ./define-attrsOfSub-foo.nix ./define-attrsOfSub-bar-enable.nix checkConfigOutput 'true' "$@" -checkConfigError 'attribute .*bar.* .* not found' "$@" ./define-force-loaOfSub-foo-enable.nix -checkConfigError 'attribute .*bar.* .* not found' "$@" ./define-loaOfSub-force-foo-enable.nix -checkConfigOutput 'true' "$@" ./define-loaOfSub-foo-force-enable.nix -checkConfigOutput 'true' "$@" ./define-loaOfSub-foo-enable-force.nix +checkConfigError 'attribute .*bar.* .* not found' "$@" ./define-force-attrsOfSub-foo-enable.nix +checkConfigError 'attribute .*bar.* .* not found' "$@" ./define-attrsOfSub-force-foo-enable.nix +checkConfigOutput 'true' "$@" ./define-attrsOfSub-foo-force-enable.nix +checkConfigOutput 'true' "$@" ./define-attrsOfSub-foo-enable-force.nix # Check mkIf with submodules. -checkConfigError 'attribute .*foo.* .* not found' config.loaOfSub.foo.enable ./declare-enable.nix ./declare-loaOfSub-any-enable.nix -set -- config.loaOfSub.foo.enable ./declare-enable.nix ./declare-loaOfSub-any-enable.nix -checkConfigError 'attribute .*foo.* .* not found' "$@" ./define-if-loaOfSub-foo-enable.nix -checkConfigError 'attribute .*foo.* .* not found' "$@" ./define-loaOfSub-if-foo-enable.nix -checkConfigError 'attribute .*foo.* .* not found' "$@" ./define-loaOfSub-foo-if-enable.nix -checkConfigOutput 'false' "$@" ./define-loaOfSub-foo-enable-if.nix -checkConfigOutput 'true' "$@" ./define-enable.nix ./define-if-loaOfSub-foo-enable.nix -checkConfigOutput 'true' "$@" ./define-enable.nix ./define-loaOfSub-if-foo-enable.nix -checkConfigOutput 'true' "$@" ./define-enable.nix ./define-loaOfSub-foo-if-enable.nix -checkConfigOutput 'true' "$@" ./define-enable.nix ./define-loaOfSub-foo-enable-if.nix +checkConfigError 'attribute .*foo.* .* not found' config.attrsOfSub.foo.enable ./declare-enable.nix ./declare-attrsOfSub-any-enable.nix +set -- config.attrsOfSub.foo.enable ./declare-enable.nix ./declare-attrsOfSub-any-enable.nix +checkConfigError 'attribute .*foo.* .* not found' "$@" ./define-if-attrsOfSub-foo-enable.nix +checkConfigError 'attribute .*foo.* .* not found' "$@" ./define-attrsOfSub-if-foo-enable.nix +checkConfigError 'attribute .*foo.* .* not found' "$@" ./define-attrsOfSub-foo-if-enable.nix +checkConfigOutput 'false' "$@" ./define-attrsOfSub-foo-enable-if.nix +checkConfigOutput 'true' "$@" ./define-enable.nix ./define-if-attrsOfSub-foo-enable.nix +checkConfigOutput 'true' "$@" ./define-enable.nix ./define-attrsOfSub-if-foo-enable.nix +checkConfigOutput 'true' "$@" ./define-enable.nix ./define-attrsOfSub-foo-if-enable.nix +checkConfigOutput 'true' "$@" ./define-enable.nix ./define-attrsOfSub-foo-enable-if.nix # Check disabledModules with config definitions and option declarations. set -- config.enable ./define-enable.nix ./declare-enable.nix @@ -138,7 +138,7 @@ checkConfigError 'while evaluating the module argument .*custom.* in .*import-cu checkConfigError 'infinite recursion encountered' "$@" # Check _module.check. -set -- config.enable ./declare-enable.nix ./define-enable.nix ./define-loaOfSub-foo.nix +set -- config.enable ./declare-enable.nix ./define-enable.nix ./define-attrsOfSub-foo.nix checkConfigError 'The option .* defined in .* does not exist.' "$@" checkConfigOutput "true" "$@" ./define-module-check.nix @@ -152,18 +152,37 @@ checkConfigOutput "12" config.value ./declare-coerced-value-unsound.nix checkConfigError 'The option value .* in .* is not.*8 bit signed integer.* or string convertible to it' config.value ./declare-coerced-value-unsound.nix ./define-value-string-bigint.nix checkConfigError 'unrecognised JSON value' config.value ./declare-coerced-value-unsound.nix ./define-value-string-arbitrary.nix -# Check loaOf with long list. -checkConfigOutput "1 2 3 4 5 6 7 8 9 10" config.result ./loaOf-with-long-list.nix - -# Check loaOf with many merges of lists. -checkConfigOutput "1 2 3 4 5 6 7 8 9 10" config.result ./loaOf-with-many-list-merges.nix - # Check mkAliasOptionModule. checkConfigOutput "true" config.enable ./alias-with-priority.nix checkConfigOutput "true" config.enableAlias ./alias-with-priority.nix checkConfigOutput "false" config.enable ./alias-with-priority-can-override.nix checkConfigOutput "false" config.enableAlias ./alias-with-priority-can-override.nix +# submoduleWith + +## specialArgs should work +checkConfigOutput "foo" config.submodule.foo ./declare-submoduleWith-special.nix + +## shorthandOnlyDefines config behaves as expected +checkConfigOutput "true" config.submodule.config ./declare-submoduleWith-shorthand.nix ./define-submoduleWith-shorthand.nix +checkConfigError 'is not of type `boolean' config.submodule.config ./declare-submoduleWith-shorthand.nix ./define-submoduleWith-noshorthand.nix +checkConfigError 'value is a boolean while a set was expected' config.submodule.config ./declare-submoduleWith-noshorthand.nix ./define-submoduleWith-shorthand.nix +checkConfigOutput "true" config.submodule.config ./declare-submoduleWith-noshorthand.nix ./define-submoduleWith-noshorthand.nix + +## submoduleWith should merge all modules in one swoop +checkConfigOutput "true" config.submodule.inner ./declare-submoduleWith-modules.nix +checkConfigOutput "true" config.submodule.outer ./declare-submoduleWith-modules.nix + +## Paths should be allowed as values and work as expected +# Temporarily disabled until https://github.com/NixOS/nixpkgs/pull/76861 +#checkConfigOutput "true" config.submodule.enable ./declare-submoduleWith-path.nix + +# Check that disabledModules works recursively and correctly +checkConfigOutput "true" config.enable ./disable-recursive/main.nix +checkConfigOutput "true" config.enable ./disable-recursive/{main.nix,disable-foo.nix} +checkConfigOutput "true" config.enable ./disable-recursive/{main.nix,disable-bar.nix} +checkConfigError 'The option .* defined in .* does not exist' config.enable ./disable-recursive/{main.nix,disable-foo.nix,disable-bar.nix} + cat <<EOF ====== module tests ====== $pass Pass diff --git a/nixpkgs/lib/tests/modules/declare-loaOfSub-any-enable.nix b/nixpkgs/lib/tests/modules/declare-attrsOfSub-any-enable.nix index 71dad1c9135..986d07227e1 100644 --- a/nixpkgs/lib/tests/modules/declare-loaOfSub-any-enable.nix +++ b/nixpkgs/lib/tests/modules/declare-attrsOfSub-any-enable.nix @@ -17,10 +17,10 @@ in { options = { - loaOfSub = lib.mkOption { + attrsOfSub = lib.mkOption { default = {}; example = {}; - type = lib.types.loaOf (lib.types.submodule [ submod ]); + type = lib.types.attrsOf (lib.types.submodule [ submod ]); description = '' Some descriptive text ''; diff --git a/nixpkgs/lib/tests/modules/declare-submoduleWith-modules.nix b/nixpkgs/lib/tests/modules/declare-submoduleWith-modules.nix new file mode 100644 index 00000000000..4736ab41751 --- /dev/null +++ b/nixpkgs/lib/tests/modules/declare-submoduleWith-modules.nix @@ -0,0 +1,30 @@ +{ lib, ... }: { + options.submodule = lib.mkOption { + type = lib.types.submoduleWith { + modules = [ + { + options.inner = lib.mkOption { + type = lib.types.bool; + default = false; + }; + } + { + outer = true; + } + ]; + }; + default = {}; + }; + + config.submodule = lib.mkMerge [ + ({ lib, ... }: { + options.outer = lib.mkOption { + type = lib.types.bool; + default = false; + }; + }) + { + inner = true; + } + ]; +} diff --git a/nixpkgs/lib/tests/modules/declare-submoduleWith-noshorthand.nix b/nixpkgs/lib/tests/modules/declare-submoduleWith-noshorthand.nix new file mode 100644 index 00000000000..af3b4ba470f --- /dev/null +++ b/nixpkgs/lib/tests/modules/declare-submoduleWith-noshorthand.nix @@ -0,0 +1,13 @@ +{ lib, ... }: let + sub.options.config = lib.mkOption { + type = lib.types.bool; + default = false; + }; +in { + options.submodule = lib.mkOption { + type = lib.types.submoduleWith { + modules = [ sub ]; + }; + default = {}; + }; +} diff --git a/nixpkgs/lib/tests/modules/declare-submoduleWith-path.nix b/nixpkgs/lib/tests/modules/declare-submoduleWith-path.nix new file mode 100644 index 00000000000..477647f3212 --- /dev/null +++ b/nixpkgs/lib/tests/modules/declare-submoduleWith-path.nix @@ -0,0 +1,12 @@ +{ lib, ... }: { + options.submodule = lib.mkOption { + type = lib.types.submoduleWith { + modules = [ + ./declare-enable.nix + ]; + }; + default = {}; + }; + + config.submodule = ./define-enable.nix; +} diff --git a/nixpkgs/lib/tests/modules/declare-submoduleWith-shorthand.nix b/nixpkgs/lib/tests/modules/declare-submoduleWith-shorthand.nix new file mode 100644 index 00000000000..63ac16293e2 --- /dev/null +++ b/nixpkgs/lib/tests/modules/declare-submoduleWith-shorthand.nix @@ -0,0 +1,14 @@ +{ lib, ... }: let + sub.options.config = lib.mkOption { + type = lib.types.bool; + default = false; + }; +in { + options.submodule = lib.mkOption { + type = lib.types.submoduleWith { + modules = [ sub ]; + shorthandOnlyDefinesConfig = true; + }; + default = {}; + }; +} diff --git a/nixpkgs/lib/tests/modules/declare-submoduleWith-special.nix b/nixpkgs/lib/tests/modules/declare-submoduleWith-special.nix new file mode 100644 index 00000000000..6b15c5bde20 --- /dev/null +++ b/nixpkgs/lib/tests/modules/declare-submoduleWith-special.nix @@ -0,0 +1,17 @@ +{ lib, ... }: { + options.submodule = lib.mkOption { + type = lib.types.submoduleWith { + modules = [ + ({ lib, ... }: { + options.foo = lib.mkOption { + default = lib.foo; + }; + }) + ]; + specialArgs.lib = lib // { + foo = "foo"; + }; + }; + default = {}; + }; +} diff --git a/nixpkgs/lib/tests/modules/define-attrsOfSub-bar-enable.nix b/nixpkgs/lib/tests/modules/define-attrsOfSub-bar-enable.nix new file mode 100644 index 00000000000..99c55d8b360 --- /dev/null +++ b/nixpkgs/lib/tests/modules/define-attrsOfSub-bar-enable.nix @@ -0,0 +1,3 @@ +{ + attrsOfSub.bar.enable = true; +} diff --git a/nixpkgs/lib/tests/modules/define-attrsOfSub-bar.nix b/nixpkgs/lib/tests/modules/define-attrsOfSub-bar.nix new file mode 100644 index 00000000000..2a33068a568 --- /dev/null +++ b/nixpkgs/lib/tests/modules/define-attrsOfSub-bar.nix @@ -0,0 +1,3 @@ +{ + attrsOfSub.bar = {}; +} diff --git a/nixpkgs/lib/tests/modules/define-attrsOfSub-foo-enable-force.nix b/nixpkgs/lib/tests/modules/define-attrsOfSub-foo-enable-force.nix new file mode 100644 index 00000000000..c9ee36446f1 --- /dev/null +++ b/nixpkgs/lib/tests/modules/define-attrsOfSub-foo-enable-force.nix @@ -0,0 +1,5 @@ +{ lib, ... }: + +{ + attrsOfSub.foo.enable = lib.mkForce false; +} diff --git a/nixpkgs/lib/tests/modules/define-attrsOfSub-foo-enable-if.nix b/nixpkgs/lib/tests/modules/define-attrsOfSub-foo-enable-if.nix new file mode 100644 index 00000000000..0b3baddb5ec --- /dev/null +++ b/nixpkgs/lib/tests/modules/define-attrsOfSub-foo-enable-if.nix @@ -0,0 +1,5 @@ +{ config, lib, ... }: + +{ + attrsOfSub.foo.enable = lib.mkIf config.enable true; +} diff --git a/nixpkgs/lib/tests/modules/define-attrsOfSub-foo-enable.nix b/nixpkgs/lib/tests/modules/define-attrsOfSub-foo-enable.nix new file mode 100644 index 00000000000..39cd63cef72 --- /dev/null +++ b/nixpkgs/lib/tests/modules/define-attrsOfSub-foo-enable.nix @@ -0,0 +1,3 @@ +{ + attrsOfSub.foo.enable = true; +} diff --git a/nixpkgs/lib/tests/modules/define-loaOfSub-foo-force-enable.nix b/nixpkgs/lib/tests/modules/define-attrsOfSub-foo-force-enable.nix index dce0ef547b3..009da7c77cd 100644 --- a/nixpkgs/lib/tests/modules/define-loaOfSub-foo-force-enable.nix +++ b/nixpkgs/lib/tests/modules/define-attrsOfSub-foo-force-enable.nix @@ -1,7 +1,7 @@ { lib, ... }: { - loaOfSub.foo = lib.mkForce { + attrsOfSub.foo = lib.mkForce { enable = false; }; } diff --git a/nixpkgs/lib/tests/modules/define-loaOfSub-foo-if-enable.nix b/nixpkgs/lib/tests/modules/define-attrsOfSub-foo-if-enable.nix index 236b2840ee5..93702dfa86f 100644 --- a/nixpkgs/lib/tests/modules/define-loaOfSub-foo-if-enable.nix +++ b/nixpkgs/lib/tests/modules/define-attrsOfSub-foo-if-enable.nix @@ -1,7 +1,7 @@ { config, lib, ... }: { - loaOfSub.foo = lib.mkIf config.enable { + attrsOfSub.foo = lib.mkIf config.enable { enable = true; }; } diff --git a/nixpkgs/lib/tests/modules/define-attrsOfSub-foo.nix b/nixpkgs/lib/tests/modules/define-attrsOfSub-foo.nix new file mode 100644 index 00000000000..e6bb531dedd --- /dev/null +++ b/nixpkgs/lib/tests/modules/define-attrsOfSub-foo.nix @@ -0,0 +1,3 @@ +{ + attrsOfSub.foo = {}; +} diff --git a/nixpkgs/lib/tests/modules/define-loaOfSub-force-foo-enable.nix b/nixpkgs/lib/tests/modules/define-attrsOfSub-force-foo-enable.nix index df5722274ee..5c02dd34314 100644 --- a/nixpkgs/lib/tests/modules/define-loaOfSub-force-foo-enable.nix +++ b/nixpkgs/lib/tests/modules/define-attrsOfSub-force-foo-enable.nix @@ -1,7 +1,7 @@ { lib, ... }: { - loaOfSub = lib.mkForce { + attrsOfSub = lib.mkForce { foo.enable = false; }; } diff --git a/nixpkgs/lib/tests/modules/define-loaOfSub-if-foo-enable.nix b/nixpkgs/lib/tests/modules/define-attrsOfSub-if-foo-enable.nix index bd2d068d31a..a3fe6051d41 100644 --- a/nixpkgs/lib/tests/modules/define-loaOfSub-if-foo-enable.nix +++ b/nixpkgs/lib/tests/modules/define-attrsOfSub-if-foo-enable.nix @@ -1,7 +1,7 @@ { config, lib, ... }: { - loaOfSub = lib.mkIf config.enable { + attrsOfSub = lib.mkIf config.enable { foo.enable = true; }; } diff --git a/nixpkgs/lib/tests/modules/define-force-attrsOfSub-foo-enable.nix b/nixpkgs/lib/tests/modules/define-force-attrsOfSub-foo-enable.nix new file mode 100644 index 00000000000..dafb2360e1f --- /dev/null +++ b/nixpkgs/lib/tests/modules/define-force-attrsOfSub-foo-enable.nix @@ -0,0 +1,5 @@ +{ lib, ... }: + +lib.mkForce { + attrsOfSub.foo.enable = false; +} diff --git a/nixpkgs/lib/tests/modules/define-force-loaOfSub-foo-enable.nix b/nixpkgs/lib/tests/modules/define-force-loaOfSub-foo-enable.nix deleted file mode 100644 index bfd8e084b59..00000000000 --- a/nixpkgs/lib/tests/modules/define-force-loaOfSub-foo-enable.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ lib, ... }: - -lib.mkForce { - loaOfSub.foo.enable = false; -} diff --git a/nixpkgs/lib/tests/modules/define-if-loaOfSub-foo-enable.nix b/nixpkgs/lib/tests/modules/define-if-attrsOfSub-foo-enable.nix index 4288d74dec0..6a8e32e802a 100644 --- a/nixpkgs/lib/tests/modules/define-if-loaOfSub-foo-enable.nix +++ b/nixpkgs/lib/tests/modules/define-if-attrsOfSub-foo-enable.nix @@ -1,5 +1,5 @@ { config, lib, ... }: lib.mkIf config.enable { - loaOfSub.foo.enable = true; + attrsOfSub.foo.enable = true; } diff --git a/nixpkgs/lib/tests/modules/define-loaOfSub-bar-enable.nix b/nixpkgs/lib/tests/modules/define-loaOfSub-bar-enable.nix deleted file mode 100644 index 422bb0a600b..00000000000 --- a/nixpkgs/lib/tests/modules/define-loaOfSub-bar-enable.nix +++ /dev/null @@ -1,3 +0,0 @@ -{ - loaOfSub.bar.enable = true; -} diff --git a/nixpkgs/lib/tests/modules/define-loaOfSub-bar.nix b/nixpkgs/lib/tests/modules/define-loaOfSub-bar.nix deleted file mode 100644 index c24315e09b6..00000000000 --- a/nixpkgs/lib/tests/modules/define-loaOfSub-bar.nix +++ /dev/null @@ -1,3 +0,0 @@ -{ - loaOfSub.bar = {}; -} diff --git a/nixpkgs/lib/tests/modules/define-loaOfSub-foo-enable-force.nix b/nixpkgs/lib/tests/modules/define-loaOfSub-foo-enable-force.nix deleted file mode 100644 index c1d7b198be5..00000000000 --- a/nixpkgs/lib/tests/modules/define-loaOfSub-foo-enable-force.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ lib, ... }: - -{ - loaOfSub.foo.enable = lib.mkForce false; -} diff --git a/nixpkgs/lib/tests/modules/define-loaOfSub-foo-enable-if.nix b/nixpkgs/lib/tests/modules/define-loaOfSub-foo-enable-if.nix deleted file mode 100644 index 44b2c96cd02..00000000000 --- a/nixpkgs/lib/tests/modules/define-loaOfSub-foo-enable-if.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ config, lib, ... }: - -{ - loaOfSub.foo.enable = lib.mkIf config.enable true; -} diff --git a/nixpkgs/lib/tests/modules/define-loaOfSub-foo-enable.nix b/nixpkgs/lib/tests/modules/define-loaOfSub-foo-enable.nix deleted file mode 100644 index 822425c71bb..00000000000 --- a/nixpkgs/lib/tests/modules/define-loaOfSub-foo-enable.nix +++ /dev/null @@ -1,3 +0,0 @@ -{ - loaOfSub.foo.enable = true; -} diff --git a/nixpkgs/lib/tests/modules/define-loaOfSub-foo.nix b/nixpkgs/lib/tests/modules/define-loaOfSub-foo.nix deleted file mode 100644 index e9b2e631f2e..00000000000 --- a/nixpkgs/lib/tests/modules/define-loaOfSub-foo.nix +++ /dev/null @@ -1,3 +0,0 @@ -{ - loaOfSub.foo = {}; -} diff --git a/nixpkgs/lib/tests/modules/define-submoduleWith-noshorthand.nix b/nixpkgs/lib/tests/modules/define-submoduleWith-noshorthand.nix new file mode 100644 index 00000000000..35e1607b6f1 --- /dev/null +++ b/nixpkgs/lib/tests/modules/define-submoduleWith-noshorthand.nix @@ -0,0 +1,3 @@ +{ + submodule.config.config = true; +} diff --git a/nixpkgs/lib/tests/modules/define-submoduleWith-shorthand.nix b/nixpkgs/lib/tests/modules/define-submoduleWith-shorthand.nix new file mode 100644 index 00000000000..17df248db8e --- /dev/null +++ b/nixpkgs/lib/tests/modules/define-submoduleWith-shorthand.nix @@ -0,0 +1,3 @@ +{ + submodule.config = true; +} diff --git a/nixpkgs/lib/tests/modules/disable-recursive/bar.nix b/nixpkgs/lib/tests/modules/disable-recursive/bar.nix new file mode 100644 index 00000000000..4d9240a432d --- /dev/null +++ b/nixpkgs/lib/tests/modules/disable-recursive/bar.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ../declare-enable.nix + ]; +} diff --git a/nixpkgs/lib/tests/modules/disable-recursive/disable-bar.nix b/nixpkgs/lib/tests/modules/disable-recursive/disable-bar.nix new file mode 100644 index 00000000000..987b2802ae8 --- /dev/null +++ b/nixpkgs/lib/tests/modules/disable-recursive/disable-bar.nix @@ -0,0 +1,7 @@ +{ + + disabledModules = [ + ./bar.nix + ]; + +} diff --git a/nixpkgs/lib/tests/modules/disable-recursive/disable-foo.nix b/nixpkgs/lib/tests/modules/disable-recursive/disable-foo.nix new file mode 100644 index 00000000000..5b68a3c4610 --- /dev/null +++ b/nixpkgs/lib/tests/modules/disable-recursive/disable-foo.nix @@ -0,0 +1,7 @@ +{ + + disabledModules = [ + ./foo.nix + ]; + +} diff --git a/nixpkgs/lib/tests/modules/disable-recursive/foo.nix b/nixpkgs/lib/tests/modules/disable-recursive/foo.nix new file mode 100644 index 00000000000..4d9240a432d --- /dev/null +++ b/nixpkgs/lib/tests/modules/disable-recursive/foo.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ../declare-enable.nix + ]; +} diff --git a/nixpkgs/lib/tests/modules/disable-recursive/main.nix b/nixpkgs/lib/tests/modules/disable-recursive/main.nix new file mode 100644 index 00000000000..48a3c6218cf --- /dev/null +++ b/nixpkgs/lib/tests/modules/disable-recursive/main.nix @@ -0,0 +1,8 @@ +{ + imports = [ + ./foo.nix + ./bar.nix + ]; + + enable = true; +} diff --git a/nixpkgs/lib/tests/modules/loaOf-with-long-list.nix b/nixpkgs/lib/tests/modules/loaOf-with-long-list.nix deleted file mode 100644 index f30903c47e5..00000000000 --- a/nixpkgs/lib/tests/modules/loaOf-with-long-list.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ config, lib, ... }: - -{ - options = { - loaOfInt = lib.mkOption { - type = lib.types.loaOf lib.types.int; - }; - - result = lib.mkOption { - type = lib.types.str; - }; - }; - - config = { - loaOfInt = [ 1 2 3 4 5 6 7 8 9 10 ]; - - result = toString (lib.attrValues config.loaOfInt); - }; -} diff --git a/nixpkgs/lib/tests/modules/loaOf-with-many-list-merges.nix b/nixpkgs/lib/tests/modules/loaOf-with-many-list-merges.nix deleted file mode 100644 index f8f8a8da82b..00000000000 --- a/nixpkgs/lib/tests/modules/loaOf-with-many-list-merges.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ config, lib, ... }: - -{ - options = { - loaOfInt = lib.mkOption { - type = lib.types.loaOf lib.types.int; - }; - - result = lib.mkOption { - type = lib.types.str; - }; - }; - - config = { - loaOfInt = lib.mkMerge (map lib.singleton [ 1 2 3 4 5 6 7 8 9 10 ]); - - result = toString (lib.attrValues config.loaOfInt); - }; -} diff --git a/nixpkgs/lib/tests/systems.nix b/nixpkgs/lib/tests/systems.nix index 818749442f9..6f52912994d 100644 --- a/nixpkgs/lib/tests/systems.nix +++ b/nixpkgs/lib/tests/systems.nix @@ -12,7 +12,7 @@ let expected = lib.sort lib.lessThan y; }; in with lib.systems.doubles; lib.runTests { - testall = mseteq all (linux ++ darwin ++ freebsd ++ openbsd ++ netbsd ++ illumos ++ wasi ++ windows ++ embedded); + testall = mseteq all (linux ++ darwin ++ freebsd ++ openbsd ++ netbsd ++ illumos ++ wasi ++ windows ++ embedded ++ js); testarm = mseteq arm [ "armv5tel-linux" "armv6l-linux" "armv7a-linux" "armv7l-linux" "arm-none" "armv7a-darwin" ]; testi686 = mseteq i686 [ "i686-linux" "i686-freebsd" "i686-netbsd" "i686-openbsd" "i686-cygwin" "i686-windows" "i686-none" "i686-darwin" ]; diff --git a/nixpkgs/lib/types.nix b/nixpkgs/lib/types.nix index 5e9a28ac4f0..4872a676657 100644 --- a/nixpkgs/lib/types.nix +++ b/nixpkgs/lib/types.nix @@ -242,8 +242,7 @@ rec { path = mkOptionType { name = "path"; - # Hacky: there is no āisPathā primop. - check = x: builtins.substring 0 1 (toString x) == "/"; + check = x: isCoercibleToString x && builtins.substring 0 1 (toString x) == "/"; merge = mergeEqualOption; }; @@ -295,26 +294,43 @@ rec { # List or attribute set of ... loaOf = elemType: let - convertAllLists = defs: + convertAllLists = loc: defs: let padWidth = stringLength (toString (length defs)); unnamedPrefix = i: "unnamed-" + fixedWidthNumber padWidth i + "."; in - imap1 (i: convertIfList (unnamedPrefix i)) defs; - - convertIfList = unnamedPrefix: def: + imap1 (i: convertIfList loc (unnamedPrefix i)) defs; + convertIfList = loc: unnamedPrefix: def: if isList def.value then let padWidth = stringLength (toString (length def.value)); unnamed = i: unnamedPrefix + fixedWidthNumber padWidth i; + res = + { inherit (def) file; + value = listToAttrs ( + imap1 (elemIdx: elem: + { name = elem.name or (unnamed elemIdx); + value = elem; + }) def.value); + }; + option = concatStringsSep "." loc; + sample = take 3 def.value; + list = concatMapStrings (x: ''{ name = "${x.name or "unnamed"}"; ...} '') sample; + set = concatMapStrings (x: ''${x.name or "unnamed"} = {...}; '') sample; + msg = '' + In file ${def.file} + a list is being assigned to the option config.${option}. + This will soon be an error as type loaOf is deprecated. + See https://git.io/fj2zm for more information. + Do + ${option} = + { ${set}...} + instead of + ${option} = + [ ${list}...] + ''; in - { inherit (def) file; - value = listToAttrs ( - imap1 (elemIdx: elem: - { name = elem.name or (unnamed elemIdx); - value = elem; - }) def.value); - } + lib.warn msg res else def; attrOnly = attrsOf elemType; @@ -322,7 +338,7 @@ rec { name = "loaOf"; description = "list or attribute set of ${elemType.description}s"; check = x: isList x || isAttrs x; - merge = loc: defs: attrOnly.merge loc (convertAllLists defs); + merge = loc: defs: attrOnly.merge loc (convertAllLists loc defs); getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name?>"]); getSubModules = elemType.getSubModules; substSubModules = m: loaOf (elemType.substSubModules m); @@ -358,25 +374,41 @@ rec { }; # A submodule (like typed attribute set). See NixOS manual. - submodule = opts: + submodule = modules: submoduleWith { + shorthandOnlyDefinesConfig = true; + modules = toList modules; + }; + + submoduleWith = + { modules + , specialArgs ? {} + , shorthandOnlyDefinesConfig ? false + }@attrs: let - opts' = toList opts; inherit (lib.modules) evalModules; + + coerce = unify: value: if isFunction value + then setFunctionArgs (args: unify (value args)) (functionArgs value) + else unify (if shorthandOnlyDefinesConfig then { config = value; } else value); + + allModules = defs: modules ++ imap1 (n: { value, file }: + # Annotate the value with the location of its definition for better error messages + coerce (lib.modules.unifyModuleSyntax file "${toString file}-${toString n}") value + ) defs; + in mkOptionType rec { name = "submodule"; check = x: isAttrs x || isFunction x; merge = loc: defs: - let - coerce = def: if isFunction def then def else { config = def; }; - modules = opts' ++ map (def: { _file = def.file; imports = [(coerce def.value)]; }) defs; - in (evalModules { - inherit modules; + (evalModules { + modules = allModules defs; + inherit specialArgs; args.name = last loc; prefix = loc; }).config; getSubOptions = prefix: (evalModules - { modules = opts'; inherit prefix; + { inherit modules prefix specialArgs; # This is a work-around due to the fact that some sub-modules, # such as the one included in an attribute set, expects a "args" # attribute to be given to the sub-module. As the option @@ -394,13 +426,29 @@ rec { # It shouldn't cause an issue since this is cosmetic for the manual. args.name = "ā¹nameāŗ"; }).options; - getSubModules = opts'; - substSubModules = m: submodule m; - functor = (defaultFunctor name) // { - # Merging of submodules is done as part of mergeOptionDecls, as we have to annotate - # each submodule with its location. - payload = []; - binOp = lhs: rhs: []; + getSubModules = modules; + substSubModules = m: submoduleWith (attrs // { + modules = m; + }); + functor = defaultFunctor name // { + type = types.submoduleWith; + payload = { + modules = modules; + specialArgs = specialArgs; + shorthandOnlyDefinesConfig = shorthandOnlyDefinesConfig; + }; + binOp = lhs: rhs: { + modules = lhs.modules ++ rhs.modules; + specialArgs = + let intersecting = builtins.intersectAttrs lhs.specialArgs rhs.specialArgs; + in if intersecting == {} + then lhs.specialArgs // rhs.specialArgs + else throw "A submoduleWith option is declared multiple times with the same specialArgs \"${toString (attrNames intersecting)}\""; + shorthandOnlyDefinesConfig = + if lhs.shorthandOnlyDefinesConfig == rhs.shorthandOnlyDefinesConfig + then lhs.shorthandOnlyDefinesConfig + else throw "A submoduleWith option is declared multiple times with conflicting shorthandOnlyDefinesConfig values"; + }; }; }; |