deps skips a forge requirement the go.mod already replaces to a directory (a package of the module's own repository), which it used to look for in a clone beside the check and fail. The new check removedpackages refuses an import of a package mesh-sdk gave up and a use of the build runner through mesh-sdk's buildstep; it is red on mesh-provisioner until the provisioner stops composing (the release's provisioner subtask). controllerdeps also refuses a go.mod requiring the controller's repository. Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
167 lines
6.0 KiB
Go
167 lines
6.0 KiB
Go
// Command removedpackages refuses a Go source of the catalogue that imports what mesh-sdk gave up in the release that
|
|
// narrowed it (novox/hq ADR 0593 §1): a package that left for its owner, and the build runner's names that left
|
|
// mesh-sdk's buildstep for mesh-build-go's package.
|
|
//
|
|
// A module compiles against the mesh-sdk version it pins, so a source that still names a removed package builds until the
|
|
// pin moves, and then breaks in a delivery of its own; and a later change could bring the import back with the old pin.
|
|
// This check refuses it at once, from the source alone:
|
|
//
|
|
// - an import of a package in Removed (or one under it);
|
|
// - in a file importing mesh-sdk's buildstep (under any name), a selector naming anything that is not in
|
|
// BuildstepContract: what is left of that package is what the delivery parts read, and the runner is
|
|
// mesh-build-go's package (git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep).
|
|
//
|
|
// It reads the non-test and test Go files under modules/ and checks/ (testdata, vendor and node_modules left out).
|
|
//
|
|
// go run . <catalogue root>
|
|
//
|
|
// Exits 1 on a finding. The lists are the release's: a package that goes later is added here with the change.
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"go/ast"
|
|
"go/parser"
|
|
"go/token"
|
|
"io/fs"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
const sdk = "git.novox.be/novox/mesh-sdk/go"
|
|
|
|
// Removed are the packages of mesh-sdk that left it, each with where its logic is now.
|
|
var Removed = map[string]string{
|
|
"buildcpu": "the build runner's package, git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep/buildcpu",
|
|
"buildstep/conformance": "the build runner's package, git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep/conformance",
|
|
"delivery/buildrun": "the builder's package (mesh-delivery-builder), imported by its repository's modules",
|
|
"compose": "the node-engine, which alone composes (ADR 0593 §6)",
|
|
"compose/frombus": "the node-engine, which alone composes (ADR 0593 §6)",
|
|
"compose/fromruntime": "the node-engine, which alone composes (ADR 0593 §6)",
|
|
"compose/judge": "the assigner's own package",
|
|
"takein": "the node-engine, which alone composes (ADR 0593 §6)",
|
|
"validate": "the node-engine, which alone composes (ADR 0593 §6)",
|
|
"facts": "nothing: the controller they served is ended (ADR 0590)",
|
|
"example": "nothing: no module imports it (ADR 0593 §12)",
|
|
"packageguard": "nothing: a test helper of mesh-sdk's own",
|
|
}
|
|
|
|
// BuildstepContract are the names mesh-sdk's buildstep keeps: the failure contract, the fetch request, the stale-step sweep,
|
|
// the step id and the module tree shape the delivery parts read.
|
|
var BuildstepContract = map[string]bool{
|
|
"AskWhat": true, "Boot": true, "By": true, "CapacitySetting": true, "Clip": true, "ConsoleFailure": true, "CutLine": true,
|
|
"EndOne": true, "EndStale": true, "EndStaleAtStart": true, "EndStaleRound": true, "Failure": true, "FetchRequest": true,
|
|
"FetchRequestProperties": true, "Hidden": true, "Launchers": true, "LauncherSuffix": true, "LineBytes": true,
|
|
"ModuleTree": true, "NewID": true, "OutputBytes": true, "Owner": true, "PackagesArg": true, "ParseFetchRequest": true,
|
|
"PassingLine": true, "RestartReason": true, "Scan": true, "ScanOf": true, "StaleAttempts": true, "StaleRetry": true,
|
|
"StaleServed": true,
|
|
}
|
|
|
|
// Findings is every refusal in the Go sources under root, sorted.
|
|
func Findings(root string) ([]string, error) {
|
|
var out []string
|
|
for _, top := range []string{"modules", "checks"} {
|
|
err := filepath.WalkDir(filepath.Join(root, top), func(path string, d fs.DirEntry, err error) error {
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return nil
|
|
}
|
|
return err
|
|
}
|
|
if d.IsDir() {
|
|
switch d.Name() {
|
|
case "testdata", "vendor", "node_modules", ".mesh-build":
|
|
return filepath.SkipDir
|
|
}
|
|
return nil
|
|
}
|
|
if !strings.HasSuffix(path, ".go") {
|
|
return nil
|
|
}
|
|
rel, _ := filepath.Rel(root, path)
|
|
found, err := fileFindings(path, filepath.ToSlash(rel))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
out = append(out, found...)
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
sort.Strings(out)
|
|
return out, nil
|
|
}
|
|
|
|
func fileFindings(path, rel string) ([]string, error) {
|
|
file, err := parser.ParseFile(token.NewFileSet(), path, nil, parser.SkipObjectResolution)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%s: %w", rel, err)
|
|
}
|
|
var out []string
|
|
buildstep := ""
|
|
for _, imp := range file.Imports {
|
|
p, err := strconv.Unquote(imp.Path.Value)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
sub, ok := strings.CutPrefix(p, sdk+"/")
|
|
if !ok {
|
|
continue
|
|
}
|
|
for pkg, to := range Removed {
|
|
if sub == pkg || strings.HasPrefix(sub, pkg+"/") {
|
|
out = append(out, fmt.Sprintf("%s: imports %s, which left mesh-sdk; it is %s (novox/hq ADR 0593 §1)", rel, p, to))
|
|
break
|
|
}
|
|
}
|
|
if sub == "buildstep" {
|
|
buildstep = "buildstep"
|
|
if imp.Name != nil {
|
|
buildstep = imp.Name.Name
|
|
}
|
|
}
|
|
}
|
|
if buildstep == "" || buildstep == "_" || buildstep == "." {
|
|
return out, nil
|
|
}
|
|
seen := map[string]bool{}
|
|
ast.Inspect(file, func(n ast.Node) bool {
|
|
sel, ok := n.(*ast.SelectorExpr)
|
|
if !ok {
|
|
return true
|
|
}
|
|
id, ok := sel.X.(*ast.Ident)
|
|
if !ok || id.Name != buildstep || !sel.Sel.IsExported() || BuildstepContract[sel.Sel.Name] || seen[sel.Sel.Name] {
|
|
return true
|
|
}
|
|
seen[sel.Sel.Name] = true
|
|
out = append(out, fmt.Sprintf("%s: uses %s.%s, which is the build runner's, no longer mesh-sdk's buildstep; import git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep (novox/hq ADR 0593 §1)", rel, buildstep, sel.Sel.Name))
|
|
return true
|
|
})
|
|
return out, nil
|
|
}
|
|
|
|
func main() {
|
|
if len(os.Args) != 2 {
|
|
fmt.Fprintln(os.Stderr, "usage: removedpackages <catalogue root>")
|
|
os.Exit(2)
|
|
}
|
|
found, err := Findings(os.Args[1])
|
|
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("no source imports a package mesh-sdk gave up")
|
|
}
|