@@ -20,13 +20,170 @@ import (
2020 "fmt"
2121 "runtime"
2222
23+ "github.com/arduino/arduino-cli/arduino"
2324 "github.com/arduino/arduino-cli/arduino/cores"
2425 "github.com/arduino/arduino-cli/arduino/cores/packageindex"
2526 "github.com/arduino/arduino-cli/executils"
27+ rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
2628 "github.com/arduino/go-paths-helper"
2729 "github.com/pkg/errors"
2830)
2931
32+ // DownloadAndInstallPlatformUpgrades runs a full installation process to upgrade the given platform.
33+ // This method takes care of downloading missing archives, upgrading platforms and tools, and
34+ // removing the previously installed platform/tools that are no longer needed after the upgrade.
35+ func (pm * PackageManager ) DownloadAndInstallPlatformUpgrades (
36+ platformRef * PlatformReference ,
37+ downloadCB rpc.DownloadProgressCB ,
38+ taskCB rpc.TaskProgressCB ,
39+ skipPostInstall bool ,
40+ ) error {
41+ if platformRef .PlatformVersion != nil {
42+ return & arduino.InvalidArgumentError {Message : tr ("Upgrade doesn't accept parameters with version" )}
43+ }
44+
45+ // Search the latest version for all specified platforms
46+ platform := pm .FindPlatform (platformRef )
47+ if platform == nil {
48+ return & arduino.PlatformNotFoundError {Platform : platformRef .String ()}
49+ }
50+ installed := pm .GetInstalledPlatformRelease (platform )
51+ if installed == nil {
52+ return & arduino.PlatformNotFoundError {Platform : platformRef .String ()}
53+ }
54+ latest := platform .GetLatestRelease ()
55+ if ! latest .Version .GreaterThan (installed .Version ) {
56+ return & arduino.PlatformAlreadyAtTheLatestVersionError {}
57+ }
58+ platformRef .PlatformVersion = latest .Version
59+
60+ platformRelease , tools , err := pm .FindPlatformReleaseDependencies (platformRef )
61+ if err != nil {
62+ return & arduino.PlatformNotFoundError {Platform : platformRef .String ()}
63+ }
64+ if err := pm .DownloadAndInstallPlatformAndTools (platformRelease , tools , downloadCB , taskCB , skipPostInstall ); err != nil {
65+ return err
66+ }
67+
68+ return nil
69+ }
70+
71+ // DownloadAndInstallPlatformAndTools runs a full installation process for the given platform and tools.
72+ // This method takes care of downloading missing archives, installing/upgrading platforms and tools, and
73+ // removing the previously installed platform/tools that are no longer needed after the upgrade.
74+ func (pm * PackageManager ) DownloadAndInstallPlatformAndTools (
75+ platformRelease * cores.PlatformRelease , requiredTools []* cores.ToolRelease ,
76+ downloadCB rpc.DownloadProgressCB , taskCB rpc.TaskProgressCB ,
77+ skipPostInstall bool ) error {
78+ log := pm .log .WithField ("platform" , platformRelease )
79+
80+ // Prerequisite checks before install
81+ toolsToInstall := []* cores.ToolRelease {}
82+ for _ , tool := range requiredTools {
83+ if tool .IsInstalled () {
84+ log .WithField ("tool" , tool ).Warn ("Tool already installed" )
85+ taskCB (& rpc.TaskProgress {Name : tr ("Tool %s already installed" , tool ), Completed : true })
86+ } else {
87+ toolsToInstall = append (toolsToInstall , tool )
88+ }
89+ }
90+
91+ // Package download
92+ taskCB (& rpc.TaskProgress {Name : tr ("Downloading packages" )})
93+ for _ , tool := range toolsToInstall {
94+ if err := pm .DownloadToolRelease (tool , nil , downloadCB ); err != nil {
95+ return err
96+ }
97+ }
98+ if err := pm .DownloadPlatformRelease (platformRelease , nil , downloadCB ); err != nil {
99+ return err
100+ }
101+ taskCB (& rpc.TaskProgress {Completed : true })
102+
103+ // Install tools first
104+ for _ , tool := range toolsToInstall {
105+ if err := pm .InstallTool (tool , taskCB ); err != nil {
106+ return err
107+ }
108+ }
109+
110+ installed := pm .GetInstalledPlatformRelease (platformRelease .Platform )
111+ installedTools := []* cores.ToolRelease {}
112+ if installed == nil {
113+ // No version of this platform is installed
114+ log .Info ("Installing platform" )
115+ taskCB (& rpc.TaskProgress {Name : tr ("Installing platform %s" , platformRelease )})
116+ } else {
117+ // A platform with a different version is already installed
118+ log .Info ("Replacing platform " + installed .String ())
119+ taskCB (& rpc.TaskProgress {Name : tr ("Replacing platform %[1]s with %[2]s" , installed , platformRelease )})
120+ platformRef := & PlatformReference {
121+ Package : platformRelease .Platform .Package .Name ,
122+ PlatformArchitecture : platformRelease .Platform .Architecture ,
123+ PlatformVersion : installed .Version ,
124+ }
125+
126+ // Get a list of tools used by the currently installed platform version.
127+ // This must be done so tools used by the currently installed version are
128+ // removed if not used also by the newly installed version.
129+ var err error
130+ _ , installedTools , err = pm .FindPlatformReleaseDependencies (platformRef )
131+ if err != nil {
132+ return & arduino.NotFoundError {Message : tr ("Can't find dependencies for platform %s" , platformRef ), Cause : err }
133+ }
134+ }
135+
136+ // Install
137+ if err := pm .InstallPlatform (platformRelease ); err != nil {
138+ log .WithError (err ).Error ("Cannot install platform" )
139+ return & arduino.FailedInstallError {Message : tr ("Cannot install platform" ), Cause : err }
140+ }
141+
142+ // If upgrading remove previous release
143+ if installed != nil {
144+ uninstallErr := pm .UninstallPlatform (installed , taskCB )
145+
146+ // In case of error try to rollback
147+ if uninstallErr != nil {
148+ log .WithError (uninstallErr ).Error ("Error upgrading platform." )
149+ taskCB (& rpc.TaskProgress {Message : tr ("Error upgrading platform: %s" , uninstallErr )})
150+
151+ // Rollback
152+ if err := pm .UninstallPlatform (platformRelease , taskCB ); err != nil {
153+ log .WithError (err ).Error ("Error rolling-back changes." )
154+ taskCB (& rpc.TaskProgress {Message : tr ("Error rolling-back changes: %s" , err )})
155+ }
156+
157+ return & arduino.FailedInstallError {Message : tr ("Cannot upgrade platform" ), Cause : uninstallErr }
158+ }
159+
160+ // Uninstall unused tools
161+ for _ , tool := range installedTools {
162+ taskCB (& rpc.TaskProgress {Name : tr ("Uninstalling %s, tool is no more required" , tool )})
163+ if ! pm .IsToolRequired (tool ) {
164+ pm .UninstallTool (tool , taskCB )
165+ }
166+ }
167+
168+ }
169+
170+ // Perform post install
171+ if ! skipPostInstall {
172+ log .Info ("Running post_install script" )
173+ taskCB (& rpc.TaskProgress {Message : tr ("Configuring platform." )})
174+ if err := pm .RunPostInstallScript (platformRelease ); err != nil {
175+ taskCB (& rpc.TaskProgress {Message : tr ("WARNING cannot configure platform: %s" , err )})
176+ }
177+ } else {
178+ log .Info ("Skipping platform configuration." )
179+ taskCB (& rpc.TaskProgress {Message : tr ("Skipping platform configuration." )})
180+ }
181+
182+ log .Info ("Platform installed" )
183+ taskCB (& rpc.TaskProgress {Message : tr ("Platform %s installed" , platformRelease ), Completed : true })
184+ return nil
185+ }
186+
30187// InstallPlatform installs a specific release of a platform.
31188func (pm * PackageManager ) InstallPlatform (platformRelease * cores.PlatformRelease ) error {
32189 destDir := pm .PackagesDir .Join (
@@ -39,7 +196,7 @@ func (pm *PackageManager) InstallPlatform(platformRelease *cores.PlatformRelease
39196
40197// InstallPlatformInDirectory installs a specific release of a platform in a specific directory.
41198func (pm * PackageManager ) InstallPlatformInDirectory (platformRelease * cores.PlatformRelease , destDir * paths.Path ) error {
42- if err := platformRelease .Resource .Install (pm .DownloadDir , pm .TempDir , destDir ); err != nil {
199+ if err := platformRelease .Resource .Install (pm .DownloadDir , pm .tempDir , destDir ); err != nil {
43200 return errors .Errorf (tr ("installing platform %[1]s: %[2]s" ), platformRelease , err )
44201 }
45202 if d , err := destDir .Abs (); err == nil {
@@ -109,25 +266,51 @@ func (pm *PackageManager) IsManagedPlatformRelease(platformRelease *cores.Platfo
109266}
110267
111268// UninstallPlatform remove a PlatformRelease.
112- func (pm * PackageManager ) UninstallPlatform (platformRelease * cores.PlatformRelease ) error {
269+ func (pm * PackageManager ) UninstallPlatform (platformRelease * cores.PlatformRelease , taskCB rpc.TaskProgressCB ) error {
270+ log := pm .log .WithField ("platform" , platformRelease )
271+
272+ log .Info ("Uninstalling platform" )
273+ taskCB (& rpc.TaskProgress {Name : tr ("Uninstalling %s" , platformRelease )})
274+
113275 if platformRelease .InstallDir == nil {
114- return fmt .Errorf (tr ("platform not installed" ))
276+ err := fmt .Errorf (tr ("platform not installed" ))
277+ log .WithError (err ).Error ("Error uninstalling" )
278+ return & arduino.FailedUninstallError {Message : err .Error ()}
115279 }
116280
117281 // Safety measure
118282 if ! pm .IsManagedPlatformRelease (platformRelease ) {
119- return fmt .Errorf (tr ("%s is not managed by package manager" ), platformRelease )
283+ err := fmt .Errorf (tr ("%s is not managed by package manager" ), platformRelease )
284+ log .WithError (err ).Error ("Error uninstalling" )
285+ return & arduino.FailedUninstallError {Message : err .Error ()}
120286 }
121287
122288 if err := platformRelease .InstallDir .RemoveAll (); err != nil {
123- return fmt .Errorf (tr ("removing platform files: %s" ), err )
289+ err = fmt .Errorf (tr ("removing platform files: %s" ), err )
290+ log .WithError (err ).Error ("Error uninstalling" )
291+ return & arduino.FailedUninstallError {Message : err .Error ()}
124292 }
293+
125294 platformRelease .InstallDir = nil
295+
296+ log .Info ("Platform uninstalled" )
297+ taskCB (& rpc.TaskProgress {Message : tr ("Platform %s uninstalled" , platformRelease ), Completed : true })
126298 return nil
127299}
128300
129301// InstallTool installs a specific release of a tool.
130- func (pm * PackageManager ) InstallTool (toolRelease * cores.ToolRelease ) error {
302+ func (pm * PackageManager ) InstallTool (toolRelease * cores.ToolRelease , taskCB rpc.TaskProgressCB ) error {
303+ log := pm .log .WithField ("Tool" , toolRelease )
304+
305+ if toolRelease .IsInstalled () {
306+ log .Warn ("Tool already installed" )
307+ taskCB (& rpc.TaskProgress {Name : tr ("Tool %s already installed" , toolRelease ), Completed : true })
308+ return nil
309+ }
310+
311+ log .Info ("Installing tool" )
312+ taskCB (& rpc.TaskProgress {Name : tr ("Installing %s" , toolRelease )})
313+
131314 toolResource := toolRelease .GetCompatibleFlavour ()
132315 if toolResource == nil {
133316 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 {
137320 "tools" ,
138321 toolRelease .Tool .Name ,
139322 toolRelease .Version .String ())
140- return toolResource .Install (pm .DownloadDir , pm .TempDir , destDir )
323+ err := toolResource .Install (pm .DownloadDir , pm .tempDir , destDir )
324+ if err != nil {
325+ log .WithError (err ).Warn ("Cannot install tool" )
326+ return & arduino.FailedInstallError {Message : tr ("Cannot install tool %s" , toolRelease ), Cause : err }
327+ }
328+ log .Info ("Tool installed" )
329+ taskCB (& rpc.TaskProgress {Message : tr ("%s installed" , toolRelease ), Completed : true })
330+
331+ return nil
141332}
142333
143334// IsManagedToolRelease returns true if the ToolRelease is managed by the PackageManager
@@ -161,20 +352,31 @@ func (pm *PackageManager) IsManagedToolRelease(toolRelease *cores.ToolRelease) b
161352}
162353
163354// UninstallTool remove a ToolRelease.
164- func (pm * PackageManager ) UninstallTool (toolRelease * cores.ToolRelease ) error {
355+ func (pm * PackageManager ) UninstallTool (toolRelease * cores.ToolRelease , taskCB rpc.TaskProgressCB ) error {
356+ log := pm .log .WithField ("Tool" , toolRelease )
357+ log .Info ("Uninstalling tool" )
358+
165359 if toolRelease .InstallDir == nil {
166360 return fmt .Errorf (tr ("tool not installed" ))
167361 }
168362
169363 // Safety measure
170364 if ! pm .IsManagedToolRelease (toolRelease ) {
171- return fmt .Errorf (tr ("tool %s is not managed by package manager" ), toolRelease )
365+ err := & arduino.FailedUninstallError {Message : tr ("tool %s is not managed by package manager" , toolRelease )}
366+ log .WithError (err ).Error ("Error uninstalling" )
367+ return err
172368 }
173369
174370 if err := toolRelease .InstallDir .RemoveAll (); err != nil {
175- return fmt .Errorf (tr ("removing tool files: %s" ), err )
371+ err = & arduino.FailedUninstallError {Message : err .Error ()}
372+ log .WithError (err ).Error ("Error uninstalling" )
373+ return err
176374 }
375+
177376 toolRelease .InstallDir = nil
377+
378+ log .Info ("Tool uninstalled" )
379+ taskCB (& rpc.TaskProgress {Message : tr ("Tool %s uninstalled" , toolRelease ), Completed : true })
178380 return nil
179381}
180382
0 commit comments