Declare preferences with a type and a predefined key, and lay mesh and node config between default and node (hq issue 630)
A preference may fall back to one reviewed mesh-wide or node-wide value instead of a module layer for the whole mesh; like a default, config fills ${setting:} only.
This commit is contained in:
@@ -114,15 +114,23 @@ func operatorsWord(key string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// SettingProblems is every way a definition's setting defaults are wrong, in its own words.
|
||||
// SettingProblems is every way a definition's setting defaults and preferences are wrong, in its own
|
||||
// words. The list of predefined keys is not needed here; PredefinedProblems judges against it.
|
||||
func SettingProblems(m Manifest) []string {
|
||||
if len(m.Settings) == 0 {
|
||||
declared := PreferencesOf(m)
|
||||
if len(declared) == 0 {
|
||||
return nil
|
||||
}
|
||||
used := settingKeysUsedBy(m)
|
||||
var problems []string
|
||||
for _, key := range sortedSettingKeys(m.Settings) {
|
||||
d := m.Settings[key]
|
||||
problems := preferenceProblems(m)
|
||||
keys := make([]string, 0, len(declared))
|
||||
for k := range declared {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, key := range keys {
|
||||
d := declared[key]
|
||||
_, old := m.Settings[key]
|
||||
say := func(format string, args ...any) {
|
||||
problems = append(problems, fmt.Sprintf("%s's setting %q: ", m.Module, key)+fmt.Sprintf(format, args...))
|
||||
}
|
||||
@@ -134,23 +142,27 @@ func SettingProblems(m Manifest) []string {
|
||||
say("the mesh reads %q itself, and a module gives it no default", key)
|
||||
continue
|
||||
}
|
||||
if d.Kind != KindPreference {
|
||||
say("kind is %q, and only a %q has a default (novox/hq ADR 0262)", d.Kind, KindPreference)
|
||||
if old && m.Settings[key].Kind != KindPreference {
|
||||
say("kind is %q, and only a %q has a default (novox/hq ADR 0262)", m.Settings[key].Kind, KindPreference)
|
||||
}
|
||||
if word := operatorsWord(key); word != "" {
|
||||
say("a key naming %q is the operator's value, and has no default — it is the "+
|
||||
"assignment's, never the definition's (novox/hq ADR 0112, ADR 0262)", word)
|
||||
}
|
||||
switch v := d.Default.(type) {
|
||||
case string:
|
||||
if strings.TrimSpace(v) == "" {
|
||||
say("an empty default is no default; give the value, or declare nothing")
|
||||
if old {
|
||||
switch v := d.Default.(type) {
|
||||
case string:
|
||||
if strings.TrimSpace(v) == "" {
|
||||
say("an empty default is no default; give the value, or declare nothing")
|
||||
}
|
||||
case float64, bool:
|
||||
case nil:
|
||||
say("no default: a key without one is the operator's, and is not declared here")
|
||||
default:
|
||||
say("a default is a string, a number or a boolean, and this is %T", d.Default)
|
||||
}
|
||||
case float64, bool:
|
||||
case nil:
|
||||
say("no default: a key without one is the operator's, and is not declared here")
|
||||
default:
|
||||
say("a default is a string, a number or a boolean, and this is %T", d.Default)
|
||||
} else if v, isString := d.Default.(string); isString && strings.TrimSpace(v) == "" {
|
||||
say("an empty default is no default; give the value, or declare nothing")
|
||||
}
|
||||
if strings.TrimSpace(d.Why) == "" {
|
||||
say("no why: say in one sentence why this default")
|
||||
@@ -164,11 +176,12 @@ func SettingProblems(m Manifest) []string {
|
||||
|
||||
// Defaults is the layer a module's own defaults make, or nothing when it gives none.
|
||||
func Defaults(m Manifest) (Layer, bool) {
|
||||
if len(m.Settings) == 0 {
|
||||
declared := PreferencesOf(m)
|
||||
if len(declared) == 0 {
|
||||
return Layer{}, false
|
||||
}
|
||||
values := map[string]any{}
|
||||
for key, d := range m.Settings {
|
||||
for key, d := range declared {
|
||||
if d.Default != nil {
|
||||
values[key] = d.Default
|
||||
}
|
||||
@@ -189,7 +202,7 @@ func WithDefaults(m Manifest, layers []Layer) []Layer {
|
||||
type SettingSource struct {
|
||||
Key string
|
||||
Value any
|
||||
// From is DefaultLayer, MeshWideLayer or the node's name.
|
||||
// From is DefaultLayer, MeshConfigLayer, NodeConfigLayer(node), MeshWideLayer or the node's name.
|
||||
From string
|
||||
// FromDefault is whether the value is the module's default, whatever From reads.
|
||||
FromDefault bool
|
||||
@@ -199,10 +212,11 @@ type SettingSource struct {
|
||||
}
|
||||
|
||||
// Effective is every key a module gives a default or a layer sets, with its value and where it came
|
||||
// from: the default, then the mesh's layer, then the node's — later wins.
|
||||
// from: the default, then mesh config, then node config, then the module's own layer on the node —
|
||||
// later wins (novox/hq issue 630).
|
||||
func Effective(m Manifest, layers []Layer) []SettingSource {
|
||||
byKey := map[string]*SettingSource{}
|
||||
for key, d := range m.Settings {
|
||||
for key, d := range PreferencesOf(m) {
|
||||
byKey[key] = &SettingSource{Key: key, Value: d.Default, From: DefaultLayer, FromDefault: true,
|
||||
Default: d.Default, HasDefault: true}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user