mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
effdbf5936
this version contains many enhancements see http://git.io/vtNwF * test/rubygems: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51092 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
347 lines
9.5 KiB
Ruby
347 lines
9.5 KiB
Ruby
require 'rubygems/command'
|
|
require 'rubygems/install_update_options'
|
|
require 'rubygems/dependency_installer'
|
|
require 'rubygems/local_remote_options'
|
|
require 'rubygems/validator'
|
|
require 'rubygems/version_option'
|
|
|
|
##
|
|
# Gem installer command line tool
|
|
#
|
|
# See `gem help install`
|
|
|
|
class Gem::Commands::InstallCommand < Gem::Command
|
|
|
|
attr_reader :installed_specs # :nodoc:
|
|
|
|
include Gem::VersionOption
|
|
include Gem::LocalRemoteOptions
|
|
include Gem::InstallUpdateOptions
|
|
|
|
def initialize
|
|
defaults = Gem::DependencyInstaller::DEFAULT_OPTIONS.merge({
|
|
:format_executable => false,
|
|
:lock => true,
|
|
:suggest_alternate => true,
|
|
:version => Gem::Requirement.default,
|
|
:without_groups => [],
|
|
})
|
|
|
|
super 'install', 'Install a gem into the local repository', defaults
|
|
|
|
add_install_update_options
|
|
add_local_remote_options
|
|
add_platform_option
|
|
add_version_option
|
|
add_prerelease_option "to be installed. (Only for listed gems)"
|
|
|
|
add_option(:"Install/Update", '-g', '--file [FILE]',
|
|
'Read from a gem dependencies API file and',
|
|
'install the listed gems') do |v,o|
|
|
v = Gem::GEM_DEP_FILES.find do |file|
|
|
File.exist? file
|
|
end unless v
|
|
|
|
unless v then
|
|
message = v ? v : "(tried #{Gem::GEM_DEP_FILES.join ', '})"
|
|
|
|
raise OptionParser::InvalidArgument,
|
|
"cannot find gem dependencies file #{message}"
|
|
end
|
|
|
|
o[:gemdeps] = v
|
|
end
|
|
|
|
add_option(:"Install/Update", '--without GROUPS', Array,
|
|
'Omit the named groups (comma separated)',
|
|
'when installing from a gem dependencies',
|
|
'file') do |v,o|
|
|
o[:without_groups].concat v.map { |without| without.intern }
|
|
end
|
|
|
|
add_option(:"Install/Update", '--default',
|
|
'Add the gem\'s full specification to',
|
|
'specifications/default and extract only its bin') do |v,o|
|
|
o[:install_as_default] = v
|
|
end
|
|
|
|
add_option(:"Install/Update", '--explain',
|
|
'Rather than install the gems, indicate which would',
|
|
'be installed') do |v,o|
|
|
o[:explain] = v
|
|
end
|
|
|
|
add_option(:"Install/Update", '--[no-]lock',
|
|
'Create a lock file (when used with -g/--file)') do |v,o|
|
|
o[:lock] = v
|
|
end
|
|
|
|
add_option(:"Install/Update", '--[no-]suggestions',
|
|
'Suggest alternates when gems are not found') do |v,o|
|
|
o[:suggest_alternate] = v
|
|
end
|
|
|
|
@installed_specs = []
|
|
end
|
|
|
|
def arguments # :nodoc:
|
|
"GEMNAME name of gem to install"
|
|
end
|
|
|
|
def defaults_str # :nodoc:
|
|
"--both --version '#{Gem::Requirement.default}' --document --no-force\n" +
|
|
"--install-dir #{Gem.dir} --lock"
|
|
end
|
|
|
|
def description # :nodoc:
|
|
<<-EOF
|
|
The install command installs local or remote gem into a gem repository.
|
|
|
|
For gems with executables ruby installs a wrapper file into the executable
|
|
directory by default. This can be overridden with the --no-wrappers option.
|
|
The wrapper allows you to choose among alternate gem versions using _version_.
|
|
|
|
For example `rake _0.7.3_ --version` will run rake version 0.7.3 if a newer
|
|
version is also installed.
|
|
|
|
Gem Dependency Files
|
|
====================
|
|
|
|
RubyGems can install a consistent set of gems across multiple environments
|
|
using `gem install -g` when a gem dependencies file (gem.deps.rb, Gemfile or
|
|
Isolate) is present. If no explicit file is given RubyGems attempts to find
|
|
one in the current directory.
|
|
|
|
When the RUBYGEMS_GEMDEPS environment variable is set to a gem dependencies
|
|
file the gems from that file will be activated at startup time. Set it to a
|
|
specific filename or to "-" to have RubyGems automatically discover the gem
|
|
dependencies file by walking up from the current directory.
|
|
|
|
NOTE: Enabling automatic discovery on multiuser systems can lead to
|
|
execution of arbitrary code when used from directories outside your control.
|
|
|
|
Extension Install Failures
|
|
==========================
|
|
|
|
If an extension fails to compile during gem installation the gem
|
|
specification is not written out, but the gem remains unpacked in the
|
|
repository. You may need to specify the path to the library's headers and
|
|
libraries to continue. You can do this by adding a -- between RubyGems'
|
|
options and the extension's build options:
|
|
|
|
$ gem install some_extension_gem
|
|
[build fails]
|
|
Gem files will remain installed in \\
|
|
/path/to/gems/some_extension_gem-1.0 for inspection.
|
|
Results logged to /path/to/gems/some_extension_gem-1.0/gem_make.out
|
|
$ gem install some_extension_gem -- --with-extension-lib=/path/to/lib
|
|
[build succeeds]
|
|
$ gem list some_extension_gem
|
|
|
|
*** LOCAL GEMS ***
|
|
|
|
some_extension_gem (1.0)
|
|
$
|
|
|
|
If you correct the compilation errors by editing the gem files you will need
|
|
to write the specification by hand. For example:
|
|
|
|
$ gem install some_extension_gem
|
|
[build fails]
|
|
Gem files will remain installed in \\
|
|
/path/to/gems/some_extension_gem-1.0 for inspection.
|
|
Results logged to /path/to/gems/some_extension_gem-1.0/gem_make.out
|
|
$ [cd /path/to/gems/some_extension_gem-1.0]
|
|
$ [edit files or what-have-you and run make]
|
|
$ gem spec ../../cache/some_extension_gem-1.0.gem --ruby > \\
|
|
../../specifications/some_extension_gem-1.0.gemspec
|
|
$ gem list some_extension_gem
|
|
|
|
*** LOCAL GEMS ***
|
|
|
|
some_extension_gem (1.0)
|
|
$
|
|
|
|
EOF
|
|
end
|
|
|
|
def usage # :nodoc:
|
|
"#{program_name} GEMNAME [GEMNAME ...] [options] -- --build-flags"
|
|
end
|
|
|
|
def check_install_dir # :nodoc:
|
|
if options[:install_dir] and options[:user_install] then
|
|
alert_error "Use --install-dir or --user-install but not both"
|
|
terminate_interaction 1
|
|
end
|
|
end
|
|
|
|
def check_version # :nodoc:
|
|
if options[:version] != Gem::Requirement.default and
|
|
get_all_gem_names.size > 1 then
|
|
alert_error "Can't use --version w/ multiple gems. Use name:ver instead."
|
|
terminate_interaction 1
|
|
end
|
|
end
|
|
|
|
def execute
|
|
if options.include? :gemdeps then
|
|
install_from_gemdeps
|
|
return # not reached
|
|
end
|
|
|
|
@installed_specs = []
|
|
|
|
ENV.delete 'GEM_PATH' if options[:install_dir].nil? and RUBY_VERSION > '1.9'
|
|
|
|
check_install_dir
|
|
check_version
|
|
|
|
load_hooks
|
|
|
|
exit_code = install_gems
|
|
|
|
show_installed
|
|
|
|
terminate_interaction exit_code
|
|
end
|
|
|
|
def install_from_gemdeps # :nodoc:
|
|
require 'rubygems/request_set'
|
|
rs = Gem::RequestSet.new
|
|
|
|
specs = rs.install_from_gemdeps options do |req, inst|
|
|
s = req.full_spec
|
|
|
|
if inst
|
|
say "Installing #{s.name} (#{s.version})"
|
|
else
|
|
say "Using #{s.name} (#{s.version})"
|
|
end
|
|
end
|
|
|
|
@installed_specs = specs
|
|
|
|
terminate_interaction
|
|
end
|
|
|
|
def install_gem name, version # :nodoc:
|
|
return if options[:conservative] and
|
|
not Gem::Dependency.new(name, version).matching_specs.empty?
|
|
|
|
req = Gem::Requirement.create(version)
|
|
|
|
if options[:ignore_dependencies] then
|
|
install_gem_without_dependencies name, req
|
|
else
|
|
inst = Gem::DependencyInstaller.new options
|
|
request_set = inst.resolve_dependencies name, req
|
|
|
|
if options[:explain]
|
|
puts "Gems to install:"
|
|
|
|
request_set.sorted_requests.each do |s|
|
|
puts " #{s.full_name}"
|
|
end
|
|
|
|
return
|
|
else
|
|
@installed_specs.concat request_set.install options
|
|
end
|
|
|
|
show_install_errors inst.errors
|
|
end
|
|
end
|
|
|
|
def install_gem_without_dependencies name, req # :nodoc:
|
|
gem = nil
|
|
|
|
if local? then
|
|
if name =~ /\.gem$/ and File.file? name then
|
|
source = Gem::Source::SpecificFile.new name
|
|
spec = source.spec
|
|
else
|
|
source = Gem::Source::Local.new
|
|
spec = source.find_gem name, req
|
|
end
|
|
gem = source.download spec if spec
|
|
end
|
|
|
|
if remote? and not gem then
|
|
dependency = Gem::Dependency.new name, req
|
|
dependency.prerelease = options[:prerelease]
|
|
|
|
fetcher = Gem::RemoteFetcher.fetcher
|
|
gem = fetcher.download_to_cache dependency
|
|
end
|
|
|
|
inst = Gem::Installer.at gem, options
|
|
inst.install
|
|
|
|
require 'rubygems/dependency_installer'
|
|
dinst = Gem::DependencyInstaller.new options
|
|
dinst.installed_gems.replace [inst.spec]
|
|
|
|
Gem.done_installing_hooks.each do |hook|
|
|
hook.call dinst, [inst.spec]
|
|
end unless Gem.done_installing_hooks.empty?
|
|
|
|
@installed_specs.push(inst.spec)
|
|
end
|
|
|
|
def install_gems # :nodoc:
|
|
exit_code = 0
|
|
|
|
get_all_gem_names_and_versions.each do |gem_name, gem_version|
|
|
gem_version ||= options[:version]
|
|
|
|
begin
|
|
install_gem gem_name, gem_version
|
|
rescue Gem::InstallError => e
|
|
alert_error "Error installing #{gem_name}:\n\t#{e.message}"
|
|
exit_code |= 1
|
|
rescue Gem::GemNotFoundException, Gem::UnsatisfiableDependencyError => e
|
|
domain = options[:domain]
|
|
domain = :local unless options[:suggest_alternate]
|
|
show_lookup_failure e.name, e.version, e.errors, domain
|
|
|
|
exit_code |= 2
|
|
end
|
|
end
|
|
|
|
exit_code
|
|
end
|
|
|
|
##
|
|
# Loads post-install hooks
|
|
|
|
def load_hooks # :nodoc:
|
|
if options[:install_as_default]
|
|
require 'rubygems/install_default_message'
|
|
else
|
|
require 'rubygems/install_message'
|
|
end
|
|
require 'rubygems/rdoc'
|
|
end
|
|
|
|
def show_install_errors errors # :nodoc:
|
|
return unless errors
|
|
|
|
errors.each do |x|
|
|
return unless Gem::SourceFetchProblem === x
|
|
|
|
msg = "Unable to pull data from '#{x.source.uri}': #{x.error.message}"
|
|
|
|
alert_warning msg
|
|
end
|
|
end
|
|
|
|
def show_installed # :nodoc:
|
|
return if @installed_specs.empty?
|
|
|
|
gems = @installed_specs.length == 1 ? 'gem' : 'gems'
|
|
say "#{@installed_specs.length} #{gems} installed"
|
|
end
|
|
|
|
end
|
|
|