novox/hq 04-ISSUES/142, and ADR 0141's own progressive insight naming this as the first of two things missing: "nothing can compile it". The toolchain list was a closed set of typescript and python, whose warning — every language is another implementation of the contracts modules share — does not attach to Go. Go is how the host, the control plane and the builder are written, and none of them is a module in that sense: the host is what APPLIES modules. The toolchain names mesh-tools-go as its base rather than pinning an upstream release here (ADR 0142, 0044): named and not pinned means the mesh answers with the copy it holds, and moving compiler is a build instead of an edit to this file. Two things beyond the list also assumed one language, and both would have failed after the entry was added: sourcesFor turned every entrypoint into a `.ts` file. The extension is the toolchain's now — one language's file extension written into the code that serves every language is a wall the next one hits. The output directory was the compiler's to create. tsc --outDir makes one; go build -o writes into a directory and does not make it, failing with a message about a path rather than about a build. Made here for every toolchain, because which compilers are forgiving is not something a reader should have to know. And a toolchain now says what it is pointed at: a file list from the module's entrypoints, or the one package the artifact is built `from`. Pointing `go build` at a file list builds a program out of exactly those files and ignores the rest of the package — a missing symbol rather than a legible refusal. Static and -trimpath: what a machine holds is a file, not a container, so a binary needing a libc it did not bring is a delivery that works until a machine differs; and a version comes from where a component sits rather than from its linker, so two builds of one commit are the same bytes.
72 lines
2.8 KiB
Go
72 lines
2.8 KiB
Go
package builder
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// Nothing could compile the mesh's own components, which is why nothing delivers the host
|
|
// (novox/hq 04-ISSUES/142, and ADR 0141's own insight naming it). The toolchain list was a closed
|
|
// set of typescript and python, and two things in the path beyond it assumed TypeScript.
|
|
|
|
func TestTheMeshCanCompileGo(t *testing.T) {
|
|
chain, err := ToolchainFor("go")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// Named, not pinned: the mesh answers with the copy it holds, so moving compiler is a build
|
|
// rather than an edit to this source (ADR 0044, 0142).
|
|
if chain.Base != "mesh-tools-go" || chain.Artifact != "build" {
|
|
t.Fatalf("the go toolchain is based on %s/%s", chain.Base, chain.Artifact)
|
|
}
|
|
joined := strings.Join(chain.Compile, " ")
|
|
// Static, because what a machine holds is a file and not a container: a binary needing a libc
|
|
// it did not bring is a delivery that works until a machine differs.
|
|
if !strings.Contains(joined, "CGO_ENABLED=0") {
|
|
t.Fatalf("the go toolchain does not build statically: %q", joined)
|
|
}
|
|
// Reproducible: a version comes from where a component sits, not from its linker (ADR 0142),
|
|
// so two builds of one commit should produce the same bytes.
|
|
if !strings.Contains(joined, "-trimpath") {
|
|
t.Fatalf("the go toolchain leaves build paths in the binary: %q", joined)
|
|
}
|
|
if chain.Unit != UnitPackage {
|
|
t.Fatalf("the go toolchain compiles %q, wanted a package", chain.Unit)
|
|
}
|
|
}
|
|
|
|
func TestEveryToolchainSaysWhatItIsPointedAt(t *testing.T) {
|
|
// The field exists because the compile path used to assume one language. A toolchain that says
|
|
// nothing would fall through to the entrypoint branch and compile a file list, which for a
|
|
// compiled language builds a program out of exactly those files and ignores the rest of the
|
|
// package — a missing symbol rather than a legible refusal.
|
|
for _, chain := range toolchains {
|
|
switch chain.Unit {
|
|
case UnitPackage:
|
|
case UnitSources:
|
|
if chain.SourceExt == "" {
|
|
t.Fatalf("%s compiles a file list and names no source extension", chain.Language)
|
|
}
|
|
if !strings.HasPrefix(chain.SourceExt, ".") {
|
|
t.Fatalf("%s's source extension %q is not an extension", chain.Language, chain.SourceExt)
|
|
}
|
|
default:
|
|
t.Fatalf("%s says it is pointed at %q, which is neither sources nor a package",
|
|
chain.Language, chain.Unit)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAnEntrypointBecomesASourceInItsOwnLanguage(t *testing.T) {
|
|
// It used to become a `.ts` whatever the language was.
|
|
out := Out("build")
|
|
got := sourcesFor([]string{out + "/tools/index.js"}, out, ".ts")
|
|
if len(got) != 1 || got[0] != "tools/index.ts" {
|
|
t.Fatalf("a typescript entrypoint became %v", got)
|
|
}
|
|
got = sourcesFor([]string{out + "/tools/index.js"}, out, ".py")
|
|
if len(got) != 1 || got[0] != "tools/index.py" {
|
|
t.Fatalf("a python entrypoint became %v", got)
|
|
}
|
|
}
|