Skip to content

Commit add66fa

Browse files
authored
devbox shell -- cmd (#158)
## Summary Simple implementation of `devbox shell -- <cmd>`. I struggled integrating this with all the other stuff that is happening with `devbox shell`. Would like thoughts on whether this is a good enough for an MVP of the feature, and later we improve it, or whether we think integrating with the other `devbox shell` logic is a must have. ## How was it tested? Ran a few commands with `devbox shell --`
1 parent 76f92d0 commit add66fa

File tree

3 files changed

+56
-8
lines changed

3 files changed

+56
-8
lines changed

boxcli/shell.go

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,17 @@ import (
1515

1616
func ShellCmd() *cobra.Command {
1717
command := &cobra.Command{
18-
Use: "shell [<dir>]",
18+
Use: "shell [<dir>] -- [<cmd>]",
1919
Short: "Start a new shell with access to your packages",
20-
Args: cobra.MaximumNArgs(1),
20+
Args: validateShellArgs,
2121
PersistentPreRunE: nixShellPersistentPreRunE,
2222
RunE: runShellCmd,
2323
}
2424
return command
2525
}
2626

2727
func runShellCmd(cmd *cobra.Command, args []string) error {
28-
path := pathArg(args)
28+
path, cmds := parseShellArgs(cmd, args)
2929

3030
// Check the directory exists.
3131
box, err := devbox.Open(path)
@@ -40,12 +40,12 @@ func runShellCmd(cmd *cobra.Command, args []string) error {
4040

4141
fmt.Println("Installing nix packages. This may take a while...")
4242

43-
err = box.Shell()
44-
var exitErr *exec.ExitError
45-
if errors.As(err, &exitErr) {
46-
cmd.SilenceErrors = true
47-
cmd.SilenceUsage = true
43+
if len(cmds) > 0 {
44+
err = box.Exec(cmds...)
45+
} else {
46+
err = box.Shell()
4847
}
48+
4949
return err
5050
}
5151

@@ -56,3 +56,22 @@ func nixShellPersistentPreRunE(cmd *cobra.Command, args []string) error {
5656
}
5757
return nil
5858
}
59+
60+
func validateShellArgs(cmd *cobra.Command, args []string) error {
61+
lenAtDash := cmd.ArgsLenAtDash()
62+
if lenAtDash > 1 {
63+
return fmt.Errorf("accepts at most 1 directory, received %d", lenAtDash)
64+
}
65+
return nil
66+
}
67+
68+
func parseShellArgs(cmd *cobra.Command, args []string) (string, []string) {
69+
index := cmd.ArgsLenAtDash()
70+
if index < 0 {
71+
index = 0
72+
}
73+
74+
path := pathArg(args[:index])
75+
cmds := args[index:]
76+
return path, cmds
77+
}

devbox.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,22 @@ func (d *Devbox) Shell() error {
149149
return sh.Run(nixDir)
150150
}
151151

152+
func (d *Devbox) Exec(cmds ...string) error {
153+
plan, err := d.Plan()
154+
if err != nil {
155+
return errors.WithStack(err)
156+
}
157+
if plan.Invalid() {
158+
return plan.Error()
159+
}
160+
err = generate(d.srcDir, plan, shellFiles)
161+
if err != nil {
162+
return errors.WithStack(err)
163+
}
164+
nixDir := filepath.Join(d.srcDir, ".devbox/gen/shell.nix")
165+
return nix.Exec(nixDir, cmds)
166+
}
167+
152168
// saveCfg writes the config file to the devbox directory.
153169
func (d *Devbox) saveCfg() error {
154170
cfgPath := filepath.Join(d.srcDir, configFilename)

nix/nix.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ import (
77
"bytes"
88
"encoding/json"
99
"fmt"
10+
"os"
1011
"os/exec"
12+
"strings"
13+
14+
"github.com/pkg/errors"
1115
)
1216

1317
func PkgExists(pkg string) bool {
@@ -22,6 +26,15 @@ type Info struct {
2226
System string
2327
}
2428

29+
func Exec(path string, command []string) error {
30+
runCmd := strings.Join(command, " ")
31+
cmd := exec.Command("nix-shell", path, "--run", runCmd)
32+
cmd.Stdin = os.Stdin
33+
cmd.Stdout = os.Stdout
34+
cmd.Stderr = os.Stderr
35+
return errors.WithStack(cmd.Run())
36+
}
37+
2538
func PkgInfo(pkg string) (*Info, bool) {
2639
buf := new(bytes.Buffer)
2740
attr := fmt.Sprintf("nixpkgs.%s", pkg)

0 commit comments

Comments
 (0)