@@ -18,164 +18,87 @@ package debug
18
18
import (
19
19
"context"
20
20
"fmt"
21
- "github.com/arduino/arduino-cli/arduino/cores"
22
- "github.com/arduino/arduino-cli/arduino/sketches"
23
- "github.com/arduino/arduino-cli/commands"
21
+ "io"
22
+
24
23
"github.com/arduino/arduino-cli/executils"
25
24
dbg "github.com/arduino/arduino-cli/rpc/debug"
26
- "github.com/arduino/go-paths-helper"
27
- "github.com/arduino/go-properties-orderedmap"
28
- "github.com/sirupsen/logrus"
29
- "os"
30
- "os/exec"
31
- "path/filepath"
32
- "strings"
33
25
)
34
26
35
27
// Debug FIXMEDOC
36
- func Debug (ctx context.Context , req * dbg.DebugReq , in func (data []bytes ), out func (data []bytes )) (* exec.Cmd , error ) {
37
- //logrus.Tracef("Debug %s on %s started", req.GetSketchPath(), req.GetFqbn())
38
-
39
- //// TODO: make a generic function to extract sketch from request
40
- // and remove duplication in commands/compile.go
41
- if req .GetSketchPath () == "" {
42
- return fmt .Errorf ("missing sketchPath" )
43
- }
44
- sketchPath := paths .New (req .GetSketchPath ())
45
- sketch , err := sketches .NewSketchFromPath (sketchPath )
28
+ func Debug (ctx context.Context , req * dbg.DebugReq , inStream dbg.Debug_StreamingOpenServer , out io.Writer ) (* dbg.StreamingOpenResp , error ) {
29
+ cmdArgs := []string {"gdb" }
30
+ // Run Tool
31
+ cmd , err := executils .Command (cmdArgs )
46
32
if err != nil {
47
- return fmt .Errorf ("opening sketch: %s" , err )
48
- }
49
-
50
- // FIXME: make a specification on how a port is specified via command line
51
- port := req .GetPort ()
52
- if port == "" {
53
- return fmt .Errorf ("no upload port provided" )
33
+ return nil , fmt .Errorf ("cannot execute upload tool: %s" , err )
54
34
}
55
35
56
- fqbnIn := req .GetFqbn ()
57
- if fqbnIn == "" && sketch != nil && sketch .Metadata != nil {
58
- fqbnIn = sketch .Metadata .CPU .Fqbn
59
- }
60
- if fqbnIn == "" {
61
- return fmt .Errorf ("no Fully Qualified Board Name provided" )
62
- }
63
- fqbn , err := cores .ParseFQBN (fqbnIn )
36
+ in , err := cmd .StdinPipe ()
64
37
if err != nil {
65
- return fmt .Errorf ("incorrect FQBN: %s" , err )
38
+ fmt .Println ("%v\n " , err )
39
+ return & dbg.StreamingOpenResp {}, nil // TODO: send error in response
66
40
}
41
+ defer in .Close ()
67
42
68
- pm := commands . GetPackageManager ( req . GetInstance (). GetId ())
43
+ cmd . Stdout = out
69
44
70
- // Find target board and board properties
71
- _ , _ , board , boardProperties , _ , err := pm .ResolveFQBN (fqbn )
45
+ err = cmd .Start ()
72
46
if err != nil {
73
- return fmt .Errorf ("incorrect FQBN: %s" , err )
74
- }
75
-
76
- // Load programmer tool
77
- uploadToolPattern , have := boardProperties .GetOk ("upload.tool" )
78
- if ! have || uploadToolPattern == "" {
79
- return fmt .Errorf ("cannot get programmer tool: undefined 'upload.tool' property" )
80
- }
81
-
82
- var referencedPlatformRelease * cores.PlatformRelease
83
- if split := strings .Split (uploadToolPattern , ":" ); len (split ) > 2 {
84
- return fmt .Errorf ("invalid 'upload.tool' property: %s" , uploadToolPattern )
85
- } else if len (split ) == 2 {
86
- referencedPackageName := split [0 ]
87
- uploadToolPattern = split [1 ]
88
- architecture := board .PlatformRelease .Platform .Architecture
89
-
90
- if referencedPackage := pm .Packages [referencedPackageName ]; referencedPackage == nil {
91
- return fmt .Errorf ("required platform %s:%s not installed" , referencedPackageName , architecture )
92
- } else if referencedPlatform := referencedPackage .Platforms [architecture ]; referencedPlatform == nil {
93
- return fmt .Errorf ("required platform %s:%s not installed" , referencedPackageName , architecture )
94
- } else {
95
- referencedPlatformRelease = pm .GetInstalledPlatformRelease (referencedPlatform )
96
- }
97
- }
98
-
99
- // Build configuration for upload
100
- uploadProperties := properties .NewMap ()
101
- if referencedPlatformRelease != nil {
102
- uploadProperties .Merge (referencedPlatformRelease .Properties )
103
- }
104
- uploadProperties .Merge (board .PlatformRelease .Properties )
105
- uploadProperties .Merge (board .PlatformRelease .RuntimeProperties ())
106
- uploadProperties .Merge (boardProperties )
107
-
108
- uploadToolProperties := uploadProperties .SubTree ("tools." + uploadToolPattern )
109
- uploadProperties .Merge (uploadToolProperties )
110
-
111
- if requiredTools , err := pm .FindToolsRequiredForBoard (board ); err == nil {
112
- for _ , requiredTool := range requiredTools {
113
- logrus .WithField ("tool" , requiredTool ).Info ("Tool required for upload" )
114
- uploadProperties .Merge (requiredTool .RuntimeProperties ())
47
+ fmt .Println ("%v\n " , err )
48
+ return & dbg.StreamingOpenResp {}, nil // TODO: send error in response
49
+ }
50
+
51
+ // we'll use these channels to communicate with the goroutines
52
+ // handling the stream and the target respectively
53
+ streamClosed := make (chan error )
54
+ targetClosed := make (chan error )
55
+ defer close (streamClosed )
56
+ defer close (targetClosed )
57
+
58
+ // now we can read the other commands and re-route to the Debug Client...
59
+ go func () {
60
+ for {
61
+ command , err := inStream .Recv ()
62
+ if err == io .EOF {
63
+ // stream was closed
64
+ streamClosed <- nil
65
+ break
66
+ }
67
+
68
+ if err != nil {
69
+ // error reading from stream
70
+ streamClosed <- err
71
+ break
72
+ }
73
+
74
+ if _ , err := in .Write (command .GetData ()); err != nil {
75
+ // error writing to target
76
+ targetClosed <- err
77
+ break
78
+ }
115
79
}
116
- }
117
-
118
- // Set properties for verbose upload
119
- Verbose := req .GetVerbose ()
120
- if Verbose {
121
- if v , ok := uploadProperties .GetOk ("upload.params.verbose" ); ok {
122
- uploadProperties .Set ("upload.verbose" , v )
123
- }
124
- } else {
125
- if v , ok := uploadProperties .GetOk ("upload.params.quiet" ); ok {
126
- uploadProperties .Set ("upload.verbose" , v )
127
- }
128
- }
129
-
130
- // Set path to compiled binary
131
- // Make the filename without the FQBN configs part
132
- fqbn .Configs = properties .NewMap ()
133
- fqbnSuffix := strings .Replace (fqbn .String (), ":" , "." , - 1 )
134
-
135
- var importPath * paths.Path
136
- var importFile string
137
- if req .GetImportFile () == "" {
138
- importPath = sketch .FullPath
139
- importFile = sketch .Name + "." + fqbnSuffix
140
- } else {
141
- importPath = paths .New (req .GetImportFile ()).Parent ()
142
- importFile = paths .New (req .GetImportFile ()).Base ()
143
- }
144
-
145
- outputTmpFile , ok := uploadProperties .GetOk ("recipe.output.tmp_file" )
146
- outputTmpFile = uploadProperties .ExpandPropsInString (outputTmpFile )
147
- if ! ok {
148
- return fmt .Errorf ("property 'recipe.output.tmp_file' not defined" )
149
- }
150
- ext := filepath .Ext (outputTmpFile )
151
- if strings .HasSuffix (importFile , ext ) {
152
- importFile = importFile [:len (importFile )- len (ext )]
153
- }
154
-
155
- uploadProperties .SetPath ("build.path" , importPath )
156
- uploadProperties .Set ("build.project_name" , importFile )
157
- uploadFile := importPath .Join (importFile + ext )
158
- if _ , err := uploadFile .Stat (); err != nil {
159
- if os .IsNotExist (err ) {
160
- return fmt .Errorf ("compiled sketch %s not found" , uploadFile .String ())
80
+ }()
81
+
82
+ // let goroutines route messages from/to the Debug
83
+ // until either the client closes the stream or the
84
+ // Debug target is closed
85
+ for {
86
+ select {
87
+ case <- ctx .Done ():
88
+ cmd .Process .Kill ()
89
+ cmd .Wait ()
90
+ case err := <- streamClosed :
91
+ fmt .Println ("streamClosed" )
92
+ cmd .Process .Kill ()
93
+ cmd .Wait ()
94
+ return & dbg.StreamingOpenResp {}, err // TODO: send error in response
95
+ case err := <- targetClosed :
96
+ fmt .Println ("targetClosed" )
97
+ cmd .Process .Kill ()
98
+ cmd .Wait ()
99
+ return & dbg.StreamingOpenResp {}, err // TODO: send error in response
161
100
}
162
- return fmt .Errorf ("cannot open sketch: %s" , err )
163
- }
164
-
165
- // Build recipe for upload
166
- recipe := uploadProperties .Get ("upload.pattern" )
167
- cmdLine := uploadProperties .ExpandPropsInString (recipe )
168
- cmdArgs , err := properties .SplitQuotedString (cmdLine , `"'` , false )
169
- if err != nil {
170
- return fmt .Errorf ("invalid recipe '%s': %s" , recipe , err )
171
- }
172
-
173
- cmdArgs := []string {"gdb" }
174
- // Run Tool
175
- cmd , err := executils .Command (cmdArgs )
176
- if err != nil {
177
- return nil , fmt .Errorf ("cannot execute upload tool: %s" , err )
178
101
}
179
102
180
- return cmd , nil
103
+ return & dbg. StreamingOpenResp {} , nil
181
104
}
0 commit comments