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:}` 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:}`: 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:}`. 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 }