Skip to content

Commit f33c11f

Browse files
committed
Wiring profiles into arduino-cli and gRPC implementation
1 parent faa33bd commit f33c11f

File tree

2 files changed

+130
-35
lines changed

2 files changed

+130
-35
lines changed

cli/instance/instance.go

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,21 @@ var tr = i18n.Tr
3737
// to execute further operations a valid Instance is mandatory.
3838
// If Init returns errors they're printed only.
3939
func CreateAndInit() *rpc.Instance {
40+
inst, _ := CreateAndInitWithProfile("", nil)
41+
return inst
42+
}
43+
44+
func CreateAndInitWithProfile(profile string, sketchPath *paths.Path) (*rpc.Instance, string) {
4045
instance, err := Create()
4146
if err != nil {
4247
feedback.Errorf(tr("Error creating instance: %v"), err)
4348
os.Exit(errorcodes.ErrGeneric)
4449
}
45-
for _, err := range Init(instance) {
50+
fqbn, errs := InitWithProfile(instance, profile, sketchPath)
51+
for _, err := range errs {
4652
feedback.Errorf(tr("Error initializing instance: %v"), err)
4753
}
48-
return instance
54+
return instance, fqbn
4955
}
5056

5157
// Create and return a new Instance.
@@ -63,19 +69,28 @@ func Create() (*rpc.Instance, error) {
6369
// Package and library indexes files are automatically updated if the
6470
// CLI is run for the first time.
6571
func Init(instance *rpc.Instance) []error {
72+
_, errs := InitWithProfile(instance, "", nil)
73+
return errs
74+
}
75+
76+
func InitWithProfile(instance *rpc.Instance, profile string, sketchPath *paths.Path) (string, []error) {
6677
errs := []error{}
6778

6879
// In case the CLI is executed for the first time
6980
if err := FirstUpdate(instance); err != nil {
70-
return append(errs, err)
81+
return "", append(errs, err)
7182
}
7283

7384
downloadCallback := output.ProgressBar()
7485
taskCallback := output.TaskProgress()
7586

76-
err := commands.Init(&rpc.InitRequest{
77-
Instance: instance,
78-
}, func(res *rpc.InitResponse) {
87+
initReq := &rpc.InitRequest{Instance: instance}
88+
if sketchPath != nil {
89+
initReq.SketchPath = sketchPath.String()
90+
initReq.Profile = profile
91+
}
92+
profileFqbn := ""
93+
err := commands.Init(initReq, func(res *rpc.InitResponse) {
7994
if st := res.GetError(); st != nil {
8095
errs = append(errs, errors.New(st.Message))
8196
}
@@ -88,12 +103,16 @@ func Init(instance *rpc.Instance) []error {
88103
taskCallback(progress.TaskProgress)
89104
}
90105
}
106+
107+
if fqbn := res.GetProfileSelectedFqbn(); fqbn != "" {
108+
profileFqbn = fqbn
109+
}
91110
})
92111
if err != nil {
93-
return append(errs, err)
112+
errs = append(errs, err)
94113
}
95114

96-
return errs
115+
return profileFqbn, errs
97116
}
98117

99118
// FirstUpdate downloads libraries and packages indexes if they don't exist.

commands/instances.go

Lines changed: 103 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -139,24 +139,10 @@ func Create(req *rpc.CreateRequest, extraUserAgent ...string) (*rpc.CreateRespon
139139
dataDir.Join("tmp"),
140140
userAgent,
141141
)
142-
143-
// Create library manager and add libraries directories
144-
lm := librariesmanager.NewLibraryManager(
142+
instance.lm = librariesmanager.NewLibraryManager(
145143
dataDir,
146144
downloadsDir,
147145
)
148-
instance.lm = lm
149-
150-
// Add directories of libraries bundled with IDE
151-
if bundledLibsDir := configuration.IDEBundledLibrariesDir(configuration.Settings); bundledLibsDir != nil {
152-
lm.AddLibrariesDir(bundledLibsDir, libraries.IDEBuiltIn)
153-
}
154-
155-
// Add libraries directory from config file
156-
lm.AddLibrariesDir(
157-
configuration.LibrariesDir(configuration.Settings),
158-
libraries.User,
159-
)
160146

161147
// Save instance
162148
instanceID := instancesCount
@@ -217,9 +203,30 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro
217203
pm := instance.PackageManager
218204
pm.Clear()
219205

220-
// Load Platforms
206+
// Try to extract profile if specified
207+
var profile *sketch.Profile
208+
if req.GetProfile() != "" {
209+
sk, err := sketch.New(paths.New(req.GetSketchPath()))
210+
if err != nil {
211+
return &arduino.InvalidArgumentError{Cause: err}
212+
}
213+
profile = sk.GetProfile(req.GetProfile())
214+
responseCallback(&rpc.InitResponse{
215+
Message: &rpc.InitResponse_ProfileSelectedFqbn{
216+
ProfileSelectedFqbn: profile.FQBN,
217+
},
218+
})
219+
}
220+
221+
loadBuiltinTools := func() []error {
222+
builtinPackage := pm.Packages.GetOrCreatePackage("builtin")
223+
return pm.LoadToolsFromPackageDir(builtinPackage, pm.PackagesDir.Join("builtin", "tools"))
224+
}
225+
221226
urls := []string{globals.DefaultIndexURL}
222-
urls = append(urls, configuration.Settings.GetStringSlice("board_manager.additional_urls")...)
227+
if profile == nil {
228+
urls = append(urls, configuration.Settings.GetStringSlice("board_manager.additional_urls")...)
229+
}
223230
for _, u := range urls {
224231
URL, err := utils.URLParse(u)
225232
if err != nil {
@@ -229,9 +236,7 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro
229236
}
230237

231238
if URL.Scheme == "file" {
232-
indexFile := paths.New(URL.Path)
233-
234-
_, err := pm.LoadPackageIndexFromFile(indexFile)
239+
_, err := pm.LoadPackageIndexFromFile(paths.New(URL.Path))
235240
if err != nil {
236241
s := status.Newf(codes.FailedPrecondition, tr("Loading index file: %v"), err)
237242
responseError(s)
@@ -245,15 +250,30 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro
245250
}
246251
}
247252

253+
// Load Platforms
254+
if profile == nil {
255+
for _, err := range pm.LoadHardware() {
256+
s := &arduino.PlatformLoadingError{Cause: err}
257+
responseError(s.ToRPCStatus())
258+
}
259+
} else {
260+
// Load platforms from profile
261+
errs := pm.LoadHardwareForProfile(
262+
profile, true, downloadCallback, taskCallback,
263+
)
264+
for _, err := range errs {
265+
s := &arduino.PlatformLoadingError{Cause: err}
266+
responseError(s.ToRPCStatus())
267+
}
268+
269+
// Load "builtin" tools
270+
_ = loadBuiltinTools()
271+
}
272+
248273
// We load hardware before verifying builtin tools are installed
249274
// otherwise we wouldn't find them and reinstall them each time
250275
// and they would never get reloaded.
251-
for _, err := range pm.LoadHardware() {
252-
s := &arduino.PlatformLoadingError{Cause: err}
253-
responseError(s.ToRPCStatus())
254-
}
255276

256-
// Get builtin tools
257277
builtinToolReleases := []*cores.ToolRelease{}
258278
for name, tool := range pm.Packages.GetOrCreatePackage("builtin").Tools {
259279
latestRelease := tool.LatestRelease()
@@ -280,7 +300,7 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro
280300
if toolsHaveBeenInstalled {
281301
// We installed at least one new tool after loading hardware
282302
// so we must reload again otherwise we would never found them.
283-
for _, err := range pm.LoadHardware() {
303+
for _, err := range loadBuiltinTools() {
284304
s := &arduino.PlatformLoadingError{Cause: err}
285305
responseError(s.ToRPCStatus())
286306
}
@@ -291,7 +311,12 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro
291311
responseError(s.ToRPCStatus())
292312
}
293313

294-
lm := instance.lm
314+
// Create library manager and add libraries directories
315+
lm := librariesmanager.NewLibraryManager(
316+
pm.IndexDir,
317+
pm.DownloadDir,
318+
)
319+
instance.lm = lm
295320

296321
// Load libraries
297322
for _, pack := range pm.Packages {
@@ -307,6 +332,57 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro
307332
responseError(s)
308333
}
309334

335+
if profile == nil {
336+
// Add directories of libraries bundled with IDE
337+
if bundledLibsDir := configuration.IDEBundledLibrariesDir(configuration.Settings); bundledLibsDir != nil {
338+
lm.AddLibrariesDir(bundledLibsDir, libraries.IDEBuiltIn)
339+
}
340+
341+
// Add libraries directory from config file
342+
lm.AddLibrariesDir(configuration.LibrariesDir(configuration.Settings), libraries.User)
343+
} else {
344+
// Load libraries required for profile
345+
for _, libraryRef := range profile.Libraries {
346+
uid := libraryRef.InternalUniqueIdentifier()
347+
libRoot := configuration.ProfilesCacheDir(configuration.Settings).Join(uid)
348+
libDir := libRoot.Join(libraryRef.Library)
349+
350+
if !libDir.IsDir() {
351+
// Download library
352+
taskCallback(&rpc.TaskProgress{Name: tr("Downloading library %s", libraryRef)})
353+
libRelease := lm.Index.FindRelease(&librariesindex.Reference{
354+
Name: libraryRef.Library,
355+
Version: libraryRef.Version,
356+
})
357+
if libRelease == nil {
358+
taskCallback(&rpc.TaskProgress{Name: tr("Library %s not found", libraryRef)})
359+
err := &arduino.LibraryNotFoundError{Library: libraryRef.Library}
360+
responseError(err.ToRPCStatus())
361+
continue
362+
}
363+
if err := libRelease.Resource.Download(lm.DownloadsDir, nil, libRelease.String(), downloadCallback); err != nil {
364+
taskCallback(&rpc.TaskProgress{Name: tr("Error downloading library %s", libraryRef)})
365+
e := &arduino.FailedLibraryInstallError{Cause: err}
366+
responseError(e.ToRPCStatus())
367+
continue
368+
}
369+
taskCallback(&rpc.TaskProgress{Completed: true})
370+
371+
// Install library
372+
taskCallback(&rpc.TaskProgress{Name: tr("Installing library %s", libraryRef)})
373+
if err := libRelease.Resource.Install(lm.DownloadsDir, libRoot, libDir); err != nil {
374+
taskCallback(&rpc.TaskProgress{Name: tr("Error installing library %s", libraryRef)})
375+
e := &arduino.FailedLibraryInstallError{Cause: err}
376+
responseError(e.ToRPCStatus())
377+
continue
378+
}
379+
taskCallback(&rpc.TaskProgress{Completed: true})
380+
}
381+
382+
lm.AddLibrariesDir(libRoot, libraries.User)
383+
}
384+
}
385+
310386
for _, err := range lm.RescanLibraries() {
311387
s := status.Newf(codes.FailedPrecondition, tr("Loading libraries: %v"), err)
312388
responseError(s)

0 commit comments

Comments
 (0)