Skip to content

Commit b1cd112

Browse files
authored
feat: add cmdutil package to provide utils for commands (#970)
## Summary 1. add cmdutil package 2. move command related functions to this package 3. tweak some error handling ## How was it tested?
1 parent 625b2f3 commit b1cd112

File tree

10 files changed

+70
-49
lines changed

10 files changed

+70
-49
lines changed

internal/boxcli/root.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"strings"
1212

1313
"github.com/spf13/cobra"
14+
1415
"go.jetpack.io/devbox/internal/boxcli/midcobra"
1516
"go.jetpack.io/devbox/internal/cloud/openssh/sshshim"
1617
"go.jetpack.io/devbox/internal/debug"
@@ -19,8 +20,8 @@ import (
1920
)
2021

2122
var (
22-
debugMiddleware *midcobra.DebugMiddleware = &midcobra.DebugMiddleware{}
23-
traceMiddleware *midcobra.TraceMiddleware = &midcobra.TraceMiddleware{}
23+
debugMiddleware = &midcobra.DebugMiddleware{}
24+
traceMiddleware = &midcobra.TraceMiddleware{}
2425
)
2526

2627
type rootCmdFlags struct {

internal/cmdutil/cmdutil.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2023 Jetpack Technologies Inc and contributors. All rights reserved.
2+
// Use of this source code is governed by the license in the LICENSE file.
3+
4+
package cmdutil
5+
6+
import (
7+
"os/exec"
8+
)
9+
10+
// Exists indicates if the command exists
11+
func Exists(command string) bool {
12+
_, err := exec.LookPath(command)
13+
return err == nil
14+
}
15+
16+
// GetPathOrDefault gets the path for the given command.
17+
// If it's not found, it will return the given value instead.
18+
func GetPathOrDefault(command string, def string) string {
19+
path, err := exec.LookPath(command)
20+
if err != nil {
21+
path = def
22+
}
23+
24+
return path
25+
}

internal/impl/devbox.go

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"go.jetpack.io/devbox/internal/boxcli/featureflag"
2727
"go.jetpack.io/devbox/internal/boxcli/generate"
2828
"go.jetpack.io/devbox/internal/boxcli/usererr"
29+
"go.jetpack.io/devbox/internal/cmdutil"
2930
"go.jetpack.io/devbox/internal/conf"
3031
"go.jetpack.io/devbox/internal/cuecfg"
3132
"go.jetpack.io/devbox/internal/debug"
@@ -383,7 +384,7 @@ func (d *Devbox) GenerateEnvrc(force bool, source string) error {
383384
)
384385
}
385386
// confirm .envrc doesn't exist and don't overwrite an existing .envrc
386-
if commandExists("direnv") {
387+
if cmdutil.Exists("direnv") {
387388
// prompt for direnv allow
388389
var result string
389390
isInteractiveMode := isatty.IsTerminal(os.Stdin.Fd())
@@ -815,22 +816,26 @@ var nixEnvCache map[string]string
815816
// Note that this is in-memory cache of the final environment, and not the same
816817
// as the nix print-dev-env cache which is stored in a file.
817818
func (d *Devbox) nixEnv(ctx context.Context) (map[string]string, error) {
818-
var err error
819-
if nixEnvCache == nil {
820-
usePrintDevEnvCache := false
821-
822-
// If lockfile is up-to-date, we can use the print-dev-env cache.
823-
if lock, err := lock.Local(d); err != nil {
824-
return nil, err
825-
} else if upToDate, err := lock.IsUpToDate(); err != nil {
826-
return nil, err
827-
} else if upToDate {
828-
usePrintDevEnvCache = true
829-
}
819+
if nixEnvCache != nil {
820+
return nixEnvCache, nil
821+
}
830822

831-
nixEnvCache, err = d.computeNixEnv(ctx, usePrintDevEnvCache)
823+
usePrintDevEnvCache := false
824+
825+
// If lockfile is up-to-date, we can use the print-dev-env cache.
826+
lockFile, err := lock.Local(d)
827+
if err != nil {
828+
return nil, err
832829
}
833-
return nixEnvCache, err
830+
upToDate, err := lockFile.IsUpToDate()
831+
if err != nil {
832+
return nil, err
833+
}
834+
if upToDate {
835+
usePrintDevEnvCache = true
836+
}
837+
838+
return d.computeNixEnv(ctx, usePrintDevEnvCache)
834839
}
835840

836841
func (d *Devbox) ogPathKey() string {
@@ -947,11 +952,6 @@ func (d *Devbox) configEnvs(computedEnv map[string]string) map[string]string {
947952
return conf.OSExpandEnvMap(d.cfg.Env, computedEnv, d.ProjectDir())
948953
}
949954

950-
func commandExists(command string) bool { // TODO: move to a utility package
951-
_, err := exec.LookPath(command)
952-
return err == nil
953-
}
954-
955955
// ignoreCurrentEnvVar contains environment variables that Devbox should remove
956956
// from the slice of [os.Environ] variables before sourcing them. These are
957957
// variables that are set automatically by a new shell.
@@ -1042,7 +1042,6 @@ func addHashToEnv(env map[string]string) error {
10421042
hash, err := cuecfg.Hash(env)
10431043
if err == nil {
10441044
env[devboxShellEnvHashVarName] = hash
1045-
10461045
}
10471046
return err
10481047
}

internal/impl/global.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,17 @@ func (d *Devbox) AddGlobal(pkgs ...string) error {
3838
found, err := nix.PkgExists(pkg, d.lockfile)
3939
if err != nil {
4040
return err
41-
} else if !found {
41+
}
42+
if !found {
4243
return nix.ErrPackageNotFound
4344
}
4445
}
45-
var added []string
4646
profilePath, err := GlobalNixProfilePath()
4747
if err != nil {
4848
return err
4949
}
5050

51+
var added []string
5152
total := len(pkgs)
5253
for idx, pkg := range pkgs {
5354
stepNum := idx + 1

internal/nix/doc.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright 2023 Jetpack Technologies Inc and contributors. All rights reserved.
22
// Use of this source code is governed by the license in the LICENSE file.
33

4-
// Go API for nix.
4+
// Package nix provides Go API for nix.
55
// Internally this is a wrapper around the nix command line utilities.
66
// I'd love to use a go SDK instead, and drop the dependency on the CLI.
77
// The dependency means that users need to install nix, before using devbox.

internal/nix/install.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818

1919
"go.jetpack.io/devbox/internal/boxcli/usererr"
2020
"go.jetpack.io/devbox/internal/build"
21+
"go.jetpack.io/devbox/internal/cmdutil"
2122
"go.jetpack.io/devbox/internal/fileutil"
2223
)
2324

@@ -82,8 +83,7 @@ func Install(writer io.Writer, daemon *bool) error {
8283
}
8384

8485
func BinaryInstalled() bool {
85-
_, err := exec.LookPath("nix")
86-
return err == nil
86+
return cmdutil.Exists("nix")
8787
}
8888

8989
func dirExists() bool {

internal/nix/run.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"os/exec"
1111

1212
"go.jetpack.io/devbox/internal/boxcli/usererr"
13+
"go.jetpack.io/devbox/internal/cmdutil"
1314
"go.jetpack.io/devbox/internal/debug"
1415
)
1516

@@ -24,10 +25,7 @@ func RunScript(projectDir string, cmdWithArgs string, env map[string]string) err
2425
}
2526

2627
// Try to find sh in the PATH, if not, default to a well known absolute path.
27-
shPath, err := exec.LookPath("sh")
28-
if err != nil {
29-
shPath = "/bin/sh"
30-
}
28+
shPath := cmdutil.GetPathOrDefault("sh", "/bin/sh")
3129
cmd := exec.Command(shPath, "-c", cmdWithArgs)
3230
cmd.Env = envPairs
3331
cmd.Dir = projectDir

internal/services/manager.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ func openGlobalConfigFile() (*os.File, error) {
109109

110110
err = lockFile(globalConfigFile)
111111
if err != nil {
112-
return nil, err
112+
return nil, fmt.Errorf("failed to lock file: %w", err)
113113
}
114114

115115
return globalConfigFile, nil
@@ -204,11 +204,11 @@ func runProcessManagerInForeground(cmd *exec.Cmd, config *globalProcessComposeCo
204204
config.File.Close()
205205

206206
err = cmd.Wait()
207-
208-
if err != nil && err.Error() == "exit status 1" {
209-
fmt.Fprintf(w, "Process-compose was terminated remotely, %s\n", err.Error())
210-
return nil
211-
} else if err != nil {
207+
if err != nil {
208+
if err.Error() == "exit status 1" {
209+
fmt.Fprintf(w, "Process-compose was terminated remotely, %s\n", err.Error())
210+
return nil
211+
}
212212
return err
213213
}
214214

@@ -246,7 +246,7 @@ func runProcessManagerInBackground(cmd *exec.Cmd, config *globalProcessComposeCo
246246

247247
err = writeGlobalProcessComposeJSON(config, config.File)
248248
if err != nil {
249-
return fmt.Errorf("failed to write global process-compose config")
249+
return fmt.Errorf("failed to write global process-compose config: %w", err)
250250
}
251251

252252
return nil

internal/vercheck/vercheck.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@ import (
1515

1616
"github.com/fatih/color"
1717
"github.com/pkg/errors"
18-
"go.jetpack.io/devbox/internal/build"
19-
"go.jetpack.io/devbox/internal/ux"
2018
"golang.org/x/mod/semver"
2119

2220
"go.jetpack.io/devbox/internal/boxcli/usererr"
21+
"go.jetpack.io/devbox/internal/build"
22+
"go.jetpack.io/devbox/internal/cmdutil"
23+
"go.jetpack.io/devbox/internal/ux"
2324
"go.jetpack.io/devbox/internal/xdg"
2425
)
2526

@@ -75,9 +76,9 @@ func SelfUpdate(stdOut, stdErr io.Writer) error {
7576

7677
func selfUpdateLauncher(stdOut, stdErr io.Writer) error {
7778
installScript := ""
78-
if _, err := exec.LookPath("curl"); err == nil {
79+
if cmdutil.Exists("curl") {
7980
installScript = "curl -fsSL https://get.jetpack.io/devbox | bash"
80-
} else if _, err := exec.LookPath("wget"); err == nil {
81+
} else if cmdutil.Exists("wget") {
8182
installScript = "wget -qO- https://get.jetpack.io/devbox | bash"
8283
} else {
8384
return usererr.New("curl or wget is required to update devbox. Please install either and try again.")

internal/wrapnix/wrapper.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ import (
99
_ "embed"
1010
"io/fs"
1111
"os"
12-
"os/exec"
1312
"path/filepath"
1413
"text/template"
1514

1615
"github.com/pkg/errors"
1716

17+
"go.jetpack.io/devbox/internal/cmdutil"
1818
"go.jetpack.io/devbox/internal/nix"
1919
"go.jetpack.io/devbox/internal/plugin"
2020
"go.jetpack.io/devbox/internal/services"
@@ -43,18 +43,14 @@ func CreateWrappers(ctx context.Context, devbox devboxer) error {
4343
return err
4444
}
4545

46-
bashPath, err := exec.LookPath("bash")
47-
if err != nil {
48-
bashPath = "/bin/bash"
49-
}
50-
5146
// Remove all old wrappers
5247
_ = os.RemoveAll(filepath.Join(devbox.ProjectDir(), plugin.WrapperPath))
5348

5449
// Recreate the bin wrapper directory
5550
destPath := filepath.Join(devbox.ProjectDir(), plugin.WrapperBinPath)
5651
_ = os.MkdirAll(destPath, 0755)
5752

53+
bashPath := cmdutil.GetPathOrDefault("bash", "/bin/bash")
5854
for _, service := range services {
5955
if err = createWrapper(&createWrapperArgs{
6056
BashPath: bashPath,

0 commit comments

Comments
 (0)