From 9f4a1281dd390dbf23145b17d126e32a93feaa3c Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Thu, 10 Feb 2022 22:53:50 +0100 Subject: [PATCH] Add `packer plugins` command and subcommands to interact with plugins (#11553) * add basic docs for plugins command * refactor docs Co-Authored-By: Wilken Rivera <1749304+nywilken@users.noreply.github.com> * add plugins command * add plugins subcommands they do nothing for now * add plugins installed command + tests * add plugins install command * add remove plugin command * better docs for the plugins install command * remove duplicate content * better output for installed plugins * add plugins required command * Update plugins_install.go * add newline after `Usage:` * Update plugins_remove.go * Update plugins_required.go * Update plugins_remove.go * Update plugins_installed.go * Update plugins_install.go * add docs * Update plugins_install.go * fix typos * Update plugins_test.go * fix typos Co-Authored-By: Wilken Rivera <1749304+nywilken@users.noreply.github.com> * Update core_wrapper.go Co-Authored-By: Wilken Rivera <1749304+nywilken@users.noreply.github.com> * Update website/content/docs/commands/plugins/remove.mdx Co-authored-by: Wilken Rivera * Update website/content/docs/commands/plugins/required.mdx Co-authored-by: Wilken Rivera * Update website/content/docs/commands/plugins/required.mdx Co-authored-by: Wilken Rivera * Update plugins_required.go * Update install.mdx * Update required.mdx * plugins requirement, warn when no plugin was found * Update website/content/docs/commands/plugins/required.mdx Co-authored-by: Wilken Rivera Co-authored-by: Wilken Rivera <1749304+nywilken@users.noreply.github.com> Co-authored-by: Wilken Rivera --- command/cli.go | 7 +- command/core_wrapper.go | 4 +- command/plugins.go | 32 +++++ command/plugins_install.go | 124 ++++++++++++++++++ command/plugins_installed.go | 78 +++++++++++ command/plugins_remove.go | 96 ++++++++++++++ command/plugins_required.go | 118 +++++++++++++++++ commands.go | 30 +++++ packer/plugin-getter/plugins.go | 25 +++- packer/plugin-getter/plugins_test.go | 66 +++++++++- .../content/docs/commands/plugins/index.mdx | 30 +++++ .../content/docs/commands/plugins/install.mdx | 24 ++++ .../docs/commands/plugins/installed.mdx | 21 +++ .../content/docs/commands/plugins/remove.mdx | 24 ++++ .../docs/commands/plugins/required.mdx | 30 +++++ website/data/docs-nav-data.json | 25 ++++ 16 files changed, 725 insertions(+), 9 deletions(-) create mode 100644 command/plugins.go create mode 100644 command/plugins_install.go create mode 100644 command/plugins_installed.go create mode 100644 command/plugins_remove.go create mode 100644 command/plugins_required.go create mode 100644 website/content/docs/commands/plugins/index.mdx create mode 100644 website/content/docs/commands/plugins/install.mdx create mode 100644 website/content/docs/commands/plugins/installed.mdx create mode 100644 website/content/docs/commands/plugins/remove.mdx create mode 100644 website/content/docs/commands/plugins/required.mdx diff --git a/command/cli.go b/command/cli.go index 82d6852eb..a9486cd52 100644 --- a/command/cli.go +++ b/command/cli.go @@ -99,12 +99,17 @@ func (ia *InitArgs) AddFlagSets(flags *flag.FlagSet) { ia.MetaArgs.AddFlagSets(flags) } -// InitArgs represents a parsed cli line for a `packer build` +// InitArgs represents a parsed cli line for a `packer init ` type InitArgs struct { MetaArgs Upgrade bool } +// PluginsRequiredArgs represents a parsed cli line for a `packer plugins required ` +type PluginsRequiredArgs struct { + MetaArgs +} + // ConsoleArgs represents a parsed cli line for a `packer console` type ConsoleArgs struct { MetaArgs diff --git a/command/core_wrapper.go b/command/core_wrapper.go index 9d61f5580..f782903fa 100644 --- a/command/core_wrapper.go +++ b/command/core_wrapper.go @@ -29,8 +29,8 @@ func (c *CoreWrapper) Initialize(_ packer.InitializeOptions) hcl.Diagnostics { func (c *CoreWrapper) PluginRequirements() (plugingetter.Requirements, hcl.Diagnostics) { return nil, hcl.Diagnostics{ &hcl.Diagnostic{ - Summary: "Packer init is supported for HCL2 configuration templates only", - Detail: "Please manually install plugins or use a HCL2 configuration that will do that for you.", + Summary: "Packer plugins currently only works with HCL2 configuration templates", + Detail: "Please manually install plugins with the plugins command or use a HCL2 configuration that will do that for you.", Severity: hcl.DiagError, }, } diff --git a/command/plugins.go b/command/plugins.go new file mode 100644 index 000000000..7ec255381 --- /dev/null +++ b/command/plugins.go @@ -0,0 +1,32 @@ +package command + +import ( + "strings" + + "github.com/mitchellh/cli" +) + +type PluginsCommand struct { + Meta +} + +func (c *PluginsCommand) Synopsis() string { + return "Interact with Packer plugins and catalog" +} + +func (c *PluginsCommand) Help() string { + helpText := ` +Usage: packer plugins [options] [args] + This command groups subcommands for interacting with Packer plugins. + +Related but not under the "plugins" command : + +- "packer init " will install all plugins required by a config. +` + + return strings.TrimSpace(helpText) +} + +func (c *PluginsCommand) Run(args []string) int { + return cli.RunResultHelp +} diff --git a/command/plugins_install.go b/command/plugins_install.go new file mode 100644 index 000000000..2e14fcca2 --- /dev/null +++ b/command/plugins_install.go @@ -0,0 +1,124 @@ +package command + +import ( + "context" + "crypto/sha256" + "fmt" + "runtime" + "strings" + + "github.com/hashicorp/go-version" + pluginsdk "github.com/hashicorp/packer-plugin-sdk/plugin" + "github.com/hashicorp/packer/hcl2template/addrs" + "github.com/hashicorp/packer/packer" + plugingetter "github.com/hashicorp/packer/packer/plugin-getter" + "github.com/hashicorp/packer/packer/plugin-getter/github" + pkrversion "github.com/hashicorp/packer/version" + "github.com/mitchellh/cli" +) + +type PluginsInstallCommand struct { + Meta +} + +func (c *PluginsInstallCommand) Synopsis() string { + return "Install latest Packer plugin [matching version constraint]" +} + +func (c *PluginsInstallCommand) Help() string { + helpText := ` +Usage: packer plugins install [] + + This command will install the most recent compatible Packer plugin matching + version constraint. + When the version constraint is omitted, the most recent version will be + installed. + + Ex: packer plugins install github.com/hashicorp/happycloud v1.2.3 +` + + return strings.TrimSpace(helpText) +} + +func (c *PluginsInstallCommand) Run(args []string) int { + ctx, cleanup := handleTermInterrupt(c.Ui) + defer cleanup() + + return c.RunContext(ctx, args) +} + +func (c *PluginsInstallCommand) RunContext(buildCtx context.Context, args []string) int { + if len(args) < 1 || len(args) > 2 { + return cli.RunResultHelp + } + + opts := plugingetter.ListInstallationsOptions{ + FromFolders: c.Meta.CoreConfig.Components.PluginConfig.KnownPluginFolders, + BinaryInstallationOptions: plugingetter.BinaryInstallationOptions{ + OS: runtime.GOOS, + ARCH: runtime.GOARCH, + APIVersionMajor: pluginsdk.APIVersionMajor, + APIVersionMinor: pluginsdk.APIVersionMinor, + Checksummers: []plugingetter.Checksummer{ + {Type: "sha256", Hash: sha256.New()}, + }, + }, + } + + plugin, diags := addrs.ParsePluginSourceString(args[0]) + if diags.HasErrors() { + c.Ui.Error(diags.Error()) + return 1 + } + + // a plugin requirement that matches them all + pluginRequirement := plugingetter.Requirement{ + Identifier: plugin, + Implicit: false, + } + + if len(args) > 1 { + constraints, err := version.NewConstraint(args[1]) + if err != nil { + c.Ui.Error(err.Error()) + return 1 + } + pluginRequirement.VersionConstraints = constraints + } + + getters := []plugingetter.Getter{ + &github.Getter{ + // In the past some terraform plugins downloads were blocked from a + // specific aws region by s3. Changing the user agent unblocked the + // downloads so having one user agent per version will help mitigate + // that a little more. Especially in the case someone forks this + // code to make it more aggressive or something. + // TODO: allow to set this from the config file or an environment + // variable. + UserAgent: "packer-getter-github-" + pkrversion.String(), + }, + } + + newInstall, err := pluginRequirement.InstallLatest(plugingetter.InstallOptions{ + InFolders: opts.FromFolders, + BinaryInstallationOptions: opts.BinaryInstallationOptions, + Getters: getters, + }) + + if err != nil { + c.Ui.Error(err.Error()) + return 1 + } + + if newInstall != nil { + msg := fmt.Sprintf("Installed plugin %s %s in %q", pluginRequirement.Identifier, newInstall.Version, newInstall.BinaryPath) + ui := &packer.ColoredUi{ + Color: packer.UiColorCyan, + Ui: c.Ui, + } + ui.Say(msg) + return 0 + } + + return 0 +} diff --git a/command/plugins_installed.go b/command/plugins_installed.go new file mode 100644 index 000000000..96ddc65d8 --- /dev/null +++ b/command/plugins_installed.go @@ -0,0 +1,78 @@ +package command + +import ( + "context" + "crypto/sha256" + "log" + "runtime" + "strings" + + plugingetter "github.com/hashicorp/packer/packer/plugin-getter" +) + +type PluginsInstalledCommand struct { + Meta +} + +func (c *PluginsInstalledCommand) Synopsis() string { + return "List all installed Packer plugin binaries" +} + +func (c *PluginsInstalledCommand) Help() string { + helpText := ` +Usage: packer plugins installed + + This command lists all installed plugin binaries that match with the current + OS and architecture. Packer's API version will be ignored. + +` + + return strings.TrimSpace(helpText) +} + +func (c *PluginsInstalledCommand) Run(args []string) int { + ctx, cleanup := handleTermInterrupt(c.Ui) + defer cleanup() + + return c.RunContext(ctx) +} + +func (c *PluginsInstalledCommand) RunContext(buildCtx context.Context) int { + + opts := plugingetter.ListInstallationsOptions{ + FromFolders: c.Meta.CoreConfig.Components.PluginConfig.KnownPluginFolders, + 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" + } + + log.Printf("[TRACE] init: %#v", opts) + + // a plugin requirement that matches them all + allPlugins := plugingetter.Requirement{ + Accessor: "", + VersionConstraints: nil, + Identifier: nil, + Implicit: false, + } + + installations, err := allPlugins.ListInstallations(opts) + if err != nil { + c.Ui.Error(err.Error()) + return 1 + } + + for _, installation := range installations { + c.Ui.Message(installation.BinaryPath) + } + + return 0 +} diff --git a/command/plugins_remove.go b/command/plugins_remove.go new file mode 100644 index 000000000..d42e92a5e --- /dev/null +++ b/command/plugins_remove.go @@ -0,0 +1,96 @@ +package command + +import ( + "context" + "crypto/sha256" + "os" + "runtime" + "strings" + + "github.com/hashicorp/go-version" + "github.com/hashicorp/packer/hcl2template/addrs" + 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 [] + + This command will remove all Packer plugins matching the version constraint + for the current OS and architecture. + When the version is omitted all installed versions will be removed. + + Ex: packer plugins remove github.com/hashicorp/happycloud v1.2.3 +` + + return strings.TrimSpace(helpText) +} + +func (c *PluginsRemoveCommand) Run(args []string) int { + ctx, cleanup := handleTermInterrupt(c.Ui) + defer cleanup() + + return c.RunContext(ctx, args) +} + +func (c *PluginsRemoveCommand) RunContext(buildCtx context.Context, args []string) int { + if len(args) < 1 || len(args) > 2 { + return cli.RunResultHelp + } + + opts := plugingetter.ListInstallationsOptions{ + FromFolders: c.Meta.CoreConfig.Components.PluginConfig.KnownPluginFolders, + BinaryInstallationOptions: plugingetter.BinaryInstallationOptions{ + OS: runtime.GOOS, + ARCH: runtime.GOARCH, + Checksummers: []plugingetter.Checksummer{ + {Type: "sha256", Hash: sha256.New()}, + }, + }, + } + + plugin, diags := addrs.ParsePluginSourceString(args[0]) + if diags.HasErrors() { + c.Ui.Error(diags.Error()) + return 1 + } + + // a plugin requirement that matches them all + pluginRequirement := plugingetter.Requirement{ + Identifier: plugin, + Implicit: false, + } + + 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 { + if err := os.Remove(installation.BinaryPath); err != nil { + c.Ui.Error(err.Error()) + return 1 + } + c.Ui.Message(installation.BinaryPath) + } + + return 0 +} diff --git a/command/plugins_required.go b/command/plugins_required.go new file mode 100644 index 000000000..f3573f1ed --- /dev/null +++ b/command/plugins_required.go @@ -0,0 +1,118 @@ +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 + + 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", 0) + 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 + } + + opts := plugingetter.ListInstallationsOptions{ + FromFolders: c.Meta.CoreConfig.Components.PluginConfig.KnownPluginFolders, + BinaryInstallationOptions: plugingetter.BinaryInstallationOptions{ + OS: runtime.GOOS, + ARCH: runtime.GOARCH, + 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 +} diff --git a/commands.go b/commands.go index 1ab629925..631b943c2 100644 --- a/commands.go +++ b/commands.go @@ -62,6 +62,36 @@ func init() { }, nil }, + "plugins": func() (cli.Command, error) { + return &command.PluginsCommand{ + Meta: *CommandMeta, + }, nil + }, + + "plugins installed": func() (cli.Command, error) { + return &command.PluginsInstalledCommand{ + Meta: *CommandMeta, + }, nil + }, + + "plugins install": func() (cli.Command, error) { + return &command.PluginsInstallCommand{ + Meta: *CommandMeta, + }, nil + }, + + "plugins remove": func() (cli.Command, error) { + return &command.PluginsRemoveCommand{ + Meta: *CommandMeta, + }, nil + }, + + "plugins required": func() (cli.Command, error) { + return &command.PluginsRequiredCommand{ + Meta: *CommandMeta, + }, nil + }, + "validate": func() (cli.Command, error) { return &command.ValidateCommand{ Meta: *CommandMeta, diff --git a/packer/plugin-getter/plugins.go b/packer/plugin-getter/plugins.go index bae24099b..98842e3a4 100644 --- a/packer/plugin-getter/plugins.go +++ b/packer/plugin-getter/plugins.go @@ -83,6 +83,9 @@ func (rlerr *RateLimitError) Error() string { } func (pr Requirement) FilenamePrefix() string { + if pr.Identifier == nil { + return "packer-plugin-" + } return "packer-plugin-" + pr.Identifier.Type + "_" } @@ -104,7 +107,12 @@ func (pr Requirement) ListInstallations(opts ListInstallationsOptions) (InstallL filenameSuffix := opts.filenameSuffix() log.Printf("[TRACE] listing potential installations for %q that match %q. %#v", pr.Identifier, pr.VersionConstraints, opts) for _, knownFolder := range opts.FromFolders { - glob := filepath.Join(knownFolder, pr.Identifier.Hostname, pr.Identifier.Namespace, pr.Identifier.Type, FilenamePrefix+"*"+filenameSuffix) + glob := "" + if pr.Identifier == nil { + glob = filepath.Join(knownFolder, "*", "*", "*", FilenamePrefix+"*"+filenameSuffix) + } else { + glob = filepath.Join(knownFolder, pr.Identifier.Hostname, pr.Identifier.Namespace, pr.Identifier.Type, FilenamePrefix+"*"+filenameSuffix) + } matches, err := filepath.Glob(glob) if err != nil { @@ -120,7 +128,13 @@ func (pr Requirement) ListInstallations(opts ListInstallationsOptions) (InstallL versionsStr := strings.TrimPrefix(fname, FilenamePrefix) versionsStr = strings.TrimSuffix(versionsStr, filenameSuffix) - // versionsStr now looks like v1.2.3_x5.1 + if pr.Identifier == nil { + if idx := strings.Index(versionsStr, "_"); idx > 0 { + versionsStr = versionsStr[idx+1:] + } + } + + // versionsStr now looks like v1.2.3_x5.1 or amazon_v1.2.3_x5.1 parts := strings.SplitN(versionsStr, "_", 2) pluginVersionStr, protocolVerionStr := parts[0], parts[1] pv, err := version.NewVersion(pluginVersionStr) @@ -131,7 +145,7 @@ func (pr Requirement) ListInstallations(opts ListInstallationsOptions) (InstallL } // no constraint means always pass, this will happen for implicit - // plugin requirements + // plugin requirements and when we list all plugins. if !pr.VersionConstraints.Check(pv) { log.Printf("[TRACE] version %q of file %q does not match constraint %q", pluginVersionStr, path, pr.VersionConstraints.String()) continue @@ -258,6 +272,11 @@ func (binOpts *BinaryInstallationOptions) CheckProtocolVersion(remoteProt string } vMajor, vMinor := parts[0], parts[1] + // no protocol version check + if binOpts.APIVersionMajor == "" && binOpts.APIVersionMinor == "" { + return nil + } + if vMajor != binOpts.APIVersionMajor { return fmt.Errorf("Unsupported remote protocol MAJOR version %q. The current MAJOR protocol version is %q."+ " This version of Packer can only communicate with plugins using that version.", vMajor, binOpts.APIVersionMajor) diff --git a/packer/plugin-getter/plugins_test.go b/packer/plugin-getter/plugins_test.go index fcd0a18d5..1e3fbe0b7 100644 --- a/packer/plugin-getter/plugins_test.go +++ b/packer/plugin-getter/plugins_test.go @@ -16,6 +16,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/go-version" + "github.com/hashicorp/hcl/v2" "github.com/hashicorp/packer/hcl2template/addrs" ) @@ -66,6 +67,61 @@ func TestPlugin_ListInstallations(t *testing.T) { wantErr bool want InstallList }{ + + { + "windows_all_plugins", + fields{ + // empty + }, + ListInstallationsOptions{ + []string{ + pluginFolderOne, + pluginFolderTwo, + }, + BinaryInstallationOptions{ + OS: "windows", ARCH: "amd64", + Ext: ".exe", + Checksummers: []Checksummer{ + { + Type: "sha256", + Hash: sha256.New(), + }, + }, + }, + }, + false, + []*Installation{ + { + Version: "v1.2.3", + BinaryPath: filepath.Join(pluginFolderOne, "github.com", "hashicorp", "amazon", "packer-plugin-amazon_v1.2.3_x5.0_windows_amd64.exe"), + }, + { + Version: "v1.2.4", + BinaryPath: filepath.Join(pluginFolderOne, "github.com", "hashicorp", "amazon", "packer-plugin-amazon_v1.2.4_x5.0_windows_amd64.exe"), + }, + { + Version: "v1.2.5", + BinaryPath: filepath.Join(pluginFolderOne, "github.com", "hashicorp", "amazon", "packer-plugin-amazon_v1.2.5_x5.0_windows_amd64.exe"), + }, + { + BinaryPath: filepath.Join(pluginFolderOne, "github.com", "hashicorp", "google", "packer-plugin-google_v4.5.6_x5.0_windows_amd64.exe"), + Version: "v4.5.6", + }, + { + Version: "v4.5.7", + BinaryPath: filepath.Join(pluginFolderOne, "github.com", "hashicorp", "google", "packer-plugin-google_v4.5.7_x5.0_windows_amd64.exe"), + }, + { + Version: "v4.5.8", + BinaryPath: filepath.Join(pluginFolderOne, "github.com", "hashicorp", "google", "packer-plugin-google_v4.5.8_x5.0_windows_amd64.exe"), + }, + { + Version: "v4.5.9", + BinaryPath: filepath.Join(pluginFolderTwo, "github.com", "hashicorp", "google", "packer-plugin-google_v4.5.9_x5.0_windows_amd64.exe"), + }, + }, + }, + { "darwin_amazon_prot_5.0", fields{ @@ -227,9 +283,13 @@ func TestPlugin_ListInstallations(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - identifier, diags := addrs.ParsePluginSourceString(tt.fields.Identifier) - if diags.HasErrors() { - t.Fatalf("%v", diags) + var identifier *addrs.Plugin + if tt.fields.Identifier != "" { + var diags hcl.Diagnostics + identifier, diags = addrs.ParsePluginSourceString(tt.fields.Identifier) + if diags.HasErrors() { + t.Fatalf("%v", diags) + } } p := Requirement{ Identifier: identifier, diff --git a/website/content/docs/commands/plugins/index.mdx b/website/content/docs/commands/plugins/index.mdx new file mode 100644 index 000000000..382b791fd --- /dev/null +++ b/website/content/docs/commands/plugins/index.mdx @@ -0,0 +1,30 @@ +--- +description: | + The "plugin" command groups subcommands for interacting with + Packer's plugin and the plugin catalog. +page_title: plugins Command +--- + +# `plugins` + +The `plugins` command groups subcommands for interacting with Packers' plugins. + +```shell-session +$ packer plugins -h +Usage: packer plugins [options] [args] + This command groups subcommands for interacting with Packer plugins. + +Related but not under the "plugins" command : + +- "packer init " will install all plugins required by a config. + +Subcommands: + install Install latest Packer plugin [matching version constraint] + installed List all installed Packer plugin binaries + remove Remove Packer plugins [matching a version] + required List plugins required by a config +``` + +## Related + +- [`packer init`](/docs/commands/init) will install all required plugins. diff --git a/website/content/docs/commands/plugins/install.mdx b/website/content/docs/commands/plugins/install.mdx new file mode 100644 index 000000000..b5a931458 --- /dev/null +++ b/website/content/docs/commands/plugins/install.mdx @@ -0,0 +1,24 @@ +--- +description: | + The "plugins install" command can install a plugin at a version constraint. +page_title: plugins Command +--- + +# `plugins install` + +The `plugins install` subcommand installs a Packer plugin at a version constraint + +```shell-session +$ packer plugins install -h +Usage: packer plugins install [] + + This command will install the most recent compatible Packer plugin matching + version constraint. When the version constraint is omitted, the most recent + version will be installed. + + Ex: packer plugins install github.com/hashicorp/happycloud v1.2.3 +``` + +## Related + +- [`packer init`](/docs/commands/init) will install all required plugins. diff --git a/website/content/docs/commands/plugins/installed.mdx b/website/content/docs/commands/plugins/installed.mdx new file mode 100644 index 000000000..2b0b330c2 --- /dev/null +++ b/website/content/docs/commands/plugins/installed.mdx @@ -0,0 +1,21 @@ +--- +description: | + The "plugins installed" command will list installed plugins. +page_title: plugins Command +--- + +# `plugins installed` + +The `plugins installed` subcommand lists installed Packer plugins + +```shell-session +$ packer plugins installed -h +Usage: packer plugins installed + + This command lists all installed plugin binaries that match with the current + OS and architecture. Packer's API version will be ignored. +``` + +## Related + +- [`packer init`](/docs/commands/init) will install all required plugins. diff --git a/website/content/docs/commands/plugins/remove.mdx b/website/content/docs/commands/plugins/remove.mdx new file mode 100644 index 000000000..8887df511 --- /dev/null +++ b/website/content/docs/commands/plugins/remove.mdx @@ -0,0 +1,24 @@ +--- +description: | + The "plugins remove" command can remove a plugin at a version constraint. +page_title: plugins Command +--- + +# `plugins remove` + +The `plugins remove` subcommand removes a Packer plugin at a version constraint + +```shell-session +$ packer plugins remove -h +Usage: packer plugins remove [] + + This command will remove all Packer plugins matching the version constraint + for the current OS and architecture. + When the version is omitted all installed versions will be removed. + + Ex: packer plugins remove github.com/hashicorp/happycloud v1.2.3 +``` + +## Related + +- [`packer init`](/docs/commands/init) will install all required plugins. diff --git a/website/content/docs/commands/plugins/required.mdx b/website/content/docs/commands/plugins/required.mdx new file mode 100644 index 000000000..25b16a64d --- /dev/null +++ b/website/content/docs/commands/plugins/required.mdx @@ -0,0 +1,30 @@ +--- +description: | + The "plugins required" command lists all plugins required in a Packer configuration. +page_title: plugins Command +--- + +# `plugins required` + +The `plugins required` command lists all plugins required by a Packer config and +all the installed binaries that match the constraint. The first binary +is the most up-to-date installed version and will be the one picked by Packer in a build. + +```shell-session +$ packer plugins required -h +Usage: packer plugins required + + 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/ +``` + +## Related + +- [`packer init`](/docs/commands/init) will install all required plugins. diff --git a/website/data/docs-nav-data.json b/website/data/docs-nav-data.json index b131d274c..366a26e15 100644 --- a/website/data/docs-nav-data.json +++ b/website/data/docs-nav-data.json @@ -17,6 +17,31 @@ "title": "init", "path": "commands/init" }, + { + "title": "plugins", + "routes": [ + { + "title": "Overview", + "path": "commands/plugins" + }, + { + "title": "install", + "path": "commands/plugins/install" + }, + { + "title": "installed", + "path": "commands/plugins/installed" + }, + { + "title": "remove", + "path": "commands/plugins/remove" + }, + { + "title": "required", + "path": "commands/plugins/required" + } + ] + }, { "title": "build", "path": "commands/build"