184 lines
5.7 KiB
Ruby
184 lines
5.7 KiB
Ruby
require 'optparse'
|
|
|
|
module Vagrant
|
|
class Commands
|
|
# This is the base command class which all sub-commands must
|
|
# inherit from. Subclasses of bases are expected to implement two
|
|
# methods: {#execute} and {#options_spec} (optional). The former
|
|
# defines the actual behavior of the command while the latter is a spec
|
|
# outlining the options that the command may take.
|
|
class Base
|
|
include Util
|
|
|
|
attr_reader :env
|
|
|
|
class << self
|
|
# Contains the list of registered subcommands. The registered commands are
|
|
# stored in a hash table and are therefore unordered.
|
|
#
|
|
# @return [Hash]
|
|
def subcommands
|
|
@subcommands ||= {}
|
|
end
|
|
|
|
# Registers a command with `vagrant`. This method allows 3rd parties to
|
|
# dynamically add new commands to the `vagrant` command, allowing plugins
|
|
# to act as 1st class citizens within vagrant.
|
|
#
|
|
# @param [String] key The subcommand which will invoke the registered command.
|
|
# @param [Class] klass. The subcommand class (a subclass of {Base})
|
|
def subcommand(key, klass)
|
|
subcommands[key] = klass
|
|
end
|
|
|
|
# Dispatches a subcommand to the proper registered command. Otherwise, it
|
|
# prints a help message.
|
|
def dispatch(env, *args)
|
|
klass = subcommands[args[0]] unless args.empty?
|
|
if klass.nil?
|
|
# Run _this_ command!
|
|
command = self.new(env)
|
|
command.execute(args)
|
|
return
|
|
end
|
|
|
|
# Shift off the front arg, since we just consumed it in finding the
|
|
# subcommand.
|
|
args.shift
|
|
|
|
# Dispatch to the next class
|
|
klass.dispatch(env, *args)
|
|
end
|
|
|
|
# Sets or reads the description, depending on if the value is set in the
|
|
# parameter.
|
|
def description(value=nil)
|
|
@description ||= ''
|
|
|
|
return @description if value.nil?
|
|
@description = value
|
|
end
|
|
end
|
|
|
|
def initialize(env)
|
|
@env = env
|
|
end
|
|
|
|
# This method should be overriden by subclasses. This is the method
|
|
# which is called by {Vagrant::Command} when a command is being
|
|
# executed. The `args` parameter is an array of parameters to the
|
|
# command (similar to ARGV)
|
|
def execute(args)
|
|
parse_options(args)
|
|
|
|
if options[:version]
|
|
puts_version
|
|
else
|
|
# Just print out the help, since this top-level command does nothing
|
|
# on its own
|
|
show_help
|
|
end
|
|
end
|
|
|
|
# This method is called by the base class to get the `optparse` configuration
|
|
# for the command.
|
|
def options_spec(opts)
|
|
opts.banner = "Usage: vagrant SUBCOMMAND"
|
|
|
|
opts.on("--version", "Output running Vagrant version.") do |v|
|
|
options[:version] = v
|
|
end
|
|
end
|
|
|
|
#-------------------------------------------------------------------
|
|
# Methods below are not meant to be overriden/implemented by subclasses
|
|
#-------------------------------------------------------------------
|
|
|
|
# Parses the options for a given command and if a name was
|
|
# given, it calls the single method, otherwise it calls the all
|
|
# method. This helper is an abstraction which allows commands to
|
|
# easily be used in both regular and multi-VM environments.
|
|
def all_or_single(args, method_prefix)
|
|
args = parse_options(args)
|
|
|
|
single_method = "#{method_prefix}_single".to_sym
|
|
if args[0]
|
|
send(single_method, args[0])
|
|
else
|
|
env.vms.keys.each do |name|
|
|
send(single_method, name)
|
|
end
|
|
end
|
|
end
|
|
|
|
# Shows the version
|
|
def puts_version
|
|
File.open(File.join(PROJECT_ROOT, "VERSION"), "r") do |f|
|
|
puts f.read
|
|
end
|
|
end
|
|
|
|
# Returns the `OptionParser` instance to be used with this subcommand,
|
|
# based on the specs defined in {#options_spec}.
|
|
def option_parser(reload=false)
|
|
@option_parser = nil if reload
|
|
@option_parser ||= OptionParser.new do |opts|
|
|
# The --help flag is available on all children commands, and will
|
|
# immediately show help.
|
|
opts.on("--help", "Show help for the current subcommand.") do
|
|
show_help
|
|
end
|
|
|
|
options_spec(opts)
|
|
end
|
|
end
|
|
|
|
# The options for the given command. This will just be an empty hash
|
|
# until {#parse_options} is called.
|
|
def options
|
|
@options ||= {}
|
|
end
|
|
|
|
# Parse options out of the command-line. This method uses `optparse`
|
|
# to parse command line options.
|
|
def parse_options(args)
|
|
option_parser.parse!(args)
|
|
rescue OptionParser::InvalidOption
|
|
show_help
|
|
end
|
|
|
|
# Gets the description of the command. This is similar grabbed from the
|
|
# class level.
|
|
def description
|
|
self.class.description
|
|
end
|
|
|
|
# Prints the help for the given command. Prior to calling this method,
|
|
# {#parse_options} must be called or a nilerror will be raised. This
|
|
# is by design.
|
|
def show_help
|
|
if !description.empty?
|
|
puts "Description: #{description}"
|
|
end
|
|
|
|
puts option_parser.help
|
|
|
|
my_klass = self.class
|
|
if !my_klass.subcommands.empty?
|
|
puts "\nSupported subcommands:"
|
|
my_klass.subcommands.keys.sort.each do |key|
|
|
klass = my_klass.subcommands[key]
|
|
next if klass.description.empty?
|
|
|
|
puts "#{' ' * 8}#{key.ljust(20)}#{klass.description}"
|
|
end
|
|
|
|
puts "\nFor help on a specific subcommand, run `vagrant SUBCOMMAND --help`"
|
|
end
|
|
|
|
exit
|
|
end
|
|
end
|
|
end
|
|
end
|