Issue 1585, S19: the strict parser, every manifest problem function and the judge's tables (192 declarations, about 5,200 lines) and their 244 tests leave; composition keeps its own refusals and the helpers it uses. The catalogue's tests decode the manifests they build. ParseManifest, ParseManifestWith, ParseManifestForInputs, CatalogueProblems and the rest are gone; mesh-delivery-indexer/judge holds them. Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
135 lines
5.6 KiB
Go
135 lines
5.6 KiB
Go
package catalogue
|
|
|
|
import (
|
|
"sort"
|
|
)
|
|
|
|
// A preference has a default; the operator's own value has none (novox/hq ADR 0262, extending ADR
|
|
// 0112 and taking the default half of ADR 0164).
|
|
//
|
|
// `${setting:<key>}` was refused whenever no layer set the key, and `settings set` refused a key no
|
|
// file asked for yet. Together they meant a running module could never gain a setting: the file that
|
|
// asks for it fails to compose until somebody sets it, and nobody can set it until the file asks.
|
|
// A definition may now give a key a default, with why, when the value is a **preference** — a font
|
|
// size, a width, a number of workers: something true of the software that a machine may tune. A
|
|
// value that is inherently the operator's — a domain, a public name, an identity, a secret — gets no
|
|
// default and stays refused by name until a layer sets it, which is what ADR 0112 and ADR 0155 were
|
|
// written for.
|
|
//
|
|
// The default is the lowest layer. The mesh's layer, then the node's, override it. It fills only
|
|
// `${setting:<key>}`: a mergeable file's content already is its defaults, and laying a default over
|
|
// it would reach every mergeable file of the module (novox/hq issue 168).
|
|
|
|
// SettingDeclaration is one key's default, as the definition gives it.
|
|
type SettingDeclaration struct {
|
|
// Kind says what sort of value this is. `preference` is the only kind with a default; it is
|
|
// stated rather than assumed so a reviewer sees the claim being made.
|
|
Kind string `json:"kind"`
|
|
// Default is the value when no layer sets the key: a string, a number or a boolean.
|
|
Default any `json:"default"`
|
|
// Why this default: one sentence for whoever wonders whether to change it.
|
|
Why string `json:"why"`
|
|
|
|
// The config form's declaration (novox/hq ADR 0348 §4, config.go): none of these is said under
|
|
// `settings`, and neither Kind nor Why under `config`.
|
|
|
|
// Type is number, string or boolean; object or list only when Trusted.
|
|
Type string `json:"type,omitempty"`
|
|
// Description says what the value is, including its unit.
|
|
Description string `json:"description,omitempty"`
|
|
// Enum, Minimum, Maximum and Pattern are its validation: the values it may take, the bounds of a
|
|
// number, and the whole of a string matching the pattern.
|
|
Enum []any `json:"enum,omitempty"`
|
|
Minimum *float64 `json:"minimum,omitempty"`
|
|
Maximum *float64 `json:"maximum,omitempty"`
|
|
Pattern string `json:"pattern,omitempty"`
|
|
// Trusted is a value that decides what runs or who can reach what (ADR 0348 §8).
|
|
Trusted bool `json:"trusted,omitempty"`
|
|
// Predefined is the predefined key the value falls back to, of the same type (ADR 0348 §2, §7).
|
|
Predefined string `json:"predefined,omitempty"`
|
|
// Required is the operator's own value: it has no default (ADR 0348 §4).
|
|
Required bool `json:"required,omitempty"`
|
|
// Runtime is a value the module's code reads at runtime rather than one placed in a file (ADR 0348 §5).
|
|
Runtime bool `json:"runtime,omitempty"`
|
|
}
|
|
|
|
// KindPreference is the kind of a setting that may have a default.
|
|
const KindPreference = "preference"
|
|
|
|
// DefaultLayer is what the layer of a module's own defaults is called where a value's source is said.
|
|
// Only said: the layer is recognised by Layer.Default, never by this name, which a node may also have.
|
|
const DefaultLayer = "default"
|
|
|
|
// meshWords are the settings keys the mesh reads itself; a module declares none of them.
|
|
var meshWords = map[string]bool{
|
|
PortsSetting: true, ExposeSetting: true, ReachSetting: true, EndpointsSetting: true,
|
|
PlacesSetting: true, AccessesSetting: true, NetworksSetting: true,
|
|
}
|
|
|
|
// 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 {
|
|
return Layer{}, false
|
|
}
|
|
values := map[string]any{}
|
|
for key, d := range m.Settings {
|
|
if d.Default != nil {
|
|
values[key] = d.Default
|
|
}
|
|
}
|
|
return Layer{From: DefaultLayer, Values: values, Default: true}, len(values) > 0
|
|
}
|
|
|
|
// WithDefaults is a module's layers with its defaults under them, for filling `${setting:<key>}`.
|
|
func WithDefaults(m Manifest, layers []Layer) []Layer {
|
|
d, has := Defaults(m)
|
|
if !has {
|
|
return layers
|
|
}
|
|
return append([]Layer{d}, layers...)
|
|
}
|
|
|
|
// SettingSource is one key's effective value and the layer it came from.
|
|
type SettingSource struct {
|
|
Key string
|
|
Value any
|
|
// From is DefaultLayer, MeshWideLayer or the node's name.
|
|
From string
|
|
// FromDefault is whether the value is the module's default, whatever From reads.
|
|
FromDefault bool
|
|
// Default is the module's default, when it gives one.
|
|
Default any
|
|
HasDefault bool
|
|
}
|
|
|
|
// 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.
|
|
func Effective(m Manifest, layers []Layer) []SettingSource {
|
|
byKey := map[string]*SettingSource{}
|
|
for key, d := range m.Settings {
|
|
if d.Default == nil {
|
|
// A required config value has no default (ADR 0348 §4); a settings declaration always has one.
|
|
continue
|
|
}
|
|
byKey[key] = &SettingSource{Key: key, Value: d.Default, From: DefaultLayer, FromDefault: true,
|
|
Default: d.Default, HasDefault: true}
|
|
}
|
|
for _, layer := range layers {
|
|
// As the layer is said, placement too: `settings` answers it as a person set it.
|
|
for key, v := range layer.Whole() {
|
|
s, ok := byKey[key]
|
|
if !ok {
|
|
s = &SettingSource{Key: key}
|
|
byKey[key] = s
|
|
}
|
|
s.Value, s.From, s.FromDefault = v, layer.From, layer.Default
|
|
}
|
|
}
|
|
out := make([]SettingSource, 0, len(byKey))
|
|
for _, s := range byKey {
|
|
out = append(out, *s)
|
|
}
|
|
sort.Slice(out, func(i, j int) bool { return out[i].Key < out[j].Key })
|
|
return out
|
|
}
|