feat: add portable submodule type #11
No reviewers
Labels
No labels
Compat
Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: auxolotl/labs#11
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/portable-submodules"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
This change may not seem like a lot, but the implications of having such a type are pretty monumental. This is a generic, extracted version of the Package type in Tidepool. With this helper it is now possible to assign whole submodule definitions to other locations in the configuration, bringing along all options and avoiding issues with otherwise preevaluated defaults.
A primary issue this fixed is one where you have two options of the same submodule type. Imagine you want to assign the value of
config.a
toconfig.b
. Well,config.a
has been evaluated and results in an attribute set full of its final config, including default values. So when you assignconfig.b = config.a
these old default values then become non-default overrides, making computed options no longer work. However, by re-evaluating the set of submodules (the config froma
and the submodule definition itself) we are able to recompute these dynamic pieces!Assignment
Notably, this type is pretty flexible in how it lets users interact with it. There are two different ways that the value may be set:
A user can operate on this submodule just like any other, setting values like the following:
The attribute set assigned to
config.a
is then transformed into a full module definition, containing the user's configuration:This module is then evaluated with all of the other definitions at this location and added to the submodule's
__modules__
list to propagate. The resulting value is the full evaluation of all these submodules:An existing portable submodule value can be assigned to another location of the same type:
The submodule's
__modules__
attribute will be detected and used directly. These modules are combined with the existing modules at this location and are evaluated just like before, producing the final value:Extension
It is quite common that you will want to use most of the values of a submodule, but you want to also modify a portion of it. Without any additional helper, this would require the use of
lib.modules.merge
to leverage the portable submodule type's merging behavior. However, this can be a bit cumbersome and we can remove the boilerplate by providing anextend
helper. This function takes a module (or direct configuration) and returns a newly evaluated portable with the__modules__
list updated.This results in the following value for
config.b
:Extension allows you to assign and operate on the values in one place rather than having to provide a list of definitions to merge.
Love this ! I got hit by this when fleshing out mudenv (though I eventually took another approach).
Any reason why to keep them separate from
lib.types.submodule
/lib.types.submodules.of
? Assuming portable submodules are strictly more powerful, I don't see why we'd want to keep "non-portable" submodules around - unless I'm wrong and there's trade-offs between both.Checkout
From your project repository, check out a new branch and test the changes.Merge
Merge the changes and update on Forgejo.