112 lines
3.6 KiB
Go
112 lines
3.6 KiB
Go
// 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 <module dir> -from <package> -binary <name> [-system arch] [-out <archive file>]
|
|
// mesh-pack -pack <directory> [-out <archive file>] (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=<system>".
|
|
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 <directory>)")
|
|
}
|
|
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)
|
|
}
|