boulder/cmd/registry.go

105 lines
2.4 KiB
Go

package cmd
import (
"fmt"
"reflect"
"sort"
"sync"
"github.com/letsencrypt/validator/v10"
)
type ConfigValidator struct {
Config interface{}
Validators map[string]validator.Func
}
var registry struct {
sync.Mutex
commands map[string]func()
configs map[string]*ConfigValidator
}
// RegisterCommand registers a subcommand and its corresponding config
// validator. The provided func() is called when the subcommand is invoked on
// the command line. The ConfigValidator is optional and used to validate the
// config file for the subcommand.
func RegisterCommand(name string, f func(), cv *ConfigValidator) {
registry.Lock()
defer registry.Unlock()
if registry.commands == nil {
registry.commands = make(map[string]func())
}
if registry.commands[name] != nil {
panic(fmt.Sprintf("command %q was registered twice", name))
}
registry.commands[name] = f
if cv == nil {
return
}
if registry.configs == nil {
registry.configs = make(map[string]*ConfigValidator)
}
if registry.configs[name] != nil {
panic(fmt.Sprintf("config validator for command %q was registered twice", name))
}
registry.configs[name] = cv
}
func LookupCommand(name string) func() {
registry.Lock()
defer registry.Unlock()
return registry.commands[name]
}
func AvailableCommands() []string {
registry.Lock()
defer registry.Unlock()
var avail []string
for name := range registry.commands {
avail = append(avail, name)
}
sort.Strings(avail)
return avail
}
// LookupConfigValidator constructs an instance of the *ConfigValidator for the
// given Boulder component name. If no *ConfigValidator was registered, nil is
// returned.
func LookupConfigValidator(name string) *ConfigValidator {
registry.Lock()
defer registry.Unlock()
if registry.configs[name] == nil {
return nil
}
// Create a new copy of the config struct so that we can validate it
// multiple times without mutating the registry's copy.
copy := reflect.New(reflect.ValueOf(
registry.configs[name].Config).Elem().Type(),
).Interface()
return &ConfigValidator{
Config: copy,
Validators: registry.configs[name].Validators,
}
}
// AvailableConfigValidators returns a list of Boulder component names for which
// a *ConfigValidator has been registered.
func AvailableConfigValidators() []string {
registry.Lock()
defer registry.Unlock()
var avail []string
for name := range registry.configs {
avail = append(avail, name)
}
sort.Strings(avail)
return avail
}