From b23dda54b806c1a7ce15182123b68ce9cab0b2aa Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 26 Jun 2012 16:18:02 -0700 Subject: [PATCH] Move command base class to a plugin component --- lib/vagrant.rb | 5 +- lib/vagrant/cli.rb | 2 +- lib/vagrant/command.rb | 169 ------------------ lib/vagrant/easy/command_base.rb | 2 +- lib/vagrant/plugin/v1.rb | 1 + lib/vagrant/plugin/v1/command.rb | 169 ++++++++++++++++++ plugins/commands/box/command/add.rb | 2 +- plugins/commands/box/command/list.rb | 2 +- plugins/commands/box/command/remove.rb | 2 +- plugins/commands/box/command/repackage.rb | 2 +- plugins/commands/box/command/root.rb | 2 +- plugins/commands/destroy/command.rb | 2 +- plugins/commands/gem/command.rb | 2 +- plugins/commands/halt/command.rb | 2 +- plugins/commands/init/command.rb | 2 +- plugins/commands/package/command.rb | 2 +- plugins/commands/provision/command.rb | 2 +- plugins/commands/reload/command.rb | 2 +- plugins/commands/resume/command.rb | 2 +- plugins/commands/ssh/command.rb | 2 +- plugins/commands/ssh_config/command.rb | 2 +- plugins/commands/status/command.rb | 2 +- plugins/commands/suspend/command.rb | 2 +- plugins/commands/up/command.rb | 2 +- .../v1/command_test.rb} | 4 +- test/unit/vagrant_test.rb | 1 + 26 files changed, 196 insertions(+), 193 deletions(-) delete mode 100644 lib/vagrant/command.rb create mode 100644 lib/vagrant/plugin/v1/command.rb rename test/unit/vagrant/{command/base_test.rb => plugin/v1/command_test.rb} (97%) diff --git a/lib/vagrant.rb b/lib/vagrant.rb index 3e78f93ca..8b18de499 100644 --- a/lib/vagrant.rb +++ b/lib/vagrant.rb @@ -86,8 +86,9 @@ module Vagrant # These are the various plugin versions and their components in # a lazy loaded Hash-like structure. c = PLUGIN_COMPONENTS = Registry.new - c.register(:"1") { Plugin::V1::Plugin } - c.register([:"1", :config]) { Plugin::V1::Config } + c.register(:"1") { Plugin::V1::Plugin } + c.register([:"1", :command]) { Plugin::V1::Command } + c.register([:"1", :config]) { Plugin::V1::Config } c.register([:"1", :provisioner]) { Plugin::V1::Provisioner } # Returns a `Vagrant::Registry` object that contains all the built-in diff --git a/lib/vagrant/cli.rb b/lib/vagrant/cli.rb index 1c1f5126d..e5616b967 100644 --- a/lib/vagrant/cli.rb +++ b/lib/vagrant/cli.rb @@ -3,7 +3,7 @@ require 'optparse' module Vagrant # Manages the command line interface to Vagrant. - class CLI < Command::Base + class CLI < Vagrant.plugin("1", :command) def initialize(argv, env) super diff --git a/lib/vagrant/command.rb b/lib/vagrant/command.rb deleted file mode 100644 index 065cefd34..000000000 --- a/lib/vagrant/command.rb +++ /dev/null @@ -1,169 +0,0 @@ -require 'log4r' - -require "vagrant/util/safe_puts" - -module Vagrant - module Command - # Base class for any CLI commands. - # - # This class provides documentation on the interface as well as helper - # functions that a command has. - class Base - include Util::SafePuts - - def initialize(argv, env) - @argv = argv - @env = env - @logger = Log4r::Logger.new("vagrant::command::#{self.class.to_s.downcase}") - end - - # This is what is called on the class to actually execute it. Any - # subclasses should implement this method and do any option parsing - # and validation here. - def execute; end - - protected - - # Parses the options given an OptionParser instance. - # - # This is a convenience method that properly handles duping the - # originally argv array so that it is not destroyed. - # - # This method will also automatically detect "-h" and "--help" - # and print help. And if any invalid options are detected, the help - # will be printed, as well. - # - # If this method returns `nil`, then you should assume that help - # was printed and parsing failed. - def parse_options(opts=nil) - # Creating a shallow copy of the arguments so the OptionParser - # doesn't destroy the originals. - argv = @argv.dup - - # Default opts to a blank optionparser if none is given - opts ||= OptionParser.new - - # Add the help option, which must be on every command. - opts.on_tail("-h", "--help", "Print this help") do - safe_puts(opts.help) - return nil - end - - opts.parse!(argv) - return argv - rescue OptionParser::InvalidOption - raise Errors::CLIInvalidOptions, :help => opts.help.chomp - end - - # Yields a VM for each target VM for the command. - # - # This is a convenience method for easily implementing methods that - # take a target VM (in the case of multi-VM) or every VM if no - # specific VM name is specified. - # - # @param [String] name The name of the VM. Nil if every VM. - # @param [Boolean] single_target If true, then an exception will be - # raised if more than one target is found. - def with_target_vms(names=nil, options=nil) - # Using VMs requires a Vagrant environment to be properly setup - raise Errors::NoEnvironmentError if !@env.root_path - - # Setup the options hash - options ||= {} - - # Require that names be an array - names ||= [] - names = [names] if !names.is_a?(Array) - - # First determine the proper array of VMs. - vms = [] - if names.length > 0 - names.each do |name| - if pattern = name[/^\/(.+?)\/$/, 1] - # This is a regular expression name, so we convert to a regular - # expression and allow that sort of matching. - regex = Regexp.new(pattern) - - @env.vms.each do |name, vm| - vms << vm if name =~ regex - end - - raise Errors::VMNoMatchError if vms.empty? - else - # String name, just look for a specific VM - vms << @env.vms[name.to_sym] - raise Errors::VMNotFoundError, :name => name if !vms[0] - end - end - else - vms = @env.vms_ordered - end - - # Make sure we're only working with one VM if single target - if options[:single_target] && vms.length != 1 - vm = @env.primary_vm - raise Errors::MultiVMTargetRequired if !vm - vms = [vm] - end - - # If we asked for reversed ordering, then reverse it - vms.reverse! if options[:reverse] - - # Go through each VM and yield it! - vms.each do |old_vm| - # We get a new VM from the environment here to avoid potentially - # stale VMs (if there was a config reload on the environment - # or something). - vm = @env.vms[old_vm.name] - yield vm - end - end - - # This method will split the argv given into three parts: the - # flags to this command, the subcommand, and the flags to the - # subcommand. For example: - # - # -v status -h -v - # - # The above would yield 3 parts: - # - # ["-v"] - # "status" - # ["-h", "-v"] - # - # These parts are useful because the first is a list of arguments - # given to the current command, the second is a subcommand, and the - # third are the commands given to the subcommand. - # - # @return [Array] The three parts. - def split_main_and_subcommand(argv) - # Initialize return variables - main_args = nil - sub_command = nil - sub_args = [] - - # We split the arguments into two: One set containing any - # flags before a word, and then the rest. The rest are what - # get actually sent on to the subcommand. - argv.each_index do |i| - if !argv[i].start_with?("-") - # We found the beginning of the sub command. Split the - # args up. - main_args = argv[0, i] - sub_command = argv[i] - sub_args = argv[i + 1, argv.length - i + 1] - - # Break so we don't find the next non flag and shift our - # main args. - break - end - end - - # Handle the case that argv was empty or didn't contain any subcommand - main_args = argv.dup if main_args.nil? - - return [main_args, sub_command, sub_args] - end - end - end -end diff --git a/lib/vagrant/easy/command_base.rb b/lib/vagrant/easy/command_base.rb index 0df8de78c..4bafe0562 100644 --- a/lib/vagrant/easy/command_base.rb +++ b/lib/vagrant/easy/command_base.rb @@ -4,7 +4,7 @@ module Vagrant module Easy # Base class for all easy commands. This contains the basic code # that knows how to run the easy commands. - class CommandBase < Vagrant::Command::Base + class CommandBase < Vagrant.plugin("1", :command) # This is the command that this easy command responds to attr_reader :command diff --git a/lib/vagrant/plugin/v1.rb b/lib/vagrant/plugin/v1.rb index 1aab6c5a3..595dcd6e3 100644 --- a/lib/vagrant/plugin/v1.rb +++ b/lib/vagrant/plugin/v1.rb @@ -5,6 +5,7 @@ require "vagrant/plugin/v1/errors" module Vagrant module Plugin module V1 + autoload :Command, "vagrant/plugin/v1/command" autoload :Config, "vagrant/plugin/v1/config" autoload :Plugin, "vagrant/plugin/v1/plugin" autoload :Provisioner, "vagrant/plugin/v1/provisioner" diff --git a/lib/vagrant/plugin/v1/command.rb b/lib/vagrant/plugin/v1/command.rb new file mode 100644 index 000000000..e40e9077d --- /dev/null +++ b/lib/vagrant/plugin/v1/command.rb @@ -0,0 +1,169 @@ +require 'log4r' + +require "vagrant/util/safe_puts" + +module Vagrant + module Plugin + module V1 + # This is the base class for a CLI command. + class Command + include Util::SafePuts + + def initialize(argv, env) + @argv = argv + @env = env + @logger = Log4r::Logger.new("vagrant::command::#{self.class.to_s.downcase}") + end + + # This is what is called on the class to actually execute it. Any + # subclasses should implement this method and do any option parsing + # and validation here. + def execute + end + + protected + + # Parses the options given an OptionParser instance. + # + # This is a convenience method that properly handles duping the + # originally argv array so that it is not destroyed. + # + # This method will also automatically detect "-h" and "--help" + # and print help. And if any invalid options are detected, the help + # will be printed, as well. + # + # If this method returns `nil`, then you should assume that help + # was printed and parsing failed. + def parse_options(opts=nil) + # Creating a shallow copy of the arguments so the OptionParser + # doesn't destroy the originals. + argv = @argv.dup + + # Default opts to a blank optionparser if none is given + opts ||= OptionParser.new + + # Add the help option, which must be on every command. + opts.on_tail("-h", "--help", "Print this help") do + safe_puts(opts.help) + return nil + end + + opts.parse!(argv) + return argv + rescue OptionParser::InvalidOption + raise Errors::CLIInvalidOptions, :help => opts.help.chomp + end + + # Yields a VM for each target VM for the command. + # + # This is a convenience method for easily implementing methods that + # take a target VM (in the case of multi-VM) or every VM if no + # specific VM name is specified. + # + # @param [String] name The name of the VM. Nil if every VM. + # @param [Boolean] single_target If true, then an exception will be + # raised if more than one target is found. + def with_target_vms(names=nil, options=nil) + # Using VMs requires a Vagrant environment to be properly setup + raise Errors::NoEnvironmentError if !@env.root_path + + # Setup the options hash + options ||= {} + + # Require that names be an array + names ||= [] + names = [names] if !names.is_a?(Array) + + # First determine the proper array of VMs. + vms = [] + if names.length > 0 + names.each do |name| + if pattern = name[/^\/(.+?)\/$/, 1] + # This is a regular expression name, so we convert to a regular + # expression and allow that sort of matching. + regex = Regexp.new(pattern) + + @env.vms.each do |name, vm| + vms << vm if name =~ regex + end + + raise Errors::VMNoMatchError if vms.empty? + else + # String name, just look for a specific VM + vms << @env.vms[name.to_sym] + raise Errors::VMNotFoundError, :name => name if !vms[0] + end + end + else + vms = @env.vms_ordered + end + + # Make sure we're only working with one VM if single target + if options[:single_target] && vms.length != 1 + vm = @env.primary_vm + raise Errors::MultiVMTargetRequired if !vm + vms = [vm] + end + + # If we asked for reversed ordering, then reverse it + vms.reverse! if options[:reverse] + + # Go through each VM and yield it! + vms.each do |old_vm| + # We get a new VM from the environment here to avoid potentially + # stale VMs (if there was a config reload on the environment + # or something). + vm = @env.vms[old_vm.name] + yield vm + end + end + + # This method will split the argv given into three parts: the + # flags to this command, the subcommand, and the flags to the + # subcommand. For example: + # + # -v status -h -v + # + # The above would yield 3 parts: + # + # ["-v"] + # "status" + # ["-h", "-v"] + # + # These parts are useful because the first is a list of arguments + # given to the current command, the second is a subcommand, and the + # third are the commands given to the subcommand. + # + # @return [Array] The three parts. + def split_main_and_subcommand(argv) + # Initialize return variables + main_args = nil + sub_command = nil + sub_args = [] + + # We split the arguments into two: One set containing any + # flags before a word, and then the rest. The rest are what + # get actually sent on to the subcommand. + argv.each_index do |i| + if !argv[i].start_with?("-") + # We found the beginning of the sub command. Split the + # args up. + main_args = argv[0, i] + sub_command = argv[i] + sub_args = argv[i + 1, argv.length - i + 1] + + # Break so we don't find the next non flag and shift our + # main args. + break + end + end + + # Handle the case that argv was empty or didn't contain any subcommand + main_args = argv.dup if main_args.nil? + + return [main_args, sub_command, sub_args] + end + end + end + end +end diff --git a/plugins/commands/box/command/add.rb b/plugins/commands/box/command/add.rb index 609b4189d..9c9f549eb 100644 --- a/plugins/commands/box/command/add.rb +++ b/plugins/commands/box/command/add.rb @@ -3,7 +3,7 @@ require 'optparse' module VagrantPlugins module CommandBox module Command - class Add < Vagrant::Command::Base + class Add < Vagrant.plugin("1", :command) def execute options = {} diff --git a/plugins/commands/box/command/list.rb b/plugins/commands/box/command/list.rb index 029f3bb45..885952493 100644 --- a/plugins/commands/box/command/list.rb +++ b/plugins/commands/box/command/list.rb @@ -3,7 +3,7 @@ require 'optparse' module VagrantPlugins module CommandBox module Command - class List < Vagrant::Command::Base + class List < Vagrant.plugin("1", :command) def execute options = {} diff --git a/plugins/commands/box/command/remove.rb b/plugins/commands/box/command/remove.rb index b10684bc1..1ea125ac5 100644 --- a/plugins/commands/box/command/remove.rb +++ b/plugins/commands/box/command/remove.rb @@ -3,7 +3,7 @@ require 'optparse' module VagrantPlugins module CommandBox module Command - class Remove < Vagrant::Command::Base + class Remove < Vagrant.plugin("1", :command) def execute options = {} diff --git a/plugins/commands/box/command/repackage.rb b/plugins/commands/box/command/repackage.rb index 0b58b9246..396df577b 100644 --- a/plugins/commands/box/command/repackage.rb +++ b/plugins/commands/box/command/repackage.rb @@ -3,7 +3,7 @@ require 'optparse' module VagrantPlugins module CommandBox module Command - class Repackage < Vagrant::Command::Base + class Repackage < Vagrant.plugin("1", :command) def execute options = {} diff --git a/plugins/commands/box/command/root.rb b/plugins/commands/box/command/root.rb index 1817989e2..5ba7754c7 100644 --- a/plugins/commands/box/command/root.rb +++ b/plugins/commands/box/command/root.rb @@ -3,7 +3,7 @@ require 'optparse' module VagrantPlugins module CommandBox module Command - class Root < Vagrant::Command::Base + class Root < Vagrant.plugin("1", :command) def initialize(argv, env) super diff --git a/plugins/commands/destroy/command.rb b/plugins/commands/destroy/command.rb index 49fb73a67..d834bf34f 100644 --- a/plugins/commands/destroy/command.rb +++ b/plugins/commands/destroy/command.rb @@ -1,6 +1,6 @@ module VagrantPlugins module CommandDestroy - class Command < Vagrant::Command::Base + class Command < Vagrant.plugin("1", :command) def execute options = {} diff --git a/plugins/commands/gem/command.rb b/plugins/commands/gem/command.rb index 116186851..6e5d00e69 100644 --- a/plugins/commands/gem/command.rb +++ b/plugins/commands/gem/command.rb @@ -5,7 +5,7 @@ require "vagrant/util/safe_puts" module VagrantPlugins module CommandGem - class Command < Vagrant::Command::Base + class Command < Vagrant.plugin("1", :command) include Vagrant::Util::SafePuts def execute diff --git a/plugins/commands/halt/command.rb b/plugins/commands/halt/command.rb index f62a41990..150b7eb37 100644 --- a/plugins/commands/halt/command.rb +++ b/plugins/commands/halt/command.rb @@ -2,7 +2,7 @@ require 'optparse' module VagrantPlugins module CommandHalt - class Command < Vagrant::Command::Base + class Command < Vagrant.plugin("1", :command) def execute options = {} diff --git a/plugins/commands/init/command.rb b/plugins/commands/init/command.rb index b7ec11a59..6fba48900 100644 --- a/plugins/commands/init/command.rb +++ b/plugins/commands/init/command.rb @@ -4,7 +4,7 @@ require 'vagrant/util/template_renderer' module VagrantPlugins module CommandInit - class Command < Vagrant::Command::Base + class Command < Vagrant.plugin("1", :command) def execute options = {} diff --git a/plugins/commands/package/command.rb b/plugins/commands/package/command.rb index ba68c56f6..d8b5e35fb 100644 --- a/plugins/commands/package/command.rb +++ b/plugins/commands/package/command.rb @@ -2,7 +2,7 @@ require 'optparse' module VagrantPlugins module CommandPackage - class Command < Vagrant::Command::Base + class Command < Vagrant.plugin("1", :command) def execute options = {} diff --git a/plugins/commands/provision/command.rb b/plugins/commands/provision/command.rb index 6b6e28eec..d6bd66cbe 100644 --- a/plugins/commands/provision/command.rb +++ b/plugins/commands/provision/command.rb @@ -2,7 +2,7 @@ require 'optparse' module VagrantPlugins module CommandProvision - class Command < Vagrant::Command::Base + class Command < Vagrant.plugin("1", :command) def execute options = {} diff --git a/plugins/commands/reload/command.rb b/plugins/commands/reload/command.rb index 81ea71cca..79f88eab0 100644 --- a/plugins/commands/reload/command.rb +++ b/plugins/commands/reload/command.rb @@ -6,7 +6,7 @@ require Vagrant.source_root.join("plugins/commands/up/start_mixins") module VagrantPlugins module CommandReload - class Command < Vagrant::Command::Base + class Command < Vagrant.plugin("1", :command) # We assume that the `up` plugin exists and that we'll have access # to this. include VagrantPlugins::CommandUp::StartMixins diff --git a/plugins/commands/resume/command.rb b/plugins/commands/resume/command.rb index 68e969aab..256593d90 100644 --- a/plugins/commands/resume/command.rb +++ b/plugins/commands/resume/command.rb @@ -2,7 +2,7 @@ require 'optparse' module VagrantPlugins module CommandResume - class Command < Vagrant::Command::Base + class Command < Vagrant.plugin("1", :command) def execute options = {} diff --git a/plugins/commands/ssh/command.rb b/plugins/commands/ssh/command.rb index e19117674..6f5aa7b3f 100644 --- a/plugins/commands/ssh/command.rb +++ b/plugins/commands/ssh/command.rb @@ -2,7 +2,7 @@ require 'optparse' module VagrantPlugins module CommandSSH - class Command < Vagrant::Command::Base + class Command < Vagrant.plugin("1", :command) def execute options = {} diff --git a/plugins/commands/ssh_config/command.rb b/plugins/commands/ssh_config/command.rb index a5e4701b2..7ca855ea5 100644 --- a/plugins/commands/ssh_config/command.rb +++ b/plugins/commands/ssh_config/command.rb @@ -4,7 +4,7 @@ require "vagrant/util/safe_puts" module VagrantPlugins module CommandSSHConfig - class Command < Vagrant::Command::Base + class Command < Vagrant.plugin("1", :command) include Vagrant::Util::SafePuts def execute diff --git a/plugins/commands/status/command.rb b/plugins/commands/status/command.rb index 4c9d1621f..0b4e7526e 100644 --- a/plugins/commands/status/command.rb +++ b/plugins/commands/status/command.rb @@ -2,7 +2,7 @@ require 'optparse' module VagrantPlugins module CommandStatus - class Command < Vagrant::Command::Base + class Command < Vagrant.plugin("1", :command) def execute options = {} diff --git a/plugins/commands/suspend/command.rb b/plugins/commands/suspend/command.rb index 317e55ca8..539be8ac5 100644 --- a/plugins/commands/suspend/command.rb +++ b/plugins/commands/suspend/command.rb @@ -2,7 +2,7 @@ require 'optparse' module VagrantPlugins module CommandSuspend - class Command < Vagrant::Command::Base + class Command < Vagrant.plugin("1", :command) def execute options = {} diff --git a/plugins/commands/up/command.rb b/plugins/commands/up/command.rb index e013b637d..1336760ed 100644 --- a/plugins/commands/up/command.rb +++ b/plugins/commands/up/command.rb @@ -6,7 +6,7 @@ require File.expand_path("../start_mixins", __FILE__) module VagrantPlugins module CommandUp - class Command < Vagrant::Command::Base + class Command < Vagrant.plugin("1", :command) include StartMixins def execute diff --git a/test/unit/vagrant/command/base_test.rb b/test/unit/vagrant/plugin/v1/command_test.rb similarity index 97% rename from test/unit/vagrant/command/base_test.rb rename to test/unit/vagrant/plugin/v1/command_test.rb index 7b14a06f5..7aad4a65e 100644 --- a/test/unit/vagrant/command/base_test.rb +++ b/test/unit/vagrant/plugin/v1/command_test.rb @@ -1,7 +1,7 @@ -require File.expand_path("../../../base", __FILE__) +require File.expand_path("../../../../base", __FILE__) require 'optparse' -describe Vagrant::Command::Base do +describe Vagrant::Plugin::V1::Command do describe "parsing options" do let(:klass) do Class.new(described_class) do diff --git a/test/unit/vagrant_test.rb b/test/unit/vagrant_test.rb index cec130e37..267038917 100644 --- a/test/unit/vagrant_test.rb +++ b/test/unit/vagrant_test.rb @@ -12,6 +12,7 @@ describe Vagrant do end it "returns the proper components for version 1" do + described_class.plugin("1", :command).should == Vagrant::Plugin::V1::Command described_class.plugin("1", :config).should == Vagrant::Plugin::V1::Config described_class.plugin("1", :provisioner).should == Vagrant::Plugin::V1::Provisioner end