Unverified Commit c7163b77 authored by Cristian Maglie's avatar Cristian Maglie Committed by GitHub

[skip-changelog] [breaking] Downloaders/Installers refactor (#1809)

* Made PackageManager.TempDir private

* Merged InstallToolRelease function into the proper packagemanager method

* Moved uninstallToolRelease into the proper packagamanger method

* Moved uninstallPlatformRelease into the proper packagamanger method

* Moved downloadToolRelease into the proper packagamanger method

* Merged downloadTool with the proper packagamanger method

* Merged downloadPlatform with the proper packagamanger method

* Moved installPlatform into a packagamanger method

* Moved upgradePlatform into a packagamanger method

* Made PackageManager.Log field private

* Removed the massive code duplication in the 'upgrade' command

* Removed the massive code duplication in the 'outdated' command

* Updated docs

* Update arduino/cores/packagemanager/install_uninstall.go
Co-authored-by: default avatarper1234 <accounts@perglass.com>

* Update arduino/cores/packagemanager/install_uninstall.go
Co-authored-by: default avatarper1234 <accounts@perglass.com>
Co-authored-by: default avatarper1234 <accounts@perglass.com>
parent d0b25569
......@@ -21,6 +21,7 @@ import (
"github.com/arduino/arduino-cli/arduino"
"github.com/arduino/arduino-cli/arduino/cores"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
"github.com/pkg/errors"
"go.bug.st/downloader/v2"
semver "go.bug.st/relaxed-semver"
)
......@@ -118,13 +119,20 @@ func (pm *PackageManager) FindPlatformReleaseDependencies(item *PlatformReferenc
}
// DownloadToolRelease downloads a ToolRelease. If the tool is already downloaded a nil Downloader
// is returned.
func (pm *PackageManager) DownloadToolRelease(tool *cores.ToolRelease, config *downloader.Config, label string, progressCB rpc.DownloadProgressCB) error {
// is returned. Uses the given downloader configuration for download, or the default config if nil.
func (pm *PackageManager) DownloadToolRelease(tool *cores.ToolRelease, config *downloader.Config, progressCB rpc.DownloadProgressCB) error {
resource := tool.GetCompatibleFlavour()
if resource == nil {
return fmt.Errorf(tr("tool not available for your OS"))
return &arduino.FailedDownloadError{
Message: tr("Error downloading tool %s", tool),
Cause: errors.New(tr("no versions available for the current OS", tool))}
}
return resource.Download(pm.DownloadDir, config, label, progressCB)
if err := resource.Download(pm.DownloadDir, config, tool.String(), progressCB); err != nil {
return &arduino.FailedDownloadError{
Message: tr("Error downloading tool %s", tool),
Cause: err}
}
return nil
}
// DownloadPlatformRelease downloads a PlatformRelease. If the platform is already downloaded a
......
......@@ -20,13 +20,170 @@ import (
"fmt"
"runtime"
"github.com/arduino/arduino-cli/arduino"
"github.com/arduino/arduino-cli/arduino/cores"
"github.com/arduino/arduino-cli/arduino/cores/packageindex"
"github.com/arduino/arduino-cli/executils"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
"github.com/arduino/go-paths-helper"
"github.com/pkg/errors"
)
// 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(
platformRef *PlatformReference,
downloadCB rpc.DownloadProgressCB,
taskCB rpc.TaskProgressCB,
skipPostInstall bool,
) error {
if platformRef.PlatformVersion != nil {
return &arduino.InvalidArgumentError{Message: tr("Upgrade doesn't accept parameters with version")}
}
// Search the latest version for all specified platforms
platform := pm.FindPlatform(platformRef)
if platform == nil {
return &arduino.PlatformNotFoundError{Platform: platformRef.String()}
}
installed := pm.GetInstalledPlatformRelease(platform)
if installed == nil {
return &arduino.PlatformNotFoundError{Platform: platformRef.String()}
}
latest := platform.GetLatestRelease()
if !latest.Version.GreaterThan(installed.Version) {
return &arduino.PlatformAlreadyAtTheLatestVersionError{}
}
platformRef.PlatformVersion = latest.Version
platformRelease, tools, err := pm.FindPlatformReleaseDependencies(platformRef)
if err != nil {
return &arduino.PlatformNotFoundError{Platform: platformRef.String()}
}
if err := pm.DownloadAndInstallPlatformAndTools(platformRelease, tools, downloadCB, taskCB, skipPostInstall); err != nil {
return err
}
return nil
}
// 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(
platformRelease *cores.PlatformRelease, requiredTools []*cores.ToolRelease,
downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB,
skipPostInstall bool) error {
log := pm.log.WithField("platform", platformRelease)
// Prerequisite checks before install
toolsToInstall := []*cores.ToolRelease{}
for _, tool := range requiredTools {
if tool.IsInstalled() {
log.WithField("tool", tool).Warn("Tool already installed")
taskCB(&rpc.TaskProgress{Name: tr("Tool %s already installed", tool), Completed: true})
} else {
toolsToInstall = append(toolsToInstall, tool)
}
}
// Package download
taskCB(&rpc.TaskProgress{Name: tr("Downloading packages")})
for _, tool := range toolsToInstall {
if err := pm.DownloadToolRelease(tool, nil, downloadCB); err != nil {
return err
}
}
if err := pm.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 {
return err
}
}
installed := pm.GetInstalledPlatformRelease(platformRelease.Platform)
installedTools := []*cores.ToolRelease{}
if installed == nil {
// No version of this platform is installed
log.Info("Installing platform")
taskCB(&rpc.TaskProgress{Name: tr("Installing platform %s", platformRelease)})
} else {
// A platform with a different version is already installed
log.Info("Replacing platform " + installed.String())
taskCB(&rpc.TaskProgress{Name: tr("Replacing platform %[1]s with %[2]s", installed, platformRelease)})
platformRef := &PlatformReference{
Package: platformRelease.Platform.Package.Name,
PlatformArchitecture: platformRelease.Platform.Architecture,
PlatformVersion: installed.Version,
}
// Get a list of tools used by the currently installed platform version.
// 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)
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 {
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)
// 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 {
log.WithError(err).Error("Error rolling-back changes.")
taskCB(&rpc.TaskProgress{Message: tr("Error rolling-back changes: %s", err)})
}
return &arduino.FailedInstallError{Message: tr("Cannot upgrade platform"), Cause: uninstallErr}
}
// 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)
}
}
}
// Perform post install
if !skipPostInstall {
log.Info("Running post_install script")
taskCB(&rpc.TaskProgress{Message: tr("Configuring platform.")})
if err := pm.RunPostInstallScript(platformRelease); err != nil {
taskCB(&rpc.TaskProgress{Message: tr("WARNING cannot configure platform: %s", err)})
}
} else {
log.Info("Skipping platform configuration.")
taskCB(&rpc.TaskProgress{Message: tr("Skipping platform configuration.")})
}
log.Info("Platform installed")
taskCB(&rpc.TaskProgress{Message: tr("Platform %s installed", platformRelease), Completed: true})
return nil
}
// InstallPlatform installs a specific release of a platform.
func (pm *PackageManager) InstallPlatform(platformRelease *cores.PlatformRelease) error {
destDir := pm.PackagesDir.Join(
......@@ -39,7 +196,7 @@ func (pm *PackageManager) InstallPlatform(platformRelease *cores.PlatformRelease
// InstallPlatformInDirectory installs a specific release of a platform in a specific directory.
func (pm *PackageManager) InstallPlatformInDirectory(platformRelease *cores.PlatformRelease, destDir *paths.Path) error {
if err := platformRelease.Resource.Install(pm.DownloadDir, pm.TempDir, destDir); err != nil {
if err := platformRelease.Resource.Install(pm.DownloadDir, pm.tempDir, destDir); err != nil {
return errors.Errorf(tr("installing platform %[1]s: %[2]s"), platformRelease, err)
}
if d, err := destDir.Abs(); err == nil {
......@@ -109,25 +266,51 @@ func (pm *PackageManager) IsManagedPlatformRelease(platformRelease *cores.Platfo
}
// UninstallPlatform remove a PlatformRelease.
func (pm *PackageManager) UninstallPlatform(platformRelease *cores.PlatformRelease) error {
func (pm *PackageManager) UninstallPlatform(platformRelease *cores.PlatformRelease, taskCB rpc.TaskProgressCB) error {
log := pm.log.WithField("platform", platformRelease)
log.Info("Uninstalling platform")
taskCB(&rpc.TaskProgress{Name: tr("Uninstalling %s", platformRelease)})
if platformRelease.InstallDir == nil {
return fmt.Errorf(tr("platform not installed"))
err := fmt.Errorf(tr("platform not installed"))
log.WithError(err).Error("Error uninstalling")
return &arduino.FailedUninstallError{Message: err.Error()}
}
// Safety measure
if !pm.IsManagedPlatformRelease(platformRelease) {
return fmt.Errorf(tr("%s is not managed by package manager"), platformRelease)
err := fmt.Errorf(tr("%s is not managed by package manager"), platformRelease)
log.WithError(err).Error("Error uninstalling")
return &arduino.FailedUninstallError{Message: err.Error()}
}
if err := platformRelease.InstallDir.RemoveAll(); err != nil {
return fmt.Errorf(tr("removing platform files: %s"), err)
err = fmt.Errorf(tr("removing platform files: %s"), err)
log.WithError(err).Error("Error uninstalling")
return &arduino.FailedUninstallError{Message: err.Error()}
}
platformRelease.InstallDir = nil
log.Info("Platform uninstalled")
taskCB(&rpc.TaskProgress{Message: tr("Platform %s uninstalled", platformRelease), Completed: true})
return nil
}
// InstallTool installs a specific release of a tool.
func (pm *PackageManager) InstallTool(toolRelease *cores.ToolRelease) error {
func (pm *PackageManager) InstallTool(toolRelease *cores.ToolRelease, taskCB rpc.TaskProgressCB) error {
log := pm.log.WithField("Tool", toolRelease)
if toolRelease.IsInstalled() {
log.Warn("Tool already installed")
taskCB(&rpc.TaskProgress{Name: tr("Tool %s already installed", toolRelease), Completed: true})
return nil
}
log.Info("Installing tool")
taskCB(&rpc.TaskProgress{Name: tr("Installing %s", toolRelease)})
toolResource := toolRelease.GetCompatibleFlavour()
if toolResource == nil {
return fmt.Errorf(tr("no compatible version of %s tools found for the current os"), toolRelease.Tool.Name)
......@@ -137,7 +320,15 @@ func (pm *PackageManager) InstallTool(toolRelease *cores.ToolRelease) error {
"tools",
toolRelease.Tool.Name,
toolRelease.Version.String())
return toolResource.Install(pm.DownloadDir, pm.TempDir, destDir)
err := toolResource.Install(pm.DownloadDir, pm.tempDir, destDir)
if err != nil {
log.WithError(err).Warn("Cannot install tool")
return &arduino.FailedInstallError{Message: tr("Cannot install tool %s", toolRelease), Cause: err}
}
log.Info("Tool installed")
taskCB(&rpc.TaskProgress{Message: tr("%s installed", toolRelease), Completed: true})
return nil
}
// IsManagedToolRelease returns true if the ToolRelease is managed by the PackageManager
......@@ -161,20 +352,31 @@ func (pm *PackageManager) IsManagedToolRelease(toolRelease *cores.ToolRelease) b
}
// UninstallTool remove a ToolRelease.
func (pm *PackageManager) UninstallTool(toolRelease *cores.ToolRelease) error {
func (pm *PackageManager) UninstallTool(toolRelease *cores.ToolRelease, taskCB rpc.TaskProgressCB) error {
log := pm.log.WithField("Tool", toolRelease)
log.Info("Uninstalling tool")
if toolRelease.InstallDir == nil {
return fmt.Errorf(tr("tool not installed"))
}
// Safety measure
if !pm.IsManagedToolRelease(toolRelease) {
return fmt.Errorf(tr("tool %s is not managed by package manager"), toolRelease)
err := &arduino.FailedUninstallError{Message: tr("tool %s is not managed by package manager", toolRelease)}
log.WithError(err).Error("Error uninstalling")
return err
}
if err := toolRelease.InstallDir.RemoveAll(); err != nil {
return fmt.Errorf(tr("removing tool files: %s"), err)
err = &arduino.FailedUninstallError{Message: err.Error()}
log.WithError(err).Error("Error uninstalling")
return err
}
toolRelease.InstallDir = nil
log.Info("Tool uninstalled")
taskCB(&rpc.TaskProgress{Message: tr("Tool %s uninstalled", toolRelease), Completed: true})
return nil
}
......
......@@ -55,7 +55,7 @@ func (pm *PackageManager) LoadHardwareFromDirectories(hardwarePaths paths.PathLi
// LoadHardwareFromDirectory read a plaform from the path passed as parameter
func (pm *PackageManager) LoadHardwareFromDirectory(path *paths.Path) []error {
var merr []error
pm.Log.Infof("Loading hardware from: %s", path)
pm.log.Infof("Loading hardware from: %s", path)
if err := path.ToAbs(); err != nil {
return append(merr, fmt.Errorf("%s: %w", tr("finding absolute path of %s", path), err))
}
......@@ -76,9 +76,9 @@ func (pm *PackageManager) LoadHardwareFromDirectory(path *paths.Path) []error {
// "Global" platform.txt used to overwrite all installed platforms.
// For more info: https://arduino.github.io/arduino-cli/latest/platform-specification/#global-platformtxt
if globalPlatformTxt := path.Join("platform.txt"); globalPlatformTxt.Exist() {
pm.Log.Infof("Loading custom platform properties: %s", globalPlatformTxt)
pm.log.Infof("Loading custom platform properties: %s", globalPlatformTxt)
if p, err := properties.LoadFromPath(globalPlatformTxt); err != nil {
pm.Log.WithError(err).Errorf("Error loading properties.")
pm.log.WithError(err).Errorf("Error loading properties.")
} else {
pm.CustomGlobalProperties.Merge(p)
}
......@@ -89,7 +89,7 @@ func (pm *PackageManager) LoadHardwareFromDirectory(path *paths.Path) []error {
// Skip tools, they're not packages and don't contain Platforms
if packager == "tools" {
pm.Log.Infof("Excluding directory: %s", packagerPath)
pm.log.Infof("Excluding directory: %s", packagerPath)
continue
}
......@@ -127,7 +127,7 @@ func (pm *PackageManager) LoadHardwareFromDirectory(path *paths.Path) []error {
// - PACKAGER/tools/TOOL-NAME/TOOL-VERSION/... (ex: arduino/tools/bossac/1.7.0/...)
toolsSubdirPath := packagerPath.Join("tools")
if toolsSubdirPath.IsDir() {
pm.Log.Infof("Checking existence of 'tools' path: %s", toolsSubdirPath)
pm.log.Infof("Checking existence of 'tools' path: %s", toolsSubdirPath)
merr = append(merr, pm.LoadToolsFromPackageDir(targetPackage, toolsSubdirPath)...)
}
// If the Package does not contain Platforms or Tools we remove it since does not contain anything valuable
......@@ -143,7 +143,7 @@ func (pm *PackageManager) LoadHardwareFromDirectory(path *paths.Path) []error {
// to the targetPackage object passed as parameter.
// A list of gRPC Status error is returned for each Platform failed to load.
func (pm *PackageManager) loadPlatforms(targetPackage *cores.Package, packageDir *paths.Path) []error {
pm.Log.Infof("Loading package %s from: %s", targetPackage.Name, packageDir)
pm.log.Infof("Loading package %s from: %s", targetPackage.Name, packageDir)
var merr []error
......@@ -220,11 +220,11 @@ func (pm *PackageManager) loadPlatform(targetPackage *cores.Package, architectur
tmp := cores.NewPackages()
index.MergeIntoPackages(tmp)
if tmpPackage := tmp.GetOrCreatePackage(targetPackage.Name); tmpPackage == nil {
pm.Log.Warnf("Can't determine bundle platform version for %s", targetPackage.Name)
pm.log.Warnf("Can't determine bundle platform version for %s", targetPackage.Name)
} else if tmpPlatform := tmpPackage.GetOrCreatePlatform(architecture); tmpPlatform == nil {
pm.Log.Warnf("Can't determine bundle platform version for %s:%s", targetPackage.Name, architecture)
pm.log.Warnf("Can't determine bundle platform version for %s:%s", targetPackage.Name, architecture)
} else if tmpPlatformRelease := tmpPlatform.GetLatestRelease(); tmpPlatformRelease == nil {
pm.Log.Warnf("Can't determine bundle platform version for %s:%s, no valid release found", targetPackage.Name, architecture)
pm.log.Warnf("Can't determine bundle platform version for %s:%s, no valid release found", targetPackage.Name, architecture)
} else {
version = tmpPlatformRelease.Version
}
......@@ -239,12 +239,12 @@ func (pm *PackageManager) loadPlatform(targetPackage *cores.Package, architectur
release := platform.GetOrCreateRelease(version)
release.IsIDEBundled = isIDEBundled
if isIDEBundled {
pm.Log.Infof("Package is built-in")
pm.log.Infof("Package is built-in")
}
if err := pm.loadPlatformRelease(release, platformPath); err != nil {
return fmt.Errorf("%s: %w", tr("loading platform release %s", release), err)
}
pm.Log.WithField("platform", release).Infof("Loaded platform")
pm.log.WithField("platform", release).Infof("Loaded platform")
} else {
// case: ARCHITECTURE/VERSION/boards.txt
......@@ -272,7 +272,7 @@ func (pm *PackageManager) loadPlatform(targetPackage *cores.Package, architectur
if err := pm.loadPlatformRelease(release, versionDir); err != nil {
return fmt.Errorf("%s: %w", tr("loading platform release %s", release), err)
}
pm.Log.WithField("platform", release).Infof("Loaded platform")
pm.log.WithField("platform", release).Infof("Loaded platform")
}
}
......@@ -357,7 +357,7 @@ func (pm *PackageManager) loadPlatformRelease(platform *cores.PlatformRelease, p
if len(split) != 2 {
return fmt.Errorf(tr("invalid pluggable monitor reference: %s"), ref)
}
pm.Log.WithField("protocol", protocol).WithField("tool", ref).Info("Adding monitor tool")
pm.log.WithField("protocol", protocol).WithField("tool", ref).Info("Adding monitor tool")
platform.Monitors[protocol] = &cores.MonitorDependency{
Packager: split[0],
Name: split[1],
......@@ -367,7 +367,7 @@ func (pm *PackageManager) loadPlatformRelease(platform *cores.PlatformRelease, p
// Support for pluggable monitors in debugging/development environments
platform.MonitorsDevRecipes = map[string]string{}
for protocol, recipe := range platform.Properties.SubTree("pluggable_monitor.pattern").AsMap() {
pm.Log.WithField("protocol", protocol).WithField("recipe", recipe).Info("Adding monitor recipe")
pm.log.WithField("protocol", protocol).WithField("recipe", recipe).Info("Adding monitor recipe")
platform.MonitorsDevRecipes[protocol] = recipe
}
......@@ -592,7 +592,7 @@ func convertUploadToolsToPluggableDiscovery(props *properties.Map) {
// LoadToolsFromPackageDir loads a set of tools from the given toolsPath. The tools will be loaded
// in the given *Package.
func (pm *PackageManager) LoadToolsFromPackageDir(targetPackage *cores.Package, toolsPath *paths.Path) []error {
pm.Log.Infof("Loading tools from dir: %s", toolsPath)
pm.log.Infof("Loading tools from dir: %s", toolsPath)
var merr []error
......@@ -637,7 +637,7 @@ func (pm *PackageManager) loadToolReleaseFromDirectory(tool *cores.Tool, version
} else {
toolRelease := tool.GetOrCreateRelease(version)
toolRelease.InstallDir = absToolReleasePath
pm.Log.WithField("tool", toolRelease).Infof("Loaded tool")
pm.log.WithField("tool", toolRelease).Infof("Loaded tool")
return nil
}
}
......@@ -655,7 +655,7 @@ func (pm *PackageManager) LoadToolsFromBundleDirectories(dirs paths.PathList) []
// LoadToolsFromBundleDirectory FIXMEDOC
func (pm *PackageManager) LoadToolsFromBundleDirectory(toolsPath *paths.Path) error {
pm.Log.Infof("Loading tools from bundle dir: %s", toolsPath)
pm.log.Infof("Loading tools from bundle dir: %s", toolsPath)
// We scan toolsPath content to find a "builtin_tools_versions.txt", if such file exists
// then the all the tools are available in the same directory, mixed together, and their
......@@ -689,7 +689,7 @@ func (pm *PackageManager) LoadToolsFromBundleDirectory(toolsPath *paths.Path) er
if builtinToolsVersionsTxtPath != "" {
// If builtin_tools_versions.txt is found create tools based on the info
// contained in that file
pm.Log.Infof("Found builtin_tools_versions.txt")
pm.log.Infof("Found builtin_tools_versions.txt")
toolPath, err := paths.New(builtinToolsVersionsTxtPath).Parent().Abs()
if err != nil {
return fmt.Errorf(tr("getting parent dir of %[1]s: %[2]s"), builtinToolsVersionsTxtPath, err)
......@@ -708,7 +708,7 @@ func (pm *PackageManager) LoadToolsFromBundleDirectory(toolsPath *paths.Path) er
version := semver.ParseRelaxed(toolVersion)
release := tool.GetOrCreateRelease(version)
release.InstallDir = toolPath
pm.Log.WithField("tool", release).Infof("Loaded tool")
pm.log.WithField("tool", release).Infof("Loaded tool")
}
}
} else {
......
......@@ -38,12 +38,12 @@ import (
// The manager also keeps track of the status of the Packages (their Platform Releases, actually)
// installed in the system.
type PackageManager struct {
Log logrus.FieldLogger
log logrus.FieldLogger
Packages cores.Packages
IndexDir *paths.Path
PackagesDir *paths.Path
DownloadDir *paths.Path
TempDir *paths.Path
tempDir *paths.Path
CustomGlobalProperties *properties.Map
profile *sketch.Profile
discoveryManager *discoverymanager.DiscoveryManager
......@@ -55,12 +55,12 @@ var tr = i18n.Tr
// NewPackageManager returns a new instance of the PackageManager
func NewPackageManager(indexDir, packagesDir, downloadDir, tempDir *paths.Path, userAgent string) *PackageManager {
return &PackageManager{
Log: logrus.StandardLogger(),
log: logrus.StandardLogger(),
Packages: cores.NewPackages(),
IndexDir: indexDir,
PackagesDir: packagesDir,
DownloadDir: downloadDir,
TempDir: tempDir,
tempDir: tempDir,
CustomGlobalProperties: properties.NewMap(),
discoveryManager: discoverymanager.New(),
userAgent: userAgent,
......@@ -386,7 +386,7 @@ func (pm *PackageManager) GetInstalledPlatformRelease(platform *cores.Platform)
}
debug := func(msg string, pl *cores.PlatformRelease) {
pm.Log.WithField("bundle", pl.IsIDEBundled).
pm.log.WithField("bundle", pl.IsIDEBundled).
WithField("version", pl.Version).
WithField("managed", pm.IsManagedPlatformRelease(pl)).
Debugf("%s: %s", msg, pl)
......@@ -465,7 +465,7 @@ func (pm *PackageManager) InstalledBoards() []*cores.Board {
// FindToolsRequiredFromPlatformRelease returns a list of ToolReleases needed by the specified PlatformRelease.
// If a ToolRelease is not found return an error
func (pm *PackageManager) FindToolsRequiredFromPlatformRelease(platform *cores.PlatformRelease) ([]*cores.ToolRelease, error) {
pm.Log.Infof("Searching tools required for platform %s", platform)
pm.log.Infof("Searching tools required for platform %s", platform)
// maps "PACKAGER:TOOL" => ToolRelease
foundTools := map[string]*cores.ToolRelease{}
......@@ -483,7 +483,7 @@ func (pm *PackageManager) FindToolsRequiredFromPlatformRelease(platform *cores.P
requiredTools := []*cores.ToolRelease{}
platform.ToolDependencies.Sort()
for _, toolDep := range platform.ToolDependencies {
pm.Log.WithField("tool", toolDep).Infof("Required tool")
pm.log.WithField("tool", toolDep).Infof("Required tool")
tool := pm.FindToolDependency(toolDep)
if tool == nil {
return nil, fmt.Errorf(tr("tool release not found: %s"), toolDep)
......@@ -494,7 +494,7 @@ func (pm *PackageManager) FindToolsRequiredFromPlatformRelease(platform *cores.P
platform.DiscoveryDependencies.Sort()
for _, discoveryDep := range platform.DiscoveryDependencies {
pm.Log.WithField("discovery", discoveryDep).Infof("Required discovery")
pm.log.WithField("discovery", discoveryDep).Infof("Required discovery")
tool := pm.FindDiscoveryDependency(discoveryDep)
if tool == nil {
return nil, fmt.Errorf(tr("discovery release not found: %s"), discoveryDep)
......@@ -505,7 +505,7 @@ func (pm *PackageManager) FindToolsRequiredFromPlatformRelease(platform *cores.P
platform.MonitorDependencies.Sort()
for _, monitorDep := range platform.MonitorDependencies {
pm.Log.WithField("monitor", monitorDep).Infof("Required monitor")
pm.log.WithField("monitor", monitorDep).Infof("Required monitor")
tool := pm.FindMonitorDependency(monitorDep)
if tool == nil {
return nil, fmt.Errorf(tr("monitor release not found: %s"), monitorDep)
......@@ -537,7 +537,7 @@ func (pm *PackageManager) GetTool(toolID string) *cores.Tool {
// FindToolsRequiredForBoard FIXMEDOC
func (pm *PackageManager) FindToolsRequiredForBoard(board *cores.Board) ([]*cores.ToolRelease, error) {
pm.Log.Infof("Searching tools required for board %s", board)
pm.log.Infof("Searching tools required for board %s", board)
// core := board.Properties["build.core"]
platform := board.PlatformRelease
......@@ -560,7 +560,7 @@ func (pm *PackageManager) FindToolsRequiredForBoard(board *cores.Board) ([]*core
requiredTools := []*cores.ToolRelease{}
platform.ToolDependencies.Sort()
for _, toolDep := range platform.ToolDependencies {
pm.Log.WithField("tool", toolDep).Infof("Required tool")
pm.log.WithField("tool", toolDep).Infof("Required tool")
tool := pm.FindToolDependency(toolDep)
if tool == nil {
return nil, fmt.Errorf(tr("tool release not found: %s"), toolDep)
......
......@@ -86,8 +86,8 @@ func (pm *PackageManager) loadProfilePlatform(platformRef *sketch.ProfilePlatfor
func (pm *PackageManager) installMissingProfilePlatform(platformRef *sketch.ProfilePlatformReference, destDir *paths.Path, downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB) error {
// Instantiate a temporary package manager only for platform installation
_ = pm.TempDir.MkdirAll()
tmp, err := paths.MkTempDir(pm.TempDir.String(), "")
_ = pm.tempDir.MkdirAll()
tmp, err := paths.MkTempDir(pm.tempDir.String(), "")
if err != nil {
return fmt.Errorf("installing missing platform: could not create temp dir %s", err)
}
......
......@@ -21,7 +21,7 @@ import (
"github.com/arduino/arduino-cli/cli/feedback"
"github.com/arduino/arduino-cli/cli/instance"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/outdated"
"github.com/arduino/arduino-cli/i18n"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
"github.com/arduino/arduino-cli/table"
......@@ -50,7 +50,7 @@ func runOutdatedCommand(cmd *cobra.Command, args []string) {
inst := instance.CreateAndInit()
logrus.Info("Executing `arduino-cli outdated`")
outdatedResp, err := commands.Outdated(context.Background(), &rpc.OutdatedRequest{
outdatedResp, err := outdated.Outdated(context.Background(), &rpc.OutdatedRequest{
Instance: inst,
})
if err != nil {
......
......@@ -24,6 +24,7 @@ import (
"github.com/arduino/arduino-cli/cli/instance"
"github.com/arduino/arduino-cli/cli/output"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/outdated"
"github.com/arduino/arduino-cli/i18n"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
"github.com/arduino/arduino-cli/table"
......@@ -70,7 +71,7 @@ func runUpdateCommand(cmd *cobra.Command, args []string) {
feedback.Errorf(tr("Error initializing instance: %v"), err)
}
outdatedResp, err := commands.Outdated(context.Background(), &rpc.OutdatedRequest{
outdatedResp, err := outdated.Outdated(context.Background(), &rpc.OutdatedRequest{
Instance: inst,
})
if err != nil {
......
......@@ -23,7 +23,7 @@ import (
"github.com/arduino/arduino-cli/cli/feedback"
"github.com/arduino/arduino-cli/cli/instance"
"github.com/arduino/arduino-cli/cli/output"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/upgrade"
"github.com/arduino/arduino-cli/i18n"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
"github.com/sirupsen/logrus"
......@@ -54,7 +54,7 @@ func runUpgradeCommand(cmd *cobra.Command, args []string) {
inst := instance.CreateAndInit()
logrus.Info("Executing `arduino-cli upgrade`")
err := commands.Upgrade(context.Background(), &rpc.UpgradeRequest{
err := upgrade.Upgrade(context.Background(), &rpc.UpgradeRequest{
Instance: inst,
SkipPostInstall: postInstallFlags.DetectSkipPostInstallValue(),
}, output.NewDownloadProgressBarCB(), output.TaskProgress())
......
......@@ -17,12 +17,9 @@ package core
import (
"context"
"errors"
"github.com/arduino/arduino-cli/arduino"
"github.com/arduino/arduino-cli/arduino/cores"
"github.com/arduino/arduino-cli/arduino/cores/packagemanager"
"github.com/arduino/arduino-cli/arduino/httpclient"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/i18n"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
......@@ -52,39 +49,15 @@ func PlatformDownload(ctx context.Context, req *rpc.PlatformDownloadRequest, dow
return nil, &arduino.PlatformNotFoundError{Platform: ref.String(), Cause: err}
}
if err := downloadPlatform(pm, platform, downloadCB); err != nil {
if err := pm.DownloadPlatformRelease(platform, nil, downloadCB); err != nil {
return nil, err
}
for _, tool := range tools {
if err := downloadTool(pm, tool, downloadCB); err != nil {
if err := pm.DownloadToolRelease(tool, nil, downloadCB); err != nil {
return nil, err
}
}
return &rpc.PlatformDownloadResponse{}, nil
}
func downloadPlatform(pm *packagemanager.PackageManager, platformRelease *cores.PlatformRelease, downloadCB rpc.DownloadProgressCB) error {
// Download platform
config, err := httpclient.GetDownloaderConfig()
if err != nil {
return &arduino.FailedDownloadError{Message: tr("Error downloading platform %s", platformRelease), Cause: err}
}
return pm.DownloadPlatformRelease(platformRelease, config, downloadCB)
}
func downloadTool(pm *packagemanager.PackageManager, tool *cores.ToolRelease, downloadCB rpc.DownloadProgressCB) error {
// Check if tool has a flavor available for the current OS
if tool.GetCompatibleFlavour() == nil {
return &arduino.FailedDownloadError{
Message: tr("Error downloading tool %s", tool),
Cause: errors.New(tr("no versions available for the current OS", tool))}
}
if err := commands.DownloadToolRelease(pm, tool, downloadCB); err != nil {
return &arduino.FailedDownloadError{Message: tr("Error downloading tool %s", tool), Cause: err}
}
return nil
}
......@@ -20,7 +20,6 @@ import (
"fmt"
"github.com/arduino/arduino-cli/arduino"
"github.com/arduino/arduino-cli/arduino/cores"
"github.com/arduino/arduino-cli/arduino/cores/packagemanager"
"github.com/arduino/arduino-cli/commands"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
......@@ -64,7 +63,7 @@ func PlatformInstall(ctx context.Context, req *rpc.PlatformInstallRequest,
}
}
if err := installPlatform(pm, platformRelease, tools, downloadCB, taskCB, req.GetSkipPostInstall()); err != nil {
if err := pm.DownloadAndInstallPlatformAndTools(platformRelease, tools, downloadCB, taskCB, req.GetSkipPostInstall()); err != nil {
return nil, err
}
......@@ -74,115 +73,3 @@ func PlatformInstall(ctx context.Context, req *rpc.PlatformInstallRequest,
return &rpc.PlatformInstallResponse{}, nil
}
func installPlatform(pm *packagemanager.PackageManager,
platformRelease *cores.PlatformRelease, requiredTools []*cores.ToolRelease,
downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB,
skipPostInstall bool) error {
log := pm.Log.WithField("platform", platformRelease)
// Prerequisite checks before install
toolsToInstall := []*cores.ToolRelease{}
for _, tool := range requiredTools {
if tool.IsInstalled() {
log.WithField("tool", tool).Warn("Tool already installed")
taskCB(&rpc.TaskProgress{Name: tr("Tool %s already installed", tool), Completed: true})
} else {
toolsToInstall = append(toolsToInstall, tool)
}
}
// Package download
taskCB(&rpc.TaskProgress{Name: tr("Downloading packages")})
for _, tool := range toolsToInstall {
if err := downloadTool(pm, tool, downloadCB); err != nil {
return err
}
}
if err := downloadPlatform(pm, platformRelease, downloadCB); err != nil {
return err
}
taskCB(&rpc.TaskProgress{Completed: true})
// Install tools first
for _, tool := range toolsToInstall {
if err := commands.InstallToolRelease(pm, tool, taskCB); err != nil {
return err
}
}
installed := pm.GetInstalledPlatformRelease(platformRelease.Platform)
installedTools := []*cores.ToolRelease{}
if installed == nil {
// No version of this platform is installed
log.Info("Installing platform")
taskCB(&rpc.TaskProgress{Name: tr("Installing platform %s", platformRelease)})
} else {
// A platform with a different version is already installed
log.Info("Replacing platform " + installed.String())
taskCB(&rpc.TaskProgress{Name: tr("Replacing platform %[1]s with %[2]s", installed, platformRelease)})
platformRef := &packagemanager.PlatformReference{
Package: platformRelease.Platform.Package.Name,
PlatformArchitecture: platformRelease.Platform.Architecture,
PlatformVersion: installed.Version,
}
// Get a list of tools used by the currently installed platform version.
// 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)
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 {
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)
// 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); err != nil {
log.WithError(err).Error("Error rolling-back changes.")
taskCB(&rpc.TaskProgress{Message: tr("Error rolling-back changes: %s", err)})
}
return &arduino.FailedInstallError{Message: tr("Cannot upgrade platform"), Cause: uninstallErr}
}
// Uninstall unused tools
for _, tool := range installedTools {
if !pm.IsToolRequired(tool) {
uninstallToolRelease(pm, tool, taskCB)
}
}
}
// Perform post install
if !skipPostInstall {
log.Info("Running post_install script")
taskCB(&rpc.TaskProgress{Message: tr("Configuring platform.")})
if err := pm.RunPostInstallScript(platformRelease); err != nil {
taskCB(&rpc.TaskProgress{Message: tr("WARNING cannot configure platform: %s", err)})
}
} else {
log.Info("Skipping platform configuration.")
taskCB(&rpc.TaskProgress{Message: tr("Skipping platform configuration.")})
}
log.Info("Platform installed")
taskCB(&rpc.TaskProgress{Message: tr("Platform %s installed", platformRelease), Completed: true})
return nil
}
......@@ -19,7 +19,6 @@ import (
"context"
"github.com/arduino/arduino-cli/arduino"
"github.com/arduino/arduino-cli/arduino/cores"
"github.com/arduino/arduino-cli/arduino/cores/packagemanager"
"github.com/arduino/arduino-cli/commands"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
......@@ -53,13 +52,14 @@ func PlatformUninstall(ctx context.Context, req *rpc.PlatformUninstallRequest, t
return nil, &arduino.NotFoundError{Message: tr("Can't find dependencies for platform %s", ref), Cause: err}
}
if err := uninstallPlatformRelease(pm, platform, taskCB); err != nil {
if err := pm.UninstallPlatform(platform, taskCB); err != nil {
return nil, err
}
for _, tool := range tools {
if !pm.IsToolRequired(tool) {
uninstallToolRelease(pm, tool, taskCB)
taskCB(&rpc.TaskProgress{Name: tr("Uninstalling %s, tool is no more required", tool)})
pm.UninstallTool(tool, taskCB)
}
}
......@@ -69,35 +69,3 @@ func PlatformUninstall(ctx context.Context, req *rpc.PlatformUninstallRequest, t
return &rpc.PlatformUninstallResponse{}, nil
}
func uninstallPlatformRelease(pm *packagemanager.PackageManager, platformRelease *cores.PlatformRelease, taskCB rpc.TaskProgressCB) error {
log := pm.Log.WithField("platform", platformRelease)
log.Info("Uninstalling platform")
taskCB(&rpc.TaskProgress{Name: tr("Uninstalling %s", platformRelease)})
if err := pm.UninstallPlatform(platformRelease); err != nil {
log.WithError(err).Error("Error uninstalling")
return &arduino.FailedUninstallError{Message: tr("Error uninstalling platform %s", platformRelease), Cause: err}
}
log.Info("Platform uninstalled")
taskCB(&rpc.TaskProgress{Message: tr("Platform %s uninstalled", platformRelease), Completed: true})
return nil
}
func uninstallToolRelease(pm *packagemanager.PackageManager, toolRelease *cores.ToolRelease, taskCB rpc.TaskProgressCB) error {
log := pm.Log.WithField("Tool", toolRelease)
log.Info("Uninstalling tool")
taskCB(&rpc.TaskProgress{Name: tr("Uninstalling %s, tool is no more required", toolRelease)})
if err := pm.UninstallTool(toolRelease); err != nil {
log.WithError(err).Error("Error uninstalling")
return &arduino.FailedUninstallError{Message: tr("Error uninstalling tool %s", toolRelease), Cause: err}
}
log.Info("Tool uninstalled")
taskCB(&rpc.TaskProgress{Message: tr("Tool %s uninstalled", toolRelease), Completed: true})
return nil
}
......@@ -38,7 +38,7 @@ func PlatformUpgrade(ctx context.Context, req *rpc.PlatformUpgradeRequest,
Package: req.PlatformPackage,
PlatformArchitecture: req.Architecture,
}
if err := upgradePlatform(pm, ref, downloadCB, taskCB, req.GetSkipPostInstall()); err != nil {
if err := pm.DownloadAndInstallPlatformUpgrades(ref, downloadCB, taskCB, req.GetSkipPostInstall()); err != nil {
return nil, err
}
......@@ -48,35 +48,3 @@ func PlatformUpgrade(ctx context.Context, req *rpc.PlatformUpgradeRequest,
return &rpc.PlatformUpgradeResponse{}, nil
}
func upgradePlatform(pm *packagemanager.PackageManager, platformRef *packagemanager.PlatformReference,
downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB, skipPostInstall bool) error {
if platformRef.PlatformVersion != nil {
return &arduino.InvalidArgumentError{Message: tr("Upgrade doesn't accept parameters with version")}
}
// Search the latest version for all specified platforms
platform := pm.FindPlatform(platformRef)
if platform == nil {
return &arduino.PlatformNotFoundError{Platform: platformRef.String()}
}
installed := pm.GetInstalledPlatformRelease(platform)
if installed == nil {
return &arduino.PlatformNotFoundError{Platform: platformRef.String()}
}
latest := platform.GetLatestRelease()
if !latest.Version.GreaterThan(installed.Version) {
return &arduino.PlatformAlreadyAtTheLatestVersionError{}
}
platformRef.PlatformVersion = latest.Version
platformRelease, tools, err := pm.FindPlatformReleaseDependencies(platformRef)
if err != nil {
return &arduino.PlatformNotFoundError{Platform: platformRef.String()}
}
if err := installPlatform(pm, platformRelease, tools, downloadCB, taskCB, skipPostInstall); err != nil {
return err
}
return nil
}
......@@ -29,7 +29,9 @@ import (
"github.com/arduino/arduino-cli/commands/core"
"github.com/arduino/arduino-cli/commands/lib"
"github.com/arduino/arduino-cli/commands/monitor"
"github.com/arduino/arduino-cli/commands/outdated"
"github.com/arduino/arduino-cli/commands/sketch"
"github.com/arduino/arduino-cli/commands/upgrade"
"github.com/arduino/arduino-cli/commands/upload"
"github.com/arduino/arduino-cli/i18n"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
......@@ -202,13 +204,13 @@ func (s *ArduinoCoreServerImpl) UpdateCoreLibrariesIndex(req *rpc.UpdateCoreLibr
// Outdated FIXMEDOC
func (s *ArduinoCoreServerImpl) Outdated(ctx context.Context, req *rpc.OutdatedRequest) (*rpc.OutdatedResponse, error) {
resp, err := commands.Outdated(ctx, req)
resp, err := outdated.Outdated(ctx, req)
return resp, convertErrorToRPCStatus(err)
}
// Upgrade FIXMEDOC
func (s *ArduinoCoreServerImpl) Upgrade(req *rpc.UpgradeRequest, stream rpc.ArduinoCoreService_UpgradeServer) error {
err := commands.Upgrade(stream.Context(), req,
err := upgrade.Upgrade(stream.Context(), req,
func(p *rpc.DownloadProgress) {
stream.Send(&rpc.UpgradeResponse{
Progress: p,
......
......@@ -17,7 +17,6 @@ package commands
import (
"context"
"errors"
"fmt"
"net/url"
"os"
......@@ -28,7 +27,6 @@ import (
"github.com/arduino/arduino-cli/arduino/cores/packageindex"
"github.com/arduino/arduino-cli/arduino/cores/packagemanager"
"github.com/arduino/arduino-cli/arduino/globals"
"github.com/arduino/arduino-cli/arduino/httpclient"
"github.com/arduino/arduino-cli/arduino/libraries"
"github.com/arduino/arduino-cli/arduino/libraries/librariesindex"
"github.com/arduino/arduino-cli/arduino/libraries/librariesmanager"
......@@ -95,11 +93,11 @@ func (instance *CoreInstance) installToolIfMissing(tool *cores.ToolRelease, down
return false, nil
}
taskCB(&rpc.TaskProgress{Name: tr("Downloading missing tool %s", tool)})
if err := DownloadToolRelease(instance.PackageManager, tool, downloadCB); err != nil {
if err := instance.PackageManager.DownloadToolRelease(tool, nil, downloadCB); err != nil {
return false, fmt.Errorf(tr("downloading %[1]s tool: %[2]s"), tool, err)
}
taskCB(&rpc.TaskProgress{Completed: true})
if err := InstallToolRelease(instance.PackageManager, tool, taskCB); err != nil {
if err := instance.PackageManager.InstallTool(tool, taskCB); err != nil {
return false, fmt.Errorf(tr("installing %[1]s tool: %[2]s"), tool, err)
}
return true, nil
......@@ -524,307 +522,6 @@ func UpdateCoreLibrariesIndex(ctx context.Context, req *rpc.UpdateCoreLibrariesI
return nil
}
// Outdated returns a list struct containing both Core and Libraries that can be updated
func Outdated(ctx context.Context, req *rpc.OutdatedRequest) (*rpc.OutdatedResponse, error) {
id := req.GetInstance().GetId()
lm := GetLibraryManager(id)
if lm == nil {
return nil, &arduino.InvalidInstanceError{}
}
outdatedLibraries := []*rpc.InstalledLibrary{}
for _, libAlternatives := range lm.Libraries {
for _, library := range libAlternatives.Alternatives {
if library.Location != libraries.User {
continue
}
available := lm.Index.FindLibraryUpdate(library)
if available == nil {
continue
}
outdatedLibraries = append(outdatedLibraries, &rpc.InstalledLibrary{
Library: getOutputLibrary(library),
Release: getOutputRelease(available),
})
}
}
pm := GetPackageManager(id)
if pm == nil {
return nil, &arduino.InvalidInstanceError{}
}
outdatedPlatforms := []*rpc.Platform{}
for _, targetPackage := range pm.Packages {
for _, installed := range targetPackage.Platforms {
if installedRelease := pm.GetInstalledPlatformRelease(installed); installedRelease != nil {
latest := installed.GetLatestRelease()
if latest == nil || latest == installedRelease {
continue
}
rpcPlatform := PlatformReleaseToRPC(latest)
rpcPlatform.Installed = installedRelease.Version.String()
outdatedPlatforms = append(
outdatedPlatforms,
rpcPlatform,
)
}
}
}
return &rpc.OutdatedResponse{
OutdatedLibraries: outdatedLibraries,
OutdatedPlatforms: outdatedPlatforms,
}, nil
}
func getOutputLibrary(lib *libraries.Library) *rpc.Library {
insdir := ""
if lib.InstallDir != nil {
insdir = lib.InstallDir.String()
}
srcdir := ""
if lib.SourceDir != nil {
srcdir = lib.SourceDir.String()
}
utldir := ""
if lib.UtilityDir != nil {
utldir = lib.UtilityDir.String()
}
cntplat := ""
if lib.ContainerPlatform != nil {
cntplat = lib.ContainerPlatform.String()
}
return &rpc.Library{
Name: lib.Name,
Author: lib.Author,
Maintainer: lib.Maintainer,
Sentence: lib.Sentence,
Paragraph: lib.Paragraph,
Website: lib.Website,
Category: lib.Category,
Architectures: lib.Architectures,
Types: lib.Types,
InstallDir: insdir,
SourceDir: srcdir,
UtilityDir: utldir,
Location: lib.Location.ToRPCLibraryLocation(),
ContainerPlatform: cntplat,
Layout: lib.Layout.ToRPCLibraryLayout(),
RealName: lib.RealName,
DotALinkage: lib.DotALinkage,
Precompiled: lib.Precompiled,
LdFlags: lib.LDflags,
IsLegacy: lib.IsLegacy,
Version: lib.Version.String(),
License: lib.License,
}
}
func getOutputRelease(lib *librariesindex.Release) *rpc.LibraryRelease {
if lib != nil {
return &rpc.LibraryRelease{
Author: lib.Author,
Version: lib.Version.String(),
Maintainer: lib.Maintainer,
Sentence: lib.Sentence,
Paragraph: lib.Paragraph,
Website: lib.Website,
Category: lib.Category,
Architectures: lib.Architectures,
Types: lib.Types,
}
}
return &rpc.LibraryRelease{}
}
// Upgrade downloads and installs outdated Cores and Libraries
func Upgrade(ctx context.Context, req *rpc.UpgradeRequest, downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB) error {
downloaderConfig, err := httpclient.GetDownloaderConfig()
if err != nil {
return err
}
lm := GetLibraryManager(req.Instance.Id)
if lm == nil {
return &arduino.InvalidInstanceError{}
}
for _, libAlternatives := range lm.Libraries {
for _, library := range libAlternatives.Alternatives {
if library.Location != libraries.User {
continue
}
available := lm.Index.FindLibraryUpdate(library)
if available == nil {
continue
}
// Downloads latest library release
taskCB(&rpc.TaskProgress{Name: tr("Downloading %s", available)})
if err := available.Resource.Download(lm.DownloadsDir, downloaderConfig, available.String(), downloadCB); err != nil {
return &arduino.FailedDownloadError{Message: tr("Error downloading library"), Cause: err}
}
// Installs downloaded library
taskCB(&rpc.TaskProgress{Name: tr("Installing %s", available)})
libPath, libReplaced, err := lm.InstallPrerequisiteCheck(available)
if errors.Is(err, librariesmanager.ErrAlreadyInstalled) {
taskCB(&rpc.TaskProgress{Message: tr("Already installed %s", available), Completed: true})
continue
} else if err != nil {
return &arduino.FailedLibraryInstallError{Cause: err}
}
if libReplaced != nil {
taskCB(&rpc.TaskProgress{Message: tr("Replacing %[1]s with %[2]s", libReplaced, available)})
}
if err := lm.Install(available, libPath); err != nil {
return &arduino.FailedLibraryInstallError{Cause: err}
}
taskCB(&rpc.TaskProgress{Message: tr("Installed %s", available), Completed: true})
}
}
pm := GetPackageManager(req.Instance.Id)
if pm == nil {
return &arduino.InvalidInstanceError{}
}
for _, targetPackage := range pm.Packages {
for _, installed := range targetPackage.Platforms {
if installedRelease := pm.GetInstalledPlatformRelease(installed); installedRelease != nil {
latest := installed.GetLatestRelease()
if latest == nil || latest == installedRelease {
continue
}
ref := &packagemanager.PlatformReference{
Package: installedRelease.Platform.Package.Name,
PlatformArchitecture: installedRelease.Platform.Architecture,
PlatformVersion: installedRelease.Version,
}
// Get list of installed tools needed by the currently installed version
_, installedTools, err := pm.FindPlatformReleaseDependencies(ref)
if err != nil {
return &arduino.NotFoundError{Message: tr("Can't find dependencies for platform %s", ref), Cause: err}
}
ref = &packagemanager.PlatformReference{
Package: latest.Platform.Package.Name,
PlatformArchitecture: latest.Platform.Architecture,
PlatformVersion: latest.Version,
}
taskCB(&rpc.TaskProgress{Name: tr("Downloading %s", latest)})
_, tools, err := pm.FindPlatformReleaseDependencies(ref)
if err != nil {
return &arduino.NotFoundError{Message: tr("Can't find dependencies for platform %s", ref), Cause: err}
}
toolsToInstall := []*cores.ToolRelease{}
for _, tool := range tools {
if tool.IsInstalled() {
logrus.WithField("tool", tool).Warn("Tool already installed")
taskCB(&rpc.TaskProgress{Name: tr("Tool %s already installed", tool), Completed: true})
} else {
toolsToInstall = append(toolsToInstall, tool)
}
}
// Downloads platform tools
for _, tool := range toolsToInstall {
if err := DownloadToolRelease(pm, tool, downloadCB); err != nil {
taskCB(&rpc.TaskProgress{Message: tr("Error downloading tool %s", tool)})
return &arduino.FailedDownloadError{Message: tr("Error downloading tool %s", tool), Cause: err}
}
}
// Downloads platform
if err := pm.DownloadPlatformRelease(latest, downloaderConfig, downloadCB); err != nil {
return &arduino.FailedDownloadError{Message: tr("Error downloading platform %s", latest), Cause: err}
}
logrus.Info("Updating platform " + installed.String())
taskCB(&rpc.TaskProgress{Name: tr("Updating platform %s", latest)})
// Installs tools
for _, tool := range toolsToInstall {
if err := InstallToolRelease(pm, tool, taskCB); err != nil {
msg := tr("Error installing tool %s", tool)
taskCB(&rpc.TaskProgress{Message: msg})
return &arduino.FailedInstallError{Message: msg, Cause: err}
}
}
// Installs platform
err = pm.InstallPlatform(latest)
if err != nil {
logrus.WithError(err).Error("Cannot install platform")
msg := tr("Error installing platform %s", latest)
taskCB(&rpc.TaskProgress{Message: msg})
return &arduino.FailedInstallError{Message: msg, Cause: err}
}
// Uninstall previously installed release
err = pm.UninstallPlatform(installedRelease)
// In case uninstall fails tries to rollback
if err != nil {
logrus.WithError(err).Error("Error updating platform.")
taskCB(&rpc.TaskProgress{Message: tr("Error upgrading platform: %s", err)})
// Rollback
if err := pm.UninstallPlatform(latest); err != nil {
logrus.WithError(err).Error("Error rolling-back changes.")
msg := tr("Error rolling-back changes")
taskCB(&rpc.TaskProgress{Message: fmt.Sprintf("%s: %s", msg, err)})
return &arduino.FailedInstallError{Message: msg, Cause: err}
}
}
// Uninstall unused tools
for _, toolRelease := range installedTools {
if !pm.IsToolRequired(toolRelease) {
log := pm.Log.WithField("Tool", toolRelease)
log.Info("Uninstalling tool")
taskCB(&rpc.TaskProgress{Name: tr("Uninstalling %s: tool is no more required", toolRelease)})
if err := pm.UninstallTool(toolRelease); err != nil {
log.WithError(err).Error("Error uninstalling")
return &arduino.FailedInstallError{Message: tr("Error uninstalling tool %s", toolRelease), Cause: err}
}
log.Info("Tool uninstalled")
taskCB(&rpc.TaskProgress{Message: tr("%s uninstalled", toolRelease), Completed: true})
}
}
// Perform post install
if !req.SkipPostInstall {
logrus.Info("Running post_install script")
taskCB(&rpc.TaskProgress{Message: tr("Configuring platform")})
if err := pm.RunPostInstallScript(latest); err != nil {
taskCB(&rpc.TaskProgress{Message: tr("WARNING: cannot run post install: %s", err)})
}
} else {
logrus.Info("Skipping platform configuration (post_install run).")
taskCB(&rpc.TaskProgress{Message: tr("Skipping platform configuration")})
}
}
}
}
return nil
}
// LoadSketch collects and returns all files composing a sketch
func LoadSketch(ctx context.Context, req *rpc.LoadSketchRequest) (*rpc.LoadSketchResponse, error) {
// TODO: This should be a ToRpc function for the Sketch struct
......
// This file is part of arduino-cli.
//
// Copyright 2022 ARDUINO SA (http://www.arduino.cc/)
//
// This software is released under the GNU General Public License version 3,
// which covers the main part of arduino-cli.
// The terms of this license can be found at:
// https://www.gnu.org/licenses/gpl-3.0.en.html
//
// You can be released from the requirements of the above licenses by purchasing
// a commercial license. Buying such a license is mandatory if you want to
// modify or otherwise use the software for commercial activities involving the
// Arduino software without disclosing the source code of your own applications.
// To purchase a commercial license, send an email to license@arduino.cc.
package outdated
import (
"context"
"github.com/arduino/arduino-cli/commands/core"
"github.com/arduino/arduino-cli/commands/lib"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
)
// Outdated returns a list struct containing both Core and Libraries that can be updated
func Outdated(ctx context.Context, req *rpc.OutdatedRequest) (*rpc.OutdatedResponse, error) {
libraryListResponse, err := lib.LibraryList(ctx, &rpc.LibraryListRequest{
Instance: req.GetInstance(),
Updatable: true,
})
if err != nil {
return nil, err
}
getPlatformsResp, err := core.GetPlatforms(&rpc.PlatformListRequest{
Instance: req.GetInstance(),
UpdatableOnly: true,
})
if err != nil {
return nil, err
}
return &rpc.OutdatedResponse{
OutdatedLibraries: libraryListResponse.GetInstalledLibraries(),
OutdatedPlatforms: getPlatformsResp,
}, nil
}
// This file is part of arduino-cli.
//
// Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
// Copyright 2022 ARDUINO SA (http://www.arduino.cc/)
//
// This software is released under the GNU General Public License version 3,
// which covers the main part of arduino-cli.
......@@ -13,44 +13,47 @@
// Arduino software without disclosing the source code of your own applications.
// To purchase a commercial license, send an email to license@arduino.cc.
package commands
package upgrade
import (
"github.com/arduino/arduino-cli/arduino"
"github.com/arduino/arduino-cli/arduino/cores"
"github.com/arduino/arduino-cli/arduino/cores/packagemanager"
"github.com/arduino/arduino-cli/arduino/httpclient"
"context"
"strings"
"github.com/arduino/arduino-cli/commands/core"
"github.com/arduino/arduino-cli/commands/lib"
"github.com/arduino/arduino-cli/commands/outdated"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
)
// DownloadToolRelease downloads a ToolRelease
func DownloadToolRelease(pm *packagemanager.PackageManager, toolRelease *cores.ToolRelease, downloadCB rpc.DownloadProgressCB) error {
config, err := httpclient.GetDownloaderConfig()
// Upgrade downloads and installs outdated Cores and Libraries
func Upgrade(ctx context.Context, req *rpc.UpgradeRequest, downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB) error {
outdatedResp, err := outdated.Outdated(ctx, &rpc.OutdatedRequest{Instance: req.GetInstance()})
if err != nil {
return err
}
return pm.DownloadToolRelease(toolRelease, config, toolRelease.String(), downloadCB)
}
// InstallToolRelease installs a ToolRelease
func InstallToolRelease(pm *packagemanager.PackageManager, toolRelease *cores.ToolRelease, taskCB rpc.TaskProgressCB) error {
log := pm.Log.WithField("Tool", toolRelease)
if toolRelease.IsInstalled() {
log.Warn("Tool already installed")
taskCB(&rpc.TaskProgress{Name: tr("Tool %s already installed", toolRelease), Completed: true})
return nil
for _, libToUpgrade := range outdatedResp.GetOutdatedLibraries() {
err := lib.LibraryInstall(ctx, &rpc.LibraryInstallRequest{
Instance: req.GetInstance(),
Name: libToUpgrade.GetLibrary().GetName(),
}, downloadCB, taskCB)
if err != nil {
return err
}
}
log.Info("Installing tool")
taskCB(&rpc.TaskProgress{Name: tr("Installing %s", toolRelease)})
err := pm.InstallTool(toolRelease)
for _, platformToUpgrade := range outdatedResp.GetOutdatedPlatforms() {
split := strings.Split(platformToUpgrade.GetId(), ":")
_, err := core.PlatformUpgrade(ctx, &rpc.PlatformUpgradeRequest{
Instance: req.GetInstance(),
PlatformPackage: split[0],
Architecture: split[1],
SkipPostInstall: req.GetSkipPostInstall(),
}, downloadCB, taskCB)
if err != nil {
log.WithError(err).Warn("Cannot install tool")
return &arduino.FailedInstallError{Message: tr("Cannot install tool %s", toolRelease), Cause: err}
return err
}
}
log.Info("Tool installed")
taskCB(&rpc.TaskProgress{Message: tr("%s installed", toolRelease), Completed: true})
return nil
}
......@@ -2,6 +2,56 @@
Here you can find a list of migration guides to handle breaking changes between releases of the CLI.
## 0.26.0
### `github.com/arduino/arduino-cli/commands.DownloadToolRelease`, and `InstallToolRelease` functions have been removed
This functionality was duplicated and already available via `PackageManager` methods.
### `github.com/arduino/arduino-cli/commands.Outdated` and `Upgrade` functions have been moved
- `github.com/arduino/arduino-cli/commands.Outdated` is now `github.com/arduino/arduino-cli/commands/outdated.Outdated`
- `github.com/arduino/arduino-cli/commands.Upgrade` is now `github.com/arduino/arduino-cli/commands/upgrade.Upgrade`
Old code must change the imports accordingly.
### `github.com/arduino-cli/arduino/cores/packagemanager.PackageManager` methods and fields change
- The `PackageManager.Log` and `TempDir` fields are now private.
- The `PackageManager.DownloadToolRelease` method has no more the `label` parameter:
```go
func (pm *PackageManager) DownloadToolRelease(tool *cores.ToolRelease, config *downloader.Config, label string, progressCB rpc.DownloadProgressCB) error {
```
has been changed to:
```go
func (pm *PackageManager) DownloadToolRelease(tool *cores.ToolRelease, config *downloader.Config, progressCB rpc.DownloadProgressCB) error {
```
Old code should remove the `label` parameter.
- The `PackageManager.UninstallPlatform`, `PackageManager.InstallTool`, and `PackageManager.UninstallTool` methods now
requires a `github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1.TaskProgressCB`
```go
func (pm *PackageManager) UninstallPlatform(platformRelease *cores.PlatformRelease) error {
func (pm *PackageManager) InstallTool(toolRelease *cores.ToolRelease) error {
func (pm *PackageManager) UninstallTool(toolRelease *cores.ToolRelease) error {
```
have been changed to:
```go
func (pm *PackageManager) UninstallPlatform(platformRelease *cores.PlatformRelease, taskCB rpc.TaskProgressCB) error {
func (pm *PackageManager) InstallTool(toolRelease *cores.ToolRelease, taskCB rpc.TaskProgressCB) error {
func (pm *PackageManager) UninstallTool(toolRelease *cores.ToolRelease, taskCB rpc.TaskProgressCB) error {
```
If you're not interested in getting the task events you can pass an empty callback function.
## 0.25.0
### go-lang function `github.com/arduino/arduino-cli/arduino/utils.FeedStreamTo` has been changed
......
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