Modules talk over the bus. The power module's bundle puts each fresh reading of its own sampler in its state draw, keyed by the machine; the bar's block shows that state, which the bar's bundle watches under the read the mesh grants it. A new catalogue check refuses a module naming another module's path under /run or /var/lib.
135 lines
3.5 KiB
Go
135 lines
3.5 KiB
Go
// Command paths holds the catalogue's modules to talking over the bus (novox/hq ADR 0260): no module
|
|
// names a path under /run or /var/lib that another module's manifest places. Such a path is that
|
|
// module's state on its machine, and a second module reading or writing it is two modules talking
|
|
// through a file, which the bus exists to replace.
|
|
//
|
|
// A module owns every `path` of its resources under /run/ or /var/lib/. Every other module's manifest
|
|
// and every file of its own except its documentation and its tests is searched for each, as a whole
|
|
// path: followed by nothing, a slash, or a character no path takes.
|
|
//
|
|
// go run . <catalogue root>
|
|
//
|
|
// Exits 1 on a finding.
|
|
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/fs"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// stateRoots are where a machine keeps a module's state.
|
|
var stateRoots = []string{"/run/", "/var/lib/"}
|
|
|
|
type manifest struct {
|
|
Module string `json:"module"`
|
|
Resources []map[string]any `json:"resources"`
|
|
}
|
|
|
|
// Finding is one module naming another's path.
|
|
type Finding struct {
|
|
Module, File, Path, Owner string
|
|
}
|
|
|
|
func (f Finding) String() string {
|
|
return fmt.Sprintf("%s names %s in %s, and the path is %s's; modules talk over the bus (novox/hq ADR 0260)",
|
|
f.Module, f.Path, f.File, f.Owner)
|
|
}
|
|
|
|
// Check is every finding in the catalogue at root.
|
|
func Check(root string) ([]Finding, error) {
|
|
dirs, err := filepath.Glob(filepath.Join(root, "modules", "*", "module.json"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
owner := map[string]string{}
|
|
modules := map[string]string{}
|
|
for _, f := range dirs {
|
|
raw, err := os.ReadFile(f)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var m manifest
|
|
if err := json.Unmarshal(raw, &m); err != nil {
|
|
return nil, fmt.Errorf("%s: %w", f, err)
|
|
}
|
|
modules[m.Module] = filepath.Dir(f)
|
|
for _, r := range m.Resources {
|
|
p, _ := r["path"].(string)
|
|
for _, root := range stateRoots {
|
|
if strings.HasPrefix(p, root) && len(p) > len(root) {
|
|
owner[strings.TrimRight(p, "/")] = m.Module
|
|
}
|
|
}
|
|
}
|
|
}
|
|
paths := make([]string, 0, len(owner))
|
|
for p := range owner {
|
|
paths = append(paths, p)
|
|
}
|
|
sort.Strings(paths)
|
|
patterns := map[string]*regexp.Regexp{}
|
|
for _, p := range paths {
|
|
patterns[p] = regexp.MustCompile(regexp.QuoteMeta(p) + `(?:$|[^A-Za-z0-9._-])`)
|
|
}
|
|
var out []Finding
|
|
names := make([]string, 0, len(modules))
|
|
for n := range modules {
|
|
names = append(names, n)
|
|
}
|
|
sort.Strings(names)
|
|
for _, module := range names {
|
|
dir := modules[module]
|
|
err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
|
|
if err != nil || d.IsDir() {
|
|
return err
|
|
}
|
|
name := d.Name()
|
|
if strings.HasSuffix(name, ".md") || strings.HasSuffix(name, "_test.go") ||
|
|
name == "go.sum" || name == "package-lock.json" {
|
|
return nil
|
|
}
|
|
raw, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
text := string(raw)
|
|
for _, p := range paths {
|
|
if owner[p] != module && patterns[p].MatchString(text) {
|
|
rel, _ := filepath.Rel(root, path)
|
|
out = append(out, Finding{Module: module, File: rel, Path: p, Owner: owner[p]})
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func main() {
|
|
root := "."
|
|
if len(os.Args) > 1 {
|
|
root = os.Args[1]
|
|
}
|
|
found, err := Check(root)
|
|
if err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(2)
|
|
}
|
|
for _, f := range found {
|
|
fmt.Println(f)
|
|
}
|
|
if len(found) > 0 {
|
|
os.Exit(1)
|
|
}
|
|
fmt.Println("paths: no module names another's state on its machine")
|
|
}
|