// mesh-pack builds a Go bundle by hand with the recipe of the mesh-build-go module and packs it with mesh-sdk's own // buildstep.Pack, printing the digest, so a hand build has the form of a built artifact and, with the same Go version, // its digest (novox/hq ADR 0526; fallback record F1; issue 1499 for the Go version). // // mesh-pack -dir -from -binary [-system arch] [-out ] // mesh-pack -pack [-out ] (a `files` archive: pack a tree as it is) // // The recipe is mesh-catalog modules/mesh-build-go cmd/mesh-build-go/build.go (recipeFlags, recipeLinkerFlags, // recipeSystemStamp, buildEnv): CGO_ENABLED=0, GOFLAGS "-trimpath -buildvcs=false -mod=mod" (-mod=vendor when the // directory vendors), GOTOOLCHAIN=local, GOPROXY=off, and -ldflags "-s -w -X main.builtFor=". package main import ( "flag" "fmt" "os" "os/exec" "path/filepath" "strings" "git.novox.be/novox/mesh-sdk/go/buildstep" ) const ( recipeFlags = "-trimpath -buildvcs=false" recipeLinkerFlags = "-s -w" recipeSystemStamp = "main.builtFor" ) // Env is the build module's environment for the compile of dir, added to the caller's own. func Env(dir string) []string { mod := "-mod=mod" if _, err := os.Stat(filepath.Join(dir, "vendor", "modules.txt")); err == nil { mod = "-mod=vendor" } return append(os.Environ(), "CGO_ENABLED=0", "GOFLAGS="+recipeFlags+" "+mod, "GOTOOLCHAIN=local", "GOPROXY=off", ) } // Args is the arguments of the go command of the recipe. func Args(dir, from, out, binary, system string) []string { linker := recipeLinkerFlags if s := strings.TrimSpace(system); s != "" { linker += " -X " + recipeSystemStamp + "=" + s } return []string{"-C", dir, "build", "-ldflags", linker, "-o", filepath.Join(out, binary), "./" + strings.Trim(from, "./")} } // Build compiles the package into a fresh directory and answers it. func Build(dir, from, binary, system string) (string, error) { out, err := os.MkdirTemp("", "mesh-pack-") if err != nil { return "", err } cmd := exec.Command("go", Args(dir, from, out, binary, system)...) cmd.Env = Env(dir) cmd.Stdout, cmd.Stderr = os.Stderr, os.Stderr if err := cmd.Run(); err != nil { os.RemoveAll(out) return "", fmt.Errorf("go build of %s: %w", from, err) } return out, nil } func run(args []string) (string, error) { fs := flag.NewFlagSet("mesh-pack", flag.ContinueOnError) dir := fs.String("dir", ".", "the Go module's directory") from := fs.String("from", "", "the package to build, relative to -dir (the artifact's from)") binary := fs.String("binary", "", "the binary's name in the archive") system := fs.String("system", "", "the system stamped into main.builtFor (an artifact's system, e.g. arch)") pack := fs.String("pack", "", "pack this directory as it is (a files archive) instead of building") outFile := fs.String("out", "", "write the archive here") if err := fs.Parse(args); err != nil { return "", err } root := *pack if root == "" { if *from == "" || *binary == "" { return "", fmt.Errorf("-from and -binary are needed (or -pack )") } out, err := Build(*dir, *from, *binary, *system) if err != nil { return "", err } defer os.RemoveAll(out) root = out } archive, digest, err := buildstep.Pack(root) if err != nil { return "", err } if *outFile != "" { if err := os.WriteFile(*outFile, archive, 0o644); err != nil { return "", err } } return digest, nil } func main() { digest, err := run(os.Args[1:]) if err != nil { fmt.Fprintln(os.Stderr, "mesh-pack:", err) os.Exit(1) } fmt.Println(digest) }