From e6eb334d4e65d6c2f519b756533683a1bde29e4d Mon Sep 17 00:00:00 2001 From: Mohammed Al Sahaf Date: Tue, 16 Aug 2022 21:27:48 +0000 Subject: [PATCH] core: add `XCADDY_GO_MOD_FLAGS` env var to allow passing custom `go mod` flags (#113) --- README.md | 4 +++- builder.go | 5 +++-- cmd/main.go | 2 ++ environment.go | 38 +++++++++++++++++++++++++++++--------- 4 files changed, 37 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 7fcecb5..6e29c34 100644 --- a/README.md +++ b/README.md @@ -157,7 +157,9 @@ Because the subcommands and flags are constrained to benefit rapid plugin protot - `XCADDY_SKIP_BUILD=1` causes xcaddy to not compile the program, it is used in conjunction with build tools such as [GoReleaser](https://goreleaser.com). Implies `XCADDY_SKIP_CLEANUP=1`. - `XCADDY_SKIP_CLEANUP=1` causes xcaddy to leave build artifacts on disk after exiting. - `XCADDY_WHICH_GO` sets the go command to use when for example more then 1 version of go is installed. -- `XCADDY_GO_BUILD_FLAGS` overrides default build arguments. Supports Unix-style shell quoting, for example: XCADDY_GO_BUILD_FLAGS="-ldflags '-w s'". +- `XCADDY_GO_BUILD_FLAGS` overrides default build arguments. Supports Unix-style shell quoting, for example: XCADDY_GO_BUILD_FLAGS="-ldflags '-w s'". The provided flags are applied to `go` commands: build, clean, get, install, list, run, and test +- `XCADDY_GO_MOD_FLAGS` overrides default `go mod` arguments. Supports Unix-style shell quoting. + --- © 2020 Matthew Holt diff --git a/builder.go b/builder.go index 328d257..ed6c5ef 100644 --- a/builder.go +++ b/builder.go @@ -45,6 +45,7 @@ type Builder struct { SkipBuild bool `json:"skip_build,omitempty"` Debug bool `json:"debug,omitempty"` BuildFlags string `json:"build_flags,omitempty"` + ModFlags string `json:"mod_flags,omitempty"` } // Build builds Caddy at the configured version with the @@ -102,13 +103,13 @@ func (b Builder) Build(ctx context.Context, outputFile string) error { log.Println("[INFO] Building Caddy") // tidy the module to ensure go.mod and go.sum are consistent with the module prereq - tidyCmd := buildEnv.newGoCommand("mod", "tidy") + tidyCmd := buildEnv.newGoModCommand("tidy") if err := buildEnv.runCommand(ctx, tidyCmd, b.TimeoutGet); err != nil { return err } // compile - cmd := buildEnv.newGoCommand("build", + cmd := buildEnv.newGoBuildCommand("build", "-o", absOutputFile, ) if b.Debug { diff --git a/cmd/main.go b/cmd/main.go index cb2ce05..432f65a 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -41,6 +41,7 @@ var ( skipCleanup = os.Getenv("XCADDY_SKIP_CLEANUP") == "1" || skipBuild buildDebugOutput = os.Getenv("XCADDY_DEBUG") == "1" buildFlags = os.Getenv("XCADDY_GO_BUILD_FLAGS") + modFlags = os.Getenv("XCADDY_GO_MOD_FLAGS") ) func Main() { @@ -136,6 +137,7 @@ func runBuild(ctx context.Context, args []string) error { SkipCleanup: skipCleanup, Debug: buildDebugOutput, BuildFlags: buildFlags, + ModFlags: modFlags, } err := builder.Build(ctx, output) if err != nil { diff --git a/environment.go b/environment.go index aff7ea4..f9069c9 100644 --- a/environment.go +++ b/environment.go @@ -100,11 +100,12 @@ func (b Builder) newEnvironment(ctx context.Context) (*environment, error) { timeoutGoGet: b.TimeoutGet, skipCleanup: b.SkipCleanup, buildFlags: b.BuildFlags, + modFlags: b.ModFlags, } // initialize the go module log.Println("[INFO] Initializing Go module") - cmd := env.newGoCommand("mod", "init") + cmd := env.newGoModCommand("init") cmd.Args = append(cmd.Args, "caddy") err = env.runCommand(ctx, cmd, 10*time.Second) if err != nil { @@ -115,7 +116,7 @@ func (b Builder) newEnvironment(ctx context.Context) (*environment, error) { replaced := make(map[string]string) for _, r := range b.Replacements { log.Printf("[INFO] Replace %s => %s", r.Old.String(), r.New.String()) - cmd := env.newGoCommand("mod", "edit", + cmd := env.newGoModCommand("edit", "-replace", fmt.Sprintf("%s=%s", r.Old.Param(), r.New.Param())) err := env.runCommand(ctx, cmd, 10*time.Second) if err != nil { @@ -181,6 +182,7 @@ type environment struct { timeoutGoGet time.Duration skipCleanup bool buildFlags string + modFlags string } // Close cleans up the build environment, including deleting @@ -194,22 +196,40 @@ func (env environment) Close() error { return os.RemoveAll(env.tempFolder) } -func (env environment) newGoCommand(args ...string) *exec.Cmd { - cmd := exec.Command(utils.GetGo(), args...) +func (env environment) newCommand(command string, args ...string) *exec.Cmd { + cmd := exec.Command(command, args...) cmd.Dir = env.tempFolder cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr + return cmd +} + +// newGoBuildCommand creates a new *exec.Cmd which assumes the first element in `args` is one of: build, clean, get, install, list, run, or test. The +// created command will also have the value of `XCADDY_GO_BUILD_FLAGS` appended to its arguments, if set. +func (env environment) newGoBuildCommand(args ...string) *exec.Cmd { + cmd := env.newCommand(utils.GetGo(), args...) + return parseAndAppendFlags(cmd, env.buildFlags) +} + +// newGoModCommand creates a new *exec.Cmd which assumes `args` are the args for `go mod` command. The +// created command will also have the value of `XCADDY_GO_MOD_FLAGS` appended to its arguments, if set. +func (env environment) newGoModCommand(args ...string) *exec.Cmd { + args = append([]string{"mod"}, args...) + cmd := env.newCommand(utils.GetGo(), args...) + return parseAndAppendFlags(cmd, env.modFlags) +} - if env.buildFlags == "" { +func parseAndAppendFlags(cmd *exec.Cmd, flags string) *exec.Cmd { + if strings.TrimSpace(flags) == "" { return cmd } - flags, err := shlex.Split(env.buildFlags) + fs, err := shlex.Split(flags) if err != nil { - log.Printf("[ERROR] Splitting arguments failed: %s", env.buildFlags) + log.Printf("[ERROR] Splitting arguments failed: %s", flags) return cmd } - cmd.Args = append(cmd.Args, flags...) + cmd.Args = append(cmd.Args, fs...) return cmd } @@ -276,7 +296,7 @@ func (env environment) execGoGet(ctx context.Context, modulePath, moduleVersion, caddy += "@" + caddyVersion } - cmd := env.newGoCommand("get", "-d", "-v") + cmd := env.newGoBuildCommand("get", "-d", "-v") // using an empty string as an additional argument to "go get" // breaks the command since it treats the empty string as a // distinct argument, so we're using an if statement to avoid it.