diff --git a/builtin/configvagrant/main.go b/builtin/configvagrant/main.go index a264e6832..b69b92968 100644 --- a/builtin/configvagrant/main.go +++ b/builtin/configvagrant/main.go @@ -2,6 +2,7 @@ package configvagrant import ( "fmt" + "github.com/hashicorp/go-hclog" sdk "github.com/hashicorp/vagrant-plugin-sdk" "github.com/hashicorp/vagrant-plugin-sdk/component" @@ -12,8 +13,8 @@ import ( var CommandOptions = []sdk.Option{ sdk.WithComponents( &Config{}, - &Command{}, ), + sdk.WithComponent(&Command{}, &component.CommandOptions{Primary: false}), sdk.WithName("configvagrant"), } diff --git a/builtin/myplugin/main.go b/builtin/myplugin/main.go index 918f601a4..37158d69c 100644 --- a/builtin/myplugin/main.go +++ b/builtin/myplugin/main.go @@ -19,11 +19,14 @@ import ( var CommandOptions = []sdk.Option{ sdk.WithComponents( // &Provider{}, - &command.Command{}, &host.AlwaysTrueHost{}, &communicator.DummyCommunicator{}, &push.Encouragement{}, ), + sdk.WithComponent(&command.Command{}, &component.CommandOptions{ + // Should keep the plugin out of the default help output + Primary: false, + }), sdk.WithComponent(&provider.Happy{}, &component.ProviderOptions{ Priority: 100, }), diff --git a/builtin/otherplugin/main.go b/builtin/otherplugin/main.go index 4ff54e447..b92963a9f 100644 --- a/builtin/otherplugin/main.go +++ b/builtin/otherplugin/main.go @@ -2,13 +2,17 @@ package otherplugin import ( sdk "github.com/hashicorp/vagrant-plugin-sdk" + "github.com/hashicorp/vagrant-plugin-sdk/component" "github.com/hashicorp/vagrant/builtin/otherplugin/guest" ) var CommandOptions = []sdk.Option{ sdk.WithComponents( - &Command{}, &guest.AlwaysTrueGuest{}, ), + sdk.WithComponent(&Command{}, &component.CommandOptions{ + // Hide command from default help output + Primary: false, + }), sdk.WithName("otherplugin"), } diff --git a/internal/cli/dynamic.go b/internal/cli/dynamic.go index d787d14af..679c74246 100644 --- a/internal/cli/dynamic.go +++ b/internal/cli/dynamic.go @@ -22,6 +22,7 @@ type DynamicCommand struct { help string parent *DynamicCommand flags []*component.CommandFlag + primary bool } func (c *DynamicCommand) Run(args []string) int { @@ -154,6 +155,10 @@ func (c *DynamicCommand) Flags() component.CommandFlags { }) } +func (c *DynamicCommand) Primary() bool { + return c.primary +} + func (c *DynamicCommand) fullName() string { var v string if c.parent != nil { diff --git a/internal/cli/main.go b/internal/cli/main.go index 8e0a64d10..a7d1d6036 100644 --- a/internal/cli/main.go +++ b/internal/cli/main.go @@ -224,6 +224,7 @@ func registerCommand( synopsis: c.Synopsis, help: c.Help, flags: flgs, + primary: c.Primary, } if parent != nil { d.parent = parent @@ -399,10 +400,13 @@ func GroupedHelpFunc(f cli.HelpFunc) cli.HelpFunc { ).Row()) d.Append(glint.Text("")) - // Add common commands + // First add hand-picked common commands helpCommandsSection(d, "Common commands", commonCommands, commands) - // Make our other commands + // Make our list of other commands by + // - skipping common commands we just printed + // - skipping hand-picked hidden commands + // - skipping commands that set CommandOptions.Primary to false ignoreMap := map[string]struct{}{} for k := range hiddenCommands { ignoreMap[k] = struct{}{} @@ -411,6 +415,16 @@ func GroupedHelpFunc(f cli.HelpFunc) cli.HelpFunc { ignoreMap[k] = struct{}{} } + for k, cmdFn := range commands { + cmd, err := cmdFn() + if err != nil { + panic(fmt.Sprintf("failed to load %q command: %s", k, err)) + } + if pc, ok := cmd.(Primaryable); ok && pc.Primary() == false { + ignoreMap[k] = struct{}{} + } + } + var otherCommands []string for k := range commands { if _, ok := ignoreMap[k]; ok { @@ -464,4 +478,8 @@ func helpCommandsSection( ).PaddingLeft(2)) } +type Primaryable interface { + Primary() bool +} + var helpText = map[string][2]string{} diff --git a/internal/cli/plugin.go b/internal/cli/plugin.go index 124db59bb..9af1603a1 100644 --- a/internal/cli/plugin.go +++ b/internal/cli/plugin.go @@ -1,14 +1,18 @@ package cli import ( + sdk "github.com/hashicorp/vagrant-plugin-sdk" "github.com/hashicorp/vagrant/internal/plugin" - "github.com/hashicorp/vagrant-plugin-sdk" ) type PluginCommand struct { *baseCommand } +func (c *PluginCommand) Primary() bool { + return false +} + func (c *PluginCommand) Run(args []string) int { plugin, ok := plugin.Builtins[args[0]] if !ok { diff --git a/internal/cli/ui.go b/internal/cli/ui.go index bee6447f0..f9b388443 100644 --- a/internal/cli/ui.go +++ b/internal/cli/ui.go @@ -99,6 +99,10 @@ func (c *UICommand) Flags() component.CommandFlags { }) } +func (c *UICommand) Primary() bool { + return true +} + // func (c *UICommand) AutocompleteArgs() complete.Predictor { // return complete.PredictNothing // } diff --git a/internal/cli/version.go b/internal/cli/version.go index 0d41a3057..ea80ae7f4 100644 --- a/internal/cli/version.go +++ b/internal/cli/version.go @@ -34,6 +34,10 @@ func (c *VersionCommand) Flags() component.CommandFlags { return c.flagSet(0, nil) } +func (c *VersionCommand) Primary() bool { + return true +} + // func (c *VersionCommand) AutocompleteArgs() complete.Predictor { // return complete.PredictNothing // } diff --git a/internal/core/basis.go b/internal/core/basis.go index 30458afee..6133a8e11 100644 --- a/internal/core/basis.go +++ b/internal/core/basis.go @@ -589,17 +589,21 @@ func (b *Basis) RunInit() (result *vagrant_server.Job_InitResult, err error) { for _, c := range cmds { fn := c.Value.(component.Command).CommandInfoFunc() + // See core.JobCommandProto raw, err := b.callDynamicFunc(ctx, b.logger, fn, (*[]*vagrant_plugin_sdk.Command_CommandInfo)(nil), argmapper.Typed(b.ctx), ) - if err != nil { return nil, err } - result.Commands = append(result.Commands, - raw.([]*vagrant_plugin_sdk.Command_CommandInfo)...) + // Primary comes from plugin options so add that to CommandInfo here + cinfos := raw.([]*vagrant_plugin_sdk.Command_CommandInfo) + copts := c.Options.(*component.CommandOptions) + cinfos[0].Primary = copts.Primary + + result.Commands = append(result.Commands, cinfos...) } return @@ -750,6 +754,7 @@ func (b *Basis) component( Name: name, ServerAddr: b.Client().ServerTarget(), }, + Options: c.Options, hooks: hooks, mappers: append(b.mappers, c.Mappers...), plugin: c, diff --git a/internal/core/component_creator.go b/internal/core/component_creator.go index b414e6cff..6f529a2be 100644 --- a/internal/core/component_creator.go +++ b/internal/core/component_creator.go @@ -12,6 +12,9 @@ type Component struct { Value interface{} Info *vagrant_server.Component + // Options for component type, see PluginInfo.ComponentOptions + Options interface{} + // These fields can be accessed internally hooks map[string][]*config.Hook labels map[string]string diff --git a/internal/core/mappers.go b/internal/core/mappers.go index 365e92ecc..621fc46db 100644 --- a/internal/core/mappers.go +++ b/internal/core/mappers.go @@ -12,6 +12,7 @@ var Mappers = []interface{}{ JobCommandProto, } +// JobCommandProto converts a CommandInfo into its proto equivalent func JobCommandProto(c *component.CommandInfo) []*vagrant_plugin_sdk.Command_CommandInfo { return jobCommandProto(c, []string{}) } diff --git a/lib/vagrant/plugin/remote/manager.rb b/lib/vagrant/plugin/remote/manager.rb index e5aab53e1..7bf0fa8e5 100644 --- a/lib/vagrant/plugin/remote/manager.rb +++ b/lib/vagrant/plugin/remote/manager.rb @@ -179,8 +179,7 @@ module Vagrant sf_class.plugin_name = plg[:name] sf_class.type = plg[:type] result.register(plg[:name].to_sym) do - # TODO(phinze): wire through CommandOptions and return them here - [proc{sf_class}, {}] + [proc{sf_class}, plg[:options]] end end end diff --git a/lib/vagrant/protobufs/proto/vagrant_plugin_sdk/plugin_pb.rb b/lib/vagrant/protobufs/proto/vagrant_plugin_sdk/plugin_pb.rb index 49753288e..13acc1654 100644 --- a/lib/vagrant/protobufs/proto/vagrant_plugin_sdk/plugin_pb.rb +++ b/lib/vagrant/protobufs/proto/vagrant_plugin_sdk/plugin_pb.rb @@ -436,6 +436,9 @@ Google::Protobuf::DescriptorPool.generated_pool.build do add_message "hashicorp.vagrant.sdk.PluginInfo.ComponentOptionsMap" do map :options, :uint32, :message, 1, "google.protobuf.Any" end + add_message "hashicorp.vagrant.sdk.PluginInfo.CommandOptions" do + optional :primary, :bool, 1 + end add_message "hashicorp.vagrant.sdk.PluginInfo.ProviderOptions" do optional :priority, :int32, 1 optional :parallel, :bool, 2 @@ -499,6 +502,7 @@ Google::Protobuf::DescriptorPool.generated_pool.build do optional :synopsis, :string, 3 repeated :flags, :message, 4, "hashicorp.vagrant.sdk.Command.Flag" repeated :subcommands, :message, 5, "hashicorp.vagrant.sdk.Command.CommandInfo" + optional :primary, :bool, 6 end add_message "hashicorp.vagrant.sdk.Command.CommandInfoResp" do optional :command_info, :message, 1, "hashicorp.vagrant.sdk.Command.CommandInfo" @@ -1120,6 +1124,7 @@ module Hashicorp PluginInfo::ComponentList = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.PluginInfo.ComponentList").msgclass PluginInfo::Name = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.PluginInfo.Name").msgclass PluginInfo::ComponentOptionsMap = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.PluginInfo.ComponentOptionsMap").msgclass + PluginInfo::CommandOptions = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.PluginInfo.CommandOptions").msgclass PluginInfo::ProviderOptions = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.PluginInfo.ProviderOptions").msgclass PluginInfo::SyncedFolderOptions = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.PluginInfo.SyncedFolderOptions").msgclass PluginManager = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.PluginManager").msgclass diff --git a/plugins/commands/serve/client/plugin_manager.rb b/plugins/commands/serve/client/plugin_manager.rb index 20c96a42b..af3f6843f 100644 --- a/plugins/commands/serve/client/plugin_manager.rb +++ b/plugins/commands/serve/client/plugin_manager.rb @@ -40,6 +40,8 @@ module VagrantPlugins return {} if plg_opts.nil? opts = mapper.unany(plg_opts) case opts + when Hashicorp::Vagrant::Sdk::PluginInfo::CommandOptions + opts.to_h when Hashicorp::Vagrant::Sdk::PluginInfo::ProviderOptions opts.to_h when Hashicorp::Vagrant::Sdk::PluginInfo::SyncedFolderOptions diff --git a/plugins/commands/serve/mappers/command.rb b/plugins/commands/serve/mappers/command.rb index 7555c448c..efc179905 100644 --- a/plugins/commands/serve/mappers/command.rb +++ b/plugins/commands/serve/mappers/command.rb @@ -102,6 +102,7 @@ module VagrantPlugins synopsis: info.synopsis, flags: flags, subcommands: subcommands, + primary: info.primary, ) end end diff --git a/plugins/commands/serve/service/command_service.rb b/plugins/commands/serve/service/command_service.rb index b0af10d41..bffd64af5 100644 --- a/plugins/commands/serve/service/command_service.rb +++ b/plugins/commands/serve/service/command_service.rb @@ -149,12 +149,15 @@ module VagrantPlugins end subcommands = get_subcommands(plugin_name, subcommand_names) + opts = Vagrant.plugin("2").local_manager.commands[plugin_name.to_sym].last + SDK::Command::CommandInfo.new( name: command_name, help: hlp_msg, flags: flags, synopsis: synopsis, - subcommands: subcommands + subcommands: subcommands, + primary: opts[:primary], ) end diff --git a/plugins/commands/serve/service/internal_service.rb b/plugins/commands/serve/service/internal_service.rb index 43f05cd50..4b32ddad7 100644 --- a/plugins/commands/serve/service/internal_service.rb +++ b/plugins/commands/serve/service/internal_service.rb @@ -124,8 +124,11 @@ module VagrantPlugins def _convert_options_to_proto(type, class_or_tuple_with_class_and_options) case type when :COMMAND - # _, command_options = class_or_tuple_with_class_and_options - return Google::Protobuf::Empty.new + _, opts = class_or_tuple_with_class_and_options + return SDK::PluginInfo::CommandOptions.new( + # Primary is always set in V2::Plugin.command + primary: opts[:primary], + ) when :COMMUNICATOR # No options for communicators return Google::Protobuf::Empty.new diff --git a/plugins/commands/serve/type/command_info.rb b/plugins/commands/serve/type/command_info.rb index 98390cbe0..f153cba02 100644 --- a/plugins/commands/serve/type/command_info.rb +++ b/plugins/commands/serve/type/command_info.rb @@ -25,14 +25,16 @@ module VagrantPlugins :help, :synopsis, :flags, - :subcommands + :subcommands, + :primary - def initialize(name:, help:, synopsis: nil, subcommands: []) + def initialize(name:, help:, synopsis: nil, subcommands: [], primary:) @name = name.to_s @help = help.to_s @synopsis = synopsis.to_s @subcommands = Array(subcommands) @flags = [] + @primary = primary end def add_flag(**kwargs) diff --git a/plugins/commands/serve/util/direct_conversions.rb b/plugins/commands/serve/util/direct_conversions.rb index d13c9a44f..9dd9fb7c2 100644 --- a/plugins/commands/serve/util/direct_conversions.rb +++ b/plugins/commands/serve/util/direct_conversions.rb @@ -200,6 +200,7 @@ class VagrantPlugins::CommandServe::Type::CommandInfo synopsis: info.synopsis, flags: flags, subcommands: subcommands, + primary: info.primary, ) end end @@ -641,6 +642,7 @@ class Hashicorp::Vagrant::Sdk::Command::CommandInfo name: name, help: help, synopsis: synopsis, + primary: primary, ).tap do |c| flags.each do |f| c.add_flag(