grafana/pkg/build/golangutils/build.go
Kevin Minehart d567f199dd
CI: add the grabpl build-backend command into the repo (#52673)
* Move the grabpl build-backend command and clean it up a bit
2022-07-28 10:11:22 -04:00

125 lines
3.1 KiB
Go

package golangutils
import (
"context"
"fmt"
"io"
"os/exec"
"strings"
"github.com/grafana/grafana/pkg/build/config"
)
type BuildOpts struct {
// Package refers to the path to the `main` package containing `func main`
Package string
// Output is used as the -o argument in the go build command
Output string
// Workdir should define some place in the module where the package path resolves.
// Go commands need to be ran inside a the Go module directory.
Workdir string
GoOS config.OS
GoArch config.Architecture
GoArm string
Go386 string
CC string
LibC string
CGoEnabled bool
CGoCFlags string
// LdFlags are joined by a space character and provided to the -ldflags argument.
// A valid element here would be `-X 'main.version=1.0.0'`.
LdFlags []string
Stdout io.ReadWriter
Stderr io.ReadWriter
Stdin io.ReadWriter
// ExtraEnv allows consumers to provide extra env args that are not defined above.
// A single element should be formatted using like so: {NAME}={VALUE}. Example: GOOS=linux.
ExtraEnv []string
// ExtraArgs allows consumers to provide extra arguments that are not defined above.
// Flag names and values should be two separate elements.
// These flags will be appended to the command arguments before the package path in "go build".
ExtraArgs []string
}
// Env constructs a list of key/value pairs for setting a build command's environment.
// Should we consider using something to unmarshal the struct to env?
func (opts BuildOpts) Env() []string {
env := []string{}
if opts.CGoEnabled {
env = append(env, "CGO_ENABLED=1")
}
if opts.GoOS != "" {
env = append(env, fmt.Sprintf("GOOS=%s", opts.GoOS))
}
if opts.GoArch != "" {
env = append(env, fmt.Sprintf("GOARCH=%s", opts.GoArch))
}
if opts.CC != "" {
env = append(env, fmt.Sprintf("CC=%s", opts.CC))
}
if opts.CGoCFlags != "" {
env = append(env, fmt.Sprintf("CGO_CFLAGS=%s", opts.CGoCFlags))
}
if opts.GoArm != "" {
env = append(env, fmt.Sprintf("GOARM=%s", opts.GoArm))
}
if opts.ExtraEnv != nil {
return append(opts.ExtraEnv, env...)
}
return env
}
// Args constructs a list of flags and values for use with the exec.Command type when running "go build".
func (opts BuildOpts) Args() []string {
args := []string{}
if opts.LdFlags != nil {
args = append(args, "-ldflags", strings.Join(opts.LdFlags, " "))
}
if opts.Output != "" {
args = append(args, "-o", opts.Output)
}
if opts.ExtraArgs != nil {
args = append(args, opts.ExtraArgs...)
}
args = append(args, opts.Package)
return args
}
// Build runs the go build process in the current shell given the opts.
// This function will panic if no Stdout/Stderr/Stdin is provided in the opts.
func RunBuild(ctx context.Context, opts BuildOpts) error {
env := opts.Env()
args := append([]string{"build"}, opts.Args()...)
// Ignore gosec G304 as this function is only used in the build process.
//nolint:gosec
cmd := exec.CommandContext(ctx, "go", args...)
cmd.Env = env
cmd.Stdout = opts.Stdout
cmd.Stderr = opts.Stderr
cmd.Stdin = opts.Stdin
cmd.Dir = opts.Workdir
return cmd.Run()
}