diff --git a/commands/instances.go b/commands/instances.go index db41ba794d0..99224f29cbd 100644 --- a/commands/instances.go +++ b/commands/instances.go @@ -294,10 +294,7 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro } // Create library manager and add libraries directories - lmb := librariesmanager.NewBuilder( - pme.IndexDir, - pme.DownloadDir, - ) + lmb := librariesmanager.NewBuilder() // Load libraries for _, pack := range pme.GetPackages() { @@ -308,10 +305,15 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro } } - if err := lmb.LoadIndex(); err != nil { + indexFile := pme.IndexDir.Join("library_index.json") + logrus.WithField("index", indexFile).Info("Loading libraries index file") + li, err := librariesindex.LoadIndex(indexFile) + if err != nil { s := status.Newf(codes.FailedPrecondition, tr("Loading index file: %v"), err) responseError(s) + li = librariesindex.EmptyIndex } + instances.SetLibrariesIndex(instance, li) if profile == nil { // Add directories of libraries bundled with IDE @@ -331,7 +333,7 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro if !libDir.IsDir() { // Download library taskCallback(&rpc.TaskProgress{Name: tr("Downloading library %s", libraryRef)}) - libRelease := lmb.Index.FindRelease(&librariesindex.Reference{ + libRelease := li.FindRelease(&librariesindex.Reference{ Name: libraryRef.Library, Version: libraryRef.Version, }) @@ -341,7 +343,7 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro responseError(err.ToRPCStatus()) continue } - if err := libRelease.Resource.Download(lmb.DownloadsDir, nil, libRelease.String(), downloadCallback, ""); err != nil { + if err := libRelease.Resource.Download(pme.DownloadDir, nil, libRelease.String(), downloadCallback, ""); err != nil { taskCallback(&rpc.TaskProgress{Name: tr("Error downloading library %s", libraryRef)}) e := &cmderrors.FailedLibraryInstallError{Cause: err} responseError(e.ToRPCStatus()) @@ -351,7 +353,7 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro // Install library taskCallback(&rpc.TaskProgress{Name: tr("Installing library %s", libraryRef)}) - if err := libRelease.Resource.Install(lmb.DownloadsDir, libRoot, libDir); err != nil { + if err := libRelease.Resource.Install(pme.DownloadDir, libRoot, libDir); err != nil { taskCallback(&rpc.TaskProgress{Name: tr("Error installing library %s", libraryRef)}) e := &cmderrors.FailedLibraryInstallError{Cause: err} responseError(e.ToRPCStatus()) @@ -366,9 +368,14 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro lm := lmb.Build() _ = instances.SetLibraryManager(instance, lm) // should never fail - for _, status := range lm.RescanLibraries() { - logrus.WithError(status.Err()).Warnf("Error loading library") - // TODO: report as warning: responseError(err) + + { + lmi, release := lm.NewInstaller() + for _, status := range lmi.RescanLibraries() { + logrus.WithError(status.Err()).Warnf("Error loading library") + // TODO: report as warning: responseError(err) + } + release() } // Refreshes the locale used, this will change the @@ -390,12 +397,17 @@ func Destroy(ctx context.Context, req *rpc.DestroyRequest) (*rpc.DestroyResponse // UpdateLibrariesIndex updates the library_index.json func UpdateLibrariesIndex(ctx context.Context, req *rpc.UpdateLibrariesIndexRequest, downloadCB rpc.DownloadProgressCB) error { logrus.Info("Updating libraries index") - lm, err := instances.GetLibraryManager(req.GetInstance()) - if err != nil { - return err + pme, release := instances.GetPackageManagerExplorer(req.GetInstance()) + if pme == nil { + return &cmderrors.InvalidInstanceError{} } + indexDir := pme.IndexDir + release() + + indexFile := indexDir.Join("library_index.json") + // indexFileSignature := indexDir.Join("library_index.json.sig") - if err := lm.IndexFile.Parent().MkdirAll(); err != nil { + if err := indexFile.Parent().MkdirAll(); err != nil { return &cmderrors.PermissionDeniedError{Message: tr("Could not create index directory"), Cause: err} } @@ -406,7 +418,7 @@ func UpdateLibrariesIndex(ctx context.Context, req *rpc.UpdateLibrariesIndexRequ } defer tmp.RemoveAll() - if err := globals.LibrariesIndexResource.Download(lm.IndexFile.Parent(), downloadCB); err != nil { + if err := globals.LibrariesIndexResource.Download(indexDir, downloadCB); err != nil { return err } diff --git a/commands/internal/instances/instances.go b/commands/internal/instances/instances.go index 44bcb8e5109..9337c267ac5 100644 --- a/commands/internal/instances/instances.go +++ b/commands/internal/instances/instances.go @@ -5,6 +5,7 @@ import ( "github.com/arduino/arduino-cli/commands/cmderrors" "github.com/arduino/arduino-cli/internal/arduino/cores/packagemanager" + "github.com/arduino/arduino-cli/internal/arduino/libraries/librariesindex" "github.com/arduino/arduino-cli/internal/arduino/libraries/librariesmanager" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/arduino/arduino-cli/version" @@ -17,6 +18,7 @@ import ( type coreInstance struct { pm *packagemanager.PackageManager lm *librariesmanager.LibrariesManager + li *librariesindex.Index } // instances contains all the running Arduino Core Services instances @@ -59,6 +61,49 @@ func GetLibraryManager(inst *rpc.Instance) (*librariesmanager.LibrariesManager, return i.lm, nil } +// GetLibraryManagerExplorer returns the library manager Explorer for the given instance. +func GetLibraryManagerExplorer(inst *rpc.Instance) (*librariesmanager.Explorer, func(), error) { + lm, err := GetLibraryManager(inst) + if err != nil { + return nil, nil, err + } + lmi, release := lm.NewExplorer() + return lmi, release, nil +} + +// GetLibraryManagerInstaller returns the library manager Installer for the given instance. +func GetLibraryManagerInstaller(inst *rpc.Instance) (*librariesmanager.Installer, func(), error) { + lm, err := GetLibraryManager(inst) + if err != nil { + return nil, nil, err + } + lmi, release := lm.NewInstaller() + return lmi, release, nil +} + +// GetLibrariesIndex returns the library index for the given instance. +func GetLibrariesIndex(inst *rpc.Instance) (*librariesindex.Index, error) { + instancesMux.Lock() + defer instancesMux.Unlock() + i := instances[inst.GetId()] + if i == nil { + return nil, &cmderrors.InvalidInstanceError{} + } + return i.li, nil +} + +// SetLibrariesIndex returns the library index for the given instance. +func SetLibrariesIndex(inst *rpc.Instance, li *librariesindex.Index) error { + instancesMux.Lock() + defer instancesMux.Unlock() + i := instances[inst.GetId()] + if i == nil { + return &cmderrors.InvalidInstanceError{} + } + i.li = li + return nil +} + // SetLibraryManager sets the library manager for the given instance. func SetLibraryManager(inst *rpc.Instance, lm *librariesmanager.LibrariesManager) bool { instancesMux.Lock() @@ -73,16 +118,18 @@ func SetLibraryManager(inst *rpc.Instance, lm *librariesmanager.LibrariesManager // Create a new *rpc.Instance ready to be initialized func Create(dataDir, packagesDir, downloadsDir *paths.Path, extraUserAgent ...string) (*rpc.Instance, error) { - instance := &coreInstance{} - // Create package manager userAgent := "arduino-cli/" + version.VersionInfo.VersionString for _, ua := range extraUserAgent { userAgent += " " + ua } tempDir := dataDir.Join("tmp") - instance.pm = packagemanager.NewBuilder(dataDir, packagesDir, downloadsDir, tempDir, userAgent).Build() - instance.lm = librariesmanager.NewBuilder(dataDir, downloadsDir).Build() + + instance := &coreInstance{ + pm: packagemanager.NewBuilder(dataDir, packagesDir, downloadsDir, tempDir, userAgent).Build(), + lm: librariesmanager.NewBuilder().Build(), + li: librariesindex.EmptyIndex, + } // Save instance instancesMux.Lock() diff --git a/commands/lib/download.go b/commands/lib/download.go index d4195cb0283..0dca62356c9 100644 --- a/commands/lib/download.go +++ b/commands/lib/download.go @@ -34,20 +34,27 @@ var tr = i18n.Tr // A DownloadProgressCB callback function must be passed to monitor download progress. func LibraryDownload(ctx context.Context, req *rpc.LibraryDownloadRequest, downloadCB rpc.DownloadProgressCB) (*rpc.LibraryDownloadResponse, error) { logrus.Info("Executing `arduino-cli lib download`") + var downloadDir *paths.Path + if pme, release := instances.GetPackageManagerExplorer(req.GetInstance()); pme == nil { + return nil, &cmderrors.InvalidInstanceError{} + } else { + downloadDir = pme.DownloadDir + release() + } - lm, err := instances.GetLibraryManager(req.GetInstance()) + li, err := instances.GetLibrariesIndex(req.GetInstance()) if err != nil { return nil, err } logrus.Info("Preparing download") - lib, err := findLibraryIndexRelease(lm, req) + lib, err := findLibraryIndexRelease(li, req) if err != nil { return nil, err } - if err := downloadLibrary(lm.DownloadsDir, lib, downloadCB, func(*rpc.TaskProgress) {}, "download"); err != nil { + if err := downloadLibrary(downloadDir, lib, downloadCB, func(*rpc.TaskProgress) {}, "download"); err != nil { return nil, err } diff --git a/commands/lib/install.go b/commands/lib/install.go index 96893a0462f..94b6eb417e4 100644 --- a/commands/lib/install.go +++ b/commands/lib/install.go @@ -33,11 +33,6 @@ import ( // LibraryInstall resolves the library dependencies, then downloads and installs the libraries into the install location. func LibraryInstall(ctx context.Context, req *rpc.LibraryInstallRequest, downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB) error { - lm, err := instances.GetLibraryManager(req.GetInstance()) - if err != nil { - return err - } - toInstall := map[string]*rpc.LibraryDependencyStatus{} installLocation := libraries.FromRPCLibraryInstallLocation(req.GetInstallLocation()) if req.GetNoDeps() { @@ -69,10 +64,32 @@ func LibraryInstall(ctx context.Context, req *rpc.LibraryInstallRequest, downloa } } + // Obtain the download directory + var downloadsDir *paths.Path + if pme, release := instances.GetPackageManagerExplorer(req.GetInstance()); pme == nil { + return &cmderrors.InvalidInstanceError{} + } else { + downloadsDir = pme.DownloadDir + release() + } + + // Obtain the library index from the manager + li, err := instances.GetLibrariesIndex(req.GetInstance()) + if err != nil { + return err + } + + // Obtain the library installer from the manager + lmi, release, err := instances.GetLibraryManagerInstaller(req.GetInstance()) + if err != nil { + return err + } + defer release() + // Find the libReleasesToInstall to install libReleasesToInstall := map[*librariesindex.Release]*librariesmanager.LibraryInstallPlan{} for _, lib := range toInstall { - libRelease, err := findLibraryIndexRelease(lm, &rpc.LibraryInstallRequest{ + libRelease, err := findLibraryIndexRelease(li, &rpc.LibraryInstallRequest{ Name: lib.GetName(), Version: lib.GetVersionRequired(), }) @@ -80,7 +97,7 @@ func LibraryInstall(ctx context.Context, req *rpc.LibraryInstallRequest, downloa return err } - installTask, err := lm.InstallPrerequisiteCheck(libRelease.Library.Name, libRelease.Version, installLocation) + installTask, err := lmi.InstallPrerequisiteCheck(libRelease.Library.Name, libRelease.Version, installLocation) if err != nil { return err } @@ -109,10 +126,10 @@ func LibraryInstall(ctx context.Context, req *rpc.LibraryInstallRequest, downloa downloadReason += "-builtin" } } - if err := downloadLibrary(lm.DownloadsDir, libRelease, downloadCB, taskCB, downloadReason); err != nil { + if err := downloadLibrary(downloadsDir, libRelease, downloadCB, taskCB, downloadReason); err != nil { return err } - if err := installLibrary(lm, libRelease, installTask, taskCB); err != nil { + if err := installLibrary(lmi, libRelease, installTask, taskCB); err != nil { return err } } @@ -124,18 +141,18 @@ func LibraryInstall(ctx context.Context, req *rpc.LibraryInstallRequest, downloa return nil } -func installLibrary(lm *librariesmanager.LibrariesManager, libRelease *librariesindex.Release, installTask *librariesmanager.LibraryInstallPlan, taskCB rpc.TaskProgressCB) error { +func installLibrary(lmi *librariesmanager.Installer, libRelease *librariesindex.Release, installTask *librariesmanager.LibraryInstallPlan, taskCB rpc.TaskProgressCB) error { taskCB(&rpc.TaskProgress{Name: tr("Installing %s", libRelease)}) logrus.WithField("library", libRelease).Info("Installing library") if libReplaced := installTask.ReplacedLib; libReplaced != nil { taskCB(&rpc.TaskProgress{Message: tr("Replacing %[1]s with %[2]s", libReplaced, libRelease)}) - if err := lm.Uninstall(libReplaced); err != nil { + if err := lmi.Uninstall(libReplaced); err != nil { return &cmderrors.FailedLibraryInstallError{ Cause: fmt.Errorf("%s: %s", tr("could not remove old library"), err)} } } - if err := lm.Install(libRelease, installTask.TargetPath); err != nil { + if err := lmi.Install(libRelease, installTask.TargetPath); err != nil { return &cmderrors.FailedLibraryInstallError{Cause: err} } @@ -149,7 +166,9 @@ func ZipLibraryInstall(ctx context.Context, req *rpc.ZipLibraryInstallRequest, t if err != nil { return err } - if err := lm.InstallZipLib(ctx, paths.New(req.GetPath()), req.GetOverwrite()); err != nil { + lmi, release := lm.NewInstaller() + defer release() + if err := lmi.InstallZipLib(ctx, paths.New(req.GetPath()), req.GetOverwrite()); err != nil { return &cmderrors.FailedLibraryInstallError{Cause: err} } taskCB(&rpc.TaskProgress{Message: tr("Library installed"), Completed: true}) @@ -162,7 +181,9 @@ func GitLibraryInstall(ctx context.Context, req *rpc.GitLibraryInstallRequest, t if err != nil { return err } - if err := lm.InstallGitLib(req.GetUrl(), req.GetOverwrite()); err != nil { + lmi, release := lm.NewInstaller() + defer release() + if err := lmi.InstallGitLib(req.GetUrl(), req.GetOverwrite()); err != nil { return &cmderrors.FailedLibraryInstallError{Cause: err} } taskCB(&rpc.TaskProgress{Message: tr("Library installed"), Completed: true}) diff --git a/commands/lib/list.go b/commands/lib/list.go index f4d74dab5e0..a1258b1b37e 100644 --- a/commands/lib/list.go +++ b/commands/lib/list.go @@ -42,16 +42,22 @@ func LibraryList(ctx context.Context, req *rpc.LibraryListRequest) (*rpc.Library } defer release() - lm, err := instances.GetLibraryManager(req.GetInstance()) + li, err := instances.GetLibrariesIndex(req.GetInstance()) if err != nil { return nil, err } + lme, release, err := instances.GetLibraryManagerExplorer(req.GetInstance()) + if err != nil { + return nil, err + } + defer release() + nameFilter := strings.ToLower(req.GetName()) var allLibs []*installedLib if fqbnString := req.GetFqbn(); fqbnString != "" { - allLibs = listLibraries(lm, req.GetUpdatable(), true) + allLibs = listLibraries(lme, li, req.GetUpdatable(), true) fqbn, err := cores.ParseFQBN(req.GetFqbn()) if err != nil { return nil, &cmderrors.InvalidFQBNError{Cause: err} @@ -91,7 +97,7 @@ func LibraryList(ctx context.Context, req *rpc.LibraryListRequest) (*rpc.Library allLibs = append(allLibs, lib) } } else { - allLibs = listLibraries(lm, req.GetUpdatable(), req.GetAll()) + allLibs = listLibraries(lme, li, req.GetUpdatable(), req.GetAll()) } installedLibs := []*rpc.InstalledLibrary{} @@ -117,25 +123,25 @@ func LibraryList(ctx context.Context, req *rpc.LibraryListRequest) (*rpc.Library } // listLibraries returns the list of installed libraries. If updatable is true it -// returns only the libraries that may be updated. -func listLibraries(lm *librariesmanager.LibrariesManager, updatable bool, all bool) []*installedLib { +// returns only the libraries that may be updated by looking at the index for updates. +// If all is true, it returns all the libraries (including the libraries builtin in the +// platforms), otherwise only the user installed libraries. +func listLibraries(lme *librariesmanager.Explorer, li *librariesindex.Index, updatable bool, all bool) []*installedLib { res := []*installedLib{} - for _, libAlternatives := range lm.Libraries { - for _, lib := range libAlternatives { - if !all { - if lib.Location != libraries.User { - continue - } - } - available := lm.Index.FindLibraryUpdate(lib) - if updatable && available == nil { + for _, lib := range lme.FindAllInstalled() { + if !all { + if lib.Location != libraries.User { continue } - res = append(res, &installedLib{ - Library: lib, - Available: available, - }) } + available := li.FindLibraryUpdate(lib) + if updatable && available == nil { + continue + } + res = append(res, &installedLib{ + Library: lib, + Available: available, + }) } return res } diff --git a/commands/lib/resolve_deps.go b/commands/lib/resolve_deps.go index b1d17bbc42c..4e12223e0a6 100644 --- a/commands/lib/resolve_deps.go +++ b/commands/lib/resolve_deps.go @@ -30,30 +30,36 @@ import ( // LibraryResolveDependencies FIXMEDOC func LibraryResolveDependencies(ctx context.Context, req *rpc.LibraryResolveDependenciesRequest) (*rpc.LibraryResolveDependenciesResponse, error) { - lm, err := instances.GetLibraryManager(req.GetInstance()) + lme, release, err := instances.GetLibraryManagerExplorer(req.GetInstance()) + if err != nil { + return nil, err + } + defer release() + + li, err := instances.GetLibrariesIndex(req.GetInstance()) if err != nil { return nil, err } // Search the requested lib - reqLibRelease, err := findLibraryIndexRelease(lm, req) + reqLibRelease, err := findLibraryIndexRelease(li, req) if err != nil { return nil, err } // Extract all installed libraries installedLibs := map[string]*libraries.Library{} - for _, lib := range listLibraries(lm, false, false) { + for _, lib := range listLibraries(lme, li, false, false) { installedLibs[lib.Library.Name] = lib.Library } // Resolve all dependencies... var overrides []*librariesindex.Release if req.GetDoNotUpdateInstalledLibraries() { - libs := lm.FindAllInstalled() + libs := lme.FindAllInstalled() libs = libs.FilterByVersionAndInstallLocation(nil, libraries.User) for _, lib := range libs { - release := lm.Index.FindRelease(&librariesindex.Reference{ + release := li.FindRelease(&librariesindex.Reference{ Name: lib.Name, Version: lib.Version, }) @@ -62,13 +68,13 @@ func LibraryResolveDependencies(ctx context.Context, req *rpc.LibraryResolveDepe } } } - deps := lm.Index.ResolveDependencies(reqLibRelease, overrides) + deps := li.ResolveDependencies(reqLibRelease, overrides) // If no solution has been found if len(deps) == 0 { // Check if there is a problem with the first level deps for _, directDep := range reqLibRelease.GetDependencies() { - if _, ok := lm.Index.Libraries[directDep.GetName()]; !ok { + if _, ok := li.Libraries[directDep.GetName()]; !ok { err := errors.New(tr("dependency '%s' is not available", directDep.GetName())) return nil, &cmderrors.LibraryDependenciesResolutionFailedError{Cause: err} } diff --git a/commands/lib/search.go b/commands/lib/search.go index cbd9bf4901a..7c2d21cdd70 100644 --- a/commands/lib/search.go +++ b/commands/lib/search.go @@ -22,26 +22,25 @@ import ( "github.com/arduino/arduino-cli/commands/internal/instances" "github.com/arduino/arduino-cli/internal/arduino/libraries/librariesindex" - "github.com/arduino/arduino-cli/internal/arduino/libraries/librariesmanager" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" semver "go.bug.st/relaxed-semver" ) // LibrarySearch FIXMEDOC func LibrarySearch(ctx context.Context, req *rpc.LibrarySearchRequest) (*rpc.LibrarySearchResponse, error) { - lm, err := instances.GetLibraryManager(req.GetInstance()) + li, err := instances.GetLibrariesIndex(req.GetInstance()) if err != nil { return nil, err } - return searchLibrary(req, lm), nil + return searchLibrary(req, li), nil } -func searchLibrary(req *rpc.LibrarySearchRequest, lm *librariesmanager.LibrariesManager) *rpc.LibrarySearchResponse { +func searchLibrary(req *rpc.LibrarySearchRequest, li *librariesindex.Index) *rpc.LibrarySearchResponse { res := []*rpc.SearchedLibrary{} query := req.GetSearchArgs() matcher := MatcherFromQueryString(query) - for _, lib := range lm.Index.Libraries { + for _, lib := range li.Libraries { if matcher(lib) { res = append(res, indexLibraryToRPCSearchLibrary(lib, req.GetOmitReleasesDetails())) } diff --git a/commands/lib/search_test.go b/commands/lib/search_test.go index 2487b146203..34ed0670290 100644 --- a/commands/lib/search_test.go +++ b/commands/lib/search_test.go @@ -19,23 +19,22 @@ import ( "strings" "testing" - "github.com/arduino/arduino-cli/internal/arduino/libraries/librariesmanager" + "github.com/arduino/arduino-cli/internal/arduino/libraries/librariesindex" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" paths "github.com/arduino/go-paths-helper" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -var customIndexPath = paths.New("testdata", "test1") -var fullIndexPath = paths.New("testdata", "full") -var qualifiedSearchIndexPath = paths.New("testdata", "qualified_search") +var customIndexPath = paths.New("testdata", "test1", "library_index.json") +var fullIndexPath = paths.New("testdata", "full", "library_index.json") +var qualifiedSearchIndexPath = paths.New("testdata", "qualified_search", "library_index.json") func TestSearchLibrary(t *testing.T) { - lmb := librariesmanager.NewBuilder(customIndexPath, nil) - lmb.LoadIndex() - lm := lmb.Build() + li, err := librariesindex.LoadIndex(customIndexPath) + require.NoError(t, err) - resp := searchLibrary(&rpc.LibrarySearchRequest{SearchArgs: "test"}, lm) + resp := searchLibrary(&rpc.LibrarySearchRequest{SearchArgs: "test"}, li) assert := assert.New(t) assert.Equal(resp.GetStatus(), rpc.LibrarySearchStatus_LIBRARY_SEARCH_STATUS_SUCCESS) assert.Equal(len(resp.GetLibraries()), 2) @@ -44,11 +43,10 @@ func TestSearchLibrary(t *testing.T) { } func TestSearchLibrarySimilar(t *testing.T) { - lmb := librariesmanager.NewBuilder(customIndexPath, nil) - lmb.LoadIndex() - lm := lmb.Build() + li, err := librariesindex.LoadIndex(customIndexPath) + require.NoError(t, err) - resp := searchLibrary(&rpc.LibrarySearchRequest{SearchArgs: "arduino"}, lm) + resp := searchLibrary(&rpc.LibrarySearchRequest{SearchArgs: "arduino"}, li) assert := assert.New(t) assert.Equal(resp.GetStatus(), rpc.LibrarySearchStatus_LIBRARY_SEARCH_STATUS_SUCCESS) assert.Equal(len(resp.GetLibraries()), 2) @@ -61,13 +59,12 @@ func TestSearchLibrarySimilar(t *testing.T) { } func TestSearchLibraryFields(t *testing.T) { - lmb := librariesmanager.NewBuilder(fullIndexPath, nil) - lmb.LoadIndex() - lm := lmb.Build() + li, err := librariesindex.LoadIndex(fullIndexPath) + require.NoError(t, err) query := func(q string) []string { libs := []string{} - for _, lib := range searchLibrary(&rpc.LibrarySearchRequest{SearchArgs: q}, lm).GetLibraries() { + for _, lib := range searchLibrary(&rpc.LibrarySearchRequest{SearchArgs: q}, li).GetLibraries() { libs = append(libs, lib.GetName()) } return libs @@ -100,13 +97,12 @@ func TestSearchLibraryFields(t *testing.T) { } func TestSearchLibraryWithQualifiers(t *testing.T) { - lmb := librariesmanager.NewBuilder(qualifiedSearchIndexPath, nil) - lmb.LoadIndex() - lm := lmb.Build() + li, err := librariesindex.LoadIndex(qualifiedSearchIndexPath) + require.NoError(t, err) query := func(q string) []string { libs := []string{} - for _, lib := range searchLibrary(&rpc.LibrarySearchRequest{SearchArgs: q}, lm).GetLibraries() { + for _, lib := range searchLibrary(&rpc.LibrarySearchRequest{SearchArgs: q}, li).GetLibraries() { libs = append(libs, lib.GetName()) } return libs diff --git a/commands/lib/uninstall.go b/commands/lib/uninstall.go index 769790e03d0..1c42d670187 100644 --- a/commands/lib/uninstall.go +++ b/commands/lib/uninstall.go @@ -35,8 +35,10 @@ func LibraryUninstall(ctx context.Context, req *rpc.LibraryUninstallRequest, tas if err != nil { return &cmderrors.InvalidLibraryError{Cause: err} } + lmi, release := lm.NewInstaller() + defer release() - libs := lm.FindByReference(ref, libraries.User) + libs := lmi.FindByReference(ref, libraries.User) if len(libs) == 0 { taskCB(&rpc.TaskProgress{Message: tr("Library %s is not installed", req.GetName()), Completed: true}) @@ -45,7 +47,7 @@ func LibraryUninstall(ctx context.Context, req *rpc.LibraryUninstallRequest, tas if len(libs) == 1 { taskCB(&rpc.TaskProgress{Name: tr("Uninstalling %s", libs)}) - lm.Uninstall(libs[0]) + lmi.Uninstall(libs[0]) taskCB(&rpc.TaskProgress{Completed: true}) return nil } diff --git a/commands/lib/upgrade.go b/commands/lib/upgrade.go index 824d645d648..11b0c0019ac 100644 --- a/commands/lib/upgrade.go +++ b/commands/lib/upgrade.go @@ -26,12 +26,18 @@ import ( // LibraryUpgradeAll upgrades all the available libraries func LibraryUpgradeAll(req *rpc.LibraryUpgradeAllRequest, downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB) error { - lm, err := instances.GetLibraryManager(req.GetInstance()) + li, err := instances.GetLibrariesIndex(req.GetInstance()) if err != nil { return err } - if err := upgrade(req.GetInstance(), listLibraries(lm, true, false), downloadCB, taskCB); err != nil { + lme, release, err := instances.GetLibraryManagerExplorer(req.GetInstance()) + if err != nil { + return err + } + defer release() + + if err := upgrade(req.GetInstance(), listLibraries(lme, li, true, false), downloadCB, taskCB); err != nil { return err } @@ -44,14 +50,20 @@ func LibraryUpgradeAll(req *rpc.LibraryUpgradeAllRequest, downloadCB rpc.Downloa // LibraryUpgrade upgrades a library func LibraryUpgrade(ctx context.Context, req *rpc.LibraryUpgradeRequest, downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB) error { - lm, err := instances.GetLibraryManager(req.GetInstance()) + li, err := instances.GetLibrariesIndex(req.GetInstance()) + if err != nil { + return err + } + + lm, release, err := instances.GetLibraryManagerExplorer(req.GetInstance()) if err != nil { return err } + defer release() // Get the library to upgrade name := req.GetName() - lib := filterByName(listLibraries(lm, false, false), name) + lib := filterByName(listLibraries(lm, li, false, false), name) if lib == nil { // library not installed... return &cmderrors.LibraryNotFoundError{Library: name} diff --git a/commands/lib/utils.go b/commands/lib/utils.go index fbb5d52208c..f78e007bd06 100644 --- a/commands/lib/utils.go +++ b/commands/lib/utils.go @@ -19,7 +19,6 @@ import ( "github.com/arduino/arduino-cli/commands" "github.com/arduino/arduino-cli/commands/cmderrors" "github.com/arduino/arduino-cli/internal/arduino/libraries/librariesindex" - "github.com/arduino/arduino-cli/internal/arduino/libraries/librariesmanager" ) type libraryReferencer interface { @@ -36,12 +35,12 @@ func createLibIndexReference(req libraryReferencer) (*librariesindex.Reference, return &librariesindex.Reference{Name: req.GetName(), Version: version}, nil } -func findLibraryIndexRelease(lm *librariesmanager.LibrariesManager, req libraryReferencer) (*librariesindex.Release, error) { +func findLibraryIndexRelease(index *librariesindex.Index, req libraryReferencer) (*librariesindex.Release, error) { ref, err := createLibIndexReference(req) if err != nil { return nil, err } - lib := lm.Index.FindRelease(ref) + lib := index.FindRelease(ref) if lib == nil { return nil, &cmderrors.LibraryNotFoundError{Library: ref.String()} } diff --git a/internal/arduino/builder/internal/detector/detector.go b/internal/arduino/builder/internal/detector/detector.go index 3ff5bbbf5f1..33c84aaeb48 100644 --- a/internal/arduino/builder/internal/detector/detector.go +++ b/internal/arduino/builder/internal/detector/detector.go @@ -598,10 +598,10 @@ func LibrariesLoader( if useCachedLibrariesResolution { // Since we are using the cached libraries resolution // the library manager is not needed. - lm = librariesmanager.NewBuilder(nil, nil).Build() + lm = librariesmanager.NewBuilder().Build() } if librariesManager == nil { - lmb := librariesmanager.NewBuilder(nil, nil) + lmb := librariesmanager.NewBuilder() builtInLibrariesFolders := builtInLibrariesDirs if builtInLibrariesFolders != nil { @@ -629,14 +629,19 @@ func LibrariesLoader( } lm = lmb.Build() - for _, status := range lm.RescanLibraries() { - // With the refactoring of the initialization step of the CLI we changed how - // errors are returned when loading platforms and libraries, that meant returning a list of - // errors instead of a single one to enhance the experience for the user. - // I have no intention right now to start a refactoring of the legacy package too, so - // here's this shitty solution for now. - // When we're gonna refactor the legacy package this will be gone. - verboseOut.Write([]byte(status.Message())) + + { + lmi, release := lm.NewInstaller() + for _, status := range lmi.RescanLibraries() { + // With the refactoring of the initialization step of the CLI we changed how + // errors are returned when loading platforms and libraries, that meant returning a list of + // errors instead of a single one to enhance the experience for the user. + // I have no intention right now to start a refactoring of the legacy package too, so + // here's this shitty solution for now. + // When we're gonna refactor the legacy package this will be gone. + verboseOut.Write([]byte(status.Message())) + } + release() } } diff --git a/internal/arduino/libraries/librariesmanager/install.go b/internal/arduino/libraries/librariesmanager/install.go index 39af1f4b704..d078518bab1 100644 --- a/internal/arduino/libraries/librariesmanager/install.go +++ b/internal/arduino/libraries/librariesmanager/install.go @@ -58,14 +58,14 @@ type LibraryInstallPlan struct { // InstallPrerequisiteCheck performs prequisite checks to install a library. It returns the // install path, where the library should be installed and the possible library that is already // installed on the same folder and it's going to be replaced by the new one. -func (lm *LibrariesManager) InstallPrerequisiteCheck(name string, version *semver.Version, installLocation libraries.LibraryLocation) (*LibraryInstallPlan, error) { - installDir, err := lm.getLibrariesDir(installLocation) +func (lmi *Installer) InstallPrerequisiteCheck(name string, version *semver.Version, installLocation libraries.LibraryLocation) (*LibraryInstallPlan, error) { + installDir, err := lmi.getLibrariesDir(installLocation) if err != nil { return nil, err } - lm.RescanLibraries() - libs := lm.FindByReference(&librariesindex.Reference{Name: name}, installLocation) + lmi.RescanLibraries() + libs := lmi.FindByReference(&librariesindex.Reference{Name: name}, installLocation) if len(libs) > 1 { libsDir := paths.NewPathList() @@ -104,12 +104,12 @@ func (lm *LibrariesManager) InstallPrerequisiteCheck(name string, version *semve } // Install installs a library on the specified path. -func (lm *LibrariesManager) Install(indexLibrary *librariesindex.Release, installPath *paths.Path) error { - return indexLibrary.Resource.Install(lm.DownloadsDir, installPath.Parent(), installPath) +func (lmi *Installer) Install(indexLibrary *librariesindex.Release, installPath *paths.Path) error { + return indexLibrary.Resource.Install(lmi.downloadsDir, installPath.Parent(), installPath) } // importLibraryFromDirectory installs a library by copying it from the given directory. -func (lm *LibrariesManager) importLibraryFromDirectory(libPath *paths.Path, overwrite bool) error { +func (lmi *Installer) importLibraryFromDirectory(libPath *paths.Path, overwrite bool) error { // Check if the library is valid and load metatada if err := validateLibrary(libPath); err != nil { return err @@ -120,7 +120,7 @@ func (lm *LibrariesManager) importLibraryFromDirectory(libPath *paths.Path, over } // Check if the library is already installed and determine install path - installPlan, err := lm.InstallPrerequisiteCheck(library.Name, library.Version, libraries.User) + installPlan, err := lmi.InstallPrerequisiteCheck(library.Name, library.Version, libraries.User) if err != nil { return err } @@ -134,7 +134,7 @@ func (lm *LibrariesManager) importLibraryFromDirectory(libPath *paths.Path, over if !overwrite { return fmt.Errorf(tr("Library %[1]s is already installed, but with a different version: %[2]s", installPlan.Name, installPlan.ReplacedLib)) } - if err := lm.Uninstall(installPlan.ReplacedLib); err != nil { + if err := lmi.Uninstall(installPlan.ReplacedLib); err != nil { return err } } @@ -148,7 +148,7 @@ func (lm *LibrariesManager) importLibraryFromDirectory(libPath *paths.Path, over } // Uninstall removes a Library -func (lm *LibrariesManager) Uninstall(lib *libraries.Library) error { +func (lmi *Installer) Uninstall(lib *libraries.Library) error { if lib == nil || lib.InstallDir == nil { return fmt.Errorf(tr("install directory not set")) } @@ -156,14 +156,14 @@ func (lm *LibrariesManager) Uninstall(lib *libraries.Library) error { return fmt.Errorf(tr("removing library directory: %s"), err) } - alternatives := lm.Libraries[lib.Name] + alternatives := lmi.libraries[lib.Name] alternatives.Remove(lib) - lm.Libraries[lib.Name] = alternatives + lmi.libraries[lib.Name] = alternatives return nil } // InstallZipLib installs a Zip library on the specified path. -func (lm *LibrariesManager) InstallZipLib(ctx context.Context, archivePath *paths.Path, overwrite bool) error { +func (lmi *Installer) InstallZipLib(ctx context.Context, archivePath *paths.Path, overwrite bool) error { // Clone library in a temporary directory tmpDir, err := paths.MkTempDir("", "") if err != nil { @@ -197,7 +197,7 @@ func (lm *LibrariesManager) InstallZipLib(ctx context.Context, archivePath *path tmpInstallPath := libRootFiles[0] // Install extracted library in the destination directory - if err := lm.importLibraryFromDirectory(tmpInstallPath, overwrite); err != nil { + if err := lmi.importLibraryFromDirectory(tmpInstallPath, overwrite); err != nil { return fmt.Errorf(tr("moving extracted archive to destination dir: %s"), err) } @@ -205,7 +205,7 @@ func (lm *LibrariesManager) InstallZipLib(ctx context.Context, archivePath *path } // InstallGitLib installs a library hosted on a git repository on the specified path. -func (lm *LibrariesManager) InstallGitLib(gitURL string, overwrite bool) error { +func (lmi *Installer) InstallGitLib(gitURL string, overwrite bool) error { gitLibraryName, ref, err := parseGitURL(gitURL) if err != nil { return err @@ -246,7 +246,7 @@ func (lm *LibrariesManager) InstallGitLib(gitURL string, overwrite bool) error { tmpInstallPath.Join(".git").RemoveAll() // Install extracted library in the destination directory - if err := lm.importLibraryFromDirectory(tmpInstallPath, overwrite); err != nil { + if err := lmi.importLibraryFromDirectory(tmpInstallPath, overwrite); err != nil { return fmt.Errorf(tr("moving extracted archive to destination dir: %s"), err) } diff --git a/internal/arduino/libraries/librariesmanager/librariesmanager.go b/internal/arduino/libraries/librariesmanager/librariesmanager.go index fe16bc36909..272317ed42b 100644 --- a/internal/arduino/libraries/librariesmanager/librariesmanager.go +++ b/internal/arduino/libraries/librariesmanager/librariesmanager.go @@ -21,6 +21,7 @@ import ( "os" "slices" "strings" + "sync" "github.com/arduino/arduino-cli/internal/arduino/cores" "github.com/arduino/arduino-cli/internal/arduino/libraries" @@ -40,16 +41,21 @@ type Builder struct { *LibrariesManager } +type Explorer struct { + *LibrariesManager +} + +type Installer struct { + *LibrariesManager +} + // LibrariesManager keeps the current status of the libraries in the system // (the list of libraries, revisions, installed paths, etc.) type LibrariesManager struct { - LibrariesDir []*LibrariesDir - Libraries map[string]libraries.List `json:"libraries"` - indexDir *paths.Path - Index *librariesindex.Index - IndexFile *paths.Path - IndexFileSignature *paths.Path - DownloadsDir *paths.Path + librariesLock sync.RWMutex + librariesDir []*LibrariesDir + libraries map[string]libraries.List + downloadsDir *paths.Path } // LibrariesDir is a directory containing libraries @@ -62,10 +68,10 @@ type LibrariesDir struct { var tr = i18n.Tr // Names returns an array with all the names of the installed libraries. -func (lm LibrariesManager) Names() []string { - res := make([]string, len(lm.Libraries)) +func (lm *Explorer) Names() []string { + res := make([]string, len(lm.libraries)) i := 0 - for n := range lm.Libraries { + for n := range lm.libraries { res[i] = n i++ } @@ -79,20 +85,10 @@ func (lm LibrariesManager) Names() []string { } // NewBuilder creates a new library manager builder. -func NewBuilder(indexDir *paths.Path, downloadsDir *paths.Path) *Builder { - var indexFile, indexFileSignature *paths.Path - if indexDir != nil { - indexFile = indexDir.Join("library_index.json") - indexFileSignature = indexDir.Join("library_index.json.sig") - } +func NewBuilder() *Builder { return &Builder{ &LibrariesManager{ - Libraries: map[string]libraries.List{}, - indexDir: indexDir, - IndexFile: indexFile, - IndexFileSignature: indexFileSignature, - DownloadsDir: downloadsDir, - Index: librariesindex.EmptyIndex, + libraries: map[string]libraries.List{}, }, } } @@ -101,12 +97,22 @@ func NewBuilder(indexDir *paths.Path, downloadsDir *paths.Path) *Builder { // LibrariesManager. A "commit" function callback is returned: calling // this function will write the new configuration into this LibrariesManager. func (lm *LibrariesManager) NewBuilder() (*Builder, func()) { - lmb := NewBuilder(lm.indexDir, lm.DownloadsDir) + lmb := NewBuilder() return lmb, func() { lmb.BuildIntoExistingLibrariesManager(lm) } } +func (lm *LibrariesManager) NewExplorer() (*Explorer, func()) { + lm.librariesLock.RLock() + return &Explorer{lm}, lm.librariesLock.RUnlock +} + +func (lm *LibrariesManager) NewInstaller() (*Installer, func()) { + lm.librariesLock.Lock() + return &Installer{lm}, lm.librariesLock.Unlock +} + // Build builds a new LibrariesManager. func (lmb *Builder) Build() *LibrariesManager { res := &LibrariesManager{} @@ -117,39 +123,24 @@ func (lmb *Builder) Build() *LibrariesManager { // BuildIntoExistingLibrariesManager will overwrite the given LibrariesManager instead // of building a new one. func (lmb *Builder) BuildIntoExistingLibrariesManager(old *LibrariesManager) { - // TODO: write-mutex lock on "old"? - old.LibrariesDir = lmb.LibrariesDir - old.Libraries = lmb.Libraries - old.Index = lmb.Index - old.IndexFile = lmb.IndexFile - old.IndexFileSignature = lmb.IndexFileSignature - old.DownloadsDir = lmb.DownloadsDir -} - -// LoadIndex reads a library_index.json from a file and returns -// the corresponding Index structure. -func (lm *Builder) LoadIndex() error { - logrus.WithField("index", lm.IndexFile).Info("Loading libraries index file") - index, err := librariesindex.LoadIndex(lm.IndexFile) - if err != nil { - lm.Index = librariesindex.EmptyIndex - return err - } - lm.Index = index - return nil + old.librariesLock.Lock() + old.librariesDir = lmb.librariesDir + old.libraries = lmb.libraries + old.downloadsDir = lmb.downloadsDir + old.librariesLock.Unlock() } // AddLibrariesDir adds path to the list of directories // to scan when searching for libraries. If a path is already // in the list it is ignored. func (lm *Builder) AddLibrariesDir(path *paths.Path, location libraries.LibraryLocation) { - for _, dir := range lm.LibrariesDir { + for _, dir := range lm.librariesDir { if dir.Path.EquivalentTo(path) { return } } logrus.WithField("dir", path).WithField("location", location.String()).Info("Adding libraries dir") - lm.LibrariesDir = append(lm.LibrariesDir, &LibrariesDir{ + lm.librariesDir = append(lm.librariesDir, &LibrariesDir{ Path: path, Location: location, }) @@ -163,13 +154,13 @@ func (lm *Builder) AddPlatformReleaseLibrariesDir(plaftormRelease *cores.Platfor if path == nil { return } - for _, dir := range lm.LibrariesDir { + for _, dir := range lm.librariesDir { if dir.Path.EquivalentTo(path) { return } } logrus.WithField("dir", path).WithField("location", location.String()).Info("Adding libraries dir") - lm.LibrariesDir = append(lm.LibrariesDir, &LibrariesDir{ + lm.librariesDir = append(lm.librariesDir, &LibrariesDir{ Path: path, Location: location, PlatformRelease: plaftormRelease, @@ -177,14 +168,10 @@ func (lm *Builder) AddPlatformReleaseLibrariesDir(plaftormRelease *cores.Platfor } // RescanLibraries reload all installed libraries in the system. -func (lm *LibrariesManager) RescanLibraries() []*status.Status { - lmb, commit := lm.NewBuilder() - lmb.LibrariesDir = append([]*LibrariesDir{}, lm.LibrariesDir...) // clone - defer commit() - +func (lmi *Installer) RescanLibraries() []*status.Status { statuses := []*status.Status{} - for _, dir := range lmb.LibrariesDir { - if errs := lmb.loadLibrariesFromDir(dir); len(errs) > 0 { + for _, dir := range lmi.librariesDir { + if errs := lmi.loadLibrariesFromDir(dir); len(errs) > 0 { statuses = append(statuses, errs...) } } @@ -192,7 +179,7 @@ func (lm *LibrariesManager) RescanLibraries() []*status.Status { } func (lm *LibrariesManager) getLibrariesDir(installLocation libraries.LibraryLocation) (*paths.Path, error) { - for _, dir := range lm.LibrariesDir { + for _, dir := range lm.librariesDir { if dir.Location == installLocation { return dir.Path, nil } @@ -209,7 +196,7 @@ func (lm *LibrariesManager) getLibrariesDir(installLocation libraries.LibraryLoc // loadLibrariesFromDir loads all libraries in the given directory. Returns // nil if the directory doesn't exists. -func (lm *Builder) loadLibrariesFromDir(librariesDir *LibrariesDir) []*status.Status { +func (lm *Installer) loadLibrariesFromDir(librariesDir *LibrariesDir) []*status.Status { statuses := []*status.Status{} subDirs, err := librariesDir.Path.ReadDir() if os.IsNotExist(err) { @@ -230,9 +217,9 @@ func (lm *Builder) loadLibrariesFromDir(librariesDir *LibrariesDir) []*status.St continue } library.ContainerPlatform = librariesDir.PlatformRelease - alternatives := lm.Libraries[library.Name] + alternatives := lm.libraries[library.Name] alternatives.Add(library) - lm.Libraries[library.Name] = alternatives + lm.libraries[library.Name] = alternatives } return statuses @@ -241,8 +228,8 @@ func (lm *Builder) loadLibrariesFromDir(librariesDir *LibrariesDir) []*status.St // FindByReference return the installed libraries matching the Reference // name and version or, if the version is nil, the libraries installed // in the installLocation. -func (lm *LibrariesManager) FindByReference(libRef *librariesindex.Reference, installLocation libraries.LibraryLocation) libraries.List { - alternatives := lm.Libraries[libRef.Name] +func (lm *Installer) FindByReference(libRef *librariesindex.Reference, installLocation libraries.LibraryLocation) libraries.List { + alternatives := lm.libraries[libRef.Name] if alternatives == nil { return nil } @@ -252,8 +239,9 @@ func (lm *LibrariesManager) FindByReference(libRef *librariesindex.Reference, in // FindAllInstalled returns all the installed libraries func (lm *LibrariesManager) FindAllInstalled() libraries.List { var res libraries.List - for _, libAlternatives := range lm.Libraries { + for _, libAlternatives := range lm.libraries { for _, libRelease := range libAlternatives { + // TODO: is this check redundant? if libRelease.InstallDir == nil { continue } diff --git a/internal/arduino/libraries/librariesmanager/librariesmanager_test.go b/internal/arduino/libraries/librariesmanager/librariesmanager_test.go index 75c8195a036..2393868999e 100644 --- a/internal/arduino/libraries/librariesmanager/librariesmanager_test.go +++ b/internal/arduino/libraries/librariesmanager/librariesmanager_test.go @@ -18,16 +18,20 @@ import ( "testing" "github.com/arduino/arduino-cli/internal/arduino/libraries" - "github.com/arduino/go-paths-helper" "github.com/stretchr/testify/require" ) func Test_RescanLibrariesCallClear(t *testing.T) { - baseDir := paths.New(t.TempDir()) - lmb := NewBuilder(baseDir.Join("index_dir"), baseDir.Join("downloads_dir")) - lmb.Libraries["testLibA"] = libraries.List{} - lmb.Libraries["testLibB"] = libraries.List{} + lmb := NewBuilder() + lmb.libraries["testLibA"] = libraries.List{} + lmb.libraries["testLibB"] = libraries.List{} lm := lmb.Build() - lm.RescanLibraries() - require.Len(t, lm.Libraries, 0) + + { + lmi, release := lm.NewInstaller() + lmi.RescanLibraries() + release() + } + + require.Len(t, lm.libraries, 0) } diff --git a/internal/arduino/libraries/librariesresolver/cpp.go b/internal/arduino/libraries/librariesresolver/cpp.go index deee71545d3..1aad85758b2 100644 --- a/internal/arduino/libraries/librariesresolver/cpp.go +++ b/internal/arduino/libraries/librariesresolver/cpp.go @@ -46,10 +46,8 @@ func NewCppResolver() *Cpp { // ScanFromLibrariesManager reads all librariers loaded in the LibrariesManager to find // and cache all C++ headers for later retrieval func (resolver *Cpp) ScanFromLibrariesManager(lm *librariesmanager.LibrariesManager) error { - for _, libAlternatives := range lm.Libraries { - for _, lib := range libAlternatives { - resolver.ScanLibrary(lib) - } + for _, lib := range lm.FindAllInstalled() { + resolver.ScanLibrary(lib) } return nil } @@ -57,11 +55,9 @@ func (resolver *Cpp) ScanFromLibrariesManager(lm *librariesmanager.LibrariesMana // ScanIDEBuiltinLibraries reads ide-builtin librariers loaded in the LibrariesManager to find // and cache all C++ headers for later retrieval. func (resolver *Cpp) ScanIDEBuiltinLibraries(lm *librariesmanager.LibrariesManager) error { - for _, libAlternatives := range lm.Libraries { - for _, lib := range libAlternatives { - if lib.Location == libraries.IDEBuiltIn { - resolver.ScanLibrary(lib) - } + for _, lib := range lm.FindAllInstalled() { + if lib.Location == libraries.IDEBuiltIn { + resolver.ScanLibrary(lib) } } return nil @@ -70,11 +66,9 @@ func (resolver *Cpp) ScanIDEBuiltinLibraries(lm *librariesmanager.LibrariesManag // ScanUserAndUnmanagedLibraries reads user/unmanaged librariers loaded in the LibrariesManager to find // and cache all C++ headers for later retrieval. func (resolver *Cpp) ScanUserAndUnmanagedLibraries(lm *librariesmanager.LibrariesManager) error { - for _, libAlternatives := range lm.Libraries { - for _, lib := range libAlternatives { - if lib.Location == libraries.User || lib.Location == libraries.Unmanaged { - resolver.ScanLibrary(lib) - } + for _, lib := range lm.FindAllInstalled() { + if lib.Location == libraries.User || lib.Location == libraries.Unmanaged { + resolver.ScanLibrary(lib) } } return nil @@ -83,16 +77,14 @@ func (resolver *Cpp) ScanUserAndUnmanagedLibraries(lm *librariesmanager.Librarie // ScanPlatformLibraries reads platform-bundled libraries for a specific platform loaded in the LibrariesManager // to find and cache all C++ headers for later retrieval. func (resolver *Cpp) ScanPlatformLibraries(lm *librariesmanager.LibrariesManager, platform *cores.PlatformRelease) error { - for _, libAlternatives := range lm.Libraries { - for _, lib := range libAlternatives { - if lib.Location != libraries.PlatformBuiltIn && lib.Location != libraries.ReferencedPlatformBuiltIn { - continue - } - if lib.ContainerPlatform != platform { - continue - } - resolver.ScanLibrary(lib) + for _, lib := range lm.FindAllInstalled() { + if lib.Location != libraries.PlatformBuiltIn && lib.Location != libraries.ReferencedPlatformBuiltIn { + continue + } + if lib.ContainerPlatform != platform { + continue } + resolver.ScanLibrary(lib) } return nil }