-
-
Notifications
You must be signed in to change notification settings - Fork 13.7k
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
lib.types: init attrsWith #344216
base: master
Are you sure you want to change the base?
lib.types: init attrsWith #344216
Conversation
0e279d8
to
52f296e
Compare
LGTM |
8176af5
to
e4f51be
Compare
Seems like a wasted opportunity actually. The type could accept a function from name to type so you really have a name, that you can even feed into the submodule specialArgs using a different name name, etc. Anyway, I guess what I'm getting at is that the attrs types should be factored into a single more capable function, because this property is not mutually exclusive with the other property about laziness ( See also I'll add that to the description as well, because this would close that. |
So before i start factoring this, and make sure the checks pass. Do you mean something like this? # Interface
# elemTypeFn :: String -> OptionType
namedAttrsOf = attrName: elemTypeFn: mkOptionType rec {
# ...
} # Simple Usage with submodule taking a function itself
# I choose username as concrete name name here.
# Couldn't make up a nice name for `namedAttr` but `name` is probably bad, since it already used in types.submodule in a different way.
mkOption {
type = namedAttrsOf "username" (attrName: submoduleWith {
specialArgs = {
inherit attrName;
};
modules = [
# ... other modules receiving the name
];
}
);
}; |
I was thinking something along the lines of attrsWith {
name = "username";
itemType = submoduleWith { modules = [ <...> ]; };
# or, perhaps later:
# itemTypeFunction = name: submoduleWith { modules = f name; specialArgs = g name; };
# and perhaps later:
# lazy = true;
}; This is more extensible and will let us cover Also, instead of |
d8d8643
to
6432843
Compare
6432843
to
dc45ca2
Compare
@roberth okay. I refactored everthing accordingly. Lets see if all checks pass. Also when looking at the usage. It might be more consistent if we name
|
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.
In summary
- This would be a good opportunity to fix
showOption
properly - Some microoptimization
# If the part is a named placeholder of the form "<...>" don't escape it. | ||
# Required for compatibility with: namedAttrsOf | ||
# Can lead to misleading escaping if somebody uses literally "<...>" in their option names. | ||
# This is the trade-off to allow for named placeholders in option names. |
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.
Right, we actually have two types of option paths: abstract ones containing placeholders, and real ones that are just data.
Treating them the same isn't quite correct, and merging a workaround could complicate a real fix.
Also note that some of these path items are not module options but attrsOf attributes, and "*"
will occur as an attribute name in certain configurations to represent a "pattern" that matches everything; for example when an HTTP server doesn't responds for an unknown virtual host, etc.
We could solve this in at least two ways
a. Leave the "option path" type as is, but use two functions
- leave
showOption
as is, suitable for concrete option paths - add
showAbstractOption
, which implements these new rules
b. Only improve the representation - represent abstract path items with a value like
{ _type = "optionPathPlaceholder"; metaVariable = "name"; __toString = this: "<${this.metaVariable}>"; }
I think (b) may have good backward compatibility and it solves the problem for module options; not just attrsOf keys.
__toString
is mostly for compatibility with existing code that kind of works when a placeholder string is passed. This happens when generating option docs.
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.
This is pre-existing tech debt, so while this is a good opportunity to fix it before making it slightly worse, perhaps this should be done in a follow-up PR instead.
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'd prefer to do this in a follow up PR if you are okay with it. Should i remove the changes from this one?
expr = lib.showOption ["<name>" "<myName>" "*" "{foo}"]; | ||
expected = "<name>.<myName>.*.\"{foo}\""; | ||
}; | ||
|
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.
Thanks for writing tests ❤️
I'd swear I've tested using optionAttrSetToDocList
before, but that must have been on an unmerged PR or external project. Anyway, it'd be good to also test this in a more end-to-end way. You can keep the tests you already wrote.
expr = lib.showOption ["<name>" "<myName>" "*" "{foo}"]; | ||
expected = "<name>.<myName>.*.\"{foo}\""; | ||
}; | ||
|
||
testCartesianProductOfEmptySet = { |
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:
Most of the tests are in lib/tests/modules{,.sh}
.
We should put all module system tests in one place. (but not in this PR)
}: | ||
let | ||
typeName = "attrsOf"; | ||
lazyMergeFn = loc: defs: |
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.
Inlining single-use bindings and constants saves a small amount of evaluator memory every time this type is instantiated.
Not refactoring these two merge functions into a single one is good, removing a conditional from the hot path.
So I think the most efficient way to do this is to inline mergeFn
and lazyMergeFn
, but then leave their implementations exactly as they are.
Description of changes
Unify the code path between
attrsOf
andlazyAtrrsOf
lazy = true
to receive set lazy type"<name>"
placeholder for option docs. This is particularly useful when"<name>"
doesn't make sense or when dealing with nested attrsOf submodule. Which would yield"<name>.<name>"
Apart from that everything should behave the same.
I first tried to wrap the attrsOf type and only override
getSubOptions
with a function taking a custom prefix. But it seems i am missing something.Context
<name>
as prefix intypes.attrsOf types.submodule
is often unhelpful #295872Things done
nix.conf
? (See Nix manual)sandbox = relaxed
sandbox = true
nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD"
. Note: all changes have to be committed, also see nixpkgs-review usage./result/bin/
)Add a 👍 reaction to pull requests you find important.