-
-
Notifications
You must be signed in to change notification settings - Fork 16.6k
Contracts RFC 189 #432529
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Contracts RFC 189 #432529
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please forgive me for a superficial first review and coming up with proofreading stuff, but maybe there's already something useful in here.
Can't say particularly much about the broad design yet but I hope I've sprinkled a bit of useful info in there.
I'd like to do a more in depth review later.
inherit (lib) mkOption; | ||
inherit (lib.types) attrs attrsOf functionTo submodule listOf str deferredModule optionType; | ||
in | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this get loaded into NixOS itself (_class = "nixos";
), or evalModules
, or anywhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was assuming adding it to module-list.nix
is enough?
nixos/modules/contracts/default.nix
Outdated
To use the `<name>` contract, create an option with either the | ||
`config.contracts.<name>.consumer` or `config.contracts.<name>.provider` | ||
type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure yet what "create an option" means here. Probably not declare an option?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed create is vague, declare seems more appropriate: one would declare an option with the type config.contracts.<name>.consumer
since that is of type optionType
. Do you see another word?
}; | ||
|
||
meta.buildDocsInSandbox = false; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thought: Neither of the backup contracts covers any scheduling of backups or integration with file system snapshots. Maybe that's ok for now, or should be covered by something else anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Contracts are for communication between the consumer and provider, without the end user intervention. I see the file backup contract here only useful for the consumer to tell what files should be backed up or not.
On the other hand, I see scheduling as the end user communicating with the provider directly. I could see a need for a common interface for scheduling though. So maybe a separate contract for that?
Now I could be wrong and there is a valid use case for the consumer having a say in the scheduling, I just did not cross it yet.
# Instead, I made a hacky import. pkgs.callPackage was also giving an | ||
# infinite recursion. | ||
# | ||
# } // config.contracts.fileBackup.behaviorTest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct, the module attrset must not be strict in (require evaluation of) config
or even options
.
Maybe imports
could be useful here? Not sure I see "a hacky import".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just assumed using import this way was more hacky or at least less favorable than relying on config.
- build manual: `(cd nixos/; nix-build release.nix -A manual.x86_64-linux)`
b869e9e
to
19d98a5
Compare
This commit makes the manual impossible to build. I understand the reason but do not know how to fix it.
Tests succeed: - nix-build -A nixosTests.contracts-fileBackup-restic - nix-build -A nixosTests.restic
Tests succeed: - nix-build -A nixosTests.contracts-fileBackup-restic - nix-build -A nixosTests.contracts-streamingBackup-restic - nix-build -A nixosTests.restic
19d98a5
to
806da47
Compare
@@ -47,6 +47,10 @@ | |||
./config/xdg/sounds.nix | |||
./config/xdg/terminal-exec.nix | |||
./config/zram.nix | |||
./contracts/default.nix |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for the record, despite this line the error i get building the manual ((cd nixos/; nix-build release.nix -A manual.x86_64-linux)
) is:
error:
… while calling the 'deepSeq' builtin
at /home/kiara/code/nixpkgs/lib/customisation.nix:478:35:
477| in
478| if drv == null then null else deepSeq drv' drv';
| ^
479|
… while evaluating the attribute 'outPath'
at /home/kiara/code/nixpkgs/lib/customisation.nix:467:13:
466| value = commonAttrs // {
467| outPath = output.outPath;
| ^
468| drvPath = output.drvPath;
(stack trace truncated; use '--show-trace' to show the full trace)
error: attribute 'contracts' missing
at /home/kiara/code/nixpkgs/nixos/modules/services/web-apps/stash.nix:435:16:
434| jwtSecretKeyFile = mkOption {
435| type = config.contracts.secret.consumer;
| ^
436| description = "Path to file containing a secret used to sign JWT tokens.";
not sure how this happened.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed I get the same. I guess only the options attribute is populated at this point, not the config?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm, config
seems introspected at plenty other tests tho?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not in the type field as far as I grepped.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that explanation seems to add up, given after commenting those lines the error seems to change:
details
~/code/nixpkgs> nix-build nixos/release.nix -A manual.x86_64-linux
these 3 derivations will be built:
/nix/store/vinkj8blr6mrsy2k5z8lk0n6i11l3vjj-lazy-options.json.drv
/nix/store/qzykfx31izdzq9c2inyvpm48xxm07x1n-options.json.drv
/nix/store/29xq1kdbafpar7v70zwag14l73cigwa8-nixos-manual-html.drv
these 12 paths will be fetched (14.00 MiB download, 49.57 MiB unpacked):
/nix/store/a8s3qf5ydqbpqcshg1dgga9lag3xgbbp-brotli-1.1.0
/nix/store/lnab2vg7mcwddh63rimw1vh82nplzsxj-brotli-1.1.0-dev
/nix/store/7bcdsr7fykhji6dy8gq8jzd8qjswf13v-documentation-highlighter
/nix/store/my02p81al90i4anmaz79ad98a397zrri-nixos-render-docs-0.0
/nix/store/8d4pij8ir718s90cj8yrhhrxd5pc81bw-nixos-test-driver-docstrings
/nix/store/fgx655d67ry55jw7dddmb49avywqkvyb-options.json
/nix/store/lk0mhvqjffjx087p8wlwf71agdkz71ha-options.json
/nix/store/xiw440bqysi2p7dr375nca54in97b0vi-options.json
/nix/store/58dmrdsib24m3468d9n5s7g9g2gcgqmg-python3.13-markdown-it-py-3.0.0
/nix/store/kiyxdnmd5j4b5i124imq8jcgh4zgcrwq-python3.13-mdit-py-plugins-0.4.2
/nix/store/aa0shvk4589im4w2wsq5qxiws381q9k8-python3.13-mdurl-0.1.2
/nix/store/7i6x1w92r7njk1fvmq2fwhz7fjsd26pa-source
copying path '/nix/store/7bcdsr7fykhji6dy8gq8jzd8qjswf13v-documentation-highlighter' from 'https://cache.nixos.org'...
copying path '/nix/store/8d4pij8ir718s90cj8yrhhrxd5pc81bw-nixos-test-driver-docstrings' from 'https://cache.nixos.org'...
copying path '/nix/store/fgx655d67ry55jw7dddmb49avywqkvyb-options.json' from 'https://cache.nixos.org'...
copying path '/nix/store/lk0mhvqjffjx087p8wlwf71agdkz71ha-options.json' from 'https://cache.nixos.org'...
copying path '/nix/store/xiw440bqysi2p7dr375nca54in97b0vi-options.json' from 'https://cache.nixos.org'...
copying path '/nix/store/7i6x1w92r7njk1fvmq2fwhz7fjsd26pa-source' from 'https://cache.nixos.org'...
copying path '/nix/store/aa0shvk4589im4w2wsq5qxiws381q9k8-python3.13-mdurl-0.1.2' from 'https://cache.nixos.org'...
copying path '/nix/store/a8s3qf5ydqbpqcshg1dgga9lag3xgbbp-brotli-1.1.0' from 'https://cache.nixos.org'...
building '/nix/store/vinkj8blr6mrsy2k5z8lk0n6i11l3vjj-lazy-options.json.drv'...
copying path '/nix/store/58dmrdsib24m3468d9n5s7g9g2gcgqmg-python3.13-markdown-it-py-3.0.0' from 'https://cache.nixos.org'...
copying path '/nix/store/lnab2vg7mcwddh63rimw1vh82nplzsxj-brotli-1.1.0-dev' from 'https://cache.nixos.org'...
copying path '/nix/store/kiyxdnmd5j4b5i124imq8jcgh4zgcrwq-python3.13-mdit-py-plugins-0.4.2' from 'https://cache.nixos.org'...
error:
… from call site
at /nix/store/349j6vlcdmf2a2xv0vz4mq7yb6wix7ql-nixos/lib/eval-cacheable-options.nix:1:1:
1| {
| ^
2| libPath,
… while calling anonymous lambda
at /nix/store/349j6vlcdmf2a2xv0vz4mq7yb6wix7ql-nixos/lib/eval-cacheable-options.nix:1:1:
1| {
| ^
2| libPath,
… while evaluating the attribute 'optionsNix'
at /nix/store/349j6vlcdmf2a2xv0vz4mq7yb6wix7ql-nixos/doc/manual/default.nix:158:36:
157| rec {
158| inherit (optionsDoc) optionsJSON optionsNix optionsDocBook;
| ^
159|
… while evaluating the attribute 'optionsNix'
at /nix/store/349j6vlcdmf2a2xv0vz4mq7yb6wix7ql-nixos/lib/make-options-doc/default.nix:180:11:
179| rec {
180| inherit optionsNix;
| ^
181|
… while calling the 'listToAttrs' builtin
at /nix/store/349j6vlcdmf2a2xv0vz4mq7yb6wix7ql-nixos/lib/make-options-doc/default.nix:167:16:
166|
167| optionsNix = builtins.listToAttrs (
| ^
168| map (o: {
… while calling the 'map' builtin
at /nix/store/349j6vlcdmf2a2xv0vz4mq7yb6wix7ql-nixos/lib/make-options-doc/default.nix:168:5:
167| optionsNix = builtins.listToAttrs (
168| map (o: {
| ^
169| name = o.name;
… from call site
at /nix/store/349j6vlcdmf2a2xv0vz4mq7yb6wix7ql-nixos/lib/make-options-doc/default.nix:120:17:
119| filteredOpts = lib.filter (opt: opt.visible && !opt.internal) transformedOpts;
120| optionsList = lib.flip map filteredOpts (
| ^
121| opt:
… while calling 'flip'
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/trivial.nix:306:11:
305| flip =
306| f: a: b:
| ^
307| f b a;
… while calling the 'map' builtin
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/trivial.nix:307:5:
306| f: a: b:
307| f b a;
| ^
308|
… while calling the 'filter' builtin
at /nix/store/349j6vlcdmf2a2xv0vz4mq7yb6wix7ql-nixos/lib/make-options-doc/default.nix:119:18:
118| transformedOpts = map transformOptions rawOpts;
119| filteredOpts = lib.filter (opt: opt.visible && !opt.internal) transformedOpts;
| ^
120| optionsList = lib.flip map filteredOpts (
… while calling the 'map' builtin
at /nix/store/349j6vlcdmf2a2xv0vz4mq7yb6wix7ql-nixos/lib/make-options-doc/default.nix:118:21:
117| rawOpts = lib.optionAttrSetToDocList options;
118| transformedOpts = map transformOptions rawOpts;
| ^
119| filteredOpts = lib.filter (opt: opt.visible && !opt.internal) transformedOpts;
… from call site
at /nix/store/349j6vlcdmf2a2xv0vz4mq7yb6wix7ql-nixos/lib/make-options-doc/default.nix:117:13:
116| let
117| rawOpts = lib.optionAttrSetToDocList options;
| ^
118| transformedOpts = map transformOptions rawOpts;
… while calling 'optionAttrSetToDocList''
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/options.nix:570:8:
569| optionAttrSetToDocList' =
570| _: options:
| ^
571| concatMap (
… while calling the 'concatMap' builtin
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/options.nix:571:5:
570| _: options:
571| concatMap (
| ^
572| opt:
… from call site
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/options.nix:609:8:
608| [ docOption ] ++ optionals subOptionsVisible subOptions
609| ) (collect isOption options);
| ^
610|
… while calling 'collect'
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/attrsets.nix:866:11:
865| collect =
866| pred: attrs:
| ^
867| if pred attrs then
… while calling the 'concatMap' builtin
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/attrsets.nix:870:7:
869| else if isAttrs attrs then
870| concatMap (collect pred) (attrValues attrs)
| ^
871| else
… while calling 'collect'
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/attrsets.nix:866:11:
865| collect =
866| pred: attrs:
| ^
867| if pred attrs then
… while calling the 'concatMap' builtin
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/attrsets.nix:870:7:
869| else if isAttrs attrs then
870| concatMap (collect pred) (attrValues attrs)
| ^
871| else
… while calling 'collect'
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/attrsets.nix:866:11:
865| collect =
866| pred: attrs:
| ^
867| if pred attrs then
… while calling the 'concatMap' builtin
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/attrsets.nix:870:7:
869| else if isAttrs attrs then
870| concatMap (collect pred) (attrValues attrs)
| ^
871| else
… while calling 'collect'
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/attrsets.nix:866:11:
865| collect =
866| pred: attrs:
| ^
867| if pred attrs then
… while evaluating a branch condition
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/attrsets.nix:867:5:
866| pred: attrs:
867| if pred attrs then
| ^
868| [ attrs ]
… from call site
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/attrsets.nix:867:8:
866| pred: attrs:
867| if pred attrs then
| ^
868| [ attrs ]
… while calling 'isType'
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/types.nix:103:20:
102| outer_types = rec {
103| isType = type: x: (x._type or "") == type;
| ^
104|
… from call site
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/types.nix:103:24:
102| outer_types = rec {
103| isType = type: x: (x._type or "") == type;
| ^
104|
… while calling anonymous lambda
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/modules.nix:854:37:
853|
854| matchedOptions = mapAttrs (n: v: v.matchedOptions) resultsByName;
| ^
855|
… while evaluating the attribute 'matchedOptions'
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/modules.nix:820:13:
819| {
820| matchedOptions = evalOptionValue loc opt defns';
| ^
821| unmatchedDefns = [ ];
… from call site
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/modules.nix:820:30:
819| {
820| matchedOptions = evalOptionValue loc opt defns';
| ^
821| unmatchedDefns = [ ];
… while calling 'evalOptionValue'
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/modules.nix:1052:15:
1051| evalOptionValue =
1052| loc: opt: defs:
| ^
1053| let
… in the left operand of the update (//) operator
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/modules.nix:1090:5:
1089| warnDeprecation opt
1090| // {
| ^
1091| value = addErrorContext "while evaluating the option `${showOption loc}':" value;
… from call site
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/modules.nix:1085:9:
1084| warnDeprecation =
1085| warnIf (opt.type.deprecationMessage != null)
| ^
1086| "The type `types.${opt.type.name}' of option `${showOption loc}' defined in ${showFiles opt.declarations} is deprecated. ${opt.type.deprecationMessage}";
… while calling 'warnIf'
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/trivial.nix:825:18:
824| */
825| warnIf = cond: msg: if cond then warn msg else x: x;
| ^
826|
… while evaluating a branch condition
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/trivial.nix:825:23:
824| */
825| warnIf = cond: msg: if cond then warn msg else x: x;
| ^
826|
… from call site
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/modules.nix:817:19:
816| let
817| opt = fixupOptionType loc (mergeOptionDecls loc decls);
| ^
818| in
… while calling 'fixupOptionType'
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/modules.nix:1296:10:
1295| fixupOptionType =
1296| loc: opt:
| ^
1297| if opt.type.getSubModules or null == null then
… while evaluating a branch condition
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/modules.nix:1297:5:
1296| loc: opt:
1297| if opt.type.getSubModules or null == null then
| ^
1298| opt // { type = opt.type or types.unspecified; }
… from call site
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/modules.nix:817:40:
816| let
817| opt = fixupOptionType loc (mergeOptionDecls loc decls);
| ^
818| in
… while calling 'mergeOptionDecls'
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/modules.nix:940:10:
939| mergeOptionDecls =
940| loc: opts:
| ^
941| foldl'
… while calling the 'foldl'' builtin
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/modules.nix:941:5:
940| loc: opts:
941| foldl'
| ^
942| (
… while calling anonymous lambda
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/modules.nix:943:14:
942| (
943| res: opt:
| ^
944| let
… in the right operand of the update (//) operator
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/modules.nix:1001:11:
1000| opt.options
1001| // res
| ^
1002| // {
… in the right operand of the update (//) operator
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/modules.nix:1002:11:
1001| // res
1002| // {
| ^
1003| declarations = res.declarations ++ [ opt._file ];
… in the right operand of the update (//) operator
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/modules.nix:1023:11:
1022| }
1023| // typeSet
| ^
1024| )
… while evaluating a branch condition
at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/modules.nix:978:20:
977| "The option `${showOption loc}' in `${opt._file}' is already declared in ${showFiles res.declarations}."
978| else if opt.options.type ? functor.wrappedDeprecationMessage then
| ^
979| { type = addDeprecatedWrapped opt.options.type; }
… while evaluating the attribute 'options.type'
at /nix/store/349j6vlcdmf2a2xv0vz4mq7yb6wix7ql-nixos/modules/services/web-apps/nextcloud.nix:1024:7:
1023| fileBackup = lib.mkOption {
1024| type = config.contracts.fileBackup.consumer;
| ^
1025| };
error: attribute 'contracts' missing
at /nix/store/349j6vlcdmf2a2xv0vz4mq7yb6wix7ql-nixos/modules/services/web-apps/nextcloud.nix:1024:14:
1023| fileBackup = lib.mkOption {
1024| type = config.contracts.fileBackup.consumer;
| ^
1025| };
Cacheable portion of option doc build failed.
Usually this means that an option attribute that ends up in documentation (eg `default` or `description`) depends on the restricted module arguments `config` or `pkgs`.
Rebuild your configuration with `--show-trace` to find the offending location. Remove the references to restricted arguments (eg by escaping their antiquotations or adding a `defaultText`) or disable the sandboxed build for the failing module by setting `meta.buildDocsInSandbox = false`.
error: builder for '/nix/store/vinkj8blr6mrsy2k5z8lk0n6i11l3vjj-lazy-options.json.drv' failed with exit code 1;
last 25 log lines:
> … while evaluating a branch condition
> at /nix/store/xq9gm26vql7v1d7alaq4q20fvr5rgaw7-lib/modules.nix:978:20:
> 977| "The option `${showOption loc}' in `${opt._file}' is already declared in ${showFiles res.declarations}."
> 978| else if opt.options.type ? functor.wrappedDeprecationMessage then
> | ^
> 979| { type = addDeprecatedWrapped opt.options.type; }
>
> … while evaluating the attribute 'options.type'
> at /nix/store/349j6vlcdmf2a2xv0vz4mq7yb6wix7ql-nixos/modules/services/web-apps/nextcloud.nix:1024:7:
> 1023| fileBackup = lib.mkOption {
> 1024| type = config.contracts.fileBackup.consumer;
> | ^
> 1025| };
>
> error: attribute 'contracts' missing
> at /nix/store/349j6vlcdmf2a2xv0vz4mq7yb6wix7ql-nixos/modules/services/web-apps/nextcloud.nix:1024:14:
> 1023| fileBackup = lib.mkOption {
> 1024| type = config.contracts.fileBackup.consumer;
> | ^
> 1025| };
> Cacheable portion of option doc build failed.
> Usually this means that an option attribute that ends up in documentation (eg `default` or `description`) depends on the restricted module arguments `config` or `pkgs`.
>
> Rebuild your configuration with `--show-trace` to find the offending location. Remove the references to restricted arguments (eg by escaping their antiquotations or adding a `defaultText`) or disable the sandboxed build for the failing module by setting `meta.buildDocsInSandbox = false`.
>
For full logs, run 'nix log /nix/store/vinkj8blr6mrsy2k5z8lk0n6i11l3vjj-lazy-options.json.drv'.
error: 1 dependencies of derivation '/nix/store/qzykfx31izdzq9c2inyvpm48xxm07x1n-options.json.drv' failed to build
error: 1 dependencies of derivation '/nix/store/29xq1kdbafpar7v70zwag14l73cigwa8-nixos-manual-html.drv' failed to build
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also the usual escape hatch of adding defaultText does not work here. There should be an equivalent defaultType 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@roberth thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Btw I’m not opposed at all to try to fix something in the eval modules code but I’d love some guidance as of at least is it the correct thing to do. That’s also why I published the RFC as-is, I just didn’t know what to do.
Same for the other issues like the one where the documentation does not build.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Normally config
is available, but NixOS also uses split evaluation for docs, making that... complicated.
Maybe some meta.buildInSandbox = false
can help?
nixpkgs/nixos/modules/misc/meta.nix
Lines 69 to 82 in 160ee19
buildDocsInSandbox = lib.mkOption { | |
type = lib.types.bool // { | |
merge = loc: defs: defs; | |
}; | |
internal = true; | |
default = true; | |
description = '' | |
Whether to include this module in the split options doc build. | |
Disable if the module references `config`, `pkgs` or other module | |
arguments that cannot be evaluated as constants. | |
This option should be defined at most once per module. | |
''; | |
}; |
passwordFile = toString (pkgs.writeText "password" "password"); | ||
initialize = true; | ||
|
||
fileBackup.consumer = config.services.nextcloud.fileBackup; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
on this dual link, my hunch would be to maybe instead have nixos/modules/services/web-apps/nextcloud.nix
add config.contracts.fileBackup.consumer.provider.consumer = cfg.fileBackup;
.
this yielded an infinite recursion tho, that seems to say is that this would make the consumer's type depend on the value of the consumer itself.
… while evaluating the option `nodes.nextcloud.contracts.fileBackup.consumer':
138| default = provider.config.consumer.input or null;
| ^
at /home/kiara/code/nixpkgs/nixos/modules/contracts/default.nix:132:45:
132| type = lib.types.nullOr interface.config.consumer;
| ^
… while evaluating the option `nodes.nextcloud.contracts.fileBackup.consumer':
at /home/kiara/code/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix:1567:57:
1567| contracts.fileBackup.consumer.provider.consumer = cfg.fileBackup;
| ^
… while evaluating the attribute 'options.type'
at /home/kiara/code/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix:1024:7:
1024| type = config.contracts.fileBackup.consumer;
| ^
...
error: infinite recursion encountered
making it `config.contracts.fileBackup.provider.consumer = cfg.fileBackup;` instead similarly yielded an infinite recursion, that i think says the provider's type would depend on the provider's own value.
at /home/kiara/code/nixpkgs/nixos/modules/services/backup/restic.nix:307:39:
307| type = lib.types.nullOr config.contracts.fileBackup.provider;
| ^
… while evaluating the option `nodes.nextcloud.contracts.fileBackup.provider':
at /home/kiara/code/nixpkgs/nixos/modules/contracts/default.nix:98:31:
98| default = consumer.config.provider.output;
| ^
at /home/kiara/code/nixpkgs/nixos/modules/contracts/default.nix:90:28:
90| type = interface.config.provider;
| ^
so hm, looks like i've mostly reproduced your infinite recursion issues so far.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, this has two downsides:
- It requires one more line in each provider definition. This would be okay if there wasn't the following downside.
- There's no way to write side effects. This means the provider can only write to its own output, which misses the whole point of having contracts in the first place.
so, @fricklerhandwerk was right on needing to type effects, huh.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to be fair, the primary effect relevant here so far (back-ups, secrets, SSL) would seem to be 'in addition to having input/output, will write to these file paths'?
like i'm not sure that'd already cover further contracts such as reverse proxying, but maybe it'd help scope things for the example in this PR.
Let me just second @roberth that this should absolutely leverage Modular Services (#428084). Modular services removes us from "singleton" hell making the interface / instance distinction much clearer. (In contrast, if you only have a single "PostgreSQL", for example, it is much harder to learn the difference between "the PostgresSQL module interface" (contract) an "a PostgresSQL instance", because all there is the "the PostgresSQL instance".) |
How would this work even, wouldn't this change a lot of the RFC as its implemented right now? |
Draft PR showing implementation of the Contracts RFC-189 as well as 3 contracts example. From this PR, only the
nixos/modules/contracts/default.nix
would be merged as part of the RFC. The rest would happen later.It is intended to be reviewed after reading the RFC document and also commit by commit.
(cd nixos/; nix-build release.nix -A manual.x86_64-linux)
(does not work yet)nix-build -A nixosTests.contracts-fileBackup-restic
nix-build -A nixosTests.contracts-secret-hardcodedSecret
nix-build -A nixosTests.contracts-streamingBackup-restic
nix-build -A nixosTests.restic
nix-build -A nixosTests.stash
Open questions:
Things done
passthru.tests
.nixpkgs-review
on this PR. See nixpkgs-review usage../result/bin/
.Add a 👍 reaction to pull requests you find important.