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 .: 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: .. 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 }