mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* lib/rubygems: Update to RubyGems HEAD(c202db2).
this version contains many enhancements see http://git.io/vtNwF * test/rubygems: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51092 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
9c4ef4b191
commit
effdbf5936
90 changed files with 2489 additions and 1159 deletions
|
@ -1,3 +1,9 @@
|
|||
Thu Jul 2 06:49:44 2015 SHIBATA Hiroshi <hsbt@ruby-lang.org>
|
||||
|
||||
* lib/rubygems: Update to RubyGems HEAD(c202db2).
|
||||
this version contains many enhancements see http://git.io/vtNwF
|
||||
* test/rubygems: ditto.
|
||||
|
||||
Wed Jul 1 23:50:34 2015 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
|
||||
|
||||
* test/net/http/test_httpresponse.rb
|
||||
|
|
|
@ -9,7 +9,7 @@ require 'rbconfig'
|
|||
require 'thread'
|
||||
|
||||
module Gem
|
||||
VERSION = '2.4.8'
|
||||
VERSION = '2.5.0'
|
||||
end
|
||||
|
||||
# Must be first since it unloads the prelude from 1.9.2
|
||||
|
@ -26,12 +26,12 @@ require 'rubygems/errors'
|
|||
# For user documentation, see:
|
||||
#
|
||||
# * <tt>gem help</tt> and <tt>gem help [command]</tt>
|
||||
# * {RubyGems User Guide}[http://docs.rubygems.org/read/book/1]
|
||||
# * {Frequently Asked Questions}[http://docs.rubygems.org/read/book/3]
|
||||
# * {RubyGems User Guide}[http://guides.rubygems.org/]
|
||||
# * {Frequently Asked Questions}[http://guides.rubygems.org/faqs]
|
||||
#
|
||||
# For gem developer documentation see:
|
||||
#
|
||||
# * {Creating Gems}[http://docs.rubygems.org/read/chapter/5]
|
||||
# * {Creating Gems}[http://guides.rubygems.org/make-your-own-gem]
|
||||
# * Gem::Specification
|
||||
# * Gem::Version for version dependency notes
|
||||
#
|
||||
|
@ -156,6 +156,7 @@ module Gem
|
|||
@@win_platform = nil
|
||||
|
||||
@configuration = nil
|
||||
@gemdeps = nil
|
||||
@loaded_specs = {}
|
||||
LOADED_SPECS_MUTEX = Mutex.new
|
||||
@path_to_default_spec_map = {}
|
||||
|
@ -184,13 +185,9 @@ module Gem
|
|||
# or if it was ambiguous (and thus unresolved) the code in our custom
|
||||
# require will try to activate the more specific version.
|
||||
|
||||
spec = Gem::Specification.find_inactive_by_path path
|
||||
|
||||
unless spec
|
||||
spec = Gem::Specification.find_by_path path
|
||||
return true if spec && spec.activated?
|
||||
return false
|
||||
end
|
||||
spec = Gem::Specification.find_by_path path
|
||||
return false unless spec
|
||||
return true if spec.activated?
|
||||
|
||||
begin
|
||||
spec.activate
|
||||
|
@ -433,7 +430,7 @@ module Gem
|
|||
|
||||
files = find_files_from_load_path glob if check_load_path
|
||||
|
||||
files.concat Gem::Specification.map { |spec|
|
||||
files.concat Gem::Specification.stubs.map { |spec|
|
||||
spec.matches_for_glob("#{glob}#{Gem.suffix_pattern}")
|
||||
}.flatten
|
||||
|
||||
|
@ -598,7 +595,7 @@ module Gem
|
|||
|
||||
unless test_syck
|
||||
begin
|
||||
gem 'psych', '~> 1.2', '>= 1.2.1'
|
||||
gem 'psych', '>= 1.2.1'
|
||||
rescue Gem::LoadError
|
||||
# It's OK if the user does not have the psych gem installed. We will
|
||||
# attempt to require the stdlib version
|
||||
|
@ -1052,7 +1049,7 @@ module Gem
|
|||
end
|
||||
|
||||
rs = Gem::RequestSet.new
|
||||
rs.load_gemdeps path
|
||||
@gemdeps = rs.load_gemdeps path
|
||||
|
||||
rs.resolve_current.map do |s|
|
||||
sp = s.full_spec
|
||||
|
@ -1082,6 +1079,12 @@ module Gem
|
|||
|
||||
attr_reader :loaded_specs
|
||||
|
||||
##
|
||||
# GemDependencyAPI object, which is set when .use_gemdeps is called.
|
||||
# This contains all the information from the Gemfile.
|
||||
|
||||
attr_reader :gemdeps
|
||||
|
||||
##
|
||||
# Register a Gem::Specification for default gem.
|
||||
#
|
||||
|
|
|
@ -22,13 +22,17 @@ class Gem::BasicSpecification
|
|||
##
|
||||
# The path this gemspec was loaded from. This attribute is not persisted.
|
||||
|
||||
attr_reader :loaded_from
|
||||
attr_accessor :loaded_from
|
||||
|
||||
##
|
||||
# Allows correct activation of git: and path: gems.
|
||||
|
||||
attr_writer :full_gem_path # :nodoc:
|
||||
|
||||
def initialize
|
||||
internal_init
|
||||
end
|
||||
|
||||
def self.default_specifications_dir
|
||||
File.join(Gem.default_dir, "specifications", "default")
|
||||
end
|
||||
|
@ -141,7 +145,7 @@ class Gem::BasicSpecification
|
|||
@full_require_paths ||=
|
||||
begin
|
||||
full_paths = raw_require_paths.map do |path|
|
||||
File.join full_gem_path, path
|
||||
File.join full_gem_path, path.untaint
|
||||
end
|
||||
|
||||
full_paths << extension_dir unless @extensions.nil? || @extensions.empty?
|
||||
|
@ -189,13 +193,7 @@ class Gem::BasicSpecification
|
|||
@gems_dir ||= File.join(loaded_from && base_dir || Gem.dir, "gems")
|
||||
end
|
||||
|
||||
##
|
||||
# Set the path the Specification was loaded from. +path+ is converted to a
|
||||
# String.
|
||||
|
||||
def loaded_from= path
|
||||
@loaded_from = path && path.to_s
|
||||
|
||||
def internal_init # :nodoc:
|
||||
@extension_dir = nil
|
||||
@extensions_dir = nil
|
||||
@full_gem_path = nil
|
||||
|
@ -263,6 +261,30 @@ class Gem::BasicSpecification
|
|||
paths.uniq
|
||||
end
|
||||
|
||||
##
|
||||
# Return all files in this gem that match for +glob+.
|
||||
|
||||
def matches_for_glob glob # TODO: rename?
|
||||
# TODO: do we need these?? Kill it
|
||||
glob = File.join(self.lib_dirs_glob, glob)
|
||||
|
||||
Dir[glob].map { |f| f.untaint } # FIX our tests are broken, run w/ SAFE=1
|
||||
end
|
||||
|
||||
##
|
||||
# Returns a string usable in Dir.glob to match all requirable paths
|
||||
# for this spec.
|
||||
|
||||
def lib_dirs_glob
|
||||
dirs = if self.require_paths.size > 1 then
|
||||
"{#{self.require_paths.join(',')}}"
|
||||
else
|
||||
self.require_paths.first
|
||||
end
|
||||
|
||||
"#{self.full_gem_path}/#{dirs}"
|
||||
end
|
||||
|
||||
##
|
||||
# Return a Gem::Specification from this gem
|
||||
|
||||
|
|
|
@ -61,10 +61,16 @@ use with other commands.
|
|||
ss.map { |spec, _| spec }
|
||||
end
|
||||
|
||||
def fetch_specs dependency # :nodoc:
|
||||
def fetch_specs name_pattern, dependency # :nodoc:
|
||||
specs = []
|
||||
|
||||
specs.concat dependency.matching_specs if local?
|
||||
if local?
|
||||
specs.concat Gem::Specification.stubs.find_all { |spec|
|
||||
name_pattern =~ spec.name and
|
||||
dependency.requirement.satisfied_by? spec.version
|
||||
}.map(&:to_spec)
|
||||
end
|
||||
|
||||
specs.concat fetch_remote_specs dependency if remote?
|
||||
|
||||
ensure_specs specs
|
||||
|
@ -72,16 +78,7 @@ use with other commands.
|
|||
specs.uniq.sort
|
||||
end
|
||||
|
||||
def gem_dependency args, version, prerelease # :nodoc:
|
||||
args << '' if args.empty?
|
||||
|
||||
pattern = if args.length == 1 and args.first =~ /\A\/(.*)\/(i)?\z/m then
|
||||
flags = $2 ? Regexp::IGNORECASE : nil
|
||||
Regexp.new $1, flags
|
||||
else
|
||||
/\A#{Regexp.union(*args)}/
|
||||
end
|
||||
|
||||
def gem_dependency pattern, version, prerelease # :nodoc:
|
||||
dependency = Gem::Deprecate.skip_during {
|
||||
Gem::Dependency.new pattern, version
|
||||
}
|
||||
|
@ -121,10 +118,12 @@ use with other commands.
|
|||
def execute
|
||||
ensure_local_only_reverse_dependencies
|
||||
|
||||
dependency =
|
||||
gem_dependency options[:args], options[:version], options[:prerelease]
|
||||
pattern = name_pattern options[:args]
|
||||
|
||||
specs = fetch_specs dependency
|
||||
dependency =
|
||||
gem_dependency pattern, options[:version], options[:prerelease]
|
||||
|
||||
specs = fetch_specs pattern, dependency
|
||||
|
||||
reverse = reverse_dependencies specs
|
||||
|
||||
|
@ -203,5 +202,16 @@ use with other commands.
|
|||
result
|
||||
end
|
||||
|
||||
end
|
||||
private
|
||||
|
||||
def name_pattern args
|
||||
args << '' if args.empty?
|
||||
|
||||
if args.length == 1 and args.first =~ /\A\/(.*)\/(i)?\z/m then
|
||||
flags = $2 ? Regexp::IGNORECASE : nil
|
||||
Regexp.new $1, flags
|
||||
else
|
||||
/\A#{Regexp.union(*args)}/
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -275,7 +275,7 @@ to write the specification by hand. For example:
|
|||
gem = fetcher.download_to_cache dependency
|
||||
end
|
||||
|
||||
inst = Gem::Installer.new gem, options
|
||||
inst = Gem::Installer.at gem, options
|
||||
inst.install
|
||||
|
||||
require 'rubygems/dependency_installer'
|
||||
|
|
|
@ -33,7 +33,7 @@ To search for remote gems use the search command.
|
|||
end
|
||||
|
||||
def usage # :nodoc:
|
||||
"#{program_name} [STRING ...]"
|
||||
"#{program_name} [REGEXP ...]"
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -156,7 +156,7 @@ extensions will be restored.
|
|||
install_defaults.to_s['--env-shebang']
|
||||
end
|
||||
|
||||
installer = Gem::Installer.new(gem,
|
||||
installer = Gem::Installer.at(gem,
|
||||
:wrappers => true,
|
||||
:force => true,
|
||||
:install_dir => spec.base_dir,
|
||||
|
|
|
@ -227,7 +227,7 @@ is too hard to use.
|
|||
|
||||
name_tuple, spec = detail_tuple
|
||||
|
||||
spec = spec.fetch_spec name_tuple unless Gem::Specification === spec
|
||||
spec = spec.fetch_spec name_tuple if spec.respond_to? :fetch_spec
|
||||
|
||||
entry << "\n"
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ module Kernel
|
|||
|
||||
begin
|
||||
RUBYGEMS_ACTIVATION_MONITOR.exit
|
||||
return gem_original_require(spec.to_fullpath(path) || path)
|
||||
return gem_original_require(path)
|
||||
end if spec
|
||||
|
||||
# Attempt to find +path+ in any unresolved gems...
|
||||
|
@ -105,7 +105,7 @@ module Kernel
|
|||
|
||||
# Ok, now find a gem that has no conflicts, starting
|
||||
# at the highest version.
|
||||
valid = found_specs.select { |s| s.conflicts.empty? }.last
|
||||
valid = found_specs.reject { |s| s.has_conflicts? }.last
|
||||
|
||||
unless valid then
|
||||
le = Gem::LoadError.new "unable to find a version of '#{names.first}' to activate"
|
||||
|
|
|
@ -164,6 +164,10 @@ class Gem::Dependency
|
|||
@type ||= :runtime
|
||||
end
|
||||
|
||||
def runtime?
|
||||
@type == :runtime || !@type
|
||||
end
|
||||
|
||||
def == other # :nodoc:
|
||||
Gem::Dependency === other &&
|
||||
self.name == other.name &&
|
||||
|
@ -270,9 +274,8 @@ class Gem::Dependency
|
|||
end
|
||||
|
||||
def matching_specs platform_only = false
|
||||
matches = Gem::Specification.stubs.find_all { |spec|
|
||||
self.name === spec.name and # TODO: == instead of ===
|
||||
requirement.satisfied_by? spec.version
|
||||
matches = Gem::Specification.stubs_for(name).find_all { |spec|
|
||||
requirement.satisfied_by? spec.version
|
||||
}.map(&:to_spec)
|
||||
|
||||
if platform_only
|
||||
|
|
|
@ -141,6 +141,9 @@ class Gem::DependencyList
|
|||
def ok_to_remove?(full_name, check_dev=true)
|
||||
gem_to_remove = find_name full_name
|
||||
|
||||
# If the state is inconsistent, at least don't crash
|
||||
return true unless gem_to_remove
|
||||
|
||||
siblings = @specs.find_all { |s|
|
||||
s.name == gem_to_remove.name &&
|
||||
s.full_name != gem_to_remove.full_name
|
||||
|
|
|
@ -66,9 +66,11 @@ class Gem::Ext::Builder
|
|||
# TODO use Process.spawn when ruby 1.8 support is dropped.
|
||||
rubygems_gemdeps, ENV['RUBYGEMS_GEMDEPS'] = ENV['RUBYGEMS_GEMDEPS'], nil
|
||||
if verbose
|
||||
puts("current directory: #{Dir.pwd}")
|
||||
puts(command)
|
||||
system(command)
|
||||
else
|
||||
results << "current directory: #{Dir.pwd}"
|
||||
results << command
|
||||
results << `#{command} #{redirector}`
|
||||
end
|
||||
|
|
|
@ -35,7 +35,12 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder
|
|||
begin
|
||||
run cmd, results
|
||||
ensure
|
||||
FileUtils.mv 'mkmf.log', dest_path if File.exist? 'mkmf.log'
|
||||
if File.exist? 'mkmf.log'
|
||||
results << "To see why this extension failed to compile, please check" \
|
||||
" the mkmf.log which can be found here:\n"
|
||||
results << " " + File.join(dest_path, 'mkmf.log') + "\n"
|
||||
FileUtils.mv 'mkmf.log', dest_path
|
||||
end
|
||||
siteconf.unlink
|
||||
end
|
||||
|
||||
|
|
|
@ -96,11 +96,10 @@ class Gem::Indexer
|
|||
# Build various indices
|
||||
|
||||
def build_indices
|
||||
Gem::Specification.dirs = []
|
||||
Gem::Specification.add_specs(*map_gems_to_specs(gem_file_list))
|
||||
|
||||
build_marshal_gemspecs
|
||||
build_modern_indices if @build_modern
|
||||
specs = map_gems_to_specs gem_file_list
|
||||
Gem::Specification._resort! specs
|
||||
build_marshal_gemspecs specs
|
||||
build_modern_indices specs if @build_modern
|
||||
|
||||
compress_indices
|
||||
end
|
||||
|
@ -108,8 +107,8 @@ class Gem::Indexer
|
|||
##
|
||||
# Builds Marshal quick index gemspecs.
|
||||
|
||||
def build_marshal_gemspecs
|
||||
count = Gem::Specification.count { |s| not s.default_gem? }
|
||||
def build_marshal_gemspecs specs
|
||||
count = specs.count
|
||||
progress = ui.progress_reporter count,
|
||||
"Generating Marshal quick index gemspecs for #{count} gems",
|
||||
"Complete"
|
||||
|
@ -117,7 +116,7 @@ class Gem::Indexer
|
|||
files = []
|
||||
|
||||
Gem.time 'Generated Marshal quick index gemspecs' do
|
||||
Gem::Specification.each do |spec|
|
||||
specs.each do |spec|
|
||||
next if spec.default_gem?
|
||||
spec_file_name = "#{spec.original_name}.gemspec.rz"
|
||||
marshal_name = File.join @quick_marshal_dir, spec_file_name
|
||||
|
@ -171,14 +170,12 @@ class Gem::Indexer
|
|||
##
|
||||
# Builds indices for RubyGems 1.2 and newer. Handles full, latest, prerelease
|
||||
|
||||
def build_modern_indices
|
||||
specs = Gem::Specification.reject { |s| s.default_gem? }
|
||||
|
||||
def build_modern_indices specs
|
||||
prerelease, released = specs.partition { |s|
|
||||
s.version.prerelease?
|
||||
}
|
||||
latest_specs =
|
||||
Gem::Specification.latest_specs.reject { |s| s.default_gem? }
|
||||
Gem::Specification._latest_specs specs
|
||||
|
||||
build_modern_index(released.sort, @specs_index, 'specs')
|
||||
build_modern_index(latest_specs.sort, @latest_specs_index, 'latest specs')
|
||||
|
@ -376,10 +373,7 @@ class Gem::Indexer
|
|||
specs = map_gems_to_specs updated_gems
|
||||
prerelease, released = specs.partition { |s| s.version.prerelease? }
|
||||
|
||||
Gem::Specification.dirs = []
|
||||
Gem::Specification.add_specs(*specs)
|
||||
|
||||
files = build_marshal_gemspecs
|
||||
files = build_marshal_gemspecs specs
|
||||
|
||||
Gem.time 'Updated indexes' do
|
||||
update_specs_index released, @dest_specs_index, @specs_index
|
||||
|
|
|
@ -61,11 +61,6 @@ class Gem::Installer
|
|||
|
||||
attr_reader :options
|
||||
|
||||
##
|
||||
# Sets the specification for .gem-less installs.
|
||||
|
||||
attr_writer :spec
|
||||
|
||||
@path_warning = false
|
||||
|
||||
@install_lock = Mutex.new
|
||||
|
@ -99,6 +94,46 @@ class Gem::Installer
|
|||
|
||||
end
|
||||
|
||||
##
|
||||
# Construct an installer object for the gem file located at +path+
|
||||
|
||||
def self.at path, options = {}
|
||||
security_policy = options[:security_policy]
|
||||
package = Gem::Package.new path, security_policy
|
||||
new package, options
|
||||
end
|
||||
|
||||
class FakePackage
|
||||
attr_accessor :spec
|
||||
|
||||
def initialize(spec)
|
||||
@spec = spec
|
||||
end
|
||||
|
||||
def extract_files destination_dir, pattern = '*'
|
||||
FileUtils.mkdir_p destination_dir
|
||||
|
||||
spec.files.each do |file|
|
||||
file = File.join destination_dir, file
|
||||
next if File.exist? file
|
||||
FileUtils.mkdir_p File.dirname(file)
|
||||
File.open file, 'w' do |fp| fp.puts "# #{file}" end
|
||||
end
|
||||
end
|
||||
|
||||
def copy_to path
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Construct an installer object for an ephemeral gem (one where we don't
|
||||
# actually have a .gem file, just a spec)
|
||||
|
||||
def self.for_spec spec, options = {}
|
||||
# FIXME: we should have a real Package class for this
|
||||
new FakePackage.new(spec), options
|
||||
end
|
||||
|
||||
##
|
||||
# Constructs an Installer instance that will install the gem located at
|
||||
# +gem+. +options+ is a Hash with the following keys:
|
||||
|
@ -122,17 +157,22 @@ class Gem::Installer
|
|||
# :build_args:: An Array of arguments to pass to the extension builder
|
||||
# process. If not set, then Gem::Command.build_args is used
|
||||
|
||||
def initialize(gem, options={})
|
||||
def initialize(package, options={})
|
||||
require 'fileutils'
|
||||
|
||||
@gem = gem
|
||||
@options = options
|
||||
@package = Gem::Package.new @gem
|
||||
if package.is_a? String
|
||||
security_policy = options[:security_policy]
|
||||
@package = Gem::Package.new package, security_policy
|
||||
if $VERBOSE
|
||||
warn "constructing an Installer object with a string is deprecated. Please use Gem::Installer.at (called from: #{caller.first})"
|
||||
end
|
||||
else
|
||||
@package = package
|
||||
end
|
||||
|
||||
process_options
|
||||
|
||||
@package.security_policy = @security_policy
|
||||
|
||||
if options[:user_install] and not options[:unpack] then
|
||||
@gem_home = Gem.user_dir
|
||||
@bin_dir = Gem.bindir gem_home unless options[:bin_dir]
|
||||
|
@ -211,7 +251,7 @@ class Gem::Installer
|
|||
# Lazy accessor for the installer's spec.
|
||||
|
||||
def spec
|
||||
@spec ||= @package.spec
|
||||
@package.spec
|
||||
rescue Gem::Package::Error => e
|
||||
raise Gem::InstallError, "invalid gem: #{e.message}"
|
||||
end
|
||||
|
@ -230,7 +270,7 @@ class Gem::Installer
|
|||
def install
|
||||
pre_install_checks
|
||||
|
||||
FileUtils.rm_f File.join gem_home, 'specifications', @spec.spec_name
|
||||
FileUtils.rm_f File.join gem_home, 'specifications', spec.spec_name
|
||||
|
||||
run_pre_install_hooks
|
||||
|
||||
|
@ -239,12 +279,12 @@ class Gem::Installer
|
|||
|
||||
FileUtils.mkdir_p gem_dir
|
||||
|
||||
spec.loaded_from = spec_file
|
||||
|
||||
if @options[:install_as_default]
|
||||
spec.loaded_from = default_spec_file
|
||||
extract_bin
|
||||
write_default_spec
|
||||
else
|
||||
spec.loaded_from = spec_file
|
||||
extract_files
|
||||
|
||||
build_extensions
|
||||
|
@ -258,7 +298,7 @@ class Gem::Installer
|
|||
|
||||
say spec.post_install_message unless spec.post_install_message.nil?
|
||||
|
||||
Gem::Installer.install_lock.synchronize { Gem::Specification.add_spec spec }
|
||||
Gem::Installer.install_lock.synchronize { Gem::Specification.reset }
|
||||
|
||||
run_post_install_hooks
|
||||
|
||||
|
@ -363,7 +403,7 @@ class Gem::Installer
|
|||
#
|
||||
|
||||
def default_spec_file
|
||||
File.join gem_home, "specifications/default", "#{spec.full_name}.gemspec"
|
||||
File.join Gem::Specification.default_specifications_dir, "#{spec.full_name}.gemspec"
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -595,7 +635,6 @@ class Gem::Installer
|
|||
@gem_home = options[:install_dir] || Gem.dir
|
||||
@ignore_dependencies = options[:ignore_dependencies]
|
||||
@format_executable = options[:format_executable]
|
||||
@security_policy = options[:security_policy]
|
||||
@wrappers = options[:wrappers]
|
||||
@only_install_dir = options[:only_install_dir]
|
||||
|
||||
|
@ -661,7 +700,7 @@ class Gem::Installer
|
|||
|
||||
require 'rubygems'
|
||||
|
||||
version = "#{Gem::Requirement.default}"
|
||||
version = "#{Gem::Requirement.default}.a"
|
||||
|
||||
if ARGV.first
|
||||
str = ARGV.first
|
||||
|
@ -764,11 +803,6 @@ TEXT
|
|||
def pre_install_checks
|
||||
verify_gem_home options[:unpack]
|
||||
|
||||
# If we're forcing the install then disable security unless the security
|
||||
# policy says that we only install signed gems.
|
||||
@security_policy = nil if
|
||||
@force and @security_policy and not @security_policy.only_signed
|
||||
|
||||
ensure_loadable_spec
|
||||
|
||||
if options[:install_as_default]
|
||||
|
@ -811,9 +845,7 @@ TEXT
|
|||
|
||||
def write_cache_file
|
||||
cache_file = File.join gem_home, 'cache', spec.file_name
|
||||
|
||||
FileUtils.cp @gem, cache_file unless File.exist? cache_file
|
||||
@package.copy_to cache_file
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -176,7 +176,7 @@ class Gem::InstallerTestCase < Gem::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
@installer = Gem::Installer.new @gem
|
||||
@installer = Gem::Installer.at @gem
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -184,7 +184,7 @@ class Gem::InstallerTestCase < Gem::TestCase
|
|||
# +user+ is true a user-install will be performed.
|
||||
|
||||
def util_installer(spec, gem_home, user=false)
|
||||
Gem::Installer.new(spec.cache_file,
|
||||
Gem::Installer.at(spec.cache_file,
|
||||
:install_dir => gem_home,
|
||||
:user_install => user)
|
||||
end
|
||||
|
|
|
@ -123,7 +123,7 @@ class Gem::Package
|
|||
# If +gem+ is an existing file in the old format a Gem::Package::Old will be
|
||||
# returned.
|
||||
|
||||
def self.new gem
|
||||
def self.new gem, security_policy = nil
|
||||
gem = if gem.is_a?(Gem::Package::Source)
|
||||
gem
|
||||
elsif gem.respond_to? :read
|
||||
|
@ -132,7 +132,7 @@ class Gem::Package
|
|||
Gem::Package::FileSource.new gem
|
||||
end
|
||||
|
||||
return super(gem) unless Gem::Package == self
|
||||
return super unless Gem::Package == self
|
||||
return super unless gem.present?
|
||||
|
||||
return super unless gem.start
|
||||
|
@ -144,7 +144,7 @@ class Gem::Package
|
|||
##
|
||||
# Creates a new package that will read or write to the file +gem+.
|
||||
|
||||
def initialize gem # :notnew:
|
||||
def initialize gem, security_policy # :notnew:
|
||||
@gem = gem
|
||||
|
||||
@build_time = Time.now
|
||||
|
@ -152,12 +152,19 @@ class Gem::Package
|
|||
@contents = nil
|
||||
@digests = Hash.new { |h, algorithm| h[algorithm] = {} }
|
||||
@files = nil
|
||||
@security_policy = nil
|
||||
@security_policy = security_policy
|
||||
@signatures = {}
|
||||
@signer = nil
|
||||
@spec = nil
|
||||
end
|
||||
|
||||
##
|
||||
# Copies this package to +path+ (if possible)
|
||||
|
||||
def copy_to path
|
||||
FileUtils.cp @gem.path, path unless File.exist? path
|
||||
end
|
||||
|
||||
##
|
||||
# Adds a checksum for each entry in the gem to checksums.yaml.gz.
|
||||
|
||||
|
@ -200,7 +207,11 @@ class Gem::Package
|
|||
|
||||
def add_files tar # :nodoc:
|
||||
@spec.files.each do |file|
|
||||
stat = File.stat file
|
||||
stat = File.lstat file
|
||||
|
||||
if stat.symlink?
|
||||
tar.add_symlink file, File.readlink(file), stat.mode
|
||||
end
|
||||
|
||||
next unless stat.file?
|
||||
|
||||
|
@ -371,6 +382,8 @@ EOM
|
|||
FileUtils.chmod entry.header.mode, destination
|
||||
end if entry.file?
|
||||
|
||||
File.symlink(install_location(entry.header.linkname, destination_dir), destination) if entry.symlink?
|
||||
|
||||
verbose destination
|
||||
end
|
||||
end
|
||||
|
@ -611,4 +624,3 @@ require 'rubygems/package/tar_header'
|
|||
require 'rubygems/package/tar_reader'
|
||||
require 'rubygems/package/tar_reader/entry'
|
||||
require 'rubygems/package/tar_writer'
|
||||
|
||||
|
|
|
@ -18,14 +18,14 @@ class Gem::Package::Old < Gem::Package
|
|||
# Creates a new old-format package reader for +gem+. Old-format packages
|
||||
# cannot be written.
|
||||
|
||||
def initialize gem
|
||||
def initialize gem, security_policy
|
||||
require 'fileutils'
|
||||
require 'zlib'
|
||||
Gem.load_yaml
|
||||
|
||||
@contents = nil
|
||||
@gem = gem
|
||||
@security_policy = nil
|
||||
@security_policy = security_policy
|
||||
@spec = nil
|
||||
end
|
||||
|
||||
|
|
|
@ -102,6 +102,13 @@ class Gem::Package::TarReader::Entry
|
|||
@header.typeflag == "0"
|
||||
end
|
||||
|
||||
##
|
||||
# Is this tar entry a symlink?
|
||||
|
||||
def symlink?
|
||||
@header.typeflag == "2"
|
||||
end
|
||||
|
||||
##
|
||||
# The position in the tar entry
|
||||
|
||||
|
@ -144,4 +151,3 @@ class Gem::Package::TarReader::Entry
|
|||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ class Gem::Package::TarTestCase < Gem::TestCase
|
|||
SP(Z(to_oct(sum, 6)))
|
||||
end
|
||||
|
||||
def header(type, fname, dname, length, mode, mtime, checksum = nil)
|
||||
def header(type, fname, dname, length, mode, mtime, checksum = nil, linkname = "")
|
||||
checksum ||= " " * 8
|
||||
|
||||
arr = [ # struct tarfile_entry_posix
|
||||
|
@ -83,7 +83,7 @@ class Gem::Package::TarTestCase < Gem::TestCase
|
|||
Z(to_oct(mtime, 11)), # char mtime[12]; 0 padded, octal, null
|
||||
checksum, # char checksum[8]; 0 padded, octal, null, space
|
||||
type, # char typeflag[1]; file: "0" dir: "5"
|
||||
"\0" * 100, # char linkname[100]; ASCII + (Z unless filled)
|
||||
ASCIIZ(linkname, 100), # char linkname[100]; ASCII + (Z unless filled)
|
||||
"ustar\0", # char magic[6]; "ustar\0"
|
||||
"00", # char version[2]; "00"
|
||||
ASCIIZ("wheel", 32), # char uname[32]; ASCIIZ
|
||||
|
@ -117,6 +117,12 @@ class Gem::Package::TarTestCase < Gem::TestCase
|
|||
header("0", fname, dname, length, mode, mtime, checksum)
|
||||
end
|
||||
|
||||
def tar_symlink_header(fname, prefix, mode, mtime, linkname)
|
||||
h = header("2", fname, prefix, 0, mode, mtime, nil, linkname)
|
||||
checksum = calc_checksum(h)
|
||||
header("2", fname, prefix, 0, mode, mtime, checksum, linkname)
|
||||
end
|
||||
|
||||
def to_oct(n, pad_size)
|
||||
"%0#{pad_size}o" % n
|
||||
end
|
||||
|
@ -133,5 +139,8 @@ class Gem::Package::TarTestCase < Gem::TestCase
|
|||
util_entry tar_dir_header("foo", "bar", 0, Time.now)
|
||||
end
|
||||
|
||||
end
|
||||
def util_symlink_entry
|
||||
util_entry tar_symlink_header("foo", "bar", 0, Time.now, "link")
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -233,6 +233,25 @@ class Gem::Package::TarWriter
|
|||
self
|
||||
end
|
||||
|
||||
##
|
||||
# Adds symlink +name+ with permissions +mode+, linking to +target+.
|
||||
|
||||
def add_symlink(name, target, mode)
|
||||
check_closed
|
||||
|
||||
name, prefix = split_name name
|
||||
|
||||
header = Gem::Package::TarHeader.new(:name => name, :mode => mode,
|
||||
:size => 0, :typeflag => "2",
|
||||
:linkname => target,
|
||||
:prefix => prefix,
|
||||
:mtime => Time.now).to_s
|
||||
|
||||
@io.write header
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
##
|
||||
# Raises IOError if the TarWriter is closed
|
||||
|
||||
|
@ -323,4 +342,3 @@ class Gem::Package::TarWriter
|
|||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -95,6 +95,7 @@ class Gem::Platform
|
|||
[os, version]
|
||||
when /netbsdelf/ then [ 'netbsdelf', nil ]
|
||||
when /openbsd(\d+\.\d+)?/ then [ 'openbsd', $1 ]
|
||||
when /bitrig(\d+\.\d+)?/ then [ 'bitrig', $1 ]
|
||||
when /solaris(\d+\.\d+)?/ then [ 'solaris', $1 ]
|
||||
# test
|
||||
when /^(\w+_platform)(\d+)?/ then [ $1, $2 ]
|
||||
|
|
|
@ -20,7 +20,7 @@ begin
|
|||
require 'rdoc/rubygems_hook'
|
||||
loaded_hook = true
|
||||
module Gem
|
||||
RDoc = RDoc::RubygemsHook
|
||||
RDoc = ::RDoc::RubygemsHook
|
||||
end
|
||||
rescue LoadError
|
||||
end
|
||||
|
@ -332,4 +332,3 @@ class Gem::RDoc # :nodoc: all
|
|||
end unless loaded_hook
|
||||
|
||||
Gem.done_installing(&Gem::RDoc.method(:generation_hook))
|
||||
|
||||
|
|
|
@ -61,18 +61,22 @@ class Gem::Request::ConnectionPools # :nodoc:
|
|||
end
|
||||
|
||||
def net_http_args uri, proxy_uri
|
||||
net_http_args = [uri.host, uri.port]
|
||||
# URI::Generic#hostname was added in ruby 1.9.3, use it if exists, otherwise
|
||||
# don't support IPv6 literals and use host.
|
||||
hostname = uri.respond_to?(:hostname) ? uri.hostname : uri.host
|
||||
net_http_args = [hostname, uri.port]
|
||||
|
||||
no_proxy = get_no_proxy_from_env
|
||||
|
||||
if proxy_uri and not no_proxy?(uri.host, no_proxy) then
|
||||
if proxy_uri and not no_proxy?(hostname, no_proxy) then
|
||||
proxy_hostname = proxy_uri.respond_to?(:hostname) ? proxy_uri.hostname : proxy_uri.host
|
||||
net_http_args + [
|
||||
proxy_uri.host,
|
||||
proxy_hostname,
|
||||
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
|
||||
elsif no_proxy? hostname, no_proxy then
|
||||
net_http_args + [nil, nil]
|
||||
else
|
||||
net_http_args
|
||||
|
|
|
@ -159,16 +159,13 @@ class Gem::RequestSet
|
|||
|
||||
path = req.download cache_dir
|
||||
|
||||
inst = Gem::Installer.new path, options
|
||||
inst = Gem::Installer.at path, options
|
||||
|
||||
yield req, inst if block_given?
|
||||
|
||||
requests << inst.install
|
||||
end
|
||||
|
||||
requests
|
||||
ensure
|
||||
raise if $!
|
||||
return requests if options[:gemdeps]
|
||||
|
||||
specs = requests.map do |request|
|
||||
|
@ -187,6 +184,8 @@ class Gem::RequestSet
|
|||
Gem.done_installing_hooks.each do |hook|
|
||||
hook.call inst, specs
|
||||
end unless Gem.done_installing_hooks.empty?
|
||||
|
||||
requests
|
||||
end
|
||||
|
||||
##
|
||||
|
|
|
@ -174,7 +174,7 @@ class Gem::RequestSet::GemDependencyAPI
|
|||
##
|
||||
# A Hash containing gem names and files to require from those gems.
|
||||
|
||||
attr_reader :requires # :nodoc:
|
||||
attr_reader :requires
|
||||
|
||||
##
|
||||
# A set of gems that are loaded via the +:path+ option to #gem
|
||||
|
|
|
@ -185,7 +185,7 @@ class Gem::RequestSet::Lockfile
|
|||
|
||||
platforms = platforms.sort_by { |platform| platform.to_s }
|
||||
|
||||
platforms.sort.each do |platform|
|
||||
platforms.each do |platform|
|
||||
out << " #{platform}"
|
||||
end
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ require 'net/http'
|
|||
# all the requirements.
|
||||
|
||||
class Gem::Resolver
|
||||
require 'rubygems/resolver/molinillo'
|
||||
|
||||
##
|
||||
# If the DEBUG_RESOLVER environment variable is set then debugging mode is
|
||||
|
@ -20,13 +21,6 @@ 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 all development dependencies should be considered.
|
||||
|
||||
|
@ -110,7 +104,6 @@ class Gem::Resolver
|
|||
@set = set || Gem::Resolver::IndexSet.new
|
||||
@needed = needed
|
||||
|
||||
@conflicts = []
|
||||
@development = false
|
||||
@development_shallow = false
|
||||
@ignore_dependencies = false
|
||||
|
@ -153,7 +146,7 @@ class Gem::Resolver
|
|||
return spec, activation_request
|
||||
end
|
||||
|
||||
def requests s, act, reqs=nil # :nodoc:
|
||||
def requests s, act, reqs=[] # :nodoc:
|
||||
return reqs if @ignore_dependencies
|
||||
|
||||
s.fetch_development_dependencies if @development
|
||||
|
@ -165,7 +158,7 @@ class Gem::Resolver
|
|||
next if d.type == :development and @development_shallow and
|
||||
act.parent
|
||||
|
||||
reqs.add Gem::Resolver::DependencyRequest.new(d, act)
|
||||
reqs << Gem::Resolver::DependencyRequest.new(d, act)
|
||||
@stats.requirement!
|
||||
end
|
||||
|
||||
|
@ -176,29 +169,27 @@ class Gem::Resolver
|
|||
reqs
|
||||
end
|
||||
|
||||
include Molinillo::UI
|
||||
|
||||
def output
|
||||
@output ||= debug? ? $stdout : File.open('/dev/null', 'w')
|
||||
end
|
||||
|
||||
def debug?
|
||||
DEBUG_RESOLVER
|
||||
end
|
||||
|
||||
include Molinillo::SpecificationProvider
|
||||
|
||||
##
|
||||
# Proceed with resolution! Returns an array of ActivationRequest objects.
|
||||
|
||||
def resolve
|
||||
@conflicts = []
|
||||
|
||||
needed = Gem::Resolver::RequirementList.new
|
||||
|
||||
@needed.reverse_each do |n|
|
||||
request = Gem::Resolver::DependencyRequest.new n, nil
|
||||
|
||||
needed.add request
|
||||
@stats.requirement!
|
||||
end
|
||||
|
||||
@stats.record_requirements needed
|
||||
|
||||
res = resolve_for needed, nil
|
||||
|
||||
raise Gem::DependencyResolutionError, res if
|
||||
res.kind_of? Gem::Resolver::Conflict
|
||||
|
||||
res.to_a
|
||||
locking_dg = Molinillo::DependencyGraph.new
|
||||
Molinillo::Resolver.new(self, self).resolve(@needed.map { |d| DependencyRequest.new d, nil }, locking_dg).tsort.map(&:payload)
|
||||
rescue Molinillo::VersionConflict => e
|
||||
conflict = e.conflicts.values.first
|
||||
raise Gem::DependencyResolutionError, Conflict.new(conflict.requirement_trees.first.first, conflict.existing, conflict.requirement)
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -221,225 +212,6 @@ class Gem::Resolver
|
|||
return matching_platform, all
|
||||
end
|
||||
|
||||
def handle_conflict(dep, existing) # :nodoc:
|
||||
# There is a conflict! We return the conflict object which will be seen by
|
||||
# the caller and be handled at the right level.
|
||||
|
||||
# If the existing activation indicates that there are other possibles for
|
||||
# it, then issue the conflict on the dependency for the activation itself.
|
||||
# Otherwise, if there was a requester, issue it on the requester's
|
||||
# request itself.
|
||||
# Finally, if the existing request has no requester (toplevel) unwind to
|
||||
# it anyway.
|
||||
|
||||
if existing.others_possible?
|
||||
conflict =
|
||||
Gem::Resolver::Conflict.new dep, existing
|
||||
elsif dep.requester
|
||||
depreq = dep.requester.request
|
||||
conflict =
|
||||
Gem::Resolver::Conflict.new depreq, existing, dep
|
||||
elsif existing.request.requester.nil?
|
||||
conflict =
|
||||
Gem::Resolver::Conflict.new dep, existing
|
||||
else
|
||||
raise Gem::DependencyError, "Unable to figure out how to unwind conflict"
|
||||
end
|
||||
|
||||
@conflicts << conflict unless @conflicts.include? conflict
|
||||
|
||||
return conflict
|
||||
end
|
||||
|
||||
# Contains the state for attempting activation of a set of possible specs.
|
||||
# +needed+ is a Gem::List of DependencyRequest objects that, well, need
|
||||
# to be satisfied.
|
||||
# +specs+ is the List of ActivationRequest that are being tested.
|
||||
# +dep+ is the DependencyRequest that was used to generate this state.
|
||||
# +spec+ is the Specification for this state.
|
||||
# +possible+ is List of DependencyRequest objects that can be tried to
|
||||
# find a complete set.
|
||||
# +conflicts+ is a [DependencyRequest, Conflict] hit tried to
|
||||
# activate the state.
|
||||
#
|
||||
State = Struct.new(:needed, :specs, :dep, :spec, :possibles, :conflicts) do
|
||||
def summary # :nodoc:
|
||||
nd = needed.map { |s| s.to_s }.sort if nd
|
||||
|
||||
if specs then
|
||||
ss = specs.map { |s| s.full_name }.sort
|
||||
ss.unshift ss.length
|
||||
end
|
||||
|
||||
d = dep.to_s
|
||||
d << " from #{dep.requester.full_name}" if dep.requester
|
||||
|
||||
ps = possibles.map { |p| p.full_name }.sort
|
||||
ps.unshift ps.length
|
||||
|
||||
cs = conflicts.map do |(s, c)|
|
||||
[s.full_name, c.conflicting_dependencies.map { |cd| cd.to_s }]
|
||||
end
|
||||
|
||||
{ :needed => nd, :specs => ss, :dep => d, :spec => spec.full_name,
|
||||
:possibles => ps, :conflicts => cs }
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# The meat of the algorithm. Given +needed+ DependencyRequest objects and
|
||||
# +specs+ being a list to ActivationRequest, calculate a new list of
|
||||
# ActivationRequest objects.
|
||||
|
||||
def resolve_for needed, specs # :nodoc:
|
||||
# The State objects that are used to attempt the activation tree.
|
||||
states = []
|
||||
|
||||
while !needed.empty?
|
||||
@stats.iteration!
|
||||
|
||||
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 }
|
||||
|
||||
# If there is already a spec activated for the requested name...
|
||||
if specs && existing = specs.find { |s| dep.name == s.name }
|
||||
# then we're done since this new dep matches the existing spec.
|
||||
next if dep.matches_spec? existing
|
||||
|
||||
conflict = handle_conflict dep, existing
|
||||
|
||||
return conflict unless dep.requester
|
||||
|
||||
explain :conflict, dep, :existing, existing.full_name
|
||||
|
||||
depreq = dep.requester.request
|
||||
|
||||
state = nil
|
||||
until states.empty?
|
||||
x = states.pop
|
||||
|
||||
i = existing.request.requester
|
||||
explain :consider, x.spec.full_name, [depreq.name, dep.name, i ? i.name : :top]
|
||||
|
||||
if x.spec.name == depreq.name or
|
||||
x.spec.name == dep.name or
|
||||
(i && (i.name == x.spec.name))
|
||||
explain :found, x.spec.full_name
|
||||
state = x
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return conflict unless state
|
||||
|
||||
@stats.backtracking!
|
||||
|
||||
needed, specs = resolve_for_conflict needed, specs, state
|
||||
|
||||
states << state unless state.possibles.empty?
|
||||
|
||||
next
|
||||
end
|
||||
|
||||
matching, all = find_possible dep
|
||||
|
||||
case matching.size
|
||||
when 0
|
||||
resolve_for_zero dep, all
|
||||
when 1
|
||||
needed, specs =
|
||||
resolve_for_single needed, specs, dep, matching
|
||||
else
|
||||
needed, specs =
|
||||
resolve_for_multiple needed, specs, states, dep, matching
|
||||
end
|
||||
end
|
||||
|
||||
specs
|
||||
end
|
||||
|
||||
##
|
||||
# Rewinds +needed+ and +specs+ to a previous state in +state+ for a conflict
|
||||
# between +dep+ and +existing+.
|
||||
|
||||
def resolve_for_conflict needed, specs, state # :nodoc:
|
||||
# We exhausted the possibles so it's definitely not going to work out,
|
||||
# bail out.
|
||||
raise Gem::ImpossibleDependenciesError.new state.dep, state.conflicts if
|
||||
state.possibles.empty?
|
||||
|
||||
# Retry resolution with this spec and add it's dependencies
|
||||
spec, act = activation_request state.dep, state.possibles
|
||||
|
||||
needed = requests spec, act, state.needed.dup
|
||||
specs = Gem::List.prepend state.specs, act
|
||||
|
||||
return needed, specs
|
||||
end
|
||||
|
||||
##
|
||||
# There are multiple +possible+ specifications for this +dep+. Updates
|
||||
# +needed+, +specs+ and +states+ for further resolution of the +possible+
|
||||
# choices.
|
||||
|
||||
def resolve_for_multiple needed, specs, states, dep, possible # :nodoc:
|
||||
# Sort them so that we try the highest versions first.
|
||||
possible = possible.sort_by do |s|
|
||||
[s.source, s.version, s.platform == Gem::Platform::RUBY ? -1 : 1]
|
||||
end
|
||||
|
||||
spec, act = activation_request dep, possible
|
||||
|
||||
# We may need to try all of +possible+, so we setup state to unwind back
|
||||
# to current +needed+ and +specs+ so we can try another. This is code is
|
||||
# what makes conflict resolution possible.
|
||||
states << State.new(needed.dup, specs, dep, spec, possible, [])
|
||||
|
||||
@stats.record_depth states
|
||||
|
||||
explain :states, states.map { |s| s.dep }
|
||||
|
||||
needed = requests spec, act, needed
|
||||
specs = Gem::List.prepend specs, act
|
||||
|
||||
return needed, specs
|
||||
end
|
||||
|
||||
##
|
||||
# Add the spec from the +possible+ list to +specs+ and process the spec's
|
||||
# dependencies by adding them to +needed+.
|
||||
|
||||
def resolve_for_single needed, specs, dep, possible # :nodoc:
|
||||
spec, act = activation_request dep, possible
|
||||
|
||||
specs = Gem::List.prepend specs, act
|
||||
|
||||
# Put the deps for at the beginning of needed
|
||||
# rather than the end to match the depth first
|
||||
# searching done by the multiple case code below.
|
||||
#
|
||||
# This keeps the error messages consistent.
|
||||
needed = requests spec, act, needed
|
||||
|
||||
return needed, specs
|
||||
end
|
||||
|
||||
##
|
||||
# When there are no possible specifications for +dep+ our work is done.
|
||||
|
||||
def resolve_for_zero dep, platform_mismatch # :nodoc:
|
||||
@missing << dep
|
||||
|
||||
unless @soft_missing
|
||||
exc = Gem::UnsatisfiableDependencyError.new dep, platform_mismatch
|
||||
exc.errors = @set.errors
|
||||
|
||||
raise exc
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the gems in +specs+ that match the local platform.
|
||||
|
||||
|
@ -449,6 +221,37 @@ class Gem::Resolver
|
|||
end
|
||||
end
|
||||
|
||||
def search_for(dependency)
|
||||
possibles, all = find_possible(dependency)
|
||||
if !@soft_missing && possibles.empty?
|
||||
@missing << dependency
|
||||
exc = Gem::UnsatisfiableDependencyError.new dependency, all
|
||||
exc.errors = @set.errors
|
||||
raise exc
|
||||
end
|
||||
possibles.sort_by { |s| [s.source, s.version, s.platform == Gem::Platform.local.to_s ? 1 : 0] }.
|
||||
map { |s| ActivationRequest.new s, dependency, [] }
|
||||
end
|
||||
|
||||
def dependencies_for(specification)
|
||||
return [] if @ignore_dependencies
|
||||
spec = specification.spec
|
||||
requests(spec, specification)
|
||||
end
|
||||
|
||||
def requirement_satisfied_by?(requirement, activated, spec)
|
||||
requirement.matches_spec? spec
|
||||
end
|
||||
|
||||
def name_for(dependency)
|
||||
dependency.name
|
||||
end
|
||||
|
||||
def allow_missing?(dependency)
|
||||
@missing << dependency
|
||||
@soft_missing
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -482,4 +285,3 @@ require 'rubygems/resolver/installed_specification'
|
|||
require 'rubygems/resolver/local_specification'
|
||||
require 'rubygems/resolver/lock_specification'
|
||||
require 'rubygems/resolver/vendor_specification'
|
||||
|
||||
|
|
|
@ -67,6 +67,8 @@ class Gem::Resolver::ActivationRequest
|
|||
@spec.full_name
|
||||
end
|
||||
|
||||
alias_method :to_s, :full_name
|
||||
|
||||
##
|
||||
# The Gem::Specification for this activation request.
|
||||
|
||||
|
@ -169,4 +171,3 @@ class Gem::Resolver::ActivationRequest
|
|||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -157,4 +157,3 @@ end
|
|||
# TODO: Remove in RubyGems 3
|
||||
|
||||
Gem::Resolver::DependencyConflict = Gem::Resolver::Conflict # :nodoc:
|
||||
|
||||
|
|
|
@ -67,6 +67,10 @@ class Gem::Resolver::DependencyRequest
|
|||
@dependency.name
|
||||
end
|
||||
|
||||
def type
|
||||
@dependency.type
|
||||
end
|
||||
|
||||
##
|
||||
# Indicate that the request is for a gem explicitly requested by the user
|
||||
|
||||
|
@ -113,4 +117,3 @@ class Gem::Resolver::DependencyRequest
|
|||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -23,8 +23,7 @@ class Gem::Resolver::GitSpecification < Gem::Resolver::SpecSpecification
|
|||
def install options = {}
|
||||
require 'rubygems/installer'
|
||||
|
||||
installer = Gem::Installer.new '', options
|
||||
installer.spec = spec
|
||||
installer = Gem::Installer.for_spec spec, options
|
||||
|
||||
yield installer if block_given?
|
||||
|
||||
|
|
1
lib/rubygems/resolver/molinillo.rb
Normal file
1
lib/rubygems/resolver/molinillo.rb
Normal file
|
@ -0,0 +1 @@
|
|||
require 'rubygems/resolver/molinillo/lib/molinillo'
|
5
lib/rubygems/resolver/molinillo/lib/molinillo.rb
Normal file
5
lib/rubygems/resolver/molinillo/lib/molinillo.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
require 'rubygems/resolver/molinillo/lib/molinillo/gem_metadata'
|
||||
require 'rubygems/resolver/molinillo/lib/molinillo/errors'
|
||||
require 'rubygems/resolver/molinillo/lib/molinillo/resolver'
|
||||
require 'rubygems/resolver/molinillo/lib/molinillo/modules/ui'
|
||||
require 'rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider'
|
|
@ -0,0 +1,266 @@
|
|||
require 'set'
|
||||
require 'tsort'
|
||||
|
||||
module Gem::Resolver::Molinillo
|
||||
# A directed acyclic graph that is tuned to hold named dependencies
|
||||
class DependencyGraph
|
||||
include Enumerable
|
||||
|
||||
# Enumerates through the vertices of the graph.
|
||||
# @return [Array<Vertex>] The graph's vertices.
|
||||
def each
|
||||
vertices.values.each { |v| yield v }
|
||||
end
|
||||
|
||||
include TSort
|
||||
|
||||
alias_method :tsort_each_node, :each
|
||||
|
||||
def tsort_each_child(vertex, &block)
|
||||
vertex.successors.each(&block)
|
||||
end
|
||||
|
||||
# Topologically sorts the given vertices.
|
||||
# @param [Enumerable<Vertex>] vertices the vertices to be sorted, which must
|
||||
# all belong to the same graph.
|
||||
# @return [Array<Vertex>] The sorted vertices.
|
||||
def self.tsort(vertices)
|
||||
TSort.tsort(
|
||||
lambda { |b| vertices.each(&b) },
|
||||
lambda { |v, &b| (v.successors & vertices).each(&b) }
|
||||
)
|
||||
end
|
||||
|
||||
# A directed edge of a {DependencyGraph}
|
||||
# @attr [Vertex] origin The origin of the directed edge
|
||||
# @attr [Vertex] destination The destination of the directed edge
|
||||
# @attr [Array] requirements The requirements the directed edge represents
|
||||
Edge = Struct.new(:origin, :destination, :requirements)
|
||||
|
||||
# @return [{String => Vertex}] vertices that have no {Vertex#predecessors},
|
||||
# keyed by by {Vertex#name}
|
||||
attr_reader :root_vertices
|
||||
# @return [{String => Vertex}] the vertices of the dependency graph, keyed
|
||||
# by {Vertex#name}
|
||||
attr_reader :vertices
|
||||
# @return [Set<Edge>] the edges of the dependency graph
|
||||
attr_reader :edges
|
||||
|
||||
def initialize
|
||||
@vertices = {}
|
||||
@edges = Set.new
|
||||
@root_vertices = {}
|
||||
end
|
||||
|
||||
# Initializes a copy of a {DependencyGraph}, ensuring that all {#vertices}
|
||||
# have the correct {Vertex#graph} set
|
||||
def initialize_copy(other)
|
||||
super
|
||||
@vertices = other.vertices.reduce({}) do |vertices, (name, vertex)|
|
||||
vertices.tap do |hash|
|
||||
hash[name] = vertex.dup.tap { |v| v.graph = self }
|
||||
end
|
||||
end
|
||||
@root_vertices = Hash[@vertices.select { |n, _v| other.root_vertices[n] }]
|
||||
@edges = other.edges.map do |edge|
|
||||
Edge.new(
|
||||
vertex_named(edge.origin.name),
|
||||
vertex_named(edge.destination.name),
|
||||
edge.requirements.dup
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# @return [String] a string suitable for debugging
|
||||
def inspect
|
||||
"#{self.class}:#{vertices.values.inspect}"
|
||||
end
|
||||
|
||||
# @return [Boolean] whether the two dependency graphs are equal, determined
|
||||
# by a recursive traversal of each {#root_vertices} and its
|
||||
# {Vertex#successors}
|
||||
def ==(other)
|
||||
root_vertices == other.root_vertices
|
||||
end
|
||||
|
||||
# @param [String] name
|
||||
# @param [Object] payload
|
||||
# @param [Array<String>] parent_names
|
||||
# @param [Object] requirement the requirement that is requiring the child
|
||||
# @return [void]
|
||||
def add_child_vertex(name, payload, parent_names, requirement)
|
||||
is_root = parent_names.include?(nil)
|
||||
parent_nodes = parent_names.compact.map { |n| vertex_named(n) }
|
||||
vertex = vertex_named(name) || if is_root
|
||||
add_root_vertex(name, payload)
|
||||
else
|
||||
add_vertex(name, payload)
|
||||
end
|
||||
vertex.payload ||= payload
|
||||
parent_nodes.each do |parent_node|
|
||||
add_edge(parent_node, vertex, requirement)
|
||||
end
|
||||
vertex
|
||||
end
|
||||
|
||||
# @param [String] name
|
||||
# @param [Object] payload
|
||||
# @return [Vertex] the vertex that was added to `self`
|
||||
def add_vertex(name, payload)
|
||||
vertex = vertices[name] ||= Vertex.new(self, name, payload)
|
||||
vertex.tap { |v| v.payload = payload }
|
||||
end
|
||||
|
||||
# @param [String] name
|
||||
# @param [Object] payload
|
||||
# @return [Vertex] the vertex that was added to `self`
|
||||
def add_root_vertex(name, payload)
|
||||
add_vertex(name, payload).tap { |v| root_vertices[name] = v }
|
||||
end
|
||||
|
||||
# Detaches the {#vertex_named} `name` {Vertex} from the graph, recursively
|
||||
# removing any non-root vertices that were orphaned in the process
|
||||
# @param [String] name
|
||||
# @return [void]
|
||||
def detach_vertex_named(name)
|
||||
vertex = vertex_named(name)
|
||||
return unless vertex
|
||||
successors = vertex.successors
|
||||
vertices.delete(name)
|
||||
edges.reject! { |e| e.origin == vertex || e.destination == vertex }
|
||||
successors.each { |v| detach_vertex_named(v.name) unless root_vertices[v.name] || v.predecessors.any? }
|
||||
end
|
||||
|
||||
# @param [String] name
|
||||
# @return [Vertex,nil] the vertex with the given name
|
||||
def vertex_named(name)
|
||||
vertices[name]
|
||||
end
|
||||
|
||||
# @param [String] name
|
||||
# @return [Vertex,nil] the root vertex with the given name
|
||||
def root_vertex_named(name)
|
||||
root_vertices[name]
|
||||
end
|
||||
|
||||
# Adds a new {Edge} to the dependency graph
|
||||
# @param [Vertex] origin
|
||||
# @param [Vertex] destination
|
||||
# @param [Object] requirement the requirement that this edge represents
|
||||
# @return [Edge] the added edge
|
||||
def add_edge(origin, destination, requirement)
|
||||
if origin == destination || destination.path_to?(origin)
|
||||
raise CircularDependencyError.new([origin, destination])
|
||||
end
|
||||
Edge.new(origin, destination, [requirement]).tap { |e| edges << e }
|
||||
end
|
||||
|
||||
# A vertex in a {DependencyGraph} that encapsulates a {#name} and a
|
||||
# {#payload}
|
||||
class Vertex
|
||||
# @return [DependencyGraph] the graph this vertex is a node of
|
||||
attr_accessor :graph
|
||||
|
||||
# @return [String] the name of the vertex
|
||||
attr_accessor :name
|
||||
|
||||
# @return [Object] the payload the vertex holds
|
||||
attr_accessor :payload
|
||||
|
||||
# @return [Arrary<Object>] the explicit requirements that required
|
||||
# this vertex
|
||||
attr_reader :explicit_requirements
|
||||
|
||||
# @param [DependencyGraph] graph see {#graph}
|
||||
# @param [String] name see {#name}
|
||||
# @param [Object] payload see {#payload}
|
||||
def initialize(graph, name, payload)
|
||||
@graph = graph
|
||||
@name = name
|
||||
@payload = payload
|
||||
@explicit_requirements = []
|
||||
end
|
||||
|
||||
# @return [Array<Object>] all of the requirements that required
|
||||
# this vertex
|
||||
def requirements
|
||||
incoming_edges.map(&:requirements).flatten + explicit_requirements
|
||||
end
|
||||
|
||||
# @return [Array<Edge>] the edges of {#graph} that have `self` as their
|
||||
# {Edge#origin}
|
||||
def outgoing_edges
|
||||
graph.edges.select { |e| e.origin.shallow_eql?(self) }
|
||||
end
|
||||
|
||||
# @return [Array<Edge>] the edges of {#graph} that have `self` as their
|
||||
# {Edge#destination}
|
||||
def incoming_edges
|
||||
graph.edges.select { |e| e.destination.shallow_eql?(self) }
|
||||
end
|
||||
|
||||
# @return [Set<Vertex>] the vertices of {#graph} that have an edge with
|
||||
# `self` as their {Edge#destination}
|
||||
def predecessors
|
||||
incoming_edges.map(&:origin).to_set
|
||||
end
|
||||
|
||||
# @return [Set<Vertex>] the vertices of {#graph} that have an edge with
|
||||
# `self` as their {Edge#origin}
|
||||
def successors
|
||||
outgoing_edges.map(&:destination).to_set
|
||||
end
|
||||
|
||||
# @return [Set<Vertex>] the vertices of {#graph} where `self` is an
|
||||
# {#ancestor?}
|
||||
def recursive_successors
|
||||
successors + successors.map(&:recursive_successors).reduce(Set.new, &:+)
|
||||
end
|
||||
|
||||
# @return [String] a string suitable for debugging
|
||||
def inspect
|
||||
"#{self.class}:#{name}(#{payload.inspect})"
|
||||
end
|
||||
|
||||
# @return [Boolean] whether the two vertices are equal, determined
|
||||
# by a recursive traversal of each {Vertex#successors}
|
||||
def ==(other)
|
||||
shallow_eql?(other) &&
|
||||
successors == other.successors
|
||||
end
|
||||
|
||||
# @return [Boolean] whether the two vertices are equal, determined
|
||||
# solely by {#name} and {#payload} equality
|
||||
def shallow_eql?(other)
|
||||
other &&
|
||||
name == other.name &&
|
||||
payload == other.payload
|
||||
end
|
||||
|
||||
alias_method :eql?, :==
|
||||
|
||||
# @return [Fixnum] a hash for the vertex based upon its {#name}
|
||||
def hash
|
||||
name.hash
|
||||
end
|
||||
|
||||
# Is there a path from `self` to `other` following edges in the
|
||||
# dependency graph?
|
||||
# @return true iff there is a path following edges within this {#graph}
|
||||
def path_to?(other)
|
||||
successors.include?(other) || successors.any? { |v| v.path_to?(other) }
|
||||
end
|
||||
|
||||
alias_method :descendent?, :path_to?
|
||||
|
||||
# Is there a path from `other` to `self` following edges in the
|
||||
# dependency graph?
|
||||
# @return true iff there is a path following edges within this {#graph}
|
||||
def ancestor?(other)
|
||||
predecessors.include?(other) || predecessors.any? { |v| v.ancestor?(other) }
|
||||
end
|
||||
|
||||
alias_method :is_reachable_from?, :ancestor?
|
||||
end
|
||||
end
|
||||
end
|
69
lib/rubygems/resolver/molinillo/lib/molinillo/errors.rb
Normal file
69
lib/rubygems/resolver/molinillo/lib/molinillo/errors.rb
Normal file
|
@ -0,0 +1,69 @@
|
|||
module Gem::Resolver::Molinillo
|
||||
# An error that occurred during the resolution process
|
||||
class ResolverError < StandardError; end
|
||||
|
||||
# An error caused by searching for a dependency that is completely unknown,
|
||||
# i.e. has no versions available whatsoever.
|
||||
class NoSuchDependencyError < ResolverError
|
||||
# @return [Object] the dependency that could not be found
|
||||
attr_accessor :dependency
|
||||
|
||||
# @return [Array<Object>] the specifications that depended upon {#dependency}
|
||||
attr_accessor :required_by
|
||||
|
||||
# @param [Object] dependency @see {#dependency}
|
||||
# @param [Array<Object>] required_by @see {#required_by}
|
||||
def initialize(dependency, required_by = [])
|
||||
@dependency = dependency
|
||||
@required_by = required_by
|
||||
super()
|
||||
end
|
||||
|
||||
def message
|
||||
sources = required_by.map { |r| "`#{r}`" }.join(' and ')
|
||||
message = "Unable to find a specification for `#{dependency}`"
|
||||
message << " depended upon by #{sources}" unless sources.empty?
|
||||
message
|
||||
end
|
||||
end
|
||||
|
||||
# An error caused by attempting to fulfil a dependency that was circular
|
||||
#
|
||||
# @note This exception will be thrown iff a {Vertex} is added to a
|
||||
# {DependencyGraph} that has a {DependencyGraph::Vertex#path_to?} an
|
||||
# existing {DependencyGraph::Vertex}
|
||||
class CircularDependencyError < ResolverError
|
||||
# [Set<Object>] the dependencies responsible for causing the error
|
||||
attr_reader :dependencies
|
||||
|
||||
# @param [Array<DependencyGraph::Vertex>] nodes the nodes in the dependency
|
||||
# that caused the error
|
||||
def initialize(nodes)
|
||||
super "There is a circular dependency between #{nodes.map(&:name).join(' and ')}"
|
||||
@dependencies = nodes.map(&:payload).to_set
|
||||
end
|
||||
end
|
||||
|
||||
# An error caused by conflicts in version
|
||||
class VersionConflict < ResolverError
|
||||
# @return [{String => Resolution::Conflict}] the conflicts that caused
|
||||
# resolution to fail
|
||||
attr_reader :conflicts
|
||||
|
||||
# @param [{String => Resolution::Conflict}] conflicts see {#conflicts}
|
||||
def initialize(conflicts)
|
||||
pairs = []
|
||||
conflicts.values.flatten.map(&:requirements).flatten.each do |conflicting|
|
||||
conflicting.each do |source, conflict_requirements|
|
||||
conflict_requirements.each do |c|
|
||||
pairs << [c, source]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
super "Unable to satisfy the following requirements:\n\n" \
|
||||
"#{pairs.map { |r, d| "- `#{r}` required by `#{d}`" }.join("\n")}"
|
||||
@conflicts = conflicts
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
module Gem::Resolver::Molinillo
|
||||
VERSION = '0.3.0'
|
||||
end
|
|
@ -0,0 +1,99 @@
|
|||
module Gem::Resolver::Molinillo
|
||||
# Provides information about specifcations and dependencies to the resolver,
|
||||
# allowing the {Resolver} class to remain generic while still providing power
|
||||
# and flexibility.
|
||||
#
|
||||
# This module contains the methods that users of Gem::Resolver::Molinillo must to implement,
|
||||
# using knowledge of their own model classes.
|
||||
module SpecificationProvider
|
||||
# Search for the specifications that match the given dependency.
|
||||
# The specifications in the returned array will be considered in reverse
|
||||
# order, so the latest version ought to be last.
|
||||
# @note This method should be 'pure', i.e. the return value should depend
|
||||
# only on the `dependency` parameter.
|
||||
#
|
||||
# @param [Object] dependency
|
||||
# @return [Array<Object>] the specifications that satisfy the given
|
||||
# `dependency`.
|
||||
def search_for(dependency)
|
||||
[]
|
||||
end
|
||||
|
||||
# Returns the dependencies of `specification`.
|
||||
# @note This method should be 'pure', i.e. the return value should depend
|
||||
# only on the `specification` parameter.
|
||||
#
|
||||
# @param [Object] specification
|
||||
# @return [Array<Object>] the dependencies that are required by the given
|
||||
# `specification`.
|
||||
def dependencies_for(specification)
|
||||
[]
|
||||
end
|
||||
|
||||
# Determines whether the given `requirement` is satisfied by the given
|
||||
# `spec`, in the context of the current `activated` dependency graph.
|
||||
#
|
||||
# @param [Object] requirement
|
||||
# @param [DependencyGraph] activated the current dependency graph in the
|
||||
# resolution process.
|
||||
# @param [Object] spec
|
||||
# @return [Boolean] whether `requirement` is satisfied by `spec` in the
|
||||
# context of the current `activated` dependency graph.
|
||||
def requirement_satisfied_by?(requirement, activated, spec)
|
||||
true
|
||||
end
|
||||
|
||||
# Returns the name for the given `dependency`.
|
||||
# @note This method should be 'pure', i.e. the return value should depend
|
||||
# only on the `dependency` parameter.
|
||||
#
|
||||
# @param [Object] dependency
|
||||
# @return [String] the name for the given `dependency`.
|
||||
def name_for(dependency)
|
||||
dependency.to_s
|
||||
end
|
||||
|
||||
# @return [String] the name of the source of explicit dependencies, i.e.
|
||||
# those passed to {Resolver#resolve} directly.
|
||||
def name_for_explicit_dependency_source
|
||||
'user-specified dependency'
|
||||
end
|
||||
|
||||
# @return [String] the name of the source of 'locked' dependencies, i.e.
|
||||
# those passed to {Resolver#resolve} directly as the `base`
|
||||
def name_for_locking_dependency_source
|
||||
'Lockfile'
|
||||
end
|
||||
|
||||
# Sort dependencies so that the ones that are easiest to resolve are first.
|
||||
# Easiest to resolve is (usually) defined by:
|
||||
# 1) Is this dependency already activated?
|
||||
# 2) How relaxed are the requirements?
|
||||
# 3) Are there any conflicts for this dependency?
|
||||
# 4) How many possibilities are there to satisfy this dependency?
|
||||
#
|
||||
# @param [Array<Object>] dependencies
|
||||
# @param [DependencyGraph] activated the current dependency graph in the
|
||||
# resolution process.
|
||||
# @param [{String => Array<Conflict>}] conflicts
|
||||
# @return [Array<Object>] a sorted copy of `dependencies`.
|
||||
def sort_dependencies(dependencies, activated, conflicts)
|
||||
dependencies.sort_by do |dependency|
|
||||
name = name_for(dependency)
|
||||
[
|
||||
activated.vertex_named(name).payload ? 0 : 1,
|
||||
conflicts[name] ? 0 : 1,
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
# Returns whether this dependency, which has no possible matching
|
||||
# specifications, can safely be ignored.
|
||||
#
|
||||
# @param [Object] dependency
|
||||
# @return [Boolean] whether this dependency can safely be skipped.
|
||||
def allow_missing?(dependency)
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
63
lib/rubygems/resolver/molinillo/lib/molinillo/modules/ui.rb
Normal file
63
lib/rubygems/resolver/molinillo/lib/molinillo/modules/ui.rb
Normal file
|
@ -0,0 +1,63 @@
|
|||
module Gem::Resolver::Molinillo
|
||||
# Conveys information about the resolution process to a user.
|
||||
module UI
|
||||
# The {IO} object that should be used to print output. `STDOUT`, by default.
|
||||
#
|
||||
# @return [IO]
|
||||
def output
|
||||
STDOUT
|
||||
end
|
||||
|
||||
# Called roughly every {#progress_rate}, this method should convey progress
|
||||
# to the user.
|
||||
#
|
||||
# @return [void]
|
||||
def indicate_progress
|
||||
output.print '.' unless debug?
|
||||
end
|
||||
|
||||
# How often progress should be conveyed to the user via
|
||||
# {#indicate_progress}, in seconds. A third of a second, by default.
|
||||
#
|
||||
# @return [Float]
|
||||
def progress_rate
|
||||
0.33
|
||||
end
|
||||
|
||||
# Called before resolution begins.
|
||||
#
|
||||
# @return [void]
|
||||
def before_resolution
|
||||
output.print 'Resolving dependencies...'
|
||||
end
|
||||
|
||||
# Called after resolution ends (either successfully or with an error).
|
||||
# By default, prints a newline.
|
||||
#
|
||||
# @return [void]
|
||||
def after_resolution
|
||||
output.puts
|
||||
end
|
||||
|
||||
# Conveys debug information to the user.
|
||||
#
|
||||
# @param [Integer] depth the current depth of the resolution process.
|
||||
# @return [void]
|
||||
def debug(depth = 0)
|
||||
if debug?
|
||||
debug_info = yield
|
||||
debug_info = debug_info.inspect unless debug_info.is_a?(String)
|
||||
output.puts debug_info.split("\n").map { |s| ' ' * depth + s }
|
||||
end
|
||||
end
|
||||
|
||||
# Whether or not debug messages should be printed.
|
||||
# By default, whether or not the `MOLINILLO_DEBUG` environment variable is
|
||||
# set.
|
||||
#
|
||||
# @return [Boolean]
|
||||
def debug?
|
||||
@debug_mode ||= ENV['MOLINILLO_DEBUG']
|
||||
end
|
||||
end
|
||||
end
|
430
lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb
Normal file
430
lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb
Normal file
|
@ -0,0 +1,430 @@
|
|||
module Gem::Resolver::Molinillo
|
||||
class Resolver
|
||||
# A specific resolution from a given {Resolver}
|
||||
class Resolution
|
||||
# A conflict that the resolution process encountered
|
||||
# @attr [Object] requirement the requirement that immediately led to the conflict
|
||||
# @attr [{String,Nil=>[Object]}] requirements the requirements that caused the conflict
|
||||
# @attr [Object, nil] existing the existing spec that was in conflict with
|
||||
# the {#possibility}
|
||||
# @attr [Object] possibility the spec that was unable to be activated due
|
||||
# to a conflict
|
||||
# @attr [Object] locked_requirement the relevant locking requirement.
|
||||
# @attr [Array<Array<Object>>] requirement_trees the different requirement
|
||||
# trees that led to every requirement for the conflicting name.
|
||||
Conflict = Struct.new(
|
||||
:requirement,
|
||||
:requirements,
|
||||
:existing,
|
||||
:possibility,
|
||||
:locked_requirement,
|
||||
:requirement_trees
|
||||
)
|
||||
|
||||
# @return [SpecificationProvider] the provider that knows about
|
||||
# dependencies, requirements, specifications, versions, etc.
|
||||
attr_reader :specification_provider
|
||||
|
||||
# @return [UI] the UI that knows how to communicate feedback about the
|
||||
# resolution process back to the user
|
||||
attr_reader :resolver_ui
|
||||
|
||||
# @return [DependencyGraph] the base dependency graph to which
|
||||
# dependencies should be 'locked'
|
||||
attr_reader :base
|
||||
|
||||
# @return [Array] the dependencies that were explicitly required
|
||||
attr_reader :original_requested
|
||||
|
||||
# @param [SpecificationProvider] specification_provider
|
||||
# see {#specification_provider}
|
||||
# @param [UI] resolver_ui see {#resolver_ui}
|
||||
# @param [Array] requested see {#original_requested}
|
||||
# @param [DependencyGraph] base see {#base}
|
||||
def initialize(specification_provider, resolver_ui, requested, base)
|
||||
@specification_provider = specification_provider
|
||||
@resolver_ui = resolver_ui
|
||||
@original_requested = requested
|
||||
@base = base
|
||||
@states = []
|
||||
@iteration_counter = 0
|
||||
end
|
||||
|
||||
# Resolves the {#original_requested} dependencies into a full dependency
|
||||
# graph
|
||||
# @raise [ResolverError] if successful resolution is impossible
|
||||
# @return [DependencyGraph] the dependency graph of successfully resolved
|
||||
# dependencies
|
||||
def resolve
|
||||
start_resolution
|
||||
|
||||
while state
|
||||
break unless state.requirements.any? || state.requirement
|
||||
indicate_progress
|
||||
if state.respond_to?(:pop_possibility_state) # DependencyState
|
||||
debug(depth) { "Creating possibility state for #{requirement} (#{possibilities.count} remaining)" }
|
||||
state.pop_possibility_state.tap { |s| states.push(s) if s }
|
||||
end
|
||||
process_topmost_state
|
||||
end
|
||||
|
||||
activated.freeze
|
||||
ensure
|
||||
end_resolution
|
||||
end
|
||||
|
||||
# @return [Integer] the number of resolver iterations in between calls to
|
||||
# {#resolver_ui}'s {UI#indicate_progress} method
|
||||
attr_accessor :iteration_rate
|
||||
private :iteration_rate
|
||||
|
||||
# @return [Time] the time at which resolution began
|
||||
attr_accessor :started_at
|
||||
private :started_at
|
||||
|
||||
# @return [Array<ResolutionState>] the stack of states for the resolution
|
||||
attr_accessor :states
|
||||
private :states
|
||||
|
||||
private
|
||||
|
||||
# Sets up the resolution process
|
||||
# @return [void]
|
||||
def start_resolution
|
||||
@started_at = Time.now
|
||||
|
||||
handle_missing_or_push_dependency_state(initial_state)
|
||||
|
||||
debug { "Starting resolution (#{@started_at})" }
|
||||
resolver_ui.before_resolution
|
||||
end
|
||||
|
||||
# Ends the resolution process
|
||||
# @return [void]
|
||||
def end_resolution
|
||||
resolver_ui.after_resolution
|
||||
debug do
|
||||
"Finished resolution (#{@iteration_counter} steps) " \
|
||||
"(Took #{(ended_at = Time.now) - @started_at} seconds) (#{ended_at})"
|
||||
end
|
||||
debug { 'Unactivated: ' + Hash[activated.vertices.reject { |_n, v| v.payload }].keys.join(', ') } if state
|
||||
debug { 'Activated: ' + Hash[activated.vertices.select { |_n, v| v.payload }].keys.join(', ') } if state
|
||||
end
|
||||
|
||||
require 'rubygems/resolver/molinillo/lib/molinillo/state'
|
||||
require 'rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider'
|
||||
|
||||
ResolutionState.new.members.each do |member|
|
||||
define_method member do |*args, &block|
|
||||
current_state = state || ResolutionState.empty
|
||||
current_state.send(member, *args, &block)
|
||||
end
|
||||
end
|
||||
|
||||
SpecificationProvider.instance_methods(false).each do |instance_method|
|
||||
define_method instance_method do |*args, &block|
|
||||
begin
|
||||
specification_provider.send(instance_method, *args, &block)
|
||||
rescue NoSuchDependencyError => error
|
||||
if state
|
||||
vertex = activated.vertex_named(name_for error.dependency)
|
||||
error.required_by += vertex.incoming_edges.map { |e| e.origin.name }
|
||||
error.required_by << name_for_explicit_dependency_source unless vertex.explicit_requirements.empty?
|
||||
end
|
||||
raise
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Processes the topmost available {RequirementState} on the stack
|
||||
# @return [void]
|
||||
def process_topmost_state
|
||||
if possibility
|
||||
attempt_to_activate
|
||||
else
|
||||
create_conflict if state.is_a? PossibilityState
|
||||
unwind_for_conflict until possibility && state.is_a?(DependencyState)
|
||||
end
|
||||
end
|
||||
|
||||
# @return [Object] the current possibility that the resolution is trying
|
||||
# to activate
|
||||
def possibility
|
||||
possibilities.last
|
||||
end
|
||||
|
||||
# @return [RequirementState] the current state the resolution is
|
||||
# operating upon
|
||||
def state
|
||||
states.last
|
||||
end
|
||||
|
||||
# Creates the initial state for the resolution, based upon the
|
||||
# {#requested} dependencies
|
||||
# @return [DependencyState] the initial state for the resolution
|
||||
def initial_state
|
||||
graph = DependencyGraph.new.tap do |dg|
|
||||
original_requested.each { |r| dg.add_root_vertex(name_for(r), nil).tap { |v| v.explicit_requirements << r } }
|
||||
end
|
||||
|
||||
requirements = sort_dependencies(original_requested, graph, {})
|
||||
initial_requirement = requirements.shift
|
||||
DependencyState.new(
|
||||
initial_requirement && name_for(initial_requirement),
|
||||
requirements,
|
||||
graph,
|
||||
initial_requirement,
|
||||
initial_requirement && search_for(initial_requirement),
|
||||
0,
|
||||
{}
|
||||
)
|
||||
end
|
||||
|
||||
# Unwinds the states stack because a conflict has been encountered
|
||||
# @return [void]
|
||||
def unwind_for_conflict
|
||||
debug(depth) { "Unwinding for conflict: #{requirement}" }
|
||||
conflicts.tap do |c|
|
||||
states.slice!((state_index_for_unwind + 1)..-1)
|
||||
raise VersionConflict.new(c) unless state
|
||||
state.conflicts = c
|
||||
end
|
||||
end
|
||||
|
||||
# @return [Integer] The index to which the resolution should unwind in the
|
||||
# case of conflict.
|
||||
def state_index_for_unwind
|
||||
current_requirement = requirement
|
||||
existing_requirement = requirement_for_existing_name(name)
|
||||
until current_requirement.nil?
|
||||
current_state = find_state_for(current_requirement)
|
||||
return states.index(current_state) if state_any?(current_state)
|
||||
current_requirement = parent_of(current_requirement)
|
||||
end
|
||||
|
||||
until existing_requirement.nil?
|
||||
existing_state = find_state_for(existing_requirement)
|
||||
return states.index(existing_state) if state_any?(existing_state)
|
||||
existing_requirement = parent_of(existing_requirement)
|
||||
end
|
||||
-1
|
||||
end
|
||||
|
||||
# @return [Object] the requirement that led to `requirement` being added
|
||||
# to the list of requirements.
|
||||
def parent_of(requirement)
|
||||
return nil unless requirement
|
||||
seen = false
|
||||
state = states.reverse_each.find do |s|
|
||||
seen ||= s.requirement == requirement
|
||||
seen && s.requirement != requirement && !s.requirements.include?(requirement)
|
||||
end
|
||||
state && state.requirement
|
||||
end
|
||||
|
||||
# @return [Object] the requirement that led to a version of a possibility
|
||||
# with the given name being activated.
|
||||
def requirement_for_existing_name(name)
|
||||
return nil unless activated.vertex_named(name).payload
|
||||
states.reverse_each.find { |s| !s.activated.vertex_named(name).payload }.requirement
|
||||
end
|
||||
|
||||
# @return [ResolutionState] the state whose `requirement` is the given
|
||||
# `requirement`.
|
||||
def find_state_for(requirement)
|
||||
return nil unless requirement
|
||||
states.reverse_each.find { |i| requirement == i.requirement && i.is_a?(DependencyState) }
|
||||
end
|
||||
|
||||
# @return [Boolean] whether or not the given state has any possibilities
|
||||
# left.
|
||||
def state_any?(state)
|
||||
state && state.possibilities.any?
|
||||
end
|
||||
|
||||
# @return [Conflict] a {Conflict} that reflects the failure to activate
|
||||
# the {#possibility} in conjunction with the current {#state}
|
||||
def create_conflict
|
||||
vertex = activated.vertex_named(name)
|
||||
requirements = {
|
||||
name_for_explicit_dependency_source => vertex.explicit_requirements,
|
||||
name_for_locking_dependency_source => Array(locked_requirement_named(name)),
|
||||
}
|
||||
vertex.incoming_edges.each { |edge| (requirements[edge.origin.payload] ||= []).unshift(*edge.requirements) }
|
||||
conflicts[name] = Conflict.new(
|
||||
requirement,
|
||||
Hash[requirements.select { |_, r| !r.empty? }],
|
||||
vertex.payload,
|
||||
possibility,
|
||||
locked_requirement_named(name),
|
||||
requirement_trees
|
||||
)
|
||||
end
|
||||
|
||||
# @return [Array<Array<Object>>] The different requirement
|
||||
# trees that led to every requirement for the current spec.
|
||||
def requirement_trees
|
||||
activated.vertex_named(name).requirements.map { |r| requirement_tree_for(r) }
|
||||
end
|
||||
|
||||
# @return [Array<Object>] the list of requirements that led to
|
||||
# `requirement` being required.
|
||||
def requirement_tree_for(requirement)
|
||||
tree = []
|
||||
while requirement
|
||||
tree.unshift(requirement)
|
||||
requirement = parent_of(requirement)
|
||||
end
|
||||
tree
|
||||
end
|
||||
|
||||
# Indicates progress roughly once every second
|
||||
# @return [void]
|
||||
def indicate_progress
|
||||
@iteration_counter += 1
|
||||
@progress_rate ||= resolver_ui.progress_rate
|
||||
if iteration_rate.nil?
|
||||
if Time.now - started_at >= @progress_rate
|
||||
self.iteration_rate = @iteration_counter
|
||||
end
|
||||
end
|
||||
|
||||
if iteration_rate && (@iteration_counter % iteration_rate) == 0
|
||||
resolver_ui.indicate_progress
|
||||
end
|
||||
end
|
||||
|
||||
# Calls the {#resolver_ui}'s {UI#debug} method
|
||||
# @param [Integer] depth the depth of the {#states} stack
|
||||
# @param [Proc] block a block that yields a {#to_s}
|
||||
# @return [void]
|
||||
def debug(depth = 0, &block)
|
||||
resolver_ui.debug(depth, &block)
|
||||
end
|
||||
|
||||
# Attempts to activate the current {#possibility}
|
||||
# @return [void]
|
||||
def attempt_to_activate
|
||||
debug(depth) { 'Attempting to activate ' + possibility.to_s }
|
||||
existing_node = activated.vertex_named(name)
|
||||
if existing_node.payload
|
||||
debug(depth) { "Found existing spec (#{existing_node.payload})" }
|
||||
attempt_to_activate_existing_spec(existing_node)
|
||||
else
|
||||
attempt_to_activate_new_spec
|
||||
end
|
||||
end
|
||||
|
||||
# Attempts to activate the current {#possibility} (given that it has
|
||||
# already been activated)
|
||||
# @return [void]
|
||||
def attempt_to_activate_existing_spec(existing_node)
|
||||
existing_spec = existing_node.payload
|
||||
if requirement_satisfied_by?(requirement, activated, existing_spec)
|
||||
new_requirements = requirements.dup
|
||||
push_state_for_requirements(new_requirements)
|
||||
else
|
||||
return if attempt_to_swap_possibility
|
||||
create_conflict
|
||||
debug(depth) { "Unsatisfied by existing spec (#{existing_node.payload})" }
|
||||
unwind_for_conflict
|
||||
end
|
||||
end
|
||||
|
||||
# Attempts to swp the current {#possibility} with the already-activated
|
||||
# spec with the given name
|
||||
# @return [Boolean] Whether the possibility was swapped into {#activated}
|
||||
def attempt_to_swap_possibility
|
||||
swapped = activated.dup
|
||||
swapped.vertex_named(name).payload = possibility
|
||||
return unless swapped.vertex_named(name).requirements.
|
||||
all? { |r| requirement_satisfied_by?(r, swapped, possibility) }
|
||||
attempt_to_activate_new_spec
|
||||
end
|
||||
|
||||
# Attempts to activate the current {#possibility} (given that it hasn't
|
||||
# already been activated)
|
||||
# @return [void]
|
||||
def attempt_to_activate_new_spec
|
||||
satisfied = begin
|
||||
locked_requirement = locked_requirement_named(name)
|
||||
requested_spec_satisfied = requirement_satisfied_by?(requirement, activated, possibility)
|
||||
locked_spec_satisfied = !locked_requirement ||
|
||||
requirement_satisfied_by?(locked_requirement, activated, possibility)
|
||||
debug(depth) { 'Unsatisfied by requested spec' } unless requested_spec_satisfied
|
||||
debug(depth) { 'Unsatisfied by locked spec' } unless locked_spec_satisfied
|
||||
requested_spec_satisfied && locked_spec_satisfied
|
||||
end
|
||||
if satisfied
|
||||
activate_spec
|
||||
else
|
||||
create_conflict
|
||||
unwind_for_conflict
|
||||
end
|
||||
end
|
||||
|
||||
# @param [String] requirement_name the spec name to search for
|
||||
# @return [Object] the locked spec named `requirement_name`, if one
|
||||
# is found on {#base}
|
||||
def locked_requirement_named(requirement_name)
|
||||
vertex = base.vertex_named(requirement_name)
|
||||
vertex && vertex.payload
|
||||
end
|
||||
|
||||
# Add the current {#possibility} to the dependency graph of the current
|
||||
# {#state}
|
||||
# @return [void]
|
||||
def activate_spec
|
||||
conflicts.delete(name)
|
||||
debug(depth) { 'Activated ' + name + ' at ' + possibility.to_s }
|
||||
vertex = activated.vertex_named(name)
|
||||
vertex.payload = possibility
|
||||
require_nested_dependencies_for(possibility)
|
||||
end
|
||||
|
||||
# Requires the dependencies that the recently activated spec has
|
||||
# @param [Object] activated_spec the specification that has just been
|
||||
# activated
|
||||
# @return [void]
|
||||
def require_nested_dependencies_for(activated_spec)
|
||||
nested_dependencies = dependencies_for(activated_spec)
|
||||
debug(depth) { "Requiring nested dependencies (#{nested_dependencies.map(&:to_s).join(', ')})" }
|
||||
nested_dependencies.each { |d| activated.add_child_vertex name_for(d), nil, [name_for(activated_spec)], d }
|
||||
|
||||
push_state_for_requirements(requirements + nested_dependencies)
|
||||
end
|
||||
|
||||
# Pushes a new {DependencyState} that encapsulates both existing and new
|
||||
# requirements
|
||||
# @param [Array] new_requirements
|
||||
# @return [void]
|
||||
def push_state_for_requirements(new_requirements, new_activated = activated.dup)
|
||||
new_requirements = sort_dependencies(new_requirements.uniq, new_activated, conflicts)
|
||||
new_requirement = new_requirements.shift
|
||||
new_name = new_requirement ? name_for(new_requirement) : ''
|
||||
possibilities = new_requirement ? search_for(new_requirement) : []
|
||||
handle_missing_or_push_dependency_state DependencyState.new(
|
||||
new_name, new_requirements, new_activated,
|
||||
new_requirement, possibilities, depth, conflicts.dup
|
||||
)
|
||||
end
|
||||
|
||||
# Pushes a new {DependencyState}.
|
||||
# If the {#specification_provider} says to
|
||||
# {SpecificationProvider#allow_missing?} that particular requirement, and
|
||||
# there are no possibilities for that requirement, then `state` is not
|
||||
# pushed, and the node in {#activated} is removed, and we continue
|
||||
# resolving the remaining requirements.
|
||||
# @param [DependencyState] state
|
||||
# @return [void]
|
||||
def handle_missing_or_push_dependency_state(state)
|
||||
if state.requirement && state.possibilities.empty? && allow_missing?(state.requirement)
|
||||
state.activated.detach_vertex_named(state.name)
|
||||
push_state_for_requirements(state.requirements, state.activated)
|
||||
else
|
||||
states.push state
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
43
lib/rubygems/resolver/molinillo/lib/molinillo/resolver.rb
Normal file
43
lib/rubygems/resolver/molinillo/lib/molinillo/resolver.rb
Normal file
|
@ -0,0 +1,43 @@
|
|||
require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph'
|
||||
|
||||
module Gem::Resolver::Molinillo
|
||||
# This class encapsulates a dependency resolver.
|
||||
# The resolver is responsible for determining which set of dependencies to
|
||||
# activate, with feedback from the the {#specification_provider}
|
||||
#
|
||||
#
|
||||
class Resolver
|
||||
require 'rubygems/resolver/molinillo/lib/molinillo/resolution'
|
||||
|
||||
# @return [SpecificationProvider] the specification provider used
|
||||
# in the resolution process
|
||||
attr_reader :specification_provider
|
||||
|
||||
# @return [UI] the UI module used to communicate back to the user
|
||||
# during the resolution process
|
||||
attr_reader :resolver_ui
|
||||
|
||||
# @param [SpecificationProvider] specification_provider
|
||||
# see {#specification_provider}
|
||||
# @param [UI] resolver_ui
|
||||
# see {#resolver_ui}
|
||||
def initialize(specification_provider, resolver_ui)
|
||||
@specification_provider = specification_provider
|
||||
@resolver_ui = resolver_ui
|
||||
end
|
||||
|
||||
# Resolves the requested dependencies into a {DependencyGraph},
|
||||
# locking to the base dependency graph (if specified)
|
||||
# @param [Array] requested an array of 'requested' dependencies that the
|
||||
# {#specification_provider} can understand
|
||||
# @param [DependencyGraph,nil] base the base dependency graph to which
|
||||
# dependencies should be 'locked'
|
||||
def resolve(requested, base = DependencyGraph.new)
|
||||
Resolution.new(specification_provider,
|
||||
resolver_ui,
|
||||
requested,
|
||||
base).
|
||||
resolve
|
||||
end
|
||||
end
|
||||
end
|
51
lib/rubygems/resolver/molinillo/lib/molinillo/state.rb
Normal file
51
lib/rubygems/resolver/molinillo/lib/molinillo/state.rb
Normal file
|
@ -0,0 +1,51 @@
|
|||
module Gem::Resolver::Molinillo
|
||||
# A state that a {Resolution} can be in
|
||||
# @attr [String] name
|
||||
# @attr [Array<Object>] requirements
|
||||
# @attr [DependencyGraph] activated
|
||||
# @attr [Object] requirement
|
||||
# @attr [Object] possibility
|
||||
# @attr [Integer] depth
|
||||
# @attr [Set<Object>] conflicts
|
||||
ResolutionState = Struct.new(
|
||||
:name,
|
||||
:requirements,
|
||||
:activated,
|
||||
:requirement,
|
||||
:possibilities,
|
||||
:depth,
|
||||
:conflicts
|
||||
)
|
||||
|
||||
class ResolutionState
|
||||
# Returns an empty resolution state
|
||||
# @return [ResolutionState] an empty state
|
||||
def self.empty
|
||||
new(nil, [], DependencyGraph.new, nil, nil, 0, Set.new)
|
||||
end
|
||||
end
|
||||
|
||||
# A state that encapsulates a set of {#requirements} with an {Array} of
|
||||
# possibilities
|
||||
class DependencyState < ResolutionState
|
||||
# Removes a possibility from `self`
|
||||
# @return [PossibilityState] a state with a single possibility,
|
||||
# the possibility that was removed from `self`
|
||||
def pop_possibility_state
|
||||
PossibilityState.new(
|
||||
name,
|
||||
requirements.dup,
|
||||
activated.dup,
|
||||
requirement,
|
||||
[possibilities.pop],
|
||||
depth + 1,
|
||||
conflicts.dup
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# A state that encapsulates a single possibility to fulfill the given
|
||||
# {#requirement}
|
||||
class PossibilityState < ResolutionState
|
||||
end
|
||||
end
|
|
@ -89,7 +89,7 @@ class Gem::Resolver::Specification
|
|||
|
||||
gem = source.download spec, destination
|
||||
|
||||
installer = Gem::Installer.new gem, options
|
||||
installer = Gem::Installer.at gem, options
|
||||
|
||||
yield installer if block_given?
|
||||
|
||||
|
|
|
@ -12,7 +12,8 @@ require 'rubygems/platform'
|
|||
require 'rubygems/deprecate'
|
||||
require 'rubygems/basic_specification'
|
||||
require 'rubygems/stub_specification'
|
||||
require 'rubygems/util/stringio'
|
||||
require 'rubygems/util/list'
|
||||
require 'stringio'
|
||||
|
||||
##
|
||||
# The Specification class contains the information for a Gem. Typically
|
||||
|
@ -172,6 +173,8 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
@@default_value[k].nil?
|
||||
}
|
||||
|
||||
@@stubs_by_name = {}
|
||||
|
||||
######################################################################
|
||||
# :section: Required gemspec attributes
|
||||
|
||||
|
@ -345,7 +348,7 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
add_bindir(@executables),
|
||||
@extra_rdoc_files,
|
||||
@extensions,
|
||||
].flatten.uniq.compact.sort
|
||||
].flatten.compact.uniq.sort
|
||||
end
|
||||
|
||||
######################################################################
|
||||
|
@ -729,12 +732,57 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
end
|
||||
end
|
||||
|
||||
def self.each_stub(dirs) # :nodoc:
|
||||
each_gemspec(dirs) do |path|
|
||||
stub = Gem::StubSpecification.new(path)
|
||||
yield stub if stub.valid?
|
||||
def self.gemspec_stubs_in dir, pattern
|
||||
Dir[File.join(dir, pattern)].map { |path|
|
||||
if dir == default_specifications_dir
|
||||
Gem::StubSpecification.default_gemspec_stub(path)
|
||||
else
|
||||
Gem::StubSpecification.gemspec_stub(path)
|
||||
end
|
||||
}.select(&:valid?)
|
||||
end
|
||||
private_class_method :gemspec_stubs_in
|
||||
|
||||
if [].respond_to? :flat_map
|
||||
def self.map_stubs(dirs, pattern) # :nodoc:
|
||||
dirs.flat_map { |dir| gemspec_stubs_in(dir, pattern) }
|
||||
end
|
||||
else # FIXME: remove when 1.8 is dropped
|
||||
def self.map_stubs(dirs, pattern) # :nodoc:
|
||||
dirs.map { |dir| gemspec_stubs_in(dir, pattern) }.flatten 1
|
||||
end
|
||||
end
|
||||
private_class_method :map_stubs
|
||||
|
||||
uniq_takes_a_block = false
|
||||
[1,2].uniq { uniq_takes_a_block = true }
|
||||
|
||||
if uniq_takes_a_block
|
||||
def self.uniq_by(list, &block) # :nodoc:
|
||||
list.uniq(&block)
|
||||
end
|
||||
else # FIXME: remove when 1.8 is dropped
|
||||
def self.uniq_by(list) # :nodoc:
|
||||
values = {}
|
||||
list.each { |item|
|
||||
value = yield item
|
||||
values[value] ||= item
|
||||
}
|
||||
values.values
|
||||
end
|
||||
end
|
||||
private_class_method :uniq_by
|
||||
|
||||
if [].respond_to? :sort_by!
|
||||
def self.sort_by! list, &block
|
||||
list.sort_by!(&block)
|
||||
end
|
||||
else # FIXME: remove when 1.8 is dropped
|
||||
def self.sort_by! list, &block
|
||||
list.replace list.sort_by(&block)
|
||||
end
|
||||
end
|
||||
private_class_method :sort_by!
|
||||
|
||||
def self.each_spec(dirs) # :nodoc:
|
||||
each_gemspec(dirs) do |path|
|
||||
|
@ -748,17 +796,33 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
|
||||
def self.stubs
|
||||
@@stubs ||= begin
|
||||
stubs = {}
|
||||
each_stub([default_specifications_dir] + dirs) do |stub|
|
||||
stubs[stub.full_name] ||= stub
|
||||
end
|
||||
stubs = map_stubs([default_specifications_dir] + dirs, "*.gemspec")
|
||||
stubs = uniq_by(stubs) { |stub| stub.full_name }
|
||||
|
||||
stubs = stubs.values
|
||||
_resort!(stubs)
|
||||
@@stubs_by_name = stubs.group_by(&:name)
|
||||
stubs
|
||||
end
|
||||
end
|
||||
|
||||
EMPTY = [].freeze # :nodoc:
|
||||
|
||||
##
|
||||
# Returns a Gem::StubSpecification for installed gem named +name+
|
||||
|
||||
def self.stubs_for name
|
||||
if @@stubs || @@stubs_by_name[name]
|
||||
@@stubs_by_name[name] || []
|
||||
else
|
||||
stubs = map_stubs([default_specifications_dir] + dirs, "#{name}-*.gemspec")
|
||||
stubs = uniq_by(stubs) { |stub| stub.full_name }.group_by(&:name)
|
||||
stubs.each_value { |v| sort_by!(v) { |i| i.version } }
|
||||
|
||||
@@stubs_by_name.merge! stubs
|
||||
@@stubs_by_name[name] ||= EMPTY
|
||||
end
|
||||
end
|
||||
|
||||
def self._resort!(specs) # :nodoc:
|
||||
specs.sort! { |a, b|
|
||||
names = a.name <=> b.name
|
||||
|
@ -783,6 +847,7 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
# properly sorted.
|
||||
|
||||
def self.add_spec spec
|
||||
warn "Gem::Specification.add_spec is deprecated and will be removed in Rubygems 3.0" unless Gem::Deprecate.skip
|
||||
# TODO: find all extraneous adds
|
||||
# puts
|
||||
# p :add_spec => [spec.full_name, caller.reject { |s| s =~ /minitest/ }]
|
||||
|
@ -797,6 +862,8 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
|
||||
_all << spec
|
||||
stubs << spec
|
||||
(@@stubs_by_name[spec.name] ||= []) << spec
|
||||
sort_by!(@@stubs_by_name[spec.name]) { |s| s.version }
|
||||
_resort!(_all)
|
||||
_resort!(stubs)
|
||||
end
|
||||
|
@ -805,14 +872,18 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
# Adds multiple specs to the known specifications.
|
||||
|
||||
def self.add_specs *specs
|
||||
warn "Gem::Specification.add_specs is deprecated and will be removed in Rubygems 3.0" unless Gem::Deprecate.skip
|
||||
|
||||
raise "nil spec!" if specs.any?(&:nil?) # TODO: remove once we're happy
|
||||
|
||||
# TODO: this is much more efficient, but we need the extra checks for now
|
||||
# _all.concat specs
|
||||
# _resort!
|
||||
|
||||
specs.each do |spec| # TODO: slow
|
||||
add_spec spec
|
||||
Gem::Deprecate.skip_during do
|
||||
specs.each do |spec| # TODO: slow
|
||||
add_spec spec
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -839,6 +910,7 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
# -- wilsonb
|
||||
|
||||
def self.all= specs
|
||||
@@stubs_by_name = specs.group_by(&:name)
|
||||
@@all = @@stubs = specs
|
||||
end
|
||||
|
||||
|
@ -927,9 +999,10 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
# Return the best specification that contains the file matching +path+.
|
||||
|
||||
def self.find_by_path path
|
||||
self.find { |spec|
|
||||
stub = stubs.find { |spec|
|
||||
spec.contains_requirable_file? path
|
||||
}
|
||||
stub && stub.to_spec
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -961,15 +1034,13 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
specs = unresolved_deps.values.map { |dep| dep.to_specs }.flatten
|
||||
|
||||
specs.reverse_each do |spec|
|
||||
trails = []
|
||||
spec.traverse do |from_spec, dep, to_spec, trail|
|
||||
next unless to_spec.conflicts.empty?
|
||||
trails << trail if to_spec.contains_requirable_file? path
|
||||
if to_spec.has_conflicts? || to_spec.conficts_when_loaded_with?(trail)
|
||||
:next
|
||||
else
|
||||
return trail.reverse if to_spec.contains_requirable_file? path
|
||||
end
|
||||
end
|
||||
|
||||
next if trails.empty?
|
||||
|
||||
return trails.map(&:reverse).sort.first.reverse
|
||||
end
|
||||
|
||||
[]
|
||||
|
@ -1008,10 +1079,14 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
# +prerelease+ is true.
|
||||
|
||||
def self.latest_specs prerelease = false
|
||||
_latest_specs Gem::Specification._all, prerelease
|
||||
end
|
||||
|
||||
def self._latest_specs specs, prerelease = false # :nodoc:
|
||||
result = Hash.new { |h,k| h[k] = {} }
|
||||
native = {}
|
||||
|
||||
Gem::Specification.reverse_each do |spec|
|
||||
specs.reverse_each do |spec|
|
||||
next if spec.version.prerelease? unless prerelease
|
||||
|
||||
native[spec.name] = spec.version if spec.platform == Gem::Platform::RUBY
|
||||
|
@ -1029,12 +1104,13 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
|
||||
def self.load file
|
||||
return unless file
|
||||
file = file.dup.untaint
|
||||
return unless File.file?(file)
|
||||
|
||||
_spec = LOAD_CACHE[file]
|
||||
return _spec if _spec
|
||||
|
||||
file = file.dup.untaint
|
||||
return unless File.file?(file)
|
||||
|
||||
code = if defined? Encoding
|
||||
File.read file, :mode => 'r:UTF-8:-'
|
||||
else
|
||||
|
@ -1126,8 +1202,11 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
# Removes +spec+ from the known specs.
|
||||
|
||||
def self.remove_spec spec
|
||||
warn "Gem::Specification.remove_spec is deprecated and will be removed in Rubygems 3.0" unless Gem::Deprecate.skip
|
||||
_all.delete spec
|
||||
stubs.delete_if { |s| s.full_name == spec.full_name }
|
||||
(@@stubs_by_name[spec.name] || []).delete_if { |s| s.full_name == spec.full_name }
|
||||
reset
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -1153,6 +1232,7 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
Gem.pre_reset_hooks.each { |hook| hook.call }
|
||||
@@all = nil
|
||||
@@stubs = nil
|
||||
@@stubs_by_name = {}
|
||||
_clear_load_cache
|
||||
unresolved = unresolved_deps
|
||||
unless unresolved.empty? then
|
||||
|
@ -1563,6 +1643,30 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
conflicts
|
||||
end
|
||||
|
||||
##
|
||||
# return true if there will be conflict when spec if loaded together with the list of specs.
|
||||
|
||||
def conficts_when_loaded_with?(list_of_specs) # :nodoc:
|
||||
result = list_of_specs.any? { |spec|
|
||||
spec.dependencies.any? { |dep| dep.runtime? && (dep.name == name) && !satisfies_requirement?(dep) }
|
||||
}
|
||||
result
|
||||
end
|
||||
|
||||
##
|
||||
# Return true if there are possible conflicts against the currently loaded specs.
|
||||
|
||||
def has_conflicts?
|
||||
self.dependencies.any? { |dep|
|
||||
if dep.runtime? then
|
||||
spec = Gem.loaded_specs[dep.name]
|
||||
spec and not spec.satisfies_requirement? dep
|
||||
else
|
||||
false
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
##
|
||||
# The date this gem was created. Lazily defaults to the current UTC date.
|
||||
#
|
||||
|
@ -1883,9 +1987,10 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
# +version+.
|
||||
|
||||
def initialize name = nil, version = nil
|
||||
super()
|
||||
@loaded = false
|
||||
@activated = false
|
||||
self.loaded_from = nil
|
||||
@loaded_from = nil
|
||||
@original_platform = nil
|
||||
@installed_by_version = nil
|
||||
|
||||
|
@ -1951,20 +2056,6 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Returns a string usable in Dir.glob to match all requirable paths
|
||||
# for this spec.
|
||||
|
||||
def lib_dirs_glob
|
||||
dirs = if self.require_paths.size > 1 then
|
||||
"{#{self.require_paths.join(',')}}"
|
||||
else
|
||||
self.require_paths.first
|
||||
end
|
||||
|
||||
"#{self.full_gem_path}/#{dirs}"
|
||||
end
|
||||
|
||||
##
|
||||
# Files in the Gem under one of the require_paths
|
||||
|
||||
|
@ -1992,9 +2083,8 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
@licenses ||= []
|
||||
end
|
||||
|
||||
def loaded_from= path # :nodoc:
|
||||
def internal_init # :nodoc:
|
||||
super
|
||||
|
||||
@bin_dir = nil
|
||||
@cache_dir = nil
|
||||
@cache_file = nil
|
||||
|
@ -2011,16 +2101,6 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
@rubygems_version = Gem::VERSION
|
||||
end
|
||||
|
||||
##
|
||||
# Return all files in this gem that match for +glob+.
|
||||
|
||||
def matches_for_glob glob # TODO: rename?
|
||||
# TODO: do we need these?? Kill it
|
||||
glob = File.join(self.lib_dirs_glob, glob)
|
||||
|
||||
Dir[glob].map { |f| f.untaint } # FIX our tests are broken, run w/ SAFE=1
|
||||
end
|
||||
|
||||
##
|
||||
# Warn about unknown attributes while loading a spec.
|
||||
|
||||
|
@ -2154,10 +2234,8 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
# Check the spec for possible conflicts and freak out if there are any.
|
||||
|
||||
def raise_if_conflicts # :nodoc:
|
||||
conf = self.conflicts
|
||||
|
||||
unless conf.empty? then
|
||||
raise Gem::ConflictError.new self, conf
|
||||
if has_conflicts? then
|
||||
raise Gem::ConflictError.new self, conflicts
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -2234,7 +2312,7 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
# List of dependencies that will automatically be activated at runtime.
|
||||
|
||||
def runtime_dependencies
|
||||
dependencies.select { |d| d.type == :runtime }
|
||||
dependencies.select(&:runtime?)
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -2461,7 +2539,7 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
builder << self
|
||||
ast = builder.tree
|
||||
|
||||
io = Gem::StringSink.new
|
||||
io = StringIO.new
|
||||
io.set_encoding Encoding::UTF_8 if Object.const_defined? :Encoding
|
||||
|
||||
Psych::Visitors::Emitter.new(io).accept(ast)
|
||||
|
@ -2480,14 +2558,28 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
# Recursively walk dependencies of this spec, executing the +block+ for each
|
||||
# hop.
|
||||
|
||||
def traverse trail = [], &block
|
||||
trail = trail + [self]
|
||||
runtime_dependencies.each do |dep|
|
||||
dep.to_specs.each do |dep_spec|
|
||||
block[self, dep, dep_spec, trail + [dep_spec]]
|
||||
dep_spec.traverse(trail, &block) unless
|
||||
trail.map(&:name).include? dep_spec.name
|
||||
def traverse trail = [], visited = {}, &block
|
||||
trail.push(self)
|
||||
begin
|
||||
dependencies.each do |dep|
|
||||
dep.to_specs.reverse_each do |dep_spec|
|
||||
next if visited.has_key?(dep_spec)
|
||||
visited[dep_spec] = true
|
||||
trail.push(dep_spec)
|
||||
begin
|
||||
result = block[self, dep, dep_spec, trail]
|
||||
ensure
|
||||
trail.pop
|
||||
end
|
||||
unless result == :next
|
||||
spec_name = dep_spec.name
|
||||
dep_spec.traverse(trail, visited, &block) unless
|
||||
trail.any? { |s| s.name == spec_name }
|
||||
end
|
||||
end
|
||||
end
|
||||
ensure
|
||||
trail.pop
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -2535,13 +2627,13 @@ class Gem::Specification < Gem::BasicSpecification
|
|||
'specification must have at least one require_path'
|
||||
end
|
||||
|
||||
@files.delete_if { |x| File.directory?(x) }
|
||||
@test_files.delete_if { |x| File.directory?(x) }
|
||||
@files.delete_if { |x| File.directory?(x) && !File.symlink?(x) }
|
||||
@test_files.delete_if { |x| File.directory?(x) && !File.symlink?(x) }
|
||||
@executables.delete_if { |x| File.directory?(File.join(@bindir, x)) }
|
||||
@extra_rdoc_files.delete_if { |x| File.directory?(x) }
|
||||
@extensions.delete_if { |x| File.directory?(x) }
|
||||
@extra_rdoc_files.delete_if { |x| File.directory?(x) && !File.symlink?(x) }
|
||||
@extensions.delete_if { |x| File.directory?(x) && !File.symlink?(x) }
|
||||
|
||||
non_files = files.reject { |x| File.file?(x) }
|
||||
non_files = files.reject { |x| File.file?(x) || File.symlink?(x) }
|
||||
|
||||
unless not packaging or non_files.empty? then
|
||||
raise Gem::InvalidSpecificationException,
|
||||
|
@ -2676,6 +2768,11 @@ http://opensource.org/licenses/alphabetical
|
|||
warning "#{executable_path} is missing #! line" unless shebang
|
||||
end
|
||||
|
||||
files.each do |file|
|
||||
next unless File.symlink?(file)
|
||||
warning "#{file} is a symlink, which is not supported on all platforms"
|
||||
end
|
||||
|
||||
validate_dependencies
|
||||
|
||||
true
|
||||
|
@ -2761,12 +2858,14 @@ open-ended dependency on #{dep} is not recommended
|
|||
return if Gem.win_platform?
|
||||
|
||||
files.each do |file|
|
||||
next unless File.file?(file)
|
||||
next if File.stat(file).mode & 0444 == 0444
|
||||
warning "#{file} is not world-readable"
|
||||
end
|
||||
|
||||
executables.each do |name|
|
||||
exec = File.join @bindir, name
|
||||
next unless File.file?(exec)
|
||||
next if File.stat(exec).executable?
|
||||
warning "#{exec} is not executable"
|
||||
end
|
||||
|
|
|
@ -15,35 +15,32 @@ class Gem::StubSpecification < Gem::BasicSpecification
|
|||
end
|
||||
|
||||
class StubLine # :nodoc: all
|
||||
attr_reader :parts
|
||||
attr_reader :name, :version, :platform, :require_paths
|
||||
|
||||
def initialize(data)
|
||||
@parts = data[PREFIX.length..-1].split(" ")
|
||||
end
|
||||
|
||||
def name
|
||||
@parts[0]
|
||||
end
|
||||
|
||||
def version
|
||||
Gem::Version.new @parts[1]
|
||||
end
|
||||
|
||||
def platform
|
||||
Gem::Platform.new @parts[2]
|
||||
end
|
||||
|
||||
def require_paths
|
||||
@parts[3..-1].join(" ").split("\0")
|
||||
parts = data[PREFIX.length..-1].split(" ")
|
||||
@name = parts[0]
|
||||
@version = Gem::Version.new parts[1]
|
||||
@platform = Gem::Platform.new parts[2]
|
||||
@require_paths = parts.drop(3).join(" ").split("\0")
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(filename)
|
||||
def self.default_gemspec_stub filename
|
||||
new filename, true
|
||||
end
|
||||
|
||||
def self.gemspec_stub filename
|
||||
new filename, false
|
||||
end
|
||||
|
||||
def initialize filename, default_gem
|
||||
self.loaded_from = filename
|
||||
@data = nil
|
||||
@extensions = nil
|
||||
@name = nil
|
||||
@spec = nil
|
||||
@default_gem = default_gem
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -57,6 +54,10 @@ class Gem::StubSpecification < Gem::BasicSpecification
|
|||
end
|
||||
end
|
||||
|
||||
def default_gem?
|
||||
@default_gem
|
||||
end
|
||||
|
||||
def build_extensions # :nodoc:
|
||||
return if default_gem?
|
||||
return if extensions.empty?
|
||||
|
@ -135,14 +136,14 @@ class Gem::StubSpecification < Gem::BasicSpecification
|
|||
# Name of the gem
|
||||
|
||||
def name
|
||||
@name ||= data.name
|
||||
data.name
|
||||
end
|
||||
|
||||
##
|
||||
# Platform of the gem
|
||||
|
||||
def platform
|
||||
@platform ||= data.platform
|
||||
data.platform
|
||||
end
|
||||
|
||||
##
|
||||
|
|
|
@ -36,6 +36,7 @@ require 'shellwords'
|
|||
require 'tmpdir'
|
||||
require 'uri'
|
||||
require 'zlib'
|
||||
require 'benchmark' # stdlib
|
||||
|
||||
Gem.load_yaml
|
||||
|
||||
|
@ -275,6 +276,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase
|
|||
@orig_ENV_HOME = ENV['HOME']
|
||||
ENV['HOME'] = @userhome
|
||||
Gem.instance_variable_set :@user_home, nil
|
||||
Gem.instance_variable_set :@gemdeps, nil
|
||||
Gem.send :remove_instance_variable, :@ruby_version if
|
||||
Gem.instance_variables.include? :@ruby_version
|
||||
|
||||
|
@ -329,6 +331,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase
|
|||
end
|
||||
|
||||
@marshal_version = "#{Marshal::MAJOR_VERSION}.#{Marshal::MINOR_VERSION}"
|
||||
@orig_LOADED_FEATURES = $LOADED_FEATURES.dup
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -337,6 +340,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase
|
|||
|
||||
def teardown
|
||||
$LOAD_PATH.replace @orig_LOAD_PATH if @orig_LOAD_PATH
|
||||
$LOADED_FEATURES.replace @orig_LOADED_FEATURES if @orig_LOADED_FEATURES
|
||||
|
||||
if @orig_BASERUBY
|
||||
RbConfig::CONFIG['BASERUBY'] = @orig_BASERUBY
|
||||
|
@ -373,6 +377,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase
|
|||
ENV['GEM_PRIVATE_KEY_PASSPHRASE'] = @orig_gem_private_key_passphrase
|
||||
|
||||
Gem::Specification._clear_load_cache
|
||||
Gem::Specification.unresolved_deps.clear
|
||||
end
|
||||
|
||||
def common_installer_setup
|
||||
|
@ -488,7 +493,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase
|
|||
gem = File.join(@tempdir, File.basename(spec.cache_file)).untaint
|
||||
end
|
||||
|
||||
Gem::Installer.new(gem, options.merge({:wrappers => true})).install
|
||||
Gem::Installer.at(gem, options.merge({:wrappers => true})).install
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -503,8 +508,11 @@ class Gem::TestCase < MiniTest::Unit::TestCase
|
|||
def uninstall_gem spec
|
||||
require 'rubygems/uninstaller'
|
||||
|
||||
Gem::Uninstaller.new(spec.name,
|
||||
:executables => true, :user_install => true).uninstall
|
||||
Class.new(Gem::Uninstaller) {
|
||||
def ask_if_ok spec
|
||||
true
|
||||
end
|
||||
}.new(spec.name, :executables => true, :user_install => true).uninstall
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -598,7 +606,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase
|
|||
|
||||
spec.loaded_from = spec.loaded_from = written_path
|
||||
|
||||
Gem::Specification.add_spec spec.for_cache
|
||||
Gem::Specification.reset
|
||||
|
||||
return spec
|
||||
end
|
||||
|
@ -654,7 +662,10 @@ class Gem::TestCase < MiniTest::Unit::TestCase
|
|||
# Install the provided specs
|
||||
|
||||
def install_specs(*specs)
|
||||
Gem::Specification.add_specs(*specs)
|
||||
specs.each do |spec|
|
||||
Gem::Installer.for_spec(spec).install
|
||||
end
|
||||
|
||||
Gem.searcher = nil
|
||||
end
|
||||
|
||||
|
@ -675,8 +686,9 @@ class Gem::TestCase < MiniTest::Unit::TestCase
|
|||
# Install the provided default specs
|
||||
|
||||
def install_default_specs(*specs)
|
||||
install_specs(*specs)
|
||||
specs.each do |spec|
|
||||
installer = Gem::Installer.for_spec(spec, :install_as_default => true)
|
||||
installer.install
|
||||
Gem.register_default_spec(spec)
|
||||
end
|
||||
end
|
||||
|
@ -788,9 +800,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
spec.loaded_from = spec.spec_file
|
||||
|
||||
Gem::Specification.add_spec spec
|
||||
Gem::Specification.reset
|
||||
|
||||
return spec
|
||||
end
|
||||
|
@ -977,14 +987,13 @@ Also, a list:
|
|||
# Best used with +@all_gems+ from #util_setup_fake_fetcher.
|
||||
|
||||
def util_setup_spec_fetcher(*specs)
|
||||
specs -= Gem::Specification._all
|
||||
Gem::Specification.add_specs(*specs)
|
||||
all_specs = Gem::Specification.to_a + specs
|
||||
Gem::Specification._resort! all_specs
|
||||
|
||||
spec_fetcher = Gem::SpecFetcher.fetcher
|
||||
|
||||
prerelease, all = Gem::Specification.partition { |spec|
|
||||
spec.version.prerelease?
|
||||
}
|
||||
prerelease, all = all_specs.partition { |spec| spec.version.prerelease? }
|
||||
latest = Gem::Specification._latest_specs all_specs
|
||||
|
||||
spec_fetcher.specs[@uri] = []
|
||||
all.each do |spec|
|
||||
|
@ -992,7 +1001,7 @@ Also, a list:
|
|||
end
|
||||
|
||||
spec_fetcher.latest_specs[@uri] = []
|
||||
Gem::Specification.latest_specs.each do |spec|
|
||||
latest.each do |spec|
|
||||
spec_fetcher.latest_specs[@uri] << spec.name_tuple
|
||||
end
|
||||
|
||||
|
@ -1008,7 +1017,7 @@ Also, a list:
|
|||
specs = all.map { |spec| spec.name_tuple }
|
||||
s_zip = util_gzip Marshal.dump Gem::NameTuple.to_basic specs
|
||||
|
||||
latest_specs = Gem::Specification.latest_specs.map do |spec|
|
||||
latest_specs = latest.map do |spec|
|
||||
spec.name_tuple
|
||||
end
|
||||
|
||||
|
@ -1023,7 +1032,7 @@ Also, a list:
|
|||
|
||||
v = Gem.marshal_version
|
||||
|
||||
Gem::Specification.each do |spec|
|
||||
all_specs.each do |spec|
|
||||
path = "#{@gem_repo}quick/Marshal.#{v}/#{spec.original_name}.gemspec.rz"
|
||||
data = Marshal.dump spec
|
||||
data_deflate = Zlib::Deflate.deflate data
|
||||
|
@ -1450,6 +1459,12 @@ begin
|
|||
rescue LoadError, Gem::LoadError
|
||||
end
|
||||
|
||||
begin
|
||||
gem 'builder'
|
||||
require 'builder/xchar'
|
||||
rescue LoadError, Gem::LoadError
|
||||
end
|
||||
|
||||
require 'rubygems/test_utilities'
|
||||
tmpdirs = []
|
||||
tmpdirs << (ENV['GEM_HOME'] = Dir.mktmpdir("home"))
|
||||
|
|
|
@ -186,7 +186,6 @@ end
|
|||
# f.gem 'a', 1
|
||||
# f.spec 'a', 2
|
||||
# f.gem 'b', 1' 'a' => '~> 1.0'
|
||||
# f.clear
|
||||
# end
|
||||
#
|
||||
# The above declaration creates two gems, a-1 and b-1, with a dependency from
|
||||
|
@ -214,18 +213,11 @@ class Gem::TestCase::SpecFetcherSetup
|
|||
@repository = repository
|
||||
|
||||
@gems = {}
|
||||
@downloaded = []
|
||||
@installed = []
|
||||
@operations = []
|
||||
end
|
||||
|
||||
##
|
||||
# Removes any created gems or specifications from Gem.dir (the default
|
||||
# install location).
|
||||
|
||||
def clear
|
||||
@operations << [:clear]
|
||||
end
|
||||
|
||||
##
|
||||
# Returns a Hash of created Specification full names and the corresponding
|
||||
# Specification.
|
||||
|
@ -254,9 +246,6 @@ class Gem::TestCase::SpecFetcherSetup
|
|||
def execute_operations # :nodoc:
|
||||
@operations.each do |operation, *arguments|
|
||||
case operation
|
||||
when :clear then
|
||||
@test.util_clear_gems
|
||||
@installed.clear
|
||||
when :gem then
|
||||
spec, gem = @test.util_gem(*arguments, &arguments.pop)
|
||||
|
||||
|
@ -264,6 +253,11 @@ class Gem::TestCase::SpecFetcherSetup
|
|||
|
||||
@gems[spec] = gem
|
||||
@installed << spec
|
||||
when :download then
|
||||
spec, gem = @test.util_gem(*arguments, &arguments.pop)
|
||||
|
||||
@gems[spec] = gem
|
||||
@downloaded << spec
|
||||
when :spec then
|
||||
spec = @test.util_spec(*arguments, &arguments.pop)
|
||||
|
||||
|
@ -286,6 +280,17 @@ class Gem::TestCase::SpecFetcherSetup
|
|||
@operations << [:gem, name, version, dependencies, block]
|
||||
end
|
||||
|
||||
##
|
||||
# Creates a gem with +name+, +version+ and +deps+. The created gem is
|
||||
# downloaded in to the cache directory but is not installed
|
||||
#
|
||||
# The specification will be yielded before gem creation for customization,
|
||||
# but only the block or the dependencies may be set, not both.
|
||||
|
||||
def download name, version, dependencies = nil, &block
|
||||
@operations << [:download, name, version, dependencies, block]
|
||||
end
|
||||
|
||||
##
|
||||
# Creates a legacy platform spec with the name 'pl' and version 1
|
||||
|
||||
|
@ -312,17 +317,12 @@ class Gem::TestCase::SpecFetcherSetup
|
|||
gem_repo, @test.gem_repo = @test.gem_repo, @repository
|
||||
@test.uri = URI @repository
|
||||
|
||||
@test.util_setup_spec_fetcher(*@gems.keys)
|
||||
@test.util_setup_spec_fetcher(*@downloaded)
|
||||
ensure
|
||||
@test.gem_repo = gem_repo
|
||||
@test.uri = URI gem_repo
|
||||
end
|
||||
|
||||
# This works around util_setup_spec_fetcher adding all created gems to the
|
||||
# installed set.
|
||||
Gem::Specification.reset
|
||||
Gem::Specification.add_specs(*@installed)
|
||||
|
||||
@gems.each do |spec, gem|
|
||||
next unless gem
|
||||
|
||||
|
|
|
@ -271,7 +271,7 @@ class Gem::Uninstaller
|
|||
|
||||
say "Successfully uninstalled #{spec.full_name}"
|
||||
|
||||
Gem::Specification.remove_spec spec
|
||||
Gem::Specification.reset
|
||||
end
|
||||
|
||||
##
|
||||
|
|
|
@ -10,8 +10,8 @@ module Gem::Util
|
|||
|
||||
def self.gunzip(data)
|
||||
require 'zlib'
|
||||
require 'rubygems/util/stringio'
|
||||
data = Gem::StringSource.new data
|
||||
require 'stringio'
|
||||
data = StringIO.new(data, 'r')
|
||||
|
||||
unzipped = Zlib::GzipReader.new(data).read
|
||||
unzipped.force_encoding Encoding::BINARY if Object.const_defined? :Encoding
|
||||
|
@ -23,8 +23,8 @@ module Gem::Util
|
|||
|
||||
def self.gzip(data)
|
||||
require 'zlib'
|
||||
require 'rubygems/util/stringio'
|
||||
zipped = Gem::StringSink.new
|
||||
require 'stringio'
|
||||
zipped = StringIO.new('','w')
|
||||
zipped.set_encoding Encoding::BINARY if Object.const_defined? :Encoding
|
||||
|
||||
Zlib::GzipWriter.wrap zipped do |io| io.write data end
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
module Gem
|
||||
List = Struct.new(:value, :tail)
|
||||
|
||||
class List
|
||||
include Enumerable
|
||||
attr_accessor :value, :tail
|
||||
|
||||
def initialize(value = nil, tail = nil)
|
||||
@value = value
|
||||
@tail = tail
|
||||
end
|
||||
|
||||
def each
|
||||
n = self
|
||||
while n
|
||||
|
@ -11,25 +17,7 @@ module Gem
|
|||
end
|
||||
|
||||
def to_a
|
||||
ary = []
|
||||
n = self
|
||||
while n
|
||||
ary.unshift n.value
|
||||
n = n.tail
|
||||
end
|
||||
|
||||
ary
|
||||
end
|
||||
|
||||
def find
|
||||
n = self
|
||||
while n
|
||||
v = n.value
|
||||
return v if yield(v)
|
||||
n = n.tail
|
||||
end
|
||||
|
||||
nil
|
||||
super.reverse
|
||||
end
|
||||
|
||||
def prepend(value)
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
class Gem::StringSink
|
||||
def initialize
|
||||
@string = ""
|
||||
end
|
||||
|
||||
attr_reader :string
|
||||
|
||||
def write(s)
|
||||
@string += s
|
||||
s.size
|
||||
end
|
||||
|
||||
def set_encoding(enc)
|
||||
@string.force_encoding enc
|
||||
end
|
||||
end
|
||||
|
||||
class Gem::StringSource
|
||||
def initialize(str)
|
||||
@string = str.dup
|
||||
end
|
||||
|
||||
def read(count=nil)
|
||||
if count
|
||||
@string.slice!(0,count)
|
||||
else
|
||||
s = @string
|
||||
@string = ""
|
||||
s
|
||||
end
|
||||
end
|
||||
|
||||
alias_method :readpartial, :read
|
||||
end
|
|
@ -232,11 +232,11 @@ class Gem::Version
|
|||
# same precision. Version "1.0" is not the same as version "1".
|
||||
|
||||
def eql? other
|
||||
self.class === other and @version == other.version
|
||||
self.class === other and @version == other._version
|
||||
end
|
||||
|
||||
def hash # :nodoc:
|
||||
@hash ||= segments.hash
|
||||
@version.hash
|
||||
end
|
||||
|
||||
def init_with coder # :nodoc:
|
||||
|
@ -333,7 +333,7 @@ class Gem::Version
|
|||
|
||||
def <=> other
|
||||
return unless Gem::Version === other
|
||||
return 0 if @version == other.version
|
||||
return 0 if @version == other._version
|
||||
|
||||
lhsegments = segments
|
||||
rhsegments = other.segments
|
||||
|
@ -357,4 +357,10 @@ class Gem::Version
|
|||
|
||||
return 0
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def _version
|
||||
@version
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,7 +16,7 @@ SIMPLE_GEM = <<-GEMDATA
|
|||
@directory = options[:directory] || Gem.dir
|
||||
@force = options[:force]
|
||||
|
||||
gem = Gem::Installer.new(__FILE__).install(@force, @directory)
|
||||
gem = Gem::Installer.at(__FILE__).install(@force, @directory)
|
||||
if options[:gen_rdoc]
|
||||
Gem::DocManager.new(gem).generate_rdoc
|
||||
end
|
||||
|
|
|
@ -37,7 +37,7 @@ class TestGem < Gem::TestCase
|
|||
c1 = new_spec "c", "1"
|
||||
c2 = new_spec "c", "2"
|
||||
|
||||
install_specs a1, b1, b2, c1, c2
|
||||
install_specs c1, c2, b1, b2, a1
|
||||
|
||||
a1.activate
|
||||
|
||||
|
@ -61,7 +61,7 @@ class TestGem < Gem::TestCase
|
|||
d1 = new_spec "d", "1", { "c" => "< 2" }, "lib/d.rb"
|
||||
d2 = new_spec "d", "2", { "c" => "< 2" }, "lib/d.rb" # this
|
||||
|
||||
install_specs a1, b1, b2, c1, c2, d1, d2
|
||||
install_specs c1, c2, b1, b2, d1, d2, a1
|
||||
|
||||
a1.activate
|
||||
|
||||
|
@ -90,6 +90,23 @@ class TestGem < Gem::TestCase
|
|||
assert_path_exists File.join(gemhome2, 'gems', 'a-1')
|
||||
end
|
||||
|
||||
def test_self_install_in_rescue
|
||||
spec_fetcher do |f|
|
||||
f.gem 'a', 1
|
||||
f.spec 'a', 2
|
||||
end
|
||||
|
||||
gemhome2 = "#{@gemhome}2"
|
||||
|
||||
installed =
|
||||
begin
|
||||
raise 'Error'
|
||||
rescue StandardError
|
||||
Gem.install 'a', '= 1', :install_dir => gemhome2
|
||||
end
|
||||
assert_equal %w[a-1], installed.map { |spec| spec.full_name }
|
||||
end
|
||||
|
||||
def test_require_missing
|
||||
save_loaded_features do
|
||||
assert_raises ::LoadError do
|
||||
|
@ -135,12 +152,12 @@ class TestGem < Gem::TestCase
|
|||
end
|
||||
|
||||
def test_self_bin_path_bin_name
|
||||
util_exec_gem
|
||||
install_specs util_exec_gem
|
||||
assert_equal @abin_path, Gem.bin_path('a', 'abin')
|
||||
end
|
||||
|
||||
def test_self_bin_path_bin_name_version
|
||||
util_exec_gem
|
||||
install_specs util_exec_gem
|
||||
assert_equal @abin_path, Gem.bin_path('a', 'abin', '4')
|
||||
end
|
||||
|
||||
|
@ -167,10 +184,11 @@ class TestGem < Gem::TestCase
|
|||
end
|
||||
|
||||
def test_self_bin_path_bin_file_gone_in_latest
|
||||
util_exec_gem
|
||||
util_spec 'a', '10' do |s|
|
||||
install_specs util_exec_gem
|
||||
spec = util_spec 'a', '10' do |s|
|
||||
s.executables = []
|
||||
end
|
||||
install_specs spec
|
||||
# Should not find a-10's non-abin (bug)
|
||||
assert_equal @abin_path, Gem.bin_path('a', 'abin')
|
||||
end
|
||||
|
@ -881,9 +899,23 @@ class TestGem < Gem::TestCase
|
|||
assert_equal %w[http://gems.example.com/], Gem.sources
|
||||
end
|
||||
|
||||
def test_try_activate_returns_true_for_activated_specs
|
||||
b = util_spec 'b', '1.0' do |spec|
|
||||
spec.files << 'lib/b.rb'
|
||||
end
|
||||
install_specs b
|
||||
|
||||
assert Gem.try_activate('b'), 'try_activate should return true'
|
||||
assert Gem.try_activate('b'), 'try_activate should still return true'
|
||||
end
|
||||
|
||||
def test_self_try_activate_missing_dep
|
||||
b = util_spec 'b', '1.0'
|
||||
a = util_spec 'a', '1.0', 'b' => '>= 1.0'
|
||||
|
||||
install_specs b, a
|
||||
uninstall_gem b
|
||||
|
||||
a_file = File.join a.gem_dir, 'lib', 'a_file.rb'
|
||||
|
||||
write_file a_file do |io|
|
||||
|
@ -898,12 +930,17 @@ class TestGem < Gem::TestCase
|
|||
end
|
||||
|
||||
def test_self_try_activate_missing_extensions
|
||||
util_spec 'ext', '1' do |s|
|
||||
spec = util_spec 'ext', '1' do |s|
|
||||
s.extensions = %w[ext/extconf.rb]
|
||||
s.mark_version
|
||||
s.installed_by_version = v('2.2')
|
||||
end
|
||||
|
||||
# write the spec without install to simulate a failed install
|
||||
write_file spec.spec_file do |io|
|
||||
io.write spec.to_ruby_for_cache
|
||||
end
|
||||
|
||||
_, err = capture_io do
|
||||
refute Gem.try_activate 'nonexistent'
|
||||
end
|
||||
|
@ -944,7 +981,7 @@ class TestGem < Gem::TestCase
|
|||
b = util_spec "b", "1", "c" => nil
|
||||
c = util_spec "c", "2"
|
||||
|
||||
install_specs a, b, c
|
||||
install_specs a, c, b
|
||||
|
||||
Gem.needs do |r|
|
||||
r.gem "a"
|
||||
|
@ -966,7 +1003,7 @@ class TestGem < Gem::TestCase
|
|||
d = new_spec "d", "1", {'e' => '= 1'}, "lib/d.rb"
|
||||
e = util_spec "e", "1"
|
||||
|
||||
install_specs a, b, c, d, e
|
||||
install_specs a, c, b, e, d
|
||||
|
||||
Gem.needs do |r|
|
||||
r.gem "a"
|
||||
|
@ -1372,16 +1409,21 @@ class TestGem < Gem::TestCase
|
|||
def test_use_gemdeps
|
||||
gem_deps_file = 'gem.deps.rb'.untaint
|
||||
spec = util_spec 'a', 1
|
||||
install_specs spec
|
||||
|
||||
spec = Gem::Specification.find { |s| s == spec }
|
||||
refute spec.activated?
|
||||
|
||||
open gem_deps_file, 'w' do |io|
|
||||
io.write 'gem "a"'
|
||||
end
|
||||
|
||||
assert_nil Gem.gemdeps
|
||||
|
||||
Gem.use_gemdeps gem_deps_file
|
||||
|
||||
assert spec.activated?
|
||||
refute_nil Gem.gemdeps
|
||||
end
|
||||
|
||||
def test_use_gemdeps_ENV
|
||||
|
@ -1430,6 +1472,8 @@ class TestGem < Gem::TestCase
|
|||
rubygems_gemdeps, ENV['RUBYGEMS_GEMDEPS'] = ENV['RUBYGEMS_GEMDEPS'], '-'
|
||||
|
||||
spec = util_spec 'a', 1
|
||||
install_specs spec
|
||||
spec = Gem::Specification.find { |s| s == spec }
|
||||
|
||||
refute spec.activated?
|
||||
|
||||
|
@ -1499,7 +1543,9 @@ You may need to `gem install -g` to install missing gems
|
|||
rubygems_gemdeps, ENV['RUBYGEMS_GEMDEPS'] = ENV['RUBYGEMS_GEMDEPS'], 'x'
|
||||
|
||||
spec = util_spec 'a', 1
|
||||
install_specs spec
|
||||
|
||||
spec = Gem::Specification.find { |s| s == spec }
|
||||
refute spec.activated?
|
||||
|
||||
open 'x', 'w' do |io|
|
||||
|
@ -1560,6 +1606,7 @@ You may need to `gem install -g` to install missing gems
|
|||
|
||||
@exec_path = File.join spec.full_gem_path, spec.bindir, 'exec'
|
||||
@abin_path = File.join spec.full_gem_path, spec.bindir, 'abin'
|
||||
spec
|
||||
end
|
||||
|
||||
def util_remove_interrupt_command
|
||||
|
|
|
@ -79,7 +79,8 @@ class TestGemAvailableSet < Gem::TestCase
|
|||
end
|
||||
|
||||
def test_remove_installed_bang
|
||||
a1, _ = util_gem 'a', '1'
|
||||
a1, _ = util_spec 'a', '1'
|
||||
install_specs a1
|
||||
|
||||
a1.activate
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
require 'rubygems/test_case'
|
||||
require 'rubygems/commands/cleanup_command'
|
||||
require 'rubygems/installer'
|
||||
|
||||
class TestGemCommandsCleanupCommand < Gem::TestCase
|
||||
|
||||
|
@ -78,8 +79,8 @@ class TestGemCommandsCleanupCommand < Gem::TestCase
|
|||
end
|
||||
|
||||
def test_execute_all_user
|
||||
@a_1_1 = util_spec 'a', '1.1'
|
||||
@a_1_1 = install_gem_user @a_1_1 # pick up user install path
|
||||
@a_1_1, = util_gem 'a', '1.1'
|
||||
@a_1_1 = install_gem @a_1_1 # pick up user install path
|
||||
|
||||
Gem::Specification.dirs = [Gem.dir, Gem.user_dir]
|
||||
|
||||
|
@ -97,8 +98,8 @@ class TestGemCommandsCleanupCommand < Gem::TestCase
|
|||
def test_execute_all_user_no_sudo
|
||||
FileUtils.chmod 0555, @gemhome
|
||||
|
||||
@a_1_1 = util_spec 'a', '1.1'
|
||||
@a_1_1 = install_gem_user @a_1_1 # pick up user install path
|
||||
@a_1_1, = util_gem 'a', '1.1'
|
||||
@a_1_1 = install_gem @a_1_1, :user_install => true # pick up user install path
|
||||
|
||||
Gem::Specification.dirs = [Gem.dir, Gem.user_dir]
|
||||
|
||||
|
@ -132,9 +133,9 @@ class TestGemCommandsCleanupCommand < Gem::TestCase
|
|||
s.add_dependency 'b', '1'
|
||||
end
|
||||
|
||||
install_gem @c
|
||||
install_gem @b_1
|
||||
install_gem @b_2
|
||||
install_gem @c
|
||||
|
||||
@cmd.options[:args] = []
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@ class TestGemCommandsDependencyCommand < Gem::TestCase
|
|||
end
|
||||
|
||||
def test_execute_no_args
|
||||
install_specs new_spec 'x', '2'
|
||||
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.spec 'a', 1
|
||||
fetcher.spec 'a', '2.a'
|
||||
|
@ -51,6 +53,8 @@ Gem dep_x-1
|
|||
|
||||
Gem pl-1-x86-linux
|
||||
|
||||
Gem x-2
|
||||
|
||||
EOF
|
||||
|
||||
assert_equal expected, @ui.output
|
||||
|
@ -71,9 +75,11 @@ Gem pl-1-x86-linux
|
|||
end
|
||||
|
||||
def test_execute_pipe_format
|
||||
util_spec 'foo' do |gem|
|
||||
spec = util_spec 'foo' do |gem|
|
||||
gem.add_dependency 'bar', '> 1'
|
||||
end
|
||||
install_specs util_spec 'bar', 2
|
||||
install_specs spec
|
||||
|
||||
@cmd.options[:args] = %w[foo]
|
||||
@cmd.options[:pipe_format] = true
|
||||
|
@ -164,6 +170,8 @@ ERROR: Only reverse dependencies for local gems are supported.
|
|||
end
|
||||
|
||||
def test_execute_remote
|
||||
install_specs new_spec 'bar', '2'
|
||||
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.spec 'foo', 2, 'bar' => '> 1'
|
||||
end
|
||||
|
|
|
@ -251,8 +251,7 @@ ERROR: Possible alternatives: non_existent_with_hint
|
|||
correctly_spelled = "nonexistent-with_hint"
|
||||
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.spec correctly_spelled, 2
|
||||
fetcher.clear
|
||||
fetcher.download correctly_spelled, 2
|
||||
end
|
||||
|
||||
@cmd.options[:args] = [misspelled]
|
||||
|
@ -310,9 +309,8 @@ ERROR: Possible alternatives: non_existent_with_hint
|
|||
|
||||
def test_execute_prerelease_wins_over_previous_ver
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'a', 1
|
||||
fetcher.gem 'a', '2.a'
|
||||
fetcher.clear
|
||||
fetcher.download 'a', 1
|
||||
fetcher.download 'a', '2.a'
|
||||
end
|
||||
|
||||
@cmd.options[:prerelease] = true
|
||||
|
@ -535,9 +533,7 @@ ERROR: Possible alternatives: non_existent_with_hint
|
|||
|
||||
def test_execute_conservative
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'b', 2
|
||||
|
||||
fetcher.clear
|
||||
fetcher.download 'b', 2
|
||||
|
||||
fetcher.gem 'a', 2
|
||||
end
|
||||
|
@ -665,8 +661,7 @@ ERROR: Possible alternatives: non_existent_with_hint
|
|||
|
||||
def test_show_source_problems_even_on_success
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'a', 2
|
||||
fetcher.clear
|
||||
fetcher.download 'a', 2
|
||||
end
|
||||
|
||||
Gem.sources << "http://nonexistent.example"
|
||||
|
@ -738,8 +733,7 @@ ERROR: Possible alternatives: non_existent_with_hint
|
|||
|
||||
def test_execute_installs_from_a_gemdeps_with_conservative
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'a', 2
|
||||
fetcher.clear
|
||||
fetcher.download 'a', 2
|
||||
fetcher.gem 'a', 1
|
||||
end
|
||||
|
||||
|
@ -763,8 +757,7 @@ ERROR: Possible alternatives: non_existent_with_hint
|
|||
|
||||
def test_execute_installs_from_a_gemdeps
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'a', 2
|
||||
fetcher.clear
|
||||
fetcher.download 'a', 2
|
||||
end
|
||||
|
||||
File.open @gemdeps, "w" do |f|
|
||||
|
@ -786,9 +779,8 @@ ERROR: Possible alternatives: non_existent_with_hint
|
|||
|
||||
def test_execute_installs_deps_a_gemdeps
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'q', '1.0'
|
||||
fetcher.gem 'r', '2.0', 'q' => nil
|
||||
fetcher.clear
|
||||
fetcher.download 'q', '1.0'
|
||||
fetcher.download 'r', '2.0', 'q' => nil
|
||||
end
|
||||
|
||||
File.open @gemdeps, "w" do |f|
|
||||
|
@ -813,9 +805,7 @@ ERROR: Possible alternatives: non_existent_with_hint
|
|||
|
||||
def test_execute_uses_deps_a_gemdeps
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'r', '2.0', 'q' => nil
|
||||
|
||||
fetcher.clear
|
||||
fetcher.download 'r', '2.0', 'q' => nil
|
||||
|
||||
fetcher.spec 'q', '1.0'
|
||||
end
|
||||
|
@ -842,9 +832,8 @@ ERROR: Possible alternatives: non_existent_with_hint
|
|||
|
||||
def test_execute_installs_deps_a_gemdeps_into_a_path
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'q', '1.0'
|
||||
fetcher.gem 'r', '2.0', 'q' => nil
|
||||
fetcher.clear
|
||||
fetcher.download 'q', '1.0'
|
||||
fetcher.download 'r', '2.0', 'q' => nil
|
||||
end
|
||||
|
||||
File.open @gemdeps, "w" do |f|
|
||||
|
@ -873,12 +862,11 @@ ERROR: Possible alternatives: non_existent_with_hint
|
|||
|
||||
def test_execute_with_gemdeps_path_ignores_system
|
||||
specs = spec_fetcher do |fetcher|
|
||||
fetcher.gem 'q', '1.0'
|
||||
fetcher.gem 'r', '2.0', 'q' => nil
|
||||
fetcher.clear
|
||||
fetcher.download 'q', '1.0'
|
||||
fetcher.download 'r', '2.0', 'q' => nil
|
||||
end
|
||||
|
||||
Gem::Specification.add_specs specs['q-1.0']
|
||||
install_specs specs['q-1.0']
|
||||
|
||||
File.open @gemdeps, "w" do |f|
|
||||
f << "gem 'r'"
|
||||
|
@ -910,7 +898,7 @@ ERROR: Possible alternatives: non_existent_with_hint
|
|||
fetcher.gem 'r', '2.0', 'q' => nil
|
||||
end
|
||||
|
||||
i = Gem::Installer.new specs['q-1.0'].cache_file, :install_dir => "gf-path"
|
||||
i = Gem::Installer.at specs['q-1.0'].cache_file, :install_dir => "gf-path"
|
||||
i.install
|
||||
|
||||
assert File.file?("gf-path/specifications/q-1.0.gemspec"), "not installed"
|
||||
|
|
|
@ -2,23 +2,10 @@ require 'rubygems/test_case'
|
|||
require 'rubygems/commands/mirror_command'
|
||||
|
||||
class TestGemCommandsMirrorCommand < Gem::TestCase
|
||||
|
||||
def setup
|
||||
super
|
||||
|
||||
@cmd = Gem::Commands::MirrorCommand.new
|
||||
|
||||
@mirror_specs = Gem::Specification.find_all_by_name('rubygems-mirror').each do |spec|
|
||||
Gem::Specification.remove_spec spec
|
||||
end
|
||||
end
|
||||
|
||||
def teardown
|
||||
@mirror_specs.each do |spec|
|
||||
Gem::Specification.add_spec spec
|
||||
end
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
def test_execute
|
||||
|
|
|
@ -15,9 +15,8 @@ class TestGemCommandsOutdatedCommand < Gem::TestCase
|
|||
|
||||
def test_execute
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.spec 'foo', '1.0'
|
||||
fetcher.spec 'foo', '2.0'
|
||||
fetcher.clear
|
||||
fetcher.download 'foo', '1.0'
|
||||
fetcher.download 'foo', '2.0'
|
||||
fetcher.gem 'foo', '0.1'
|
||||
fetcher.gem 'foo', '0.2'
|
||||
end
|
||||
|
|
|
@ -103,10 +103,12 @@ class TestGemCommandsPristineCommand < Gem::TestCase
|
|||
|
||||
assert_path_exists gem_exec
|
||||
|
||||
ruby_exec = sprintf Gem.default_exec_format, 'ruby'
|
||||
|
||||
if win_platform?
|
||||
assert_match %r%\A#!\s*ruby%, File.read(gem_exec)
|
||||
assert_match %r%\A#!\s*#{ruby_exec}%, File.read(gem_exec)
|
||||
else
|
||||
assert_match %r%\A#!\s*/usr/bin/env ruby%, File.read(gem_exec)
|
||||
assert_match %r%\A#!\s*/usr/bin/env #{ruby_exec}%, File.read(gem_exec)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -151,10 +153,11 @@ class TestGemCommandsPristineCommand < Gem::TestCase
|
|||
|
||||
ext_path = File.join @tempdir, 'ext', 'a', 'extconf.rb'
|
||||
write_file ext_path do |io|
|
||||
io.write '# extconf.rb'
|
||||
io.write "# extconf.rb\nrequire 'mkmf'; create_makefile 'a'"
|
||||
end
|
||||
|
||||
util_build_gem a
|
||||
install_gem a
|
||||
|
||||
@cmd.options[:args] = %w[a]
|
||||
@cmd.options[:extensions] = false
|
||||
|
@ -403,7 +406,7 @@ class TestGemCommandsPristineCommand < Gem::TestCase
|
|||
end
|
||||
|
||||
def test_execute_unknown_gem_at_remote_source
|
||||
util_spec 'a'
|
||||
install_specs util_spec 'a'
|
||||
|
||||
@cmd.options[:args] = %w[a]
|
||||
|
||||
|
@ -442,9 +445,10 @@ class TestGemCommandsPristineCommand < Gem::TestCase
|
|||
def test_execute_bundled_gem_on_old_rubies
|
||||
util_set_RUBY_VERSION '1.9.3', 551
|
||||
|
||||
util_spec 'bigdecimal', '1.1.0' do |s|
|
||||
spec = util_spec 'bigdecimal', '1.1.0' do |s|
|
||||
s.summary = "This bigdecimal is bundled with Ruby"
|
||||
end
|
||||
install_specs spec
|
||||
|
||||
@cmd.options[:args] = %w[bigdecimal]
|
||||
|
||||
|
|
|
@ -1,23 +1,22 @@
|
|||
require 'rubygems/test_case'
|
||||
require 'rubygems/commands/query_command'
|
||||
|
||||
class TestGemCommandsQueryCommand < Gem::TestCase
|
||||
|
||||
module TestGemCommandsQueryCommandSetup
|
||||
def setup
|
||||
super
|
||||
|
||||
@cmd = Gem::Commands::QueryCommand.new
|
||||
|
||||
@specs = spec_fetcher do |fetcher|
|
||||
fetcher.spec 'a', 1
|
||||
fetcher.spec 'a', 2
|
||||
fetcher.spec 'a', '3.a'
|
||||
end
|
||||
@specs = add_gems_to_fetcher
|
||||
|
||||
@fetcher.data["#{@gem_repo}Marshal.#{Gem.marshal_version}"] = proc do
|
||||
raise Gem::RemoteFetcher::FetchError
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class TestGemCommandsQueryCommandWithInstalledGems < Gem::TestCase
|
||||
include TestGemCommandsQueryCommandSetup
|
||||
|
||||
def test_execute
|
||||
spec_fetcher do |fetcher|
|
||||
|
@ -42,37 +41,6 @@ pl (1 i386-linux)
|
|||
assert_equal '', @ui.error
|
||||
end
|
||||
|
||||
def test_execute_platform
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.clear
|
||||
|
||||
fetcher.spec 'a', 1
|
||||
fetcher.spec 'a', 1 do |s|
|
||||
s.platform = 'x86-linux'
|
||||
end
|
||||
|
||||
fetcher.spec 'a', 2 do |s|
|
||||
s.platform = 'universal-darwin'
|
||||
end
|
||||
end
|
||||
|
||||
@cmd.handle_options %w[-r -a]
|
||||
|
||||
use_ui @ui do
|
||||
@cmd.execute
|
||||
end
|
||||
|
||||
expected = <<-EOF
|
||||
|
||||
*** REMOTE GEMS ***
|
||||
|
||||
a (2 universal-darwin, 1 ruby x86-linux)
|
||||
EOF
|
||||
|
||||
assert_equal expected, @ui.output
|
||||
assert_equal '', @ui.error
|
||||
end
|
||||
|
||||
def test_execute_all
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.legacy_platform
|
||||
|
@ -147,56 +115,6 @@ a (2)
|
|||
This is a lot of text. This is a lot of text. This is a lot of text.
|
||||
This is a lot of text.
|
||||
|
||||
pl (1)
|
||||
Platform: i386-linux
|
||||
Author: A User
|
||||
Homepage: http://example.com
|
||||
|
||||
this is a summary
|
||||
EOF
|
||||
|
||||
assert_equal expected, @ui.output
|
||||
assert_equal '', @ui.error
|
||||
end
|
||||
|
||||
def test_execute_details_platform
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.clear
|
||||
|
||||
fetcher.spec 'a', 1 do |s|
|
||||
s.platform = 'x86-linux'
|
||||
end
|
||||
|
||||
fetcher.spec 'a', 2 do |s|
|
||||
s.summary = 'This is a lot of text. ' * 4
|
||||
s.authors = ['Abraham Lincoln', 'Hirohito']
|
||||
s.homepage = 'http://a.example.com/'
|
||||
s.platform = 'universal-darwin'
|
||||
end
|
||||
|
||||
fetcher.legacy_platform
|
||||
end
|
||||
|
||||
@cmd.handle_options %w[-r -d]
|
||||
|
||||
use_ui @ui do
|
||||
@cmd.execute
|
||||
end
|
||||
|
||||
expected = <<-EOF
|
||||
|
||||
*** REMOTE GEMS ***
|
||||
|
||||
a (2, 1)
|
||||
Platforms:
|
||||
1: x86-linux
|
||||
2: universal-darwin
|
||||
Authors: Abraham Lincoln, Hirohito
|
||||
Homepage: http://a.example.com/
|
||||
|
||||
This is a lot of text. This is a lot of text. This is a lot of text.
|
||||
This is a lot of text.
|
||||
|
||||
pl (1)
|
||||
Platform: i386-linux
|
||||
Author: A User
|
||||
|
@ -526,10 +444,130 @@ pl (1 i386-linux)
|
|||
assert_equal '', @ui.error
|
||||
end
|
||||
|
||||
def test_make_entry
|
||||
a_2_name = @specs['a-2'].original_name
|
||||
|
||||
@fetcher.data.delete \
|
||||
"#{@gem_repo}quick/Marshal.#{Gem.marshal_version}/#{a_2_name}.gemspec.rz"
|
||||
|
||||
a2 = @specs['a-2']
|
||||
entry_tuples = [
|
||||
[Gem::NameTuple.new(a2.name, a2.version, a2.platform),
|
||||
Gem.sources.first],
|
||||
]
|
||||
|
||||
platforms = { a2.version => [a2.platform] }
|
||||
|
||||
entry = @cmd.send :make_entry, entry_tuples, platforms
|
||||
|
||||
assert_equal 'a (2)', entry
|
||||
end
|
||||
|
||||
# Test for multiple args handling!
|
||||
def test_execute_multiple_args
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.legacy_platform
|
||||
end
|
||||
|
||||
@cmd.handle_options %w[a pl]
|
||||
|
||||
use_ui @ui do
|
||||
@cmd.execute
|
||||
end
|
||||
|
||||
assert_match %r%^a %, @ui.output
|
||||
assert_match %r%^pl %, @ui.output
|
||||
assert_equal '', @ui.error
|
||||
end
|
||||
|
||||
def test_show_gems
|
||||
@cmd.options[:name] = //
|
||||
@cmd.options[:domain] = :remote
|
||||
|
||||
use_ui @ui do
|
||||
@cmd.send :show_gems, /a/i, false
|
||||
end
|
||||
|
||||
assert_match %r%^a %, @ui.output
|
||||
refute_match %r%^pl %, @ui.output
|
||||
assert_empty @ui.error
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def add_gems_to_fetcher
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.spec 'a', 1
|
||||
fetcher.spec 'a', 2
|
||||
fetcher.spec 'a', '3.a'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class TestGemCommandsQueryCommandWithoutInstalledGems < Gem::TestCase
|
||||
include TestGemCommandsQueryCommandSetup
|
||||
|
||||
def test_execute_platform
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.spec 'a', 1
|
||||
fetcher.spec 'a', 1 do |s|
|
||||
s.platform = 'x86-linux'
|
||||
end
|
||||
|
||||
fetcher.spec 'a', 2 do |s|
|
||||
s.platform = 'universal-darwin'
|
||||
end
|
||||
end
|
||||
|
||||
@cmd.handle_options %w[-r -a]
|
||||
|
||||
use_ui @ui do
|
||||
@cmd.execute
|
||||
end
|
||||
|
||||
expected = <<-EOF
|
||||
|
||||
*** REMOTE GEMS ***
|
||||
|
||||
a (2 universal-darwin, 1 ruby x86-linux)
|
||||
EOF
|
||||
|
||||
assert_equal expected, @ui.output
|
||||
assert_equal '', @ui.error
|
||||
end
|
||||
|
||||
def test_execute_default_details
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.spec 'a', 2
|
||||
end
|
||||
|
||||
a1 = new_default_spec 'a', 1
|
||||
install_default_specs a1
|
||||
|
||||
@cmd.handle_options %w[-l -d]
|
||||
|
||||
use_ui @ui do
|
||||
@cmd.execute
|
||||
end
|
||||
|
||||
expected = <<-EOF
|
||||
|
||||
*** LOCAL GEMS ***
|
||||
|
||||
a (2, 1)
|
||||
Author: A User
|
||||
Homepage: http://example.com
|
||||
Installed at (2): #{@gemhome}
|
||||
(1, default): #{a1.base_dir}
|
||||
|
||||
this is a summary
|
||||
EOF
|
||||
|
||||
assert_equal expected, @ui.output
|
||||
end
|
||||
|
||||
def test_execute_local_details
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.clear
|
||||
|
||||
fetcher.spec 'a', 1 do |s|
|
||||
s.platform = 'x86-linux'
|
||||
end
|
||||
|
@ -583,86 +621,13 @@ pl (1)
|
|||
assert_equal expected, @ui.output
|
||||
end
|
||||
|
||||
def test_execute_default_details
|
||||
private
|
||||
|
||||
def add_gems_to_fetcher
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.clear
|
||||
|
||||
fetcher.spec 'a', 2
|
||||
fetcher.download 'a', 1
|
||||
fetcher.download 'a', 2
|
||||
fetcher.download 'a', '3.a'
|
||||
end
|
||||
|
||||
a1 = new_default_spec 'a', 1
|
||||
install_default_specs a1
|
||||
|
||||
@cmd.handle_options %w[-l -d]
|
||||
|
||||
use_ui @ui do
|
||||
@cmd.execute
|
||||
end
|
||||
|
||||
expected = <<-EOF
|
||||
|
||||
*** LOCAL GEMS ***
|
||||
|
||||
a (2, 1)
|
||||
Author: A User
|
||||
Homepage: http://example.com
|
||||
Installed at (2): #{@gemhome}
|
||||
(1, default): #{a1.base_dir}
|
||||
|
||||
this is a summary
|
||||
EOF
|
||||
|
||||
assert_equal expected, @ui.output
|
||||
end
|
||||
|
||||
def test_make_entry
|
||||
a_2_name = @specs['a-2'].original_name
|
||||
|
||||
@fetcher.data.delete \
|
||||
"#{@gem_repo}quick/Marshal.#{Gem.marshal_version}/#{a_2_name}.gemspec.rz"
|
||||
|
||||
a2 = @specs['a-2']
|
||||
entry_tuples = [
|
||||
[Gem::NameTuple.new(a2.name, a2.version, a2.platform),
|
||||
Gem.sources.first],
|
||||
]
|
||||
|
||||
platforms = { a2.version => [a2.platform] }
|
||||
|
||||
entry = @cmd.send :make_entry, entry_tuples, platforms
|
||||
|
||||
assert_equal 'a (2)', entry
|
||||
end
|
||||
|
||||
# Test for multiple args handling!
|
||||
def test_execute_multiple_args
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.legacy_platform
|
||||
end
|
||||
|
||||
@cmd.handle_options %w[a pl]
|
||||
|
||||
use_ui @ui do
|
||||
@cmd.execute
|
||||
end
|
||||
|
||||
assert_match %r%^a %, @ui.output
|
||||
assert_match %r%^pl %, @ui.output
|
||||
assert_equal '', @ui.error
|
||||
end
|
||||
|
||||
def test_show_gems
|
||||
@cmd.options[:name] = //
|
||||
@cmd.options[:domain] = :remote
|
||||
|
||||
use_ui @ui do
|
||||
@cmd.send :show_gems, /a/i, false
|
||||
end
|
||||
|
||||
assert_match %r%^a %, @ui.output
|
||||
refute_match %r%^pl %, @ui.output
|
||||
assert_empty @ui.error
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -26,8 +26,8 @@ class TestGemCommandsSpecificationCommand < Gem::TestCase
|
|||
end
|
||||
|
||||
def test_execute_all
|
||||
util_spec 'foo', '0.0.1'
|
||||
util_spec 'foo', '0.0.2'
|
||||
install_specs util_spec 'foo', '0.0.1'
|
||||
install_specs util_spec 'foo', '0.0.2'
|
||||
|
||||
@cmd.options[:args] = %w[foo]
|
||||
@cmd.options[:all] = true
|
||||
|
@ -89,8 +89,8 @@ class TestGemCommandsSpecificationCommand < Gem::TestCase
|
|||
end
|
||||
|
||||
def test_execute_exact_match
|
||||
util_spec 'foo'
|
||||
util_spec 'foo_bar'
|
||||
install_specs util_spec 'foo'
|
||||
install_specs util_spec 'foo_bar'
|
||||
|
||||
@cmd.options[:args] = %w[foo]
|
||||
|
||||
|
|
|
@ -13,10 +13,12 @@ class TestGemCommandsStaleCommand < Gem::TestCase
|
|||
foo_bar = util_spec 'foo_bar' do |gem|
|
||||
gem.files = files
|
||||
end
|
||||
install_specs foo_bar
|
||||
|
||||
bar_baz = util_spec 'bar_baz' do |gem|
|
||||
gem.files = files
|
||||
end
|
||||
install_specs bar_baz
|
||||
|
||||
files.each do |file|
|
||||
filename = File.join(bar_baz.full_gem_path, file)
|
||||
|
|
|
@ -24,7 +24,7 @@ class TestGemCommandsUninstallCommand < Gem::InstallerTestCase
|
|||
|
||||
gemhome2 = "#{@gemhome}2"
|
||||
|
||||
a_4 = util_spec 'a', 4
|
||||
a_4, = util_gem 'a', 4
|
||||
install_gem a_4, :install_dir => gemhome2
|
||||
|
||||
Gem::Specification.dirs = [@gemhome, gemhome2]
|
||||
|
@ -41,7 +41,7 @@ class TestGemCommandsUninstallCommand < Gem::InstallerTestCase
|
|||
@cmd.execute
|
||||
end
|
||||
|
||||
assert_equal %w[a-4 a_evil-9 b-2 c-1.2 default-1 dep_x-1 pl-1-x86-linux x-1],
|
||||
assert_equal %w[a_evil-9 b-2 c-1.2 default-1 dep_x-1 pl-1-x86-linux x-1],
|
||||
Gem::Specification.all_names.sort
|
||||
end
|
||||
|
||||
|
@ -213,7 +213,7 @@ class TestGemCommandsUninstallCommand < Gem::InstallerTestCase
|
|||
|
||||
gemhome2 = "#{@gemhome}2"
|
||||
|
||||
a_4 = util_spec 'a', 4
|
||||
a_4, = util_gem 'a', 4
|
||||
install_gem a_4, :install_dir => gemhome2
|
||||
|
||||
Gem::Specification.dirs = [@gemhome, gemhome2]
|
||||
|
@ -229,7 +229,7 @@ class TestGemCommandsUninstallCommand < Gem::InstallerTestCase
|
|||
@cmd.execute
|
||||
end
|
||||
|
||||
assert_equal %w[a-4 default-1], Gem::Specification.all_names.sort
|
||||
assert_equal %w[default-1], Gem::Specification.all_names.sort
|
||||
end
|
||||
|
||||
def test_handle_options
|
||||
|
|
|
@ -101,10 +101,8 @@ class TestGemCommandsUnpackCommand < Gem::TestCase
|
|||
|
||||
def test_execute_remote
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.spec 'a', 1
|
||||
fetcher.gem 'a', 2
|
||||
|
||||
fetcher.clear
|
||||
fetcher.download 'a', 1
|
||||
fetcher.download 'a', 2
|
||||
end
|
||||
|
||||
Gem.configuration.verbose = :really
|
||||
|
@ -184,8 +182,8 @@ class TestGemCommandsUnpackCommand < Gem::TestCase
|
|||
|
||||
foo_path = File.join(@tempdir, "#{foo_spec.full_name}.gem")
|
||||
foo_bar_path = File.join(@tempdir, "#{foo_bar_spec.full_name}.gem")
|
||||
Gem::Installer.new(foo_path).install
|
||||
Gem::Installer.new(foo_bar_path).install
|
||||
Gem::Installer.at(foo_path).install
|
||||
Gem::Installer.at(foo_bar_path).install
|
||||
|
||||
@cmd.options[:args] = %w[foo]
|
||||
|
||||
|
|
|
@ -18,11 +18,9 @@ class TestGemCommandsUpdateCommand < Gem::TestCase
|
|||
@cmd.options[:document] = []
|
||||
|
||||
@specs = spec_fetcher do |fetcher|
|
||||
fetcher.gem 'a', 1
|
||||
fetcher.gem 'a', 2
|
||||
fetcher.gem 'a', '3.a'
|
||||
|
||||
fetcher.clear
|
||||
fetcher.download 'a', 1
|
||||
fetcher.download 'a', 2
|
||||
fetcher.download 'a', '3.a'
|
||||
end
|
||||
|
||||
@a1_path = @specs['a-1'].cache_file
|
||||
|
@ -32,10 +30,7 @@ class TestGemCommandsUpdateCommand < Gem::TestCase
|
|||
|
||||
def test_execute
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'a', 2
|
||||
|
||||
fetcher.clear
|
||||
|
||||
fetcher.download 'a', 2
|
||||
fetcher.spec 'a', 1
|
||||
end
|
||||
|
||||
|
@ -54,10 +49,8 @@ class TestGemCommandsUpdateCommand < Gem::TestCase
|
|||
|
||||
def test_execute_multiple
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'a', 2
|
||||
fetcher.gem 'ab', 2
|
||||
|
||||
fetcher.clear
|
||||
fetcher.download 'a', 2
|
||||
fetcher.download 'ab', 2
|
||||
|
||||
fetcher.spec 'a', 1
|
||||
fetcher.spec 'ab', 1
|
||||
|
@ -78,9 +71,7 @@ class TestGemCommandsUpdateCommand < Gem::TestCase
|
|||
|
||||
def test_execute_system
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'rubygems-update', 9 do |s| s.files = %w[setup.rb] end
|
||||
|
||||
fetcher.clear
|
||||
fetcher.download 'rubygems-update', 9 do |s| s.files = %w[setup.rb] end
|
||||
end
|
||||
|
||||
@cmd.options[:args] = []
|
||||
|
@ -100,11 +91,9 @@ class TestGemCommandsUpdateCommand < Gem::TestCase
|
|||
|
||||
def test_execute_system_at_latest
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'rubygems-update', Gem::VERSION do |s|
|
||||
fetcher.download 'rubygems-update', Gem::VERSION do |s|
|
||||
s.files = %w[setup.rb]
|
||||
end
|
||||
|
||||
fetcher.clear
|
||||
end
|
||||
|
||||
@cmd.options[:args] = []
|
||||
|
@ -123,10 +112,8 @@ class TestGemCommandsUpdateCommand < Gem::TestCase
|
|||
|
||||
def test_execute_system_multiple
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'rubygems-update', 8 do |s| s.files = %w[setup.rb] end
|
||||
fetcher.gem 'rubygems-update', 9 do |s| s.files = %w[setup.rb] end
|
||||
|
||||
fetcher.clear
|
||||
fetcher.download 'rubygems-update', 8 do |s| s.files = %w[setup.rb] end
|
||||
fetcher.download 'rubygems-update', 9 do |s| s.files = %w[setup.rb] end
|
||||
end
|
||||
|
||||
@cmd.options[:args] = []
|
||||
|
@ -146,10 +133,8 @@ class TestGemCommandsUpdateCommand < Gem::TestCase
|
|||
|
||||
def test_execute_system_specific
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'rubygems-update', 8 do |s| s.files = %w[setup.rb] end
|
||||
fetcher.gem 'rubygems-update', 9 do |s| s.files = %w[setup.rb] end
|
||||
|
||||
fetcher.clear
|
||||
fetcher.download 'rubygems-update', 8 do |s| s.files = %w[setup.rb] end
|
||||
fetcher.download 'rubygems-update', 9 do |s| s.files = %w[setup.rb] end
|
||||
end
|
||||
|
||||
@cmd.options[:args] = []
|
||||
|
@ -169,10 +154,8 @@ class TestGemCommandsUpdateCommand < Gem::TestCase
|
|||
|
||||
def test_execute_system_specifically_to_latest_version
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'rubygems-update', 8 do |s| s.files = %w[setup.rb] end
|
||||
fetcher.gem 'rubygems-update', 9 do |s| s.files = %w[setup.rb] end
|
||||
|
||||
fetcher.clear
|
||||
fetcher.download 'rubygems-update', 8 do |s| s.files = %w[setup.rb] end
|
||||
fetcher.download 'rubygems-update', 9 do |s| s.files = %w[setup.rb] end
|
||||
end
|
||||
|
||||
@cmd.options[:args] = []
|
||||
|
@ -213,11 +196,9 @@ class TestGemCommandsUpdateCommand < Gem::TestCase
|
|||
|
||||
def test_execute_dependencies
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'a', 2, 'b' => 2, 'c' => 2
|
||||
fetcher.gem 'b', 2
|
||||
fetcher.gem 'c', 2
|
||||
|
||||
fetcher.clear
|
||||
fetcher.download 'a', 2, 'b' => 2, 'c' => 2
|
||||
fetcher.download 'b', 2
|
||||
fetcher.download 'c', 2
|
||||
|
||||
fetcher.spec 'a', 1, 'c' => '1.2'
|
||||
fetcher.spec 'c', '1.2'
|
||||
|
@ -243,10 +224,7 @@ class TestGemCommandsUpdateCommand < Gem::TestCase
|
|||
def test_execute_rdoc
|
||||
skip if RUBY_VERSION <= "1.8.7"
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'a', 2
|
||||
|
||||
fetcher.clear
|
||||
|
||||
fetcher.download 'a', 2
|
||||
fetcher.spec 'a', 1
|
||||
end
|
||||
|
||||
|
@ -269,9 +247,7 @@ class TestGemCommandsUpdateCommand < Gem::TestCase
|
|||
|
||||
def test_execute_named
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'a', 2
|
||||
|
||||
fetcher.clear
|
||||
fetcher.download 'a', 2
|
||||
|
||||
fetcher.spec 'a', 1
|
||||
end
|
||||
|
@ -292,8 +268,7 @@ class TestGemCommandsUpdateCommand < Gem::TestCase
|
|||
|
||||
def test_execute_named_some_up_to_date
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'a', 2
|
||||
fetcher.clear
|
||||
fetcher.download 'a', 2
|
||||
fetcher.spec 'a', 1
|
||||
|
||||
fetcher.spec 'b', 2
|
||||
|
@ -334,9 +309,7 @@ class TestGemCommandsUpdateCommand < Gem::TestCase
|
|||
|
||||
def test_execute_named_up_to_date_prerelease
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'a', '3.a'
|
||||
|
||||
fetcher.clear
|
||||
fetcher.download 'a', '3.a'
|
||||
|
||||
fetcher.gem 'a', 2
|
||||
end
|
||||
|
@ -376,10 +349,7 @@ class TestGemCommandsUpdateCommand < Gem::TestCase
|
|||
|
||||
def test_execute_user_install
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'a', 2
|
||||
|
||||
fetcher.clear
|
||||
|
||||
fetcher.download 'a', 2
|
||||
fetcher.spec 'a', 1
|
||||
end
|
||||
|
||||
|
|
|
@ -73,6 +73,7 @@ class TestGemCommandsWhichCommand < Gem::TestCase
|
|||
@foo_bar = util_spec 'foo_bar' do |gem|
|
||||
gem.files = files
|
||||
end
|
||||
install_specs @foo_bar
|
||||
|
||||
files.each do |file|
|
||||
filename = File.join(@foo_bar.full_gem_path, file)
|
||||
|
|
|
@ -294,10 +294,11 @@ class TestGemDependency < Gem::TestCase
|
|||
end
|
||||
|
||||
def test_to_spec
|
||||
util_spec 'a', '1'
|
||||
a_1 = util_spec 'a', '1'
|
||||
a_2 = util_spec 'a', '2'
|
||||
|
||||
a_dep = dep 'a', '>= 0'
|
||||
install_specs a_1, a_2
|
||||
|
||||
assert_equal a_2, a_dep.to_spec
|
||||
end
|
||||
|
@ -307,6 +308,7 @@ class TestGemDependency < Gem::TestCase
|
|||
a_1_1_a = util_spec 'a', '1.1.a'
|
||||
|
||||
a_dep = dep 'a', '>= 0'
|
||||
install_specs a_1, a_1_1_a
|
||||
|
||||
assert_equal a_1, a_dep.to_spec
|
||||
|
||||
|
@ -317,7 +319,8 @@ class TestGemDependency < Gem::TestCase
|
|||
end
|
||||
|
||||
def test_to_specs_suggests_other_versions
|
||||
a = util_spec 'a', '1.0', 'b' => '>= 1.0'
|
||||
a = util_spec 'a', '1.0'
|
||||
install_specs a
|
||||
|
||||
a_file = File.join a.gem_dir, 'lib', 'a_file.rb'
|
||||
|
||||
|
@ -335,7 +338,8 @@ class TestGemDependency < Gem::TestCase
|
|||
end
|
||||
|
||||
def test_to_specs_indicates_total_gem_set_size
|
||||
a = util_spec 'a', '1.0', 'b' => '>= 1.0'
|
||||
a = util_spec 'a', '1.0'
|
||||
install_specs a
|
||||
|
||||
a_file = File.join a.gem_dir, 'lib', 'a_file.rb'
|
||||
|
||||
|
|
|
@ -406,7 +406,7 @@ class TestGemDependencyInstaller < Gem::TestCase
|
|||
def test_install_dependency_existing
|
||||
util_setup_gems
|
||||
|
||||
Gem::Installer.new(@a1_gem).install
|
||||
Gem::Installer.at(@a1_gem).install
|
||||
FileUtils.mv @a1_gem, @tempdir
|
||||
FileUtils.mv @b1_gem, @tempdir
|
||||
inst = nil
|
||||
|
@ -437,7 +437,7 @@ class TestGemDependencyInstaller < Gem::TestCase
|
|||
|
||||
_, f1_gem = util_gem 'f', '1', 'e' => nil
|
||||
|
||||
Gem::Installer.new(e1_gem).install
|
||||
Gem::Installer.at(e1_gem).install
|
||||
FileUtils.rm_r e1.extension_dir
|
||||
|
||||
FileUtils.mv e1_gem, @tempdir
|
||||
|
@ -525,7 +525,7 @@ class TestGemDependencyInstaller < Gem::TestCase
|
|||
inst = nil
|
||||
|
||||
Dir.chdir @tempdir do
|
||||
Gem::Installer.new('a-1.gem').install
|
||||
Gem::Installer.at('a-1.gem').install
|
||||
|
||||
inst = Gem::DependencyInstaller.new :domain => :local
|
||||
inst.install 'b-1.gem'
|
||||
|
@ -669,7 +669,7 @@ class TestGemDependencyInstaller < Gem::TestCase
|
|||
FileUtils.mv @a1_gem, @tempdir
|
||||
FileUtils.mv @b1_gem, @tempdir
|
||||
|
||||
inst = Gem::Installer.new @a1.file_name
|
||||
inst = Gem::Installer.at @a1.file_name
|
||||
inst.install
|
||||
|
||||
gemhome2 = File.join @tempdir, 'gemhome2'
|
||||
|
@ -799,7 +799,7 @@ class TestGemDependencyInstaller < Gem::TestCase
|
|||
def test_install_reinstall
|
||||
util_setup_gems
|
||||
|
||||
Gem::Installer.new(@a1_gem).install
|
||||
Gem::Installer.at(@a1_gem).install
|
||||
FileUtils.mv @a1_gem, @tempdir
|
||||
inst = nil
|
||||
|
||||
|
|
|
@ -157,7 +157,7 @@ This directory does not appear to be a RubyGems repository, skipping
|
|||
|
||||
refute doctor.gem_repository?, 'no gems installed'
|
||||
|
||||
util_spec 'a'
|
||||
install_specs util_spec 'a'
|
||||
|
||||
doctor = Gem::Doctor.new @gemhome
|
||||
|
||||
|
|
|
@ -29,12 +29,16 @@ class TestGemExtConfigureBuilder < Gem::TestCase
|
|||
Gem::Ext::ConfigureBuilder.build nil, nil, @dest_path, output
|
||||
end
|
||||
|
||||
assert_match(/^current directory:/, output.shift)
|
||||
assert_equal "sh ./configure --prefix=#{@dest_path}", output.shift
|
||||
assert_equal "", output.shift
|
||||
assert_match(/^current directory:/, output.shift)
|
||||
assert_contains_make_command 'clean', output.shift
|
||||
assert_match(/^ok$/m, output.shift)
|
||||
assert_match(/^current directory:/, output.shift)
|
||||
assert_contains_make_command '', output.shift
|
||||
assert_match(/^ok$/m, output.shift)
|
||||
assert_match(/^current directory:/, output.shift)
|
||||
assert_contains_make_command 'install', output.shift
|
||||
assert_match(/^ok$/m, output.shift)
|
||||
end
|
||||
|
@ -54,6 +58,7 @@ class TestGemExtConfigureBuilder < Gem::TestCase
|
|||
|
||||
assert_match 'configure failed', error.message
|
||||
|
||||
assert_match(/^current directory:/, output.shift)
|
||||
assert_equal "#{sh_prefix_configure}#{@dest_path}", output.shift
|
||||
assert_match %r(#{shell_error_msg}), output.shift
|
||||
assert_equal true, output.empty?
|
||||
|
@ -73,10 +78,9 @@ class TestGemExtConfigureBuilder < Gem::TestCase
|
|||
Gem::Ext::ConfigureBuilder.build nil, nil, @dest_path, output
|
||||
end
|
||||
|
||||
assert_contains_make_command 'clean', output[0]
|
||||
assert_contains_make_command '', output[2]
|
||||
assert_contains_make_command 'install', output[4]
|
||||
assert_contains_make_command 'clean', output[1]
|
||||
assert_contains_make_command '', output[4]
|
||||
assert_contains_make_command 'install', output[7]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -33,11 +33,13 @@ class TestGemExtExtConfBuilder < Gem::TestCase
|
|||
assert_same result, output
|
||||
end
|
||||
|
||||
assert_match(/^#{Gem.ruby}.* extconf.rb/, output[0])
|
||||
assert_equal "creating Makefile\n", output[1]
|
||||
assert_contains_make_command 'clean', output[2]
|
||||
assert_contains_make_command '', output[4]
|
||||
assert_contains_make_command 'install', output[6]
|
||||
assert_match(/^current directory:/, output[0])
|
||||
assert_match(/^#{Gem.ruby}.* extconf.rb/, output[1])
|
||||
assert_equal "creating Makefile\n", output[2]
|
||||
assert_match(/^current directory:/, output[3])
|
||||
assert_contains_make_command 'clean', output[4]
|
||||
assert_contains_make_command '', output[7]
|
||||
assert_contains_make_command 'install', output[10]
|
||||
assert_empty Dir.glob(File.join(@ext, 'siteconf*.rb'))
|
||||
end
|
||||
|
||||
|
@ -54,10 +56,10 @@ class TestGemExtExtConfBuilder < Gem::TestCase
|
|||
Gem::Ext::ExtConfBuilder.build 'extconf.rb', nil, @dest_path, output
|
||||
end
|
||||
|
||||
assert_equal "creating Makefile\n", output[1]
|
||||
assert_contains_make_command 'clean', output[2]
|
||||
assert_contains_make_command '', output[4]
|
||||
assert_contains_make_command 'install', output[6]
|
||||
assert_equal "creating Makefile\n", output[2]
|
||||
assert_contains_make_command 'clean', output[4]
|
||||
assert_contains_make_command '', output[7]
|
||||
assert_contains_make_command 'install', output[10]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -78,8 +80,8 @@ class TestGemExtExtConfBuilder < Gem::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
assert_equal "creating Makefile\n", output[1]
|
||||
assert_contains_make_command 'clean', output[2]
|
||||
assert_equal "creating Makefile\n", output[2]
|
||||
assert_contains_make_command 'clean', output[4]
|
||||
end
|
||||
ensure
|
||||
ENV['make'] = env_make
|
||||
|
@ -106,7 +108,9 @@ class TestGemExtExtConfBuilder < Gem::TestCase
|
|||
|
||||
assert_equal 'extconf failed, exit code 1', error.message
|
||||
|
||||
assert_match(/^#{Gem.ruby}.* extconf.rb/, output[0])
|
||||
assert_match(/^#{Gem.ruby}.* extconf.rb/, output[1])
|
||||
assert_match(File.join(@dest_path, 'mkmf.log'), output[4])
|
||||
|
||||
assert_path_exists File.join @dest_path, 'mkmf.log'
|
||||
end
|
||||
|
||||
|
@ -147,9 +151,9 @@ end
|
|||
Gem::Ext::ExtConfBuilder.build 'extconf.rb', nil, @dest_path, output
|
||||
end
|
||||
|
||||
assert_contains_make_command 'clean', output[2]
|
||||
assert_contains_make_command '', output[4]
|
||||
assert_contains_make_command 'install', output[6]
|
||||
assert_contains_make_command 'clean', output[4]
|
||||
assert_contains_make_command '', output[7]
|
||||
assert_contains_make_command 'install', output[10]
|
||||
assert_empty Dir.glob(File.join(@ext, 'siteconf*.rb'))
|
||||
end
|
||||
|
||||
|
@ -173,9 +177,9 @@ end
|
|||
Gem::Ext::ExtConfBuilder.make @ext, output
|
||||
end
|
||||
|
||||
assert_contains_make_command 'clean', output[0]
|
||||
assert_contains_make_command '', output[2]
|
||||
assert_contains_make_command 'install', output[4]
|
||||
assert_contains_make_command 'clean', output[1]
|
||||
assert_contains_make_command '', output[4]
|
||||
assert_contains_make_command 'install', output[7]
|
||||
end
|
||||
|
||||
def test_class_make_no_Makefile
|
||||
|
|
|
@ -294,7 +294,7 @@ class TestGemIndexer < Gem::TestCase
|
|||
|
||||
sys_gem = util_spec 'systemgem', '1.0'
|
||||
util_build_gem sys_gem
|
||||
Gem::Specification.add_spec sys_gem
|
||||
install_default_gems sys_gem
|
||||
yield
|
||||
util_remove_gem sys_gem
|
||||
end
|
||||
|
|
|
@ -129,7 +129,7 @@ class TestGemInstallUpdateOptions < Gem::InstallerTestCase
|
|||
|
||||
assert @cmd.options[:user_install]
|
||||
|
||||
@installer = Gem::Installer.new @gem, @cmd.options
|
||||
@installer = Gem::Installer.at @gem, @cmd.options
|
||||
@installer.install
|
||||
assert_path_exists File.join(Gem.user_dir, 'gems')
|
||||
assert_path_exists File.join(Gem.user_dir, 'gems', @spec.full_name)
|
||||
|
@ -149,7 +149,7 @@ class TestGemInstallUpdateOptions < Gem::InstallerTestCase
|
|||
Gem.use_paths @gemhome, @userhome
|
||||
|
||||
assert_raises(Gem::FilePermissionError) do
|
||||
Gem::Installer.new(@gem, @cmd.options).install
|
||||
Gem::Installer.at(@gem, @cmd.options).install
|
||||
end
|
||||
end
|
||||
ensure
|
||||
|
|
|
@ -36,7 +36,7 @@ class TestGemInstaller < Gem::InstallerTestCase
|
|||
|
||||
require 'rubygems'
|
||||
|
||||
version = \">= 0\"
|
||||
version = \">= 0.a\"
|
||||
|
||||
if ARGV.first
|
||||
str = ARGV.first
|
||||
|
@ -257,7 +257,7 @@ gem 'other', version
|
|||
s.add_dependency 'garbage ~> 5'
|
||||
end
|
||||
|
||||
installer = Gem::Installer.new a_gem
|
||||
installer = Gem::Installer.at a_gem
|
||||
|
||||
e = assert_raises Gem::InstallError do
|
||||
installer.ensure_loadable_spec
|
||||
|
@ -275,7 +275,7 @@ gem 'other', version
|
|||
end
|
||||
|
||||
policy = Gem::Security::HighSecurity
|
||||
installer = Gem::Installer.new a_gem, :security_policy => policy
|
||||
installer = Gem::Installer.at a_gem, :security_policy => policy
|
||||
|
||||
assert_raises Gem::Security::Exception do
|
||||
installer.ensure_loadable_spec
|
||||
|
@ -322,7 +322,7 @@ gem 'other', version
|
|||
:install_dir => "/non/existent"
|
||||
}
|
||||
|
||||
inst = Gem::Installer.new '', options
|
||||
inst = Gem::Installer.at '', options
|
||||
|
||||
Gem::Installer.path_warning = false
|
||||
|
||||
|
@ -575,8 +575,8 @@ gem 'other', version
|
|||
util_make_exec
|
||||
one = @spec.dup
|
||||
one.version = 1
|
||||
@installer = Gem::Installer.for_spec spec
|
||||
@installer.gem_dir = util_gem_dir one
|
||||
@installer.spec = spec
|
||||
|
||||
@installer.generate_bin
|
||||
|
||||
|
@ -672,14 +672,14 @@ gem 'other', version
|
|||
util_build_gem spec
|
||||
FileUtils.mv spec.cache_file, @tempdir
|
||||
|
||||
installer = Gem::Installer.new gem
|
||||
installer = Gem::Installer.at gem
|
||||
|
||||
assert_equal File.join(@gemhome, 'gems', spec.full_name), installer.gem_dir
|
||||
assert_equal File.join(@gemhome, 'bin'), installer.bin_dir
|
||||
end
|
||||
|
||||
def test_initialize_user_install
|
||||
installer = Gem::Installer.new @gem, :user_install => true
|
||||
installer = Gem::Installer.at @gem, :user_install => true
|
||||
|
||||
assert_equal File.join(Gem.user_dir, 'gems', @spec.full_name),
|
||||
installer.gem_dir
|
||||
|
@ -688,7 +688,7 @@ gem 'other', version
|
|||
|
||||
def test_initialize_user_install_bin_dir
|
||||
installer =
|
||||
Gem::Installer.new @gem, :user_install => true, :bin_dir => @tempdir
|
||||
Gem::Installer.at @gem, :user_install => true, :bin_dir => @tempdir
|
||||
|
||||
assert_equal File.join(Gem.user_dir, 'gems', @spec.full_name),
|
||||
installer.gem_dir
|
||||
|
@ -870,7 +870,7 @@ gem 'other', version
|
|||
Gem::Package.build @spec
|
||||
end
|
||||
end
|
||||
@installer = Gem::Installer.new @gem
|
||||
@installer = Gem::Installer.at @gem
|
||||
build_rake_in do
|
||||
use_ui @ui do
|
||||
assert_equal @spec, @installer.install
|
||||
|
@ -884,7 +884,7 @@ gem 'other', version
|
|||
|
||||
def test_install_force
|
||||
use_ui @ui do
|
||||
installer = Gem::Installer.new old_ruby_required, :force => true
|
||||
installer = Gem::Installer.at old_ruby_required, :force => true
|
||||
installer.install
|
||||
end
|
||||
|
||||
|
@ -993,7 +993,7 @@ gem 'other', version
|
|||
use_ui @ui do
|
||||
path = Gem::Package.build @spec
|
||||
|
||||
@installer = Gem::Installer.new path
|
||||
@installer = Gem::Installer.at path
|
||||
@installer.install
|
||||
end
|
||||
|
||||
|
@ -1016,7 +1016,7 @@ gem 'other', version
|
|||
use_ui @ui do
|
||||
path = Gem::Package.build @spec
|
||||
|
||||
installer = Gem::Installer.new path, :install_dir => gemhome2
|
||||
installer = Gem::Installer.at path, :install_dir => gemhome2
|
||||
installer.install
|
||||
end
|
||||
|
||||
|
@ -1056,7 +1056,7 @@ gem 'other', version
|
|||
use_ui @ui do
|
||||
path = Gem::Package.build @spec
|
||||
|
||||
@installer = Gem::Installer.new path
|
||||
@installer = Gem::Installer.at path
|
||||
@installer.install
|
||||
end
|
||||
assert_path_exists File.join @spec.gem_dir, rb
|
||||
|
@ -1097,7 +1097,7 @@ gem 'other', version
|
|||
use_ui @ui do
|
||||
path = Gem::Package.build @spec
|
||||
|
||||
@installer = Gem::Installer.new path
|
||||
@installer = Gem::Installer.at path
|
||||
@installer.install
|
||||
end
|
||||
assert_path_exists so
|
||||
|
@ -1175,7 +1175,7 @@ gem 'other', version
|
|||
# that it work everything out on it's own.
|
||||
Gem::Specification.reset
|
||||
|
||||
installer = Gem::Installer.new gem, :install_dir => gemhome2
|
||||
installer = Gem::Installer.at gem, :install_dir => gemhome2
|
||||
|
||||
build_rake_in do
|
||||
use_ui @ui do
|
||||
|
@ -1186,7 +1186,7 @@ gem 'other', version
|
|||
|
||||
def test_pre_install_checks_ruby_version
|
||||
use_ui @ui do
|
||||
installer = Gem::Installer.new old_ruby_required
|
||||
installer = Gem::Installer.at old_ruby_required
|
||||
e = assert_raises Gem::InstallError do
|
||||
installer.pre_install_checks
|
||||
end
|
||||
|
@ -1205,7 +1205,7 @@ gem 'other', version
|
|||
gem = File.join(@gemhome, 'cache', spec.file_name)
|
||||
|
||||
use_ui @ui do
|
||||
@installer = Gem::Installer.new gem
|
||||
@installer = Gem::Installer.at gem
|
||||
e = assert_raises Gem::InstallError do
|
||||
@installer.pre_install_checks
|
||||
end
|
||||
|
@ -1231,7 +1231,7 @@ gem 'other', version
|
|||
def test_process_options_build_root
|
||||
build_root = File.join @tempdir, 'build_root'
|
||||
|
||||
@installer = Gem::Installer.new @gem, :build_root => build_root
|
||||
@installer = Gem::Installer.at @gem, :build_root => build_root
|
||||
|
||||
assert_equal Pathname(build_root), @installer.build_root
|
||||
assert_equal File.join(build_root, @gemhome, 'bin'), @installer.bin_dir
|
||||
|
@ -1406,7 +1406,7 @@ gem 'other', version
|
|||
end
|
||||
|
||||
def test_write_build_info_file_install_dir
|
||||
installer = Gem::Installer.new @gem, :install_dir => "#{@gemhome}2"
|
||||
installer = Gem::Installer.at @gem, :install_dir => "#{@gemhome}2"
|
||||
|
||||
installer.build_args = %w[
|
||||
--with-libyaml-dir /usr/local/Cellar/libyaml/0.1.4
|
||||
|
@ -1426,8 +1426,7 @@ gem 'other', version
|
|||
FileUtils.mv cache_file, gem
|
||||
refute_path_exists cache_file
|
||||
|
||||
installer = Gem::Installer.new gem
|
||||
installer.spec = @spec
|
||||
installer = Gem::Installer.at gem
|
||||
installer.gem_home = @gemhome
|
||||
|
||||
installer.write_cache_file
|
||||
|
@ -1439,7 +1438,7 @@ gem 'other', version
|
|||
FileUtils.rm @spec.spec_file
|
||||
refute_path_exists @spec.spec_file
|
||||
|
||||
@installer.spec = @spec
|
||||
@installer = Gem::Installer.for_spec @spec
|
||||
@installer.gem_home = @gemhome
|
||||
|
||||
@installer.write_spec
|
||||
|
@ -1459,7 +1458,7 @@ gem 'other', version
|
|||
|
||||
@spec.files = %w[a.rb b.rb c.rb]
|
||||
|
||||
@installer.spec = @spec
|
||||
@installer = Gem::Installer.for_spec @spec
|
||||
@installer.gem_home = @gemhome
|
||||
|
||||
@installer.write_spec
|
||||
|
@ -1474,6 +1473,13 @@ gem 'other', version
|
|||
assert_match %r!/gemhome/gems/a-2$!, @installer.dir
|
||||
end
|
||||
|
||||
def test_default_gem_loaded_from
|
||||
spec = util_spec 'a'
|
||||
installer = Gem::Installer.for_spec spec, :install_as_default => true
|
||||
installer.install
|
||||
assert_predicate spec, :default_gem?
|
||||
end
|
||||
|
||||
def test_default_gem
|
||||
FileUtils.rm_f File.join(Gem.dir, 'specifications')
|
||||
|
||||
|
@ -1490,10 +1496,10 @@ gem 'other', version
|
|||
installed_exec = File.join util_inst_bindir, 'executable'
|
||||
assert_path_exists installed_exec
|
||||
|
||||
assert File.directory? File.join(Gem.dir, 'specifications')
|
||||
assert File.directory? File.join(Gem.dir, 'specifications', 'default')
|
||||
assert File.directory? File.join(Gem.default_dir, 'specifications')
|
||||
assert File.directory? File.join(Gem.default_dir, 'specifications', 'default')
|
||||
|
||||
default_spec = eval File.read File.join(Gem.dir, 'specifications', 'default', 'a-2.gemspec')
|
||||
default_spec = eval File.read File.join(Gem.default_dir, 'specifications', 'default', 'a-2.gemspec')
|
||||
assert_equal Gem::Version.new("2"), default_spec.version
|
||||
assert_equal ['bin/executable'], default_spec.files
|
||||
end
|
||||
|
|
|
@ -132,6 +132,37 @@ class TestGemPackage < Gem::Package::TarTestCase
|
|||
assert_equal %w[lib/code.rb], files
|
||||
end
|
||||
|
||||
def test_add_files_symlink
|
||||
skip 'symlink not supported' if Gem.win_platform?
|
||||
|
||||
spec = Gem::Specification.new
|
||||
spec.files = %w[lib/code.rb lib/code_sym.rb]
|
||||
|
||||
FileUtils.mkdir_p 'lib'
|
||||
open 'lib/code.rb', 'w' do |io| io.write '# lib/code.rb' end
|
||||
File.symlink('lib/code.rb', 'lib/code_sym.rb')
|
||||
|
||||
package = Gem::Package.new 'bogus.gem'
|
||||
package.spec = spec
|
||||
|
||||
tar = util_tar do |tar_io|
|
||||
package.add_files tar_io
|
||||
end
|
||||
|
||||
tar.rewind
|
||||
|
||||
files, symlinks = [], []
|
||||
|
||||
Gem::Package::TarReader.new tar do |tar_io|
|
||||
tar_io.each_entry do |entry|
|
||||
(entry.symlink? ? symlinks : files) << entry.full_name
|
||||
end
|
||||
end
|
||||
|
||||
assert_equal %w[lib/code.rb], files
|
||||
assert_equal %w[lib/code_sym.rb], symlinks
|
||||
end
|
||||
|
||||
def test_build
|
||||
spec = Gem::Specification.new 'build', '1'
|
||||
spec.summary = 'build'
|
||||
|
@ -396,6 +427,21 @@ class TestGemPackage < Gem::Package::TarTestCase
|
|||
"#{@destination} is not allowed", e.message)
|
||||
end
|
||||
|
||||
def test_extract_tar_gz_symlink_absolute
|
||||
package = Gem::Package.new @gem
|
||||
|
||||
tgz_io = util_tar_gz do |tar|
|
||||
tar.add_symlink 'code.rb', '/absolute.rb', 0644
|
||||
end
|
||||
|
||||
e = assert_raises Gem::Package::PathError do
|
||||
package.extract_tar_gz tgz_io, @destination
|
||||
end
|
||||
|
||||
assert_equal("installing into parent path /absolute.rb of " +
|
||||
"#{@destination} is not allowed", e.message)
|
||||
end
|
||||
|
||||
def test_extract_tar_gz_directory
|
||||
package = Gem::Package.new @gem
|
||||
|
||||
|
@ -821,4 +867,3 @@ class TestGemPackage < Gem::Package::TarTestCase
|
|||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -92,6 +92,14 @@ class TestGemPackageTarReaderEntry < Gem::Package::TarTestCase
|
|||
close_util_entry(dir_ent) if dir_ent
|
||||
end
|
||||
|
||||
def test_symlink_eh
|
||||
assert_equal false, @entry.symlink?
|
||||
symlink_ent = util_symlink_entry
|
||||
assert_equal true, symlink_ent.symlink?
|
||||
ensure
|
||||
close_util_entry(symlink_ent) if symlink_ent
|
||||
end
|
||||
|
||||
def test_file_eh
|
||||
assert_equal true, @entry.file?
|
||||
dir_ent = util_dir_entry
|
||||
|
@ -131,4 +139,3 @@ class TestGemPackageTarReaderEntry < Gem::Package::TarTestCase
|
|||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -30,6 +30,16 @@ class TestGemPackageTarWriter < Gem::Package::TarTestCase
|
|||
assert_equal 1024, @io.pos
|
||||
end
|
||||
|
||||
def test_add_symlink
|
||||
Time.stub :now, Time.at(1458518157) do
|
||||
@tar_writer.add_symlink 'x', 'y', 0644
|
||||
|
||||
assert_headers_equal(tar_symlink_header('x', '', 0644, Time.now, 'y'),
|
||||
@io.string[0, 512])
|
||||
end
|
||||
assert_equal 512, @io.pos
|
||||
end
|
||||
|
||||
def test_add_file_digest
|
||||
digest_algorithms = Digest::SHA1, Digest::SHA512
|
||||
|
||||
|
@ -251,4 +261,3 @@ class TestGemPackageTarWriter < Gem::Package::TarTestCase
|
|||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -80,6 +80,15 @@ class TestGemRequestConnectionPool < Gem::TestCase
|
|||
assert_equal ['example', 80], net_http_args
|
||||
end
|
||||
|
||||
def test_net_http_args_ipv6
|
||||
pools = Gem::Request::ConnectionPools.new nil, []
|
||||
|
||||
net_http_args = pools.send :net_http_args, URI('http://[::1]'), nil
|
||||
|
||||
expected_host = RUBY_VERSION >= "1.9.3" ? "::1" : "[::1]"
|
||||
assert_equal [expected_host, 80], net_http_args
|
||||
end
|
||||
|
||||
def test_net_http_args_proxy
|
||||
pools = Gem::Request::ConnectionPools.new nil, []
|
||||
|
||||
|
|
|
@ -141,10 +141,9 @@ Gems to install:
|
|||
|
||||
def test_install_from_gemdeps_lockfile
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'a', 1
|
||||
fetcher.gem 'a', 2
|
||||
fetcher.gem 'b', 1, 'a' => '>= 0'
|
||||
fetcher.clear
|
||||
fetcher.download 'a', 1
|
||||
fetcher.download 'a', 2
|
||||
fetcher.download 'b', 1, 'a' => '>= 0'
|
||||
end
|
||||
|
||||
rs = Gem::RequestSet.new
|
||||
|
@ -445,10 +444,8 @@ ruby "0"
|
|||
end
|
||||
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem "a", "1", "b" => "= 1"
|
||||
fetcher.gem "b", "1"
|
||||
|
||||
fetcher.clear
|
||||
fetcher.download "a", "1", "b" => "= 1"
|
||||
fetcher.download "b", "1"
|
||||
end
|
||||
|
||||
rs = Gem::RequestSet.new
|
||||
|
|
|
@ -338,13 +338,11 @@ DEPENDENCIES
|
|||
|
||||
def test_to_s_gem_source
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.spec 'a', 2
|
||||
fetcher.clear
|
||||
fetcher.download 'a', 2
|
||||
end
|
||||
|
||||
spec_fetcher 'http://other.example/' do |fetcher|
|
||||
fetcher.spec 'b', 2
|
||||
fetcher.clear
|
||||
fetcher.download 'b', 2
|
||||
end
|
||||
|
||||
Gem.sources << 'http://other.example/'
|
||||
|
|
|
@ -95,24 +95,6 @@ class TestGemResolver < Gem::TestCase
|
|||
assert_same index_set, composed
|
||||
end
|
||||
|
||||
def test_handle_conflict
|
||||
a1 = util_spec 'a', 1
|
||||
|
||||
r1 = Gem::Resolver::DependencyRequest.new dep('a', '= 1'), nil
|
||||
r2 = Gem::Resolver::DependencyRequest.new dep('a', '= 2'), nil
|
||||
r3 = Gem::Resolver::DependencyRequest.new dep('a', '= 3'), nil
|
||||
|
||||
existing = Gem::Resolver::ActivationRequest.new a1, r1, false
|
||||
|
||||
res = Gem::Resolver.new [a1]
|
||||
|
||||
res.handle_conflict r2, existing
|
||||
res.handle_conflict r2, existing
|
||||
res.handle_conflict r3, existing
|
||||
|
||||
assert_equal 2, res.conflicts.length
|
||||
end
|
||||
|
||||
def test_requests
|
||||
a1 = util_spec 'a', 1, 'b' => 2
|
||||
|
||||
|
@ -122,11 +104,11 @@ class TestGemResolver < Gem::TestCase
|
|||
|
||||
res = Gem::Resolver.new [a1]
|
||||
|
||||
reqs = Gem::Resolver::RequirementList.new
|
||||
reqs = []
|
||||
|
||||
res.requests a1, act, reqs
|
||||
|
||||
assert_equal ['b (= 2)'], reqs.to_a.map { |req| req.to_s }
|
||||
assert_equal ['b (= 2)'], reqs.map { |req| req.to_s }
|
||||
end
|
||||
|
||||
def test_requests_development
|
||||
|
@ -144,11 +126,11 @@ class TestGemResolver < Gem::TestCase
|
|||
res = Gem::Resolver.new [act]
|
||||
res.development = true
|
||||
|
||||
reqs = Gem::Resolver::RequirementList.new
|
||||
reqs = []
|
||||
|
||||
res.requests spec, act, reqs
|
||||
|
||||
assert_equal ['b (= 2)'], reqs.to_a.map { |req| req.to_s }
|
||||
assert_equal ['b (= 2)'], reqs.map { |req| req.to_s }
|
||||
|
||||
assert spec.instance_variable_defined? :@called
|
||||
end
|
||||
|
@ -163,7 +145,7 @@ class TestGemResolver < Gem::TestCase
|
|||
res = Gem::Resolver.new [a1]
|
||||
res.ignore_dependencies = true
|
||||
|
||||
reqs = Gem::Resolver::RequirementList.new
|
||||
reqs = []
|
||||
|
||||
res.requests a1, act, reqs
|
||||
|
||||
|
@ -438,19 +420,19 @@ class TestGemResolver < Gem::TestCase
|
|||
r.resolve
|
||||
end
|
||||
|
||||
deps = [make_dep("c", "= 1"), make_dep("c", "= 2")]
|
||||
deps = [make_dep("c", "= 2"), make_dep("c", "= 1")]
|
||||
assert_equal deps, e.conflicting_dependencies
|
||||
|
||||
con = e.conflict
|
||||
|
||||
act = con.activated
|
||||
assert_equal "c-2", act.spec.full_name
|
||||
assert_equal "c-1", act.spec.full_name
|
||||
|
||||
parent = act.parent
|
||||
assert_equal "b-1", parent.spec.full_name
|
||||
assert_equal "a-1", parent.spec.full_name
|
||||
|
||||
act = con.requester
|
||||
assert_equal "a-1", act.spec.full_name
|
||||
assert_equal "b-1", act.spec.full_name
|
||||
end
|
||||
|
||||
def test_raises_when_a_gem_is_missing
|
||||
|
@ -538,11 +520,11 @@ class TestGemResolver < Gem::TestCase
|
|||
assert_equal req('>= 0'), dependency.requirement
|
||||
|
||||
activated = e.conflict.activated
|
||||
assert_equal 'c-1', activated.full_name
|
||||
assert_equal 'c-2', activated.full_name
|
||||
|
||||
assert_equal dep('c', '= 1'), activated.request.dependency
|
||||
assert_equal dep('c', '>= 2'), activated.request.dependency
|
||||
|
||||
assert_equal [dep('c', '>= 2'), dep('c', '= 1')],
|
||||
assert_equal [dep('c', '= 1'), dep('c', '>= 2')],
|
||||
e.conflict.conflicting_dependencies
|
||||
end
|
||||
|
||||
|
@ -730,4 +712,3 @@ class TestGemResolver < Gem::TestCase
|
|||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -4,9 +4,8 @@ class TestGemResolverInstallerSet < Gem::TestCase
|
|||
|
||||
def test_add_always_install
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.spec 'a', 1
|
||||
fetcher.spec 'a', 2
|
||||
fetcher.clear
|
||||
fetcher.download 'a', 1
|
||||
fetcher.download 'a', 2
|
||||
end
|
||||
|
||||
util_gem 'a', 1
|
||||
|
@ -39,11 +38,10 @@ class TestGemResolverInstallerSet < Gem::TestCase
|
|||
|
||||
def test_add_always_install_platform
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.spec 'a', 1
|
||||
fetcher.spec 'a', 2 do |s|
|
||||
fetcher.download 'a', 1
|
||||
fetcher.download 'a', 2 do |s|
|
||||
s.platform = Gem::Platform.new 'x86-freebsd-9'
|
||||
end
|
||||
fetcher.clear
|
||||
end
|
||||
|
||||
set = Gem::Resolver::InstallerSet.new :both
|
||||
|
@ -139,8 +137,7 @@ class TestGemResolverInstallerSet < Gem::TestCase
|
|||
|
||||
def test_find_all_always_install
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.spec 'a', 2
|
||||
fetcher.clear
|
||||
fetcher.download 'a', 2
|
||||
end
|
||||
|
||||
util_gem 'a', 1
|
||||
|
@ -156,9 +153,8 @@ class TestGemResolverInstallerSet < Gem::TestCase
|
|||
|
||||
def test_find_all_prerelease
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.spec 'a', '1'
|
||||
fetcher.spec 'a', '1.a'
|
||||
fetcher.clear
|
||||
fetcher.download 'a', '1'
|
||||
fetcher.download 'a', '1.a'
|
||||
end
|
||||
|
||||
set = Gem::Resolver::InstallerSet.new :both
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
require 'rubygems/test_case'
|
||||
require 'rubygems/installer'
|
||||
require 'rubygems/resolver'
|
||||
|
||||
class TestGemResolverLockSpecification < Gem::TestCase
|
||||
|
@ -34,8 +35,7 @@ class TestGemResolverLockSpecification < Gem::TestCase
|
|||
|
||||
def test_install
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'a', 2
|
||||
fetcher.clear
|
||||
fetcher.download 'a', 2
|
||||
end
|
||||
|
||||
spec = @LS.new @set, 'a', v(2), @source, Gem::Platform::RUBY
|
||||
|
@ -85,6 +85,7 @@ class TestGemResolverLockSpecification < Gem::TestCase
|
|||
|
||||
def test_spec_loaded
|
||||
real_spec = util_spec 'a', 2
|
||||
install_specs real_spec
|
||||
real_spec.activate
|
||||
|
||||
version = v(2)
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
require 'benchmark'
|
||||
require 'rubygems/test_case'
|
||||
require 'pathname'
|
||||
require 'stringio'
|
||||
require 'rubygems/ext'
|
||||
require 'rubygems/specification'
|
||||
require 'rubygems/installer'
|
||||
|
||||
class TestGemSpecification < Gem::TestCase
|
||||
|
||||
|
@ -112,7 +114,7 @@ end
|
|||
c2 = new_spec "c", "2"
|
||||
|
||||
Gem::Specification.reset
|
||||
install_specs a1, b1, b2, c1, c2
|
||||
install_specs c1, c2, b1, b2, a1
|
||||
|
||||
a1.activate
|
||||
assert_equal %w(a-1), loaded_spec_names
|
||||
|
@ -125,6 +127,32 @@ end
|
|||
end
|
||||
end
|
||||
|
||||
def test_find_in_unresolved_tree_is_not_exponentiental
|
||||
save_loaded_features do
|
||||
num_of_pkg = 7
|
||||
num_of_version_per_pkg = 3
|
||||
packages = (0..num_of_pkg).map do |pkgi|
|
||||
(0..num_of_version_per_pkg).map do |pkg_version|
|
||||
deps = Hash[((pkgi + 1)..num_of_pkg).map { |deppkgi|
|
||||
["pkg#{deppkgi}", ">= 0"]
|
||||
}]
|
||||
new_spec "pkg#{pkgi}", pkg_version.to_s, deps
|
||||
end
|
||||
end
|
||||
base = new_spec "pkg_base", "1", {"pkg0" => ">= 0"}
|
||||
|
||||
Gem::Specification.reset
|
||||
install_specs(*packages.flatten.reverse)
|
||||
install_specs base
|
||||
base.activate
|
||||
|
||||
tms = Benchmark.measure {
|
||||
assert_raises(LoadError) { require 'no_such_file_foo' }
|
||||
}
|
||||
assert_operator tms.total, :<=, 10
|
||||
end
|
||||
end
|
||||
|
||||
def test_self_activate_ambiguous_indirect
|
||||
save_loaded_features do
|
||||
a1 = new_spec "a", "1", "b" => "> 0"
|
||||
|
@ -133,7 +161,7 @@ end
|
|||
c1 = new_spec "c", "1", nil, "lib/d.rb"
|
||||
c2 = new_spec "c", "2", nil, "lib/d.rb"
|
||||
|
||||
install_specs a1, b1, b2, c1, c2
|
||||
install_specs c1, c2, b1, b2, a1
|
||||
|
||||
a1.activate
|
||||
assert_equal %w(a-1), loaded_spec_names
|
||||
|
@ -155,7 +183,7 @@ end
|
|||
c1 = new_spec "c", "1", nil, "lib/d.rb"
|
||||
c2 = new_spec("c", "2", { "a" => "1" }, "lib/d.rb") # conflicts with a-2
|
||||
|
||||
install_specs a1, a2, b1, b2, c1, c2
|
||||
install_specs c1, b1, a1, a2, c2, b2
|
||||
|
||||
a2.activate
|
||||
assert_equal %w(a-2), loaded_spec_names
|
||||
|
@ -177,7 +205,7 @@ end
|
|||
c2 = new_spec "c", "2"
|
||||
d1 = new_spec "d", "1", nil, "lib/d.rb"
|
||||
|
||||
install_specs a1, b1, b2, c1, c2, d1
|
||||
install_specs d1, c1, c2, b1, b2, a1
|
||||
|
||||
a1.activate
|
||||
assert_equal %w(a-1), loaded_spec_names
|
||||
|
@ -190,6 +218,155 @@ end
|
|||
end
|
||||
end
|
||||
|
||||
def test_require_should_prefer_latest_gem_level1
|
||||
save_loaded_features do
|
||||
a1 = new_spec "a", "1", "b" => "> 0"
|
||||
b1 = new_spec "b", "1", "c" => ">= 0" # unresolved
|
||||
b2 = new_spec "b", "2", "c" => ">= 0"
|
||||
c1 = new_spec "c", "1", nil, "lib/c.rb" # 1st level
|
||||
c2 = new_spec "c", "2", nil, "lib/c.rb"
|
||||
|
||||
install_specs c1, c2, b1, b2, a1
|
||||
|
||||
a1.activate
|
||||
|
||||
require "c"
|
||||
|
||||
assert_equal %w(a-1 b-2 c-2), loaded_spec_names
|
||||
end
|
||||
end
|
||||
|
||||
def test_require_should_prefer_latest_gem_level2
|
||||
save_loaded_features do
|
||||
a1 = new_spec "a", "1", "b" => "> 0"
|
||||
b1 = new_spec "b", "1", "c" => ">= 0" # unresolved
|
||||
b2 = new_spec "b", "2", "c" => ">= 0"
|
||||
c1 = new_spec "c", "1", "d" => ">= 0" # 1st level
|
||||
c2 = new_spec "c", "2", "d" => ">= 0"
|
||||
d1 = new_spec "d", "1", nil, "lib/d.rb" # 2nd level
|
||||
d2 = new_spec "d", "2", nil, "lib/d.rb"
|
||||
|
||||
install_specs d1, d2, c1, c2, b1, b2, a1
|
||||
|
||||
a1.activate
|
||||
|
||||
require "d"
|
||||
|
||||
assert_equal %w(a-1 b-2 c-2 d-2), loaded_spec_names
|
||||
end
|
||||
end
|
||||
|
||||
def test_require_finds_in_2nd_level_indirect
|
||||
save_loaded_features do
|
||||
a1 = new_spec "a", "1", "b" => "> 0"
|
||||
b1 = new_spec "b", "1", "c" => ">= 0" # unresolved
|
||||
b2 = new_spec "b", "2", "c" => ">= 0"
|
||||
c1 = new_spec "c", "1", "d" => "<= 2" # 1st level
|
||||
c2 = new_spec "c", "2", "d" => "<= 2"
|
||||
d1 = new_spec "d", "1", nil, "lib/d.rb" # 2nd level
|
||||
d2 = new_spec "d", "2", nil, "lib/d.rb"
|
||||
d3 = new_spec "d", "3", nil, "lib/d.rb"
|
||||
|
||||
install_specs d1, d2, d3, c1, c2, b1, b2, a1
|
||||
|
||||
a1.activate
|
||||
|
||||
require "d"
|
||||
|
||||
assert_equal %w(a-1 b-2 c-2 d-2), loaded_spec_names
|
||||
end
|
||||
end
|
||||
|
||||
def test_require_should_prefer_reachable_gems
|
||||
save_loaded_features do
|
||||
a1 = new_spec "a", "1", "b" => "> 0"
|
||||
b1 = new_spec "b", "1", "c" => ">= 0" # unresolved
|
||||
b2 = new_spec "b", "2", "c" => ">= 0"
|
||||
c1 = new_spec "c", "1", "d" => "<= 2" # 1st level
|
||||
c2 = new_spec "c", "2", "d" => "<= 2"
|
||||
d1 = new_spec "d", "1", nil, "lib/d.rb" # 2nd level
|
||||
d2 = new_spec "d", "2", nil, "lib/d.rb"
|
||||
d3 = new_spec "d", "3", nil, "lib/d.rb"
|
||||
e = new_spec "anti_d", "1", nil, "lib/d.rb"
|
||||
|
||||
install_specs d1, d2, d3, e, c1, c2, b1, b2, a1
|
||||
|
||||
a1.activate
|
||||
|
||||
require "d"
|
||||
|
||||
assert_equal %w(a-1 b-2 c-2 d-2), loaded_spec_names
|
||||
end
|
||||
end
|
||||
|
||||
def test_require_should_not_conflict
|
||||
save_loaded_features do
|
||||
base = new_spec "0", "1", "A" => ">= 1"
|
||||
a1 = new_spec "A", "1", {"c" => ">= 2", "b" => "> 0"}, "lib/a.rb"
|
||||
a2 = new_spec "A", "2", {"c" => ">= 2", "b" => "> 0"}, "lib/a.rb"
|
||||
b1 = new_spec "b", "1", {"c" => "= 1"}, "lib/d.rb"
|
||||
b2 = new_spec "b", "2", {"c" => "= 2"}, "lib/d.rb"
|
||||
c1 = new_spec "c", "1", {}, "lib/c.rb"
|
||||
c2 = new_spec "c", "2", {}, "lib/c.rb"
|
||||
c3 = new_spec "c", "3", {}, "lib/c.rb"
|
||||
|
||||
install_specs c1, c2, c3, b1, b2, a1, a2, base
|
||||
|
||||
base.activate
|
||||
assert_equal %w(0-1), loaded_spec_names
|
||||
assert_equal ["A (>= 1)"], unresolved_names
|
||||
|
||||
require "d"
|
||||
|
||||
assert_equal %w(0-1 A-2 b-2 c-2), loaded_spec_names
|
||||
assert_equal [], unresolved_names
|
||||
end
|
||||
end
|
||||
|
||||
def test_inner_clonflict_in_indirect_gems
|
||||
save_loaded_features do
|
||||
a1 = new_spec "a", "1", "b" => "> 0"
|
||||
b1 = new_spec "b", "1", "c" => ">= 1" # unresolved
|
||||
b2 = new_spec "b", "2", "c" => ">= 1", "d" => "< 3"
|
||||
c1 = new_spec "c", "1", "d" => "<= 2" # 1st level
|
||||
c2 = new_spec "c", "2", "d" => "<= 2"
|
||||
c3 = new_spec "c", "3", "d" => "<= 3"
|
||||
d1 = new_spec "d", "1", nil, "lib/d.rb" # 2nd level
|
||||
d2 = new_spec "d", "2", nil, "lib/d.rb"
|
||||
d3 = new_spec "d", "3", nil, "lib/d.rb"
|
||||
|
||||
install_specs d1, d2, d3, c1, c2, c3, b1, b2, a1
|
||||
|
||||
a1.activate
|
||||
|
||||
require "d"
|
||||
|
||||
assert_includes [%w(a-1 b-2 c-3 d-2),%w(a-1 b-2 d-2)], loaded_spec_names
|
||||
end
|
||||
end
|
||||
|
||||
def test_inner_clonflict_in_indirect_gems_reversed
|
||||
save_loaded_features do
|
||||
a1 = new_spec "a", "1", "b" => "> 0"
|
||||
b1 = new_spec "b", "1", "xc" => ">= 1" # unresolved
|
||||
b2 = new_spec "b", "2", "xc" => ">= 1", "d" => "< 3"
|
||||
c1 = new_spec "xc", "1", "d" => "<= 3" # 1st level
|
||||
c2 = new_spec "xc", "2", "d" => "<= 2"
|
||||
c3 = new_spec "xc", "3", "d" => "<= 3"
|
||||
d1 = new_spec "d", "1", nil, "lib/d.rb" # 2nd level
|
||||
d2 = new_spec "d", "2", nil, "lib/d.rb"
|
||||
d3 = new_spec "d", "3", nil, "lib/d.rb"
|
||||
|
||||
install_specs d1, d2, d3, c1, c2, c3, b1, b2, a1
|
||||
|
||||
a1.activate
|
||||
|
||||
require "d"
|
||||
|
||||
assert_includes [%w(a-1 b-2 d-2 xc-3), %w(a-1 b-2 d-2)], loaded_spec_names
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# [A] depends on
|
||||
# [C] = 1.0 depends on
|
||||
|
@ -197,13 +374,14 @@ end
|
|||
# [B] ~> 1.0 (satisfied by 1.0)
|
||||
|
||||
def test_self_activate_checks_dependencies
|
||||
a, _ = util_spec 'a', '1.0'
|
||||
a = util_spec 'a', '1.0'
|
||||
a.add_dependency 'c', '= 1.0'
|
||||
a.add_dependency 'b', '~> 1.0'
|
||||
|
||||
util_spec 'b', '1.0'
|
||||
util_spec 'b', '2.0'
|
||||
c, _ = util_spec 'c', '1.0', 'b' => '= 2.0'
|
||||
b1 = util_spec 'b', '1.0'
|
||||
b2 = util_spec 'b', '2.0'
|
||||
c = util_spec 'c', '1.0', 'b' => '= 2.0'
|
||||
install_specs b1, b2, c, a
|
||||
|
||||
e = assert_raises Gem::LoadError do
|
||||
assert_activate nil, a, c, "b"
|
||||
|
@ -220,10 +398,12 @@ end
|
|||
# [B] = 2.0
|
||||
|
||||
def test_self_activate_divergent
|
||||
a, _ = util_spec 'a', '1.0', 'b' => '~> 1.0', 'c' => '= 1.0'
|
||||
util_spec 'b', '1.0'
|
||||
util_spec 'b', '2.0'
|
||||
c, _ = util_spec 'c', '1.0', 'b' => '= 2.0'
|
||||
a = util_spec 'a', '1.0', 'b' => '~> 1.0', 'c' => '= 1.0'
|
||||
b1 = util_spec 'b', '1.0'
|
||||
b2 = util_spec 'b', '2.0'
|
||||
c = util_spec 'c', '1.0', 'b' => '= 2.0'
|
||||
|
||||
install_specs b1, b2, c, a
|
||||
|
||||
e = assert_raises Gem::ConflictError do
|
||||
assert_activate nil, a, c, "b"
|
||||
|
@ -241,6 +421,8 @@ end
|
|||
@d1 = util_spec 'd', '1'
|
||||
@d2 = util_spec 'd', '2'
|
||||
|
||||
install_specs @d1, @d2, e1
|
||||
|
||||
assert_activate %w[d-1 e-1], e1, "d"
|
||||
end
|
||||
|
||||
|
@ -259,6 +441,7 @@ end
|
|||
@w1 = util_spec 'w', '1', 'x' => nil
|
||||
|
||||
util_set_arch 'cpu-my_platform1'
|
||||
install_specs @x1_m, @x1_o, @w1
|
||||
|
||||
assert_activate %w[x-1-cpu-my_platform-1 w-1], @w1, @x1_m
|
||||
end
|
||||
|
@ -274,6 +457,7 @@ end
|
|||
end
|
||||
|
||||
@z1 = util_spec 'z', '1', 'y' => nil
|
||||
install_specs @y1, @y1_1_p, @z1
|
||||
|
||||
assert_activate %w[y-1 z-1], @z1, @y1
|
||||
end
|
||||
|
@ -291,6 +475,7 @@ end
|
|||
s.add_dependency 'a'
|
||||
s.add_development_dependency 'aa'
|
||||
end
|
||||
install_specs @a1_pre, @b1, @c1_pre
|
||||
|
||||
assert_activate %w[a-1.a b-1 c-1.a], @c1_pre, @a1_pre, @b1
|
||||
end
|
||||
|
@ -300,7 +485,7 @@ end
|
|||
b1 = new_spec "b", "1", nil, "lib/b/c.rb"
|
||||
b2 = new_spec "b", "2", nil, "lib/b/c.rb"
|
||||
|
||||
install_specs a1, b1, b2
|
||||
install_specs b1, b2, a1
|
||||
|
||||
a1.activate
|
||||
save_loaded_features do
|
||||
|
@ -320,7 +505,7 @@ end
|
|||
d1 = new_spec "d", "1", { "c" => "< 2" }, "lib/d.rb"
|
||||
d2 = new_spec "d", "2", { "c" => "< 2" }, "lib/d.rb" # this
|
||||
|
||||
install_specs a1, b1, b2, c1, c2, d1, d2
|
||||
install_specs c1, c2, b1, b2, d1, d2, a1
|
||||
|
||||
a1.activate
|
||||
|
||||
|
@ -347,7 +532,7 @@ end
|
|||
c1 = new_spec "c", "1"
|
||||
c2 = new_spec "c", "2"
|
||||
|
||||
install_specs a1, b1, b2, c1, c2
|
||||
install_specs c1, c2, b1, b2, a1
|
||||
|
||||
a1.activate
|
||||
assert_equal %w(a-1 b-1 c-1), loaded_spec_names
|
||||
|
@ -367,8 +552,9 @@ end
|
|||
|
||||
def test_self_activate_unrelated
|
||||
a = util_spec 'a', '1.0', 'b' => '>= 1.0'
|
||||
util_spec 'b', '1.0'
|
||||
b = util_spec 'b', '1.0'
|
||||
c = util_spec 'c', '1.0'
|
||||
install_specs b, c, a
|
||||
|
||||
assert_activate %w[b-1.0 c-1.0 a-1.0], a, c, "b"
|
||||
end
|
||||
|
@ -384,10 +570,11 @@ end
|
|||
|
||||
def test_self_activate_over
|
||||
a = util_spec 'a', '1.0', 'b' => '>= 1.0', 'c' => '= 1.0'
|
||||
util_spec 'b', '1.0'
|
||||
util_spec 'b', '1.1'
|
||||
util_spec 'b', '2.0'
|
||||
util_spec 'c', '1.0', 'b' => '~> 1.0'
|
||||
install_specs util_spec 'b', '1.0'
|
||||
install_specs util_spec 'b', '1.1'
|
||||
install_specs util_spec 'b', '2.0'
|
||||
install_specs util_spec 'c', '1.0', 'b' => '~> 1.0'
|
||||
install_specs a
|
||||
|
||||
a.activate
|
||||
|
||||
|
@ -407,10 +594,12 @@ end
|
|||
# first resolve through a dependency that is later pruned.
|
||||
|
||||
def test_self_activate_under
|
||||
a, _ = util_spec 'a', '1.0', 'b' => '~> 1.0', 'c' => '= 1.0'
|
||||
util_spec 'b', '1.0'
|
||||
util_spec 'b', '1.1'
|
||||
c, _ = util_spec 'c', '1.0', 'b' => '= 1.0'
|
||||
a = util_spec 'a', '1.0', 'b' => '~> 1.0', 'c' => '= 1.0'
|
||||
b1 = util_spec 'b', '1.0'
|
||||
b1_1 = util_spec 'b', '1.1'
|
||||
c = util_spec 'c', '1.0', 'b' => '= 1.0'
|
||||
|
||||
install_specs b1, b1_1, c, a
|
||||
|
||||
assert_activate %w[b-1.0 c-1.0 a-1.0], a, c, "b"
|
||||
end
|
||||
|
@ -424,10 +613,11 @@ end
|
|||
# [C1] depends on nothing
|
||||
|
||||
def test_self_activate_dropped
|
||||
a1, = util_spec 'a', '1', 'b' => nil
|
||||
util_spec 'b', '1', 'c' => nil
|
||||
util_spec 'b', '2'
|
||||
util_spec 'c', '1'
|
||||
a1 = util_spec 'a', '1', 'b' => nil
|
||||
b1 = util_spec 'b', '1', 'c' => nil
|
||||
b2 = util_spec 'b', '2'
|
||||
c1 = util_spec 'c', '1'
|
||||
install_specs c1, b1, b2, a1
|
||||
|
||||
assert_activate %w[b-2 a-1], a1, "b"
|
||||
end
|
||||
|
@ -443,17 +633,20 @@ end
|
|||
# resolve.
|
||||
|
||||
def test_self_activate_raggi_the_edgecase_generator
|
||||
a, _ = util_spec 'a', '1.0', 'b' => '>= 1.0', 'c' => '>= 1.0'
|
||||
util_spec 'b', '1.0'
|
||||
util_spec 'b', '1.1', 'z' => '>= 1.0'
|
||||
c, _ = util_spec 'c', '1.0', 'b' => '= 1.0'
|
||||
a = util_spec 'a', '1.0', 'b' => '>= 1.0', 'c' => '>= 1.0'
|
||||
b1 = util_spec 'b', '1.0'
|
||||
b1_0 = util_spec 'b', '1.1', 'z' => '>= 1.0'
|
||||
c = util_spec 'c', '1.0', 'b' => '= 1.0'
|
||||
z = util_spec 'z', '1'
|
||||
|
||||
install_specs z, b1, b1_0, c, z
|
||||
|
||||
assert_activate %w[b-1.0 c-1.0 a-1.0], a, c, "b"
|
||||
end
|
||||
|
||||
def test_self_activate_conflict
|
||||
util_spec 'b', '1.0'
|
||||
util_spec 'b', '2.0'
|
||||
install_specs util_spec 'b', '1.0'
|
||||
install_specs util_spec 'b', '2.0'
|
||||
|
||||
gem "b", "= 1.0"
|
||||
|
||||
|
@ -465,6 +658,7 @@ end
|
|||
def test_self_all_equals
|
||||
a = new_spec "foo", "1", nil, "lib/foo.rb"
|
||||
|
||||
install_specs a
|
||||
Gem::Specification.all = [a]
|
||||
|
||||
assert_equal a, Gem::Specification.find_inactive_by_path('foo')
|
||||
|
@ -854,9 +1048,7 @@ dependencies: []
|
|||
|
||||
def test_self_outdated
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.spec 'a', 4
|
||||
|
||||
fetcher.clear
|
||||
fetcher.download 'a', 4
|
||||
|
||||
fetcher.spec 'a', 3
|
||||
end
|
||||
|
@ -866,10 +1058,8 @@ dependencies: []
|
|||
|
||||
def test_self_outdated_and_latest_remotes
|
||||
specs = spec_fetcher do |fetcher|
|
||||
fetcher.spec 'a', 4
|
||||
fetcher.spec 'b', 3
|
||||
|
||||
fetcher.clear
|
||||
fetcher.download 'a', 4
|
||||
fetcher.download 'b', 3
|
||||
|
||||
fetcher.spec 'a', '3.a'
|
||||
fetcher.spec 'b', 2
|
||||
|
@ -884,10 +1074,13 @@ dependencies: []
|
|||
end
|
||||
|
||||
def test_self_remove_spec
|
||||
install_specs @a1
|
||||
|
||||
assert_includes Gem::Specification.all_names, 'a-1'
|
||||
assert_includes Gem::Specification.stubs.map { |s| s.full_name }, 'a-1'
|
||||
|
||||
Gem::Specification.remove_spec @a1
|
||||
uninstall_gem @a1
|
||||
Gem::Specification.reset
|
||||
|
||||
refute_includes Gem::Specification.all_names, 'a-1'
|
||||
refute_includes Gem::Specification.stubs.map { |s| s.full_name }, 'a-1'
|
||||
|
@ -902,7 +1095,7 @@ dependencies: []
|
|||
|
||||
FileUtils.rm @a1.spec_file # bug #698
|
||||
|
||||
Gem::Specification.remove_spec @a1
|
||||
Gem::Specification.reset
|
||||
|
||||
refute_includes Gem::Specification.all_names, 'a-1'
|
||||
refute_includes Gem::Specification.stubs.map { |s| s.full_name }, 'a-1'
|
||||
|
@ -1183,6 +1376,17 @@ dependencies: []
|
|||
assert_path_exists @ext.extension_dir
|
||||
end
|
||||
|
||||
def test_default_spec_stub_is_marked_default
|
||||
default = new_default_spec 'default', 2
|
||||
install_default_gems default
|
||||
|
||||
stub = Gem::Specification.stubs.find { |s| s.name == 'default' }
|
||||
assert_predicate stub, :default_gem?
|
||||
|
||||
stub = Gem::Specification.find_all_by_name('default').first
|
||||
assert_predicate stub, :default_gem?
|
||||
end
|
||||
|
||||
def test_build_extensions_built
|
||||
ext_spec
|
||||
|
||||
|
@ -1419,7 +1623,9 @@ dependencies: []
|
|||
|
||||
assert_empty @gem.dependent_gems
|
||||
|
||||
bonobo = util_spec 'bonobo'
|
||||
bonobo = util_spec 'bonobo', 1
|
||||
install_gem bonobo
|
||||
install_gem @gem
|
||||
|
||||
expected = [
|
||||
[@gem, @bonobo, [bonobo]],
|
||||
|
@ -1932,7 +2138,7 @@ dependencies: []
|
|||
c1 = new_spec "c", "1", nil, "lib/d.rb"
|
||||
c2 = new_spec("c", "2", { "a" => "1" }, "lib/d.rb") # conflicts with a-2
|
||||
|
||||
install_specs a1, a2, b1, b2, c1, c2
|
||||
install_specs c1, b1, a1, a2, c2, b2
|
||||
|
||||
a1.activate
|
||||
c1.activate
|
||||
|
@ -2014,6 +2220,19 @@ dependencies: []
|
|||
assert_equal ['test/suite.rb'], @a1.test_files
|
||||
end
|
||||
|
||||
def test_runtime_predicate_true
|
||||
@a2.add_runtime_dependency 'b', '1'
|
||||
assert_predicate @a2.dependencies.first, :runtime?
|
||||
|
||||
@a2.dependencies.first.instance_variable_set :@type, nil
|
||||
assert_predicate @a2.dependencies.first, :runtime?
|
||||
end
|
||||
|
||||
def test_runtime_predicate_false
|
||||
@a2.add_development_dependency 'b', '1'
|
||||
refute_predicate @a2.dependencies.first, :runtime?
|
||||
end
|
||||
|
||||
def test_to_ruby
|
||||
@a2.add_runtime_dependency 'b', '1'
|
||||
@a2.dependencies.first.instance_variable_set :@type, nil
|
||||
|
@ -2533,13 +2752,13 @@ duplicate dependency on b (>= 1.2.3), (~> 1.2) use:
|
|||
@a1.extensions << 'ext/a/extconf.rb'
|
||||
|
||||
Dir.chdir @tempdir do
|
||||
FileUtils.ln_s '/root/path', 'lib2' unless vc_windows?
|
||||
FileUtils.ln_s 'lib/code.rb', 'lib2' unless vc_windows?
|
||||
|
||||
e = assert_raises Gem::InvalidSpecificationException do
|
||||
use_ui @ui do
|
||||
@a1.validate
|
||||
end
|
||||
|
||||
assert_equal '["lib2"] are not files', e.message
|
||||
assert_match 'WARNING: lib2 is a symlink, which is not supported on all platforms', @ui.error
|
||||
end
|
||||
|
||||
assert_equal %w[bin/exec ext/a/extconf.rb lib/code.rb lib2 test/suite.rb].sort,
|
||||
|
@ -2656,6 +2875,20 @@ http://opensource.org/licenses/alphabetical
|
|||
end
|
||||
end
|
||||
|
||||
def test_validate_permissions_of_missing_file_non_packaging
|
||||
skip 'chmod not supported' if Gem.win_platform?
|
||||
|
||||
util_setup_validate
|
||||
|
||||
Dir.chdir @tempdir do
|
||||
File.delete File.join('lib', 'code.rb')
|
||||
|
||||
use_ui @ui do
|
||||
assert @a1.validate(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_validate_platform_legacy
|
||||
util_setup_validate
|
||||
|
||||
|
@ -2992,7 +3225,8 @@ end
|
|||
end
|
||||
|
||||
def test_find_by_name
|
||||
util_spec "a"
|
||||
install_specs util_spec "a"
|
||||
install_specs util_spec "a", 1
|
||||
|
||||
assert Gem::Specification.find_by_name "a"
|
||||
assert Gem::Specification.find_by_name "a", "1"
|
||||
|
@ -3008,6 +3242,8 @@ end
|
|||
|
||||
b.activate
|
||||
|
||||
install_specs b
|
||||
|
||||
assert Gem::Specification.find_by_name "b"
|
||||
|
||||
assert_raises Gem::LoadError do
|
||||
|
|
|
@ -9,7 +9,7 @@ class TestStubSpecification < Gem::TestCase
|
|||
def setup
|
||||
super
|
||||
|
||||
@foo = Gem::StubSpecification.new FOO
|
||||
@foo = Gem::StubSpecification.gemspec_stub FOO
|
||||
end
|
||||
|
||||
def test_initialize
|
||||
|
@ -31,7 +31,7 @@ class TestStubSpecification < Gem::TestCase
|
|||
end
|
||||
|
||||
def test_initialize_missing_stubline
|
||||
stub = Gem::StubSpecification.new(BAR)
|
||||
stub = Gem::StubSpecification.gemspec_stub(BAR)
|
||||
assert_equal "bar", stub.name
|
||||
assert_equal Gem::Version.new("0.0.2"), stub.version
|
||||
assert_equal Gem::Platform.new("ruby"), stub.platform
|
||||
|
@ -72,6 +72,21 @@ class TestStubSpecification < Gem::TestCase
|
|||
assert_equal expected, stub.full_require_paths
|
||||
end
|
||||
|
||||
def test_lib_dirs_glob
|
||||
stub = stub_without_extension
|
||||
|
||||
assert_equal File.join(stub.full_gem_path, 'lib'), stub.lib_dirs_glob
|
||||
end
|
||||
|
||||
def test_matches_for_glob
|
||||
stub = stub_without_extension
|
||||
code_rb = File.join stub.gem_dir, 'lib', 'code.rb'
|
||||
FileUtils.mkdir_p File.dirname code_rb
|
||||
FileUtils.touch code_rb
|
||||
|
||||
assert_equal code_rb, stub.matches_for_glob('code*').first
|
||||
end
|
||||
|
||||
def test_missing_extensions_eh
|
||||
stub = stub_with_extension do |s|
|
||||
extconf_rb = File.join s.gem_dir, s.extensions.first
|
||||
|
@ -103,7 +118,7 @@ class TestStubSpecification < Gem::TestCase
|
|||
io.write spec.to_ruby_for_cache
|
||||
end
|
||||
|
||||
default_spec = Gem::StubSpecification.new spec.loaded_from
|
||||
default_spec = Gem::StubSpecification.gemspec_stub spec.loaded_from
|
||||
|
||||
refute default_spec.missing_extensions?
|
||||
end
|
||||
|
@ -125,7 +140,7 @@ class TestStubSpecification < Gem::TestCase
|
|||
def test_to_spec_with_other_specs_loaded_does_not_warn
|
||||
real_foo = util_spec @foo.name, @foo.version
|
||||
real_foo.activate
|
||||
bar = Gem::StubSpecification.new BAR
|
||||
bar = Gem::StubSpecification.gemspec_stub BAR
|
||||
refute_predicate Gem.loaded_specs, :empty?
|
||||
assert bar.to_spec
|
||||
end
|
||||
|
@ -164,7 +179,7 @@ end
|
|||
|
||||
io.flush
|
||||
|
||||
stub = Gem::StubSpecification.new io.path
|
||||
stub = Gem::StubSpecification.gemspec_stub io.path
|
||||
|
||||
yield stub if block_given?
|
||||
|
||||
|
@ -187,7 +202,7 @@ end
|
|||
|
||||
io.flush
|
||||
|
||||
stub = Gem::StubSpecification.new io.path
|
||||
stub = Gem::StubSpecification.gemspec_stub io.path
|
||||
|
||||
yield stub if block_given?
|
||||
|
||||
|
|
|
@ -158,6 +158,7 @@ class TestGemUninstaller < Gem::InstallerTestCase
|
|||
uninstaller = Gem::Uninstaller.new nil
|
||||
|
||||
@spec.loaded_from = @spec.loaded_from.gsub @spec.full_name, '\&-legacy'
|
||||
@spec.internal_init # blow out cache. but why did ^^ depend on cache?
|
||||
@spec.platform = 'legacy'
|
||||
|
||||
assert_equal true, uninstaller.path_ok?(@gemhome, @spec)
|
||||
|
@ -236,7 +237,7 @@ create_makefile '#{@spec.name}'
|
|||
use_ui @ui do
|
||||
path = Gem::Package.build @spec
|
||||
|
||||
installer = Gem::Installer.new path
|
||||
installer = Gem::Installer.at path
|
||||
installer.install
|
||||
end
|
||||
|
||||
|
|
|
@ -27,5 +27,13 @@ class TestGemUtil < Gem::TestCase
|
|||
assert_equal File.join(@tempdir, 'a'), enum.next
|
||||
end
|
||||
|
||||
def test_linked_list_find
|
||||
list = [1,2,3,4,5].inject(Gem::List.new(0)) { |m,o|
|
||||
Gem::List.new o, m
|
||||
}
|
||||
assert_equal 5, list.find { |x| x == 5 }
|
||||
assert_equal 4, list.find { |x| x == 4 }
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -26,11 +26,11 @@ class TestGemRequire < Gem::TestCase
|
|||
def setup
|
||||
super
|
||||
|
||||
@old_loaded_features = $LOADED_FEATURES.dup
|
||||
assert_raises LoadError do
|
||||
save_loaded_features do
|
||||
require 'test_gem_require_a'
|
||||
end
|
||||
require 'test_gem_require_a'
|
||||
end
|
||||
$LOADED_FEATURES.replace @old_loaded_features
|
||||
end
|
||||
|
||||
def assert_require(path)
|
||||
|
@ -49,6 +49,36 @@ class TestGemRequire < Gem::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
# Providing -I on the commandline should always beat gems
|
||||
def test_dash_i_beats_gems
|
||||
a1 = new_spec "a", "1", {"b" => "= 1"}, "lib/test_gem_require_a.rb"
|
||||
b1 = new_spec "b", "1", {"c" => "> 0"}, "lib/b/c.rb"
|
||||
c1 = new_spec "c", "1", nil, "lib/c/c.rb"
|
||||
c2 = new_spec "c", "2", nil, "lib/c/c.rb"
|
||||
|
||||
install_specs c1, c2, b1, a1
|
||||
|
||||
dir = Dir.mktmpdir
|
||||
dash_i_arg = File.join dir, 'lib'
|
||||
|
||||
c_rb = File.join dash_i_arg, 'b', 'c.rb'
|
||||
|
||||
FileUtils.mkdir_p File.dirname c_rb
|
||||
File.open(c_rb, 'w') { |f| f.write "class Object; HELLO = 'world' end" }
|
||||
|
||||
lp = $LOAD_PATH.dup
|
||||
|
||||
# Pretend to provide a commandline argument that overrides a file in gem b
|
||||
$LOAD_PATH.unshift dash_i_arg
|
||||
|
||||
assert_require 'test_gem_require_a'
|
||||
assert_require 'b/c' # this should be required from -I
|
||||
assert_equal "world", ::Object::HELLO
|
||||
ensure
|
||||
$LOAD_PATH.replace lp
|
||||
Object.send :remove_const, :HELLO if Object.const_defined? :HELLO
|
||||
end
|
||||
|
||||
def test_concurrent_require
|
||||
Object.const_set :FILE_ENTERED_LATCH, Latch.new(2)
|
||||
Object.const_set :FILE_EXIT_LATCH, Latch.new(1)
|
||||
|
@ -82,16 +112,14 @@ class TestGemRequire < Gem::TestCase
|
|||
b1 = new_spec "b", "1", nil, "lib/b/c.rb"
|
||||
b2 = new_spec "b", "2", nil, "lib/b/c.rb"
|
||||
|
||||
install_specs a1, b1, b2
|
||||
install_specs b1, b2, a1
|
||||
|
||||
save_loaded_features do
|
||||
assert_require 'test_gem_require_a'
|
||||
assert_equal %w(a-1 b-1), loaded_spec_names
|
||||
assert_equal unresolved_names, []
|
||||
assert_require 'test_gem_require_a'
|
||||
assert_equal %w(a-1 b-1), loaded_spec_names
|
||||
assert_equal unresolved_names, []
|
||||
|
||||
assert_require "b/c"
|
||||
assert_equal %w(a-1 b-1), loaded_spec_names
|
||||
end
|
||||
assert_require "b/c"
|
||||
assert_equal %w(a-1 b-1), loaded_spec_names
|
||||
end
|
||||
|
||||
def test_require_is_lazy_with_inexact_req
|
||||
|
@ -99,32 +127,28 @@ class TestGemRequire < Gem::TestCase
|
|||
b1 = new_spec "b", "1", nil, "lib/b/c.rb"
|
||||
b2 = new_spec "b", "2", nil, "lib/b/c.rb"
|
||||
|
||||
install_specs a1, b1, b2
|
||||
install_specs b1, b2, a1
|
||||
|
||||
save_loaded_features do
|
||||
assert_require 'test_gem_require_a'
|
||||
assert_equal %w(a-1), loaded_spec_names
|
||||
assert_equal unresolved_names, ["b (>= 1)"]
|
||||
assert_require 'test_gem_require_a'
|
||||
assert_equal %w(a-1), loaded_spec_names
|
||||
assert_equal unresolved_names, ["b (>= 1)"]
|
||||
|
||||
assert_require "b/c"
|
||||
assert_equal %w(a-1 b-2), loaded_spec_names
|
||||
end
|
||||
assert_require "b/c"
|
||||
assert_equal %w(a-1 b-2), loaded_spec_names
|
||||
end
|
||||
|
||||
def test_require_is_not_lazy_with_one_possible
|
||||
a1 = new_spec "a", "1", {"b" => ">= 1"}, "lib/test_gem_require_a.rb"
|
||||
b1 = new_spec "b", "1", nil, "lib/b/c.rb"
|
||||
|
||||
install_specs a1, b1
|
||||
install_specs b1, a1
|
||||
|
||||
save_loaded_features do
|
||||
assert_require 'test_gem_require_a'
|
||||
assert_equal %w(a-1 b-1), loaded_spec_names
|
||||
assert_equal unresolved_names, []
|
||||
assert_require 'test_gem_require_a'
|
||||
assert_equal %w(a-1 b-1), loaded_spec_names
|
||||
assert_equal unresolved_names, []
|
||||
|
||||
assert_require "b/c"
|
||||
assert_equal %w(a-1 b-1), loaded_spec_names
|
||||
end
|
||||
assert_require "b/c"
|
||||
assert_equal %w(a-1 b-1), loaded_spec_names
|
||||
end
|
||||
|
||||
def test_require_can_use_a_pathname_object
|
||||
|
@ -132,129 +156,114 @@ class TestGemRequire < Gem::TestCase
|
|||
|
||||
install_specs a1
|
||||
|
||||
save_loaded_features do
|
||||
assert_require Pathname.new 'test_gem_require_a'
|
||||
assert_equal %w(a-1), loaded_spec_names
|
||||
assert_equal unresolved_names, []
|
||||
end
|
||||
assert_require Pathname.new 'test_gem_require_a'
|
||||
assert_equal %w(a-1), loaded_spec_names
|
||||
assert_equal unresolved_names, []
|
||||
end
|
||||
|
||||
def test_activate_via_require_respects_loaded_files
|
||||
require 'benchmark' # stdlib
|
||||
save_loaded_features do
|
||||
a1 = new_spec "a", "1", {"b" => ">= 1"}, "lib/test_gem_require_a.rb"
|
||||
b1 = new_spec "b", "1", nil, "lib/benchmark.rb"
|
||||
b2 = new_spec "b", "2", nil, "lib/benchmark.rb"
|
||||
a1 = new_spec "a", "1", {"b" => ">= 1"}, "lib/test_gem_require_a.rb"
|
||||
b1 = new_spec "b", "1", nil, "lib/benchmark.rb"
|
||||
b2 = new_spec "b", "2", nil, "lib/benchmark.rb"
|
||||
|
||||
install_specs a1, b1, b2
|
||||
install_specs b1, b2, a1
|
||||
|
||||
require 'test_gem_require_a'
|
||||
assert_equal unresolved_names, ["b (>= 1)"]
|
||||
require 'test_gem_require_a'
|
||||
assert_equal unresolved_names, ["b (>= 1)"]
|
||||
|
||||
refute require('benchmark'), "benchmark should have already been loaded"
|
||||
refute require('benchmark'), "benchmark should have already been loaded"
|
||||
|
||||
# We detected that we should activate b-2, so we did so, but
|
||||
# then original_require decided "I've already got benchmark.rb" loaded.
|
||||
# This case is fine because our lazy loading is provided exactly
|
||||
# the same behavior as eager loading would have.
|
||||
# We detected that we should activate b-2, so we did so, but
|
||||
# then original_require decided "I've already got benchmark.rb" loaded.
|
||||
# This case is fine because our lazy loading is provided exactly
|
||||
# the same behavior as eager loading would have.
|
||||
|
||||
assert_equal %w(a-1 b-2), loaded_spec_names
|
||||
end
|
||||
assert_equal %w(a-1 b-2), loaded_spec_names
|
||||
end
|
||||
|
||||
def test_already_activated_direct_conflict
|
||||
save_loaded_features do
|
||||
a1 = new_spec "a", "1", { "b" => "> 0" }
|
||||
b1 = new_spec "b", "1", { "c" => ">= 1" }, "lib/ib.rb"
|
||||
b2 = new_spec "b", "2", { "c" => ">= 2" }, "lib/ib.rb"
|
||||
c1 = new_spec "c", "1", nil, "lib/d.rb"
|
||||
c2 = new_spec("c", "2", nil, "lib/d.rb")
|
||||
a1 = new_spec "a", "1", { "b" => "> 0" }
|
||||
b1 = new_spec "b", "1", { "c" => ">= 1" }, "lib/ib.rb"
|
||||
b2 = new_spec "b", "2", { "c" => ">= 2" }, "lib/ib.rb"
|
||||
c1 = new_spec "c", "1", nil, "lib/d.rb"
|
||||
c2 = new_spec("c", "2", nil, "lib/d.rb")
|
||||
|
||||
install_specs a1, b1, b2, c1, c2
|
||||
install_specs c1, c2, b1, b2, a1
|
||||
|
||||
a1.activate
|
||||
c1.activate
|
||||
assert_equal %w(a-1 c-1), loaded_spec_names
|
||||
assert_equal ["b (> 0)"], unresolved_names
|
||||
a1.activate
|
||||
c1.activate
|
||||
assert_equal %w(a-1 c-1), loaded_spec_names
|
||||
assert_equal ["b (> 0)"], unresolved_names
|
||||
|
||||
assert require("ib")
|
||||
assert require("ib")
|
||||
|
||||
assert_equal %w(a-1 b-1 c-1), loaded_spec_names
|
||||
assert_equal [], unresolved_names
|
||||
end
|
||||
assert_equal %w(a-1 b-1 c-1), loaded_spec_names
|
||||
assert_equal [], unresolved_names
|
||||
end
|
||||
|
||||
def test_multiple_gems_with_the_same_path
|
||||
save_loaded_features do
|
||||
a1 = new_spec "a", "1", { "b" => "> 0", "x" => "> 0" }
|
||||
b1 = new_spec "b", "1", { "c" => ">= 1" }, "lib/ib.rb"
|
||||
b2 = new_spec "b", "2", { "c" => ">= 2" }, "lib/ib.rb"
|
||||
x1 = new_spec "x", "1", nil, "lib/ib.rb"
|
||||
x2 = new_spec "x", "2", nil, "lib/ib.rb"
|
||||
c1 = new_spec "c", "1", nil, "lib/d.rb"
|
||||
c2 = new_spec("c", "2", nil, "lib/d.rb")
|
||||
a1 = new_spec "a", "1", { "b" => "> 0", "x" => "> 0" }
|
||||
b1 = new_spec "b", "1", { "c" => ">= 1" }, "lib/ib.rb"
|
||||
b2 = new_spec "b", "2", { "c" => ">= 2" }, "lib/ib.rb"
|
||||
x1 = new_spec "x", "1", nil, "lib/ib.rb"
|
||||
x2 = new_spec "x", "2", nil, "lib/ib.rb"
|
||||
c1 = new_spec "c", "1", nil, "lib/d.rb"
|
||||
c2 = new_spec("c", "2", nil, "lib/d.rb")
|
||||
|
||||
install_specs a1, b1, b2, c1, c2, x1, x2
|
||||
install_specs c1, c2, x1, x2, b1, b2, a1
|
||||
|
||||
a1.activate
|
||||
c1.activate
|
||||
assert_equal %w(a-1 c-1), loaded_spec_names
|
||||
assert_equal ["b (> 0)", "x (> 0)"], unresolved_names
|
||||
a1.activate
|
||||
c1.activate
|
||||
assert_equal %w(a-1 c-1), loaded_spec_names
|
||||
assert_equal ["b (> 0)", "x (> 0)"], unresolved_names
|
||||
|
||||
e = assert_raises(Gem::LoadError) do
|
||||
require("ib")
|
||||
end
|
||||
|
||||
assert_equal "ib found in multiple gems: b, x", e.message
|
||||
e = assert_raises(Gem::LoadError) do
|
||||
require("ib")
|
||||
end
|
||||
|
||||
assert_equal "ib found in multiple gems: b, x", e.message
|
||||
end
|
||||
|
||||
def test_unable_to_find_good_unresolved_version
|
||||
save_loaded_features do
|
||||
a1 = new_spec "a", "1", { "b" => "> 0" }
|
||||
b1 = new_spec "b", "1", { "c" => ">= 2" }, "lib/ib.rb"
|
||||
b2 = new_spec "b", "2", { "c" => ">= 3" }, "lib/ib.rb"
|
||||
a1 = new_spec "a", "1", { "b" => "> 0" }
|
||||
b1 = new_spec "b", "1", { "c" => ">= 2" }, "lib/ib.rb"
|
||||
b2 = new_spec "b", "2", { "c" => ">= 3" }, "lib/ib.rb"
|
||||
|
||||
c1 = new_spec "c", "1", nil, "lib/d.rb"
|
||||
c2 = new_spec "c", "2", nil, "lib/d.rb"
|
||||
c3 = new_spec "c", "3", nil, "lib/d.rb"
|
||||
c1 = new_spec "c", "1", nil, "lib/d.rb"
|
||||
c2 = new_spec "c", "2", nil, "lib/d.rb"
|
||||
c3 = new_spec "c", "3", nil, "lib/d.rb"
|
||||
|
||||
install_specs a1, b1, b2, c1, c2, c3
|
||||
install_specs c1, c2, c3, b1, b2, a1
|
||||
|
||||
a1.activate
|
||||
c1.activate
|
||||
assert_equal %w(a-1 c-1), loaded_spec_names
|
||||
assert_equal ["b (> 0)"], unresolved_names
|
||||
a1.activate
|
||||
c1.activate
|
||||
assert_equal %w(a-1 c-1), loaded_spec_names
|
||||
assert_equal ["b (> 0)"], unresolved_names
|
||||
|
||||
e = assert_raises(Gem::LoadError) do
|
||||
require("ib")
|
||||
end
|
||||
|
||||
assert_equal "unable to find a version of 'b' to activate", e.message
|
||||
e = assert_raises(Gem::LoadError) do
|
||||
require("ib")
|
||||
end
|
||||
|
||||
assert_equal "unable to find a version of 'b' to activate", e.message
|
||||
end
|
||||
|
||||
def test_default_gem_only
|
||||
save_loaded_features do
|
||||
default_gem_spec = new_default_spec("default", "2.0.0.0",
|
||||
nil, "default/gem.rb")
|
||||
install_default_specs(default_gem_spec)
|
||||
assert_require "default/gem"
|
||||
assert_equal %w(default-2.0.0.0), loaded_spec_names
|
||||
end
|
||||
default_gem_spec = new_default_spec("default", "2.0.0.0",
|
||||
nil, "default/gem.rb")
|
||||
install_default_specs(default_gem_spec)
|
||||
assert_require "default/gem"
|
||||
assert_equal %w(default-2.0.0.0), loaded_spec_names
|
||||
end
|
||||
|
||||
def test_default_gem_and_normal_gem
|
||||
save_loaded_features do
|
||||
default_gem_spec = new_default_spec("default", "2.0.0.0",
|
||||
nil, "default/gem.rb")
|
||||
install_default_specs(default_gem_spec)
|
||||
normal_gem_spec = new_spec("default", "3.0", nil,
|
||||
"lib/default/gem.rb")
|
||||
install_specs(normal_gem_spec)
|
||||
assert_require "default/gem"
|
||||
assert_equal %w(default-3.0), loaded_spec_names
|
||||
end
|
||||
default_gem_spec = new_default_spec("default", "2.0.0.0",
|
||||
nil, "default/gem.rb")
|
||||
install_default_specs(default_gem_spec)
|
||||
normal_gem_spec = new_spec("default", "3.0", nil,
|
||||
"lib/default/gem.rb")
|
||||
install_specs(normal_gem_spec)
|
||||
assert_require "default/gem"
|
||||
assert_equal %w(default-3.0), loaded_spec_names
|
||||
end
|
||||
|
||||
def loaded_spec_names
|
||||
|
@ -264,12 +273,4 @@ class TestGemRequire < Gem::TestCase
|
|||
def unresolved_names
|
||||
Gem::Specification.unresolved_deps.values.map(&:to_s).sort
|
||||
end
|
||||
|
||||
def save_loaded_features
|
||||
old_loaded_features = $LOADED_FEATURES.dup
|
||||
yield
|
||||
ensure
|
||||
$LOADED_FEATURES.replace old_loaded_features
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue