1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Merge rubygems master.

This is RC version of Rubygems 2.7.0.
  688fb7e83c

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60133 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
hsbt 2017-10-08 01:32:18 +00:00
parent 6b05153a3a
commit c00e84327f
96 changed files with 2021 additions and 701 deletions

View file

@ -39,7 +39,7 @@ require 'rubygems/errors'
# Further RubyGems documentation can be found at: # Further RubyGems documentation can be found at:
# #
# * {RubyGems Guides}[http://guides.rubygems.org] # * {RubyGems Guides}[http://guides.rubygems.org]
# * {RubyGems API}[http://rubygems.rubyforge.org/rdoc] (also available from # * {RubyGems API}[http://www.rubydoc.info/github/rubygems/rubygems] (also available from
# <tt>gem server</tt>) # <tt>gem server</tt>)
# #
# == RubyGems Plugins # == RubyGems Plugins
@ -47,15 +47,16 @@ require 'rubygems/errors'
# As of RubyGems 1.3.2, RubyGems will load plugins installed in gems or # As of RubyGems 1.3.2, RubyGems will load plugins installed in gems or
# $LOAD_PATH. Plugins must be named 'rubygems_plugin' (.rb, .so, etc) and # $LOAD_PATH. Plugins must be named 'rubygems_plugin' (.rb, .so, etc) and
# placed at the root of your gem's #require_path. Plugins are discovered via # placed at the root of your gem's #require_path. Plugins are discovered via
# Gem::find_files then loaded. Take care when implementing a plugin as your # Gem::find_files and then loaded. Take care when implementing a plugin as your
# plugin file may be loaded multiple times if multiple versions of your gem # plugin file may be loaded multiple times if multiple versions of your gem
# are installed. # are installed.
# #
# For an example plugin, see the graph gem which adds a `gem graph` command. # For an example plugin, see the {Graph gem}[https://github.com/seattlerb/graph]
# which adds a `gem graph` command.
# #
# == RubyGems Defaults, Packaging # == RubyGems Defaults, Packaging
# #
# RubyGems defaults are stored in rubygems/defaults.rb. If you're packaging # RubyGems defaults are stored in lib/rubygems/defaults.rb. If you're packaging
# RubyGems or implementing Ruby you can change RubyGems' defaults. # RubyGems or implementing Ruby you can change RubyGems' defaults.
# #
# For RubyGems packagers, provide lib/rubygems/defaults/operating_system.rb # For RubyGems packagers, provide lib/rubygems/defaults/operating_system.rb
@ -65,7 +66,7 @@ require 'rubygems/errors'
# override any defaults from lib/rubygems/defaults.rb. # override any defaults from lib/rubygems/defaults.rb.
# #
# If you need RubyGems to perform extra work on install or uninstall, your # If you need RubyGems to perform extra work on install or uninstall, your
# defaults override file can set pre and post install and uninstall hooks. # defaults override file can set pre/post install and uninstall hooks.
# See Gem::pre_install, Gem::pre_uninstall, Gem::post_install, # See Gem::pre_install, Gem::pre_uninstall, Gem::post_install,
# Gem::post_uninstall. # Gem::post_uninstall.
# #
@ -106,6 +107,8 @@ require 'rubygems/errors'
# #
# (If your name is missing, PLEASE let us know!) # (If your name is missing, PLEASE let us know!)
# #
# == License
#
# See {LICENSE.txt}[rdoc-ref:lib/rubygems/LICENSE.txt] for permissions. # See {LICENSE.txt}[rdoc-ref:lib/rubygems/LICENSE.txt] for permissions.
# #
# Thanks! # Thanks!
@ -130,6 +133,7 @@ module Gem
GEM_DEP_FILES = %w[ GEM_DEP_FILES = %w[
gem.deps.rb gem.deps.rb
gems.rb
Gemfile Gemfile
Isolate Isolate
] ]
@ -159,7 +163,7 @@ module Gem
# these are defined in Ruby 1.8.7, hence the need for this convoluted setup. # these are defined in Ruby 1.8.7, hence the need for this convoluted setup.
READ_BINARY_ERRORS = begin READ_BINARY_ERRORS = begin
read_binary_errors = [Errno::EACCES] read_binary_errors = [Errno::EACCES, Errno::EROFS]
read_binary_errors << Errno::ENOTSUP if Errno.const_defined?(:ENOTSUP) read_binary_errors << Errno::ENOTSUP if Errno.const_defined?(:ENOTSUP)
read_binary_errors read_binary_errors
end.freeze end.freeze
@ -174,6 +178,8 @@ module Gem
write_binary_errors write_binary_errors
end.freeze end.freeze
USE_BUNDLER_FOR_GEMDEPS = true # :nodoc:
@@win_platform = nil @@win_platform = nil
@configuration = nil @configuration = nil
@ -266,17 +272,22 @@ module Gem
return loaded if loaded && dep.matches_spec?(loaded) return loaded if loaded && dep.matches_spec?(loaded)
specs = dep.matching_specs(true) find_specs = proc { dep.matching_specs(true) }
if dep.to_s == "bundler (>= 0.a)"
raise Gem::GemNotFoundException, specs = Gem::BundlerVersionFinder.without_filtering(&find_specs)
"can't find gem #{dep}" if specs.empty? else
specs = find_specs.call
end
specs = specs.find_all { |spec| specs = specs.find_all { |spec|
spec.executables.include? exec_name spec.executables.include? exec_name
} if exec_name } if exec_name
unless spec = specs.first unless spec = specs.first
msg = "can't find gem #{name} (#{requirements}) with executable #{exec_name}" msg = "can't find gem #{dep} with executable #{exec_name}"
if name == "bundler" && bundler_message = Gem::BundlerVersionFinder.missing_version_message
msg = bundler_message
end
raise Gem::GemNotFoundException, msg raise Gem::GemNotFoundException, msg
end end
@ -297,7 +308,10 @@ module Gem
def self.activate_bin_path name, exec_name, requirement # :nodoc: def self.activate_bin_path name, exec_name, requirement # :nodoc:
spec = find_spec_for_exe name, exec_name, [requirement] spec = find_spec_for_exe name, exec_name, [requirement]
Gem::LOADED_SPECS_MUTEX.synchronize { spec.activate } Gem::LOADED_SPECS_MUTEX.synchronize do
spec.activate
finish_resolve
end
spec.bin_file exec_name spec.bin_file exec_name
end end
@ -356,12 +370,16 @@ module Gem
# package is not available as a gem, return nil. # package is not available as a gem, return nil.
def self.datadir(gem_name) def self.datadir(gem_name)
# TODO: deprecate
spec = @loaded_specs[gem_name] spec = @loaded_specs[gem_name]
return nil if spec.nil? return nil if spec.nil?
spec.datadir spec.datadir
end end
class << self
extend Gem::Deprecate
deprecate :datadir, "spec.datadir", 2016, 10
end
## ##
# A Zlib::Deflate.deflate wrapper # A Zlib::Deflate.deflate wrapper
@ -594,7 +612,6 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
# Zlib::GzipReader wrapper that unzips +data+. # Zlib::GzipReader wrapper that unzips +data+.
def self.gunzip(data) def self.gunzip(data)
require 'rubygems/util'
Gem::Util.gunzip data Gem::Util.gunzip data
end end
@ -602,7 +619,6 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
# Zlib::GzipWriter wrapper that zips +data+. # Zlib::GzipWriter wrapper that zips +data+.
def self.gzip(data) def self.gzip(data)
require 'rubygems/util'
Gem::Util.gzip data Gem::Util.gzip data
end end
@ -610,7 +626,6 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
# A Zlib::Inflate#inflate wrapper # A Zlib::Inflate#inflate wrapper
def self.inflate(data) def self.inflate(data)
require 'rubygems/util'
Gem::Util.inflate data Gem::Util.inflate data
end end
@ -715,9 +730,20 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
## ##
# The file name and line number of the caller of the caller of this method. # The file name and line number of the caller of the caller of this method.
#
# +depth+ is how many layers up the call stack it should go.
#
# e.g.,
#
# def a; Gem.location_of_caller; end
# a #=> ["x.rb", 2] # (it'll vary depending on file name and line number)
#
# def b; c; end
# def c; Gem.location_of_caller(2); end
# b #=> ["x.rb", 6] # (it'll vary depending on file name and line number)
def self.location_of_caller def self.location_of_caller(depth = 1)
caller[1] =~ /(.*?):(\d+).*?$/i caller[depth] =~ /(.*?):(\d+).*?$/i
file = $1 file = $1
lineno = $2.to_i lineno = $2.to_i
@ -1148,8 +1174,6 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
path = path.dup path = path.dup
if path == "-" then if path == "-" then
require 'rubygems/util'
Gem::Util.traverse_parents Dir.pwd do |directory| Gem::Util.traverse_parents Dir.pwd do |directory|
dep_file = GEM_DEP_FILES.find { |f| File.file?(f) } dep_file = GEM_DEP_FILES.find { |f| File.file?(f) }
@ -1168,18 +1192,36 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
raise ArgumentError, "Unable to find gem dependencies file at #{path}" raise ArgumentError, "Unable to find gem dependencies file at #{path}"
end end
rs = Gem::RequestSet.new if USE_BUNDLER_FOR_GEMDEPS
@gemdeps = rs.load_gemdeps path
ENV["BUNDLE_GEMFILE"] ||= File.expand_path(path)
require 'rubygems/user_interaction'
Gem::DefaultUserInteraction.use_ui(ui) do
require "bundler"
@gemdeps = Bundler.setup
Bundler.ui = nil
@gemdeps.requested_specs.map(&:to_spec).sort_by(&:name)
end
else
rs = Gem::RequestSet.new
@gemdeps = rs.load_gemdeps path
rs.resolve_current.map do |s|
s.full_spec.tap(&:activate)
end
rs.resolve_current.map do |s|
sp = s.full_spec
sp.activate
sp
end end
rescue Gem::LoadError, Gem::UnsatisfiableDependencyError => e rescue => e
warn e.message case e
warn "You may need to `gem install -g` to install missing gems" when Gem::LoadError, Gem::UnsatisfiableDependencyError, (defined?(Bundler::GemNotFound) ? Bundler::GemNotFound : Gem::LoadError)
warn "" warn e.message
warn "You may need to `gem install -g` to install missing gems"
warn ""
else
raise
end
end end
class << self class << self
@ -1225,6 +1267,8 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
prefix_pattern = /^(#{prefix_group})/ prefix_pattern = /^(#{prefix_group})/
end end
suffix_pattern = /#{Regexp.union(Gem.suffixes)}\z/
spec.files.each do |file| spec.files.each do |file|
if new_format if new_format
file = file.sub(prefix_pattern, "") file = file.sub(prefix_pattern, "")
@ -1232,6 +1276,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
end end
@path_to_default_spec_map[file] = spec @path_to_default_spec_map[file] = spec
@path_to_default_spec_map[file.sub(suffix_pattern, "")] = spec
end end
end end
@ -1239,11 +1284,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
# Find a Gem::Specification of default gem from +path+ # Find a Gem::Specification of default gem from +path+
def find_unresolved_default_spec(path) def find_unresolved_default_spec(path)
Gem.suffixes.each do |suffix| @path_to_default_spec_map[path]
spec = @path_to_default_spec_map["#{path}#{suffix}"]
return spec if spec
end
nil
end end
## ##
@ -1314,6 +1355,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
MARSHAL_SPEC_DIR = "quick/Marshal.#{Gem.marshal_version}/" MARSHAL_SPEC_DIR = "quick/Marshal.#{Gem.marshal_version}/"
autoload :BundlerVersionFinder, 'rubygems/bundler_version_finder'
autoload :ConfigFile, 'rubygems/config_file' autoload :ConfigFile, 'rubygems/config_file'
autoload :Dependency, 'rubygems/dependency' autoload :Dependency, 'rubygems/dependency'
autoload :DependencyList, 'rubygems/dependency_list' autoload :DependencyList, 'rubygems/dependency_list'
@ -1329,6 +1371,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
autoload :SourceList, 'rubygems/source_list' autoload :SourceList, 'rubygems/source_list'
autoload :SpecFetcher, 'rubygems/spec_fetcher' autoload :SpecFetcher, 'rubygems/spec_fetcher'
autoload :Specification, 'rubygems/specification' autoload :Specification, 'rubygems/specification'
autoload :Util, 'rubygems/util'
autoload :Version, 'rubygems/version' autoload :Version, 'rubygems/version'
require "rubygems/specification" require "rubygems/specification"

View file

@ -71,7 +71,7 @@ class Gem::BasicSpecification
elsif missing_extensions? then elsif missing_extensions? then
@ignored = true @ignored = true
warn "Ignoring #{full_name} because its extensions are not built. " + warn "Ignoring #{full_name} because its extensions are not built. " +
"Try: gem pristine #{name} --version #{version}" "Try: gem pristine #{name} --version #{version}"
return false return false
end end
@ -275,10 +275,10 @@ class Gem::BasicSpecification
# for this spec. # for this spec.
def lib_dirs_glob def lib_dirs_glob
dirs = if self.require_paths.size > 1 then dirs = if self.raw_require_paths.size > 1 then
"{#{self.require_paths.join(',')}}" "{#{self.raw_require_paths.join(',')}}"
else else
self.require_paths.first self.raw_require_paths.first
end end
"#{self.full_gem_path}/#{dirs}".dup.untaint "#{self.full_gem_path}/#{dirs}".dup.untaint

View file

@ -0,0 +1,112 @@
module Gem::BundlerVersionFinder
@without_filtering = false
def self.without_filtering
without_filtering, @without_filtering = true, @without_filtering
yield
ensure
@without_filtering = without_filtering
end
def self.bundler_version
version, _ = bundler_version_with_reason
return unless version
Gem::Version.new(version)
end
def self.bundler_version_with_reason
return if @without_filtering
if v = ENV["BUNDLER_VERSION"]
return [v, "`$BUNDLER_VERSION`"]
end
if v = bundle_update_bundler_version
return if v == true
return [v, "`bundle update --bundler`"]
end
v, lockfile = lockfile_version
if v
return [v, "your #{lockfile}"]
end
end
def self.missing_version_message
return unless vr = bundler_version_with_reason
<<-EOS
Could not find 'bundler' (#{vr.first}) required by #{vr.last}.
To update to the lastest version installed on your system, run `bundle update --bundler`.
To install the missing version, run `gem install bundler:#{vr.first}`
EOS
end
def self.compatible?(spec)
return true unless spec.name == "bundler".freeze
return true unless bundler_version = self.bundler_version
if bundler_version.segments.first >= 2
spec.version == bundler_version
else # 1.x
spec.version.segments.first < 2
end
end
def self.filter!(specs)
return unless bundler_version = self.bundler_version
if bundler_version.segments.first >= 2
specs.reject! { |spec| spec.version != bundler_version }
else # 1.x
specs.reject! { |spec| spec.version.segments.first >= 2}
end
end
def self.bundle_update_bundler_version
return unless File.basename($0) == "bundle".freeze
return unless "update".start_with?(ARGV.first || " ")
bundler_version = nil
update_index = nil
ARGV.each_with_index do |a, i|
if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
bundler_version = a
end
next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
bundler_version = $1 || true
update_index = i
end
bundler_version
end
private_class_method :bundle_update_bundler_version
def self.lockfile_version
return unless lockfile = lockfile_contents
lockfile, contents = lockfile
lockfile ||= "lockfile"
regexp = /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
return unless contents =~ regexp
[$1, lockfile]
end
private_class_method :lockfile_version
def self.lockfile_contents
gemfile = ENV["BUNDLE_GEMFILE"]
gemfile = nil if gemfile && gemfile.empty?
Gem::Util.traverse_parents Dir.pwd do |directory|
next unless gemfile = Gem::GEM_DEP_FILES.find { |f| File.file?(f.untaint) }
gemfile = File.join directory, gemfile
break
end unless gemfile
return unless gemfile
lockfile = case gemfile
when "gems.rb" then "gems.locked"
else "#{gemfile}.lock"
end.untaint
return unless File.file?(lockfile)
[lockfile, File.read(lockfile)]
end
private_class_method :lockfile_contents
end

View file

@ -527,7 +527,7 @@ class Gem::Command
end end
add_common_option("--silent", add_common_option("--silent",
"Silence rubygems output") do |value, options| "Silence RubyGems output") do |value, options|
options[:silent] = true options[:silent] = true
end end

View file

@ -58,6 +58,8 @@ class Gem::CommandManager
:rdoc, :rdoc,
:search, :search,
:server, :server,
:signin,
:signout,
:sources, :sources,
:specification, :specification,
:stale, :stale,
@ -161,7 +163,7 @@ class Gem::CommandManager
say Gem::VERSION say Gem::VERSION
terminate_interaction 0 terminate_interaction 0
when /^-/ then when /^-/ then
alert_error "Invalid option: #{args.first}. See 'gem --help'." alert_error "Invalid option: #{args.first}. See 'gem --help'."
terminate_interaction 1 terminate_interaction 1
else else
cmd_name = args.shift.downcase cmd_name = args.shift.downcase

View file

@ -84,6 +84,11 @@ class Gem::Commands::CertCommand < Gem::Command
options[:sign] << cert_file options[:sign] << cert_file
end end
add_option('-d', '--days NUMBER_OF_DAYS',
'Days before the certificate expires') do |days, options|
options[:expiration_length_days] = days.to_i
end
end end
def add_certificate certificate # :nodoc: def add_certificate certificate # :nodoc:
@ -105,16 +110,20 @@ class Gem::Commands::CertCommand < Gem::Command
list_certificates_matching filter list_certificates_matching filter
end end
options[:build].each do |name| options[:build].each do |email|
build name build email
end end
sign_certificates unless options[:sign].empty? sign_certificates unless options[:sign].empty?
end end
def build name def build email
if !valid_email?(email)
raise Gem::CommandLineError, "Invalid email address #{email}"
end
key, key_path = build_key key, key_path = build_key
cert_path = build_cert name, key cert_path = build_cert email, key
say "Certificate: #{cert_path}" say "Certificate: #{cert_path}"
@ -124,8 +133,16 @@ class Gem::Commands::CertCommand < Gem::Command
end end
end end
def build_cert name, key # :nodoc: def build_cert email, key # :nodoc:
cert = Gem::Security.create_cert_email name, key expiration_length_days = options[:expiration_length_days]
age =
if expiration_length_days.nil? || expiration_length_days == 0
Gem::Security::ONE_YEAR
else
Gem::Security::ONE_DAY * expiration_length_days
end
cert = Gem::Security.create_cert_email email, key, age
Gem::Security.write cert, "gem-public_cert.pem" Gem::Security.write cert, "gem-public_cert.pem"
end end
@ -273,5 +290,13 @@ For further reading on signing gems see `ri Gem::Security`.
end end
end end
private
def valid_email? email
# It's simple, but is all we need
email =~ /\A.+@.+\z/
end
end if defined?(OpenSSL::SSL) end if defined?(OpenSSL::SSL)

View file

@ -66,7 +66,7 @@ If no gems are named all gems in GEM_HOME are cleaned.
clean_gems clean_gems
end end
say "Clean Up Complete" say "Clean up complete"
verbose do verbose do
skipped = @default_gems.map { |spec| spec.full_name } skipped = @default_gems.map { |spec| spec.full_name }

View file

@ -367,7 +367,7 @@ platform.
elsif possibilities.size > 1 then elsif possibilities.size > 1 then
alert_warning "Ambiguous command #{command_name} (#{possibilities.join(', ')})" alert_warning "Ambiguous command #{command_name} (#{possibilities.join(', ')})"
else else
alert_warning "Unknown command #{command_name}. Try: gem help commands" alert_warning "Unknown command #{command_name}. Try: gem help commands"
end end
end end

View file

@ -40,7 +40,9 @@ permission to.
options[:remove] << value options[:remove] << value
end end
add_option '-h', '--host HOST', 'Use another gemcutter-compatible host' do |value, options| add_option '-h', '--host HOST',
'Use another gemcutter-compatible host',
' (e.g. https://rubygems.org)' do |value, options|
options[:host] = value options[:host] = value
end end
end end

View file

@ -125,14 +125,14 @@ extensions will be restored.
next next
end end
unless spec.extensions.empty? or options[:extensions] then unless spec.extensions.empty? or options[:extensions] or options[:only_executables] then
say "Skipped #{spec.full_name}, it needs to compile an extension" say "Skipped #{spec.full_name}, it needs to compile an extension"
next next
end end
gem = spec.cache_file gem = spec.cache_file
unless File.exist? gem then unless File.exist? gem or options[:only_executables] then
require 'rubygems/remote_fetcher' require 'rubygems/remote_fetcher'
say "Cached gem for #{spec.full_name} not found, attempting to fetch..." say "Cached gem for #{spec.full_name} not found, attempting to fetch..."
@ -157,16 +157,19 @@ extensions will be restored.
install_defaults.to_s['--env-shebang'] install_defaults.to_s['--env-shebang']
end end
installer = Gem::Installer.at(gem, installer_options = {
:wrappers => true, :wrappers => true,
:force => true, :force => true,
:install_dir => spec.base_dir, :install_dir => spec.base_dir,
:env_shebang => env_shebang, :env_shebang => env_shebang,
:build_args => spec.build_args) :build_args => spec.build_args,
}
if options[:only_executables] then if options[:only_executables] then
installer = Gem::Installer.for_spec(spec, installer_options)
installer.generate_bin installer.generate_bin
else else
installer = Gem::Installer.at(gem, installer_options)
installer.install installer.install
end end

View file

@ -33,7 +33,8 @@ command. For further discussion see the help for the yank command.
add_key_option add_key_option
add_option('--host HOST', add_option('--host HOST',
'Push to another gemcutter-compatible host') do |value, options| 'Push to another gemcutter-compatible host',
' (e.g. https://rubygems.org)') do |value, options|
options[:host] = value options[:host] = value
end end

View file

@ -255,22 +255,21 @@ is too hard to use.
name_tuples.map { |n| n.version }.uniq name_tuples.map { |n| n.version }.uniq
else else
platforms.sort.reverse.map do |version, pls| platforms.sort.reverse.map do |version, pls|
if pls == [Gem::Platform::RUBY] then out = version.to_s
if options[:domain] == :remote || specs.all? { |spec| spec.is_a? Gem::Source }
version if options[:domain] == :local
else default = specs.any? do |s|
spec = specs.select { |s| s.version == version } !s.is_a?(Gem::Source) && s.version == version && s.default_gem?
if spec.first.default_gem?
"default: #{version}"
else
version
end
end end
else out = "default: #{out}" if default
ruby = pls.delete Gem::Platform::RUBY
platform_list = [ruby, *pls.sort].compact
"#{version} #{platform_list.join ' '}"
end end
if pls != [Gem::Platform::RUBY] then
platform_list = [pls.delete(Gem::Platform::RUBY), *pls.sort].compact
out = platform_list.unshift(out).join(' ')
end
out
end end
end end

View file

@ -15,10 +15,11 @@ class Gem::Commands::SetupCommand < Gem::Command
super 'setup', 'Install RubyGems', super 'setup', 'Install RubyGems',
:format_executable => true, :document => %w[ri], :format_executable => true, :document => %w[ri],
:site_or_vendor => 'sitelibdir', :site_or_vendor => 'sitelibdir',
:destdir => '', :prefix => '', :previous_version => '' :destdir => '', :prefix => '', :previous_version => '',
:regenerate_binstubs => true
add_option '--previous-version=VERSION', add_option '--previous-version=VERSION',
'Previous version of rubygems', 'Previous version of RubyGems',
'Used for changelog processing' do |version, options| 'Used for changelog processing' do |version, options|
options[:previous_version] = version options[:previous_version] = version
end end
@ -42,7 +43,7 @@ class Gem::Commands::SetupCommand < Gem::Command
add_option '--[no-]format-executable', add_option '--[no-]format-executable',
'Makes `gem` match ruby', 'Makes `gem` match ruby',
'If ruby is ruby18, gem will be gem18' do |value, options| 'If Ruby is ruby18, gem will be gem18' do |value, options|
options[:format_executable] = value options[:format_executable] = value
end end
@ -79,6 +80,15 @@ class Gem::Commands::SetupCommand < Gem::Command
options[:document].uniq! options[:document].uniq!
end end
add_option '--[no-]regenerate-binstubs',
'Regenerate gem binstubs' do |value, options|
if value then
options[:regenerate_binstubs] = true
else
options.delete(:regenerate_binstubs)
end
end
@verbose = nil @verbose = nil
end end
@ -92,7 +102,7 @@ class Gem::Commands::SetupCommand < Gem::Command
end end
def defaults_str # :nodoc: def defaults_str # :nodoc:
"--format-executable --document ri" "--format-executable --document ri --regenerate-binstubs"
end end
def description # :nodoc: def description # :nodoc:
@ -142,8 +152,12 @@ By default, this RubyGems will install gem as:
remove_old_lib_files lib_dir remove_old_lib_files lib_dir
install_default_bundler_gem
say "RubyGems #{Gem::VERSION} installed" say "RubyGems #{Gem::VERSION} installed"
regenerate_binstubs
uninstall_old_gemcutter uninstall_old_gemcutter
documentation_success = install_rdoc documentation_success = install_rdoc
@ -190,7 +204,7 @@ By default, this RubyGems will install gem as:
if options[:document].include? 'ri' then if options[:document].include? 'ri' then
say "Ruby Interactive (ri) documentation was installed. ri is kind of like man " say "Ruby Interactive (ri) documentation was installed. ri is kind of like man "
say "pages for ruby libraries. You may access it like this:" say "pages for Ruby libraries. You may access it like this:"
say " ri Classname" say " ri Classname"
say " ri Classname.class_method" say " ri Classname.class_method"
say " ri Classname#instance_method" say " ri Classname#instance_method"
@ -202,59 +216,64 @@ By default, this RubyGems will install gem as:
end end
end end
def install_executables(bin_dir)
say "Installing gem executable" if @verbose
def install_executables(bin_dir)
@bin_file_names = [] @bin_file_names = []
Dir.chdir 'bin' do executables = { 'gem' => 'bin' }
bin_files = Dir['*'] executables['bundler'] = 'bundler/exe' if Gem::USE_BUNDLER_FOR_GEMDEPS
executables.each do |tool, path|
say "Installing #{tool} executable" if @verbose
bin_files.delete 'update_rubygems' Dir.chdir path do
bin_files = Dir['*']
bin_files.each do |bin_file| bin_files -= %w[update_rubygems bundler bundle_ruby]
bin_file_formatted = if options[:format_executable] then
Gem.default_exec_format % bin_file
else
bin_file
end
dest_file = File.join bin_dir, bin_file_formatted bin_files.each do |bin_file|
bin_tmp_file = File.join Dir.tmpdir, "#{bin_file}.#{$$}" bin_file_formatted = if options[:format_executable] then
Gem.default_exec_format % bin_file
else
bin_file
end
begin dest_file = File.join bin_dir, bin_file_formatted
bin = File.readlines bin_file bin_tmp_file = File.join Dir.tmpdir, "#{bin_file}.#{$$}"
bin[0] = "#!#{Gem.ruby}\n"
File.open bin_tmp_file, 'w' do |fp| begin
fp.puts bin.join bin = File.readlines bin_file
bin[0] = "#!#{Gem.ruby}\n"
File.open bin_tmp_file, 'w' do |fp|
fp.puts bin.join
end
install bin_tmp_file, dest_file, :mode => 0755
@bin_file_names << dest_file
ensure
rm bin_tmp_file
end end
install bin_tmp_file, dest_file, :mode => 0755 next unless Gem.win_platform?
@bin_file_names << dest_file
ensure
rm bin_tmp_file
end
next unless Gem.win_platform? begin
bin_cmd_file = File.join Dir.tmpdir, "#{bin_file}.bat"
begin File.open bin_cmd_file, 'w' do |file|
bin_cmd_file = File.join Dir.tmpdir, "#{bin_file}.bat" file.puts <<-TEXT
@ECHO OFF
IF NOT "%~f0" == "~f0" GOTO :WinNT
@"#{File.basename(Gem.ruby).chomp('"')}" "#{dest_file}" %1 %2 %3 %4 %5 %6 %7 %8 %9
GOTO :EOF
:WinNT
@"#{File.basename(Gem.ruby).chomp('"')}" "%~dpn0" %*
TEXT
end
File.open bin_cmd_file, 'w' do |file| install bin_cmd_file, "#{dest_file}.bat", :mode => 0755
file.puts <<-TEXT ensure
@ECHO OFF rm bin_cmd_file
IF NOT "%~f0" == "~f0" GOTO :WinNT
@"#{File.basename(Gem.ruby).chomp('"')}" "#{dest_file}" %1 %2 %3 %4 %5 %6 %7 %8 %9
GOTO :EOF
:WinNT
@"#{File.basename(Gem.ruby).chomp('"')}" "%~dpn0" %*
TEXT
end end
install bin_cmd_file, "#{dest_file}.bat", :mode => 0755
ensure
rm bin_cmd_file
end end
end end
end end
@ -269,18 +288,22 @@ TEXT
end end
def install_lib(lib_dir) def install_lib(lib_dir)
say "Installing RubyGems" if @verbose libs = { 'RubyGems' => 'lib' }
libs['Bundler'] = 'bundler/lib' if Gem::USE_BUNDLER_FOR_GEMDEPS
libs.each do |tool, path|
say "Installing #{tool}" if @verbose
lib_files = rb_files_in 'lib' lib_files = rb_files_in path
pem_files = pem_files_in 'lib' pem_files = pem_files_in path
Dir.chdir 'lib' do Dir.chdir path do
lib_files.each do |lib_file| lib_files.each do |lib_file|
install_file lib_file, lib_dir install_file lib_file, lib_dir
end end
pem_files.each do |pem_file| pem_files.each do |pem_file|
install_file pem_file, lib_dir install_file pem_file, lib_dir
end
end end
end end
end end
@ -326,6 +349,29 @@ TEXT
return false return false
end end
def install_default_bundler_gem
return unless Gem::USE_BUNDLER_FOR_GEMDEPS
bundler_spec = Gem::Specification.load("bundler/bundler.gemspec")
bundler_spec.files = Dir["bundler/{*.md,{lib,exe,man}/**/*}"]
bundler_spec.executables -= %w[bundler bundle_ruby]
Dir.entries(Gem::Specification.default_specifications_dir).
select {|gs| gs.start_with?("bundler-") }.
each {|gs| File.delete(File.join(Gem::Specification.default_specifications_dir, gs)) }
default_spec_path = File.join(Gem::Specification.default_specifications_dir, "#{bundler_spec.full_name}.gemspec")
Gem.write_binary(default_spec_path, bundler_spec.to_ruby)
bundler_spec = Gem::Specification.load(default_spec_path)
Dir.entries(bundler_spec.gems_dir).
select {|default_gem| default_gem.start_with?("bundler-") }.
each {|default_gem| rm_r File.join(bundler_spec.gems_dir, default_gem) }
mkdir_p bundler_spec.bin_dir
bundler_spec.executables.each {|e| cp File.join("bundler", bundler_spec.bindir, e), File.join(bundler_spec.bin_dir, e) }
end
def make_destination_dirs(install_destdir) def make_destination_dirs(install_destdir)
lib_dir, bin_dir = Gem.default_rubygems_dirs lib_dir, bin_dir = Gem.default_rubygems_dirs
@ -397,7 +443,7 @@ TEXT
old_bin_path = File.join bin_dir, old_bin_file old_bin_path = File.join bin_dir, old_bin_file
next unless File.exist? old_bin_path next unless File.exist? old_bin_path
deprecation_message = "`#{old_bin_file}` has been deprecated. Use `#{new_name}` instead." deprecation_message = "`#{old_bin_file}` has been deprecated. Use `#{new_name}` instead."
File.open old_bin_path, 'w' do |fp| File.open old_bin_path, 'w' do |fp|
fp.write <<-EOF fp.write <<-EOF
@ -416,23 +462,26 @@ abort "#{deprecation_message}"
end end
def remove_old_lib_files lib_dir def remove_old_lib_files lib_dir
rubygems_dir = File.join lib_dir, 'rubygems' lib_dirs = { File.join(lib_dir, 'rubygems') => 'lib/rubygems' }
lib_files = rb_files_in 'lib/rubygems' lib_dirs[File.join(lib_dir, 'bundler')] = 'bundler/lib/bundler' if Gem::USE_BUNDLER_FOR_GEMDEPS
lib_dirs.each do |old_lib_dir, new_lib_dir|
lib_files = rb_files_in(new_lib_dir)
old_lib_files = rb_files_in rubygems_dir old_lib_files = rb_files_in(old_lib_dir)
to_remove = old_lib_files - lib_files to_remove = old_lib_files - lib_files
to_remove.delete_if do |file| to_remove.delete_if do |file|
file.start_with? 'defaults' file.start_with? 'defaults'
end end
Dir.chdir rubygems_dir do Dir.chdir old_lib_dir do
to_remove.each do |file| to_remove.each do |file|
FileUtils.rm_f file FileUtils.rm_f file
warn "unable to remove old file #{file} please remove it by hand" if warn "unable to remove old file #{file} please remove it by hand" if
File.exist? file File.exist? file
end
end end
end end
end end
@ -480,5 +529,11 @@ abort "#{deprecation_message}"
rescue Gem::InstallError rescue Gem::InstallError
end end
end def regenerate_binstubs
require "rubygems/commands/pristine_command"
say "Regenerating binstubs"
command = Gem::Commands::PristineCommand.new
command.invoke(*%w[--all --only-executables --silent])
end
end

View file

@ -0,0 +1,33 @@
# frozen_string_literal: true
require 'rubygems/command'
require 'rubygems/gemcutter_utilities'
class Gem::Commands::SigninCommand < Gem::Command
include Gem::GemcutterUtilities
def initialize
super 'signin', 'Sign in to any gemcutter-compatible host. '\
'It defaults to https://rubygems.org'
add_option('--host HOST', 'Push to another gemcutter-compatible host') do |value, options|
options[:host] = value
end
end
def description # :nodoc:
'The signin command executes host sign in for a push server (the default is'\
' https://rubygems.org). The host can be provided with the host flag or can'\
' be inferred from the provided gem. Host resolution matches the resolution'\
' strategy for the push command.'
end
def usage # :nodoc:
program_name
end
def execute
sign_in options[:host]
end
end

View file

@ -0,0 +1,33 @@
# frozen_string_literal: true
require 'rubygems/command'
class Gem::Commands::SignoutCommand < Gem::Command
def initialize
super 'signout', 'Sign out from all the current sessions.'
end
def description # :nodoc:
'The `signout` command is used to sign out from all current sessions,'\
' allowing you to sign in using a different set of credentials.'
end
def usage # :nodoc:
program_name
end
def execute
credentials_path = Gem.configuration.credentials_path
if !File.exist?(credentials_path) then
alert_error 'You are not currently signed in.'
elsif !File.writable?(credentials_path) then
alert_error "File '#{Gem.configuration.credentials_path}' is read-only."\
' Please make sure it is writable.'
else
Gem.configuration.unset_api_key!
say 'You have successfully signed out from all sessions.'
end
end
end

View file

@ -30,7 +30,7 @@ class Gem::Commands::UninstallCommand < Gem::Command
options[:ignore] = value options[:ignore] = value
end end
add_option('-D', '--[no-]-check-development', add_option('-D', '--[no-]check-development',
'Check development dependencies while uninstalling', 'Check development dependencies while uninstalling',
'(default: false)') do |value, options| '(default: false)') do |value, options|
options[:check_dev] = value options[:check_dev] = value
@ -143,7 +143,9 @@ that is a dependency of an existing gem. You can use the
deplist = Gem::DependencyList.new deplist = Gem::DependencyList.new
get_all_gem_names.uniq.each do |name| get_all_gem_names.uniq.each do |name|
Gem::Specification.find_all_by_name(name).each do |spec| gem_specs = Gem::Specification.find_all_by_name(name)
say("Gem '#{name}' is not installed") if gem_specs.empty?
gem_specs.each do |spec|
deplist.add spec deplist.add spec
end end
end end
@ -162,4 +164,3 @@ that is a dependency of an existing gem. You can use the
end end
end end

View file

@ -2,11 +2,20 @@
require 'rubygems/command' require 'rubygems/command'
require 'rubygems/installer' require 'rubygems/installer'
require 'rubygems/version_option' require 'rubygems/version_option'
require 'rubygems/security_option'
require 'rubygems/remote_fetcher' require 'rubygems/remote_fetcher'
# forward-declare
module Gem::Security # :nodoc:
class Policy # :nodoc:
end
end
class Gem::Commands::UnpackCommand < Gem::Command class Gem::Commands::UnpackCommand < Gem::Command
include Gem::VersionOption include Gem::VersionOption
include Gem::SecurityOption
def initialize def initialize
require 'fileutils' require 'fileutils'
@ -24,6 +33,7 @@ class Gem::Commands::UnpackCommand < Gem::Command
options[:spec] = true options[:spec] = true
end end
add_security_option
add_version_option add_version_option
end end
@ -63,6 +73,8 @@ command help for an example.
# at the same time.) # at the same time.)
def execute def execute
security_policy = options[:security_policy]
get_all_gem_names.each do |name| get_all_gem_names.each do |name|
dependency = Gem::Dependency.new name, options[:version] dependency = Gem::Dependency.new name, options[:version]
path = get_path dependency path = get_path dependency
@ -73,7 +85,7 @@ command help for an example.
end end
if @options[:spec] then if @options[:spec] then
spec, metadata = get_metadata path spec, metadata = get_metadata path, security_policy
if metadata.nil? then if metadata.nil? then
alert_error "--spec is unsupported on '#{name}' (old format gem)" alert_error "--spec is unsupported on '#{name}' (old format gem)"
@ -89,7 +101,7 @@ command help for an example.
basename = File.basename path, '.gem' basename = File.basename path, '.gem'
target_dir = File.expand_path basename, options[:target] target_dir = File.expand_path basename, options[:target]
package = Gem::Package.new path package = Gem::Package.new path, security_policy
package.extract_files target_dir package.extract_files target_dir
say "Unpacked gem: '#{target_dir}'" say "Unpacked gem: '#{target_dir}'"
@ -158,8 +170,8 @@ command help for an example.
#-- #--
# TODO move to Gem::Package as #raw_spec or something # TODO move to Gem::Package as #raw_spec or something
def get_metadata path def get_metadata path, security_policy = nil
format = Gem::Package.new path format = Gem::Package.new path, security_policy
spec = format.spec spec = format.spec
metadata = nil metadata = nil

View file

@ -70,7 +70,7 @@ command to remove old versions.
def check_latest_rubygems version # :nodoc: def check_latest_rubygems version # :nodoc:
if Gem.rubygems_version == version then if Gem.rubygems_version == version then
say "Latest version currently installed. Aborting." say "Latest version already installed. Done."
terminate_interaction terminate_interaction
end end

View file

@ -56,7 +56,7 @@ requiring to see why it does not behave as you expect.
paths = find_paths arg, dirs paths = find_paths arg, dirs
if paths.empty? then if paths.empty? then
alert_error "Can't find ruby library file or shared library #{arg}" alert_error "Can't find Ruby library file or shared library #{arg}"
found &&= false found &&= false
else else

View file

@ -11,19 +11,11 @@ class Gem::Commands::YankCommand < Gem::Command
def description # :nodoc: def description # :nodoc:
<<-EOF <<-EOF
The yank command removes a gem you pushed to a server from the server's The yank command permanently removes a gem you pushed to a server.
index.
Note that if you push a gem to rubygems.org the yank command does not
prevent other people from downloading the gem via the download link.
Once you have pushed a gem several downloads will happen automatically Once you have pushed a gem several downloads will happen automatically
via the webhooks. If you accidentally pushed passwords or other sensitive via the webhooks. If you accidentally pushed passwords or other sensitive
data you will need to change them immediately and yank your gem. data you will need to change them immediately and yank your gem.
If you are yanking a gem due to intellectual property reasons contact
http://help.rubygems.org for permanent removal. Be sure to mention this
as the reason for the removal request.
EOF EOF
end end
@ -42,7 +34,8 @@ as the reason for the removal request.
add_platform_option("remove") add_platform_option("remove")
add_option('--host HOST', add_option('--host HOST',
'Yank from another gemcutter-compatible host') do |value, options| 'Yank from another gemcutter-compatible host',
' (e.g. https://rubygems.org)') do |value, options|
options[:host] = value options[:host] = value
end end

View file

@ -336,6 +336,15 @@ if you believe they were disclosed to a third party.
load_api_keys # reload load_api_keys # reload
end end
##
# Remove the +~/.gem/credentials+ file to clear all the current sessions.
def unset_api_key!
return false unless File.exist?(credentials_path)
File.delete(credentials_path)
end
def load_file(filename) def load_file(filename)
Gem.load_yaml Gem.load_yaml
@ -419,31 +428,11 @@ if you believe they were disclosed to a third party.
# to_yaml only overwrites things you can't override on the command line. # to_yaml only overwrites things you can't override on the command line.
def to_yaml # :nodoc: def to_yaml # :nodoc:
yaml_hash = {} yaml_hash = {}
yaml_hash[:backtrace] = if @hash.key?(:backtrace) yaml_hash[:backtrace] = @hash.fetch(:backtrace, DEFAULT_BACKTRACE)
@hash[:backtrace] yaml_hash[:bulk_threshold] = @hash.fetch(:bulk_threshold, DEFAULT_BULK_THRESHOLD)
else
DEFAULT_BACKTRACE
end
yaml_hash[:bulk_threshold] = if @hash.key?(:bulk_threshold)
@hash[:bulk_threshold]
else
DEFAULT_BULK_THRESHOLD
end
yaml_hash[:sources] = Gem.sources.to_a yaml_hash[:sources] = Gem.sources.to_a
yaml_hash[:update_sources] = @hash.fetch(:update_sources, DEFAULT_UPDATE_SOURCES)
yaml_hash[:update_sources] = if @hash.key?(:update_sources) yaml_hash[:verbose] = @hash.fetch(:verbose, DEFAULT_VERBOSITY)
@hash[:update_sources]
else
DEFAULT_UPDATE_SOURCES
end
yaml_hash[:verbose] = if @hash.key?(:verbose)
@hash[:verbose]
else
DEFAULT_VERBOSITY
end
yaml_hash[:ssl_verify_mode] = yaml_hash[:ssl_verify_mode] =
@hash[:ssl_verify_mode] if @hash.key? :ssl_verify_mode @hash[:ssl_verify_mode] if @hash.key? :ssl_verify_mode

View file

@ -41,8 +41,7 @@ module Kernel
path = path.to_path if path.respond_to? :to_path path = path.to_path if path.respond_to? :to_path
spec = Gem.find_unresolved_default_spec(path) if spec = Gem.find_unresolved_default_spec(path)
if spec
Gem.remove_unresolved_default_spec(spec) Gem.remove_unresolved_default_spec(spec)
begin begin
Kernel.send(:gem, spec.name) Kernel.send(:gem, spec.name)
@ -66,12 +65,10 @@ module Kernel
#-- #--
# TODO request access to the C implementation of this to speed up RubyGems # TODO request access to the C implementation of this to speed up RubyGems
spec = Gem::Specification.find_active_stub_by_path path if Gem::Specification.find_active_stub_by_path(path)
begin
RUBYGEMS_ACTIVATION_MONITOR.exit RUBYGEMS_ACTIVATION_MONITOR.exit
return gem_original_require(path) return gem_original_require(path)
end if spec end
# Attempt to find +path+ in any unresolved gems... # Attempt to find +path+ in any unresolved gems...
@ -109,7 +106,7 @@ module Kernel
# Ok, now find a gem that has no conflicts, starting # Ok, now find a gem that has no conflicts, starting
# at the highest version. # at the highest version.
valid = found_specs.reject { |s| s.has_conflicts? }.first valid = found_specs.find { |s| !s.has_conflicts? }
unless valid then unless valid then
le = Gem::LoadError.new "unable to find a version of '#{names.first}' to activate" le = Gem::LoadError.new "unable to find a version of '#{names.first}' to activate"
@ -143,4 +140,3 @@ module Kernel
private :require private :require
end end

View file

@ -280,6 +280,8 @@ class Gem::Dependency
requirement.satisfied_by?(spec.version) && env_req.satisfied_by?(spec.version) requirement.satisfied_by?(spec.version) && env_req.satisfied_by?(spec.version)
}.map(&:to_spec) }.map(&:to_spec)
Gem::BundlerVersionFinder.filter!(matches) if name == "bundler".freeze
if platform_only if platform_only
matches.reject! { |spec| matches.reject! { |spec|
spec.nil? || !Gem::Platform.match(spec.platform) spec.nil? || !Gem::Platform.match(spec.platform)

View file

@ -7,6 +7,7 @@ require 'rubygems/spec_fetcher'
require 'rubygems/user_interaction' require 'rubygems/user_interaction'
require 'rubygems/source' require 'rubygems/source'
require 'rubygems/available_set' require 'rubygems/available_set'
require 'rubygems/deprecate'
## ##
# Installs a gem along with all its dependencies from local and remote gems. # Installs a gem along with all its dependencies from local and remote gems.
@ -46,6 +47,9 @@ class Gem::DependencyInstaller
attr_reader :gems_to_install # :nodoc: attr_reader :gems_to_install # :nodoc:
extend Gem::Deprecate
deprecate :gems_to_install, :none, 2016, 10
## ##
# List of gems installed by #install in alphabetic order # List of gems installed by #install in alphabetic order

View file

@ -58,6 +58,9 @@ module Gem
private private
def build_message def build_message
if name == "bundler" && message = Gem::BundlerVersionFinder.missing_version_message
return message
end
names = specs.map(&:full_name) names = specs.map(&:full_name)
"Could not find '#{name}' (#{requirement}) - did find: [#{names.join ','}]\n" "Could not find '#{name}' (#{requirement}) - did find: [#{names.join ','}]\n"
end end

View file

@ -154,6 +154,12 @@ class Gem::ImpossibleDependenciesError < Gem::Exception
end end
class Gem::InstallError < Gem::Exception; end class Gem::InstallError < Gem::Exception; end
class Gem::RuntimeRequirementNotMetError < Gem::InstallError
attr_accessor :suggestion
def message
[suggestion, super].compact.join("\n\t")
end
end
## ##
# Potentially raised when a specification is validated. # Potentially raised when a specification is validated.

View file

@ -183,7 +183,7 @@ EOF
return if @spec.extensions.empty? return if @spec.extensions.empty?
if @build_args.empty? if @build_args.empty?
say "Building native extensions. This could take a while..." say "Building native extensions. This could take a while..."
else else
say "Building native extensions with: '#{@build_args.join ' '}'" say "Building native extensions with: '#{@build_args.join ' '}'"
say "This could take a while..." say "This could take a while..."

View file

@ -8,6 +8,7 @@
require 'rubygems' require 'rubygems'
require 'rubygems/command_manager' require 'rubygems/command_manager'
require 'rubygems/config_file' require 'rubygems/config_file'
require 'rubygems/deprecate'
## ##
# Load additional plugins from $LOAD_PATH # Load additional plugins from $LOAD_PATH
@ -26,7 +27,10 @@ Gem.load_env_plugins rescue nil
class Gem::GemRunner class Gem::GemRunner
def initialize(options={}) def initialize(options={})
# TODO: nuke these options if !options.empty? && !Gem::Deprecate.skip
Kernel.warn "NOTE: passing options to Gem::GemRunner.new is deprecated with no replacement. It will be removed on or after 2016-10-01."
end
@command_manager_class = options[:command_manager] || Gem::CommandManager @command_manager_class = options[:command_manager] || Gem::CommandManager
@config_file_class = options[:config_file] || Gem::ConfigFile @config_file_class = options[:config_file] || Gem::ConfigFile
end end

View file

@ -6,37 +6,18 @@
#++ #++
require 'rubygems' require 'rubygems'
require 'rubygems/security_option'
# forward-declare
module Gem::Security # :nodoc:
class Policy # :nodoc:
end
end
## ##
# Mixin methods for install and update options for Gem::Commands # Mixin methods for install and update options for Gem::Commands
module Gem::InstallUpdateOptions module Gem::InstallUpdateOptions
include Gem::SecurityOption
## ##
# Add the install/update options to the option parser. # Add the install/update options to the option parser.
def add_install_update_options def add_install_update_options
# TODO: use @parser.accept
OptionParser.accept Gem::Security::Policy do |value|
require 'rubygems/security'
raise OptionParser::InvalidArgument, 'OpenSSL not installed' unless
defined?(Gem::Security::HighSecurity)
value = Gem::Security::Policies[value]
valid = Gem::Security::Policies.keys.sort
message = "#{value} (#{valid.join ', '} are valid)"
raise OptionParser::InvalidArgument, message if value.nil?
value
end
add_option(:"Install/Update", '-i', '--install-dir DIR', add_option(:"Install/Update", '-i', '--install-dir DIR',
'Gem repository directory to get installed', 'Gem repository directory to get installed',
'gems') do |value, options| 'gems') do |value, options|
@ -124,11 +105,7 @@ module Gem::InstallUpdateOptions
options[:wrappers] = value options[:wrappers] = value
end end
add_option(:"Install/Update", '-P', '--trust-policy POLICY', add_security_option
Gem::Security::Policy,
'Specify gem trust policy') do |value, options|
options[:security_policy] = value
end
add_option(:"Install/Update", '--ignore-dependencies', add_option(:"Install/Update", '--ignore-dependencies',
'Do not install any required dependent gems') do |value, options| 'Do not install any required dependent gems') do |value, options|
@ -136,8 +113,8 @@ module Gem::InstallUpdateOptions
end end
add_option(:"Install/Update", '--[no-]format-executable', add_option(:"Install/Update", '--[no-]format-executable',
'Make installed executable names match ruby.', 'Make installed executable names match Ruby.',
'If ruby is ruby18, foo_exec will be', 'If Ruby is ruby18, foo_exec will be',
'foo_exec18') do |value, options| 'foo_exec18') do |value, options|
options[:format_executable] = value options[:format_executable] = value
end end

View file

@ -136,8 +136,9 @@ class Gem::Installer
end end
## ##
# Constructs an Installer instance that will install the gem located at # Constructs an Installer instance that will install the gem at +package+ which
# +gem+. +options+ is a Hash with the following keys: # can either be a path or an instance of Gem::Package. +options+ is a Hash
# with the following keys:
# #
# :bin_dir:: Where to put a bin wrapper if needed. # :bin_dir:: Where to put a bin wrapper if needed.
# :development:: Whether or not development dependencies should be installed. # :development:: Whether or not development dependencies should be installed.
@ -157,6 +158,7 @@ class Gem::Installer
# :wrappers:: Install wrappers if true, symlinks if false. # :wrappers:: Install wrappers if true, symlinks if false.
# :build_args:: An Array of arguments to pass to the extension builder # :build_args:: An Array of arguments to pass to the extension builder
# process. If not set, then Gem::Command.build_args is used # process. If not set, then Gem::Command.build_args is used
# :post_install_message:: Print gem post install message if true
def initialize(package, options={}) def initialize(package, options={})
require 'fileutils' require 'fileutils'
@ -471,7 +473,7 @@ class Gem::Installer
unless File.exist? bin_path then unless File.exist? bin_path then
# TODO change this to a more useful warning # TODO change this to a more useful warning
warn "#{bin_path} maybe `gem pristine #{spec.name}` will fix it?" warn "`#{bin_path}` does not exist, maybe `gem pristine #{spec.name}` will fix it?"
next next
end end
@ -608,7 +610,9 @@ class Gem::Installer
def ensure_required_ruby_version_met # :nodoc: def ensure_required_ruby_version_met # :nodoc:
if rrv = spec.required_ruby_version then if rrv = spec.required_ruby_version then
unless rrv.satisfied_by? Gem.ruby_version then unless rrv.satisfied_by? Gem.ruby_version then
raise Gem::InstallError, "#{spec.name} requires Ruby version #{rrv}." ruby_version = Gem.ruby_api_version
raise Gem::RuntimeRequirementNotMetError,
"#{spec.name} requires Ruby version #{rrv}. The current ruby version is #{ruby_version}."
end end
end end
end end
@ -616,8 +620,9 @@ class Gem::Installer
def ensure_required_rubygems_version_met # :nodoc: def ensure_required_rubygems_version_met # :nodoc:
if rrgv = spec.required_rubygems_version then if rrgv = spec.required_rubygems_version then
unless rrgv.satisfied_by? Gem.rubygems_version then unless rrgv.satisfied_by? Gem.rubygems_version then
raise Gem::InstallError, rg_version = Gem::VERSION
"#{spec.name} requires RubyGems version #{rrgv}. " + raise Gem::RuntimeRequirementNotMetError,
"#{spec.name} requires RubyGems version #{rrgv}. The current RubyGems version is #{rg_version}. " +
"Try 'gem update --system' to update RubyGems itself." "Try 'gem update --system' to update RubyGems itself."
end end
end end
@ -821,7 +826,7 @@ TEXT
# #
# Version and dependency checks are skipped if this install is forced. # Version and dependency checks are skipped if this install is forced.
# #
# The dependent check will be skipped this install is ignoring dependencies. # The dependent check will be skipped if the install is ignoring dependencies.
def pre_install_checks def pre_install_checks
verify_gem_home options[:unpack] verify_gem_home options[:unpack]

View file

@ -1,6 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'rubygems/test_case' require 'rubygems/test_case'
require 'rubygems/installer' require 'rubygems/installer'
require 'rubygems/deprecate'
class Gem::Installer class Gem::Installer
@ -72,7 +73,7 @@ class Gem::InstallerTestCase < Gem::TestCase
# a spec named 'a', intended for regular installs # a spec named 'a', intended for regular installs
# @user_spec:: # @user_spec::
# a spec named 'b', intended for user installs # a spec named 'b', intended for user installs
#
# @gem:: # @gem::
# the path to a built gem from @spec # the path to a built gem from @spec
# @user_spec:: # @user_spec::
@ -107,15 +108,17 @@ class Gem::InstallerTestCase < Gem::TestCase
end end
def util_gem_bindir spec = @spec # :nodoc: def util_gem_bindir spec = @spec # :nodoc:
# TODO: deprecate
spec.bin_dir spec.bin_dir
end end
def util_gem_dir spec = @spec # :nodoc: def util_gem_dir spec = @spec # :nodoc:
# TODO: deprecate
spec.gem_dir spec.gem_dir
end end
extend Gem::Deprecate
deprecate :util_gem_bindir, "@spec.bin_dir", 2016, 10
deprecate :util_gem_dir, "@spec.gem_dir", 2016, 10
## ##
# The path where installed executables live # The path where installed executables live

View file

@ -124,7 +124,7 @@ class Gem::Package::Old < Gem::Package
break unless line break unless line
end end
raise Gem::Exception, "Failed to find end of ruby script while reading gem" raise Gem::Exception, "Failed to find end of Ruby script while reading gem"
end end
## ##

View file

@ -83,7 +83,7 @@ class Gem::Request
e.message =~ / -- openssl$/ e.message =~ / -- openssl$/
raise Gem::Exception.new( raise Gem::Exception.new(
'Unable to require openssl, install OpenSSL and rebuild ruby (preferred) or use non-HTTPS sources') 'Unable to require openssl, install OpenSSL and rebuild Ruby (preferred) or use non-HTTPS sources')
end end
def self.verify_certificate store_context def self.verify_certificate store_context

View file

@ -163,9 +163,26 @@ class Gem::RequestSet
end end
end end
spec = req.spec.install options do |installer| spec =
yield req, installer if block_given? begin
end req.spec.install options do |installer|
yield req, installer if block_given?
end
rescue Gem::RuntimeRequirementNotMetError => e
recent_match = req.spec.set.find_all(req.request).sort_by(&:version).reverse_each.find do |s|
s = s.spec
s.required_ruby_version.satisfied_by?(Gem.ruby_version) && s.required_rubygems_version.satisfied_by?(Gem.rubygems_version)
end
if recent_match
suggestion = "The last version of #{req.request} to support your Ruby & RubyGems was #{recent_match.version}. Try installing it with `gem install #{recent_match.name} -v #{recent_match.version}`"
suggestion += " and then running the current command again" unless @always_install.include?(req.spec.spec)
else
suggestion = "There are no versions of #{req.request} compatible with your Ruby & RubyGems"
suggestion += ". Maybe try installing an older version of the gem you're looking for?" unless @always_install.include?(req.spec.spec)
end
e.suggestion = suggestion
raise
end
requests << spec requests << spec
end end

View file

@ -786,7 +786,7 @@ Gem dependencies file #{@path} includes git reference for both ref/branch and ta
engine_version = options[:engine_version] engine_version = options[:engine_version]
raise ArgumentError, raise ArgumentError,
'you must specify engine_version along with the ruby engine' if 'You must specify engine_version along with the Ruby engine' if
engine and not engine_version engine and not engine_version
return true if @installing return true if @installing
@ -799,7 +799,7 @@ Gem dependencies file #{@path} includes git reference for both ref/branch and ta
end end
if engine and engine != Gem.ruby_engine then if engine and engine != Gem.ruby_engine then
message = "Your ruby engine is #{Gem.ruby_engine}, " + message = "Your Ruby engine is #{Gem.ruby_engine}, " +
"but your #{gem_deps_file} requires #{engine}" "but your #{gem_deps_file} requires #{engine}"
raise Gem::RubyVersionMismatch, message raise Gem::RubyVersionMismatch, message
@ -810,7 +810,7 @@ Gem dependencies file #{@path} includes git reference for both ref/branch and ta
if engine_version != my_engine_version then if engine_version != my_engine_version then
message = message =
"Your ruby engine version is #{Gem.ruby_engine} #{my_engine_version}, " + "Your Ruby engine version is #{Gem.ruby_engine} #{my_engine_version}, " +
"but your #{gem_deps_file} requires #{engine} #{engine_version}" "but your #{gem_deps_file} requires #{engine} #{engine_version}"
raise Gem::RubyVersionMismatch, message raise Gem::RubyVersionMismatch, message

View file

@ -51,7 +51,11 @@ class Gem::Requirement
# If the input is "weird", the default version requirement is # If the input is "weird", the default version requirement is
# returned. # returned.
def self.create input def self.create *inputs
return new inputs if inputs.length > 1
input = inputs.shift
case input case input
when Gem::Requirement then when Gem::Requirement then
input input

View file

@ -230,8 +230,28 @@ class Gem::Resolver
exc.errors = @set.errors exc.errors = @set.errors
raise exc raise exc
end end
possibles.sort_by { |s| [s.source, s.version, Gem::Platform.local =~ s.platform ? 1 : 0] }.
map { |s| ActivationRequest.new s, dependency, [] } sources = []
groups = Hash.new { |hash, key| hash[key] = [] }
# create groups & sources in the same loop
sources = possibles.map { |spec|
source = spec.source
groups[source] << spec
source
}.uniq.reverse
activation_requests = []
sources.each do |source|
groups[source].
sort_by { |spec| [spec.version, Gem::Platform.local =~ spec.platform ? 1 : 0] }.
map { |spec| ActivationRequest.new spec, dependency, [] }.
each { |activation_request| activation_requests << activation_request }
end
activation_requests
end end
def dependencies_for(specification) def dependencies_for(specification)

View file

@ -41,6 +41,7 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
@ignore_dependencies = false @ignore_dependencies = false
@ignore_installed = false @ignore_installed = false
@local = {} @local = {}
@local_source = Gem::Source::Local.new
@remote_set = Gem::Resolver::BestSet.new @remote_set = Gem::Resolver::BestSet.new
@specs = {} @specs = {}
end end
@ -136,13 +137,11 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
res.concat matching_local res.concat matching_local
local_source = Gem::Source::Local.new
begin begin
if local_spec = local_source.find_gem(name, dep.requirement) then if local_spec = @local_source.find_gem(name, dep.requirement) then
res << Gem::Resolver::IndexSpecification.new( res << Gem::Resolver::IndexSpecification.new(
self, local_spec.name, local_spec.version, self, local_spec.name, local_spec.version,
local_source, local_spec.platform) @local_source, local_spec.platform)
end end
rescue Gem::Package::FormatError rescue Gem::Package::FormatError
# ignore # ignore
@ -194,7 +193,7 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
# Has a local gem for +dep_name+ been added to this set? # Has a local gem for +dep_name+ been added to this set?
def local? dep_name # :nodoc: def local? dep_name # :nodoc:
spec, = @local[dep_name] spec, _ = @local[dep_name]
spec spec
end end
@ -226,4 +225,3 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
end end
end end

View file

@ -340,7 +340,9 @@ module Gem::Security
# Digest algorithm used to sign gems # Digest algorithm used to sign gems
DIGEST_ALGORITHM = DIGEST_ALGORITHM =
if defined?(OpenSSL::Digest::SHA1) then if defined?(OpenSSL::Digest::SHA256) then
OpenSSL::Digest::SHA256
elsif defined?(OpenSSL::Digest::SHA1) then
OpenSSL::Digest::SHA1 OpenSSL::Digest::SHA1
end end
@ -363,7 +365,7 @@ module Gem::Security
## ##
# Length of keys created by KEY_ALGORITHM # Length of keys created by KEY_ALGORITHM
KEY_LENGTH = 2048 KEY_LENGTH = 3072
## ##
# Cipher used to encrypt the key pair used to sign gems. # Cipher used to encrypt the key pair used to sign gems.
@ -371,10 +373,15 @@ module Gem::Security
KEY_CIPHER = OpenSSL::Cipher.new('AES-256-CBC') if defined?(OpenSSL::Cipher) KEY_CIPHER = OpenSSL::Cipher.new('AES-256-CBC') if defined?(OpenSSL::Cipher)
##
# One day in seconds
ONE_DAY = 86400
## ##
# One year in seconds # One year in seconds
ONE_YEAR = 86400 * 365 ONE_YEAR = ONE_DAY * 365
## ##
# The default set of extensions are: # The default set of extensions are:

View file

@ -0,0 +1,43 @@
# frozen_string_literal: true
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
# See LICENSE.txt for permissions.
#++
require 'rubygems'
# forward-declare
module Gem::Security # :nodoc:
class Policy # :nodoc:
end
end
##
# Mixin methods for security option for Gem::Commands
module Gem::SecurityOption
def add_security_option
# TODO: use @parser.accept
OptionParser.accept Gem::Security::Policy do |value|
require 'rubygems/security'
raise OptionParser::InvalidArgument, 'OpenSSL not installed' unless
defined?(Gem::Security::HighSecurity)
policy = Gem::Security::Policies[value]
unless policy
valid = Gem::Security::Policies.keys.sort
raise OptionParser::InvalidArgument, "#{value} (#{valid.join ', '} are valid)"
end
policy
end
add_option(:"Install/Update", '-P', '--trust-policy POLICY',
Gem::Security::Policy,
'Specify gem trust policy') do |value, options|
options[:security_policy] = value
end
end
end

View file

@ -573,19 +573,11 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
add_date res add_date res
case req.request_uri.path case req.request_uri.path
when %r|^/quick/(Marshal.#{Regexp.escape Gem.marshal_version}/)?(.*?)-([0-9.]+[^-]*?)(-.*?)?\.gemspec\.rz$| then when %r|^/quick/(Marshal.#{Regexp.escape Gem.marshal_version}/)?(.*?)\.gemspec\.rz$| then
marshal_format, name, version, platform = $1, $2, $3, $4 marshal_format, full_name = $1, $2
specs = Gem::Specification.find_all_by_name name, version specs = Gem::Specification.find_all_by_full_name(full_name)
selector = [name, version, platform].map(&:inspect).join ' ' selector = full_name.inspect
platform = if platform then
Gem::Platform.new platform.sub(/^-/, '')
else
Gem::Platform::RUBY
end
specs = specs.select { |s| s.platform == platform }
if specs.empty? then if specs.empty? then
res.status = 404 res.status = 404

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'uri' autoload :FileUtils, 'fileutils'
require 'fileutils' autoload :URI, 'uri'
## ##
# A Source knows how to list and fetch gems from a RubyGems marshal index. # A Source knows how to list and fetch gems from a RubyGems marshal index.
@ -67,7 +67,11 @@ class Gem::Source
return -1 if !other.uri return -1 if !other.uri
@uri.to_s <=> other.uri.to_s # Returning 1 here ensures that when sorting a list of sources, the
# original ordering of sources supplied by the user is preserved.
return 1 unless @uri.to_s == other.uri.to_s
0
else else
nil nil
end end
@ -232,4 +236,3 @@ require 'rubygems/source/specific_file'
require 'rubygems/source/local' require 'rubygems/source/local'
require 'rubygems/source/lock' require 'rubygems/source/lock'
require 'rubygems/source/vendor' require 'rubygems/source/vendor'

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'digest'
require 'rubygems/util' require 'rubygems/util'
## ##
@ -226,6 +225,8 @@ class Gem::Source::Git < Gem::Source
# A hash for the git gem based on the git repository URI. # A hash for the git gem based on the git repository URI.
def uri_hash # :nodoc: def uri_hash # :nodoc:
require 'digest' # required here to avoid deadlocking in Gem.activate_bin_path (because digest is a gem on 2.5+)
normalized = normalized =
if @repository =~ %r%^\w+://(\w+@)?% then if @repository =~ %r%^\w+://(\w+@)?% then
uri = URI(@repository).normalize.to_s.sub %r%/$%,'' uri = URI(@repository).normalize.to_s.sub %r%/$%,''

View file

@ -9,6 +9,7 @@ class Gem::Source::Local < Gem::Source
@specs = nil @specs = nil
@api_uri = nil @api_uri = nil
@uri = nil @uri = nil
@load_specs_names = {}
end end
## ##
@ -34,45 +35,47 @@ class Gem::Source::Local < Gem::Source
end end
def load_specs type # :nodoc: def load_specs type # :nodoc:
names = [] @load_specs_names[type] ||= begin
names = []
@specs = {} @specs = {}
Dir["*.gem"].each do |file| Dir["*.gem"].each do |file|
begin begin
pkg = Gem::Package.new(file) pkg = Gem::Package.new(file)
rescue SystemCallError, Gem::Package::FormatError rescue SystemCallError, Gem::Package::FormatError
# ignore # ignore
else
tup = pkg.spec.name_tuple
@specs[tup] = [File.expand_path(file), pkg]
case type
when :released
unless pkg.spec.version.prerelease?
names << pkg.spec.name_tuple
end
when :prerelease
if pkg.spec.version.prerelease?
names << pkg.spec.name_tuple
end
when :latest
tup = pkg.spec.name_tuple
cur = names.find { |x| x.name == tup.name }
if !cur
names << tup
elsif cur.version < tup.version
names.delete cur
names << tup
end
else else
names << pkg.spec.name_tuple tup = pkg.spec.name_tuple
@specs[tup] = [File.expand_path(file), pkg]
case type
when :released
unless pkg.spec.version.prerelease?
names << pkg.spec.name_tuple
end
when :prerelease
if pkg.spec.version.prerelease?
names << pkg.spec.name_tuple
end
when :latest
tup = pkg.spec.name_tuple
cur = names.find { |x| x.name == tup.name }
if !cur
names << tup
elsif cur.version < tup.version
names.delete cur
names << tup
end
else
names << pkg.spec.name_tuple
end
end end
end end
end
names names
end
end end
def find_gem gem_name, version = Gem::Requirement.default, # :nodoc: def find_gem gem_name, version = Gem::Requirement.default, # :nodoc:
@ -88,7 +91,7 @@ class Gem::Source::Local < Gem::Source
if version.satisfied_by?(s.version) if version.satisfied_by?(s.version)
if prerelease if prerelease
found << s found << s
elsif !s.version.prerelease? elsif !s.version.prerelease? || version.prerelease?
found << s found << s
end end
end end

View file

@ -34,6 +34,10 @@ class Gem::Source::Lock < Gem::Source
0 == (self <=> other) 0 == (self <=> other)
end end
def hash # :nodoc:
@wrapped.hash ^ 3
end
## ##
# Delegates to the wrapped source's fetch_spec method. # Delegates to the wrapped source's fetch_spec method.
@ -46,4 +50,3 @@ class Gem::Source::Lock < Gem::Source
end end
end end

View file

@ -2,5 +2,7 @@
require 'rubygems/source' require 'rubygems/source'
require 'rubygems/source_local' require 'rubygems/source_local'
# TODO warn upon require, this file is deprecated. unless Gem::Deprecate.skip
Kernel.warn "#{Gem.location_of_caller(3).join(':')}: Warning: Requiring rubygems/source_local is deprecated; please use rubygems/source/local instead."
end

View file

@ -1,5 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'rubygems/source/specific_file' require 'rubygems/source/specific_file'
# TODO warn upon require, this file is deprecated. unless Gem::Deprecate.skip
Kernel.warn "#{Gem.location_of_caller(3).join(':')}: Warning: Requiring rubygems/source_specific_file is deprecated; please use rubygems/source/specific_file instead."
end

View file

@ -184,10 +184,10 @@ class Gem::SpecFetcher
# Suggests gems based on the supplied +gem_name+. Returns an array of # Suggests gems based on the supplied +gem_name+. Returns an array of
# alternative gem names. # alternative gem names.
def suggest_gems_from_name gem_name def suggest_gems_from_name(gem_name, type = :latest)
gem_name = gem_name.downcase.tr('_-', '') gem_name = gem_name.downcase.tr('_-', '')
max = gem_name.size / 2 max = gem_name.size / 2
names = available_specs(:latest).first.values.flatten(1) names = available_specs(type).first.values.flatten(1)
matches = names.map { |n| matches = names.map { |n|
next unless n.match_platform? next unless n.match_platform?
@ -201,7 +201,11 @@ class Gem::SpecFetcher
[n.name, distance] [n.name, distance]
}.compact }.compact
matches = matches.uniq.sort_by { |name, dist| dist } matches = if matches.empty? && type != :prerelease
suggest_gems_from_name gem_name, :prerelease
else
matches.uniq.sort_by { |name, dist| dist }
end
matches.first(5).map { |name, dist| name } matches.first(5).map { |name, dist| name }
end end

View file

@ -30,6 +30,7 @@ require 'stringio'
# s.email = 'rubycoder@example.com' # s.email = 'rubycoder@example.com'
# s.files = ["lib/example.rb"] # s.files = ["lib/example.rb"]
# s.homepage = 'https://rubygems.org/gems/example' # s.homepage = 'https://rubygems.org/gems/example'
# s.metadata = { "source_code_uri" => "https://github.com/example/example" }
# end # end
# #
# Starting in RubyGems 2.0, a Specification can hold arbitrary # Starting in RubyGems 2.0, a Specification can hold arbitrary
@ -157,16 +158,20 @@ class Gem::Specification < Gem::BasicSpecification
:summary => nil, :summary => nil,
:test_files => [], :test_files => [],
:version => nil, :version => nil,
} }.freeze
Dupable = { } # :nodoc: INITIALIZE_CODE_FOR_DEFAULTS = { } # :nodoc:
@@default_value.each do |k,v| @@default_value.each do |k,v|
case v INITIALIZE_CODE_FOR_DEFAULTS[k] = case v
when Time, Numeric, Symbol, true, false, nil when [], {}, true, false, nil, Numeric, Symbol
Dupable[k] = false v.inspect
when String
v.dump
when Numeric
"default_value(:#{k})"
else else
Dupable[k] = true "default_value(:#{k}).dup"
end end
end end
@ -208,34 +213,6 @@ class Gem::Specification < Gem::BasicSpecification
attr_reader :version attr_reader :version
##
# Paths in the gem to add to <code>$LOAD_PATH</code> when this gem is
# activated.
#--
# See also #require_paths
#++
# If you have an extension you do not need to add <code>"ext"</code> to the
# require path, the extension build process will copy the extension files
# into "lib" for you.
#
# The default value is <code>"lib"</code>
#
# Usage:
#
# # If all library files are in the root directory...
# spec.require_paths = ['.']
def require_paths=(val)
@require_paths = Array(val)
end
##
# The version of RubyGems used to create this gem.
#
# Do not set this, it is set automatically when the gem is packaged.
attr_accessor :rubygems_version
## ##
# A short summary of this gem's description. Displayed in `gem list -d`. # A short summary of this gem's description. Displayed in `gem list -d`.
# #
@ -247,6 +224,42 @@ class Gem::Specification < Gem::BasicSpecification
attr_reader :summary attr_reader :summary
##
# Files included in this gem. You cannot append to this accessor, you must
# assign to it.
#
# Only add files you can require to this list, not directories, etc.
#
# Directories are automatically stripped from this list when building a gem,
# other non-files cause an error.
#
# Usage:
#
# require 'rake'
# spec.files = FileList['lib/**/*.rb',
# 'bin/*',
# '[A-Z]*',
# 'test/**/*'].to_a
#
# # or without Rake...
# spec.files = Dir['lib/**/*.rb'] + Dir['bin/*']
# spec.files += Dir['[A-Z]*'] + Dir['test/**/*']
# spec.files.reject! { |fn| fn.include? "CVS" }
def files
# DO NOT CHANGE TO ||= ! This is not a normal accessor. (yes, it sucks)
# DOC: Why isn't it normal? Why does it suck? How can we fix this?
@files = [@files,
@test_files,
add_bindir(@executables),
@extra_rdoc_files,
@extensions,
].flatten.compact.uniq.sort
end
######################################################################
# :section: Recommended gemspec attributes
## ##
# Singular writer for #authors # Singular writer for #authors
# #
@ -269,6 +282,148 @@ class Gem::Specification < Gem::BasicSpecification
@authors = Array(value).flatten.grep(String) @authors = Array(value).flatten.grep(String)
end end
##
# A long description of this gem
#
# The description should be more detailed than the summary but not
# excessively long. A few paragraphs is a recommended length with no
# examples or formatting.
#
# Usage:
#
# spec.description = <<-EOF
# Rake is a Make-like program implemented in Ruby. Tasks and
# dependencies are specified in standard Ruby syntax.
# EOF
attr_reader :description
##
# A contact email address (or addresses) for this gem
#
# Usage:
#
# spec.email = 'john.jones@example.com'
# spec.email = ['jack@example.com', 'jill@example.com']
attr_accessor :email
##
# The URL of this gem's home page
#
# Usage:
#
# spec.homepage = 'https://github.com/ruby/rake'
attr_accessor :homepage
##
# The license for this gem.
#
# The license must be no more than 64 characters.
#
# This should just be the name of your license. The full text of the license
# should be inside of the gem (at the top level) when you build it.
#
# The simplest way, is to specify the standard SPDX ID
# https://spdx.org/licenses/ for the license.
# Ideally you should pick one that is OSI (Open Source Initiative)
# http://opensource.org/licenses/alphabetical approved.
#
# The most commonly used OSI approved licenses are MIT and Apache-2.0.
# GitHub also provides a license picker at http://choosealicense.com/.
#
# You should specify a license for your gem so that people know how they are
# permitted to use it, and any restrictions you're placing on it. Not
# specifying a license means all rights are reserved; others have no rights
# to use the code for any purpose.
#
# You can set multiple licenses with #licenses=
#
# Usage:
# spec.license = 'MIT'
def license=o
self.licenses = [o]
end
##
# The license(s) for the library.
#
# Each license must be a short name, no more than 64 characters.
#
# This should just be the name of your license. The full
# text of the license should be inside of the gem when you build it.
#
# See #license= for more discussion
#
# Usage:
# spec.licenses = ['MIT', 'GPL-2.0']
def licenses= licenses
@licenses = Array licenses
end
##
# The metadata holds extra data for this gem that may be useful to other
# consumers and is settable by gem authors without requiring an update to
# the rubygems software.
#
# Metadata items have the following restrictions:
#
# * The metadata must be a Hash object
# * All keys and values must be Strings
# * Keys can be a maximum of 128 bytes and values can be a maximum of 1024
# bytes
# * All strings must be UTF-8, no binary data is allowed
#
# You can use metadata to specify links to your gem's homepage, codebase,
# documentation, wiki, mailing list, issue tracker and changelog.
#
# s.metadata = {
# "bug_tracker_uri" => "https://example.com/user/bestgemever/issues",
# "changelog_uri" => "https://example.com/user/bestgemever/CHANGELOG.md",
# "documentation_uri" => "https://www.example.info/gems/bestgemever/0.0.1",
# "homepage_uri" => "https://bestgemever.example.io",
# "mailing_list_uri" => "https://groups.example.com/bestgemever",
# "source_code_uri" => "https://example.com/user/bestgemever",
# "wiki_uri" => "https://example.com/user/bestgemever/wiki"
# }
#
# These links will be used on your gem's page on rubygems.org and must pass
# validation against following regex.
#
# %r{\Ahttps?:\/\/([^\s:@]+:[^\s:@]*@)?[A-Za-z\d\-]+(\.[A-Za-z\d\-]+)+\.?(:\d{1,5})?([\/?]\S*)?\z}
attr_accessor :metadata
######################################################################
# :section: Optional gemspec attributes
##
# The path in the gem for executable scripts. Usually 'bin'
#
# Usage:
#
# spec.bindir = 'bin'
attr_accessor :bindir
##
# The certificate chain used to sign this gem. See Gem::Security for
# details.
attr_accessor :cert_chain
##
# A message that gets displayed after the gem is installed.
#
# Usage:
#
# spec.post_install_message = "Thanks for installing!"
attr_accessor :post_install_message
## ##
# The platform this gem runs on. # The platform this gem runs on.
# #
@ -327,104 +482,26 @@ class Gem::Specification < Gem::BasicSpecification
end end
## ##
# Files included in this gem. You cannot append to this accessor, you must # Paths in the gem to add to <code>$LOAD_PATH</code> when this gem is
# assign to it. # activated.
#--
# See also #require_paths
#++
# If you have an extension you do not need to add <code>"ext"</code> to the
# require path, the extension build process will copy the extension files
# into "lib" for you.
# #
# Only add files you can require to this list, not directories, etc. # The default value is <code>"lib"</code>
#
# Directories are automatically stripped from this list when building a gem,
# other non-files cause an error.
# #
# Usage: # Usage:
# #
# require 'rake' # # If all library files are in the root directory...
# spec.files = FileList['lib/**/*.rb', # spec.require_paths = ['.']
# 'bin/*',
# '[A-Z]*',
# 'test/**/*'].to_a
#
# # or without Rake...
# spec.files = Dir['lib/**/*.rb'] + Dir['bin/*']
# spec.files += Dir['[A-Z]*'] + Dir['test/**/*']
# spec.files.reject! { |fn| fn.include? "CVS" }
def files def require_paths=(val)
# DO NOT CHANGE TO ||= ! This is not a normal accessor. (yes, it sucks) @require_paths = Array(val)
# DOC: Why isn't it normal? Why does it suck? How can we fix this?
@files = [@files,
@test_files,
add_bindir(@executables),
@extra_rdoc_files,
@extensions,
].flatten.compact.uniq.sort
end end
######################################################################
# :section: Optional gemspec attributes
##
# The path in the gem for executable scripts. Usually 'bin'
#
# Usage:
#
# spec.bindir = 'bin'
attr_accessor :bindir
##
# The certificate chain used to sign this gem. See Gem::Security for
# details.
attr_accessor :cert_chain
##
# A long description of this gem
#
# The description should be more detailed than the summary but not
# excessively long. A few paragraphs is a recommended length with no
# examples or formatting.
#
# Usage:
#
# spec.description = <<-EOF
# Rake is a Make-like program implemented in Ruby. Tasks and
# dependencies are specified in standard Ruby syntax.
# EOF
attr_reader :description
##
# :category: Recommended gemspec attributes
#
# A contact email address (or addresses) for this gem
#
# Usage:
#
# spec.email = 'john.jones@example.com'
# spec.email = ['jack@example.com', 'jill@example.com']
attr_accessor :email
##
# :category: Recommended gemspec attributes
#
# The URL of this gem's home page
#
# Usage:
#
# spec.homepage = 'https://github.com/ruby/rake'
attr_accessor :homepage
##
# A message that gets displayed after the gem is installed.
#
# Usage:
#
# spec.post_install_message = "Thanks for installing!"
attr_accessor :post_install_message
## ##
# The version of Ruby required by this gem # The version of Ruby required by this gem
@ -435,32 +512,18 @@ class Gem::Specification < Gem::BasicSpecification
attr_reader :required_rubygems_version attr_reader :required_rubygems_version
##
# The version of RubyGems used to create this gem.
#
# Do not set this, it is set automatically when the gem is packaged.
attr_accessor :rubygems_version
## ##
# The key used to sign this gem. See Gem::Security for details. # The key used to sign this gem. See Gem::Security for details.
attr_accessor :signing_key attr_accessor :signing_key
##
# :attr_accessor: metadata
#
# The metadata holds extra data for this gem that may be useful to other
# consumers and is settable by gem authors without requiring an update to
# the rubygems software.
#
# Metadata items have the following restrictions:
#
# * The metadata must be a Hash object
# * All keys and values must be Strings
# * Keys can be a maximum of 128 bytes and values can be a maximum of 1024
# bytes
# * All strings must be UTF-8, no binary data is allowed
#
# To add metadata for the location of a issue tracker:
#
# s.metadata = { "issue_tracker" => "https://example/issues" }
attr_accessor :metadata
## ##
# Adds a development dependency named +gem+ with +requirements+ to this # Adds a development dependency named +gem+ with +requirements+ to this
# gem. # gem.
@ -473,7 +536,7 @@ class Gem::Specification < Gem::BasicSpecification
# activated when a gem is required. # activated when a gem is required.
def add_development_dependency(gem, *requirements) def add_development_dependency(gem, *requirements)
add_dependency_with_type(gem, :development, *requirements) add_dependency_with_type(gem, :development, requirements)
end end
## ##
@ -484,7 +547,7 @@ class Gem::Specification < Gem::BasicSpecification
# spec.add_runtime_dependency 'example', '~> 1.1', '>= 1.1.4' # spec.add_runtime_dependency 'example', '~> 1.1', '>= 1.1.4'
def add_runtime_dependency(gem, *requirements) def add_runtime_dependency(gem, *requirements)
add_dependency_with_type(gem, :runtime, *requirements) add_dependency_with_type(gem, :runtime, requirements)
end end
## ##
@ -556,56 +619,6 @@ class Gem::Specification < Gem::BasicSpecification
@installed_by_version = Gem::Version.new version @installed_by_version = Gem::Version.new version
end end
##
# :category: Recommended gemspec attributes
#
# The license for this gem.
#
# The license must be no more than 64 characters.
#
# This should just be the name of your license. The full text of the license
# should be inside of the gem (at the top level) when you build it.
#
# The simplest way, is to specify the standard SPDX ID
# https://spdx.org/licenses/ for the license.
# Ideally you should pick one that is OSI (Open Source Initiative)
# http://opensource.org/licenses/alphabetical approved.
#
# The most commonly used OSI approved licenses are MIT and Apache-2.0.
# GitHub also provides a license picker at http://choosealicense.com/.
#
# You should specify a license for your gem so that people know how they are
# permitted to use it, and any restrictions you're placing on it. Not
# specifying a license means all rights are reserved; others have no rights
# to use the code for any purpose.
#
# You can set multiple licenses with #licenses=
#
# Usage:
# spec.license = 'MIT'
def license=o
self.licenses = [o]
end
##
# :category: Recommended gemspec attributes
# The license(s) for the library.
#
# Each license must be a short name, no more than 64 characters.
#
# This should just be the name of your license. The full
# text of the license should be inside of the gem when you build it.
#
# See #license= for more discussion
#
# Usage:
# spec.licenses = ['MIT', 'GPL-2.0']
def licenses= licenses
@licenses = Array licenses
end
## ##
# Specifies the rdoc options to be used when generating API documentation. # Specifies the rdoc options to be used when generating API documentation.
# #
@ -885,7 +898,7 @@ class Gem::Specification < Gem::BasicSpecification
# properly sorted. # properly sorted.
def self.add_spec spec def self.add_spec spec
warn "Gem::Specification.add_spec is deprecated and will be removed in Rubygems 3.0" unless Gem::Deprecate.skip warn "Gem::Specification.add_spec is deprecated and will be removed in RubyGems 3.0" unless Gem::Deprecate.skip
# TODO: find all extraneous adds # TODO: find all extraneous adds
# puts # puts
# p :add_spec => [spec.full_name, caller.reject { |s| s =~ /minitest/ }] # p :add_spec => [spec.full_name, caller.reject { |s| s =~ /minitest/ }]
@ -910,7 +923,7 @@ class Gem::Specification < Gem::BasicSpecification
# Adds multiple specs to the known specifications. # Adds multiple specs to the known specifications.
def self.add_specs *specs def self.add_specs *specs
warn "Gem::Specification.add_specs is deprecated and will be removed in Rubygems 3.0" unless Gem::Deprecate.skip 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 raise "nil spec!" if specs.any?(&:nil?) # TODO: remove once we're happy
@ -1022,6 +1035,13 @@ class Gem::Specification < Gem::BasicSpecification
Gem::Dependency.new(name, *requirements).matching_specs Gem::Dependency.new(name, *requirements).matching_specs
end end
##
# Returns every spec that has the given +full_name+
def self.find_all_by_full_name(full_name)
stubs.select {|s| s.full_name == full_name }.map(&:to_spec)
end
## ##
# Find the best specification matching a +name+ and +requirements+. Raises # Find the best specification matching a +name+ and +requirements+. Raises
# if the dependency doesn't resolve to a valid specification. # if the dependency doesn't resolve to a valid specification.
@ -1040,6 +1060,7 @@ class Gem::Specification < Gem::BasicSpecification
def self.find_by_path path def self.find_by_path path
path = path.dup.freeze path = path.dup.freeze
spec = @@spec_with_requirable_file[path] ||= (stubs.find { |s| spec = @@spec_with_requirable_file[path] ||= (stubs.find { |s|
next unless Gem::BundlerVersionFinder.compatible?(s)
s.contains_requirable_file? path s.contains_requirable_file? path
} || NOT_FOUND) } || NOT_FOUND)
spec.to_spec spec.to_spec
@ -1051,7 +1072,9 @@ class Gem::Specification < Gem::BasicSpecification
def self.find_inactive_by_path path def self.find_inactive_by_path path
stub = stubs.find { |s| stub = stubs.find { |s|
s.contains_requirable_file? path unless s.activated? next if s.activated?
next unless Gem::BundlerVersionFinder.compatible?(s)
s.contains_requirable_file? path
} }
stub && stub.to_spec stub && stub.to_spec
end end
@ -1250,7 +1273,7 @@ class Gem::Specification < Gem::BasicSpecification
# Removes +spec+ from the known specs. # Removes +spec+ from the known specs.
def self.remove_spec spec def self.remove_spec spec
warn "Gem::Specification.remove_spec is deprecated and will be removed in Rubygems 3.0" unless Gem::Deprecate.skip warn "Gem::Specification.remove_spec is deprecated and will be removed in RubyGems 3.0" unless Gem::Deprecate.skip
_all.delete spec _all.delete spec
stubs.delete_if { |s| s.full_name == spec.full_name } stubs.delete_if { |s| s.full_name == spec.full_name }
(@@stubs_by_name[spec.name] || []).delete_if { |s| s.full_name == spec.full_name } (@@stubs_by_name[spec.name] || []).delete_if { |s| s.full_name == spec.full_name }
@ -1520,7 +1543,7 @@ class Gem::Specification < Gem::BasicSpecification
# +requirements+. Valid types are currently <tt>:runtime</tt> and # +requirements+. Valid types are currently <tt>:runtime</tt> and
# <tt>:development</tt>. # <tt>:development</tt>.
def add_dependency_with_type(dependency, type, *requirements) def add_dependency_with_type(dependency, type, requirements)
requirements = if requirements.empty? then requirements = if requirements.empty? then
Gem::Requirement.default Gem::Requirement.default
else else
@ -2026,6 +2049,20 @@ class Gem::Specification < Gem::BasicSpecification
yaml_initialize coder.tag, coder.map yaml_initialize coder.tag, coder.map
end end
eval <<-RB, binding, __FILE__, __LINE__ + 1
def set_nil_attributes_to_nil
#{@@nil_attributes.map {|key| "@#{key} = nil" }.join "; "}
end
private :set_nil_attributes_to_nil
def set_not_nil_attributes_to_default_values
#{@@non_nil_attributes.map {|key| "@#{key} = #{INITIALIZE_CODE_FOR_DEFAULTS[key]}" }.join ";"}
end
private :set_not_nil_attributes_to_default_values
RB
## ##
# Specification constructor. Assigns the default values to the attributes # Specification constructor. Assigns the default values to the attributes
# and yields itself for further initialization. Optionally takes +name+ and # and yields itself for further initialization. Optionally takes +name+ and
@ -2041,15 +2078,8 @@ class Gem::Specification < Gem::BasicSpecification
@original_platform = nil @original_platform = nil
@installed_by_version = nil @installed_by_version = nil
@@nil_attributes.each do |key| set_nil_attributes_to_nil
instance_variable_set "@#{key}", nil set_not_nil_attributes_to_default_values
end
@@non_nil_attributes.each do |key|
default = default_value(key)
value = Dupable[key] ? default.dup : default
instance_variable_set "@#{key}", value
end
@new_platform = Gem::Platform::RUBY @new_platform = Gem::Platform::RUBY
@ -2746,29 +2776,7 @@ class Gem::Specification < Gem::BasicSpecification
'metadata must be a hash' 'metadata must be a hash'
end end
metadata.keys.each do |k| validate_metadata
if !k.kind_of?(String)
raise Gem::InvalidSpecificationException,
'metadata keys must be a String'
end
if k.size > 128
raise Gem::InvalidSpecificationException,
"metadata key too large (#{k.size} > 128)"
end
end
metadata.values.each do |k|
if !k.kind_of?(String)
raise Gem::InvalidSpecificationException,
'metadata values must be a String'
end
if k.size > 1024
raise Gem::InvalidSpecificationException,
"metadata value too large (#{k.size} > 1024)"
end
end
licenses.each { |license| licenses.each { |license|
if license.length > 64 if license.length > 64
@ -2822,7 +2830,7 @@ http://spdx.org/licenses or '#{Gem::Licenses::NONSTANDARD}' for a nonstandard li
# Warnings # Warnings
%w[author email homepage summary].each do |attribute| %w[author homepage summary files].each do |attribute|
value = self.send attribute value = self.send attribute
warning "no #{attribute} specified" if value.nil? or value.empty? warning "no #{attribute} specified" if value.nil? or value.empty?
end end
@ -2855,6 +2863,48 @@ http://spdx.org/licenses or '#{Gem::Licenses::NONSTANDARD}' for a nonstandard li
end end
end end
def validate_metadata
url_validation_regex = %r{\Ahttps?:\/\/([^\s:@]+:[^\s:@]*@)?[A-Za-z\d\-]+(\.[A-Za-z\d\-]+)+\.?(:\d{1,5})?([\/?]\S*)?\z}
link_keys = %w(
bug_tracker_uri
changelog_uri
documentation_uri
homepage_uri
mailing_list_uri
source_code_uri
wiki_uri
)
metadata.each do|key, value|
if !key.kind_of?(String)
raise Gem::InvalidSpecificationException,
"metadata keys must be a String"
end
if key.size > 128
raise Gem::InvalidSpecificationException,
"metadata key too large (#{key.size} > 128)"
end
if !value.kind_of?(String)
raise Gem::InvalidSpecificationException,
"metadata values must be a String"
end
if value.size > 1024
raise Gem::InvalidSpecificationException,
"metadata value too large (#{value.size} > 1024)"
end
if link_keys.include? key
if value !~ url_validation_regex
raise Gem::InvalidSpecificationException,
"metadata['#{key}'] has invalid link: #{value.inspect}"
end
end
end
end
## ##
# Checks that dependencies use requirements as we recommend. Warnings are # Checks that dependencies use requirements as we recommend. Warnings are
# issued when dependencies are open-ended or overly strict for semantic # issued when dependencies are open-ended or overly strict for semantic

View file

@ -188,9 +188,8 @@ class Gem::StubSpecification < Gem::BasicSpecification
def to_spec def to_spec
@spec ||= if @data then @spec ||= if @data then
Gem.loaded_specs.values.find { |spec| loaded = Gem.loaded_specs[name]
spec.name == name and spec.version == version loaded if loaded && loaded.version == version
}
end end
@spec ||= Gem::Specification.load(loaded_from) @spec ||= Gem::Specification.load(loaded_from)

View file

@ -25,6 +25,7 @@ unless Gem::Dependency.new('rdoc', '>= 3.10').matching_specs.empty?
gem 'json' gem 'json'
end end
require 'bundler'
require 'minitest/autorun' require 'minitest/autorun'
require 'rubygems/deprecate' require 'rubygems/deprecate'
@ -222,6 +223,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase
@orig_gem_vendor = ENV['GEM_VENDOR'] @orig_gem_vendor = ENV['GEM_VENDOR']
@orig_gem_spec_cache = ENV['GEM_SPEC_CACHE'] @orig_gem_spec_cache = ENV['GEM_SPEC_CACHE']
@orig_rubygems_gemdeps = ENV['RUBYGEMS_GEMDEPS'] @orig_rubygems_gemdeps = ENV['RUBYGEMS_GEMDEPS']
@orig_bundle_gemfile = ENV['BUNDLE_GEMFILE']
@orig_rubygems_host = ENV['RUBYGEMS_HOST'] @orig_rubygems_host = ENV['RUBYGEMS_HOST']
ENV.keys.find_all { |k| k.start_with?('GEM_REQUIREMENT_') }.each do |k| ENV.keys.find_all { |k| k.start_with?('GEM_REQUIREMENT_') }.each do |k|
ENV.delete k ENV.delete k
@ -232,7 +234,12 @@ class Gem::TestCase < MiniTest::Unit::TestCase
@current_dir = Dir.pwd @current_dir = Dir.pwd
@fetcher = nil @fetcher = nil
@ui = Gem::MockGemUi.new
Bundler.ui = Bundler::UI::Silent.new
@ui = Gem::MockGemUi.new
# This needs to be a new instance since we call use_ui(@ui) when we want to
# capture output
Gem::DefaultUserInteraction.ui = Gem::MockGemUi.new
tmpdir = File.expand_path Dir.tmpdir tmpdir = File.expand_path Dir.tmpdir
tmpdir.untaint tmpdir.untaint
@ -323,6 +330,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase
Gem.loaded_specs.clear Gem.loaded_specs.clear
Gem.clear_default_specs Gem.clear_default_specs
Gem::Specification.unresolved_deps.clear Gem::Specification.unresolved_deps.clear
Bundler.reset!
Gem.configuration.verbose = true Gem.configuration.verbose = true
Gem.configuration.update_sources = true Gem.configuration.update_sources = true
@ -394,6 +402,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase
ENV['GEM_VENDOR'] = @orig_gem_vendor ENV['GEM_VENDOR'] = @orig_gem_vendor
ENV['GEM_SPEC_CACHE'] = @orig_gem_spec_cache ENV['GEM_SPEC_CACHE'] = @orig_gem_spec_cache
ENV['RUBYGEMS_GEMDEPS'] = @orig_rubygems_gemdeps ENV['RUBYGEMS_GEMDEPS'] = @orig_rubygems_gemdeps
ENV['BUNDLE_GEMFILE'] = @orig_bundle_gemfile
ENV['RUBYGEMS_HOST'] = @orig_rubygems_host ENV['RUBYGEMS_HOST'] = @orig_rubygems_host
Gem.ruby = @orig_ruby if @orig_ruby Gem.ruby = @orig_ruby if @orig_ruby

View file

@ -7,11 +7,6 @@
require 'rubygems/util' require 'rubygems/util'
begin
require 'io/console'
rescue LoadError
end
## ##
# Module that defines the default UserInteraction. Any class including this # Module that defines the default UserInteraction. Any class including this
# module will have access to the +ui+ method that returns the default UI. # module will have access to the +ui+ method that returns the default UI.
@ -314,12 +309,21 @@ class Gem::StreamUI
password password
end end
if IO.method_defined?(:noecho) then def require_io_console
def _gets_noecho @require_io_console ||= begin
@ins.noecho {@ins.gets} begin
require 'io/console'
rescue LoadError
end
true
end end
elsif Gem.win_platform? end
def _gets_noecho
def _gets_noecho
require_io_console
if IO.method_defined?(:noecho) then
@ins.noecho {@ins.gets}
elsif Gem.win_platform?
require "Win32API" require "Win32API"
password = '' password = ''
@ -332,9 +336,7 @@ class Gem::StreamUI
end end
end end
password password
end else
else
def _gets_noecho
system "stty -echo" system "stty -echo"
begin begin
@ins.gets @ins.gets

View file

@ -109,26 +109,15 @@ module Gem::Util
## ##
# Enumerates the parents of +directory+. # Enumerates the parents of +directory+.
def self.traverse_parents directory def self.traverse_parents directory, &block
return enum_for __method__, directory unless block_given? return enum_for __method__, directory unless block_given?
here = File.expand_path directory here = File.expand_path directory
start = here loop do
Dir.chdir here, &block
Dir.chdir start new_here = File.expand_path('..', here)
return if new_here == here # toplevel
begin here = new_here
loop do
yield here
Dir.chdir '..'
return if Dir.pwd == here # toplevel
here = Dir.pwd
end
ensure
Dir.chdir start
end end
end end

View file

@ -170,7 +170,7 @@ class Gem::Version
# True if the +version+ string matches RubyGems' requirements. # True if the +version+ string matches RubyGems' requirements.
def self.correct? version def self.correct? version
version.to_s =~ ANCHORED_VERSION_PATTERN !!(version.to_s =~ ANCHORED_VERSION_PATTERN)
end end
## ##
@ -241,7 +241,7 @@ class Gem::Version
end end
def hash # :nodoc: def hash # :nodoc:
@version.hash canonical_segments.hash
end end
def init_with coder # :nodoc: def init_with coder # :nodoc:
@ -335,7 +335,7 @@ class Gem::Version
def <=> other def <=> other
return unless Gem::Version === other return unless Gem::Version === other
return 0 if @version == other._version return 0 if @version == other._version || canonical_segments == other.canonical_segments
lhsegments = _segments lhsegments = _segments
rhsegments = other._segments rhsegments = other._segments
@ -360,6 +360,13 @@ class Gem::Version
return 0 return 0
end end
def canonical_segments
@canonical_segments ||=
_split_segments.map! do |segments|
segments.reverse_each.drop_while {|s| s == 0 }.reverse
end.reduce(&:concat)
end
protected protected
def _version def _version
@ -375,4 +382,11 @@ class Gem::Version
/^\d+$/ =~ s ? s.to_i : s /^\d+$/ =~ s ? s.to_i : s
end.freeze end.freeze
end end
def _split_segments
string_start = _segments.index {|s| s.is_a?(String) }
string_segments = segments
numeric_segments = string_segments.slice!(0, string_start || string_segments.size)
return numeric_segments, string_segments
end
end end

View file

@ -58,7 +58,12 @@ module Gem::VersionOption
add_option('-v', '--version VERSION', Gem::Requirement, add_option('-v', '--version VERSION', Gem::Requirement,
"Specify version of gem to #{task}", *wrap) do "Specify version of gem to #{task}", *wrap) do
|value, options| |value, options|
options[:version] = value # Allow handling for multiple --version operators
if options[:version] && !options[:version].none?
options[:version].concat([value])
else
options[:version] = value
end
explicit_prerelease_set = !options[:explicit_prerelease].nil? explicit_prerelease_set = !options[:explicit_prerelease].nil?
options[:explicit_prerelease] = false unless explicit_prerelease_set options[:explicit_prerelease] = false unless explicit_prerelease_set

View file

@ -0,0 +1,40 @@
-----BEGIN PRIVATE KEY-----
MIIG/gIBADANBgkqhkiG9w0BAQEFAASCBugwggbkAgEAAoIBgQDIl6Ne1eCreYAe
j+Qkbygv06KqtcarwjNpSPJFq+G/R6xzGfbiuJDGePnlzqyAN6sti8r/tDD8orMS
l3EUSQTvFAVJKxbBDnklHUozdaX+giw+fi7onRJ3sQE2j7GhjahXZB0vmx20wU9v
sazZ0IU/x7k8X7WbVRCYig99UVn28zsq586LN5u/w7qXo50156bfmeDS8tt+TKSK
PkQQYuO+AulWDVdwHycKSzCE7SPWiZ/scFUirN4Stfw0bJZbr8VQ6QBAhHcHgd6B
tcZ1vBDC656zsWgpGWNTCU9mSBWV3UMk8mdwkO/jz8mXYSBfbyLESkhc8slf47zd
dqs1iZZOmVVlz/TXYc9N9d8DTl3OR/YYy04mdrysf4ijB6HV9U7NrRbjcKqKwTjW
xMWsFDdc1d5WCTsXzKjvB582LspGYxv9zgs0KkhSChGTA0qCqGdl0ZVx1Q0suW5O
7XlcEWAp9gSww0RW3E1zkrUARcB4mQgyC89kvE4y9RW4/KzZDcsCAwEAAQKCAYEA
uhQJBkGLgCZe1nsO3UmMUwmVPZ0QpmapgIKd1EnFScb4T3IHl3w1ORgiYa9eUDbU
AZVLg/co9kMLsTRxPqsZ+5pr6Nsi6YY+lVJdce0yRi2FU5eEdl63MfcuM+oKkt4x
CpihhnbzkKk+wlNlEE2iPm9NA5eZhXXcxlRUWCEuPqqV+ZA+BuFYBwVPw7mQbd/t
6kD50VZejQQWIvPt+fFyaOKUiDIqKaWMdr0XTkgZ1bunchMmttr7ywms4wjUVktv
LWMmI8wEMXfxR+xOtigwolSuFn+djWgh02KEc4gSQD3KGKshps5cMrLxxkwIoaC8
rDxKfdUtixBx6JzrN0Wmq7f/oLpvzxTXoQTu30BvpUOr9evZjE/3ZYXiGCxoSDEL
cvdZHvd+4r0TEkuxNBebq5106bJCBTuq6awwiwAodrsH5DCnqkkrv9tnkVi71NnV
UfnF/C4i5clpJK+Rx4bub9SiqJuyEfQBDlEHdCDwKVASk6B3gXD2mgkJu+EdShkp
AoHBAPx27s3iBN1gRGzD9GU0x2z7uMrgXzXh71kCvzzkfOli5fpIvCyoOR8CIfok
Ph8Kth4c+Bz4bmp6c859yxm5aBdQb3y34LDvCkqEeFCs9XX31QTMjJ1Y3R6Iyun5
nJzzZ5BtJbLFTHw9/p/pCUmJscUP8nQLwBMLIk4HzmrVXVLKJyaakK4LbsCChBc5
XwCqzWFKbMRZM3X8PaZp3DCo9iA5/TyzkQMTucLSYaxDDG+YNtYQPB8J5wkFWTD8
5//WZQKBwQDLZr9CnPR8HcrG46+rDzoZO1nXqaaEQMZhmm25lpL5oSHLrm4elGDp
vH5SRcCPz986InRszMROI3xvYpGtFsAzff3UVY0M8uDQcEKucHtd4wmFHefzYmKo
cvR9PuGmotk6yYpb+cMITT6sCzC4OHPz3DQAclmswRZchHYd2Zkv7tjgE0dXS9nw
XKaH5vQC4wjWBc857scHz0WYJLlj8s8UM9Fludz7kuagXczrsFIONxvrFKNJXeYl
muFCQl8hOG8CgcEA4ZZkTBNpxWX/vjBacRR4HinPNXjHmp4IAMEzoHWKKAD2/m1/
t2eZotuFAL7hw1sO4FmCWmCiSQKh+CDvGk1RdYOqGwcy/uaZi3xTBcOGkaKh9WfR
PcfpzR7uMaOZDaVxJNxikxs4/MtoefsBEXS4JB3bx1W4i0unm5HeIBgHC7MWyKfU
H7CXhe0Zmqbo/O+iFQ0ro0cRdJuvesOcvN49Dw7B+Tt6mAVIN41FOWev9QdN+HkJ
P7LZfnYI/Hz/0NsBAoHADm2+eZI6wac3YD58kqzk2S9doy/UsSMLL5dN21F0IaMt
i45XH3I1Ib+OUnXCQDFly3DwQ1uPPV/FDv22CcpIXh6859gdxmJgUkj0Yf12suVN
IpVJg/lhuENXVp8kULbSpBnx565jCG66WGf+z8Kpbw4a3kE+XUPhOzTmUB3EgSL3
XYXglK+7yRI5egCHJMFIOi51Uc2/bq1kaXOJdy6dQ/idDRNPOsVj+NJOnBWI7Js6
LsXrA2RW1CoVeqbMqsWfAoHAAabWXkQ74BuTo+P7lbfnFa6qLfTRnkWBkKKpWSAZ
ZBLfGsw2F5ZzrfwXtLriPcQJNA+3q3u1WPiGZkjV4QnFMt+Kgcg8ahW94vDEgfex
OSQyrlioT2m9DLJNXXHxo3+0ePNQkmoMQbNRUwdYjBuK7dqNDmFQ8Oo8SxtlV2sL
ntLc47NvFaxDlOvnj9ftQv6ZhdzXQmKGiuZWxtrrjFgHJm8KhMS8IF9xHM3d0uYb
sbykscVdmz3lOmUZrxCeIJvk
-----END PRIVATE KEY-----

View file

@ -0,0 +1,25 @@
-----BEGIN CERTIFICATE-----
MIIENDCCApygAwIBAgIBATANBgkqhkiG9w0BAQsFADAqMQ8wDQYDVQQDDAZub2Jv
ZHkxFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMCAXDTE2MDEwMTAwMDAwMFoYDzk5
OTkxMjMxMjM1OTU5WjAqMQ8wDQYDVQQDDAZub2JvZHkxFzAVBgoJkiaJk/IsZAEZ
FgdleGFtcGxlMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAyJejXtXg
q3mAHo/kJG8oL9OiqrXGq8IzaUjyRavhv0escxn24riQxnj55c6sgDerLYvK/7Qw
/KKzEpdxFEkE7xQFSSsWwQ55JR1KM3Wl/oIsPn4u6J0Sd7EBNo+xoY2oV2QdL5sd
tMFPb7Gs2dCFP8e5PF+1m1UQmIoPfVFZ9vM7KufOizebv8O6l6OdNeem35ng0vLb
fkykij5EEGLjvgLpVg1XcB8nCkswhO0j1omf7HBVIqzeErX8NGyWW6/FUOkAQIR3
B4HegbXGdbwQwuues7FoKRljUwlPZkgVld1DJPJncJDv48/Jl2EgX28ixEpIXPLJ
X+O83XarNYmWTplVZc/012HPTfXfA05dzkf2GMtOJna8rH+Ioweh1fVOza0W43Cq
isE41sTFrBQ3XNXeVgk7F8yo7wefNi7KRmMb/c4LNCpIUgoRkwNKgqhnZdGVcdUN
LLluTu15XBFgKfYEsMNEVtxNc5K1AEXAeJkIMgvPZLxOMvUVuPys2Q3LAgMBAAGj
YzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIEMB0GA1UdDgQWBBSf
hxDG5kMk4VhQNMcuLhULi3gMpTAfBgNVHSMEGDAWgBSfhxDG5kMk4VhQNMcuLhUL
i3gMpTANBgkqhkiG9w0BAQsFAAOCAYEAuvY1Nc8lkjCWEnVlAB0yfx85+xa/6zoQ
9w4cG/Nk+M2XNXRmp0c6FQgy7Y/aRxIobJnJfo2S1yJIPfzBuxb/oOy4ikYGmrYV
JUJFs4KaMPz8nM13YVI+KtskNEs0Pb8kcb0ZO640f0ptkgFDN/rvezu2uxqTlaD+
NSy+O+2Xr5T1Qq2eT2ui3mint26sA2g2cZqkqIdeEWHz/wf5ECMANvgCvE4efduI
oSwFbdb32UKKzppGW+usUbCgEH++EVNWN7VG8F7bvsnPDmuW2J2p2jjvg76H5eK2
OtnI180JV2Qb80d2lKOS24Mq9edhCzh9AUFsTAfaQ1iBUE4P353G67RF88ZNvV1A
n9DIgbMBf97bByUmp+5MWMXWJ9AcqyXQFsQutEQMudor8P9UqwpCVUkxijpfFxvM
HOBVArYRsdhbjNRGpVAVHdzpJ2AQNTQVeSS7YdzHAzGIVksKHL3K5QJuUJCgNa52
9H5201wSTxSAhlhoPTT06OHmIGiTvXZS
-----END CERTIFICATE-----

View file

@ -8,7 +8,7 @@ class TestConfig < Gem::TestCase
util_make_gems util_make_gems
spec = Gem::Specification.find_by_name("a") spec = Gem::Specification.find_by_name("a")
spec.activate spec.activate
assert_equal "#{spec.full_gem_path}/data/a", Gem.datadir('a') assert_equal "#{spec.full_gem_path}/data/a", spec.datadir
end end
def test_good_rake_path_is_escaped def test_good_rake_path_is_escaped

View file

@ -180,6 +180,35 @@ class TestGem < Gem::TestCase
assert_match 'a-2/bin/exec', Gem.bin_path('a', 'exec', '>= 0') assert_match 'a-2/bin/exec', Gem.bin_path('a', 'exec', '>= 0')
end end
def test_activate_bin_path_resolves_eagerly
a1 = util_spec 'a', '1' do |s|
s.executables = ['exec']
s.add_dependency 'b'
end
b1 = util_spec 'b', '1' do |s|
s.add_dependency 'c', '2'
end
b2 = util_spec 'b', '2' do |s|
s.add_dependency 'c', '1'
end
c1 = util_spec 'c', '1'
c2 = util_spec 'c', '2'
install_specs c1, c2, b1, b2, a1
Gem.activate_bin_path("a", "exec", ">= 0")
# If we didn't eagerly resolve, this would activate c-2 and then the
# finish_resolve would cause a conflict
gem 'c'
Gem.finish_resolve
assert_equal %w(a-1 b-2 c-1), loaded_spec_names
end
def test_self_bin_path_no_exec_name def test_self_bin_path_no_exec_name
e = assert_raises ArgumentError do e = assert_raises ArgumentError do
Gem.bin_path 'a' Gem.bin_path 'a'
@ -275,11 +304,13 @@ class TestGem < Gem::TestCase
expected = File.join @gemhome, 'gems', foo.full_name, 'data', 'foo' expected = File.join @gemhome, 'gems', foo.full_name, 'data', 'foo'
assert_equal expected, Gem.datadir('foo') assert_equal expected, Gem::Specification.find_by_name("foo").datadir
end end
def test_self_datadir_nonexistent_package def test_self_datadir_nonexistent_package
assert_nil Gem.datadir('xyzzy') assert_raises(Gem::MissingSpecError) do
Gem::Specification.find_by_name("xyzzy").datadir
end
end end
def test_self_default_exec_format def test_self_default_exec_format
@ -368,7 +399,7 @@ class TestGem < Gem::TestCase
begin begin
Dir.chdir 'detect/a/b' Dir.chdir 'detect/a/b'
assert_empty Gem.detect_gemdeps assert_equal add_bundler_full_name([]), Gem.detect_gemdeps.map(&:full_name)
ensure ensure
Dir.chdir @tempdir Dir.chdir @tempdir
end end
@ -1068,7 +1099,7 @@ class TestGem < Gem::TestCase
refute Gem.try_activate 'nonexistent' refute Gem.try_activate 'nonexistent'
end end
expected = "Ignoring ext-1 because its extensions are not built. " + expected = "Ignoring ext-1 because its extensions are not built. " +
"Try: gem pristine ext --version 1\n" "Try: gem pristine ext --version 1\n"
assert_equal expected, err assert_equal expected, err
@ -1079,7 +1110,8 @@ class TestGem < Gem::TestCase
orig_path = ENV.delete 'GEM_PATH' orig_path = ENV.delete 'GEM_PATH'
Gem.use_paths nil, nil Gem.use_paths nil, nil
assert_equal Gem.default_dir, Gem.paths.home assert_equal Gem.default_dir, Gem.paths.home
assert_equal (Gem.default_path + [Gem.paths.home]).uniq, Gem.paths.path path = (Gem.default_path + [Gem.paths.home]).uniq
assert_equal path, Gem.paths.path
ensure ensure
ENV['GEM_HOME'] = orig_home ENV['GEM_HOME'] = orig_home
ENV['GEM_PATH'] = orig_path ENV['GEM_PATH'] = orig_path
@ -1420,7 +1452,7 @@ class TestGem < Gem::TestCase
Gem.detect_gemdeps Gem.detect_gemdeps
assert_equal %w!a-1 b-1 c-1!, loaded_spec_names assert_equal add_bundler_full_name(%W(a-1 b-1 c-1)), loaded_spec_names
end end
def test_auto_activation_of_detected_gemdeps_file def test_auto_activation_of_detected_gemdeps_file
@ -1443,10 +1475,20 @@ class TestGem < Gem::TestCase
ENV['RUBYGEMS_GEMDEPS'] = "-" ENV['RUBYGEMS_GEMDEPS'] = "-"
assert_equal [a,b,c], Gem.detect_gemdeps.sort_by { |s| s.name } expected_specs = [a, b, (Gem::USE_BUNDLER_FOR_GEMDEPS || nil) && util_spec("bundler", Bundler::VERSION), c].compact
assert_equal expected_specs, Gem.detect_gemdeps.sort_by { |s| s.name }
end end
LIB_PATH = File.expand_path "../../../lib".dup.untaint, __FILE__.dup.untaint LIB_PATH = File.expand_path "../../../lib".dup.untaint, __FILE__.dup.untaint
BUNDLER_LIB_PATH = File.expand_path $LOAD_PATH.find {|lp| File.file?(File.join(lp, "bundler.rb")) }.dup.untaint
BUNDLER_FULL_NAME = "bundler-#{Bundler::VERSION}"
def add_bundler_full_name(names)
return names unless Gem::USE_BUNDLER_FOR_GEMDEPS
names << BUNDLER_FULL_NAME
names.sort!
names
end
def test_looks_for_gemdeps_files_automatically_on_start def test_looks_for_gemdeps_files_automatically_on_start
util_clear_gems util_clear_gems
@ -1466,7 +1508,8 @@ class TestGem < Gem::TestCase
ENV['RUBYGEMS_GEMDEPS'] = "-" ENV['RUBYGEMS_GEMDEPS'] = "-"
path = File.join @tempdir, "gem.deps.rb" path = File.join @tempdir, "gem.deps.rb"
cmd = [Gem.ruby.dup.untaint, "-I#{LIB_PATH.untaint}", "-rrubygems"] cmd = [Gem.ruby.dup.untaint, "-I#{LIB_PATH.untaint}",
"-I#{BUNDLER_LIB_PATH.untaint}", "-rrubygems"]
if RUBY_VERSION < '1.9' if RUBY_VERSION < '1.9'
cmd << "-e 'puts Gem.loaded_specs.values.map(&:full_name).sort'" cmd << "-e 'puts Gem.loaded_specs.values.map(&:full_name).sort'"
cmd = cmd.join(' ') cmd = cmd.join(' ')
@ -1508,7 +1551,8 @@ class TestGem < Gem::TestCase
Dir.mkdir "sub1" Dir.mkdir "sub1"
path = File.join @tempdir, "gem.deps.rb" path = File.join @tempdir, "gem.deps.rb"
cmd = [Gem.ruby.dup.untaint, "-Csub1", "-I#{LIB_PATH.untaint}", "-rrubygems"] cmd = [Gem.ruby.dup.untaint, "-Csub1", "-I#{LIB_PATH.untaint}",
"-I#{BUNDLER_LIB_PATH.untaint}", "-rrubygems"]
if RUBY_VERSION < '1.9' if RUBY_VERSION < '1.9'
cmd << "-e 'puts Gem.loaded_specs.values.map(&:full_name).sort'" cmd << "-e 'puts Gem.loaded_specs.values.map(&:full_name).sort'"
cmd = cmd.join(' ') cmd = cmd.join(' ')
@ -1603,7 +1647,7 @@ class TestGem < Gem::TestCase
Gem.use_gemdeps gem_deps_file Gem.use_gemdeps gem_deps_file
assert spec.activated? assert_equal add_bundler_full_name(%W(a-1)), loaded_spec_names
refute_nil Gem.gemdeps refute_nil Gem.gemdeps
end end
@ -1664,7 +1708,7 @@ class TestGem < Gem::TestCase
Gem.use_gemdeps Gem.use_gemdeps
assert spec.activated? assert_equal add_bundler_full_name(%W(a-1)), loaded_spec_names
ensure ensure
ENV['RUBYGEMS_GEMDEPS'] = rubygems_gemdeps ENV['RUBYGEMS_GEMDEPS'] = rubygems_gemdeps
end end
@ -1706,11 +1750,25 @@ class TestGem < Gem::TestCase
io.write 'gem "a"' io.write 'gem "a"'
end end
expected = <<-EXPECTED platform = Bundler::GemHelpers.generic_local_platform
if platform == Gem::Platform::RUBY
platform = ''
else
platform = " #{platform}"
end
expected = if Gem::USE_BUNDLER_FOR_GEMDEPS
<<-EXPECTED
Could not find gem 'a#{platform}' in any of the gem sources listed in your Gemfile.
You may need to `gem install -g` to install missing gems
EXPECTED
else
<<-EXPECTED
Unable to resolve dependency: user requested 'a (>= 0)' Unable to resolve dependency: user requested 'a (>= 0)'
You may need to `gem install -g` to install missing gems You may need to `gem install -g` to install missing gems
EXPECTED EXPECTED
end
assert_output nil, expected do assert_output nil, expected do
Gem.use_gemdeps Gem.use_gemdeps
@ -1735,7 +1793,7 @@ You may need to `gem install -g` to install missing gems
Gem.use_gemdeps Gem.use_gemdeps
assert spec.activated? assert_equal add_bundler_full_name(%W(a-1)), loaded_spec_names
ensure ensure
ENV['RUBYGEMS_GEMDEPS'] = rubygems_gemdeps ENV['RUBYGEMS_GEMDEPS'] = rubygems_gemdeps
end end

View file

@ -0,0 +1,125 @@
# frozen_string_literal: true
require 'rubygems/test_case'
class TestGemBundlerVersionFinder < Gem::TestCase
def setup
@argv = ARGV.dup
@env = ENV.to_hash.clone
ENV.delete("BUNDLER_VERSION")
@dollar_0 = $0
end
def teardown
ARGV.replace @argv
ENV.replace @env
$0 = @dollar_0
end
def bvf
Gem::BundlerVersionFinder
end
def test_bundler_version_defaults_to_nil
assert_nil bvf.bundler_version
end
def test_bundler_version_with_env_var
ENV["BUNDLER_VERSION"] = "1.1.1.1"
assert_equal v("1.1.1.1"), bvf.bundler_version
end
def test_bundler_version_with_bundle_update_bundler
ARGV.replace %w[update --bundler]
assert_nil bvf.bundler_version
$0 = "/foo/bar/bundle"
assert_nil bvf.bundler_version
ARGV.replace %w[update --bundler=1.1.1.1 gem_name]
assert_equal v("1.1.1.1"), bvf.bundler_version
ARGV.replace %w[update --bundler 1.1.1.1 gem_name]
assert_equal v("1.1.1.1"), bvf.bundler_version
ARGV.replace %w[update --bundler\ 1.1.1.1 gem_name]
assert_equal v("1.1.1.1"), bvf.bundler_version
ARGV.replace %w[update --bundler\ 1.1.1.2 --bundler --bundler 1.1.1.1 gem_name]
assert_equal v("1.1.1.1"), bvf.bundler_version
$0 = "other"
assert_nil bvf.bundler_version
end
def test_bundler_version_with_lockfile
bvf.stub(:lockfile_contents, [nil, ""]) do
assert_nil bvf.bundler_version
end
bvf.stub(:lockfile_contents, [nil, "\n\nBUNDLED WITH\n 1.1.1.1\n"]) do
assert_equal v("1.1.1.1"), bvf.bundler_version
end
bvf.stub(:lockfile_contents, [nil, "\n\nBUNDLED WITH\n fjdkslfjdkslfjsldk\n"]) do
assert_nil bvf.bundler_version
end
end
def test_bundler_version_with_reason
assert_nil bvf.bundler_version_with_reason
bvf.stub(:lockfile_contents, [nil, "\n\nBUNDLED WITH\n 1.1.1.1\n"]) do
assert_equal ["1.1.1.1", "your lockfile"], bvf.bundler_version_with_reason
$0 = "bundle"
ARGV.replace %w[update --bundler]
assert_nil bvf.bundler_version_with_reason
ARGV.replace %w[update --bundler=1.1.1.2]
assert_equal ["1.1.1.2", "`bundle update --bundler`"], bvf.bundler_version_with_reason
ENV["BUNDLER_VERSION"] = "1.1.1.3"
assert_equal ["1.1.1.3", "`$BUNDLER_VERSION`"], bvf.bundler_version_with_reason
end
end
def test_compatible
assert bvf.compatible?(util_spec("foo"))
assert bvf.compatible?(util_spec("bundler", 1.1))
bvf.stub(:bundler_version, v("1.1.1.1")) do
assert bvf.compatible?(util_spec("foo"))
assert bvf.compatible?(util_spec("bundler", "1.1.1.1"))
assert bvf.compatible?(util_spec("bundler", "1.1.1.a"))
assert bvf.compatible?(util_spec("bundler", "1.999"))
refute bvf.compatible?(util_spec("bundler", "2.999"))
end
bvf.stub(:bundler_version, v("2.1.1.1")) do
assert bvf.compatible?(util_spec("foo"))
assert bvf.compatible?(util_spec("bundler", "2.1.1.1"))
refute bvf.compatible?(util_spec("bundler", "2.1.1.a"))
refute bvf.compatible?(util_spec("bundler", "1.999"))
refute bvf.compatible?(util_spec("bundler", "2.999"))
end
end
def test_filter
versions = %w[1 1.0 1.0.1.1 2.a 3 3.0]
specs = versions.map { |v| util_spec("bundler", v) }
assert_equal %w[1 1.0 1.0.1.1 2.a 3 3.0], util_filter_specs(specs).map(&:version).map(&:to_s)
bvf.stub(:bundler_version, v("2.1.1.1")) do
assert_empty util_filter_specs(specs).map(&:version).map(&:to_s)
end
bvf.stub(:bundler_version, v("1.1.1.1")) do
assert_equal %w[1 1.0 1.0.1.1], util_filter_specs(specs).map(&:version).map(&:to_s)
end
bvf.stub(:bundler_version, v("1")) do
assert_equal %w[1 1.0 1.0.1.1], util_filter_specs(specs).map(&:version).map(&:to_s)
end
bvf.stub(:bundler_version, v("2.a")) do
assert_equal %w[2.a], util_filter_specs(specs).map(&:version).map(&:to_s)
end
bvf.stub(:bundler_version, v("3")) do
assert_equal %w[3 3.0], util_filter_specs(specs).map(&:version).map(&:to_s)
end
end
def util_filter_specs(specs)
specs = specs.dup
bvf.filter!(specs)
specs
end
end

View file

@ -170,7 +170,7 @@ class TestGemCommand < Gem::TestCase
@cmd.add_option('-f', '--file FILE', 'File option') do |value, options| @cmd.add_option('-f', '--file FILE', 'File option') do |value, options|
options[:help] = true options[:help] = true
end end
@cmd.add_option('--silent', 'Silence rubygems output') do |value, options| @cmd.add_option('--silent', 'Silence RubyGems output') do |value, options|
options[:silent] = true options[:silent] = true
end end
assert @cmd.handles?(['-x']) assert @cmd.handles?(['-x'])

View file

@ -1,3 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'rubygems/test_case' require 'rubygems/test_case'
require 'rubygems/commands/build_command' require 'rubygems/commands/build_command'
@ -117,5 +118,30 @@ class TestGemCommandsBuildCommand < Gem::TestCase
util_test_build_gem @gem, gemspec_file, false util_test_build_gem @gem, gemspec_file, false
end end
end CERT_FILE = cert_path 'public3072'
SIGNING_KEY = key_path 'private3072'
def test_build_signed_gem
trust_dir = Gem::Security.trust_dir
spec = util_spec 'some_gem' do |s|
s.signing_key = SIGNING_KEY
s.cert_chain = [CERT_FILE]
end
gemspec_file = File.join(@tempdir, spec.spec_name)
File.open gemspec_file, 'w' do |gs|
gs.write spec.to_ruby
end
util_test_build_gem spec, gemspec_file
trust_dir.trust_cert OpenSSL::X509::Certificate.new(File.read(CERT_FILE))
gem = Gem::Package.new(File.join(@tempdir, spec.file_name),
Gem::Security::HighSecurity)
assert gem.verify
end
end

View file

@ -130,6 +130,70 @@ Added '/CN=alternate/DC=example'
assert_path_exists File.join(@tempdir, 'gem-public_cert.pem') assert_path_exists File.join(@tempdir, 'gem-public_cert.pem')
end end
def test_execute_build_bad_email_address
passphrase = 'Foo bar'
email = "nobody@"
@cmd.handle_options %W[--build #{email}]
@build_ui = Gem::MockGemUi.new "#{passphrase}\n#{passphrase}"
use_ui @build_ui do
e = assert_raises Gem::CommandLineError do
@cmd.execute
end
assert_equal "Invalid email address #{email}",
e.message
refute_path_exists File.join(@tempdir, 'gem-private_key.pem')
refute_path_exists File.join(@tempdir, 'gem-public_cert.pem')
end
end
def test_execute_build_expiration_days
passphrase = 'Foo bar'
@cmd.handle_options %W[
--build nobody@example.com
--days 26
]
@build_ui = Gem::MockGemUi.new "#{passphrase}\n#{passphrase}"
use_ui @build_ui do
@cmd.execute
end
output = @build_ui.output.squeeze("\n").split "\n"
assert_equal "Passphrase for your Private Key: ",
output.shift
assert_equal "Please repeat the passphrase for your Private Key: ",
output.shift
assert_equal "Certificate: #{File.join @tempdir, 'gem-public_cert.pem'}",
output.shift
assert_equal "Private Key: #{File.join @tempdir, 'gem-private_key.pem'}",
output.shift
assert_equal "Don't forget to move the key file to somewhere private!",
output.shift
assert_empty output
assert_empty @build_ui.error
assert_path_exists File.join(@tempdir, 'gem-private_key.pem')
assert_path_exists File.join(@tempdir, 'gem-public_cert.pem')
pem = File.read("#{@tempdir}/gem-public_cert.pem")
cert = OpenSSL::X509::Certificate.new(pem)
test = (cert.not_after - cert.not_before).to_i / (24 * 60 * 60)
assert_equal(test, 26)
end
def test_execute_build_bad_passphrase_confirmation def test_execute_build_bad_passphrase_confirmation
passphrase = 'Foo bar' passphrase = 'Foo bar'
passphrase_confirmation = 'Fu bar' passphrase_confirmation = 'Fu bar'

View file

@ -96,6 +96,39 @@ class TestGemCommandsInstallCommand < Gem::TestCase
assert_match "1 gem installed", @ui.output assert_match "1 gem installed", @ui.output
end end
def test_execute_local_transitive_prerelease
specs = spec_fetcher do |fetcher|
fetcher.download 'a', 2, 'b' => "2.a", 'c' => '3'
fetcher.download 'b', '2.a'
fetcher.download 'c', '3'
end
@cmd.options[:domain] = :local
FileUtils.mv specs['a-2'].cache_file, @tempdir
FileUtils.mv specs['b-2.a'].cache_file, @tempdir
FileUtils.mv specs['c-3'].cache_file, @tempdir
@cmd.options[:args] = %w[a]
use_ui @ui do
orig_dir = Dir.pwd
begin
Dir.chdir @tempdir
FileUtils.rm_r [@gemhome, "gems"]
assert_raises Gem::MockGemUi::SystemExitException, @ui.error do
@cmd.execute
end
ensure
Dir.chdir orig_dir
end
end
assert_equal %w[a-2 b-2.a c-3], @cmd.installed_specs.map { |spec| spec.full_name }.sort
assert_match "3 gems installed", @ui.output
end
def test_execute_no_user_install def test_execute_no_user_install
skip 'skipped on MS Windows (chmod has no effect)' if win_platform? skip 'skipped on MS Windows (chmod has no effect)' if win_platform?
@ -588,7 +621,7 @@ ERROR: Possible alternatives: non_existent_with_hint
done_installing = true done_installing = true
end end
spec = quick_spec 'a', 2 spec = util_spec 'a', 2
util_build_gem spec util_build_gem spec
@ -616,7 +649,7 @@ ERROR: Possible alternatives: non_existent_with_hint
end end
def test_install_gem_ignore_dependencies_specific_file def test_install_gem_ignore_dependencies_specific_file
spec = quick_spec 'a', 2 spec = util_spec 'a', 2
util_build_gem spec util_build_gem spec

View file

@ -145,7 +145,7 @@ class TestGemCommandsPristineCommand < Gem::TestCase
out = @ui.output.split "\n" out = @ui.output.split "\n"
assert_equal 'Restoring gems to pristine condition...', out.shift assert_equal 'Restoring gems to pristine condition...', out.shift
assert_equal 'Building native extensions. This could take a while...', assert_equal 'Building native extensions. This could take a while...',
out.shift out.shift
assert_equal "Restored #{a.full_name}", out.shift assert_equal "Restored #{a.full_name}", out.shift
assert_empty out, out.inspect assert_empty out, out.inspect

View file

@ -637,6 +637,25 @@ EOF
assert_equal expected, @ui.output assert_equal expected, @ui.output
end end
def test_execute_show_default_gems_with_platform
a1 = new_default_spec 'a', 1
a1.platform = 'java'
install_default_specs a1
use_ui @ui do
@cmd.execute
end
expected = <<-EOF
*** LOCAL GEMS ***
a (default: 1 java)
EOF
assert_equal expected, @ui.output
end
def test_execute_default_details def test_execute_default_details
spec_fetcher do |fetcher| spec_fetcher do |fetcher|
fetcher.spec 'a', 2 fetcher.spec 'a', 2

View file

@ -20,6 +20,13 @@ class TestGemCommandsSetupCommand < Gem::TestCase
open 'lib/rubygems.rb', 'w' do |io| io.puts '# rubygems.rb' end open 'lib/rubygems.rb', 'w' do |io| io.puts '# rubygems.rb' end
open 'lib/rubygems/test_case.rb', 'w' do |io| io.puts '# test_case.rb' end open 'lib/rubygems/test_case.rb', 'w' do |io| io.puts '# test_case.rb' end
open 'lib/rubygems/ssl_certs/rubygems.org/foo.pem', 'w' do |io| io.puts 'PEM' end open 'lib/rubygems/ssl_certs/rubygems.org/foo.pem', 'w' do |io| io.puts 'PEM' end
FileUtils.mkdir_p 'bundler/exe'
FileUtils.mkdir_p 'bundler/lib/bundler'
open 'bundler/exe/bundle', 'w' do |io| io.puts '# bundle' end
open 'bundler/lib/bundler.rb', 'w' do |io| io.puts '# bundler.rb' end
open 'bundler/lib/bundler/b.rb', 'w' do |io| io.puts '# b.rb' end
end end
def test_pem_files_in def test_pem_files_in
@ -40,12 +47,18 @@ class TestGemCommandsSetupCommand < Gem::TestCase
assert_path_exists File.join(dir, 'rubygems.rb') assert_path_exists File.join(dir, 'rubygems.rb')
assert_path_exists File.join(dir, 'rubygems/ssl_certs/rubygems.org/foo.pem') assert_path_exists File.join(dir, 'rubygems/ssl_certs/rubygems.org/foo.pem')
if Gem::USE_BUNDLER_FOR_GEMDEPS
assert_path_exists File.join(dir, 'bundler.rb')
assert_path_exists File.join(dir, 'bundler/b.rb')
end
end end
end end
def test_remove_old_lib_files def test_remove_old_lib_files
lib = File.join @install_dir, 'lib' lib = File.join @install_dir, 'lib'
lib_rubygems = File.join lib, 'rubygems' lib_rubygems = File.join lib, 'rubygems'
lib_bundler = File.join lib, 'bundler'
lib_rubygems_defaults = File.join lib_rubygems, 'defaults' lib_rubygems_defaults = File.join lib_rubygems, 'defaults'
securerandom_rb = File.join lib, 'securerandom.rb' securerandom_rb = File.join lib, 'securerandom.rb'
@ -55,13 +68,16 @@ class TestGemCommandsSetupCommand < Gem::TestCase
old_builder_rb = File.join lib_rubygems, 'builder.rb' old_builder_rb = File.join lib_rubygems, 'builder.rb'
old_format_rb = File.join lib_rubygems, 'format.rb' old_format_rb = File.join lib_rubygems, 'format.rb'
old_bundler_c_rb = File.join lib_bundler, 'c.rb'
FileUtils.mkdir_p lib_rubygems_defaults FileUtils.mkdir_p lib_rubygems_defaults
FileUtils.mkdir_p lib_bundler
open securerandom_rb, 'w' do |io| io.puts '# securerandom.rb' end open securerandom_rb, 'w' do |io| io.puts '# securerandom.rb' end
open old_builder_rb, 'w' do |io| io.puts '# builder.rb' end open old_builder_rb, 'w' do |io| io.puts '# builder.rb' end
open old_format_rb, 'w' do |io| io.puts '# format.rb' end open old_format_rb, 'w' do |io| io.puts '# format.rb' end
open old_bundler_c_rb, 'w' do |io| io.puts '# c.rb' end
open engine_defaults_rb, 'w' do |io| io.puts '# jruby.rb' end open engine_defaults_rb, 'w' do |io| io.puts '# jruby.rb' end
open os_defaults_rb, 'w' do |io| io.puts '# operating_system.rb' end open os_defaults_rb, 'w' do |io| io.puts '# operating_system.rb' end
@ -70,6 +86,7 @@ class TestGemCommandsSetupCommand < Gem::TestCase
refute_path_exists old_builder_rb refute_path_exists old_builder_rb
refute_path_exists old_format_rb refute_path_exists old_format_rb
refute_path_exists old_bundler_c_rb if Gem::USE_BUNDLER_FOR_GEMDEPS
assert_path_exists securerandom_rb assert_path_exists securerandom_rb
assert_path_exists engine_defaults_rb assert_path_exists engine_defaults_rb

View file

@ -0,0 +1,95 @@
# frozen_string_literal: true
require 'rubygems/test_case'
require 'rubygems/commands/signin_command'
require 'rubygems/installer'
class TestGemCommandsSigninCommand < Gem::TestCase
def setup
super
Gem.configuration.rubygems_api_key = nil
Gem.configuration.api_keys.clear
@cmd = Gem::Commands::SigninCommand.new
end
def teardown
credentials_path = Gem.configuration.credentials_path
File.delete(credentials_path) if File.exist?(credentials_path)
super
end
def test_execute_when_not_already_signed_in
sign_in_ui = util_capture() { @cmd.execute }
assert_match %r{Signed in.}, sign_in_ui.output
end
def test_execute_when_already_signed_in_with_same_host
host = 'http://some-gemcutter-compatible-host.org'
sign_in_ui = util_capture(nil, host) { @cmd.execute }
old_credentials = YAML.load_file Gem.configuration.credentials_path
sign_in_ui = util_capture(nil, host) { @cmd.execute }
new_credentials = YAML.load_file Gem.configuration.credentials_path
assert_equal old_credentials[host], new_credentials[host]
end
def test_execute_when_already_signed_in_with_different_host
api_key = 'a5fdbb6ba150cbb83aad2bb2fede64cf04045xxxx'
sign_in_ui = util_capture(nil, nil, api_key) { @cmd.execute }
host = 'http://some-gemcutter-compatible-host.org'
sign_in_ui = util_capture(nil, host, api_key) { @cmd.execute }
credentials = YAML.load_file Gem.configuration.credentials_path
assert_equal credentials[:rubygems_api_key], api_key
assert_equal credentials[host], nil
end
def test_execute_with_host_supplied
host = 'http://some-gemcutter-compatible-host.org'
sign_in_ui = util_capture(nil, host) { @cmd.execute }
assert_match %r{Enter your #{host} credentials.}, sign_in_ui.output
assert_match %r{Signed in.}, sign_in_ui.output
api_key = 'a5fdbb6ba150cbb83aad2bb2fede64cf040453903'
credentials = YAML.load_file Gem.configuration.credentials_path
assert_equal api_key, credentials[host]
end
def test_execute_with_valid_creds_set_for_default_host
util_capture {@cmd.execute}
api_key = 'a5fdbb6ba150cbb83aad2bb2fede64cf040453903'
credentials = YAML.load_file Gem.configuration.credentials_path
assert_equal api_key, credentials[:rubygems_api_key]
end
# Utility method to capture IO/UI within the block passed
def util_capture ui_stub = nil, host = nil, api_key = nil
api_key ||= 'a5fdbb6ba150cbb83aad2bb2fede64cf040453903'
response = [api_key, 200, 'OK']
email = 'you@example.com'
password = 'secret'
fetcher = Gem::FakeFetcher.new
# Set the expected response for the Web-API supplied
ENV['RUBYGEMS_HOST'] = host || Gem::DEFAULT_HOST
data_key = "#{ENV['RUBYGEMS_HOST']}/api/v1/api_key"
fetcher.data[data_key] = response
Gem::RemoteFetcher.fetcher = fetcher
sign_in_ui = ui_stub || Gem::MockGemUi.new("#{email}\n#{password}\n")
use_ui sign_in_ui do
yield
end
sign_in_ui
end
end

View file

@ -0,0 +1,37 @@
# frozen_string_literal: true
require 'rubygems/test_case'
require 'rubygems/commands/signout_command'
require 'rubygems/installer'
class TestGemCommandsSignoutCommand < Gem::TestCase
def setup
super
@cmd = Gem::Commands::SignoutCommand.new
end
def teardown
super
File.delete Gem.configuration.credentials_path if File.exist?(Gem.configuration.credentials_path)
end
def test_execute_when_user_is_signed_in
FileUtils.mkdir_p File.dirname(Gem.configuration.credentials_path)
FileUtils::touch Gem.configuration.credentials_path
@sign_out_ui = Gem::MockGemUi.new
use_ui(@sign_out_ui) { @cmd.execute }
assert_match %r{You have successfully signed out}, @sign_out_ui.output
assert_equal false, File.exist?(Gem.configuration.credentials_path)
end
def test_execute_when_not_signed_in # i.e. no credential file created
@sign_out_ui = Gem::MockGemUi.new
use_ui(@sign_out_ui) { @cmd.execute }
assert_match %r{You are not currently signed in}, @sign_out_ui.error
end
end

View file

@ -279,5 +279,17 @@ WARNING: Use your OS package manager to uninstall vendor gems
RbConfig::CONFIG['vendordir'] = orig_vendordir RbConfig::CONFIG['vendordir'] = orig_vendordir
end end
def test_execute_with_gem_not_installed
@cmd.options[:args] = ['d']
use_ui ui do
@cmd.execute
end
output = ui.output.split "\n"
assert_equal output.first, "Gem 'd' is not installed"
end
end end

View file

@ -107,7 +107,7 @@ class TestGemCommandsUpdateCommand < Gem::TestCase
end end
out = @ui.output.split "\n" out = @ui.output.split "\n"
assert_equal "Latest version currently installed. Aborting.", out.shift assert_equal "Latest version already installed. Done.", out.shift
assert_empty out assert_empty out
end end

View file

@ -33,7 +33,7 @@ class TestGemCommandsWhichCommand < Gem::TestCase
end end
assert_equal '', @ui.output assert_equal '', @ui.output
assert_match %r%Can.t find ruby library file or shared library directory\n%, assert_match %r%Can.t find Ruby library file or shared library directory\n%,
@ui.error @ui.error
end end
@ -51,7 +51,7 @@ class TestGemCommandsWhichCommand < Gem::TestCase
end end
assert_equal "#{@foo_bar.full_gem_path}/lib/foo_bar.rb\n", @ui.output assert_equal "#{@foo_bar.full_gem_path}/lib/foo_bar.rb\n", @ui.output
assert_match %r%Can.t find ruby library file or shared library missinglib\n%, assert_match %r%Can.t find Ruby library file or shared library missinglib\n%,
@ui.error @ui.error
end end
@ -65,7 +65,7 @@ class TestGemCommandsWhichCommand < Gem::TestCase
end end
assert_equal '', @ui.output assert_equal '', @ui.output
assert_match %r%Can.t find ruby library file or shared library missinglib\n%, assert_match %r%Can.t find Ruby library file or shared library missinglib\n%,
@ui.error @ui.error
end end

View file

@ -338,6 +338,34 @@ class TestGemDependency < Gem::TestCase
assert_match "Could not find 'a' (= 2.0) - did find: [a-1.0]", e.message assert_match "Could not find 'a' (= 2.0) - did find: [a-1.0]", e.message
end end
def test_to_specs_respects_bundler_version
b = util_spec 'bundler', '2.0.0.pre.1'
b_1 = util_spec 'bundler', '1'
install_specs b, b_1
b_file = File.join b.gem_dir, 'lib', 'bundler', 'setup.rb'
write_file b_file do |io|
io.puts '# setup.rb'
end
dep = Gem::Dependency.new "bundler", ">= 0.a"
assert_equal [b, b_1], dep.to_specs
Gem::BundlerVersionFinder.stub(:bundler_version_with_reason, ["3.5", "reason"]) do
e = assert_raises Gem::MissingSpecVersionError do
dep.to_specs
end
assert_match "Could not find 'bundler' (3.5) required by reason.\nTo update to the lastest version installed on your system, run `bundle update --bundler`.\nTo install the missing version, run `gem install bundler:3.5`\n", e.message
end
Gem::BundlerVersionFinder.stub(:bundler_version_with_reason, ["2.0.0.pre.1", "reason"]) do
assert_equal [b], dep.to_specs
end
end
def test_to_specs_indicates_total_gem_set_size def test_to_specs_indicates_total_gem_set_size
a = util_spec 'a', '1.0' a = util_spec 'a', '1.0'
install_specs a install_specs a

View file

@ -239,7 +239,7 @@ install:
assert_match(/\AERROR: Failed to build gem native extension.$/, e.message) assert_match(/\AERROR: Failed to build gem native extension.$/, e.message)
assert_equal "Building native extensions. This could take a while...\n", assert_equal "Building native extensions. This could take a while...\n",
@ui.output @ui.output
assert_equal '', @ui.error assert_equal '', @ui.error
@ -272,7 +272,7 @@ install:
assert_match(/^\s*No builder for extension ''$/, e.message) assert_match(/^\s*No builder for extension ''$/, e.message)
assert_equal "Building native extensions. This could take a while...\n", assert_equal "Building native extensions. This could take a while...\n",
@ui.output @ui.output
assert_equal '', @ui.error assert_equal '', @ui.error

View file

@ -121,9 +121,10 @@ class TestGemInstallUpdateOptions < Gem::InstallerTestCase
def test_security_policy_unknown def test_security_policy_unknown
@cmd.add_install_update_options @cmd.add_install_update_options
assert_raises OptionParser::InvalidArgument do e = assert_raises OptionParser::InvalidArgument do
@cmd.handle_options %w[-P UnknownSecurity] @cmd.handle_options %w[-P UnknownSecurity]
end end
assert_includes e.message, "UnknownSecurity"
end end
def test_user_install_enabled def test_user_install_enabled

View file

@ -87,7 +87,7 @@ end
end end
util_make_exec util_make_exec
@installer.gem_dir = util_gem_dir @spec @installer.gem_dir = @spec.gem_dir
@installer.wrappers = true @installer.wrappers = true
@installer.generate_bin @installer.generate_bin
@ -304,7 +304,7 @@ gem 'other', version
def test_extract_files def test_extract_files
@installer.extract_files @installer.extract_files
assert_path_exists File.join util_gem_dir, 'bin/executable' assert_path_exists File.join @spec.gem_dir, 'bin/executable'
end end
def test_generate_bin_bindir def test_generate_bin_bindir
@ -314,12 +314,12 @@ gem 'other', version
@spec.bindir = '.' @spec.bindir = '.'
exec_file = @installer.formatted_program_filename 'executable' exec_file = @installer.formatted_program_filename 'executable'
exec_path = File.join util_gem_dir(@spec), exec_file exec_path = File.join @spec.gem_dir, exec_file
File.open exec_path, 'w' do |f| File.open exec_path, 'w' do |f|
f.puts '#!/usr/bin/ruby' f.puts '#!/usr/bin/ruby'
end end
@installer.gem_dir = util_gem_dir @installer.gem_dir = @spec.gem_dir
@installer.generate_bin @installer.generate_bin
@ -355,7 +355,7 @@ gem 'other', version
def test_generate_bin_script def test_generate_bin_script
@installer.wrappers = true @installer.wrappers = true
util_make_exec util_make_exec
@installer.gem_dir = util_gem_dir @installer.gem_dir = @spec.gem_dir
@installer.generate_bin @installer.generate_bin
assert File.directory? util_inst_bindir assert File.directory? util_inst_bindir
@ -371,7 +371,7 @@ gem 'other', version
@installer.format_executable = true @installer.format_executable = true
@installer.wrappers = true @installer.wrappers = true
util_make_exec util_make_exec
@installer.gem_dir = util_gem_dir @installer.gem_dir = @spec.gem_dir
Gem::Installer.exec_format = 'foo-%s-bar' Gem::Installer.exec_format = 'foo-%s-bar'
@installer.generate_bin @installer.generate_bin
@ -385,7 +385,7 @@ gem 'other', version
def test_generate_bin_script_format_disabled def test_generate_bin_script_format_disabled
@installer.wrappers = true @installer.wrappers = true
util_make_exec util_make_exec
@installer.gem_dir = util_gem_dir @installer.gem_dir = @spec.gem_dir
Gem::Installer.exec_format = 'foo-%s-bar' Gem::Installer.exec_format = 'foo-%s-bar'
@installer.generate_bin @installer.generate_bin
@ -474,10 +474,10 @@ gem 'other', version
def test_generate_bin_script_wrappers def test_generate_bin_script_wrappers
@installer.wrappers = true @installer.wrappers = true
util_make_exec util_make_exec
@installer.gem_dir = util_gem_dir @installer.gem_dir = @spec.gem_dir
installed_exec = File.join(util_inst_bindir, 'executable') installed_exec = File.join(util_inst_bindir, 'executable')
real_exec = File.join util_gem_dir, 'bin', 'executable' real_exec = File.join @spec.gem_dir, 'bin', 'executable'
# fake --no-wrappers for previous install # fake --no-wrappers for previous install
unless Gem.win_platform? then unless Gem.win_platform? then
@ -501,13 +501,13 @@ gem 'other', version
@installer.wrappers = false @installer.wrappers = false
util_make_exec util_make_exec
@installer.gem_dir = util_gem_dir @installer.gem_dir = @spec.gem_dir
@installer.generate_bin @installer.generate_bin
assert_equal true, File.directory?(util_inst_bindir) assert_equal true, File.directory?(util_inst_bindir)
installed_exec = File.join util_inst_bindir, 'executable' installed_exec = File.join util_inst_bindir, 'executable'
assert_equal true, File.symlink?(installed_exec) assert_equal true, File.symlink?(installed_exec)
assert_equal(File.join(util_gem_dir, 'bin', 'executable'), assert_equal(File.join(@spec.gem_dir, 'bin', 'executable'),
File.readlink(installed_exec)) File.readlink(installed_exec))
end end
@ -523,7 +523,7 @@ gem 'other', version
def test_generate_bin_symlink_no_perms def test_generate_bin_symlink_no_perms
@installer.wrappers = false @installer.wrappers = false
util_make_exec util_make_exec
@installer.gem_dir = util_gem_dir @installer.gem_dir = @spec.gem_dir
Dir.mkdir util_inst_bindir Dir.mkdir util_inst_bindir
@ -545,11 +545,11 @@ gem 'other', version
@installer.wrappers = false @installer.wrappers = false
util_make_exec util_make_exec
@installer.gem_dir = util_gem_dir @installer.gem_dir = @spec.gem_dir
@installer.generate_bin @installer.generate_bin
installed_exec = File.join(util_inst_bindir, 'executable') installed_exec = File.join(util_inst_bindir, 'executable')
assert_equal(File.join(util_gem_dir, 'bin', 'executable'), assert_equal(File.join(@spec.gem_dir, 'bin', 'executable'),
File.readlink(installed_exec)) File.readlink(installed_exec))
@spec = Gem::Specification.new do |s| @spec = Gem::Specification.new do |s|
@ -562,7 +562,7 @@ gem 'other', version
end end
util_make_exec util_make_exec
@installer.gem_dir = util_gem_dir @spec @installer.gem_dir = @spec.gem_dir
@installer.generate_bin @installer.generate_bin
installed_exec = File.join(util_inst_bindir, 'executable') installed_exec = File.join(util_inst_bindir, 'executable')
assert_equal(@spec.bin_file('executable'), assert_equal(@spec.bin_file('executable'),
@ -575,11 +575,11 @@ gem 'other', version
@installer.wrappers = false @installer.wrappers = false
util_make_exec util_make_exec
@installer.gem_dir = util_gem_dir @installer.gem_dir = @spec.gem_dir
@installer.generate_bin @installer.generate_bin
installed_exec = File.join(util_inst_bindir, 'executable') installed_exec = File.join(util_inst_bindir, 'executable')
assert_equal(File.join(util_gem_dir, 'bin', 'executable'), assert_equal(File.join(@spec.gem_dir, 'bin', 'executable'),
File.readlink(installed_exec)) File.readlink(installed_exec))
spec = Gem::Specification.new do |s| spec = Gem::Specification.new do |s|
@ -595,12 +595,12 @@ gem 'other', version
one = @spec.dup one = @spec.dup
one.version = 1 one.version = 1
@installer = Gem::Installer.for_spec spec @installer = Gem::Installer.for_spec spec
@installer.gem_dir = util_gem_dir one @installer.gem_dir = one.gem_dir
@installer.generate_bin @installer.generate_bin
installed_exec = File.join util_inst_bindir, 'executable' installed_exec = File.join util_inst_bindir, 'executable'
expected = File.join util_gem_dir, 'bin', 'executable' expected = File.join @spec.gem_dir, 'bin', 'executable'
assert_equal(expected, assert_equal(expected,
File.readlink(installed_exec), File.readlink(installed_exec),
"Ensure symlink not moved") "Ensure symlink not moved")
@ -611,7 +611,7 @@ gem 'other', version
@installer.wrappers = true @installer.wrappers = true
util_make_exec util_make_exec
@installer.gem_dir = util_gem_dir @installer.gem_dir = @spec.gem_dir
@installer.generate_bin @installer.generate_bin
@ -630,7 +630,7 @@ gem 'other', version
util_installer @spec, @gemhome util_installer @spec, @gemhome
@installer.wrappers = false @installer.wrappers = false
@installer.gem_dir = util_gem_dir @installer.gem_dir = @spec.gem_dir
@installer.generate_bin @installer.generate_bin
@ -648,7 +648,7 @@ gem 'other', version
File.const_set(:ALT_SEPARATOR, '\\') File.const_set(:ALT_SEPARATOR, '\\')
@installer.wrappers = false @installer.wrappers = false
util_make_exec util_make_exec
@installer.gem_dir = util_gem_dir @installer.gem_dir = @spec.gem_dir
use_ui @ui do use_ui @ui do
@installer.generate_bin @installer.generate_bin
@ -1421,10 +1421,11 @@ gem 'other', version
def test_pre_install_checks_ruby_version def test_pre_install_checks_ruby_version
use_ui @ui do use_ui @ui do
installer = Gem::Installer.at old_ruby_required installer = Gem::Installer.at old_ruby_required
e = assert_raises Gem::InstallError do e = assert_raises Gem::RuntimeRequirementNotMetError do
installer.pre_install_checks installer.pre_install_checks
end end
assert_equal 'old_ruby_required requires Ruby version = 1.4.6.', rv = Gem.ruby_api_version
assert_equal "old_ruby_required requires Ruby version = 1.4.6. The current ruby version is #{rv}.",
e.message e.message
end end
end end
@ -1440,10 +1441,11 @@ gem 'other', version
use_ui @ui do use_ui @ui do
@installer = Gem::Installer.at gem @installer = Gem::Installer.at gem
e = assert_raises Gem::InstallError do e = assert_raises Gem::RuntimeRequirementNotMetError do
@installer.pre_install_checks @installer.pre_install_checks
end end
assert_equal 'old_rubygems_required requires RubyGems version < 0. ' + rgv = Gem::VERSION
assert_equal "old_rubygems_required requires RubyGems version < 0. The current RubyGems version is #{rgv}. " +
"Try 'gem update --system' to update RubyGems itself.", e.message "Try 'gem update --system' to update RubyGems itself.", e.message
end end
end end
@ -1739,7 +1741,7 @@ gem 'other', version
@installer.wrappers = true @installer.wrappers = true
@installer.options[:install_as_default] = true @installer.options[:install_as_default] = true
@installer.gem_dir = util_gem_dir @spec @installer.gem_dir = @spec.gem_dir
@installer.generate_bin @installer.generate_bin
use_ui @ui do use_ui @ui do

View file

@ -1,4 +1,4 @@
# coding: UTF-8 # coding: utf-8
# frozen_string_literal: true # frozen_string_literal: true
require 'rubygems/package/tar_test_case' require 'rubygems/package/tar_test_case'
@ -84,7 +84,7 @@ class TestGemPackage < Gem::Package::TarTestCase
io.write spec.to_yaml io.write spec.to_yaml
end end
metadata_sha1 = Digest::SHA1.hexdigest s.string metadata_sha256 = Digest::SHA256.hexdigest s.string
metadata_sha512 = Digest::SHA512.hexdigest s.string metadata_sha512 = Digest::SHA512.hexdigest s.string
expected = { expected = {
@ -95,9 +95,9 @@ class TestGemPackage < Gem::Package::TarTestCase
} }
if defined?(OpenSSL::Digest) then if defined?(OpenSSL::Digest) then
expected['SHA1'] = { expected['SHA256'] = {
'metadata.gz' => metadata_sha1, 'metadata.gz' => metadata_sha256,
'data.tar.gz' => Digest::SHA1.hexdigest(tar), 'data.tar.gz' => Digest::SHA256.hexdigest(tar),
} }
end end

View file

@ -555,7 +555,7 @@ PeIQQkFng2VVot/WAQbv3ePqWq07g1BBcwIBAg==
nil nil
end end
assert_equal nil, fetcher.fetch_path(@uri + 'foo.gz', Time.at(0)) assert_nil fetcher.fetch_path(@uri + 'foo.gz', Time.at(0))
end end
def test_fetch_path_io_error def test_fetch_path_io_error
@ -621,7 +621,7 @@ PeIQQkFng2VVot/WAQbv3ePqWq07g1BBcwIBAg==
nil nil
end end
assert_equal nil, fetcher.fetch_path(URI.parse(@gem_repo), Time.at(0)) assert_nil fetcher.fetch_path(URI.parse(@gem_repo), Time.at(0))
end end
def test_implicit_no_proxy def test_implicit_no_proxy

View file

@ -753,7 +753,7 @@ end
@gda.ruby RUBY_VERSION, :engine => 'jruby', :engine_version => '1.7.4' @gda.ruby RUBY_VERSION, :engine => 'jruby', :engine_version => '1.7.4'
end end
assert_equal 'Your ruby engine is ruby, but your gem.deps.rb requires jruby', assert_equal 'Your Ruby engine is ruby, but your gem.deps.rb requires jruby',
e.message e.message
end end
end end
@ -764,7 +764,7 @@ end
@gda.ruby RUBY_VERSION, :engine => 'jruby', :engine_version => '1.7.4' @gda.ruby RUBY_VERSION, :engine => 'jruby', :engine_version => '1.7.4'
end end
assert_equal 'Your ruby engine version is jruby 1.7.6, but your gem.deps.rb requires jruby 1.7.4', assert_equal 'Your Ruby engine version is jruby 1.7.6, but your gem.deps.rb requires jruby 1.7.4',
e.message e.message
end end
end end
@ -774,7 +774,7 @@ end
@gda.ruby RUBY_VERSION, :engine => 'jruby' @gda.ruby RUBY_VERSION, :engine => 'jruby'
end end
assert_equal 'you must specify engine_version along with the ruby engine', assert_equal 'You must specify engine_version along with the Ruby engine',
e.message e.message
end end

View file

@ -30,6 +30,12 @@ class TestGemRequirement < Gem::TestCase
assert_requirement_equal "= 2", v(2) assert_requirement_equal "= 2", v(2)
end end
def test_create
assert_equal req("= 1"), Gem::Requirement.create("= 1")
assert_equal req(">= 1.2", "<= 1.3"), Gem::Requirement.create([">= 1.2", "<= 1.3"])
assert_equal req(">= 1.2", "<= 1.3"), Gem::Requirement.create(">= 1.2", "<= 1.3")
end
def test_empty_requirements_is_none def test_empty_requirements_is_none
r = Gem::Requirement.new r = Gem::Requirement.new
assert_equal true, r.none? assert_equal true, r.none?

View file

@ -683,6 +683,32 @@ class TestGemResolver < Gem::TestCase
assert_resolves_to [b1, c1, d2], r assert_resolves_to [b1, c1, d2], r
end end
def test_sorts_by_source_then_version
sourceA = Gem::Source.new 'http://example.com/a'
sourceB = Gem::Source.new 'http://example.com/b'
sourceC = Gem::Source.new 'http://example.com/c'
spec_A_1 = new_spec 'some-dep', '0.0.1'
spec_A_2 = new_spec 'some-dep', '1.0.0'
spec_B_1 = new_spec 'some-dep', '0.0.1'
spec_B_2 = new_spec 'some-dep', '0.0.2'
spec_C_1 = new_spec 'some-dep', '0.1.0'
set = StaticSet.new [
Gem::Resolver::SpecSpecification.new(nil, spec_B_1, sourceB),
Gem::Resolver::SpecSpecification.new(nil, spec_B_2, sourceB),
Gem::Resolver::SpecSpecification.new(nil, spec_C_1, sourceC),
Gem::Resolver::SpecSpecification.new(nil, spec_A_2, sourceA),
Gem::Resolver::SpecSpecification.new(nil, spec_A_1, sourceA),
]
dependency = make_dep 'some-dep', '> 0'
resolver = Gem::Resolver.new [dependency], set
assert_resolves_to [spec_B_2], resolver
end
def test_select_local_platforms def test_select_local_platforms
r = Gem::Resolver.new nil, nil r = Gem::Resolver.new nil, nil

View file

@ -15,7 +15,7 @@ class TestGemResolverConflict < Gem::TestCase
dep = Gem::Resolver::DependencyRequest.new dep('net-ssh', '>= 2.0.13'), nil dep = Gem::Resolver::DependencyRequest.new dep('net-ssh', '>= 2.0.13'), nil
spec = quick_spec 'net-ssh', '2.2.2' spec = util_spec 'net-ssh', '2.2.2'
active = active =
Gem::Resolver::ActivationRequest.new spec, dep Gem::Resolver::ActivationRequest.new spec, dep

View file

@ -61,6 +61,7 @@ class TestGemSecurity < Gem::TestCase
cert = @SEC.create_cert_self_signed subject, PRIVATE_KEY, 60 cert = @SEC.create_cert_self_signed subject, PRIVATE_KEY, 60
assert_equal '/CN=nobody/DC=example', cert.issuer.to_s assert_equal '/CN=nobody/DC=example', cert.issuer.to_s
assert_equal "sha256WithRSAEncryption", cert.signature_algorithm
end end
def test_class_create_cert_email def test_class_create_cert_email
@ -120,6 +121,7 @@ class TestGemSecurity < Gem::TestCase
end end
def test_class_re_sign def test_class_re_sign
assert_equal "sha1WithRSAEncryption", EXPIRED_CERT.signature_algorithm
re_signed = Gem::Security.re_sign EXPIRED_CERT, PRIVATE_KEY, 60 re_signed = Gem::Security.re_sign EXPIRED_CERT, PRIVATE_KEY, 60
assert_in_delta Time.now, re_signed.not_before, 10 assert_in_delta Time.now, re_signed.not_before, 10
@ -127,6 +129,7 @@ class TestGemSecurity < Gem::TestCase
assert_equal EXPIRED_CERT.serial + 1, re_signed.serial assert_equal EXPIRED_CERT.serial + 1, re_signed.serial
assert re_signed.verify PUBLIC_KEY assert re_signed.verify PUBLIC_KEY
assert_equal "sha256WithRSAEncryption", re_signed.signature_algorithm
end end
def test_class_re_sign_not_self_signed def test_class_re_sign_not_self_signed
@ -218,6 +221,8 @@ class TestGemSecurity < Gem::TestCase
assert_in_delta Time.now, signed.not_before, 10 assert_in_delta Time.now, signed.not_before, 10
assert_in_delta Time.now + 60, signed.not_after, 10 assert_in_delta Time.now + 60, signed.not_after, 10
assert_equal "sha256WithRSAEncryption", signed.signature_algorithm
assert_equal 5, signed.extensions.length, assert_equal 5, signed.extensions.length,
signed.extensions.map { |e| e.to_a.first } signed.extensions.map { |e| e.to_a.first }

View file

@ -1,4 +1,4 @@
# coding: UTF-8 # coding: utf-8
# frozen_string_literal: true # frozen_string_literal: true
require 'rubygems/test_case' require 'rubygems/test_case'
@ -34,7 +34,7 @@ class TestGemSecurityPolicy < Gem::TestCase
s.files = %w[lib/code.rb] s.files = %w[lib/code.rb]
end end
@sha1 = OpenSSL::Digest::SHA1 @digest = Gem::Security::DIGEST_ALGORITHM
@trust_dir = Gem::Security.trust_dir.dir # HACK use the object @trust_dir = Gem::Security.trust_dir.dir # HACK use the object
@no = Gem::Security::NoSecurity @no = Gem::Security::NoSecurity
@ -69,7 +69,7 @@ class TestGemSecurityPolicy < Gem::TestCase
signature = sign data signature = sign data
assert @almost_no.check_data(PUBLIC_KEY, @sha1, signature, data) assert @almost_no.check_data(PUBLIC_KEY, @digest, signature, data)
end end
def test_check_data_invalid def test_check_data_invalid
@ -80,7 +80,7 @@ class TestGemSecurityPolicy < Gem::TestCase
invalid = digest 'hello!' invalid = digest 'hello!'
e = assert_raises Gem::Security::Exception do e = assert_raises Gem::Security::Exception do
@almost_no.check_data PUBLIC_KEY, @sha1, signature, invalid @almost_no.check_data PUBLIC_KEY, @digest, signature, invalid
end end
assert_equal 'invalid signature', e.message assert_equal 'invalid signature', e.message
@ -238,18 +238,18 @@ class TestGemSecurityPolicy < Gem::TestCase
def test_check_trust def test_check_trust
Gem::Security.trust_dir.trust_cert PUBLIC_CERT Gem::Security.trust_dir.trust_cert PUBLIC_CERT
assert @high.check_trust [PUBLIC_CERT], @sha1, @trust_dir assert @high.check_trust [PUBLIC_CERT], @digest, @trust_dir
end end
def test_check_trust_child def test_check_trust_child
Gem::Security.trust_dir.trust_cert PUBLIC_CERT Gem::Security.trust_dir.trust_cert PUBLIC_CERT
assert @high.check_trust [PUBLIC_CERT, CHILD_CERT], @sha1, @trust_dir assert @high.check_trust [PUBLIC_CERT, CHILD_CERT], @digest, @trust_dir
end end
def test_check_trust_empty_chain def test_check_trust_empty_chain
e = assert_raises Gem::Security::Exception do e = assert_raises Gem::Security::Exception do
@chain.check_trust [], @sha1, @trust_dir @chain.check_trust [], @digest, @trust_dir
end end
assert_equal 'missing root certificate', e.message assert_equal 'missing root certificate', e.message
@ -259,7 +259,7 @@ class TestGemSecurityPolicy < Gem::TestCase
Gem::Security.trust_dir.trust_cert PUBLIC_CERT Gem::Security.trust_dir.trust_cert PUBLIC_CERT
e = assert_raises Gem::Security::Exception do e = assert_raises Gem::Security::Exception do
@high.check_trust [WRONG_KEY_CERT], @sha1, @trust_dir @high.check_trust [WRONG_KEY_CERT], @digest, @trust_dir
end end
assert_equal "trusted root certificate #{PUBLIC_CERT.subject} checksum " + assert_equal "trusted root certificate #{PUBLIC_CERT.subject} checksum " +
@ -268,7 +268,7 @@ class TestGemSecurityPolicy < Gem::TestCase
def test_check_trust_no_chain def test_check_trust_no_chain
e = assert_raises Gem::Security::Exception do e = assert_raises Gem::Security::Exception do
@chain.check_trust nil, @sha1, @trust_dir @chain.check_trust nil, @digest, @trust_dir
end end
assert_equal 'missing signing chain', e.message assert_equal 'missing signing chain', e.message
@ -276,7 +276,7 @@ class TestGemSecurityPolicy < Gem::TestCase
def test_check_trust_no_trust def test_check_trust_no_trust
e = assert_raises Gem::Security::Exception do e = assert_raises Gem::Security::Exception do
@high.check_trust [PUBLIC_CERT], @sha1, @trust_dir @high.check_trust [PUBLIC_CERT], @digest, @trust_dir
end end
assert_equal "root cert #{PUBLIC_CERT.subject} is not trusted", e.message assert_equal "root cert #{PUBLIC_CERT.subject} is not trusted", e.message
@ -284,7 +284,7 @@ class TestGemSecurityPolicy < Gem::TestCase
def test_check_trust_no_trust_child def test_check_trust_no_trust_child
e = assert_raises Gem::Security::Exception do e = assert_raises Gem::Security::Exception do
@high.check_trust [PUBLIC_CERT, CHILD_CERT], @sha1, @trust_dir @high.check_trust [PUBLIC_CERT, CHILD_CERT], @digest, @trust_dir
end end
assert_equal "root cert #{PUBLIC_CERT.subject} is not trusted " + assert_equal "root cert #{PUBLIC_CERT.subject} is not trusted " +
@ -370,7 +370,7 @@ class TestGemSecurityPolicy < Gem::TestCase
data = digest 'goodbye' data = digest 'goodbye'
signatures[1] = PRIVATE_KEY.sign @sha1.new, data.digest signatures[1] = PRIVATE_KEY.sign @digest.new, data.digest
e = assert_raises Gem::Security::Exception do e = assert_raises Gem::Security::Exception do
@almost_no.verify [PUBLIC_CERT], nil, digests, signatures @almost_no.verify [PUBLIC_CERT], nil, digests, signatures
@ -453,17 +453,17 @@ class TestGemSecurityPolicy < Gem::TestCase
metadata_gz = Gem.gzip @spec.to_yaml metadata_gz = Gem.gzip @spec.to_yaml
package = Gem::Package.new 'nonexistent.gem' package = Gem::Package.new 'nonexistent.gem'
package.checksums['SHA1'] = {} package.checksums[Gem::Security::DIGEST_NAME] = {}
s = StringIO.new metadata_gz s = StringIO.new metadata_gz
def s.full_name() 'metadata.gz' end def s.full_name() 'metadata.gz' end
digests = package.digest s digests = package.digest s
metadata_gz_digest = digests['SHA1']['metadata.gz'] metadata_gz_digest = digests[Gem::Security::DIGEST_NAME]['metadata.gz']
signatures = {} signatures = {}
signatures['metadata.gz'] = signatures['metadata.gz'] =
PRIVATE_KEY.sign @sha1.new, metadata_gz_digest.digest PRIVATE_KEY.sign @digest.new, metadata_gz_digest.digest
assert @high.verify_signatures @spec, digests, signatures assert @high.verify_signatures @spec, digests, signatures
end end
@ -476,19 +476,19 @@ class TestGemSecurityPolicy < Gem::TestCase
metadata_gz = Gem.gzip @spec.to_yaml metadata_gz = Gem.gzip @spec.to_yaml
package = Gem::Package.new 'nonexistent.gem' package = Gem::Package.new 'nonexistent.gem'
package.checksums['SHA1'] = {} package.checksums[Gem::Security::DIGEST_NAME] = {}
s = StringIO.new metadata_gz s = StringIO.new metadata_gz
def s.full_name() 'metadata.gz' end def s.full_name() 'metadata.gz' end
digests = package.digest s digests = package.digest s
digests['SHA1']['data.tar.gz'] = OpenSSL::Digest.new 'SHA1', 'hello' digests[Gem::Security::DIGEST_NAME]['data.tar.gz'] = @digest.new 'hello'
metadata_gz_digest = digests['SHA1']['metadata.gz'] metadata_gz_digest = digests[Gem::Security::DIGEST_NAME]['metadata.gz']
signatures = {} signatures = {}
signatures['metadata.gz'] = signatures['metadata.gz'] =
PRIVATE_KEY.sign @sha1.new, metadata_gz_digest.digest PRIVATE_KEY.sign @digest.new, metadata_gz_digest.digest
e = assert_raises Gem::Security::Exception do e = assert_raises Gem::Security::Exception do
@high.verify_signatures @spec, digests, signatures @high.verify_signatures @spec, digests, signatures
@ -505,13 +505,13 @@ class TestGemSecurityPolicy < Gem::TestCase
metadata_gz = Gem.gzip @spec.to_yaml metadata_gz = Gem.gzip @spec.to_yaml
package = Gem::Package.new 'nonexistent.gem' package = Gem::Package.new 'nonexistent.gem'
package.checksums['SHA1'] = {} package.checksums[Gem::Security::DIGEST_NAME] = {}
s = StringIO.new metadata_gz s = StringIO.new metadata_gz
def s.full_name() 'metadata.gz' end def s.full_name() 'metadata.gz' end
digests = package.digest s digests = package.digest s
digests['SHA1']['data.tar.gz'] = OpenSSL::Digest.new 'SHA1', 'hello' digests[Gem::Security::DIGEST_NAME]['data.tar.gz'] = @digest.new 'hello'
assert_raises Gem::Security::Exception do assert_raises Gem::Security::Exception do
@high.verify_signatures @spec, digests, {} @high.verify_signatures @spec, digests, {}
@ -519,19 +519,19 @@ class TestGemSecurityPolicy < Gem::TestCase
end end
def digest data def digest data
digester = @sha1.new digester = @digest.new
digester << data digester << data
digester digester
end end
def sign data, key = PRIVATE_KEY def sign data, key = PRIVATE_KEY
key.sign @sha1.new, data.digest key.sign @digest.new, data.digest
end end
def dummy_signatures key = PRIVATE_KEY def dummy_signatures key = PRIVATE_KEY
data = digest 'hello' data = digest 'hello'
digests = { 'SHA1' => { 0 => data } } digests = { Gem::Security::DIGEST_NAME => { 0 => data } }
signatures = { 0 => sign(data, key) } signatures = { 0 => sign(data, key) }
return digests, signatures return digests, signatures

View file

@ -121,12 +121,12 @@ class TestGemSecuritySigner < Gem::TestCase
signature = signer.sign 'hello' signature = signer.sign 'hello'
expected = <<-EXPECTED expected = <<-EXPECTED
pxSf9ScaghbMNmNp8fqSJj7BiIGpbuoOVYCOM3TJNH9STLILA5z3xKp3gM6w cHze2sEfRysoUMCfGVAx/7o8jxj5liJJ2ptNxe2jf3l+EZvyjdqpXo9Ndzxx
VJ7aGsh9KCP485ftS3J9Kb/lKJsyoSkkRSQ5QG+LnyZwMuWlThPDR5o7q6al 6xLp2rxLG4K2//ip4aCH5Sh7hnia+F5u6iuLBETPlklPrmw5dnuKZxolz+vM
0oxE7vvbbqxFqcT4ojWIkwxJxOluFWmt2D8I6QTX2vLAn09y+Kl66AOrT7R5 0O1aOZsQHcVzQoESTGjkms3KZk+gn3lg0sSBbAV5/LyDYoHCEjxlcA5D+Olb
UinbXkz04VwcNvkBqJyko3yWxFKiGNpntZQg4jIw4L+h97EOaZp8H96udzQH rDmRyBMOnMS+q489OZ5Hr6B2YJJ3QbUwIZNhUeNmOxIBEYTrrKkZ92qkxbRN
Da3K0YZ6FsqLDFNnWAFhve3kmpE3CludpvDqH0piq0zKqnOiqAcvICIpPaJP qhlqFP4jR6zXFeyBCOr0KpTiWBNuxBFXDsxmhGyt2BOIjD6qmKn7RSIfYg/U
c7NM7KZZjj7G++SXjYTEI1PHSA7aFQ/i/+qSUvx+Pg== toqvglr0kdbknSRRjBVLK6tsgr07aLT9gNP7mTW2PA==
EXPECTED EXPECTED
assert_equal expected, [signature].pack('m') assert_equal expected, [signature].pack('m')

View file

@ -18,7 +18,7 @@ class TestGemSecurityTrustDir < Gem::TestCase
end end
def test_cert_path def test_cert_path
digest = OpenSSL::Digest::SHA1.hexdigest PUBLIC_CERT.subject.to_s digest = Gem::Security::DIGEST_ALGORITHM.hexdigest PUBLIC_CERT.subject.to_s
expected = File.join @dest_dir, "cert-#{digest}.pem" expected = File.join @dest_dir, "cert-#{digest}.pem"
@ -42,7 +42,7 @@ class TestGemSecurityTrustDir < Gem::TestCase
end end
def test_name_path def test_name_path
digest = OpenSSL::Digest::SHA1.hexdigest PUBLIC_CERT.subject.to_s digest = Gem::Security::DIGEST_ALGORITHM.hexdigest PUBLIC_CERT.subject.to_s
expected = File.join @dest_dir, "cert-#{digest}.pem" expected = File.join @dest_dir, "cert-#{digest}.pem"

View file

@ -222,7 +222,7 @@ class TestGemServer < Gem::TestCase
assert_equal 404, @res.status, @res.body assert_equal 404, @res.status, @res.body
assert_match %r| \d\d:\d\d:\d\d |, @res['date'] assert_match %r| \d\d:\d\d:\d\d |, @res['date']
assert_equal 'text/plain', @res['content-type'] assert_equal 'text/plain', @res['content-type']
assert_equal 'No gems found matching "z" "9" nil', @res.body assert_equal 'No gems found matching "z-9"', @res.body
assert_equal 404, @res.status assert_equal 404, @res.status
end end
@ -291,6 +291,23 @@ class TestGemServer < Gem::TestCase
assert_equal v('3.a'), spec.version assert_equal v('3.a'), spec.version
end end
def test_quick_marshal_a_b_1_3_a_gemspec_rz
quick_gem 'a-b-1', '3.a'
data = StringIO.new "GET /quick/Marshal.#{Gem.marshal_version}/a-b-1-3.a.gemspec.rz HTTP/1.0\r\n\r\n"
@req.parse data
@server.quick @req, @res
assert_equal 200, @res.status, @res.body
assert @res['date']
assert_equal 'application/x-deflate', @res['content-type']
spec = Marshal.load Gem.inflate(@res.body)
assert_equal 'a-b-1', spec.name
assert_equal v('3.a'), spec.version
end
def test_rdoc def test_rdoc
data = StringIO.new "GET /rdoc?q=a HTTP/1.0\r\n\r\n" data = StringIO.new "GET /rdoc?q=a HTTP/1.0\r\n\r\n"
@req.parse data @req.parse data

View file

@ -228,6 +228,15 @@ class TestGemSource < Gem::TestCase
assert_equal(-1, remote. <=>(no_uri), 'remote <=> no_uri') assert_equal(-1, remote. <=>(no_uri), 'remote <=> no_uri')
end end
def test_spaceship_order_is_preserved_when_uri_differs
sourceA = Gem::Source.new "http://example.com/a"
sourceB = Gem::Source.new "http://example.com/b"
assert_equal( 0, sourceA. <=>(sourceA), 'sourceA <=> sourceA')
assert_equal( 1, sourceA. <=>(sourceB), 'sourceA <=> sourceB')
assert_equal( 1, sourceB. <=>(sourceA), 'sourceB <=> sourceA')
end
def test_update_cache_eh def test_update_cache_eh
assert @source.update_cache? assert @source.update_cache?
end end

View file

@ -169,6 +169,26 @@ class TestGemSpecFetcher < Gem::TestCase
assert_equal "bad news from the internet (#{@gem_repo})", sfp.error.message assert_equal "bad news from the internet (#{@gem_repo})", sfp.error.message
end end
def test_suggest_gems_from_name_latest
spec_fetcher do|fetcher|
fetcher.spec 'example', 1
fetcher.spec 'other-example', 1
end
suggestions = @sf.suggest_gems_from_name('examplw')
assert_equal ['example'], suggestions
end
def test_suggest_gems_from_name_prerelease
spec_fetcher do|fetcher|
fetcher.spec 'example', '1.a'
fetcher.spec 'other-example', 1
end
suggestions = @sf.suggest_gems_from_name('examplw')
assert_equal ['example'], suggestions
end
def test_available_specs_latest def test_available_specs_latest
spec_fetcher do |fetcher| spec_fetcher do |fetcher|
fetcher.spec 'a', 1 fetcher.spec 'a', 1

View file

@ -1586,7 +1586,7 @@ dependencies: []
refute @ext.contains_requirable_file? 'nonexistent' refute @ext.contains_requirable_file? 'nonexistent'
end end
expected = "Ignoring ext-1 because its extensions are not built. " + expected = "Ignoring ext-1 because its extensions are not built. " +
"Try: gem pristine ext --version 1\n" "Try: gem pristine ext --version 1\n"
assert_equal expected, err assert_equal expected, err
@ -2748,14 +2748,6 @@ duplicate dependency on c (>= 1.2.3, development), (~> 1.2) use:
util_setup_validate util_setup_validate
Dir.chdir @tempdir do Dir.chdir @tempdir do
@a1.email = ""
use_ui @ui do
@a1.validate
end
assert_match "#{w}: no email specified\n", @ui.error, "error"
@a1.email = "FIxxxXME (your e-mail)".sub(/xxx/, "") @a1.email = "FIxxxXME (your e-mail)".sub(/xxx/, "")
e = assert_raises Gem::InvalidSpecificationException do e = assert_raises Gem::InvalidSpecificationException do
@ -2977,6 +2969,43 @@ Did you mean 'Ruby'?
warning warning
end end
def test_validate_empty_files
util_setup_validate
use_ui @ui do
# we have to set all of these for #files to be empty
@a1.files = []
@a1.test_files = []
@a1.executables = []
@a1.validate
end
assert_match "no files specified", @ui.error
end
def test_validate_empty_homepage
util_setup_validate
use_ui @ui do
@a1.homepage = nil
@a1.validate
end
assert_match "no homepage specified", @ui.error
end
def test_validate_empty_summary
util_setup_validate
use_ui @ui do
@a1.summary = nil
@a1.validate
end
assert_match "no summary specified", @ui.error
end
def test_validate_name def test_validate_name
util_setup_validate util_setup_validate
@ -3252,7 +3281,11 @@ Did you mean 'Ruby'?
Dir.chdir @tempdir do Dir.chdir @tempdir do
@m1 = quick_gem 'm', '1' do |s| @m1 = quick_gem 'm', '1' do |s|
s.files = %w[lib/code.rb] s.files = %w[lib/code.rb]
s.metadata = { 'one' => "two", 'two' => "three" } s.metadata = {
"one" => "two",
"home" => "three",
"homepage_uri" => "https://example.com/user/repo"
}
end end
use_ui @ui do use_ui @ui do
@ -3329,6 +3362,23 @@ Did you mean 'Ruby'?
end end
end end
def test_metadata_link_validation_fails
util_setup_validate
Dir.chdir @tempdir do
@m2 = quick_gem 'm', '2' do |s|
s.files = %w[lib/code.rb]
s.metadata = { 'homepage_uri' => 'http:/example.com' }
end
e = assert_raises Gem::InvalidSpecificationException do
@m2.validate
end
assert_equal "metadata['homepage_uri'] has invalid link: \"http:/example.com\"", e.message
end
end
def test_metadata_specs def test_metadata_specs
valid_ruby_spec = <<-EOF valid_ruby_spec = <<-EOF
# -*- encoding: utf-8 -*- # -*- encoding: utf-8 -*-
@ -3406,6 +3456,31 @@ end
refute @a1.missing_extensions? refute @a1.missing_extensions?
end end
def test_find_all_by_full_name
pl = Gem::Platform.new 'i386-linux'
a1 = util_spec "a", "1"
a1_pre = util_spec "a", "1.0.0.pre.1"
a_1_platform = util_spec("a", "1") {|s| s.platform = pl }
a_b_1 = util_spec "a-b", "1"
a_b_1_platform = util_spec("a-b", "1") {|s| s.platform = pl }
a_b_1_1 = util_spec "a-b-1", "1"
a_b_1_1_platform = util_spec("a-b-1", "1") {|s| s.platform = pl }
install_specs(a1, a1_pre, a_1_platform, a_b_1, a_b_1_platform,
a_b_1_1, a_b_1_1_platform)
assert_equal [a1], Gem::Specification.find_all_by_full_name("a-1")
assert_equal [a1_pre], Gem::Specification.find_all_by_full_name("a-1.0.0.pre.1")
assert_equal [a_1_platform], Gem::Specification.find_all_by_full_name("a-1-x86-linux")
assert_equal [a_b_1_1], Gem::Specification.find_all_by_full_name("a-b-1-1")
assert_equal [a_b_1_1_platform], Gem::Specification.find_all_by_full_name("a-b-1-1-x86-linux")
assert_equal [], Gem::Specification.find_all_by_full_name("monkeys")
assert_equal [], Gem::Specification.find_all_by_full_name("a-1-foo")
end
def test_find_by_name def test_find_by_name
install_specs util_spec "a" install_specs util_spec "a"
install_specs util_spec "a", 1 install_specs util_spec "a", 1

View file

@ -71,7 +71,7 @@ class TestStubSpecification < Gem::TestCase
refute stub.contains_requirable_file? 'nonexistent' refute stub.contains_requirable_file? 'nonexistent'
end end
expected = "Ignoring stub_e-2 because its extensions are not built. " + expected = "Ignoring stub_e-2 because its extensions are not built. " +
"Try: gem pristine stub_e --version 2\n" "Try: gem pristine stub_e --version 2\n"
assert_equal expected, err assert_equal expected, err
@ -95,6 +95,12 @@ class TestStubSpecification < Gem::TestCase
assert_equal File.join(stub.full_gem_path, 'lib'), stub.lib_dirs_glob assert_equal File.join(stub.full_gem_path, 'lib'), stub.lib_dirs_glob
end end
def test_lib_dirs_glob_with_extension
stub = stub_with_extension
assert_equal File.join(stub.full_gem_path, 'lib'), stub.lib_dirs_glob
end
def test_matches_for_glob def test_matches_for_glob
stub = stub_without_extension stub = stub_without_extension
code_rb = File.join stub.gem_dir, 'lib', 'code.rb' code_rb = File.join stub.gem_dir, 'lib', 'code.rb'

View file

@ -26,6 +26,7 @@ class TestGemUtil < Gem::TestCase
assert_equal File.join(@tempdir, 'a/b/c'), enum.next assert_equal File.join(@tempdir, 'a/b/c'), enum.next
assert_equal File.join(@tempdir, 'a/b'), enum.next assert_equal File.join(@tempdir, 'a/b'), enum.next
assert_equal File.join(@tempdir, 'a'), enum.next assert_equal File.join(@tempdir, 'a'), enum.next
loop { break if enum.next.nil? } # exhaust the enumerator
end end
def test_linked_list_find def test_linked_list_find

View file

@ -41,6 +41,11 @@ class TestGemVersion < Gem::TestCase
assert_equal v('1.1'), Gem::Version.create(ver) assert_equal v('1.1'), Gem::Version.create(ver)
end end
def test_class_correct
assert_equal true, Gem::Version.correct?("5.1")
assert_equal false, Gem::Version.correct?("an incorrect version")
end
def test_class_new_subclass def test_class_new_subclass
v1 = Gem::Version.new '1' v1 = Gem::Version.new '1'
v2 = V.new '1' v2 = V.new '1'
@ -65,7 +70,8 @@ class TestGemVersion < Gem::TestCase
def test_hash def test_hash
assert_equal v("1.2").hash, v("1.2").hash assert_equal v("1.2").hash, v("1.2").hash
refute_equal v("1.2").hash, v("1.3").hash refute_equal v("1.2").hash, v("1.3").hash
refute_equal v("1.2").hash, v("1.2.0").hash assert_equal v("1.2").hash, v("1.2.0").hash
assert_equal v("1.2.pre.1").hash, v("1.2.0.pre.1.0").hash
end end
def test_initialize def test_initialize
@ -76,18 +82,23 @@ class TestGemVersion < Gem::TestCase
assert_version_equal "1", 1 assert_version_equal "1", 1
end end
def test_initialize_bad def test_initialize_invalid
%W[ invalid_versions = %W[
junk junk
1.0\n2.0 1.0\n2.0
1..2 1..2
1.2\ 3.4 1.2\ 3.4
].each do |bad| ]
e = assert_raises ArgumentError, bad do
Gem::Version.new bad # DON'T TOUCH THIS WITHOUT CHECKING CVE-2013-4287
invalid_versions << "2.3422222.222.222222222.22222.ads0as.dasd0.ddd2222.2.qd3e."
invalid_versions.each do |invalid|
e = assert_raises ArgumentError, invalid do
Gem::Version.new invalid
end end
assert_equal "Malformed version number string #{bad}", e.message, bad assert_equal "Malformed version number string #{invalid}", e.message, invalid
end end
end end
@ -105,6 +116,9 @@ class TestGemVersion < Gem::TestCase
assert_prerelease '1.A' assert_prerelease '1.A'
assert_prerelease '1-1'
assert_prerelease '1-a'
refute_prerelease "1.2.0" refute_prerelease "1.2.0"
refute_prerelease "2.9" refute_prerelease "2.9"
refute_prerelease "22.1.50.0" refute_prerelease "22.1.50.0"
@ -160,6 +174,12 @@ class TestGemVersion < Gem::TestCase
assert_equal [9,8,7], v("9.8.7").segments assert_equal [9,8,7], v("9.8.7").segments
end end
def test_canonical_segments
assert_equal [1], v("1.0.0").canonical_segments
assert_equal [1, "a", 1], v("1.0.0.a.1.0").canonical_segments
assert_equal [1, 2, 3, "pre", 1], v("1.2.3-1").canonical_segments
end
# Asserts that +version+ is a prerelease. # Asserts that +version+ is a prerelease.
def assert_prerelease version def assert_prerelease version
@ -189,6 +209,7 @@ class TestGemVersion < Gem::TestCase
def assert_version_equal expected, actual def assert_version_equal expected, actual
assert_equal v(expected), v(actual) assert_equal v(expected), v(actual)
assert_equal v(expected).hash, v(actual).hash, "since #{actual} == #{expected}, they must have the same hash"
end end
# Assert that two versions are eql?. Checks both directions. # Assert that two versions are eql?. Checks both directions.

View file

@ -106,6 +106,21 @@ class TestGemVersionOption < Gem::TestCase
assert_equal expected, @cmd.options assert_equal expected, @cmd.options
end end
def test_multiple_version_operator_option_compound
@cmd.add_version_option
@cmd.handle_options ['--version', '< 1', '--version', '> 0.9']
expected = {
:args => [],
:explicit_prerelease => false,
:prerelease => false,
:version => Gem::Requirement.new('< 1', '> 0.9'),
}
assert_equal expected, @cmd.options
end
def test_version_option_explicit_prerelease def test_version_option_explicit_prerelease
@cmd.add_prerelease_option @cmd.add_prerelease_option
@cmd.add_version_option @cmd.add_version_option

View file

@ -90,4 +90,34 @@ class TestKernel < Gem::TestCase
assert gem('a', '= 1'), "Should load" assert gem('a', '= 1'), "Should load"
refute $:.any? { |p| %r{a-1/bin} =~ p } refute $:.any? { |p| %r{a-1/bin} =~ p }
end end
def test_gem_bundler
quick_gem 'bundler', '1'
quick_gem 'bundler', '2.a'
assert gem('bundler')
assert $:.any? { |p| %r{bundler-1/lib} =~ p }
end
def test_gem_bundler_missing_bundler_version
Gem::BundlerVersionFinder.stub(:bundler_version_with_reason, ["55", "reason"]) do
quick_gem 'bundler', '1'
quick_gem 'bundler', '2.a'
e = assert_raises Gem::MissingSpecVersionError do
gem('bundler')
end
assert_match "Could not find 'bundler' (55) required by reason.", e.message
end
end
def test_gem_bundler_inferred_bundler_version
Gem::BundlerVersionFinder.stub(:bundler_version_with_reason, ["1", "reason"]) do
quick_gem 'bundler', '1'
quick_gem 'bundler', '2.a'
assert gem('bundler', '>= 0.a')
assert $:.any? { |p| %r{bundler-1/lib} =~ p }
end
end
end end

View file

@ -383,6 +383,44 @@ class TestGemRequire < Gem::TestCase
assert_equal %w(a-1), loaded_spec_names assert_equal %w(a-1), loaded_spec_names
end end
def test_require_bundler
b1 = new_spec('bundler', '1', nil, "lib/bundler/setup.rb")
b2a = new_spec('bundler', '2.a', nil, "lib/bundler/setup.rb")
install_specs b1, b2a
require "rubygems/bundler_version_finder"
$:.clear
assert_require 'bundler/setup'
assert_equal %w[bundler-2.a], loaded_spec_names
assert_empty unresolved_names
end
def test_require_bundler_missing_bundler_version
Gem::BundlerVersionFinder.stub(:bundler_version_with_reason, ["55", "reason"]) do
b1 = new_spec('bundler', '1.999999999', nil, "lib/bundler/setup.rb")
b2a = new_spec('bundler', '2.a', nil, "lib/bundler/setup.rb")
install_specs b1, b2a
e = assert_raises Gem::MissingSpecVersionError do
gem('bundler')
end
assert_match "Could not find 'bundler' (55) required by reason.", e.message
end
end
def test_require_bundler_with_bundler_version
Gem::BundlerVersionFinder.stub(:bundler_version_with_reason, ["1", "reason"]) do
b1 = new_spec('bundler', '1.999999999', nil, "lib/bundler/setup.rb")
b2 = new_spec('bundler', '2', nil, "lib/bundler/setup.rb")
install_specs b1, b2
$:.clear
assert_require 'bundler/setup'
assert_equal %w[bundler-1.999999999], loaded_spec_names
end
end
def silence_warnings def silence_warnings
old_verbose, $VERBOSE = $VERBOSE, false old_verbose, $VERBOSE = $VERBOSE, false
yield yield