@@ -18,6 +18,8 @@ package debug
18
18
import (
19
19
"context"
20
20
"encoding/json"
21
+ "errors"
22
+ "reflect"
21
23
"slices"
22
24
"strconv"
23
25
"strings"
@@ -41,25 +43,83 @@ func GetDebugConfig(ctx context.Context, req *rpc.GetDebugConfigRequest) (*rpc.G
41
43
return nil , & arduino.InvalidInstanceError {}
42
44
}
43
45
defer release ()
44
- return getDebugProperties (req , pme )
46
+ return getDebugProperties (req , pme , false )
45
47
}
46
48
47
- func getDebugProperties (req * rpc.GetDebugConfigRequest , pme * packagemanager.Explorer ) (* rpc.GetDebugConfigResponse , error ) {
48
- // TODO: make a generic function to extract sketch from request
49
- // and remove duplication in commands/compile.go
50
- if req .GetSketchPath () == "" {
51
- return nil , & arduino.MissingSketchPathError {}
49
+ // IsDebugSupported checks if the given board/programmer configuration supports debugging.
50
+ func IsDebugSupported (ctx context.Context , req * rpc.IsDebugSupportedRequest ) (* rpc.IsDebugSupportedResponse , error ) {
51
+ pme , release := instances .GetPackageManagerExplorer (req .GetInstance ())
52
+ if pme == nil {
53
+ return nil , & arduino.InvalidInstanceError {}
54
+ }
55
+ defer release ()
56
+ configRequest := & rpc.GetDebugConfigRequest {
57
+ Instance : req .GetInstance (),
58
+ Fqbn : req .GetFqbn (),
59
+ SketchPath : "" ,
60
+ Port : req .GetPort (),
61
+ Interpreter : req .GetInterpreter (),
62
+ ImportDir : "" ,
63
+ Programmer : req .GetProgrammer (),
64
+ }
65
+ expectedOutput , err := getDebugProperties (configRequest , pme , true )
66
+ var x * arduino.FailedDebugError
67
+ if errors .As (err , & x ) {
68
+ return & rpc.IsDebugSupportedResponse {DebuggingSupported : false }, nil
52
69
}
53
- sketchPath := paths .New (req .GetSketchPath ())
54
- sk , err := sketch .New (sketchPath )
55
70
if err != nil {
56
- return nil , & arduino.CantOpenSketchError {Cause : err }
71
+ return nil , err
72
+ }
73
+
74
+ // Compute the minimum FQBN required to get the same debug configuration.
75
+ // (i.e. the FQBN cleaned up of the options that do not affect the debugger configuration)
76
+ minimumFQBN := cores .MustParseFQBN (req .GetFqbn ())
77
+ for _ , config := range minimumFQBN .Configs .Keys () {
78
+ checkFQBN := minimumFQBN .Clone ()
79
+ checkFQBN .Configs .Remove (config )
80
+ configRequest .Fqbn = checkFQBN .String ()
81
+ checkOutput , err := getDebugProperties (configRequest , pme , true )
82
+ if err == nil && reflect .DeepEqual (expectedOutput , checkOutput ) {
83
+ minimumFQBN .Configs .Remove (config )
84
+ }
85
+ }
86
+ return & rpc.IsDebugSupportedResponse {
87
+ DebuggingSupported : true ,
88
+ DebugFqbn : minimumFQBN .String (),
89
+ }, nil
90
+ }
91
+
92
+ func getDebugProperties (req * rpc.GetDebugConfigRequest , pme * packagemanager.Explorer , skipSketchChecks bool ) (* rpc.GetDebugConfigResponse , error ) {
93
+ var (
94
+ sketchName string
95
+ sketchDefaultFQBN string
96
+ sketchDefaultBuildPath * paths.Path
97
+ )
98
+ if ! skipSketchChecks {
99
+ // TODO: make a generic function to extract sketch from request
100
+ // and remove duplication in commands/compile.go
101
+ if req .GetSketchPath () == "" {
102
+ return nil , & arduino.MissingSketchPathError {}
103
+ }
104
+ sketchPath := paths .New (req .GetSketchPath ())
105
+ sk , err := sketch .New (sketchPath )
106
+ if err != nil {
107
+ return nil , & arduino.CantOpenSketchError {Cause : err }
108
+ }
109
+ sketchName = sk .Name
110
+ sketchDefaultFQBN = sk .GetDefaultFQBN ()
111
+ sketchDefaultBuildPath = sk .DefaultBuildPath ()
112
+ } else {
113
+ // Use placeholder sketch data
114
+ sketchName = "Sketch"
115
+ sketchDefaultFQBN = ""
116
+ sketchDefaultBuildPath = paths .New ("SketchBuildPath" )
57
117
}
58
118
59
119
// XXX Remove this code duplication!!
60
120
fqbnIn := req .GetFqbn ()
61
- if fqbnIn == "" && sk != nil {
62
- fqbnIn = sk . GetDefaultFQBN ()
121
+ if fqbnIn == "" {
122
+ fqbnIn = sketchDefaultFQBN
63
123
}
64
124
if fqbnIn == "" {
65
125
return nil , & arduino.MissingFQBNError {}
@@ -124,16 +184,18 @@ func getDebugProperties(req *rpc.GetDebugConfigRequest, pme *packagemanager.Expl
124
184
if importDir := req .GetImportDir (); importDir != "" {
125
185
importPath = paths .New (importDir )
126
186
} else {
127
- importPath = sk .DefaultBuildPath ()
128
- }
129
- if ! importPath .Exist () {
130
- return nil , & arduino.NotFoundError {Message : tr ("Compiled sketch not found in %s" , importPath )}
187
+ importPath = sketchDefaultBuildPath
131
188
}
132
- if ! importPath .IsDir () {
133
- return nil , & arduino.NotFoundError {Message : tr ("Expected compiled sketch in directory %s, but is a file instead" , importPath )}
189
+ if ! skipSketchChecks {
190
+ if ! importPath .Exist () {
191
+ return nil , & arduino.NotFoundError {Message : tr ("Compiled sketch not found in %s" , importPath )}
192
+ }
193
+ if ! importPath .IsDir () {
194
+ return nil , & arduino.NotFoundError {Message : tr ("Expected compiled sketch in directory %s, but is a file instead" , importPath )}
195
+ }
134
196
}
135
197
toolProperties .SetPath ("build.path" , importPath )
136
- toolProperties .Set ("build.project_name" , sk . Name + ".ino" )
198
+ toolProperties .Set ("build.project_name" , sketchName + ".ino" )
137
199
138
200
// Set debug port property
139
201
port := req .GetPort ()
0 commit comments