From efeb5ecda685a2945ae1be0235323e5f968363d7 Mon Sep 17 00:00:00 2001 From: adman Date: Fri, 29 May 2026 01:14:56 +0200 Subject: [PATCH] add file comment generation and hashing for reproducible output in proto_generator --- go.sum | 2 -- proto_generated/v1_21_11/proto.go | 6 ++-- proto_generated/v1_21_8/proto.go | 3 ++ proto_generated/v1_21_9/proto.go | 3 ++ proto_generator/main.go | 50 +++++++++++++++++++++++++++++-- proto_generator/printer.go | 38 ++++++++++++++++++++++- 6 files changed, 95 insertions(+), 7 deletions(-) diff --git a/go.sum b/go.sum index c1ab7a8..389efe2 100644 --- a/go.sum +++ b/go.sum @@ -2,7 +2,5 @@ github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9L github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= diff --git a/proto_generated/v1_21_11/proto.go b/proto_generated/v1_21_11/proto.go index bce6e29..97e7709 100644 --- a/proto_generated/v1_21_11/proto.go +++ b/proto_generated/v1_21_11/proto.go @@ -1,12 +1,14 @@ +// Code generated by strom. DO NOT EDIT. +// source: minecraft-data/pc/1.21.11/protocol.json (sha256:5d0fffae79fe3d99919d16f79ed22d4c76d80fcddf92868b93abda1f55867dd8) +// version: (devel) (go1.26.3-X:nodwarf5) package v1_21_11 import ( "encoding/binary" - "io" - "github.com/admin-else/strom/nbt" "github.com/admin-else/strom/proto_base" "github.com/google/uuid" + "io" ) type ArmorTrimMaterial struct { diff --git a/proto_generated/v1_21_8/proto.go b/proto_generated/v1_21_8/proto.go index a2b3f1c..0f8a7c7 100644 --- a/proto_generated/v1_21_8/proto.go +++ b/proto_generated/v1_21_8/proto.go @@ -1,3 +1,6 @@ +// Code generated by strom. DO NOT EDIT. +// source: minecraft-data/pc/1.21.8/protocol.json (sha256:627f4138d1a6e4a6fff1cde6008c95a72cd580728aafca8ba62ad0ef21c88f61) +// version: (devel) (go1.26.3-X:nodwarf5) package v1_21_8 import ( diff --git a/proto_generated/v1_21_9/proto.go b/proto_generated/v1_21_9/proto.go index eb7635b..1ca99fa 100644 --- a/proto_generated/v1_21_9/proto.go +++ b/proto_generated/v1_21_9/proto.go @@ -1,3 +1,6 @@ +// Code generated by strom. DO NOT EDIT. +// source: minecraft-data/pc/1.21.9/protocol.json (sha256:5c5c5947ac583745cb1ea9a8b2fa654f0356349f37fa0248ba2e44baf4e5c485) +// version: (devel) (go1.26.3-X:nodwarf5) package v1_21_9 import ( diff --git a/proto_generator/main.go b/proto_generator/main.go index 1b45d34..8f79150 100644 --- a/proto_generator/main.go +++ b/proto_generator/main.go @@ -1,12 +1,14 @@ package main import ( + "crypto/sha256" "errors" "fmt" "go/ast" "go/token" "io" "os" + "runtime/debug" "slices" "strconv" "strings" @@ -319,7 +321,34 @@ func (g *Generator) GenerateProtocol(protocol Protocol, version string) (err err return } -func Generate(version string, w io.Writer) (packetInfos []PacketInfo, err error) { +func ToolVersion() string { + info, ok := debug.ReadBuildInfo() + if !ok { + return "devel" + } + return info.Main.Version +} + +func GoVersion() string { + info, ok := debug.ReadBuildInfo() + if !ok { + return "unknown" + } + return info.GoVersion +} + +func HashFile(path string) (string, error) { + // Read from embedded filesystem since minecraft-data is embedded via go:embed + b, err := data.MinecraftData.ReadFile(path) + if err != nil { + return "", err + } + h := sha256.New() + h.Write(b) + return fmt.Sprintf("sha256:%x", h.Sum(nil)), nil +} + +func Generate(version string, w io.Writer, sourceHash string) (packetInfos []PacketInfo, err error) { protocol := Protocol{} err = data.LoadVersionedJson(version, "protocol", &protocol) if err != nil { @@ -329,6 +358,15 @@ func Generate(version string, w io.Writer) (packetInfos []PacketInfo, err error) g := &Generator{Protocol: protocol} g.File = NewFile("v" + strings.ReplaceAll(version, ".", "_")) + + // Add file header comment for IDE recognition and reproducibility + sourcePath := "minecraft-data/" + data.Paths.Data[version]["protocol"] + "/protocol.json" + toolVersion := ToolVersion() + goVersion := GoVersion() + comment := fmt.Sprintf("Code generated by strom. DO NOT EDIT.\nsource: %s (%s)\nversion: %s (%s)", + sourcePath, sourceHash, toolVersion, goVersion) + AddFileComment(g.File, comment) + AppendDecl(g.File, Import("encoding/binary", "io", "github.com/admin-else/strom/proto_base", "github.com/admin-else/strom/nbt", "github.com/google/uuid")) g.RegisterNatives() g.RegisterDecoderNatives() @@ -354,7 +392,15 @@ func generateVersion(v string) (packetInfos []PacketInfo, err error) { return } defer f.Close() - packetInfos, err = Generate(v, f) + + // Compute hash of source protocol.json for reproducibility + sourcePath := "minecraft-data/" + data.Paths.Data[v]["protocol"] + "/protocol.json" + sourceHash, err := HashFile(sourcePath) + if err != nil { + return + } + + packetInfos, err = Generate(v, f, sourceHash) if err != nil { return } diff --git a/proto_generator/printer.go b/proto_generator/printer.go index 490e930..713c85f 100644 --- a/proto_generator/printer.go +++ b/proto_generator/printer.go @@ -1,11 +1,13 @@ package main import ( + "bytes" "fmt" "go/ast" "go/format" "go/token" "io" + "strings" ) func NewStruct() (s *ast.StructType) { @@ -357,8 +359,42 @@ func AppendDecl(file *ast.File, decl ast.Decl) { file.Decls = append(file.Decls, decl) } +// AddFileComment adds a comment block at the top of the file +func AddFileComment(f *ast.File, comment string) { + f.Doc = &ast.CommentGroup{} + lines := strings.Split(comment, "\n") + for _, line := range lines { + f.Doc.List = append(f.Doc.List, &ast.Comment{Text: "// " + line}) + } +} + func PrintToFile(f *ast.File, w io.Writer) error { - return format.Node(w, token.NewFileSet(), f) + // Extract doc comment header if present + var header string + if f.Doc != nil { + for _, c := range f.Doc.List { + header += c.Text + "\n" + } + f.Doc = nil // Clear so go/format doesn't print it + } + + // Format the file + var buf bytes.Buffer + if err := format.Node(&buf, token.NewFileSet(), f); err != nil { + return err + } + + // Find where "package " starts in formatted output + formatted := buf.String() + pkgIndex := strings.Index(formatted, "package ") + if pkgIndex < 0 { + pkgIndex = 0 + } + + // Write header, then formatted content starting from package + w.Write([]byte(header)) + w.Write([]byte(formatted[pkgIndex:])) + return nil } func IfErrNil() *ast.IfStmt {