Unverified Commit 29c70df8 authored by MatteoPologruto's avatar MatteoPologruto Committed by GitHub

Add support for pre_uninstall scripts (#2311)

* Add skip_pre_uninstall parameter to gRPC platform requests

* Add pre-uninstall flags to CLI arguments

* Run pre-uninstall script when a platform or tool is uninstalled

* Document the changes

* Include pre-uninstall script run into the unit test
parent f6645a89
...@@ -38,6 +38,7 @@ func (pme *Explorer) DownloadAndInstallPlatformUpgrades( ...@@ -38,6 +38,7 @@ func (pme *Explorer) DownloadAndInstallPlatformUpgrades(
downloadCB rpc.DownloadProgressCB, downloadCB rpc.DownloadProgressCB,
taskCB rpc.TaskProgressCB, taskCB rpc.TaskProgressCB,
skipPostInstall bool, skipPostInstall bool,
skipPreUninstall bool,
) (*cores.PlatformRelease, error) { ) (*cores.PlatformRelease, error) {
if platformRef.PlatformVersion != nil { if platformRef.PlatformVersion != nil {
return nil, &arduino.InvalidArgumentError{Message: tr("Upgrade doesn't accept parameters with version")} return nil, &arduino.InvalidArgumentError{Message: tr("Upgrade doesn't accept parameters with version")}
...@@ -62,7 +63,7 @@ func (pme *Explorer) DownloadAndInstallPlatformUpgrades( ...@@ -62,7 +63,7 @@ func (pme *Explorer) DownloadAndInstallPlatformUpgrades(
if err != nil { if err != nil {
return nil, &arduino.PlatformNotFoundError{Platform: platformRef.String()} return nil, &arduino.PlatformNotFoundError{Platform: platformRef.String()}
} }
if err := pme.DownloadAndInstallPlatformAndTools(platformRelease, tools, downloadCB, taskCB, skipPostInstall); err != nil { if err := pme.DownloadAndInstallPlatformAndTools(platformRelease, tools, downloadCB, taskCB, skipPostInstall, skipPreUninstall); err != nil {
return nil, err return nil, err
} }
...@@ -75,7 +76,7 @@ func (pme *Explorer) DownloadAndInstallPlatformUpgrades( ...@@ -75,7 +76,7 @@ func (pme *Explorer) DownloadAndInstallPlatformUpgrades(
func (pme *Explorer) DownloadAndInstallPlatformAndTools( func (pme *Explorer) DownloadAndInstallPlatformAndTools(
platformRelease *cores.PlatformRelease, requiredTools []*cores.ToolRelease, platformRelease *cores.PlatformRelease, requiredTools []*cores.ToolRelease,
downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB, downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB,
skipPostInstall bool) error { skipPostInstall bool, skipPreUninstall bool) error {
log := pme.log.WithField("platform", platformRelease) log := pme.log.WithField("platform", platformRelease)
// Prerequisite checks before install // Prerequisite checks before install
...@@ -142,7 +143,7 @@ func (pme *Explorer) DownloadAndInstallPlatformAndTools( ...@@ -142,7 +143,7 @@ func (pme *Explorer) DownloadAndInstallPlatformAndTools(
// If upgrading remove previous release // If upgrading remove previous release
if installed != nil { if installed != nil {
uninstallErr := pme.UninstallPlatform(installed, taskCB) uninstallErr := pme.UninstallPlatform(installed, taskCB, skipPreUninstall)
// In case of error try to rollback // In case of error try to rollback
if uninstallErr != nil { if uninstallErr != nil {
...@@ -150,7 +151,7 @@ func (pme *Explorer) DownloadAndInstallPlatformAndTools( ...@@ -150,7 +151,7 @@ func (pme *Explorer) DownloadAndInstallPlatformAndTools(
taskCB(&rpc.TaskProgress{Message: tr("Error upgrading platform: %s", uninstallErr)}) taskCB(&rpc.TaskProgress{Message: tr("Error upgrading platform: %s", uninstallErr)})
// Rollback // Rollback
if err := pme.UninstallPlatform(platformRelease, taskCB); err != nil { if err := pme.UninstallPlatform(platformRelease, taskCB, skipPreUninstall); err != nil {
log.WithError(err).Error("Error rolling-back changes.") log.WithError(err).Error("Error rolling-back changes.")
taskCB(&rpc.TaskProgress{Message: tr("Error rolling-back changes: %s", err)}) taskCB(&rpc.TaskProgress{Message: tr("Error rolling-back changes: %s", err)})
} }
...@@ -162,7 +163,7 @@ func (pme *Explorer) DownloadAndInstallPlatformAndTools( ...@@ -162,7 +163,7 @@ func (pme *Explorer) DownloadAndInstallPlatformAndTools(
for _, tool := range installedTools { for _, tool := range installedTools {
taskCB(&rpc.TaskProgress{Name: tr("Uninstalling %s, tool is no more required", tool)}) taskCB(&rpc.TaskProgress{Name: tr("Uninstalling %s, tool is no more required", tool)})
if !pme.IsToolRequired(tool) { if !pme.IsToolRequired(tool) {
pme.UninstallTool(tool, taskCB) pme.UninstallTool(tool, taskCB, skipPreUninstall)
} }
} }
...@@ -175,7 +176,7 @@ func (pme *Explorer) DownloadAndInstallPlatformAndTools( ...@@ -175,7 +176,7 @@ func (pme *Explorer) DownloadAndInstallPlatformAndTools(
if !platformRelease.IsInstalled() { if !platformRelease.IsInstalled() {
return errors.New(tr("platform not installed")) return errors.New(tr("platform not installed"))
} }
stdout, stderr, err := pme.RunPostInstallScript(platformRelease.InstallDir) stdout, stderr, err := pme.RunPreOrPostScript(platformRelease.InstallDir, "post_install")
skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stdout), Completed: true}) skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stdout), Completed: true})
skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stderr), Completed: true}) skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stderr), Completed: true})
if err != nil { if err != nil {
...@@ -229,16 +230,16 @@ func (pme *Explorer) cacheInstalledJSON(platformRelease *cores.PlatformRelease) ...@@ -229,16 +230,16 @@ func (pme *Explorer) cacheInstalledJSON(platformRelease *cores.PlatformRelease)
return nil return nil
} }
// RunPostInstallScript runs the post_install.sh (or post_install.bat) script for the // RunPreOrPostScript runs either the post_install.sh (or post_install.bat) or the pre_uninstall.sh (or pre_uninstall.bat)
// specified platformRelease or toolRelease. // script for the specified platformRelease or toolRelease.
func (pme *Explorer) RunPostInstallScript(installDir *paths.Path) ([]byte, []byte, error) { func (pme *Explorer) RunPreOrPostScript(installDir *paths.Path, prefix string) ([]byte, []byte, error) {
postInstallFilename := "post_install.sh" scriptFilename := prefix + ".sh"
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
postInstallFilename = "post_install.bat" scriptFilename = prefix + ".bat"
} }
postInstall := installDir.Join(postInstallFilename) script := installDir.Join(scriptFilename)
if postInstall.Exist() && postInstall.IsNotDir() { if script.Exist() && script.IsNotDir() {
cmd, err := executils.NewProcessFromPath(pme.GetEnvVarsForSpawnedProcess(), postInstall) cmd, err := executils.NewProcessFromPath(pme.GetEnvVarsForSpawnedProcess(), script)
if err != nil { if err != nil {
return []byte{}, []byte{}, err return []byte{}, []byte{}, err
} }
...@@ -270,7 +271,7 @@ func (pme *Explorer) IsManagedPlatformRelease(platformRelease *cores.PlatformRel ...@@ -270,7 +271,7 @@ func (pme *Explorer) IsManagedPlatformRelease(platformRelease *cores.PlatformRel
} }
// UninstallPlatform remove a PlatformRelease. // UninstallPlatform remove a PlatformRelease.
func (pme *Explorer) UninstallPlatform(platformRelease *cores.PlatformRelease, taskCB rpc.TaskProgressCB) error { func (pme *Explorer) UninstallPlatform(platformRelease *cores.PlatformRelease, taskCB rpc.TaskProgressCB, skipPreUninstall bool) error {
log := pme.log.WithField("platform", platformRelease) log := pme.log.WithField("platform", platformRelease)
log.Info("Uninstalling platform") log.Info("Uninstalling platform")
...@@ -289,6 +290,20 @@ func (pme *Explorer) UninstallPlatform(platformRelease *cores.PlatformRelease, t ...@@ -289,6 +290,20 @@ func (pme *Explorer) UninstallPlatform(platformRelease *cores.PlatformRelease, t
return &arduino.FailedUninstallError{Message: err.Error()} return &arduino.FailedUninstallError{Message: err.Error()}
} }
if !skipPreUninstall {
log.Info("Running pre_uninstall script")
taskCB(&rpc.TaskProgress{Message: tr("Running pre_uninstall script.")})
stdout, stderr, err := pme.RunPreOrPostScript(platformRelease.InstallDir, "pre_uninstall")
skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stdout), Completed: true})
skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stderr), Completed: true})
if err != nil {
taskCB(&rpc.TaskProgress{Message: tr("WARNING cannot run pre_uninstall script: %s", err), Completed: true})
}
} else {
log.Info("Skipping pre_uninstall script.")
taskCB(&rpc.TaskProgress{Message: tr("Skipping pre_uninstall script.")})
}
if err := platformRelease.InstallDir.RemoveAll(); err != nil { if err := platformRelease.InstallDir.RemoveAll(); err != nil {
err = fmt.Errorf(tr("removing platform files: %s"), err) err = fmt.Errorf(tr("removing platform files: %s"), err)
log.WithError(err).Error("Error uninstalling") log.WithError(err).Error("Error uninstalling")
...@@ -339,7 +354,7 @@ func (pme *Explorer) InstallTool(toolRelease *cores.ToolRelease, taskCB rpc.Task ...@@ -339,7 +354,7 @@ func (pme *Explorer) InstallTool(toolRelease *cores.ToolRelease, taskCB rpc.Task
if !skipPostInstall { if !skipPostInstall {
log.Info("Running tool post_install script") log.Info("Running tool post_install script")
taskCB(&rpc.TaskProgress{Message: tr("Configuring tool.")}) taskCB(&rpc.TaskProgress{Message: tr("Configuring tool.")})
stdout, stderr, err := pme.RunPostInstallScript(toolRelease.InstallDir) stdout, stderr, err := pme.RunPreOrPostScript(toolRelease.InstallDir, "post_install")
skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stdout)}) skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stdout)})
skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stderr)}) skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stderr)})
if err != nil { if err != nil {
...@@ -373,7 +388,7 @@ func (pme *Explorer) IsManagedToolRelease(toolRelease *cores.ToolRelease) bool { ...@@ -373,7 +388,7 @@ func (pme *Explorer) IsManagedToolRelease(toolRelease *cores.ToolRelease) bool {
} }
// UninstallTool remove a ToolRelease. // UninstallTool remove a ToolRelease.
func (pme *Explorer) UninstallTool(toolRelease *cores.ToolRelease, taskCB rpc.TaskProgressCB) error { func (pme *Explorer) UninstallTool(toolRelease *cores.ToolRelease, taskCB rpc.TaskProgressCB, skipPreUninstall bool) error {
log := pme.log.WithField("Tool", toolRelease) log := pme.log.WithField("Tool", toolRelease)
log.Info("Uninstalling tool") log.Info("Uninstalling tool")
...@@ -388,6 +403,20 @@ func (pme *Explorer) UninstallTool(toolRelease *cores.ToolRelease, taskCB rpc.Ta ...@@ -388,6 +403,20 @@ func (pme *Explorer) UninstallTool(toolRelease *cores.ToolRelease, taskCB rpc.Ta
return err return err
} }
if !skipPreUninstall {
log.Info("Running pre_uninstall script")
taskCB(&rpc.TaskProgress{Message: tr("Running pre_uninstall script.")})
stdout, stderr, err := pme.RunPreOrPostScript(toolRelease.InstallDir, "pre_uninstall")
skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stdout), Completed: true})
skipEmptyMessageTaskProgressCB(taskCB)(&rpc.TaskProgress{Message: string(stderr), Completed: true})
if err != nil {
taskCB(&rpc.TaskProgress{Message: tr("WARNING cannot run pre_uninstall script: %s", err), Completed: true})
}
} else {
log.Info("Skipping pre_uninstall script.")
taskCB(&rpc.TaskProgress{Message: tr("Skipping pre_uninstall script.")})
}
if err := toolRelease.InstallDir.RemoveAll(); err != nil { if err := toolRelease.InstallDir.RemoveAll(); err != nil {
err = &arduino.FailedUninstallError{Message: err.Error()} err = &arduino.FailedUninstallError{Message: err.Error()}
log.WithError(err).Error("Error uninstalling") log.WithError(err).Error("Error uninstalling")
......
...@@ -921,7 +921,7 @@ func TestVariantAndCoreSelection(t *testing.T) { ...@@ -921,7 +921,7 @@ func TestVariantAndCoreSelection(t *testing.T) {
}) })
} }
func TestRunPostInstall(t *testing.T) { func TestRunScript(t *testing.T) {
pmb := NewBuilder(nil, nil, nil, nil, "test") pmb := NewBuilder(nil, nil, nil, nil, "test")
pm := pmb.Build() pm := pmb.Build()
pme, release := pm.NewExplorer() pme, release := pm.NewExplorer()
...@@ -930,29 +930,49 @@ func TestRunPostInstall(t *testing.T) { ...@@ -930,29 +930,49 @@ func TestRunPostInstall(t *testing.T) {
// prepare dummy post install script // prepare dummy post install script
dir := paths.New(t.TempDir()) dir := paths.New(t.TempDir())
var scriptPath *paths.Path type Test struct {
var err error testName string
if runtime.GOOS == "windows" { scriptName string
scriptPath = dir.Join("post_install.bat") }
err = scriptPath.WriteFile([]byte( tests := []Test{
`@echo off {
echo sent in stdout testName: "PostInstallScript",
echo sent in stderr 1>&2`)) scriptName: "post_install",
} else { },
scriptPath = dir.Join("post_install.sh") {
err = scriptPath.WriteFile([]byte( testName: "PreUninstallScript",
`#!/bin/sh scriptName: "pre_uninstall",
echo "sent in stdout" },
echo "sent in stderr" 1>&2`))
} }
require.NoError(t, err)
err = os.Chmod(scriptPath.String(), 0777)
require.NoError(t, err)
stdout, stderr, err := pme.RunPostInstallScript(dir)
require.NoError(t, err)
// `HasPrefix` because windows seem to add a trailing space at the end for _, test := range tests {
require.Equal(t, "sent in stdout", strings.Trim(string(stdout), "\n\r ")) t.Run(test.testName, func(t *testing.T) {
require.Equal(t, "sent in stderr", strings.Trim(string(stderr), "\n\r ")) var scriptPath *paths.Path
var err error
if runtime.GOOS == "windows" {
scriptPath = dir.Join(test.scriptName + ".bat")
err = scriptPath.WriteFile([]byte(
`@echo off
echo sent in stdout
echo sent in stderr 1>&2`))
} else {
scriptPath = dir.Join(test.scriptName + ".sh")
err = scriptPath.WriteFile([]byte(
`#!/bin/sh
echo "sent in stdout"
echo "sent in stderr" 1>&2`))
}
require.NoError(t, err)
err = os.Chmod(scriptPath.String(), 0777)
require.NoError(t, err)
stdout, stderr, err := pme.RunPreOrPostScript(dir, test.scriptName)
require.NoError(t, err)
// `HasPrefix` because windows seem to add a trailing space at the end
require.Equal(t, "sent in stdout", strings.Trim(string(stdout), "\n\r "))
require.Equal(t, "sent in stderr", strings.Trim(string(stderr), "\n\r "))
})
}
} }
...@@ -63,7 +63,7 @@ func PlatformInstall(ctx context.Context, req *rpc.PlatformInstallRequest, downl ...@@ -63,7 +63,7 @@ func PlatformInstall(ctx context.Context, req *rpc.PlatformInstallRequest, downl
} }
} }
if err := pme.DownloadAndInstallPlatformAndTools(platformRelease, tools, downloadCB, taskCB, req.GetSkipPostInstall()); err != nil { if err := pme.DownloadAndInstallPlatformAndTools(platformRelease, tools, downloadCB, taskCB, req.GetSkipPostInstall(), req.GetSkipPreUninstall()); err != nil {
return err return err
} }
......
...@@ -64,14 +64,14 @@ func platformUninstall(ctx context.Context, req *rpc.PlatformUninstallRequest, t ...@@ -64,14 +64,14 @@ func platformUninstall(ctx context.Context, req *rpc.PlatformUninstallRequest, t
return &arduino.NotFoundError{Message: tr("Can't find dependencies for platform %s", ref), Cause: err} return &arduino.NotFoundError{Message: tr("Can't find dependencies for platform %s", ref), Cause: err}
} }
if err := pme.UninstallPlatform(platform, taskCB); err != nil { if err := pme.UninstallPlatform(platform, taskCB, req.GetSkipPreUninstall()); err != nil {
return err return err
} }
for _, tool := range tools { for _, tool := range tools {
if !pme.IsToolRequired(tool) { if !pme.IsToolRequired(tool) {
taskCB(&rpc.TaskProgress{Name: tr("Uninstalling %s, tool is no more required", tool)}) taskCB(&rpc.TaskProgress{Name: tr("Uninstalling %s, tool is no more required", tool)})
pme.UninstallTool(tool, taskCB) pme.UninstallTool(tool, taskCB, req.GetSkipPreUninstall())
} }
} }
......
...@@ -17,6 +17,7 @@ package core ...@@ -17,6 +17,7 @@ package core
import ( import (
"context" "context"
"github.com/arduino/arduino-cli/arduino/cores" "github.com/arduino/arduino-cli/arduino/cores"
"github.com/arduino/arduino-cli/arduino" "github.com/arduino/arduino-cli/arduino"
...@@ -39,7 +40,7 @@ func PlatformUpgrade(ctx context.Context, req *rpc.PlatformUpgradeRequest, downl ...@@ -39,7 +40,7 @@ func PlatformUpgrade(ctx context.Context, req *rpc.PlatformUpgradeRequest, downl
Package: req.PlatformPackage, Package: req.PlatformPackage,
PlatformArchitecture: req.Architecture, PlatformArchitecture: req.Architecture,
} }
platform, err := pme.DownloadAndInstallPlatformUpgrades(ref, downloadCB, taskCB, req.GetSkipPostInstall()) platform, err := pme.DownloadAndInstallPlatformUpgrades(ref, downloadCB, taskCB, req.GetSkipPostInstall(), req.GetSkipPreUninstall())
if err != nil { if err != nil {
return platform, err return platform, err
} }
......
...@@ -1559,3 +1559,21 @@ software is in use: ...@@ -1559,3 +1559,21 @@ software is in use:
- **Arduino CLI**: (since 0.12.0) runs the script for any installed platform when Arduino CLI is in "interactive" mode. - **Arduino CLI**: (since 0.12.0) runs the script for any installed platform when Arduino CLI is in "interactive" mode.
This behavior This behavior
[can be configured](https://arduino.github.io/arduino-cli/latest/commands/arduino-cli_core_install/#options) [can be configured](https://arduino.github.io/arduino-cli/latest/commands/arduino-cli_core_install/#options)
## Pre-uninstall script
Before Boards Manager starts uninstalling a platform, it checks for the presence of a script named:
- `pre_uninstall.bat` - when running on Windows
- `pre_uninstall.sh` - when running on any non-Windows operating system
If present, the script is executed.
This script may be used to configure the user's system for the removal of drivers, stopping background programs and
execute any action that should be performed before the platform files are removed.
The circumstances under which the pre-uninstall script will run are different depending on which Arduino development
software is in use:
- **Arduino CLI**: runs the script for any installed platform when Arduino CLI is in "interactive" mode. This behavior
[can be configured](https://arduino.github.io/arduino-cli/latest/commands/arduino-cli_core_install/#options)
...@@ -21,33 +21,47 @@ import ( ...@@ -21,33 +21,47 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
// PostInstallFlags contains flags data used by the core install and the upgrade command // PrePostScriptsFlags contains flags data used by the core install and the upgrade command
// This is useful so all flags used by commands that need // This is useful so all flags used by commands that need
// this information are consistent with each other. // this information are consistent with each other.
type PostInstallFlags struct { type PrePostScriptsFlags struct {
runPostInstall bool // force the execution of installation scripts runPostInstall bool // force the execution of installation scripts
skipPostInstall bool // skip the execution of installation scripts skipPostInstall bool // skip the execution of installation scripts
runPreUninstall bool // force the execution of pre uninstall scripts
skipPreUninstall bool // skip the execution of pre uninstall scripts
} }
// AddToCommand adds flags that can be used to force running or skipping // AddToCommand adds flags that can be used to force running or skipping
// of post installation scripts // of post installation scripts
func (p *PostInstallFlags) AddToCommand(cmd *cobra.Command) { func (p *PrePostScriptsFlags) AddToCommand(cmd *cobra.Command) {
cmd.Flags().BoolVar(&p.runPostInstall, "run-post-install", false, tr("Force run of post-install scripts (if the CLI is not running interactively).")) cmd.Flags().BoolVar(&p.runPostInstall, "run-post-install", false, tr("Force run of post-install scripts (if the CLI is not running interactively)."))
cmd.Flags().BoolVar(&p.skipPostInstall, "skip-post-install", false, tr("Force skip of post-install scripts (if the CLI is running interactively).")) cmd.Flags().BoolVar(&p.skipPostInstall, "skip-post-install", false, tr("Force skip of post-install scripts (if the CLI is running interactively)."))
cmd.Flags().BoolVar(&p.runPreUninstall, "run-pre-uninstall", false, tr("Force run of pre-uninstall scripts (if the CLI is not running interactively)."))
cmd.Flags().BoolVar(&p.skipPreUninstall, "skip-pre-uninstall", false, tr("Force skip of pre-uninstall scripts (if the CLI is running interactively)."))
} }
// GetRunPostInstall returns the run-post-install flag value // GetRunPostInstall returns the run-post-install flag value
func (p *PostInstallFlags) GetRunPostInstall() bool { func (p *PrePostScriptsFlags) GetRunPostInstall() bool {
return p.runPostInstall return p.runPostInstall
} }
// GetSkipPostInstall returns the skip-post-install flag value // GetSkipPostInstall returns the skip-post-install flag value
func (p *PostInstallFlags) GetSkipPostInstall() bool { func (p *PrePostScriptsFlags) GetSkipPostInstall() bool {
return p.skipPostInstall return p.skipPostInstall
} }
// GetRunPreUninstall returns the run-post-install flag value
func (p *PrePostScriptsFlags) GetRunPreUninstall() bool {
return p.runPreUninstall
}
// GetSkipPreUninstall returns the skip-post-install flag value
func (p *PrePostScriptsFlags) GetSkipPreUninstall() bool {
return p.skipPreUninstall
}
// DetectSkipPostInstallValue returns true if a post install script must be run // DetectSkipPostInstallValue returns true if a post install script must be run
func (p *PostInstallFlags) DetectSkipPostInstallValue() bool { func (p *PrePostScriptsFlags) DetectSkipPostInstallValue() bool {
if p.GetRunPostInstall() { if p.GetRunPostInstall() {
logrus.Info("Will run post-install by user request") logrus.Info("Will run post-install by user request")
return false return false
...@@ -64,3 +78,22 @@ func (p *PostInstallFlags) DetectSkipPostInstallValue() bool { ...@@ -64,3 +78,22 @@ func (p *PostInstallFlags) DetectSkipPostInstallValue() bool {
logrus.Info("Running from console, will run post-install by default") logrus.Info("Running from console, will run post-install by default")
return false return false
} }
// DetectSkipPreUninstallValue returns true if a post install script must be run
func (p *PrePostScriptsFlags) DetectSkipPreUninstallValue() bool {
if p.GetRunPreUninstall() {
logrus.Info("Will run pre-uninstall by user request")
return false
}
if p.GetSkipPreUninstall() {
logrus.Info("Will skip pre-uninstall by user request")
return true
}
if !configuration.IsInteractive {
logrus.Info("Not running from console, will skip pre-uninstall by default")
return true
}
logrus.Info("Running from console, will run pre-uninstall by default")
return false
}
...@@ -31,7 +31,7 @@ import ( ...@@ -31,7 +31,7 @@ import (
func initInstallCommand() *cobra.Command { func initInstallCommand() *cobra.Command {
var noOverwrite bool var noOverwrite bool
var postInstallFlags arguments.PostInstallFlags var scriptFlags arguments.PrePostScriptsFlags
installCommand := &cobra.Command{ installCommand := &cobra.Command{
Use: fmt.Sprintf("install %s:%s[@%s]...", tr("PACKAGER"), tr("ARCH"), tr("VERSION")), Use: fmt.Sprintf("install %s:%s[@%s]...", tr("PACKAGER"), tr("ARCH"), tr("VERSION")),
Short: tr("Installs one or more cores and corresponding tool dependencies."), Short: tr("Installs one or more cores and corresponding tool dependencies."),
...@@ -45,18 +45,18 @@ func initInstallCommand() *cobra.Command { ...@@ -45,18 +45,18 @@ func initInstallCommand() *cobra.Command {
arguments.CheckFlagsConflicts(cmd, "run-post-install", "skip-post-install") arguments.CheckFlagsConflicts(cmd, "run-post-install", "skip-post-install")
}, },
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
runInstallCommand(args, postInstallFlags, noOverwrite) runInstallCommand(args, scriptFlags, noOverwrite)
}, },
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return arguments.GetInstallableCores(), cobra.ShellCompDirectiveDefault return arguments.GetInstallableCores(), cobra.ShellCompDirectiveDefault
}, },
} }
postInstallFlags.AddToCommand(installCommand) scriptFlags.AddToCommand(installCommand)
installCommand.Flags().BoolVar(&noOverwrite, "no-overwrite", false, tr("Do not overwrite already installed platforms.")) installCommand.Flags().BoolVar(&noOverwrite, "no-overwrite", false, tr("Do not overwrite already installed platforms."))
return installCommand return installCommand
} }
func runInstallCommand(args []string, postInstallFlags arguments.PostInstallFlags, noOverwrite bool) { func runInstallCommand(args []string, scriptFlags arguments.PrePostScriptsFlags, noOverwrite bool) {
inst := instance.CreateAndInit() inst := instance.CreateAndInit()
logrus.Info("Executing `arduino-cli core install`") logrus.Info("Executing `arduino-cli core install`")
...@@ -67,12 +67,13 @@ func runInstallCommand(args []string, postInstallFlags arguments.PostInstallFlag ...@@ -67,12 +67,13 @@ func runInstallCommand(args []string, postInstallFlags arguments.PostInstallFlag
for _, platformRef := range platformsRefs { for _, platformRef := range platformsRefs {
platformInstallRequest := &rpc.PlatformInstallRequest{ platformInstallRequest := &rpc.PlatformInstallRequest{
Instance: inst, Instance: inst,
PlatformPackage: platformRef.PackageName, PlatformPackage: platformRef.PackageName,
Architecture: platformRef.Architecture, Architecture: platformRef.Architecture,
Version: platformRef.Version, Version: platformRef.Version,
SkipPostInstall: postInstallFlags.DetectSkipPostInstallValue(), SkipPostInstall: scriptFlags.DetectSkipPostInstallValue(),
NoOverwrite: noOverwrite, NoOverwrite: noOverwrite,
SkipPreUninstall: scriptFlags.DetectSkipPreUninstallValue(),
} }
_, err := core.PlatformInstall(context.Background(), platformInstallRequest, feedback.ProgressBar(), feedback.TaskProgress()) _, err := core.PlatformInstall(context.Background(), platformInstallRequest, feedback.ProgressBar(), feedback.TaskProgress())
if err != nil { if err != nil {
......
...@@ -30,21 +30,25 @@ import ( ...@@ -30,21 +30,25 @@ import (
) )
func initUninstallCommand() *cobra.Command { func initUninstallCommand() *cobra.Command {
var preUninstallFlags arguments.PrePostScriptsFlags
uninstallCommand := &cobra.Command{ uninstallCommand := &cobra.Command{
Use: fmt.Sprintf("uninstall %s:%s ...", tr("PACKAGER"), tr("ARCH")), Use: fmt.Sprintf("uninstall %s:%s ...", tr("PACKAGER"), tr("ARCH")),
Short: tr("Uninstalls one or more cores and corresponding tool dependencies if no longer used."), Short: tr("Uninstalls one or more cores and corresponding tool dependencies if no longer used."),
Long: tr("Uninstalls one or more cores and corresponding tool dependencies if no longer used."), Long: tr("Uninstalls one or more cores and corresponding tool dependencies if no longer used."),
Example: " " + os.Args[0] + " core uninstall arduino:samd\n", Example: " " + os.Args[0] + " core uninstall arduino:samd\n",
Args: cobra.MinimumNArgs(1), Args: cobra.MinimumNArgs(1),
Run: runUninstallCommand, Run: func(cmd *cobra.Command, args []string) {
runUninstallCommand(args, preUninstallFlags)
},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return arguments.GetUninstallableCores(), cobra.ShellCompDirectiveDefault return arguments.GetUninstallableCores(), cobra.ShellCompDirectiveDefault
}, },
} }
preUninstallFlags.AddToCommand(uninstallCommand)
return uninstallCommand return uninstallCommand
} }
func runUninstallCommand(cmd *cobra.Command, args []string) { func runUninstallCommand(args []string, preUninstallFlags arguments.PrePostScriptsFlags) {
inst := instance.CreateAndInit() inst := instance.CreateAndInit()
logrus.Info("Executing `arduino-cli core uninstall`") logrus.Info("Executing `arduino-cli core uninstall`")
...@@ -60,9 +64,10 @@ func runUninstallCommand(cmd *cobra.Command, args []string) { ...@@ -60,9 +64,10 @@ func runUninstallCommand(cmd *cobra.Command, args []string) {
} }
for _, platformRef := range platformsRefs { for _, platformRef := range platformsRefs {
_, err := core.PlatformUninstall(context.Background(), &rpc.PlatformUninstallRequest{ _, err := core.PlatformUninstall(context.Background(), &rpc.PlatformUninstallRequest{
Instance: inst, Instance: inst,
PlatformPackage: platformRef.PackageName, PlatformPackage: platformRef.PackageName,
Architecture: platformRef.Architecture, Architecture: platformRef.Architecture,
SkipPreUninstall: preUninstallFlags.DetectSkipPreUninstallValue(),
}, feedback.NewTaskProgressCB()) }, feedback.NewTaskProgressCB())
if err != nil { if err != nil {
feedback.Fatal(tr("Error during uninstall: %v", err), feedback.ErrGeneric) feedback.Fatal(tr("Error during uninstall: %v", err), feedback.ErrGeneric)
......
...@@ -32,7 +32,7 @@ import ( ...@@ -32,7 +32,7 @@ import (
) )
func initUpgradeCommand() *cobra.Command { func initUpgradeCommand() *cobra.Command {
var postInstallFlags arguments.PostInstallFlags var postInstallFlags arguments.PrePostScriptsFlags
upgradeCommand := &cobra.Command{ upgradeCommand := &cobra.Command{
Use: fmt.Sprintf("upgrade [%s:%s] ...", tr("PACKAGER"), tr("ARCH")), Use: fmt.Sprintf("upgrade [%s:%s] ...", tr("PACKAGER"), tr("ARCH")),
Short: tr("Upgrades one or all installed platforms to the latest version."), Short: tr("Upgrades one or all installed platforms to the latest version."),
...@@ -43,21 +43,21 @@ func initUpgradeCommand() *cobra.Command { ...@@ -43,21 +43,21 @@ func initUpgradeCommand() *cobra.Command {
" # " + tr("upgrade arduino:samd to the latest version") + "\n" + " # " + tr("upgrade arduino:samd to the latest version") + "\n" +
" " + os.Args[0] + " core upgrade arduino:samd", " " + os.Args[0] + " core upgrade arduino:samd",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
runUpgradeCommand(args, postInstallFlags.DetectSkipPostInstallValue()) runUpgradeCommand(args, postInstallFlags.DetectSkipPostInstallValue(), postInstallFlags.DetectSkipPreUninstallValue())
}, },
} }
postInstallFlags.AddToCommand(upgradeCommand) postInstallFlags.AddToCommand(upgradeCommand)
return upgradeCommand return upgradeCommand
} }
func runUpgradeCommand(args []string, skipPostInstall bool) { func runUpgradeCommand(args []string, skipPostInstall bool, skipPreUninstall bool) {
inst := instance.CreateAndInit() inst := instance.CreateAndInit()
logrus.Info("Executing `arduino-cli core upgrade`") logrus.Info("Executing `arduino-cli core upgrade`")
Upgrade(inst, args, skipPostInstall) Upgrade(inst, args, skipPostInstall, skipPreUninstall)
} }
// Upgrade upgrades one or all installed platforms to the latest version. // Upgrade upgrades one or all installed platforms to the latest version.
func Upgrade(inst *rpc.Instance, args []string, skipPostInstall bool) { func Upgrade(inst *rpc.Instance, args []string, skipPostInstall bool, skipPreUninstall bool) {
// if no platform was passed, upgrade allthethings // if no platform was passed, upgrade allthethings
if len(args) == 0 { if len(args) == 0 {
targets, err := core.PlatformList(&rpc.PlatformListRequest{ targets, err := core.PlatformList(&rpc.PlatformListRequest{
...@@ -102,10 +102,11 @@ func Upgrade(inst *rpc.Instance, args []string, skipPostInstall bool) { ...@@ -102,10 +102,11 @@ func Upgrade(inst *rpc.Instance, args []string, skipPostInstall bool) {
} }
r := &rpc.PlatformUpgradeRequest{ r := &rpc.PlatformUpgradeRequest{
Instance: inst, Instance: inst,
PlatformPackage: platformRef.PackageName, PlatformPackage: platformRef.PackageName,
Architecture: platformRef.Architecture, Architecture: platformRef.Architecture,
SkipPostInstall: skipPostInstall, SkipPostInstall: skipPostInstall,
SkipPreUninstall: skipPreUninstall,
} }
response, err := core.PlatformUpgrade(context.Background(), r, feedback.ProgressBar(), feedback.TaskProgress()) response, err := core.PlatformUpgrade(context.Background(), r, feedback.ProgressBar(), feedback.TaskProgress())
warningMissingIndex(response) warningMissingIndex(response)
......
...@@ -31,7 +31,7 @@ var tr = i18n.Tr ...@@ -31,7 +31,7 @@ var tr = i18n.Tr
// NewCommand creates a new `upgrade` command // NewCommand creates a new `upgrade` command
func NewCommand() *cobra.Command { func NewCommand() *cobra.Command {
var postInstallFlags arguments.PostInstallFlags var postInstallFlags arguments.PrePostScriptsFlags
upgradeCommand := &cobra.Command{ upgradeCommand := &cobra.Command{
Use: "upgrade", Use: "upgrade",
Short: tr("Upgrades installed cores and libraries."), Short: tr("Upgrades installed cores and libraries."),
...@@ -39,16 +39,16 @@ func NewCommand() *cobra.Command { ...@@ -39,16 +39,16 @@ func NewCommand() *cobra.Command {
Example: " " + os.Args[0] + " upgrade", Example: " " + os.Args[0] + " upgrade",
Args: cobra.NoArgs, Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
runUpgradeCommand(postInstallFlags.DetectSkipPostInstallValue()) runUpgradeCommand(postInstallFlags.DetectSkipPostInstallValue(), postInstallFlags.DetectSkipPreUninstallValue())
}, },
} }
postInstallFlags.AddToCommand(upgradeCommand) postInstallFlags.AddToCommand(upgradeCommand)
return upgradeCommand return upgradeCommand
} }
func runUpgradeCommand(skipPostInstall bool) { func runUpgradeCommand(skipPostInstall bool, skipPreUninstall bool) {
inst := instance.CreateAndInit() inst := instance.CreateAndInit()
logrus.Info("Executing `arduino-cli upgrade`") logrus.Info("Executing `arduino-cli upgrade`")
lib.Upgrade(inst, []string{}) lib.Upgrade(inst, []string{})
core.Upgrade(inst, []string{}, skipPostInstall) core.Upgrade(inst, []string{}, skipPostInstall, skipPreUninstall)
} }
This diff is collapsed.
...@@ -36,6 +36,9 @@ message PlatformInstallRequest { ...@@ -36,6 +36,9 @@ message PlatformInstallRequest {
// Set to true to skip installation if a different version of the platform // Set to true to skip installation if a different version of the platform
// is already installed. // is already installed.
bool no_overwrite = 6; bool no_overwrite = 6;
// Set to true to not run (eventual) pre uninstall scripts for trusted
// platforms when performing platform upgrades
bool skip_pre_uninstall = 7;
} }
message PlatformInstallResponse { message PlatformInstallResponse {
...@@ -69,6 +72,9 @@ message PlatformUninstallRequest { ...@@ -69,6 +72,9 @@ message PlatformUninstallRequest {
string platform_package = 2; string platform_package = 2;
// Architecture name of the platform (e.g., `avr`). // Architecture name of the platform (e.g., `avr`).
string architecture = 3; string architecture = 3;
// Set to true to not run (eventual) pre uninstall scripts for trusted
// platforms
bool skip_pre_uninstall = 4;
} }
message PlatformUninstallResponse { message PlatformUninstallResponse {
...@@ -90,6 +96,9 @@ message PlatformUpgradeRequest { ...@@ -90,6 +96,9 @@ message PlatformUpgradeRequest {
// Set to true to not run (eventual) post install scripts for trusted // Set to true to not run (eventual) post install scripts for trusted
// platforms // platforms
bool skip_post_install = 4; bool skip_post_install = 4;
// Set to true to not run (eventual) pre uninstall scripts for trusted
// platforms when performing platform upgrades
bool skip_pre_uninstall = 5;
} }
message PlatformUpgradeResponse { message PlatformUpgradeResponse {
......
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