Files
mesh-delivery/sdk/buildstep/toolchain.go
T

82 lines
2.7 KiB
Go

package buildstep
import (
"bytes"
"encoding/json"
"fmt"
"strings"
"time"
)
// ToolchainVersion is the layout version of a toolchains value.
const ToolchainVersion = 1
// Toolchain is the value of a build module's state toolchains under the key <node>.<language>: the version of the
// language's toolchain installed on the node, the build module's recipe version, and when the module saw them. It is
// the part build-step's `Toolchain`, the layout every node-build seat gives that state; the three build modules share
// this neutral form (a seat's generated type is one package per seat). A test reads each seat's fixture strictly into it.
type Toolchain struct {
V int `json:"v,omitempty"`
Language string `json:"language"`
Version string `json:"version"`
Recipe string `json:"recipe"`
At time.Time `json:"at,omitzero"`
}
func checkToolchainLanguage(language string) error {
switch language {
case "go", "typescript":
return nil
}
return fmt.Errorf("buildstep: the toolchain language %q is not go or typescript", language)
}
// ToolchainKey is the key of a node's toolchain of one language: <node>.<language>. It refuses an empty node, a node
// with a dot and a language other than go or typescript.
func ToolchainKey(node, language string) (string, error) {
if node == "" || strings.ContainsAny(node, ". ") {
return "", fmt.Errorf("buildstep: %q is not a node name", node)
}
if err := checkToolchainLanguage(language); err != nil {
return "", err
}
return node + "." + language, nil
}
func (t Toolchain) check() error {
if err := checkToolchainLanguage(t.Language); err != nil {
return err
}
if t.Version == "" || t.Recipe == "" {
return fmt.Errorf("buildstep: a %s toolchain needs its version and its recipe", t.Language)
}
return nil
}
// EncodeToolchain is t as JSON; it refuses a language other than go or typescript and an empty version or recipe.
func EncodeToolchain(t Toolchain) ([]byte, error) {
if err := t.check(); err != nil {
return nil, err
}
t.V = ToolchainVersion
return json.Marshal(t)
}
// DecodeToolchain reads a toolchains value, refusing an unknown field, another layout version and what
// EncodeToolchain refuses.
func DecodeToolchain(data []byte) (Toolchain, error) {
var t Toolchain
dec := json.NewDecoder(bytes.NewReader(data))
dec.DisallowUnknownFields()
if err := dec.Decode(&t); err != nil {
return Toolchain{}, fmt.Errorf("buildstep: a toolchain does not read: %w", err)
}
if t.V != ToolchainVersion {
return Toolchain{}, fmt.Errorf("buildstep: a toolchain of version %d, this reads %d", t.V, ToolchainVersion)
}
if err := t.check(); err != nil {
return Toolchain{}, err
}
return t, nil
}