diff --git a/cmd/finch/nerdctl.go b/cmd/finch/nerdctl.go index 86f437bbf..b0a2b9b86 100644 --- a/cmd/finch/nerdctl.go +++ b/cmd/finch/nerdctl.go @@ -4,16 +4,20 @@ package main import ( + "bufio" "fmt" + "os" + "path/filepath" + "strings" "github.com/spf13/cobra" + "github.com/runfinch/finch/pkg/command" "github.com/runfinch/finch/pkg/flog" + "github.com/runfinch/finch/pkg/lima" + "github.com/runfinch/finch/pkg/system" "k8s.io/apimachinery/pkg/util/sets" - - "github.com/runfinch/finch/pkg/command" - "github.com/runfinch/finch/pkg/lima" ) const nerdctlCmdName = "nerdctl" @@ -59,15 +63,35 @@ func (nc *nerdctlCommand) run(cmdName string, args []string) error { if err != nil { return err } - - var nerdctlArgs []string - for _, arg := range args { - if arg == "--debug" { + var ( + nerdctlArgs []string + skip bool + ) + for i, arg := range args { + // pre-parsing environment values on the command line may pre-fetch the next + // argument; will skip in this loop based on result of parsing env entries + if skip { + skip = false + continue + } + switch { + case arg == "--debug": // explicitly setting log level to avoid `--debug` flag being interpreted as nerdctl command nc.logger.SetLevel(flog.Debug) - continue + case argIsEnv(arg): + shouldSkip, addArgs := handleEnv(arg, args[i+1]) + skip = shouldSkip + nerdctlArgs = append(nerdctlArgs, addArgs...) + case strings.HasPrefix(arg, "--env-file"): + shouldSkip, additionalEnvs, err := handleEnvFile(arg, args[i+1]) + if err != nil { + return err + } + skip = shouldSkip + nerdctlArgs = append(nerdctlArgs, additionalEnvs...) + default: + nerdctlArgs = append(nerdctlArgs, arg) } - nerdctlArgs = append(nerdctlArgs, arg) } limaArgs := append([]string{"shell", limaInstanceName, nerdctlCmdName, cmdName}, nerdctlArgs...) @@ -122,6 +146,86 @@ func (nc *nerdctlCommand) shouldReplaceForHelp(cmdName string, args []string) bo return false } +func argIsEnv(arg string) bool { + if strings.HasPrefix(arg, "-e") || (strings.HasPrefix(arg, "--env") && !strings.HasPrefix(arg, "--env-file")) { + return true + } + return false +} + +func handleEnv(arg, arg2 string) (bool, []string) { + stdlib := system.NewStdLib() + var ( + additionalArgs []string + envVar string + skip bool + ) + switch arg { + case "-e", "--env": + skip = true + envVar = arg2 + default: + // flag and value are in the same string + if strings.HasPrefix(arg, "-e") { + envVar = arg[2:] + } else { + // only other case is "--env="; skip that prefix + envVar = arg[6:] + } + } + + if !strings.Contains(envVar, "=") { + // need to lookup value from OS environment, and only set if it exists in the env + if val, ok := stdlib.LookupEnv(envVar); ok { + additionalArgs = append(additionalArgs, "-e", fmt.Sprintf("%s=%s", envVar, val)) + } + } else { + additionalArgs = append(additionalArgs, "-e", envVar) + } + return skip, additionalArgs +} + +func handleEnvFile(arg, arg2 string) (bool, []string, error) { + var ( + filename string + additionalArgs []string + skip bool + ) + + switch arg { + case "--env-file": + skip = true + filename = arg2 + default: + filename = arg[11:] + } + + file, err := os.Open(filepath.Clean(filename)) + if err != nil { + return false, []string{}, err + } + defer file.Close() //nolint:errcheck,gosec // close of a file in O_RDONLY mode has no gosec issue + + stdlib := system.NewStdLib() + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := scanner.Text() + if !strings.Contains(line, "=") { + // only has the variable name; need to lookup value + if val, ok := stdlib.LookupEnv(line); ok { + additionalArgs = append(additionalArgs, "-e", fmt.Sprintf("%s=%s", line, val)) + } + } else { + // a name and value; add as a "-e" param to the command line + additionalArgs = append(additionalArgs, "-e", line) + } + } + if err := scanner.Err(); err != nil { + return skip, []string{}, err + } + return skip, additionalArgs, nil +} + var nerdctlCmds = map[string]string{ "build": "Build an image from Dockerfile", "builder": "Manage builds", diff --git a/pkg/system/stdlib.go b/pkg/system/stdlib.go index 8dde8d2f4..0f9f1d1c7 100644 --- a/pkg/system/stdlib.go +++ b/pkg/system/stdlib.go @@ -38,6 +38,10 @@ func (s *StdLib) Env(key string) string { return os.Getenv(key) } +func (s *StdLib) LookupEnv(key string) (string, bool) { + return os.LookupEnv(key) +} + func (s *StdLib) Stdin() *os.File { return os.Stdin }