Skip to content

Commit

Permalink
Showing 142 changed files with 2,213 additions and 8,445 deletions.
2 changes: 1 addition & 1 deletion lib/ruby/shared/gauntlet_rubygems.rb
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@
# rvsh-0.4.5 : No such file or directory - bin/rvsh
# xen-0.1.2.1 : authors must be Array of Strings

class GemGauntlet < Gauntlet # :nodoc:
class GemGauntlet < Gauntlet
def run(name)
warn name

244 changes: 97 additions & 147 deletions lib/ruby/shared/rubygems.rb

Large diffs are not rendered by default.

9 changes: 3 additions & 6 deletions lib/ruby/shared/rubygems/available_set.rb
Original file line number Diff line number Diff line change
@@ -4,12 +4,9 @@ class Gem::AvailableSet

Tuple = Struct.new(:spec, :source)

attr_accessor :remote # :nodoc:

def initialize
@set = []
@sorted = nil
@remote = true
end

attr_reader :set
@@ -119,18 +116,18 @@ def to_request_set development = :none

##
#
# Used by the Resolver, the protocol to use a AvailableSet as a
# Used by the DependencyResolver, the protocol to use a AvailableSet as a
# search Set.

def find_all(req)
dep = req.dependency

match = @set.find_all do |t|
dep.match? t.spec
dep.matches_spec? t.spec
end

match.map do |t|
Gem::Resolver::LocalSpecification.new(self, t.spec, t.source)
Gem::DependencyResolver::InstalledSpecification.new(self, t.spec, t.source)
end
end

171 changes: 12 additions & 159 deletions lib/ruby/shared/rubygems/basic_specification.rb
Original file line number Diff line number Diff line change
@@ -4,31 +4,11 @@

class Gem::BasicSpecification

##
# Allows installation of extensions for git: gems.

attr_writer :base_dir # :nodoc:

##
# Sets the directory where extensions for this gem will be installed.

attr_writer :extension_dir # :nodoc:

##
# Is this specification ignored for activation purposes?

attr_writer :ignored # :nodoc:

##
# The path this gemspec was loaded from. This attribute is not persisted.

attr_reader :loaded_from

##
# Allows correct activation of git: and path: gems.

attr_writer :full_gem_path # :nodoc:

def self.default_specifications_dir
File.join(Gem.default_dir, "specifications", "default")
end
@@ -58,51 +38,20 @@ def base_dir
# Return true if this spec can require +file+.

def contains_requirable_file? file
@contains_requirable_file ||= {}
@contains_requirable_file[file] ||=
begin
if instance_variable_defined?(:@ignored) or
instance_variable_defined?('@ignored') then
return false
elsif missing_extensions? then
@ignored = true

warn "Ignoring #{full_name} because its extensions are not built. " +
"Try: gem pristine #{name} --version #{version}"
return false
end

suffixes = Gem.suffixes

full_require_paths.any? do |dir|
base = "#{dir}/#{file}"
suffixes.any? { |suf| File.file? "#{base}#{suf}" }
end
end ? :yes : :no
@contains_requirable_file[file] == :yes
root = full_gem_path
suffixes = Gem.suffixes

require_paths.any? do |lib|
base = "#{root}/#{lib}/#{file}"
suffixes.any? { |suf| File.file? "#{base}#{suf}" }
end
end

def default_gem?
loaded_from &&
File.dirname(loaded_from) == self.class.default_specifications_dir
end

##
# Returns full path to the directory where gem's extensions are installed.

def extension_dir
@extension_dir ||= File.expand_path File.join(extensions_dir, full_name)
end

##
# Returns path to the extensions directory.

def extensions_dir
@extensions_dir ||= Gem.default_ext_dir_for(base_dir) ||
File.join(base_dir, 'extensions', Gem::Platform.local.to_s,
Gem.extension_api_version)
end

def find_full_gem_path # :nodoc:
# TODO: also, shouldn't it default to full_name if it hasn't been written?
path = File.expand_path File.join(gems_dir, full_name)
@@ -134,53 +83,6 @@ def full_name
end
end

##
# Full paths in the gem to add to <code>$LOAD_PATH</code> when this gem is
# activated.

def full_require_paths
@full_require_paths ||=
begin
full_paths = raw_require_paths.map do |path|
File.join full_gem_path, path
end

full_paths.unshift extension_dir unless @extensions.nil? || @extensions.empty?

full_paths
end
end

##
# Full path of the target library file.
# If the file is not in this gem, return nil.

def to_fullpath path
if activated? then
@paths_map ||= {}
@paths_map[path] ||=
begin
fullpath = nil
suffixes = Gem.suffixes
full_require_paths.find do |dir|
suffixes.find do |suf|
File.file?(fullpath = "#{dir}/#{path}#{suf}")
end
end ? fullpath : nil
end
else
nil
end
end

##
# Returns the full path to this spec's gem directory.
# eg: /usr/local/lib/ruby/1.8/gems/mygem-1.0

def gem_dir
@gem_dir ||= File.expand_path File.join(gems_dir, full_name)
end

##
# Returns the full path to the gems directory containing this spec's
# gem directory. eg: /usr/local/lib/ruby/1.8/gems
@@ -197,12 +99,9 @@ def gems_dir
def loaded_from= path
@loaded_from = path && path.to_s

@extension_dir = nil
@extensions_dir = nil
@full_gem_path = nil
@gem_dir = nil
@gems_dir = nil
@base_dir = nil
@full_gem_path = nil
@gems_dir = nil
@base_dir = nil
end

##
@@ -219,49 +118,11 @@ def platform
raise NotImplementedError
end

def raw_require_paths # :nodoc:
Array(@require_paths)
end

##
# Paths in the gem to add to <code>$LOAD_PATH</code> when this gem is
# activated.
#
# See also #require_paths=
#
# If you have an extension you do not need to add <code>"ext"</code> to the
# require path, the extension build process will copy the extension files
# into "lib" for you.
#
# The default value is <code>"lib"</code>
#
# Usage:
#
# # If all library files are in the root directory...
# spec.require_path = '.'
# Require paths of the gem

def require_paths
return raw_require_paths if @extensions.nil? || @extensions.empty?

[extension_dir].concat raw_require_paths
end

##
# Returns the paths to the source files for use with analysis and
# documentation tools. These paths are relative to full_gem_path.

def source_paths
paths = raw_require_paths.dup

if @extensions then
ext_dirs = @extensions.map do |extension|
extension.split(File::SEPARATOR, 2).first
end.uniq

paths.concat ext_dirs
end

paths.uniq
raise NotImplementedError
end

##
@@ -278,13 +139,5 @@ def version
raise NotImplementedError
end

##
# Whether this specification is stubbed - i.e. we have information
# about the gem from a stub line, without having to evaluate the
# entire gemspec file.
def stubbed?
raise NotImplementedError
end

end

5 changes: 1 addition & 4 deletions lib/ruby/shared/rubygems/command.rb
Original file line number Diff line number Diff line change
@@ -148,8 +148,6 @@ def execute

##
# Display to the user that a gem couldn't be found and reasons why
#--
# TODO: replace +domain+ with a parameter to suppress suggestions

def show_lookup_failure(gem_name, version, errors, domain)
if errors and !errors.empty?
@@ -559,8 +557,7 @@ def wrap(text, width) # :doc:
Further help:
gem help commands list all 'gem' commands
gem help examples show some examples of usage
gem help gem_dependencies gem dependencies file guide
gem help platforms gem platforms guide
gem help platforms show information about platforms
gem help <COMMAND> show help on COMMAND
(e.g. 'gem help install')
gem server present a web page at
3 changes: 1 addition & 2 deletions lib/ruby/shared/rubygems/command_manager.rb
Original file line number Diff line number Diff line change
@@ -48,7 +48,6 @@ class Gem::CommandManager
:list,
:lock,
:mirror,
:open,
:outdated,
:owner,
:pristine,
@@ -137,7 +136,7 @@ def command_names
def run(args, build_args=nil)
process_args(args, build_args)
rescue StandardError, Timeout::Error => ex
alert_error "While executing gem ... (#{ex.class})\n #{ex}"
alert_error "While executing gem ... (#{ex.class})\n #{ex.to_s}"
ui.backtrace ex

terminate_interaction(1)
24 changes: 13 additions & 11 deletions lib/ruby/shared/rubygems/commands/cert_command.rb
Original file line number Diff line number Diff line change
@@ -129,21 +129,23 @@ def build_cert name, key # :nodoc:
end

def build_key # :nodoc:
return options[:key] if options[:key]
if options[:key] then
options[:key]
else
passphrase = ask_for_password 'Passphrase for your Private Key:'
say "\n"

passphrase = ask_for_password 'Passphrase for your Private Key:'
say "\n"
passphrase_confirmation = ask_for_password 'Please repeat the passphrase for your Private Key:'
say "\n"

passphrase_confirmation = ask_for_password 'Please repeat the passphrase for your Private Key:'
say "\n"
raise Gem::CommandLineError,
"Passphrase and passphrase confirmation don't match" unless passphrase == passphrase_confirmation

raise Gem::CommandLineError,
"Passphrase and passphrase confirmation don't match" unless passphrase == passphrase_confirmation
key = Gem::Security.create_key
key_path = Gem::Security.write key, "gem-private_key.pem", 0600, passphrase

key = Gem::Security.create_key
key_path = Gem::Security.write key, "gem-private_key.pem", 0600, passphrase

return key, key_path
return key, key_path
end
end

def certificates_matching filter
4 changes: 2 additions & 2 deletions lib/ruby/shared/rubygems/commands/cleanup_command.rb
Original file line number Diff line number Diff line change
@@ -67,10 +67,10 @@ def execute

