packer/command/plugins_required.go
Lucas Bajolet a852434410 packer: fix listing on windows with .exe ext
Listing installed plugins on Windows requires the extension to be set in
the ListOptions, otherwise they are not discovered.

While working on the discovery code, and consolidating it in a single
location, we've forgotten to pass the argument to ListInstallations, so
that makes it impossible to automatically discover installed components
on Windows.

This commit fixes this issue for the plugins required, and the general
discovery process during build/validate.
2024-05-16 13:27:50 -04:00

126 lines
3.1 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package command
import (
"context"
"crypto/sha256"
"fmt"
"runtime"
"strings"
pluginsdk "github.com/hashicorp/packer-plugin-sdk/plugin"
plugingetter "github.com/hashicorp/packer/packer/plugin-getter"
"github.com/mitchellh/cli"
)
type PluginsRequiredCommand struct {
Meta
}
func (c *PluginsRequiredCommand) Synopsis() string {
return "List plugins required by a config"
}
func (c *PluginsRequiredCommand) Help() string {
helpText := `
Usage: packer plugins required <path>
This command will list every Packer plugin required by a Packer config, in
packer.required_plugins blocks. All binaries matching the required version
constrain and the current OS and Architecture will be listed. The most recent
version (and the first of the list) will be the one picked by Packer during a
build.
Ex: packer plugins required require.pkr.hcl
Ex: packer plugins required path/to/folder/
`
return strings.TrimSpace(helpText)
}
func (c *PluginsRequiredCommand) Run(args []string) int {
ctx, cleanup := handleTermInterrupt(c.Ui)
defer cleanup()
cfg, ret := c.ParseArgs(args)
if ret != 0 {
return ret
}
return c.RunContext(ctx, cfg)
}
func (c *PluginsRequiredCommand) ParseArgs(args []string) (*PluginsRequiredArgs, int) {
var cfg PluginsRequiredArgs
flags := c.Meta.FlagSet("plugins required")
flags.Usage = func() { c.Ui.Say(c.Help()) }
cfg.AddFlagSets(flags)
if err := flags.Parse(args); err != nil {
return &cfg, 1
}
args = flags.Args()
if len(args) != 1 {
return &cfg, cli.RunResultHelp
}
cfg.Path = args[0]
return &cfg, 0
}
func (c *PluginsRequiredCommand) RunContext(buildCtx context.Context, cla *PluginsRequiredArgs) int {
packerStarter, ret := c.GetConfig(&cla.MetaArgs)
if ret != 0 {
return ret
}
// Get plugins requirements
reqs, diags := packerStarter.PluginRequirements()
ret = writeDiags(c.Ui, nil, diags)
if ret != 0 {
return ret
}
ext := ""
if runtime.GOOS == "windows" {
ext = ".exe"
}
opts := plugingetter.ListInstallationsOptions{
PluginDirectory: c.Meta.CoreConfig.Components.PluginConfig.PluginDirectory,
BinaryInstallationOptions: plugingetter.BinaryInstallationOptions{
OS: runtime.GOOS,
ARCH: runtime.GOARCH,
Ext: ext,
APIVersionMajor: pluginsdk.APIVersionMajor,
APIVersionMinor: pluginsdk.APIVersionMinor,
Checksummers: []plugingetter.Checksummer{
{Type: "sha256", Hash: sha256.New()},
},
},
}
for _, pluginRequirement := range reqs {
s := fmt.Sprintf("%s %s %q", pluginRequirement.Accessor, pluginRequirement.Identifier.String(), pluginRequirement.VersionConstraints.String())
installs, err := pluginRequirement.ListInstallations(opts)
if err != nil {
c.Ui.Error(err.Error())
return 1
}
for _, install := range installs {
s += fmt.Sprintf(" %s", install.BinaryPath)
}
c.Ui.Message(s)
}
if len(reqs) == 0 {
c.Ui.Message(`
No plugins requirement found, make sure you reference a Packer config
containing a packer.required_plugins block. See
https://www.packer.io/docs/templates/hcl_templates/blocks/packer
for more info.`)
}
return 0
}