8000 [breaking] daemon: Fix concurrency and streamline access to PackageManager by cmaglie · Pull Request #1828 · arduino/arduino-cli · GitHub
[go: up one dir, main page]

Skip to content

[breaking] daemon: Fix concurrency and streamline access to PackageManager #1828

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Aug 26, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

10000
Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Created packagemanager.Explorer to query PackageManager data
The Explorer object can be see as a read-only "view" to the underlying
PackageManager: we may ask the PackageManager to create an Explorer on
itself. The returned explorer will held a read-lock on the
PackageManager until it's disposed.

This architecture should prevent unwanted changes on the PackageManager
while it's being used, and viceversa, when the PackageManager is updated
it should be guaranteed that no Explorers are reading it.
  • Loading branch information
cmaglie committed Aug 22, 2022
commit 1b8a35c3db6a825f12604ed2da82cb884adcb635
10 changes: 5 additions & 5 deletions arduino/cores/packagemanager/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func (platform *PlatformReference) String() string {
// FindPlatform returns the Platform matching the PlatformReference or nil if not found.
// The PlatformVersion field of the reference is ignored.
func (pm *PackageManager) FindPlatform(ref *PlatformReference) *cores.Platform {
targetPackage, ok := pm.Packages[ref.Package]
targetPackage, ok := pm.packages[ref.Package]
if !ok {
return nil
}
Expand All @@ -71,7 +71,7 @@ func (pm *PackageManager) FindPlatformRelease(ref *PlatformReference) *cores.Pla
// FindPlatformReleaseDependencies takes a PlatformReference and returns a set of items to download and
// a set of outputs for non existing platforms.
func (pm *PackageManager) FindPlatformReleaseDependencies(item *PlatformReference) (*cores.PlatformRelease, []*cores.ToolRelease, error) {
targetPackage, exists := pm.Packages[item.Package]
targetPackage, exists := pm.packages[item.Package]
if !exists {
return nil, nil, fmt.Errorf(tr("package %s not found"), item.Package)
}
Expand All @@ -94,22 +94,22 @@ func (pm *PackageManager) FindPlatformReleaseDependencies(item *PlatformReferenc
}

// replaces "latest" with latest version too
toolDeps, err := pm.Packages.GetPlatformReleaseToolDependencies(release)
toolDeps, err := pm.packages.GetPlatformReleaseToolDependencies(release)
if err != nil {
return nil, nil, fmt.Errorf(tr("getting tool dependencies for platform %[1]s: %[2]s"), release.String(), err)
}

// discovery dependencies differ from normal tool since we always want to use the latest
// available version for the platform package
discoveryDependencies, err := pm.Packages.GetPlatformReleaseDiscoveryDependencies(release)
discoveryDependencies, err := pm.packages.GetPlatformReleaseDiscoveryDependencies(release)
if err != nil {
return nil, nil, fmt.Errorf(tr("getting discovery dependencies for platform %[1]s: %[2]s"), release.String(), err)
}
toolDeps = append(toolDeps, discoveryDependencies...)

// monitor dependencies differ from normal tool since we always want to use the latest
// available version for the platform package
monitorDependencies, err := pm.Packages.GetPlatformReleaseMonitorDependencies(release)
monitorDependencies, err := pm.packages.GetPlatformReleaseMonitorDependencies(release)
if err != nil {
return nil, nil, fmt.Errorf(tr("getting monitor dependencies for platform %[1]s: %[2]s"), release.String(), err)
}
Expand Down
4 changes: 2 additions & 2 deletions arduino/cores/packagemanager/identify.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ import (

// IdentifyBoard returns a list of boards whose identification properties match the
// provided ones.
func (pm *PackageManager) IdentifyBoard(idProps *properties.Map) []*cores.Board {
func (pme *Explorer) IdentifyBoard(idProps *properties.Map) []*cores.Board {
if idProps.Size() == 0 {
return []*cores.Board{}
}
foundBoards := []*cores.Board{}
for _, board := range pm.InstalledBoards() {
for _, board := range pme.InstalledBoards() {
if board.IsBoardMatchingIDProperties(idProps) {
foundBoards = append(foundBoards, board)
}
Expand Down
46 changes: 23 additions & 23 deletions arduino/cores/packagemanager/install_uninstall.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import (
// DownloadAndInstallPlatformUpgrades runs a full installation process to upgrade the given platform.
// This method takes care of downloading missing archives, upgrading platforms and tools, and
// removing the previously installed platform/tools that are no longer needed after the upgrade.
func (pm *PackageManager) DownloadAndInstallPlatformUpgrades(
func (pme *Explorer) DownloadAndInstallPlatformUpgrades(
platformRef *PlatformReference,
downloadCB rpc.DownloadProgressCB,
taskCB rpc.TaskProgressCB,
Expand All @@ -43,11 +43,11 @@ func (pm *PackageManager) DownloadAndInstallPlatformUpgrades(
}

// Search the latest version for all specified platforms
platform := pm.FindPlatform(platformRef)
platform := pme.FindPlatform(platformRef)
if platform == nil {
return &arduino.PlatformNotFoundError{Platform: platformRef.String()}
}
installed := pm.GetInstalledPlatformRelease(platform)
installed := pme.GetInstalledPlatformRelease(platform)
if installed == nil {
return &arduino.PlatformNotFoundError{Platform: platformRef.String()}
}
Expand All @@ -57,11 +57,11 @@ func (pm *PackageManager) DownloadAndInstallPlatformUpgrades(
}
platformRef.PlatformVersion = latest.Version

platformRelease, tools, err := pm.FindPlatformReleaseDependencies(platformRef)
platformRelease, tools, err := pme.FindPlatformReleaseDependencies(platformRef)
if err != nil {
return &arduino.PlatformNotFoundError{Platform: platformRef.String()}
}
if err := pm.DownloadAndInstallPlatformAndTools(platformRelease, tools, downloadCB, taskCB, skipPostInstall); err != nil {
if err := pme.DownloadAndInstallPlatformAndTools(platformRelease, tools, downloadCB, taskCB, skipPostInstall); err != nil {
return err
}

Expand All @@ -71,11 +71,11 @@ func (pm *PackageManager) DownloadAndInstallPlatformUpgrades(
// DownloadAndInstallPlatformAndTools runs a full installation process for the given platform and tools.
// This method takes care of downloading missing archives, installing/upgrading platforms and tools, and
// removing the previously installed platform/tools that are no longer needed after the upgrade.
func (pm *PackageManager) DownloadAndInstallPlatformAndTools(
func (pme *Explorer) DownloadAndInstallPlatformAndTools(
platformRelease *cores.PlatformRelease, requiredTools []*cores.ToolRelease,
downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB,
skipPostInstall bool) error {
log := pm.log.WithField("platform", platformRelease)
log := pme.log.WithField("platform", platformRelease)

// Prerequisite checks before install
toolsToInstall := []*cores.ToolRelease{}
Expand All @@ -91,23 +91,23 @@ func (pm *PackageManager) DownloadAndInstallPlatformAndTools(
// Package download
taskCB(&rpc.TaskProgress{Name: tr("Downloading packages")})
for _, tool := range toolsToInstall {
if err := pm.DownloadToolRelease(tool, nil, downloadCB); err != nil {
if err := pme.DownloadToolRelease(tool, nil, downloadCB); err != nil {
return err
}
}
if err := pm.DownloadPlatformRelease(platformRelease, nil, downloadCB); err != nil {
if err := pme.DownloadPlatformRelease(platformRelease, nil, downloadCB); err != nil {
return err
}
taskCB(&rpc.TaskProgress{Completed: true})

// Install tools first
for _, tool := range toolsToInstall {
if err := pm.InstallTool(tool, taskCB); err != nil {
if err := pme.InstallTool(tool, taskCB); err != nil {
return err
}
}

installed := pm.GetInstalledPlatformRelease(platformRelease.Platform)
installed := pme.GetInstalledPlatformRelease(platformRelease.Platform)
installedTools := []*cores.ToolRelease{}
if installed == nil {
// No version of this platform is installed
Expand All @@ -127,29 +127,29 @@ func (pm *PackageManager) DownloadAndInstallPlatformAndTools(
// This must be done so tools used by the currently installed version are
// removed if not used also by the newly installed version.
var err error
_, installedTools, err = pm.FindPlatformReleaseDependencies(platformRef)
_, installedTools, err = pme.FindPlatformReleaseDependencies(platformRef)
if err != nil {
return &arduino.NotFoundError{Message: tr("Can't find dependencies for platform %s", platformRef), Cause: err}
}
}

// Install
if err := pm.InstallPlatform(platformRelease); err != nil {
if err := pme.InstallPlatform(platformRelease); err != nil {
log.WithError(err).Error("Cannot install platform")
return &arduino.FailedInstallError{Message: tr("Cannot install platform"), Cause: err}
}

// If upgrading remove previous release
if installed != nil {
uninstallErr := pm.UninstallPlatform(installed, taskCB)
uninstallErr := pme.UninstallPlatform(installed, taskCB)

// In case of error try to rollback
if uninstallErr != nil {
log.WithError(uninstallErr).Error("Error upgrading platform.")
taskCB(&rpc.TaskProgress{Message: tr("Error upgrading platform: %s", uninstallErr)})

// Rollback
if err := pm.UninstallPlatform(platformRelease, taskCB); err != nil {
if err := pme.UninstallPlatform(platformRelease, taskCB); err != nil {
log.WithError(err).Error("Error rolling-back changes.")
taskCB(&rpc.TaskProgress{Message: tr("Error rolling-back changes: %s", err)})
}
Expand All @@ -160,8 +160,8 @@ func (pm *PackageManager) DownloadAndInstallPlatformAndTools(
// Uninstall unused tools
for _, tool := range installedTools {
taskCB(&rpc.TaskProgress{Name: tr("Uninstalling %s, tool is no more required", tool)})
if !pm.IsToolRequired(tool) {
pm.UninstallTool(tool, taskCB)
if !pme.IsToolRequired(tool) {
pme.UninstallTool(tool, taskCB)
}
}

Expand All @@ -171,7 +171,7 @@ func (pm *PackageManager) DownloadAndInstallPlatformAndTools(
if !skipPostInstall {
log.Info("Running post_install script")
taskCB(&rpc.TaskProgress{Message: tr("Configuring platform.")})
if err := pm.RunPostInstallScript(platformRelease); err != nil {
if err := pme.RunPostInstallScript(platformRelease); err != nil {
taskCB(&rpc.TaskProgress{Message: tr("WARNING cannot configure platform: %s", err)})
}
} else {
Expand Down Expand Up @@ -223,7 +223,7 @@ func (pm *PackageManager) cacheInstalledJSON(platformRelease *cores.PlatformRele

// RunPostInstallScript runs the post_install.sh (or post_install.bat) script for the
// specified platformRelease.
func (pm *PackageManager) RunPostInstallScript(platformRelease *cores.PlatformRelease) error {
func (pme *Explorer) RunPostInstallScript(platformRelease *cores.PlatformRelease) error {
if !platformRelease.IsInstalled() {
return errors.New(tr("platform not installed"))
}
Expand All @@ -233,7 +233,7 @@ func (pm *PackageManager) RunPostInstallScript(platformRelease *cores.PlatformRe
}
postInstall := platformRelease.InstallDir.Join(postInstallFilename)
if postInstall.Exist() && postInstall.IsNotDir() {
cmd, err := executils.NewProcessFromPath(pm.GetEnvVarsForSpawnedProcess(), postInstall)
cmd, err := executils.NewProcessFromPath(pme.GetEnvVarsForSpawnedProcess(), postInstall)
if err != nil {
return err
}
Expand Down Expand Up @@ -382,11 +382,11 @@ func (pm *PackageManager) UninstallTool(toolRelease *cores.ToolRelease, taskCB r

// IsToolRequired returns true if any of the installed platforms requires the toolRelease
// passed as parameter
func (pm *PackageManager) IsToolRequired(toolRelease *cores.ToolRelease) bool {
func (pme *Explorer) IsToolRequired(toolRelease *cores.ToolRelease) bool {
// Search in all installed platforms
for _, targetPackage := range pm.Packages {
for _, targetPackage := range pme.packages {
for _, platform := range targetPackage.Platforms {
if platformRelease := pm.GetInstalledPlatformRelease(platform); platformRelease != nil {
if platformRelease := pme.GetInstalledPlatformRelease(platform); platformRelease != nil {
if platformRelease.RequiresToolRelease(toolRelease) {
return true
}
Expand Down
36 changes: 18 additions & 18 deletions arduino/cores/packagemanager/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ func (pm *Builder) LoadHardwareFromDirectory(path *paths.Path) []error {
if p, err := properties.LoadFromPath(globalPlatformTxt); err != nil {
pm.log.WithError(err).Errorf("Error loading properties.")
} else {
pm.CustomGlobalProperties.Merge(p)
pm.packagesCustomGlobalProperties.Merge(p)
}
}

Expand Down Expand Up @@ -121,7 +121,7 @@ func (pm *Builder) LoadHardwareFromDirectory(path *paths.Path) []error {
architectureParentPath = packagerPath
}

targetPackage := pm.Packages.GetOrCreatePackage(packager)
targetPackage := pm.packages.GetOrCreatePackage(packager)
merr = append(merr, pm.loadPlatforms(targetPackage, architectureParentPath)...)

// Check if we have tools to load, the directory structure is as follows:
Expand All @@ -133,7 +133,7 @@ func (pm *Builder) LoadHardwareFromDirectory(path *paths.Path) []error {
}
// If the Package does not contain Platforms or Tools we remove it since does not contain anything valuable
if len(targetPackage.Platforms) == 0 && len(targetPackage.Tools) == 0 {
delete(pm.Packages, packager)
delete(pm.packages, packager)
}
}

Expand Down Expand Up @@ -706,7 +706,7 @@ func (pm *Builder) LoadToolsFromBundleDirectory(toolsPath *paths.Path) error {
}

for packager, toolsData := range all.FirstLevelOf() {
targetPackage := pm.Packages.GetOrCreatePackage(packager)
targetPackage := pm.packages.GetOrCreatePackage(packager)

for toolName, toolVersion := range toolsData.AsMap() {
tool := targetPackage.GetOrCreateTool(toolName)
Expand All @@ -718,7 +718,7 @@ func (pm *Builder) LoadToolsFromBundleDirectory(toolsPath *paths.Path) error {
}
} else {
// otherwise load the tools inside the unnamed package
unnamedPackage := pm.Packages.GetOrCreatePackage("")
unnamedPackage := pm.packages.GetOrCreatePackage("")
pm.LoadToolsFromPackageDir(unnamedPackage, toolsPath)
}
return nil
Expand All @@ -729,18 +729,18 @@ func (pm *Builder) LoadToolsFromBundleDirectory(toolsPath *paths.Path) error {
// * A PluggableDiscovery instance can't be created
// * Tools required by the PlatformRelease cannot be found
// * Command line to start PluggableDiscovery has malformed or mismatched quotes
func (pm *PackageManager) LoadDiscoveries() []error {
func (pme *Explorer) LoadDiscoveries() []error {
var merr []error
for _, platform := range pm.InstalledPlatformReleases() {
merr = append(merr, pm.loadDiscoveries(platform)...)
for _, platform := range pme.InstalledPlatformReleases() {
merr = append(merr, pme.loadDiscoveries(platform)...)
}
merr = append(merr, pm.loadBuiltinDiscoveries()...)
merr = append(merr, pme.loadBuiltinDiscoveries()...)
return merr
}

// loadDiscovery loads the discovery tool with id, if it cannot be found a non-nil status is returned
func (pm *PackageManager) loadDiscovery(id string) error {
tool := pm.GetTool(id)
func (pme *Explorer) loadDiscovery(id string) error {
tool := pme.GetTool(id)
if tool == nil {
return errors.New(tr("discovery %s not found", id))
}
Expand All @@ -750,22 +750,22 @@ func (pm *PackageManager) loadDiscovery(id string) error {
}
discoveryPath := toolRelease.InstallDir.Join(tool.Name).String()
d := discovery.New(id, discoveryPath)
pm.discoveryManager.Add(d)
pme.discoveryManager.Add(d)
return nil
}

// loadBuiltinDiscoveries loads the discovery tools that are part of the builtin package
func (pm *PackageManager) loadBuiltinDiscoveries() []error {
func (pme *Explorer) loadBuiltinDiscoveries() []error {
var merr []error
for _, id := range []string{"builtin:serial-discovery", "builtin:mdns-discovery"} {
if err := pm.loadDiscovery(id); err != nil {
if err := pme.loadDiscovery(id); err != nil {
merr = append(merr, err)
}
}
return merr
}

func (pm *PackageManager) loadDiscoveries(release *cores.PlatformRelease) []error {
func (pme *Explorer) loadDiscoveries(release *cores.PlatformRelease) []error {
var merr []error
discoveryProperties := release.Properties.SubTree("pluggable_discovery")

Expand All @@ -784,7 +784,7 @@ func (pm *PackageManager) loadDiscoveries(release *cores.PlatformRelease) []erro
//
// If both indexed and unindexed properties are found the unindexed are ignored
for _, id := range discoveryProperties.ExtractSubIndexLists("required") {
if err := pm.loadDiscovery(id); err != nil {
if err := pme.loadDiscovery(id); err != nil {
merr = append(merr, err)
}
}
Expand All @@ -799,7 +799,7 @@ func (pm *PackageManager) loadDiscoveries(release *cores.PlatformRelease) []erro
var tools []*cores.ToolRelease
if len(discoveryIDs) > 0 {
var err error
tools, err = pm.FindToolsRequiredFromPlatformRelease(release)
tools, err = pme.FindToolsRequiredFromPlatformRelease(release)
if err != nil {
merr = append(merr, err)
}
Expand Down Expand Up @@ -827,7 +827,7 @@ func (pm *PackageManager) loadDiscoveries(release *cores.PlatformRelease) []erro
merr = append(merr, err)
} else {
d := discovery.New(discoveryID, cmdArgs...)
pm.discoveryManager.Add(d)
pme.discoveryManager.Add(d)
}
}

Expand Down
Loading
0