Skip to content

Commit fea53ad

Browse files
committed
dap: return error from evaluate command in repl context
In the repl context, we will now return the error instead of directly printing it. We also suppress reporting errors from cobra. The logic flow has also been changed to prevent returning errors from cobra unless there was something related to the command line invocation so usage will only be printed when a command was typed wrong and it will not show up for every error. Signed-off-by: Jonathan A. Sternberg <[email protected]>
1 parent a1ca46e commit fea53ad

File tree

1 file changed

+58
-31
lines changed

1 file changed

+58
-31
lines changed

dap/eval.go

Lines changed: 58 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -29,43 +29,70 @@ func (d *Adapter[C]) Evaluate(ctx Context, req *dap.EvaluateRequest, resp *dap.E
2929
return nil
3030
}
3131

32-
var t *thread
33-
if req.Arguments.FrameId > 0 {
34-
if t = d.getThreadByFrameID(req.Arguments.FrameId); t == nil {
35-
return errors.Errorf("no thread with frame id %d", req.Arguments.FrameId)
36-
}
37-
} else {
38-
if t = d.getFirstThread(); t == nil {
39-
return errors.New("no paused thread")
40-
}
41-
}
42-
43-
cmd := d.replCommands(ctx, t, resp)
32+
var retErr error
33+
cmd := d.replCommands(ctx, req, resp, &retErr)
4434
cmd.SetArgs(args)
4535
cmd.SetErr(d.Out())
4636
if err := cmd.Execute(); err != nil {
47-
fmt.Fprintf(d.Out(), "ERROR: %+v\n", err)
37+
// This error should only happen if there was something command
38+
// related that malfunctioned as it will also print usage.
39+
// Normal errors should set retErr from replCommands.
40+
return err
4841
}
49-
return nil
42+
return retErr
5043
}
5144

52-
func (d *Adapter[C]) replCommands(ctx Context, t *thread, resp *dap.EvaluateResponse) *cobra.Command {
53-
rootCmd := &cobra.Command{}
45+
func (d *Adapter[C]) replCommands(ctx Context, req *dap.EvaluateRequest, resp *dap.EvaluateResponse, retErr *error) *cobra.Command {
46+
rootCmd := &cobra.Command{
47+
SilenceErrors: true,
48+
}
5449

55-
execCmd := &cobra.Command{
56-
Use: "exec",
57-
RunE: func(cmd *cobra.Command, args []string) error {
58-
if !d.supportsExec {
59-
return errors.New("cannot exec without runInTerminal client capability")
60-
}
61-
return t.Exec(ctx, args, resp)
62-
},
50+
execCmd, execOpts := replCmd(ctx, "exec", resp, retErr, d.execCmd)
51+
execCmd.PreRun = func(cmd *cobra.Command, args []string) {
52+
execOpts.FrameID = req.Arguments.FrameId
6353
}
6454
rootCmd.AddCommand(execCmd)
6555
return rootCmd
6656
}
6757

68-
func (t *thread) Exec(ctx Context, args []string, eresp *dap.EvaluateResponse) (retErr error) {
58+
type execOptions struct {
59+
FrameID int
60+
}
61+
62+
func (d *Adapter[C]) execCmd(ctx Context, args []string, flags execOptions) (string, error) {
63+
if !d.supportsExec {
64+
return "", errors.New("cannot exec without runInTerminal client capability")
65+
}
66+
67+
var t *thread
68+
if flags.FrameID > 0 {
69+
if t = d.getThreadByFrameID(flags.FrameID); t == nil {
70+
return "", errors.Errorf("no thread with frame id %d", flags.FrameID)
71+
}
72+
} else {
73+
if t = d.getFirstThread(); t == nil {
74+
return "", errors.New("no paused thread")
75+
}
76+
}
77+
return t.Exec(ctx, args)
78+
}
79+
80+
func replCmd[Flags any, RetVal any](ctx Context, name string, resp *dap.EvaluateResponse, retErr *error, fn func(ctx Context, args []string, flags Flags) (RetVal, error)) (*cobra.Command, *Flags) {
81+
flags := new(Flags)
82+
return &cobra.Command{
83+
Use: name,
84+
Run: func(cmd *cobra.Command, args []string) {
85+
v, err := fn(ctx, args, *flags)
86+
if err != nil {
87+
*retErr = err
88+
return
89+
}
90+
resp.Body.Result = fmt.Sprint(v)
91+
},
92+
}, flags
93+
}
94+
95+
func (t *thread) Exec(ctx Context, args []string) (message string, retErr error) {
6996
cfg := &build.InvokeConfig{Tty: true}
7097
if len(cfg.Entrypoint) == 0 && len(cfg.Cmd) == 0 {
7198
cfg.Entrypoint = []string{"/bin/sh"} // launch shell by default
@@ -75,7 +102,7 @@ func (t *thread) Exec(ctx Context, args []string, eresp *dap.EvaluateResponse) (
75102

76103
ctr, err := build.NewContainer(ctx, t.rCtx, cfg)
77104
if err != nil {
78-
return err
105+
return "", err
79106
}
80107
defer func() {
81108
if retErr != nil {
@@ -85,7 +112,7 @@ func (t *thread) Exec(ctx Context, args []string, eresp *dap.EvaluateResponse) (
85112

86113
dir, err := os.MkdirTemp("", "buildx-dap-exec")
87114
if err != nil {
88-
return err
115+
return "", err
89116
}
90117
defer func() {
91118
if retErr != nil {
@@ -96,7 +123,7 @@ func (t *thread) Exec(ctx Context, args []string, eresp *dap.EvaluateResponse) (
96123
socketPath := filepath.Join(dir, "s.sock")
97124
l, err := net.Listen("unix", socketPath)
98125
if err != nil {
99-
return err
126+
return "", err
100127
}
101128

102129
go func() {
@@ -121,11 +148,11 @@ func (t *thread) Exec(ctx Context, args []string, eresp *dap.EvaluateResponse) (
121148

122149
resp := ctx.Request(req)
123150
if !resp.GetResponse().Success {
124-
return errors.New(resp.GetResponse().Message)
151+
return "", errors.New(resp.GetResponse().Message)
125152
}
126153

127-
eresp.Body.Result = fmt.Sprintf("Started process attached to %s.", socketPath)
128-
return nil
154+
message = fmt.Sprintf("Started process attached to %s.", socketPath)
155+
return message, nil
129156
}
130157

131158
func (t *thread) runExec(l net.Listener, ctr *build.Container, cfg *build.InvokeConfig) {

0 commit comments

Comments
 (0)