package gocmd import ( "bytes" "context" "fmt" "os" "path/filepath" "strings" "git.cw.tr/mukan-network/mukan-ignite/ignite/pkg/cmdrunner/exec" "git.cw.tr/mukan-network/mukan-ignite/ignite/pkg/cmdrunner/step" "git.cw.tr/mukan-network/mukan-ignite/ignite/pkg/errors" "git.cw.tr/mukan-network/mukan-ignite/ignite/pkg/goenv" ) const ( // CommandInstall represents go "install" command. CommandInstall = "install" // CommandGet represents go "get" command. CommandGet = "get" // CommandBuild represents go "build" command. CommandBuild = "build" // CommandMod represents go "mod" command. CommandMod = "mod" // CommandModTidy represents go mod "tidy" command. CommandModTidy = "tidy" // CommandModVerify represents go mod "verify" command. CommandModVerify = "verify" // CommandModDownload represents go mod "download" command. CommandModDownload = "download" // CommandFmt represents go "fmt" command. CommandFmt = "fmt" // CommandEnv represents go "env" command. CommandEnv = "env" // CommandList represents go "list" command. CommandList = "list" // CommandTest represents go "test" command. CommandTest = "test" // EnvGOARCH represents GOARCH variable. EnvGOARCH = "GOARCH" // EnvGOMOD represents GOMOD variable. EnvGOMOD = "GOMOD" // EnvGOOS represents GOOS variable. EnvGOOS = "GOOS" // FlagGcflags represents gcflags go flag. FlagGcflags = "-gcflags" // FlagGcflagsValueDebug represents debug go flags. FlagGcflagsValueDebug = "all=-N -l" // FlagLdflags represents ldflags go flag. FlagLdflags = "-ldflags" // FlagTags represents tags go flag. FlagTags = "-tags" // FlagMod represents mod go flag. FlagMod = "-mod" // FlagModValueReadOnly represents readonly go flag. FlagModValueReadOnly = "readonly" // FlagOut represents out go flag. FlagOut = "-o" ) // Env returns the value of `go env name`. func Env(name string) (string, error) { var b bytes.Buffer err := exec.Exec(context.Background(), []string{Name(), CommandEnv, name}, exec.StepOption(step.Stdout(&b))) return b.String(), err } // Name returns the name of Go binary to use. func Name() string { custom := os.Getenv("GONAME") if custom != "" { return custom } return "go" } // Fmt runs go fmt on path. func Fmt(ctx context.Context, path string, options ...exec.Option) error { return exec.Exec(ctx, []string{Name(), CommandFmt, "./..."}, append(options, exec.StepOption(step.Workdir(path)))...) } // ModTidy runs go mod tidy on path with options. func ModTidy(ctx context.Context, path string, options ...exec.Option) error { return exec.Exec(ctx, []string{Name(), CommandMod, CommandModTidy}, append(options, exec.StepOption(step.Workdir(path)), // FIXME(tb) untagged version of ignite/cli triggers a 404 not found when go // mod tidy requests the sumdb, until we understand why, we disable sumdb. // related issue: https://github.com/golang/go/issues/56174 // Also disable Go toolchain download because it doesn't work without a valid // GOSUMDB value: https://go.dev/doc/toolchain#download exec.StepOption(step.Env("GOSUMDB=off", "GOTOOLCHAIN=local+path")), )...) } // ModVerify runs go mod verify on path with options. func ModVerify(ctx context.Context, path string, options ...exec.Option) error { return exec.Exec(ctx, []string{Name(), CommandMod, CommandModVerify}, append(options, exec.StepOption(step.Workdir(path)))...) } // ModDownload runs go mod download on a path with options. func ModDownload(ctx context.Context, path string, json bool, options ...exec.Option) error { command := []string{Name(), CommandMod, CommandModDownload} if json { command = append(command, "-json") } return exec.Exec(ctx, command, append(options, exec.StepOption(step.Workdir(path)))...) } // BuildPath runs go install on cmd folder with options. func BuildPath(ctx context.Context, output, binary, path string, flags []string, options ...exec.Option) error { binaryOutput, err := binaryPath(output, binary) if err != nil { return err } command := []string{ Name(), CommandBuild, FlagOut, binaryOutput, } command = append(command, flags...) command = append(command, ".") return exec.Exec(ctx, command, append(options, exec.StepOption(step.Workdir(path)))...) } // Build runs go build on path with options. func Build(ctx context.Context, out, path string, flags []string, options ...exec.Option) error { command := []string{ Name(), CommandBuild, FlagOut, out, } command = append(command, flags...) return exec.Exec(ctx, command, append(options, exec.StepOption(step.Workdir(path)))...) } // InstallAll runs go install ./... on path with options. func InstallAll(ctx context.Context, path string, flags []string, options ...exec.Option) error { command := []string{ Name(), CommandInstall, } command = append(command, flags...) command = append(command, "./...") return exec.Exec(ctx, command, append(options, exec.StepOption(step.Workdir(path)))...) } // Install runs go install pkgs on path with options. func Install(ctx context.Context, path string, pkgs []string, options ...exec.Option) error { command := []string{ Name(), CommandInstall, } command = append(command, pkgs...) return exec.Exec(ctx, command, append(options, exec.StepOption(step.Workdir(path)))...) } // Get runs go get pkgs on path with options. func Get(ctx context.Context, path string, pkgs []string, options ...exec.Option) error { command := []string{ Name(), CommandGet, } command = append(command, pkgs...) return exec.Exec(ctx, command, append(options, exec.StepOption(step.Workdir(path)))...) } // List returns the list of packages in path. func List(ctx context.Context, path string, flags []string, options ...exec.Option) ([]string, error) { command := []string{ Name(), CommandList, } command = append(command, flags...) var b bytes.Buffer err := exec.Exec(ctx, command, append(options, exec.StepOption(step.Workdir(path)), exec.StepOption(step.Stdout(&b)))...) if err != nil { return nil, err } return strings.Fields(b.String()), nil } func Test(ctx context.Context, path string, flags []string, options ...exec.Option) error { command := []string{ Name(), CommandTest, } command = append(command, flags...) return exec.Exec(ctx, command, append(options, exec.StepOption(step.Workdir(path)))...) } // Ldflags returns a combined ldflags set from flags. func Ldflags(flags ...string) string { return strings.Join(flags, " ") } // Tags returns a combined tags set from flags. func Tags(tags ...string) string { return strings.Join(tags, " ") } // BuildTarget builds a GOOS:GOARCH pair. func BuildTarget(goos, goarch string) string { return fmt.Sprintf("%s:%s", goos, goarch) } // ParseTarget parses GOOS:GOARCH pair. func ParseTarget(t string) (goos, goarch string, err error) { parsed := strings.Split(t, ":") if len(parsed) != 2 { return "", "", errors.New("invalid Go target, expected in GOOS:GOARCH format") } return parsed[0], parsed[1], nil } // PackageLiteral returns the string representation of package part of go get [package]. func PackageLiteral(path, version string) string { return fmt.Sprintf("%s@%s", path, version) } // Imports runs goimports on path with options. func GoImports(ctx context.Context, path string) error { return exec.Exec(ctx, []string{"go", "tool", "golang.org/x/tools/cmd/goimports", "-w", path}) } // binaryPath determines the path where binary will be located at. func binaryPath(output, binary string) (string, error) { if output != "" { outputAbs, err := filepath.Abs(output) if err != nil { return "", err } return filepath.Join(outputAbs, binary), nil } return filepath.Join(goenv.Bin(), binary), nil }