154 lines
6.0 KiB
Go
154 lines
6.0 KiB
Go
// Mgmt
|
|
// Copyright (C) 2013-2024+ James Shubin and the project contributors
|
|
// Written by James Shubin <james@shubin.ca> and the project contributors
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
//
|
|
// Additional permission under GNU GPL version 3 section 7
|
|
//
|
|
// If you modify this program, or any covered work, by linking or combining it
|
|
// with embedded mcl code and modules (and that the embedded mcl code and
|
|
// modules which link with this program, contain a copy of their source code in
|
|
// the authoritative form) containing parts covered by the terms of any other
|
|
// license, the licensors of this program grant you additional permission to
|
|
// convey the resulting work. Furthermore, the licensors of this program grant
|
|
// the original author, James Shubin, additional permission to update this
|
|
// additional permission if he deems it necessary to achieve the goals of this
|
|
// additional permission.
|
|
|
|
// Package vars provides a framework for language vars.
|
|
package vars
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/purpleidea/mgmt/lang/interfaces"
|
|
)
|
|
|
|
const (
|
|
// ConstNamespace is the string prefix for all top-level built-in vars.
|
|
ConstNamespace = "const"
|
|
|
|
// ResourceNamespace is the string prefix for all top-level resource
|
|
// specific built-in vars, that exist under the ConstNamespace header.
|
|
ResourceNamespace = "res"
|
|
)
|
|
|
|
// Value is a shortcut to using this type.
|
|
// XXX: Eventually we might get rid of this entirely and use types.Value instead
|
|
// of interfaces.Var which seems to be unnecessary at the moment.
|
|
type Value = interfaces.Var
|
|
|
|
// registeredVars is a global map of all possible vars which can be used. You
|
|
// should never touch this map directly. Use methods like Register instead.
|
|
var registeredVars = make(map[string]func() interfaces.Var) // must initialize
|
|
|
|
// Register takes a var and its name and makes it available for use. It is
|
|
// commonly called in the init() method of the var at program startup. There is
|
|
// no matching Unregister function.
|
|
func Register(name string, fn func() interfaces.Var) {
|
|
if _, ok := registeredVars[name]; ok {
|
|
panic(fmt.Sprintf("a var named %s is already registered", name))
|
|
}
|
|
//gob.Register(fn())
|
|
registeredVars[name] = fn
|
|
}
|
|
|
|
// ModuleRegister is exactly like Register, except that it registers within a
|
|
// named module. This is a helper function.
|
|
func ModuleRegister(module, name string, v func() interfaces.Var) {
|
|
Register(module+interfaces.ModuleSep+name, v)
|
|
}
|
|
|
|
// resourceConstHelper is a helper function to manage the const topology.
|
|
func resourceConstHelper(kind, param, field string) string {
|
|
// const.res.file.state.exists = "exists"
|
|
// TODO: should it be: const.res.file.params.state.exists = "exists" ?
|
|
chunks := []string{
|
|
ConstNamespace,
|
|
ResourceNamespace,
|
|
kind,
|
|
param,
|
|
field,
|
|
}
|
|
//return ConstNamespace + interfaces.ModuleSep + ResourceNamespace + interfaces.ModuleSep + kind + interfaces.ModuleSep + param + interfaces.ModuleSep + field
|
|
return strings.Join(chunks, interfaces.ModuleSep) // cleaner code
|
|
}
|
|
|
|
// RegisterResourceParam registers a single const param for a resource. You
|
|
// might prefer to use RegisterResourceParams instead.
|
|
func RegisterResourceParam(kind, param, field string, value func() interfaces.Var) {
|
|
Register(resourceConstHelper(kind, param, field), value)
|
|
}
|
|
|
|
// RegisterResourceParams registers a map of const params for a resource. The
|
|
// params mapping keys are the param name and the param field name. Finally, the
|
|
// value is the specific type value for that constant.
|
|
func RegisterResourceParams(kind string, params map[string]map[string]func() interfaces.Var) {
|
|
for param, mapping := range params {
|
|
for field, value := range mapping {
|
|
Register(resourceConstHelper(kind, param, field), value)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Lookup returns a pointer to the var implementation.
|
|
func Lookup(name string) (interfaces.Var, error) {
|
|
f, exists := registeredVars[name]
|
|
if !exists {
|
|
return nil, fmt.Errorf("not found")
|
|
}
|
|
return f(), nil
|
|
}
|
|
|
|
// LookupPrefix returns a map of names to vars that start with a module prefix.
|
|
// This search automatically adds the period separator. So if you want vars in
|
|
// the `const` prefix, search for `const`, not `const.` and it will find all the
|
|
// correctly registered vars. This removes that prefix from the result in the
|
|
// map keys that it returns. If you search for an empty prefix, then this will
|
|
// return all the top-level functions that aren't in a module.
|
|
func LookupPrefix(prefix string) map[string]func() interfaces.Var {
|
|
result := make(map[string]func() interfaces.Var)
|
|
for name, f := range registeredVars {
|
|
// requested top-level vars, and no module separators...
|
|
if prefix == "" {
|
|
if !strings.Contains(name, interfaces.ModuleSep) {
|
|
result[name] = f // copy
|
|
}
|
|
continue
|
|
}
|
|
sep := prefix + interfaces.ModuleSep
|
|
if !strings.HasPrefix(name, sep) {
|
|
continue
|
|
}
|
|
s := strings.TrimPrefix(name, sep) // remove the prefix
|
|
result[s] = f // copy
|
|
}
|
|
return result
|
|
}
|
|
|
|
// Map returns a map from all registered var names to a function to return that
|
|
// one. We return a copy of our internal registered var store so that this
|
|
// result can be manipulated safely. We return the vars that produce the Var
|
|
// interface because we might use this result to create multiple vars, and each
|
|
// one might need to have its own unique memory address to work properly.
|
|
func Map() map[string]func() interfaces.Var {
|
|
m := make(map[string]func() interfaces.Var)
|
|
for name, fn := range registeredVars { // copy
|
|
m[name] = fn
|
|
}
|
|
return m
|
|
}
|