nodesRunningMe looked for printed lines in what is a JSON list, so every register tool's "also on" hint and every nodes: "all" named no machine.
104 lines
3.8 KiB
Go
104 lines
3.8 KiB
Go
package main
|
|
|
|
// The "instead of" table in the agent's managed instructions (novox/hq ADR 0245): to do this, call that
|
|
// address, not this shell command — generated on every render from what each seat verb and module tool
|
|
// says it replaces, so it cannot drift from the tools the mesh has.
|
|
//
|
|
// Short: a row per seat or module, its top what this machine's agent reached round most — the tools the
|
|
// guard named most often in its record.
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// InsteadOfRows is how many rows — seats and modules — the table holds; the rest are one search away.
|
|
const InsteadOfRows = 16
|
|
|
|
// insteadOrder is the order rows are taken in: a machine's seat, a module on a machine, the mesh's seat.
|
|
func insteadOrder(r Replacement) int {
|
|
switch {
|
|
case r.Seat && r.NodeScoped:
|
|
return 0
|
|
case !r.Seat:
|
|
return 1
|
|
}
|
|
return 2
|
|
}
|
|
|
|
func code(s string) string { return "`" + strings.ReplaceAll(s, "`", "'") + "`" }
|
|
|
|
// insteadGroup is one row: a seat or a module, and its verbs that replace a command.
|
|
type insteadGroup struct {
|
|
prefix string // `<node>/node-service-manager.` or `mesh-controller.`
|
|
verbs []Replacement
|
|
refused int
|
|
}
|
|
|
|
// InsteadOf is the section, or "" when the mesh said nothing replaces anything — an older controller,
|
|
// or one not yet asked.
|
|
//
|
|
// One row per seat or module, every verb of it that replaces a command in the row, so a verb is never cut
|
|
// for being late in its seat's list; the rows the guard here named most come first, then the machines'
|
|
// seats, the modules' tools and the mesh's own seats in the records' order.
|
|
func InsteadOf(m *MeshTools) string {
|
|
if m == nil || len(m.Replacements) == 0 {
|
|
return ""
|
|
}
|
|
var groups []*insteadGroup
|
|
at := map[string]*insteadGroup{}
|
|
for order := 0; order <= 2; order++ {
|
|
for _, r := range m.Replacements {
|
|
if insteadOrder(r) != order {
|
|
continue
|
|
}
|
|
prefix := r.Address[:strings.LastIndex(r.Address, ".")+1]
|
|
if r.NodeScoped {
|
|
prefix = "<node>/" + prefix
|
|
}
|
|
g := at[prefix]
|
|
if g == nil {
|
|
g = &insteadGroup{prefix: prefix}
|
|
at[prefix] = g
|
|
groups = append(groups, g)
|
|
}
|
|
g.verbs = append(g.verbs, r)
|
|
g.refused += m.Refused[r.Address]
|
|
}
|
|
}
|
|
sort.SliceStable(groups, func(i, j int) bool { return groups[i].refused > groups[j].refused })
|
|
for _, g := range groups {
|
|
sort.SliceStable(g.verbs, func(i, j int) bool { return m.Refused[g.verbs[i].Address] > m.Refused[g.verbs[j].Address] })
|
|
}
|
|
more := 0
|
|
if len(groups) > InsteadOfRows {
|
|
more = len(groups) - InsteadOfRows
|
|
groups = groups[:InsteadOfRows]
|
|
}
|
|
var b strings.Builder
|
|
b.WriteString("\n## Instead of a shell command\n\n")
|
|
b.WriteString("Generated from what each seat verb and module tool says it replaces (`replaces`, novox/hq ADR 0245),\n")
|
|
b.WriteString("rewritten on every render. Call `<address><verb>` through `mesh_call`, `<node>` being the machine;\n")
|
|
b.WriteString("`mesh_search` with the command you would have typed finds it too.\n\n")
|
|
b.WriteString("| call | the verb — instead of |\n|---|---|\n")
|
|
for _, g := range groups {
|
|
var cells []string
|
|
for _, r := range g.verbs {
|
|
var not []string
|
|
for _, c := range r.Replaces {
|
|
not = append(not, code(c))
|
|
}
|
|
cells = append(cells, code(r.Address[strings.LastIndex(r.Address, ".")+1:])+" — "+strings.Join(not, ", "))
|
|
}
|
|
fmt.Fprintf(&b, "| %s | %s |\n", code(g.prefix), strings.ReplaceAll(strings.Join(cells, " · "), "|", "/"))
|
|
}
|
|
if more > 0 {
|
|
fmt.Fprintf(&b, "\n%d more seats and modules: `mesh_search` with the command finds the tool for it.\n", more)
|
|
}
|
|
b.WriteString("\n- **Never `ssh` to a mesh machine**, and never edit `/etc/hosts` or set `HOSTALIASES` for a mesh\n" +
|
|
" name: the guard on this session's shell refuses it and names the tool. Where no tool covers what you\n" +
|
|
" need, none is worked around: say so, and the tool is created in the module that owns it, on its seat.\n")
|
|
return b.String()
|
|
}
|