You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
281 lines
7.5 KiB
281 lines
7.5 KiB
#--
|
|
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
|
|
# All rights reserved.
|
|
# See LICENSE.txt for permissions.
|
|
#++
|
|
|
|
require 'rubygems/user_interaction'
|
|
|
|
module Gem
|
|
|
|
####################################################################
|
|
# Base class for all Gem commands.
|
|
class Command
|
|
include UserInteraction
|
|
|
|
Option = Struct.new(:short, :long, :description, :handler)
|
|
|
|
attr_reader :command, :options
|
|
attr_accessor :summary, :defaults, :program_name
|
|
|
|
# Initialize a generic gem command.
|
|
def initialize(command, summary=nil, defaults={})
|
|
@command = command
|
|
@summary = summary
|
|
@program_name = "gem #{command}"
|
|
@defaults = defaults
|
|
@options = defaults.dup
|
|
@option_list = []
|
|
@parser = nil
|
|
end
|
|
|
|
# Override to provide command handling.
|
|
def execute
|
|
fail "Generic command has no actions"
|
|
end
|
|
|
|
# Override to display the usage for an individual gem command.
|
|
def usage
|
|
"#{program_name}"
|
|
end
|
|
|
|
# Override to provide details of the arguments a command takes.
|
|
# It should return a left-justified string, one argument per line.
|
|
def arguments
|
|
""
|
|
end
|
|
|
|
# Override to display the default values of the command
|
|
# options. (similar to +arguments+, but displays the default
|
|
# values).
|
|
def defaults_str
|
|
""
|
|
end
|
|
|
|
# Display the help message for this command.
|
|
def show_help
|
|
parser.program_name = usage
|
|
say parser
|
|
end
|
|
|
|
# Invoke the command with the given list of arguments.
|
|
def invoke(*args)
|
|
handle_options(args)
|
|
if options[:help]
|
|
show_help
|
|
elsif @when_invoked
|
|
@when_invoked.call(options)
|
|
else
|
|
execute
|
|
end
|
|
end
|
|
|
|
# Call the given block when invoked.
|
|
#
|
|
# Normal command invocations just executes the +execute+ method of
|
|
# the command. Specifying an invocation block allows the test
|
|
# methods to override the normal action of a command to determine
|
|
# that it has been invoked correctly.
|
|
def when_invoked(&block)
|
|
@when_invoked = block
|
|
end
|
|
|
|
# Add a option (and a handler) to this command.
|
|
def add_option(*args, &handler)
|
|
@option_list << [args, handler]
|
|
end
|
|
|
|
# Remove a previously defined command option.
|
|
def remove_option(name)
|
|
@option_list.reject! { |args, handler| args.any? { |x| x =~ /^#{name}/ } }
|
|
end
|
|
|
|
# Merge a set of command options with the set of default options
|
|
# (without modifying the default option hash).
|
|
def merge_options(new_options)
|
|
@options = @defaults.clone
|
|
new_options.each do |k,v| @options[k] = v end
|
|
end
|
|
|
|
# True if the command handles the given argument list.
|
|
def handles?(args)
|
|
begin
|
|
parser.parse!(args.dup)
|
|
return true
|
|
rescue
|
|
return false
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
# Return the command manager instance.
|
|
def command_manager
|
|
Gem::CommandManager.instance
|
|
end
|
|
|
|
# Handle the given list of arguments by parsing them and recording
|
|
# the results.
|
|
def handle_options(args)
|
|
args = add_extra_args(args)
|
|
@options = @defaults.clone
|
|
parser.parse!(args)
|
|
@options[:args] = args
|
|
end
|
|
|
|
def add_extra_args(args)
|
|
result = []
|
|
s_extra = Command.specific_extra_args(@command)
|
|
extra = Command.extra_args + s_extra
|
|
while ! extra.empty?
|
|
ex = []
|
|
ex << extra.shift
|
|
ex << extra.shift if extra.first.to_s =~ /^[^-]/
|
|
result << ex if handles?(ex)
|
|
end
|
|
result.flatten!
|
|
result.concat(args)
|
|
result
|
|
end
|
|
|
|
# Create on demand parser.
|
|
def parser
|
|
create_option_parser if @parser.nil?
|
|
@parser
|
|
end
|
|
|
|
def create_option_parser
|
|
require 'optparse'
|
|
@parser = OptionParser.new
|
|
option_names = {}
|
|
@parser.separator("")
|
|
unless @option_list.empty?
|
|
@parser.separator(" Options:")
|
|
configure_options(@option_list, option_names)
|
|
@parser.separator("")
|
|
end
|
|
@parser.separator(" Common Options:")
|
|
configure_options(Command.common_options, option_names)
|
|
@parser.separator("")
|
|
unless arguments.empty?
|
|
@parser.separator(" Arguments:")
|
|
arguments.split(/\n/).each do |arg_desc|
|
|
@parser.separator(" #{arg_desc}")
|
|
end
|
|
@parser.separator("")
|
|
end
|
|
@parser.separator(" Summary:")
|
|
@parser.separator(" #@summary")
|
|
unless defaults_str.empty?
|
|
@parser.separator("")
|
|
@parser.separator(" Defaults:")
|
|
defaults_str.split(/\n/).each do |line|
|
|
@parser.separator(" #{line}")
|
|
end
|
|
end
|
|
end
|
|
|
|
def configure_options(option_list, option_names)
|
|
option_list.each do |args, handler|
|
|
dashes = args.select { |arg| arg =~ /^-/ }
|
|
next if dashes.any? { |arg| option_names[arg] }
|
|
@parser.on(*args) do |value|
|
|
handler.call(value, @options)
|
|
end
|
|
dashes.each do |arg| option_names[arg] = true end
|
|
end
|
|
end
|
|
|
|
##################################################################
|
|
# Class methods for Command.
|
|
class << self
|
|
def common_options
|
|
@common_options ||= []
|
|
end
|
|
|
|
def add_common_option(*args, &handler)
|
|
Gem::Command.common_options << [args, handler]
|
|
end
|
|
|
|
def extra_args
|
|
@extra_args ||= []
|
|
end
|
|
|
|
def extra_args=(value)
|
|
case value
|
|
when Array
|
|
@extra_args = value
|
|
when String
|
|
@extra_args = value.split
|
|
end
|
|
end
|
|
|
|
# Return an array of extra arguments for the command. The extra
|
|
# arguments come from the gem configuration file read at program
|
|
# startup.
|
|
def specific_extra_args(cmd)
|
|
specific_extra_args_hash[cmd]
|
|
end
|
|
|
|
# Add a list of extra arguments for the given command. +args+
|
|
# may be an array or a string to be split on white space.
|
|
def add_specific_extra_args(cmd,args)
|
|
args = args.split(/\s+/) if args.kind_of? String
|
|
specific_extra_args_hash[cmd] = args
|
|
end
|
|
|
|
# Accessor for the specific extra args hash (self initializing).
|
|
def specific_extra_args_hash
|
|
@specific_extra_args_hash ||= Hash.new do |h,k|
|
|
h[k] = Array.new
|
|
end
|
|
end
|
|
end
|
|
|
|
# ----------------------------------------------------------------
|
|
# Add the options common to all commands.
|
|
|
|
add_common_option('--source URL',
|
|
'Use URL as the remote source for gems') do
|
|
|value, options|
|
|
require_gem("sources")
|
|
Gem.sources.clear
|
|
Gem.sources << value
|
|
end
|
|
|
|
add_common_option('-p', '--[no-]http-proxy [URL]',
|
|
'Use HTTP proxy for remote operations') do
|
|
|value, options|
|
|
options[:http_proxy] = (value == false) ? :no_proxy : value
|
|
end
|
|
|
|
add_common_option('-h', '--help',
|
|
'Get help on this command') do
|
|
|value, options|
|
|
options[:help] = true
|
|
end
|
|
|
|
add_common_option('-v', '--verbose',
|
|
'Set the verbose level of output') do
|
|
|value, options|
|
|
Gem.configuration.verbose = value
|
|
end
|
|
|
|
# Backtrace and config-file are added so they show up in the help
|
|
# commands. Both options are actually handled before the other
|
|
# options get parsed.
|
|
|
|
add_common_option('--config-file FILE',
|
|
"Use this config file instead of default") do
|
|
end
|
|
|
|
add_common_option('--backtrace',
|
|
'Show stack backtrace on errors') do
|
|
end
|
|
|
|
add_common_option('--debug',
|
|
'Turn on Ruby debugging') do
|
|
end
|
|
end # class
|
|
end # module
|