say "Clean Up Complete"

verbose do
if Gem.configuration.really_verbose then
skipped = @default_gems.map { |spec| spec.full_name }

"Skipped default gems: #{skipped.join ', '}"
say "Skipped default gems: #{skipped.join ', '}"
end
end

34 changes: 7 additions & 27 deletions lib/ruby/shared/rubygems/commands/contents_command.rb
Original file line number Diff line number Diff line change
@@ -8,8 +8,7 @@ class Gem::Commands::ContentsCommand < Gem::Command

def initialize
super 'contents', 'Display the contents of the installed gems',
:specdirs => [], :lib_only => false, :prefix => true,
:show_install_dir => false
:specdirs => [], :lib_only => false, :prefix => true

add_version_option

@@ -33,11 +32,6 @@ def initialize
options[:prefix] = prefix
end

add_option( '--[no-]show-install-dir',
'Show only the gem install dir') do |show, options|
options[:show_install_dir] = show
end

@path_kind = nil
@spec_dirs = nil
@version = nil
@@ -71,12 +65,7 @@ def execute
names = gem_names

names.each do |name|
found =
if options[:show_install_dir] then
gem_install_dir name
else
gem_contents name
end
found = gem_contents name

terminate_interaction 1 unless found or names.length > 1
end
@@ -102,14 +91,14 @@ def files_in_gem spec
end

def files_in_default_gem spec
spec.files.map do |file|
spec.files.sort.map do |file|
case file
when /\A#{spec.bindir}\//
[RbConfig::CONFIG['bindir'], $POSTMATCH]
[Gem::ConfigMap[:bindir], $POSTMATCH]
when /\.so\z/
[RbConfig::CONFIG['archdir'], file]
[Gem::ConfigMap[:archdir], file]
else
[RbConfig::CONFIG['rubylibdir'], file]
[Gem::ConfigMap[:rubylibdir], file]
end
end
end
@@ -126,16 +115,6 @@ def gem_contents name
true
end

def gem_install_dir name
spec = spec_for name

return false unless spec

say spec.gem_dir

true
end

def gem_names # :nodoc:
if options[:all] then
Gem::Specification.map(&:name)
@@ -146,6 +125,7 @@ def gem_names # :nodoc:

def path_description spec_dirs # :nodoc:
if spec_dirs.empty? then
spec_dirs = Gem::Specification.dirs
"default gem paths"
else
"specified path"
4 changes: 2 additions & 2 deletions lib/ruby/shared/rubygems/commands/dependency_command.rb
Original file line number Diff line number Diff line change
@@ -31,7 +31,7 @@ def initialize
end

def arguments # :nodoc:
"REGEXP show dependencies for gems whose names start with REGEXP"
"GEMNAME name of gem to show dependencies for"
end

def defaults_str # :nodoc:
@@ -50,7 +50,7 @@ def description # :nodoc:
end

def usage # :nodoc:
"#{program_name} REGEXP"
"#{program_name} GEMNAME"
end

def fetch_remote_specs dependency # :nodoc:
7 changes: 2 additions & 5 deletions lib/ruby/shared/rubygems/commands/environment_command.rb
Original file line number Diff line number Diff line change
@@ -28,9 +28,8 @@ def description # :nodoc:
gemrc files, environment variables and built-in defaults.
Command line argument defaults and some RubyGems defaults can be set in a
~/.gemrc file for individual users and a gemrc in the SYSTEM CONFIGURATION
DIRECTORY for all users. These files are YAML files with the following YAML
keys:
~/.gemrc file for individual users and a /etc/gemrc for all users. These
files are YAML files with the following YAML keys:
:sources: A YAML array of remote gem repositories to install gems from
:verbose: Verbosity of the gem command. false, true, and :really are the
@@ -121,8 +120,6 @@ def show_environment # :nodoc:

out << " - SPEC CACHE DIRECTORY: #{Gem.spec_cache_dir}\n"

out << " - SYSTEM CONFIGURATION DIRECTORY: #{Gem::ConfigFile::SYSTEM_CONFIG_PATH}\n"

out << " - RUBYGEMS PLATFORMS:\n"
Gem.platforms.each do |platform|
out << " - #{platform}\n"
Original file line number Diff line number Diff line change
@@ -62,7 +62,7 @@ def description # :nodoc:
end

def execute
# This is always true because it's the only way now.
# This is always true becasue it's the only way now.
options[:build_modern] = true

if not File.exist?(options[:directory]) or
219 changes: 20 additions & 199 deletions lib/ruby/shared/rubygems/commands/help_command.rb
Original file line number Diff line number Diff line change
@@ -52,183 +52,6 @@ class Gem::Commands::HelpCommand < Gem::Command
gem update --system
EOF

GEM_DEPENDENCIES = <<-EOF
A gem dependencies file allows installation of a consistent set of gems across
multiple environments. The RubyGems implementation is designed to be
compatible with Bundler's Gemfile format. You can see additional
documentation on the format at:
http://bundler.io
RubyGems automatically looks for these gem dependencies files:
* gem.deps.rb
* Gemfile
* Isolate
These files are looked up automatically using `gem install -g`, or you can
specify a custom file.
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.
You can also activate gem dependencies at program startup using
Gem.use_gemdeps.
NOTE: Enabling automatic discovery on multiuser systems can lead to execution
of arbitrary code when used from directories outside your control.
Gem Dependencies
================
Use #gem to declare which gems you directly depend upon:
gem 'rake'
To depend on a specific set of versions:
gem 'rake', '~> 10.3', '>= 10.3.2'
RubyGems will require the gem name when activating the gem using
the RUBYGEMS_GEMDEPS environment variable or Gem::use_gemdeps. Use the
require: option to override this behavior if the gem does not have a file of
that name or you don't want to require those files:
gem 'my_gem', require: 'other_file'
To prevent RubyGems from requiring any files use:
gem 'my_gem', require: false
To load dependencies from a .gemspec file:
gemspec
RubyGems looks for the first .gemspec file in the current directory. To
override this use the name: option:
gemspec name: 'specific_gem'
To look in a different directory use the path: option:
gemspec name: 'specific_gem', path: 'gemspecs'
To depend on a gem unpacked into a local directory:
gem 'modified_gem', path: 'vendor/modified_gem'
To depend on a gem from git:
gem 'private_gem', git: 'git@my.company.example:private_gem.git'
To depend on a gem from github:
gem 'private_gem', github: 'my_company/private_gem'
To depend on a gem from a github gist:
gem 'bang', gist: '1232884'
Git, github and gist support the ref:, branch: and tag: options to specify a
commit reference or hash, branch or tag respectively to use for the gem.
Setting the submodules: option to true for git, github and gist dependencies
causes fetching of submodules when fetching the repository.
You can depend on multiple gems from a single repository with the git method:
git 'https://github.com/rails/rails.git' do
gem 'activesupport'
gem 'activerecord'
end
Gem Sources
===========
RubyGems uses the default sources for regular `gem install` for gem
dependencies files. Unlike bundler, you do need to specify a source.
You can override the sources used for downloading gems with:
source 'https://gem_server.example'
You may specify multiple sources. Unlike bundler the prepend: option is not
supported. Sources are used in-order, to prepend a source place it at the
front of the list.
Gem Platform
============
You can restrict gem dependencies to specific platforms with the #platform
and #platforms methods:
platform :ruby_21 do
gem 'debugger'
end
See the bundler Gemfile manual page for a list of platforms supported in a gem
dependencies file.:
http://bundler.io/v1.6/man/gemfile.5.html
Ruby Version and Engine Dependency
==================================
You can specifiy the version, engine and engine version of ruby to use with
your gem dependencies file. If you are not running the specified version
RubyGems will raise an exception.
To depend on a specific version of ruby:
ruby '2.1.2'
To depend on a specific ruby engine:
ruby '1.9.3', engine: 'jruby'
To depend on a specific ruby engine version:
ruby '1.9.3', engine: 'jruby', engine_version: '1.7.11'
Grouping Dependencies
=====================
Gem dependencies may be placed in groups that can be excluded from install.
Dependencies required for development or testing of your code may be excluded
when installed in a production environment.
A #gem dependency may be placed in a group using the group: option:
gem 'minitest', group: :test
To install dependencies from a gemfile without specific groups use the
`--without` option for `gem install -g`:
$ gem install -g --without test
The group: option also accepts multiple groups if the gem fits in multiple
categories.
Multiple groups may be excluded during install by comma-separating the groups for `--without` or by specifying `--without` multiple times.
The #group method can also be used to place gems in groups:
group :test do
gem 'minitest'
gem 'minitest-emoji'
end
The #group method allows multiple groups.
The #gemspec development dependencies are placed in the :development group by
default. This may be overriden with the :development_group option:
gemspec development_group: :other
EOF

PLATFORMS = <<-'EOF'
RubyGems platforms are composed of three parts, a CPU, an OS, and a
version. These values are taken from values in rbconfig.rb. You can view
@@ -267,16 +90,6 @@ class Gem::Commands::HelpCommand < Gem::Command
Gem::Platform::CURRENT. This will correctly mark the gem with your ruby's
platform.
EOF

# NOTE when updating also update Gem::Command::HELP

SUBCOMMANDS = [
["commands", :show_commands],
["options", Gem::Command::HELP],
["examples", EXAMPLES],
["gem_dependencies", GEM_DEPENDENCIES],
["platforms", PLATFORMS],
]
# :startdoc:

def initialize
@@ -285,27 +98,35 @@ def initialize
@command_manager = Gem::CommandManager.instance
end

