| // Copyright 2026 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // A stand-alone Go module that generates ../schema.go using the |
| // upstream Wycheproof JSON schema documents. |
| // |
| // We maintain this in a separate Go module and vendor the resulting |
| // generated .go code to avoid the standard library taking a direct |
| // dependency on the c2sp/wycheproof or atombender/go-jsonschema modules. |
| |
| package main |
| |
| import ( |
| "bufio" |
| "fmt" |
| "io/fs" |
| "log" |
| "os" |
| "path/filepath" |
| "strings" |
| |
| "github.com/atombender/go-jsonschema/pkg/generator" |
| "github.com/c2sp/wycheproof" |
| ) |
| |
| func main() { |
| outputName := "schema.go" |
| cfg := generator.Config{ |
| DefaultPackageName: "wycheproof", |
| DefaultOutputName: outputName, |
| Tags: []string{"json"}, |
| Warner: func(message string) { |
| log.Printf("go-jsonschema: %s", message) |
| }, |
| } |
| gen, err := generator.New(cfg) |
| if err != nil { |
| log.Fatal(err) |
| } |
| |
| // Without upstream modifications we can't use the embedded Wycheproof |
| // schema FS directly w/ go-jsonschema and instead make files in a tempdir |
| // on the native FS. See https://github.com/omissis/go-jsonschema/issues/495 |
| schemaDir, err := os.MkdirTemp("", "*-wycheproof") |
| if err != nil { |
| log.Fatal(err) |
| } |
| defer os.RemoveAll(schemaDir) |
| |
| rawSchemas, _ := fs.ReadDir(wycheproof.Schemas, ".") |
| for _, entry := range rawSchemas { |
| entryName := entry.Name() |
| schemaFile := filepath.Join(schemaDir, entryName) |
| |
| schemaData, err := fs.ReadFile(wycheproof.Schemas, entryName) |
| if err != nil { |
| log.Fatalf("reading %s: %v", entryName, err) |
| } |
| err = os.WriteFile(schemaFile, schemaData, 0644) |
| if err != nil { |
| log.Fatalf("writing %s: %v", schemaFile, err) |
| } |
| } |
| |
| // Note: it's important we process schemas in a second pass after writing |
| // **all** of the schema file content to disk so that go-jsonschema can |
| // resolve cross-file references. |
| for _, entry := range rawSchemas { |
| entryName := entry.Name() |
| schemaFile := filepath.Join(schemaDir, entryName) |
| |
| err = gen.DoFile(schemaFile) |
| if err != nil { |
| log.Fatalf("processing %s: %v", schemaFile, err) |
| } |
| } |
| |
| sources, err := gen.Sources() |
| if err != nil { |
| log.Fatalf("error generating sources: %v\n", err) |
| } |
| if sourceCount := len(sources); sourceCount != 1 { |
| log.Fatalf("expected to generate 1 source file, got %d\n", sourceCount) |
| } |
| content, ok := sources[outputName] |
| if !ok { |
| log.Fatalf("missing generated %q output file source", outputName) |
| } |
| outFile := filepath.Join("../", outputName) |
| if err := os.WriteFile(outFile, content, 0644); err != nil { |
| log.Fatalf("error writing file %s: %v\n", outFile, err) |
| } |
| |
| // Write a sibling file recording the Wycheproof module version that the |
| // generated schema.go was produced against. The wycheproof package uses |
| // this constant to fetch matching test vectors at runtime. We avoid reading |
| // go.sum at test time because it might not be available (e.g. if the test |
| // binary was copied to a remote machine). |
| version, err := wycheproofVersionFromSum("go.sum") |
| if err != nil { |
| log.Fatalf("extracting wycheproof version: %v", err) |
| } |
| const versionFile = "../schemaversion.go" |
| versionSrc := fmt.Sprintf(`// Copyright 2026 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Code generated by _schema/schema_gen.go, DO NOT EDIT. |
| |
| package wycheproof |
| |
| // wycheproofVersion is the github.com/c2sp/wycheproof module version that |
| // schema.go was generated against. |
| const wycheproofVersion = %q |
| `, version) |
| if err := os.WriteFile(versionFile, []byte(versionSrc), 0644); err != nil { |
| log.Fatalf("writing %s: %v", versionFile, err) |
| } |
| } |
| |
| // wycheproofVersionFromSum returns the github.com/c2sp/wycheproof module |
| // version recorded in the given go.sum file. |
| func wycheproofVersionFromSum(path string) (string, error) { |
| f, err := os.Open(path) |
| if err != nil { |
| return "", err |
| } |
| defer f.Close() |
| |
| var version string |
| found := 0 |
| scanner := bufio.NewScanner(f) |
| for scanner.Scan() { |
| fields := strings.Fields(scanner.Text()) |
| if len(fields) == 3 && fields[0] == "github.com/c2sp/wycheproof" { |
| version = strings.TrimSuffix(fields[1], "/go.mod") |
| found++ |
| } |
| } |
| if err := scanner.Err(); err != nil { |
| return "", err |
| } |
| switch { |
| case found == 0: |
| return "", fmt.Errorf("%s: missing github.com/c2sp/wycheproof entry", path) |
| case found > 2: |
| return "", fmt.Errorf("%s: %d github.com/c2sp/wycheproof entries (run 'go mod tidy')", path, found) |
| } |
| return version, nil |
| } |