@@ -18,7 +18,16 @@ package debug
1818import (
1919 "context"
2020 "fmt"
21+ "github.com/arduino/arduino-cli/arduino/cores"
22+ "github.com/arduino/arduino-cli/arduino/sketches"
23+ "github.com/arduino/arduino-cli/commands"
24+ "github.com/arduino/go-paths-helper"
25+ "github.com/arduino/go-properties-orderedmap"
26+ "github.com/sirupsen/logrus"
2127 "io"
28+ "os"
29+ "path/filepath"
30+ "strings"
2231 "time"
2332
2433 "github.com/arduino/arduino-cli/executils"
@@ -27,7 +36,149 @@ import (
2736
2837// Debug FIXMEDOC
2938func Debug (ctx context.Context , req * dbg.DebugConfigReq , inStream dbg.Debug_DebugServer , out io.Writer ) (* dbg.DebugResp , error ) {
30- cmdArgs := []string {"gdb" }
39+
40+ // TODO: make a generic function to extract sketch from request
41+ // and remove duplication in commands/compile.go
42+ if req .GetSketchPath () == "" {
43+ return nil , fmt .Errorf ("missing sketchPath" )
44+ }
45+ sketchPath := paths .New (req .GetSketchPath ())
46+ sketch , err := sketches .NewSketchFromPath (sketchPath )
47+ if err != nil {
48+ return nil , fmt .Errorf ("opening sketch: %s" , err )
49+ }
50+
51+ // FIXME: make a specification on how a port is specified via command line
52+ port := req .GetPort ()
53+ if port == "" {
54+ return nil , fmt .Errorf ("no upload port provided" )
55+ }
56+
57+ fqbnIn := req .GetFqbn ()
58+ if fqbnIn == "" && sketch != nil && sketch .Metadata != nil {
59+ fqbnIn = sketch .Metadata .CPU .Fqbn
60+ }
61+ if fqbnIn == "" {
62+ return nil , fmt .Errorf ("no Fully Qualified Board Name provided" )
63+ }
64+ fqbn , err := cores .ParseFQBN (fqbnIn )
65+ if err != nil {
66+ return nil , fmt .Errorf ("incorrect FQBN: %s" , err )
67+ }
68+
69+ pm := commands .GetPackageManager (req .GetInstance ().GetId ())
70+
71+ // Find target board and board properties
72+ _ , _ , board , boardProperties , _ , err := pm .ResolveFQBN (fqbn )
73+ if err != nil {
74+ return nil , fmt .Errorf ("incorrect FQBN: %s" , err )
75+ }
76+
77+ // Load programmer tool
78+ uploadToolPattern , have := boardProperties .GetOk ("debug.tool" )
79+ if ! have || uploadToolPattern == "" {
80+ return nil , fmt .Errorf ("cannot get programmer tool: undefined 'debug.tool' property" )
81+ }
82+
83+ var referencedPlatformRelease * cores.PlatformRelease
84+ if split := strings .Split (uploadToolPattern , ":" ); len (split ) > 2 {
85+ return nil , fmt .Errorf ("invalid 'debug.tool' property: %s" , uploadToolPattern )
86+ } else if len (split ) == 2 {
87+ referencedPackageName := split [0 ]
88+ uploadToolPattern = split [1 ]
89+ architecture := board .PlatformRelease .Platform .Architecture
90+
91+ if referencedPackage := pm .Packages [referencedPackageName ]; referencedPackage == nil {
92+ return nil , fmt .Errorf ("required platform %s:%s not installed" , referencedPackageName , architecture )
93+ } else if referencedPlatform := referencedPackage .Platforms [architecture ]; referencedPlatform == nil {
94+ return nil , fmt .Errorf ("required platform %s:%s not installed" , referencedPackageName , architecture )
95+ } else {
96+ referencedPlatformRelease = pm .GetInstalledPlatformRelease (referencedPlatform )
97+ }
98+ }
99+
100+ // Build configuration for upload
101+ debugProperties := properties .NewMap ()
102+ if referencedPlatformRelease != nil {
103+ debugProperties .Merge (referencedPlatformRelease .Properties )
104+ }
105+ debugProperties .Merge (board .PlatformRelease .Properties )
106+ debugProperties .Merge (board .PlatformRelease .RuntimeProperties ())
107+ debugProperties .Merge (boardProperties )
108+
109+ uploadToolProperties := debugProperties .SubTree ("tools." + uploadToolPattern )
110+ debugProperties .Merge (uploadToolProperties )
111+
112+ if requiredTools , err := pm .FindToolsRequiredForBoard (board ); err == nil {
113+ for _ , requiredTool := range requiredTools {
114+ logrus .WithField ("tool" , requiredTool ).Info ("Tool required for upload" )
115+ debugProperties .Merge (requiredTool .RuntimeProperties ())
116+ }
117+ }
118+
119+ // Set properties for verbose upload
120+ Verbose := req .GetVerbose ()
121+ if Verbose {
122+ if v , ok := debugProperties .GetOk ("debug.params.verbose" ); ok {
123+ debugProperties .Set ("debug.verbose" , v )
124+ }
125+ } else {
126+ if v , ok := debugProperties .GetOk ("debug.params.quiet" ); ok {
127+ debugProperties .Set ("debug.verbose" , v )
128+ }
129+ }
130+
131+ // Set path to compiled binary
132+ // Make the filename without the FQBN configs part
133+ fqbn .Configs = properties .NewMap ()
134+ fqbnSuffix := strings .Replace (fqbn .String (), ":" , "." , - 1 )
135+
136+ var importPath * paths.Path
137+ var importFile string
138+ if req .GetImportFile () == "" {
139+ importPath = sketch .FullPath
140+ importFile = sketch .Name + "." + fqbnSuffix
141+ } else {
142+ importPath = paths .New (req .GetImportFile ()).Parent ()
143+ importFile = paths .New (req .GetImportFile ()).Base ()
144+ }
145+
146+ outputTmpFile , ok := debugProperties .GetOk ("recipe.output.tmp_file" )
147+ outputTmpFile = debugProperties .ExpandPropsInString (outputTmpFile )
148+ if ! ok {
149+ return nil , fmt .Errorf ("property 'recipe.output.tmp_file' not defined" )
150+ }
151+ ext := filepath .Ext (outputTmpFile )
152+ if strings .HasSuffix (importFile , ext ) {
153+ importFile = importFile [:len (importFile )- len (ext )]
154+ }
155+
156+ debugProperties .SetPath ("build.path" , importPath )
157+ debugProperties .Set ("build.project_name" , importFile )
158+ uploadFile := importPath .Join (importFile + ext )
159+ if _ , err := uploadFile .Stat (); err != nil {
160+ if os .IsNotExist (err ) {
161+ return nil , fmt .Errorf ("compiled sketch %s not found" , uploadFile .String ())
162+ }
163+ return nil , fmt .Errorf ("cannot open sketch: %s" , err )
164+ }
165+
166+ // Set serial port property
167+ debugProperties .Set ("serial.port" , port )
168+ if strings .HasPrefix (port , "/dev/" ) {
169+ debugProperties .Set ("serial.port.file" , port [5 :])
170+ } else {
171+ debugProperties .Set ("serial.port.file" , port )
172+ }
173+
174+ // Build recipe for upload
175+ recipe := debugProperties .Get ("debug.pattern" )
176+ cmdLine := debugProperties .ExpandPropsInString (recipe )
177+ cmdArgs , err := properties .SplitQuotedString (cmdLine , `"'` , false )
178+ if err != nil {
179+ return nil , fmt .Errorf ("invalid recipe '%s': %s" , recipe , err )
180+ }
181+
31182 // Run Tool
32183 cmd , err := executils .Command (cmdArgs )
33184 if err != nil {
0 commit comments