| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- /*
- Copyright 2019 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package markers
- import (
- "fmt"
- "sync"
- )
- // Registry keeps track of registered definitions, and allows for easy lookup.
- // It's thread-safe, and the zero-value can be safely used.
- type Registry struct {
- forPkg map[string]*Definition
- forType map[string]*Definition
- forField map[string]*Definition
- helpFor map[*Definition]*DefinitionHelp
- mu sync.RWMutex
- initOnce sync.Once
- }
- func (r *Registry) init() {
- r.initOnce.Do(func() {
- if r.forPkg == nil {
- r.forPkg = make(map[string]*Definition)
- }
- if r.forType == nil {
- r.forType = make(map[string]*Definition)
- }
- if r.forField == nil {
- r.forField = make(map[string]*Definition)
- }
- if r.helpFor == nil {
- r.helpFor = make(map[*Definition]*DefinitionHelp)
- }
- })
- }
- // Define defines a new marker with the given name, target, and output type.
- // It's a shortcut around
- // r.Register(MakeDefinition(name, target, obj))
- func (r *Registry) Define(name string, target TargetType, obj interface{}) error {
- def, err := MakeDefinition(name, target, obj)
- if err != nil {
- return err
- }
- return r.Register(def)
- }
- // Register registers the given marker definition with this registry for later lookup.
- func (r *Registry) Register(def *Definition) error {
- r.init()
- r.mu.Lock()
- defer r.mu.Unlock()
- switch def.Target {
- case DescribesPackage:
- r.forPkg[def.Name] = def
- case DescribesType:
- r.forType[def.Name] = def
- case DescribesField:
- r.forField[def.Name] = def
- default:
- return fmt.Errorf("unknown target type %v", def.Target)
- }
- return nil
- }
- // AddHelp stores the given help in the registry, marking it as associated with
- // the given definition.
- func (r *Registry) AddHelp(def *Definition, help *DefinitionHelp) {
- r.init()
- r.mu.Lock()
- defer r.mu.Unlock()
- r.helpFor[def] = help
- }
- // Lookup fetches the definition corresponding to the given name and target type.
- func (r *Registry) Lookup(name string, target TargetType) *Definition {
- r.init()
- r.mu.RLock()
- defer r.mu.RUnlock()
- switch target {
- case DescribesPackage:
- return tryAnonLookup(name, r.forPkg)
- case DescribesType:
- return tryAnonLookup(name, r.forType)
- case DescribesField:
- return tryAnonLookup(name, r.forField)
- default:
- return nil
- }
- }
- // HelpFor fetches the help for a given definition, if present.
- func (r *Registry) HelpFor(def *Definition) *DefinitionHelp {
- r.init()
- r.mu.RLock()
- defer r.mu.RUnlock()
- return r.helpFor[def]
- }
- // AllDefinitions returns all marker definitions known to this registry.
- func (r *Registry) AllDefinitions() []*Definition {
- res := make([]*Definition, 0, len(r.forPkg)+len(r.forType)+len(r.forField))
- for _, def := range r.forPkg {
- res = append(res, def)
- }
- for _, def := range r.forType {
- res = append(res, def)
- }
- for _, def := range r.forField {
- res = append(res, def)
- }
- return res
- }
- // tryAnonLookup tries looking up the given marker as both an struct-based
- // marker and an anonymous marker, returning whichever format matches first,
- // preferring the longer (anonymous) name in case of conflicts.
- func tryAnonLookup(name string, defs map[string]*Definition) *Definition {
- // NB(directxman12): we look up anonymous names first to work with
- // legacy style marker definitions that have a namespaced approach
- // (e.g. deepcopy-gen, which uses `+k8s:deepcopy-gen=foo,bar` *and*
- // `+k8s.io:deepcopy-gen:interfaces=foo`).
- name, anonName, _ := splitMarker(name)
- if def, exists := defs[anonName]; exists {
- return def
- }
- return defs[name]
- }
|