Skip to content

Commit

Permalink
DRAFT
Browse files Browse the repository at this point in the history
  • Loading branch information
cmaglie committed Dec 27, 2023
1 parent e3ccdb4 commit 21ae56d
Show file tree
Hide file tree
Showing 17 changed files with 366 additions and 250 deletions.
40 changes: 26 additions & 14 deletions commands/instances.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,10 +301,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() {
Expand All @@ -319,10 +316,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
Expand All @@ -348,7 +350,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,
})
Expand All @@ -358,7 +360,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())
Expand All @@ -368,7 +370,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())
Expand All @@ -386,9 +388,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
Expand All @@ -410,12 +417,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())
pme, release, err := instances.GetPackageManagerExplorer(req.GetInstance())
if err != nil {
return err
}
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}
}

Expand All @@ -426,7 +438,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
}

Expand Down
55 changes: 51 additions & 4 deletions commands/internal/instances/instances.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
Expand Down Expand Up @@ -60,6 +62,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()
Expand All @@ -74,16 +119,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()
Expand Down
13 changes: 10 additions & 3 deletions commands/lib/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -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, err := instances.GetPackageManagerExplorer(req.GetInstance()); err != nil {
return nil, err
} 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.Index, 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
}

Expand Down
60 changes: 43 additions & 17 deletions commands/lib/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,25 +33,27 @@ 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())
// Obtain the library index from the manager
li, err := instances.GetLibrariesIndex(req.GetInstance())
if err != nil {
return err
}

toInstall := map[string]*rpc.LibraryDependencyStatus{}
installLocation := libraries.FromRPCLibraryInstallLocation(req.GetInstallLocation())
if req.GetNoDeps() {
toInstall[req.GetName()] = &rpc.LibraryDependencyStatus{
Name: req.GetName(),
VersionRequired: req.GetVersion(),
}
} else {
res, err := LibraryResolveDependencies(ctx, &rpc.LibraryResolveDependenciesRequest{
Instance: req.GetInstance(),
Name: req.GetName(),
Version: req.GetVersion(),
DoNotUpdateInstalledLibraries: req.GetNoOverwrite(),
})
// Obtain the library explorer from the instance
lme, releaseLme, err := instances.GetLibraryManagerExplorer(req.GetInstance())
if err != nil {
return err
}

res, err := libraryResolveDependencies(ctx, lme, li, req.GetName(), req.GetVersion(), req.GetNoOverwrite())
releaseLme()
if err != nil {
return err
}
Expand All @@ -69,18 +71,35 @@ func LibraryInstall(ctx context.Context, req *rpc.LibraryInstallRequest, downloa
}
}

// Obtain the download directory
var downloadsDir *paths.Path
if pme, releasePme, err := instances.GetPackageManagerExplorer(req.GetInstance()); err != nil {
return err
} else {
downloadsDir = pme.DownloadDir
releasePme()
}

// Obtain the library installer from the manager
lmi, releaseLmi, err := instances.GetLibraryManagerInstaller(req.GetInstance())
if err != nil {
return err
}
defer releaseLmi()

// Find the libReleasesToInstall to install
libReleasesToInstall := map[*librariesindex.Release]*librariesmanager.LibraryInstallPlan{}
installLocation := libraries.FromRPCLibraryInstallLocation(req.GetInstallLocation())
for _, lib := range toInstall {
libRelease, err := findLibraryIndexRelease(lm.Index, &rpc.LibraryInstallRequest{
libRelease, err := findLibraryIndexRelease(li, &rpc.LibraryInstallRequest{
Name: lib.GetName(),
Version: lib.GetVersionRequired(),
})
if err != nil {
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
}
Expand Down Expand Up @@ -109,10 +128,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, downloadsDir, libRelease, installTask, taskCB); err != nil {
return err
}
}
Expand All @@ -124,18 +143,21 @@ 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, downloadsDir *paths.Path, 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 {

installPath := installTask.TargetPath
tmpDirPath := installPath.Parent()
if err := libRelease.Resource.Install(downloadsDir, tmpDirPath, installPath); err != nil {
return &cmderrors.FailedLibraryInstallError{Cause: err}
}

Expand All @@ -149,7 +171,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})
Expand All @@ -162,7 +186,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})
Expand Down
Loading

0 comments on commit 21ae56d

Please sign in to comment.