зеркало из https://github.com/github/ruby.git
[rubygems/rubygems] Add gem exec command
https://github.com/rubygems/rubygems/commit/ca69a317f3
This commit is contained in:
Родитель
693e4dec23
Коммит
cbe14cc8e6
|
@ -201,11 +201,15 @@ class Gem::Command
|
|||
# respectively.
|
||||
def get_all_gem_names_and_versions
|
||||
get_all_gem_names.map do |name|
|
||||
if /\A(.*):(#{Gem::Requirement::PATTERN_RAW})\z/ =~ name
|
||||
[$1, $2]
|
||||
else
|
||||
[name]
|
||||
end
|
||||
extract_gem_name_and_version(name)
|
||||
end
|
||||
end
|
||||
|
||||
def extract_gem_name_and_version(name) # :nodoc:
|
||||
if /\A(.*):(#{Gem::Requirement::PATTERN_RAW})\z/ =~ name
|
||||
[$1, $2]
|
||||
else
|
||||
[name]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ class Gem::CommandManager
|
|||
:contents,
|
||||
:dependency,
|
||||
:environment,
|
||||
:exec,
|
||||
:fetch,
|
||||
:generate_index,
|
||||
:help,
|
||||
|
|
|
@ -0,0 +1,186 @@
|
|||
# frozen_string_literal: true
|
||||
require_relative "../command"
|
||||
require_relative "../package"
|
||||
require_relative "../version_option"
|
||||
|
||||
class Gem::Commands::ExecCommand < Gem::Command
|
||||
include Gem::VersionOption
|
||||
|
||||
def initialize
|
||||
super "exec", "Run a command from a gem", {
|
||||
version: Gem::Requirement.default,
|
||||
}
|
||||
|
||||
add_platform_option
|
||||
add_version_option
|
||||
add_prerelease_option "to be installed"
|
||||
|
||||
add_option "-g", "--gem GEM", "run the executable from the given gem" do |value, options|
|
||||
options[:gem_name] = value
|
||||
end
|
||||
|
||||
add_option(:"Install/Update", "--conservative",
|
||||
"Prefer the most recent installed version, ",
|
||||
"rather than the latest version overall") do |value, options|
|
||||
options[:conservative] = true
|
||||
end
|
||||
end
|
||||
|
||||
def arguments # :nodoc:
|
||||
"COMMAND the executable command to run"
|
||||
end
|
||||
|
||||
def defaults_str # :nodoc:
|
||||
"--version '#{Gem::Requirement.default}'"
|
||||
end
|
||||
|
||||
def description # :nodoc:
|
||||
<<-EOF
|
||||
EOF
|
||||
end
|
||||
|
||||
def usage # :nodoc:
|
||||
"#{program_name} [options --] COMMAND [args]"
|
||||
end
|
||||
|
||||
def execute
|
||||
check_executable
|
||||
|
||||
print_command
|
||||
if options[:conservative]
|
||||
install_if_needed
|
||||
else
|
||||
install
|
||||
activate!
|
||||
end
|
||||
|
||||
load!
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def handle_options(args)
|
||||
args = add_extra_args(args)
|
||||
check_deprecated_options(args)
|
||||
@options = Marshal.load Marshal.dump @defaults # deep copy
|
||||
parser.order!(args) do |v|
|
||||
# put the non-option back at the front of the list of arguments
|
||||
args.unshift(v)
|
||||
|
||||
# stop parsing once we hit the first non-option,
|
||||
# so you can call `gem exec rails --version` and it prints the rails
|
||||
# version rather than rubygem's
|
||||
break
|
||||
end
|
||||
@options[:args] = args
|
||||
|
||||
options[:executable], gem_version = extract_gem_name_and_version(options[:args].shift)
|
||||
options[:gem_name] ||= options[:executable]
|
||||
options[:version] = gem_version if gem_version
|
||||
end
|
||||
|
||||
def check_executable
|
||||
if options[:executable].nil?
|
||||
raise Gem::CommandLineError,
|
||||
"Please specify an executable to run (e.g. #{program_name} COMMAND)"
|
||||
end
|
||||
end
|
||||
|
||||
def print_command
|
||||
verbose "running #{program_name} with:\n"
|
||||
opts = options.reject {|_, v| v.nil? || Array(v).empty? }
|
||||
max_length = opts.map {|k, _| k.size }.max
|
||||
opts.each do |k, v|
|
||||
next if v.nil?
|
||||
verbose "\t#{k.to_s.rjust(max_length)}: #{v} "
|
||||
end
|
||||
verbose ""
|
||||
end
|
||||
|
||||
def install_if_needed
|
||||
activate!
|
||||
rescue Gem::MissingSpecError
|
||||
verbose "#{dependency_to_s} not available locally"
|
||||
install
|
||||
activate!
|
||||
end
|
||||
|
||||
def install
|
||||
gem_name = options[:gem_name]
|
||||
gem_version = options[:version]
|
||||
|
||||
home = Gem.paths.home
|
||||
home = File.join(home, "gem_exec")
|
||||
Gem.use_paths(home, Gem.path + [home])
|
||||
|
||||
suppress_always_install do
|
||||
Gem.install(gem_name, gem_version)
|
||||
end
|
||||
rescue Gem::InstallError => e
|
||||
alert_error "Error installing #{gem_name}:\n\t#{e.message}"
|
||||
terminate_interaction 1
|
||||
rescue Gem::GemNotFoundException => e
|
||||
show_lookup_failure e.name, e.version, e.errors, false
|
||||
|
||||
terminate_interaction 2
|
||||
rescue Gem::UnsatisfiableDependencyError => e
|
||||
show_lookup_failure e.name, e.version, e.errors, false,
|
||||
"'#{gem_name}' (#{gem_version})"
|
||||
|
||||
terminate_interaction 2
|
||||
end
|
||||
|
||||
def activate!
|
||||
gem(options[:gem_name], options[:version])
|
||||
Gem.finish_resolve
|
||||
end
|
||||
|
||||
def load!
|
||||
argv = ARGV.clone
|
||||
ARGV.replace options[:args]
|
||||
|
||||
exe = executable = options[:executable]
|
||||
|
||||
contains_executable = Gem.loaded_specs.values.select do |spec|
|
||||
spec.executables.include?(executable)
|
||||
end
|
||||
|
||||
if contains_executable.any? {|s| s.name == executable }
|
||||
contains_executable.select! {|s| s.name == executable }
|
||||
end
|
||||
|
||||
if contains_executable.empty?
|
||||
if (spec = Gem.loaded_specs[executable]) && (exe = spec.executable)
|
||||
contains_executable << spec
|
||||
else
|
||||
alert_error "Failed to load executable `#{executable}`," \
|
||||
" are you sure the gem `#{options[:gem_name]}` contains it?"
|
||||
terminate_interaction 1
|
||||
end
|
||||
end
|
||||
|
||||
if contains_executable.size > 1
|
||||
alert_error "Ambiguous which gem `#{executable}` should come from: " \
|
||||
"the options are #{contains_executable.map(&:name)}, " \
|
||||
"specify one via `-g`"
|
||||
terminate_interaction 1
|
||||
end
|
||||
|
||||
load Gem.activate_bin_path(contains_executable.first.name, exe, ">= 0.a")
|
||||
ensure
|
||||
ARGV.replace argv
|
||||
end
|
||||
|
||||
def suppress_always_install
|
||||
name = :always_install
|
||||
cls = ::Gem::Resolver::InstallerSet
|
||||
method = cls.instance_method(name)
|
||||
cls.define_method(name) { [] }
|
||||
|
||||
begin
|
||||
yield
|
||||
ensure
|
||||
cls.define_method(name, method)
|
||||
end
|
||||
end
|
||||
end
|
Загрузка…
Ссылка в новой задаче