...

Source file src/github.com/letsencrypt/boulder/cmd/registry.go

Documentation: github.com/letsencrypt/boulder/cmd

     1  package cmd
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"sort"
     7  	"sync"
     8  
     9  	"github.com/letsencrypt/validator/v10"
    10  )
    11  
    12  type ConfigValidator struct {
    13  	Config     interface{}
    14  	Validators map[string]validator.Func
    15  }
    16  
    17  var registry struct {
    18  	sync.Mutex
    19  	commands map[string]func()
    20  	configs  map[string]*ConfigValidator
    21  }
    22  
    23  // RegisterCommand registers a subcommand and its corresponding config
    24  // validator. The provided func() is called when the subcommand is invoked on
    25  // the command line. The ConfigValidator is optional and used to validate the
    26  // config file for the subcommand.
    27  func RegisterCommand(name string, f func(), cv *ConfigValidator) {
    28  	registry.Lock()
    29  	defer registry.Unlock()
    30  
    31  	if registry.commands == nil {
    32  		registry.commands = make(map[string]func())
    33  	}
    34  
    35  	if registry.commands[name] != nil {
    36  		panic(fmt.Sprintf("command %q was registered twice", name))
    37  	}
    38  	registry.commands[name] = f
    39  
    40  	if cv == nil {
    41  		return
    42  	}
    43  
    44  	if registry.configs == nil {
    45  		registry.configs = make(map[string]*ConfigValidator)
    46  	}
    47  
    48  	if registry.configs[name] != nil {
    49  		panic(fmt.Sprintf("config validator for command %q was registered twice", name))
    50  	}
    51  	registry.configs[name] = cv
    52  }
    53  
    54  func LookupCommand(name string) func() {
    55  	registry.Lock()
    56  	defer registry.Unlock()
    57  	return registry.commands[name]
    58  }
    59  
    60  func AvailableCommands() []string {
    61  	registry.Lock()
    62  	defer registry.Unlock()
    63  	var avail []string
    64  	for name := range registry.commands {
    65  		avail = append(avail, name)
    66  	}
    67  	sort.Strings(avail)
    68  	return avail
    69  }
    70  
    71  // LookupConfigValidator constructs an instance of the *ConfigValidator for the
    72  // given Boulder component name. If no *ConfigValidator was registered, nil is
    73  // returned.
    74  func LookupConfigValidator(name string) *ConfigValidator {
    75  	registry.Lock()
    76  	defer registry.Unlock()
    77  	if registry.configs[name] == nil {
    78  		return nil
    79  	}
    80  
    81  	// Create a new copy of the config struct so that we can validate it
    82  	// multiple times without mutating the registry's copy.
    83  	copy := reflect.New(reflect.ValueOf(
    84  		registry.configs[name].Config).Elem().Type(),
    85  	).Interface()
    86  
    87  	return &ConfigValidator{
    88  		Config:     copy,
    89  		Validators: registry.configs[name].Validators,
    90  	}
    91  }
    92  
    93  // AvailableConfigValidators returns a list of Boulder component names for which
    94  // a *ConfigValidator has been registered.
    95  func AvailableConfigValidators() []string {
    96  	registry.Lock()
    97  	defer registry.Unlock()
    98  	var avail []string
    99  	for name := range registry.configs {
   100  		avail = append(avail, name)
   101  	}
   102  	sort.Strings(avail)
   103  	return avail
   104  }
   105  

View as plain text