@@ -35,9 +35,62 @@ import (
3535 dbg "github.com/arduino/arduino-cli/rpc/debug"
3636)
3737
38- // Debug FIXMEDOC
38+ // Debug command launches a debug tool for a sketch.
39+ // It also implements streams routing:
40+ // gRPC In -> tool stdIn
41+ // grpc Out <- tool stdOut
42+ // grpc Out <- tool stdErr
43+ // It also implements tool process lifecycle management
3944func Debug (ctx context.Context , req * dbg.DebugConfigReq , inStream io.Reader , out io.Writer ) (* dbg.DebugResp , error ) {
4045
46+ // get tool commandLine from core recipe
47+ commandLine , err := getCommandLine (req )
48+ if err != nil {
49+ return nil , fmt .Errorf ("cannot get command line for tool: %s" , err )
50+ }
51+
52+ // Run Tool
53+ cmd , err := executils .Command (commandLine )
54+ if err != nil {
55+ return nil , fmt .Errorf ("cannot execute debug tool: %s" , err )
56+ }
57+
58+ // Get stdIn pipe from tool
59+ in , err := cmd .StdinPipe ()
60+ if err != nil {
61+ fmt .Printf ("%v\n " , err )
62+ return & dbg.DebugResp {Error : err .Error ()}, nil
63+ }
64+ defer in .Close ()
65+
66+ // Merge tool StdOut and StdErr to stream them in the io.Writer passed stream
67+ cmd .Stdout = out
68+ cmd .Stderr = out
69+
70+ // Start the debug command
71+ if err := cmd .Start (); err != nil {
72+ fmt .Printf ("%v\n " , err )
73+ return & dbg.DebugResp {Error : err .Error ()}, nil
74+ }
75+
76+ go func () {
77+ // copy data from passed inStream into command stdIn
78+ io .Copy (in , inStream )
79+ // In any case, try process termination after a second to avoid leaving
80+ // zombie process.
81+ time .Sleep (time .Second )
82+ cmd .Process .Kill ()
83+ }()
84+
85+ // Wait for process to finish
86+ if err := cmd .Wait (); err != nil {
87+ return & dbg.DebugResp {Error : err .Error ()}, nil
88+ }
89+ return & dbg.DebugResp {}, nil
90+ }
91+
92+ // getCommandLine compose a debug command represented by a core recipe
93+ func getCommandLine (req * dbg.DebugConfigReq ) ([]string , error ) {
4194 // TODO: make a generic function to extract sketch from request
4295 // and remove duplication in commands/compile.go
4396 if req .GetSketchPath () == "" {
@@ -52,7 +105,7 @@ func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream io.Reader, out
52105 // FIXME: make a specification on how a port is specified via command line
53106 port := req .GetPort ()
54107 if port == "" {
55- return nil , fmt .Errorf ("no upload port provided" )
108+ return nil , fmt .Errorf ("no debug port provided" )
56109 }
57110
58111 fqbnIn := req .GetFqbn ()
@@ -98,7 +151,7 @@ func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream io.Reader, out
98151 }
99152 }
100153
101- // Build configuration for upload
154+ // Build configuration for debug
102155 toolProperties := properties .NewMap ()
103156 if referencedPlatformRelease != nil {
104157 toolProperties .Merge (referencedPlatformRelease .Properties )
@@ -109,26 +162,13 @@ func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream io.Reader, out
109162
110163 requestedToolProperties := toolProperties .SubTree ("tools." + toolName )
111164 toolProperties .Merge (requestedToolProperties )
112-
113165 if requiredTools , err := pm .FindToolsRequiredForBoard (board ); err == nil {
114166 for _ , requiredTool := range requiredTools {
115- logrus .WithField ("tool" , requiredTool ).Info ("Tool required for upload " )
167+ logrus .WithField ("tool" , requiredTool ).Info ("Tool required for debug " )
116168 toolProperties .Merge (requiredTool .RuntimeProperties ())
117169 }
118170 }
119171
120- // Set properties for verbose upload
121- verbose := req .GetVerbose ()
122- if verbose {
123- if v , ok := toolProperties .GetOk ("debug.params.verbose" ); ok {
124- toolProperties .Set ("debug.verbose" , v )
125- }
126- } else {
127- if v , ok := toolProperties .GetOk ("debug.params.quiet" ); ok {
128- toolProperties .Set ("debug.verbose" , v )
129- }
130- }
131-
132172 // Set path to compiled binary
133173 // Make the filename without the FQBN configs part
134174 fqbn .Configs = properties .NewMap ()
@@ -179,44 +219,5 @@ func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream io.Reader, out
179219 if err != nil {
180220 return nil , fmt .Errorf ("invalid recipe '%s': %s" , recipe , err )
181221 }
182-
183- // for _, arg := range cmdArgs {
184- // fmt.Println(">>", arg)
185- // }
186- // time.Sleep(time.Hour)
187-
188- // Run Tool
189- cmd , err := executils .Command (cmdArgs )
190- if err != nil {
191- return nil , fmt .Errorf ("cannot execute upload tool: %s" , err )
192- }
193-
194- in , err := cmd .StdinPipe ()
195- if err != nil {
196- fmt .Printf ("%v\n " , err )
197- return & dbg.DebugResp {Error : err .Error ()}, nil
198- }
199- defer in .Close ()
200-
201- cmd .Stdout = out
202- cmd .Stderr = out
203-
204- if err := cmd .Start (); err != nil {
205- fmt .Printf ("%v\n " , err )
206- return & dbg.DebugResp {Error : err .Error ()}, nil
207- }
208-
209- // now we can read the other commands and re-route to the Debug Client...
210- go func () {
211- io .Copy (in , inStream )
212- // In any case, try process termination after a second to avoid leaving
213- // zombie process.
214- time .Sleep (time .Second )
215- cmd .Process .Kill ()
216- }()
217-
218- if err := cmd .Wait (); err != nil {
219- return & dbg.DebugResp {Error : err .Error ()}, nil
220- }
221- return & dbg.DebugResp {}, nil
222+ return cmdArgs , nil
222223}
0 commit comments