diff --git a/cmd/finch/main.go b/cmd/finch/main.go index 6b301b8fc..b4460ec4b 100644 --- a/cmd/finch/main.go +++ b/cmd/finch/main.go @@ -125,7 +125,7 @@ func virtualMachineCommands( } func initializeNerdctlCommands(lcc command.LimaCmdCreator, logger flog.Logger) []*cobra.Command { - nerdctlCommandCreator := newNerdctlCommandCreator(lcc, logger) + nerdctlCommandCreator := newNerdctlCommandCreator(lcc, system.NewStdLib(), logger) var allNerdctlCommands []*cobra.Command for cmdName, cmdDescription := range nerdctlCmds { allNerdctlCommands = append(allNerdctlCommands, nerdctlCommandCreator.create(cmdName, cmdDescription)) diff --git a/cmd/finch/nerdctl.go b/cmd/finch/nerdctl.go index 86f437bbf..8eb50af9c 100644 --- a/cmd/finch/nerdctl.go +++ b/cmd/finch/nerdctl.go @@ -4,27 +4,41 @@ 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" +// NerdctlCommandSystemDeps contains the system dependencies for newNerdctlCommand. +// +//go:generate mockgen -copyright_file=../../copyright_header -destination=../../pkg/mocks/nerdctl_cmd_system_deps.go -package=mocks -mock_names NerdctlCommandSystemDeps=NerdctlCommandSystemDeps -source=nerdctl.go NerdctlCommandSystemDeps +type NerdctlCommandSystemDeps interface { + system.EnvChecker +} + type nerdctlCommandCreator struct { - creator command.LimaCmdCreator - logger flog.Logger + creator command.LimaCmdCreator + systemDeps NerdctlCommandSystemDeps + logger flog.Logger } -func newNerdctlCommandCreator(creator command.LimaCmdCreator, logger flog.Logger) *nerdctlCommandCreator { - return &nerdctlCommandCreator{creator: creator, logger: logger} +func newNerdctlCommandCreator(creator command.LimaCmdCreator, systemDeps NerdctlCommandSystemDeps, + logger flog.Logger, +) *nerdctlCommandCreator { + return &nerdctlCommandCreator{creator: creator, systemDeps: systemDeps, logger: logger} } func (ncc *nerdctlCommandCreator) create(cmdName string, cmdDesc string) *cobra.Command { @@ -35,19 +49,20 @@ func (ncc *nerdctlCommandCreator) create(cmdName string, cmdDesc string) *cobra. // the args passed to nerdctlCommand.run will be empty because // cobra will try to parse `-d alpine` as if alpine is the value of the `-d` flag. DisableFlagParsing: true, - RunE: newNerdctlCommand(ncc.creator, ncc.logger).runAdapter, + RunE: newNerdctlCommand(ncc.creator, ncc.systemDeps, ncc.logger).runAdapter, } return command } type nerdctlCommand struct { - creator command.LimaCmdCreator - logger flog.Logger + creator command.LimaCmdCreator + systemDeps NerdctlCommandSystemDeps + logger flog.Logger } -func newNerdctlCommand(creator command.LimaCmdCreator, logger flog.Logger) *nerdctlCommand { - return &nerdctlCommand{creator: creator, logger: logger} +func newNerdctlCommand(creator command.LimaCmdCreator, systemDeps NerdctlCommandSystemDeps, logger flog.Logger) *nerdctlCommand { + return &nerdctlCommand{creator: creator, systemDeps: systemDeps, logger: logger} } func (nc *nerdctlCommand) runAdapter(cmd *cobra.Command, args []string) error { @@ -59,18 +74,63 @@ func (nc *nerdctlCommand) run(cmdName string, args []string) error { if err != nil { return err } + var ( + nerdctlArgs, envs, fileEnvs []string + skip bool + ) - var nerdctlArgs []string - for _, arg := range args { - if arg == "--debug" { + for i, arg := range args { + // parsing environment values from the command line may pre-fetch and + // consume the next argument; this loop variable will skip these pre-consumed + // entries from the command line + 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, addEnv := handleEnv(nc.systemDeps, arg, args[i+1]) + skip = shouldSkip + if addEnv != "" { + envs = append(envs, addEnv) + } + + case strings.HasPrefix(arg, "--env-file"): + shouldSkip, addEnvs, err := handleEnvFile(nc.systemDeps, arg, args[i+1]) + if err != nil { + return err + } + skip = shouldSkip + fileEnvs = append(fileEnvs, addEnvs...) + default: + nerdctlArgs = append(nerdctlArgs, arg) } - nerdctlArgs = append(nerdctlArgs, arg) } + // to handle environment variables properly, we add all entries found via + // env-file includes to the map first and then all command line environment + // flags, making sure that command line overrides environment file options, + // and that later command line flags override earlier ones + envVars := make(map[string]string) - limaArgs := append([]string{"shell", limaInstanceName, nerdctlCmdName, cmdName}, nerdctlArgs...) + for _, e := range fileEnvs { + evar, eval, _ := strings.Cut(e, "=") + envVars[evar] = eval + } + for _, e := range envs { + evar, eval, _ := strings.Cut(e, "=") + envVars[evar] = eval + } + + var finalArgs []string + for key, val := range envVars { + finalArgs = append(finalArgs, "-e", fmt.Sprintf("%s=%s", key, val)) + } + finalArgs = append(finalArgs, nerdctlArgs...) + + limaArgs := append([]string{"shell", limaInstanceName, nerdctlCmdName, cmdName}, finalArgs...) if nc.shouldReplaceForHelp(cmdName, args) { return nc.creator.RunWithReplacingStdout([]command.Replacement{{Source: "nerdctl", Target: "finch"}}, limaArgs...) @@ -122,6 +182,92 @@ 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(systemDeps NerdctlCommandSystemDeps, arg, arg2 string) (bool, string) { + var ( + 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, "=") { + return skip, envVar + } + // if no value was provided we need to check the OS environment + // for a value and only set if it exists in the current env + if val, ok := systemDeps.LookupEnv(envVar); ok { + return skip, fmt.Sprintf("%s=%s", envVar, val) + } + // no value found; do not set the variable in the env + return skip, "" +} + +func handleEnvFile(systemDeps NerdctlCommandSystemDeps, arg, arg2 string) (bool, []string, error) { + var ( + filename 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 + + scanner := bufio.NewScanner(file) + + var envs []string + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + if len(line) == 0 { + continue + } + switch { + case strings.HasPrefix(line, "#"): + // ignore comments + continue + case !strings.Contains(line, "="): + // only has the variable name; need to lookup value + if val, ok := systemDeps.LookupEnv(line); ok { + envs = append(envs, fmt.Sprintf("%s=%s", line, val)) + } + default: + // contains a name and value + envs = append(envs, line) + } + } + if err := scanner.Err(); err != nil { + return skip, []string{}, err + } + return skip, envs, nil +} + var nerdctlCmds = map[string]string{ "build": "Build an image from Dockerfile", "builder": "Manage builds", diff --git a/cmd/finch/nerdctl_test.go b/cmd/finch/nerdctl_test.go index 57e4b78de..7f17f8ee7 100644 --- a/cmd/finch/nerdctl_test.go +++ b/cmd/finch/nerdctl_test.go @@ -6,6 +6,7 @@ package main import ( "errors" "fmt" + "os" "testing" "github.com/golang/mock/gomock" @@ -25,7 +26,7 @@ var testStdoutRs = []command.Replacement{ func TestNerdctlCommandCreator_create(t *testing.T) { t.Parallel() - cmd := newNerdctlCommandCreator(nil, nil).create("build", "build description") + cmd := newNerdctlCommandCreator(nil, nil, nil).create("build", "build description") assert.Equal(t, cmd.Name(), "build") assert.Equal(t, cmd.DisableFlagParsing, true) } @@ -64,10 +65,11 @@ func TestNerdctlCommand_runAdaptor(t *testing.T) { ctrl := gomock.NewController(t) lcc := mocks.NewLimaCmdCreator(ctrl) + ncsd := mocks.NewNerdctlCommandSystemDeps(ctrl) logger := mocks.NewLogger(ctrl) tc.mockSvc(lcc, logger, ctrl) - assert.NoError(t, newNerdctlCommand(lcc, logger).runAdapter(tc.cmd, tc.args)) + assert.NoError(t, newNerdctlCommand(lcc, ncsd, logger).runAdapter(tc.cmd, tc.args)) }) } } @@ -80,14 +82,14 @@ func TestNerdctlCommand_run(t *testing.T) { cmdName string args []string wantErr error - mockSvc func(*mocks.LimaCmdCreator, *mocks.Logger, *gomock.Controller) + mockSvc func(*mocks.LimaCmdCreator, *mocks.NerdctlCommandSystemDeps, *mocks.Logger, *gomock.Controller) }{ { name: "happy path", cmdName: "build", args: []string{"-t", "demo", "."}, wantErr: nil, - mockSvc: func(lcc *mocks.LimaCmdCreator, logger *mocks.Logger, ctrl *gomock.Controller) { + mockSvc: func(lcc *mocks.LimaCmdCreator, ncsd *mocks.NerdctlCommandSystemDeps, logger *mocks.Logger, ctrl *gomock.Controller) { getVMStatusC := mocks.NewCommand(ctrl) lcc.EXPECT().CreateWithoutStdio("ls", "-f", "{{.Status}}", limaInstanceName).Return(getVMStatusC) getVMStatusC.EXPECT().Output().Return([]byte("Running"), nil) @@ -103,7 +105,7 @@ func TestNerdctlCommand_run(t *testing.T) { args: []string{"-t", "demo", "."}, wantErr: fmt.Errorf("instance %q is stopped, run `finch %s start` to start the instance", limaInstanceName, virtualMachineRootCmd), - mockSvc: func(lcc *mocks.LimaCmdCreator, logger *mocks.Logger, ctrl *gomock.Controller) { + mockSvc: func(lcc *mocks.LimaCmdCreator, ncsd *mocks.NerdctlCommandSystemDeps, logger *mocks.Logger, ctrl *gomock.Controller) { getVMStatusC := mocks.NewCommand(ctrl) lcc.EXPECT().CreateWithoutStdio("ls", "-f", "{{.Status}}", limaInstanceName).Return(getVMStatusC) getVMStatusC.EXPECT().Output().Return([]byte("Stopped"), nil) @@ -117,7 +119,7 @@ func TestNerdctlCommand_run(t *testing.T) { wantErr: fmt.Errorf( "instance %q does not exist, run `finch %s init` to create a new instance", limaInstanceName, virtualMachineRootCmd), - mockSvc: func(lcc *mocks.LimaCmdCreator, logger *mocks.Logger, ctrl *gomock.Controller) { + mockSvc: func(lcc *mocks.LimaCmdCreator, ncsd *mocks.NerdctlCommandSystemDeps, logger *mocks.Logger, ctrl *gomock.Controller) { getVMStatusC := mocks.NewCommand(ctrl) lcc.EXPECT().CreateWithoutStdio("ls", "-f", "{{.Status}}", limaInstanceName).Return(getVMStatusC) getVMStatusC.EXPECT().Output().Return([]byte(""), nil) @@ -129,7 +131,7 @@ func TestNerdctlCommand_run(t *testing.T) { cmdName: "build", args: []string{"-t", "demo", "."}, wantErr: errors.New("unrecognized system status"), - mockSvc: func(lcc *mocks.LimaCmdCreator, logger *mocks.Logger, ctrl *gomock.Controller) { + mockSvc: func(lcc *mocks.LimaCmdCreator, ncsd *mocks.NerdctlCommandSystemDeps, logger *mocks.Logger, ctrl *gomock.Controller) { getVMStatusC := mocks.NewCommand(ctrl) lcc.EXPECT().CreateWithoutStdio("ls", "-f", "{{.Status}}", limaInstanceName).Return(getVMStatusC) getVMStatusC.EXPECT().Output().Return([]byte("Broken"), nil) @@ -141,7 +143,7 @@ func TestNerdctlCommand_run(t *testing.T) { cmdName: "build", args: []string{"-t", "demo", "."}, wantErr: errors.New("get status error"), - mockSvc: func(lcc *mocks.LimaCmdCreator, logger *mocks.Logger, ctrl *gomock.Controller) { + mockSvc: func(lcc *mocks.LimaCmdCreator, ncsd *mocks.NerdctlCommandSystemDeps, logger *mocks.Logger, ctrl *gomock.Controller) { getVMStatusC := mocks.NewCommand(ctrl) lcc.EXPECT().CreateWithoutStdio("ls", "-f", "{{.Status}}", limaInstanceName).Return(getVMStatusC) getVMStatusC.EXPECT().Output().Return([]byte("Broken"), errors.New("get status error")) @@ -152,7 +154,7 @@ func TestNerdctlCommand_run(t *testing.T) { cmdName: "pull", args: []string{"test:tag", "--debug"}, wantErr: nil, - mockSvc: func(lcc *mocks.LimaCmdCreator, logger *mocks.Logger, ctrl *gomock.Controller) { + mockSvc: func(lcc *mocks.LimaCmdCreator, ncsd *mocks.NerdctlCommandSystemDeps, logger *mocks.Logger, ctrl *gomock.Controller) { getVMStatusC := mocks.NewCommand(ctrl) lcc.EXPECT().CreateWithoutStdio("ls", "-f", "{{.Status}}", limaInstanceName).Return(getVMStatusC) getVMStatusC.EXPECT().Output().Return([]byte("Running"), nil) @@ -163,12 +165,48 @@ func TestNerdctlCommand_run(t *testing.T) { c.EXPECT().Run() }, }, + { + name: "with environment flags parsing and env value doesn't exist", + cmdName: "run", + args: []string{"--rm", "-e", "ARG1=val1", "--env=ARG2", "-eARG3", "alpine:latest", "env"}, + wantErr: nil, + mockSvc: func(lcc *mocks.LimaCmdCreator, ncsd *mocks.NerdctlCommandSystemDeps, logger *mocks.Logger, ctrl *gomock.Controller) { + getVMStatusC := mocks.NewCommand(ctrl) + lcc.EXPECT().CreateWithoutStdio("ls", "-f", "{{.Status}}", limaInstanceName).Return(getVMStatusC) + getVMStatusC.EXPECT().Output().Return([]byte("Running"), nil) + logger.EXPECT().Debugf("Status of virtual machine: %s", "Running") + c := mocks.NewCommand(ctrl) + ncsd.EXPECT().LookupEnv("ARG2") + ncsd.EXPECT().LookupEnv("ARG3") + lcc.EXPECT().Create("shell", limaInstanceName, nerdctlCmdName, "run", + "-e", "ARG1=val1", "--rm", "alpine:latest", "env").Return(c) + c.EXPECT().Run() + }, + }, + { + name: "with environment flags parsing and env value exists", + cmdName: "run", + args: []string{"--rm", "--env=ARG2", "-eARG3", "alpine:latest", "env"}, + wantErr: nil, + mockSvc: func(lcc *mocks.LimaCmdCreator, ncsd *mocks.NerdctlCommandSystemDeps, logger *mocks.Logger, ctrl *gomock.Controller) { + getVMStatusC := mocks.NewCommand(ctrl) + lcc.EXPECT().CreateWithoutStdio("ls", "-f", "{{.Status}}", limaInstanceName).Return(getVMStatusC) + getVMStatusC.EXPECT().Output().Return([]byte("Running"), nil) + logger.EXPECT().Debugf("Status of virtual machine: %s", "Running") + c := mocks.NewCommand(ctrl) + ncsd.EXPECT().LookupEnv("ARG2") + ncsd.EXPECT().LookupEnv("ARG3").Return("val3", true) + lcc.EXPECT().Create("shell", limaInstanceName, nerdctlCmdName, "run", + "-e", "ARG3=val3", "--rm", "alpine:latest", "env").Return(c) + c.EXPECT().Run() + }, + }, { name: "with --help flag", cmdName: "pull", args: []string{"test:tag", "--help"}, wantErr: nil, - mockSvc: func(lcc *mocks.LimaCmdCreator, logger *mocks.Logger, ctrl *gomock.Controller) { + mockSvc: func(lcc *mocks.LimaCmdCreator, ncsd *mocks.NerdctlCommandSystemDeps, logger *mocks.Logger, ctrl *gomock.Controller) { getVMStatusC := mocks.NewCommand(ctrl) lcc.EXPECT().CreateWithoutStdio("ls", "-f", "{{.Status}}", limaInstanceName).Return(getVMStatusC) getVMStatusC.EXPECT().Output().Return([]byte("Running"), nil) @@ -182,7 +220,7 @@ func TestNerdctlCommand_run(t *testing.T) { cmdName: "pull", args: []string{"test:tag", "--help"}, wantErr: fmt.Errorf("failed to replace"), - mockSvc: func(lcc *mocks.LimaCmdCreator, logger *mocks.Logger, ctrl *gomock.Controller) { + mockSvc: func(lcc *mocks.LimaCmdCreator, ncsd *mocks.NerdctlCommandSystemDeps, logger *mocks.Logger, ctrl *gomock.Controller) { getVMStatusC := mocks.NewCommand(ctrl) lcc.EXPECT().CreateWithoutStdio("ls", "-f", "{{.Status}}", limaInstanceName).Return(getVMStatusC) getVMStatusC.EXPECT().Output().Return([]byte("Running"), nil) @@ -201,11 +239,75 @@ func TestNerdctlCommand_run(t *testing.T) { ctrl := gomock.NewController(t) lcc := mocks.NewLimaCmdCreator(ctrl) + ncsd := mocks.NewNerdctlCommandSystemDeps(ctrl) logger := mocks.NewLogger(ctrl) - tc.mockSvc(lcc, logger, ctrl) - assert.Equal(t, tc.wantErr, newNerdctlCommand(lcc, logger).run(tc.cmdName, tc.args)) + tc.mockSvc(lcc, ncsd, logger, ctrl) + assert.Equal(t, tc.wantErr, newNerdctlCommand(lcc, ncsd, logger).run(tc.cmdName, tc.args)) }) } + t.Run("with --env-file flag replacement", func(t *testing.T) { + t.Parallel() + f, err := os.CreateTemp("", "envfiletest") + assert.NoError(t, err) + defer func() { + f.Close() //nolint:errcheck,gosec //temp file during unit test + os.Remove(f.Name()) //nolint:errcheck,gosec //temp file during unit test + }() + envFileStr := "# a comment\nARG1=val1\n ARG2\n\n # a 2nd comment\nNOTSETARG\n " + _, err = f.Write([]byte(envFileStr)) + assert.NoError(t, err) + cmdName := "run" + args := []string{"--rm", "--env-file", f.Name(), "alpine:latest", "env"} + mockSvc := func(lcc *mocks.LimaCmdCreator, ncsd *mocks.NerdctlCommandSystemDeps, logger *mocks.Logger, ctrl *gomock.Controller) { + getVMStatusC := mocks.NewCommand(ctrl) + lcc.EXPECT().CreateWithoutStdio("ls", "-f", "{{.Status}}", limaInstanceName).Return(getVMStatusC) + getVMStatusC.EXPECT().Output().Return([]byte("Running"), nil) + logger.EXPECT().Debugf("Status of virtual machine: %s", "Running") + c := mocks.NewCommand(ctrl) + ncsd.EXPECT().LookupEnv("ARG2") + ncsd.EXPECT().LookupEnv("NOTSETARG") + lcc.EXPECT().Create("shell", limaInstanceName, nerdctlCmdName, "run", "-e", "ARG1=val1", "--rm", "alpine:latest", "env").Return(c) + c.EXPECT().Run() + } + ctrl := gomock.NewController(t) + lcc := mocks.NewLimaCmdCreator(ctrl) + ncsd := mocks.NewNerdctlCommandSystemDeps(ctrl) + logger := mocks.NewLogger(ctrl) + mockSvc(lcc, ncsd, logger, ctrl) + assert.Equal(t, nil, newNerdctlCommand(lcc, ncsd, logger).run(cmdName, args)) + }) + + t.Run("with --env-file flag replacement and existing env value", func(t *testing.T) { + t.Parallel() + f, err := os.CreateTemp("", "envfiletest") + assert.NoError(t, err) + defer func() { + f.Close() //nolint:errcheck,gosec //temp file during unit test + os.Remove(f.Name()) //nolint:errcheck,gosec //temp file during unit test + }() + envFileStr := "# a comment\n ARG2\n\n # a 2nd comment\nNOTSETARG\n " + _, err = f.Write([]byte(envFileStr)) + assert.NoError(t, err) + cmdName := "run" + args := []string{"--rm", "--env-file", f.Name(), "alpine:latest", "env"} + mockSvc := func(lcc *mocks.LimaCmdCreator, ncsd *mocks.NerdctlCommandSystemDeps, logger *mocks.Logger, ctrl *gomock.Controller) { + getVMStatusC := mocks.NewCommand(ctrl) + lcc.EXPECT().CreateWithoutStdio("ls", "-f", "{{.Status}}", limaInstanceName).Return(getVMStatusC) + getVMStatusC.EXPECT().Output().Return([]byte("Running"), nil) + logger.EXPECT().Debugf("Status of virtual machine: %s", "Running") + c := mocks.NewCommand(ctrl) + ncsd.EXPECT().LookupEnv("ARG2").Return("val2", true) + ncsd.EXPECT().LookupEnv("NOTSETARG") + lcc.EXPECT().Create("shell", limaInstanceName, nerdctlCmdName, "run", "-e", "ARG2=val2", "--rm", "alpine:latest", "env").Return(c) + c.EXPECT().Run() + } + ctrl := gomock.NewController(t) + lcc := mocks.NewLimaCmdCreator(ctrl) + ncsd := mocks.NewNerdctlCommandSystemDeps(ctrl) + logger := mocks.NewLogger(ctrl) + mockSvc(lcc, ncsd, logger, ctrl) + assert.Equal(t, nil, newNerdctlCommand(lcc, ncsd, logger).run(cmdName, args)) + }) } func TestNerdctlCommand_shouldReplaceForHelp(t *testing.T) { @@ -264,8 +366,9 @@ func TestNerdctlCommand_shouldReplaceForHelp(t *testing.T) { ctrl := gomock.NewController(t) lcc := mocks.NewLimaCmdCreator(ctrl) + ncsd := mocks.NewNerdctlCommandSystemDeps(ctrl) logger := mocks.NewLogger(ctrl) - assert.True(t, newNerdctlCommand(lcc, logger).shouldReplaceForHelp(tc.cmdName, tc.args)) + assert.True(t, newNerdctlCommand(lcc, ncsd, logger).shouldReplaceForHelp(tc.cmdName, tc.args)) }) } } diff --git a/pkg/mocks/nerdctl_cmd_system_deps.go b/pkg/mocks/nerdctl_cmd_system_deps.go new file mode 100644 index 000000000..68a6942f4 --- /dev/null +++ b/pkg/mocks/nerdctl_cmd_system_deps.go @@ -0,0 +1,52 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by MockGen. DO NOT EDIT. +// Source: nerdctl.go + +// Package mocks is a generated GoMock package. +package mocks + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" +) + +// NerdctlCommandSystemDeps is a mock of NerdctlCommandSystemDeps interface. +type NerdctlCommandSystemDeps struct { + ctrl *gomock.Controller + recorder *NerdctlCommandSystemDepsMockRecorder +} + +// NerdctlCommandSystemDepsMockRecorder is the mock recorder for NerdctlCommandSystemDeps. +type NerdctlCommandSystemDepsMockRecorder struct { + mock *NerdctlCommandSystemDeps +} + +// NewNerdctlCommandSystemDeps creates a new mock instance. +func NewNerdctlCommandSystemDeps(ctrl *gomock.Controller) *NerdctlCommandSystemDeps { + mock := &NerdctlCommandSystemDeps{ctrl: ctrl} + mock.recorder = &NerdctlCommandSystemDepsMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *NerdctlCommandSystemDeps) EXPECT() *NerdctlCommandSystemDepsMockRecorder { + return m.recorder +} + +// LookupEnv mocks base method. +func (m *NerdctlCommandSystemDeps) LookupEnv(key string) (string, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LookupEnv", key) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// LookupEnv indicates an expected call of LookupEnv. +func (mr *NerdctlCommandSystemDepsMockRecorder) LookupEnv(key interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LookupEnv", reflect.TypeOf((*NerdctlCommandSystemDeps)(nil).LookupEnv), key) +} 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 } diff --git a/pkg/system/system.go b/pkg/system/system.go index 985a9e060..92c6323e9 100644 --- a/pkg/system/system.go +++ b/pkg/system/system.go @@ -47,6 +47,11 @@ type EnvGetter interface { Env(key string) string } +// EnvChecker mocks out os.LookupEnv. +type EnvChecker interface { + LookupEnv(key string) (string, bool) +} + // StdinGetter mocks out os.Stdin. type StdinGetter interface { Stdin() *os.File