The v3 migration put application.Get() in backend/events and a ServiceStartup hook in backend/explore, both of which cmd/indexbuild reaches. v3's application package is GTK/WebKit bindings on Linux, so the index-artifact job — a plain golang container with CGO_ENABLED=0, on the stated grounds that neither command imports the app — stopped compiling with "undefined: pointer". That job owns the ~205 GB dump checkpoint, so it is the worst place to learn this. Both are behind the indexbuild tag now: the one app.Event.Emit lives in runtime_wails.go, runtime_indexbuild.go answers ErrNoRuntime (what the app itself returns before Run, so Deliver's callers need no second path), and explore's ServiceStartup moves to its own tagged file. TestIndexToolsDoNotImportWails walks `go list -deps -tags indexbuild` so the claim the workflow makes is checked rather than assumed.
97 lines
2.6 KiB
Go
97 lines
2.6 KiB
Go
package events_test
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// allowedEmitters are the only files permitted to call the Wails
|
|
// runtime's event emitter directly. There is one call and it lives in
|
|
// runtime_wails.go rather than emit.go because naming the application
|
|
// package is what forces cgo, and cmd/indexbuild builds this package
|
|
// without it.
|
|
var allowedEmitters = map[string]bool{
|
|
filepath.Join("backend", "events", "runtime_wails.go"): true,
|
|
}
|
|
|
|
// TestNoDirectRuntimeEmits fails if anything outside backend/events
|
|
// calls the Wails runtime's event emitter directly.
|
|
//
|
|
// The original reason was survival: v2's runtime.EventsEmit called
|
|
// log.Fatalf on a context that did not carry the runtime, so a direct
|
|
// call from a background worker could take the process down. v3's
|
|
// emit takes no context and cannot do that, and the rule is kept for
|
|
// the weaker but still real reason — one emit path is what lets
|
|
// emitStatus drop an unchanged payload for every caller at once.
|
|
//
|
|
// This is a text walk rather than a golangci-lint rule because
|
|
// golangci-lint runs once per build configuration, so a call in an
|
|
// indexbuild- or dev-tagged file is only seen by the pass that compiles
|
|
// it. Walking the tree sees all three, plus anything tagged out
|
|
// entirely.
|
|
func TestNoDirectRuntimeEmits(t *testing.T) {
|
|
// A selector, not a bare name: built at runtime so this file does
|
|
// not match itself, and qualified so it catches the call however
|
|
// the application value is named (app.Event.Emit, a.Event.Emit,
|
|
// application.Get().Event.Emit) without matching an identifier
|
|
// that merely ends in the same letters.
|
|
needle := ".Event" + ".Emit("
|
|
|
|
root := filepath.Join("..", "..")
|
|
|
|
skipDirs := map[string]bool{
|
|
".git": true,
|
|
"node_modules": true,
|
|
"frontend": true,
|
|
"build": true,
|
|
}
|
|
|
|
err := filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if d.IsDir() {
|
|
if skipDirs[d.Name()] {
|
|
return filepath.SkipDir
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
if filepath.Ext(path) != ".go" {
|
|
return nil
|
|
}
|
|
|
|
rel, relErr := filepath.Rel(root, path)
|
|
if relErr != nil {
|
|
return relErr
|
|
}
|
|
|
|
if allowedEmitters[rel] {
|
|
return nil
|
|
}
|
|
|
|
src, readErr := os.ReadFile(path)
|
|
if readErr != nil {
|
|
return readErr
|
|
}
|
|
|
|
for i, line := range strings.Split(string(src), "\n") {
|
|
if strings.Contains(line, needle) {
|
|
t.Errorf(
|
|
"%s:%d calls the Wails emitter directly; use events.Emit\n\t%s",
|
|
rel, i+1, strings.TrimSpace(line),
|
|
)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("walking %s: %v", root, err)
|
|
}
|
|
}
|