Unverified Commit 51573f21 authored by Cristian Maglie's avatar Cristian Maglie Committed by GitHub

[skip-changelog] refactoring: Added `LibrariesManager.Clone()` / Auto-scan...

[skip-changelog] refactoring: Added `LibrariesManager.Clone()` / Auto-scan libs on `LibrariesManager.Build()` (#2491)

* Added LibrariesManager.Clone() / Auto-scan libraries on LibrariesManager.Build()

* Ensure AddLibrariesDir do not share input parameters

* Fixed wrong loop... ooops
parent 2972ed8d
...@@ -308,7 +308,7 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro ...@@ -308,7 +308,7 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro
for _, pack := range pme.GetPackages() { for _, pack := range pme.GetPackages() {
for _, platform := range pack.Platforms { for _, platform := range pack.Platforms {
if platformRelease := pme.GetInstalledPlatformRelease(platform); platformRelease != nil { if platformRelease := pme.GetInstalledPlatformRelease(platform); platformRelease != nil {
lmb.AddLibrariesDir(&librariesmanager.LibrariesDir{ lmb.AddLibrariesDir(librariesmanager.LibrariesDir{
PlatformRelease: platformRelease, PlatformRelease: platformRelease,
Path: platformRelease.GetLibrariesDir(), Path: platformRelease.GetLibrariesDir(),
Location: libraries.PlatformBuiltIn, Location: libraries.PlatformBuiltIn,
...@@ -336,14 +336,14 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro ...@@ -336,14 +336,14 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro
if profile == nil { if profile == nil {
// Add directories of libraries bundled with IDE // Add directories of libraries bundled with IDE
if bundledLibsDir := configuration.IDEBuiltinLibrariesDir(configuration.Settings); bundledLibsDir != nil { if bundledLibsDir := configuration.IDEBuiltinLibrariesDir(configuration.Settings); bundledLibsDir != nil {
lmb.AddLibrariesDir(&librariesmanager.LibrariesDir{ lmb.AddLibrariesDir(librariesmanager.LibrariesDir{
Path: bundledLibsDir, Path: bundledLibsDir,
Location: libraries.IDEBuiltIn, Location: libraries.IDEBuiltIn,
}) })
} }
// Add libraries directory from config file // Add libraries directory from config file
lmb.AddLibrariesDir(&librariesmanager.LibrariesDir{ lmb.AddLibrariesDir(librariesmanager.LibrariesDir{
Path: configuration.LibrariesDir(configuration.Settings), Path: configuration.LibrariesDir(configuration.Settings),
Location: libraries.User, Location: libraries.User,
}) })
...@@ -383,24 +383,19 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro ...@@ -383,24 +383,19 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro
taskCallback(&rpc.TaskProgress{Completed: true}) taskCallback(&rpc.TaskProgress{Completed: true})
} }
lmb.AddLibrariesDir(&librariesmanager.LibrariesDir{ lmb.AddLibrariesDir(librariesmanager.LibrariesDir{
Path: libRoot, Path: libRoot,
Location: libraries.User, Location: libraries.User,
}) })
} }
} }
lm := lmb.Build() lm, libsLoadingWarnings := lmb.Build()
_ = instances.SetLibraryManager(instance, lm) // should never fail _ = instances.SetLibraryManager(instance, lm) // should never fail
for _, status := range libsLoadingWarnings {
{
lmi, release := lm.NewInstaller()
for _, status := range lmi.RescanLibraries() {
logrus.WithError(status.Err()).Warnf("Error loading library") logrus.WithError(status.Err()).Warnf("Error loading library")
// TODO: report as warning: responseError(err) // TODO: report as warning: responseError(err)
} }
release()
}
// Refreshes the locale used, this will change the // Refreshes the locale used, this will change the
// language of the CLI if the locale is different // language of the CLI if the locale is different
......
...@@ -126,9 +126,12 @@ func Create(dataDir, packagesDir, downloadsDir *paths.Path, extraUserAgent ...st ...@@ -126,9 +126,12 @@ func Create(dataDir, packagesDir, downloadsDir *paths.Path, extraUserAgent ...st
} }
tempDir := dataDir.Join("tmp") tempDir := dataDir.Join("tmp")
pm := packagemanager.NewBuilder(dataDir, packagesDir, downloadsDir, tempDir, userAgent).Build()
lm, _ := librariesmanager.NewBuilder().Build()
instance := &coreInstance{ instance := &coreInstance{
pm: packagemanager.NewBuilder(dataDir, packagesDir, downloadsDir, tempDir, userAgent).Build(), pm: pm,
lm: librariesmanager.NewBuilder().Build(), lm: lm,
li: librariesindex.EmptyIndex, li: librariesindex.EmptyIndex,
} }
......
...@@ -598,7 +598,7 @@ func LibrariesLoader( ...@@ -598,7 +598,7 @@ func LibrariesLoader(
if useCachedLibrariesResolution { if useCachedLibrariesResolution {
// Since we are using the cached libraries resolution // Since we are using the cached libraries resolution
// the library manager is not needed. // the library manager is not needed.
lm = librariesmanager.NewBuilder().Build() lm, _ = librariesmanager.NewBuilder().Build()
} }
if librariesManager == nil { if librariesManager == nil {
lmb := librariesmanager.NewBuilder() lmb := librariesmanager.NewBuilder()
...@@ -608,20 +608,20 @@ func LibrariesLoader( ...@@ -608,20 +608,20 @@ func LibrariesLoader(
if err := builtInLibrariesFolders.ToAbs(); err != nil { if err := builtInLibrariesFolders.ToAbs(); err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }
lmb.AddLibrariesDir(&librariesmanager.LibrariesDir{ lmb.AddLibrariesDir(librariesmanager.LibrariesDir{
Path: builtInLibrariesFolders, Path: builtInLibrariesFolders,
Location: libraries.IDEBuiltIn, Location: libraries.IDEBuiltIn,
}) })
} }
if actualPlatform != targetPlatform { if actualPlatform != targetPlatform {
lmb.AddLibrariesDir(&librariesmanager.LibrariesDir{ lmb.AddLibrariesDir(librariesmanager.LibrariesDir{
PlatformRelease: actualPlatform, PlatformRelease: actualPlatform,
Path: actualPlatform.GetLibrariesDir(), Path: actualPlatform.GetLibrariesDir(),
Location: libraries.ReferencedPlatformBuiltIn, Location: libraries.ReferencedPlatformBuiltIn,
}) })
} }
lmb.AddLibrariesDir(&librariesmanager.LibrariesDir{ lmb.AddLibrariesDir(librariesmanager.LibrariesDir{
PlatformRelease: targetPlatform, PlatformRelease: targetPlatform,
Path: targetPlatform.GetLibrariesDir(), Path: targetPlatform.GetLibrariesDir(),
Location: libraries.PlatformBuiltIn, Location: libraries.PlatformBuiltIn,
...@@ -632,25 +632,22 @@ func LibrariesLoader( ...@@ -632,25 +632,22 @@ func LibrariesLoader(
return nil, nil, nil, err return nil, nil, nil, err
} }
for _, folder := range librariesFolders { for _, folder := range librariesFolders {
lmb.AddLibrariesDir(&librariesmanager.LibrariesDir{ lmb.AddLibrariesDir(librariesmanager.LibrariesDir{
Path: folder, Path: folder,
Location: libraries.User, // XXX: Should be libraries.Unmanaged? Location: libraries.User, // XXX: Should be libraries.Unmanaged?
}) })
} }
for _, dir := range libraryDirs { for _, dir := range libraryDirs {
lmb.AddLibrariesDir(&librariesmanager.LibrariesDir{ lmb.AddLibrariesDir(librariesmanager.LibrariesDir{
Path: dir, Path: dir,
Location: libraries.Unmanaged, Location: libraries.Unmanaged,
IsSingleLibrary: true, IsSingleLibrary: true,
}) })
} }
lm = lmb.Build() newLm, libsLoadingWarnings := lmb.Build()
for _, status := range libsLoadingWarnings {
{
lmi, release := lm.NewInstaller()
for _, status := range lmi.RescanLibraries() {
// With the refactoring of the initialization step of the CLI we changed how // 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 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. // errors instead of a single one to enhance the experience for the user.
...@@ -659,8 +656,7 @@ func LibrariesLoader( ...@@ -659,8 +656,7 @@ func LibrariesLoader(
// When we're gonna refactor the legacy package this will be gone. // When we're gonna refactor the legacy package this will be gone.
verboseOut.Write([]byte(status.Message())) verboseOut.Write([]byte(status.Message()))
} }
release() lm = newLm
}
} }
allLibs := lm.FindAllInstalled() allLibs := lm.FindAllInstalled()
......
...@@ -65,6 +65,7 @@ type LibrariesDir struct { ...@@ -65,6 +65,7 @@ type LibrariesDir struct {
Location libraries.LibraryLocation Location libraries.LibraryLocation
PlatformRelease *cores.PlatformRelease PlatformRelease *cores.PlatformRelease
IsSingleLibrary bool // true if Path points directly to a library instad of a dir of libraries IsSingleLibrary bool // true if Path points directly to a library instad of a dir of libraries
scanned bool
} }
var tr = i18n.Tr var tr = i18n.Tr
...@@ -95,14 +96,19 @@ func NewBuilder() *Builder { ...@@ -95,14 +96,19 @@ func NewBuilder() *Builder {
} }
} }
// NewBuilder creates a Builder with the same configuration of this // Clone creates a Builder starting with a copy of the same configuration
// LibrariesManager. A "commit" function callback is returned: calling // of this LibrariesManager. At the moment of the Build() only the added
// this function will write the new configuration into this LibrariesManager. // libraries directories will be scanned, keeping the existing directories
func (lm *LibrariesManager) NewBuilder() (*Builder, func()) { // "cached" to optimize scan. If you need to do a full rescan you must use
// the RescanLibraries method of the Installer.
func (lm *LibrariesManager) Clone() *Builder {
lmb := NewBuilder() lmb := NewBuilder()
return lmb, func() { lmb.librariesDir = append(lmb.librariesDir, lm.librariesDir...)
lmb.BuildIntoExistingLibrariesManager(lm) for libName, libAlternatives := range lm.libraries {
// TODO: Maybe we should deep clone libAlternatives...
lmb.libraries[libName] = append(lmb.libraries[libName], libAlternatives...)
} }
return lmb
} }
// NewExplorer returns a new Explorer. The returned function must be called // NewExplorer returns a new Explorer. The returned function must be called
...@@ -120,10 +126,18 @@ func (lm *LibrariesManager) NewInstaller() (*Installer, func()) { ...@@ -120,10 +126,18 @@ func (lm *LibrariesManager) NewInstaller() (*Installer, func()) {
} }
// Build builds a new LibrariesManager. // Build builds a new LibrariesManager.
func (lmb *Builder) Build() *LibrariesManager { func (lmb *Builder) Build() (*LibrariesManager, []*status.Status) {
var statuses []*status.Status
res := &LibrariesManager{} res := &LibrariesManager{}
for _, dir := range lmb.librariesDir {
if !dir.scanned {
if errs := lmb.loadLibrariesFromDir(dir); len(errs) > 0 {
statuses = append(statuses, errs...)
}
}
}
lmb.BuildIntoExistingLibrariesManager(res) lmb.BuildIntoExistingLibrariesManager(res)
return res return res, statuses
} }
// BuildIntoExistingLibrariesManager will overwrite the given LibrariesManager instead // BuildIntoExistingLibrariesManager will overwrite the given LibrariesManager instead
...@@ -138,7 +152,7 @@ func (lmb *Builder) BuildIntoExistingLibrariesManager(old *LibrariesManager) { ...@@ -138,7 +152,7 @@ func (lmb *Builder) BuildIntoExistingLibrariesManager(old *LibrariesManager) {
// AddLibrariesDir adds path to the list of directories // AddLibrariesDir adds path to the list of directories
// to scan when searching for libraries. If a path is already // to scan when searching for libraries. If a path is already
// in the list it is ignored. // in the list it is ignored.
func (lmb *Builder) AddLibrariesDir(libDir *LibrariesDir) { func (lmb *Builder) AddLibrariesDir(libDir LibrariesDir) {
if libDir.Path == nil { if libDir.Path == nil {
return return
} }
...@@ -151,7 +165,7 @@ func (lmb *Builder) AddLibrariesDir(libDir *LibrariesDir) { ...@@ -151,7 +165,7 @@ func (lmb *Builder) AddLibrariesDir(libDir *LibrariesDir) {
WithField("location", libDir.Location.String()). WithField("location", libDir.Location.String()).
WithField("isSingleLibrary", libDir.IsSingleLibrary). WithField("isSingleLibrary", libDir.IsSingleLibrary).
Info("Adding libraries dir") Info("Adding libraries dir")
lmb.librariesDir = append(lmb.librariesDir, libDir) lmb.librariesDir = append(lmb.librariesDir, &libDir)
} }
// RescanLibraries reload all installed libraries in the system. // RescanLibraries reload all installed libraries in the system.
...@@ -184,9 +198,11 @@ func (lm *LibrariesManager) getLibrariesDir(installLocation libraries.LibraryLoc ...@@ -184,9 +198,11 @@ func (lm *LibrariesManager) getLibrariesDir(installLocation libraries.LibraryLoc
// loadLibrariesFromDir loads all libraries in the given directory. Returns // loadLibrariesFromDir loads all libraries in the given directory. Returns
// nil if the directory doesn't exists. // nil if the directory doesn't exists.
func (lmi *Installer) loadLibrariesFromDir(librariesDir *LibrariesDir) []*status.Status { func (lm *LibrariesManager) loadLibrariesFromDir(librariesDir *LibrariesDir) []*status.Status {
statuses := []*status.Status{} statuses := []*status.Status{}
librariesDir.scanned = true
var libDirs paths.PathList var libDirs paths.PathList
if librariesDir.IsSingleLibrary { if librariesDir.IsSingleLibrary {
libDirs.Add(librariesDir.Path) libDirs.Add(librariesDir.Path)
...@@ -212,9 +228,9 @@ func (lmi *Installer) loadLibrariesFromDir(librariesDir *LibrariesDir) []*status ...@@ -212,9 +228,9 @@ func (lmi *Installer) loadLibrariesFromDir(librariesDir *LibrariesDir) []*status
continue continue
} }
library.ContainerPlatform = librariesDir.PlatformRelease library.ContainerPlatform = librariesDir.PlatformRelease
alternatives := lmi.libraries[library.Name] alternatives := lm.libraries[library.Name]
alternatives.Add(library) alternatives.Add(library)
lmi.libraries[library.Name] = alternatives lm.libraries[library.Name] = alternatives
} }
return statuses return statuses
......
...@@ -21,17 +21,25 @@ import ( ...@@ -21,17 +21,25 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func Test_RescanLibrariesCallClear(t *testing.T) { func TestLibrariesBuilderScanCloneRescan(t *testing.T) {
lmb := NewBuilder() lmb := NewBuilder()
lmb.libraries["testLibA"] = libraries.List{} lmb.libraries["testLibA"] = libraries.List{}
lmb.libraries["testLibB"] = libraries.List{} lmb.libraries["testLibB"] = libraries.List{}
lm := lmb.Build() lm, warns := lmb.Build()
require.Empty(t, warns)
require.Len(t, lm.libraries, 2)
// Cloning should keep existing libraries
lm2, warns2 := lm.Clone().Build()
require.Empty(t, warns2)
require.Len(t, lm2.libraries, 2)
// Full rescan should update libs
{ {
lmi, release := lm.NewInstaller() lmi2, release := lm2.NewInstaller()
lmi.RescanLibraries() lmi2.RescanLibraries()
release() release()
} }
require.Len(t, lm.libraries, 2) // Ensure deep-coping worked as expected...
require.Len(t, lm.libraries, 0) require.Len(t, lm2.libraries, 0)
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment