82 lines
2.7 KiB
Go
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
|
|
}
|