From 3b22ee4a1f8c1664bf1c597797c150c1b2ab935e Mon Sep 17 00:00:00 2001 From: Joshua Rich Date: Thu, 3 Oct 2024 21:42:52 +1000 Subject: [PATCH] build(mage): :bug: split build and package environment generation --- build/magefiles/build.go | 22 ++++----------- build/magefiles/helpers.go | 58 ++++++++++++++++++++++++++++++-------- build/magefiles/package.go | 33 ++++++++-------------- 3 files changed, 62 insertions(+), 51 deletions(-) diff --git a/build/magefiles/build.go b/build/magefiles/build.go index 87431ee88..430a8a494 100644 --- a/build/magefiles/build.go +++ b/build/magefiles/build.go @@ -9,8 +9,6 @@ import ( "errors" "fmt" "log/slog" - "os" - "path/filepath" "runtime" "github.com/magefile/mage/mg" @@ -54,20 +52,13 @@ func (b Build) CI() error { // buildProject is the shared method that all exported build targets use. It // runs the bare minimum steps to build a binary of the agent. -// -//nolint:mnd func buildProject() error { - // Remove any existing dist directory. - if err := os.RemoveAll(distPath); err != nil { - return fmt.Errorf("could not clean dist directory: %w", err) - } - // Recreate an empty dist directory for this build. - if err := os.Mkdir(distPath, 0o755); err != nil { - return fmt.Errorf("could not create dist directory: %w", err) + if err := cleanDir(distPath); err != nil { + return errors.Join(ErrBuildFailed, err) } // Set-up the build environment. - envMap, err := generateEnv() + buildEnv, err := generateBuildEnv() if err != nil { return errors.Join(ErrBuildFailed, err) } @@ -78,16 +69,13 @@ func buildProject() error { return errors.Join(ErrBuildFailed, err) } - // Set an appropriate output file based on the arch to build for. - outputFile := filepath.Join(distPath, "/go-hass-agent-"+envMap["PLATFORMPAIR"]) - //nolint:sloglint slog.Info("Running go build...", - slog.String("output", outputFile), + slog.String("output", buildEnv["OUTPUT"]), slog.String("build.host", runtime.GOARCH)) // Run the build. - if err := sh.RunWithV(envMap, "go", "build", "-ldflags="+ldflags, "-o", outputFile); err != nil { + if err := sh.RunWithV(buildEnv, "go", "build", "-ldflags="+ldflags, "-o", buildEnv["OUTPUT"]); err != nil { return fmt.Errorf("failed to build project: %w", err) } diff --git a/build/magefiles/helpers.go b/build/magefiles/helpers.go index a896a0f03..816b06b93 100644 --- a/build/magefiles/helpers.go +++ b/build/magefiles/helpers.go @@ -9,6 +9,7 @@ import ( "fmt" "log/slog" "os" + "path/filepath" "runtime" "slices" "strings" @@ -100,7 +101,7 @@ func getVersion() (string, error) { return version, nil } -// hash returns the git hash for the current repo or "" if none. +// getGitHash returns the git hash for the current repo or "" if none. func getGitHash() (string, error) { hash, err := sh.Output("git", "rev-parse", "--short", "HEAD") if err != nil { @@ -120,10 +121,10 @@ func getBuildDate() (string, error) { return date, nil } -// generateEnv will create a map[string]string containing environment variables -// and their values necessary for building the package on the given +// generateBuildEnv will create a map[string]string containing environment +// variables and their values necessary for building Go Hass Agent on the given // architecture. -func generateEnv() (map[string]string, error) { +func generateBuildEnv() (map[string]string, error) { envMap := make(map[string]string) // CGO_ENABLED is required. @@ -136,18 +137,12 @@ func generateEnv() (map[string]string, error) { // Set APPVERSION to current version. envMap["APPVERSION"] = version - // Set NFPM_ARCH so that nfpm knows how to package for this arch. - envMap["NFPM_ARCH"] = runtime.GOARCH - // Get the value of BUILDPLATFORM (if set) from the environment, which // indicates cross-compilation has been requested. _, arch, ver := parseBuildPlatform() if arch != "" && arch != runtime.GOARCH { slog.Info("Setting up cross-compilation.") - // Update NFPM_ARCH to the target arch. - envMap["NFPM_ARCH"] = arch + ver - // Set additional build-related variables based on the target arch. switch arch { case "arm": @@ -169,14 +164,41 @@ func generateEnv() (map[string]string, error) { envMap["PLATFORMPAIR"] = runtime.GOARCH } + // Set an appropriate output file based on the arch to build for. + envMap["OUTPUT"] = filepath.Join(distPath, "/go-hass-agent-"+envMap["PLATFORMPAIR"]) + + return envMap, nil +} + +// generatePkgEnv will create a map[string]string containing environment +// variables and their values necessary for packaging Go Hass Agent on the given +// architecture. +func generatePkgEnv() (map[string]string, error) { + envMap := make(map[string]string) + + version, err := getVersion() + if err != nil { + return nil, fmt.Errorf("could not generate env: %w", err) + } + // Set APPVERSION to current version. + envMap["APPVERSION"] = version + // Set NFPM_ARCH so that nfpm knows how to package for this arch. + envMap["NFPM_ARCH"] = runtime.GOARCH + // Parse the build platform from the environment. + _, arch, ver := parseBuildPlatform() + // For arm, set the NFPM_ARCH to include the revision. + if arch != "" && arch != runtime.GOARCH { + slog.Info("Setting up cross-compilation.") + // Update NFPM_ARCH to the target arch. + envMap["NFPM_ARCH"] = arch + ver + } + return envMap, nil } // parseBuildPlatform reads the TARGETPLATFORM environment variable, which should // always be set, and extracts the value into appropriate GOOS, GOARCH and GOARM // (if applicable) variables. -// -//nolint:mnd func parseBuildPlatform() (operatingsystem, architecture, version string) { var buildPlatform string @@ -199,3 +221,15 @@ func parseBuildPlatform() (operatingsystem, architecture, version string) { return operatingsystem, architecture, version } + +func cleanDir(path string) error { + if err := os.RemoveAll(path); err != nil { + return fmt.Errorf("could not clean directory %s: %w", path, err) + } + + if err := os.MkdirAll(path, 0o755); err != nil { + return fmt.Errorf("could not create directory %s: %w", path, err) + } + + return nil +} diff --git a/build/magefiles/package.go b/build/magefiles/package.go index 42e46df0e..3aebbad06 100644 --- a/build/magefiles/package.go +++ b/build/magefiles/package.go @@ -6,10 +6,8 @@ package main import ( - "errors" "fmt" "log/slog" - "os" "path/filepath" "slices" "strings" @@ -21,49 +19,40 @@ import ( type Package mg.Namespace var ( - pkgformats = []string{"rpm", "deb", "archlinux"} - pkgPath = filepath.Join(distPath, "pkg") - nfpmBaseArgs = []string{"run", "github.com/goreleaser/nfpm/v2/cmd/nfpm", "package", "--config", ".nfpm.yaml", "--target", pkgPath} - - ErrNoBuildEnv = errors.New("no build and/or version environment variables") - ErrNfpmInstallFailed = errors.New("unable to install nfpm") + pkgformats = []string{"rpm", "deb", "archlinux"} + pkgPath = filepath.Join(distPath, "pkg") + nfpmCommandLine = []string{"go", "run", "github.com/goreleaser/nfpm/v2/cmd/nfpm", "package", "--config", ".nfpm.yaml", "--target", pkgPath} ) // Nfpm builds packages using nfpm. -// -//nolint:mnd,cyclop func (Package) Nfpm() error { - if err := os.RemoveAll(pkgPath); err != nil { - return fmt.Errorf("could not clean dist directory: %w", err) - } - - if err := os.MkdirAll(pkgPath, 0o755); err != nil { - return fmt.Errorf("could not create dist directory: %w", err) + if err := cleanDir(pkgPath); err != nil { + return fmt.Errorf("cannot run nfpm: %w", err) } - envMap, err := generateEnv() + pkgEnv, err := generatePkgEnv() if err != nil { - return fmt.Errorf("failed to create environment: %w", err) + return fmt.Errorf("cannot run nfpm: %w", err) } for _, pkgformat := range pkgformats { slog.Info("Building package with nfpm.", slog.String("format", pkgformat)) - args := slices.Concat(nfpmBaseArgs, []string{"--packager", pkgformat}) + args := slices.Concat(nfpmCommandLine[1:], []string{"--packager", pkgformat}) - if err := sh.RunWithV(envMap, "go", args...); err != nil { + if err := sh.RunWithV(pkgEnv, nfpmCommandLine[0], args...); err != nil { return fmt.Errorf("could not run nfpm: %w", err) } // nfpm creates the same package name for armv6 and armv7 deb packages, // so we need to rename them. - if envMap["GOARCH"] == "arm" && pkgformat == "deb" { + if pkgEnv["GOARCH"] == "arm" && pkgformat == "deb" { debPkgs, err := filepath.Glob(distPath + "/pkg/*.deb") if err != nil || debPkgs == nil { return fmt.Errorf("could not find arm deb package: %w", err) } oldDebPkg := debPkgs[0] - newDebPkg := strings.ReplaceAll(oldDebPkg, "armhf", "arm"+envMap["GOARM"]+"hf") + newDebPkg := strings.ReplaceAll(oldDebPkg, "armhf", "arm"+pkgEnv["GOARM"]+"hf") if err = sh.Copy(newDebPkg, oldDebPkg); err != nil { return fmt.Errorf("could not rename old arm deb package: %w", err)