@@ -29,43 +29,74 @@ 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 ) {
96+ if t .rCtx == nil {
97+ return "" , errors .New ("no container context for exec" )
98+ }
99+
69100 cfg := & build.InvokeConfig {Tty : true }
70101 if len (cfg .Entrypoint ) == 0 && len (cfg .Cmd ) == 0 {
71102 cfg .Entrypoint = []string {"/bin/sh" } // launch shell by default
@@ -75,7 +106,7 @@ func (t *thread) Exec(ctx Context, args []string, eresp *dap.EvaluateResponse) (
75106
76107 ctr , err := build .NewContainer (ctx , t .rCtx , cfg )
77108 if err != nil {
78- return err
109+ return "" , err
79110 }
80111 defer func () {
81112 if retErr != nil {
@@ -85,7 +116,7 @@ func (t *thread) Exec(ctx Context, args []string, eresp *dap.EvaluateResponse) (
85116
86117 dir , err := os .MkdirTemp ("" , "buildx-dap-exec" )
87118 if err != nil {
88- return err
119+ return "" , err
89120 }
90121 defer func () {
91122 if retErr != nil {
@@ -96,7 +127,7 @@ func (t *thread) Exec(ctx Context, args []string, eresp *dap.EvaluateResponse) (
96127 socketPath := filepath .Join (dir , "s.sock" )
97128 l , err := net .Listen ("unix" , socketPath )
98129 if err != nil {
99- return err
130+ return "" , err
100131 }
101132
102133 go func () {
@@ -121,11 +152,11 @@ func (t *thread) Exec(ctx Context, args []string, eresp *dap.EvaluateResponse) (
121152
122153 resp := ctx .Request (req )
123154 if ! resp .GetResponse ().Success {
124- return errors .New (resp .GetResponse ().Message )
155+ return "" , errors .New (resp .GetResponse ().Message )
125156 }
126157
127- eresp . Body . Result = fmt .Sprintf ("Started process attached to %s." , socketPath )
128- return nil
158+ message = fmt .Sprintf ("Started process attached to %s." , socketPath )
159+ return message , nil
129160}
130161
131162func (t * thread ) runExec (l net.Listener , ctr * build.Container , cfg * build.InvokeConfig ) {
0 commit comments