mirror of
https://github.com/hashicorp/packer.git
synced 2026-02-03 20:39:29 -05:00
189 lines
5 KiB
Go
189 lines
5 KiB
Go
// Copyright IBM Corp. 2013, 2025
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package command
|
|
|
|
import (
|
|
"context"
|
|
"crypto/sha256"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"github.com/hashicorp/go-version"
|
|
"github.com/hashicorp/hcl/v2"
|
|
"github.com/hashicorp/packer/hcl2template/addrs"
|
|
"github.com/hashicorp/packer/packer"
|
|
plugingetter "github.com/hashicorp/packer/packer/plugin-getter"
|
|
"github.com/mitchellh/cli"
|
|
)
|
|
|
|
type PluginsRemoveCommand struct {
|
|
Meta
|
|
}
|
|
|
|
func (c *PluginsRemoveCommand) Synopsis() string {
|
|
return "Remove Packer plugins [matching a version]"
|
|
}
|
|
|
|
func (c *PluginsRemoveCommand) Help() string {
|
|
helpText := `
|
|
Usage: packer plugins remove <plugin> [<version constraint>]
|
|
|
|
This command will remove one or more installed Packer plugins.
|
|
|
|
To remove a plugin matching a version constraint for the current OS and architecture.
|
|
|
|
packer plugins remove github.com/hashicorp/happycloud v1.2.3
|
|
|
|
To remove all versions of a plugin for the current OS and architecture omit the version constraint.
|
|
|
|
packer plugins remove github.com/hashicorp/happycloud
|
|
|
|
To remove a single plugin binary from the Packer plugin directory specify the absolute path to an installed binary. This syntax does not allow for version matching.
|
|
|
|
packer plugins remove ~/.config/plugins/github.com/hashicorp/happycloud/packer-plugin-happycloud_v1.0.0_x5.0_linux_amd64
|
|
`
|
|
|
|
return strings.TrimSpace(helpText)
|
|
}
|
|
|
|
func (c *PluginsRemoveCommand) Run(args []string) int {
|
|
ctx, cleanup := handleTermInterrupt(c.Ui)
|
|
defer cleanup()
|
|
|
|
return c.RunContext(ctx, args)
|
|
}
|
|
|
|
// deletePluginBinary removes a local plugin binary, and its related checksum file.
|
|
func deletePluginBinary(pluginPath string) error {
|
|
if err := os.Remove(pluginPath); err != nil {
|
|
return err
|
|
}
|
|
shasumFile := fmt.Sprintf("%s_SHA256SUM", pluginPath)
|
|
|
|
if _, err := os.Stat(shasumFile); err != nil {
|
|
log.Printf("[INFO] No SHA256SUM file to remove for the plugin, ignoring.")
|
|
return nil
|
|
}
|
|
|
|
return os.Remove(shasumFile)
|
|
}
|
|
|
|
func (c *PluginsRemoveCommand) RunContext(buildCtx context.Context, args []string) int {
|
|
if len(args) < 1 || len(args) > 2 {
|
|
return cli.RunResultHelp
|
|
}
|
|
|
|
pluginDir, err := packer.PluginFolder()
|
|
if err != nil {
|
|
return writeDiags(c.Ui, nil, hcl.Diagnostics{
|
|
&hcl.Diagnostic{
|
|
Severity: hcl.DiagError,
|
|
Summary: "Failed to get the plugin directory",
|
|
Detail: fmt.Sprintf(
|
|
"The directory in which plugins are installed could not be fetched from the environment. This is likely a Packer bug. Error: %s",
|
|
err),
|
|
},
|
|
})
|
|
}
|
|
|
|
if filepath.IsAbs(args[0]) {
|
|
if len(args) != 1 {
|
|
c.Ui.Error("Unsupported: no version constraint may be specified with a local plugin path.\n")
|
|
return cli.RunResultHelp
|
|
}
|
|
|
|
if !strings.Contains(args[0], pluginDir) {
|
|
return writeDiags(c.Ui, nil, hcl.Diagnostics{
|
|
&hcl.Diagnostic{
|
|
Severity: hcl.DiagError,
|
|
Summary: "Invalid plugin location",
|
|
Detail: fmt.Sprintf(
|
|
"The path %q is not under the plugin directory inferred by Packer (%s) and will not be removed.",
|
|
args[0],
|
|
pluginDir),
|
|
},
|
|
})
|
|
}
|
|
|
|
log.Printf("will delete plugin located at %q", args[0])
|
|
err := deletePluginBinary(args[0])
|
|
if err != nil {
|
|
return writeDiags(c.Ui, nil, hcl.Diagnostics{
|
|
&hcl.Diagnostic{
|
|
Severity: hcl.DiagError,
|
|
Summary: "Failed to delete plugin",
|
|
Detail: fmt.Sprintf("The plugin %q failed to be deleted with the following error: %q", args[0], err),
|
|
},
|
|
})
|
|
}
|
|
|
|
c.Ui.Say(args[0])
|
|
|
|
return 0
|
|
}
|
|
|
|
opts := plugingetter.ListInstallationsOptions{
|
|
PluginDirectory: c.Meta.CoreConfig.Components.PluginConfig.PluginDirectory,
|
|
BinaryInstallationOptions: plugingetter.BinaryInstallationOptions{
|
|
OS: runtime.GOOS,
|
|
ARCH: runtime.GOARCH,
|
|
Checksummers: []plugingetter.Checksummer{
|
|
{Type: "sha256", Hash: sha256.New()},
|
|
},
|
|
},
|
|
}
|
|
|
|
if runtime.GOOS == "windows" && opts.Ext == "" {
|
|
opts.BinaryInstallationOptions.Ext = ".exe"
|
|
}
|
|
|
|
plugin, err := addrs.ParsePluginSourceString(args[0])
|
|
if err != nil {
|
|
c.Ui.Errorf("Invalid source string %q: %s", args[0], err)
|
|
return 1
|
|
}
|
|
|
|
// a plugin requirement that matches them all
|
|
pluginRequirement := plugingetter.Requirement{
|
|
Identifier: plugin,
|
|
}
|
|
|
|
if len(args) > 1 {
|
|
constraints, err := version.NewConstraint(args[1])
|
|
if err != nil {
|
|
c.Ui.Error(err.Error())
|
|
return 1
|
|
}
|
|
pluginRequirement.VersionConstraints = constraints
|
|
}
|
|
|
|
installations, err := pluginRequirement.ListInstallations(opts)
|
|
if err != nil {
|
|
c.Ui.Error(err.Error())
|
|
return 1
|
|
}
|
|
for _, installation := range installations {
|
|
err := deletePluginBinary(installation.BinaryPath)
|
|
if err != nil {
|
|
c.Ui.Error(fmt.Sprintf("Failed to remove plugin %q: %q", installation.BinaryPath, err))
|
|
continue
|
|
}
|
|
c.Ui.Message(installation.BinaryPath)
|
|
}
|
|
|
|
if len(installations) == 0 {
|
|
errMsg := fmt.Sprintf("No installed plugin found matching the plugin constraints %s", args[0])
|
|
if len(args) == 2 {
|
|
errMsg = fmt.Sprintf("%s %s", errMsg, args[1])
|
|
}
|
|
c.Ui.Error(errMsg)
|
|
return 1
|
|
}
|
|
|
|
return 0
|
|
}
|