Skip to content

Commit 4b1eac3

Browse files
Run pre-uninstall script when a platform or tool is uninstalled
1 parent e0f0051 commit 4b1eac3

File tree

9 files changed

+85
-48
lines changed

9 files changed

+85
-48
lines changed

arduino/cores/packagemanager/install_uninstall.go

+46-17
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ func (pme *Explorer) DownloadAndInstallPlatformUpgrades(
3838
downloadCB rpc.DownloadProgressCB,
3939
taskCB rpc.TaskProgressCB,
4040
skipPostInstall bool,
41+
skipPreUninstall bool,
4142
) (*cores.PlatformRelease, error) {
4243
if platformRef.PlatformVersion != nil {
4344
return nil, &arduino.InvalidArgumentError{Message: tr("Upgrade doesn't accept parameters with version")}
@@ -62,7 +63,7 @@ func (pme *Explorer) DownloadAndInstallPlatformUpgrades(
6263
if err != nil {
6364
return nil, &arduino.PlatformNotFoundError{Platform: platformRef.String()}
6465
}
65-
if err := pme.DownloadAndInstallPlatformAndTools(platformRelease, tools, downloadCB, taskCB, skipPostInstall); err != nil {
66+
if err := pme.DownloadAndInstallPlatformAndTools(platformRelease, tools, downloadCB, taskCB, skipPostInstall, skipPreUninstall); err != nil {
6667
return nil, err
6768
}
6869

@@ -75,7 +76,7 @@ func (pme *Explorer) DownloadAndInstallPlatformUpgrades(
7576
func (pme *Explorer) DownloadAndInstallPlatformAndTools(
7677
platformRelease *cores.PlatformRelease, requiredTools []*cores.ToolRelease,
7778
downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB,
78-
skipPostInstall bool) error {
79+
skipPostInstall bool, skipPreUninstall bool) error {
7980
log := pme.log.WithField("platform", platformRelease)
8081

8182
// Prerequisite checks before install
@@ -142,15 +143,15 @@ func (pme *Explorer) DownloadAndInstallPlatformAndTools(
142143

143144
// If upgrading remove previous release
144145
if installed != nil {
145-
uninstallErr := pme.UninstallPlatform(installed, taskCB)
146+
uninstallErr := pme.UninstallPlatform(installed, taskCB, skipPreUninstall)
146147

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

152153
// Rollback
153-
if err := pme.UninstallPlatform(platformRelease, taskCB); err != nil {
154+
if err := pme.UninstallPlatform(platformRelease, taskCB, skipPreUninstall); err != nil {
154155
log.WithError(err).Error("Error rolling-back changes.")
155156
taskCB(&rpc.TaskProgress{Message: tr("Error rolling-back changes: %s", err)})
156157
}
@@ -162,7 +163,7 @@ func (pme *Explorer) DownloadAndInstallPlatformAndTools(
162163
for _, tool := range installedTools {
163164
taskCB(&rpc.TaskProgress{Name: tr("Uninstalling %s, tool is no more required", tool)})
164165
if !pme.IsToolRequired(tool) {
165-
pme.UninstallTool(tool, taskCB)
166+
pme.UninstallTool(tool, taskCB, skipPreUninstall)
166167
}
167168
}
168169

@@ -175,7 +176,7 @@ func (pme *Explorer) DownloadAndInstallPlatformAndTools(
175176
if !platformRelease.IsInstalled() {
176177
return errors.New(tr("platform not installed"))
177178
}
178-
stdout, stderr, err := pme.RunPostInstallScript(platformRelease.InstallDir)
179+
stdout, stderr, err := pme.RunPreOrPostScript(platformRelease.InstallDir, "post_install")
179180
skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stdout), Completed: true})
180181
skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stderr), Completed: true})
181182
if err != nil {
@@ -229,16 +230,16 @@ func (pme *Explorer) cacheInstalledJSON(platformRelease *cores.PlatformRelease)
229230
return nil
230231
}
231232

232-
// RunPostInstallScript runs the post_install.sh (or post_install.bat) script for the
233-
// specified platformRelease or toolRelease.
234-
func (pme *Explorer) RunPostInstallScript(installDir *paths.Path) ([]byte, []byte, error) {
235-
postInstallFilename := "post_install.sh"
233+
// RunPreOrPostScript runs either the post_install.sh (or post_install.bat) or the pre_uninstall.sh (or pre_uninstall.bat)
234+
// script for the specified platformRelease or toolRelease.
235+
func (pme *Explorer) RunPreOrPostScript(installDir *paths.Path, prefix string) ([]byte, []byte, error) {
236+
scriptFilename := prefix + ".sh"
236237
if runtime.GOOS == "windows" {
237-
postInstallFilename = "post_install.bat"
238+
scriptFilename = prefix + ".bat"
238239
}
239-
postInstall := installDir.Join(postInstallFilename)
240-
if postInstall.Exist() && postInstall.IsNotDir() {
241-
cmd, err := executils.NewProcessFromPath(pme.GetEnvVarsForSpawnedProcess(), postInstall)
240+
script := installDir.Join(scriptFilename)
241+
if script.Exist() && script.IsNotDir() {
242+
cmd, err := executils.NewProcessFromPath(pme.GetEnvVarsForSpawnedProcess(), script)
242243
if err != nil {
243244
return []byte{}, []byte{}, err
244245
}
@@ -270,7 +271,7 @@ func (pme *Explorer) IsManagedPlatformRelease(platformRelease *cores.PlatformRel
270271
}
271272

272273
// UninstallPlatform remove a PlatformRelease.
273-
func (pme *Explorer) UninstallPlatform(platformRelease *cores.PlatformRelease, taskCB rpc.TaskProgressCB) error {
274+
func (pme *Explorer) UninstallPlatform(platformRelease *cores.PlatformRelease, taskCB rpc.TaskProgressCB, skipPreUninstall bool) error {
274275
log := pme.log.WithField("platform", platformRelease)
275276

276277
log.Info("Uninstalling platform")
@@ -289,6 +290,20 @@ func (pme *Explorer) UninstallPlatform(platformRelease *cores.PlatformRelease, t
289290
return &arduino.FailedUninstallError{Message: err.Error()}
290291
}
291292

293+
if !skipPreUninstall {
294+
log.Info("Running pre_uninstall script")
295+
taskCB(&rpc.TaskProgress{Message: tr("Running pre_uninstall script.")})
296+
stdout, stderr, err := pme.RunPreOrPostScript(platformRelease.InstallDir, "pre_uninstall")
297+
skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stdout), Completed: true})
298+
skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stderr), Completed: true})
299+
if err != nil {
300+
taskCB(&rpc.TaskProgress{Message: tr("WARNING cannot run pre_uninstall script: %s", err), Completed: true})
301+
}
302+
} else {
303+
log.Info("Skipping pre_uninstall script.")
304+
taskCB(&rpc.TaskProgress{Message: tr("Skipping pre_uninstall script.")})
305+
}
306+
292307
if err := platformRelease.InstallDir.RemoveAll(); err != nil {
293308
err = fmt.Errorf(tr("removing platform files: %s"), err)
294309
log.WithError(err).Error("Error uninstalling")
@@ -339,7 +354,7 @@ func (pme *Explorer) InstallTool(toolRelease *cores.ToolRelease, taskCB rpc.Task
339354
if !skipPostInstall {
340355
log.Info("Running tool post_install script")
341356
taskCB(&rpc.TaskProgress{Message: tr("Configuring tool.")})
342-
stdout, stderr, err := pme.RunPostInstallScript(toolRelease.InstallDir)
357+
stdout, stderr, err := pme.RunPreOrPostScript(toolRelease.InstallDir, "post_install")
343358
skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stdout)})
344359
skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stderr)})
345360
if err != nil {
@@ -373,7 +388,7 @@ func (pme *Explorer) IsManagedToolRelease(toolRelease *cores.ToolRelease) bool {
373388
}
374389

375390
// UninstallTool remove a ToolRelease.
376-
func (pme *Explorer) UninstallTool(toolRelease *cores.ToolRelease, taskCB rpc.TaskProgressCB) error {
391+
func (pme *Explorer) UninstallTool(toolRelease *cores.ToolRelease, taskCB rpc.TaskProgressCB, skipPreUninstall bool) error {
377392
log := pme.log.WithField("Tool", toolRelease)
378393
log.Info("Uninstalling tool")
379394

@@ -388,6 +403,20 @@ func (pme *Explorer) UninstallTool(toolRelease *cores.ToolRelease, taskCB rpc.Ta
388403
return err
389404
}
390405

406+
if !skipPreUninstall {
407+
log.Info("Running pre_uninstall script")
408+
taskCB(&rpc.TaskProgress{Message: tr("Running pre_uninstall script.")})
409+
stdout, stderr, err := pme.RunPreOrPostScript(toolRelease.InstallDir, "pre_uninstall")
410+
skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stdout), Completed: true})
411+
skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stderr), Completed: true})
412+
if err != nil {
413+
taskCB(&rpc.TaskProgress{Message: tr("WARNING cannot run pre_uninstall script: %s", err), Completed: true})
414+
}
415+
} else {
416+
log.Info("Skipping pre_uninstall script.")
417+
taskCB(&rpc.TaskProgress{Message: tr("Skipping pre_uninstall script.")})
418+
}
419+
391420
if err := toolRelease.InstallDir.RemoveAll(); err != nil {
392421
err = &arduino.FailedUninstallError{Message: err.Error()}
393422
log.WithError(err).Error("Error uninstalling")

arduino/cores/packagemanager/package_manager_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -949,7 +949,7 @@ func TestRunPostInstall(t *testing.T) {
949949
require.NoError(t, err)
950950
err = os.Chmod(scriptPath.String(), 0777)
951951
require.NoError(t, err)
952-
stdout, stderr, err := pme.RunPostInstallScript(dir)
952+
stdout, stderr, err := pme.RunPreOrPostScript(dir, "post_install")
953953
require.NoError(t, err)
954954

955955
// `HasPrefix` because windows seem to add a trailing space at the end

commands/core/install.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func PlatformInstall(ctx context.Context, req *rpc.PlatformInstallRequest, downl
6363
}
6464
}
6565

66-
if err := pme.DownloadAndInstallPlatformAndTools(platformRelease, tools, downloadCB, taskCB, req.GetSkipPostInstall()); err != nil {
66+
if err := pme.DownloadAndInstallPlatformAndTools(platformRelease, tools, downloadCB, taskCB, req.GetSkipPostInstall(), req.GetSkipPreUninstall()); err != nil {
6767
return err
6868
}
6969

commands/core/uninstall.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,14 @@ func platformUninstall(ctx context.Context, req *rpc.PlatformUninstallRequest, t
6464
return &arduino.NotFoundError{Message: tr("Can't find dependencies for platform %s", ref), Cause: err}
6565
}
6666

67-
if err := pme.UninstallPlatform(platform, taskCB); err != nil {
67+
if err := pme.UninstallPlatform(platform, taskCB, req.GetSkipPreUninstall()); err != nil {
6868
return err
6969
}
7070

7171
for _, tool := range tools {
7272
if !pme.IsToolRequired(tool) {
7373
taskCB(&rpc.TaskProgress{Name: tr("Uninstalling %s, tool is no more required", tool)})
74-
pme.UninstallTool(tool, taskCB)
74+
pme.UninstallTool(tool, taskCB, req.GetSkipPreUninstall())
7575
}
7676
}
7777

commands/core/upgrade.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package core
1717

1818
import (
1919
"context"
20+
2021
"github.com/arduino/arduino-cli/arduino/cores"
2122

2223
"github.com/arduino/arduino-cli/arduino"
@@ -39,7 +40,7 @@ func PlatformUpgrade(ctx context.Context, req *rpc.PlatformUpgradeRequest, downl
3940
Package: req.PlatformPackage,
4041
PlatformArchitecture: req.Architecture,
4142
}
42-
platform, err := pme.DownloadAndInstallPlatformUpgrades(ref, downloadCB, taskCB, req.GetSkipPostInstall())
43+
platform, err := pme.DownloadAndInstallPlatformUpgrades(ref, downloadCB, taskCB, req.GetSkipPostInstall(), req.GetSkipPreUninstall())
4344
if err != nil {
4445
return platform, err
4546
}

internal/cli/core/install.go

+11-10
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import (
3131

3232
func initInstallCommand() *cobra.Command {
3333
var noOverwrite bool
34-
var postInstallFlags arguments.PrePostScriptsFlags
34+
var scriptFlags arguments.PrePostScriptsFlags
3535
installCommand := &cobra.Command{
3636
Use: fmt.Sprintf("install %s:%s[@%s]...", tr("PACKAGER"), tr("ARCH"), tr("VERSION")),
3737
Short: tr("Installs one or more cores and corresponding tool dependencies."),
@@ -45,18 +45,18 @@ func initInstallCommand() *cobra.Command {
4545
arguments.CheckFlagsConflicts(cmd, "run-post-install", "skip-post-install")
4646
},
4747
Run: func(cmd *cobra.Command, args []string) {
48-
runInstallCommand(args, postInstallFlags, noOverwrite)
48+
runInstallCommand(args, scriptFlags, noOverwrite)
4949
},
5050
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
5151
return arguments.GetInstallableCores(), cobra.ShellCompDirectiveDefault
5252
},
5353
}
54-
postInstallFlags.AddToCommand(installCommand)
54+
scriptFlags.AddToCommand(installCommand)
5555
installCommand.Flags().BoolVar(&noOverwrite, "no-overwrite", false, tr("Do not overwrite already installed platforms."))
5656
return installCommand
5757
}
5858

59-
func runInstallCommand(args []string, postInstallFlags arguments.PrePostScriptsFlags, noOverwrite bool) {
59+
func runInstallCommand(args []string, scriptFlags arguments.PrePostScriptsFlags, noOverwrite bool) {
6060
inst := instance.CreateAndInit()
6161
logrus.Info("Executing `arduino-cli core install`")
6262

@@ -67,12 +67,13 @@ func runInstallCommand(args []string, postInstallFlags arguments.PrePostScriptsF
6767

6868
for _, platformRef := range platformsRefs {
6969
platformInstallRequest := &rpc.PlatformInstallRequest{
70-
Instance: inst,
71-
PlatformPackage: platformRef.PackageName,
72-
Architecture: platformRef.Architecture,
73-
Version: platformRef.Version,
74-
SkipPostInstall: postInstallFlags.DetectSkipPostInstallValue(),
75-
NoOverwrite: noOverwrite,
70+
Instance: inst,
71+
PlatformPackage: platformRef.PackageName,
72+
Architecture: platformRef.Architecture,
73+
Version: platformRef.Version,
74+
SkipPostInstall: scriptFlags.DetectSkipPostInstallValue(),
75+
NoOverwrite: noOverwrite,
76+
SkipPreUninstall: scriptFlags.DetectSkipPreUninstallValue(),
7677
}
7778
_, err := core.PlatformInstall(context.Background(), platformInstallRequest, feedback.ProgressBar(), feedback.TaskProgress())
7879
if err != nil {

internal/cli/core/uninstall.go

+10-5
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,25 @@ import (
3030
)
3131

3232
func initUninstallCommand() *cobra.Command {
33+
var preUninstallFlags arguments.PrePostScriptsFlags
3334
uninstallCommand := &cobra.Command{
3435
Use: fmt.Sprintf("uninstall %s:%s ...", tr("PACKAGER"), tr("ARCH")),
3536
Short: tr("Uninstalls one or more cores and corresponding tool dependencies if no longer used."),
3637
Long: tr("Uninstalls one or more cores and corresponding tool dependencies if no longer used."),
3738
Example: " " + os.Args[0] + " core uninstall arduino:samd\n",
3839
Args: cobra.MinimumNArgs(1),
39-
Run: runUninstallCommand,
40+
Run: func(cmd *cobra.Command, args []string) {
41+
runUninstallCommand(args, preUninstallFlags)
42+
},
4043
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
4144
return arguments.GetUninstallableCores(), cobra.ShellCompDirectiveDefault
4245
},
4346
}
47+
preUninstallFlags.AddToCommand(uninstallCommand)
4448
return uninstallCommand
4549
}
4650

47-
func runUninstallCommand(cmd *cobra.Command, args []string) {
51+
func runUninstallCommand(args []string, preUninstallFlags arguments.PrePostScriptsFlags) {
4852
inst := instance.CreateAndInit()
4953
logrus.Info("Executing `arduino-cli core uninstall`")
5054

@@ -60,9 +64,10 @@ func runUninstallCommand(cmd *cobra.Command, args []string) {
6064
}
6165
for _, platformRef := range platformsRefs {
6266
_, err := core.PlatformUninstall(context.Background(), &rpc.PlatformUninstallRequest{
63-
Instance: inst,
64-
PlatformPackage: platformRef.PackageName,
65-
Architecture: platformRef.Architecture,
67+
Instance: inst,
68+
PlatformPackage: platformRef.PackageName,
69+
Architecture: platformRef.Architecture,
70+
SkipPreUninstall: preUninstallFlags.DetectSkipPreUninstallValue(),
6671
}, feedback.NewTaskProgressCB())
6772
if err != nil {
6873
feedback.Fatal(tr("Error during uninstall: %v", err), feedback.ErrGeneric)

internal/cli/core/upgrade.go

+9-8
Original file line numberDiff line numberDiff line change
@@ -43,21 +43,21 @@ func initUpgradeCommand() *cobra.Command {
4343
" # " + tr("upgrade arduino:samd to the latest version") + "\n" +
4444
" " + os.Args[0] + " core upgrade arduino:samd",
4545
Run: func(cmd *cobra.Command, args []string) {
46-
runUpgradeCommand(args, postInstallFlags.DetectSkipPostInstallValue())
46+
runUpgradeCommand(args, postInstallFlags.DetectSkipPostInstallValue(), postInstallFlags.DetectSkipPreUninstallValue())
4747
},
4848
}
4949
postInstallFlags.AddToCommand(upgradeCommand)
5050
return upgradeCommand
5151
}
5252

53-
func runUpgradeCommand(args []string, skipPostInstall bool) {
53+
func runUpgradeCommand(args []string, skipPostInstall bool, skipPreUninstall bool) {
5454
inst := instance.CreateAndInit()
5555
logrus.Info("Executing `arduino-cli core upgrade`")
56-
Upgrade(inst, args, skipPostInstall)
56+
Upgrade(inst, args, skipPostInstall, skipPreUninstall)
5757
}
5858

5959
// Upgrade upgrades one or all installed platforms to the latest version.
60-
func Upgrade(inst *rpc.Instance, args []string, skipPostInstall bool) {
60+
func Upgrade(inst *rpc.Instance, args []string, skipPostInstall bool, skipPreUninstall bool) {
6161
// if no platform was passed, upgrade allthethings
6262
if len(args) == 0 {
6363
targets, err := core.PlatformList(&rpc.PlatformListRequest{
@@ -102,10 +102,11 @@ func Upgrade(inst *rpc.Instance, args []string, skipPostInstall bool) {
102102
}
103103

104104
r := &rpc.PlatformUpgradeRequest{
105-
Instance: inst,
106-
PlatformPackage: platformRef.PackageName,
107-
Architecture: platformRef.Architecture,
108-
SkipPostInstall: skipPostInstall,
105+
Instance: inst,
106+
PlatformPackage: platformRef.PackageName,
107+
Architecture: platformRef.Architecture,
108+
SkipPostInstall: skipPostInstall,
109+
SkipPreUninstall: skipPreUninstall,
109110
}
110111
response, err := core.PlatformUpgrade(context.Background(), r, feedback.ProgressBar(), feedback.TaskProgress())
111112
warningMissingIndex(response)

internal/cli/upgrade/upgrade.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,16 @@ func NewCommand() *cobra.Command {
3939
Example: " " + os.Args[0] + " upgrade",
4040
Args: cobra.NoArgs,
4141
Run: func(cmd *cobra.Command, args []string) {
42-
runUpgradeCommand(postInstallFlags.DetectSkipPostInstallValue())
42+
runUpgradeCommand(postInstallFlags.DetectSkipPostInstallValue(), postInstallFlags.DetectSkipPreUninstallValue())
4343
},
4444
}
4545
postInstallFlags.AddToCommand(upgradeCommand)
4646
return upgradeCommand
4747
}
4848

49-
func runUpgradeCommand(skipPostInstall bool) {
49+
func runUpgradeCommand(skipPostInstall bool, skipPreUninstall bool) {
5050
inst := instance.CreateAndInit()
5151
logrus.Info("Executing `arduino-cli upgrade`")
5252
lib.Upgrade(inst, []string{})
53-
core.Upgrade(inst, []string{}, skipPostInstall)
53+
core.Upgrade(inst, []string{}, skipPostInstall, skipPreUninstall)
5454
}

0 commit comments

Comments
 (0)