-
Notifications
You must be signed in to change notification settings - Fork 3
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
Retool how validators register and are called: everything's a tag! #89
Retool how validators register and are called: everything's a tag! #89
Conversation
5165747
to
ca520e4
Compare
For giggles I added some WIP commits to make This probably could have been simpler, and list-map could be treated "specially" (with info passed to validators), but I wanted to see if I could do it functional-style. It sorta works. There are some issues around pointerness, still, and it's not as understandable as I'd like, but I think you can get the idea. Basically there's a family of list-oriented validators which work together to collect info about keys and then extract old values when we can. The big remaining problem is that tags are discovered in sort-order, which means that
If we like the approach, we can see how subfield would work, too. |
ca520e4
to
4e424a7
Compare
For more giggles, I made I can't yet reverse that, until I convert subfield to a regular tag. |
2d63642
to
0cc2ffa
Compare
staging/src/k8s.io/code-generator/cmd/validation-gen/validators/registry.go
Outdated
Show resolved
Hide resolved
staging/src/k8s.io/code-generator/cmd/validation-gen/validators/options.go
Outdated
Show resolved
Hide resolved
staging/src/k8s.io/code-generator/cmd/validation-gen/validators/validators.go
Outdated
Show resolved
Hide resolved
188a158
to
cb73101
Compare
I've caught up on the commits. I'll put some comments in the code, but would like to start with some high level thoughts: The improvements to how validators are registered and how context scopes are checked all looks great. Separating out TypeValidators looks fine. Unions are the only tag we have (that I'm aware of) that needs to inspect multiple tags. Re: Making I do wonder if we're doing to end up needing a third pass to make this all clean? Currently we have:
Unless we add more passes and intermediate data structures, any validation specific code in
This would allow discovery pass to be fully generalized to use with other generators, while still giving us a data structure that we can use to fully represent the validation code that we'd like to emit. I don't think we should hold this PR up on this idea. But this seems like a good place to discuss the longer term goals. |
ACK the sentiment! I think the intermediate that you are looking for is ultimately going to be the "iptables" version of this. Since discussion on Friday, I have been thinking a lot about it, and I think I see how to get there, but I want to focus on delivering SOMETHING before retooling it all again. I think this "regularity" of tags helps. I have spent some time hacking on weekend, cleaning up the output tests for tags (found some bugs!!) and when I am done witht htat I will rip out all the now unused generator code, but in discovery and emit passes. I think the result will make it plain how we can proceed. |
Cleanup and tests will be in subsequent commits.
Cleanup and tests will be in subsequent commits.
Cleanup and tests will be in subsequent commits.
Upon trying to clean up the now obsolete builti-in code, I realized I had totally missed the non-tag iteration of lists (e.g. calling the type-validation func for each item). Fixing that was deeper than I expected. After this: - the eachVal/eachKey validators expose a helper function for use by main generation code (they are special). - discover() looks for the case of aliases to maps/slices and adds type-validation calls to "for each" the key/val types' validation funcs. - discoverStruct() does the same for map/slice fields - discoverAlias() is gone, it had been reduced to ~5 LOC and a comment. - all built-in iteration logic is gone, in favor of the eachVal and eachKey tag logic - safe.NewListMap is gone - hasValidations() is now a global rather than only available to generation-phase (with hazard documented) - the last built-in tag is gone - Some edge cases we just don't support (because it's hard and we don't need them): - alias to pointer - pointer to alias of slide/map/pointer I went through all the test differences and made sure they made sense. In hindsight, these issues should have been obvious in earlier commits. There's still some room for cleanup after this.
34faa1e
to
45c00a6
Compare
LGTM I'm all caught up. This is excellent progress. Let's iterate on the dev branch from here |
Hi, sry to borther! I came across this PR and I'm interested in this topic. Is there any KEP that provides background information on it? |
Hi @caozhuozi , you can check on kubernetes/enhancements#5074 . Thanks for your interests. |
@yongruilin Thank you!! |
Looking at how to not fail silently when tags are used wrong. I started adding more lint rules for things like "you can't use +optional on a type". It struck me that this is something that should be handled more first-class, rather than ex post facto. We will inevitably forget to add the lint rules for some tags.
We have the tag docs struct which includes a "contexts" list, which indicates when a tag is usable. I tried automating that check as a lint rule and it's not ideal as-is. It also highlighted that most of our tag docs are just WRONG (cargo culted) and that the context definitions we have are not really great.
Examples:
Lastly, each ExtractValidations() call doesn't have enough information to DTRT even if we fixed the above.
This PR started with expanding the contexts to distinguish struct-fields from list/map keys/values. It evolved into a different way of approaching tags.
Rather than each plugin's
ExtractValidations()
being responsible for checking that it is used in an appropriate context (and getting new args to indicate the extra information), I tried to do something a little more "scaffolding" centric. It changes the init sequence to register validators which include the tag string and contexts (basically the docs struct, but more fine-grained), but also having generic code look up the tags, ensure correct context, and then call a method to produce the specific FunctionGen objects.Basically, centralize the tag-processing. Now generation will fail with errors like:
or
...but the
optional
plugin didn't have to do the work. Some plugins still need to do work, like if they only apply to strings, but that seems OK to me.This PR includes all my commits, even when later commits undo or change part of it, so readers can see the thought process. In particular, this centralized tag handling is insufficient for things like
union
which needs to run on the TYPE, but the tags are on FIELDs.Now there are "tag validators" and "type validators" (which run AFTER child fields). Union has tag handlers that are used to validate context (e.g. "+union only applies to struct fields") and accumulate info, and a type handler which uses the accumulated info.
I wanted to move registry to a different package, but to avoid a circular dep, it has to become 3 packages, and it didn't seem worthwhile.