зеркало из https://github.com/github/ruby.git
* lib/rubygems: Update to RubyGems 2.4.1 master(713ab65)
Complete history at: https://github.com/rubygems/rubygems/blob/master/History.txt#L3-L216 * test/rubygems: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@47582 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
e548c09d42
Коммит
4de117a615
|
@ -1,3 +1,11 @@
|
|||
Sun Sep 14 12:29:02 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
|
||||
|
||||
* lib/rubygems: Update to RubyGems 2.4.1 master(713ab65)
|
||||
Complete history at:
|
||||
https://github.com/rubygems/rubygems/blob/master/History.txt#L3-L216
|
||||
|
||||
* test/rubygems: ditto.
|
||||
|
||||
Sun Sep 14 11:03:24 2014 Aaron Patterson <aaron@tenderlovemaking.com>
|
||||
|
||||
* ext/psych/lib/psych.rb: update version
|
||||
|
|
|
@ -6,9 +6,10 @@
|
|||
#++
|
||||
|
||||
require 'rbconfig'
|
||||
require 'thread'
|
||||
|
||||
module Gem
|
||||
VERSION = '2.2.2'
|
||||
VERSION = '2.4.1'
|
||||
end
|
||||
|
||||
# Must be first since it unloads the prelude from 1.9.2
|
||||
|
@ -56,8 +57,8 @@ require 'rubygems/errors'
|
|||
# RubyGems defaults are stored in rubygems/defaults.rb. If you're packaging
|
||||
# RubyGems or implementing Ruby you can change RubyGems' defaults.
|
||||
#
|
||||
# For RubyGems packagers, provide lib/rubygems/operating_system.rb and
|
||||
# override any defaults from lib/rubygems/defaults.rb.
|
||||
# For RubyGems packagers, provide lib/rubygems/defaults/operating_system.rb
|
||||
# and override any defaults from lib/rubygems/defaults.rb.
|
||||
#
|
||||
# For Ruby implementers, provide lib/rubygems/defaults/#{RUBY_ENGINE}.rb and
|
||||
# override any defaults from lib/rubygems/defaults.rb.
|
||||
|
@ -83,7 +84,7 @@ require 'rubygems/errors'
|
|||
# * Chad Fowler -- chad(at)chadfowler.com
|
||||
# * David Black -- dblack(at)wobblini.net
|
||||
# * Paul Brannan -- paul(at)atdesk.com
|
||||
# * Jim Weirich -- jim(at)weirichhouse.org
|
||||
# * Jim Weirich -- jim(at)weirichhouse.org
|
||||
#
|
||||
# Contributors:
|
||||
#
|
||||
|
@ -156,6 +157,7 @@ module Gem
|
|||
|
||||
@configuration = nil
|
||||
@loaded_specs = {}
|
||||
LOADED_SPECS_MUTEX = Mutex.new
|
||||
@path_to_default_spec_map = {}
|
||||
@platforms = []
|
||||
@ruby = nil
|
||||
|
@ -298,7 +300,7 @@ module Gem
|
|||
end
|
||||
|
||||
##
|
||||
# The path the the data directory specified by the gem name. If the
|
||||
# The path to the data directory specified by the gem name. If the
|
||||
# package is not available as a gem, return nil.
|
||||
|
||||
def self.datadir(gem_name)
|
||||
|
@ -544,9 +546,9 @@ module Gem
|
|||
# Fetching: minitest-3.0.1.gem (100%)
|
||||
# => [#<Gem::Specification:0x1013b4528 @name="minitest", ...>]
|
||||
|
||||
def self.install name, version = Gem::Requirement.default, **options
|
||||
def self.install name, version = Gem::Requirement.default, *options
|
||||
require "rubygems/dependency_installer"
|
||||
inst = Gem::DependencyInstaller.new(**options)
|
||||
inst = Gem::DependencyInstaller.new(*options)
|
||||
inst.install name, version
|
||||
inst.installed_gems
|
||||
end
|
||||
|
@ -995,19 +997,31 @@ module Gem
|
|||
end
|
||||
|
||||
##
|
||||
# Looks for gem dependency files (gem.deps.rb, Gemfile, Isolate) from the
|
||||
# current directory up and activates the gems in the first file found.
|
||||
# Looks for a gem dependency file at +path+ and activates the gems in the
|
||||
# file if found. If the file is not found an ArgumentError is raised.
|
||||
#
|
||||
# If +path+ is not given the RUBYGEMS_GEMDEPS environment variable is used,
|
||||
# but if no file is found no exception is raised.
|
||||
#
|
||||
# If '-' is given for +path+ RubyGems searches up from the current working
|
||||
# directory for gem dependency files (gem.deps.rb, Gemfile, Isolate) and
|
||||
# activates the gems in the first one found.
|
||||
#
|
||||
# You can run this automatically when rubygems starts. To enable, set
|
||||
# the <code>RUBYGEMS_GEMDEPS</code> environment variable to either the path
|
||||
# of your Gemfile or "-" to auto-discover in parent directories.
|
||||
# of your gem dependencies file or "-" to auto-discover in parent
|
||||
# directories.
|
||||
#
|
||||
# NOTE: Enabling automatic discovery on multiuser systems can lead to
|
||||
# execution of arbitrary code when used from directories outside your
|
||||
# control.
|
||||
|
||||
def self.use_gemdeps
|
||||
return unless path = ENV['RUBYGEMS_GEMDEPS']
|
||||
def self.use_gemdeps path = nil
|
||||
raise_exception = path
|
||||
|
||||
path ||= ENV['RUBYGEMS_GEMDEPS']
|
||||
return unless path
|
||||
|
||||
path = path.dup
|
||||
|
||||
if path == "-" then
|
||||
|
@ -1025,7 +1039,11 @@ module Gem
|
|||
|
||||
path.untaint
|
||||
|
||||
return unless File.file? path
|
||||
unless File.file? path then
|
||||
return unless raise_exception
|
||||
|
||||
raise ArgumentError, "Unable to find gem dependencies file at #{path}"
|
||||
end
|
||||
|
||||
rs = Gem::RequestSet.new
|
||||
rs.load_gemdeps path
|
||||
|
@ -1035,6 +1053,10 @@ module Gem
|
|||
sp.activate
|
||||
sp
|
||||
end
|
||||
rescue Gem::LoadError, Gem::UnsatisfiableDependencyError => e
|
||||
warn e.message
|
||||
warn "You may need to `gem install -g` to install missing gems"
|
||||
warn ""
|
||||
end
|
||||
|
||||
class << self
|
||||
|
|
|
@ -126,7 +126,7 @@ class Gem::AvailableSet
|
|||
dep = req.dependency
|
||||
|
||||
match = @set.find_all do |t|
|
||||
dep.matches_spec? t.spec
|
||||
dep.match? t.spec
|
||||
end
|
||||
|
||||
match.map do |t|
|
||||
|
|
|
@ -14,6 +14,11 @@ class Gem::BasicSpecification
|
|||
|
||||
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.
|
||||
|
||||
|
@ -53,7 +58,16 @@ class Gem::BasicSpecification
|
|||
# Return true if this spec can require +file+.
|
||||
|
||||
def contains_requirable_file? file
|
||||
build_extensions
|
||||
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 #{full_name}"
|
||||
return false
|
||||
end
|
||||
|
||||
suffixes = Gem.suffixes
|
||||
|
||||
|
@ -120,11 +134,11 @@ class Gem::BasicSpecification
|
|||
# activated.
|
||||
|
||||
def full_require_paths
|
||||
full_paths = @require_paths.map do |path|
|
||||
full_paths = raw_require_paths.map do |path|
|
||||
File.join full_gem_path, path
|
||||
end
|
||||
|
||||
full_paths.unshift extension_dir unless @extensions.empty?
|
||||
full_paths.unshift extension_dir unless @extensions.nil? || @extensions.empty?
|
||||
|
||||
full_paths
|
||||
end
|
||||
|
@ -176,7 +190,7 @@ class Gem::BasicSpecification
|
|||
end
|
||||
|
||||
def raw_require_paths # :nodoc:
|
||||
@require_paths
|
||||
Array(@require_paths)
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -197,13 +211,9 @@ class Gem::BasicSpecification
|
|||
# spec.require_path = '.'
|
||||
|
||||
def require_paths
|
||||
return @require_paths if @extensions.empty?
|
||||
return raw_require_paths if @extensions.nil? || @extensions.empty?
|
||||
|
||||
relative_extension_dir =
|
||||
File.join '..', '..', 'extensions', Gem::Platform.local.to_s,
|
||||
Gem.extension_api_version, full_name
|
||||
|
||||
[relative_extension_dir].concat @require_paths
|
||||
[extension_dir].concat raw_require_paths
|
||||
end
|
||||
|
||||
##
|
||||
|
|
|
@ -148,6 +148,8 @@ class Gem::Command
|
|||
|
||||
##
|
||||
# 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?
|
||||
|
@ -557,7 +559,8 @@ basic help message containing pointers to more information.
|
|||
Further help:
|
||||
gem help commands list all 'gem' commands
|
||||
gem help examples show some examples of usage
|
||||
gem help platforms show information about platforms
|
||||
gem help gem_dependencies gem dependencies file guide
|
||||
gem help platforms gem platforms guide
|
||||
gem help <COMMAND> show help on COMMAND
|
||||
(e.g. 'gem help install')
|
||||
gem server present a web page at
|
||||
|
|
|
@ -48,6 +48,7 @@ class Gem::CommandManager
|
|||
:list,
|
||||
:lock,
|
||||
:mirror,
|
||||
:open,
|
||||
:outdated,
|
||||
:owner,
|
||||
:pristine,
|
||||
|
|
|
@ -129,23 +129,21 @@ class Gem::Commands::CertCommand < Gem::Command
|
|||
end
|
||||
|
||||
def build_key # :nodoc:
|
||||
if options[:key] then
|
||||
options[:key]
|
||||
else
|
||||
passphrase = ask_for_password 'Passphrase for your Private Key:'
|
||||
say "\n"
|
||||
return options[:key] if options[:key]
|
||||
|
||||
passphrase_confirmation = ask_for_password 'Please repeat the passphrase for your Private Key:'
|
||||
say "\n"
|
||||
passphrase = ask_for_password 'Passphrase for your Private Key:'
|
||||
say "\n"
|
||||
|
||||
raise Gem::CommandLineError,
|
||||
"Passphrase and passphrase confirmation don't match" unless passphrase == passphrase_confirmation
|
||||
passphrase_confirmation = ask_for_password 'Please repeat the passphrase for your Private Key:'
|
||||
say "\n"
|
||||
|
||||
key = Gem::Security.create_key
|
||||
key_path = Gem::Security.write key, "gem-private_key.pem", 0600, passphrase
|
||||
raise Gem::CommandLineError,
|
||||
"Passphrase and passphrase confirmation don't match" unless passphrase == passphrase_confirmation
|
||||
|
||||
return key, key_path
|
||||
end
|
||||
key = Gem::Security.create_key
|
||||
key_path = Gem::Security.write key, "gem-private_key.pem", 0600, passphrase
|
||||
|
||||
return key, key_path
|
||||
end
|
||||
|
||||
def certificates_matching filter
|
||||
|
|
|
@ -67,10 +67,10 @@ If no gems are named all gems in GEM_HOME are cleaned.
|
|||
|
||||
say "Clean Up Complete"
|
||||
|
||||
if Gem.configuration.really_verbose then
|
||||
verbose do
|
||||
skipped = @default_gems.map { |spec| spec.full_name }
|
||||
|
||||
say "Skipped default gems: #{skipped.join ', '}"
|
||||
"Skipped default gems: #{skipped.join ', '}"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -8,7 +8,8 @@ class Gem::Commands::ContentsCommand < Gem::Command
|
|||
|
||||
def initialize
|
||||
super 'contents', 'Display the contents of the installed gems',
|
||||
:specdirs => [], :lib_only => false, :prefix => true
|
||||
:specdirs => [], :lib_only => false, :prefix => true,
|
||||
:show_install_dir => false
|
||||
|
||||
add_version_option
|
||||
|
||||
|
@ -32,6 +33,11 @@ class Gem::Commands::ContentsCommand < Gem::Command
|
|||
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
|
||||
|
@ -65,7 +71,12 @@ prefix or only the files that are requireable.
|
|||
names = gem_names
|
||||
|
||||
names.each do |name|
|
||||
found = gem_contents name
|
||||
found =
|
||||
if options[:show_install_dir] then
|
||||
gem_install_dir name
|
||||
else
|
||||
gem_contents name
|
||||
end
|
||||
|
||||
terminate_interaction 1 unless found or names.length > 1
|
||||
end
|
||||
|
@ -115,6 +126,16 @@ prefix or only the files that are requireable.
|
|||
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)
|
||||
|
|
|
@ -31,7 +31,7 @@ class Gem::Commands::DependencyCommand < Gem::Command
|
|||
end
|
||||
|
||||
def arguments # :nodoc:
|
||||
"GEMNAME name of gem to show dependencies for"
|
||||
"REGEXP show dependencies for gems whose names start with REGEXP"
|
||||
end
|
||||
|
||||
def defaults_str # :nodoc:
|
||||
|
@ -50,7 +50,7 @@ use with other commands.
|
|||
end
|
||||
|
||||
def usage # :nodoc:
|
||||
"#{program_name} GEMNAME"
|
||||
"#{program_name} REGEXP"
|
||||
end
|
||||
|
||||
def fetch_remote_specs dependency # :nodoc:
|
||||
|
|
|
@ -28,8 +28,9 @@ The RubyGems environment can be controlled through command line arguments,
|
|||
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 /etc/gemrc for all users. These
|
||||
files are YAML files with the following YAML keys:
|
||||
~/.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:
|
||||
|
||||
:sources: A YAML array of remote gem repositories to install gems from
|
||||
:verbose: Verbosity of the gem command. false, true, and :really are the
|
||||
|
@ -120,6 +121,8 @@ lib/rubygems/defaults/operating_system.rb
|
|||
|
||||
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"
|
||||
|
|
|
@ -52,6 +52,183 @@ Some examples of 'gem' usage.
|
|||
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
|
||||
|
@ -90,6 +267,16 @@ When building platform gems, set the platform in the gem specification to
|
|||
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
|
||||
|
@ -98,15 +285,6 @@ platform.
|
|||
@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
|
||||
|
@ -114,19 +292,20 @@ platform.
|
|||
def execute
|
||||
arg = options[:args][0]
|
||||
|
||||
if begins? "commands", arg then
|
||||
show_commands
|
||||
_, help = SUBCOMMANDS.find do |command,|
|
||||
begins? command, arg
|
||||
end
|
||||
|
||||
elsif begins? "options", arg then
|
||||
say Gem::Command::HELP
|
||||
if help then
|
||||
if Symbol === help then
|
||||
send help
|
||||
else
|
||||
say help
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
elsif begins? "examples", arg then
|
||||
say EXAMPLES
|
||||
|
||||
elsif begins? "platforms", arg then
|
||||
say PLATFORMS
|
||||
|
||||
elsif options[:help] then
|
||||
if options[:help] then
|
||||
show_help
|
||||
|
||||
elsif arg then
|
||||
|
|
|
@ -21,6 +21,8 @@ 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 => [],
|
||||
})
|
||||
|
@ -69,6 +71,16 @@ class Gem::Commands::InstallCommand < Gem::Command
|
|||
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
|
||||
|
||||
|
@ -78,7 +90,7 @@ class Gem::Commands::InstallCommand < Gem::Command
|
|||
|
||||
def defaults_str # :nodoc:
|
||||
"--both --version '#{Gem::Requirement.default}' --document --no-force\n" +
|
||||
"--install-dir #{Gem.dir}"
|
||||
"--install-dir #{Gem.dir} --lock"
|
||||
end
|
||||
|
||||
def description # :nodoc:
|
||||
|
@ -92,6 +104,25 @@ 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
|
||||
|
@ -204,23 +235,20 @@ to write the specification by hand. For example:
|
|||
install_gem_without_dependencies name, req
|
||||
else
|
||||
inst = Gem::DependencyInstaller.new options
|
||||
request_set = inst.resolve_dependencies name, req
|
||||
|
||||
if options[:explain]
|
||||
request_set = inst.resolve_dependencies name, req
|
||||
|
||||
puts "Gems to install:"
|
||||
|
||||
request_set.specs.map { |s| s.full_name }.sort.each do |s|
|
||||
puts " #{s}"
|
||||
request_set.sorted_requests.each do |s|
|
||||
puts " #{s.full_name}"
|
||||
end
|
||||
|
||||
return
|
||||
else
|
||||
inst.install name, req
|
||||
@installed_specs.concat request_set.install options
|
||||
end
|
||||
|
||||
@installed_specs.push(*inst.installed_gems)
|
||||
|
||||
show_install_errors inst.errors
|
||||
end
|
||||
end
|
||||
|
@ -250,6 +278,14 @@ to write the specification by hand. For example:
|
|||
inst = Gem::Installer.new 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
|
||||
|
||||
|
@ -264,8 +300,10 @@ to write the specification by hand. For example:
|
|||
rescue Gem::InstallError => e
|
||||
alert_error "Error installing #{gem_name}:\n\t#{e.message}"
|
||||
exit_code |= 1
|
||||
rescue Gem::GemNotFoundException => e
|
||||
show_lookup_failure e.name, e.version, e.errors, options[:domain]
|
||||
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
|
||||
|
|
|
@ -8,13 +8,13 @@ require 'rubygems/commands/query_command'
|
|||
class Gem::Commands::ListCommand < Gem::Commands::QueryCommand
|
||||
|
||||
def initialize
|
||||
super 'list', 'Display local gems whose name starts with STRING'
|
||||
super 'list', 'Display local gems whose name matches REGEXP'
|
||||
|
||||
remove_option('--name-matches')
|
||||
end
|
||||
|
||||
def arguments # :nodoc:
|
||||
"STRING start of gem name to look for"
|
||||
"REGEXP regexp to look for in gem name"
|
||||
end
|
||||
|
||||
def defaults_str # :nodoc:
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
require 'English'
|
||||
require 'rubygems/command'
|
||||
require 'rubygems/version_option'
|
||||
require 'rubygems/util'
|
||||
|
||||
class Gem::Commands::OpenCommand < Gem::Command
|
||||
|
||||
include Gem::VersionOption
|
||||
|
||||
def initialize
|
||||
super 'open', 'Open gem sources in editor'
|
||||
|
||||
add_option('-e', '--editor EDITOR', String,
|
||||
"Opens gem sources in EDITOR") do |editor, options|
|
||||
options[:editor] = editor || get_env_editor
|
||||
end
|
||||
end
|
||||
|
||||
def arguments # :nodoc:
|
||||
"GEMNAME name of gem to open in editor"
|
||||
end
|
||||
|
||||
def defaults_str # :nodoc:
|
||||
"-e #{get_env_editor}"
|
||||
end
|
||||
|
||||
def description # :nodoc:
|
||||
<<-EOF
|
||||
The open command opens gem in editor and changes current path
|
||||
to gem's source directory. Editor can be specified with -e option,
|
||||
otherwise rubygems will look for editor in $EDITOR, $VISUAL and
|
||||
$GEM_EDITOR variables.
|
||||
EOF
|
||||
end
|
||||
|
||||
def usage # :nodoc:
|
||||
"#{program_name} GEMNAME [-e EDITOR]"
|
||||
end
|
||||
|
||||
def get_env_editor
|
||||
ENV['GEM_EDITOR'] ||
|
||||
ENV['VISUAL'] ||
|
||||
ENV['EDITOR'] ||
|
||||
'vi'
|
||||
end
|
||||
|
||||
def execute
|
||||
@version = options[:version] || Gem::Requirement.default
|
||||
@editor = options[:editor] || get_env_editor
|
||||
|
||||
found = open_gem(get_one_gem_name)
|
||||
|
||||
terminate_interaction 1 unless found
|
||||
end
|
||||
|
||||
def open_gem name
|
||||
spec = spec_for name
|
||||
return false unless spec
|
||||
|
||||
open_editor(spec.full_gem_path)
|
||||
end
|
||||
|
||||
def open_editor path
|
||||
system(*@editor.split(/\s+/) + [path])
|
||||
end
|
||||
|
||||
def spec_for name
|
||||
spec = Gem::Specification.find_all_by_name(name, @version).last
|
||||
|
||||
return spec if spec
|
||||
|
||||
say "Unable to find gem '#{name}'"
|
||||
end
|
||||
end
|
|
@ -86,7 +86,9 @@ permission to.
|
|||
request.add_field "Authorization", api_key
|
||||
end
|
||||
|
||||
with_response response, "Removing #{owner}"
|
||||
action = method == :delete ? "Removing" : "Adding"
|
||||
|
||||
with_response response, "#{action} #{owner}"
|
||||
rescue
|
||||
# ignore
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@ require 'rubygems/commands/query_command'
|
|||
class Gem::Commands::SearchCommand < Gem::Commands::QueryCommand
|
||||
|
||||
def initialize
|
||||
super 'search', 'Display remote gems whose name contains STRING'
|
||||
super 'search', 'Display remote gems whose name matches REGEXP'
|
||||
|
||||
remove_option '--name-matches'
|
||||
|
||||
|
@ -12,7 +12,7 @@ class Gem::Commands::SearchCommand < Gem::Commands::QueryCommand
|
|||
end
|
||||
|
||||
def arguments # :nodoc:
|
||||
"STRING fragment of gem name to search for"
|
||||
"REGEXP regexp to search for in gem name"
|
||||
end
|
||||
|
||||
def defaults_str # :nodoc:
|
||||
|
@ -21,8 +21,8 @@ class Gem::Commands::SearchCommand < Gem::Commands::QueryCommand
|
|||
|
||||
def description # :nodoc:
|
||||
<<-EOF
|
||||
The search command displays remote gems whose name contains the given
|
||||
string.
|
||||
The search command displays remote gems whose name matches the given
|
||||
regexp.
|
||||
|
||||
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,7 @@ To list local gems use the list command.
|
|||
end
|
||||
|
||||
def usage # :nodoc:
|
||||
"#{program_name} [STRING]"
|
||||
"#{program_name} [REGEXP]"
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -446,7 +446,7 @@ abort "#{deprecation_message}"
|
|||
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
|
||||
|
|
|
@ -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
|
||||
:check_dev => false, :vendor => false
|
||||
|
||||
add_option('-a', '--[no-]all',
|
||||
'Uninstall all matching versions'
|
||||
|
@ -76,6 +76,18 @@ class Gem::Commands::UninstallCommand < Gem::Command
|
|||
|
||||
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:
|
||||
|
|
|
@ -16,6 +16,8 @@ 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],
|
||||
|
@ -45,7 +47,7 @@ class Gem::Commands::UpdateCommand < Gem::Command
|
|||
end
|
||||
|
||||
def arguments # :nodoc:
|
||||
"GEMNAME name of gem to update"
|
||||
"REGEXP regexp to search for in gem name"
|
||||
end
|
||||
|
||||
def defaults_str # :nodoc:
|
||||
|
@ -56,13 +58,13 @@ class Gem::Commands::UpdateCommand < Gem::Command
|
|||
<<-EOF
|
||||
The update command will update your gems to the latest version.
|
||||
|
||||
The update comamnd does not remove the previous version. Use the cleanup
|
||||
The update command does not remove the previous version. Use the cleanup
|
||||
command to remove old versions.
|
||||
EOF
|
||||
end
|
||||
|
||||
def usage # :nodoc:
|
||||
"#{program_name} GEMNAME [GEMNAME ...]"
|
||||
"#{program_name} REGEXP [REGEXP ...]"
|
||||
end
|
||||
|
||||
def check_latest_rubygems version # :nodoc:
|
||||
|
@ -97,10 +99,14 @@ command to remove old versions.
|
|||
|
||||
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.map { |spec| spec.name }.join ' '}"
|
||||
say "Gems updated: #{updated_names.join(' ')}"
|
||||
say "Gems already up-to-date: #{not_updated_names.join(' ')}" unless not_updated_names.empty?
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -199,15 +205,11 @@ command to remove old versions.
|
|||
|
||||
@installer ||= Gem::DependencyInstaller.new options
|
||||
|
||||
success = false
|
||||
|
||||
say "Updating #{name}"
|
||||
begin
|
||||
@installer.install name, Gem::Requirement.new(version)
|
||||
success = true
|
||||
rescue Gem::InstallError => e
|
||||
rescue Gem::InstallError, Gem::DependencyError => e
|
||||
alert_error "Error installing #{name}:\n\t#{e.message}"
|
||||
success = false
|
||||
end
|
||||
|
||||
@installer.installed_gems.each do |spec|
|
||||
|
@ -259,7 +261,7 @@ command to remove old versions.
|
|||
|
||||
highest_installed_gems.each do |l_name, l_spec|
|
||||
next if not gem_names.empty? and
|
||||
gem_names.all? { |name| /#{name}/ !~ l_spec.name }
|
||||
gem_names.none? { |name| name == l_spec.name }
|
||||
|
||||
highest_remote_ver = highest_remote_version l_spec
|
||||
|
||||
|
@ -272,4 +274,3 @@ command to remove old versions.
|
|||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -44,10 +44,7 @@ as the reason for the removal request.
|
|||
options[:undo] = true
|
||||
end
|
||||
|
||||
add_option('-k', '--key KEY_NAME',
|
||||
'Use API key from your gem credentials file') do |value, options|
|
||||
options[:key] = value
|
||||
end
|
||||
add_key_option
|
||||
end
|
||||
|
||||
def execute
|
||||
|
@ -55,14 +52,12 @@ as the reason for the removal request.
|
|||
|
||||
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, api_key)
|
||||
unyank_gem(version, platform)
|
||||
else
|
||||
yank_gem(version, platform, api_key)
|
||||
yank_gem(version, platform)
|
||||
end
|
||||
else
|
||||
say "A version argument is required: #{usage}"
|
||||
|
@ -70,19 +65,19 @@ as the reason for the removal request.
|
|||
end
|
||||
end
|
||||
|
||||
def yank_gem(version, platform, api_key)
|
||||
def yank_gem(version, platform)
|
||||
say "Yanking gem from #{self.host}..."
|
||||
yank_api_request(:delete, version, platform, "api/v1/gems/yank", api_key)
|
||||
yank_api_request(:delete, version, platform, "api/v1/gems/yank")
|
||||
end
|
||||
|
||||
def unyank_gem(version, platform, api_key)
|
||||
def unyank_gem(version, platform)
|
||||
say "Unyanking gem from #{host}..."
|
||||
yank_api_request(:put, version, platform, "api/v1/gems/unyank", api_key)
|
||||
yank_api_request(:put, version, platform, "api/v1/gems/unyank")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def yank_api_request(method, version, platform, api, api_key)
|
||||
def yank_api_request(method, version, platform, api)
|
||||
name = get_one_gem_name
|
||||
response = rubygems_api_request(method, api) do |request|
|
||||
request.add_field("Authorization", api_key)
|
||||
|
|
|
@ -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.
|
||||
|
@ -383,6 +383,8 @@ if you believe they were disclosed to a third party.
|
|||
@backtrace = true
|
||||
when /^--debug$/ then
|
||||
$DEBUG = true
|
||||
|
||||
warn 'NOTE: Debugging mode prints all exceptions even when rescued'
|
||||
else
|
||||
@args << arg
|
||||
end
|
||||
|
@ -428,6 +430,15 @@ if you believe they were disclosed to a third party.
|
|||
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)
|
||||
|
|
|
@ -26,6 +26,11 @@ 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
|
||||
|
@ -51,7 +56,9 @@ module Kernel
|
|||
end
|
||||
|
||||
spec = Gem::Dependency.new(gem_name, *requirements).to_spec
|
||||
spec.activate if spec
|
||||
Gem::LOADED_SPECS_MUTEX.synchronize {
|
||||
spec.activate
|
||||
} if spec
|
||||
end
|
||||
|
||||
private :gem
|
||||
|
|
|
@ -50,12 +50,8 @@ module Kernel
|
|||
# normal require handle loading a gem from the rescue below.
|
||||
|
||||
if Gem::Specification.unresolved_deps.empty? then
|
||||
begin
|
||||
RUBYGEMS_ACTIVATION_MONITOR.exit
|
||||
return gem_original_require(path)
|
||||
ensure
|
||||
RUBYGEMS_ACTIVATION_MONITOR.enter
|
||||
end
|
||||
RUBYGEMS_ACTIVATION_MONITOR.exit
|
||||
return gem_original_require(path)
|
||||
end
|
||||
|
||||
# If +path+ is for a gem that has already been loaded, don't
|
||||
|
@ -71,8 +67,6 @@ module Kernel
|
|||
begin
|
||||
RUBYGEMS_ACTIVATION_MONITOR.exit
|
||||
return gem_original_require(path)
|
||||
ensure
|
||||
RUBYGEMS_ACTIVATION_MONITOR.enter
|
||||
end if spec
|
||||
|
||||
# Attempt to find +path+ in any unresolved gems...
|
||||
|
@ -105,6 +99,7 @@ module Kernel
|
|||
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
|
||||
|
||||
|
@ -115,32 +110,27 @@ module Kernel
|
|||
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
|
||||
|
||||
begin
|
||||
RUBYGEMS_ACTIVATION_MONITOR.exit
|
||||
return gem_original_require(path)
|
||||
ensure
|
||||
RUBYGEMS_ACTIVATION_MONITOR.enter
|
||||
end
|
||||
RUBYGEMS_ACTIVATION_MONITOR.exit
|
||||
return gem_original_require(path)
|
||||
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
|
||||
begin
|
||||
RUBYGEMS_ACTIVATION_MONITOR.exit
|
||||
return gem_original_require(path)
|
||||
ensure
|
||||
RUBYGEMS_ACTIVATION_MONITOR.enter
|
||||
end
|
||||
RUBYGEMS_ACTIVATION_MONITOR.exit
|
||||
return gem_original_require(path)
|
||||
else
|
||||
RUBYGEMS_ACTIVATION_MONITOR.exit
|
||||
end
|
||||
|
||||
raise load_error
|
||||
ensure
|
||||
RUBYGEMS_ACTIVATION_MONITOR.exit
|
||||
end
|
||||
|
||||
private :require
|
||||
|
|
|
@ -89,11 +89,11 @@ module Gem
|
|||
# Default gem load path
|
||||
|
||||
def self.default_path
|
||||
if Gem.user_home && File.exist?(Gem.user_home) then
|
||||
[user_dir, default_dir]
|
||||
else
|
||||
[default_dir]
|
||||
end
|
||||
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
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -160,4 +160,18 @@ module Gem
|
|||
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
|
||||
|
|
|
@ -74,7 +74,7 @@ class Gem::Dependency
|
|||
end
|
||||
|
||||
def inspect # :nodoc:
|
||||
if @prerelease
|
||||
if prerelease? then
|
||||
"<%s type=%p name=%p requirements=%p prerelease=ok>" %
|
||||
[self.class, self.type, self.name, requirement.to_s]
|
||||
else
|
||||
|
@ -145,7 +145,6 @@ class Gem::Dependency
|
|||
@requirement = @version_requirements if defined?(@version_requirements)
|
||||
end
|
||||
|
||||
# DOC: this method needs documentation or :nodoc''d
|
||||
def requirements_list
|
||||
requirement.as_list
|
||||
end
|
||||
|
@ -205,9 +204,19 @@ class Gem::Dependency
|
|||
|
||||
alias === =~
|
||||
|
||||
# DOC: this method needs either documented or :nodoc'd
|
||||
##
|
||||
# :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.
|
||||
|
||||
def match? obj, version=nil
|
||||
def match? obj, version=nil, allow_prerelease=false
|
||||
if !version
|
||||
name = obj.name
|
||||
version = obj.version
|
||||
|
@ -216,12 +225,23 @@ class Gem::Dependency
|
|||
end
|
||||
|
||||
return false unless self.name === name
|
||||
return true if requirement.none?
|
||||
|
||||
requirement.satisfied_by? Gem::Version.new(version)
|
||||
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
|
||||
end
|
||||
|
||||
# DOC: this method needs either documented or :nodoc'd
|
||||
##
|
||||
# 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.
|
||||
|
||||
def matches_spec? spec
|
||||
return false unless name === spec.name
|
||||
|
@ -249,8 +269,6 @@ class Gem::Dependency
|
|||
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 ===
|
||||
|
@ -273,8 +291,6 @@ class Gem::Dependency
|
|||
@requirement.specific?
|
||||
end
|
||||
|
||||
# DOC: this method needs either documented or :nodoc'd
|
||||
|
||||
def to_specs
|
||||
matches = matching_specs true
|
||||
|
||||
|
@ -287,12 +303,13 @@ class Gem::Dependency
|
|||
|
||||
if specs.empty?
|
||||
total = Gem::Specification.to_a.size
|
||||
error = Gem::LoadError.new \
|
||||
"Could not find '#{name}' (#{requirement}) among #{total} total gem(s)"
|
||||
msg = "Could not find '#{name}' (#{requirement}) among #{total} total gem(s)\n"
|
||||
else
|
||||
error = Gem::LoadError.new \
|
||||
"Could not find '#{name}' (#{requirement}) - did find: [#{specs.join ','}]"
|
||||
msg = "Could not find '#{name}' (#{requirement}) - did find: [#{specs.join ','}]\n"
|
||||
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
|
||||
|
@ -303,11 +320,15 @@ class Gem::Dependency
|
|||
matches
|
||||
end
|
||||
|
||||
# DOC: this method needs either documented or :nodoc'd
|
||||
|
||||
def to_spec
|
||||
matches = self.to_specs
|
||||
|
||||
matches.find { |spec| spec.activated? } or matches.last
|
||||
active = matches.find { |spec| spec.activated? }
|
||||
|
||||
return active if active
|
||||
|
||||
matches.delete_if { |spec| spec.version.prerelease? } unless prerelease?
|
||||
|
||||
matches.last
|
||||
end
|
||||
end
|
||||
|
|
|
@ -72,6 +72,7 @@ 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
|
||||
|
||||
|
@ -102,7 +103,7 @@ class Gem::DependencyInstaller
|
|||
|
||||
@cache_dir = options[:cache_dir] || @install_dir
|
||||
|
||||
@errors = nil
|
||||
@errors = []
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -157,6 +158,7 @@ class Gem::DependencyInstaller
|
|||
|
||||
dependency_list.remove_specs_unsatisfied_by dependencies
|
||||
end
|
||||
|
||||
##
|
||||
# Creates an AvailableSet to install from based on +dep_or_name+ and
|
||||
# +version+
|
||||
|
@ -243,9 +245,9 @@ class Gem::DependencyInstaller
|
|||
# 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.
|
||||
if Gem.configuration.really_verbose then
|
||||
say "Error fetching remote data:\t\t#{e.message}"
|
||||
say "Falling back to local-only install"
|
||||
verbose do
|
||||
"Error fetching remote data:\t\t#{e.message}\n" \
|
||||
"Falling back to local-only install"
|
||||
end
|
||||
@domain = :local
|
||||
end
|
||||
|
@ -375,13 +377,16 @@ class Gem::DependencyInstaller
|
|||
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
|
||||
|
@ -415,25 +420,59 @@ class Gem::DependencyInstaller
|
|||
end
|
||||
|
||||
def resolve_dependencies dep_or_name, version # :nodoc:
|
||||
as = available_set_for dep_or_name, version
|
||||
|
||||
request_set = as.to_request_set install_development_deps
|
||||
request_set = Gem::RequestSet.new
|
||||
request_set.development = @development
|
||||
request_set.development_shallow = @dev_shallow
|
||||
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.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
|
||||
end
|
||||
|
||||
composed_set = Gem::Resolver.compose_sets as, installer_set
|
||||
request_set.resolve installer_set
|
||||
|
||||
request_set.resolve composed_set
|
||||
@errors.concat request_set.errors
|
||||
|
||||
request_set
|
||||
end
|
||||
|
|
|
@ -105,7 +105,7 @@ class Gem::Doctor
|
|||
next if ent == "." || ent == ".."
|
||||
|
||||
child = File.join(directory, ent)
|
||||
next unless File.exists?(child)
|
||||
next unless File.exist?(child)
|
||||
|
||||
basename = File.basename(child, extension)
|
||||
next if installed_specs.include? basename
|
||||
|
|
|
@ -19,6 +19,36 @@ module Gem
|
|||
attr_accessor :requirement
|
||||
end
|
||||
|
||||
# Raised when there are conflicting gem specs loaded
|
||||
|
||||
class ConflictError < LoadError
|
||||
|
||||
##
|
||||
# A Hash mapping conflicting specifications to the dependencies that
|
||||
# caused the conflict
|
||||
|
||||
attr_reader :conflicts
|
||||
|
||||
##
|
||||
# The specification that had the conflict
|
||||
|
||||
attr_reader :target
|
||||
|
||||
def initialize target, conflicts
|
||||
@target = target
|
||||
@conflicts = conflicts
|
||||
@name = target.name
|
||||
|
||||
reason = conflicts.map { |act, dependencies|
|
||||
"#{act.full_name} conflicts with #{dependencies.join(", ")}"
|
||||
}.join ", "
|
||||
|
||||
# TODO: improve message by saying who activated `con`
|
||||
|
||||
super("Unable to activate #{target.full_name}, because #{reason}")
|
||||
end
|
||||
end
|
||||
|
||||
class ErrorReason; end
|
||||
|
||||
# Generated when trying to lookup a gem to indicate that the gem
|
||||
|
|
|
@ -27,7 +27,7 @@ class Gem::DependencyRemovalException < Gem::Exception; end
|
|||
# toplevel. Indicates which dependencies were incompatible through #conflict
|
||||
# and #conflicting_dependencies
|
||||
|
||||
class Gem::DependencyResolutionError < Gem::Exception
|
||||
class Gem::DependencyResolutionError < Gem::DependencyError
|
||||
|
||||
attr_reader :conflict
|
||||
|
||||
|
@ -214,7 +214,7 @@ end
|
|||
# Raised by Resolver when a dependency requests a gem for which
|
||||
# there is no spec.
|
||||
|
||||
class Gem::UnsatisfiableDependencyError < Gem::Exception
|
||||
class Gem::UnsatisfiableDependencyError < Gem::DependencyError
|
||||
|
||||
##
|
||||
# The unsatisfiable dependency. This is a
|
||||
|
@ -222,6 +222,11 @@ class Gem::UnsatisfiableDependencyError < Gem::Exception
|
|||
|
||||
attr_reader :dependency
|
||||
|
||||
##
|
||||
# Errors encountered which may have contributed to this exception
|
||||
|
||||
attr_accessor :errors
|
||||
|
||||
##
|
||||
# Creates a new UnsatisfiableDependencyError for the unsatisfiable
|
||||
# Gem::Resolver::DependencyRequest +dep+
|
||||
|
@ -239,6 +244,21 @@ class Gem::UnsatisfiableDependencyError < Gem::Exception
|
|||
end
|
||||
|
||||
@dependency = dep
|
||||
@errors = []
|
||||
end
|
||||
|
||||
##
|
||||
# The name of the unresolved dependency
|
||||
|
||||
def name
|
||||
@dependency.name
|
||||
end
|
||||
|
||||
##
|
||||
# The Requirement of the unresolved dependency (not Version).
|
||||
|
||||
def version
|
||||
@dependency.requirement
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -161,7 +161,7 @@ EOF
|
|||
results = builder.build(extension, @gem_dir, dest_path,
|
||||
results, @build_args, lib_dir)
|
||||
|
||||
say results.join("\n") if Gem.configuration.really_verbose
|
||||
verbose { results.join("\n") }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -11,13 +11,15 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder
|
|||
FileEntry = FileUtils::Entry_ # :nodoc:
|
||||
|
||||
def self.build(extension, directory, dest_path, results, args=[], lib_dir=nil)
|
||||
tmp_dest = Dir.mktmpdir(".gem.", ".")
|
||||
# relative path required as some versions of mktmpdir return an absolute
|
||||
# path which breaks make if it includes a space in the name
|
||||
tmp_dest = get_relative_path(Dir.mktmpdir(".gem.", "."))
|
||||
|
||||
t = nil
|
||||
Tempfile.open %w"siteconf .rb", "." do |siteconf|
|
||||
t = siteconf
|
||||
siteconf.puts "require 'rbconfig'"
|
||||
siteconf.puts "dest_path = #{(tmp_dest || dest_path).dump}"
|
||||
siteconf.puts "dest_path = #{tmp_dest.dump}"
|
||||
%w[sitearchdir sitelibdir].each do |dir|
|
||||
siteconf.puts "RbConfig::MAKEFILE_CONFIG['#{dir}'] = dest_path"
|
||||
siteconf.puts "RbConfig::CONFIG['#{dir}'] = dest_path"
|
||||
|
@ -25,14 +27,10 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder
|
|||
|
||||
siteconf.flush
|
||||
|
||||
siteconf_path = File.expand_path siteconf.path
|
||||
|
||||
rubyopt = ENV["RUBYOPT"]
|
||||
destdir = ENV["DESTDIR"]
|
||||
|
||||
begin
|
||||
ENV["RUBYOPT"] = ["-r#{siteconf_path}", rubyopt].compact.join(' ')
|
||||
cmd = [Gem.ruby, File.basename(extension), *args].join ' '
|
||||
cmd = [Gem.ruby, "-r", get_relative_path(siteconf.path), File.basename(extension), *args].join ' '
|
||||
|
||||
begin
|
||||
run cmd, results
|
||||
|
@ -42,7 +40,6 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder
|
|||
end
|
||||
|
||||
ENV["DESTDIR"] = nil
|
||||
ENV["RUBYOPT"] = rubyopt
|
||||
|
||||
make dest_path, results
|
||||
|
||||
|
@ -57,11 +54,10 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder
|
|||
|
||||
FileEntry.new(tmp_dest).traverse do |ent|
|
||||
destent = ent.class.new(dest_path, ent.rel)
|
||||
destent.exist? or File.rename(ent.path, destent.path)
|
||||
destent.exist? or FileUtils.mv(ent.path, destent.path)
|
||||
end
|
||||
end
|
||||
ensure
|
||||
ENV["RUBYOPT"] = rubyopt
|
||||
ENV["DESTDIR"] = destdir
|
||||
end
|
||||
end
|
||||
|
@ -72,5 +68,11 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder
|
|||
FileUtils.rm_rf tmp_dest if tmp_dest
|
||||
end
|
||||
|
||||
private
|
||||
def self.get_relative_path(path)
|
||||
path[0..Dir.pwd.length-1] = '.' if path.start_with?(Dir.pwd)
|
||||
path
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ module Gem::GemcutterUtilities
|
|||
|
||||
def sign_in sign_in_host = nil
|
||||
sign_in_host ||= self.host
|
||||
return if Gem.configuration.rubygems_api_key
|
||||
return if api_key
|
||||
|
||||
pretty_host = if Gem::DEFAULT_HOST == sign_in_host then
|
||||
'RubyGems.org'
|
||||
|
|
|
@ -59,6 +59,23 @@ module Gem::InstallUpdateOptions
|
|||
end
|
||||
end
|
||||
|
||||
add_option(:"Install/Update", '--build-root DIR',
|
||||
'Temporary installation root. Useful for building',
|
||||
'packages. Do not use this when installing remote gems.') do |value, options|
|
||||
options[:build_root] = File.expand_path(value)
|
||||
end
|
||||
|
||||
add_option(:"Install/Update", '--vendor',
|
||||
'Install gem into 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
|
||||
|
||||
options[:vendor] = true
|
||||
options[:install_dir] = Gem.vendor_dir
|
||||
end
|
||||
|
||||
add_option(:"Install/Update", '-N', '--no-document',
|
||||
'Disable documentation generation') do |value, options|
|
||||
options[:document] = []
|
||||
|
|
|
@ -39,7 +39,9 @@ class Gem::Installer
|
|||
|
||||
include Gem::UserInteraction
|
||||
|
||||
# DOC: Missing docs or :nodoc:.
|
||||
##
|
||||
# Filename of the gem being installed.
|
||||
|
||||
attr_reader :gem
|
||||
|
||||
##
|
||||
|
@ -47,6 +49,8 @@ class Gem::Installer
|
|||
|
||||
attr_reader :bin_dir
|
||||
|
||||
attr_reader :build_root # :nodoc:
|
||||
|
||||
##
|
||||
# The gem repository the gem will be installed into
|
||||
|
||||
|
@ -64,6 +68,8 @@ class Gem::Installer
|
|||
|
||||
@path_warning = false
|
||||
|
||||
@install_lock = Mutex.new
|
||||
|
||||
class << self
|
||||
|
||||
##
|
||||
|
@ -71,7 +77,19 @@ class Gem::Installer
|
|||
|
||||
attr_accessor :path_warning
|
||||
|
||||
# DOC: Missing docs or :nodoc:.
|
||||
##
|
||||
# Certain aspects of the install process are not thread-safe. This lock is
|
||||
# used to allow multiple threads to install Gems at the same time.
|
||||
|
||||
attr_reader :install_lock
|
||||
|
||||
##
|
||||
# Overrides the executable format.
|
||||
#
|
||||
# This is a sprintf format with a "%s" which will be replaced with the
|
||||
# executable name. It is based off the ruby executable name's difference
|
||||
# from "ruby".
|
||||
|
||||
attr_writer :exec_format
|
||||
|
||||
# Defaults to use Ruby's program prefix and suffix.
|
||||
|
@ -240,7 +258,7 @@ class Gem::Installer
|
|||
|
||||
say spec.post_install_message unless spec.post_install_message.nil?
|
||||
|
||||
Gem::Specification.add_spec spec unless Gem::Specification.include? spec
|
||||
Gem::Installer.install_lock.synchronize { Gem::Specification.add_spec spec }
|
||||
|
||||
run_post_install_hooks
|
||||
|
||||
|
@ -318,6 +336,7 @@ class Gem::Installer
|
|||
# True if the gems in the system satisfy +dependency+.
|
||||
|
||||
def installation_satisfies_dependency?(dependency)
|
||||
return true if @options[:development] and dependency.type == :development
|
||||
return true if installed_specs.detect { |s| dependency.matches_spec? s }
|
||||
return false if @only_install_dir
|
||||
not dependency.matching_specs.empty?
|
||||
|
@ -382,12 +401,11 @@ class Gem::Installer
|
|||
file.puts windows_stub_script(bindir, filename)
|
||||
end
|
||||
|
||||
say script_path if Gem.configuration.really_verbose
|
||||
verbose script_path
|
||||
end
|
||||
end
|
||||
|
||||
# DOC: Missing docs or :nodoc:.
|
||||
def generate_bin
|
||||
def generate_bin # :nodoc:
|
||||
return if spec.executables.nil? or spec.executables.empty?
|
||||
|
||||
Dir.mkdir @bin_dir unless File.exist? @bin_dir
|
||||
|
@ -433,7 +451,7 @@ class Gem::Installer
|
|||
file.print app_script_text(filename)
|
||||
end
|
||||
|
||||
say bin_script_path if Gem.configuration.really_verbose
|
||||
verbose bin_script_path
|
||||
|
||||
generate_windows_script filename, bindir
|
||||
end
|
||||
|
@ -536,8 +554,7 @@ class Gem::Installer
|
|||
end
|
||||
end
|
||||
|
||||
# DOC: Missing docs or :nodoc:.
|
||||
def ensure_required_ruby_version_met
|
||||
def ensure_required_ruby_version_met # :nodoc:
|
||||
if rrv = spec.required_ruby_version then
|
||||
unless rrv.satisfied_by? Gem.ruby_version then
|
||||
raise Gem::InstallError, "#{spec.name} requires Ruby version #{rrv}."
|
||||
|
@ -545,8 +562,7 @@ class Gem::Installer
|
|||
end
|
||||
end
|
||||
|
||||
# DOC: Missing docs or :nodoc:.
|
||||
def ensure_required_rubygems_version_met
|
||||
def ensure_required_rubygems_version_met # :nodoc:
|
||||
if rrgv = spec.required_rubygems_version then
|
||||
unless rrgv.satisfied_by? Gem.rubygems_version then
|
||||
raise Gem::InstallError,
|
||||
|
@ -556,8 +572,7 @@ class Gem::Installer
|
|||
end
|
||||
end
|
||||
|
||||
# DOC: Missing docs or :nodoc:.
|
||||
def ensure_dependencies_met
|
||||
def ensure_dependencies_met # :nodoc:
|
||||
deps = spec.runtime_dependencies
|
||||
deps |= spec.development_dependencies if @development
|
||||
|
||||
|
@ -566,8 +581,7 @@ class Gem::Installer
|
|||
end
|
||||
end
|
||||
|
||||
# DOC: Missing docs or :nodoc:.
|
||||
def process_options
|
||||
def process_options # :nodoc:
|
||||
@options = {
|
||||
:bin_dir => nil,
|
||||
:env_shebang => false,
|
||||
|
@ -590,12 +604,20 @@ class Gem::Installer
|
|||
# (or use) a new bin dir under the gem_home.
|
||||
@bin_dir = options[:bin_dir] || Gem.bindir(gem_home)
|
||||
@development = options[:development]
|
||||
@build_root = options[:build_root]
|
||||
|
||||
@build_args = options[:build_args] || Gem::Command.build_args
|
||||
|
||||
unless @build_root.nil?
|
||||
require 'pathname'
|
||||
@build_root = Pathname.new(@build_root).expand_path
|
||||
@bin_dir = File.join(@build_root, options[:bin_dir] || Gem.bindir(@gem_home))
|
||||
@gem_home = File.join(@build_root, @gem_home)
|
||||
alert_warning "You build with buildroot.\n Build root: #{@build_root}\n Bin dir: #{@bin_dir}\n Gem home: #{@gem_home}"
|
||||
end
|
||||
end
|
||||
|
||||
# DOC: Missing docs or :nodoc:.
|
||||
def check_that_user_bin_dir_is_in_path
|
||||
def check_that_user_bin_dir_is_in_path # :nodoc:
|
||||
user_bin_dir = @bin_dir || Gem.bindir(gem_home)
|
||||
user_bin_dir = user_bin_dir.gsub(File::SEPARATOR, File::ALT_SEPARATOR) if
|
||||
File::ALT_SEPARATOR
|
||||
|
@ -606,16 +628,19 @@ class Gem::Installer
|
|||
user_bin_dir = user_bin_dir.downcase
|
||||
end
|
||||
|
||||
unless path.split(File::PATH_SEPARATOR).include? user_bin_dir then
|
||||
unless self.class.path_warning then
|
||||
alert_warning "You don't have #{user_bin_dir} in your PATH,\n\t gem executables will not run."
|
||||
self.class.path_warning = true
|
||||
path = path.split(File::PATH_SEPARATOR)
|
||||
|
||||
unless path.include? user_bin_dir then
|
||||
unless !Gem.win_platform? && (path.include? user_bin_dir.sub(ENV['HOME'], '~'))
|
||||
unless self.class.path_warning then
|
||||
alert_warning "You don't have #{user_bin_dir} in your PATH,\n\t gem executables will not run."
|
||||
self.class.path_warning = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# DOC: Missing docs or :nodoc:.
|
||||
def verify_gem_home(unpack = false)
|
||||
def verify_gem_home(unpack = false) # :nodoc:
|
||||
FileUtils.mkdir_p gem_home
|
||||
raise Gem::FilePermissionError, gem_home unless
|
||||
unpack or File.writable?(gem_home)
|
||||
|
@ -660,10 +685,10 @@ TEXT
|
|||
return <<-TEXT
|
||||
@ECHO OFF
|
||||
IF NOT "%~f0" == "~f0" GOTO :WinNT
|
||||
@"#{ruby}" "#{File.join(bindir, bin_file_name)}" %1 %2 %3 %4 %5 %6 %7 %8 %9
|
||||
@"#{bindir.tr(File::SEPARATOR, File::ALT_SEPARATOR)}\\#{ruby}" "#{File.join(bindir, bin_file_name)}" %1 %2 %3 %4 %5 %6 %7 %8 %9
|
||||
GOTO :EOF
|
||||
:WinNT
|
||||
@"#{ruby}" "%~dpn0" %*
|
||||
@"%~dp0#{ruby}" "%~dpn0" %*
|
||||
TEXT
|
||||
end
|
||||
|
||||
|
|
|
@ -101,6 +101,8 @@ class Gem::InstallerTestCase < Gem::TestCase
|
|||
|
||||
@installer = util_installer @spec, @gemhome
|
||||
@user_installer = util_installer @user_spec, Gem.user_dir, :user
|
||||
|
||||
Gem::Installer.path_warning = false
|
||||
end
|
||||
|
||||
def util_gem_bindir spec = @spec # :nodoc:
|
||||
|
|
|
@ -100,8 +100,8 @@ module Gem::LocalRemoteOptions
|
|||
def add_source_option
|
||||
accept_uri_http
|
||||
|
||||
add_option(:"Local/Remote", '--source URL', URI::HTTP,
|
||||
'Add URL as a remote source for gems') do |source, options|
|
||||
add_option(:"Local/Remote", '-s', '--source URL', URI::HTTP,
|
||||
'Append URL to list of remote gem sources') do |source, options|
|
||||
|
||||
source << '/' if source !~ /\/\z/
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ class Gem::NameTuple
|
|||
"#{@name}-#{@version}"
|
||||
else
|
||||
"#{@name}-#{@version}-#{@platform}"
|
||||
end
|
||||
end.untaint
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -90,7 +90,9 @@ class Gem::NameTuple
|
|||
alias to_s inspect # :nodoc:
|
||||
|
||||
def <=> other
|
||||
to_a <=> other.to_a
|
||||
[@name, @version, @platform == Gem::Platform::RUBY ? -1 : 1] <=>
|
||||
[other.name, other.version,
|
||||
other.platform == Gem::Platform::RUBY ? -1 : 1]
|
||||
end
|
||||
|
||||
include Comparable
|
||||
|
|
|
@ -54,10 +54,12 @@ class Gem::Package
|
|||
class FormatError < Error
|
||||
attr_reader :path
|
||||
|
||||
def initialize message, path = nil
|
||||
@path = path
|
||||
def initialize message, source = nil
|
||||
if source
|
||||
@path = source.path
|
||||
|
||||
message << " in #{path}" if path
|
||||
message << " in #{path}" if path
|
||||
end
|
||||
|
||||
super message
|
||||
end
|
||||
|
@ -80,6 +82,7 @@ class Gem::Package
|
|||
|
||||
class TarInvalidError < Error; end
|
||||
|
||||
|
||||
attr_accessor :build_time # :nodoc:
|
||||
|
||||
##
|
||||
|
@ -114,19 +117,26 @@ class Gem::Package
|
|||
end
|
||||
|
||||
##
|
||||
# Creates a new Gem::Package for the file at +gem+.
|
||||
# Creates a new Gem::Package for the file at +gem+. +gem+ can also be
|
||||
# provided as an IO object.
|
||||
#
|
||||
# If +gem+ is an existing file in the old format a Gem::Package::Old will be
|
||||
# returned.
|
||||
|
||||
def self.new gem
|
||||
return super unless Gem::Package == self
|
||||
return super unless File.exist? gem
|
||||
gem = if gem.is_a?(Gem::Package::Source)
|
||||
gem
|
||||
elsif gem.respond_to? :read
|
||||
Gem::Package::IOSource.new gem
|
||||
else
|
||||
Gem::Package::FileSource.new gem
|
||||
end
|
||||
|
||||
start = File.read gem, 20
|
||||
return super(gem) unless Gem::Package == self
|
||||
return super unless gem.present?
|
||||
|
||||
return super unless start
|
||||
return super unless start.include? 'MD5SUM ='
|
||||
return super unless gem.start
|
||||
return super unless gem.start.include? 'MD5SUM ='
|
||||
|
||||
Gem::Package::Old.new gem
|
||||
end
|
||||
|
@ -227,7 +237,7 @@ class Gem::Package
|
|||
|
||||
setup_signer
|
||||
|
||||
open @gem, 'wb' do |gem_io|
|
||||
@gem.with_write_io do |gem_io|
|
||||
Gem::Package::TarWriter.new gem_io do |gem|
|
||||
add_metadata gem
|
||||
add_contents gem
|
||||
|
@ -255,7 +265,7 @@ EOM
|
|||
|
||||
@contents = []
|
||||
|
||||
open @gem, 'rb' do |io|
|
||||
@gem.with_read_io do |io|
|
||||
gem_tar = Gem::Package::TarReader.new io
|
||||
|
||||
gem_tar.each do |entry|
|
||||
|
@ -312,7 +322,7 @@ EOM
|
|||
|
||||
FileUtils.mkdir_p destination_dir
|
||||
|
||||
open @gem, 'rb' do |io|
|
||||
@gem.with_read_io do |io|
|
||||
reader = Gem::Package::TarReader.new io
|
||||
|
||||
reader.each do |entry|
|
||||
|
@ -360,7 +370,7 @@ EOM
|
|||
out.write entry.read
|
||||
end if entry.file?
|
||||
|
||||
say destination if Gem.configuration.really_verbose
|
||||
verbose destination
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -490,7 +500,7 @@ EOM
|
|||
@files = []
|
||||
@spec = nil
|
||||
|
||||
open @gem, 'rb' do |io|
|
||||
@gem.with_read_io do |io|
|
||||
Gem::Package::TarReader.new io do |reader|
|
||||
read_checksums reader
|
||||
|
||||
|
@ -592,6 +602,9 @@ EOM
|
|||
end
|
||||
|
||||
require 'rubygems/package/digest_io'
|
||||
require 'rubygems/package/source'
|
||||
require 'rubygems/package/file_source'
|
||||
require 'rubygems/package/io_source'
|
||||
require 'rubygems/package/old'
|
||||
require 'rubygems/package/tar_header'
|
||||
require 'rubygems/package/tar_reader'
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
##
|
||||
# The primary source of gems is a file on disk, including all usages
|
||||
# internal to rubygems.
|
||||
#
|
||||
# This is a private class, do not depend on it directly. Instead, pass a path
|
||||
# object to `Gem::Package.new`.
|
||||
|
||||
class Gem::Package::FileSource < Gem::Package::Source # :nodoc: all
|
||||
|
||||
attr_reader :path
|
||||
|
||||
def initialize path
|
||||
@path = path
|
||||
end
|
||||
|
||||
def start
|
||||
@start ||= File.read path, 20
|
||||
end
|
||||
|
||||
def present?
|
||||
File.exist? path
|
||||
end
|
||||
|
||||
def with_write_io &block
|
||||
open path, 'wb', &block
|
||||
end
|
||||
|
||||
def with_read_io &block
|
||||
open path, 'rb', &block
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
##
|
||||
# Supports reading and writing gems from/to a generic IO object. This is
|
||||
# useful for other applications built on top of rubygems, such as
|
||||
# rubygems.org.
|
||||
#
|
||||
# This is a private class, do not depend on it directly. Instead, pass an IO
|
||||
# object to `Gem::Package.new`.
|
||||
|
||||
class Gem::Package::IOSource < Gem::Package::Source # :nodoc: all
|
||||
|
||||
attr_reader :io
|
||||
|
||||
def initialize io
|
||||
@io = io
|
||||
end
|
||||
|
||||
def start
|
||||
@start ||= begin
|
||||
if io.pos > 0
|
||||
raise Gem::Package::Error, "Cannot read start unless IO is at start"
|
||||
end
|
||||
|
||||
value = io.read 20
|
||||
io.rewind
|
||||
value
|
||||
end
|
||||
end
|
||||
|
||||
def present?
|
||||
true
|
||||
end
|
||||
|
||||
def with_read_io
|
||||
yield io
|
||||
end
|
||||
|
||||
def with_write_io
|
||||
yield io
|
||||
end
|
||||
|
||||
def path
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -37,7 +37,7 @@ class Gem::Package::Old < Gem::Package
|
|||
|
||||
return @contents if @contents
|
||||
|
||||
open @gem, 'rb' do |io|
|
||||
@gem.with_read_io do |io|
|
||||
read_until_dashes io # spec
|
||||
header = file_list io
|
||||
|
||||
|
@ -53,7 +53,7 @@ class Gem::Package::Old < Gem::Package
|
|||
|
||||
errstr = "Error reading files from gem"
|
||||
|
||||
open @gem, 'rb' do |io|
|
||||
@gem.with_read_io do |io|
|
||||
read_until_dashes io # spec
|
||||
header = file_list io
|
||||
raise Gem::Exception, errstr unless header
|
||||
|
@ -83,7 +83,7 @@ class Gem::Package::Old < Gem::Package
|
|||
out.write file_data
|
||||
end
|
||||
|
||||
say destination if Gem.configuration.really_verbose
|
||||
verbose destination
|
||||
end
|
||||
end
|
||||
rescue Zlib::DataError
|
||||
|
@ -136,7 +136,7 @@ class Gem::Package::Old < Gem::Package
|
|||
|
||||
yaml = ''
|
||||
|
||||
open @gem, 'rb' do |io|
|
||||
@gem.with_read_io do |io|
|
||||
skip_ruby io
|
||||
read_until_dashes io do |line|
|
||||
yaml << line
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
class Gem::Package::Source # :nodoc:
|
||||
end
|
||||
|
|
@ -129,6 +129,8 @@ class Gem::Package::TarReader::Entry
|
|||
ret
|
||||
end
|
||||
|
||||
alias readpartial read # :nodoc:
|
||||
|
||||
##
|
||||
# Rewinds to the beginning of the tar file entry
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ class Gem::Platform
|
|||
|
||||
def self.local
|
||||
arch = RbConfig::CONFIG['arch']
|
||||
arch = "#{arch}_60" if arch =~ /mswin32$/
|
||||
arch = "#{arch}_60" if arch =~ /mswin(?:32|64)$/
|
||||
@local ||= new(arch)
|
||||
end
|
||||
|
||||
|
@ -173,6 +173,7 @@ class Gem::Platform
|
|||
when /^dalvik(\d+)?$/ then [nil, 'dalvik', $1 ]
|
||||
when /dotnet(\-(\d+\.\d+))?/ then ['universal','dotnet', $2 ]
|
||||
when /mswin32(\_(\d+))?/ then ['x86', 'mswin32', $2 ]
|
||||
when /mswin64(\_(\d+))?/ then ['x64', 'mswin64', $2 ]
|
||||
when 'powerpc-darwin' then ['powerpc', 'darwin', nil ]
|
||||
when /powerpc-darwin(\d)/ then ['powerpc', 'darwin', $1 ]
|
||||
when /sparc-solaris2.8/ then ['sparc', 'solaris', '2.8' ]
|
||||
|
|
|
@ -263,7 +263,7 @@ class Gem::RDoc # :nodoc: all
|
|||
Gem::Requirement.new('>= 2.4.0') =~ self.class.rdoc_version
|
||||
|
||||
r = new_rdoc
|
||||
say "rdoc #{args.join ' '}" if Gem.configuration.really_verbose
|
||||
verbose { "rdoc #{args.join ' '}" }
|
||||
|
||||
Dir.chdir @spec.full_gem_path do
|
||||
begin
|
||||
|
@ -279,7 +279,6 @@ class Gem::RDoc # :nodoc: all
|
|||
ui.errs.puts "... RDOC args: #{args.join(' ')}"
|
||||
ui.backtrace ex
|
||||
ui.errs.puts "(continuing with the rest of the installation)"
|
||||
ensure
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,6 +2,7 @@ require 'rubygems'
|
|||
require 'rubygems/request'
|
||||
require 'rubygems/uri_formatter'
|
||||
require 'rubygems/user_interaction'
|
||||
require 'rubygems/request/connection_pools'
|
||||
require 'resolv'
|
||||
|
||||
##
|
||||
|
@ -73,6 +74,9 @@ class Gem::RemoteFetcher
|
|||
Socket.do_not_reverse_lookup = true
|
||||
|
||||
@proxy = proxy
|
||||
@pools = {}
|
||||
@pool_lock = Mutex.new
|
||||
@cert_files = Gem::Request.get_cert_files
|
||||
|
||||
@dns = dns
|
||||
end
|
||||
|
@ -154,11 +158,10 @@ class Gem::RemoteFetcher
|
|||
# REFACTOR: split this up and dispatch on scheme (eg download_http)
|
||||
# REFACTOR: be sure to clean up fake fetcher when you do this... cleaner
|
||||
case scheme
|
||||
when 'http', 'https' then
|
||||
when 'http', 'https', 's3' then
|
||||
unless File.exist? local_gem_path then
|
||||
begin
|
||||
say "Downloading gem #{gem_file_name}" if
|
||||
Gem.configuration.really_verbose
|
||||
verbose "Downloading gem #{gem_file_name}"
|
||||
|
||||
remote_gem_path = source_uri + "gems/#{gem_file_name}"
|
||||
|
||||
|
@ -168,8 +171,7 @@ class Gem::RemoteFetcher
|
|||
|
||||
alternate_name = "#{spec.original_name}.gem"
|
||||
|
||||
say "Failed, downloading gem #{alternate_name}" if
|
||||
Gem.configuration.really_verbose
|
||||
verbose "Failed, downloading gem #{alternate_name}"
|
||||
|
||||
remote_gem_path = source_uri + "gems/#{alternate_name}"
|
||||
|
||||
|
@ -188,8 +190,7 @@ class Gem::RemoteFetcher
|
|||
local_gem_path = source_uri.to_s
|
||||
end
|
||||
|
||||
say "Using local gem #{local_gem_path}" if
|
||||
Gem.configuration.really_verbose
|
||||
verbose "Using local gem #{local_gem_path}"
|
||||
when nil then # TODO test for local overriding cache
|
||||
source_path = if Gem.win_platform? && source_uri.scheme &&
|
||||
!source_uri.path.include?(':') then
|
||||
|
@ -207,8 +208,7 @@ class Gem::RemoteFetcher
|
|||
local_gem_path = source_uri.to_s
|
||||
end
|
||||
|
||||
say "Using local gem #{local_gem_path}" if
|
||||
Gem.configuration.really_verbose
|
||||
verbose "Using local gem #{local_gem_path}"
|
||||
else
|
||||
raise ArgumentError, "unsupported URI scheme #{source_uri.scheme}"
|
||||
end
|
||||
|
@ -232,6 +232,7 @@ class Gem::RemoteFetcher
|
|||
|
||||
case response
|
||||
when Net::HTTPOK, Net::HTTPNotModified then
|
||||
response.uri = uri if response.respond_to? :uri
|
||||
head ? response : response.body
|
||||
when Net::HTTPMovedPermanently, Net::HTTPFound, Net::HTTPSeeOther,
|
||||
Net::HTTPTemporaryRedirect then
|
||||
|
@ -265,7 +266,7 @@ class Gem::RemoteFetcher
|
|||
|
||||
data = send "fetch_#{uri.scheme}", uri, mtime, head
|
||||
|
||||
if data and !head and uri.to_s =~ /gz$/
|
||||
if data and !head and uri.to_s =~ /\.gz$/
|
||||
begin
|
||||
data = Gem.gunzip data
|
||||
rescue Zlib::GzipFile::Error
|
||||
|
@ -286,6 +287,11 @@ class Gem::RemoteFetcher
|
|||
end
|
||||
end
|
||||
|
||||
def fetch_s3(uri, mtime = nil, head = false)
|
||||
public_uri = sign_s3_url(uri)
|
||||
fetch_https public_uri, mtime, head
|
||||
end
|
||||
|
||||
##
|
||||
# Downloads +uri+ to +path+ if necessary. If no path is given, it just
|
||||
# passes the data.
|
||||
|
@ -332,18 +338,57 @@ class Gem::RemoteFetcher
|
|||
# connections to reduce connect overhead.
|
||||
|
||||
def request(uri, request_class, last_modified = nil)
|
||||
request = Gem::Request.new uri, request_class, last_modified, @proxy
|
||||
proxy = proxy_for @proxy, uri
|
||||
pool = pools_for(proxy).pool_for uri
|
||||
|
||||
request = Gem::Request.new uri, request_class, last_modified, pool
|
||||
|
||||
request.fetch do |req|
|
||||
yield req if block_given?
|
||||
end
|
||||
ensure
|
||||
request.close if request
|
||||
end
|
||||
|
||||
def https?(uri)
|
||||
uri.scheme.downcase == 'https'
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# we have our own signing code here to avoid a dependency on the aws-sdk gem
|
||||
# fortunately, a simple GET request isn't too complex to sign properly
|
||||
def sign_s3_url(uri, expiration = nil)
|
||||
require 'base64'
|
||||
require 'openssl'
|
||||
|
||||
unless uri.user && uri.password
|
||||
raise FetchError.new("credentials needed in s3 source, like s3://key:secret@bucket-name/", uri.to_s)
|
||||
end
|
||||
|
||||
expiration ||= s3_expiration
|
||||
canonical_path = "/#{uri.host}#{uri.path}"
|
||||
payload = "GET\n\n\n#{expiration}\n#{canonical_path}"
|
||||
digest = OpenSSL::HMAC.digest('sha1', uri.password, payload)
|
||||
# URI.escape is deprecated, and there isn't yet a replacement that does quite what we want
|
||||
signature = Base64.encode64(digest).gsub("\n", '').gsub(/[\+\/=]/) { |c| BASE64_URI_TRANSLATE[c] }
|
||||
URI.parse("https://#{uri.host}.s3.amazonaws.com#{uri.path}?AWSAccessKeyId=#{uri.user}&Expires=#{expiration}&Signature=#{signature}")
|
||||
end
|
||||
|
||||
def s3_expiration
|
||||
(Time.now + 3600).to_i # one hour from now
|
||||
end
|
||||
|
||||
BASE64_URI_TRANSLATE = { '+' => '%2B', '/' => '%2F', '=' => '%3D' }.freeze
|
||||
|
||||
private
|
||||
|
||||
def proxy_for proxy, uri
|
||||
Gem::Request.proxy_uri(proxy || Gem::Request.get_proxy_from_env(uri.scheme))
|
||||
end
|
||||
|
||||
def pools_for proxy
|
||||
@pool_lock.synchronize do
|
||||
@pools[proxy] ||= Gem::Request::ConnectionPools.new proxy, @cert_files
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -7,41 +7,43 @@ class Gem::Request
|
|||
|
||||
include Gem::UserInteraction
|
||||
|
||||
attr_reader :proxy_uri
|
||||
###
|
||||
# Legacy. This is used in tests.
|
||||
def self.create_with_proxy uri, request_class, last_modified, proxy # :nodoc:
|
||||
cert_files = get_cert_files
|
||||
proxy ||= get_proxy_from_env(uri.scheme)
|
||||
pool = ConnectionPools.new proxy_uri(proxy), cert_files
|
||||
|
||||
def initialize(uri, request_class, last_modified, proxy)
|
||||
new(uri, request_class, last_modified, pool.pool_for(uri))
|
||||
end
|
||||
|
||||
def self.proxy_uri proxy # :nodoc:
|
||||
case proxy
|
||||
when :no_proxy then nil
|
||||
when URI::HTTP then proxy
|
||||
else URI.parse(proxy)
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(uri, request_class, last_modified, pool)
|
||||
@uri = uri
|
||||
@request_class = request_class
|
||||
@last_modified = last_modified
|
||||
@requests = Hash.new 0
|
||||
@connections = {}
|
||||
@connections_mutex = Mutex.new
|
||||
@user_agent = user_agent
|
||||
|
||||
@proxy_uri =
|
||||
case proxy
|
||||
when :no_proxy then nil
|
||||
when nil then get_proxy_from_env uri.scheme
|
||||
when URI::HTTP then proxy
|
||||
else URI.parse(proxy)
|
||||
end
|
||||
@env_no_proxy = get_no_proxy_from_env
|
||||
@connection_pool = pool
|
||||
end
|
||||
|
||||
def close
|
||||
@connections.each_value do |conn|
|
||||
conn.finish
|
||||
end
|
||||
end
|
||||
def proxy_uri; @connection_pool.proxy_uri; end
|
||||
def cert_files; @connection_pool.cert_files; end
|
||||
|
||||
def add_rubygems_trusted_certs(store)
|
||||
def self.get_cert_files
|
||||
pattern = File.expand_path("./ssl_certs/*.pem", File.dirname(__FILE__))
|
||||
Dir.glob(pattern).each do |ssl_cert_file|
|
||||
store.add_file ssl_cert_file
|
||||
end
|
||||
Dir.glob(pattern)
|
||||
end
|
||||
|
||||
def configure_connection_for_https(connection)
|
||||
def self.configure_connection_for_https(connection, cert_files)
|
||||
require 'net/https'
|
||||
connection.use_ssl = true
|
||||
connection.verify_mode =
|
||||
|
@ -55,7 +57,9 @@ class Gem::Request
|
|||
end
|
||||
|
||||
store.set_default_paths
|
||||
add_rubygems_trusted_certs(store)
|
||||
cert_files.each do |ssl_cert_file|
|
||||
store.add_file ssl_cert_file
|
||||
end
|
||||
if Gem.configuration.ssl_ca_cert
|
||||
if File.directory? Gem.configuration.ssl_ca_cert
|
||||
store.add_path Gem.configuration.ssl_ca_cert
|
||||
|
@ -64,6 +68,7 @@ class Gem::Request
|
|||
end
|
||||
end
|
||||
connection.cert_store = store
|
||||
connection
|
||||
rescue LoadError => e
|
||||
raise unless (e.respond_to?(:path) && e.path == 'openssl') ||
|
||||
e.message =~ / -- openssl$/
|
||||
|
@ -77,31 +82,7 @@ class Gem::Request
|
|||
# connection, using a proxy if needed.
|
||||
|
||||
def connection_for(uri)
|
||||
net_http_args = [uri.host, uri.port]
|
||||
|
||||
if @proxy_uri and not no_proxy?(uri.host) then
|
||||
net_http_args += [
|
||||
@proxy_uri.host,
|
||||
@proxy_uri.port,
|
||||
Gem::UriFormatter.new(@proxy_uri.user).unescape,
|
||||
Gem::UriFormatter.new(@proxy_uri.password).unescape,
|
||||
]
|
||||
end
|
||||
|
||||
connection_id = [Thread.current.object_id, *net_http_args].join ':'
|
||||
|
||||
connection = @connections_mutex.synchronize do
|
||||
@connections[connection_id] ||= Net::HTTP.new(*net_http_args)
|
||||
@connections[connection_id]
|
||||
end
|
||||
|
||||
if https?(uri) and not connection.started? then
|
||||
configure_connection_for_https(connection)
|
||||
end
|
||||
|
||||
connection.start unless connection.started?
|
||||
|
||||
connection
|
||||
@connection_pool.checkout
|
||||
rescue defined?(OpenSSL::SSL) ? OpenSSL::SSL::SSLError : Errno::EHOSTDOWN,
|
||||
Errno::EHOSTDOWN => e
|
||||
raise Gem::RemoteFetcher::FetchError.new(e.message, uri)
|
||||
|
@ -125,6 +106,37 @@ class Gem::Request
|
|||
|
||||
yield request if block_given?
|
||||
|
||||
perform_request request
|
||||
end
|
||||
|
||||
##
|
||||
# Returns a proxy URI for the given +scheme+ if one is set in the
|
||||
# environment variables.
|
||||
|
||||
def self.get_proxy_from_env scheme = 'http'
|
||||
_scheme = scheme.downcase
|
||||
_SCHEME = scheme.upcase
|
||||
env_proxy = ENV["#{_scheme}_proxy"] || ENV["#{_SCHEME}_PROXY"]
|
||||
|
||||
no_env_proxy = env_proxy.nil? || env_proxy.empty?
|
||||
|
||||
return get_proxy_from_env 'http' if no_env_proxy and _scheme != 'http'
|
||||
return :no_proxy if no_env_proxy
|
||||
|
||||
uri = URI(Gem::UriFormatter.new(env_proxy).normalize)
|
||||
|
||||
if uri and uri.user.nil? and uri.password.nil? then
|
||||
user = ENV["#{_scheme}_proxy_user"] || ENV["#{_SCHEME}_PROXY_USER"]
|
||||
password = ENV["#{_scheme}_proxy_pass"] || ENV["#{_SCHEME}_PROXY_PASS"]
|
||||
|
||||
uri.user = Gem::UriFormatter.new(user).escape
|
||||
uri.password = Gem::UriFormatter.new(password).escape
|
||||
end
|
||||
|
||||
uri
|
||||
end
|
||||
|
||||
def perform_request request # :nodoc:
|
||||
connection = connection_for @uri
|
||||
|
||||
retried = false
|
||||
|
@ -133,8 +145,7 @@ class Gem::Request
|
|||
begin
|
||||
@requests[connection.object_id] += 1
|
||||
|
||||
say "#{request.method} #{@uri}" if
|
||||
Gem.configuration.really_verbose
|
||||
verbose "#{request.method} #{@uri}"
|
||||
|
||||
file_name = File.basename(@uri.path)
|
||||
# perform download progress reporter only for gems
|
||||
|
@ -163,11 +174,10 @@ class Gem::Request
|
|||
response = connection.request request
|
||||
end
|
||||
|
||||
say "#{response.code} #{response.message}" if
|
||||
Gem.configuration.really_verbose
|
||||
verbose "#{response.code} #{response.message}"
|
||||
|
||||
rescue Net::HTTPBadResponse
|
||||
say "bad response" if Gem.configuration.really_verbose
|
||||
verbose "bad response"
|
||||
|
||||
reset connection
|
||||
|
||||
|
@ -182,8 +192,7 @@ class Gem::Request
|
|||
Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE
|
||||
|
||||
requests = @requests[connection.object_id]
|
||||
say "connection reset after #{requests} requests, retrying" if
|
||||
Gem.configuration.really_verbose
|
||||
verbose "connection reset after #{requests} requests, retrying"
|
||||
|
||||
raise Gem::RemoteFetcher::FetchError.new('too many connection resets', @uri) if retried
|
||||
|
||||
|
@ -194,57 +203,8 @@ class Gem::Request
|
|||
end
|
||||
|
||||
response
|
||||
end
|
||||
|
||||
##
|
||||
# Returns list of no_proxy entries (if any) from the environment
|
||||
|
||||
def get_no_proxy_from_env
|
||||
env_no_proxy = ENV['no_proxy'] || ENV['NO_PROXY']
|
||||
|
||||
return [] if env_no_proxy.nil? or env_no_proxy.empty?
|
||||
|
||||
env_no_proxy.split(/\s*,\s*/)
|
||||
end
|
||||
|
||||
##
|
||||
# Returns a proxy URI for the given +scheme+ if one is set in the
|
||||
# environment variables.
|
||||
|
||||
def get_proxy_from_env scheme = 'http'
|
||||
_scheme = scheme.downcase
|
||||
_SCHEME = scheme.upcase
|
||||
env_proxy = ENV["#{_scheme}_proxy"] || ENV["#{_SCHEME}_PROXY"]
|
||||
|
||||
no_env_proxy = env_proxy.nil? || env_proxy.empty?
|
||||
|
||||
return get_proxy_from_env 'http' if no_env_proxy and _scheme != 'http'
|
||||
return nil if no_env_proxy
|
||||
|
||||
uri = URI(Gem::UriFormatter.new(env_proxy).normalize)
|
||||
|
||||
if uri and uri.user.nil? and uri.password.nil? then
|
||||
user = ENV["#{_scheme}_proxy_user"] || ENV["#{_SCHEME}_PROXY_USER"]
|
||||
password = ENV["#{_scheme}_proxy_pass"] || ENV["#{_SCHEME}_PROXY_PASS"]
|
||||
|
||||
uri.user = Gem::UriFormatter.new(user).escape
|
||||
uri.password = Gem::UriFormatter.new(password).escape
|
||||
end
|
||||
|
||||
uri
|
||||
end
|
||||
|
||||
def https?(uri)
|
||||
uri.scheme.downcase == 'https'
|
||||
end
|
||||
|
||||
def no_proxy? host
|
||||
host = host.downcase
|
||||
@env_no_proxy.each do |pattern|
|
||||
pattern = pattern.downcase
|
||||
return true if host[-pattern.length, pattern.length ] == pattern
|
||||
end
|
||||
return false
|
||||
ensure
|
||||
@connection_pool.checkin connection
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -278,3 +238,7 @@ class Gem::Request
|
|||
|
||||
end
|
||||
|
||||
require 'rubygems/request/http_pool'
|
||||
require 'rubygems/request/https_pool'
|
||||
require 'rubygems/request/connection_pools'
|
||||
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
require 'thread'
|
||||
|
||||
class Gem::Request::ConnectionPools # :nodoc:
|
||||
|
||||
@client = Net::HTTP
|
||||
|
||||
class << self
|
||||
attr_accessor :client
|
||||
end
|
||||
|
||||
def initialize proxy_uri, cert_files
|
||||
@proxy_uri = proxy_uri
|
||||
@cert_files = cert_files
|
||||
@pools = {}
|
||||
@pool_mutex = Mutex.new
|
||||
end
|
||||
|
||||
def pool_for uri
|
||||
http_args = net_http_args(uri, @proxy_uri)
|
||||
key = http_args + [https?(uri)]
|
||||
@pool_mutex.synchronize do
|
||||
@pools[key] ||=
|
||||
if https? uri then
|
||||
Gem::Request::HTTPSPool.new(http_args, @cert_files, @proxy_uri)
|
||||
else
|
||||
Gem::Request::HTTPPool.new(http_args, @cert_files, @proxy_uri)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
##
|
||||
# Returns list of no_proxy entries (if any) from the environment
|
||||
|
||||
def get_no_proxy_from_env
|
||||
env_no_proxy = ENV['no_proxy'] || ENV['NO_PROXY']
|
||||
|
||||
return [] if env_no_proxy.nil? or env_no_proxy.empty?
|
||||
|
||||
env_no_proxy.split(/\s*,\s*/)
|
||||
end
|
||||
|
||||
def https? uri
|
||||
uri.scheme.downcase == 'https'
|
||||
end
|
||||
|
||||
def no_proxy? host, env_no_proxy
|
||||
host = host.downcase
|
||||
|
||||
env_no_proxy.any? do |pattern|
|
||||
pattern = pattern.downcase
|
||||
|
||||
host[-pattern.length, pattern.length] == pattern or
|
||||
(pattern.start_with? '.' and pattern[1..-1] == host)
|
||||
end
|
||||
end
|
||||
|
||||
def net_http_args uri, proxy_uri
|
||||
net_http_args = [uri.host, uri.port]
|
||||
|
||||
no_proxy = get_no_proxy_from_env
|
||||
|
||||
if proxy_uri and not no_proxy?(uri.host, no_proxy) then
|
||||
net_http_args + [
|
||||
proxy_uri.host,
|
||||
proxy_uri.port,
|
||||
Gem::UriFormatter.new(proxy_uri.user).unescape,
|
||||
Gem::UriFormatter.new(proxy_uri.password).unescape,
|
||||
]
|
||||
elsif no_proxy? uri.host, no_proxy then
|
||||
net_http_args += [nil, nil]
|
||||
else
|
||||
net_http_args
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
##
|
||||
# A connection "pool" that only manages one connection for now. Provides
|
||||
# thread safe `checkout` and `checkin` methods. The pool consists of one
|
||||
# connection that corresponds to `http_args`. This class is private, do not
|
||||
# use it.
|
||||
|
||||
class Gem::Request::HTTPPool # :nodoc:
|
||||
attr_reader :cert_files, :proxy_uri
|
||||
|
||||
def initialize http_args, cert_files, proxy_uri
|
||||
@http_args = http_args
|
||||
@cert_files = cert_files
|
||||
@proxy_uri = proxy_uri
|
||||
@queue = SizedQueue.new 1
|
||||
@queue << nil
|
||||
end
|
||||
|
||||
def checkout
|
||||
@queue.pop || make_connection
|
||||
end
|
||||
|
||||
def checkin connection
|
||||
@queue.push connection
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def make_connection
|
||||
setup_connection Gem::Request::ConnectionPools.client.new(*@http_args)
|
||||
end
|
||||
|
||||
def setup_connection connection
|
||||
connection.start
|
||||
connection
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
class Gem::Request::HTTPSPool < Gem::Request::HTTPPool # :nodoc:
|
||||
private
|
||||
|
||||
def setup_connection connection
|
||||
Gem::Request.configure_connection_for_https(connection, @cert_files)
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
require 'rubygems'
|
||||
require 'tsort'
|
||||
|
||||
##
|
||||
|
@ -21,12 +20,22 @@ class Gem::RequestSet
|
|||
##
|
||||
# Array of gems to install even if already installed
|
||||
|
||||
attr_reader :always_install
|
||||
attr_accessor :always_install
|
||||
|
||||
attr_reader :dependencies
|
||||
|
||||
attr_accessor :development
|
||||
|
||||
##
|
||||
# Errors fetching gems during resolution.
|
||||
|
||||
attr_reader :errors
|
||||
|
||||
##
|
||||
# Set to true if you want to install only direct development dependencies.
|
||||
|
||||
attr_accessor :development_shallow
|
||||
|
||||
##
|
||||
# The set of git gems imported via load_gemdeps.
|
||||
|
||||
|
@ -38,11 +47,20 @@ class Gem::RequestSet
|
|||
|
||||
attr_accessor :ignore_dependencies
|
||||
|
||||
attr_reader :install_dir # :nodoc:
|
||||
|
||||
##
|
||||
# If true, allow dependencies to match prerelease gems.
|
||||
|
||||
attr_accessor :prerelease
|
||||
|
||||
##
|
||||
# When false no remote sets are used for resolving gems.
|
||||
|
||||
attr_accessor :remote
|
||||
|
||||
attr_reader :resolver # :nodoc:
|
||||
|
||||
##
|
||||
# Sets used for resolution
|
||||
|
||||
|
@ -71,11 +89,15 @@ class Gem::RequestSet
|
|||
@dependencies = deps
|
||||
|
||||
@always_install = []
|
||||
@conservative = false
|
||||
@dependency_names = {}
|
||||
@development = false
|
||||
@development_shallow = false
|
||||
@errors = []
|
||||
@git_set = nil
|
||||
@ignore_dependencies = false
|
||||
@install_dir = Gem.dir
|
||||
@prerelease = false
|
||||
@remote = true
|
||||
@requests = []
|
||||
@sets = []
|
||||
|
@ -116,12 +138,14 @@ class Gem::RequestSet
|
|||
|
||||
def install options, &block # :yields: request, installer
|
||||
if dir = options[:install_dir]
|
||||
return install_into dir, false, options, &block
|
||||
requests = install_into dir, false, options, &block
|
||||
return requests
|
||||
end
|
||||
|
||||
cache_dir = options[:cache_dir] || Gem.dir
|
||||
@prerelease = options[:prerelease]
|
||||
|
||||
specs = []
|
||||
requests = []
|
||||
|
||||
sorted_requests.each do |req|
|
||||
if req.installed? then
|
||||
|
@ -139,10 +163,30 @@ class Gem::RequestSet
|
|||
|
||||
yield req, inst if block_given?
|
||||
|
||||
specs << inst.install
|
||||
requests << inst.install
|
||||
end
|
||||
|
||||
specs
|
||||
requests
|
||||
ensure
|
||||
raise if $!
|
||||
return requests if options[:gemdeps]
|
||||
|
||||
specs = requests.map do |request|
|
||||
case request
|
||||
when Gem::Resolver::ActivationRequest then
|
||||
request.spec.spec
|
||||
else
|
||||
request
|
||||
end
|
||||
end
|
||||
|
||||
require 'rubygems/dependency_installer'
|
||||
inst = Gem::DependencyInstaller.new options
|
||||
inst.installed_gems.replace specs
|
||||
|
||||
Gem.done_installing_hooks.each do |hook|
|
||||
hook.call inst, specs
|
||||
end unless Gem.done_installing_hooks.empty?
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -156,17 +200,19 @@ class Gem::RequestSet
|
|||
gemdeps = options[:gemdeps]
|
||||
|
||||
@install_dir = options[:install_dir] || Gem.dir
|
||||
@prerelease = options[:prerelease]
|
||||
@remote = options[:domain] != :local
|
||||
@conservative = true if options[:conservative]
|
||||
|
||||
load_gemdeps gemdeps, options[:without_groups]
|
||||
gem_deps_api = load_gemdeps gemdeps, options[:without_groups], true
|
||||
|
||||
resolve
|
||||
|
||||
if options[:explain]
|
||||
puts "Gems to install:"
|
||||
|
||||
specs.map { |s| s.full_name }.sort.each do |s|
|
||||
puts " #{s}"
|
||||
sorted_requests.each do |spec|
|
||||
puts " #{spec.full_name}"
|
||||
end
|
||||
|
||||
if Gem.configuration.really_verbose
|
||||
|
@ -175,8 +221,11 @@ class Gem::RequestSet
|
|||
else
|
||||
installed = install options, &block
|
||||
|
||||
lockfile = Gem::RequestSet::Lockfile.new self, gemdeps
|
||||
lockfile.write
|
||||
if options.fetch :lock, true then
|
||||
lockfile =
|
||||
Gem::RequestSet::Lockfile.new self, gemdeps, gem_deps_api.dependencies
|
||||
lockfile.write
|
||||
end
|
||||
|
||||
installed
|
||||
end
|
||||
|
@ -192,8 +241,10 @@ class Gem::RequestSet
|
|||
|
||||
installed = []
|
||||
|
||||
options[:development] = false
|
||||
options[:install_dir] = dir
|
||||
options[:only_install_dir] = true
|
||||
@prerelease = options[:prerelease]
|
||||
|
||||
sorted_requests.each do |request|
|
||||
spec = request.spec
|
||||
|
@ -218,7 +269,7 @@ class Gem::RequestSet
|
|||
##
|
||||
# Load a dependency management file.
|
||||
|
||||
def load_gemdeps path, without_groups = []
|
||||
def load_gemdeps path, without_groups = [], installing = false
|
||||
@git_set = Gem::Resolver::GitSet.new
|
||||
@vendor_set = Gem::Resolver::VendorSet.new
|
||||
|
||||
|
@ -228,6 +279,7 @@ class Gem::RequestSet
|
|||
lockfile.parse
|
||||
|
||||
gf = Gem::RequestSet::GemDependencyAPI.new self, path
|
||||
gf.installing = installing
|
||||
gf.without_groups = without_groups if without_groups
|
||||
gf.load
|
||||
end
|
||||
|
@ -243,15 +295,29 @@ class Gem::RequestSet
|
|||
|
||||
set = Gem::Resolver.compose_sets(*@sets)
|
||||
set.remote = @remote
|
||||
set.prerelease = @prerelease
|
||||
|
||||
resolver = Gem::Resolver.new @dependencies, set
|
||||
resolver.development = @development
|
||||
resolver.development_shallow = @development_shallow
|
||||
resolver.ignore_dependencies = @ignore_dependencies
|
||||
resolver.soft_missing = @soft_missing
|
||||
|
||||
if @conservative
|
||||
installed_gems = {}
|
||||
Gem::Specification.find_all do |spec|
|
||||
(installed_gems[spec.name] ||= []) << spec
|
||||
end
|
||||
resolver.skip_gems = installed_gems
|
||||
end
|
||||
|
||||
@resolver = resolver
|
||||
|
||||
@requests = resolver.resolve
|
||||
|
||||
@errors = set.errors
|
||||
|
||||
@requests
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -284,16 +350,20 @@ class Gem::RequestSet
|
|||
node.spec.dependencies.each do |dep|
|
||||
next if dep.type == :development and not @development
|
||||
|
||||
match = @requests.find { |r| dep.match? r.spec.name, r.spec.version }
|
||||
if match
|
||||
begin
|
||||
yield match
|
||||
rescue TSort::Cyclic
|
||||
end
|
||||
else
|
||||
unless @soft_missing
|
||||
raise Gem::DependencyError, "Unresolved dependency found during sorting - #{dep} (requested by #{node.spec.full_name})"
|
||||
end
|
||||
match = @requests.find { |r|
|
||||
dep.match? r.spec.name, r.spec.version, @prerelease
|
||||
}
|
||||
|
||||
unless match then
|
||||
next if dep.type == :development and @development_shallow
|
||||
next if @soft_missing
|
||||
raise Gem::DependencyError,
|
||||
"Unresolved dependency found during sorting - #{dep} (requested by #{node.spec.full_name})"
|
||||
end
|
||||
|
||||
begin
|
||||
yield match
|
||||
rescue TSort::Cyclic
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,5 +1,33 @@
|
|||
##
|
||||
# A semi-compatible DSL for the Bundler Gemfile and Isolate formats.
|
||||
# A semi-compatible DSL for the Bundler Gemfile and Isolate gem dependencies
|
||||
# files.
|
||||
#
|
||||
# To work with both the Bundler Gemfile and Isolate formats this
|
||||
# implementation takes some liberties to allow compatibility with each, most
|
||||
# notably in #source.
|
||||
#
|
||||
# A basic gem dependencies file will look like the following:
|
||||
#
|
||||
# source 'https://rubygems.org'
|
||||
#
|
||||
# gem 'rails', '3.2.14a
|
||||
# gem 'devise', '~> 2.1', '>= 2.1.3'
|
||||
# gem 'cancan'
|
||||
# gem 'airbrake'
|
||||
# gem 'pg'
|
||||
#
|
||||
# RubyGems recommends saving this as gem.deps.rb over Gemfile or Isolate.
|
||||
#
|
||||
# To install the gems in this Gemfile use `gem install -g` to install it and
|
||||
# create a lockfile. The lockfile will ensure that when you make changes to
|
||||
# your gem dependencies file a minimum amount of change is made to the
|
||||
# dependencies of your gems.
|
||||
#
|
||||
# RubyGems can activate all the gems in your dependencies file at startup
|
||||
# using the RUBYGEMS_GEMDEPS environment variable or through Gem.use_gemdeps.
|
||||
# See Gem.use_gemdeps for details and warnings.
|
||||
#
|
||||
# See `gem help install` and `gem help gem_dependencies` for further details.
|
||||
|
||||
class Gem::RequestSet::GemDependencyAPI
|
||||
|
||||
|
@ -21,6 +49,8 @@ class Gem::RequestSet::GemDependencyAPI
|
|||
:ruby_21 => %w[ruby rbx maglev],
|
||||
}
|
||||
|
||||
mswin = Gem::Platform.new 'x86-mswin32'
|
||||
mswin64 = Gem::Platform.new 'x64-mswin64'
|
||||
x86_mingw = Gem::Platform.new 'x86-mingw32'
|
||||
x64_mingw = Gem::Platform.new 'x64-mingw32'
|
||||
|
||||
|
@ -39,7 +69,15 @@ class Gem::RequestSet::GemDependencyAPI
|
|||
:mri_19 => Gem::Platform::RUBY,
|
||||
:mri_20 => Gem::Platform::RUBY,
|
||||
:mri_21 => Gem::Platform::RUBY,
|
||||
:mswin => Gem::Platform::RUBY,
|
||||
:mswin => mswin,
|
||||
:mswin_18 => mswin,
|
||||
:mswin_19 => mswin,
|
||||
:mswin_20 => mswin,
|
||||
:mswin_21 => mswin,
|
||||
:mswin64 => mswin64,
|
||||
:mswin64_19 => mswin64,
|
||||
:mswin64_20 => mswin64,
|
||||
:mswin64_21 => mswin64,
|
||||
:rbx => Gem::Platform::RUBY,
|
||||
:ruby => Gem::Platform::RUBY,
|
||||
:ruby_18 => Gem::Platform::RUBY,
|
||||
|
@ -73,6 +111,14 @@ class Gem::RequestSet::GemDependencyAPI
|
|||
:mri_20 => tilde_gt_2_0_0,
|
||||
:mri_21 => tilde_gt_2_1_0,
|
||||
:mswin => gt_eq_0,
|
||||
:mswin_18 => tilde_gt_1_8_0,
|
||||
:mswin_19 => tilde_gt_1_9_0,
|
||||
:mswin_20 => tilde_gt_2_0_0,
|
||||
:mswin_21 => tilde_gt_2_1_0,
|
||||
:mswin64 => gt_eq_0,
|
||||
:mswin64_19 => tilde_gt_1_9_0,
|
||||
:mswin64_20 => tilde_gt_2_0_0,
|
||||
:mswin64_21 => tilde_gt_2_1_0,
|
||||
:rbx => gt_eq_0,
|
||||
:ruby => gt_eq_0,
|
||||
:ruby_18 => tilde_gt_1_8_0,
|
||||
|
@ -96,6 +142,14 @@ class Gem::RequestSet::GemDependencyAPI
|
|||
:mri_20 => :never,
|
||||
:mri_21 => :never,
|
||||
:mswin => :only,
|
||||
:mswin_18 => :only,
|
||||
:mswin_19 => :only,
|
||||
:mswin_20 => :only,
|
||||
:mswin_21 => :only,
|
||||
:mswin64 => :only,
|
||||
:mswin64_19 => :only,
|
||||
:mswin64_20 => :only,
|
||||
:mswin64_21 => :only,
|
||||
:rbx => :never,
|
||||
:ruby => :never,
|
||||
:ruby_18 => :never,
|
||||
|
@ -107,6 +161,11 @@ class Gem::RequestSet::GemDependencyAPI
|
|||
:x64_mingw_21 => :only,
|
||||
}
|
||||
|
||||
##
|
||||
# The gems required by #gem statements in the gem.deps.rb file
|
||||
|
||||
attr_reader :dependencies
|
||||
|
||||
##
|
||||
# A set of gems that are loaded via the +:git+ option to #gem
|
||||
|
||||
|
@ -136,14 +195,31 @@ class Gem::RequestSet::GemDependencyAPI
|
|||
@path = path
|
||||
|
||||
@current_groups = nil
|
||||
@current_platform = nil
|
||||
@current_platforms = nil
|
||||
@current_repository = nil
|
||||
@dependencies = {}
|
||||
@default_sources = true
|
||||
@git_set = @set.git_set
|
||||
@git_sources = {}
|
||||
@installing = false
|
||||
@requires = Hash.new { |h, name| h[name] = [] }
|
||||
@vendor_set = @set.vendor_set
|
||||
@gem_sources = {}
|
||||
@without_groups = []
|
||||
|
||||
git_source :github do |repo_name|
|
||||
repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include? "/"
|
||||
|
||||
"git://github.com/#{repo_name}.git"
|
||||
end
|
||||
|
||||
git_source :bitbucket do |repo_name|
|
||||
repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include? "/"
|
||||
|
||||
user, = repo_name.split "/", 2
|
||||
|
||||
"https://#{user}@bitbucket.org/#{repo_name}.git"
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -187,14 +263,26 @@ class Gem::RequestSet::GemDependencyAPI
|
|||
end
|
||||
|
||||
##
|
||||
# Loads the gem dependency file
|
||||
# Changes the behavior of gem dependency file loading to installing mode.
|
||||
# In installing mode certain restrictions are ignored such as ruby version
|
||||
# mismatch checks.
|
||||
|
||||
def installing= installing # :nodoc:
|
||||
@installing = installing
|
||||
end
|
||||
|
||||
##
|
||||
# Loads the gem dependency file and returns self.
|
||||
|
||||
def load
|
||||
instance_eval File.read(@path).untaint, @path, 1
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
##
|
||||
# :category: Gem Dependencies DSL
|
||||
#
|
||||
# :call-seq:
|
||||
# gem(name)
|
||||
# gem(name, *requirements)
|
||||
|
@ -202,6 +290,66 @@ class Gem::RequestSet::GemDependencyAPI
|
|||
#
|
||||
# Specifies a gem dependency with the given +name+ and +requirements+. You
|
||||
# may also supply +options+ following the +requirements+
|
||||
#
|
||||
# +options+ include:
|
||||
#
|
||||
# require: ::
|
||||
# RubyGems does not provide any autorequire features so requires in a gem
|
||||
# dependencies file are recorded but ignored.
|
||||
#
|
||||
# In bundler the require: option overrides the file to require during
|
||||
# Bundler.require. By default the name of the dependency is required in
|
||||
# Bundler. A single file or an Array of files may be given.
|
||||
#
|
||||
# To disable requiring any file give +false+:
|
||||
#
|
||||
# gem 'rake', require: false
|
||||
#
|
||||
# group: ::
|
||||
# Place the dependencies in the given dependency group. A single group or
|
||||
# an Array of groups may be given.
|
||||
#
|
||||
# See also #group
|
||||
#
|
||||
# platform: ::
|
||||
# Only install the dependency on the given platform. A single platform or
|
||||
# an Array of platforms may be given.
|
||||
#
|
||||
# See #platform for a list of platforms available.
|
||||
#
|
||||
# path: ::
|
||||
# Install this dependency from an unpacked gem in the given directory.
|
||||
#
|
||||
# gem 'modified_gem', path: 'vendor/modified_gem'
|
||||
#
|
||||
# git: ::
|
||||
# Install this dependency from a git repository:
|
||||
#
|
||||
# gem 'private_gem', git: git@my.company.example:private_gem.git'
|
||||
#
|
||||
# gist: ::
|
||||
# Install this dependency from the gist ID:
|
||||
#
|
||||
# gem 'bang', gist: '1232884'
|
||||
#
|
||||
# github: ::
|
||||
# Install this dependency from a github git repository:
|
||||
#
|
||||
# gem 'private_gem', github: 'my_company/private_gem'
|
||||
#
|
||||
# submodules: ::
|
||||
# Set to +true+ to include submodules when fetching the git repository for
|
||||
# git:, gist: and github: dependencies.
|
||||
#
|
||||
# ref: ::
|
||||
# Use the given commit name or SHA for git:, gist: and github:
|
||||
# dependencies.
|
||||
#
|
||||
# branch: ::
|
||||
# Use the given branch for git:, gist: and github: dependencies.
|
||||
#
|
||||
# tag: ::
|
||||
# Use the given tag for git:, gist: and github: dependencies.
|
||||
|
||||
def gem name, *requirements
|
||||
options = requirements.pop if requirements.last.kind_of?(Hash)
|
||||
|
@ -211,9 +359,20 @@ class Gem::RequestSet::GemDependencyAPI
|
|||
|
||||
source_set = false
|
||||
|
||||
source_set ||= gem_path name, options
|
||||
source_set ||= gem_git name, options
|
||||
source_set ||= gem_github name, options
|
||||
source_set ||= gem_path name, options
|
||||
source_set ||= gem_git name, options
|
||||
source_set ||= gem_git_source name, options
|
||||
|
||||
duplicate = @dependencies.include? name
|
||||
|
||||
@dependencies[name] =
|
||||
if requirements.empty? and not source_set then
|
||||
nil
|
||||
elsif source_set then
|
||||
'!'
|
||||
else
|
||||
requirements
|
||||
end
|
||||
|
||||
return unless gem_platforms options
|
||||
|
||||
|
@ -225,6 +384,12 @@ class Gem::RequestSet::GemDependencyAPI
|
|||
|
||||
gem_requires name, options
|
||||
|
||||
if duplicate then
|
||||
warn <<-WARNING
|
||||
Gem dependencies file #{@path} requires #{name} more than once.
|
||||
WARNING
|
||||
end
|
||||
|
||||
@set.gem name, *requirements
|
||||
end
|
||||
|
||||
|
@ -258,21 +423,27 @@ class Gem::RequestSet::GemDependencyAPI
|
|||
private :gem_git
|
||||
|
||||
##
|
||||
# Handles the github: option from +options+ for gem +name+.
|
||||
# Handles a git gem option from +options+ for gem +name+ for a git source
|
||||
# registered through git_source.
|
||||
#
|
||||
# Returns +true+ if the path option was handled.
|
||||
# Returns +true+ if the custom source option was handled.
|
||||
|
||||
def gem_github name, options # :nodoc:
|
||||
return unless path = options.delete(:github)
|
||||
def gem_git_source name, options # :nodoc:
|
||||
return unless git_source = (@git_sources.keys & options.keys).last
|
||||
|
||||
options[:git] = "git://github.com/#{path}.git"
|
||||
source_callback = @git_sources[git_source]
|
||||
source_param = options.delete git_source
|
||||
|
||||
git_url = source_callback.call source_param
|
||||
|
||||
options[:git] = git_url
|
||||
|
||||
gem_git name, options
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
private :gem_github
|
||||
private :gem_git_source
|
||||
|
||||
##
|
||||
# Handles the :group and :groups +options+ for the gem with the given
|
||||
|
@ -314,8 +485,9 @@ class Gem::RequestSet::GemDependencyAPI
|
|||
# platform matches the current platform.
|
||||
|
||||
def gem_platforms options # :nodoc:
|
||||
platform_names = Array(options.delete :platforms)
|
||||
platform_names << @current_platform if @current_platform
|
||||
platform_names = Array(options.delete :platform)
|
||||
platform_names.concat Array(options.delete :platforms)
|
||||
platform_names.concat @current_platforms if @current_platforms
|
||||
|
||||
return true if platform_names.empty?
|
||||
|
||||
|
@ -343,7 +515,7 @@ class Gem::RequestSet::GemDependencyAPI
|
|||
private :gem_platforms
|
||||
|
||||
##
|
||||
# Handles the require: option from +options+ and adds those files, or the
|
||||
# Records the require: option from +options+ and adds those files, or the
|
||||
# default file to the require list for +name+.
|
||||
|
||||
def gem_requires name, options # :nodoc:
|
||||
|
@ -362,6 +534,11 @@ class Gem::RequestSet::GemDependencyAPI
|
|||
# :category: Gem Dependencies DSL
|
||||
#
|
||||
# Block form for specifying gems from a git +repository+.
|
||||
#
|
||||
# git 'https://github.com/rails/rails.git' do
|
||||
# gem 'activesupport'
|
||||
# gem 'activerecord'
|
||||
# end
|
||||
|
||||
def git repository
|
||||
@current_repository = repository
|
||||
|
@ -372,6 +549,15 @@ class Gem::RequestSet::GemDependencyAPI
|
|||
@current_repository = nil
|
||||
end
|
||||
|
||||
##
|
||||
# Defines a custom git source that uses +name+ to expand git repositories
|
||||
# for use in gems built from git repositories. You must provide a block
|
||||
# that accepts a git repository name for expansion.
|
||||
|
||||
def git_source name, &callback
|
||||
@git_sources[name] = callback
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the basename of the file the dependencies were loaded from
|
||||
|
||||
|
@ -383,6 +569,23 @@ class Gem::RequestSet::GemDependencyAPI
|
|||
# :category: Gem Dependencies DSL
|
||||
#
|
||||
# Loads dependencies from a gemspec file.
|
||||
#
|
||||
# +options+ include:
|
||||
#
|
||||
# name: ::
|
||||
# The name portion of the gemspec file. Defaults to searching for any
|
||||
# gemspec file in the current directory.
|
||||
#
|
||||
# gemspec name: 'my_gem'
|
||||
#
|
||||
# path: ::
|
||||
# The path the gemspec lives in. Defaults to the current directory:
|
||||
#
|
||||
# gemspec 'my_gem', path: 'gemspecs', name: 'my_gem'
|
||||
#
|
||||
# development_group: ::
|
||||
# The group to add development dependencies to. By default this is
|
||||
# :development. Only one group may be specified.
|
||||
|
||||
def gemspec options = {}
|
||||
name = options.delete(:name) || '{,*}'
|
||||
|
@ -404,7 +607,20 @@ class Gem::RequestSet::GemDependencyAPI
|
|||
|
||||
##
|
||||
# :category: Gem Dependencies DSL
|
||||
#
|
||||
# Block form for placing a dependency in the given +groups+.
|
||||
#
|
||||
# group :development do
|
||||
# gem 'debugger'
|
||||
# end
|
||||
#
|
||||
# group :development, :test do
|
||||
# gem 'minitest'
|
||||
# end
|
||||
#
|
||||
# Groups can be excluded at install time using `gem install -g --without
|
||||
# development`. See `gem help install` and `gem help gem_dependencies` for
|
||||
# further details.
|
||||
|
||||
def group *groups
|
||||
@current_groups = groups
|
||||
|
@ -440,28 +656,72 @@ class Gem::RequestSet::GemDependencyAPI
|
|||
##
|
||||
# :category: Gem Dependencies DSL
|
||||
#
|
||||
# Block form for restricting gems to a particular platform.
|
||||
# Block form for restricting gems to a set of platforms.
|
||||
#
|
||||
# The gem dependencies platform is different from Gem::Platform. A platform
|
||||
# gem.deps.rb platform matches on the ruby engine, the ruby version and
|
||||
# whether or not windows is allowed.
|
||||
#
|
||||
# :ruby, :ruby_XY ::
|
||||
# Matches non-windows, non-jruby implementations where X and Y can be used
|
||||
# to match releases in the 1.8, 1.9, 2.0 or 2.1 series.
|
||||
#
|
||||
# :mri, :mri_XY ::
|
||||
# Matches non-windows C Ruby (Matz Ruby) or only the 1.8, 1.9, 2.0 or
|
||||
# 2.1 series.
|
||||
#
|
||||
# :mingw, :mingw_XY ::
|
||||
# Matches 32 bit C Ruby on MinGW or only the 1.8, 1.9, 2.0 or 2.1 series.
|
||||
#
|
||||
# :x64_mingw, :x64_mingw_XY ::
|
||||
# Matches 64 bit C Ruby on MinGW or only the 1.8, 1.9, 2.0 or 2.1 series.
|
||||
#
|
||||
# :mswin, :mswin_XY ::
|
||||
# Matches 32 bit C Ruby on Microsoft Windows or only the 1.8, 1.9, 2.0 or
|
||||
# 2.1 series.
|
||||
#
|
||||
# :mswin64, :mswin64_XY ::
|
||||
# Matches 64 bit C Ruby on Microsoft Windows or only the 1.8, 1.9, 2.0 or
|
||||
# 2.1 series.
|
||||
#
|
||||
# :jruby, :jruby_XY ::
|
||||
# Matches JRuby or JRuby in 1.8 or 1.9 mode.
|
||||
#
|
||||
# :maglev ::
|
||||
# Matches Maglev
|
||||
#
|
||||
# :rbx ::
|
||||
# Matches non-windows Rubinius
|
||||
#
|
||||
# NOTE: There is inconsistency in what environment a platform matches. You
|
||||
# may need to read the source to know the exact details.
|
||||
|
||||
def platform what
|
||||
@current_platform = what
|
||||
def platform *platforms
|
||||
@current_platforms = platforms
|
||||
|
||||
yield
|
||||
|
||||
ensure
|
||||
@current_platform = nil
|
||||
@current_platforms = nil
|
||||
end
|
||||
|
||||
##
|
||||
# :category: Gem Dependencies DSL
|
||||
#
|
||||
# Block form for restricting gems to a particular platform.
|
||||
# Block form for restricting gems to a particular set of platforms. See
|
||||
# #platform.
|
||||
|
||||
alias :platforms :platform
|
||||
|
||||
##
|
||||
# :category: Gem Dependencies DSL
|
||||
# Restricts this gem dependencies file to the given ruby +version+. The
|
||||
# +:engine+ options from Bundler are currently ignored.
|
||||
#
|
||||
# Restricts this gem dependencies file to the given ruby +version+.
|
||||
#
|
||||
# You may also provide +engine:+ and +engine_version:+ options to restrict
|
||||
# this gem dependencies file to a particular ruby engine and its engine
|
||||
# version. This matching is performed by using the RUBY_ENGINE and
|
||||
# engine_specific VERSION constants. (For JRuby, JRUBY_VERSION).
|
||||
|
||||
def ruby version, options = {}
|
||||
engine = options[:engine]
|
||||
|
@ -471,6 +731,8 @@ class Gem::RequestSet::GemDependencyAPI
|
|||
'you must specify engine_version along with the ruby engine' if
|
||||
engine and not engine_version
|
||||
|
||||
return true if @installing
|
||||
|
||||
unless RUBY_VERSION == version then
|
||||
message = "Your Ruby version is #{RUBY_VERSION}, " +
|
||||
"but your #{gem_deps_file} requires #{version}"
|
||||
|
@ -503,7 +765,16 @@ class Gem::RequestSet::GemDependencyAPI
|
|||
##
|
||||
# :category: Gem Dependencies DSL
|
||||
#
|
||||
# Sets +url+ as a source for gems for this dependency API.
|
||||
# Sets +url+ as a source for gems for this dependency API. RubyGems uses
|
||||
# the default configured sources if no source was given. If a source is set
|
||||
# only that source is used.
|
||||
#
|
||||
# This method differs in behavior from Bundler:
|
||||
#
|
||||
# * The +:gemcutter+, # +:rubygems+ and +:rubyforge+ sources are not
|
||||
# supported as they are deprecated in bundler.
|
||||
# * The +prepend:+ option is not supported. If you wish to order sources
|
||||
# then list them in your preferred order.
|
||||
|
||||
def source url
|
||||
Gem.sources.clear if @default_sources
|
||||
|
|
|
@ -49,11 +49,14 @@ class Gem::RequestSet::Lockfile
|
|||
# Creates a new Lockfile for the given +request_set+ and +gem_deps_file+
|
||||
# location.
|
||||
|
||||
def initialize request_set, gem_deps_file
|
||||
def initialize request_set, gem_deps_file, dependencies = nil
|
||||
@set = request_set
|
||||
@dependencies = dependencies
|
||||
@gem_deps_file = File.expand_path(gem_deps_file)
|
||||
@gem_deps_dir = File.dirname(@gem_deps_file)
|
||||
|
||||
@gem_deps_file.untaint unless gem_deps_file.tainted?
|
||||
|
||||
@current_token = nil
|
||||
@line = 0
|
||||
@line_pos = 0
|
||||
|
@ -64,19 +67,42 @@ class Gem::RequestSet::Lockfile
|
|||
def add_DEPENDENCIES out # :nodoc:
|
||||
out << "DEPENDENCIES"
|
||||
|
||||
@requests.sort_by { |r| r.name }.each do |request|
|
||||
spec = request.spec
|
||||
dependencies =
|
||||
if @dependencies then
|
||||
@dependencies.sort_by { |name,| name }.map do |name, requirement|
|
||||
requirement_string =
|
||||
if '!' == requirement then
|
||||
requirement
|
||||
else
|
||||
Gem::Requirement.new(requirement).for_lockfile
|
||||
end
|
||||
|
||||
if [Gem::Resolver::VendorSpecification,
|
||||
Gem::Resolver::GitSpecification].include? spec.class then
|
||||
out << " #{request.name}!"
|
||||
[name, requirement_string]
|
||||
end
|
||||
else
|
||||
requirement = request.request.dependency.requirement
|
||||
@requests.sort_by { |r| r.name }.map do |request|
|
||||
spec = request.spec
|
||||
name = request.name
|
||||
requirement = request.request.dependency.requirement
|
||||
|
||||
out << " #{request.name}#{requirement.for_lockfile}"
|
||||
requirement_string =
|
||||
if [Gem::Resolver::VendorSpecification,
|
||||
Gem::Resolver::GitSpecification].include? spec.class then
|
||||
"!"
|
||||
else
|
||||
requirement.for_lockfile
|
||||
end
|
||||
|
||||
[name, requirement_string]
|
||||
end
|
||||
end
|
||||
|
||||
dependencies = dependencies.map do |name, requirement_string|
|
||||
" #{name}#{requirement_string}"
|
||||
end
|
||||
|
||||
out.concat dependencies
|
||||
|
||||
out << nil
|
||||
end
|
||||
|
||||
|
@ -93,12 +119,15 @@ class Gem::RequestSet::Lockfile
|
|||
out << " specs:"
|
||||
|
||||
requests.sort_by { |request| request.name }.each do |request|
|
||||
next if request.spec.name == 'bundler'
|
||||
platform = "-#{request.spec.platform}" unless
|
||||
Gem::Platform::RUBY == request.spec.platform
|
||||
|
||||
out << " #{request.name} (#{request.version}#{platform})"
|
||||
|
||||
request.full_spec.dependencies.sort.each do |dependency|
|
||||
next if dependency.type == :development
|
||||
|
||||
requirement = dependency.requirement
|
||||
out << " #{dependency.name}#{requirement.for_lockfile}"
|
||||
end
|
||||
|
@ -166,9 +195,8 @@ class Gem::RequestSet::Lockfile
|
|||
out << "PLATFORMS"
|
||||
|
||||
platforms = @requests.map { |request| request.spec.platform }.uniq
|
||||
platforms.delete Gem::Platform::RUBY if platforms.length > 1
|
||||
|
||||
platforms.each do |platform|
|
||||
platforms.sort.each do |platform|
|
||||
out << " #{platform}"
|
||||
end
|
||||
|
||||
|
@ -250,7 +278,7 @@ class Gem::RequestSet::Lockfile
|
|||
Gem::Resolver::VendorSet === set
|
||||
}.map { |set|
|
||||
set.specs[name]
|
||||
}.first
|
||||
}.compact.first
|
||||
|
||||
requirements << spec.version
|
||||
when :l_paren then
|
||||
|
@ -277,26 +305,33 @@ class Gem::RequestSet::Lockfile
|
|||
end
|
||||
|
||||
def parse_GEM # :nodoc:
|
||||
get :entry, 'remote'
|
||||
_, data, = get :text
|
||||
sources = []
|
||||
|
||||
source = Gem::Source.new data
|
||||
while [:entry, 'remote'] == peek.first(2) do
|
||||
get :entry, 'remote'
|
||||
_, data, = get :text
|
||||
skip :newline
|
||||
|
||||
skip :newline
|
||||
sources << Gem::Source.new(data)
|
||||
end
|
||||
|
||||
sources << Gem::Source.new(Gem::DEFAULT_HOST) if sources.empty?
|
||||
|
||||
get :entry, 'specs'
|
||||
|
||||
skip :newline
|
||||
|
||||
set = Gem::Resolver::LockSet.new source
|
||||
last_spec = nil
|
||||
set = Gem::Resolver::LockSet.new sources
|
||||
last_specs = nil
|
||||
|
||||
while not @tokens.empty? and :text == peek.first do
|
||||
_, name, column, = get :text
|
||||
|
||||
case peek[0]
|
||||
when :newline then
|
||||
last_spec.add_dependency Gem::Dependency.new name if column == 6
|
||||
last_specs.each do |spec|
|
||||
spec.add_dependency Gem::Dependency.new name if column == 6
|
||||
end
|
||||
when :l_paren then
|
||||
get :l_paren
|
||||
|
||||
|
@ -308,11 +343,13 @@ class Gem::RequestSet::Lockfile
|
|||
platform =
|
||||
platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY
|
||||
|
||||
last_spec = set.add name, version, platform
|
||||
last_specs = set.add name, version, platform
|
||||
else
|
||||
dependency = parse_dependency name, data
|
||||
|
||||
last_spec.add_dependency dependency
|
||||
last_specs.each do |spec|
|
||||
spec.add_dependency dependency
|
||||
end
|
||||
end
|
||||
|
||||
get :r_paren
|
||||
|
@ -337,11 +374,21 @@ class Gem::RequestSet::Lockfile
|
|||
|
||||
skip :newline
|
||||
|
||||
type, value = peek.first 2
|
||||
if type == :entry and %w[branch ref tag].include? value then
|
||||
get
|
||||
get :text
|
||||
|
||||
skip :newline
|
||||
end
|
||||
|
||||
get :entry, 'specs'
|
||||
|
||||
skip :newline
|
||||
|
||||
set = Gem::Resolver::GitSet.new
|
||||
set.root_dir = @set.install_dir
|
||||
|
||||
last_spec = nil
|
||||
|
||||
while not @tokens.empty? and :text == peek.first do
|
||||
|
@ -360,7 +407,7 @@ class Gem::RequestSet::Lockfile
|
|||
else
|
||||
dependency = parse_dependency name, data
|
||||
|
||||
last_spec.spec.dependencies << dependency
|
||||
last_spec.add_dependency dependency
|
||||
end
|
||||
|
||||
get :r_paren
|
||||
|
@ -403,7 +450,7 @@ class Gem::RequestSet::Lockfile
|
|||
else
|
||||
dependency = parse_dependency name, data
|
||||
|
||||
last_spec.spec.dependencies << dependency
|
||||
last_spec.dependencies << dependency
|
||||
end
|
||||
|
||||
get :r_paren
|
||||
|
@ -432,7 +479,7 @@ class Gem::RequestSet::Lockfile
|
|||
# the first token of the requirements and returns a Gem::Dependency object.
|
||||
|
||||
def parse_dependency name, op # :nodoc:
|
||||
return Gem::Dependency.new name unless peek[0] == :text
|
||||
return Gem::Dependency.new name, op unless peek[0] == :text
|
||||
|
||||
_, version, = get :text
|
||||
|
||||
|
@ -575,8 +622,10 @@ class Gem::RequestSet::Lockfile
|
|||
# Writes the lock file alongside the gem dependencies file
|
||||
|
||||
def write
|
||||
content = to_s
|
||||
|
||||
open "#{@gem_deps_file}.lock", 'w' do |io|
|
||||
io.write to_s
|
||||
io.write content
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -8,6 +8,9 @@ Gem.load_yaml if defined? ::YAML
|
|||
##
|
||||
# A Requirement is a set of one or more version restrictions. It supports a
|
||||
# few (<tt>=, !=, >, <, >=, <=, ~></tt>) different restriction operators.
|
||||
#
|
||||
# See Gem::Version for a description on how versions and requirements work
|
||||
# together in RubyGems.
|
||||
|
||||
class Gem::Requirement
|
||||
OPS = { #:nodoc:
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
require 'rubygems'
|
||||
require 'rubygems/dependency'
|
||||
require 'rubygems/exceptions'
|
||||
require 'rubygems/util/list'
|
||||
|
@ -21,16 +20,23 @@ class Gem::Resolver
|
|||
|
||||
DEBUG_RESOLVER = !ENV['DEBUG_RESOLVER'].nil?
|
||||
|
||||
require 'pp' if DEBUG_RESOLVER
|
||||
|
||||
##
|
||||
# Contains all the conflicts encountered while doing resolution
|
||||
|
||||
attr_reader :conflicts
|
||||
|
||||
##
|
||||
# Set to true if development dependencies should be considered.
|
||||
# Set to true if all development dependencies should be considered.
|
||||
|
||||
attr_accessor :development
|
||||
|
||||
##
|
||||
# Set to true if immediate development dependencies should be considered.
|
||||
|
||||
attr_accessor :development_shallow
|
||||
|
||||
##
|
||||
# When true, no dependencies are looked up for requested gems.
|
||||
|
||||
|
@ -43,6 +49,12 @@ class Gem::Resolver
|
|||
|
||||
attr_reader :stats
|
||||
|
||||
##
|
||||
# Hash of gems to skip resolution. Keyed by gem name, with arrays of
|
||||
# gem specifications as values.
|
||||
|
||||
attr_accessor :skip_gems
|
||||
|
||||
##
|
||||
# When a missing dependency, don't stop. Just go on and record what was
|
||||
# missing.
|
||||
|
@ -100,26 +112,27 @@ class Gem::Resolver
|
|||
|
||||
@conflicts = []
|
||||
@development = false
|
||||
@development_shallow = false
|
||||
@ignore_dependencies = false
|
||||
@missing = []
|
||||
@skip_gems = {}
|
||||
@soft_missing = false
|
||||
@stats = Gem::Resolver::Stats.new
|
||||
end
|
||||
|
||||
def explain stage, *data # :nodoc:
|
||||
if DEBUG_RESOLVER
|
||||
d = data.map { |x| x.inspect }.join(", ")
|
||||
STDOUT.printf "%20s %s\n", stage.to_s.upcase, d
|
||||
end
|
||||
return unless DEBUG_RESOLVER
|
||||
|
||||
d = data.map { |x| x.pretty_inspect }.join(", ")
|
||||
$stderr.printf "%10s %s\n", stage.to_s.upcase, d
|
||||
end
|
||||
|
||||
def explain_list stage, data # :nodoc:
|
||||
if DEBUG_RESOLVER
|
||||
STDOUT.printf "%20s (%d entries)\n", stage.to_s.upcase, data.size
|
||||
data.each do |d|
|
||||
STDOUT.printf "%20s %s\n", "", d
|
||||
end
|
||||
end
|
||||
def explain_list stage # :nodoc:
|
||||
return unless DEBUG_RESOLVER
|
||||
|
||||
data = yield
|
||||
$stderr.printf "%10s (%d entries)\n", stage.to_s.upcase, data.size
|
||||
PP.pp data, $stderr unless data.empty?
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -132,6 +145,7 @@ class Gem::Resolver
|
|||
spec = possible.pop
|
||||
|
||||
explain :activate, [spec.full_name, possible.size]
|
||||
explain :possible, possible
|
||||
|
||||
activation_request =
|
||||
Gem::Resolver::ActivationRequest.new spec, dep, possible
|
||||
|
@ -142,8 +156,15 @@ class Gem::Resolver
|
|||
def requests s, act, reqs=nil # :nodoc:
|
||||
return reqs if @ignore_dependencies
|
||||
|
||||
s.fetch_development_dependencies if @development
|
||||
|
||||
s.dependencies.reverse_each do |d|
|
||||
next if d.type == :development and not @development
|
||||
next if d.type == :development and @development_shallow and
|
||||
act.development?
|
||||
next if d.type == :development and @development_shallow and
|
||||
act.parent
|
||||
|
||||
reqs.add Gem::Resolver::DependencyRequest.new(d, act)
|
||||
@stats.requirement!
|
||||
end
|
||||
|
@ -186,6 +207,15 @@ class Gem::Resolver
|
|||
|
||||
def find_possible dependency # :nodoc:
|
||||
all = @set.find_all dependency
|
||||
|
||||
if (skip_dep_gems = skip_gems[dependency.name]) && !skip_dep_gems.empty?
|
||||
matching = all.select do |api_spec|
|
||||
skip_dep_gems.any? { |s| api_spec.version == s.version }
|
||||
end
|
||||
|
||||
all = matching unless matching.empty?
|
||||
end
|
||||
|
||||
matching_platform = select_local_platforms all
|
||||
|
||||
return matching_platform, all
|
||||
|
@ -270,8 +300,8 @@ class Gem::Resolver
|
|||
|
||||
dep = needed.remove
|
||||
explain :try, [dep, dep.requester ? dep.requester.request : :toplevel]
|
||||
explain_list :next5, needed.next5
|
||||
explain_list :specs, Array(specs).map { |x| x.full_name }.sort
|
||||
explain_list(:next5) { needed.next5 }
|
||||
explain_list(:specs) { Array(specs).map { |x| x.full_name }.sort }
|
||||
|
||||
# If there is already a spec activated for the requested name...
|
||||
if specs && existing = specs.find { |s| dep.name == s.name }
|
||||
|
@ -403,7 +433,10 @@ class Gem::Resolver
|
|||
@missing << dep
|
||||
|
||||
unless @soft_missing
|
||||
raise Gem::UnsatisfiableDependencyError.new(dep, platform_mismatch)
|
||||
exc = Gem::UnsatisfiableDependencyError.new dep, platform_mismatch
|
||||
exc.errors = @set.errors
|
||||
|
||||
raise exc
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -38,6 +38,13 @@ class Gem::Resolver::ActivationRequest
|
|||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Is this activation request for a development dependency?
|
||||
|
||||
def development?
|
||||
@request.development?
|
||||
end
|
||||
|
||||
##
|
||||
# Downloads a gem at +path+ and returns the file path.
|
||||
|
||||
|
|
|
@ -34,6 +34,8 @@ class Gem::Resolver::APISet < Gem::Resolver::Set
|
|||
|
||||
@data = Hash.new { |h,k| h[k] = [] }
|
||||
@source = Gem::Source.new @uri
|
||||
|
||||
@to_fetch = []
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -45,6 +47,10 @@ class Gem::Resolver::APISet < Gem::Resolver::Set
|
|||
|
||||
return res unless @remote
|
||||
|
||||
if @to_fetch.include?(req.name)
|
||||
prefetch_now
|
||||
end
|
||||
|
||||
versions(req.name).each do |ver|
|
||||
if req.dependency.match? req.name, ver[:number]
|
||||
res << Gem::Resolver::APISpecification.new(self, ver)
|
||||
|
@ -61,9 +67,13 @@ class Gem::Resolver::APISet < Gem::Resolver::Set
|
|||
def prefetch reqs
|
||||
return unless @remote
|
||||
names = reqs.map { |r| r.dependency.name }
|
||||
needed = names - @data.keys
|
||||
needed = names - @data.keys - @to_fetch
|
||||
|
||||
return if needed.empty?
|
||||
@to_fetch += needed
|
||||
end
|
||||
|
||||
def prefetch_now
|
||||
needed, @to_fetch = @to_fetch, []
|
||||
|
||||
uri = @dep_uri + "?gems=#{needed.sort.join ','}"
|
||||
str = Gem::RemoteFetcher.fetcher.fetch_path uri
|
||||
|
|
|
@ -34,6 +34,12 @@ class Gem::Resolver::APISpecification < Gem::Resolver::Specification
|
|||
@dependencies == other.dependencies
|
||||
end
|
||||
|
||||
def fetch_development_dependencies # :nodoc:
|
||||
spec = source.fetch_spec Gem::NameTuple.new @name, @version, @platform
|
||||
|
||||
@dependencies = spec.dependencies
|
||||
end
|
||||
|
||||
def installable_platform? # :nodoc:
|
||||
Gem::Platform.match @platform
|
||||
end
|
||||
|
|
|
@ -28,6 +28,10 @@ class Gem::Resolver::BestSet < Gem::Resolver::ComposedSet
|
|||
pick_sets if @remote and @sets.empty?
|
||||
|
||||
super
|
||||
rescue Gem::RemoteFetcher::FetchError => e
|
||||
replace_failed_api_set e
|
||||
|
||||
retry
|
||||
end
|
||||
|
||||
def prefetch reqs # :nodoc:
|
||||
|
@ -46,5 +50,29 @@ class Gem::Resolver::BestSet < Gem::Resolver::ComposedSet
|
|||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Replaces a failed APISet for the URI in +error+ with an IndexSet.
|
||||
#
|
||||
# If no matching APISet can be found the original +error+ is raised.
|
||||
#
|
||||
# The calling method must retry the exception to repeat the lookup.
|
||||
|
||||
def replace_failed_api_set error # :nodoc:
|
||||
uri = error.uri
|
||||
uri = URI uri unless URI === uri
|
||||
uri.query = nil
|
||||
|
||||
raise error unless api_set = @sets.find { |set|
|
||||
Gem::Resolver::APISet === set and set.dep_uri == uri
|
||||
}
|
||||
|
||||
index_set = Gem::Resolver::IndexSet.new api_set.source
|
||||
|
||||
@sets.map! do |set|
|
||||
next set unless set == api_set
|
||||
index_set
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -21,6 +21,18 @@ class Gem::Resolver::ComposedSet < Gem::Resolver::Set
|
|||
@sets = sets
|
||||
end
|
||||
|
||||
##
|
||||
# When +allow_prerelease+ is set to +true+ prereleases gems are allowed to
|
||||
# match dependencies.
|
||||
|
||||
def prerelease= allow_prerelease
|
||||
super
|
||||
|
||||
sets.each do |set|
|
||||
set.prerelease = allow_prerelease
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Sets the remote network access for all composed sets.
|
||||
|
||||
|
@ -30,6 +42,10 @@ class Gem::Resolver::ComposedSet < Gem::Resolver::Set
|
|||
@sets.each { |set| set.remote = remote }
|
||||
end
|
||||
|
||||
def errors
|
||||
@errors + @sets.map { |set| set.errors }.flatten
|
||||
end
|
||||
|
||||
##
|
||||
# Finds all specs matching +req+ in all sets.
|
||||
|
||||
|
|
|
@ -52,11 +52,40 @@ class Gem::Resolver::Conflict
|
|||
|
||||
def explanation
|
||||
activated = @activated.spec.full_name
|
||||
requirement = @failed_dep.dependency.requirement
|
||||
dependency = @failed_dep.dependency
|
||||
requirement = dependency.requirement
|
||||
alternates = dependency.matching_specs.map { |spec| spec.full_name }
|
||||
|
||||
" Activated %s via:\n %s\n instead of (%s) via:\n %s\n" % [
|
||||
activated, request_path(@activated).join(', '),
|
||||
requirement, request_path(requester).join(', '),
|
||||
unless alternates.empty? then
|
||||
matching = <<-MATCHING.chomp
|
||||
|
||||
Gems matching %s:
|
||||
%s
|
||||
MATCHING
|
||||
|
||||
matching = matching % [
|
||||
dependency,
|
||||
alternates.join(', '),
|
||||
]
|
||||
end
|
||||
|
||||
explanation = <<-EXPLANATION
|
||||
Activated %s
|
||||
which does not match conflicting dependency (%s)
|
||||
|
||||
Conflicting dependency chains:
|
||||
%s
|
||||
|
||||
versus:
|
||||
%s
|
||||
%s
|
||||
EXPLANATION
|
||||
|
||||
explanation % [
|
||||
activated, requirement,
|
||||
request_path(@activated).reverse.join(", depends on\n "),
|
||||
request_path(@failed_dep).reverse.join(", depends on\n "),
|
||||
matching,
|
||||
]
|
||||
end
|
||||
|
||||
|
@ -95,10 +124,19 @@ class Gem::Resolver::Conflict
|
|||
path = []
|
||||
|
||||
while current do
|
||||
requirement = current.request.dependency.requirement
|
||||
path << "#{current.spec.full_name} (#{requirement})"
|
||||
case current
|
||||
when Gem::Resolver::ActivationRequest then
|
||||
path <<
|
||||
"#{current.request.dependency}, #{current.spec.version} activated"
|
||||
|
||||
current = current.parent
|
||||
current = current.parent
|
||||
when Gem::Resolver::DependencyRequest then
|
||||
path << "#{current.dependency}"
|
||||
|
||||
current = current.requester
|
||||
else
|
||||
raise Gem::Exception, "[BUG] unknown request class #{current.class}"
|
||||
end
|
||||
end
|
||||
|
||||
path = ['user request (gem command or Gemfile)'] if path.empty?
|
||||
|
|
|
@ -35,7 +35,26 @@ class Gem::Resolver::DependencyRequest
|
|||
end
|
||||
|
||||
##
|
||||
# Does this dependency request match +spec+
|
||||
# Is this dependency a development dependency?
|
||||
|
||||
def development?
|
||||
@dependency.type == :development
|
||||
end
|
||||
|
||||
##
|
||||
# Does this dependency request match +spec+?
|
||||
#
|
||||
# NOTE: #match? only matches prerelease versions when #dependency is a
|
||||
# prerelease dependency.
|
||||
|
||||
def match? spec, allow_prerelease = false
|
||||
@dependency.match? spec, nil, allow_prerelease
|
||||
end
|
||||
|
||||
##
|
||||
# Does this dependency request match +spec+?
|
||||
#
|
||||
# NOTE: #matches_spec? matches prerelease versions. See also #match?
|
||||
|
||||
def matches_spec?(spec)
|
||||
@dependency.matches_spec? spec
|
||||
|
|
|
@ -80,7 +80,7 @@ class Gem::Resolver::GitSet < Gem::Resolver::Set
|
|||
prefetch nil
|
||||
|
||||
specs.values.select do |spec|
|
||||
req.matches_spec? spec
|
||||
req.match? spec
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -12,11 +12,15 @@ class Gem::Resolver::GitSpecification < Gem::Resolver::SpecSpecification
|
|||
@source == other.source
|
||||
end
|
||||
|
||||
def add_dependency dependency # :nodoc:
|
||||
spec.dependencies << dependency
|
||||
end
|
||||
|
||||
##
|
||||
# Installing a git gem only involves building the extensions and generating
|
||||
# the executables.
|
||||
|
||||
def install options
|
||||
def install options = {}
|
||||
require 'rubygems/installer'
|
||||
|
||||
installer = Gem::Installer.new '', options
|
||||
|
@ -31,5 +35,25 @@ class Gem::Resolver::GitSpecification < Gem::Resolver::SpecSpecification
|
|||
installer.run_post_install_hooks
|
||||
end
|
||||
|
||||
def pretty_print q # :nodoc:
|
||||
q.group 2, '[GitSpecification', ']' do
|
||||
q.breakable
|
||||
q.text "name: #{name}"
|
||||
|
||||
q.breakable
|
||||
q.text "version: #{version}"
|
||||
|
||||
q.breakable
|
||||
q.text 'dependencies:'
|
||||
q.breakable
|
||||
q.pp dependencies
|
||||
|
||||
q.breakable
|
||||
q.text "source:"
|
||||
q.breakable
|
||||
q.pp @source
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -18,7 +18,9 @@ class Gem::Resolver::IndexSet < Gem::Resolver::Set
|
|||
|
||||
@all = Hash.new { |h,k| h[k] = [] }
|
||||
|
||||
list, = @f.available_specs :released
|
||||
list, errors = @f.available_specs :complete
|
||||
|
||||
@errors.concat errors
|
||||
|
||||
list.each do |uri, specs|
|
||||
specs.each do |n|
|
||||
|
@ -41,7 +43,7 @@ class Gem::Resolver::IndexSet < Gem::Resolver::Set
|
|||
name = req.dependency.name
|
||||
|
||||
@all[name].each do |uri, n|
|
||||
if req.dependency.match? n then
|
||||
if req.match? n, @prerelease then
|
||||
res << Gem::Resolver::IndexSpecification.new(
|
||||
self, n.name, n.version, uri, n.platform)
|
||||
end
|
||||
|
|
|
@ -14,7 +14,7 @@ class Gem::Resolver::InstalledSpecification < Gem::Resolver::SpecSpecification
|
|||
# This is a null install as this specification is already installed.
|
||||
# +options+ are ignored.
|
||||
|
||||
def install options
|
||||
def install options = {}
|
||||
yield nil
|
||||
end
|
||||
|
||||
|
@ -29,6 +29,24 @@ class Gem::Resolver::InstalledSpecification < Gem::Resolver::SpecSpecification
|
|||
super
|
||||
end
|
||||
|
||||
def pretty_print q # :nodoc:
|
||||
q.group 2, '[InstalledSpecification', ']' do
|
||||
q.breakable
|
||||
q.text "name: #{name}"
|
||||
|
||||
q.breakable
|
||||
q.text "version: #{version}"
|
||||
|
||||
q.breakable
|
||||
q.text "platform: #{platform}"
|
||||
|
||||
q.breakable
|
||||
q.text 'dependencies:'
|
||||
q.breakable
|
||||
q.pp spec.dependencies
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# The source for this specification
|
||||
|
||||
|
|
|
@ -20,6 +20,11 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
|
|||
|
||||
attr_accessor :ignore_installed # :nodoc:
|
||||
|
||||
##
|
||||
# The remote_set looks up remote gems for installation.
|
||||
|
||||
attr_reader :remote_set # :nodoc:
|
||||
|
||||
##
|
||||
# Creates a new InstallerSet that will look for gems in +domain+.
|
||||
|
||||
|
@ -34,10 +39,52 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
|
|||
@always_install = []
|
||||
@ignore_dependencies = false
|
||||
@ignore_installed = false
|
||||
@local = {}
|
||||
@remote_set = Gem::Resolver::BestSet.new
|
||||
@specs = {}
|
||||
end
|
||||
|
||||
##
|
||||
# Looks up the latest specification for +dependency+ and adds it to the
|
||||
# always_install list.
|
||||
|
||||
def add_always_install dependency
|
||||
request = Gem::Resolver::DependencyRequest.new dependency, nil
|
||||
|
||||
found = find_all request
|
||||
|
||||
found.delete_if { |s|
|
||||
s.version.prerelease? and not s.local?
|
||||
} unless dependency.prerelease?
|
||||
|
||||
found = found.select do |s|
|
||||
Gem::Source::SpecificFile === s.source or
|
||||
Gem::Platform::RUBY == s.platform or
|
||||
Gem::Platform.local === s.platform
|
||||
end
|
||||
|
||||
if found.empty? then
|
||||
exc = Gem::UnsatisfiableDependencyError.new request
|
||||
exc.errors = errors
|
||||
|
||||
raise exc
|
||||
end
|
||||
|
||||
newest = found.max_by do |s|
|
||||
[s.version, s.platform == Gem::Platform::RUBY ? -1 : 1]
|
||||
end
|
||||
|
||||
@always_install << newest.spec
|
||||
end
|
||||
|
||||
##
|
||||
# Adds a local gem requested using +dep_name+ with the given +spec+ that can
|
||||
# be loaded and installed using the +source+.
|
||||
|
||||
def add_local dep_name, spec, source
|
||||
@local[dep_name] = [spec, source]
|
||||
end
|
||||
|
||||
##
|
||||
# Should local gems should be considered?
|
||||
|
||||
|
@ -52,6 +99,13 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
|
|||
@domain == :both or @domain == :remote
|
||||
end
|
||||
|
||||
##
|
||||
# Errors encountered while resolving gems
|
||||
|
||||
def errors
|
||||
@errors + @remote_set.errors
|
||||
end
|
||||
|
||||
##
|
||||
# Returns an array of IndexSpecification objects matching DependencyRequest
|
||||
# +req+.
|
||||
|
@ -62,30 +116,53 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
|
|||
dep = req.dependency
|
||||
|
||||
return res if @ignore_dependencies and
|
||||
@always_install.none? { |spec| dep.matches_spec? spec }
|
||||
@always_install.none? { |spec| dep.match? spec }
|
||||
|
||||
name = dep.name
|
||||
|
||||
dep.matching_specs.each do |gemspec|
|
||||
next if @always_install.include? gemspec
|
||||
next if @always_install.any? { |spec| spec.name == gemspec.name }
|
||||
|
||||
res << Gem::Resolver::InstalledSpecification.new(self, gemspec)
|
||||
end unless @ignore_installed
|
||||
|
||||
if consider_local? then
|
||||
matching_local = @local.values.select do |spec, _|
|
||||
req.match? spec
|
||||
end.map do |spec, source|
|
||||
Gem::Resolver::LocalSpecification.new self, spec, source
|
||||
end
|
||||
|
||||
res.concat matching_local
|
||||
|
||||
local_source = Gem::Source::Local.new
|
||||
|
||||
if spec = local_source.find_gem(name, dep.requirement) then
|
||||
if local_spec = local_source.find_gem(name, dep.requirement) then
|
||||
res << Gem::Resolver::IndexSpecification.new(
|
||||
self, spec.name, spec.version, local_source, spec.platform)
|
||||
self, local_spec.name, local_spec.version,
|
||||
local_source, local_spec.platform)
|
||||
end
|
||||
end
|
||||
|
||||
res.delete_if do |spec|
|
||||
spec.version.prerelease? and not dep.prerelease?
|
||||
end
|
||||
|
||||
res.concat @remote_set.find_all req if consider_remote?
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
def prefetch(reqs)
|
||||
@remote_set.prefetch(reqs)
|
||||
end
|
||||
|
||||
def prerelease= allow_prerelease
|
||||
super
|
||||
|
||||
@remote_set.prerelease = allow_prerelease
|
||||
end
|
||||
|
||||
def inspect # :nodoc:
|
||||
always_install = @always_install.map { |s| s.full_name }
|
||||
|
||||
|
@ -108,6 +185,15 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
|
|||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Has a local gem for +dep_name+ been added to this set?
|
||||
|
||||
def local? dep_name # :nodoc:
|
||||
spec, = @local[dep_name]
|
||||
|
||||
spec
|
||||
end
|
||||
|
||||
def pretty_print q # :nodoc:
|
||||
q.group 2, '[InstallerSet', ']' do
|
||||
q.breakable
|
||||
|
|
|
@ -12,5 +12,30 @@ class Gem::Resolver::LocalSpecification < Gem::Resolver::SpecSpecification
|
|||
super
|
||||
end
|
||||
|
||||
def local? # :nodoc:
|
||||
true
|
||||
end
|
||||
|
||||
def pretty_print q # :nodoc:
|
||||
q.group 2, '[LocalSpecification', ']' do
|
||||
q.breakable
|
||||
q.text "name: #{name}"
|
||||
|
||||
q.breakable
|
||||
q.text "version: #{version}"
|
||||
|
||||
q.breakable
|
||||
q.text "platform: #{platform}"
|
||||
|
||||
q.breakable
|
||||
q.text 'dependencies:'
|
||||
q.breakable
|
||||
q.pp dependencies
|
||||
|
||||
q.breakable
|
||||
q.text "source: #{@source.path}"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -6,13 +6,16 @@ class Gem::Resolver::LockSet < Gem::Resolver::Set
|
|||
attr_reader :specs # :nodoc:
|
||||
|
||||
##
|
||||
# Creates a new LockSet from the given +source+
|
||||
# Creates a new LockSet from the given +sources+
|
||||
|
||||
def initialize source
|
||||
def initialize sources
|
||||
super()
|
||||
|
||||
@source = Gem::Source::Lock.new source
|
||||
@specs = []
|
||||
@sources = sources.map do |source|
|
||||
Gem::Source::Lock.new source
|
||||
end
|
||||
|
||||
@specs = []
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -25,13 +28,14 @@ class Gem::Resolver::LockSet < Gem::Resolver::Set
|
|||
def add name, version, platform # :nodoc:
|
||||
version = Gem::Version.new version
|
||||
|
||||
spec =
|
||||
Gem::Resolver::LockSpecification.new self, name, version, @source,
|
||||
specs = @sources.map do |source|
|
||||
Gem::Resolver::LockSpecification.new self, name, version, source,
|
||||
platform
|
||||
end
|
||||
|
||||
@specs << spec
|
||||
@specs.concat specs
|
||||
|
||||
spec
|
||||
specs
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -40,7 +44,7 @@ class Gem::Resolver::LockSet < Gem::Resolver::Set
|
|||
|
||||
def find_all req
|
||||
@specs.select do |spec|
|
||||
req.matches_spec? spec
|
||||
req.match? spec
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ class Gem::Resolver::LockSpecification < Gem::Resolver::Specification
|
|||
# This is a null install as a locked specification is considered installed.
|
||||
# +options+ are ignored.
|
||||
|
||||
def install options
|
||||
def install options = {}
|
||||
destination = options[:install_dir] || Gem.dir
|
||||
|
||||
if File.exist? File.join(destination, 'specifications', spec.spec_name) then
|
||||
|
@ -41,10 +41,36 @@ class Gem::Resolver::LockSpecification < Gem::Resolver::Specification
|
|||
@dependencies << dependency
|
||||
end
|
||||
|
||||
def pretty_print q # :nodoc:
|
||||
q.group 2, '[LockSpecification', ']' do
|
||||
q.breakable
|
||||
q.text "name: #{@name}"
|
||||
|
||||
q.breakable
|
||||
q.text "version: #{@version}"
|
||||
|
||||
unless @platform == Gem::Platform::RUBY then
|
||||
q.breakable
|
||||
q.text "platform: #{@platform}"
|
||||
end
|
||||
|
||||
unless @dependencies.empty? then
|
||||
q.breakable
|
||||
q.text 'dependencies:'
|
||||
q.breakable
|
||||
q.pp @dependencies
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# A specification constructed from the lockfile is returned
|
||||
|
||||
def spec
|
||||
@spec ||= Gem::Specification.find { |spec|
|
||||
spec.name == @name and spec.version == @version
|
||||
}
|
||||
|
||||
@spec ||= Gem::Specification.new do |s|
|
||||
s.name = @name
|
||||
s.version = @version
|
||||
|
|
|
@ -9,8 +9,20 @@ class Gem::Resolver::Set
|
|||
|
||||
attr_accessor :remote
|
||||
|
||||
##
|
||||
# Errors encountered when resolving gems
|
||||
|
||||
attr_accessor :errors
|
||||
|
||||
##
|
||||
# When true, allows matching of requests to prerelease gems.
|
||||
|
||||
attr_accessor :prerelease
|
||||
|
||||
def initialize # :nodoc:
|
||||
@remote = true
|
||||
@prerelease = false
|
||||
@remote = true
|
||||
@errors = []
|
||||
end
|
||||
|
||||
##
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
|
||||
class Gem::Resolver::SpecSpecification < Gem::Resolver::Specification
|
||||
|
||||
attr_reader :spec # :nodoc:
|
||||
|
||||
##
|
||||
# A SpecSpecification is created for a +set+ for a Gem::Specification in
|
||||
# +spec+. The +source+ is either where the +spec+ came from, or should be
|
||||
|
|
|
@ -30,6 +30,14 @@ class Gem::Resolver::Specification
|
|||
|
||||
attr_reader :source
|
||||
|
||||
##
|
||||
# The Gem::Specification for this Resolver::Specification.
|
||||
#
|
||||
# Implementers, note that #install updates @spec, so be sure to cache the
|
||||
# Gem::Specification in @spec when overriding.
|
||||
|
||||
attr_reader :spec
|
||||
|
||||
##
|
||||
# The version of the gem for this specification.
|
||||
|
||||
|
@ -47,6 +55,13 @@ class Gem::Resolver::Specification
|
|||
@version = nil
|
||||
end
|
||||
|
||||
##
|
||||
# Fetches development dependencies if the source does not provide them by
|
||||
# default (see APISpecification).
|
||||
|
||||
def fetch_development_dependencies # :nodoc:
|
||||
end
|
||||
|
||||
##
|
||||
# The name and version of the specification.
|
||||
#
|
||||
|
@ -61,8 +76,11 @@ class Gem::Resolver::Specification
|
|||
# install method yields a Gem::Installer instance, which indicates the
|
||||
# gem will be installed, or +nil+, which indicates the gem is already
|
||||
# installed.
|
||||
#
|
||||
# After installation #spec is updated to point to the just-installed
|
||||
# specification.
|
||||
|
||||
def install options
|
||||
def install options = {}
|
||||
require 'rubygems/installer'
|
||||
|
||||
destination = options[:install_dir] || Gem.dir
|
||||
|
@ -75,7 +93,7 @@ class Gem::Resolver::Specification
|
|||
|
||||
yield installer if block_given?
|
||||
|
||||
installer.install
|
||||
@spec = installer.install
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -85,5 +103,8 @@ class Gem::Resolver::Specification
|
|||
Gem::Platform.match spec.platform
|
||||
end
|
||||
|
||||
def local? # :nodoc:
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -43,6 +43,8 @@ class Gem::Resolver::VendorSet < Gem::Resolver::Set
|
|||
|
||||
@specs[spec.name] = spec
|
||||
@directories[spec] = directory
|
||||
|
||||
spec
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -51,7 +53,7 @@ class Gem::Resolver::VendorSet < Gem::Resolver::Set
|
|||
|
||||
def find_all req
|
||||
@specs.values.select do |spec|
|
||||
req.matches_spec? spec
|
||||
req.match? spec
|
||||
end.map do |spec|
|
||||
source = Gem::Source::Vendor.new @directories[spec]
|
||||
Gem::Resolver::VendorSpecification.new self, spec, source
|
||||
|
|
|
@ -16,7 +16,7 @@ class Gem::Resolver::VendorSpecification < Gem::Resolver::SpecSpecification
|
|||
# This is a null install as this gem was unpacked into a directory.
|
||||
# +options+ are ignored.
|
||||
|
||||
def install options
|
||||
def install options = {}
|
||||
yield nil
|
||||
end
|
||||
|
||||
|
|
|
@ -218,6 +218,7 @@ class Gem::Security::Policy
|
|||
# against
|
||||
else
|
||||
alert_warning "#{full_name} is not signed"
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -530,6 +530,36 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
|
|||
end
|
||||
end
|
||||
|
||||
def prerelease_specs req, res
|
||||
reset_gems
|
||||
|
||||
res['content-type'] = 'application/x-gzip'
|
||||
|
||||
add_date res
|
||||
|
||||
specs = Gem::Specification.select do |spec|
|
||||
spec.version.prerelease?
|
||||
end.sort.map do |spec|
|
||||
platform = spec.original_platform || Gem::Platform::RUBY
|
||||
[spec.name, spec.version, platform]
|
||||
end
|
||||
|
||||
specs = Marshal.dump specs
|
||||
|
||||
if req.path =~ /\.gz$/ then
|
||||
specs = Gem.gzip specs
|
||||
res['content-type'] = 'application/x-gzip'
|
||||
else
|
||||
res['content-type'] = 'application/octet-stream'
|
||||
end
|
||||
|
||||
if req.request_method == 'HEAD' then
|
||||
res['content-length'] = specs.length
|
||||
else
|
||||
res.body << specs
|
||||
end
|
||||
end
|
||||
|
||||
def quick(req, res)
|
||||
reset_gems
|
||||
|
||||
|
@ -537,7 +567,7 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
|
|||
add_date res
|
||||
|
||||
case req.request_uri.path
|
||||
when %r|^/quick/(Marshal.#{Regexp.escape Gem.marshal_version}/)?(.*?)-([0-9.]+)(-.*?)?\.gemspec\.rz$| then
|
||||
when %r|^/quick/(Marshal.#{Regexp.escape Gem.marshal_version}/)?(.*?)-([0-9.]+[^-]*?)(-.*?)?\.gemspec\.rz$| then
|
||||
marshal_format, name, version, platform = $1, $2, $3, $4
|
||||
specs = Gem::Specification.find_all_by_name name, version
|
||||
|
||||
|
@ -757,6 +787,11 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
|
|||
@server.mount_proc "/latest_specs.#{Gem.marshal_version}.gz",
|
||||
method(:latest_specs)
|
||||
|
||||
@server.mount_proc "/prerelease_specs.#{Gem.marshal_version}",
|
||||
method(:prerelease_specs)
|
||||
@server.mount_proc "/prerelease_specs.#{Gem.marshal_version}.gz",
|
||||
method(:prerelease_specs)
|
||||
|
||||
@server.mount_proc "/quick/", method(:quick)
|
||||
|
||||
@server.mount_proc("/gem-server-rdoc-style.css") do |req, res|
|
||||
|
|
|
@ -78,15 +78,21 @@ class Gem::Source
|
|||
# Returns a Set that can fetch specifications from this source.
|
||||
|
||||
def dependency_resolver_set # :nodoc:
|
||||
return Gem::Resolver::IndexSet.new self if 'file' == api_uri.scheme
|
||||
|
||||
bundler_api_uri = api_uri + './api/v1/dependencies'
|
||||
|
||||
begin
|
||||
fetcher = Gem::RemoteFetcher.fetcher
|
||||
fetcher.fetch_path bundler_api_uri, nil, true
|
||||
response = fetcher.fetch_path bundler_api_uri, nil, true
|
||||
rescue Gem::RemoteFetcher::FetchError
|
||||
Gem::Resolver::IndexSet.new self
|
||||
else
|
||||
Gem::Resolver::APISet.new bundler_api_uri
|
||||
if response.respond_to? :uri then
|
||||
Gem::Resolver::APISet.new response.uri
|
||||
else
|
||||
Gem::Resolver::APISet.new bundler_api_uri
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -100,6 +106,8 @@ class Gem::Source
|
|||
def cache_dir(uri)
|
||||
# Correct for windows paths
|
||||
escaped_path = uri.path.sub(/^\/([a-z]):\//i, '/\\1-/')
|
||||
escaped_path.untaint
|
||||
|
||||
File.join Gem.spec_cache_dir, "#{uri.host}%#{uri.port}", File.dirname(escaped_path)
|
||||
end
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ class Gem::Source::Git < Gem::Source
|
|||
# will be checked out when the gem is installed.
|
||||
|
||||
def initialize name, repository, reference, submodules = false
|
||||
super(nil)
|
||||
super repository
|
||||
|
||||
@name = name
|
||||
@repository = repository
|
||||
|
@ -67,7 +67,7 @@ class Gem::Source::Git < Gem::Source
|
|||
case other
|
||||
when Gem::Source::Git then
|
||||
0
|
||||
when Gem::Source::Installed,
|
||||
when Gem::Source::Vendor,
|
||||
Gem::Source::Lock then
|
||||
-1
|
||||
when Gem::Source then
|
||||
|
@ -101,7 +101,7 @@ class Gem::Source::Git < Gem::Source
|
|||
Dir.chdir install_dir do
|
||||
system @git, 'fetch', '--quiet', '--force', '--tags', install_dir
|
||||
|
||||
success = system @git, 'reset', '--quiet', '--hard', @reference
|
||||
success = system @git, 'reset', '--quiet', '--hard', rev_parse
|
||||
|
||||
success &&=
|
||||
Gem::Util.silent_system @git, 'submodule', 'update',
|
||||
|
|
|
@ -12,7 +12,8 @@ class Gem::Source::Installed < Gem::Source
|
|||
|
||||
def <=> other
|
||||
case other
|
||||
when Gem::Source::Lock,
|
||||
when Gem::Source::Git,
|
||||
Gem::Source::Lock,
|
||||
Gem::Source::Vendor then
|
||||
-1
|
||||
when Gem::Source::Installed then
|
||||
|
@ -31,5 +32,9 @@ class Gem::Source::Installed < Gem::Source
|
|||
nil
|
||||
end
|
||||
|
||||
def pretty_print q # :nodoc:
|
||||
q.text '[Installed]'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -4,6 +4,11 @@
|
|||
|
||||
class Gem::Source::SpecificFile < Gem::Source
|
||||
|
||||
##
|
||||
# The path to the gem for this specific file.
|
||||
|
||||
attr_reader :path
|
||||
|
||||
##
|
||||
# Creates a new SpecificFile for the gem in +file+
|
||||
|
||||
|
@ -37,7 +42,7 @@ class Gem::Source::SpecificFile < Gem::Source
|
|||
end
|
||||
|
||||
def pretty_print q # :nodoc:
|
||||
q.group 2, '[Local:', ']' do
|
||||
q.group 2, '[SpecificFile:', ']' do
|
||||
q.breakable
|
||||
q.text @path
|
||||
end
|
||||
|
|
|
@ -186,7 +186,7 @@ class Gem::SpecFetcher
|
|||
def suggest_gems_from_name gem_name
|
||||
gem_name = gem_name.downcase.tr('_-', '')
|
||||
max = gem_name.size / 2
|
||||
names = available_specs(:complete).first.values.flatten(1)
|
||||
names = available_specs(:latest).first.values.flatten(1)
|
||||
|
||||
matches = names.map { |n|
|
||||
next unless n.match_platform?
|
||||
|
@ -258,18 +258,11 @@ class Gem::SpecFetcher
|
|||
# etc.). If +gracefully_ignore+ is true, errors are ignored.
|
||||
|
||||
def tuples_for(source, type, gracefully_ignore=false) # :nodoc:
|
||||
cache = @caches[type]
|
||||
|
||||
tuples =
|
||||
begin
|
||||
cache[source.uri] ||=
|
||||
source.load_specs(type).sort_by { |tup| tup.name }
|
||||
rescue Gem::RemoteFetcher::FetchError
|
||||
raise unless gracefully_ignore
|
||||
[]
|
||||
end
|
||||
|
||||
tuples
|
||||
@caches[type][source.uri] ||=
|
||||
source.load_specs(type).sort_by { |tup| tup.name }
|
||||
rescue Gem::RemoteFetcher::FetchError
|
||||
raise unless gracefully_ignore
|
||||
[]
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -14,12 +14,6 @@ require 'rubygems/basic_specification'
|
|||
require 'rubygems/stub_specification'
|
||||
require 'rubygems/util/stringio'
|
||||
|
||||
# :stopdoc:
|
||||
# date.rb can't be loaded for `make install` due to miniruby
|
||||
# Date is needed for old gems that stored #date as Date instead of Time.
|
||||
class Date; end
|
||||
# :startdoc:
|
||||
|
||||
##
|
||||
# The Specification class contains the information for a Gem. Typically
|
||||
# defined in a .gemspec file or a Rakefile, and looks like this:
|
||||
|
@ -218,9 +212,11 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
# Usage:
|
||||
#
|
||||
# # If all library files are in the root directory...
|
||||
# spec.require_path = '.'
|
||||
# spec.require_paths = ['.']
|
||||
|
||||
attr_writer :require_paths
|
||||
def require_paths=(val)
|
||||
@require_paths = Array(val)
|
||||
end
|
||||
|
||||
##
|
||||
# The version of RubyGems used to create this gem.
|
||||
|
@ -373,7 +369,9 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
##
|
||||
# A long description of this gem
|
||||
#
|
||||
# The description should be more detailed than the summary.
|
||||
# The description should be more detailed than the summary but not
|
||||
# excessively long. A few paragraphs is a recommended length with no
|
||||
# examples or formatting.
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
|
@ -412,6 +410,16 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
|
||||
attr_accessor :post_install_message
|
||||
|
||||
##
|
||||
# The version of Ruby required by this gem
|
||||
|
||||
attr_reader :required_ruby_version
|
||||
|
||||
##
|
||||
# The RubyGems version required by this gem
|
||||
|
||||
attr_reader :required_rubygems_version
|
||||
|
||||
##
|
||||
# The key used to sign this gem. See Gem::Security for details.
|
||||
|
||||
|
@ -472,6 +480,9 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
# found in bindir. These files must be executable Ruby files. Files that
|
||||
# use bash or other interpreters will not work.
|
||||
#
|
||||
# Executables included may only be ruby scripts, not scripts for other
|
||||
# languages or compiled binaries.
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# spec.executables << 'rake'
|
||||
|
@ -532,20 +543,26 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
|
||||
##
|
||||
# :category: Recommended gemspec attributes
|
||||
#
|
||||
# The license for this gem.
|
||||
#
|
||||
# The license must be a short name, no more than 64 characters.
|
||||
# The license must be no more than 64 characters.
|
||||
#
|
||||
# This should just be the name of your license. The full
|
||||
# text of the license should be inside of the gem when you build it.
|
||||
# This should just be the name of your license. The full text of the license
|
||||
# should be inside of the gem (at the top level) when you build it.
|
||||
#
|
||||
# See http://opensource.org/licenses/alphabetical for a list of licenses and
|
||||
# their abbreviations (or short names). GitHub also provides a
|
||||
# license picker at http://choosealicense.com/
|
||||
# The simplest way, is to specify the standard SPDX ID
|
||||
# https://spdx.org/licenses/ for the license.
|
||||
# Ideally you should pick one that is OSI (Open Source Initiative)
|
||||
# http://opensource.org/licenses/alphabetical approved.
|
||||
#
|
||||
# According to copyright law, not having an OSI-approved open source license
|
||||
# means you have no rights to use the code for any purpose-- in other words,
|
||||
# "all rights reserved".
|
||||
# The most commonly used OSI approved licenses are BSD-3-Clause and MIT.
|
||||
# GitHub also provides a license picker at http://choosealicense.com/.
|
||||
#
|
||||
# You should specify a license for your gem so that people know how they are
|
||||
# permitted to use it, and any restrictions you're placing on it. Not
|
||||
# specifying a license means all rights are reserved; others have no rights
|
||||
# to use the code for any purpose.
|
||||
#
|
||||
# You can set multiple licenses with #licenses=
|
||||
#
|
||||
|
@ -607,6 +624,13 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
@required_ruby_version = Gem::Requirement.create req
|
||||
end
|
||||
|
||||
##
|
||||
# The RubyGems version required by this gem
|
||||
|
||||
def required_rubygems_version= req
|
||||
@required_rubygems_version = Gem::Requirement.create req
|
||||
end
|
||||
|
||||
##
|
||||
# Lists the external (to RubyGems) requirements that must be met for this gem
|
||||
# to work. It's simply information for the user.
|
||||
|
@ -628,7 +652,7 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
# spec.test_files = Dir.glob('test/tc_*.rb')
|
||||
# spec.test_files = ['tests/test-suite.rb']
|
||||
|
||||
def test_files= files
|
||||
def test_files= files # :nodoc:
|
||||
@test_files = Array files
|
||||
end
|
||||
|
||||
|
@ -661,16 +685,6 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
|
||||
attr_writer :original_platform # :nodoc:
|
||||
|
||||
##
|
||||
# The version of Ruby required by this gem
|
||||
|
||||
attr_reader :required_ruby_version
|
||||
|
||||
##
|
||||
# The RubyGems version required by this gem
|
||||
|
||||
attr_reader :required_rubygems_version
|
||||
|
||||
##
|
||||
# The rubyforge project this gem lives under. i.e. RubyGems'
|
||||
# rubyforge_project is "rubygems".
|
||||
|
@ -1259,9 +1273,13 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
# there are conflicts upon activation.
|
||||
|
||||
def activate
|
||||
raise_if_conflicts
|
||||
other = Gem.loaded_specs[self.name]
|
||||
if other then
|
||||
check_version_conflict other
|
||||
return false
|
||||
end
|
||||
|
||||
return false if Gem.loaded_specs[self.name]
|
||||
raise_if_conflicts
|
||||
|
||||
activate_dependencies
|
||||
add_self_to_load_path
|
||||
|
@ -1403,7 +1421,10 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
|
||||
def build_args
|
||||
if File.exist? build_info_file
|
||||
File.readlines(build_info_file).map { |x| x.strip }
|
||||
build_info = File.readlines build_info_file
|
||||
build_info = build_info.map { |x| x.strip }
|
||||
build_info.delete ""
|
||||
build_info
|
||||
else
|
||||
[]
|
||||
end
|
||||
|
@ -1418,8 +1439,8 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
return if extensions.empty?
|
||||
return if installed_by_version < Gem::Version.new('2.2.0.preview.2')
|
||||
return if File.exist? gem_build_complete_path
|
||||
return if !File.writable?(base_dir) &&
|
||||
!File.exist?(File.join(base_dir, 'extensions'))
|
||||
return if !File.writable?(base_dir)
|
||||
return if !File.exist?(File.join(base_dir, 'extensions'))
|
||||
|
||||
begin
|
||||
# We need to require things in $LOAD_PATH without looking for the
|
||||
|
@ -1477,13 +1498,12 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
|
||||
def conflicts
|
||||
conflicts = {}
|
||||
Gem.loaded_specs.values.each do |spec|
|
||||
bad = self.runtime_dependencies.find_all { |dep|
|
||||
spec.name == dep.name and not spec.satisfies_requirement? dep
|
||||
}
|
||||
|
||||
conflicts[spec] = bad unless bad.empty?
|
||||
end
|
||||
self.runtime_dependencies.each { |dep|
|
||||
spec = Gem.loaded_specs[dep.name]
|
||||
if spec and not spec.satisfies_requirement? dep
|
||||
(conflicts[spec] ||= []) << dep
|
||||
end
|
||||
}
|
||||
conflicts
|
||||
end
|
||||
|
||||
|
@ -1496,6 +1516,11 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
@date ||= TODAY
|
||||
end
|
||||
|
||||
DateLike = Object.new # :nodoc:
|
||||
def DateLike.===(obj) # :nodoc:
|
||||
defined?(::Date) and Date === obj
|
||||
end
|
||||
|
||||
DateTimeFormat = # :nodoc:
|
||||
/\A
|
||||
(\d{4})-(\d{2})-(\d{2})
|
||||
|
@ -1525,7 +1550,7 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
raise(Gem::InvalidSpecificationException,
|
||||
"invalid date format in specification: #{date.inspect}")
|
||||
end
|
||||
when Time, Date then
|
||||
when Time, DateLike then
|
||||
Time.utc(date.year, date.month, date.day)
|
||||
else
|
||||
TODAY
|
||||
|
@ -1779,7 +1804,7 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
##
|
||||
# True if this gem has files in test_files
|
||||
|
||||
def has_unit_tests?
|
||||
def has_unit_tests? # :nodoc:
|
||||
not test_files.empty?
|
||||
end
|
||||
|
||||
|
@ -1952,6 +1977,19 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Is this specification missing its extensions? When this returns true you
|
||||
# probably want to build_extensions
|
||||
|
||||
def missing_extensions?
|
||||
return false if default_gem?
|
||||
return false if extensions.empty?
|
||||
return false if installed_by_version < Gem::Version.new('2.2.0.preview.2')
|
||||
return false if File.exist? gem_build_complete_path
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
##
|
||||
# Normalize the list of files so that:
|
||||
# * All file lists have redundancies removed.
|
||||
|
@ -2035,35 +2073,35 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Raise an exception if the version of this spec conflicts with the one
|
||||
# that is already loaded (+other+)
|
||||
|
||||
def check_version_conflict other # :nodoc:
|
||||
return if self.version == other.version
|
||||
|
||||
# This gem is already loaded. If the currently loaded gem is not in the
|
||||
# list of candidate gems, then we have a version conflict.
|
||||
|
||||
msg = "can't activate #{full_name}, already activated #{other.full_name}"
|
||||
|
||||
e = Gem::LoadError.new msg
|
||||
e.name = self.name
|
||||
# TODO: e.requirement = dep.requirement
|
||||
|
||||
raise e
|
||||
end
|
||||
|
||||
private :check_version_conflict
|
||||
|
||||
##
|
||||
# Check the spec for possible conflicts and freak out if there are any.
|
||||
|
||||
def raise_if_conflicts
|
||||
other = Gem.loaded_specs[self.name]
|
||||
|
||||
if other and self.version != other.version then
|
||||
# This gem is already loaded. If the currently loaded gem is not in the
|
||||
# list of candidate gems, then we have a version conflict.
|
||||
|
||||
msg = "can't activate #{full_name}, already activated #{other.full_name}"
|
||||
|
||||
e = Gem::LoadError.new msg
|
||||
e.name = self.name
|
||||
# TODO: e.requirement = dep.requirement
|
||||
|
||||
raise e
|
||||
end
|
||||
|
||||
def raise_if_conflicts # :nodoc:
|
||||
conf = self.conflicts
|
||||
|
||||
unless conf.empty? then
|
||||
y = conf.map { |act,con|
|
||||
"#{act.full_name} conflicts with #{con.join(", ")}"
|
||||
}.join ", "
|
||||
|
||||
# TODO: improve message by saying who activated `con`
|
||||
|
||||
raise Gem::LoadError, "Unable to activate #{self.full_name}, because #{y}"
|
||||
raise Gem::ConflictError.new self, conf
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -2087,14 +2125,7 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
# Singular accessor for #require_paths
|
||||
|
||||
def require_path= path
|
||||
self.require_paths = [path]
|
||||
end
|
||||
|
||||
##
|
||||
# The RubyGems version required by this gem
|
||||
|
||||
def required_rubygems_version= req
|
||||
@required_rubygems_version = Gem::Requirement.create req
|
||||
self.require_paths = Array(path)
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -2129,7 +2160,7 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
seg = obj.keys.sort.map { |k| "#{k.to_s.dump} => #{obj[k].to_s.dump}" }
|
||||
"{ #{seg.join(', ')} }"
|
||||
when Gem::Version then obj.to_s.dump
|
||||
when Date then obj.strftime('%Y-%m-%d').dump
|
||||
when DateLike then obj.strftime('%Y-%m-%d').dump
|
||||
when Time then obj.strftime('%Y-%m-%d').dump
|
||||
when Numeric then obj.inspect
|
||||
when true, false, nil then obj.inspect
|
||||
|
@ -2217,14 +2248,14 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
##
|
||||
# Singular accessor for #test_files
|
||||
|
||||
def test_file
|
||||
def test_file # :nodoc:
|
||||
val = test_files and val.first
|
||||
end
|
||||
|
||||
##
|
||||
# Singular mutator for #test_files
|
||||
|
||||
def test_file= file
|
||||
def test_file= file # :nodoc:
|
||||
self.test_files = [file]
|
||||
end
|
||||
|
||||
|
@ -2232,7 +2263,7 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
# Test files included in this gem. You cannot append to this accessor, you
|
||||
# must assign to it.
|
||||
|
||||
def test_files
|
||||
def test_files # :nodoc:
|
||||
# Handle the possibility that we have @test_suite_file but not
|
||||
# @test_files. This will happen when an old gem is loaded via
|
||||
# YAML.
|
||||
|
@ -2256,7 +2287,7 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
mark_version
|
||||
result = []
|
||||
result << "# -*- encoding: utf-8 -*-"
|
||||
result << "#{Gem::StubSpecification::PREFIX}#{name} #{version} #{platform} #{@require_paths.join("\0")}"
|
||||
result << "#{Gem::StubSpecification::PREFIX}#{name} #{version} #{platform} #{raw_require_paths.join("\0")}"
|
||||
result << "#{Gem::StubSpecification::PREFIX}#{extensions.join "\0"}" unless
|
||||
extensions.empty?
|
||||
result << nil
|
||||
|
@ -2273,7 +2304,7 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
if metadata and !metadata.empty?
|
||||
result << " s.metadata = #{ruby_code metadata} if s.respond_to? :metadata="
|
||||
end
|
||||
result << " s.require_paths = #{ruby_code @require_paths}"
|
||||
result << " s.require_paths = #{ruby_code raw_require_paths}"
|
||||
|
||||
handled = [
|
||||
:dependencies,
|
||||
|
@ -2443,7 +2474,7 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
"invalid value for attribute name: \"#{name.inspect}\""
|
||||
end
|
||||
|
||||
if @require_paths.empty? then
|
||||
if raw_require_paths.empty? then
|
||||
raise Gem::InvalidSpecificationException,
|
||||
'specification must have at least one require_path'
|
||||
end
|
||||
|
@ -2627,7 +2658,8 @@ duplicate dependency on #{dep}, (#{prev.requirement}) use:
|
|||
dep.requirement.requirements.any? do |op, version|
|
||||
op == '~>' and
|
||||
not version.prerelease? and
|
||||
version.segments.length > 2
|
||||
version.segments.length > 2 and
|
||||
version.segments.first != 0
|
||||
end
|
||||
|
||||
if overly_strict then
|
||||
|
|
|
@ -120,6 +120,13 @@ class Gem::StubSpecification < Gem::BasicSpecification
|
|||
super
|
||||
end
|
||||
|
||||
def missing_extensions?
|
||||
return false if default_gem?
|
||||
return false if extensions.empty?
|
||||
|
||||
to_spec.missing_extensions?
|
||||
end
|
||||
|
||||
##
|
||||
# Name of the gem
|
||||
|
||||
|
@ -147,7 +154,14 @@ class Gem::StubSpecification < Gem::BasicSpecification
|
|||
# The full Gem::Specification for this gem, loaded from evalling its gemspec
|
||||
|
||||
def to_spec
|
||||
@spec ||= Gem.loaded_specs.values.find { |spec|
|
||||
spec.name == @name and spec.version == @version
|
||||
}
|
||||
|
||||
@spec ||= Gem::Specification.load(loaded_from)
|
||||
@spec.ignored = @ignored if instance_variable_defined? :@ignored
|
||||
|
||||
@spec
|
||||
end
|
||||
|
||||
##
|
||||
|
|
|
@ -218,8 +218,11 @@ class Gem::TestCase < MiniTest::Unit::TestCase
|
|||
def setup
|
||||
super
|
||||
|
||||
@orig_gem_home = ENV['GEM_HOME']
|
||||
@orig_gem_path = ENV['GEM_PATH']
|
||||
@orig_gem_home = ENV['GEM_HOME']
|
||||
@orig_gem_path = ENV['GEM_PATH']
|
||||
@orig_gem_vendor = ENV['GEM_VENDOR']
|
||||
|
||||
ENV['GEM_VENDOR'] = nil
|
||||
|
||||
@current_dir = Dir.pwd
|
||||
@fetcher = nil
|
||||
|
@ -347,8 +350,9 @@ class Gem::TestCase < MiniTest::Unit::TestCase
|
|||
|
||||
FileUtils.rm_rf @tempdir unless ENV['KEEP_FILES']
|
||||
|
||||
ENV['GEM_HOME'] = @orig_gem_home
|
||||
ENV['GEM_PATH'] = @orig_gem_path
|
||||
ENV['GEM_HOME'] = @orig_gem_home
|
||||
ENV['GEM_PATH'] = @orig_gem_path
|
||||
ENV['GEM_VENDOR'] = @orig_gem_vendor
|
||||
|
||||
Gem.ruby = @orig_ruby if @orig_ruby
|
||||
|
||||
|
@ -1263,7 +1267,7 @@ Also, a list:
|
|||
# The StaticSet is a static set of gem specifications used for testing only.
|
||||
# It is available by requiring Gem::TestCase.
|
||||
|
||||
class StaticSet
|
||||
class StaticSet < Gem::Resolver::Set
|
||||
|
||||
##
|
||||
# A StaticSet ignores remote because it has a fixed set of gems.
|
||||
|
@ -1274,6 +1278,8 @@ Also, a list:
|
|||
# Creates a new StaticSet for the given +specs+
|
||||
|
||||
def initialize(specs)
|
||||
super()
|
||||
|
||||
@specs = specs
|
||||
|
||||
@remote = true
|
||||
|
@ -1299,7 +1305,7 @@ Also, a list:
|
|||
# Finds all gems matching +dep+ in this set.
|
||||
|
||||
def find_all(dep)
|
||||
@specs.find_all { |s| dep.matches_spec? s }
|
||||
@specs.find_all { |s| dep.match? s, @prerelease }
|
||||
end
|
||||
|
||||
##
|
||||
|
|
|
@ -38,6 +38,8 @@ class Gem::FakeFetcher
|
|||
end
|
||||
|
||||
def find_data(path)
|
||||
return File.read path.path if URI === path and 'file' == path.scheme
|
||||
|
||||
if URI === path and "URI::#{path.scheme.upcase}" != path.class.name then
|
||||
raise ArgumentError,
|
||||
"mismatch for scheme #{path.scheme} and class #{path.class}"
|
||||
|
|
|
@ -26,6 +26,16 @@ module Gem::Text
|
|||
result.join("\n").gsub(/^/, " " * indent)
|
||||
end
|
||||
|
||||
def min3 a, b, c # :nodoc:
|
||||
if a < b && a < c
|
||||
a
|
||||
elsif b < a && b < c
|
||||
b
|
||||
else
|
||||
c
|
||||
end
|
||||
end
|
||||
|
||||
# This code is based directly on the Text gem implementation
|
||||
# Returns a value representing the "cost" of transforming str1 into str2
|
||||
def levenshtein_distance str1, str2
|
||||
|
@ -42,16 +52,16 @@ module Gem::Text
|
|||
d = (0..m).to_a
|
||||
x = nil
|
||||
|
||||
n.times do |i|
|
||||
str1.each_char.each_with_index do |char1,i|
|
||||
e = i+1
|
||||
|
||||
m.times do |j|
|
||||
cost = (s[i] == t[j]) ? 0 : 1
|
||||
x = [
|
||||
str2.each_char.each_with_index do |char2,j|
|
||||
cost = (char1 == char2) ? 0 : 1
|
||||
x = min3(
|
||||
d[j+1] + 1, # insertion
|
||||
e + 1, # deletion
|
||||
d[j] + cost # substitution
|
||||
].min
|
||||
)
|
||||
d[j] = e
|
||||
e = x
|
||||
end
|
||||
|
|
|
@ -96,6 +96,8 @@ class Gem::Uninstaller
|
|||
(@user_install and spec.base_dir == Gem.user_dir)
|
||||
end
|
||||
|
||||
list.sort!
|
||||
|
||||
if list.empty? then
|
||||
if other_repo_specs.empty?
|
||||
if default_specs.empty?
|
||||
|
@ -120,7 +122,8 @@ class Gem::Uninstaller
|
|||
remove_all list
|
||||
|
||||
elsif list.size > 1 then
|
||||
gem_names = list.collect {|gem| gem.full_name} + ["All versions"]
|
||||
gem_names = list.map { |gem| gem.full_name }
|
||||
gem_names << "All versions"
|
||||
|
||||
say
|
||||
_, index = choose_from_list "Select gem to uninstall:", gem_names
|
||||
|
|
|
@ -157,6 +157,14 @@ module Gem::UserInteraction
|
|||
def terminate_interaction exit_code = 0
|
||||
ui.terminate_interaction exit_code
|
||||
end
|
||||
|
||||
##
|
||||
# Calls +say+ with +msg+ or the results of the block if really_verbose
|
||||
# is true.
|
||||
|
||||
def verbose msg = nil
|
||||
say(msg || yield) if Gem.configuration.really_verbose
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
|
|
|
@ -143,6 +143,10 @@
|
|||
# "~> 3.0.0" 3.0.0 ... 3.1
|
||||
# "~> 3.5" 3.5 ... 4.0
|
||||
# "~> 3.5.0" 3.5.0 ... 3.6
|
||||
# "~> 3" 3.0 ... 4.0
|
||||
#
|
||||
# For the last example, single-digit versions are automatically extended with
|
||||
# a zero to give a sensible result.
|
||||
|
||||
class Gem::Version
|
||||
autoload :Requirement, 'rubygems/requirement'
|
||||
|
@ -189,7 +193,7 @@ class Gem::Version
|
|||
@@all = {}
|
||||
|
||||
def self.new version # :nodoc:
|
||||
return super unless Gem::VERSION == self.class
|
||||
return super unless Gem::Version == self
|
||||
|
||||
@@all[version] ||= super
|
||||
end
|
||||
|
|
|
@ -75,6 +75,21 @@ class TestGem < Gem::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
def test_self_install
|
||||
spec_fetcher do |f|
|
||||
f.gem 'a', 1
|
||||
f.spec 'a', 2
|
||||
end
|
||||
|
||||
gemhome2 = "#{@gemhome}2"
|
||||
|
||||
installed = Gem.install 'a', '= 1', :install_dir => gemhome2
|
||||
|
||||
assert_equal %w[a-1], installed.map { |spec| spec.full_name }
|
||||
|
||||
assert_path_exists File.join(gemhome2, 'gems', 'a-1')
|
||||
end
|
||||
|
||||
def test_require_missing
|
||||
save_loaded_features do
|
||||
assert_raises ::LoadError do
|
||||
|
@ -216,6 +231,58 @@ class TestGem < Gem::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
def test_default_path
|
||||
orig_vendordir = RbConfig::CONFIG['vendordir']
|
||||
RbConfig::CONFIG['vendordir'] = File.join @tempdir, 'vendor'
|
||||
|
||||
FileUtils.rm_rf Gem.user_home
|
||||
|
||||
expected = [Gem.default_dir]
|
||||
|
||||
assert_equal expected, Gem.default_path
|
||||
ensure
|
||||
RbConfig::CONFIG['vendordir'] = orig_vendordir
|
||||
end
|
||||
|
||||
def test_default_path_missing_vendor
|
||||
orig_vendordir = RbConfig::CONFIG['vendordir']
|
||||
RbConfig::CONFIG.delete 'vendordir'
|
||||
|
||||
FileUtils.rm_rf Gem.user_home
|
||||
|
||||
expected = [Gem.default_dir]
|
||||
|
||||
assert_equal expected, Gem.default_path
|
||||
ensure
|
||||
RbConfig::CONFIG['vendordir'] = orig_vendordir
|
||||
end
|
||||
|
||||
def test_default_path_user_home
|
||||
orig_vendordir = RbConfig::CONFIG['vendordir']
|
||||
RbConfig::CONFIG['vendordir'] = File.join @tempdir, 'vendor'
|
||||
|
||||
expected = [Gem.user_dir, Gem.default_dir]
|
||||
|
||||
assert_equal expected, Gem.default_path
|
||||
ensure
|
||||
RbConfig::CONFIG['vendordir'] = orig_vendordir
|
||||
end
|
||||
|
||||
def test_default_path_vendor_dir
|
||||
orig_vendordir = RbConfig::CONFIG['vendordir']
|
||||
RbConfig::CONFIG['vendordir'] = File.join @tempdir, 'vendor'
|
||||
|
||||
FileUtils.mkdir_p Gem.vendor_dir
|
||||
|
||||
FileUtils.rm_rf Gem.user_home
|
||||
|
||||
expected = [Gem.default_dir, Gem.vendor_dir]
|
||||
|
||||
assert_equal expected, Gem.default_path
|
||||
ensure
|
||||
RbConfig::CONFIG['vendordir'] = orig_vendordir
|
||||
end
|
||||
|
||||
def test_self_default_sources
|
||||
assert_equal %w[https://rubygems.org/], Gem.default_sources
|
||||
end
|
||||
|
@ -816,6 +883,23 @@ class TestGem < Gem::TestCase
|
|||
assert_match %r%Could not find 'b' %, e.message
|
||||
end
|
||||
|
||||
def test_self_try_activate_missing_extensions
|
||||
util_spec 'ext', '1' do |s|
|
||||
s.extensions = %w[ext/extconf.rb]
|
||||
s.mark_version
|
||||
s.installed_by_version = v('2.2')
|
||||
end
|
||||
|
||||
_, err = capture_io do
|
||||
refute Gem.try_activate 'nonexistent'
|
||||
end
|
||||
|
||||
expected = "Ignoring ext-1 because its extensions are not built. " +
|
||||
"Try: gem pristine ext-1\n"
|
||||
|
||||
assert_equal expected, err
|
||||
end
|
||||
|
||||
def test_self_use_paths
|
||||
util_ensure_gem_dirs
|
||||
|
||||
|
@ -951,6 +1035,30 @@ class TestGem < Gem::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
def test_self_vendor_dir
|
||||
expected =
|
||||
File.join RbConfig::CONFIG['vendordir'], 'gems',
|
||||
RbConfig::CONFIG['ruby_version']
|
||||
|
||||
assert_equal expected, Gem.vendor_dir
|
||||
end
|
||||
|
||||
def test_self_vendor_dir_ENV_GEM_VENDOR
|
||||
ENV['GEM_VENDOR'] = File.join @tempdir, 'vendor', 'gems'
|
||||
|
||||
assert_equal ENV['GEM_VENDOR'], Gem.vendor_dir
|
||||
refute Gem.vendor_dir.frozen?
|
||||
end
|
||||
|
||||
def test_self_vendor_dir_missing
|
||||
orig_vendordir = RbConfig::CONFIG['vendordir']
|
||||
RbConfig::CONFIG.delete 'vendordir'
|
||||
|
||||
assert_nil Gem.vendor_dir
|
||||
ensure
|
||||
RbConfig::CONFIG['vendordir'] = orig_vendordir
|
||||
end
|
||||
|
||||
def test_load_plugins
|
||||
skip 'Insecure operation - chdir' if RUBY_VERSION <= "1.8.7"
|
||||
plugin_path = File.join "lib", "rubygems_plugin.rb"
|
||||
|
@ -1251,13 +1359,28 @@ class TestGem < Gem::TestCase
|
|||
end
|
||||
|
||||
def test_use_gemdeps
|
||||
gem_deps_file = 'gem.deps.rb'.untaint
|
||||
spec = util_spec 'a', 1
|
||||
|
||||
refute spec.activated?
|
||||
|
||||
open gem_deps_file, 'w' do |io|
|
||||
io.write 'gem "a"'
|
||||
end
|
||||
|
||||
Gem.use_gemdeps gem_deps_file
|
||||
|
||||
assert spec.activated?
|
||||
end
|
||||
|
||||
def test_use_gemdeps_ENV
|
||||
rubygems_gemdeps, ENV['RUBYGEMS_GEMDEPS'] = ENV['RUBYGEMS_GEMDEPS'], nil
|
||||
|
||||
spec = util_spec 'a', 1
|
||||
|
||||
refute spec.activated?
|
||||
|
||||
open 'Gemfile', 'w' do |io|
|
||||
open 'gem.deps.rb', 'w' do |io|
|
||||
io.write 'gem "a"'
|
||||
end
|
||||
|
||||
|
@ -1268,6 +1391,29 @@ class TestGem < Gem::TestCase
|
|||
ENV['RUBYGEMS_GEMDEPS'] = rubygems_gemdeps
|
||||
end
|
||||
|
||||
def test_use_gemdeps_argument_missing
|
||||
e = assert_raises ArgumentError do
|
||||
Gem.use_gemdeps 'gem.deps.rb'
|
||||
end
|
||||
|
||||
assert_equal 'Unable to find gem dependencies file at gem.deps.rb',
|
||||
e.message
|
||||
end
|
||||
|
||||
def test_use_gemdeps_argument_missing_match_ENV
|
||||
rubygems_gemdeps, ENV['RUBYGEMS_GEMDEPS'] =
|
||||
ENV['RUBYGEMS_GEMDEPS'], 'gem.deps.rb'
|
||||
|
||||
e = assert_raises ArgumentError do
|
||||
Gem.use_gemdeps 'gem.deps.rb'
|
||||
end
|
||||
|
||||
assert_equal 'Unable to find gem dependencies file at gem.deps.rb',
|
||||
e.message
|
||||
ensure
|
||||
ENV['RUBYGEMS_GEMDEPS'] = rubygems_gemdeps
|
||||
end
|
||||
|
||||
def test_use_gemdeps_automatic
|
||||
skip 'Insecure operation - chdir' if RUBY_VERSION <= "1.8.7"
|
||||
rubygems_gemdeps, ENV['RUBYGEMS_GEMDEPS'] = ENV['RUBYGEMS_GEMDEPS'], '-'
|
||||
|
@ -1287,6 +1433,17 @@ class TestGem < Gem::TestCase
|
|||
ENV['RUBYGEMS_GEMDEPS'] = rubygems_gemdeps
|
||||
end
|
||||
|
||||
def test_use_gemdeps_automatic_missing
|
||||
skip 'Insecure operation - chdir' if RUBY_VERSION <= "1.8.7"
|
||||
rubygems_gemdeps, ENV['RUBYGEMS_GEMDEPS'] = ENV['RUBYGEMS_GEMDEPS'], '-'
|
||||
|
||||
Gem.use_gemdeps
|
||||
|
||||
assert true # count
|
||||
ensure
|
||||
ENV['RUBYGEMS_GEMDEPS'] = rubygems_gemdeps
|
||||
end
|
||||
|
||||
def test_use_gemdeps_disabled
|
||||
rubygems_gemdeps, ENV['RUBYGEMS_GEMDEPS'] = ENV['RUBYGEMS_GEMDEPS'], ''
|
||||
|
||||
|
@ -1294,7 +1451,7 @@ class TestGem < Gem::TestCase
|
|||
|
||||
refute spec.activated?
|
||||
|
||||
open 'Gemfile', 'w' do |io|
|
||||
open 'gem.deps.rb', 'w' do |io|
|
||||
io.write 'gem "a"'
|
||||
end
|
||||
|
||||
|
@ -1305,6 +1462,27 @@ class TestGem < Gem::TestCase
|
|||
ENV['RUBYGEMS_GEMDEPS'] = rubygems_gemdeps
|
||||
end
|
||||
|
||||
def test_use_gemdeps_missing_gem
|
||||
skip 'Insecure operation - read' if RUBY_VERSION <= "1.8.7"
|
||||
rubygems_gemdeps, ENV['RUBYGEMS_GEMDEPS'] = ENV['RUBYGEMS_GEMDEPS'], 'x'
|
||||
|
||||
open 'x', 'w' do |io|
|
||||
io.write 'gem "a"'
|
||||
end
|
||||
|
||||
expected = <<-EXPECTED
|
||||
Unable to resolve dependency: user requested 'a (>= 0)'
|
||||
You may need to `gem install -g` to install missing gems
|
||||
|
||||
EXPECTED
|
||||
|
||||
assert_output nil, expected do
|
||||
Gem.use_gemdeps
|
||||
end
|
||||
ensure
|
||||
ENV['RUBYGEMS_GEMDEPS'] = rubygems_gemdeps
|
||||
end
|
||||
|
||||
def test_use_gemdeps_specific
|
||||
skip 'Insecure operation - read' if RUBY_VERSION <= "1.8.7"
|
||||
rubygems_gemdeps, ENV['RUBYGEMS_GEMDEPS'] = ENV['RUBYGEMS_GEMDEPS'], 'x'
|
||||
|
|
|
@ -3,6 +3,7 @@ require 'rubygems/available_set'
|
|||
require 'rubygems/security'
|
||||
|
||||
class TestGemAvailableSet < Gem::TestCase
|
||||
|
||||
def setup
|
||||
super
|
||||
|
||||
|
@ -23,22 +24,24 @@ class TestGemAvailableSet < Gem::TestCase
|
|||
end
|
||||
|
||||
def test_find_all
|
||||
a1, a1_gem = util_gem 'a', 1
|
||||
a1, a1_gem = util_gem 'a', 1
|
||||
a1a, a1a_gem = util_gem 'a', '1.a'
|
||||
|
||||
source = Gem::Source::SpecificFile.new a1_gem
|
||||
a1_source = Gem::Source::SpecificFile.new a1_gem
|
||||
a1a_source = Gem::Source::SpecificFile.new a1a_gem
|
||||
|
||||
set = Gem::AvailableSet.new
|
||||
set.add a1, source
|
||||
set.add a1, a1_source
|
||||
set.add a1a, a1a_source
|
||||
|
||||
dep = Gem::Resolver::DependencyRequest.new dep('a'), nil
|
||||
|
||||
specs = set.find_all dep
|
||||
assert_equal %w[a-1], set.find_all(dep).map { |spec| spec.full_name }
|
||||
|
||||
spec = specs.first
|
||||
dep = Gem::Resolver::DependencyRequest.new dep('a', '>= 0.a'), nil
|
||||
|
||||
assert_kind_of Gem::Resolver::LocalSpecification, spec
|
||||
|
||||
assert_equal 'a-1', spec.full_name
|
||||
assert_equal %w[a-1 a-1.a],
|
||||
set.find_all(dep).map { |spec| spec.full_name }.sort
|
||||
end
|
||||
|
||||
def test_match_platform
|
||||
|
|
|
@ -184,5 +184,60 @@ class TestGemCommand < Gem::TestCase
|
|||
assert_equal ['-h', 'command'], args
|
||||
end
|
||||
|
||||
def test_show_lookup_failure_suggestions_local
|
||||
correct = "non_existent_with_hint"
|
||||
misspelled = "nonexistent_with_hint"
|
||||
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.spec correct, 2
|
||||
end
|
||||
|
||||
use_ui @ui do
|
||||
@cmd.show_lookup_failure misspelled, Gem::Requirement.default, [], :local
|
||||
end
|
||||
|
||||
expected = <<-EXPECTED
|
||||
ERROR: Could not find a valid gem 'nonexistent_with_hint' (>= 0) in any repository
|
||||
EXPECTED
|
||||
|
||||
assert_equal expected, @ui.error
|
||||
end
|
||||
|
||||
def test_show_lookup_failure_suggestions_none
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.spec 'correct', 2
|
||||
end
|
||||
|
||||
use_ui @ui do
|
||||
@cmd.show_lookup_failure 'other', Gem::Requirement.default, [], :remote
|
||||
end
|
||||
|
||||
expected = <<-EXPECTED
|
||||
ERROR: Could not find a valid gem 'other' (>= 0) in any repository
|
||||
EXPECTED
|
||||
|
||||
assert_equal expected, @ui.error
|
||||
end
|
||||
|
||||
def test_show_lookup_failure_suggestions_remote
|
||||
correct = "non_existent_with_hint"
|
||||
misspelled = "nonexistent_with_hint"
|
||||
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.spec correct, 2
|
||||
end
|
||||
|
||||
use_ui @ui do
|
||||
@cmd.show_lookup_failure misspelled, Gem::Requirement.default, [], :remote
|
||||
end
|
||||
|
||||
expected = <<-EXPECTED
|
||||
ERROR: Could not find a valid gem 'nonexistent_with_hint' (>= 0) in any repository
|
||||
ERROR: Possible alternatives: non_existent_with_hint
|
||||
EXPECTED
|
||||
|
||||
assert_equal expected, @ui.error
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -179,6 +179,7 @@ Added '/CN=alternate/DC=example'
|
|||
assert_empty @ui.error
|
||||
|
||||
assert_path_exists File.join(@tempdir, 'gem-public_cert.pem')
|
||||
refute_path_exists File.join(@tempdir, 'gem-private_key.pem')
|
||||
end
|
||||
|
||||
def test_execute_build_encrypted_key
|
||||
|
|
|
@ -9,8 +9,8 @@ class TestGemCommandsContentsCommand < Gem::TestCase
|
|||
@cmd = Gem::Commands::ContentsCommand.new
|
||||
end
|
||||
|
||||
def gem name
|
||||
spec = quick_gem name do |gem|
|
||||
def gem name, version = 2
|
||||
spec = quick_gem name, version do |gem|
|
||||
gem.files = %W[lib/#{name}.rb Rakefile]
|
||||
end
|
||||
write_file File.join(*%W[gems #{spec.full_name} lib #{name}.rb])
|
||||
|
@ -135,6 +135,40 @@ class TestGemCommandsContentsCommand < Gem::TestCase
|
|||
assert_equal "", @ui.error
|
||||
end
|
||||
|
||||
def test_execute_show_install_dir
|
||||
@cmd.options[:args] = %w[foo]
|
||||
@cmd.options[:show_install_dir] = true
|
||||
|
||||
gem 'foo'
|
||||
|
||||
use_ui @ui do
|
||||
@cmd.execute
|
||||
end
|
||||
|
||||
expected = File.join @gemhome, 'gems', 'foo-2'
|
||||
|
||||
assert_equal "#{expected}\n", @ui.output
|
||||
assert_equal "", @ui.error
|
||||
end
|
||||
|
||||
def test_execute_show_install_dir_version
|
||||
@cmd.options[:args] = %w[foo]
|
||||
@cmd.options[:show_install_dir] = true
|
||||
@cmd.options[:version] = Gem::Requirement.new '= 1'
|
||||
|
||||
gem 'foo', 1
|
||||
gem 'foo', 2
|
||||
|
||||
use_ui @ui do
|
||||
@cmd.execute
|
||||
end
|
||||
|
||||
expected = File.join @gemhome, 'gems', 'foo-1'
|
||||
|
||||
assert_equal "#{expected}\n", @ui.output
|
||||
assert_equal "", @ui.error
|
||||
end
|
||||
|
||||
def test_execute_no_prefix
|
||||
@cmd.options[:args] = %w[foo]
|
||||
@cmd.options[:prefix] = false
|
||||
|
@ -183,13 +217,22 @@ lib/foo.rb
|
|||
assert @cmd.options[:prefix]
|
||||
assert_empty @cmd.options[:specdirs]
|
||||
assert_nil @cmd.options[:version]
|
||||
refute @cmd.options[:show_install_dir]
|
||||
|
||||
@cmd.send :handle_options, %w[-l -s foo --version 0.0.2 --no-prefix]
|
||||
@cmd.send :handle_options, %w[
|
||||
-l
|
||||
-s
|
||||
foo
|
||||
--version 0.0.2
|
||||
--no-prefix
|
||||
--show-install-dir
|
||||
]
|
||||
|
||||
assert @cmd.options[:lib_only]
|
||||
refute @cmd.options[:prefix]
|
||||
assert_equal %w[foo], @cmd.options[:specdirs]
|
||||
assert_equal Gem::Requirement.new('0.0.2'), @cmd.options[:version]
|
||||
assert @cmd.options[:show_install_dir]
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -28,6 +28,7 @@ class TestGemCommandsEnvironmentCommand < Gem::TestCase
|
|||
assert_match %r|RUBYGEMS PREFIX: |, @ui.output
|
||||
assert_match %r|RUBY EXECUTABLE:.*#{RbConfig::CONFIG['ruby_install_name']}|,
|
||||
@ui.output
|
||||
assert_match %r|SYSTEM CONFIGURATION DIRECTORY:|, @ui.output
|
||||
assert_match %r|EXECUTABLE DIRECTORY:|, @ui.output
|
||||
assert_match %r|RUBYGEMS PLATFORMS:|, @ui.output
|
||||
assert_match %r|- #{Gem::Platform.local}|, @ui.output
|
||||
|
|
|
@ -22,6 +22,13 @@ class TestGemCommandsHelpCommand < Gem::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
def test_gem_help_gem_dependencies
|
||||
util_gem 'gem_dependencies' do |out, err|
|
||||
assert_match 'gem.deps.rb', out
|
||||
assert_equal '', err
|
||||
end
|
||||
end
|
||||
|
||||
def test_gem_help_platforms
|
||||
util_gem 'platforms' do |out, err|
|
||||
assert_match(/x86-freebsd/, out)
|
||||
|
|
|
@ -24,6 +24,7 @@ class TestGemCommandsInstallCommand < Gem::TestCase
|
|||
|
||||
Gem::Command.build_args = @orig_args
|
||||
File.unlink @gemdeps if File.file? @gemdeps
|
||||
File.unlink "#{@gemdeps}.lock" if File.file? "#{@gemdeps}.lock"
|
||||
end
|
||||
|
||||
def test_execute_exclude_prerelease
|
||||
|
@ -194,6 +195,32 @@ class TestGemCommandsInstallCommand < Gem::TestCase
|
|||
assert_match(%r!Unable to download data from http://not-there.nothing!, errs.shift)
|
||||
end
|
||||
|
||||
def test_execute_nonexistent_hint_disabled
|
||||
misspelled = "nonexistent_with_hint"
|
||||
correctly_spelled = "non_existent_with_hint"
|
||||
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.spec correctly_spelled, 2
|
||||
end
|
||||
|
||||
@cmd.options[:args] = [misspelled]
|
||||
@cmd.options[:suggest_alternate] = false
|
||||
|
||||
use_ui @ui do
|
||||
e = assert_raises Gem::MockGemUi::TermError do
|
||||
@cmd.execute
|
||||
end
|
||||
|
||||
assert_equal 2, e.exit_code
|
||||
end
|
||||
|
||||
expected = <<-EXPECTED
|
||||
ERROR: Could not find a valid gem 'nonexistent_with_hint' (>= 0) in any repository
|
||||
EXPECTED
|
||||
|
||||
assert_equal expected, @ui.error
|
||||
end
|
||||
|
||||
def test_execute_nonexistent_with_hint
|
||||
misspelled = "nonexistent_with_hint"
|
||||
correctly_spelled = "non_existent_with_hint"
|
||||
|
@ -238,7 +265,10 @@ ERROR: Possible alternatives: non_existent_with_hint
|
|||
assert_equal 2, e.exit_code
|
||||
end
|
||||
|
||||
expected = ["ERROR: Could not find a valid gem 'non-existent_with-hint' (>= 0) in any repository", "ERROR: Possible alternatives: nonexistent-with_hint"]
|
||||
expected = [
|
||||
"ERROR: Could not find a valid gem 'non-existent_with-hint' (>= 0) in any repository",
|
||||
"ERROR: Possible alternatives: nonexistent-with_hint"
|
||||
]
|
||||
|
||||
output = @ui.error.split "\n"
|
||||
|
||||
|
@ -535,6 +565,11 @@ ERROR: Possible alternatives: non_existent_with_hint
|
|||
end
|
||||
|
||||
def test_install_gem_ignore_dependencies_both
|
||||
done_installing = false
|
||||
Gem.done_installing do
|
||||
done_installing = true
|
||||
end
|
||||
|
||||
spec = quick_spec 'a', 2
|
||||
|
||||
util_build_gem spec
|
||||
|
@ -546,6 +581,8 @@ ERROR: Possible alternatives: non_existent_with_hint
|
|||
@cmd.install_gem 'a', '>= 0'
|
||||
|
||||
assert_equal %w[a-2], @cmd.installed_specs.map { |s| s.full_name }
|
||||
|
||||
assert done_installing, 'documentation was not generated'
|
||||
end
|
||||
|
||||
def test_install_gem_ignore_dependencies_remote
|
||||
|
@ -622,8 +659,8 @@ ERROR: Possible alternatives: non_existent_with_hint
|
|||
end
|
||||
|
||||
assert_equal 2, e.exit_code
|
||||
assert_match %r!Could not find a valid gem 'blah' \(>= 0\)!, @ui.error
|
||||
assert_match %r!Unable to download data from http://not-there\.nothing!, @ui.error
|
||||
|
||||
assert_match 'Unable to download data', @ui.error
|
||||
end
|
||||
|
||||
def test_show_source_problems_even_on_success
|
||||
|
@ -648,7 +685,7 @@ ERROR: Possible alternatives: non_existent_with_hint
|
|||
|
||||
e = @ui.error
|
||||
|
||||
x = "WARNING: Unable to pull data from 'http://nonexistent.example': no data for http://nonexistent.example/latest_specs.4.8.gz (http://nonexistent.example/latest_specs.4.8.gz)\n"
|
||||
x = "WARNING: Unable to pull data from 'http://nonexistent.example': no data for http://nonexistent.example/specs.4.8.gz (http://nonexistent.example/specs.4.8.gz)\n"
|
||||
assert_equal x, e
|
||||
end
|
||||
|
||||
|
@ -672,6 +709,56 @@ ERROR: Possible alternatives: non_existent_with_hint
|
|||
assert_equal %w[], @cmd.installed_specs.map { |spec| spec.full_name }
|
||||
|
||||
assert_match "Using a (2)", @ui.output
|
||||
assert File.exist?("#{@gemdeps}.lock")
|
||||
end
|
||||
|
||||
def test_execute_uses_from_a_gemdeps_with_no_lock
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'a', 2
|
||||
end
|
||||
|
||||
File.open @gemdeps, "w" do |f|
|
||||
f << "gem 'a'"
|
||||
end
|
||||
|
||||
@cmd.handle_options %w[--no-lock]
|
||||
@cmd.options[:gemdeps] = @gemdeps
|
||||
|
||||
use_ui @ui do
|
||||
assert_raises Gem::MockGemUi::SystemExitException, @ui.error do
|
||||
@cmd.execute
|
||||
end
|
||||
end
|
||||
|
||||
assert_equal %w[], @cmd.installed_specs.map { |spec| spec.full_name }
|
||||
|
||||
assert_match "Using a (2)", @ui.output
|
||||
assert !File.exist?("#{@gemdeps}.lock")
|
||||
end
|
||||
|
||||
def test_execute_installs_from_a_gemdeps_with_conservative
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'a', 2
|
||||
fetcher.clear
|
||||
fetcher.gem 'a', 1
|
||||
end
|
||||
|
||||
File.open @gemdeps, "w" do |f|
|
||||
f << "gem 'a'"
|
||||
end
|
||||
|
||||
@cmd.handle_options %w[--conservative]
|
||||
@cmd.options[:gemdeps] = @gemdeps
|
||||
|
||||
use_ui @ui do
|
||||
assert_raises Gem::MockGemUi::SystemExitException, @ui.error do
|
||||
@cmd.execute
|
||||
end
|
||||
end
|
||||
|
||||
assert_equal %w[], @cmd.installed_specs.map { |spec| spec.full_name }
|
||||
|
||||
assert_match "Using a (1)", @ui.output
|
||||
end
|
||||
|
||||
def test_execute_installs_from_a_gemdeps
|
||||
|
@ -885,6 +972,18 @@ ERROR: Possible alternatives: non_existent_with_hint
|
|||
assert_equal 'gem.deps.rb', @cmd.options[:gemdeps]
|
||||
end
|
||||
|
||||
def test_handle_options_suggest
|
||||
assert @cmd.options[:suggest_alternate]
|
||||
|
||||
@cmd.handle_options %w[--no-suggestions]
|
||||
|
||||
refute @cmd.options[:suggest_alternate]
|
||||
|
||||
@cmd.handle_options %w[--suggestions]
|
||||
|
||||
assert @cmd.options[:suggest_alternate]
|
||||
end
|
||||
|
||||
def test_handle_options_without
|
||||
@cmd.handle_options %w[--without test]
|
||||
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
require 'rubygems/test_case'
|
||||
require 'rubygems/commands/open_command'
|
||||
|
||||
class TestGemCommandsOpenCommand < Gem::TestCase
|
||||
|
||||
def setup
|
||||
super
|
||||
|
||||
@cmd = Gem::Commands::OpenCommand.new
|
||||
end
|
||||
|
||||
def gem name
|
||||
spec = quick_gem name do |gem|
|
||||
gem.files = %W[lib/#{name}.rb Rakefile]
|
||||
end
|
||||
write_file File.join(*%W[gems #{spec.full_name} lib #{name}.rb])
|
||||
write_file File.join(*%W[gems #{spec.full_name} Rakefile])
|
||||
end
|
||||
|
||||
def test_execute
|
||||
@cmd.options[:args] = %w[foo]
|
||||
@cmd.options[:editor] = "#{Gem.ruby} -e0 --"
|
||||
|
||||
gem 'foo'
|
||||
|
||||
use_ui @ui do
|
||||
@cmd.execute
|
||||
end
|
||||
|
||||
assert_equal "", @ui.error
|
||||
end
|
||||
|
||||
def test_execute_bad_gem
|
||||
@cmd.options[:args] = %w[foo]
|
||||
|
||||
assert_raises Gem::MockGemUi::TermError do
|
||||
use_ui @ui do
|
||||
@cmd.execute
|
||||
end
|
||||
end
|
||||
|
||||
assert_match %r|Unable to find gem 'foo'|, @ui.output
|
||||
assert_equal "", @ui.error
|
||||
end
|
||||
|
||||
end
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче