Leave out a block its holder cannot render, and keep if-capability to known names on offered kinds (hq ADR 0255)
mesh/merge-gate pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step; every machine composes with the change as it…
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer delivery to the same trunk took over its walk
mesh/merge-gate pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step; every machine composes with the change as it…
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer delivery to the same trunk took over its walk
A piece whose shows the holder's template does not know rendered as nothing and failed the whole machine's declaration; it is now left out and named, for push, plan and the merge gate. quote escapes DEL, which TOML refuses bare. An if-capability nothing detects, or on a kind a holder depends on, would drop a piece silently, so both are refused.
This commit is contained in:
@@ -49,17 +49,27 @@ type PlaceField struct {
|
||||
// OrderDefault is a piece's order when it gives none: the middle of 0–99.
|
||||
const OrderDefault = 50
|
||||
|
||||
// capabilityName is what an `if-capability` may name: a capability as a node's profile reports it.
|
||||
// capabilityName is the shape of a capability's name, as a node's profile reports it.
|
||||
var capabilityName = regexp.MustCompile(`^[a-z0-9][a-z0-9-]*$`)
|
||||
|
||||
// KnownCapabilities is every capability the node-engine detects (mesh-host internal/profile), the
|
||||
// names an `if-capability` may give (novox/hq ADR 0255). A name nothing detects would leave its
|
||||
// contribution out on every machine, silently, so it is refused. A detector added there is added here.
|
||||
var KnownCapabilities = []string{
|
||||
"battery", "container-runtime", "firewall", "graphical-session", "overlay", "package-manager",
|
||||
"power-meter", "privileged", "seat", "service-manager", "uplink-dhcpcd", "uplink-networkmanager",
|
||||
"uplink-systemd-networkd", "virtualisation",
|
||||
}
|
||||
|
||||
// renderFuncs are the functions a holder's template may call. `quote` writes a value as a JSON
|
||||
// string — a valid basic string in TOML and in most tools' grammars — so a contributed command
|
||||
// with quotes in it cannot break out of the holder's line.
|
||||
var renderFuncs = template.FuncMap{
|
||||
"quote": func(v any) (string, error) {
|
||||
b, err := json.Marshal(fmt.Sprint(v))
|
||||
return string(b), err
|
||||
},
|
||||
// string with DEL escaped as well — JSON leaves it bare, and TOML refuses it — which makes it a valid
|
||||
// basic string in TOML and in most tools' grammars, so a contributed command with quotes or control
|
||||
// characters in it cannot break out of the holder's line.
|
||||
var renderFuncs = template.FuncMap{"quote": quote}
|
||||
|
||||
func quote(v any) (string, error) {
|
||||
b, err := json.Marshal(fmt.Sprint(v))
|
||||
return strings.ReplaceAll(string(b), "\x7f", `\u007f`), err
|
||||
}
|
||||
|
||||
// shapedProblems is what is wrong with one contribution of a kind received as data.
|
||||
@@ -197,7 +207,11 @@ type placedPiece struct {
|
||||
// shapedContributions is every module's data of one kind to one seat, narrowed by where and by the
|
||||
// machine's capabilities, ordered, and rendered through the holder's template — each piece under a
|
||||
// comment line naming its module.
|
||||
func shapedContributions(modules []Manifest, holder Manifest, s Seat, r Receivable, where map[string]string, caps map[string]bool) (string, error) {
|
||||
//
|
||||
// A piece the template renders to nothing — a `shows` the holder does not know yet — or fails on is
|
||||
// left out and answered as unplaced, naming its module: the other pieces and the rest of the machine's
|
||||
// declaration go on (novox/hq ADR 0255).
|
||||
func shapedContributions(modules []Manifest, holder Manifest, s Seat, r Receivable, where map[string]string, caps map[string]bool) (string, []string, error) {
|
||||
var pieces []placedPiece
|
||||
for _, m := range inModuleOrder(modules) {
|
||||
for _, c := range m.allContributions() {
|
||||
@@ -224,18 +238,24 @@ func shapedContributions(modules []Manifest, holder Manifest, s Seat, r Receivab
|
||||
}
|
||||
}
|
||||
if len(pieces) == 0 {
|
||||
return "", nil
|
||||
return "", nil, nil
|
||||
}
|
||||
t, err := holderTemplate(holder, s, r.Kind)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", nil, err
|
||||
}
|
||||
sort.SliceStable(pieces, func(a, b int) bool { return pieces[a].order < pieces[b].order })
|
||||
var b strings.Builder
|
||||
var unplaced []string
|
||||
for _, p := range pieces {
|
||||
out, err := renderPiece(t, p.module, p.data)
|
||||
if err == nil && strings.TrimSpace(out) == "" {
|
||||
err = fmt.Errorf("%s's template renders nothing for it", holder.Module)
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
unplaced = append(unplaced, fmt.Sprintf("%s's %s:%s %s is not placed by %s: %v",
|
||||
p.module, s.Name, r.Kind, describePiece(p.data), holder.Module, err))
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(&b, "%s %s\n", r.Comment, p.module)
|
||||
b.WriteString(out)
|
||||
@@ -243,7 +263,19 @@ func shapedContributions(modules []Manifest, holder Manifest, s Seat, r Receivab
|
||||
b.WriteString("\n")
|
||||
}
|
||||
}
|
||||
return b.String(), nil
|
||||
return b.String(), unplaced, nil
|
||||
}
|
||||
|
||||
// describePiece is a piece in one line, its fields in order, for a person reading why it was left out.
|
||||
func describePiece(data map[string]any) string {
|
||||
var parts []string
|
||||
for _, k := range sortedKeys(data) {
|
||||
if _, nested := data[k].(map[string]any); nested {
|
||||
continue
|
||||
}
|
||||
parts = append(parts, fmt.Sprintf("%s=%v", k, data[k]))
|
||||
}
|
||||
return "(" + strings.Join(parts, " ") + ")"
|
||||
}
|
||||
|
||||
// capable is whether a contribution applies on a machine with these capabilities: always, unless it
|
||||
|
||||
Reference in New Issue
Block a user