Merge pull request 'A host the mesh builds knows what it was built for' (#158) from fix/161-a-built-host-knows-what-it-was-built-for into main
This commit was merged in pull request #158.
This commit is contained in:
@@ -877,6 +877,14 @@ func compile(ctx context.Context, run Runner, tree string, chain Toolchain,
|
|||||||
base,
|
base,
|
||||||
}
|
}
|
||||||
invocation = append(invocation, chain.Compile...)
|
invocation = append(invocation, chain.Compile...)
|
||||||
|
// What it was built for, linked in. The compile line carries `-ldflags` already; this appends a
|
||||||
|
// second one, which the Go linker accepts and merges. A host with no system refuses every
|
||||||
|
// declaration before it applies anything (novox/hq 04-ISSUES/161), and it is the artifact that
|
||||||
|
// knows — the target is a property of the artifact rather than of the recipe (ADR 0142).
|
||||||
|
if chain.SystemStamp != "" && strings.TrimSpace(a.System) != "" {
|
||||||
|
invocation = append(invocation, "-ldflags",
|
||||||
|
"-X "+chain.SystemStamp+"="+strings.TrimSpace(a.System))
|
||||||
|
}
|
||||||
if chain.OutputFlag != "" {
|
if chain.OutputFlag != "" {
|
||||||
// A compiler pointed at a package is told the file to write, not the directory: the name a
|
// A compiler pointed at a package is told the file to write, not the directory: the name a
|
||||||
// machine runs it by is not always the name of the package that built it. The host's command
|
// machine runs it by is not always the name of the package that built it. The host's command
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package builder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A host built without knowing its system refuses every declaration before applying anything —
|
||||||
|
// safely, totally, and with nothing reporting it. The mesh built one, delivered it, started it, and
|
||||||
|
// it would have refused the first thing it was asked to do (novox/hq 04-ISSUES/161).
|
||||||
|
|
||||||
|
func TestTheGoToolchainStampsTheArtifactsSystem(t *testing.T) {
|
||||||
|
chain, err := ToolchainFor("go")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if chain.SystemStamp != "main.builtFor" {
|
||||||
|
t.Fatalf("the go toolchain fills %q", chain.SystemStamp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestALanguageWithNoPinnedSystemStampsNothing(t *testing.T) {
|
||||||
|
// Interpreted output is not pinned to a system, and a manifest declaring one for it is already
|
||||||
|
// refused. Nothing to fill.
|
||||||
|
for _, language := range []string{"typescript", "python"} {
|
||||||
|
chain, err := ToolchainFor(language)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if chain.SystemStamp != "" {
|
||||||
|
t.Fatalf("%s fills %q, and its output is not pinned to a system",
|
||||||
|
language, chain.SystemStamp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTheStampIsTheOneThingTakenFromTheArtifact(t *testing.T) {
|
||||||
|
// The toolchain accepts nothing else from the module — anything it could override it would be
|
||||||
|
// writing a Dockerfile to override. The system is the stated exception, because a compiled
|
||||||
|
// binary is per system and the artifact is what declares one (ADR 0142).
|
||||||
|
chain, err := ToolchainFor("go")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
joined := strings.Join(chain.Compile, " ")
|
||||||
|
if strings.Contains(joined, "${") || strings.Contains(joined, "%s") {
|
||||||
|
t.Fatalf("the compile line takes something from the module: %q", joined)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -49,6 +49,18 @@ type Toolchain struct {
|
|||||||
// is named as it will be FOUND, inside the unpacked bundle, so the source is the same path with
|
// is named as it will be FOUND, inside the unpacked bundle, so the source is the same path with
|
||||||
// the output directory taken off the front and this on the end.
|
// the output directory taken off the front and this on the end.
|
||||||
SourceExt string
|
SourceExt string
|
||||||
|
// SystemStamp is the variable this language's linker fills with the artifact's declared system,
|
||||||
|
// for a language whose binaries are pinned to one at link time (novox/hq ADR 0005).
|
||||||
|
//
|
||||||
|
// **The one thing a toolchain takes from the artifact, and 0142 says why**: the target is a
|
||||||
|
// property of the artifact rather than of the recipe, because a compiled binary is per system
|
||||||
|
// and a toolchain that accepted it from the module would be accepting a build instruction. This
|
||||||
|
// is the narrow exception, named here rather than inferred.
|
||||||
|
//
|
||||||
|
// Empty for a language that compiles to nothing pinned. A host built without it refuses every
|
||||||
|
// declaration before applying anything — safely, totally, and with nothing reporting it
|
||||||
|
// (novox/hq 04-ISSUES/161).
|
||||||
|
SystemStamp string
|
||||||
}
|
}
|
||||||
|
|
||||||
// What a toolchain is pointed at.
|
// What a toolchain is pointed at.
|
||||||
@@ -122,6 +134,9 @@ var toolchains = []Toolchain{
|
|||||||
// directory holding one executable, which is what the delivery mechanism expects
|
// directory holding one executable, which is what the delivery mechanism expects
|
||||||
// (novox/hq ADR 0141).
|
// (novox/hq ADR 0141).
|
||||||
Unit: UnitPackage,
|
Unit: UnitPackage,
|
||||||
|
// The mesh's own Go components read the system they were built for from this variable, and
|
||||||
|
// refuse to touch a machine without one.
|
||||||
|
SystemStamp: "main.builtFor",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Language: "python",
|
Language: "python",
|
||||||
|
|||||||
Reference in New Issue
Block a user