diff options
Diffstat (limited to 'lib/rubygems/command_manager.rb')
| -rw-r--r-- | lib/rubygems/command_manager.rb | 354 |
1 files changed, 231 insertions, 123 deletions
diff --git a/lib/rubygems/command_manager.rb b/lib/rubygems/command_manager.rb index dd9a1aee15..76b2fba835 100644 --- a/lib/rubygems/command_manager.rb +++ b/lib/rubygems/command_manager.rb @@ -1,146 +1,254 @@ +# frozen_string_literal: true + #-- # Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others. # All rights reserved. # See LICENSE.txt for permissions. #++ -require 'timeout' -require 'rubygems/command' -require 'rubygems/user_interaction' - -module Gem - - #################################################################### - # The command manager registers and installs all the individual - # sub-commands supported by the gem command. - class CommandManager - include UserInteraction - - # Return the authoritative instance of the command manager. - def self.instance - @command_manager ||= CommandManager.new - end - - # Register all the subcommands supported by the gem command. - def initialize - @commands = {} - register_command :build - register_command :cert - register_command :check - register_command :cleanup - register_command :contents - register_command :dependency - register_command :environment - register_command :fetch - register_command :generate_index - register_command :help - register_command :install - register_command :list - register_command :lock - register_command :mirror - register_command :outdated - register_command :pristine - register_command :query - register_command :rdoc - register_command :search - register_command :server - register_command :sources - register_command :specification - register_command :stale - register_command :uninstall - register_command :unpack - register_command :update - register_command :which - end - - # Register the command object. - def register_command(command_obj) - @commands[command_obj] = false - end - - # Return the registered command from the command name. - def [](command_name) - command_name = command_name.intern - return nil if @commands[command_name].nil? - @commands[command_name] ||= load_and_instantiate(command_name) +require_relative "command" +require_relative "user_interaction" +require_relative "text" + +## +# The command manager registers and installs all the individual sub-commands +# supported by the gem command. +# +# Extra commands can be provided by writing a rubygems_plugin.rb +# file in an installed gem. You should register your command against the +# Gem::CommandManager instance, like this: +# +# # file rubygems_plugin.rb +# require 'rubygems/command_manager' +# +# Gem::CommandManager.instance.register_command :edit +# +# You should put the implementation of your command in rubygems/commands. +# +# # file rubygems/commands/edit_command.rb +# class Gem::Commands::EditCommand < Gem::Command +# # ... +# end +# +# See Gem::Command for instructions on writing gem commands. + +class Gem::CommandManager + include Gem::Text + include Gem::UserInteraction + + BUILTIN_COMMANDS = [ # :nodoc: + :build, + :cert, + :check, + :cleanup, + :contents, + :dependency, + :environment, + :exec, + :fetch, + :generate_index, + :help, + :info, + :install, + :list, + :lock, + :mirror, + :open, + :outdated, + :owner, + :pristine, + :push, + :rdoc, + :rebuild, + :search, + :server, + :signin, + :signout, + :sources, + :specification, + :stale, + :uninstall, + :unpack, + :update, + :which, + :yank, + ].freeze + + ALIAS_COMMANDS = { + "i" => "install", + "login" => "signin", + "logout" => "signout", + }.freeze + + ## + # Return the authoritative instance of the command manager. + + def self.instance + @instance ||= new + end + + ## + # Returns self. Allows a CommandManager instance to stand + # in for the class itself. + + def instance + self + end + + ## + # Reset the authoritative instance of the command manager. + + def self.reset + @instance = nil + end + + ## + # Register all the subcommands supported by the gem command. + + def initialize + require_relative "vendored_timeout" + @commands = {} + + BUILTIN_COMMANDS.each do |name| + register_command name end - - # Return a list of all command names (as strings). - def command_names - @commands.keys.collect {|key| key.to_s}.sort + end + + ## + # Register the Symbol +command+ as a gem command. + + def register_command(command, obj = false) + @commands[command] = obj + end + + ## + # Unregister the Symbol +command+ as a gem command. + + def unregister_command(command) + @commands.delete command + end + + ## + # Returns a Command instance for +command_name+ + + def [](command_name) + command_name = command_name.intern + return nil if @commands[command_name].nil? + @commands[command_name] ||= load_and_instantiate(command_name) + end + + ## + # Return a sorted list of all command names as strings. + + def command_names + @commands.keys.collect(&:to_s).sort + end + + ## + # Run the command specified by +args+. + + def run(args, build_args = nil) + process_args(args, build_args) + rescue StandardError, Gem::Timeout::Error => ex + if ex.respond_to?(:detailed_message) + msg = ex.detailed_message(highlight: false).sub(/\A(.*?)(?: \(.+?\))/) { $1 } + else + msg = ex.message end - - # Run the config specified by +args+. - def run(args) - process_args(args) - rescue StandardError, Timeout::Error => ex - alert_error "While executing gem ... (#{ex.class})\n #{ex.to_s}" - ui.errs.puts "\t#{ex.backtrace.join "\n\t"}" if - Gem.configuration.backtrace - terminate_interaction(1) - rescue Interrupt - alert_error "Interrupted" - terminate_interaction(1) + alert_error clean_text("While executing gem ... (#{ex.class})\n #{msg}") + ui.backtrace ex + + terminate_interaction(1) + rescue Interrupt + alert_error clean_text("Interrupted") + terminate_interaction(1) + end + + def process_args(args, build_args = nil) + if args.empty? + say Gem::Command::HELP + terminate_interaction 1 end - def process_args(args) - args = args.to_str.split(/\s+/) if args.respond_to?(:to_str) - if args.size == 0 - say Gem::Command::HELP - terminate_interaction(1) - end - case args[0] - when '-h', '--help' - say Gem::Command::HELP - terminate_interaction(0) - when '-v', '--version' - say Gem::RubyGemsVersion - terminate_interaction(0) - when /^-/ - alert_error "Invalid option: #{args[0]}. See 'gem --help'." - terminate_interaction(1) + case args.first + when "-h", "--help" then + say Gem::Command::HELP + terminate_interaction 0 + when "-v", "--version" then + say Gem::VERSION + terminate_interaction 0 + when "-C" then + args.shift + start_point = args.shift + if Dir.exist?(start_point) + Dir.chdir(start_point) { invoke_command(args, build_args) } else - cmd_name = args.shift.downcase - cmd = find_command(cmd_name) - cmd.invoke(*args) + alert_error clean_text("#{start_point} isn't a directory.") + terminate_interaction 1 end + when /^-/ then + alert_error clean_text("Invalid option: #{args.first}. See 'gem --help'.") + terminate_interaction 1 + else + invoke_command(args, build_args) end + end - def find_command(cmd_name) - possibilities = find_command_possibilities(cmd_name) - if possibilities.size > 1 - raise "Ambiguous command #{cmd_name} matches [#{possibilities.join(', ')}]" - end - if possibilities.size < 1 - raise "Unknown command #{cmd_name}" - end + def find_command(cmd_name) + cmd_name = find_alias_command cmd_name - self[possibilities.first] - end + possibilities = find_command_possibilities cmd_name - def find_command_possibilities(cmd_name) - len = cmd_name.length - self.command_names.select { |n| cmd_name == n[0,len] } + if possibilities.size > 1 + raise Gem::CommandLineError, + "Ambiguous command #{cmd_name} matches [#{possibilities.join(", ")}]" + elsif possibilities.empty? + raise Gem::UnknownCommandError.new(cmd_name) end - - private - def load_and_instantiate(command_name) - command_name = command_name.to_s - retried = false + self[possibilities.first] + end + + def find_alias_command(cmd_name) + alias_name = ALIAS_COMMANDS[cmd_name] + alias_name ? alias_name : cmd_name + end + + def find_command_possibilities(cmd_name) + len = cmd_name.length + found = command_names.select {|name| cmd_name == name[0, len] } + + exact = found.find {|name| name == cmd_name } + + exact ? [exact] : found + end + + private + + def load_and_instantiate(command_name) + command_name = command_name.to_s + const_name = command_name.capitalize.gsub(/_(.)/) { $1.upcase } << "Command" + + begin begin - const_name = command_name.capitalize.gsub(/_(.)/) { $1.upcase } - Gem::Commands.const_get("#{const_name}Command").new - rescue NameError - if retried then - raise - else - retried = true - require "rubygems/commands/#{command_name}_command" - retry - end + require "rubygems/commands/#{command_name}_command" + rescue LoadError + # it may have been defined from a rubygems_plugin.rb file end + + Gem::Commands.const_get(const_name).new + rescue StandardError => e + alert_error clean_text("Loading command: #{command_name} (#{e.class})\n\t#{e}") + ui.backtrace e end end -end + + def invoke_command(args, build_args) + cmd_name = args.shift.downcase + cmd = find_command cmd_name + terminate_interaction 1 unless cmd + cmd.deprecation_warning if cmd.deprecated? + cmd.invoke_with_build_args args, build_args + end +end |