def arguments # :nodoc:
args = <<-EOF
commands List all 'gem' commands
examples Show examples of 'gem' usage
<command> Show specific help for <command>
EOF
return args.gsub(/^\s+/, '')
end

def usage # :nodoc:
"#{program_name} ARGUMENT"
end

def execute
arg = options[:args][0]

_, help = SUBCOMMANDS.find do |command,|
begins? command, arg
end
if begins? "commands", arg then
show_commands

if help then
if Symbol === help then
send help
else
say help
end
return
end
elsif begins? "options", arg then
say Gem::Command::HELP

elsif begins? "examples", arg then
say EXAMPLES

elsif begins? "platforms", arg then
say PLATFORMS

if options[:help] then
elsif options[:help] then
show_help

elsif arg then
145 changes: 19 additions & 126 deletions lib/ruby/shared/rubygems/commands/install_command.rb
Original file line number Diff line number Diff line change
@@ -21,10 +21,7 @@ class Gem::Commands::InstallCommand < Gem::Command
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
@@ -35,53 +32,19 @@ def initialize
add_version_option
add_prerelease_option "to be installed. (Only for listed gems)"

add_option(:"Install/Update", '-g', '--file [FILE]',
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 = []
@installed_specs = nil
end

def arguments # :nodoc:
@@ -90,7 +53,7 @@ def arguments # :nodoc:

def defaults_str # :nodoc:
"--both --version '#{Gem::Requirement.default}' --document --no-force\n" +
"--install-dir #{Gem.dir} --lock"
"--install-dir #{Gem.dir}"
end

def description # :nodoc:
@@ -104,25 +67,6 @@ def description # :nodoc:
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
@@ -185,9 +129,9 @@ def check_version # :nodoc:
end

def execute
if options.include? :gemdeps then
install_from_gemdeps
return # not reached
if gf = options[:gemdeps] then
install_from_gemdeps gf
return
end

@installed_specs = []
@@ -203,14 +147,17 @@ def execute

show_installed

terminate_interaction exit_code
raise Gem::SystemExitException, exit_code
end

def install_from_gemdeps # :nodoc:
def install_from_gemdeps gf # :nodoc:
require 'rubygems/request_set'
rs = Gem::RequestSet.new
rs.load_gemdeps gf

specs = rs.install_from_gemdeps options do |req, inst|
rs.resolve

specs = rs.install options do |req, inst|
s = req.full_spec

if inst
@@ -222,71 +169,19 @@ def install_from_gemdeps # :nodoc:

@installed_specs = specs

terminate_interaction
raise Gem::SystemExitException, 0
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.new gem, options
inst.install

require 'rubygems/dependency_installer'
dinst = Gem::DependencyInstaller.new options
dinst.installed_gems.replace [inst.spec]
inst = Gem::DependencyInstaller.new options
inst.install name, Gem::Requirement.create(version)

Gem.done_installing_hooks.each do |hook|
hook.call dinst, [inst.spec]
end unless Gem.done_installing_hooks.empty?
@installed_specs.push(*inst.installed_gems)

@installed_specs.push(inst.spec)
show_install_errors inst.errors
end

def install_gems # :nodoc:
@@ -300,10 +195,8 @@ def install_gems # :nodoc:
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
rescue Gem::GemNotFoundException => e
show_lookup_failure e.name, e.version, e.errors, options[:domain]

exit_code |= 2
end
12 changes: 9 additions & 3 deletions lib/ruby/shared/rubygems/commands/list_command.rb
Original file line number Diff line number Diff line change
@@ -8,13 +8,13 @@
class Gem::Commands::ListCommand < Gem::Commands::QueryCommand

def initialize
super 'list', 'Display local gems whose name matches REGEXP'
super 'list', 'Display local gems whose name starts with STRING'

remove_option('--name-matches')
end

def arguments # :nodoc:
"REGEXP regexp to look for in gem name"
"STRING start of gem name to look for"
end

def defaults_str # :nodoc:
@@ -33,7 +33,13 @@ def description # :nodoc:
end

def usage # :nodoc:
"#{program_name} [STRING ...]"
"#{program_name} [STRING]"
end

def execute
string = get_one_optional_argument || ''
options[:name] = /^#{string}/i
super
end

end
32 changes: 15 additions & 17 deletions lib/ruby/shared/rubygems/commands/mirror_command.rb
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
require 'rubygems/command'

unless defined? Gem::Commands::MirrorCommand
class Gem::Commands::MirrorCommand < Gem::Command
def initialize
super('mirror', 'Mirror all gem files (requires rubygems-mirror)')
begin
Gem::Specification.find_by_name('rubygems-mirror').activate
rescue Gem::LoadError
# no-op
end
class Gem::Commands::MirrorCommand < Gem::Command
def initialize
super('mirror', 'Mirror all gem files (requires rubygems-mirror)')
begin
Gem::Specification.find_by_name('rubygems-mirror').activate
rescue Gem::LoadError
# no-op
end
end

def description # :nodoc:
<<-EOF
def description # :nodoc:
<<-EOF
The mirror command has been moved to the rubygems-mirror gem.
EOF
end

def execute
alert_error "Install the rubygems-mirror gem for the mirror command"
end
EOF
end

def execute
alert_error "Install the rubygems-mirror gem for the mirror command"
end

end
74 changes: 0 additions & 74 deletions lib/ruby/shared/rubygems/commands/open_command.rb

This file was deleted.

2 changes: 1 addition & 1 deletion lib/ruby/shared/rubygems/commands/outdated_command.rb
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ def initialize

def description # :nodoc:
<<-EOF
The outdated command lists gems you may wish to upgrade to a newer version.
The outdated command lists gems you way wish to upgrade to a newer version.
You can check for dependency mismatches using the dependency command and
update the gems with the update or install commands.
4 changes: 1 addition & 3 deletions lib/ruby/shared/rubygems/commands/owner_command.rb
Original file line number Diff line number Diff line change
@@ -86,9 +86,7 @@ def manage_owners method, name, owners
request.add_field "Authorization", api_key
end

action = method == :delete ? "Removing" : "Adding"

with_response response, "#{action} #{owner}"
with_response response, "Removing #{owner}"
rescue
# ignore
end
31 changes: 2 additions & 29 deletions lib/ruby/shared/rubygems/commands/pristine_command.rb
Original file line number Diff line number Diff line change
@@ -12,7 +12,6 @@ def initialize
'Restores installed gems to pristine condition from files located in the gem cache',
:version => Gem::Requirement.default,
:extensions => true,
:extensions_set => false,
:all => false

add_option('--all',
@@ -24,8 +23,7 @@ def initialize
add_option('--[no-]extensions',
'Restore gems with extensions',
'in addition to regular gems') do |value, options|
options[:extensions_set] = true
options[:extensions] = value
options[:extensions] = value
end

add_option('--only-executables',
@@ -64,9 +62,6 @@ def description # :nodoc:
If --no-extensions is provided pristine will not attempt to restore a gem
with an extension.
If --extensions is given (but not --all or gem names) only gems with
extensions will be restored.
EOF
end

@@ -77,14 +72,6 @@ def usage # :nodoc:
def execute
specs = if options[:all] then
Gem::Specification.map

# `--extensions` must be explicitly given to pristine only gems
# with extensions.
elsif options[:extensions_set] and
options[:extensions] and options[:args].empty? then
Gem::Specification.select do |spec|
spec.extensions and not spec.extensions.empty?
end
else
get_all_gem_names.map do |gem_name|
Gem::Specification.find_all_by_name gem_name, options[:version]
@@ -109,11 +96,6 @@ def execute
next
end

if spec.bundled_gem_in_old_ruby?
say "Skipped #{spec.full_name}, it is bundled with old Ruby"
next
end

unless spec.extensions.empty? or options[:extensions] then
say "Skipped #{spec.full_name}, it needs to compile an extension"
next
@@ -125,17 +107,8 @@ def execute
require 'rubygems/remote_fetcher'

say "Cached gem for #{spec.full_name} not found, attempting to fetch..."

dep = Gem::Dependency.new spec.name, spec.version
found, _ = Gem::SpecFetcher.fetcher.spec_for_dependency dep

if found.empty?
say "Skipped #{spec.full_name}, it was not found from cache and remote sources"
next
end

spec_candidate, source = found.first
Gem::RemoteFetcher.fetcher.download spec_candidate, source.uri.to_s, spec.base_dir
Gem::RemoteFetcher.fetcher.download_to_cache dep
end

env_shebang =
13 changes: 4 additions & 9 deletions lib/ruby/shared/rubygems/commands/push_command.rb
Original file line number Diff line number Diff line change
@@ -69,18 +69,13 @@ def send_gem name
terminate_interaction 1
end

gem_data = Gem::Package.new(name)

unless @host then
@host = gem_data.spec.metadata['default_gem_server']
if gem_data = Gem::Package.new(name) then
@host = gem_data.spec.metadata['default_gem_server']
end
end

# Always include this, even if it's nil
args << @host

if gem_data.spec.metadata.has_key?('allowed_push_host')
args << gem_data.spec.metadata['allowed_push_host']
end
args << @host if @host

say "Pushing gem to #{@host || Gem.host}..."

50 changes: 17 additions & 33 deletions lib/ruby/shared/rubygems/commands/query_command.rb
Original file line number Diff line number Diff line change
@@ -72,26 +72,16 @@ def description # :nodoc:

def execute
exit_code = 0
if options[:args].to_a.empty? and options[:name].source.empty?
name = options[:name]
no_name = true
elsif !options[:name].source.empty?
name = Array(options[:name])
else
name = options[:args].to_a.map{|arg| /#{arg}/i }
end

name = options[:name]
prerelease = options[:prerelease]

unless options[:installed].nil? then
if no_name then
if name.source.empty? then
alert_error "You must specify a gem name"
exit_code |= 4
elsif name.count > 1
alert_error "You must specify only ONE gem!"
exit_code |= 4
else
installed = installed? name.first, options[:version]
installed = installed? name, options[:version]
installed = !installed unless options[:installed]

if installed then
@@ -105,22 +95,6 @@ def execute
terminate_interaction exit_code
end

names = Array(name)
names.each { |n| show_gems n, prerelease }
end

private

def display_header type
if (ui.outs.tty? and Gem.configuration.verbose) or both? then
say
say "*** #{type} GEMS ***"
say
end
end

#Guts of original execute
def show_gems name, prerelease
req = Gem::Requirement.default
# TODO: deprecate for real
dep = Gem::Deprecate.skip_during { Gem::Dependency.new name, req }
@@ -131,7 +105,11 @@ def show_gems name, prerelease
alert_warning "prereleases are always shown locally"
end

display_header 'LOCAL'
if ui.outs.tty? or both? then
say
say "*** LOCAL GEMS ***"
say
end

specs = Gem::Specification.find_all { |s|
s.name =~ name and req =~ s.version
@@ -145,7 +123,11 @@ def show_gems name, prerelease
end

if remote? then
display_header 'REMOTE'
if ui.outs.tty? or both? then
say
say "*** REMOTE GEMS ***"
say
end

fetcher = Gem::SpecFetcher.fetcher

@@ -161,18 +143,20 @@ def show_gems name, prerelease
:latest
end

if name.source.empty?
if options[:name].source.empty?
spec_tuples = fetcher.detect(type) { true }
else
spec_tuples = fetcher.detect(type) do |name_tuple|
name === name_tuple.name
options[:name] === name_tuple.name
end
end

output_query_results spec_tuples
end
end

private

##
# Check if gem +name+ version +version+ is installed.

16 changes: 11 additions & 5 deletions lib/ruby/shared/rubygems/commands/search_command.rb
Original file line number Diff line number Diff line change
@@ -4,15 +4,15 @@
class Gem::Commands::SearchCommand < Gem::Commands::QueryCommand

def initialize
super 'search', 'Display remote gems whose name matches REGEXP'
super 'search', 'Display remote gems whose name contains STRING'

remove_option '--name-matches'

defaults[:domain] = :remote
end

def arguments # :nodoc:
"REGEXP regexp to search for in gem name"
"STRING fragment of gem name to search for"
end

def defaults_str # :nodoc:
@@ -21,8 +21,8 @@ def defaults_str # :nodoc:

def description # :nodoc:
<<-EOF
The search command displays remote gems whose name matches the given
regexp.
The search command displays remote gems whose name contains the given
string.
The --details option displays additional details from the gem but will
take a little longer to complete as it must download the information
@@ -33,7 +33,13 @@ def description # :nodoc:
end

def usage # :nodoc:
"#{program_name} [REGEXP]"
"#{program_name} [STRING]"
end

def execute
string = get_one_optional_argument
options[:name] = /#{string}/i
super
end

end
18 changes: 9 additions & 9 deletions lib/ruby/shared/rubygems/commands/setup_command.rb
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ def initialize

super 'setup', 'Install RubyGems',
:format_executable => true, :document => %w[ri],
:site_or_vendor => 'sitelibdir',
:site_or_vendor => :sitelibdir,
:destdir => '', :prefix => '', :previous_version => ''

add_option '--previous-version=VERSION',
@@ -36,7 +36,7 @@ def initialize

add_option '--[no-]vendor',
'Install into vendorlibdir not sitelibdir' do |vendor, options|
options[:site_or_vendor] = vendor ? 'vendorlibdir' : 'sitelibdir'
options[:site_or_vendor] = vendor ? :vendorlibdir : :sitelibdir
end

add_option '--[no-]format-executable',
@@ -343,19 +343,19 @@ def generate_default_dirs(install_destdir)
site_or_vendor = options[:site_or_vendor]

if prefix.empty? then
lib_dir = RbConfig::CONFIG[site_or_vendor]
bin_dir = RbConfig::CONFIG['bindir']
lib_dir = Gem::ConfigMap[site_or_vendor]
bin_dir = Gem::ConfigMap[:bindir]
else
# Apple installed RubyGems into libdir, and RubyGems <= 1.1.0 gets
# confused about installation location, so switch back to
# sitelibdir/vendorlibdir.
if defined?(APPLE_GEM_HOME) and
# just in case Apple and RubyGems don't get this patched up proper.
(prefix == RbConfig::CONFIG['libdir'] or
(prefix == Gem::ConfigMap[:libdir] or
# this one is important
prefix == File.join(RbConfig::CONFIG['libdir'], 'ruby')) then
lib_dir = RbConfig::CONFIG[site_or_vendor]
bin_dir = RbConfig::CONFIG['bindir']
prefix == File.join(Gem::ConfigMap[:libdir], 'ruby')) then
lib_dir = Gem::ConfigMap[site_or_vendor]
bin_dir = Gem::ConfigMap[:bindir]
else
lib_dir = File.join prefix, 'lib'
bin_dir = File.join prefix, 'bin'
@@ -446,7 +446,7 @@ def show_release_notes
history.force_encoding Encoding::UTF_8 if
Object.const_defined? :Encoding

history = history.sub(/^# coding:.*?(?=^=)/m, '')
history = history.sub(/^# coding:.*?^=/m, '')

text = history.split(HISTORY_HEADER)
text.shift # correct an off-by-one generated by split
2 changes: 1 addition & 1 deletion lib/ruby/shared/rubygems/commands/specification_command.rb
Original file line number Diff line number Diff line change
@@ -127,7 +127,7 @@ def execute
end

unless options[:all] then
specs = [specs.max_by { |s| s.version }]
specs = [specs.sort_by { |s| s.version }.last]
end

specs.each do |s|
16 changes: 2 additions & 14 deletions lib/ruby/shared/rubygems/commands/uninstall_command.rb
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ class Gem::Commands::UninstallCommand < Gem::Command
def initialize
super 'uninstall', 'Uninstall gems from the local repository',
:version => Gem::Requirement.default, :user_install => true,
:check_dev => false, :vendor => false
:check_dev => false

add_option('-a', '--[no-]all',
'Uninstall all matching versions'
@@ -76,18 +76,6 @@ def initialize

add_version_option
add_platform_option

add_option('--vendor',
'Uninstall gem from the vendor directory.',
'Only for use by gem repackagers.') do |value, options|
unless Gem.vendor_dir then
raise OptionParser::InvalidOption.new 'your platform is not supported'
end

alert_warning 'Use your OS package manager to uninstall vendor gems'
options[:vendor] = true
options[:install_dir] = Gem.vendor_dir
end
end

def arguments # :nodoc:
@@ -124,7 +112,7 @@ def execute
end

def uninstall_all
specs = Gem::Specification.reject { |spec| spec.default_gem? }
_, specs = Gem::Specification.partition { |spec| spec.default_gem? }

specs.each do |spec|
options[:version] = spec.version
2 changes: 1 addition & 1 deletion lib/ruby/shared/rubygems/commands/unpack_command.rb
Original file line number Diff line number Diff line change
@@ -134,7 +134,7 @@ def get_path dependency

specs = dependency.matching_specs

selected = specs.max_by { |s| s.version }
selected = specs.sort_by { |s| s.version }.last # HACK: hunt last down

return Gem::RemoteFetcher.fetcher.download_to_cache(dependency) unless
selected
39 changes: 15 additions & 24 deletions lib/ruby/shared/rubygems/commands/update_command.rb
Original file line number Diff line number Diff line change
@@ -16,8 +16,6 @@ class Gem::Commands::UpdateCommand < Gem::Command

attr_reader :installer # :nodoc:

attr_reader :updated # :nodoc:

def initialize
super 'update', 'Update installed gems to the latest version',
:document => %w[rdoc ri],
@@ -47,7 +45,7 @@ def initialize
end

def arguments # :nodoc:
"REGEXP regexp to search for in gem name"
"GEMNAME name of gem to update"
end

def defaults_str # :nodoc:
@@ -58,13 +56,13 @@ def description # :nodoc:
<<-EOF
The update command will update your gems to the latest version.
The update command does not remove the previous version. Use the cleanup
The update comamnd does not remove the previous version. Use the cleanup
command to remove old versions.
EOF
end

def usage # :nodoc:
"#{program_name} REGEXP [REGEXP ...]"
"#{program_name} GEMNAME [GEMNAME ...]"
end

def check_latest_rubygems version # :nodoc:
@@ -84,6 +82,8 @@ def check_update_arguments # :nodoc:
end

def execute
hig = {}

if options[:system] then
update_rubygems
return
@@ -97,14 +97,10 @@ def execute

updated = update_gems gems_to_update

updated_names = updated.map { |spec| spec.name }
not_updated_names = options[:args].uniq - updated_names

if updated.empty? then
say "Nothing to update"
else
say "Gems updated: #{updated_names.join(' ')}"
say "Gems already up-to-date: #{not_updated_names.join(' ')}" unless not_updated_names.empty?
say "Gems updated: #{updated.map { |spec| spec.name }.join ' '}"
end
end

@@ -114,11 +110,7 @@ def fetch_remote_gems spec # :nodoc:

fetcher = Gem::SpecFetcher.fetcher

spec_tuples, errors = fetcher.search_for_dependency dependency

error = errors.find { |e| e.respond_to? :exception }

raise error if error
spec_tuples, _ = fetcher.search_for_dependency dependency

spec_tuples
end
@@ -142,7 +134,7 @@ def highest_remote_version spec # :nodoc:
g.name == spec.name and g.match_platform?
end

highest_remote_gem = matching_gems.max_by { |g,_| g.version }
highest_remote_gem = matching_gems.sort_by { |g,_| g.version }.last

highest_remote_gem ||= [Gem::NameTuple.null]

@@ -201,16 +193,17 @@ def rubygems_target_version
def update_gem name, version = Gem::Requirement.default
return if @updated.any? { |spec| spec.name == name }

update_options = options.dup
update_options[:prerelease] = version.prerelease?
@installer ||= Gem::DependencyInstaller.new options

@installer = Gem::DependencyInstaller.new update_options
success = false

say "Updating #{name}"
begin
@installer.install name, Gem::Requirement.new(version)
rescue Gem::InstallError, Gem::DependencyError => e
success = true
rescue Gem::InstallError => e
alert_error "Error installing #{name}:\n\t#{e.message}"
success = false
end

@installer.installed_gems.each do |spec|
@@ -251,9 +244,6 @@ def update_rubygems_arguments # :nodoc:
args << '--no-rdoc' unless options[:document].include? 'rdoc'
args << '--no-ri' unless options[:document].include? 'ri'
args << '--no-format-executable' if options[:no_format_executable]
args << '--previous-version' << Gem::VERSION if
options[:system] == true or
Gem::Version.new(options[:system]) >= Gem::Version.new(2)
args
end

@@ -262,7 +252,7 @@ def which_to_update highest_installed_gems, gem_names, system = false

highest_installed_gems.each do |l_name, l_spec|
next if not gem_names.empty? and
gem_names.none? { |name| name == l_spec.name }
gem_names.all? { |name| /#{name}/ !~ l_spec.name }

highest_remote_ver = highest_remote_version l_spec

@@ -275,3 +265,4 @@ def which_to_update highest_installed_gems, gem_names, system = false
end

end

13 changes: 8 additions & 5 deletions lib/ruby/shared/rubygems/commands/which_command.rb
Original file line number Diff line number Diff line change
@@ -35,7 +35,7 @@ def description # :nodoc:
end

def execute
found = true
found = false

options[:args].each do |arg|
arg = arg.sub(/#{Regexp.union(*Gem.suffixes)}$/, '')
@@ -45,9 +45,9 @@ def execute

if spec then
if options[:search_gems_first] then
dirs = spec.full_require_paths + $LOAD_PATH
dirs = gem_paths(spec) + $LOAD_PATH
else
dirs = $LOAD_PATH + spec.full_require_paths
dirs = $LOAD_PATH + gem_paths(spec)
end
end

@@ -56,10 +56,9 @@ def execute

if paths.empty? then
alert_error "Can't find ruby library file or shared library #{arg}"

found &&= false
else
say paths
found = true
end
end

@@ -82,6 +81,10 @@ def find_paths(package_name, dirs)
result
end

def gem_paths(spec)
spec.require_paths.collect { |d| File.join spec.full_gem_path, d }
end

def usage # :nodoc:
"#{program_name} FILE [FILE ...]"
end
21 changes: 13 additions & 8 deletions lib/ruby/shared/rubygems/commands/yank_command.rb
Original file line number Diff line number Diff line change
@@ -44,40 +44,45 @@ def initialize
options[:undo] = true
end

add_key_option
add_option('-k', '--key KEY_NAME',
'Use API key from your gem credentials file') do |value, options|
options[:key] = value
end
end

def execute
sign_in

version = get_version_from_requirements(options[:version])
platform = get_platform_from_requirements(options)
api_key = Gem.configuration.rubygems_api_key
api_key = Gem.configuration.api_keys[options[:key].to_sym] if options[:key]

if version then
if options[:undo] then
unyank_gem(version, platform)
unyank_gem(version, platform, api_key)
else
yank_gem(version, platform)
yank_gem(version, platform, api_key)
end
else
say "A version argument is required: #{usage}"
terminate_interaction
end
end

def yank_gem(version, platform)
def yank_gem(version, platform, api_key)
say "Yanking gem from #{self.host}..."
yank_api_request(:delete, version, platform, "api/v1/gems/yank")
yank_api_request(:delete, version, platform, "api/v1/gems/yank", api_key)
end

def unyank_gem(version, platform)
def unyank_gem(version, platform, api_key)
say "Unyanking gem from #{host}..."
yank_api_request(:put, version, platform, "api/v1/gems/unyank")
yank_api_request(:put, version, platform, "api/v1/gems/unyank", api_key)
end

private

def yank_api_request(method, version, platform, api)
def yank_api_request(method, version, platform, api, api_key)
name = get_one_gem_name
response = rubygems_api_request(method, api) do |request|
request.add_field("Authorization", api_key)
7 changes: 1 addition & 6 deletions lib/ruby/shared/rubygems/compatibility.rb
Original file line number Diff line number Diff line change
@@ -33,12 +33,7 @@ class << Gem
module Gem
RubyGemsVersion = VERSION

# TODO remove at RubyGems 3

RbConfigPriorities = %w[
MAJOR
MINOR
TEENY
EXEEXT RUBY_SO_NAME arch bindir datadir libdir ruby_install_name
ruby_version rubylibprefix sitedir sitelibdir vendordir vendorlibdir
rubylibdir
@@ -47,7 +42,7 @@ module Gem
unless defined?(ConfigMap)
##
# Configuration settings from ::RbConfig
ConfigMap = Hash.new do |cm, key| # TODO remove at RubyGems 3
ConfigMap = Hash.new do |cm, key|
cm[key] = RbConfig::CONFIG[key.to_s]
end
else
22 changes: 5 additions & 17 deletions lib/ruby/shared/rubygems/config_file.rb
Original file line number Diff line number Diff line change
@@ -57,7 +57,7 @@ class Gem::ConfigFile

# :stopdoc:

SYSTEM_CONFIG_PATH =
system_config_path =
begin
require "etc"
Etc.sysconfdir
@@ -86,7 +86,7 @@ class Gem::ConfigFile

# :startdoc:

SYSTEM_WIDE_CONFIG_FILE = File.join SYSTEM_CONFIG_PATH, 'gemrc'
SYSTEM_WIDE_CONFIG_FILE = File.join system_config_path, 'gemrc'

##
# List of arguments supplied to the config file object.
@@ -137,10 +137,9 @@ class Gem::ConfigFile
attr_reader :ssl_verify_mode

##
# Path name of directory or file of openssl CA certificate, used for remote
# https connection
# Path name of directory or file of openssl CA certificate, used for remote https connection

attr_accessor :ssl_ca_cert
attr_reader :ssl_ca_cert

##
# Path name of directory or file of openssl client certificate, used for remote https connection with client authentication
@@ -337,7 +336,7 @@ def load_file(filename)
end
return content
rescue *YAMLErrors => e
warn "Failed to load #{filename}, #{e}"
warn "Failed to load #{filename}, #{e.to_s}"
rescue Errno::EACCES
warn "Failed to load #{filename} due to permissions problem."
end
@@ -383,8 +382,6 @@ def handle_arguments(arg_list)
@backtrace = true
when /^--debug$/ then
$DEBUG = true

warn 'NOTE: Debugging mode prints all exceptions even when rescued'
else
@args << arg
end
@@ -430,15 +427,6 @@ def to_yaml # :nodoc:
DEFAULT_VERBOSITY
end

yaml_hash[:ssl_verify_mode] =
@hash[:ssl_verify_mode] if @hash.key? :ssl_verify_mode

yaml_hash[:ssl_ca_cert] =
@hash[:ssl_ca_cert] if @hash.key? :ssl_ca_cert

yaml_hash[:ssl_client_cert] =
@hash[:ssl_client_cert] if @hash.key? :ssl_client_cert

keys = yaml_hash.keys.map { |key| key.to_s }
keys << 'debug'
re = Regexp.union(*keys)
24 changes: 2 additions & 22 deletions lib/ruby/shared/rubygems/core_ext/kernel_gem.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
##
# RubyGems adds the #gem method to allow activation of specific gem versions
# and overrides the #require method on Kernel to make gems appear as if they
# live on the <code>$LOAD_PATH</code>. See the documentation of these methods
# for further detail.

module Kernel

# REFACTOR: This should be pulled out into some kind of hacks file.
@@ -26,11 +20,6 @@ module Kernel
# Kernel#gem should be called *before* any require statements (otherwise
# RubyGems may load a conflicting library version).
#
# Kernel#gem only loads prerelease versions when prerelease +requirements+
# are given:
#
# gem 'rake', '>= 1.1.a', '< 2'
#
# In older RubyGems versions, the environment variable GEM_SKIP could be
# used to skip activation of specified gems, for example to test out changes
# that haven't been installed yet. Now RubyGems defers to -I and the
@@ -55,17 +44,8 @@ def gem(gem_name, *requirements) # :doc:
gem_name = gem_name.name
end

dep = Gem::Dependency.new(gem_name, *requirements)

loaded = Gem.loaded_specs[gem_name]

return false if loaded && dep.matches_spec?(loaded)

spec = dep.to_spec

Gem::LOADED_SPECS_MUTEX.synchronize {
spec.activate
} if spec
spec = Gem::Dependency.new(gem_name, *requirements).to_spec
spec.activate if spec
end

private :gem
36 changes: 23 additions & 13 deletions lib/ruby/shared/rubygems/core_ext/kernel_require.rb
Original file line number Diff line number Diff line change
@@ -50,8 +50,12 @@ def require path
# normal require handle loading a gem from the rescue below.

if Gem::Specification.unresolved_deps.empty? then
RUBYGEMS_ACTIVATION_MONITOR.exit
return gem_original_require(path)
begin
RUBYGEMS_ACTIVATION_MONITOR.exit
return gem_original_require(path)
ensure
RUBYGEMS_ACTIVATION_MONITOR.enter
end
end

# If +path+ is for a gem that has already been loaded, don't
@@ -66,7 +70,9 @@ def require path

begin
RUBYGEMS_ACTIVATION_MONITOR.exit
return gem_original_require(spec.to_fullpath(path) || path)
return gem_original_require(path)
ensure
RUBYGEMS_ACTIVATION_MONITOR.enter
end if spec

# Attempt to find +path+ in any unresolved gems...
@@ -99,7 +105,6 @@ def require path
names = found_specs.map(&:name).uniq

if names.size > 1 then
RUBYGEMS_ACTIVATION_MONITOR.exit
raise Gem::LoadError, "#{path} found in multiple gems: #{names.join ', '}"
end

@@ -110,27 +115,32 @@ def require path
unless valid then
le = Gem::LoadError.new "unable to find a version of '#{names.first}' to activate"
le.name = names.first
RUBYGEMS_ACTIVATION_MONITOR.exit
raise le
end

valid.activate
end

RUBYGEMS_ACTIVATION_MONITOR.exit
return gem_original_require(path)
begin
RUBYGEMS_ACTIVATION_MONITOR.exit
return gem_original_require(path)
ensure
RUBYGEMS_ACTIVATION_MONITOR.enter
end
rescue LoadError => load_error
RUBYGEMS_ACTIVATION_MONITOR.enter

if load_error.message.start_with?("Could not find") or
(load_error.message.end_with?(path) and Gem.try_activate(path)) then
RUBYGEMS_ACTIVATION_MONITOR.exit
return gem_original_require(path)
else
RUBYGEMS_ACTIVATION_MONITOR.exit
begin
RUBYGEMS_ACTIVATION_MONITOR.exit
return gem_original_require(path)
ensure
RUBYGEMS_ACTIVATION_MONITOR.enter
end
end

raise load_error
ensure
RUBYGEMS_ACTIVATION_MONITOR.exit
end

private :require
63 changes: 15 additions & 48 deletions lib/ruby/shared/rubygems/defaults.rb
Original file line number Diff line number Diff line change
@@ -29,39 +29,28 @@ def self.default_spec_cache_dir
def self.default_dir
path = if defined? RUBY_FRAMEWORK_VERSION then
[
File.dirname(RbConfig::CONFIG['sitedir']),
File.dirname(ConfigMap[:sitedir]),
'Gems',
RbConfig::CONFIG['ruby_version']
ConfigMap[:ruby_version]
]
elsif RbConfig::CONFIG['rubylibprefix'] then
elsif ConfigMap[:rubylibprefix] then
[
RbConfig::CONFIG['rubylibprefix'],
ConfigMap[:rubylibprefix],
'gems',
RbConfig::CONFIG['ruby_version']
ConfigMap[:ruby_version]
]
else
[
RbConfig::CONFIG['libdir'],
ConfigMap[:libdir],
ruby_engine,
'gems',
RbConfig::CONFIG['ruby_version']
ConfigMap[:ruby_version]
]
end

@default_dir ||= File.join(*path)
end

##
# Returns binary extensions dir for specified RubyGems base dir or nil
# if such directory cannot be determined.
#
# By default, the binary extensions are located side by side with their
# Ruby counterparts, therefore nil is returned

def self.default_ext_dir_for base_dir
nil
end

##
# Paths where RubyGems' .rb files and bin files are installed

@@ -74,7 +63,7 @@ def self.default_rubygems_dirs

def self.user_dir
parts = [Gem.user_home, '.gem', ruby_engine]
parts << RbConfig::CONFIG['ruby_version'] unless RbConfig::CONFIG['ruby_version'].empty?
parts << ConfigMap[:ruby_version] unless ConfigMap[:ruby_version].empty?
File.join parts
end

@@ -89,18 +78,18 @@ def self.path_separator
# Default gem load path

def self.default_path
path = []
path << user_dir if user_home && File.exist?(user_home)
path << default_dir
path << vendor_dir if vendor_dir and File.directory? vendor_dir
path
if Gem.user_home && File.exist?(Gem.user_home) then
[user_dir, default_dir]
else
[default_dir]
end
end

##
# Deduce Ruby's --program-prefix and --program-suffix from its install name

def self.default_exec_format
exec_format = RbConfig::CONFIG['ruby_install_name'].sub('ruby', '%s') rescue '%s'
exec_format = ConfigMap[:ruby_install_name].sub('ruby', '%s') rescue '%s'

unless exec_format =~ /%s/ then
raise Gem::Exception,
@@ -117,7 +106,7 @@ def self.default_bindir
if defined? RUBY_FRAMEWORK_VERSION then # mac framework support
'/usr/bin'
else # generic install
RbConfig::CONFIG['bindir']
ConfigMap[:bindir]
end
end

@@ -152,26 +141,4 @@ def self.default_cert_path
def self.default_gems_use_full_paths?
ruby_engine != 'ruby'
end

##
# Install extensions into lib as well as into the extension directory.

def self.install_extension_in_lib # :nodoc:
true
end

##
# Directory where vendor gems are installed.

def self.vendor_dir # :nodoc:
if vendor_dir = ENV['GEM_VENDOR'] then
return vendor_dir.dup
end

return nil unless RbConfig::CONFIG.key? 'vendordir'

File.join RbConfig::CONFIG['vendordir'], 'gems',
RbConfig::CONFIG['ruby_version']
end

end
59 changes: 19 additions & 40 deletions lib/ruby/shared/rubygems/dependency.rb
Original file line number Diff line number Diff line change
@@ -74,7 +74,7 @@ def hash # :nodoc:
end

def inspect # :nodoc:
if prerelease? then
if @prerelease
"<%s type=%p name=%p requirements=%p prerelease=ok>" %
[self.class, self.type, self.name, requirement.to_s]
else
@@ -145,6 +145,7 @@ def requirement
@requirement = @version_requirements if defined?(@version_requirements)
end

# DOC: this method needs documentation or :nodoc''d
def requirements_list
requirement.as_list
end
@@ -204,19 +205,9 @@ def =~ other

alias === =~

##
# :call-seq:
# dep.match? name => true or false
# dep.match? name, version => true or false
# dep.match? spec => true or false
#
# Does this dependency match the specification described by +name+ and
# +version+ or match +spec+?
#
# NOTE: Unlike #matches_spec? this method does not return true when the
# version is a prerelease version unless this is a prerelease dependency.
# DOC: this method needs either documented or :nodoc'd

def match? obj, version=nil, allow_prerelease=false
def match? obj, version=nil
if !version
name = obj.name
version = obj.version
@@ -225,23 +216,12 @@ def match? obj, version=nil, allow_prerelease=false
end

return false unless self.name === name
return true if requirement.none?

version = Gem::Version.new version

return true if requirement.none? and not version.prerelease?
return false if version.prerelease? and
not allow_prerelease and
not prerelease?

requirement.satisfied_by? version
requirement.satisfied_by? Gem::Version.new(version)
end

##
# Does this dependency match +spec+?
#
# NOTE: This is not a convenience method. Unlike #match? this method
# returns true when +spec+ is a prerelease version even if this dependency
# is not a prerelease dependency.
# DOC: this method needs either documented or :nodoc'd

def matches_spec? spec
return false unless name === spec.name
@@ -269,6 +249,8 @@ def merge other
self.class.new name, self_req.as_list.concat(other_req.as_list)
end

# DOC: this method needs either documented or :nodoc'd

def matching_specs platform_only = false
matches = Gem::Specification.stubs.find_all { |spec|
self.name === spec.name and # TODO: == instead of ===
@@ -281,7 +263,7 @@ def matching_specs platform_only = false
}
end

matches.sort_by { |s| s.sort_obj } # HACK: shouldn't be needed
matches = matches.sort_by { |s| s.sort_obj } # HACK: shouldn't be needed
end

##
@@ -291,6 +273,8 @@ def specific?
@requirement.specific?
end

# DOC: this method needs either documented or :nodoc'd

def to_specs
matches = matching_specs true

@@ -303,13 +287,12 @@ def to_specs

if specs.empty?
total = Gem::Specification.to_a.size
msg = "Could not find '#{name}' (#{requirement}) among #{total} total gem(s)\n"
error = Gem::LoadError.new \
"Could not find '#{name}' (#{requirement}) among #{total} total gem(s)"
else
msg = "Could not find '#{name}' (#{requirement}) - did find: [#{specs.join ','}]\n"
error = Gem::LoadError.new \
"Could not find '#{name}' (#{requirement}) - did find: [#{specs.join ','}]"
end
msg << "Checked in 'GEM_PATH=#{Gem.path.join(File::PATH_SEPARATOR)}', execute `gem env` for more information"

error = Gem::LoadError.new(msg)
error.name = self.name
error.requirement = self.requirement
raise error
@@ -320,15 +303,11 @@ def to_specs
matches
end

# DOC: this method needs either documented or :nodoc'd

def to_spec
matches = self.to_specs

active = matches.find { |spec| spec.activated? }

return active if active

matches.delete_if { |spec| spec.version.prerelease? } unless prerelease?

matches.last
matches.find { |spec| spec.activated? } or matches.last
end
end
103 changes: 18 additions & 85 deletions lib/ruby/shared/rubygems/dependency_installer.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require 'rubygems'
require 'rubygems/dependency_list'
require 'rubygems/dependency_resolver'
require 'rubygems/package'
require 'rubygems/installer'
require 'rubygems/spec_fetcher'
@@ -72,7 +73,6 @@ class Gem::DependencyInstaller
def initialize options = {}
@only_install_dir = !!options[:install_dir]
@install_dir = options[:install_dir] || Gem.dir
@build_root = options[:build_root]

options = DEFAULT_OPTIONS.merge options

@@ -103,7 +103,7 @@ def initialize options = {}

@cache_dir = options[:cache_dir] || @install_dir

@errors = []
@errors = nil
end

##
@@ -158,7 +158,6 @@ def add_found_dependencies to_do, dependency_list # :nodoc:

dependency_list.remove_specs_unsatisfied_by dependencies
end

##
# Creates an AvailableSet to install from based on +dep_or_name+ and
# +version+
@@ -197,7 +196,7 @@ def consider_remote?
# sources. Gems are sorted with newer gems preferred over older gems, and
# local gems preferred over remote gems.

def find_gems_with_sources dep, best_only=false # :nodoc:
def find_gems_with_sources dep # :nodoc:
set = Gem::AvailableSet.new

if consider_local?
@@ -212,42 +211,23 @@ def find_gems_with_sources dep, best_only=false # :nodoc:

if consider_remote?
begin
# TODO this is pulled from #spec_for_dependency to allow
# us to filter tuples before fetching specs.
#
tuples, errors = Gem::SpecFetcher.fetcher.search_for_dependency dep

if best_only && !tuples.empty?
tuples.sort! { |a,b| b[0].version <=> a[0].version }
tuples = [tuples.first]
end

specs = []
tuples.each do |tup, source|
begin
spec = source.fetch_spec(tup)
rescue Gem::RemoteFetcher::FetchError => e
errors << Gem::SourceFetchProblem.new(source, e)
else
specs << [spec, source]
end
end
found, errors = Gem::SpecFetcher.fetcher.spec_for_dependency dep

if @errors
@errors += errors
else
@errors = errors
end

set << specs
set << found

rescue Gem::RemoteFetcher::FetchError => e
# FIX if there is a problem talking to the network, we either need to always tell
# the user (no really_verbose) or fail hard, not silently tell them that we just
# couldn't find their requested gem.
verbose do
"Error fetching remote data:\t\t#{e.message}\n" \
"Falling back to local-only install"
if Gem.configuration.really_verbose then
say "Error fetching remote data:\t\t#{e.message}"
say "Falling back to local-only install"
end
@domain = :local
end
@@ -270,14 +250,6 @@ def find_spec_by_name_and_version gem_name,
if gem_name =~ /\.gem$/ and File.file? gem_name then
src = Gem::Source::SpecificFile.new(gem_name)
set.add src.spec, src
elsif gem_name =~ /\.gem$/ then
Dir[gem_name].each do |name|
begin
src = Gem::Source::SpecificFile.new name
set.add src.spec, src
rescue Gem::Package::FormatError
end
end
else
local = Gem::Source::Local.new

@@ -291,7 +263,7 @@ def find_spec_by_name_and_version gem_name,
dep = Gem::Dependency.new gem_name, version
dep.prerelease = true if prerelease

set = find_gems_with_sources(dep, true)
set = find_gems_with_sources(dep)
set.match_platform!
end

@@ -306,7 +278,7 @@ def find_spec_by_name_and_version gem_name,
# Gathers all dependencies necessary for the installation from local and
# remote sources unless the ignore_dependencies was given.
#--
# TODO remove at RubyGems 3
# TODO remove, no longer used

def gather_dependencies # :nodoc:
specs = @available.all_specs
@@ -377,16 +349,13 @@ def install dep_or_name, version = Gem::Requirement.default
options = {
:bin_dir => @bin_dir,
:build_args => @build_args,
:document => @document,
:env_shebang => @env_shebang,
:force => @force,
:format_executable => @format_executable,
:ignore_dependencies => @ignore_dependencies,
:prerelease => @prerelease,
:security_policy => @security_policy,
:user_install => @user_install,
:wrappers => @wrappers,
:build_root => @build_root,
:install_as_default => @install_as_default
}
options[:install_dir] = @install_dir if @only_install_dir
@@ -420,59 +389,23 @@ def install_development_deps # :nodoc:
end

def resolve_dependencies dep_or_name, version # :nodoc:
request_set = Gem::RequestSet.new
request_set.development = @development
request_set.development_shallow = @dev_shallow
as = available_set_for dep_or_name, version

request_set = as.to_request_set install_development_deps
request_set.soft_missing = @force
request_set.prerelease = @prerelease
request_set.remote = false unless consider_remote?

installer_set = Gem::Resolver::InstallerSet.new @domain
installer_set = Gem::DependencyResolver::InstallerSet.new @domain
installer_set.always_install.concat request_set.always_install
installer_set.ignore_installed = @only_install_dir

if consider_local?
if dep_or_name =~ /\.gem$/ and File.file? dep_or_name then
src = Gem::Source::SpecificFile.new dep_or_name
installer_set.add_local dep_or_name, src.spec, src
version = src.spec.version if version == Gem::Requirement.default
elsif dep_or_name =~ /\.gem$/ then
Dir[dep_or_name].each do |name|
begin
src = Gem::Source::SpecificFile.new name
installer_set.add_local dep_or_name, src.spec, src
rescue Gem::Package::FormatError
end
end
# else This is a dependency. InstallerSet handles this case
end
end

dependency =
if spec = installer_set.local?(dep_or_name) then
Gem::Dependency.new spec.name, version
elsif String === dep_or_name then
Gem::Dependency.new dep_or_name, version
else
dep_or_name
end

dependency.prerelease = @prerelease

request_set.import [dependency]

installer_set.add_always_install dependency

request_set.always_install = installer_set.always_install

if @ignore_dependencies then
installer_set.ignore_dependencies = true
request_set.ignore_dependencies = true
request_set.soft_missing = true
request_set.soft_missing = true
end

request_set.resolve installer_set
composed_set = Gem::DependencyResolver.compose_sets as, installer_set

@errors.concat request_set.errors
request_set.resolve composed_set

request_set
end
6 changes: 5 additions & 1 deletion lib/ruby/shared/rubygems/dependency_list.rb
Original file line number Diff line number Diff line change
@@ -219,7 +219,11 @@ def tsort_each_child(node)
dependencies.each do |dep|
specs.each do |spec|
if spec.satisfies_requirement? dep then
yield spec
begin
yield spec
rescue TSort::Cyclic
# do nothing
end
break
end
end
254 changes: 254 additions & 0 deletions lib/ruby/shared/rubygems/dependency_resolver.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
require 'rubygems'
require 'rubygems/dependency'
require 'rubygems/exceptions'
require 'rubygems/util/list'

require 'uri'
require 'net/http'

##
# Given a set of Gem::Dependency objects as +needed+ and a way to query the
# set of available specs via +set+, calculates a set of ActivationRequest
# objects which indicate all the specs that should be activated to meet the
# all the requirements.

class Gem::DependencyResolver

##
# Contains all the conflicts encountered while doing resolution

attr_reader :conflicts

attr_accessor :development

attr_reader :missing

##
# When a missing dependency, don't stop. Just go on and record what was
# missing.

attr_accessor :soft_missing

def self.compose_sets *sets
Gem::DependencyResolver::ComposedSet.new(*sets)
end

##
# Provide a DependencyResolver that queries only against the already
# installed gems.

def self.for_current_gems needed
new needed, Gem::DependencyResolver::CurrentSet.new
end

##
# Create DependencyResolver object which will resolve the tree starting
# with +needed+ Depedency objects.
#
# +set+ is an object that provides where to look for specifications to
# satisify the Dependencies. This defaults to IndexSet, which will query
# rubygems.org.

def initialize needed, set = nil
@set = set || Gem::DependencyResolver::IndexSet.new
@needed = needed

@conflicts = nil
@development = false
@missing = []
@soft_missing = false
end

def requests s, act, reqs=nil
s.dependencies.reverse_each do |d|
next if d.type == :development and not @development
reqs = Gem::List.new Gem::DependencyResolver::DependencyRequest.new(d, act), reqs
end

@set.prefetch reqs

reqs
end

##
# Proceed with resolution! Returns an array of ActivationRequest objects.

def resolve
@conflicts = []

needed = nil

@needed.reverse_each do |n|
request = Gem::DependencyResolver::DependencyRequest.new n, nil

needed = Gem::List.new request, needed
end

res = resolve_for needed, nil

raise Gem::DependencyResolutionError, res if
res.kind_of? Gem::DependencyResolver::DependencyConflict

res.to_a
end

##
# The meat of the algorithm. Given +needed+ DependencyRequest objects and
# +specs+ being a list to ActivationRequest, calculate a new list of
# ActivationRequest objects.

def resolve_for needed, specs
while needed
dep = needed.value
needed = needed.tail

# If there is already a spec activated for the requested name...
if specs && existing = specs.find { |s| dep.name == s.name }

# then we're done since this new dep matches the
# existing spec.
next if dep.matches_spec? existing

# There is a conflict! We return the conflict
# object which will be seen by the caller and be
# handled at the right level.

# If the existing activation indicates that there
# are other possibles for it, then issue the conflict
# on the dep for the activation itself. Otherwise, issue
# it on the requester's request itself.
#
if existing.others_possible?
conflict =
Gem::DependencyResolver::DependencyConflict.new dep, existing
else
depreq = existing.request.requester.request
conflict =
Gem::DependencyResolver::DependencyConflict.new depreq, existing, dep
end
@conflicts << conflict

return conflict
end

# Get a list of all specs that satisfy dep and platform
possible = @set.find_all dep
possible = select_local_platforms possible

case possible.size
when 0
@missing << dep

unless @soft_missing
# If there are none, then our work here is done.
raise Gem::UnsatisfiableDependencyError, dep
end
when 1
# If there is one, then we just add it to specs
# and process the specs dependencies by adding
# them to needed.

spec = possible.first
act = Gem::DependencyResolver::ActivationRequest.new spec, dep, false

specs = Gem::List.prepend specs, act

# Put the deps for at the beginning of needed
# rather than the end to match the depth first
# searching done by the multiple case code below.
#
# This keeps the error messages consistent.
needed = requests(spec, act, needed)
else
# There are multiple specs for this dep. This is
# the case that this class is built to handle.

# Sort them so that we try the highest versions
# first.
possible = possible.sort_by do |s|
[s.source, s.version, s.platform == Gem::Platform::RUBY ? -1 : 1]
end

# We track the conflicts seen so that we can report them
# to help the user figure out how to fix the situation.
conflicts = []

# To figure out which to pick, we keep resolving
# given each one being activated and if there isn't
# a conflict, we know we've found a full set.
#
# We use an until loop rather than #reverse_each
# to keep the stack short since we're using a recursive
# algorithm.
#
until possible.empty?
s = possible.pop

# Recursively call #resolve_for with this spec
# and add it's dependencies into the picture...

act = Gem::DependencyResolver::ActivationRequest.new s, dep

try = requests(s, act, needed)

res = resolve_for try, Gem::List.prepend(specs, act)

# While trying to resolve these dependencies, there may
# be a conflict!

if res.kind_of? Gem::DependencyResolver::DependencyConflict
# The conflict might be created not by this invocation
# but rather one up the stack, so if we can't attempt
# to resolve this conflict (conflict isn't with the spec +s+)
# then just return it so the caller can try to sort it out.
return res unless res.for_spec? s

# Otherwise, this is a conflict that we can attempt to fix
conflicts << [s, res]

# Optimization:
#
# Because the conflict indicates the dependency that trigger
# it, we can prune possible based on this new information.
#
# This cuts down on the number of iterations needed.
possible.delete_if { |x| !res.dependency.matches_spec? x }
else
# No conflict, return the specs
return res
end
end

# We tried all possibles and nothing worked, so we let the user
# know and include as much information about the problem since
# the user is going to have to take action to fix this.
raise Gem::ImpossibleDependenciesError.new(dep, conflicts)
end
end

specs
end

##
# Returns the gems in +specs+ that match the local platform.

def select_local_platforms specs # :nodoc:
specs.select do |spec|
Gem::Platform.match spec.platform
end
end

end

require 'rubygems/dependency_resolver/api_set'
require 'rubygems/dependency_resolver/api_specification'
require 'rubygems/dependency_resolver/activation_request'
require 'rubygems/dependency_resolver/composed_set'
require 'rubygems/dependency_resolver/current_set'
require 'rubygems/dependency_resolver/dependency_conflict'
require 'rubygems/dependency_resolver/dependency_request'
require 'rubygems/dependency_resolver/index_set'
require 'rubygems/dependency_resolver/index_specification'
require 'rubygems/dependency_resolver/installed_specification'
require 'rubygems/dependency_resolver/installer_set'

109 changes: 109 additions & 0 deletions lib/ruby/shared/rubygems/dependency_resolver/activation_request.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
##
# Specifies a Specification object that should be activated.
# Also contains a dependency that was used to introduce this
# activation.

class Gem::DependencyResolver::ActivationRequest

attr_reader :request

attr_reader :spec

def initialize spec, req, others_possible = true
@spec = spec
@request = req
@others_possible = others_possible
end

def == other
case other
when Gem::Specification
@spec == other
when Gem::DependencyResolver::ActivationRequest
@spec == other.spec && @request == other.request
else
false
end
end

def download path
if @spec.respond_to? :source
source = @spec.source
else
source = Gem.sources.first
end

Gem.ensure_gem_subdirectories path

source.download full_spec, path
end

def full_name
@spec.full_name
end

def full_spec
Gem::Specification === @spec ? @spec : @spec.spec
end

def inspect # :nodoc:
others_possible = nil
others_possible = ' (others possible)' if @others_possible

'#<%s for %p from %s%s>' % [
self.class, @spec, @request, others_possible
]
end

##
# Indicates if the requested gem has already been installed.

def installed?
this_spec = full_spec

Gem::Specification.any? do |s|
s == this_spec
end
end

def name
@spec.name
end

##
# Indicate if this activation is one of a set of possible
# requests for the same Dependency request.

def others_possible?
@others_possible
end

##
# Return the ActivationRequest that contained the dependency
# that we were activated for.

def parent
@request.requester
end

def pretty_print q # :nodoc:
q.group 2, '[Activation request', ']' do
q.breakable
q.pp @spec

q.breakable
q.text ' for '
q.pp @request


q.breakable
q.text ' (other possible)' if @others_possible
end
end

def version
@spec.version
end

end

65 changes: 65 additions & 0 deletions lib/ruby/shared/rubygems/dependency_resolver/api_set.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
##
# The global rubygems pool, available via the rubygems.org API.
# Returns instances of APISpecification.

class Gem::DependencyResolver::APISet

def initialize
@data = Hash.new { |h,k| h[k] = [] }
@dep_uri = URI 'https://rubygems.org/api/v1/dependencies'
end

##
# Return an array of APISpecification objects matching
# DependencyRequest +req+.

def find_all req
res = []

versions(req.name).each do |ver|
if req.dependency.match? req.name, ver[:number]
res << Gem::DependencyResolver::APISpecification.new(self, ver)
end
end

res
end

##
# A hint run by the resolver to allow the Set to fetch
# data for DependencyRequests +reqs+.

def prefetch reqs
names = reqs.map { |r| r.dependency.name }
needed = names.find_all { |d| !@data.key?(d) }

return if needed.empty?

uri = @dep_uri + "?gems=#{needed.sort.join ','}"
str = Gem::RemoteFetcher.fetcher.fetch_path uri

Marshal.load(str).each do |ver|
@data[ver[:name]] << ver
end
end

##
# Return data for all versions of the gem +name+.

def versions name
if @data.key?(name)
return @data[name]
end

uri = @dep_uri + "?gems=#{name}"
str = Gem::RemoteFetcher.fetcher.fetch_path uri

Marshal.load(str).each do |ver|
@data[ver[:name]] << ver
end

@data[name]
end

end

39 changes: 39 additions & 0 deletions lib/ruby/shared/rubygems/dependency_resolver/api_specification.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
##
# Represents a specification retrieved via the rubygems.org
# API. This is used to avoid having to load the full
# Specification object when all we need is the name, version,
# and dependencies.

class Gem::DependencyResolver::APISpecification

attr_reader :dependencies
attr_reader :name
attr_reader :platform
attr_reader :set # :nodoc:
attr_reader :version

def initialize(set, api_data)
@set = set
@name = api_data[:name]
@version = Gem::Version.new api_data[:number]
@platform = api_data[:platform]
@dependencies = api_data[:dependencies].map do |name, ver|
Gem::Dependency.new name, ver.split(/\s*,\s*/)
end
end

def == other # :nodoc:
self.class === other and
@set == other.set and
@name == other.name and
@version == other.version and
@platform == other.platform and
@dependencies == other.dependencies
end

def full_name
"#{@name}-#{@version}"
end

end

18 changes: 18 additions & 0 deletions lib/ruby/shared/rubygems/dependency_resolver/composed_set.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
class Gem::DependencyResolver::ComposedSet

def initialize *sets
@sets = sets
end

def find_all req
res = []
@sets.each { |s| res += s.find_all(req) }
res
end

def prefetch reqs
@sets.each { |s| s.prefetch(reqs) }
end

end

Original file line number Diff line number Diff line change
@@ -3,11 +3,14 @@
# all the normal settings that control where to look
# for installed gems.

class Gem::Resolver::CurrentSet < Gem::Resolver::Set
class Gem::DependencyResolver::CurrentSet

def find_all req
req.dependency.matching_specs
end

def prefetch gems
end

end

Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
##
# Used internally to indicate that a dependency conflicted
# with a spec that would be activated.

class Gem::DependencyResolver::DependencyConflict

attr_reader :activated

attr_reader :dependency

def initialize(dependency, activated, failed_dep=dependency)
@dependency = dependency
@activated = activated
@failed_dep = failed_dep
end

##
# Return the 2 dependency objects that conflicted

def conflicting_dependencies
[@failed_dep.dependency, @activated.request.dependency]
end

##
# Explanation of the conflict used by exceptions to print useful messages

def explanation
activated = @activated.spec.full_name
requirement = @failed_dep.dependency.requirement

" Activated %s instead of (%s) via:\n %s\n" % [
activated, requirement, request_path.join(', ')
]
end

def for_spec?(spec)
@dependency.name == spec.name
end

def pretty_print q # :nodoc:
q.group 2, '[Dependency conflict: ', ']' do
q.breakable

q.text 'activated '
q.pp @activated

q.breakable
q.text ' dependency '
q.pp @dependency

q.breakable
if @dependency == @failed_dep then
q.text ' failed'
else
q.text ' failed dependency '
q.pp @failed_dep
end
end
end

##
# Path of specifications that requested this dependency

def request_path
current = requester
path = []

while current do
path << current.spec.full_name

current = current.request.requester
end

path
end

##
# Return the Specification that listed the dependency

def requester
@failed_dep.requester
end

end

Loading

0 comments on commit e835fd1

Please sign in to comment.