···7777* `runtimeDeps` is used to wrap libraries into `LD_LIBRARY_PATH`. This is how dotnet usually handles runtime dependencies.
7878* `buildType` is used to change the type of build. Possible values are `Release`, `Debug`, etc. By default, this is set to `Release`.
7979* `dotnet-sdk` is useful in cases where you need to change what dotnet SDK is being used.
8080-* `dotnet-runtime` is useful in cases where you need to change what dotnet runtime is being used.
8080+* `dotnet-runtime` is useful in cases where you need to change what dotnet runtime is being used. This can be either a regular dotnet runtime, or an aspnetcore.
8181+* `dotnet-test-sdk` is useful in cases where unit tests expect a different dotnet SDK. By default, this is set to the `dotnet-sdk` attribute.
8282+* `testProjectFile` is useful in cases where the regular project file does not contain the unit tests. By default, this is set to the `projectFile` attribute.
8383+* `disabledTests` is used to disable running specific unit tests. This gets passed as: `dotnet test --filter "FullyQualifiedName!={}"`, to ensure compatibility with all unit test frameworks.
8184* `dotnetRestoreFlags` can be used to pass flags to `dotnet restore`.
8285* `dotnetBuildFlags` can be used to pass flags to `dotnet build`.
8686+* `dotnetTestFlags` can be used to pass flags to `dotnet test`.
8387* `dotnetInstallFlags` can be used to pass flags to `dotnet install`.
8488* `dotnetFlags` can be used to pass flags to all of the above phases.
8589
+53-9
lib/modules.nix
···52525353rec {
54545555- /* Evaluate a set of modules. The result is a set of two
5656- attributes: ‘options’: the nested set of all option declarations,
5757- and ‘config’: the nested set of all option values.
5555+ /*
5656+ Evaluate a set of modules. The result is a set with the attributes:
5757+5858+ ‘options’: The nested set of all option declarations,
5959+6060+ ‘config’: The nested set of all option values.
6161+6262+ ‘type’: A module system type representing the module set as a submodule,
6363+ to be extended by configuration from the containing module set.
6464+6565+ ‘extendModules’: A function similar to ‘evalModules’ but building on top
6666+ of the module set. Its arguments, ‘modules’ and ‘specialArgs’ are
6767+ added to the existing values.
6868+6969+ Using ‘extendModules’ a few times has no performance impact as long
7070+ as you only reference the final ‘options’ and ‘config’.
7171+ If you do reference multiple ‘config’ (or ‘options’) from before and
7272+ after ‘extendModules’, performance is the same as with multiple
7373+ ‘evalModules’ invocations, because the new modules' ability to
7474+ override existing configuration fundamentally requires a new
7575+ fixpoint to be constructed.
7676+7777+ ‘_module’: A portion of the configuration tree which is elided from
7878+ ‘config’. It contains some values that are mostly internal to the
7979+ module system implementation.
8080+5881 !!! Please think twice before adding to this argument list! The more
5982 that is specified here instead of in the modules themselves the harder
6083 it is to transparently move a set of modules to be a submodule of another
6184 config (as the proper arguments need to be replicated at each call to
6285 evalModules) and the less declarative the module set is. */
6363- evalModules = { modules
8686+ evalModules = evalModulesArgs@
8787+ { modules
6488 , prefix ? []
6589 , # This should only be used for special arguments that need to be evaluated
6690 # when resolving module structure (like in imports). For everything else,
···120144 };
121145122146 config = {
123123- _module.args = args;
147147+ _module.args = {
148148+ inherit extendModules;
149149+ } // args;
124150 };
125151 };
126152···183209 else throw baseMsg
184210 else null;
185211186186- result = builtins.seq checkUnmatched {
187187- inherit options;
188188- config = removeAttrs config [ "_module" ];
189189- inherit (config) _module;
212212+ checked = builtins.seq checkUnmatched;
213213+214214+ extendModules = extendArgs@{
215215+ modules ? [],
216216+ specialArgs ? {},
217217+ prefix ? [],
218218+ }:
219219+ evalModules (evalModulesArgs // {
220220+ modules = evalModulesArgs.modules ++ modules;
221221+ specialArgs = evalModulesArgs.specialArgs or {} // specialArgs;
222222+ prefix = extendArgs.prefix or evalModulesArgs.prefix;
223223+ });
224224+225225+ type = lib.types.submoduleWith {
226226+ inherit modules specialArgs;
227227+ };
228228+229229+ result = {
230230+ options = checked options;
231231+ config = checked (removeAttrs config [ "_module" ]);
232232+ _module = checked (config._module);
233233+ inherit extendModules type;
190234 };
191235 in result;
192236
+7-3
lib/options.nix
···7474 apply ? null,
7575 # Whether the option is for NixOS developers only.
7676 internal ? null,
7777- # Whether the option shows up in the manual.
7777+ # Whether the option shows up in the manual. Default: true. Use false to hide the option and any sub-options from submodules. Use "shallow" to hide only sub-options.
7878 visible ? null,
7979 # Whether the option can be set only once
8080 readOnly ? null,
···180180 description = opt.description or (lib.warn "Option `${name}' has no description." "This option has no description.");
181181 declarations = filter (x: x != unknownModule) opt.declarations;
182182 internal = opt.internal or false;
183183- visible = opt.visible or true;
183183+ visible =
184184+ if (opt?visible && opt.visible == "shallow")
185185+ then true
186186+ else opt.visible or true;
184187 readOnly = opt.readOnly or false;
185188 type = opt.type.description or null;
186189 }
···192195 subOptions =
193196 let ss = opt.type.getSubOptions opt.loc;
194197 in if ss != {} then optionAttrSetToDocList' opt.loc ss else [];
198198+ subOptionsVisible = docOption.visible && opt.visible or null != "shallow";
195199 in
196196- [ docOption ] ++ optionals docOption.visible subOptions) (collect isOption options);
200200+ [ docOption ] ++ optionals subOptionsVisible subOptions) (collect isOption options);
197201198202199203 /* This function recursively removes all derivation attributes from
+7
lib/tests/modules.sh
···179179# which evaluates all the modules defined by the type)
180180checkConfigOutput "submodule" options.submodule.type.description ./declare-submoduleWith-modules.nix
181181182182+## submodules can be declared using (evalModules {...}).type
183183+checkConfigOutput "true" config.submodule.inner ./declare-submodule-via-evalModules.nix
184184+checkConfigOutput "true" config.submodule.outer ./declare-submodule-via-evalModules.nix
185185+# Should also be able to evaluate the type name (which evaluates freeformType,
186186+# which evaluates all the modules defined by the type)
187187+checkConfigOutput "submodule" options.submodule.type.description ./declare-submodule-via-evalModules.nix
188188+182189## Paths should be allowed as values and work as expected
183190checkConfigOutput "true" config.submodule.enable ./declare-submoduleWith-path.nix
184191
···505505 then setFunctionArgs (args: unify (value args)) (functionArgs value)
506506 else unify (if shorthandOnlyDefinesConfig then { config = value; } else value);
507507508508- allModules = defs: modules ++ imap1 (n: { value, file }:
508508+ allModules = defs: imap1 (n: { value, file }:
509509 if isAttrs value || isFunction value then
510510 # Annotate the value with the location of its definition for better error messages
511511 coerce (lib.modules.unifyModuleSyntax file "${toString file}-${toString n}") value
512512 else value
513513 ) defs;
514514515515- freeformType = (evalModules {
516516- inherit modules specialArgs;
517517- args.name = "‹name›";
518518- })._module.freeformType;
515515+ base = evalModules {
516516+ inherit specialArgs;
517517+ modules = [{
518518+ # This is a work-around for the fact that some sub-modules,
519519+ # such as the one included in an attribute set, expects an "args"
520520+ # attribute to be given to the sub-module. As the option
521521+ # evaluation does not have any specific attribute name yet, we
522522+ # provide a default for the documentation and the freeform type.
523523+ #
524524+ # This is necessary as some option declaration might use the
525525+ # "name" attribute given as argument of the submodule and use it
526526+ # as the default of option declarations.
527527+ #
528528+ # We use lookalike unicode single angle quotation marks because
529529+ # of the docbook transformation the options receive. In all uses
530530+ # > and < wouldn't be encoded correctly so the encoded values
531531+ # would be used, and use of `<` and `>` would break the XML document.
532532+ # It shouldn't cause an issue since this is cosmetic for the manual.
533533+ _module.args.name = lib.mkOptionDefault "‹name›";
534534+ }] ++ modules;
535535+ };
536536+537537+ freeformType = base._module.freeformType;
519538520539 in
521540 mkOptionType rec {
···523542 description = freeformType.description or name;
524543 check = x: isAttrs x || isFunction x || path.check x;
525544 merge = loc: defs:
526526- (evalModules {
527527- modules = allModules defs;
528528- inherit specialArgs;
529529- args.name = last loc;
545545+ (base.extendModules {
546546+ modules = [ { _module.args.name = last loc; } ] ++ allModules defs;
530547 prefix = loc;
531548 }).config;
532549 emptyValue = { value = {}; };
533533- getSubOptions = prefix: (evalModules
534534- { inherit modules prefix specialArgs;
535535- # This is a work-around due to the fact that some sub-modules,
536536- # such as the one included in an attribute set, expects a "args"
537537- # attribute to be given to the sub-module. As the option
538538- # evaluation does not have any specific attribute name, we
539539- # provide a default one for the documentation.
540540- #
541541- # This is mandatory as some option declaration might use the
542542- # "name" attribute given as argument of the submodule and use it
543543- # as the default of option declarations.
544544- #
545545- # Using lookalike unicode single angle quotation marks because
546546- # of the docbook transformation the options receive. In all uses
547547- # > and < wouldn't be encoded correctly so the encoded values
548548- # would be used, and use of `<` and `>` would break the XML document.
549549- # It shouldn't cause an issue since this is cosmetic for the manual.
550550- args.name = "‹name›";
551551- }).options // optionalAttrs (freeformType != null) {
550550+ getSubOptions = prefix: (base.extendModules
551551+ { inherit prefix; }).options // optionalAttrs (freeformType != null) {
552552 # Expose the sub options of the freeform type. Note that the option
553553 # discovery doesn't care about the attribute name used here, so this
554554 # is just to avoid conflicts with potential options from the submodule
+1-1
nixos/lib/eval-config.nix
···6161 args = extraArgs;
6262 specialArgs =
6363 { modulesPath = builtins.toString ../modules; } // specialArgs;
6464- }) config options _module;
6464+ }) config options _module type;
65656666 # These are the extra arguments passed to every module. In
6767 # particular, Nixpkgs is passed through the "pkgs" argument.
···2233{ name ? "${args.pname}-${args.version}"
44, enableParallelBuilding ? true
55+, doCheck ? false
56# Flags to pass to `makeWrapper`. This is done to avoid double wrapping.
67, makeWrapperArgs ? []
78···910, dotnetRestoreFlags ? []
1011# Flags to pass to `dotnet build`.
1112, dotnetBuildFlags ? []
1313+# Flags to pass to `dotnet test`, if running tests is enabled.
1414+, dotnetTestFlags ? []
1215# Flags to pass to `dotnet install`.
1316, dotnetInstallFlags ? []
1417# Flags to pass to dotnet in all phases.
···2730# These get wrapped into `LD_LIBRARY_PATH`.
2831, runtimeDeps ? []
29323333+# Tests to disable. This gets passed to `dotnet test --filter "FullyQualifiedName!={}"`, to ensure compatibility with all frameworks.
3434+# See https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-test#filter-option-details for more details.
3535+, disabledTests ? []
3636+# The project file to run unit tests against. This is usually the regular project file, but sometimes it needs to be manually set.
3737+, testProjectFile ? projectFile
3838+3039# The type of build to perform. This is passed to `dotnet` with the `--configuration` flag. Possible values are `Release`, `Debug`, etc.
3140, buildType ? "Release"
3241# The dotnet SDK to use.
3342, dotnet-sdk ? dotnetCorePackages.sdk_5_0
3443# The dotnet runtime to use.
3544, dotnet-runtime ? dotnetCorePackages.runtime_5_0
4545+# The dotnet SDK to run tests against. This can differentiate from the SDK compiled against.
4646+, dotnet-test-sdk ? dotnet-sdk
3647, ... } @ args:
37483849assert projectFile == null -> throw "Defining the `projectFile` attribute is required. This is usually an `.csproj`, or `.sln` file.";
···117128 "''${dotnetFlags[@]}"
118129119130 runHook postBuild
131131+ '';
132132+133133+ checkPhase = args.checkPhase or ''
134134+ runHook preCheck
135135+136136+ ${lib.getBin dotnet-test-sdk}/bin/dotnet test "$testProjectFile" \
137137+ -maxcpucount:${if enableParallelBuilding then "$NIX_BUILD_CORES" else "1"} \
138138+ -p:ContinuousIntegrationBuild=true \
139139+ -p:Deterministic=true \
140140+ --configuration "$buildType" \
141141+ --no-build \
142142+ --logger "console;verbosity=normal" \
143143+ ${lib.optionalString (disabledTests != []) "--filter \"FullyQualifiedName!=${lib.concatStringsSep "|FullyQualifiedName!=" disabledTests}\""} \
144144+ "''${dotnetTestFlags[@]}" \
145145+ "''${dotnetFlags[@]}"
146146+147147+ runHook postCheck
120148 '';
121149122150 installPhase = args.installPhase or ''