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

Update to RubyGems 1.3.4 r2223

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@23659 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
drbrain 2009-06-09 21:38:59 +00:00
parent a6afbaeb3b
commit 31c94ffeb5
126 changed files with 7610 additions and 3747 deletions

View file

@ -1,3 +1,7 @@
Wed Jun 10 06:28:15 2009 Eric Hodel <drbrain@segment7.net>
* lib/rubygems*: Upgrade to RubyGems 1.3.4 r2223.
Tue Jun 9 22:38:09 2009 Tadayoshi Funaba <tadf@dotrb.org> Tue Jun 9 22:38:09 2009 Tadayoshi Funaba <tadf@dotrb.org>
* lib/cmath.rb (log10): raised exception when the given number is * lib/cmath.rb (log10): raised exception when the given number is

View file

@ -9,16 +9,13 @@ require 'rubygems'
require 'rubygems/gem_runner' require 'rubygems/gem_runner'
require 'rubygems/exceptions' require 'rubygems/exceptions'
required_version = Gem::Requirement.new "> 1.8.3" required_version = Gem::Requirement.new ">= 1.8.6"
unless required_version.satisfied_by? Gem.ruby_version then unless required_version.satisfied_by? Gem.ruby_version then
abort "Expected Ruby Version #{required_version}, was #{Gem.ruby_version}" abort "Expected Ruby Version #{required_version}, is #{Gem.ruby_version}"
end end
# We need to preserve the original ARGV to use for passing gem options args = ARGV.clone
# to source gems. If there is a -- in the line, strip all options after
# it...its for the source building process.
args = !ARGV.include?("--") ? ARGV.clone : ARGV[0...ARGV.index("--")]
begin begin
Gem::GemRunner.new.run args Gem::GemRunner.new.run args

View file

@ -6,8 +6,11 @@
# * Encoding.default_external does not reflects -E. # * Encoding.default_external does not reflects -E.
# * Should not expect Encoding.default_internal. # * Should not expect Encoding.default_internal.
# * Locale encoding is available. # * Locale encoding is available.
if defined?(Gem) then if defined?(Gem) then
# :stopdoc:
module Kernel module Kernel
def gem(gem_name, *version_requirements) def gem(gem_name, *version_requirements)
@ -18,20 +21,17 @@ if defined?(Gem) then
module Gem module Gem
class LoadError < ::LoadError
end
ConfigMap = { ConfigMap = {
:sitedir => RbConfig::CONFIG["sitedir"],
:ruby_version => RbConfig::CONFIG["ruby_version"],
:rubylibprefix => RbConfig::CONFIG["rubylibprefix"],
:libdir => RbConfig::CONFIG["libdir"],
:sitelibdir => RbConfig::CONFIG["sitelibdir"],
:arch => RbConfig::CONFIG["arch"],
:bindir => RbConfig::CONFIG["bindir"],
:EXEEXT => RbConfig::CONFIG["EXEEXT"], :EXEEXT => RbConfig::CONFIG["EXEEXT"],
:RUBY_SO_NAME => RbConfig::CONFIG["RUBY_SO_NAME"], :RUBY_SO_NAME => RbConfig::CONFIG["RUBY_SO_NAME"],
:ruby_install_name => RbConfig::CONFIG["ruby_install_name"] :arch => RbConfig::CONFIG["arch"],
:bindir => RbConfig::CONFIG["bindir"],
:libdir => RbConfig::CONFIG["libdir"],
:ruby_install_name => RbConfig::CONFIG["ruby_install_name"],
:ruby_version => RbConfig::CONFIG["ruby_version"],
:rubylibprefix => RbConfig::CONFIG["rubylibprefix"],
:sitedir => RbConfig::CONFIG["sitedir"],
:sitelibdir => RbConfig::CONFIG["sitelibdir"],
} }
def self.dir def self.dir
@ -67,24 +67,30 @@ if defined?(Gem) then
end end
def self.set_home(home) def self.set_home(home)
home = home.gsub File::ALT_SEPARATOR, File::SEPARATOR if File::ALT_SEPARATOR
@gem_home = home @gem_home = home
ensure_gem_subdirectories(@gem_home)
end end
def self.set_paths(gpaths) def self.set_paths(gpaths)
if gpaths if gpaths
@gem_path = gpaths.split(File::PATH_SEPARATOR) @gem_path = gpaths.split(File::PATH_SEPARATOR)
if File::ALT_SEPARATOR then
@gem_path.map! do |path|
path.gsub File::ALT_SEPARATOR, File::SEPARATOR
end
end
@gem_path << Gem.dir @gem_path << Gem.dir
else else
# TODO: should this be Gem.default_path instead?
@gem_path = [Gem.dir] @gem_path = [Gem.dir]
end end
@gem_path.uniq! @gem_path.uniq!
@gem_path.each do |gp| ensure_gem_subdirectories(gp) end
end
def self.ensure_gem_subdirectories(path)
end end
# begin rubygems/defaults
@post_install_hooks ||= [] @post_install_hooks ||= []
@post_uninstall_hooks ||= [] @post_uninstall_hooks ||= []
@ -106,8 +112,13 @@ if defined?(Gem) then
if defined? RUBY_FRAMEWORK_VERSION then if defined? RUBY_FRAMEWORK_VERSION then
File.join File.dirname(ConfigMap[:sitedir]), 'Gems', File.join File.dirname(ConfigMap[:sitedir]), 'Gems',
ConfigMap[:ruby_version] ConfigMap[:ruby_version]
# 1.9.2dev reverted to 1.8 style path
elsif RUBY_VERSION > '1.9' and RUBY_VERSION < '1.9.2' then
File.join(ConfigMap[:libdir], ConfigMap[:ruby_install_name], 'gems',
ConfigMap[:ruby_version])
else else
ConfigMap[:sitelibdir].sub(%r'/site_ruby/(?=[^/]+)', '/gems/') File.join(ConfigMap[:libdir], ruby_engine, 'gems',
ConfigMap[:ruby_version])
end end
end end
@ -123,15 +134,25 @@ if defined?(Gem) then
# Default gem load path # Default gem load path
def self.default_path def self.default_path
if File.exist?(Gem.user_home)
[user_dir, default_dir] [user_dir, default_dir]
else
[default_dir]
end
end end
## ##
# Deduce Ruby's --program-prefix and --program-suffix from its install name # Deduce Ruby's --program-prefix and --program-suffix from its install name
def self.default_exec_format def self.default_exec_format
baseruby = ConfigMap[:BASERUBY] || 'ruby' exec_format = ConfigMap[:ruby_install_name].sub('ruby', '%s') rescue '%s'
ConfigMap[:RUBY_INSTALL_NAME].sub(baseruby, '%s') rescue '%s'
unless exec_format =~ /%s/ then
raise Gem::Exception,
"[BUG] invalid exec_format #{exec_format.inspect}, no %s"
end
exec_format
end end
## ##
@ -171,7 +192,9 @@ if defined?(Gem) then
end end
# end rubygems/defaults
##
# Methods before this line will be removed when QuickLoader is replaced # Methods before this line will be removed when QuickLoader is replaced
# with the real RubyGems # with the real RubyGems
@ -179,7 +202,7 @@ if defined?(Gem) then
begin begin
verbose, debug = $VERBOSE, $DEBUG verbose, debug = $VERBOSE, $DEBUG
$DEBUG = $VERBOSE = nil $VERBOSE = $DEBUG = nil
begin begin
require 'rubygems/defaults/operating_system' require 'rubygems/defaults/operating_system'
@ -226,14 +249,14 @@ if defined?(Gem) then
def push_gem_version_on_load_path(gem_name, *version_requirements) def push_gem_version_on_load_path(gem_name, *version_requirements)
if version_requirements.empty? if version_requirements.empty?
unless GemPaths.has_key?(gem_name) unless GemPaths.has_key?(gem_name) then
raise Gem::LoadError.new("Could not find RubyGem #{gem_name} (>= 0)\n") raise Gem::LoadError, "Could not find RubyGem #{gem_name} (>= 0)\n"
end end
# highest version gems already active # highest version gems already active
return false return false
else else
if version_requirements.length > 1 if version_requirements.length > 1 then
QuickLoader.load_full_rubygems_library QuickLoader.load_full_rubygems_library
return gem(gem_name, *version_requirements) return gem(gem_name, *version_requirements)
end end
@ -241,26 +264,24 @@ if defined?(Gem) then
requirement, version = version_requirements[0].split requirement, version = version_requirements[0].split
requirement.strip! requirement.strip!
if loaded_version = GemVersions[gem_name] if loaded_version = GemVersions[gem_name] then
case requirement case requirement
when ">", ">=" when ">", ">=" then
if (loaded_version <=> Gem.calculate_integers_for_gem_version(version)) >= 0 return false if
return false (loaded_version <=> Gem.integers_for(version)) >= 0
end when "~>" then
when "~>" required_version = Gem.integers_for version
required_version = Gem.calculate_integers_for_gem_version(version)
if (loaded_version[0] == required_version[0]) return false if loaded_version.first == required_version.first
return false
end
end end
end end
QuickLoader.load_full_rubygems_library QuickLoader.load_full_rubygems_library
gem(gem_name, *version_requirements) gem gem_name, *version_requirements
end end
end end
def calculate_integers_for_gem_version(gem_version) def integers_for(gem_version)
numbers = gem_version.split(".").collect {|n| n.to_i} numbers = gem_version.split(".").collect {|n| n.to_i}
numbers.pop while numbers.last == 0 numbers.pop while numbers.last == 0
numbers << 0 if numbers.empty? numbers << 0 if numbers.empty?
@ -270,16 +291,20 @@ if defined?(Gem) then
def push_all_highest_version_gems_on_load_path def push_all_highest_version_gems_on_load_path
Gem.path.each do |path| Gem.path.each do |path|
gems_directory = File.join(path, "gems") gems_directory = File.join(path, "gems")
if File.exist?(gems_directory)
if File.exist?(gems_directory) then
Dir.entries(gems_directory).each do |gem_directory_name| Dir.entries(gems_directory).each do |gem_directory_name|
next if gem_directory_name == "." || gem_directory_name == ".." next if gem_directory_name == "." || gem_directory_name == ".."
dash = gem_directory_name.rindex("-") dash = gem_directory_name.rindex("-")
next if dash.nil? next if dash.nil?
gem_name = gem_directory_name[0...dash] gem_name = gem_directory_name[0...dash]
current_version = GemVersions[gem_name] current_version = GemVersions[gem_name]
new_version = calculate_integers_for_gem_version(gem_directory_name[dash+1..-1]) new_version = integers_for(gem_directory_name[dash+1..-1])
if current_version
if (current_version <=> new_version) == -1 if current_version then
if (current_version <=> new_version) == -1 then
GemVersions[gem_name] = new_version GemVersions[gem_name] = new_version
GemPaths[gem_name] = File.join(gems_directory, gem_directory_name) GemPaths[gem_name] = File.join(gems_directory, gem_directory_name)
end end
@ -309,7 +334,7 @@ if defined?(Gem) then
# "tag" the first require_path inserted into the $LOAD_PATH to enable # "tag" the first require_path inserted into the $LOAD_PATH to enable
# indexing correctly with rubygems proper when it inserts an explicitly # indexing correctly with rubygems proper when it inserts an explicitly
# gem version # gem version
unless require_paths.empty? unless require_paths.empty? then
require_paths.first.instance_variable_set(:@gem_prelude_index, true) require_paths.first.instance_variable_set(:@gem_prelude_index, true)
end end
# gem directories must come after -I and ENV['RUBYLIB'] # gem directories must come after -I and ENV['RUBYLIB']
@ -318,8 +343,9 @@ if defined?(Gem) then
def const_missing(constant) def const_missing(constant)
QuickLoader.load_full_rubygems_library QuickLoader.load_full_rubygems_library
if Gem.const_defined?(constant)
Gem.const_get(constant) if Gem.const_defined?(constant) then
Gem.const_get constant
else else
super super
end end

50
lib/gauntlet_rubygems.rb Normal file
View file

@ -0,0 +1,50 @@
require 'rubygems'
require 'gauntlet'
##
# GemGauntlet validates all current gems. Currently these packages are
# borked:
#
# Asami-0.04 : No such file or directory - bin/Asami.rb
# ObjectGraph-1.0.1 : No such file or directory - bin/objectgraph
# evil-ruby-0.1.0 : authors must be Array of Strings
# fresh_cookies-1.0.0 : authors must be Array of Strings
# plugems_deploy-0.2.0 : authors must be Array of Strings
# pmsrb-0.2.0 : authors must be Array of Strings
# pqa-1.6 : authors must be Array of Strings
# rant-0.5.7 : authors must be Array of Strings
# rvsh-0.4.5 : No such file or directory - bin/rvsh
# xen-0.1.2.1 : authors must be Array of Strings
class GemGauntlet < Gauntlet
def run(name)
warn name
spec = begin
Gem::Specification.load 'gemspec'
rescue SyntaxError
Gem::Specification.from_yaml File.read('gemspec')
end
spec.validate
self.data[name] = false
self.dirty = true
rescue SystemCallError, Gem::InvalidSpecificationException => e
self.data[name] = e.message
self.dirty = true
end
def should_skip?(name)
self.data[name] == false
end
def report
self.data.sort.reject { |k,v| !v }.each do |k,v|
puts "%-21s: %s" % [k, v]
end
end
end
gauntlet = GemGauntlet.new
gauntlet.run_the_gauntlet ARGV.shift
gauntlet.report

View file

@ -4,20 +4,17 @@
# See LICENSE.txt for permissions. # See LICENSE.txt for permissions.
#++ #++
module RbConfig module RbConfig
# Only define datadir if it doesn't already exist. ##
unless RbConfig.respond_to?(:datadir) # Return the path to the data directory associated with the given package
# name. Normally this is just
# "#{RbConfig::CONFIG['datadir']}/#{package_name}", but may be modified by
# packages like RubyGems to handle versioned data directories.
# Return the path to the data directory associated with the given def self.datadir(package_name)
# package name. Normally this is just
# "#{RbConfig::CONFIG['datadir']}/#{package_name}", but may be
# modified by packages like RubyGems to handle versioned data
# directories.
def RbConfig.datadir(package_name)
File.join(CONFIG['datadir'], package_name) File.join(CONFIG['datadir'], package_name)
end end unless RbConfig.respond_to?(:datadir)
end
end end

View file

@ -8,11 +8,29 @@
require 'rubygems/rubygems_version' require 'rubygems/rubygems_version'
require 'rubygems/defaults' require 'rubygems/defaults'
require 'thread' require 'thread'
require 'etc'
module Gem module Gem
##
# Raised when RubyGems is unable to load or activate a gem. Contains the
# name and version requirements of the gem that either conflicts with
# already activated gems or that RubyGems is otherwise unable to activate.
class LoadError < ::LoadError class LoadError < ::LoadError
attr_accessor :name, :version_requirement
##
# Name of gem
attr_accessor :name
##
# Version requirement of gem
attr_accessor :version_requirement
end end
end end
module Kernel module Kernel
@ -54,18 +72,102 @@ module Kernel
end end
## ##
# Main module to hold all RubyGem classes/modules. # RubyGems is the Ruby standard for publishing and managing third party
# libraries.
#
# For user documentation, see:
#
# * <tt>gem help</tt> and <tt>gem help [command]</tt>
# * {RubyGems User Guide}[http://docs.rubygems.org/read/book/1]
# * {Frequently Asked Questions}[http://docs.rubygems.org/read/book/3]
#
# For gem developer documentation see:
#
# * {Creating Gems}[http://docs.rubygems.org/read/chapter/5]
# * Gem::Specification
#
# Further RubyGems documentation can be found at:
#
# * {RubyGems API}[http://rubygems.rubyforge.org/rdoc] (also available from
# <tt>gem server</tt>)
# * {RubyGems Bookshelf}[http://rubygem.org]
#
# == RubyGems Plugins
#
# As of RubyGems 1.3.2, RubyGems will load plugins installed in gems or
# $LOAD_PATH. Plugins must be named 'rubygems_plugin' are discovered via
# Gem::find_files then loaded. Take care when implementing a plugin as your
# plugin file may be loaded multiple times if multiple versions of your gem
# are installed.
#
# For an example plugin, see the graph gem which adds a `gem graph` command.
#
# == RubyGems Defaults, Packaging
#
# RubyGems defaults are stored in rubygems/defaults.rb. If you're packaging
# RubyGems or implementing Ruby you can change RubyGems' defaults.
#
# For RubyGems packagers, provide lib/rubygems/operating_system.rb and
# override any defaults from lib/rubygems/defaults.rb.
#
# For Ruby implementers, provide lib/rubygems/#{RUBY_ENGINE}.rb and override
# any defaults from lib/rubygems/defaults.rb.
#
# 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.
# See Gem::pre_install, Gem::pre_uninstall, Gem::post_install,
# Gem::post_uninstall.
#
# == Bugs
#
# You can submit bugs to the
# {RubyGems bug tracker}[http://rubyforge.org/tracker/?atid=575&group_id=126&func=browse]
# on RubyForge
#
# == Credits
#
# RubyGems is currently maintained by Eric Hodel.
#
# RubyGems was originally developed at RubyConf 2003 by:
#
# * Rich Kilmer -- rich(at)infoether.com
# * Chad Fowler -- chad(at)chadfowler.com
# * David Black -- dblack(at)wobblini.net
# * Paul Brannan -- paul(at)atdesk.com
# * Jim Weirch -- {jim(at)weirichhouse.org}[mailto:jim@weirichhouse.org]
#
# Contributors:
#
# * Gavin Sinclair -- gsinclair(at)soyabean.com.au
# * George Marrows -- george.marrows(at)ntlworld.com
# * Dick Davies -- rasputnik(at)hellooperator.net
# * Mauricio Fernandez -- batsman.geo(at)yahoo.com
# * Simon Strandgaard -- neoneye(at)adslhome.dk
# * Dave Glasser -- glasser(at)mit.edu
# * Paul Duncan -- pabs(at)pablotron.org
# * Ville Aine -- vaine(at)cs.helsinki.fi
# * Eric Hodel -- drbrain(at)segment7.net
# * Daniel Berger -- djberg96(at)gmail.com
# * Phil Hagelberg -- technomancy(at)gmail.com
# * Ryan Davis
#
# (If your name is missing, PLEASE let us know!)
#
# Thanks!
#
# -The RubyGems Team
module Gem module Gem
##
# Configuration settings from ::RbConfig
ConfigMap = {} unless defined?(ConfigMap) ConfigMap = {} unless defined?(ConfigMap)
require 'rbconfig' require 'rbconfig'
RbConfig = Config unless defined? ::RbConfig
ConfigMap.merge!( ConfigMap.merge!(
:BASERUBY => RbConfig::CONFIG["BASERUBY"],
:EXEEXT => RbConfig::CONFIG["EXEEXT"], :EXEEXT => RbConfig::CONFIG["EXEEXT"],
:RUBY_INSTALL_NAME => RbConfig::CONFIG["RUBY_INSTALL_NAME"],
:RUBY_SO_NAME => RbConfig::CONFIG["RUBY_SO_NAME"], :RUBY_SO_NAME => RbConfig::CONFIG["RUBY_SO_NAME"],
:arch => RbConfig::CONFIG["arch"], :arch => RbConfig::CONFIG["arch"],
:bindir => RbConfig::CONFIG["bindir"], :bindir => RbConfig::CONFIG["bindir"],
@ -79,11 +181,16 @@ module Gem
:vendorlibdir => RbConfig::CONFIG["vendorlibdir"] :vendorlibdir => RbConfig::CONFIG["vendorlibdir"]
) )
##
# Default directories in a gem repository
DIRECTORIES = %w[cache doc gems specifications] unless defined?(DIRECTORIES) DIRECTORIES = %w[cache doc gems specifications] unless defined?(DIRECTORIES)
# :stopdoc:
MUTEX = Mutex.new MUTEX = Mutex.new
RubyGemsPackageVersion = RubyGemsVersion RubyGemsPackageVersion = RubyGemsVersion
# :startdoc:
## ##
# An Array of Regexps that match windows ruby platforms. # An Array of Regexps that match windows ruby platforms.
@ -102,6 +209,7 @@ module Gem
@configuration = nil @configuration = nil
@loaded_specs = {} @loaded_specs = {}
@loaded_stacks = {}
@platforms = [] @platforms = []
@ruby = nil @ruby = nil
@sources = [] @sources = []
@ -128,6 +236,14 @@ module Gem
# Gem::Requirement and Gem::Version documentation. # Gem::Requirement and Gem::Version documentation.
def self.activate(gem, *version_requirements) def self.activate(gem, *version_requirements)
if version_requirements.last.is_a?(Hash)
options = version_requirements.pop
else
options = {}
end
sources = options[:sources] || []
if version_requirements.empty? then if version_requirements.empty? then
version_requirements = Gem::Requirement.default version_requirements = Gem::Requirement.default
end end
@ -146,8 +262,18 @@ module Gem
existing_spec = @loaded_specs[gem.name] existing_spec = @loaded_specs[gem.name]
unless matches.any? { |spec| spec.version == existing_spec.version } then unless matches.any? { |spec| spec.version == existing_spec.version } then
raise Gem::Exception, sources_message = sources.map { |spec| spec.full_name }
"can't activate #{gem}, already activated #{existing_spec.full_name}" stack_message = @loaded_stacks[gem.name].map { |spec| spec.full_name }
msg = "can't activate #{gem} for #{sources_message.inspect}, "
msg << "already activated #{existing_spec.full_name} for "
msg << "#{stack_message.inspect}"
e = Gem::LoadError.new msg
e.name = gem.name
e.version_requirement = gem.version_requirements
raise e
end end
return false return false
@ -159,10 +285,11 @@ module Gem
spec.loaded = true spec.loaded = true
@loaded_specs[spec.name] = spec @loaded_specs[spec.name] = spec
@loaded_stacks[spec.name] = sources.dup
# Load dependent gems first # Load dependent gems first
spec.runtime_dependencies.each do |dep_gem| spec.runtime_dependencies.each do |dep_gem|
activate dep_gem activate dep_gem, :sources => [spec, *sources]
end end
# bin directory must come before library directories # bin directory must come before library directories
@ -227,6 +354,35 @@ module Gem
!Gem.source_index.search(gem).empty? !Gem.source_index.search(gem).empty?
end end
##
# Find the full path to the executable for gem +name+. If the +exec_name+
# is not given, the gem's default_executable is chosen, otherwise the
# specifed executable's path is returned. +version_requirements+ allows you
# to specify specific gem versions.
def self.bin_path(name, exec_name = nil, *version_requirements)
version_requirements = Gem::Requirement.default if
version_requirements.empty?
spec = Gem.source_index.find_name(name, version_requirements).last
raise Gem::GemNotFoundException,
"can't find gem #{name} (#{version_requirements})" unless spec
exec_name ||= spec.default_executable
unless exec_name
msg = "no default executable for #{spec.full_name}"
raise Gem::Exception, msg
end
unless spec.executables.include? exec_name
msg = "can't find executable #{exec_name} for #{spec.full_name}"
raise Gem::Exception, msg
end
File.join(spec.full_gem_path, spec.bindir, exec_name).sub(/.*\s.*/m, '"\&"')
end
## ##
# The mode needed to read a file as straight binary. # The mode needed to read a file as straight binary.
@ -351,14 +507,27 @@ module Gem
# #
# Gem.find_files('rdoc/discover').each do |path| load path end # Gem.find_files('rdoc/discover').each do |path| load path end
# #
# find_files does not search $LOAD_PATH for files, only gems. # find_files search $LOAD_PATH for files as well as gems.
#
# Note that find_files will return all files even if they are from different
# versions of the same gem.
def self.find_files(path) def self.find_files(path)
load_path_files = $LOAD_PATH.map do |load_path|
files = Dir["#{File.expand_path path, load_path}#{Gem.suffix_pattern}"]
files.select do |load_path_file|
File.file? load_path_file.untaint
end
end.flatten
specs = searcher.find_all path specs = searcher.find_all path
specs.map do |spec| specs_files = specs.map do |spec|
searcher.matching_files spec, path searcher.matching_files spec, path
end.flatten end.flatten
(load_path_files + specs_files).flatten.uniq
end end
## ##
@ -373,7 +542,17 @@ module Gem
# least on Win32). # least on Win32).
def self.find_home def self.find_home
File.expand_path("~") unless RUBY_VERSION > '1.9' then
['HOME', 'USERPROFILE'].each do |homekey|
return ENV[homekey] if ENV[homekey]
end
if ENV['HOMEDRIVE'] && ENV['HOMEPATH'] then
return "#{ENV['HOMEDRIVE']}#{ENV['HOMEPATH']}"
end
end
File.expand_path "~"
rescue rescue
if File::ALT_SEPARATOR then if File::ALT_SEPARATOR then
"C:/" "C:/"
@ -477,22 +656,13 @@ module Gem
# 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.
def self.location_of_caller def self.location_of_caller
caller[1] =~ /(.*?):(\d+)$/i caller[1] =~ /(.*?):(\d+).*?$/i
file = $1 file = $1
lineno = $2.to_i lineno = $2.to_i
[file, lineno] [file, lineno]
end end
##
# manage_gems is useless and deprecated. Don't call it anymore.
def self.manage_gems # :nodoc:
file, lineno = location_of_caller
warn "#{file}:#{lineno}:Warning: Gem::manage_gems is deprecated and will be removed on or after March 2009."
end
## ##
# The version of the Marshal format for your Ruby. # The version of the Marshal format for your Ruby.
@ -586,6 +756,33 @@ module Gem
end end
end end
##
# Promotes the load paths of the +gem_name+ over the load paths of
# +over_name+. Useful for allowing one gem to override features in another
# using #find_files.
def self.promote_load_path(gem_name, over_name)
gem = Gem.loaded_specs[gem_name]
over = Gem.loaded_specs[over_name]
raise ArgumentError, "gem #{gem_name} is not activated" if gem.nil?
raise ArgumentError, "gem #{over_name} is not activated" if over.nil?
last_gem_path = File.join gem.full_gem_path, gem.require_paths.last
over_paths = over.require_paths.map do |path|
File.join over.full_gem_path, path
end
over_paths.each do |path|
$LOAD_PATH.delete path
end
gem = $LOAD_PATH.index(last_gem_path) + 1
$LOAD_PATH.insert(gem, *over_paths)
end
## ##
# Refresh source_index from disk and clear searcher. # Refresh source_index from disk and clear searcher.
@ -628,15 +825,23 @@ module Gem
private_class_method :report_activate_error private_class_method :report_activate_error
def self.required_location(gemname, libfile, *version_constraints) ##
version_constraints = Gem::Requirement.default if version_constraints.empty? # Full path to +libfile+ in +gemname+. Searches for the latest gem unless
matches = Gem.source_index.find_name(gemname, version_constraints) # +requirements+ is given.
def self.required_location(gemname, libfile, *requirements)
requirements = Gem::Requirement.default if requirements.empty?
matches = Gem.source_index.find_name gemname, requirements
return nil if matches.empty? return nil if matches.empty?
spec = matches.last spec = matches.last
spec.require_paths.each do |path| spec.require_paths.each do |path|
result = File.join(spec.full_gem_path, path, libfile) result = File.join spec.full_gem_path, path, libfile
return result if File.exist?(result) return result if File.exist? result
end end
nil nil
end end
@ -662,7 +867,13 @@ module Gem
def self.ruby_version def self.ruby_version
return @ruby_version if defined? @ruby_version return @ruby_version if defined? @ruby_version
version = RUBY_VERSION.dup version = RUBY_VERSION.dup
version << ".#{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL
if defined?(RUBY_PATCHLEVEL) && RUBY_PATCHLEVEL != -1 then
version << ".#{RUBY_PATCHLEVEL}"
elsif defined?(RUBY_REVISION) then
version << ".dev.#{RUBY_REVISION}"
end
@ruby_version = Gem::Version.new version @ruby_version = Gem::Version.new version
end end
@ -679,7 +890,7 @@ module Gem
# Set the Gem home directory (as reported by Gem.dir). # Set the Gem home directory (as reported by Gem.dir).
def self.set_home(home) def self.set_home(home)
home = home.gsub(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR home = home.gsub File::ALT_SEPARATOR, File::SEPARATOR if File::ALT_SEPARATOR
@gem_home = home @gem_home = home
end end
@ -756,6 +967,31 @@ module Gem
['', '.rb', '.rbw', '.so', '.bundle', '.dll', '.sl', '.jar'] ['', '.rb', '.rbw', '.so', '.bundle', '.dll', '.sl', '.jar']
end end
##
# Prints the amount of time the supplied block takes to run using the debug
# UI output.
def self.time(msg, width = 0, display = Gem.configuration.verbose)
now = Time.now
value = yield
elapsed = Time.now - now
ui.say "%2$*1$s: %3$3.3fs" % [-width, msg, elapsed] if display
value
end
##
# Lazily loads DefaultUserInteraction and returns the default UI.
def self.ui
require 'rubygems/user_interaction'
Gem::DefaultUserInteraction.ui
end
## ##
# Use the +home+ and +paths+ values for Gem.dir and Gem.path. Used mainly # Use the +home+ and +paths+ values for Gem.dir and Gem.path. Used mainly
# by the unit tests to provide environment isolation. # by the unit tests to provide environment isolation.
@ -786,6 +1022,9 @@ module Gem
class << self class << self
##
# Hash of loaded Gem::Specification keyed by name
attr_reader :loaded_specs attr_reader :loaded_specs
## ##
@ -817,25 +1056,27 @@ module Gem
end end
##
# Location of Marshal quick gemspecs on remote repositories
MARSHAL_SPEC_DIR = "quick/Marshal.#{Gem.marshal_version}/" MARSHAL_SPEC_DIR = "quick/Marshal.#{Gem.marshal_version}/"
##
# Location of legacy YAML quick gemspecs on remote repositories
YAML_SPEC_DIR = 'quick/' YAML_SPEC_DIR = 'quick/'
end end
module RbConfig ##
# :stopdoc: # Return the path to the data directory associated with the named package. If
class << self # the package is loaded as a gem, return the gem specific data directory.
# Return the path to the data directory associated with the named # Otherwise return a path to the share area as define by
# package. If the package is loaded as a gem, return the gem # "#{ConfigMap[:datadir]}/#{package_name}".
# specific data directory. Otherwise return a path to the share
# area as define by "#{ConfigMap[:datadir]}/#{package_name}". def RbConfig.datadir(package_name)
def datadir(package_name)
Gem.datadir(package_name) || Gem.datadir(package_name) ||
File.join(Gem::ConfigMap[:datadir], package_name) File.join(Gem::ConfigMap[:datadir], package_name)
end
end
# :startdoc:
end end
require 'rubygems/exceptions' require 'rubygems/exceptions'
@ -866,3 +1107,14 @@ if RUBY_VERSION < '1.9' then
end end
Gem.clear_paths Gem.clear_paths
plugins = Gem.find_files 'rubygems_plugin'
plugins.each do |plugin|
begin
load plugin
rescue => e
warn "error loading #{plugin.inspect}: #{e.message} (#{e.class})"
end
end

View file

@ -4,20 +4,18 @@
# See LICENSE.txt for permissions. # See LICENSE.txt for permissions.
#++ #++
module Gem ##
# The Builder class processes RubyGem specification files
# to produce a .gem file.
## class Gem::Builder
# The Builder class processes RubyGem specification files
# to produce a .gem file.
#
class Builder
include UserInteraction include Gem::UserInteraction
## ##
# Constructs a builder instance for the provided specification # Constructs a builder instance for the provided specification
# #
# spec:: [Gem::Specification] The specification instance # spec:: [Gem::Specification] The specification instance
#
def initialize(spec) def initialize(spec)
require "yaml" require "yaml"
require "rubygems/package" require "rubygems/package"
@ -29,7 +27,7 @@ module Gem
## ##
# Builds the gem from the specification. Returns the name of the file # Builds the gem from the specification. Returns the name of the file
# written. # written.
#
def build def build
@spec.mark_version @spec.mark_version
@spec.validate @spec.validate
@ -50,17 +48,21 @@ EOM
private private
##
# If the signing key was specified, then load the file, and swap to the
# public key (TODO: we should probably just omit the signing key in favor of
# the signing certificate, but that's for the future, also the signature
# algorithm should be configurable)
def sign def sign
# if the signing key was specified, then load the file, and swap
# to the public key (TODO: we should probably just omit the
# signing key in favor of the signing certificate, but that's for
# the future, also the signature algorithm should be configurable)
signer = nil signer = nil
if @spec.respond_to?(:signing_key) && @spec.signing_key
signer = Gem::Security::Signer.new(@spec.signing_key, @spec.cert_chain) if @spec.respond_to?(:signing_key) and @spec.signing_key then
signer = Gem::Security::Signer.new @spec.signing_key, @spec.cert_chain
@spec.signing_key = nil @spec.signing_key = nil
@spec.cert_chain = signer.cert_chain.map { |cert| cert.to_s } @spec.cert_chain = signer.cert_chain.map { |cert| cert.to_s }
end end
signer signer
end end
@ -71,6 +73,7 @@ EOM
@spec.files.each do |file| @spec.files.each do |file|
next if File.directory? file next if File.directory? file
next if file == @spec.file_name # Don't add gem onto itself
stat = File.stat file stat = File.stat file
mode = stat.mode & 0777 mode = stat.mode & 0777
@ -83,6 +86,5 @@ EOM
end end
end end
end end
end
end end

View file

@ -5,38 +5,114 @@
#++ #++
require 'optparse' require 'optparse'
require 'rubygems/user_interaction' require 'rubygems/user_interaction'
module Gem ##
# Base class for all Gem commands. When creating a new gem command, define
# #new, #execute, #arguments, #defaults_str, #description and #usage
# (as appropriate). See the above mentioned methods for details.
#
# A very good example to look at is Gem::Commands::ContentsCommand
# Base class for all Gem commands. When creating a new gem command, define class Gem::Command
# #arguments, #defaults_str, #description and #usage (as appropriate).
class Command
include UserInteraction include Gem::UserInteraction
##
# The name of the command. # The name of the command.
attr_reader :command attr_reader :command
##
# The options for the command. # The options for the command.
attr_reader :options attr_reader :options
##
# The default options for the command. # The default options for the command.
attr_accessor :defaults attr_accessor :defaults
##
# The name of the command for command-line invocation. # The name of the command for command-line invocation.
attr_accessor :program_name attr_accessor :program_name
##
# A short description of the command. # A short description of the command.
attr_accessor :summary attr_accessor :summary
##
# Arguments used when building gems
def self.build_args
@build_args ||= []
end
def self.build_args=(value)
@build_args = value
end
def self.common_options
@common_options ||= []
end
def self.add_common_option(*args, &handler)
Gem::Command.common_options << [args, handler]
end
def self.extra_args
@extra_args ||= []
end
def self.extra_args=(value)
case value
when Array
@extra_args = value
when String
@extra_args = value.split
end
end
##
# Return an array of extra arguments for the command. The extra arguments
# come from the gem configuration file read at program startup.
def self.specific_extra_args(cmd)
specific_extra_args_hash[cmd]
end
##
# Add a list of extra arguments for the given command. +args+ may be an
# array or a string to be split on white space.
def self.add_specific_extra_args(cmd,args)
args = args.split(/\s+/) if args.kind_of? String
specific_extra_args_hash[cmd] = args
end
##
# Accessor for the specific extra args hash (self initializing).
def self.specific_extra_args_hash
@specific_extra_args_hash ||= Hash.new do |h,k|
h[k] = Array.new
end
end
##
# Initializes a generic gem command named +command+. +summary+ is a short # Initializes a generic gem command named +command+. +summary+ is a short
# description displayed in `gem help commands`. +defaults+ are the # description displayed in `gem help commands`. +defaults+ are the default
# default options. Defaults should be mirrored in #defaults_str, unless # options. Defaults should be mirrored in #defaults_str, unless there are
# there are none. # none.
# #
# Use add_option to add command-line switches. # When defining a new command subclass, use add_option to add command-line
# switches.
#
# Unhandled arguments (gem names, files, etc.) are left in
# <tt>options[:args]</tt>.
def initialize(command, summary=nil, defaults={}) def initialize(command, summary=nil, defaults={})
@command = command @command = command
@summary = summary @summary = summary
@ -48,18 +124,30 @@ module Gem
@when_invoked = nil @when_invoked = nil
end end
##
# True if +long+ begins with the characters from +short+. # True if +long+ begins with the characters from +short+.
def begins?(long, short) def begins?(long, short)
return false if short.nil? return false if short.nil?
long[0, short.length] == short long[0, short.length] == short
end end
##
# Override to provide command handling. # Override to provide command handling.
#
# #options will be filled in with your parsed options, unparsed options will
# be left in <tt>options[:args]</tt>.
#
# See also: #get_all_gem_names, #get_one_gem_name,
# #get_one_optional_argument
def execute def execute
fail "Generic command has no actions" raise Gem::Exception, "generic command has no actions"
end end
##
# Get all gem names from the command line. # Get all gem names from the command line.
def get_all_gem_names def get_all_gem_names
args = options[:args] args = options[:args]
@ -71,8 +159,10 @@ module Gem
gem_names = args.select { |arg| arg !~ /^-/ } gem_names = args.select { |arg| arg !~ /^-/ }
end end
##
# Get the single gem name from the command line. Fail if there is no gem # Get the single gem name from the command line. Fail if there is no gem
# name or if there is more than one gem name given. # name or if there is more than one gem name given.
def get_one_gem_name def get_one_gem_name
args = options[:args] args = options[:args]
@ -89,43 +179,74 @@ module Gem
args.first args.first
end end
##
# Get a single optional argument from the command line. If more than one # Get a single optional argument from the command line. If more than one
# argument is given, return only the first. Return nil if none are given. # argument is given, return only the first. Return nil if none are given.
def get_one_optional_argument def get_one_optional_argument
args = options[:args] || [] args = options[:args] || []
args.first args.first
end end
# Override to provide details of the arguments a command takes. ##
# It should return a left-justified string, one argument per line. # Override to provide details of the arguments a command takes. It should
# return a left-justified string, one argument per line.
#
# For example:
#
# def usage
# "#{program_name} FILE [FILE ...]"
# end
#
# def arguments
# "FILE name of file to find"
# end
def arguments def arguments
"" ""
end end
# Override to display the default values of the command ##
# options. (similar to +arguments+, but displays the default # Override to display the default values of the command options. (similar to
# values). # +arguments+, but displays the default values).
#
# For example:
#
# def defaults_str
# --no-gems-first --no-all
# end
def defaults_str def defaults_str
"" ""
end end
##
# Override to display a longer description of what this command does. # Override to display a longer description of what this command does.
def description def description
nil nil
end end
##
# Override to display the usage for an individual gem command. # Override to display the usage for an individual gem command.
#
# The text "[options]" is automatically appended to the usage text.
def usage def usage
program_name program_name
end end
##
# Display the help message for the command. # Display the help message for the command.
def show_help def show_help
parser.program_name = usage parser.program_name = usage
say parser say parser
end end
##
# Invoke the command with the given list of arguments. # Invoke the command with the given list of arguments.
def invoke(*args) def invoke(*args)
handle_options(args) handle_options(args)
if options[:help] if options[:help]
@ -137,43 +258,56 @@ module Gem
end end
end end
##
# Call the given block when invoked. # Call the given block when invoked.
# #
# Normal command invocations just executes the +execute+ method of # Normal command invocations just executes the +execute+ method of the
# the command. Specifying an invocation block allows the test # command. Specifying an invocation block allows the test methods to
# methods to override the normal action of a command to determine # override the normal action of a command to determine that it has been
# that it has been invoked correctly. # invoked correctly.
def when_invoked(&block) def when_invoked(&block)
@when_invoked = block @when_invoked = block
end end
##
# Add a command-line option and handler to the command. # Add a command-line option and handler to the command.
# #
# See OptionParser#make_switch for an explanation of +opts+. # See OptionParser#make_switch for an explanation of +opts+.
# #
# +handler+ will be called with two values, the value of the argument and # +handler+ will be called with two values, the value of the argument and
# the options hash. # the options hash.
#
# If the first argument of add_option is a Symbol, it's used to group
# options in output. See `gem help list` for an example.
def add_option(*opts, &handler) # :yields: value, options def add_option(*opts, &handler) # :yields: value, options
group_name = Symbol === opts.first ? opts.shift : :options group_name = Symbol === opts.first ? opts.shift : :options
@option_groups[group_name] << [opts, handler] @option_groups[group_name] << [opts, handler]
end end
##
# Remove previously defined command-line argument +name+. # Remove previously defined command-line argument +name+.
def remove_option(name) def remove_option(name)
@option_groups.each do |_, option_list| @option_groups.each do |_, option_list|
option_list.reject! { |args, _| args.any? { |x| x =~ /^#{name}/ } } option_list.reject! { |args, _| args.any? { |x| x =~ /^#{name}/ } }
end end
end end
# Merge a set of command options with the set of default options ##
# (without modifying the default option hash). # Merge a set of command options with the set of default options (without
# modifying the default option hash).
def merge_options(new_options) def merge_options(new_options)
@options = @defaults.clone @options = @defaults.clone
new_options.each do |k,v| @options[k] = v end new_options.each do |k,v| @options[k] = v end
end end
##
# True if the command handles the given argument list. # True if the command handles the given argument list.
def handles?(args) def handles?(args)
begin begin
parser.parse!(args.dup) parser.parse!(args.dup)
@ -183,8 +317,10 @@ module Gem
end end
end end
# Handle the given list of arguments by parsing them and recording ##
# the results. # Handle the given list of arguments by parsing them and recording the
# results.
def handle_options(args) def handle_options(args)
args = add_extra_args(args) args = add_extra_args(args)
@options = @defaults.clone @options = @defaults.clone
@ -192,16 +328,22 @@ module Gem
@options[:args] = args @options[:args] = args
end end
##
# Adds extra args from ~/.gemrc
def add_extra_args(args) def add_extra_args(args)
result = [] result = []
s_extra = Command.specific_extra_args(@command)
extra = Command.extra_args + s_extra s_extra = Gem::Command.specific_extra_args(@command)
while ! extra.empty? extra = Gem::Command.extra_args + s_extra
until extra.empty? do
ex = [] ex = []
ex << extra.shift ex << extra.shift
ex << extra.shift if extra.first.to_s =~ /^[^-]/ ex << extra.shift if extra.first.to_s =~ /^[^-]/
result << ex if handles?(ex) result << ex if handles?(ex)
end end
result.flatten! result.flatten!
result.concat(args) result.concat(args)
result result
@ -209,7 +351,9 @@ module Gem
private private
##
# Create on demand parser. # Create on demand parser.
def parser def parser
create_option_parser if @parser.nil? create_option_parser if @parser.nil?
@parser @parser
@ -227,7 +371,7 @@ module Gem
configure_options group_name, option_list configure_options group_name, option_list
end end
configure_options "Common", Command.common_options configure_options "Common", Gem::Command.common_options
@parser.separator("") @parser.separator("")
unless arguments.empty? unless arguments.empty?
@ -280,63 +424,18 @@ module Gem
@parser.separator '' @parser.separator ''
end end
##
# Wraps +text+ to +width+ # Wraps +text+ to +width+
def wrap(text, width)
def wrap(text, width) # :doc:
text.gsub(/(.{1,#{width}})( +|$\n?)|(.{1,#{width}})/, "\\1\\3\n") text.gsub(/(.{1,#{width}})( +|$\n?)|(.{1,#{width}})/, "\\1\\3\n")
end end
##################################################################
# Class methods for Command.
class << self
def common_options
@common_options ||= []
end
def add_common_option(*args, &handler)
Gem::Command.common_options << [args, handler]
end
def extra_args
@extra_args ||= []
end
def extra_args=(value)
case value
when Array
@extra_args = value
when String
@extra_args = value.split
end
end
# Return an array of extra arguments for the command. The extra
# arguments come from the gem configuration file read at program
# startup.
def specific_extra_args(cmd)
specific_extra_args_hash[cmd]
end
# Add a list of extra arguments for the given command. +args+
# may be an array or a string to be split on white space.
def add_specific_extra_args(cmd,args)
args = args.split(/\s+/) if args.kind_of? String
specific_extra_args_hash[cmd] = args
end
# Accessor for the specific extra args hash (self initializing).
def specific_extra_args_hash
@specific_extra_args_hash ||= Hash.new do |h,k|
h[k] = Array.new
end
end
end
# ---------------------------------------------------------------- # ----------------------------------------------------------------
# Add the options common to all commands. # Add the options common to all commands.
add_common_option('-h', '--help', add_common_option('-h', '--help',
'Get help on this command') do 'Get help on this command') do |value, options|
|value, options|
options[:help] = true options[:help] = true
end end
@ -359,7 +458,7 @@ module Gem
# options get parsed. # options get parsed.
add_common_option('--config-file FILE', add_common_option('--config-file FILE',
"Use this config file instead of default") do 'Use this config file instead of default') do
end end
add_common_option('--backtrace', add_common_option('--backtrace',
@ -371,6 +470,7 @@ module Gem
end end
# :stopdoc: # :stopdoc:
HELP = %{ HELP = %{
RubyGems is a sophisticated package manager for Ruby. This is a RubyGems is a sophisticated package manager for Ruby. This is a
basic help message containing pointers to more information. basic help message containing pointers to more information.
@ -392,15 +492,20 @@ module Gem
gem help platforms show information about platforms gem help platforms show information about platforms
gem help <COMMAND> show help on COMMAND gem help <COMMAND> show help on COMMAND
(e.g. 'gem help install') (e.g. 'gem help install')
gem server present a web page at
http://localhost:8808/
with info about installed gems
Further information: Further information:
http://rubygems.rubyforge.org http://rubygems.rubyforge.org
}.gsub(/^ /, "") }.gsub(/^ /, '')
# :startdoc: # :startdoc:
end # class
# This is where Commands will be placed in the namespace
module Commands; end
end end
##
# This is where Commands will be placed in the namespace
module Gem::Commands
end

View file

@ -8,20 +8,39 @@ require 'timeout'
require 'rubygems/command' require 'rubygems/command'
require 'rubygems/user_interaction' require 'rubygems/user_interaction'
module Gem ##
# The command manager registers and installs all the individual sub-commands
# supported by the gem command.
#
# Extra commands can be provided by writing a rubygems_plugin.rb
# file in an installed gem. You should register your command against the
# Gem::CommandManager instance, like this:
#
# # file rubygems_plugin.rb
# require 'rubygems/command_manager'
#
# class Gem::Commands::EditCommand < Gem::Command
# # ...
# end
#
# Gem::CommandManager.instance.register_command :edit
#
# See Gem::Command for instructions on writing gem commands.
#################################################################### class Gem::CommandManager
# The command manager registers and installs all the individual
# sub-commands supported by the gem command.
class CommandManager
include UserInteraction
include Gem::UserInteraction
##
# Return the authoritative instance of the command manager. # Return the authoritative instance of the command manager.
def self.instance def self.instance
@command_manager ||= CommandManager.new @command_manager ||= new
end end
##
# Register all the subcommands supported by the gem command. # Register all the subcommands supported by the gem command.
def initialize def initialize
@commands = {} @commands = {}
register_command :build register_command :build
@ -53,24 +72,32 @@ module Gem
register_command :which register_command :which
end end
##
# Register the command object. # Register the command object.
def register_command(command_obj) def register_command(command_obj)
@commands[command_obj] = false @commands[command_obj] = false
end end
##
# Return the registered command from the command name. # Return the registered command from the command name.
def [](command_name) def [](command_name)
command_name = command_name.intern command_name = command_name.intern
return nil if @commands[command_name].nil? return nil if @commands[command_name].nil?
@commands[command_name] ||= load_and_instantiate(command_name) @commands[command_name] ||= load_and_instantiate(command_name)
end end
# Return a list of all command names (as strings). ##
# Return a sorted list of all command names (as strings).
def command_names def command_names
@commands.keys.collect {|key| key.to_s}.sort @commands.keys.collect {|key| key.to_s}.sort
end end
##
# Run the config specified by +args+. # Run the config specified by +args+.
def run(args) def run(args)
process_args(args) process_args(args)
rescue StandardError, Timeout::Error => ex rescue StandardError, Timeout::Error => ex
@ -107,11 +134,10 @@ module Gem
end end
def find_command(cmd_name) def find_command(cmd_name)
possibilities = find_command_possibilities(cmd_name) possibilities = find_command_possibilities cmd_name
if possibilities.size > 1 if possibilities.size > 1 then
raise "Ambiguous command #{cmd_name} matches [#{possibilities.join(', ')}]" raise "Ambiguous command #{cmd_name} matches [#{possibilities.join(', ')}]"
end elsif possibilities.size < 1 then
if possibilities.size < 1
raise "Unknown command #{cmd_name}" raise "Unknown command #{cmd_name}"
end end
@ -120,7 +146,8 @@ module Gem
def find_command_possibilities(cmd_name) def find_command_possibilities(cmd_name)
len = cmd_name.length len = cmd_name.length
self.command_names.select { |n| cmd_name == n[0,len] }
command_names.select { |n| cmd_name == n[0, len] }
end end
private private
@ -142,5 +169,6 @@ module Gem
end end
end end
end end
end
end end

View file

@ -21,6 +21,10 @@ class Gem::Commands::CheckCommand < Gem::Command
options[:alien] = true options[:alien] = true
end end
add_option('-v', '--verbose', "Spew more words") do |value, options|
options[:verbose] = true
end
add_option('-t', '--test', "Run unit tests for gem") do |value, options| add_option('-t', '--test', "Run unit tests for gem") do |value, options|
options[:test] = true options[:test] = true
end end
@ -38,16 +42,17 @@ class Gem::Commands::CheckCommand < Gem::Command
if options[:alien] if options[:alien]
say "Performing the 'alien' operation" say "Performing the 'alien' operation"
Gem::Validator.new.alien.each do |key, val| say
if(val.size > 0) gems = get_all_gem_names rescue []
Gem::Validator.new.alien(gems).sort.each do |key, val|
unless val.empty? then
say "#{key} has #{val.size} problems" say "#{key} has #{val.size} problems"
val.each do |error_entry| val.each do |error_entry|
say "\t#{error_entry.path}:" say " #{error_entry.path}:"
say "\t#{error_entry.problem}" say " #{error_entry.problem}"
say
end end
else else
say "#{key} is error-free" say "#{key} is error-free" if options[:verbose]
end end
say say
end end

View file

@ -1,6 +1,7 @@
require 'rubygems/command' require 'rubygems/command'
require 'rubygems/source_index' require 'rubygems/source_index'
require 'rubygems/dependency_list' require 'rubygems/dependency_list'
require 'rubygems/uninstaller'
class Gem::Commands::CleanupCommand < Gem::Command class Gem::Commands::CleanupCommand < Gem::Command
@ -22,6 +23,13 @@ class Gem::Commands::CleanupCommand < Gem::Command
"--no-dryrun" "--no-dryrun"
end end
def description # :nodoc:
<<-EOF
The cleanup command removes old gems from GEM_HOME. If an older version is
installed elsewhere in GEM_PATH the cleanup command won't touch it.
EOF
end
def usage # :nodoc: def usage # :nodoc:
"#{program_name} [GEMNAME ...]" "#{program_name} [GEMNAME ...]"
end end
@ -41,7 +49,8 @@ class Gem::Commands::CleanupCommand < Gem::Command
unless options[:args].empty? then unless options[:args].empty? then
options[:args].each do |gem_name| options[:args].each do |gem_name|
specs = Gem.cache.search(/^#{gem_name}$/i) dep = Gem::Dependency.new gem_name, Gem::Requirement.default
specs = Gem.source_index.search dep
specs.each do |spec| specs.each do |spec|
gems_to_cleanup << spec gems_to_cleanup << spec
end end
@ -56,7 +65,6 @@ class Gem::Commands::CleanupCommand < Gem::Command
primary_gems[spec.name].version != spec.version primary_gems[spec.name].version != spec.version
} }
uninstall_command = Gem::CommandManager.instance['uninstall']
deplist = Gem::DependencyList.new deplist = Gem::DependencyList.new
gems_to_cleanup.uniq.each do |spec| deplist.add spec end gems_to_cleanup.uniq.each do |spec| deplist.add spec end
@ -69,14 +77,21 @@ class Gem::Commands::CleanupCommand < Gem::Command
say "Attempting to uninstall #{spec.full_name}" say "Attempting to uninstall #{spec.full_name}"
options[:args] = [spec.name] options[:args] = [spec.name]
options[:version] = "= #{spec.version}"
options[:executables] = false
uninstaller = Gem::Uninstaller.new spec.name, options uninstall_options = {
:executables => false,
:version => "= #{spec.version}",
}
if Gem.user_dir == spec.installation_path then
uninstall_options[:install_dir] = spec.installation_path
end
uninstaller = Gem::Uninstaller.new spec.name, uninstall_options
begin begin
uninstaller.uninstall uninstaller.uninstall
rescue Gem::DependencyRemovalException, rescue Gem::DependencyRemovalException, Gem::InstallError,
Gem::GemNotInHomeException => e Gem::GemNotInHomeException => e
say "Unable to uninstall #{spec.full_name}:" say "Unable to uninstall #{spec.full_name}:"
say "\t#{e.class}: #{e.message}" say "\t#{e.class}: #{e.message}"

View file

@ -11,6 +11,11 @@ class Gem::Commands::ContentsCommand < Gem::Command
add_version_option add_version_option
add_option( '--all',
"Contents for all gems") do |all, options|
options[:all] = all
end
add_option('-s', '--spec-dir a,b,c', Array, add_option('-s', '--spec-dir a,b,c', Array,
"Search for gems under specific paths") do |spec_dirs, options| "Search for gems under specific paths") do |spec_dirs, options|
options[:specdirs] = spec_dirs options[:specdirs] = spec_dirs
@ -20,6 +25,11 @@ class Gem::Commands::ContentsCommand < Gem::Command
"Only return files in the Gem's lib_dirs") do |lib_only, options| "Only return files in the Gem's lib_dirs") do |lib_only, options|
options[:lib_only] = lib_only options[:lib_only] = lib_only
end end
add_option( '--[no-]prefix',
"Don't include installed path prefix") do |prefix, options|
options[:prefix] = prefix
end
end end
def arguments # :nodoc: def arguments # :nodoc:
@ -27,46 +37,60 @@ class Gem::Commands::ContentsCommand < Gem::Command
end end
def defaults_str # :nodoc: def defaults_str # :nodoc:
"--no-lib-only" "--no-lib-only --prefix"
end end
def usage # :nodoc: def usage # :nodoc:
"#{program_name} GEMNAME" "#{program_name} GEMNAME [GEMNAME ...]"
end end
def execute def execute
version = options[:version] || Gem::Requirement.default version = options[:version] || Gem::Requirement.default
gem = get_one_gem_name
s = options[:specdirs].map do |i| spec_dirs = options[:specdirs].map do |i|
[i, File.join(i, "specifications")] [i, File.join(i, "specifications")]
end.flatten end.flatten
path_kind = if s.empty? then path_kind = if spec_dirs.empty? then
s = Gem::SourceIndex.installed_spec_directories spec_dirs = Gem::SourceIndex.installed_spec_directories
"default gem paths" "default gem paths"
else else
"specified path" "specified path"
end end
si = Gem::SourceIndex.from_gems_in(*s) si = Gem::SourceIndex.from_gems_in(*spec_dirs)
gem_spec = si.find_name(gem, version).last gem_names = if options[:all] then
si.map { |_, spec| spec.name }
else
get_all_gem_names
end
gem_names.each do |name|
gem_spec = si.find_name(name, version).last
unless gem_spec then unless gem_spec then
say "Unable to find gem '#{gem}' in #{path_kind}" say "Unable to find gem '#{name}' in #{path_kind}"
if Gem.configuration.verbose then if Gem.configuration.verbose then
say "\nDirectories searched:" say "\nDirectories searched:"
s.each { |dir| say dir } spec_dirs.each { |dir| say dir }
end end
terminate_interaction terminate_interaction 1 if gem_names.length == 1
end end
files = options[:lib_only] ? gem_spec.lib_files : gem_spec.files files = options[:lib_only] ? gem_spec.lib_files : gem_spec.files
files.each do |f| files.each do |f|
say File.join(gem_spec.full_gem_path, f) path = if options[:prefix] then
File.join gem_spec.full_gem_path, f
else
f
end
say path
end
end end
end end

View file

@ -1,57 +1,133 @@
require 'rubygems/command' require 'rubygems/command'
require 'rubygems/indexer' require 'rubygems/indexer'
##
# Generates a index files for use as a gem server.
#
# See `gem help generate_index`
class Gem::Commands::GenerateIndexCommand < Gem::Command class Gem::Commands::GenerateIndexCommand < Gem::Command
def initialize def initialize
super 'generate_index', super 'generate_index',
'Generates the index files for a gem server directory', 'Generates the index files for a gem server directory',
:directory => '.' :directory => '.', :build_legacy => true, :build_modern => true
add_option '-d', '--directory=DIRNAME', add_option '-d', '--directory=DIRNAME',
'repository base dir containing gems subdir' do |dir, options| 'repository base dir containing gems subdir' do |dir, options|
options[:directory] = File.expand_path dir options[:directory] = File.expand_path dir
end end
add_option '--[no-]legacy',
'Generate indexes for RubyGems older than',
'1.2.0' do |value, options|
unless options[:build_modern] or value then
raise OptionParser::InvalidOption, 'no indicies will be built'
end
options[:build_legacy] = value
end
add_option '--[no-]modern',
'Generate indexes for RubyGems newer',
'than 1.2.0' do |value, options|
unless options[:build_legacy] or value then
raise OptionParser::InvalidOption, 'no indicies will be built'
end
options[:build_modern] = value
end
add_option '--update',
'Update modern indexes with gems added',
'since the last update' do |value, options|
options[:update] = value
end
add_option :RSS, '--rss-gems-host=GEM_HOST',
'Host name where gems are served from,',
'used for GUID and enclosure values' do |value, options|
options[:rss_gems_host] = value
end
add_option :RSS, '--rss-host=HOST',
'Host name for more gems information,',
'used for RSS feed link' do |value, options|
options[:rss_host] = value
end
add_option :RSS, '--rss-title=TITLE',
'Set title for RSS feed' do |value, options|
options[:rss_title] = value
end
end end
def defaults_str # :nodoc: def defaults_str # :nodoc:
"--directory ." "--directory . --legacy --modern"
end end
def description # :nodoc: def description # :nodoc:
<<-EOF <<-EOF
The generate_index command creates a set of indexes for serving gems The generate_index command creates a set of indexes for serving gems
statically. The command expects a 'gems' directory under the path given to statically. The command expects a 'gems' directory under the path given to
the --directory option. When done, it will generate a set of files like this: the --directory option. The given directory will be the directory you serve
as the gem repository.
gems/ # .gem files you want to index For `gem generate_index --directory /path/to/repo`, expose /path/to/repo via
your HTTP server configuration (not /path/to/repo/gems).
When done, it will generate a set of files like this:
gems/*.gem # .gem files you want to
# index
specs.<version>.gz # specs index
latest_specs.<version>.gz # latest specs index
prerelease_specs.<version>.gz # prerelease specs index
quick/Marshal.<version>/<gemname>.gemspec.rz # Marshal quick index file
# these files support legacy RubyGems
quick/index quick/index
quick/index.rz # quick index manifest quick/index.rz # quick index manifest
quick/<gemname>.gemspec.rz # legacy YAML quick index file quick/<gemname>.gemspec.rz # legacy YAML quick index
quick/Marshal.<version>/<gemname>.gemspec.rz # Marshal quick index file # file
Marshal.<version> Marshal.<version>
Marshal.<version>.Z # Marshal full index Marshal.<version>.Z # Marshal full index
yaml yaml
yaml.Z # legacy YAML full index yaml.Z # legacy YAML full index
The .Z and .rz extension files are compressed with the inflate algorithm. The The .Z and .rz extension files are compressed with the inflate algorithm.
Marshal version number comes from ruby's Marshal::MAJOR_VERSION and The Marshal version number comes from ruby's Marshal::MAJOR_VERSION and
Marshal::MINOR_VERSION constants. It is used to ensure compatibility. The Marshal::MINOR_VERSION constants. It is used to ensure compatibility.
yaml indexes exist for legacy RubyGems clients and fallback in case of Marshal The yaml indexes exist for legacy RubyGems clients and fallback in case of
version changes. Marshal version changes.
If --rss-host and --rss-gem-host are given an RSS feed will be generated at
index.rss containing gems released in the last two days.
EOF EOF
end end
def execute def execute
if options[:update] and
(options[:rss_host] or options[:rss_gems_host]) then
alert_error '--update not compatible with RSS generation'
terminate_interaction 1
end
if not File.exist?(options[:directory]) or if not File.exist?(options[:directory]) or
not File.directory?(options[:directory]) then not File.directory?(options[:directory]) then
alert_error "unknown directory name #{directory}." alert_error "unknown directory name #{directory}."
terminate_interaction 1 terminate_interaction 1
else else
indexer = Gem::Indexer.new options[:directory] indexer = Gem::Indexer.new options.delete(:directory), options
if options[:update] then
indexer.update_index
else
indexer.generate_index indexer.generate_index
end end
end end
end
end end

View file

@ -6,6 +6,11 @@ require 'rubygems/local_remote_options'
require 'rubygems/validator' require 'rubygems/validator'
require 'rubygems/version_option' require 'rubygems/version_option'
##
# Gem installer command line tool
#
# See `gem help install`
class Gem::Commands::InstallCommand < Gem::Command class Gem::Commands::InstallCommand < Gem::Command
include Gem::VersionOption include Gem::VersionOption
@ -43,11 +48,51 @@ class Gem::Commands::InstallCommand < Gem::Command
The install command installs local or remote gem into a gem repository. The install command installs local or remote gem into a gem repository.
For gems with executables ruby installs a wrapper file into the executable For gems with executables ruby installs a wrapper file into the executable
directory by deault. This can be overridden with the --no-wrappers option. directory by default. This can be overridden with the --no-wrappers option.
The wrapper allows you to choose among alternate gem versions using _version_. The wrapper allows you to choose among alternate gem versions using _version_.
For example `rake _0.7.3_ --version` will run rake version 0.7.3 if a newer For example `rake _0.7.3_ --version` will run rake version 0.7.3 if a newer
version is also installed. version is also installed.
If an extension fails to compile during gem installation the gem
specification is not written out, but the gem remains unpacked in the
repository. You may need to specify the path to the library's headers and
libraries to continue. You can do this by adding a -- between RubyGems'
options and the extension's build options:
$ gem install some_extension_gem
[build fails]
Gem files will remain installed in \\
/path/to/gems/some_extension_gem-1.0 for inspection.
Results logged to /path/to/gems/some_extension_gem-1.0/gem_make.out
$ gem install some_extension_gem -- --with-extension-lib=/path/to/lib
[build succeeds]
$ gem list some_extension_gem
*** LOCAL GEMS ***
some_extension_gem (1.0)
$
If you correct the compilation errors by editing the gem files you will need
to write the specification by hand. For example:
$ gem install some_extension_gem
[build fails]
Gem files will remain installed in \\
/path/to/gems/some_extension_gem-1.0 for inspection.
Results logged to /path/to/gems/some_extension_gem-1.0/gem_make.out
$ [cd /path/to/gems/some_extension_gem-1.0]
$ [edit files or what-have-you and run make]
$ gem spec ../../cache/some_extension_gem-1.0.gem --ruby > \\
../../specifications/some_extension_gem-1.0.gemspec
$ gem list some_extension_gem
*** LOCAL GEMS ***
some_extension_gem (1.0)
$
EOF EOF
end end
@ -65,24 +110,11 @@ version is also installed.
ENV.delete 'GEM_PATH' if options[:install_dir].nil? and RUBY_VERSION > '1.9' ENV.delete 'GEM_PATH' if options[:install_dir].nil? and RUBY_VERSION > '1.9'
install_options = {
:env_shebang => options[:env_shebang],
:domain => options[:domain],
:force => options[:force],
:format_executable => options[:format_executable],
:ignore_dependencies => options[:ignore_dependencies],
:install_dir => options[:install_dir],
:security_policy => options[:security_policy],
:wrappers => options[:wrappers],
:bin_dir => options[:bin_dir],
:development => options[:development],
}
exit_code = 0 exit_code = 0
get_all_gem_names.each do |gem_name| get_all_gem_names.each do |gem_name|
begin begin
inst = Gem::DependencyInstaller.new install_options inst = Gem::DependencyInstaller.new options
inst.install gem_name, options[:version] inst.install gem_name, options[:version]
inst.installed_gems.each do |spec| inst.installed_gems.each do |spec|
@ -96,24 +128,16 @@ version is also installed.
rescue Gem::GemNotFoundException => e rescue Gem::GemNotFoundException => e
alert_error e.message alert_error e.message
exit_code |= 2 exit_code |= 2
# rescue => e
# # TODO: Fix this handle to allow the error to propagate to
# # the top level handler. Examine the other errors as
# # well. This implementation here looks suspicious to me --
# # JimWeirich (4/Jan/05)
# alert_error "Error installing gem #{gem_name}: #{e.message}"
# return
end end
end end
unless installed_gems.empty? then unless installed_gems.empty? then
gems = installed_gems.length == 1 ? 'gem' : 'gems' gems = installed_gems.length == 1 ? 'gem' : 'gems'
say "#{installed_gems.length} #{gems} installed" say "#{installed_gems.length} #{gems} installed"
end
# NOTE: *All* of the RI documents must be generated first. # NOTE: *All* of the RI documents must be generated first. For some
# For some reason, RI docs cannot be generated after any RDoc # reason, RI docs cannot be generated after any RDoc documents are
# documents are generated. # generated.
if options[:generate_ri] then if options[:generate_ri] then
installed_gems.each do |gem| installed_gems.each do |gem|
@ -131,15 +155,17 @@ version is also installed.
if options[:test] then if options[:test] then
installed_gems.each do |spec| installed_gems.each do |spec|
gem_spec = Gem::SourceIndex.from_installed_gems.search(spec.name, spec.version.version).first gem_spec = Gem::SourceIndex.from_installed_gems.find_name(spec.name, spec.version.version).first
result = Gem::Validator.new.unit_test(gem_spec) result = Gem::Validator.new.unit_test(gem_spec)
if result and not result.passed? if result and not result.passed?
unless ask_yes_no("...keep Gem?", true) then unless ask_yes_no("...keep Gem?", true)
require 'rubygems/uninstaller'
Gem::Uninstaller.new(spec.name, :version => spec.version.version).uninstall Gem::Uninstaller.new(spec.name, :version => spec.version.version).uninstall
end end
end end
end end
end end
end
raise Gem::SystemExitException, exit_code raise Gem::SystemExitException, exit_code
end end

View file

@ -2,9 +2,11 @@ require 'rubygems/command'
require 'rubygems/local_remote_options' require 'rubygems/local_remote_options'
require 'rubygems/spec_fetcher' require 'rubygems/spec_fetcher'
require 'rubygems/version_option' require 'rubygems/version_option'
require 'rubygems/text'
class Gem::Commands::QueryCommand < Gem::Command class Gem::Commands::QueryCommand < Gem::Command
include Gem::Text
include Gem::LocalRemoteOptions include Gem::LocalRemoteOptions
include Gem::VersionOption include Gem::VersionOption
@ -43,6 +45,11 @@ class Gem::Commands::QueryCommand < Gem::Command
options[:all] = value options[:all] = value
end end
add_option( '--prerelease',
'Display prerelease versions') do |value, options|
options[:prerelease] = value
end
add_local_remote_options add_local_remote_options
end end
@ -54,6 +61,7 @@ class Gem::Commands::QueryCommand < Gem::Command
exit_code = 0 exit_code = 0
name = options[:name] name = options[:name]
prerelease = options[:prerelease]
if options[:installed] then if options[:installed] then
if name.source.empty? then if name.source.empty? then
@ -72,6 +80,10 @@ class Gem::Commands::QueryCommand < Gem::Command
dep = Gem::Dependency.new name, Gem::Requirement.default dep = Gem::Dependency.new name, Gem::Requirement.default
if local? then if local? then
if prerelease and not both? then
alert_warning "prereleases are always shown locally"
end
if ui.outs.tty? or both? then if ui.outs.tty? or both? then
say say
say "*** LOCAL GEMS ***" say "*** LOCAL GEMS ***"
@ -98,8 +110,13 @@ class Gem::Commands::QueryCommand < Gem::Command
begin begin
fetcher = Gem::SpecFetcher.fetcher fetcher = Gem::SpecFetcher.fetcher
spec_tuples = fetcher.find_matching dep, all, false spec_tuples = fetcher.find_matching dep, all, false, prerelease
rescue Gem::RemoteFetcher::FetchError => e rescue Gem::RemoteFetcher::FetchError => e
if prerelease then
raise Gem::OperationNotSupportedError,
"Prereleases not supported on legacy repositories"
end
raise unless fetcher.warn_legacy e do raise unless fetcher.warn_legacy e do
require 'rubygems/source_info_cache' require 'rubygems/source_info_cache'
@ -145,6 +162,12 @@ class Gem::Commands::QueryCommand < Gem::Command
version version
end.reverse end.reverse
platforms = Hash.new { |h,version| h[version] = [] }
matching_tuples.map do |(name, version, platform,_),_|
platforms[version] << platform if platform
end
seen = {} seen = {}
matching_tuples.delete_if do |(name, version,_),_| matching_tuples.delete_if do |(name, version,_),_|
@ -174,6 +197,28 @@ class Gem::Commands::QueryCommand < Gem::Command
end end
entry << "\n" entry << "\n"
non_ruby = platforms.any? do |_, pls|
pls.any? { |pl| pl != Gem::Platform::RUBY }
end
if non_ruby then
if platforms.length == 1 then
title = platforms.values.length == 1 ? 'Platform' : 'Platforms'
entry << " #{title}: #{platforms.values.sort.join ', '}\n"
else
entry << " Platforms:\n"
platforms.sort_by do |version,|
version
end.each do |version, pls|
label = " #{version}: "
data = format_text pls.sort.join(', '), 68, label.length
data[0, label.length] = label
entry << data << "\n"
end
end
end
authors = "Author#{spec.authors.length > 1 ? 's' : ''}: " authors = "Author#{spec.authors.length > 1 ? 's' : ''}: "
authors << spec.authors.join(', ') authors << spec.authors.join(', ')
entry << format_text(authors, 68, 4) entry << format_text(authors, 68, 4)
@ -187,6 +232,12 @@ class Gem::Commands::QueryCommand < Gem::Command
entry << "\n" << format_text("Homepage: #{spec.homepage}", 68, 4) entry << "\n" << format_text("Homepage: #{spec.homepage}", 68, 4)
end end
if spec.license and not spec.license.empty? then
licenses = "License#{spec.licenses.length > 1 ? 's' : ''}: "
licenses << spec.licenses.join(', ')
entry << "\n" << format_text(licenses, 68, 4)
end
if spec.loaded_from then if spec.loaded_from then
if matching_tuples.length == 1 then if matching_tuples.length == 1 then
loaded_from = File.dirname File.dirname(spec.loaded_from) loaded_from = File.dirname File.dirname(spec.loaded_from)
@ -209,25 +260,5 @@ class Gem::Commands::QueryCommand < Gem::Command
say output.join(options[:details] ? "\n\n" : "\n") say output.join(options[:details] ? "\n\n" : "\n")
end end
##
# Used for wrapping and indenting text
def format_text(text, wrap, indent=0)
result = []
work = text.dup
while work.length > wrap
if work =~ /^(.{0,#{wrap}})[ \n]/o then
result << $1
work.slice!(0, $&.length)
else
result << work.slice!(0, wrap)
end
end
result << work if work.length.nonzero?
result.join("\n").gsub(/^/, " " * indent)
end
end end

View file

@ -2,34 +2,30 @@ require 'rubygems/command'
require 'rubygems/version_option' require 'rubygems/version_option'
require 'rubygems/doc_manager' require 'rubygems/doc_manager'
module Gem class Gem::Commands::RdocCommand < Gem::Command
module Commands include Gem::VersionOption
class RdocCommand < Command
include VersionOption
def initialize def initialize
super('rdoc', super 'rdoc', 'Generates RDoc for pre-installed gems',
'Generates RDoc for pre-installed gems',
{
:version => Gem::Requirement.default, :version => Gem::Requirement.default,
:include_rdoc => true, :include_rdoc => true, :include_ri => true
:include_ri => true,
})
add_option('--all', add_option('--all',
'Generate RDoc/RI documentation for all', 'Generate RDoc/RI documentation for all',
'installed gems') do |value, options| 'installed gems') do |value, options|
options[:all] = value options[:all] = value
end end
add_option('--[no-]rdoc', add_option('--[no-]rdoc',
'Include RDoc generated documents') do 'Include RDoc generated documents') do |value, options|
|value, options|
options[:include_rdoc] = value options[:include_rdoc] = value
end end
add_option('--[no-]ri', add_option('--[no-]ri',
'Include RI generated documents' 'Include RI generated documents') do |value, options|
) do |value, options|
options[:include_ri] = value options[:include_ri] = value
end end
add_version_option add_version_option
end end
@ -46,14 +42,14 @@ module Gem
end end
def execute def execute
if options[:all] if options[:all] then
specs = Gem::SourceIndex.from_installed_gems.collect { |name, spec| specs = Gem::SourceIndex.from_installed_gems.collect { |name, spec|
spec spec
} }
else else
gem_name = get_one_gem_name gem_name = get_one_gem_name
specs = Gem::SourceIndex.from_installed_gems.search( dep = Gem::Dependency.new gem_name, options[:version]
gem_name, options[:version]) specs = Gem::SourceIndex.from_installed_gems.search dep
end end
if specs.empty? if specs.empty?
@ -76,7 +72,5 @@ module Gem
true true
end end
end
end
end end

View file

@ -1,17 +1,12 @@
require 'rubygems/command' require 'rubygems/command'
require 'rubygems/commands/query_command' require 'rubygems/commands/query_command'
module Gem class Gem::Commands::SearchCommand < Gem::Commands::QueryCommand
module Commands
class SearchCommand < QueryCommand
def initialize def initialize
super( super 'search', 'Display all gems whose name contains STRING'
'search',
'Display all gems whose name contains STRING' remove_option '--name-matches'
)
remove_option('--name-matches')
end end
def arguments # :nodoc: def arguments # :nodoc:
@ -31,7 +26,6 @@ module Gem
options[:name] = /#{string}/i options[:name] = /#{string}/i
super super
end end
end
end
end end

View file

@ -7,7 +7,23 @@ class Gem::Commands::ServerCommand < Gem::Command
super 'server', 'Documentation and gem repository HTTP server', super 'server', 'Documentation and gem repository HTTP server',
:port => 8808, :gemdir => Gem.dir, :daemon => false :port => 8808, :gemdir => Gem.dir, :daemon => false
add_option '-p', '--port=PORT', Integer, OptionParser.accept :Port do |port|
if port =~ /\A\d+\z/ then
port = Integer port
raise OptionParser::InvalidArgument, "#{port}: not a port number" if
port > 65535
port
else
begin
Socket.getservbyname port
rescue SocketError => e
raise OptionParser::InvalidArgument, "#{port}: no such named service"
end
end
end
add_option '-p', '--port=PORT', :Port,
'port to listen on' do |port, options| 'port to listen on' do |port, options|
options[:port] = port options[:port] = port
end end
@ -37,6 +53,12 @@ for gem installation.
To install gems from a running server, use `gem install GEMNAME --source To install gems from a running server, use `gem install GEMNAME --source
http://gem_server_host:8808` http://gem_server_host:8808`
You can set up a shortcut to gem server documentation using the URL:
http://localhost:8808/rdoc?q=%s - Firefox
http://localhost:8808/rdoc?q=* - LaunchBar
EOF EOF
end end

View file

@ -0,0 +1,353 @@
require 'rubygems/command'
require 'fileutils'
require 'rbconfig'
require 'tmpdir'
require 'pathname'
##
# Installs RubyGems itself. This command is ordinarily only available from a
# RubyGems checkout or tarball.
class Gem::Commands::SetupCommand < Gem::Command
def initialize
super 'setup', 'Install RubyGems',
:format_executable => true, :rdoc => true, :ri => true,
:site_or_vendor => :sitelibdir,
:destdir => '', :prefix => ''
add_option '--prefix=PREFIX',
'Prefix path for installing RubyGems',
'Will not affect gem repository location' do |prefix, options|
options[:prefix] = File.expand_path prefix
end
add_option '--destdir=DESTDIR',
'Root directory to install RubyGems into',
'Mainly used for packaging RubyGems' do |destdir, options|
options[:destdir] = File.expand_path destdir
end
add_option '--[no-]vendor',
'Install into vendorlibdir not sitelibdir',
'(Requires Ruby 1.8.7)' do |vendor, options|
if vendor and Gem.ruby_version < Gem::Version.new('1.8.7') then
raise OptionParser::InvalidOption,
"requires ruby 1.8.7+ (you have #{Gem.ruby_version})"
end
options[:site_or_vendor] = vendor ? :vendorlibdir : :sitelibdir
end
add_option '--[no-]format-executable',
'Makes `gem` match ruby',
'If ruby is ruby18, gem will be gem18' do |value, options|
options[:format_executable] = value
end
add_option '--[no-]rdoc',
'Generate RDoc documentation for RubyGems' do |value, options|
options[:rdoc] = value
end
add_option '--[no-]ri',
'Generate RI documentation for RubyGems' do |value, options|
options[:ri] = value
end
end
def check_ruby_version
required_version = Gem::Requirement.new '>= 1.8.6'
unless required_version.satisfied_by? Gem.ruby_version then
alert_error "Expected Ruby version #{required_version}, is #{Gem.ruby_version}"
terminate_interaction 1
end
end
def defaults_str # :nodoc:
"--format-executable --rdoc --ri"
end
def description # :nodoc:
<<-EOF
Installs RubyGems itself.
RubyGems installs RDoc for itself in GEM_HOME. By default this is:
#{Gem.dir}
If you prefer a different directory, set the GEM_HOME environment variable.
RubyGems will install the gem command with a name matching ruby's
prefix and suffix. If ruby was installed as `ruby18`, gem will be
installed as `gem18`.
By default, this RubyGems will install gem as:
#{Gem.default_exec_format % 'gem'}
EOF
end
def execute
install_destdir = options[:destdir]
unless install_destdir.empty? then
ENV['GEM_HOME'] ||= File.join(install_destdir,
Gem.default_dir.gsub(/^[a-zA-Z]:/, ''))
end
check_ruby_version
if Gem.configuration.really_verbose then
extend FileUtils::Verbose
else
extend FileUtils
end
lib_dir, bin_dir = make_destination_dirs install_destdir
install_lib lib_dir
install_executables bin_dir
remove_old_bin_files bin_dir
remove_source_caches install_destdir
install_rdoc
say
say "-" * 78
say
release_notes = File.join Dir.pwd, 'doc', 'release_notes',
"rel_#{Gem::RubyGemsVersion.gsub '.', '_'}.rdoc"
if File.exist? release_notes then
say File.read(release_notes)
else
say "Oh-no! Unable to find release notes!"
say "Looked in: #{release_notes}" if Gem.configuration.really_verbose
end
say
say "-" * 78
say
say "RubyGems installed the following executables:"
say @bin_file_names.map { |name| "\t#{name}\n" }
say
unless @bin_file_names.grep(/#{File::SEPARATOR}gem$/) then
say "If `gem` was installed by a previous RubyGems installation, you may need"
say "to remove it by hand."
say
end
end
def install_executables(bin_dir)
say "Installing gem executable"
@bin_file_names = []
Dir.chdir 'bin' do
bin_files = Dir['*']
bin_files.delete 'update_rubygems'
bin_files.each do |bin_file|
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_tmp_file = File.join Dir.tmpdir, bin_file
begin
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
next unless Gem.win_platform?
begin
bin_cmd_file = File.join Dir.tmpdir, "#{bin_file}.bat"
File.open bin_cmd_file, 'w' do |file|
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
install bin_cmd_file, "#{dest_file}.bat", :mode => 0755
ensure
rm bin_cmd_file
end
end
end
end
def install_lib(lib_dir)
say "Installing RubyGems"
Dir.chdir 'lib' do
lib_files = Dir[File.join('**', '*rb')]
lib_files.each do |lib_file|
dest_file = File.join lib_dir, lib_file
dest_dir = File.dirname dest_file
mkdir_p dest_dir unless File.directory? dest_dir
install lib_file, dest_file, :mode => 0644
end
end
end
def install_rdoc
gem_doc_dir = File.join Gem.dir, 'doc'
rubygems_name = "rubygems-#{Gem::RubyGemsVersion}"
rubygems_doc_dir = File.join gem_doc_dir, rubygems_name
if File.writable? gem_doc_dir and
(not File.exist? rubygems_doc_dir or
File.writable? rubygems_doc_dir) then
say "Removing old RubyGems RDoc and ri"
Dir[File.join(Gem.dir, 'doc', 'rubygems-[0-9]*')].each do |dir|
rm_rf dir
end
if options[:ri] then
ri_dir = File.join rubygems_doc_dir, 'ri'
say "Installing #{rubygems_name} ri into #{ri_dir}"
run_rdoc '--ri', '--op', ri_dir
end
if options[:rdoc] then
rdoc_dir = File.join rubygems_doc_dir, 'rdoc'
say "Installing #{rubygems_name} rdoc into #{rdoc_dir}"
run_rdoc '--op', rdoc_dir
end
else
say "Skipping RDoc generation, #{gem_doc_dir} not writable"
say "Set the GEM_HOME environment variable if you want RDoc generated"
end
end
def make_destination_dirs(install_destdir)
lib_dir = nil
bin_dir = nil
prefix = options[:prefix]
site_or_vendor = options[:site_or_vendor]
if prefix.empty? then
lib_dir = Gem::ConfigMap[site_or_vendor]
bin_dir = Gem::ConfigMap[:bindir]
else
# Apple installed RubyGems into libdir, and RubyGems <= 1.1.0 gets
# confused about installation location, so switch back to
# sitelibdir/vendorlibdir.
if defined?(APPLE_GEM_HOME) and
# just in case Apple and RubyGems don't get this patched up proper.
(prefix == Gem::ConfigMap[:libdir] or
# this one is important
prefix == File.join(Gem::ConfigMap[:libdir], 'ruby')) then
lib_dir = Gem::ConfigMap[site_or_vendor]
bin_dir = Gem::ConfigMap[:bindir]
else
lib_dir = File.join prefix, 'lib'
bin_dir = File.join prefix, 'bin'
end
end
unless install_destdir.empty? then
lib_dir = File.join install_destdir, lib_dir.gsub(/^[a-zA-Z]:/, '')
bin_dir = File.join install_destdir, bin_dir.gsub(/^[a-zA-Z]:/, '')
end
mkdir_p lib_dir
mkdir_p bin_dir
return lib_dir, bin_dir
end
def remove_old_bin_files(bin_dir)
old_bin_files = {
'gem_mirror' => 'gem mirror',
'gem_server' => 'gem server',
'gemlock' => 'gem lock',
'gemri' => 'ri',
'gemwhich' => 'gem which',
'index_gem_repository.rb' => 'gem generate_index',
}
old_bin_files.each do |old_bin_file, new_name|
old_bin_path = File.join bin_dir, old_bin_file
next unless File.exist? old_bin_path
deprecation_message = "`#{old_bin_file}` has been deprecated. Use `#{new_name}` instead."
File.open old_bin_path, 'w' do |fp|
fp.write <<-EOF
#!#{Gem.ruby}
abort "#{deprecation_message}"
EOF
end
next unless Gem.win_platform?
File.open "#{old_bin_path}.bat", 'w' do |fp|
fp.puts %{@ECHO.#{deprecation_message}}
end
end
end
def remove_source_caches(install_destdir)
if install_destdir.empty?
require 'rubygems/source_info_cache'
user_cache_file = File.join(install_destdir,
Gem::SourceInfoCache.user_cache_file)
system_cache_file = File.join(install_destdir,
Gem::SourceInfoCache.system_cache_file)
say "Removing old source_cache files"
rm_f user_cache_file if File.writable? File.dirname(user_cache_file)
rm_f system_cache_file if File.writable? File.dirname(system_cache_file)
end
end
def run_rdoc(*args)
begin
gem 'rdoc'
rescue Gem::LoadError
end
require 'rdoc/rdoc'
args << '--quiet'
args << '--main' << 'README'
args << '.' << 'README' << 'LICENSE.txt' << 'GPL.txt'
r = RDoc::RDoc.new
r.document args
end
end

View file

@ -3,9 +3,12 @@ require 'rubygems/command'
require 'rubygems/remote_fetcher' require 'rubygems/remote_fetcher'
require 'rubygems/source_info_cache' require 'rubygems/source_info_cache'
require 'rubygems/spec_fetcher' require 'rubygems/spec_fetcher'
require 'rubygems/local_remote_options'
class Gem::Commands::SourcesCommand < Gem::Command class Gem::Commands::SourcesCommand < Gem::Command
include Gem::LocalRemoteOptions
def initialize def initialize
super 'sources', super 'sources',
'Manage the sources and cache file RubyGems uses to search for gems' 'Manage the sources and cache file RubyGems uses to search for gems'
@ -30,6 +33,8 @@ class Gem::Commands::SourcesCommand < Gem::Command
add_option '-u', '--update', 'Update source cache' do |value, options| add_option '-u', '--update', 'Update source cache' do |value, options|
options[:update] = value options[:update] = value
end end
add_proxy_option
end end
def defaults_str def defaults_str

View file

@ -12,7 +12,8 @@ class Gem::Commands::SpecificationCommand < Gem::Command
def initialize def initialize
super 'specification', 'Display gem specification (in yaml)', super 'specification', 'Display gem specification (in yaml)',
:domain => :local, :version => Gem::Requirement.default :domain => :local, :version => Gem::Requirement.default,
:format => :yaml
add_version_option('examine') add_version_option('examine')
add_platform_option add_platform_option
@ -22,26 +23,62 @@ class Gem::Commands::SpecificationCommand < Gem::Command
options[:all] = true options[:all] = true
end end
add_option('--ruby', 'Output ruby format') do |value, options|
options[:format] = :ruby
end
add_option('--yaml', 'Output RUBY format') do |value, options|
options[:format] = :yaml
end
add_option('--marshal', 'Output Marshal format') do |value, options|
options[:format] = :marshal
end
add_local_remote_options add_local_remote_options
end end
def arguments # :nodoc: def arguments # :nodoc:
"GEMFILE name of gem to show the gemspec for" <<-ARGS
GEMFILE name of gem to show the gemspec for
FIELD name of gemspec field to show
ARGS
end end
def defaults_str # :nodoc: def defaults_str # :nodoc:
"--local --version '#{Gem::Requirement.default}'" "--local --version '#{Gem::Requirement.default}' --yaml"
end end
def usage # :nodoc: def usage # :nodoc:
"#{program_name} [GEMFILE]" "#{program_name} [GEMFILE] [FIELD]"
end end
def execute def execute
specs = [] specs = []
gem = get_one_gem_name gem = options[:args].shift
unless gem then
raise Gem::CommandLineError,
"Please specify a gem name or file on the command line"
end
dep = Gem::Dependency.new gem, options[:version] dep = Gem::Dependency.new gem, options[:version]
field = get_one_optional_argument
if field then
field = field.intern
if options[:format] == :ruby then
raise Gem::CommandLineError, "--ruby and FIELD are mutually exclusive"
end
unless Gem::Specification.attribute_names.include? field then
raise Gem::CommandLineError,
"no field %p on Gem::Specification" % field.to_s
end
end
if local? then if local? then
if File.exist? gem then if File.exist? gem then
specs << Gem::Format.from_file_by_path(gem).spec rescue nil specs << Gem::Format.from_file_by_path(gem).spec rescue nil
@ -63,7 +100,17 @@ class Gem::Commands::SpecificationCommand < Gem::Command
terminate_interaction 1 terminate_interaction 1
end end
output = lambda { |s| say s.to_yaml; say "\n" } output = lambda do |s|
s = s.send field if field
say case options[:format]
when :ruby then s.to_ruby
when :marshal then Marshal.dump s
else s.to_yaml
end
say "\n"
end
if options[:all] then if options[:all] then
specs.each(&output) specs.each(&output)

View file

@ -2,15 +2,18 @@ require 'rubygems/command'
require 'rubygems/version_option' require 'rubygems/version_option'
require 'rubygems/uninstaller' require 'rubygems/uninstaller'
module Gem ##
module Commands # Gem uninstaller command line tool
class UninstallCommand < Command #
# See `gem help uninstall`
include VersionOption class Gem::Commands::UninstallCommand < Gem::Command
include Gem::VersionOption
def initialize def initialize
super 'uninstall', 'Uninstall gems from the local repository', super 'uninstall', 'Uninstall gems from the local repository',
:version => Gem::Requirement.default :version => Gem::Requirement.default, :user_install => true
add_option('-a', '--[no-]all', add_option('-a', '--[no-]all',
'Uninstall all matching versions' 'Uninstall all matching versions'
@ -40,6 +43,12 @@ module Gem
options[:bin_dir] = File.expand_path(value) options[:bin_dir] = File.expand_path(value)
end end
add_option('--[no-]user-install',
'Uninstall from user\'s home directory',
'in addition to GEM_HOME.') do |value, options|
options[:user_install] = value
end
add_version_option add_version_option
add_platform_option add_platform_option
end end
@ -50,7 +59,8 @@ module Gem
def defaults_str # :nodoc: def defaults_str # :nodoc:
"--version '#{Gem::Requirement.default}' --no-force " \ "--version '#{Gem::Requirement.default}' --no-force " \
"--install-dir #{Gem.dir}" "--install-dir #{Gem.dir}\n" \
"--user-install"
end end
def usage # :nodoc: def usage # :nodoc:
@ -68,6 +78,6 @@ module Gem
end end
end end
end end
end
end
end end

View file

@ -12,7 +12,7 @@ class Gem::Commands::UnpackCommand < Gem::Command
:version => Gem::Requirement.default, :version => Gem::Requirement.default,
:target => Dir.pwd :target => Dir.pwd
add_option('--target', 'target directory for unpacking') do |value, options| add_option('--target=DIR', 'target directory for unpacking') do |value, options|
options[:target] = value options[:target] = value
end end
@ -35,9 +35,10 @@ class Gem::Commands::UnpackCommand < Gem::Command
# TODO: allow, e.g., 'gem unpack rake-0.3.1'. Find a general solution for # TODO: allow, e.g., 'gem unpack rake-0.3.1'. Find a general solution for
# this, so that it works for uninstall as well. (And check other commands # this, so that it works for uninstall as well. (And check other commands
# at the same time.) # at the same time.)
def execute def execute
gemname = get_one_gem_name get_all_gem_names.each do |name|
path = get_path(gemname, options[:version]) path = get_path name, options[:version]
if path then if path then
basename = File.basename(path).sub(/\.gem$/, '') basename = File.basename(path).sub(/\.gem$/, '')
@ -46,7 +47,8 @@ class Gem::Commands::UnpackCommand < Gem::Command
Gem::Installer.new(path, :unpack => true).unpack target_dir Gem::Installer.new(path, :unpack => true).unpack target_dir
say "Unpacked gem: '#{target_dir}'" say "Unpacked gem: '#{target_dir}'"
else else
alert_error "Gem '#{gemname}' not installed." alert_error "Gem '#{name}' not installed."
end
end end
end end

View file

@ -80,20 +80,27 @@ class Gem::Commands::UpdateCommand < Gem::Command
gems_to_update.uniq.sort.each do |name| gems_to_update.uniq.sort.each do |name|
next if updated.any? { |spec| spec.name == name } next if updated.any? { |spec| spec.name == name }
success = false
say "Updating #{name}" say "Updating #{name}"
begin
installer.install name installer.install name
success = true
rescue Gem::InstallError => e
alert_error "Error installing #{name}:\n\t#{e.message}"
success = false
end
installer.installed_gems.each do |spec| installer.installed_gems.each do |spec|
updated << spec updated << spec
say "Successfully installed #{spec.full_name}" say "Successfully installed #{spec.full_name}" if success
end end
end end
if gems_to_update.include? "rubygems-update" then if gems_to_update.include? "rubygems-update" then
Gem.source_index.refresh! Gem.source_index.refresh!
update_gems = Gem.source_index.search 'rubygems-update' update_gems = Gem.source_index.find_name 'rubygems-update'
latest_update_gem = update_gems.sort_by { |s| s.version }.last latest_update_gem = update_gems.sort_by { |s| s.version }.last
@ -106,6 +113,20 @@ class Gem::Commands::UpdateCommand < Gem::Command
say "Nothing to update" say "Nothing to update"
else else
say "Gems updated: #{updated.map { |spec| spec.name }.join ', '}" say "Gems updated: #{updated.map { |spec| spec.name }.join ', '}"
if options[:generate_ri] then
updated.each do |gem|
Gem::DocManager.new(gem, options[:rdoc_args]).generate_ri
end
Gem::DocManager.update_ri_cache
end
if options[:generate_rdoc] then
updated.each do |gem|
Gem::DocManager.new(gem, options[:rdoc_args]).generate_rdoc
end
end
end end
end end
end end

View file

@ -46,7 +46,7 @@ class Gem::Commands::WhichCommand < Gem::Command
end end
say "(checking gem #{spec.full_name} for #{arg})" if say "(checking gem #{spec.full_name} for #{arg})" if
Gem.configuration.verbose Gem.configuration.verbose and $stdout.tty?
end end
paths = find_paths arg, dirs paths = find_paths arg, dirs

View file

@ -5,7 +5,6 @@
#++ #++
require 'yaml' require 'yaml'
require 'rubygems'
# Store the gem command options specified in the configuration file. The # Store the gem command options specified in the configuration file. The
# config file object acts much like a hash. # config file object acts much like a hash.
@ -36,7 +35,8 @@ class Gem::ConfigFile
CSIDL_COMMON_APPDATA = 0x0023 CSIDL_COMMON_APPDATA = 0x0023
path = 0.chr * 260 path = 0.chr * 260
SHGetFolderPath = Win32API.new 'shell32', 'SHGetFolderPath', 'PLPLP', 'L', :stdcall SHGetFolderPath = Win32API.new 'shell32', 'SHGetFolderPath', 'PLPLP', 'L',
:stdcall
SHGetFolderPath.call nil, CSIDL_COMMON_APPDATA, nil, 1, path SHGetFolderPath.call nil, CSIDL_COMMON_APPDATA, nil, 1, path
path.strip path.strip

View file

@ -20,8 +20,13 @@ module Gem
if defined? RUBY_FRAMEWORK_VERSION then if defined? RUBY_FRAMEWORK_VERSION then
File.join File.dirname(ConfigMap[:sitedir]), 'Gems', File.join File.dirname(ConfigMap[:sitedir]), 'Gems',
ConfigMap[:ruby_version] ConfigMap[:ruby_version]
# 1.9.2dev reverted to 1.8 style path
elsif RUBY_VERSION > '1.9' and RUBY_VERSION < '1.9.2' then
File.join(ConfigMap[:libdir], ConfigMap[:ruby_install_name], 'gems',
ConfigMap[:ruby_version])
else else
ConfigMap[:sitelibdir].sub(%r'/site_ruby/(?=[^/]+)', '/gems/') File.join(ConfigMap[:libdir], ruby_engine, 'gems',
ConfigMap[:ruby_version])
end end
end end
@ -37,15 +42,25 @@ module Gem
# Default gem load path # Default gem load path
def self.default_path def self.default_path
if File.exist?(Gem.user_home)
[user_dir, default_dir] [user_dir, default_dir]
else
[default_dir]
end
end end
## ##
# Deduce Ruby's --program-prefix and --program-suffix from its install name # Deduce Ruby's --program-prefix and --program-suffix from its install name
def self.default_exec_format def self.default_exec_format
baseruby = ConfigMap[:BASERUBY] || 'ruby' exec_format = ConfigMap[:ruby_install_name].sub('ruby', '%s') rescue '%s'
ConfigMap[:RUBY_INSTALL_NAME].sub(baseruby, '%s') rescue '%s'
unless exec_format =~ /%s/ then
raise Gem::Exception,
"[BUG] invalid exec_format #{exec_format.inspect}, no %s"
end
exec_format
end end
## ##

View file

@ -4,8 +4,6 @@
# See LICENSE.txt for permissions. # See LICENSE.txt for permissions.
#++ #++
require 'rubygems'
## ##
# The Dependency class holds a Gem name and a Gem::Requirement # The Dependency class holds a Gem name and a Gem::Requirement
@ -72,7 +70,7 @@ class Gem::Dependency
alias requirements_list requirement_list alias requirements_list requirement_list
def normalize def normalize
ver = @version_requirement.instance_eval { @version } ver = @version_requirement.instance_variable_get :@version
@version_requirements = Gem::Requirement.new([ver]) @version_requirements = Gem::Requirement.new([ver])
@version_requirement = nil @version_requirement = nil
end end
@ -81,6 +79,21 @@ class Gem::Dependency
"#{name} (#{version_requirements}, #{@type || :runtime})" "#{name} (#{version_requirements}, #{@type || :runtime})"
end end
def pretty_print(q) # :nodoc:
q.group 1, 'Gem::Dependency.new(', ')' do
q.pp @name
q.text ','
q.breakable
q.pp @version_requirements
q.text ','
q.breakable
q.pp @type
end
end
def ==(other) # :nodoc: def ==(other) # :nodoc:
self.class === other && self.class === other &&
self.name == other.name && self.name == other.name &&
@ -89,15 +102,22 @@ class Gem::Dependency
end end
## ##
# Uses this dependency as a pattern to compare to the dependency +other+. # Uses this dependency as a pattern to compare to +other+. This dependency
# This dependency will match if the name matches the other's name, and other # will match if the name matches the other's name, and other has only an
# has only an equal version requirement that satisfies this dependency. # equal version requirement that satisfies this dependency.
def =~(other) def =~(other)
return false unless self.class === other other = if self.class === other then
other
else
return false unless other.respond_to? :name and
other.respond_to? :version
Gem::Dependency.new other.name, other.version
end
pattern = @name pattern = @name
pattern = /\A#{@name}\Z/ unless Regexp === pattern pattern = /\A#{Regexp.escape @name}\Z/ unless Regexp === pattern
return false unless pattern =~ other.name return false unless pattern =~ other.name
@ -111,9 +131,18 @@ class Gem::Dependency
version_requirements.satisfied_by? version version_requirements.satisfied_by? version
end end
def hash # :nodoc: ##
# A dependency's hash is the sum of the hash of the #name, #type and
# #version_requirements
def hash
name.hash + type.hash + version_requirements.hash name.hash + type.hash + version_requirements.hash
end end
def inspect # :nodoc:
"<%s type=%p name=%p requirements=%p>" % [self.class, @type, @name,
version_requirements.to_s]
end
end end

View file

@ -20,8 +20,9 @@ class Gem::DependencyInstaller
:force => false, :force => false,
:format_executable => false, # HACK dup :format_executable => false, # HACK dup
:ignore_dependencies => false, :ignore_dependencies => false,
:prerelease => false,
:security_policy => nil, # HACK NoSecurity requires OpenSSL. AlmostNo? Low? :security_policy => nil, # HACK NoSecurity requires OpenSSL. AlmostNo? Low?
:wrappers => true :wrappers => true,
} }
## ##
@ -37,6 +38,7 @@ class Gem::DependencyInstaller
# :format_executable:: See Gem::Installer#initialize. # :format_executable:: See Gem::Installer#initialize.
# :ignore_dependencies:: Don't install any dependencies. # :ignore_dependencies:: Don't install any dependencies.
# :install_dir:: See Gem::Installer#install. # :install_dir:: See Gem::Installer#install.
# :prerelease:: Allow prerelease versions
# :security_policy:: See Gem::Installer::new and Gem::Security. # :security_policy:: See Gem::Installer::new and Gem::Security.
# :user_install:: See Gem::Installer.new # :user_install:: See Gem::Installer.new
# :wrappers:: See Gem::Installer::new # :wrappers:: See Gem::Installer::new
@ -58,6 +60,7 @@ class Gem::DependencyInstaller
@force = options[:force] @force = options[:force]
@format_executable = options[:format_executable] @format_executable = options[:format_executable]
@ignore_dependencies = options[:ignore_dependencies] @ignore_dependencies = options[:ignore_dependencies]
@prerelease = options[:prerelease]
@security_policy = options[:security_policy] @security_policy = options[:security_policy]
@user_install = options[:user_install] @user_install = options[:user_install]
@wrappers = options[:wrappers] @wrappers = options[:wrappers]
@ -90,10 +93,10 @@ class Gem::DependencyInstaller
req req
end end
all = requirements.length > 1 || all = !@prerelease && (requirements.length > 1 ||
(requirements.first != ">=" and requirements.first != ">") (requirements.first != ">=" and requirements.first != ">"))
found = Gem::SpecFetcher.fetcher.fetch dep, all found = Gem::SpecFetcher.fetcher.fetch dep, all, true, @prerelease
gems_and_sources.push(*found) gems_and_sources.push(*found)
rescue Gem::RemoteFetcher::FetchError => e rescue Gem::RemoteFetcher::FetchError => e

View file

@ -8,6 +8,7 @@ require 'tsort'
class Gem::DependencyList class Gem::DependencyList
include Enumerable
include TSort include TSort
def self.from_source_index(src_index) def self.from_source_index(src_index)
@ -24,24 +25,27 @@ class Gem::DependencyList
@specs = [] @specs = []
end end
##
# Adds +gemspecs+ to the dependency list. # Adds +gemspecs+ to the dependency list.
def add(*gemspecs) def add(*gemspecs)
@specs.push(*gemspecs) @specs.push(*gemspecs)
end end
# Return a list of the specifications in the dependency list, ##
# sorted in order so that no spec in the list depends on a gem # Return a list of the specifications in the dependency list, sorted in
# earlier in the list. # order so that no spec in the list depends on a gem earlier in the list.
# #
# This is useful when removing gems from a set of installed gems. # This is useful when removing gems from a set of installed gems. By
# By removing them in the returned order, you don't get into as # removing them in the returned order, you don't get into as many dependency
# many dependency issues. # issues.
# #
# If there are circular dependencies (yuck!), then gems will be # If there are circular dependencies (yuck!), then gems will be returned in
# returned in order until only the circular dependents and anything # order until only the circular dependents and anything they reference are
# they reference are left. Then arbitrary gemspecs will be returned # left. Then arbitrary gemspecs will be returned until the circular
# until the circular dependency is broken, after which gems will be # dependency is broken, after which gems will be returned in dependency
# returned in dependency order again. # order again.
def dependency_order def dependency_order
sorted = strongly_connected_components.flatten sorted = strongly_connected_components.flatten
@ -62,11 +66,20 @@ class Gem::DependencyList
result.reverse result.reverse
end end
##
# Iterator over dependency_order
def each(&block)
dependency_order.each(&block)
end
def find_name(full_name) def find_name(full_name)
@specs.find { |spec| spec.full_name == full_name } @specs.find { |spec| spec.full_name == full_name }
end end
##
# Are all the dependencies in the list satisfied? # Are all the dependencies in the list satisfied?
def ok? def ok?
@specs.all? do |spec| @specs.all? do |spec|
spec.runtime_dependencies.all? do |dep| spec.runtime_dependencies.all? do |dep|
@ -75,10 +88,12 @@ class Gem::DependencyList
end end
end end
##
# Is is ok to remove a gem from the dependency list? # Is is ok to remove a gem from the dependency list?
# #
# If removing the gemspec creates breaks a currently ok dependency, # If removing the gemspec creates breaks a currently ok dependency, then it
# then it is NOT ok to remove the gem. # is NOT ok to remove the gem.
def ok_to_remove?(full_name) def ok_to_remove?(full_name)
gem_to_remove = find_name full_name gem_to_remove = find_name full_name
@ -106,9 +121,10 @@ class Gem::DependencyList
@specs.delete_if { |spec| spec.full_name == full_name } @specs.delete_if { |spec| spec.full_name == full_name }
end end
# Return a hash of predecessors. <tt>result[spec]</tt> is an ##
# Array of gemspecs that have a dependency satisfied by the named # Return a hash of predecessors. <tt>result[spec]</tt> is an Array of
# spec. # gemspecs that have a dependency satisfied by the named spec.
def spec_predecessors def spec_predecessors
result = Hash.new { |h,k| h[k] = [] } result = Hash.new { |h,k| h[k] = [] }
@ -151,13 +167,17 @@ class Gem::DependencyList
private private
##
# Count the number of gemspecs in the list +specs+ that are not in # Count the number of gemspecs in the list +specs+ that are not in
# +ignored+. # +ignored+.
def active_count(specs, ignored) def active_count(specs, ignored)
result = 0 result = 0
specs.each do |spec| specs.each do |spec|
result += 1 unless ignored[spec.full_name] result += 1 unless ignored[spec.full_name]
end end
result result
end end

View file

@ -41,12 +41,23 @@ class Gem::DocManager
begin begin
require 'rdoc/rdoc' require 'rdoc/rdoc'
@rdoc_version = if defined? RDoc::VERSION then
Gem::Version.new RDoc::VERSION
else
Gem::Version.new '1.0.1' # HACK parsing is hard
end
rescue LoadError => e rescue LoadError => e
raise Gem::DocumentError, raise Gem::DocumentError,
"ERROR: RDoc documentation generator not installed!" "ERROR: RDoc documentation generator not installed: #{e}"
end end
end end
def self.rdoc_version
@rdoc_version
end
## ##
# Updates the RI cache for RDoc 2 if it is installed # Updates the RI cache for RDoc 2 if it is installed
@ -94,10 +105,8 @@ class Gem::DocManager
# RI docs generation to fail if run after RDoc). # RI docs generation to fail if run after RDoc).
def generate_ri def generate_ri
if @spec.has_rdoc then
setup_rdoc setup_rdoc
install_ri # RDoc bug, ri goes first install_ri # RDoc bug, ri goes first
end
FileUtils.mkdir_p @doc_dir unless File.exist?(@doc_dir) FileUtils.mkdir_p @doc_dir unless File.exist?(@doc_dir)
end end
@ -110,10 +119,8 @@ class Gem::DocManager
# RI docs generation to fail if run after RDoc). # RI docs generation to fail if run after RDoc).
def generate_rdoc def generate_rdoc
if @spec.has_rdoc then
setup_rdoc setup_rdoc
install_rdoc install_rdoc
end
FileUtils.mkdir_p @doc_dir unless File.exist?(@doc_dir) FileUtils.mkdir_p @doc_dir unless File.exist?(@doc_dir)
end end
@ -151,8 +158,17 @@ class Gem::DocManager
args << '--quiet' args << '--quiet'
args << @spec.require_paths.clone args << @spec.require_paths.clone
args << @spec.extra_rdoc_files args << @spec.extra_rdoc_files
args << '--title' << "#{@spec.full_name} Documentation"
args = args.flatten.map do |arg| arg.to_s end args = args.flatten.map do |arg| arg.to_s end
if self.class.rdoc_version >= Gem::Version.new('2.4.0') then
args.delete '--inline-source'
args.delete '--promiscuous'
args.delete '-p'
args.delete '--one-file'
# HACK more
end
r = RDoc::RDoc.new r = RDoc::RDoc.new
old_pwd = Dir.pwd old_pwd = Dir.pwd

View file

@ -1,5 +1,3 @@
require 'rubygems'
## ##
# Base exception class for RubyGems. All exception raised by RubyGems are a # Base exception class for RubyGems. All exception raised by RubyGems are a
# subclass of this one. # subclass of this one.

View file

@ -4,8 +4,6 @@
# See LICENSE.txt for permissions. # See LICENSE.txt for permissions.
#++ #++
require 'rubygems/ext'
class Gem::Ext::Builder class Gem::Ext::Builder
def self.class_name def self.class_name

View file

@ -11,6 +11,7 @@ class Gem::Ext::ConfigureBuilder < Gem::Ext::Builder
def self.build(extension, directory, dest_path, results) def self.build(extension, directory, dest_path, results)
unless File.exist?('Makefile') then unless File.exist?('Makefile') then
cmd = "sh ./configure --prefix=#{dest_path}" cmd = "sh ./configure --prefix=#{dest_path}"
cmd << " #{Gem::Command.build_args.join ' '}" unless Gem::Command.build_args.empty?
run cmd, results run cmd, results
end end

View file

@ -5,12 +5,13 @@
#++ #++
require 'rubygems/ext/builder' require 'rubygems/ext/builder'
require 'rubygems/command'
class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder
def self.build(extension, directory, dest_path, results) def self.build(extension, directory, dest_path, results)
cmd = "#{Gem.ruby} #{File.basename extension}" cmd = "#{Gem.ruby} #{File.basename extension}"
cmd << " #{ARGV.join ' '}" unless ARGV.empty? cmd << " #{Gem::Command.build_args.join ' '}" unless Gem::Command.build_args.empty?
run cmd, results run cmd, results

View file

@ -5,17 +5,21 @@
#++ #++
require 'rubygems/ext/builder' require 'rubygems/ext/builder'
require 'rubygems/command'
class Gem::Ext::RakeBuilder < Gem::Ext::Builder class Gem::Ext::RakeBuilder < Gem::Ext::Builder
def self.build(extension, directory, dest_path, results) def self.build(extension, directory, dest_path, results)
if File.basename(extension) =~ /mkrf_conf/i then if File.basename(extension) =~ /mkrf_conf/i then
cmd = "#{Gem.ruby} #{File.basename extension}" cmd = "#{Gem.ruby} #{File.basename extension}"
cmd << " #{ARGV.join " "}" unless ARGV.empty? cmd << " #{Gem::Command.build_args.join " "}" unless Gem::Command.build_args.empty?
run cmd, results run cmd, results
end end
cmd = ENV['rake'] || 'rake' # Deal with possible spaces in the path, e.g. C:/Program Files
dest_path = '"' + dest_path + '"' if dest_path.include?(' ')
cmd = ENV['rake'] || "#{Gem.ruby} -rubygems #{Gem.bin_path('rake')}" rescue Gem.default_exec_format % 'rake'
cmd += " RUBYARCHDIR=#{dest_path} RUBYLIBDIR=#{dest_path}" # ENV is frozen cmd += " RUBYARCHDIR=#{dest_path} RUBYLIBDIR=#{dest_path}" # ENV is frozen
run cmd, results run cmd, results

View file

@ -8,14 +8,14 @@ require 'fileutils'
require 'rubygems/package' require 'rubygems/package'
module Gem ##
# Gem::Format knows the guts of the RubyGem .gem file format and provides the
# capability to read gem files
class Gem::Format
##
# The format class knows the guts of the RubyGem .gem file format
# and provides the capability to read gem files
#
class Format
attr_accessor :spec, :file_entries, :gem_path attr_accessor :spec, :file_entries, :gem_path
extend Gem::UserInteraction extend Gem::UserInteraction
## ##
@ -33,7 +33,7 @@ module Gem
# the data from the gem file # the data from the gem file
# #
# file_path:: [String] Path to the gem file # file_path:: [String] Path to the gem file
#
def self.from_file_by_path(file_path, security_policy = nil) def self.from_file_by_path(file_path, security_policy = nil)
format = nil format = nil
@ -45,7 +45,7 @@ module Gem
if File.read(file_path, 20).include?("MD5SUM =") if File.read(file_path, 20).include?("MD5SUM =")
require 'rubygems/old_format' require 'rubygems/old_format'
format = OldFormat.from_file_by_path(file_path) format = Gem::OldFormat.from_file_by_path(file_path)
else else
open file_path, Gem.binary_mode do |io| open file_path, Gem.binary_mode do |io|
format = from_io io, file_path, security_policy format = from_io io, file_path, security_policy
@ -60,11 +60,11 @@ module Gem
# the data from the gem file # the data from the gem file
# #
# io:: [IO] Stream from which to read the gem # io:: [IO] Stream from which to read the gem
#
def self.from_io(io, gem_path="(io)", security_policy = nil) def self.from_io(io, gem_path="(io)", security_policy = nil)
format = new gem_path format = new gem_path
Package.open io, 'r', security_policy do |pkg| Gem::Package.open io, 'r', security_policy do |pkg|
format.spec = pkg.metadata format.spec = pkg.metadata
format.file_entries = [] format.file_entries = []
@ -83,5 +83,5 @@ module Gem
format format
end end
end
end end

View file

@ -4,23 +4,30 @@
# See LICENSE.txt for permissions. # See LICENSE.txt for permissions.
#++ #++
#--
# Some system might not have OpenSSL installed, therefore the core # Some system might not have OpenSSL installed, therefore the core
# library file openssl might not be available. We localize testing # library file openssl might not be available. We localize testing
# for the presence of OpenSSL in this file. # for the presence of OpenSSL in this file.
#++
module Gem module Gem
class << self class << self
##
# Is SSL (used by the signing commands) available on this # Is SSL (used by the signing commands) available on this
# platform? # platform?
def ssl_available? def ssl_available?
require 'rubygems/gem_openssl'
@ssl_available @ssl_available
end end
# Set the value of the ssl_available flag. ##
# Is SSL available?
attr_writer :ssl_available attr_writer :ssl_available
##
# Ensure that SSL is available. Throw an exception if it is not. # Ensure that SSL is available. Throw an exception if it is not.
def ensure_ssl_available def ensure_ssl_available
unless ssl_available? unless ssl_available?
fail Gem::Exception, "SSL is not installed on this system" fail Gem::Exception, "SSL is not installed on this system"
@ -61,6 +68,8 @@ rescue LoadError, StandardError
Gem.ssl_available = false Gem.ssl_available = false
end end
# :stopdoc:
module Gem::SSL module Gem::SSL
# We make our own versions of the constants here. This allows us # We make our own versions of the constants here. This allows us
@ -70,7 +79,7 @@ module Gem::SSL
# These constants are only used during load time. At runtime, any # These constants are only used during load time. At runtime, any
# method that makes a direct reference to SSL software must be # method that makes a direct reference to SSL software must be
# protected with a Gem.ensure_ssl_available call. # protected with a Gem.ensure_ssl_available call.
#
if Gem.ssl_available? then if Gem.ssl_available? then
PKEY_RSA = OpenSSL::PKey::RSA PKEY_RSA = OpenSSL::PKey::RSA
DIGEST_SHA1 = OpenSSL::Digest::SHA1 DIGEST_SHA1 = OpenSSL::Digest::SHA1
@ -81,3 +90,5 @@ module Gem::SSL
end end
# :startdoc:

View file

@ -4,8 +4,6 @@
# See LICENSE.txt for permissions. # See LICENSE.txt for permissions.
#++ #++
require 'rubygems'
## ##
# GemPathSearcher has the capability to find loadable files inside # GemPathSearcher has the capability to find loadable files inside
# gems. It generates data up front to speed up searches later. # gems. It generates data up front to speed up searches later.
@ -80,11 +78,15 @@ class Gem::GemPathSearcher
## ##
# Return a list of all installed gemspecs, sorted by alphabetical order and # Return a list of all installed gemspecs, sorted by alphabetical order and
# in reverse version order. # in reverse version order. (bar-2, bar-1, foo-2)
def init_gemspecs def init_gemspecs
Gem.source_index.map { |_, spec| spec }.sort { |a,b| specs = Gem.source_index.map { |_, spec| spec }
(a.name <=> b.name).nonzero? || (b.version <=> a.version)
specs.sort { |a, b|
names = a.name <=> b.name
next names if names.nonzero?
b.version <=> a.version
} }
end end

View file

@ -8,12 +8,16 @@ require 'rubygems/command_manager'
require 'rubygems/config_file' require 'rubygems/config_file'
require 'rubygems/doc_manager' require 'rubygems/doc_manager'
module Gem ##
# Run an instance of the gem program.
#
# Gem::GemRunner is only intended for internal use by RubyGems itself. It
# does not form any public API and may change at any time for any reason.
#
# If you would like to duplicate functionality of `gem` commands, use the
# classes they call directly.
#################################################################### class Gem::GemRunner
# Run an instance of the gem program.
#
class GemRunner
def initialize(options={}) def initialize(options={})
@command_manager_class = options[:command_manager] || Gem::CommandManager @command_manager_class = options[:command_manager] || Gem::CommandManager
@ -21,11 +25,25 @@ module Gem
@doc_manager_class = options[:doc_manager] || Gem::DocManager @doc_manager_class = options[:doc_manager] || Gem::DocManager
end end
##
# Run the gem command with the following arguments. # Run the gem command with the following arguments.
def run(args) def run(args)
start_time = Time.now start_time = Time.now
do_configuration(args)
if args.include?('--')
# We need to preserve the original ARGV to use for passing gem options
# to source gems. If there is a -- in the line, strip all options after
# it...its for the source building process.
build_args = args[args.index("--") + 1...args.length]
args = args[0...args.index("--")]
end
Gem::Command.build_args = build_args if build_args
do_configuration args
cmd = @command_manager_class.instance cmd = @command_manager_class.instance
cmd.command_names.each do |command_name| cmd.command_names.each do |command_name|
config_args = Gem.configuration[command_name] config_args = Gem.configuration[command_name]
config_args = case config_args config_args = case config_args
@ -34,12 +52,14 @@ module Gem
else else
Array(config_args) Array(config_args)
end end
Command.add_specific_extra_args command_name, config_args Gem::Command.add_specific_extra_args command_name, config_args
end end
cmd.run(Gem.configuration.args)
cmd.run Gem.configuration.args
end_time = Time.now end_time = Time.now
if Gem.configuration.benchmark
printf "\nExecution time: %0.2f seconds.\n", end_time-start_time if Gem.configuration.benchmark then
printf "\nExecution time: %0.2f seconds.\n", end_time - start_time
puts "Press Enter to finish" puts "Press Enter to finish"
STDIN.gets STDIN.gets
end end
@ -54,5 +74,5 @@ module Gem
@doc_manager_class.configured_args = Gem.configuration[:rdoc] @doc_manager_class.configured_args = Gem.configuration[:rdoc]
end end
end # class end
end # module

View file

@ -6,6 +6,7 @@ require 'rubygems'
require 'rubygems/format' require 'rubygems/format'
begin begin
gem 'builder'
require 'builder/xchar' require 'builder/xchar'
rescue LoadError rescue LoadError
end end
@ -17,11 +18,36 @@ class Gem::Indexer
include Gem::UserInteraction include Gem::UserInteraction
##
# Build indexes for RubyGems older than 1.2.0 when true
attr_accessor :build_legacy
##
# Build indexes for RubyGems 1.2.0 and newer when true
attr_accessor :build_modern
## ##
# Index install location # Index install location
attr_reader :dest_directory attr_reader :dest_directory
##
# Specs index install location
attr_reader :dest_specs_index
##
# Latest specs index install location
attr_reader :dest_latest_specs_index
##
# Prerelease specs index install location
attr_reader :dest_prerelease_specs_index
## ##
# Index build directory # Index build directory
@ -30,12 +56,21 @@ class Gem::Indexer
## ##
# Create an indexer that will index the gems in +directory+. # Create an indexer that will index the gems in +directory+.
def initialize(directory) def initialize(directory, options = {})
unless ''.respond_to? :to_xs then unless ''.respond_to? :to_xs then
fail "Gem::Indexer requires that the XML Builder library be installed:" \ fail "Gem::Indexer requires that the XML Builder library be installed:" \
"\n\tgem install builder" "\n\tgem install builder"
end end
options = { :build_legacy => true, :build_modern => true }.merge options
@build_legacy = options[:build_legacy]
@build_modern = options[:build_modern]
@rss_title = options[:rss_title]
@rss_host = options[:rss_host]
@rss_gems_host = options[:rss_gems_host]
@dest_directory = directory @dest_directory = directory
@directory = File.join Dir.tmpdir, "gem_generate_index_#{$$}" @directory = File.join Dir.tmpdir, "gem_generate_index_#{$$}"
@ -54,22 +89,19 @@ class Gem::Indexer
@specs_index = File.join @directory, "specs.#{Gem.marshal_version}" @specs_index = File.join @directory, "specs.#{Gem.marshal_version}"
@latest_specs_index = File.join @directory, @latest_specs_index = File.join @directory,
"latest_specs.#{Gem.marshal_version}" "latest_specs.#{Gem.marshal_version}"
@prerelease_specs_index = File.join(@directory,
"prerelease_specs.#{Gem.marshal_version}")
files = [ @dest_specs_index = File.join @dest_directory,
@specs_index, "specs.#{Gem.marshal_version}"
"#{@specs_index}.gz", @dest_latest_specs_index = File.join @dest_directory,
@latest_specs_index, "latest_specs.#{Gem.marshal_version}"
"#{@latest_specs_index}.gz", @dest_prerelease_specs_index = File.join @dest_directory,
@quick_dir, "prerelease_specs.#{Gem.marshal_version}"
@master_index,
"#{@master_index}.Z",
@marshal_index,
"#{@marshal_index}.Z",
]
@files = files.map do |path| @rss_index = File.join @directory, 'index.rss'
path.sub @directory, ''
end @files = []
end end
## ##
@ -91,78 +123,68 @@ class Gem::Indexer
# Build various indicies # Build various indicies
def build_indicies(index) def build_indicies(index)
# Marshal gemspecs are used by both modern and legacy RubyGems
build_marshal_gemspecs index
build_legacy_indicies index if @build_legacy
build_modern_indicies index if @build_modern
build_rss index
compress_indicies
end
##
# Builds indicies for RubyGems older than 1.2.x
def build_legacy_indicies(index)
progress = ui.progress_reporter index.size, progress = ui.progress_reporter index.size,
"Generating quick index gemspecs for #{index.size} gems", "Generating YAML quick index gemspecs for #{index.size} gems",
"Complete" "Complete"
Gem.time 'Generated YAML quick index gemspecs' do
index.each do |original_name, spec| index.each do |original_name, spec|
spec_file_name = "#{original_name}.gemspec.rz" spec_file_name = "#{original_name}.gemspec.rz"
yaml_name = File.join @quick_dir, spec_file_name yaml_name = File.join @quick_dir, spec_file_name
marshal_name = File.join @quick_marshal_dir, spec_file_name
yaml_zipped = Gem.deflate spec.to_yaml yaml_zipped = Gem.deflate spec.to_yaml
open yaml_name, 'wb' do |io| io.write yaml_zipped end open yaml_name, 'wb' do |io| io.write yaml_zipped end
marshal_zipped = Gem.deflate Marshal.dump(spec)
open marshal_name, 'wb' do |io| io.write marshal_zipped end
progress.updated original_name progress.updated original_name
end end
progress.done progress.done
say "Generating specs index"
open @specs_index, 'wb' do |io|
specs = index.sort.map do |_, spec|
platform = spec.original_platform
platform = Gem::Platform::RUBY if platform.nil? or platform.empty?
[spec.name, spec.version, platform]
end
specs = compact_specs specs
Marshal.dump specs, io
end
say "Generating latest specs index"
open @latest_specs_index, 'wb' do |io|
specs = index.latest_specs.sort.map do |spec|
platform = spec.original_platform
platform = Gem::Platform::RUBY if platform.nil? or platform.empty?
[spec.name, spec.version, platform]
end
specs = compact_specs specs
Marshal.dump specs, io
end end
say "Generating quick index" say "Generating quick index"
quick_index = File.join @quick_dir, 'index' Gem.time 'Generated quick index' do
open quick_index, 'wb' do |io| open @quick_index, 'wb' do |io|
io.puts index.sort.map { |_, spec| spec.original_name } io.puts index.sort.map { |_, spec| spec.original_name }
end end
end
say "Generating latest index" say "Generating latest index"
latest_index = File.join @quick_dir, 'latest_index' Gem.time 'Generated latest index' do
open latest_index, 'wb' do |io| open @latest_index, 'wb' do |io|
io.puts index.latest_specs.sort.map { |spec| spec.original_name } io.puts index.latest_specs.sort.map { |spec| spec.original_name }
end end
end
# Don't need prerelease legacy index
say "Generating Marshal master index" say "Generating Marshal master index"
Gem.time 'Generated Marshal master index' do
open @marshal_index, 'wb' do |io| open @marshal_index, 'wb' do |io|
io.write index.dump io.write index.dump
end end
end
progress = ui.progress_reporter index.size, progress = ui.progress_reporter index.size,
"Generating YAML master index for #{index.size} gems (this may take a while)", "Generating YAML master index for #{index.size} gems (this may take a while)",
"Complete" "Complete"
Gem.time 'Generated YAML master index' do
open @master_index, 'wb' do |io| open @master_index, 'wb' do |io|
io.puts "--- !ruby/object:#{index.class}" io.puts "--- !ruby/object:#{index.class}"
io.puts "gems:" io.puts "gems:"
@ -179,37 +201,219 @@ class Gem::Indexer
end end
progress.done progress.done
end
say "Compressing indicies" @files << @quick_dir
# use gzip for future files. @files << @master_index
@files << "#{@master_index}.Z"
@files << @marshal_index
@files << "#{@marshal_index}.Z"
end
compress quick_index, 'rz' ##
paranoid quick_index, 'rz' # Builds Marshal quick index gemspecs.
compress latest_index, 'rz' def build_marshal_gemspecs(index)
paranoid latest_index, 'rz' progress = ui.progress_reporter index.size,
"Generating Marshal quick index gemspecs for #{index.size} gems",
"Complete"
compress @marshal_index, 'Z' files = []
paranoid @marshal_index, 'Z'
compress @master_index, 'Z' Gem.time 'Generated Marshal quick index gemspecs' do
paranoid @master_index, 'Z' (index.gems.merge(index.prerelease_gems)).each do |original_name, spec|
spec_file_name = "#{original_name}.gemspec.rz"
marshal_name = File.join @quick_marshal_dir, spec_file_name
gzip @specs_index marshal_zipped = Gem.deflate Marshal.dump(spec)
gzip @latest_specs_index open marshal_name, 'wb' do |io| io.write marshal_zipped end
files << marshal_name
progress.updated original_name
end
progress.done
end
@files << @quick_marshal_dir
files
end
##
# Build a single index for RubyGems 1.2 and newer
def build_modern_index(index, file, name)
say "Generating #{name} index"
Gem.time "Generated #{name} index" do
open(file, 'wb') do |io|
specs = index.map do |*spec|
# We have to splat here because latest_specs is an array,
# while the others are hashes. See the TODO in source_index.rb
spec = spec.flatten.last
platform = spec.original_platform
# win32-api-1.0.4-x86-mswin32-60
unless String === platform then
alert_warning "Skipping invalid platform in gem: #{spec.full_name}"
next
end
platform = Gem::Platform::RUBY if platform.nil? or platform.empty?
[spec.name, spec.version, platform]
end
specs = compact_specs(specs)
Marshal.dump(specs, io)
end
end
end
##
# Builds indicies for RubyGems 1.2 and newer. Handles full, latest, prerelease
def build_modern_indicies(index)
build_modern_index(index.sort, @specs_index, 'specs')
build_modern_index(index.latest_specs.sort,
@latest_specs_index,
'latest specs')
build_modern_index(index.prerelease_specs.sort,
@prerelease_specs_index,
'prerelease specs')
@files += [@specs_index,
"#{@specs_index}.gz",
@latest_specs_index,
"#{@latest_specs_index}.gz",
@prerelease_specs_index,
"#{@prerelease_specs_index}.gz"]
end
##
# Builds an RSS feed for past two days gem releases according to the gem's
# date.
def build_rss(index)
if @rss_host.nil? or @rss_gems_host.nil? then
if Gem.configuration.really_verbose then
alert_warning "no --rss-host or --rss-gems-host, RSS generation disabled"
end
return
end
require 'cgi'
require 'rubygems/text'
extend Gem::Text
Gem.time 'Generated rss' do
open @rss_index, 'wb' do |io|
rss_host = CGI.escapeHTML @rss_host
rss_title = CGI.escapeHTML(@rss_title || 'gems')
io.puts <<-HEADER
<?xml version="1.0"?>
<rss version="2.0">
<channel>
<title>#{rss_title}</title>
<link>http://#{rss_host}</link>
<description>Recently released gems from http://#{rss_host}</description>
<generator>RubyGems v#{Gem::RubyGemsVersion}</generator>
<docs>http://cyber.law.harvard.edu/rss/rss.html</docs>
HEADER
today = Gem::Specification::TODAY
yesterday = today - 86400
index = index.select do |_, spec|
spec_date = spec.date
case spec_date
when Date
Time.parse(spec_date.to_s) >= yesterday
when Time
spec_date >= yesterday
end
end
index = index.select do |_, spec|
spec_date = spec.date
case spec_date
when Date
Time.parse(spec_date.to_s) <= today
when Time
spec_date <= today
end
end
index.sort_by { |_, spec| [-spec.date.to_i, spec] }.each do |_, spec|
gem_path = CGI.escapeHTML "http://#{@rss_gems_host}/gems/#{spec.full_name}.gem"
size = File.stat(spec.loaded_from).size rescue next
description = spec.description || spec.summary || ''
authors = Array spec.authors
emails = Array spec.email
authors = emails.zip(authors).map do |email, author|
email += " (#{author})" if author and not author.empty?
end.join ', '
description = description.split(/\n\n+/).map do |chunk|
format_text chunk, 78
end
description = description.join "\n\n"
item = ''
item << <<-ITEM
<item>
<title>#{CGI.escapeHTML spec.full_name}</title>
<description>
&lt;pre&gt;#{CGI.escapeHTML description.chomp}&lt;/pre&gt;
</description>
<author>#{CGI.escapeHTML authors}</author>
<guid>#{CGI.escapeHTML spec.full_name}</guid>
<enclosure url=\"#{gem_path}\"
length=\"#{size}\" type=\"application/octet-stream\" />
<pubDate>#{spec.date.rfc2822}</pubDate>
ITEM
item << <<-ITEM if spec.homepage
<link>#{CGI.escapeHTML spec.homepage}</link>
ITEM
item << <<-ITEM
</item>
ITEM
io.puts item
end
io.puts <<-FOOTER
</channel>
</rss>
FOOTER
end
end
@files << @rss_index
end end
## ##
# Collect specifications from .gem files from the gem directory. # Collect specifications from .gem files from the gem directory.
def collect_specs def collect_specs(gems = gem_file_list)
index = Gem::SourceIndex.new index = Gem::SourceIndex.new
progress = ui.progress_reporter gem_file_list.size, progress = ui.progress_reporter gems.size,
"Loading #{gem_file_list.size} gems from #{@dest_directory}", "Loading #{gems.size} gems from #{@dest_directory}",
"Loaded all gems" "Loaded all gems"
gem_file_list.each do |gemfile| Gem.time 'loaded' do
gems.each do |gemfile|
if File.size(gemfile.to_s) == 0 then if File.size(gemfile.to_s) == 0 then
alert_warning "Skipping zero-length gem: #{gemfile}" alert_warning "Skipping zero-length gem: #{gemfile}"
next next
@ -217,16 +421,20 @@ class Gem::Indexer
begin begin
spec = Gem::Format.from_file_by_path(gemfile).spec spec = Gem::Format.from_file_by_path(gemfile).spec
spec.loaded_from = gemfile
unless gemfile =~ /\/#{Regexp.escape spec.original_name}.*\.gem\z/i then unless gemfile =~ /\/#{Regexp.escape spec.original_name}.*\.gem\z/i then
alert_warning "Skipping misnamed gem: #{gemfile} => #{spec.full_name} (#{spec.original_name})" expected_name = spec.full_name
expected_name << " (#{spec.original_name})" if
spec.original_name != spec.full_name
alert_warning "Skipping misnamed gem: #{gemfile} should be named #{expected_name}"
next next
end end
abbreviate spec abbreviate spec
sanitize spec sanitize spec
index.gems[spec.original_name] = spec index.add_spec spec, spec.original_name
progress.updated spec.original_name progress.updated spec.original_name
@ -239,10 +447,42 @@ class Gem::Indexer
end end
progress.done progress.done
end
index index
end end
##
# Compresses indicies on disk
#--
# All future files should be compressed using gzip, not deflate
def compress_indicies
say "Compressing indicies"
Gem.time 'Compressed indicies' do
if @build_legacy then
compress @quick_index, 'rz'
paranoid @quick_index, 'rz'
compress @latest_index, 'rz'
paranoid @latest_index, 'rz'
compress @marshal_index, 'Z'
paranoid @marshal_index, 'Z'
compress @master_index, 'Z'
paranoid @master_index, 'Z'
end
if @build_modern then
gzip @specs_index
gzip @latest_specs_index
gzip @prerelease_specs_index
end
end
end
## ##
# Compacts Marshal output for the specs index data source by using identical # Compacts Marshal output for the specs index data source by using identical
# objects as much as possible. # objects as much as possible.
@ -282,7 +522,7 @@ class Gem::Indexer
end end
## ##
# Builds and installs indexicies. # Builds and installs indicies.
def generate_index def generate_index
make_temp_directories make_temp_directories
@ -311,7 +551,27 @@ class Gem::Indexer
say "Moving index into production dir #{@dest_directory}" if verbose say "Moving index into production dir #{@dest_directory}" if verbose
@files.each do |file| files = @files.dup
files.delete @quick_marshal_dir if files.include? @quick_dir
if files.include? @quick_marshal_dir and
not files.include? @quick_dir then
files.delete @quick_marshal_dir
quick_marshal_dir = @quick_marshal_dir.sub @directory, ''
dst_name = File.join @dest_directory, quick_marshal_dir
FileUtils.mkdir_p File.dirname(dst_name), :verbose => verbose
FileUtils.rm_rf dst_name, :verbose => verbose
FileUtils.mv @quick_marshal_dir, dst_name, :verbose => verbose,
:force => true
end
files = files.map do |path|
path.sub @directory, ''
end
files.each do |file|
src_name = File.join @directory, file src_name = File.join @directory, file
dst_name = File.join @dest_directory, file dst_name = File.join @dest_directory, file
@ -366,5 +626,87 @@ class Gem::Indexer
string ? string.to_s.to_xs : string string ? string.to_s.to_xs : string
end end
##
# Perform an in-place update of the repository from newly added gems. Only
# works for modern indicies, and sets #build_legacy to false when run.
def update_index
@build_legacy = false
make_temp_directories
specs_mtime = File.stat(@dest_specs_index).mtime
newest_mtime = Time.at 0
updated_gems = gem_file_list.select do |gem|
gem_mtime = File.stat(gem).mtime
newest_mtime = gem_mtime if gem_mtime > newest_mtime
gem_mtime >= specs_mtime
end
if updated_gems.empty? then
say 'No new gems'
terminate_interaction 0
end
index = collect_specs updated_gems
files = build_marshal_gemspecs index
Gem.time 'Updated indexes' do
update_specs_index index, @dest_specs_index, @specs_index
update_specs_index index, @dest_latest_specs_index, @latest_specs_index
update_specs_index(index.prerelease_gems, @dest_prerelease_specs_index,
@prerelease_specs_index)
end
compress_indicies
verbose = Gem.configuration.really_verbose
say "Updating production dir #{@dest_directory}" if verbose
files << @specs_index
files << "#{@specs_index}.gz"
files << @latest_specs_index
files << "#{@latest_specs_index}.gz"
files << @prerelease_specs_index
files << "#{@prerelease_specs_index}.gz"
files = files.map do |path|
path.sub @directory, ''
end
files.each do |file|
src_name = File.join @directory, file
dst_name = File.join @dest_directory, File.dirname(file)
FileUtils.mv src_name, dst_name, :verbose => verbose,
:force => true
File.utime newest_mtime, newest_mtime, dst_name
end
end
##
# Combines specs in +index+ and +source+ then writes out a new copy to
# +dest+. For a latest index, does not ensure the new file is minimal.
def update_specs_index(index, source, dest)
specs_index = Marshal.load Gem.read_binary(source)
index.each do |_, spec|
platform = spec.original_platform
platform = Gem::Platform::RUBY if platform.nil? or platform.empty?
specs_index << [spec.name, spec.version, platform]
end
specs_index = compact_specs specs_index.uniq.sort
open dest, 'wb' do |io|
Marshal.dump specs_index, io
end
end
end end

View file

@ -9,9 +9,12 @@ require 'rubygems/security'
## ##
# 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
##
# 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
OptionParser.accept Gem::Security::Policy do |value| OptionParser.accept Gem::Security::Policy do |value|
value = Gem::Security::Policies[value] value = Gem::Security::Policies[value]
@ -92,7 +95,7 @@ module Gem::InstallUpdateOptions
add_option(:"Install/Update", '--[no-]user-install', add_option(:"Install/Update", '--[no-]user-install',
'Install in user\'s home directory instead', 'Install in user\'s home directory instead',
'of GEM_HOME. Defaults to using home directory', 'of GEM_HOME. Defaults to using home',
'only if GEM_HOME is not writable.') do |value, options| 'only if GEM_HOME is not writable.') do |value, options|
options[:user_install] = value options[:user_install] = value
end end
@ -102,9 +105,18 @@ module Gem::InstallUpdateOptions
"dependencies") do |value, options| "dependencies") do |value, options|
options[:development] = true options[:development] = true
end end
add_option(:"Install/Update", "--prerelease",
"Install prerelease versions of a gem if",
"available. Defaults to skipping",
"prereleases.") do |value, options|
options[:prerelease] = true
end
end end
##
# Default options for the gem install command. # Default options for the gem install command.
def install_update_defaults_str def install_update_defaults_str
'--rdoc --no-force --no-test --wrappers' '--rdoc --no-force --no-test --wrappers'
end end

View file

@ -13,16 +13,27 @@ require 'rubygems/ext'
require 'rubygems/require_paths_builder' require 'rubygems/require_paths_builder'
## ##
# The installer class processes RubyGem .gem files and installs the # The installer class processes RubyGem .gem files and installs the files
# files contained in the .gem into the Gem.path. # contained in the .gem into the Gem.path.
# #
# Gem::Installer does the work of putting files in all the right places on the # Gem::Installer does the work of putting files in all the right places on the
# filesystem including unpacking the gem into its gem dir, installing the # filesystem including unpacking the gem into its gem dir, installing the
# gemspec in the specifications dir, storing the cached gem in the cache dir, # gemspec in the specifications dir, storing the cached gem in the cache dir,
# and installing either wrappers or symlinks for executables. # and installing either wrappers or symlinks for executables.
#
# The installer fires pre and post install hooks. Hooks can be added either
# through a rubygems_plugin.rb file in an installed gem or via a
# rubygems/defaults/#{RUBY_ENGINE}.rb or rubygems/defaults/operating_system.rb
# file. See Gem.pre_install and Gem.post_install for details.
class Gem::Installer class Gem::Installer
##
# Paths where env(1) might live. Some systems are broken and have it in
# /bin
ENV_PATHS = %w[/usr/bin/env /bin/env]
## ##
# Raised when there is an error while building extensions. # Raised when there is an error while building extensions.
# #
@ -71,8 +82,6 @@ class Gem::Installer
end end
ENV_PATHS = %w[/usr/bin/env /bin/env]
## ##
# Constructs an Installer instance that will install the gem located at # Constructs an Installer instance that will install the gem located at
# +gem+. +options+ is a Hash with the following keys: # +gem+. +options+ is a Hash with the following keys:
@ -121,7 +130,7 @@ class Gem::Installer
begin begin
FileUtils.mkdir_p @gem_home FileUtils.mkdir_p @gem_home
rescue Errno::EACCES, Errno::ENOTDIR rescue Errno::EACCES, Errno::ENOTDIR
# We'll divert to ~/.gem below # We'll divert to ~/.gems below
end end
if not File.writable? @gem_home or if not File.writable? @gem_home or
@ -131,7 +140,7 @@ class Gem::Installer
if options[:user_install] == false then # You don't want to use ~ if options[:user_install] == false then # You don't want to use ~
raise Gem::FilePermissionError, @gem_home raise Gem::FilePermissionError, @gem_home
elsif options[:user_install].nil? then elsif options[:user_install].nil? then
unless self.class.home_install_warning then unless self.class.home_install_warning or options[:unpack] then
alert_warning "Installing to ~/.gem since #{@gem_home} and\n\t #{Gem.bindir} aren't both writable." alert_warning "Installing to ~/.gem since #{@gem_home} and\n\t #{Gem.bindir} aren't both writable."
self.class.home_install_warning = true self.class.home_install_warning = true
end end
@ -392,19 +401,21 @@ class Gem::Installer
ruby_name = Gem::ConfigMap[:ruby_install_name] if @env_shebang ruby_name = Gem::ConfigMap[:ruby_install_name] if @env_shebang
path = File.join @gem_dir, @spec.bindir, bin_file_name path = File.join @gem_dir, @spec.bindir, bin_file_name
first_line = File.open(path, "rb") {|file| file.gets} first_line = File.open(path, "rb") {|file| file.gets}
if /\A#!/ =~ first_line then if /\A#!/ =~ first_line then
# Preserve extra words on shebang line, like "-w". Thanks RPA. # Preserve extra words on shebang line, like "-w". Thanks RPA.
shebang = first_line.sub(/\A\#!.*?ruby\S*(?=(\s+\S+))/, "#!#{Gem.ruby}") shebang = first_line.sub(/\A\#!.*?ruby\S*(?=(\s+\S+))/, "#!#{Gem.ruby}")
opts = $1 opts = $1
shebang.strip! # Avoid nasty ^M issues. shebang.strip! # Avoid nasty ^M issues.
end end
if !ruby_name
if not ruby_name then
"#!#{Gem.ruby}#{opts}" "#!#{Gem.ruby}#{opts}"
elsif opts elsif opts then
%{#!/bin/sh\n'exec' #{ruby_name.dump} '-x' "$0" "$@"\n#{shebang}} "#!/bin/sh\n'exec' #{ruby_name.dump} '-x' \"$0\" \"$@\"\n#{shebang}"
else else
# Create a plain shebang line. # Create a plain shebang line.
@env_path ||= ENV_PATHS.find {|path| File.executable?(path)} @env_path ||= ENV_PATHS.find {|env_path| File.executable? env_path }
"#!#{@env_path} #{ruby_name}" "#!#{@env_path} #{ruby_name}"
end end
end end
@ -432,7 +443,7 @@ if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
end end
gem '#{@spec.name}', version gem '#{@spec.name}', version
load '#{bin_file_name}' load Gem.bin_path('#{@spec.name}', '#{bin_file_name}', version)
TEXT TEXT
end end
@ -443,10 +454,10 @@ TEXT
<<-TEXT <<-TEXT
@ECHO OFF @ECHO OFF
IF NOT "%~f0" == "~f0" GOTO :WinNT IF NOT "%~f0" == "~f0" GOTO :WinNT
@"#{File.basename(Gem.ruby)}" "#{File.join(bindir, bin_file_name)}" %1 %2 %3 %4 %5 %6 %7 %8 %9 @"#{File.basename(Gem.ruby).chomp('"')}" "#{File.join(bindir, bin_file_name)}" %1 %2 %3 %4 %5 %6 %7 %8 %9
GOTO :EOF GOTO :EOF
:WinNT :WinNT
@"#{File.basename(Gem.ruby)}" "%~dpn0" %* @"#{File.basename(Gem.ruby).chomp('"')}" "%~dpn0" %*
TEXT TEXT
end end
@ -531,6 +542,7 @@ Results logged to #{File.join(Dir.pwd, 'gem_make.out')}
raise Gem::InstallError, msg raise Gem::InstallError, msg
end end
FileUtils.rm_rf(path) if File.exists?(path)
FileUtils.mkdir_p File.dirname(path) FileUtils.mkdir_p File.dirname(path)
File.open(path, "wb") do |out| File.open(path, "wb") do |out|

View file

@ -23,7 +23,9 @@ module Gem::LocalRemoteOptions
raise OptionParser::InvalidArgument, value raise OptionParser::InvalidArgument, value
end end
raise OptionParser::InvalidArgument, value unless uri.scheme == 'http' unless ['http', 'https', 'file'].include?(uri.scheme)
raise OptionParser::InvalidArgument, value
end
value value
end end
@ -90,7 +92,7 @@ module Gem::LocalRemoteOptions
source << '/' if source !~ /\/\z/ source << '/' if source !~ /\/\z/
if options[:added_source] then if options[:added_source] then
Gem.sources << source Gem.sources << source unless Gem.sources.include?(source)
else else
options[:added_source] = true options[:added_source] = true
Gem.sources.replace [source] Gem.sources.replace [source]
@ -99,10 +101,9 @@ module Gem::LocalRemoteOptions
end end
## ##
# Add the --update-source option # Add the --update-sources option
def add_update_sources_option def add_update_sources_option
add_option(:"Local/Remote", '-u', '--[no-]update-sources', add_option(:"Local/Remote", '-u', '--[no-]update-sources',
'Update local source cache') do |value, options| 'Update local source cache') do |value, options|
Gem.configuration.update_sources = value Gem.configuration.update_sources = value

View file

@ -4,39 +4,40 @@
# See LICENSE.txt for permissions. # See LICENSE.txt for permissions.
#++ #++
require 'rubygems'
require 'fileutils' require 'fileutils'
require 'yaml' require 'yaml'
require 'zlib' require 'zlib'
module Gem ##
# The format class knows the guts of the RubyGem .gem file format and provides
# the capability to read gem files
class Gem::OldFormat
##
# The format class knows the guts of the RubyGem .gem file format
# and provides the capability to read gem files
#
class OldFormat
attr_accessor :spec, :file_entries, :gem_path attr_accessor :spec, :file_entries, :gem_path
## ##
# Constructs an instance of a Format object, representing the gem's # Constructs an instance of a Format object, representing the gem's data
# data structure. # structure.
# #
# gem:: [String] The file name of the gem # gem:: [String] The file name of the gem
#
def initialize(gem_path) def initialize(gem_path)
@gem_path = gem_path @gem_path = gem_path
end end
## ##
# Reads the named gem file and returns a Format object, representing # Reads the named gem file and returns a Format object, representing the
# the data from the gem file # data from the gem file
# #
# file_path:: [String] Path to the gem file # file_path:: [String] Path to the gem file
#
def self.from_file_by_path(file_path) def self.from_file_by_path(file_path)
unless File.exist?(file_path) unless File.exist?(file_path)
raise Gem::Exception, "Cannot load gem file [#{file_path}]" raise Gem::Exception, "Cannot load gem file [#{file_path}]"
end end
File.open(file_path, 'rb') do |file| File.open(file_path, 'rb') do |file|
from_io(file, file_path) from_io(file, file_path)
end end
@ -47,7 +48,7 @@ module Gem
# the data from the gem file # the data from the gem file
# #
# io:: [IO] Stream from which to read the gem # io:: [IO] Stream from which to read the gem
#
def self.from_io(io, gem_path="(io)") def self.from_io(io, gem_path="(io)")
format = self.new(gem_path) format = self.new(gem_path)
skip_ruby(io) skip_ruby(io)
@ -60,12 +61,13 @@ module Gem
end end
private private
## ##
# Skips the Ruby self-install header. After calling this method, the # Skips the Ruby self-install header. After calling this method, the
# IO index will be set after the Ruby code. # IO index will be set after the Ruby code.
# #
# file:: [IO] The IO to process (skip the Ruby code) # file:: [IO] The IO to process (skip the Ruby code)
#
def self.skip_ruby(file) def self.skip_ruby(file)
end_seen = false end_seen = false
loop { loop {
@ -75,7 +77,8 @@ module Gem
break break
end end
} }
if(end_seen == false) then
if end_seen == false then
raise Gem::Exception.new("Failed to find end of ruby script while reading gem") raise Gem::Exception.new("Failed to find end of ruby script while reading gem")
end end
end end
@ -86,19 +89,19 @@ module Gem
# IO index will be set after the specification header. # IO index will be set after the specification header.
# #
# file:: [IO] The IO to process # file:: [IO] The IO to process
#
def self.read_spec(file) def self.read_spec(file)
yaml = '' yaml = ''
begin
read_until_dashes(file) do |line| read_until_dashes file do |line|
yaml << line yaml << line
end end
Specification.from_yaml(yaml)
Gem::Specification.from_yaml yaml
rescue YAML::Error => e rescue YAML::Error => e
raise Gem::Exception.new("Failed to parse gem specification out of gem file") raise Gem::Exception, "Failed to parse gem specification out of gem file"
rescue ArgumentError => e rescue ArgumentError => e
raise Gem::Exception.new("Failed to parse gem specification out of gem file") raise Gem::Exception, "Failed to parse gem specification out of gem file"
end
end end
## ##
@ -107,14 +110,13 @@ module Gem
# #
# file:: [IO] The IO to process # file:: [IO] The IO to process
# block:: [String] The read line # block:: [String] The read line
#
def self.read_until_dashes(file) def self.read_until_dashes(file)
while((line = file.gets) && line.chomp.strip != "---") do while((line = file.gets) && line.chomp.strip != "---") do
yield line yield line
end end
end end
## ##
# Reads the embedded file data from a gem file, yielding an entry # Reads the embedded file data from a gem file, yielding an entry
# containing metadata about the file and the file contents themselves # containing metadata about the file and the file contents themselves
@ -123,7 +125,7 @@ module Gem
# Gem file read/writer # Gem file read/writer
# #
# gem_file:: [IO] The IO to process # gem_file:: [IO] The IO to process
#
def self.read_files_from_gem(gem_file) def self.read_files_from_gem(gem_file)
errstr = "Error reading files from gem" errstr = "Error reading files from gem"
header_yaml = '' header_yaml = ''
@ -132,7 +134,8 @@ module Gem
header_yaml << line header_yaml << line
end end
header = YAML.load(header_yaml) header = YAML.load(header_yaml)
raise Gem::Exception.new(errstr) unless header raise Gem::Exception, errstr unless header
header.each do |entry| header.each do |entry|
file_data = '' file_data = ''
self.read_until_dashes(gem_file) do |line| self.read_until_dashes(gem_file) do |line|
@ -140,9 +143,10 @@ module Gem
end end
yield [entry, Zlib::Inflate.inflate(file_data.strip.unpack("m")[0])] yield [entry, Zlib::Inflate.inflate(file_data.strip.unpack("m")[0])]
end end
rescue Exception,Zlib::DataError => e rescue Zlib::DataError => e
raise Gem::Exception.new(errstr) raise Gem::Exception, errstr
end
end end
end end
end end

View file

@ -3,8 +3,6 @@
# See LICENSE.txt for additional licensing information. # See LICENSE.txt for additional licensing information.
#-- #--
require 'rubygems/package'
module Gem::Package::FSyncDir module Gem::Package::FSyncDir
private private

View file

@ -3,8 +3,6 @@
# See LICENSE.txt for additional licensing information. # See LICENSE.txt for additional licensing information.
#-- #--
require 'rubygems/package'
## ##
#-- #--
# struct tarfile_entry_posix { # struct tarfile_entry_posix {
@ -26,9 +24,13 @@ require 'rubygems/package'
# char prefix[155]; # ASCII + (Z unless filled) # char prefix[155]; # ASCII + (Z unless filled)
# }; # };
#++ #++
# A header for a tar file
class Gem::Package::TarHeader class Gem::Package::TarHeader
##
# Fields in the tar header
FIELDS = [ FIELDS = [
:checksum, :checksum,
:devmajor, :devmajor,
@ -48,6 +50,9 @@ class Gem::Package::TarHeader
:version, :version,
] ]
##
# Pack format for a tar header
PACK_FORMAT = 'a100' + # name PACK_FORMAT = 'a100' + # name
'a8' + # mode 'a8' + # mode
'a8' + # uid 'a8' + # uid
@ -65,6 +70,9 @@ class Gem::Package::TarHeader
'a8' + # devminor 'a8' + # devminor
'a155' # prefix 'a155' # prefix
##
# Unpack format for a tar header
UNPACK_FORMAT = 'A100' + # name UNPACK_FORMAT = 'A100' + # name
'A8' + # mode 'A8' + # mode
'A8' + # uid 'A8' + # uid
@ -84,6 +92,9 @@ class Gem::Package::TarHeader
attr_reader(*FIELDS) attr_reader(*FIELDS)
##
# Creates a tar header from IO +stream+
def self.from(stream) def self.from(stream)
header = stream.read 512 header = stream.read 512
empty = (header == "\0" * 512) empty = (header == "\0" * 512)
@ -147,6 +158,9 @@ class Gem::Package::TarHeader
# :empty => empty # :empty => empty
end end
##
# Creates a new TarHeader using +vals+
def initialize(vals) def initialize(vals)
unless vals[:name] && vals[:size] && vals[:prefix] && vals[:mode] then unless vals[:name] && vals[:size] && vals[:prefix] && vals[:mode] then
raise ArgumentError, ":name, :size, :prefix and :mode required" raise ArgumentError, ":name, :size, :prefix and :mode required"
@ -171,11 +185,14 @@ class Gem::Package::TarHeader
@empty = vals[:empty] @empty = vals[:empty]
end end
##
# Is the tar entry empty?
def empty? def empty?
@empty @empty
end end
def ==(other) def ==(other) # :nodoc:
self.class === other and self.class === other and
@checksum == other.checksum and @checksum == other.checksum and
@devmajor == other.devmajor and @devmajor == other.devmajor and
@ -195,11 +212,14 @@ class Gem::Package::TarHeader
@version == other.version @version == other.version
end end
def to_s def to_s # :nodoc:
update_checksum update_checksum
header header
end end
##
# Updates the TarHeader's checksum
def update_checksum def update_checksum
header = header " " * 8 header = header " " * 8
@checksum = oct calculate_checksum(header), 6 @checksum = oct calculate_checksum(header), 6

View file

@ -3,8 +3,6 @@
# See LICENSE.txt for additional licensing information. # See LICENSE.txt for additional licensing information.
#-- #--
require 'rubygems/package'
class Gem::Package::TarInput class Gem::Package::TarInput
include Gem::Package::FSyncDir include Gem::Package::FSyncDir
@ -72,9 +70,9 @@ class Gem::Package::TarInput
# map trust policy from string to actual class (or a serialized YAML # map trust policy from string to actual class (or a serialized YAML
# file, if that exists) # file, if that exists)
if String === security_policy then if String === security_policy then
if Gem::Security::Policy.key? security_policy then if Gem::Security::Policies.key? security_policy then
# load one of the pre-defined security policies # load one of the pre-defined security policies
security_policy = Gem::Security::Policy[security_policy] security_policy = Gem::Security::Policies[security_policy]
elsif File.exist? security_policy then elsif File.exist? security_policy then
# FIXME: this doesn't work yet # FIXME: this doesn't work yet
security_policy = YAML.load File.read(security_policy) security_policy = YAML.load File.read(security_policy)
@ -136,10 +134,10 @@ class Gem::Package::TarInput
def extract_entry(destdir, entry, expected_md5sum = nil) def extract_entry(destdir, entry, expected_md5sum = nil)
if entry.directory? then if entry.directory? then
dest = File.join(destdir, entry.full_name) dest = File.join destdir, entry.full_name
if File.dir? dest then if File.directory? dest then
@fileops.chmod entry.header.mode, dest, :verbose=>false @fileops.chmod entry.header.mode, dest, :verbose => false
else else
@fileops.mkdir_p dest, :mode => entry.header.mode, :verbose => false @fileops.mkdir_p dest, :mode => entry.header.mode, :verbose => false
end end

View file

@ -3,8 +3,6 @@
# See LICENSE.txt for additional licensing information. # See LICENSE.txt for additional licensing information.
#-- #--
require 'rubygems/package'
## ##
# TarOutput is a wrapper to TarWriter that builds gem-format tar file. # TarOutput is a wrapper to TarWriter that builds gem-format tar file.
# #
@ -66,8 +64,10 @@ class Gem::Package::TarOutput
Zlib::GzipWriter.wrap(sio || inner) do |os| Zlib::GzipWriter.wrap(sio || inner) do |os|
Gem::Package::TarWriter.new os do |data_tar_writer| Gem::Package::TarWriter.new os do |data_tar_writer|
# :stopdoc:
def data_tar_writer.metadata() @metadata end def data_tar_writer.metadata() @metadata end
def data_tar_writer.metadata=(metadata) @metadata = metadata end def data_tar_writer.metadata=(metadata) @metadata = metadata end
# :startdoc:
yield data_tar_writer yield data_tar_writer

View file

@ -3,14 +3,21 @@
# See LICENSE.txt for additional licensing information. # See LICENSE.txt for additional licensing information.
#-- #--
require 'rubygems/package' ##
# TarReader reads tar files and allows iteration over their items
class Gem::Package::TarReader class Gem::Package::TarReader
include Gem::Package include Gem::Package
##
# Raised if the tar IO is not seekable
class UnexpectedEOF < StandardError; end class UnexpectedEOF < StandardError; end
##
# Creates a new TarReader on +io+ and yields it to the block, if given.
def self.new(io) def self.new(io)
reader = super reader = super
@ -25,14 +32,24 @@ class Gem::Package::TarReader
nil nil
end end
##
# Creates a new tar file reader on +io+ which needs to respond to #pos,
# #eof?, #read, #getc and #pos=
def initialize(io) def initialize(io)
@io = io @io = io
@init_pos = io.pos @init_pos = io.pos
end end
##
# Close the tar file
def close def close
end end
##
# Iterates over files in the tarball yielding each entry
def each def each
loop do loop do
return if @io.eof? return if @io.eof?
@ -84,3 +101,5 @@ class Gem::Package::TarReader
end end
require 'rubygems/package/tar_reader/entry'

View file

@ -3,12 +3,19 @@
# See LICENSE.txt for additional licensing information. # See LICENSE.txt for additional licensing information.
#-- #--
require 'rubygems/package' ##
# Class for reading entries out of a tar file
class Gem::Package::TarReader::Entry class Gem::Package::TarReader::Entry
##
# Header for this tar entry
attr_reader :header attr_reader :header
##
# Creates a new tar entry for +header+ that will be read from +io+
def initialize(header, io) def initialize(header, io)
@closed = false @closed = false
@header = header @header = header
@ -21,24 +28,39 @@ class Gem::Package::TarReader::Entry
raise IOError, "closed #{self.class}" if closed? raise IOError, "closed #{self.class}" if closed?
end end
##
# Number of bytes read out of the tar entry
def bytes_read def bytes_read
@read @read
end end
##
# Closes the tar entry
def close def close
@closed = true @closed = true
end end
##
# Is the tar entry closed?
def closed? def closed?
@closed @closed
end end
##
# Are we at the end of the tar entry?
def eof? def eof?
check_closed check_closed
@read >= @header.size @read >= @header.size
end end
##
# Full name of the tar entry
def full_name def full_name
if @header.prefix != "" then if @header.prefix != "" then
File.join @header.prefix, @header.name File.join @header.prefix, @header.name
@ -47,6 +69,9 @@ class Gem::Package::TarReader::Entry
end end
end end
##
# Read one byte from the tar entry
def getc def getc
check_closed check_closed
@ -58,20 +83,33 @@ class Gem::Package::TarReader::Entry
ret ret
end end
##
# Is this tar entry a directory?
def directory? def directory?
@header.typeflag == "5" @header.typeflag == "5"
end end
##
# Is this tar entry a file?
def file? def file?
@header.typeflag == "0" @header.typeflag == "0"
end end
##
# The position in the tar entry
def pos def pos
check_closed check_closed
bytes_read bytes_read
end end
##
# Reads +len+ bytes from the tar file entry, or the rest of the entry if
# nil
def read(len = nil) def read(len = nil)
check_closed check_closed
@ -86,6 +124,9 @@ class Gem::Package::TarReader::Entry
ret ret
end end
##
# Rewinds to the beginning of the tar file entry
def rewind def rewind
check_closed check_closed

View file

@ -3,15 +3,30 @@
# See LICENSE.txt for additional licensing information. # See LICENSE.txt for additional licensing information.
#-- #--
require 'rubygems/package' ##
# Allows writing of tar files
class Gem::Package::TarWriter class Gem::Package::TarWriter
class FileOverflow < StandardError; end class FileOverflow < StandardError; end
##
# IO wrapper that allows writing a limited amount of data
class BoundedStream class BoundedStream
attr_reader :limit, :written ##
# Maximum number of bytes that can be written
attr_reader :limit
##
# Number of bytes written
attr_reader :written
##
# Wraps +io+ and allows up to +limit+ bytes to be written
def initialize(io, limit) def initialize(io, limit)
@io = io @io = io
@ -19,6 +34,10 @@ class Gem::Package::TarWriter
@written = 0 @written = 0
end end
##
# Writes +data+ onto the IO, raising a FileOverflow exception if the
# number of bytes will be more than #limit
def write(data) def write(data)
if data.size + @written > @limit if data.size + @written > @limit
raise FileOverflow, "You tried to feed more data than fits in the file." raise FileOverflow, "You tried to feed more data than fits in the file."
@ -30,18 +49,30 @@ class Gem::Package::TarWriter
end end
##
# IO wrapper that provides only #write
class RestrictedStream class RestrictedStream
##
# Creates a new RestrictedStream wrapping +io+
def initialize(io) def initialize(io)
@io = io @io = io
end end
##
# Writes +data+ onto the IO
def write(data) def write(data)
@io.write data @io.write data
end end
end end
##
# Creates a new TarWriter, yielding it if a block is given
def self.new(io) def self.new(io)
writer = super writer = super
@ -56,12 +87,19 @@ class Gem::Package::TarWriter
nil nil
end end
##
# Creates a new TarWriter that will write to +io+
def initialize(io) def initialize(io)
@io = io @io = io
@closed = false @closed = false
end end
def add_file(name, mode) ##
# Adds file +name+ with permissions +mode+, and yields an IO for writing the
# file to
def add_file(name, mode) # :yields: io
check_closed check_closed
raise Gem::Package::NonSeekableIO unless @io.respond_to? :pos= raise Gem::Package::NonSeekableIO unless @io.respond_to? :pos=
@ -90,7 +128,11 @@ class Gem::Package::TarWriter
self self
end end
def add_file_simple(name, mode, size) ##
# Add file +name+ with permissions +mode+ +size+ bytes long. Yields an IO
# to write the file to.
def add_file_simple(name, mode, size) # :yields: io
check_closed check_closed
name, prefix = split_name name name, prefix = split_name name
@ -112,10 +154,16 @@ class Gem::Package::TarWriter
self self
end end
##
# Raises IOError if the TarWriter is closed
def check_closed def check_closed
raise IOError, "closed #{self.class}" if closed? raise IOError, "closed #{self.class}" if closed?
end end
##
# Closes the TarWriter
def close def close
check_closed check_closed
@ -125,16 +173,25 @@ class Gem::Package::TarWriter
@closed = true @closed = true
end end
##
# Is the TarWriter closed?
def closed? def closed?
@closed @closed
end end
##
# Flushes the TarWriter's IO
def flush def flush
check_closed check_closed
@io.flush if @io.respond_to? :flush @io.flush if @io.respond_to? :flush
end end
##
# Creates a new directory in the tar file +name+ with +mode+
def mkdir(name, mode) def mkdir(name, mode)
check_closed check_closed
@ -149,6 +206,9 @@ class Gem::Package::TarWriter
self self
end end
##
# Splits +name+ into a name and prefix that can fit in the TarHeader
def split_name(name) # :nodoc: def split_name(name) # :nodoc:
raise Gem::Package::TooLongFileName if name.size > 256 raise Gem::Package::TooLongFileName if name.size > 256

View file

@ -0,0 +1,118 @@
# Copyright (c) 2003, 2004 Jim Weirich, 2009 Eric Hodel
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
require 'rubygems'
begin
gem 'rake'
rescue Gem::LoadError
end
require 'rake/packagetask'
##
# Create a package based upon a Gem::Specification. Gem packages, as well as
# zip files and tar/gzipped packages can be produced by this task.
#
# In addition to the Rake targets generated by Rake::PackageTask, a
# Gem::PackageTask will also generate the following tasks:
#
# [<b>"<em>package_dir</em>/<em>name</em>-<em>version</em>.gem"</b>]
# Create a RubyGems package with the given name and version.
#
# Example using a Gem::Specification:
#
# require 'rubygems'
# require 'rubygems/package_task'
#
# spec = Gem::Specification.new do |s|
# s.platform = Gem::Platform::RUBY
# s.summary = "Ruby based make-like utility."
# s.name = 'rake'
# s.version = PKG_VERSION
# s.requirements << 'none'
# s.require_path = 'lib'
# s.autorequire = 'rake'
# s.files = PKG_FILES
# s.description = <<-EOF
# Rake is a Make-like program implemented in Ruby. Tasks
# and dependencies are specified in standard Ruby syntax.
# EOF
# end
#
# Gem::PackageTask.new(spec) do |pkg|
# pkg.need_zip = true
# pkg.need_tar = true
# end
class Gem::PackageTask < Rake::PackageTask
##
# Ruby Gem::Specification containing the metadata for this package. The
# name, version and package_files are automatically determined from the
# gemspec and don't need to be explicitly provided.
attr_accessor :gem_spec
##
# Create a Gem Package task library. Automatically define the gem if a
# block is given. If no block is supplied, then #define needs to be called
# to define the task.
def initialize(gem_spec)
init gem_spec
yield self if block_given?
define if block_given?
end
##
# Initialization tasks without the "yield self" or define operations.
def init(gem)
super gem.name, gem.version
@gem_spec = gem
@package_files += gem_spec.files if gem_spec.files
end
##
# Create the Rake tasks and actions specified by this Gem::PackageTask.
# (+define+ is automatically called if a block is given to +new+).
def define
super
task :package => [:gem]
desc "Build the gem file #{gem_file}"
task :gem => ["#{package_dir}/#{gem_file}"]
file "#{package_dir}/#{gem_file}" => [package_dir] + @gem_spec.files do
when_writing("Creating #{gem_spec.full_name}.gem") {
Gem::Builder.new(gem_spec).build
verbose(true) {
mv gem_file, "#{package_dir}/#{gem_file}"
}
}
end
end
def gem_file
"#{@gem_spec.full_name}.gem"
end
end

View file

@ -1,5 +1,3 @@
require 'rubygems'
## ##
# Available list of platforms for targeting Gem installations. # Available list of platforms for targeting Gem installations.
@ -106,6 +104,10 @@ class Gem::Platform
to_a.compact.join '-' to_a.compact.join '-'
end end
def empty?
to_s.empty?
end
## ##
# Is +other+ equal to this platform? Two platforms are equal if they have # Is +other+ equal to this platform? Two platforms are equal if they have
# the same CPU, OS and version. # the same CPU, OS and version.
@ -143,14 +145,14 @@ class Gem::Platform
when String then when String then
# This data is from http://gems.rubyforge.org/gems/yaml on 19 Aug 2007 # This data is from http://gems.rubyforge.org/gems/yaml on 19 Aug 2007
other = case other other = case other
when /^i686-darwin(\d)/ then ['x86', 'darwin', $1] when /^i686-darwin(\d)/ then ['x86', 'darwin', $1 ]
when /^i\d86-linux/ then ['x86', 'linux', nil] when /^i\d86-linux/ then ['x86', 'linux', nil ]
when 'java', 'jruby' then [nil, 'java', nil] when 'java', 'jruby' then [nil, 'java', nil ]
when /mswin32(\_(\d+))?/ then ['x86', 'mswin32', $2] when /mswin32(\_(\d+))?/ then ['x86', 'mswin32', $2 ]
when 'powerpc-darwin' then ['powerpc', 'darwin', nil] when 'powerpc-darwin' then ['powerpc', 'darwin', nil ]
when /powerpc-darwin(\d)/ then ['powerpc', 'darwin', $1] when /powerpc-darwin(\d)/ then ['powerpc', 'darwin', $1 ]
when /sparc-solaris2.8/ then ['sparc', 'solaris', '2.8'] when /sparc-solaris2.8/ then ['sparc', 'solaris', '2.8' ]
when /universal-darwin(\d)/ then ['universal', 'darwin', $1] when /universal-darwin(\d)/ then ['universal', 'darwin', $1 ]
else other else other
end end

View file

@ -55,7 +55,7 @@ class Gem::RemoteFetcher
# HTTP_PROXY_PASS) # HTTP_PROXY_PASS)
# * <tt>:no_proxy</tt>: ignore environment variables and _don't_ use a proxy # * <tt>:no_proxy</tt>: ignore environment variables and _don't_ use a proxy
def initialize(proxy) def initialize(proxy = nil)
Socket.do_not_reverse_lookup = true Socket.do_not_reverse_lookup = true
@connections = {} @connections = {}
@ -86,7 +86,11 @@ class Gem::RemoteFetcher
FileUtils.mkdir_p cache_dir rescue nil unless File.exist? cache_dir FileUtils.mkdir_p cache_dir rescue nil unless File.exist? cache_dir
source_uri = URI.parse source_uri unless URI::Generic === source_uri # Always escape URI's to deal with potential spaces and such
unless URI::Generic === source_uri
source_uri = URI.parse(URI.escape(source_uri))
end
scheme = source_uri.scheme scheme = source_uri.scheme
# URI.parse gets confused by MS Windows paths with forward slashes. # URI.parse gets confused by MS Windows paths with forward slashes.
@ -101,7 +105,7 @@ class Gem::RemoteFetcher
remote_gem_path = source_uri + "gems/#{gem_file_name}" remote_gem_path = source_uri + "gems/#{gem_file_name}"
gem = Gem::RemoteFetcher.fetcher.fetch_path remote_gem_path gem = self.fetch_path remote_gem_path
rescue Gem::RemoteFetcher::FetchError rescue Gem::RemoteFetcher::FetchError
raise if spec.original_platform == spec.platform raise if spec.original_platform == spec.platform
@ -112,16 +116,34 @@ class Gem::RemoteFetcher
remote_gem_path = source_uri + "gems/#{alternate_name}" remote_gem_path = source_uri + "gems/#{alternate_name}"
gem = Gem::RemoteFetcher.fetcher.fetch_path remote_gem_path gem = self.fetch_path remote_gem_path
end end
File.open local_gem_path, 'wb' do |fp| File.open local_gem_path, 'wb' do |fp|
fp.write gem fp.write gem
end end
end end
when nil, 'file' then # TODO test for local overriding cache when 'file' then
begin begin
FileUtils.cp source_uri.to_s, local_gem_path path = source_uri.path
path = File.dirname(path) if File.extname(path) == '.gem'
remote_gem_path = File.join(path, 'gems', gem_file_name)
FileUtils.cp(remote_gem_path, local_gem_path)
rescue Errno::EACCES
local_gem_path = source_uri.to_s
end
say "Using local gem #{local_gem_path}" if
Gem.configuration.really_verbose
when nil then # TODO test for local overriding cache
begin
if Gem.win_platform? && source_uri.scheme && !source_uri.path.include?(':')
FileUtils.cp URI.unescape(source_uri.scheme + ':' + source_uri.path), local_gem_path
else
FileUtils.cp URI.unescape(source_uri.path), local_gem_path
end
rescue Errno::EACCES rescue Errno::EACCES
local_gem_path = source_uri.to_s local_gem_path = source_uri.to_s
end end
@ -177,7 +199,7 @@ class Gem::RemoteFetcher
return nil if env_proxy.nil? or env_proxy.empty? return nil if env_proxy.nil? or env_proxy.empty?
uri = URI.parse env_proxy uri = URI.parse(normalize_uri(env_proxy))
if uri and uri.user.nil? and uri.password.nil? then if uri and uri.user.nil? and uri.password.nil? then
# Probably we have http_proxy_* variables? # Probably we have http_proxy_* variables?
@ -233,10 +255,25 @@ class Gem::RemoteFetcher
def open_uri_or_path(uri, last_modified = nil, head = false, depth = 0) def open_uri_or_path(uri, last_modified = nil, head = false, depth = 0)
raise "block is dead" if block_given? raise "block is dead" if block_given?
return open(get_file_uri_path(uri)) if file_uri? uri
uri = URI.parse uri unless URI::Generic === uri uri = URI.parse uri unless URI::Generic === uri
raise ArgumentError, 'uri is not an HTTP URI' unless URI::HTTP === uri
# This check is redundant unless Gem::RemoteFetcher is likely
# to be used directly, since the scheme is checked elsewhere.
# - Daniel Berger
unless ['http', 'https', 'file'].include?(uri.scheme)
raise ArgumentError, 'uri scheme is invalid'
end
if uri.scheme == 'file'
path = uri.path
# Deal with leading slash on Windows paths
if path[0].chr == '/' && path[1].chr =~ /[a-zA-Z]/ && path[2].chr == ':'
path = path[1..-1]
end
return Gem.read_binary(path)
end
fetch_type = head ? Net::HTTP::Head : Net::HTTP::Get fetch_type = head ? Net::HTTP::Head : Net::HTTP::Get
response = request uri, fetch_type, last_modified response = request uri, fetch_type, last_modified
@ -326,19 +363,5 @@ class Gem::RemoteFetcher
connection.start connection.start
end end
##
# Checks if the provided string is a file:// URI.
def file_uri?(uri)
uri =~ %r{\Afile://}
end
##
# Given a file:// URI, returns its local path.
def get_file_uri_path(uri)
uri.sub(%r{\Afile://}, '')
end
end end

View file

@ -1,7 +1,9 @@
module Gem require 'rubygems'
module RequirePathsBuilder
module Gem::RequirePathsBuilder
def write_require_paths_file_if_needed(spec = @spec, gem_home = @gem_home) def write_require_paths_file_if_needed(spec = @spec, gem_home = @gem_home)
return if spec.require_paths == ["lib"] && (spec.bindir.nil? || spec.bindir == "bin") return if spec.require_paths == ["lib"] &&
(spec.bindir.nil? || spec.bindir == "bin")
file_name = File.join(gem_home, 'gems', "#{@spec.full_name}", ".require_paths") file_name = File.join(gem_home, 'gems', "#{@spec.full_name}", ".require_paths")
file_name.untaint file_name.untaint
File.open(file_name, "w") do |file| File.open(file_name, "w") do |file|
@ -11,5 +13,5 @@ module Gem
file.puts spec.bindir if spec.bindir file.puts spec.bindir if spec.bindir
end end
end end
end
end end

View file

@ -4,8 +4,6 @@
# See LICENSE.txt for permissions. # See LICENSE.txt for permissions.
#++ #++
require 'rubygems/version'
## ##
# Requirement version includes a prefaced comparator in addition # Requirement version includes a prefaced comparator in addition
# to a version number. # to a version number.
@ -26,10 +24,10 @@ class Gem::Requirement
"<" => lambda { |v, r| v < r }, "<" => lambda { |v, r| v < r },
">=" => lambda { |v, r| v >= r }, ">=" => lambda { |v, r| v >= r },
"<=" => lambda { |v, r| v <= r }, "<=" => lambda { |v, r| v <= r },
"~>" => lambda { |v, r| v >= r && v < r.bump } "~>" => lambda { |v, r| v = v.release; v >= r && v < r.bump }
} }
OP_RE = /#{OPS.keys.map{ |k| Regexp.quote k }.join '|'}/o OP_RE = OPS.keys.map{ |k| Regexp.quote k }.join '|'
## ##
# Factory method to create a Gem::Requirement object. Input may be a # Factory method to create a Gem::Requirement object. Input may be a
@ -65,7 +63,7 @@ class Gem::Requirement
## ##
# Constructs a Requirement from +requirements+ which can be a String, a # Constructs a Requirement from +requirements+ which can be a String, a
# Gem::Version, or an Array of those. See parse for details on the # Gem::Version, or an Array of those. See #parse for details on the
# formatting of requirement strings. # formatting of requirement strings.
def initialize(requirements) def initialize(requirements)
@ -99,11 +97,15 @@ class Gem::Requirement
as_list.join(", ") as_list.join(", ")
end end
def pretty_print(q) # :nodoc:
q.group 1, 'Gem::Requirement.new(', ')' do
q.pp as_list
end
end
def as_list def as_list
normalize normalize
@requirements.collect { |req| @requirements.map do |op, version| "#{op} #{version}" end
"#{req[0]} #{req[1]}"
}
end end
def normalize def normalize
@ -129,18 +131,23 @@ class Gem::Requirement
OPS[op].call(version, required_version) OPS[op].call(version, required_version)
end end
def prerelease?
# TODO: why is @requirements a nested array?
@requirements.any?{ |r| r[1].prerelease? }
end
## ##
# Parse the version requirement obj returning the operator and version. # Parse the version requirement obj returning the operator and version.
# #
# The requirement can be a String or a Gem::Version. A String can be an # The requirement can be a String or a Gem::Version. A String can be an
# operator (<, <=, =, =>, >, !=, ~>), a version number, or both, operator # operator (<, <=, =, >=, >, !=, ~>), a version number, or both, operator
# first. # first.
def parse(obj) def parse(obj)
case obj case obj
when /^\s*(#{OP_RE})\s*([0-9.]+)\s*$/o then when /^\s*(#{OP_RE})\s*(#{Gem::Version::VERSION_PATTERN})\s*$/o then
[$1, Gem::Version.new($2)] [$1, Gem::Version.new($2)]
when /^\s*([0-9.]+)\s*$/ then when /^\s*(#{Gem::Version::VERSION_PATTERN})\s*$/o then
['=', Gem::Version.new($1)] ['=', Gem::Version.new($1)]
when /^\s*(#{OP_RE})\s*$/o then when /^\s*(#{OP_RE})\s*$/o then
[$1, Gem::Version.new('0')] [$1, Gem::Version.new('0')]

View file

@ -1,6 +1,19 @@
#--
# DO NOT EDIT # DO NOT EDIT
# This file is auto-generated by build scripts. # This file is auto-generated by build scripts.
# See: rake update_version # See: rake update_version
#++
module Gem module Gem
RubyGemsVersion = '1.3.1'
##
# The version of RubyGems you are using
RubyGemsVersion = '1.3.4'
##
# The version of RubyGems you are using (duplicated for familiarity)
VERSION = RubyGemsVersion
end end

View file

@ -17,6 +17,7 @@ require 'rubygems/doc_manager'
# name/version/platform index # name/version/platform index
# * "/quick/" - Individual gemspecs # * "/quick/" - Individual gemspecs
# * "/gems" - Direct access to download the installable gems # * "/gems" - Direct access to download the installable gems
# * "/rdoc?q=" - Search for installed rdoc documentation
# * legacy indexes: # * legacy indexes:
# * "/Marshal.#{Gem.marshal_version}" - Full SourceIndex dump of metadata # * "/Marshal.#{Gem.marshal_version}" - Full SourceIndex dump of metadata
# for installed gems # for installed gems
@ -32,9 +33,20 @@ require 'rubygems/doc_manager'
class Gem::Server class Gem::Server
include ERB::Util
include Gem::UserInteraction include Gem::UserInteraction
DOC_TEMPLATE = <<-'WEBPAGE' SEARCH = <<-SEARCH
<form class="headerSearch" name="headerSearchForm" method="get" action="/rdoc">
<div id="search" style="float:right">
<span>Filter/Search</span>
<input id="q" type="text" style="width:10em" name="q"/>
<button type="submit" style="display:none" />
</div>
</form>
SEARCH
DOC_TEMPLATE = <<-'DOC_TEMPLATE'
<?xml version="1.0" encoding="iso-8859-1"?> <?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html <!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
@ -47,6 +59,7 @@ class Gem::Server
</head> </head>
<body> <body>
<div id="fileHeader"> <div id="fileHeader">
<%= SEARCH %>
<h1>RubyGems Documentation Index</h1> <h1>RubyGems Documentation Index</h1>
</div> </div>
<!-- banner header --> <!-- banner header -->
@ -114,10 +127,10 @@ class Gem::Server
</div> </div>
</body> </body>
</html> </html>
WEBPAGE DOC_TEMPLATE
# CSS is copy & paste from rdoc-style.css, RDoc V1.0.1 - 20041108 # CSS is copy & paste from rdoc-style.css, RDoc V1.0.1 - 20041108
RDOC_CSS = <<-RDOCCSS RDOC_CSS = <<-RDOC_CSS
body { body {
font-family: Verdana,Arial,Helvetica,sans-serif; font-family: Verdana,Arial,Helvetica,sans-serif;
font-size: 90%; font-size: 90%;
@ -325,7 +338,92 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
.ruby-comment { color: #b22222; font-weight: bold; background: transparent; } .ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
.ruby-regexp { color: #ffa07a; background: transparent; } .ruby-regexp { color: #ffa07a; background: transparent; }
.ruby-value { color: #7fffd4; background: transparent; } .ruby-value { color: #7fffd4; background: transparent; }
RDOCCSS RDOC_CSS
RDOC_NO_DOCUMENTATION = <<-'NO_DOC'
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Found documentation</title>
<link rel="stylesheet" href="gem-server-rdoc-style.css" type="text/css" media="screen" />
</head>
<body>
<div id="fileHeader">
<%= SEARCH %>
<h1>No documentation found</h1>
</div>
<div id="bodyContent">
<div id="contextContent">
<div id="description">
<p>No gems matched <%= h query.inspect %></p>
<p>
Back to <a href="/">complete gem index</a>
</p>
</div>
</div>
</div>
<div id="validator-badges">
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
</div>
</body>
</html>
NO_DOC
RDOC_SEARCH_TEMPLATE = <<-'RDOC_SEARCH'
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Found documentation</title>
<link rel="stylesheet" href="gem-server-rdoc-style.css" type="text/css" media="screen" />
</head>
<body>
<div id="fileHeader">
<%= SEARCH %>
<h1>Found documentation</h1>
</div>
<!-- banner header -->
<div id="bodyContent">
<div id="contextContent">
<div id="description">
<h1>Summary</h1>
<p><%=doc_items.length%> documentation topics found.</p>
<h1>Topics</h1>
<dl>
<% doc_items.each do |doc_item| %>
<dt>
<b><%=doc_item[:name]%></b>
<a href="<%=doc_item[:url]%>">[rdoc]</a>
</dt>
<dd>
<%=doc_item[:summary]%>
<br/>
<br/>
</dd>
<% end %>
</dl>
<p>
Back to <a href="/">complete gem index</a>
</p>
</div>
</div>
</div>
<div id="validator-badges">
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
</div>
</body>
</html>
RDOC_SEARCH
def self.run(options) def self.run(options)
new(options[:gemdir], options[:port], options[:daemon]).run new(options[:gemdir], options[:port], options[:daemon]).run
@ -533,6 +631,90 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
res.body = result res.body = result
end end
##
# Can be used for quick navigation to the rdoc documentation. You can then
# define a search shortcut for your browser. E.g. in Firefox connect
# 'shortcut:rdoc' to http://localhost:8808/rdoc?q=%s template. Then you can
# directly open the ActionPack documentation by typing 'rdoc actionp'. If
# there are multiple hits for the search term, they are presented as a list
# with links.
#
# Search algorithm aims for an intuitive search:
# 1. first try to find the gems and documentation folders which name
# starts with the search term
# 2. search for entries, that *contain* the search term
# 3. show all the gems
#
# If there is only one search hit, user is immediately redirected to the
# documentation for the particular gem, otherwise a list with results is
# shown.
#
# === Additional trick - install documentation for ruby core
#
# Note: please adjust paths accordingly use for example 'locate yaml.rb' and
# 'gem environment' to identify directories, that are specific for your
# local installation
#
# 1. install ruby sources
# cd /usr/src
# sudo apt-get source ruby
#
# 2. generate documentation
# rdoc -o /usr/lib/ruby/gems/1.8/doc/core/rdoc \
# /usr/lib/ruby/1.8 ruby1.8-1.8.7.72
#
# By typing 'rdoc core' you can now access the core documentation
def rdoc(req, res)
query = req.query['q']
show_rdoc_for_pattern("#{query}*", res) && return
show_rdoc_for_pattern("*#{query}*", res) && return
template = ERB.new RDOC_NO_DOCUMENTATION
res['content-type'] = 'text/html'
res.body = template.result binding
end
##
# Returns true and prepares http response, if rdoc for the requested gem
# name pattern was found.
#
# The search is based on the file system content, not on the gems metadata.
# This allows additional documentation folders like 'core' for the ruby core
# documentation - just put it underneath the main doc folder.
def show_rdoc_for_pattern(pattern, res)
found_gems = Dir.glob("#{@gem_dir}/doc/#{pattern}").select {|path|
File.exist? File.join(path, 'rdoc/index.html')
}
case found_gems.length
when 0
return false
when 1
new_path = File.basename(found_gems[0])
res.status = 302
res['Location'] = "/doc_root/#{new_path}/rdoc/index.html"
return true
else
doc_items = []
found_gems.each do |file_name|
base_name = File.basename(file_name)
doc_items << {
:name => base_name,
:url => "/doc_root/#{base_name}/rdoc/index.html",
:summary => ''
}
end
template = ERB.new(RDOC_SEARCH_TEMPLATE)
res['content-type'] = 'text/html'
result = template.result binding
res.body = result
return true
end
end
def run def run
@server.listen nil, @port @server.listen nil, @port
@ -564,6 +746,8 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
@server.mount_proc "/", method(:root) @server.mount_proc "/", method(:root)
@server.mount_proc "/rdoc", method(:rdoc)
paths = { "/gems" => "/cache/", "/doc_root" => "/doc/" } paths = { "/gems" => "/cache/", "/doc_root" => "/doc/" }
paths.each do |mount_point, mount_dir| paths.each do |mount_point, mount_dir|
@server.mount(mount_point, WEBrick::HTTPServlet::FileHandler, @server.mount(mount_point, WEBrick::HTTPServlet::FileHandler,

View file

@ -4,12 +4,14 @@
# See LICENSE.txt for permissions. # See LICENSE.txt for permissions.
#++ #++
require 'rubygems'
require 'rubygems/user_interaction' require 'rubygems/user_interaction'
require 'rubygems/specification' require 'rubygems/specification'
# :stopdoc:
module Gem module Gem
autoload(:SpecFetcher, 'rubygems/spec_fetcher') autoload :SpecFetcher, 'rubygems/spec_fetcher'
end end
# :startdoc:
## ##
# The SourceIndex object indexes all the gems available from a # The SourceIndex object indexes all the gems available from a
@ -28,7 +30,7 @@ class Gem::SourceIndex
include Gem::UserInteraction include Gem::UserInteraction
attr_reader :gems # :nodoc: attr_reader :gems, :prerelease_gems # :nodoc:
## ##
# Directories to use to refresh this SourceIndex when calling refresh! # Directories to use to refresh this SourceIndex when calling refresh!
@ -81,13 +83,15 @@ class Gem::SourceIndex
# loaded spec. # loaded spec.
def load_specification(file_name) def load_specification(file_name)
begin return nil unless file_name and File.exist? file_name
spec_code = if RUBY_VERSION < '1.9' then spec_code = if RUBY_VERSION < '1.9' then
File.read file_name File.read file_name
else else
File.read file_name, :encoding => 'UTF-8' File.read file_name, :encoding => 'UTF-8'
end.untaint end.untaint
begin
gemspec = eval spec_code, binding, file_name gemspec = eval spec_code, binding, file_name
if gemspec.is_a?(Gem::Specification) if gemspec.is_a?(Gem::Specification)
@ -104,23 +108,32 @@ class Gem::SourceIndex
alert_warning "#{e.inspect}\n#{spec_code}" alert_warning "#{e.inspect}\n#{spec_code}"
alert_warning "Invalid .gemspec format in '#{file_name}'" alert_warning "Invalid .gemspec format in '#{file_name}'"
end end
return nil return nil
end end
end end
## ##
# Constructs a source index instance from the provided # Constructs a source index instance from the provided specifications, which
# specifications # is a Hash of gem full names and Gem::Specifications.
# #--
# specifications:: # TODO merge @gems and @prerelease_gems and provide a separate method
# [Hash] hash of [Gem name, Gem::Specification] pairs # #prerelease_gems
def initialize(specifications={}) def initialize(specifications={})
@gems = specifications @gems, @prerelease_gems = [{}, {}]
specifications.each{ |full_name, spec| add_spec spec }
@spec_dirs = nil @spec_dirs = nil
end end
##
# Both regular and prerelease gems
def all_gems
@gems.merge @prerelease_gems
end
## ##
# Reconstruct the source index from the specifications in +spec_dirs+. # Reconstruct the source index from the specifications in +spec_dirs+.
@ -170,14 +183,29 @@ class Gem::SourceIndex
result[name] << spec result[name] << spec
end end
# TODO: why is this a hash while @gems is an array? Seems like
# structural similarity would be good.
result.values.flatten result.values.flatten
end end
##
# An array including only the prerelease gemspecs
def prerelease_specs
@prerelease_gems.values
end
## ##
# Add a gem specification to the source index. # Add a gem specification to the source index.
def add_spec(gem_spec) def add_spec(gem_spec, name = gem_spec.full_name)
@gems[gem_spec.full_name] = gem_spec # No idea why, but the Indexer wants to insert them using original_name
# instead of full_name. So we make it an optional arg.
if gem_spec.version.prerelease?
@prerelease_gems[name] = gem_spec
else
@gems[name] = gem_spec
end
end end
## ##
@ -193,7 +221,11 @@ class Gem::SourceIndex
# Remove a gem specification named +full_name+. # Remove a gem specification named +full_name+.
def remove_spec(full_name) def remove_spec(full_name)
@gems.delete(full_name) if @gems.key? full_name then
@gems.delete full_name
else
@prerelease_gems.delete full_name
end
end end
## ##
@ -215,18 +247,18 @@ class Gem::SourceIndex
# change in the index. # change in the index.
def index_signature def index_signature
require 'rubygems/digest/sha2' require 'digest'
Gem::SHA256.new.hexdigest(@gems.keys.sort.join(',')).to_s Digest::SHA256.new.hexdigest(@gems.keys.sort.join(',')).to_s
end end
## ##
# The signature for the given gem specification. # The signature for the given gem specification.
def gem_signature(gem_full_name) def gem_signature(gem_full_name)
require 'rubygems/digest/sha2' require 'digest'
Gem::SHA256.new.hexdigest(@gems[gem_full_name].to_yaml).to_s Digest::SHA256.new.hexdigest(@gems[gem_full_name].to_yaml).to_s
end end
def size def size
@ -238,7 +270,7 @@ class Gem::SourceIndex
# Find a gem by an exact match on the short name. # Find a gem by an exact match on the short name.
def find_name(gem_name, version_requirement = Gem::Requirement.default) def find_name(gem_name, version_requirement = Gem::Requirement.default)
dep = Gem::Dependency.new(/^#{gem_name}$/, version_requirement) dep = Gem::Dependency.new gem_name, version_requirement
search dep search dep
end end
@ -257,7 +289,7 @@ class Gem::SourceIndex
# TODO - Remove support and warning for legacy arguments after 2008/11 # TODO - Remove support and warning for legacy arguments after 2008/11
unless Gem::Dependency === gem_pattern unless Gem::Dependency === gem_pattern
warn "#{Gem.location_of_caller.join ':'}:Warning: Gem::SourceIndex#search support for #{gem_pattern.class} patterns is deprecated" warn "#{Gem.location_of_caller.join ':'}:Warning: Gem::SourceIndex#search support for #{gem_pattern.class} patterns is deprecated, use #find_name"
end end
case gem_pattern case gem_pattern
@ -282,7 +314,7 @@ class Gem::SourceIndex
version_requirement = Gem::Requirement.create version_requirement version_requirement = Gem::Requirement.create version_requirement
end end
specs = @gems.values.select do |spec| specs = all_gems.values.select do |spec|
spec.name =~ gem_pattern and spec.name =~ gem_pattern and
version_requirement.satisfied_by? spec.version version_requirement.satisfied_by? spec.version
end end
@ -545,15 +577,15 @@ class Gem::SourceIndex
end end
# :stopdoc:
module Gem module Gem
# :stopdoc: ##
# Cache is an alias for SourceIndex to allow older YAMLized source index # Cache is an alias for SourceIndex to allow older YAMLized source index
# objects to load properly. # objects to load properly.
Cache = SourceIndex Cache = SourceIndex
# :startdoc:
end end
# :startdoc:

View file

@ -13,8 +13,8 @@ class Gem::SourceInfoCacheEntry
attr_reader :source_index attr_reader :source_index
## ##
# The size of the of the source entry. Used to determine if the # The size of the source entry. Used to determine if the source index has
# source index has changed. # changed.
attr_reader :size attr_reader :size

View file

@ -1,6 +1,6 @@
require 'zlib' require 'zlib'
require 'fileutils'
require 'rubygems'
require 'rubygems/remote_fetcher' require 'rubygems/remote_fetcher'
require 'rubygems/user_interaction' require 'rubygems/user_interaction'
@ -26,6 +26,11 @@ class Gem::SpecFetcher
attr_reader :specs # :nodoc: attr_reader :specs # :nodoc:
##
# Cache of prerelease specs
attr_reader :prerelease_specs # :nodoc:
@fetcher = nil @fetcher = nil
def self.fetcher def self.fetcher
@ -42,6 +47,7 @@ class Gem::SpecFetcher
@specs = {} @specs = {}
@latest_specs = {} @latest_specs = {}
@prerelease_specs = {}
@fetcher = Gem::RemoteFetcher.fetcher @fetcher = Gem::RemoteFetcher.fetcher
end end
@ -56,10 +62,10 @@ class Gem::SpecFetcher
## ##
# Fetch specs matching +dependency+. If +all+ is true, all matching # Fetch specs matching +dependency+. If +all+ is true, all matching
# versions are returned. If +matching_platform+ is false, all platforms are # versions are returned. If +matching_platform+ is false, all platforms are
# returned. # returned. If +prerelease+ is true, prerelease versions are included.
def fetch(dependency, all = false, matching_platform = true) def fetch(dependency, all = false, matching_platform = true, prerelease = false)
specs_and_sources = find_matching dependency, all, matching_platform specs_and_sources = find_matching dependency, all, matching_platform, prerelease
specs_and_sources.map do |spec_tuple, source_uri| specs_and_sources.map do |spec_tuple, source_uri|
[fetch_spec(spec_tuple, URI.parse(source_uri)), source_uri] [fetch_spec(spec_tuple, URI.parse(source_uri)), source_uri]
@ -110,10 +116,10 @@ class Gem::SpecFetcher
# versions are returned. If +matching_platform+ is false, gems for all # versions are returned. If +matching_platform+ is false, gems for all
# platforms are returned. # platforms are returned.
def find_matching(dependency, all = false, matching_platform = true) def find_matching(dependency, all = false, matching_platform = true, prerelease = false)
found = {} found = {}
list(all).each do |source_uri, specs| list(all, prerelease).each do |source_uri, specs|
found[source_uri] = specs.select do |spec_name, version, spec_platform| found[source_uri] = specs.select do |spec_name, version, spec_platform|
dependency =~ Gem::Dependency.new(spec_name, version) and dependency =~ Gem::Dependency.new(spec_name, version) and
(not matching_platform or Gem::Platform.match(spec_platform)) (not matching_platform or Gem::Platform.match(spec_platform))
@ -155,28 +161,37 @@ class Gem::SpecFetcher
## ##
# Returns a list of gems available for each source in Gem::sources. If # Returns a list of gems available for each source in Gem::sources. If
# +all+ is true, all versions are returned instead of only latest versions. # +all+ is true, all versions are returned instead of only latest
# versions. If +prerelease+ is true, include prerelease versions.
def list(all = false, prerelease = false)
# TODO: make type the only argument
type = if all
:all
elsif prerelease
:prerelease
else
:latest
end
def list(all = false)
list = {} list = {}
file = all ? 'specs' : 'latest_specs' file = { :latest => 'latest_specs',
:prerelease => 'prerelease_specs',
:all => 'specs' }[type]
cache = { :latest => @latest_specs,
:prerelease => @prerelease_specs,
:all => @specs }[type]
Gem.sources.each do |source_uri| Gem.sources.each do |source_uri|
source_uri = URI.parse source_uri source_uri = URI.parse source_uri
if all and @specs.include? source_uri then unless cache.include? source_uri
list[source_uri] = @specs[source_uri] cache[source_uri] = load_specs source_uri, file
elsif not all and @latest_specs.include? source_uri then
list[source_uri] = @latest_specs[source_uri]
else
specs = load_specs source_uri, file
cache = all ? @specs : @latest_specs
cache[source_uri] = specs
list[source_uri] = specs
end end
list[source_uri] = cache[source_uri]
end end
list list
@ -206,7 +221,14 @@ class Gem::SpecFetcher
loaded = true loaded = true
end end
specs = Marshal.load spec_dump specs = begin
Marshal.load spec_dump
rescue ArgumentError
spec_dump = @fetcher.fetch_path spec_path
loaded = true
Marshal.load spec_dump
end
if loaded and @update_cache then if loaded and @update_cache then
begin begin

View file

@ -4,43 +4,28 @@
# See LICENSE.txt for permissions. # See LICENSE.txt for permissions.
#++ #++
require 'rubygems'
require 'rubygems/version' require 'rubygems/version'
require 'rubygems/requirement' require 'rubygems/requirement'
require 'rubygems/platform' require 'rubygems/platform'
# :stopdoc: # :stopdoc:
# Time::today has been deprecated in 0.9.5 and will be removed.
if RUBY_VERSION < '1.9' then
def Time.today
t = Time.now
t - ((t.to_f + t.gmt_offset) % 86400)
end unless defined? Time.today
end
class Date; end # for ruby_code if date.rb wasn't required class Date; end # for ruby_code if date.rb wasn't required
# :startdoc: # :startdoc:
module Gem ##
# The Specification class contains the metadata for a Gem. Typically
# defined in a .gemspec file or a Rakefile, and looks like this:
#
# spec = Gem::Specification.new do |s|
# s.name = 'rfoo'
# s.version = '1.0'
# s.summary = 'Example gem specification'
# ...
# end
#
# For a great way to package gems, use Hoe.
## class Gem::Specification
# == Gem::Specification
#
# The Specification class contains the metadata for a Gem. Typically
# defined in a .gemspec file or a Rakefile, and looks like this:
#
# spec = Gem::Specification.new do |s|
# s.name = 'rfoo'
# s.version = '1.0'
# s.summary = 'Example gem specification'
# ...
# end
#
# There are many <em>gemspec attributes</em>, and the best place to learn
# about them in the "Gemspec Reference" linked from the RubyGems wiki.
class Specification
## ##
# Allows deinstallation of gems with legacy platforms. # Allows deinstallation of gems with legacy platforms.
@ -62,7 +47,7 @@ module Gem
# #
# NOTE RubyGems < 1.2 cannot load specification versions > 2. # NOTE RubyGems < 1.2 cannot load specification versions > 2.
CURRENT_SPECIFICATION_VERSION = 2 CURRENT_SPECIFICATION_VERSION = 3
## ##
# An informal list of changes to the specification. The highest-valued # An informal list of changes to the specification. The highest-valued
@ -78,20 +63,18 @@ module Gem
'Added "required_rubygems_version"', 'Added "required_rubygems_version"',
'Now forward-compatible with future versions', 'Now forward-compatible with future versions',
], ],
3 => [
'Added Fixnum validation to the specification_version'
]
} }
# :stopdoc: # :stopdoc:
MARSHAL_FIELDS = { -1 => 16, 1 => 16, 2 => 16 } MARSHAL_FIELDS = { -1 => 16, 1 => 16, 2 => 16, 3 => 17 }
now = Time.at(Time.now.to_i) now = Time.at(Time.now.to_i)
TODAY = now - ((now.to_i + now.gmt_offset) % 86400) TODAY = now - ((now.to_i + now.gmt_offset) % 86400)
# :startdoc: # :startdoc:
##
# List of Specification instances.
@@list = []
## ##
# Optional block used to gather newly defined instances. # Optional block used to gather newly defined instances.
@ -99,6 +82,7 @@ module Gem
## ##
# List of attribute names: [:name, :version, ...] # List of attribute names: [:name, :version, ...]
@@required_attributes = [] @@required_attributes = []
## ##
@ -165,14 +149,6 @@ module Gem
@@array_attributes.dup @@array_attributes.dup
end end
##
# A list of Specification instances that have been defined in this Ruby
# instance.
def self.list
@@list
end
## ##
# Specifies the +name+ and +default+ for a specification attribute, and # Specifies the +name+ and +default+ for a specification attribute, and
# creates a reader and writer method like Module#attr_accessor. # creates a reader and writer method like Module#attr_accessor.
@ -302,6 +278,7 @@ module Gem
@homepage, @homepage,
@has_rdoc, @has_rdoc,
@new_platform, @new_platform,
@licenses
] ]
end end
@ -346,6 +323,7 @@ module Gem
spec.instance_variable_set :@has_rdoc, array[15] spec.instance_variable_set :@has_rdoc, array[15]
spec.instance_variable_set :@new_platform, array[16] spec.instance_variable_set :@new_platform, array[16]
spec.instance_variable_set :@platform, array[16].to_s spec.instance_variable_set :@platform, array[16].to_s
spec.instance_variable_set :@license, array[17]
spec.instance_variable_set :@loaded, false spec.instance_variable_set :@loaded, false
spec spec
@ -426,25 +404,40 @@ module Gem
not test_files.empty? not test_files.empty?
end end
alias has_test_suite? has_unit_tests? # :nodoc: deprecated # :stopdoc:
alias has_test_suite? has_unit_tests?
# :startdoc:
## ##
# Specification constructor. Assigns the default values to the # Specification constructor. Assigns the default values to the attributes
# attributes, adds this spec to the list of loaded specs (see # and yields itself for further initialization.
# Specification.list), and yields itself for further initialization.
def initialize def initialize
@new_platform = nil @new_platform = nil
assign_defaults assign_defaults
@loaded = false @loaded = false
@loaded_from = nil @loaded_from = nil
@@list << self
yield self if block_given? yield self if block_given?
@@gather.call(self) if @@gather @@gather.call(self) if @@gather
end end
##
# Duplicates array_attributes from +other_spec+ so state isn't shared.
def initialize_copy(other_spec)
other_ivars = other_spec.instance_variables
other_ivars = other_ivars.map { |ivar| ivar.intern } if # for 1.9
other_ivars.any? { |ivar| String === ivar }
self.class.array_attributes.each do |name|
name = :"@#{name}"
next unless other_ivars.include? name
instance_variable_set name, other_spec.instance_variable_get(name).dup
end
end
## ##
# Each attribute has a default value (possibly nil). Here, we initialize # Each attribute has a default value (possibly nil). Here, we initialize
# all attributes to their default value. This is done through the # all attributes to their default value. This is done through the
@ -527,7 +520,7 @@ module Gem
# Sets the rubygems_version to the current RubyGems version # Sets the rubygems_version to the current RubyGems version
def mark_version def mark_version
@rubygems_version = RubyGemsVersion @rubygems_version = Gem::RubyGemsVersion
end end
## ##
@ -615,9 +608,11 @@ module Gem
# The directory that this gem was installed into. # The directory that this gem was installed into.
def installation_path def installation_path
path = File.dirname(@loaded_from).split(File::SEPARATOR)[0..-2] unless @loaded_from then
path = path.join File::SEPARATOR raise Gem::Exception, "spec #{full_name} is not from an installed gem"
File.expand_path path end
File.expand_path File.dirname(File.dirname(@loaded_from))
end end
## ##
@ -632,7 +627,7 @@ module Gem
# Returns an object you can use to sort specifications in #sort_by. # Returns an object you can use to sort specifications in #sort_by.
def sort_obj def sort_obj
[@name, @version.to_ints, @new_platform == Gem::Platform::RUBY ? -1 : 1] [@name, @version, @new_platform == Gem::Platform::RUBY ? -1 : 1]
end end
def <=>(other) # :nodoc: def <=>(other) # :nodoc:
@ -794,9 +789,9 @@ module Gem
extend Gem::UserInteraction extend Gem::UserInteraction
normalize normalize
if rubygems_version != RubyGemsVersion then if rubygems_version != Gem::RubyGemsVersion then
raise Gem::InvalidSpecificationException, raise Gem::InvalidSpecificationException,
"expected RubyGems version #{RubyGemsVersion}, was #{rubygems_version}" "expected RubyGems version #{Gem::RubyGemsVersion}, was #{rubygems_version}"
end end
@@required_attributes.each do |symbol| @@required_attributes.each do |symbol|
@ -806,13 +801,41 @@ module Gem
end end
end end
unless String === name then
raise Gem::InvalidSpecificationException,
"invalid value for attribute name: \"#{name.inspect}\""
end
if require_paths.empty? then if require_paths.empty? then
raise Gem::InvalidSpecificationException, raise Gem::InvalidSpecificationException,
"specification must have at least one require_path" 'specification must have at least one require_path'
end
@files.delete_if do |file| File.directory? file end
@test_files.delete_if do |file| File.directory? file end
@executables.delete_if do |file|
File.directory? File.join(bindir, file)
end
@extra_rdoc_files.delete_if do |file| File.directory? file end
@extensions.delete_if do |file| File.directory? file end
non_files = files.select do |file|
!File.file? file
end
unless non_files.empty? then
non_files = non_files.map { |file| file.inspect }
raise Gem::InvalidSpecificationException,
"[#{non_files.join ", "}] are not files"
end
unless specification_version.is_a?(Fixnum)
raise Gem::InvalidSpecificationException,
'specification_version must be a Fixnum (did you mean version?)'
end end
case platform case platform
when Gem::Platform, Platform::RUBY then # ok when Gem::Platform, Gem::Platform::RUBY then # ok
else else
raise Gem::InvalidSpecificationException, raise Gem::InvalidSpecificationException,
"invalid platform #{platform.inspect}, see Gem::Platform" "invalid platform #{platform.inspect}, see Gem::Platform"
@ -824,15 +847,51 @@ module Gem
'authors must be Array of Strings' 'authors must be Array of Strings'
end end
licenses.each { |license|
if license.length > 64
raise Gem::InvalidSpecificationException,
"each license must be 64 characters or less"
end
}
# reject FIXME and TODO
unless authors.grep(/FIXME|TODO/).empty? then
raise Gem::InvalidSpecificationException,
'"FIXME" or "TODO" is not an author'
end
unless Array(email).grep(/FIXME|TODO/).empty? then
raise Gem::InvalidSpecificationException,
'"FIXME" or "TODO" is not an email address'
end
if description =~ /FIXME|TODO/ then
raise Gem::InvalidSpecificationException,
'"FIXME" or "TODO" is not a description'
end
if summary =~ /FIXME|TODO/ then
raise Gem::InvalidSpecificationException,
'"FIXME" or "TODO" is not a summary'
end
if homepage and not homepage.empty? and
homepage !~ /\A[a-z][a-z\d+.-]*:/i then
raise Gem::InvalidSpecificationException,
"\"#{homepage}\" is not a URI"
end
# Warnings # Warnings
%w[author email homepage rubyforge_project summary].each do |attribute| %w[author description email homepage rubyforge_project summary].each do |attribute|
value = self.send attribute value = self.send attribute
alert_warning "no #{attribute} specified" if value.nil? or value.empty? alert_warning "no #{attribute} specified" if value.nil? or value.empty?
end end
alert_warning "RDoc will not be generated (has_rdoc == false)" unless if summary and not summary.empty? and description == summary then
has_rdoc alert_warning 'description and summary are identical'
end
alert_warning "deprecated autorequire specified" if autorequire alert_warning "deprecated autorequire specified" if autorequire
@ -851,8 +910,6 @@ module Gem
# * All file lists have redundancies removed. # * All file lists have redundancies removed.
# * Files referenced in the extra_rdoc_files are included in the package # * Files referenced in the extra_rdoc_files are included in the package
# file list. # file list.
#
# Also, the summary and description are converted to a normal format.
def normalize def normalize
if defined?(@extra_rdoc_files) and @extra_rdoc_files then if defined?(@extra_rdoc_files) and @extra_rdoc_files then
@ -885,10 +942,42 @@ module Gem
out out
end end
def to_s def to_s # :nodoc:
"#<Gem::Specification name=#{@name} version=#{@version}>" "#<Gem::Specification name=#{@name} version=#{@version}>"
end end
def pretty_print(q) # :nodoc:
q.group 2, 'Gem::Specification.new do |s|', 'end' do
q.breakable
attributes = @@attributes.sort_by { |attr_name,| attr_name.to_s }
attributes.each do |attr_name, default|
current_value = self.send attr_name
if current_value != default or
self.class.required_attribute? attr_name then
q.text "s.#{attr_name} = "
if attr_name == :date then
current_value = current_value.utc
q.text "Time.utc(#{current_value.year}, #{current_value.month}, #{current_value.day})"
else
q.pp current_value
end
q.breakable
end
end
end
end
##
# Adds a dependency on gem +dependency+ with type +type+ that requires
# +requirements+. Valid types are currently <tt>:runtime</tt> and
# <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
@ -899,7 +988,7 @@ module Gem
unless dependency.respond_to?(:name) && unless dependency.respond_to?(:name) &&
dependency.respond_to?(:version_requirements) dependency.respond_to?(:version_requirements)
dependency = Dependency.new(dependency, requirements, type) dependency = Gem::Dependency.new(dependency, requirements, type)
end end
dependencies << dependency dependencies << dependency
@ -907,11 +996,12 @@ module Gem
private :add_dependency_with_type private :add_dependency_with_type
##
# Finds all gems that satisfy +dep+
def find_all_satisfiers(dep) def find_all_satisfiers(dep)
Gem.source_index.each do |name,gem| Gem.source_index.each do |_, gem|
if(gem.satisfies_requirement?(dep)) then yield gem if gem.satisfies_requirement? dep
yield gem
end
end end
end end
@ -932,7 +1022,7 @@ module Gem
when true, false, nil then obj.inspect when true, false, nil then obj.inspect
when Gem::Platform then "Gem::Platform.new(#{obj.to_a.inspect})" when Gem::Platform then "Gem::Platform.new(#{obj.to_a.inspect})"
when Gem::Requirement then "Gem::Requirement.new(#{obj.to_s.inspect})" when Gem::Requirement then "Gem::Requirement.new(#{obj.to_s.inspect})"
else raise Exception, "ruby_code case not handled: #{obj.class}" else raise Gem::Exception, "ruby_code case not handled: #{obj.class}"
end end
end end
@ -941,36 +1031,50 @@ module Gem
# :section: Required gemspec attributes # :section: Required gemspec attributes
## ##
# :attr_accessor: rubygems_version
#
# The version of RubyGems used to create this gem # The version of RubyGems used to create this gem
required_attribute :rubygems_version, Gem::RubyGemsVersion required_attribute :rubygems_version, Gem::RubyGemsVersion
## ##
# :attr_accessor: specification_version
#
# The Gem::Specification version of this gemspec # The Gem::Specification version of this gemspec
required_attribute :specification_version, CURRENT_SPECIFICATION_VERSION required_attribute :specification_version, CURRENT_SPECIFICATION_VERSION
## ##
# :attr_accessor: name
#
# This gem's name # This gem's name
required_attribute :name required_attribute :name
## ##
# :attr_accessor: version
#
# This gem's version # This gem's version
required_attribute :version required_attribute :version
## ##
# :attr_accessor: date
#
# The date this gem was created # The date this gem was created
required_attribute :date, TODAY required_attribute :date, TODAY
## ##
# :attr_accessor: summary
#
# 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`.
required_attribute :summary required_attribute :summary
## ##
# :attr_accessor: require_paths
#
# Paths in the gem to add to $LOAD_PATH when this gem is activated # Paths in the gem to add to $LOAD_PATH when this gem is activated
required_attribute :require_paths, ['lib'] required_attribute :require_paths, ['lib']
@ -978,46 +1082,64 @@ module Gem
# :section: Optional gemspec attributes # :section: Optional gemspec attributes
## ##
# :attr_accessor: email
#
# A contact email for this gem # A contact email for this gem
attribute :email attribute :email
## ##
# :attr_accessor: homepage
#
# The URL of this gem's home page # The URL of this gem's home page
attribute :homepage attribute :homepage
## ##
# :attr_accessor: rubyforge_project
#
# The rubyforge project this gem lives under. i.e. RubyGems' # The rubyforge project this gem lives under. i.e. RubyGems'
# rubyforge_project is "rubygems". # rubyforge_project is "rubygems".
attribute :rubyforge_project attribute :rubyforge_project
## ##
# :attr_accessor: description
#
# A long description of this gem # A long description of this gem
attribute :description attribute :description
## ##
# :attr_accessor: autorequire
#
# Autorequire was used by old RubyGems to automatically require a file. # Autorequire was used by old RubyGems to automatically require a file.
# It no longer is supported. # It no longer is supported.
attribute :autorequire attribute :autorequire
## ##
# :attr_accessor: default_executable
#
# The default executable for this gem. # The default executable for this gem.
attribute :default_executable attribute :default_executable
## ##
# :attr_accessor: bindir
#
# The path in the gem for executable scripts # The path in the gem for executable scripts
attribute :bindir, 'bin' attribute :bindir, 'bin'
## ##
# True if this gem is RDoc-compliant # :attr_accessor: has_rdoc
#
# Deprecated and ignored, defaults to true.
#
# Formerly used to indicate this gem was RDoc-capable.
attribute :has_rdoc, false attribute :has_rdoc, true
## ##
# True if this gem supports RDoc # True if this gem supports RDoc
@ -1025,80 +1147,125 @@ module Gem
alias :has_rdoc? :has_rdoc alias :has_rdoc? :has_rdoc
## ##
# :attr_accessor: required_ruby_version
#
# The ruby of version required by this gem # The ruby of version required by this gem
attribute :required_ruby_version, Gem::Requirement.default attribute :required_ruby_version, Gem::Requirement.default
## ##
# :attr_accessor: required_rubygems_version
#
# The RubyGems version required by this gem # The RubyGems version required by this gem
attribute :required_rubygems_version, Gem::Requirement.default attribute :required_rubygems_version, Gem::Requirement.default
## ##
# :attr_accessor: platform
#
# The platform this gem runs on. See Gem::Platform for details. # The platform this gem runs on. See Gem::Platform for details.
attribute :platform, Gem::Platform::RUBY attribute :platform, Gem::Platform::RUBY
## ##
# :attr_accessor: signing_key
#
# The key used to sign this gem. See Gem::Security for details. # The key used to sign this gem. See Gem::Security for details.
attribute :signing_key, nil attribute :signing_key, nil
## ##
# :attr_accessor: cert_chain
#
# The certificate chain used to sign this gem. See Gem::Security for # The certificate chain used to sign this gem. See Gem::Security for
# details. # details.
attribute :cert_chain, [] attribute :cert_chain, []
## ##
# :attr_accessor: post_install_message
#
# A message that gets displayed after the gem is installed # A message that gets displayed after the gem is installed
attribute :post_install_message, nil attribute :post_install_message, nil
## ##
# :attr_accessor: authors
#
# The list of authors who wrote this gem # The list of authors who wrote this gem
array_attribute :authors array_attribute :authors
## ##
# Files included in this gem # :attr_accessor: licenses
#
# The license(s) for the library. Each license must be a short name, no
# more than 64 characters.
array_attribute :licenses
##
# :attr_accessor: files
#
# 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.
array_attribute :files array_attribute :files
## ##
# Test files included in this gem # :attr_accessor: test_files
#
# Test files included in this gem. You cannot append to this accessor, you
# must assign to it.
array_attribute :test_files array_attribute :test_files
## ##
# :attr_accessor: rdoc_options
#
# An ARGV-style array of options to RDoc # An ARGV-style array of options to RDoc
array_attribute :rdoc_options array_attribute :rdoc_options
## ##
# :attr_accessor: extra_rdoc_files
#
# Extra files to add to RDoc # Extra files to add to RDoc
array_attribute :extra_rdoc_files array_attribute :extra_rdoc_files
## ##
# :attr_accessor: executables
#
# Executables included in the gem # Executables included in the gem
array_attribute :executables array_attribute :executables
## ##
# :attr_accessor: extensions
#
# Extensions to build when installing the gem. See # Extensions to build when installing the gem. See
# Gem::Installer#build_extensions for valid values. # Gem::Installer#build_extensions for valid values.
array_attribute :extensions array_attribute :extensions
## ##
# :attr_accessor: requirements
#
# An array or things required by this gem. Not used by anything # An array or things required by this gem. Not used by anything
# presently. # presently.
array_attribute :requirements array_attribute :requirements
## ##
# A list of Gem::Dependency objects this gem depends on. Only appendable. # :attr_reader: dependencies
#
# A list of Gem::Dependency objects this gem depends on.
array_attribute :dependencies array_attribute :dependencies
@ -1107,27 +1274,48 @@ module Gem
# :section: Aliased gemspec attributes # :section: Aliased gemspec attributes
## ##
# Singular accessor for executables # Singular accessor for #executables
attribute_alias_singular :executable, :executables attribute_alias_singular :executable, :executables
## ##
# Singular accessor for authors # Singular accessor for #authors
attribute_alias_singular :author, :authors attribute_alias_singular :author, :authors
## ##
# Singular accessor for require_paths # Singular accessor for #licenses
attribute_alias_singular :license, :licenses
##
# Singular accessor for #require_paths
attribute_alias_singular :require_path, :require_paths attribute_alias_singular :require_path, :require_paths
## ##
# Singular accessor for test_files # Singular accessor for #test_files
attribute_alias_singular :test_file, :test_files attribute_alias_singular :test_file, :test_files
##
# has_rdoc is now ignored
overwrite_accessor :has_rdoc do
true
end
##
# has_rdoc is now ignored
overwrite_accessor :has_rdoc= do |value|
@has_rdoc = true
end
overwrite_accessor :version= do |version| overwrite_accessor :version= do |version|
@version = Version.create(version) @version = Gem::Version.create(version)
self.required_rubygems_version = '> 1.3.1' if @version.prerelease?
return @version
end end
overwrite_accessor :platform do overwrite_accessor :platform do
@ -1153,8 +1341,6 @@ module Gem
@new_platform = Gem::Platform::RUBY @new_platform = Gem::Platform::RUBY
when 'mswin32' then # was Gem::Platform::WIN32 when 'mswin32' then # was Gem::Platform::WIN32
@new_platform = Gem::Platform.new 'x86-mswin32' @new_platform = Gem::Platform.new 'x86-mswin32'
when 'mswin64' then
@new_platform = Gem::Platform.new 'x86-mswin64'
when 'i586-linux' then # was Gem::Platform::LINUX_586 when 'i586-linux' then # was Gem::Platform::LINUX_586
@new_platform = Gem::Platform.new 'x86-linux' @new_platform = Gem::Platform.new 'x86-linux'
when 'powerpc-darwin' then # was Gem::Platform::DARWIN when 'powerpc-darwin' then # was Gem::Platform::DARWIN
@ -1211,11 +1397,7 @@ module Gem
end end
overwrite_accessor :description= do |str| overwrite_accessor :description= do |str|
@description = if str then @description = str.to_s
str.strip.
gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').
gsub(/\n[ \t]*/, " ")
end
end end
overwrite_accessor :default_executable do overwrite_accessor :default_executable do
@ -1258,7 +1440,5 @@ module Gem
result.uniq.compact result.uniq.compact
end end
end
end end

30
lib/rubygems/text.rb Normal file
View file

@ -0,0 +1,30 @@
require 'rubygems'
##
# A collection of text-wrangling methods
module Gem::Text
##
# Wraps +text+ to +wrap+ characters and optionally indents by +indent+
# characters
def format_text(text, wrap, indent=0)
result = []
work = text.dup
while work.length > wrap do
if work =~ /^(.{0,#{wrap}})[ \n]/ then
result << $1
work.slice!(0, $&.length)
else
result << work.slice!(0, wrap)
end
end
result << work if work.length.nonzero?
result.join("\n").gsub(/^/, " " * indent)
end
end

View file

@ -1,6 +1,6 @@
# #
# This file defines a $log variable for logging, and a time() method for recording timing # This file defines a $log variable for logging, and a time() method for
# information. # recording timing information.
# #
#-- #--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others. # Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
@ -8,18 +8,21 @@
# See LICENSE.txt for permissions. # See LICENSE.txt for permissions.
#++ #++
require 'rubygems'
file, lineno = Gem.location_of_caller
warn "#{file}:#{lineno}:Warning: RubyGems' lib/rubygems/timer.rb deprecated and will be removed on or after June 2009."
$log = Object.new $log = Object.new
def $log.debug(str)
STDERR.puts str # :stopdoc:
def $log.debug(message)
Gem.debug message
end end
def time(msg, width=25) def time(msg, width=25, &block)
t = Time.now Gem.time(msg, width, &block)
return_value = yield
elapsed = Time.now.to_f - t.to_f
elapsed = sprintf("%3.3f", elapsed)
$log.debug "#{msg.ljust(width)}: #{elapsed}s"
return_value
end end
# :startdoc:

View file

@ -12,6 +12,11 @@ require 'rubygems/user_interaction'
## ##
# An Uninstaller. # An Uninstaller.
#
# The uninstaller fires pre and post uninstall hooks. Hooks can be added
# either through a rubygems_plugin.rb file in an installed gem or via a
# rubygems/defaults/#{RUBY_ENGINE}.rb or rubygems/defaults/operating_system.rb
# file. See Gem.pre_uninstall and Gem.post_uninstall for details.
class Gem::Uninstaller class Gem::Uninstaller
@ -46,8 +51,17 @@ class Gem::Uninstaller
@force_ignore = options[:ignore] @force_ignore = options[:ignore]
@bin_dir = options[:bin_dir] @bin_dir = options[:bin_dir]
# only add user directory if install_dir is not set
@user_install = false
@user_install = options[:user_install] unless options[:install_dir]
spec_dir = File.join @gem_home, 'specifications' spec_dir = File.join @gem_home, 'specifications'
@source_index = Gem::SourceIndex.from_gems_in spec_dir @source_index = Gem::SourceIndex.from_gems_in spec_dir
if @user_install then
user_dir = File.join Gem.user_dir, 'specifications'
@user_index = Gem::SourceIndex.from_gems_in user_dir
end
end end
## ##
@ -56,9 +70,10 @@ class Gem::Uninstaller
def uninstall def uninstall
list = @source_index.find_name @gem, @version list = @source_index.find_name @gem, @version
list += @user_index.find_name @gem, @version if @user_install
if list.empty? then if list.empty? then
raise Gem::InstallError, "Unknown gem #{@gem} #{@version}" raise Gem::InstallError, "cannot uninstall, check `gem list -d #{@gem}`"
elsif list.size > 1 and @force_all then elsif list.size > 1 and @force_all then
remove_all list.dup remove_all list.dup
@ -91,8 +106,8 @@ class Gem::Uninstaller
hook.call self hook.call self
end end
specs.each { |s| remove_executables s } remove_executables @spec
remove spec, specs remove @spec, specs
Gem.post_uninstall_hooks.each do |hook| Gem.post_uninstall_hooks.each do |hook|
hook.call self hook.call self
@ -105,29 +120,29 @@ class Gem::Uninstaller
# Removes installed executables and batch files (windows only) for # Removes installed executables and batch files (windows only) for
# +gemspec+. # +gemspec+.
def remove_executables(gemspec) def remove_executables(spec)
return if gemspec.nil? return if spec.nil?
if gemspec.executables.size > 0 then unless spec.executables.empty? then
bindir = @bin_dir ? @bin_dir : (Gem.bindir @gem_home) bindir = @bin_dir ? @bin_dir : Gem.bindir(spec.installation_path)
list = @source_index.find_name(gemspec.name).delete_if { |spec| list = @source_index.find_name(spec.name).delete_if { |s|
spec.version == gemspec.version s.version == spec.version
} }
executables = gemspec.executables.clone executables = spec.executables.clone
list.each do |spec| list.each do |s|
spec.executables.each do |exe_name| s.executables.each do |exe_name|
executables.delete(exe_name) executables.delete exe_name
end end
end end
return if executables.size == 0 return if executables.empty?
answer = if @force_executables.nil? then answer = if @force_executables.nil? then
ask_yes_no("Remove executables:\n" \ ask_yes_no("Remove executables:\n" \
"\t#{gemspec.executables.join(", ")}\n\nin addition to the gem?", "\t#{spec.executables.join(", ")}\n\nin addition to the gem?",
true) # " # appease ruby-mode - don't ask true) # " # appease ruby-mode - don't ask
else else
@force_executables @force_executables
@ -138,7 +153,7 @@ class Gem::Uninstaller
else else
raise Gem::FilePermissionError, bindir unless File.writable? bindir raise Gem::FilePermissionError, bindir unless File.writable? bindir
gemspec.executables.each do |exe_name| spec.executables.each do |exe_name|
say "Removing #{exe_name}" say "Removing #{exe_name}"
FileUtils.rm_f File.join(bindir, exe_name) FileUtils.rm_f File.join(bindir, exe_name)
FileUtils.rm_f File.join(bindir, "#{exe_name}.bat") FileUtils.rm_f File.join(bindir, "#{exe_name}.bat")
@ -169,7 +184,8 @@ class Gem::Uninstaller
"Uninstallation aborted due to dependent gem(s)" "Uninstallation aborted due to dependent gem(s)"
end end
unless path_ok? spec then unless path_ok?(@gem_home, spec) or
(@user_install and path_ok?(Gem.user_dir, spec)) then
e = Gem::GemNotInHomeException.new \ e = Gem::GemNotInHomeException.new \
"Gem is not installed in directory #{@gem_home}" "Gem is not installed in directory #{@gem_home}"
e.spec = spec e.spec = spec
@ -210,9 +226,12 @@ class Gem::Uninstaller
list.delete spec list.delete spec
end end
def path_ok?(spec) ##
full_path = File.join @gem_home, 'gems', spec.full_name # Is +spec+ in +gem_dir+?
original_path = File.join @gem_home, 'gems', spec.original_name
def path_ok?(gem_dir, spec)
full_path = File.join gem_dir, 'gems', spec.full_name
original_path = File.join gem_dir, 'gems', spec.original_name
full_path == spec.full_gem_path || original_path == spec.full_gem_path full_path == spec.full_gem_path || original_path == spec.full_gem_path
end end
@ -221,6 +240,7 @@ class Gem::Uninstaller
return true if @force_ignore return true if @force_ignore
deplist = Gem::DependencyList.from_source_index @source_index deplist = Gem::DependencyList.from_source_index @source_index
deplist.add(*@user_index.gems.values) if @user_install
deplist.ok_to_remove?(spec.full_name) || ask_if_ok(spec) deplist.ok_to_remove?(spec.full_name) || ask_if_ok(spec)
end end

View file

@ -4,13 +4,11 @@
# See LICENSE.txt for permissions. # See LICENSE.txt for permissions.
#++ #++
module Gem ##
# Module that defines the default UserInteraction. Any class including this
# module will have access to the +ui+ method that returns the default UI.
## module Gem::DefaultUserInteraction
# Module that defines the default UserInteraction. Any class including this
# module will have access to the +ui+ method that returns the default UI.
module DefaultUserInteraction
## ##
# The default UI is a class variable of the singleton class for this # The default UI is a class variable of the singleton class for this
@ -48,43 +46,67 @@ module Gem
# See DefaultUserInteraction::ui # See DefaultUserInteraction::ui
def ui def ui
DefaultUserInteraction.ui Gem::DefaultUserInteraction.ui
end end
## ##
# See DefaultUserInteraction::ui= # See DefaultUserInteraction::ui=
def ui=(new_ui) def ui=(new_ui)
DefaultUserInteraction.ui = new_ui Gem::DefaultUserInteraction.ui = new_ui
end end
## ##
# See DefaultUserInteraction::use_ui # See DefaultUserInteraction::use_ui
def use_ui(new_ui, &block) def use_ui(new_ui, &block)
DefaultUserInteraction.use_ui(new_ui, &block) Gem::DefaultUserInteraction.use_ui(new_ui, &block)
end end
end end
##
# Make the default UI accessable without the "ui." prefix. Classes
# including this module may use the interaction methods on the default UI
# directly. Classes may also reference the ui and ui= methods.
#
# Example:
#
# class X
# include Gem::UserInteraction
#
# def get_answer
# n = ask("What is the meaning of life?")
# end
# end
module Gem::UserInteraction
include Gem::DefaultUserInteraction
## ##
# Make the default UI accessable without the "ui." prefix. Classes # :method: alert
# including this module may use the interaction methods on the default UI
# directly. Classes may also reference the ui and ui= methods.
#
# Example:
#
# class X
# include Gem::UserInteraction
#
# def get_answer
# n = ask("What is the meaning of life?")
# end
# end
module UserInteraction ##
# :method: alert_error
include DefaultUserInteraction ##
# :method: alert_warning
##
# :method: ask
##
# :method: ask_yes_no
##
# :method: choose_from_list
##
# :method: say
##
# :method: terminate_interaction
[:alert, [:alert,
:alert_error, :alert_error,
@ -100,12 +122,12 @@ module Gem
end end
}, __FILE__, __LINE__ }, __FILE__, __LINE__
end end
end end
## ##
# StreamUI implements a simple stream based user interface. # Gem::StreamUI implements a simple stream based user interface.
class StreamUI class Gem::StreamUI
attr_reader :ins, :outs, :errs attr_reader :ins, :outs, :errs
@ -228,6 +250,13 @@ module Gem
ask(question) if question ask(question) if question
end end
##
# Display a debug message on the same location as error messages.
def debug(statement)
@errs.puts statement
end
## ##
# Terminate the application with exit code +status+, running any exit # Terminate the application with exit code +status+, running any exit
# handlers that might have been defined. # handlers that might have been defined.
@ -270,7 +299,8 @@ module Gem
# A basic dotted progress reporter. # A basic dotted progress reporter.
class SimpleProgressReporter class SimpleProgressReporter
include DefaultUserInteraction
include Gem::DefaultUserInteraction
attr_reader :count attr_reader :count
@ -306,7 +336,8 @@ module Gem
# A progress reporter that prints out messages about the current progress. # A progress reporter that prints out messages about the current progress.
class VerboseProgressReporter class VerboseProgressReporter
include DefaultUserInteraction
include Gem::DefaultUserInteraction
attr_reader :count attr_reader :count
@ -335,26 +366,25 @@ module Gem
@out.puts @terminal_message @out.puts @terminal_message
end end
end end
end
##
# Subclass of StreamUI that instantiates the user interaction using STDIN,
# STDOUT, and STDERR.
class ConsoleUI < StreamUI
def initialize
super(STDIN, STDOUT, STDERR)
end
end
##
# SilentUI is a UI choice that is absolutely silent.
class SilentUI
def method_missing(sym, *args, &block)
self
end
end
end end
##
# Subclass of StreamUI that instantiates the user interaction using STDIN,
# STDOUT, and STDERR.
class Gem::ConsoleUI < Gem::StreamUI
def initialize
super STDIN, STDOUT, STDERR
end
end
##
# SilentUI is a UI choice that is absolutely silent.
class Gem::SilentUI
def method_missing(sym, *args, &block)
self
end
end

View file

@ -6,10 +6,17 @@
require 'find' require 'find'
require 'rubygems/digest/md5' require 'digest'
require 'rubygems/format' require 'rubygems/format'
require 'rubygems/installer' require 'rubygems/installer'
# Load test-unit 2.x if it's a gem
begin
Gem.activate('test-unit')
rescue Gem::LoadError
# Ignore - use the test-unit library that's part of the standard library
end
## ##
# Validator performs various gem file and gem database validation # Validator performs various gem file and gem database validation
@ -33,7 +40,7 @@ class Gem::Validator
sum_data = gem_data.gsub(/MD5SUM = "([a-z0-9]+)"/, sum_data = gem_data.gsub(/MD5SUM = "([a-z0-9]+)"/,
"MD5SUM = \"#{"F" * 32}\"") "MD5SUM = \"#{"F" * 32}\"")
unless Gem::MD5.hexdigest(sum_data) == $1.to_s then unless Digest::MD5.hexdigest(sum_data) == $1.to_s then
raise Gem::VerificationError, 'invalid checksum for gem file' raise Gem::VerificationError, 'invalid checksum for gem file'
end end
end end
@ -48,7 +55,7 @@ class Gem::Validator
gem_data = file.read gem_data = file.read
verify_gem gem_data verify_gem gem_data
end end
rescue Errno::ENOENT rescue Errno::ENOENT, Errno::EINVAL
raise Gem::VerificationError, "missing gem file #{gem_path}" raise Gem::VerificationError, "missing gem file #{gem_path}"
end end
@ -56,13 +63,11 @@ class Gem::Validator
def find_files_for_gem(gem_directory) def find_files_for_gem(gem_directory)
installed_files = [] installed_files = []
Find.find(gem_directory) {|file_name| Find.find gem_directory do |file_name|
fn = file_name.slice((gem_directory.size)..(file_name.size-1)).sub(/^\//, "") fn = file_name[gem_directory.size..file_name.size-1].sub(/^\//, "")
if(!(fn =~ /CVS/ || File.directory?(fn) || fn == "")) then installed_files << fn unless
installed_files << fn fn =~ /CVS/ || fn.empty? || File.directory?(file_name)
end end
}
installed_files installed_files
end end
@ -81,53 +86,82 @@ class Gem::Validator
# #
# returns a hash of ErrorData objects, keyed on the problem gem's name. # returns a hash of ErrorData objects, keyed on the problem gem's name.
def alien def alien(gems=[])
errors = {} errors = Hash.new { |h,k| h[k] = {} }
Gem::SourceIndex.from_installed_gems.each do |gem_name, gem_spec| Gem::SourceIndex.from_installed_gems.each do |gem_name, gem_spec|
errors[gem_name] ||= [] next unless gems.include? gem_spec.name unless gems.empty?
gem_path = File.join(Gem.dir, "cache", gem_spec.full_name) + ".gem" install_dir = gem_spec.installation_path
spec_path = File.join(Gem.dir, "specifications", gem_spec.full_name) + ".gemspec" gem_path = File.join(install_dir, "cache", gem_spec.full_name) + ".gem"
gem_directory = File.join(Gem.dir, "gems", gem_spec.full_name) spec_path = File.join(install_dir, "specifications",
gem_spec.full_name) + ".gemspec"
gem_directory = gem_spec.full_gem_path
installed_files = find_files_for_gem(gem_directory) unless File.directory? gem_directory then
errors[gem_name][gem_spec.full_name] =
"Gem registered but doesn't exist at #{gem_directory}"
next
end
unless File.exist? spec_path then unless File.exist? spec_path then
errors[gem_name] << ErrorData.new(spec_path, "Spec file doesn't exist for installed gem") errors[gem_name][spec_path] = "Spec file missing for installed gem"
end end
begin begin
verify_gem_file(gem_path) verify_gem_file(gem_path)
good, gone, unreadable = nil, nil, nil, nil
open gem_path, Gem.binary_mode do |file| open gem_path, Gem.binary_mode do |file|
format = Gem::Format.from_file_by_path(gem_path) format = Gem::Format.from_file_by_path(gem_path)
format.file_entries.each do |entry, data|
# Found this file. Delete it from list
installed_files.delete remove_leading_dot_dir(entry['path'])
good, gone = format.file_entries.partition { |entry, _|
File.exist? File.join(gem_directory, entry['path'])
}
gone.map! { |entry, _| entry['path'] }
gone.sort.each do |path|
errors[gem_name][path] = "Missing file"
end
good, unreadable = good.partition { |entry, _|
File.readable? File.join(gem_directory, entry['path'])
}
unreadable.map! { |entry, _| entry['path'] }
unreadable.sort.each do |path|
errors[gem_name][path] = "Unreadable file"
end
good.each do |entry, data|
begin
next unless data # HACK `gem check -a mkrf` next unless data # HACK `gem check -a mkrf`
open File.join(gem_directory, entry['path']), Gem.binary_mode do |f| open File.join(gem_directory, entry['path']), Gem.binary_mode do |f|
unless Gem::MD5.hexdigest(f.read).to_s == unless Digest::MD5.hexdigest(f.read).to_s ==
Gem::MD5.hexdigest(data).to_s then Digest::MD5.hexdigest(data).to_s then
errors[gem_name] << ErrorData.new(entry['path'], "installed file doesn't match original from gem") errors[gem_name][entry['path']] = "Modified from original"
end end
end end
end end
end end
rescue Gem::VerificationError => e
errors[gem_name] << ErrorData.new(gem_path, e.message)
end end
# Clean out directories that weren't explicitly included in the gemspec installed_files = find_files_for_gem(gem_directory)
# FIXME: This still allows arbitrary incorrect directories. good.map! { |entry, _| entry['path'] }
installed_files.delete_if {|potential_directory| extras = installed_files - good - unreadable
File.directory?(File.join(gem_directory, potential_directory))
} extras.each do |extra|
if(installed_files.size > 0) then errors[gem_name][extra] = "Extra file"
errors[gem_name] << ErrorData.new(gem_path, "Unmanaged files in gem: #{installed_files.inspect}")
end end
rescue Gem::VerificationError => e
errors[gem_name][gem_path] = e.message
end
end
errors.each do |name, subhash|
errors[name] = subhash.map { |path, msg| ErrorData.new(path, msg) }
end end
errors errors
@ -167,7 +201,7 @@ class Gem::Validator
def unit_test(gem_spec) def unit_test(gem_spec)
start_dir = Dir.pwd start_dir = Dir.pwd
Dir.chdir(gem_spec.full_gem_path) Dir.chdir(gem_spec.full_gem_path)
$: << File.join(Gem.dir, "gems", gem_spec.full_name) $: << gem_spec.full_gem_path
# XXX: why do we need this gem_spec when we've already got 'spec'? # XXX: why do we need this gem_spec when we've already got 'spec'?
test_files = gem_spec.test_files test_files = gem_spec.test_files
@ -200,7 +234,6 @@ class Gem::Validator
Dir.chdir(start_dir) Dir.chdir(start_dir)
end end
private
def remove_leading_dot_dir(path) def remove_leading_dot_dir(path)
path.sub(/^\.\//, "") path.sub(/^\.\//, "")
end end

View file

@ -4,27 +4,81 @@
# See LICENSE.txt for permissions. # See LICENSE.txt for permissions.
#++ #++
require 'rubygems'
## ##
# The Version class processes string versions into comparable values # The Version class processes string versions into comparable
# values. A version string should normally be a series of numbers
# separated by periods. Each part (digits separated by periods) is
# considered its own number, and these are used for sorting. So for
# instance, 3.10 sorts higher than 3.2 because ten is greater than
# two.
#
# If any part contains letters (currently only a-z are supported) then
# that version is considered prerelease. Versions with a prerelease
# part in the Nth part sort less than versions with N-1 parts. Prerelease
# parts are sorted alphabetically using the normal Ruby string sorting
# rules.
#
# Prereleases sort between real releases (newest to oldest):
#
# 1. 1.0
# 2. 1.0.b
# 3. 1.0.a
# 4. 0.9
class Gem::Version class Gem::Version
class Part
include Comparable include Comparable
attr_reader :ints attr_reader :value
def initialize(value)
@value = (value =~ /\A\d+\z/) ? value.to_i : value
end
def to_s
self.value.to_s
end
def inspect
@value
end
def alpha?
String === value
end
def numeric?
Fixnum === value
end
def <=>(other)
if self.numeric? && other.alpha? then
1
elsif self.alpha? && other.numeric? then
-1
else
self.value <=> other.value
end
end
def succ
self.class.new(self.value.succ)
end
end
include Comparable
VERSION_PATTERN = '[0-9]+(\.[0-9a-z]+)*'
attr_reader :version attr_reader :version
##
# Returns true if +version+ is a valid version string.
def self.correct?(version) def self.correct?(version)
case version pattern = /\A\s*(#{VERSION_PATTERN})*\s*\z/
when Integer, /\A\s*(\d+(\.-?\d+)*)*\s*\z/ then true
else false version.is_a? Integer or
end version =~ pattern or
version.to_s =~ pattern
end end
## ##
@ -47,7 +101,7 @@ class Gem::Version
## ##
# Constructs a Version from the +version+ string. A version string is a # Constructs a Version from the +version+ string. A version string is a
# series of digits separated by dots. # series of digits or ASCII letters separated by dots.
def initialize(version) def initialize(version)
raise ArgumentError, "Malformed version number string #{version}" unless raise ArgumentError, "Malformed version number string #{version}" unless
@ -60,46 +114,43 @@ class Gem::Version
"#<#{self.class} #{@version.inspect}>" "#<#{self.class} #{@version.inspect}>"
end end
##
# Dump only the raw version string, not the complete object # Dump only the raw version string, not the complete object
def marshal_dump def marshal_dump
[@version] [@version]
end end
##
# Load custom marshal format # Load custom marshal format
def marshal_load(array) def marshal_load(array)
self.version = array[0] self.version = array[0]
end end
def parts
@parts ||= normalize
end
## ##
# Strip ignored trailing zeros. # Strip ignored trailing zeros.
def normalize def normalize
@ints = build_array_from_version_string parts_arr = parse_parts_from_version_string
if parts_arr.length != 1
return if @ints.length == 1 parts_arr.pop while parts_arr.last && parts_arr.last.value == 0
parts_arr = [Part.new(0)] if parts_arr.empty?
@ints.pop while @ints.last == 0 end
parts_arr
@ints = [0] if @ints.empty?
end end
## ##
# Returns the text representation of the version # Returns the text representation of the version
#
# return:: [String] version as string
#
def to_s def to_s
@version @version
end end
##
# Returns an integer array representation of this Version.
def to_ints
normalize unless @ints
@ints
end
def to_yaml_properties def to_yaml_properties
['@version'] ['@version']
end end
@ -109,6 +160,23 @@ class Gem::Version
normalize normalize
end end
##
# A version is considered a prerelease if any part contains a letter.
def prerelease?
parts.any? { |part| part.alpha? }
end
##
# The release for this version (e.g. 1.2.0.a -> 1.2.0)
# Non-prerelease versions return themselves
def release
return self unless prerelease?
rel_parts = parts.dup
rel_parts.pop while rel_parts.any? { |part| part.alpha? }
self.class.new(rel_parts.join('.'))
end
def yaml_initialize(tag, values) def yaml_initialize(tag, values)
self.version = values['version'] self.version = values['version']
end end
@ -120,7 +188,14 @@ class Gem::Version
def <=>(other) def <=>(other)
return nil unless self.class === other return nil unless self.class === other
return 1 unless other return 1 unless other
@ints <=> other.ints mine, theirs = balance(self.parts.dup, other.parts.dup)
mine <=> theirs
end
def balance(a, b)
a << Part.new(0) while a.size < b.size
b << Part.new(0) while b.size < a.size
[a, b]
end end
## ##
@ -135,24 +210,33 @@ class Gem::Version
@version.hash @version.hash
end end
# Return a new version object where the next to the last revision ##
# number is one greater. (e.g. 5.3.1 => 5.4) # Return a new version object where the next to the last revision number is
# one greater. (e.g. 5.3.1 => 5.4)
#
# Pre-release (alpha) parts are ignored. (e.g 5.3.1.b2 => 5.4)
def bump def bump
ints = build_array_from_version_string parts = parse_parts_from_version_string
ints.pop if ints.size > 1 parts.pop while parts.any? { |part| part.alpha? }
ints[-1] += 1 parts.pop if parts.size > 1
self.class.new(ints.join(".")) parts[-1] = parts[-1].succ
self.class.new(parts.join("."))
end end
def build_array_from_version_string def parse_parts_from_version_string # :nodoc:
@version.to_s.scan(/\d+/).map { |s| s.to_i } @version.to_s.scan(/[0-9a-z]+/i).map { |s| Part.new(s) }
end
def pretty_print(q) # :nodoc:
q.text "Gem::Version.new(#{@version.inspect})"
end end
private :build_array_from_version_string
#:stopdoc: #:stopdoc:
require 'rubygems/requirement' require 'rubygems/requirement'
##
# Gem::Requirement's original definition is nested in Version. # Gem::Requirement's original definition is nested in Version.
# Although an inappropriate place, current gems specs reference the nested # Although an inappropriate place, current gems specs reference the nested
# class name explicitly. To remain compatible with old software loading # class name explicitly. To remain compatible with old software loading

View file

@ -41,6 +41,7 @@ module Gem::VersionOption
"Specify version of gem to #{task}", *wrap) do "Specify version of gem to #{task}", *wrap) do
|value, options| |value, options|
options[:version] = value options[:version] = value
options[:prerelease] = true if value.prerelease?
end end
end end

View file

View file

@ -1,4 +1,3 @@
require 'minitest/unit'
require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities') require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities')
require 'rubygems/installer' require 'rubygems/installer'
@ -20,17 +19,17 @@ class GemInstallerTestCase < RubyGemTestCase
def setup def setup
super super
@spec = quick_gem "a" @spec = quick_gem 'a'
@gem = File.join @tempdir, "#{@spec.full_name}.gem" @gem = File.join @tempdir, "#{@spec.full_name}.gem"
util_build_gem @spec @installer = util_installer @spec, @gem, @gemhome
FileUtils.mv File.join(@gemhome, 'cache', "#{@spec.full_name}.gem"),
@tempdir
@installer = Gem::Installer.new @gem @user_spec = quick_gem 'b'
@installer.gem_dir = util_gem_dir @user_gem = File.join @tempdir, "#{@user_spec.full_name}.gem"
@installer.gem_home = @gemhome
@installer.spec = @spec @user_installer = util_installer @user_spec, @user_gem, Gem.user_dir
@user_installer.gem_dir = File.join(Gem.user_dir, 'gems',
@user_spec.full_name)
end end
def util_gem_bindir(version = '2') def util_gem_bindir(version = '2')
@ -49,8 +48,7 @@ class GemInstallerTestCase < RubyGemTestCase
@spec.executables = ["my_exec"] @spec.executables = ["my_exec"]
FileUtils.mkdir_p util_gem_bindir(version) FileUtils.mkdir_p util_gem_bindir(version)
exec_file = @installer.formatted_program_filename "my_exec" exec_path = File.join util_gem_bindir(version), "my_exec"
exec_path = File.join util_gem_bindir(version), exec_file
File.open exec_path, 'w' do |f| File.open exec_path, 'w' do |f|
f.puts shebang f.puts shebang
end end
@ -82,5 +80,18 @@ class GemInstallerTestCase < RubyGemTestCase
@installer = Gem::Installer.new @gem @installer = Gem::Installer.new @gem
end end
def util_installer(spec, gem_path, gem_home)
util_build_gem spec
FileUtils.mv File.join(@gemhome, 'cache', "#{spec.full_name}.gem"),
@tempdir
installer = Gem::Installer.new gem_path
installer.gem_dir = util_gem_dir
installer.gem_home = gem_home
installer.spec = spec
installer
end
end end

View file

@ -1,20 +1,6 @@
require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities') require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities')
require 'rubygems/package' require 'rubygems/package'
class File
# straight from setup.rb
def self.dir?(path)
# for corrupted windows stat()
File.directory?((path[-1,1] == '/') ? path : path + '/')
end
def self.read_b(name)
File.open(name, "rb") { |f| f.read }
end
end
class TarTestCase < RubyGemTestCase class TarTestCase < RubyGemTestCase
def ASCIIZ(str, length) def ASCIIZ(str, length)

View file

@ -8,24 +8,35 @@ at_exit { $SAFE = 1 }
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
require 'rubygems' if RUBY_VERSION > '1.9' then
Gem::QuickLoader.load_full_rubygems_library
else
require 'rubygems'
end
require 'fileutils' require 'fileutils'
begin begin
gem 'minitest', '>= 1.3.1'
require 'minitest/unit' require 'minitest/unit'
rescue LoadError rescue Gem::LoadError
warn "Install minitest gem" warn "Install minitest gem >= 1.3.1"
raise raise
end end
require 'tmpdir' require 'tmpdir'
require 'uri' require 'uri'
require 'rubygems/package' require 'rubygems/package'
require 'rubygems/test_utilities' require 'rubygems/test_utilities'
require 'pp'
begin
gem 'rdoc'
rescue Gem::LoadError
end
require 'rdoc/rdoc'
require File.join(File.expand_path(File.dirname(__FILE__)), 'mockgemui') require File.join(File.expand_path(File.dirname(__FILE__)), 'mockgemui')
module Gem module Gem
@ruby = ENV['RUBY']
def self.searcher=(searcher) def self.searcher=(searcher)
MUTEX.synchronize do @searcher = searcher end MUTEX.synchronize do @searcher = searcher end
end end
@ -64,6 +75,8 @@ class RubyGemTestCase < MiniTest::Unit::TestCase
@latest_usrcache = File.join(@gemhome, ".gem", "latest_user_cache") @latest_usrcache = File.join(@gemhome, ".gem", "latest_user_cache")
@userhome = File.join @tempdir, 'userhome' @userhome = File.join @tempdir, 'userhome'
Gem.ensure_gem_subdirectories @gemhome
@orig_ENV_HOME = ENV['HOME'] @orig_ENV_HOME = ENV['HOME']
ENV['HOME'] = @userhome ENV['HOME'] = @userhome
Gem.instance_variable_set :@user_home, nil Gem.instance_variable_set :@user_home, nil
@ -85,7 +98,7 @@ class RubyGemTestCase < MiniTest::Unit::TestCase
Gem::SpecFetcher.fetcher = nil Gem::SpecFetcher.fetcher = nil
@orig_BASERUBY = Gem::ConfigMap[:BASERUBY] @orig_BASERUBY = Gem::ConfigMap[:BASERUBY]
Gem::ConfigMap[:BASERUBY] = Gem::ConfigMap[:RUBY_INSTALL_NAME] Gem::ConfigMap[:BASERUBY] = Gem::ConfigMap[:ruby_install_name]
@orig_arch = Gem::ConfigMap[:arch] @orig_arch = Gem::ConfigMap[:arch]
@ -160,6 +173,13 @@ class RubyGemTestCase < MiniTest::Unit::TestCase
Gem::Installer.new(gem, :wrappers => true).install Gem::Installer.new(gem, :wrappers => true).install
end end
def mu_pp(obj)
s = ''
s = PP.pp obj, s
s = s.force_encoding(Encoding.default_external) if defined? Encoding
s.chomp
end
def prep_cache_files(lc) def prep_cache_files(lc)
@usr_si ||= Gem::SourceIndex.new @usr_si ||= Gem::SourceIndex.new
@usr_sice ||= Gem::SourceInfoCacheEntry.new @usr_si, 0 @usr_sice ||= Gem::SourceInfoCacheEntry.new @usr_si, 0
@ -254,10 +274,8 @@ class RubyGemTestCase < MiniTest::Unit::TestCase
Gem::Builder.new(spec).build Gem::Builder.new(spec).build
end end
cache_dir = File.join(@gemhome, 'cache')
FileUtils.mkdir_p cache_dir
FileUtils.mv "#{spec.full_name}.gem", FileUtils.mv "#{spec.full_name}.gem",
File.join(cache_dir, "#{spec.original_name}.gem") File.join(@gemhome, 'cache', "#{spec.original_name}.gem")
end end
end end
@ -294,14 +312,30 @@ class RubyGemTestCase < MiniTest::Unit::TestCase
out.string out.string
end end
def util_make_gems def util_make_gems(prerelease = false)
@a1 = quick_gem 'a', '1' do |s|
s.files = %w[lib/code.rb]
s.require_paths = %w[lib]
s.date = Gem::Specification::TODAY - 86400
s.homepage = 'http://a.example.com'
s.email = %w[example@example.com example2@example.com]
s.authors = %w[Example Example2]
s.description = <<-DESC
This line is really, really long. So long, in fact, that it is more than eighty characters long! The purpose of this line is for testing wrapping behavior because sometimes people don't wrap their text to eighty characters. Without the wrapping, the text might not look good in the RSS feed.
Also, a list:
* An entry that's actually kind of sort
* an entry that's really long, which will probably get wrapped funny. That's ok, somebody wasn't thinking straight when they made it more than eighty characters.
DESC
end
init = proc do |s| init = proc do |s|
s.files = %w[lib/code.rb] s.files = %w[lib/code.rb]
s.require_paths = %w[lib] s.require_paths = %w[lib]
end end
@a1 = quick_gem('a', '1', &init)
@a2 = quick_gem('a', '2', &init) @a2 = quick_gem('a', '2', &init)
@a3a = quick_gem('a', '3.a', &init)
@a_evil9 = quick_gem('a_evil', '9', &init) @a_evil9 = quick_gem('a_evil', '9', &init)
@b2 = quick_gem('b', '2', &init) @b2 = quick_gem('b', '2', &init)
@c1_2 = quick_gem('c', '1.2', &init) @c1_2 = quick_gem('c', '1.2', &init)
@ -312,13 +346,23 @@ class RubyGemTestCase < MiniTest::Unit::TestCase
s.instance_variable_set :@original_platform, 'i386-linux' s.instance_variable_set :@original_platform, 'i386-linux'
end end
if prerelease
@a2_pre = quick_gem('a', '2.a', &init)
write_file File.join(*%W[gems #{@a2_pre.original_name} lib code.rb]) do
end
util_build_gem @a2_pre
end
write_file File.join(*%W[gems #{@a1.original_name} lib code.rb]) do end write_file File.join(*%W[gems #{@a1.original_name} lib code.rb]) do end
write_file File.join(*%W[gems #{@a2.original_name} lib code.rb]) do end write_file File.join(*%W[gems #{@a2.original_name} lib code.rb]) do end
write_file File.join(*%W[gems #{@a3a.original_name} lib code.rb]) do end
write_file File.join(*%W[gems #{@b2.original_name} lib code.rb]) do end write_file File.join(*%W[gems #{@b2.original_name} lib code.rb]) do end
write_file File.join(*%W[gems #{@c1_2.original_name} lib code.rb]) do end write_file File.join(*%W[gems #{@c1_2.original_name} lib code.rb]) do end
write_file File.join(*%W[gems #{@pl1.original_name} lib code.rb]) do end write_file File.join(*%W[gems #{@pl1.original_name} lib code.rb]) do end
[@a1, @a2, @a_evil9, @b2, @c1_2, @pl1].each { |spec| util_build_gem spec } [@a1, @a2, @a3a, @a_evil9, @b2, @c1_2, @pl1].each do |spec|
util_build_gem spec
end
FileUtils.rm_r File.join(@gemhome, 'gems', @pl1.original_name) FileUtils.rm_r File.join(@gemhome, 'gems', @pl1.original_name)
@ -338,26 +382,28 @@ class RubyGemTestCase < MiniTest::Unit::TestCase
platform platform
end end
def util_setup_fake_fetcher def util_setup_fake_fetcher(prerelease = false)
require 'zlib' require 'zlib'
require 'socket' require 'socket'
require 'rubygems/remote_fetcher' require 'rubygems/remote_fetcher'
@fetcher = Gem::FakeFetcher.new @fetcher = Gem::FakeFetcher.new
util_make_gems util_make_gems(prerelease)
@all_gems = [@a1, @a2, @a_evil9, @b2, @c1_2].sort @all_gems = [@a1, @a2, @a3a, @a_evil9, @b2, @c1_2].sort
@all_gem_names = @all_gems.map { |gem| gem.full_name } @all_gem_names = @all_gems.map { |gem| gem.full_name }
gem_names = [@a1.full_name, @a2.full_name, @b2.full_name] gem_names = [@a1.full_name, @a2.full_name, @a3a.full_name, @b2.full_name]
@gem_names = gem_names.sort.join("\n") @gem_names = gem_names.sort.join("\n")
@source_index = Gem::SourceIndex.new @source_index = Gem::SourceIndex.new
@source_index.add_spec @a1 @source_index.add_spec @a1
@source_index.add_spec @a2 @source_index.add_spec @a2
@source_index.add_spec @a3a
@source_index.add_spec @a_evil9 @source_index.add_spec @a_evil9
@source_index.add_spec @c1_2 @source_index.add_spec @c1_2
@source_index.add_spec @a2_pre if prerelease
Gem::RemoteFetcher.fetcher = @fetcher Gem::RemoteFetcher.fetcher = @fetcher
end end
@ -400,7 +446,13 @@ class RubyGemTestCase < MiniTest::Unit::TestCase
spec_fetcher.latest_specs[@uri] << spec_tuple spec_fetcher.latest_specs[@uri] << spec_tuple
end end
si.gems.sort_by { |_,spec| spec }.each do |_, spec| spec_fetcher.prerelease_specs[@uri] = []
si.prerelease_specs.sort.each do |spec|
spec_tuple = [spec.name, spec.version, spec.original_platform]
spec_fetcher.prerelease_specs[@uri] << spec_tuple
end
(si.gems.merge si.prerelease_gems).sort_by { |_,spec| spec }.each do |_, spec|
path = "#{@gem_repo}quick/Marshal.#{Gem.marshal_version}/#{spec.original_name}.gemspec.rz" path = "#{@gem_repo}quick/Marshal.#{Gem.marshal_version}/#{spec.original_name}.gemspec.rz"
data = Marshal.dump spec data = Marshal.dump spec
data_deflate = Zlib::Deflate.deflate data data_deflate = Zlib::Deflate.deflate data
@ -422,6 +474,42 @@ class RubyGemTestCase < MiniTest::Unit::TestCase
Gem.win_platform? Gem.win_platform?
end end
# Returns whether or not we're on a version of Ruby built with VC++ (or
# Borland) versus Cygwin, Mingw, etc.
#
def self.vc_windows?
RUBY_PLATFORM.match('mswin')
end
# Returns whether or not we're on a version of Ruby built with VC++ (or
# Borland) versus Cygwin, Mingw, etc.
#
def vc_windows?
RUBY_PLATFORM.match('mswin')
end
# Returns the make command for the current platform. For versions of Ruby
# built on MS Windows with VC++ or Borland it will return 'nmake'. On all
# other platforms, including Cygwin, it will return 'make'.
#
def self.make_command
vc_windows? ? 'nmake' : 'make'
end
# Returns the make command for the current platform. For versions of Ruby
# built on MS Windows with VC++ or Borland it will return 'nmake'. On all
# other platforms, including Cygwin, it will return 'make'.
#
def make_command
vc_windows? ? 'nmake' : 'make'
end
# Returns whether or not the nmake command could be found.
#
def nmake_found?
system('nmake /? 1>NUL 2>&1')
end
# NOTE Allow tests to use a random (but controlled) port number instead of # NOTE Allow tests to use a random (but controlled) port number instead of
# a hardcoded one. This helps CI tools when running parallels builds on # a hardcoded one. This helps CI tools when running parallels builds on
# the same builder slave. # the same builder slave.

View file

@ -56,7 +56,8 @@ class MockGemUi < Gem::StreamUI
def terminate_interaction(status=0) def terminate_interaction(status=0)
@terminated = true @terminated = true
raise TermError raise TermError unless status == 0
raise Gem::SystemExitException, status
end end
end end

View file

@ -0,0 +1,16 @@
require 'rubygems/command_manager'
class Gem::Commands::InterruptCommand < Gem::Command
def initialize
super('interrupt', 'Raises an Interrupt Exception', {})
end
def execute
raise Interrupt, "Interrupt exception"
end
end
Gem::CommandManager.instance.register_command :interrupt

View file

@ -5,32 +5,28 @@
#++ #++
SIMPLE_GEM = <<-GEMDATA SIMPLE_GEM = <<-GEMDATA
MD5SUM = "954df67d9475aa2f4fbba20aa33649c8" MD5SUM = "e3701f9db765a2358aef94c40ded71c8"
if $0 == __FILE__ if $0 == __FILE__
require 'optparse' require 'optparse'
options = {} options = {}
ARGV.options do |opts| ARGV.options do |opts|
opts.on_tail("--help", "show this message") {puts opts; exit} opts.on_tail("--help", "show this message") {puts opts; exit}
opts.on('--dir=DIRNAME', "Installation directory for the Gem") {|x| opts.on('--dir=DIRNAME', "Installation directory for the Gem") {|options[:directory]|}
options[:directory] = x opts.on('--force', "Force Gem to intall, bypassing dependency checks") {|options[:force]|}
} opts.on('--gen-rdoc', "Generate RDoc documentation for the Gem") {|options[:gen_rdoc]|}
opts.on('--force', "Force Gem to intall, bypassing dependency checks") {|x|
options[:force] = x
}
opts.on('--gen-rdoc', "Generate RDoc documentation for the Gem") {|x|
options[:gen_rdoc] = x
}
opts.parse! opts.parse!
end end
require 'rubygems/installer' require 'rubygems'
@directory = options[:directory] || Gem.dir
@force = options[:force]
gem = Gem::Installer.new(__FILE__, options).install gem = Gem::Installer.new(__FILE__).install(@force, @directory)
if options[:gen_rdoc] if options[:gen_rdoc]
Gem::DocManager.new(gem).generate_rdoc Gem::DocManager.new(gem).generate_rdoc
end end
end end
__END__ __END__
--- !ruby/object:Gem::Specification --- !ruby/object:Gem::Specification

View file

@ -24,6 +24,7 @@ class TestGem < RubyGemTestCase
expected = [ expected = [
File.join(@gemhome, *%W[gems #{@a1.full_name} lib]), File.join(@gemhome, *%W[gems #{@a1.full_name} lib]),
File.join(@gemhome, *%W[gems #{@a2.full_name} lib]), File.join(@gemhome, *%W[gems #{@a2.full_name} lib]),
File.join(@gemhome, *%W[gems #{@a3a.full_name} lib]),
File.join(@gemhome, *%W[gems #{@a_evil9.full_name} lib]), File.join(@gemhome, *%W[gems #{@a_evil9.full_name} lib]),
File.join(@gemhome, *%W[gems #{@b2.full_name} lib]), File.join(@gemhome, *%W[gems #{@b2.full_name} lib]),
File.join(@gemhome, *%W[gems #{@c1_2.full_name} lib]), File.join(@gemhome, *%W[gems #{@c1_2.full_name} lib]),
@ -41,6 +42,56 @@ class TestGem < RubyGemTestCase
assert(!Gem.available?("monkeys")) assert(!Gem.available?("monkeys"))
end end
def test_self_bin_path_bin_name
util_exec_gem
assert_equal @abin_path, Gem.bin_path('a', 'abin')
end
def test_self_bin_path_bin_name_version
util_exec_gem
assert_equal @abin_path, Gem.bin_path('a', 'abin', '4')
end
def test_self_bin_path_name
util_exec_gem
assert_equal @exec_path, Gem.bin_path('a')
end
def test_self_bin_path_name_version
util_exec_gem
assert_equal @exec_path, Gem.bin_path('a', nil, '4')
end
def test_self_bin_path_no_default_bin
quick_gem 'a', '2' do |s|
s.executables = ['exec']
end
assert_raises(Gem::Exception) do
Gem.bin_path('a', '2')
end
end
def test_self_bin_path_no_bin_file
quick_gem 'a', '1'
assert_raises(Gem::Exception) do
Gem.bin_path('a', '1')
end
end
def test_self_bin_path_with_spaces
quick_gem 'sp ace', '3' do |s|
s.executables = ['exec']
end
path = Gem.bin_path('sp ace', 'exec')
assert_equal %w(" "), [path[0,1], path[-1,1]], "Path should be escaped"
end
def test_self_bin_path_not_found
assert_raises(Gem::GemNotFoundException) do
Gem.bin_path('non-existent')
end
end
def test_self_bindir def test_self_bindir
assert_equal File.join(@gemhome, 'bin'), Gem.bindir assert_equal File.join(@gemhome, 'bin'), Gem.bindir
assert_equal File.join(@gemhome, 'bin'), Gem.bindir(Gem.dir) assert_equal File.join(@gemhome, 'bin'), Gem.bindir(Gem.dir)
@ -111,39 +162,30 @@ class TestGem < RubyGemTestCase
end end
def test_self_default_exec_format def test_self_default_exec_format
orig_BASERUBY = Gem::ConfigMap[:BASERUBY] orig_RUBY_INSTALL_NAME = Gem::ConfigMap[:ruby_install_name]
orig_RUBY_INSTALL_NAME = Gem::ConfigMap[:RUBY_INSTALL_NAME] Gem::ConfigMap[:ruby_install_name] = 'ruby'
Gem::ConfigMap[:BASERUBY] = 'ruby'
Gem::ConfigMap[:RUBY_INSTALL_NAME] = 'ruby'
assert_equal '%s', Gem.default_exec_format assert_equal '%s', Gem.default_exec_format
ensure ensure
Gem::ConfigMap[:BASERUBY] = orig_BASERUBY Gem::ConfigMap[:ruby_install_name] = orig_RUBY_INSTALL_NAME
Gem::ConfigMap[:RUBY_INSTALL_NAME] = orig_RUBY_INSTALL_NAME
end end
def test_self_default_exec_format_18 def test_self_default_exec_format_18
orig_BASERUBY = Gem::ConfigMap[:BASERUBY] orig_RUBY_INSTALL_NAME = Gem::ConfigMap[:ruby_install_name]
orig_RUBY_INSTALL_NAME = Gem::ConfigMap[:RUBY_INSTALL_NAME] Gem::ConfigMap[:ruby_install_name] = 'ruby18'
Gem::ConfigMap[:BASERUBY] = 'ruby'
Gem::ConfigMap[:RUBY_INSTALL_NAME] = 'ruby18'
assert_equal '%s18', Gem.default_exec_format assert_equal '%s18', Gem.default_exec_format
ensure ensure
Gem::ConfigMap[:BASERUBY] = orig_BASERUBY Gem::ConfigMap[:ruby_install_name] = orig_RUBY_INSTALL_NAME
Gem::ConfigMap[:RUBY_INSTALL_NAME] = orig_RUBY_INSTALL_NAME
end end
def test_self_default_exec_format_jruby def test_self_default_exec_format_jruby
orig_BASERUBY = Gem::ConfigMap[:BASERUBY] orig_RUBY_INSTALL_NAME = Gem::ConfigMap[:ruby_install_name]
orig_RUBY_INSTALL_NAME = Gem::ConfigMap[:RUBY_INSTALL_NAME] Gem::ConfigMap[:ruby_install_name] = 'jruby'
Gem::ConfigMap[:BASERUBY] = 'ruby'
Gem::ConfigMap[:RUBY_INSTALL_NAME] = 'jruby'
assert_equal 'j%s', Gem.default_exec_format assert_equal 'j%s', Gem.default_exec_format
ensure ensure
Gem::ConfigMap[:BASERUBY] = orig_BASERUBY Gem::ConfigMap[:ruby_install_name] = orig_RUBY_INSTALL_NAME
Gem::ConfigMap[:RUBY_INSTALL_NAME] = orig_RUBY_INSTALL_NAME
end end
def test_self_default_sources def test_self_default_sources
@ -166,7 +208,7 @@ class TestGem < RubyGemTestCase
def test_self_ensure_gem_directories_missing_parents def test_self_ensure_gem_directories_missing_parents
gemdir = File.join @tempdir, 'a/b/c/gemdir' gemdir = File.join @tempdir, 'a/b/c/gemdir'
FileUtils.rm_rf File.join(@tempdir, 'a') rescue nil FileUtils.rm_rf File.join(@tempdir, 'a') rescue nil
assert !File.exist?(File.join(@tempdir, 'a')), refute File.exist?(File.join(@tempdir, 'a')),
"manually remove #{File.join @tempdir, 'a'}, tests are broken" "manually remove #{File.join @tempdir, 'a'}, tests are broken"
Gem.use_paths gemdir Gem.use_paths gemdir
@ -179,14 +221,14 @@ class TestGem < RubyGemTestCase
def test_self_ensure_gem_directories_write_protected def test_self_ensure_gem_directories_write_protected
gemdir = File.join @tempdir, "egd" gemdir = File.join @tempdir, "egd"
FileUtils.rm_r gemdir rescue nil FileUtils.rm_r gemdir rescue nil
assert !File.exist?(gemdir), "manually remove #{gemdir}, tests are broken" refute File.exist?(gemdir), "manually remove #{gemdir}, tests are broken"
FileUtils.mkdir_p gemdir FileUtils.mkdir_p gemdir
FileUtils.chmod 0400, gemdir FileUtils.chmod 0400, gemdir
Gem.use_paths gemdir Gem.use_paths gemdir
Gem.ensure_gem_subdirectories gemdir Gem.ensure_gem_subdirectories gemdir
assert !File.exist?("#{gemdir}/cache") refute File.exist?("#{gemdir}/cache")
ensure ensure
FileUtils.chmod 0600, gemdir FileUtils.chmod 0600, gemdir
end end
@ -196,14 +238,14 @@ class TestGem < RubyGemTestCase
gemdir = "#{parent}/a/b/c" gemdir = "#{parent}/a/b/c"
FileUtils.rm_r parent rescue nil FileUtils.rm_r parent rescue nil
assert !File.exist?(parent), "manually remove #{parent}, tests are broken" refute File.exist?(parent), "manually remove #{parent}, tests are broken"
FileUtils.mkdir_p parent FileUtils.mkdir_p parent
FileUtils.chmod 0400, parent FileUtils.chmod 0400, parent
Gem.use_paths(gemdir) Gem.use_paths(gemdir)
Gem.ensure_gem_subdirectories gemdir Gem.ensure_gem_subdirectories gemdir
assert !File.exist?("#{gemdir}/cache") refute File.exist?("#{gemdir}/cache")
ensure ensure
FileUtils.chmod 0600, parent FileUtils.chmod 0600, parent
end end
@ -223,18 +265,20 @@ class TestGem < RubyGemTestCase
end end
def test_self_find_files def test_self_find_files
discover_path = File.join 'lib', 'foo', 'discover.rb'
foo1 = quick_gem 'foo', '1' do |s| foo1 = quick_gem 'foo', '1' do |s|
s.files << 'lib/foo/discover.rb' s.files << discover_path
end end
foo2 = quick_gem 'foo', '2' do |s| foo2 = quick_gem 'foo', '2' do |s|
s.files << 'lib/foo/discover.rb' s.files << discover_path
end end
path = File.join 'gems', foo1.full_name, 'lib', 'foo', 'discover.rb' path = File.join 'gems', foo1.full_name, discover_path
write_file(path) { |fp| fp.puts "# #{path}" } write_file(path) { |fp| fp.puts "# #{path}" }
path = File.join 'gems', foo2.full_name, 'lib', 'foo', 'discover.rb' path = File.join 'gems', foo2.full_name, discover_path
write_file(path) { |fp| fp.puts "# #{path}" } write_file(path) { |fp| fp.puts "# #{path}" }
@fetcher = Gem::FakeFetcher.new @fetcher = Gem::FakeFetcher.new
@ -245,18 +289,19 @@ class TestGem < RubyGemTestCase
Gem.searcher = nil Gem.searcher = nil
expected = [ expected = [
File.join(foo1.full_gem_path, 'lib', 'foo', 'discover.rb'), File.expand_path('foo/discover.rb', File.dirname(__FILE__)),
File.join(foo2.full_gem_path, 'lib', 'foo', 'discover.rb'), File.join(foo2.full_gem_path, discover_path),
File.join(foo1.full_gem_path, discover_path),
] ]
assert_equal expected, Gem.find_files('foo/discover').sort assert_equal expected, Gem.find_files('foo/discover')
end end
def test_self_latest_load_paths def test_self_latest_load_paths
util_make_gems util_make_gems
expected = [ expected = [
File.join(@gemhome, *%W[gems #{@a2.full_name} lib]), File.join(@gemhome, *%W[gems #{@a3a.full_name} lib]),
File.join(@gemhome, *%W[gems #{@a_evil9.full_name} lib]), File.join(@gemhome, *%W[gems #{@a_evil9.full_name} lib]),
File.join(@gemhome, *%W[gems #{@b2.full_name} lib]), File.join(@gemhome, *%W[gems #{@b2.full_name} lib]),
File.join(@gemhome, *%W[gems #{@c1_2.full_name} lib]), File.join(@gemhome, *%W[gems #{@c1_2.full_name} lib]),
@ -298,7 +343,7 @@ class TestGem < RubyGemTestCase
apple_gem_home = File.join @tempdir, 'apple_gem_home' apple_gem_home = File.join @tempdir, 'apple_gem_home'
Gem.const_set :APPLE_GEM_HOME, apple_gem_home Gem.const_set :APPLE_GEM_HOME, apple_gem_home
assert Gem.path.include?(apple_gem_home) assert_includes Gem.path, apple_gem_home
ensure ensure
Gem.send :remove_const, :APPLE_GEM_HOME Gem.send :remove_const, :APPLE_GEM_HOME
end end
@ -309,7 +354,7 @@ class TestGem < RubyGemTestCase
apple_gem_home = File.join @tempdir, 'apple_gem_home' apple_gem_home = File.join @tempdir, 'apple_gem_home'
Gem.const_set :APPLE_GEM_HOME, apple_gem_home Gem.const_set :APPLE_GEM_HOME, apple_gem_home
assert !Gem.path.include?(apple_gem_home) refute Gem.path.include?(apple_gem_home)
ensure ensure
Gem.send :remove_const, :APPLE_GEM_HOME Gem.send :remove_const, :APPLE_GEM_HOME
end end
@ -404,13 +449,13 @@ class TestGem < RubyGemTestCase
FileUtils.mv a1_spec, @tempdir FileUtils.mv a1_spec, @tempdir
assert !Gem.source_index.gems.include?(@a1.full_name) refute Gem.source_index.gems.include?(@a1.full_name)
FileUtils.mv File.join(@tempdir, "#{@a1.full_name}.gemspec"), a1_spec FileUtils.mv File.join(@tempdir, "#{@a1.full_name}.gemspec"), a1_spec
Gem.refresh Gem.refresh
assert Gem.source_index.gems.include?(@a1.full_name) assert_includes Gem.source_index.gems, @a1.full_name
assert_equal nil, Gem.instance_variable_get(:@searcher) assert_equal nil, Gem.instance_variable_get(:@searcher)
end end
@ -463,11 +508,28 @@ class TestGem < RubyGemTestCase
Gem::ConfigMap[:EXEEXT] = orig_exe_ext Gem::ConfigMap[:EXEEXT] = orig_exe_ext
end end
def test_self_ruby_version def test_self_ruby_version_1_8_5
version = RUBY_VERSION.dup util_set_RUBY_VERSION '1.8.5'
version << ".#{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL
assert_equal Gem::Version.new(version), Gem.ruby_version assert_equal Gem::Version.new('1.8.5'), Gem.ruby_version
ensure
util_restore_RUBY_VERSION
end
def test_self_ruby_version_1_8_6p287
util_set_RUBY_VERSION '1.8.6', 287
assert_equal Gem::Version.new('1.8.6.287'), Gem.ruby_version
ensure
util_restore_RUBY_VERSION
end
def test_self_ruby_version_1_9_2dev_r23493
util_set_RUBY_VERSION '1.9.2', -1, 23493
assert_equal Gem::Version.new('1.9.2.dev.23493'), Gem.ruby_version
ensure
util_restore_RUBY_VERSION
end end
def test_self_searcher def test_self_searcher
@ -478,13 +540,12 @@ class TestGem < RubyGemTestCase
other = File.join @tempdir, 'other' other = File.join @tempdir, 'other'
path = [@userhome, other].join File::PATH_SEPARATOR path = [@userhome, other].join File::PATH_SEPARATOR
Gem.send :set_paths, path Gem.send :set_paths, path
path = Gem.path
assert_equal path[0], @userhome assert_equal [@userhome, other, @gemhome], Gem.path
assert_equal path[1], other
end end
def test_self_set_paths_nonexistent_home def test_self_set_paths_nonexistent_home
ENV['GEM_HOME'] = @gemhome
Gem.clear_paths Gem.clear_paths
other = File.join @tempdir, 'other' other = File.join @tempdir, 'other'
@ -493,7 +554,7 @@ class TestGem < RubyGemTestCase
Gem.send :set_paths, other Gem.send :set_paths, other
refute File.exist?(File.join(other, 'gems')) assert_equal [other, @gemhome], Gem.path
end end
def test_self_source_index def test_self_source_index
@ -538,6 +599,28 @@ class TestGem < RubyGemTestCase
end end
end end
def test_self_user_home_user_drive_and_path
Gem.clear_paths
# safe-keep env variables
orig_home, orig_user_profile = ENV['HOME'], ENV['USERPROFILE']
orig_user_drive, orig_user_path = ENV['HOMEDRIVE'], ENV['HOMEPATH']
# prepare the environment
ENV.delete('HOME')
ENV.delete('USERPROFILE')
ENV['HOMEDRIVE'] = 'Z:'
ENV['HOMEPATH'] = '\\Users\\RubyUser'
assert_equal "Z:\\Users\\RubyUser", Gem.user_home
ensure
ENV['HOME'] = orig_home
ENV['USERPROFILE'] = orig_user_profile
ENV['USERDRIVE'] = orig_user_drive
ENV['USERPATH'] = orig_user_path
end if '1.9' > RUBY_VERSION
def util_ensure_gem_dirs def util_ensure_gem_dirs
Gem.ensure_gem_subdirectories @gemhome Gem.ensure_gem_subdirectories @gemhome
@additional.each do |dir| @additional.each do |dir|
@ -545,5 +628,46 @@ class TestGem < RubyGemTestCase
end end
end end
def util_exec_gem
spec, _ = quick_gem 'a', '4' do |s|
s.default_executable = 'exec'
s.executables = ['exec', 'abin']
end
@exec_path = File.join spec.full_gem_path, spec.bindir, 'exec'
@abin_path = File.join spec.full_gem_path, spec.bindir, 'abin'
end
def util_set_RUBY_VERSION(version, patchlevel = nil, revision = nil)
if Gem.instance_variables.include? :@ruby_version or
Gem.instance_variables.include? '@ruby_version' then
Gem.send :remove_instance_variable, :@ruby_version
end
@RUBY_VERSION = RUBY_VERSION
@RUBY_PATCHLEVEL = RUBY_PATCHLEVEL if defined?(RUBY_PATCHLEVEL)
@RUBY_REVISION = RUBY_REVISION if defined?(RUBY_REVISION)
Object.send :remove_const, :RUBY_VERSION
Object.send :remove_const, :RUBY_PATCHLEVEL if defined?(RUBY_PATCHLEVEL)
Object.send :remove_const, :RUBY_REVISION if defined?(RUBY_REVISION)
Object.const_set :RUBY_VERSION, version
Object.const_set :RUBY_PATCHLEVEL, patchlevel if patchlevel
Object.const_set :RUBY_REVISION, revision if revision
end
def util_restore_RUBY_VERSION
Object.send :remove_const, :RUBY_VERSION
Object.send :remove_const, :RUBY_PATCHLEVEL if defined?(RUBY_PATCHLEVEL)
Object.send :remove_const, :RUBY_REVISION if defined?(RUBY_REVISION)
Object.const_set :RUBY_VERSION, @RUBY_VERSION
Object.const_set :RUBY_PATCHLEVEL, @RUBY_PATCHLEVEL if
defined?(@RUBY_PATCHLEVEL)
Object.const_set :RUBY_REVISION, @RUBY_REVISION if
defined?(@RUBY_REVISION)
end
end end

View file

@ -55,16 +55,6 @@ class TestGemCommand < RubyGemTestCase
assert_equal [], h assert_equal [], h
end end
def test_add_option_overlapping_common_and_local_options
@cmd.add_option('-x', '--zip', 'BAD!') do end
@cmd.add_option('-z', '--exe', 'BAD!') do end
@cmd.add_option('-x', '--exe', 'BAD!') do end
assert_match %r|-x, --exe|, @cmd.parser.to_s
refute_match %r|-z, --exe|, @cmd.parser.to_s
refute_match %r|-x, --zip|, @cmd.parser.to_s
end
def test_basic_accessors def test_basic_accessors
assert_equal "doit", @cmd.command assert_equal "doit", @cmd.command
assert_equal "gem doit", @cmd.program_name assert_equal "gem doit", @cmd.program_name
@ -182,9 +172,9 @@ class TestGemCommand < RubyGemTestCase
assert @cmd.handles?(['--help', 'command']) assert @cmd.handles?(['--help', 'command'])
assert @cmd.handles?(['-f', 'filename']) assert @cmd.handles?(['-f', 'filename'])
assert @cmd.handles?(['--file=filename']) assert @cmd.handles?(['--file=filename'])
assert ! @cmd.handles?(['-z']) refute @cmd.handles?(['-z'])
assert ! @cmd.handles?(['-f']) refute @cmd.handles?(['-f'])
assert ! @cmd.handles?(['--toothpaste']) refute @cmd.handles?(['--toothpaste'])
args = ['-h', 'command'] args = ['-h', 'command']
@cmd.handles?(args) @cmd.handles?(args)

View file

@ -7,29 +7,16 @@
require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities') require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities')
require 'rubygems/command_manager' require 'rubygems/command_manager'
class InterruptCommand < Gem::Command
def initialize
super('interrupt', 'Raises an Interrupt Exception', {})
end
def execute
raise Interrupt, "Interrupt exception"
end
end
class TestGemCommandManager < RubyGemTestCase class TestGemCommandManager < RubyGemTestCase
def setup def setup
super super
@command_manager = Gem::CommandManager.new @command_manager = Gem::CommandManager.instance
end end
def test_run_interrupt def test_run_interrupt
use_ui @ui do use_ui @ui do
@command_manager.register_command :interrupt
assert_raises MockGemUi::TermError do assert_raises MockGemUi::TermError do
@command_manager.run 'interrupt' @command_manager.run 'interrupt'
end end

View file

@ -105,7 +105,7 @@ class TestGemCommandsCertCommand < RubyGemTestCase
assert_equal "Removed '/CN=rubygems/DC=example/DC=com'\n", @ui.output assert_equal "Removed '/CN=rubygems/DC=example/DC=com'\n", @ui.output
assert_equal '', @ui.error assert_equal '', @ui.error
assert !File.exist?(@cert_file_name) refute File.exist?(@cert_file_name)
end end
def test_execute_sign def test_execute_sign

View file

@ -24,6 +24,27 @@ class TestGemCommandsContentsCommand < RubyGemTestCase
assert_equal "", @ui.error assert_equal "", @ui.error
end end
def test_execute_all
@cmd.options[:all] = true
quick_gem 'foo' do |gem|
gem.files = %w[lib/foo.rb Rakefile]
end
quick_gem 'bar' do |gem|
gem.files = %w[lib/bar.rb Rakefile]
end
use_ui @ui do
@cmd.execute
end
assert_match %r|lib/foo\.rb|, @ui.output
assert_match %r|lib/bar\.rb|, @ui.output
assert_match %r|Rakefile|, @ui.output
assert_equal "", @ui.error
end
def test_execute_bad_gem def test_execute_bad_gem
@cmd.options[:args] = %w[foo] @cmd.options[:args] = %w[foo]
@ -75,6 +96,48 @@ class TestGemCommandsContentsCommand < RubyGemTestCase
assert_equal "", @ui.error assert_equal "", @ui.error
end end
def test_execute_multiple
@cmd.options[:args] = %w[foo bar]
quick_gem 'foo' do |gem|
gem.files = %w[lib/foo.rb Rakefile]
end
quick_gem 'bar' do |gem|
gem.files = %w[lib/bar.rb Rakefile]
end
use_ui @ui do
@cmd.execute
end
assert_match %r|lib/foo\.rb|, @ui.output
assert_match %r|lib/bar\.rb|, @ui.output
assert_match %r|Rakefile|, @ui.output
assert_equal "", @ui.error
end
def test_execute_no_prefix
@cmd.options[:args] = %w[foo]
@cmd.options[:prefix] = false
quick_gem 'foo' do |gem|
gem.files = %w[lib/foo.rb Rakefile]
end
use_ui @ui do
@cmd.execute
end
expected = <<-EOF
lib/foo.rb
Rakefile
EOF
assert_equal expected, @ui.output
assert_equal "", @ui.error
end
def test_handle_options def test_handle_options
assert_equal false, @cmd.options[:lib_only] assert_equal false, @cmd.options[:lib_only]
assert_equal [], @cmd.options[:specdirs] assert_equal [], @cmd.options[:specdirs]

View file

@ -24,7 +24,7 @@ class TestGemCommandsEnvironmentCommand < RubyGemTestCase
assert_match %r|INSTALLATION DIRECTORY: #{Regexp.escape @gemhome}|, assert_match %r|INSTALLATION DIRECTORY: #{Regexp.escape @gemhome}|,
@ui.output @ui.output
assert_match %r|RUBYGEMS PREFIX: |, @ui.output assert_match %r|RUBYGEMS PREFIX: |, @ui.output
assert_match %r|RUBY EXECUTABLE:.*#{Gem::ConfigMap[:RUBY_INSTALL_NAME]}|, assert_match %r|RUBY EXECUTABLE:.*#{Gem::ConfigMap[:ruby_install_name]}|,
@ui.output @ui.output
assert_match %r|EXECUTABLE DIRECTORY:|, @ui.output assert_match %r|EXECUTABLE DIRECTORY:|, @ui.output
assert_match %r|RUBYGEMS PLATFORMS:|, @ui.output assert_match %r|RUBYGEMS PLATFORMS:|, @ui.output

View file

@ -1,4 +1,3 @@
require 'minitest/unit'
require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities') require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities')
require 'rubygems/indexer' require 'rubygems/indexer'
require 'rubygems/commands/generate_index_command' require 'rubygems/commands/generate_index_command'
@ -28,5 +27,109 @@ class TestGemCommandsGenerateIndexCommand < RubyGemTestCase
assert File.exist?(quick_index_rz), quick_index_rz assert File.exist?(quick_index_rz), quick_index_rz
end end
def test_execute_rss_update
@cmd.options[:update] = true
@cmd.options[:rss_host] = 'example.com'
@cmd.options[:rss_gems_host] = 'gems.example.com'
use_ui @ui do
assert_raises MockGemUi::TermError do
@cmd.execute
end
end
assert_equal "ERROR: --update not compatible with RSS generation\n",
@ui.error
assert_empty @ui.output
end
def test_handle_options_directory
return if win_platform?
refute_equal '/nonexistent', @cmd.options[:directory]
@cmd.handle_options %w[--directory /nonexistent]
assert_equal '/nonexistent', @cmd.options[:directory]
end
def test_handle_options_directory_windows
return unless win_platform?
refute_equal '/nonexistent', @cmd.options[:directory]
@cmd.handle_options %w[--directory C:/nonexistent]
assert_equal 'C:/nonexistent', @cmd.options[:directory]
end
def test_handle_options_invalid
e = assert_raises OptionParser::InvalidOption do
@cmd.handle_options %w[--no-modern --no-legacy]
end
assert_equal 'invalid option: --no-legacy no indicies will be built',
e.message
@cmd = Gem::Commands::GenerateIndexCommand.new
e = assert_raises OptionParser::InvalidOption do
@cmd.handle_options %w[--no-legacy --no-modern]
end
assert_equal 'invalid option: --no-modern no indicies will be built',
e.message
end
def test_handle_options_legacy
@cmd.handle_options %w[--legacy]
assert @cmd.options[:build_legacy]
assert @cmd.options[:build_modern], ':build_modern not set'
end
def test_handle_options_modern
@cmd.handle_options %w[--modern]
assert @cmd.options[:build_legacy]
assert @cmd.options[:build_modern], ':build_modern not set'
end
def test_handle_options_no_legacy
@cmd.handle_options %w[--no-legacy]
refute @cmd.options[:build_legacy]
assert @cmd.options[:build_modern]
end
def test_handle_options_no_modern
@cmd.handle_options %w[--no-modern]
assert @cmd.options[:build_legacy]
refute @cmd.options[:build_modern]
end
def test_handle_options_rss_gems_host
@cmd.handle_options %w[--rss-gems-host gems.example.com]
assert_equal 'gems.example.com', @cmd.options[:rss_gems_host]
end
def test_handle_options_rss_host
@cmd.handle_options %w[--rss-host example.com]
assert_equal 'example.com', @cmd.options[:rss_host]
end
def test_handle_options_rss_title
@cmd.handle_options %w[--rss-title Example\ Gems]
assert_equal 'Example Gems', @cmd.options[:rss_title]
end
def test_handle_options_update
@cmd.handle_options %w[--update]
assert @cmd.options[:update]
end
end if ''.respond_to? :to_xs end if ''.respond_to? :to_xs

View file

@ -11,6 +11,52 @@ class TestGemCommandsInstallCommand < RubyGemTestCase
@cmd.options[:generate_ri] = false @cmd.options[:generate_ri] = false
end end
def test_execute_exclude_prerelease
util_setup_fake_fetcher(:prerelease)
util_setup_spec_fetcher @a2, @a2_pre
@fetcher.data["#{@gem_repo}gems/#{@a2.full_name}.gem"] =
read_binary(File.join(@gemhome, 'cache', "#{@a2.full_name}.gem"))
@fetcher.data["#{@gem_repo}gems/#{@a2_pre.full_name}.gem"] =
read_binary(File.join(@gemhome, 'cache', "#{@a2_pre.full_name}.gem"))
@cmd.options[:args] = [@a2.name]
use_ui @ui do
e = assert_raises Gem::SystemExitException do
@cmd.execute
end
assert_equal 0, e.exit_code, @ui.error
end
assert_match(/Successfully installed #{@a2.full_name}$/, @ui.output)
refute_match(/Successfully installed #{@a2_pre.full_name}$/, @ui.output)
end
def test_execute_explicit_version_includes_prerelease
util_setup_fake_fetcher(:prerelease)
util_setup_spec_fetcher @a2, @a2_pre
@fetcher.data["#{@gem_repo}gems/#{@a2.full_name}.gem"] =
read_binary(File.join(@gemhome, 'cache', "#{@a2.full_name}.gem"))
@fetcher.data["#{@gem_repo}gems/#{@a2_pre.full_name}.gem"] =
read_binary(File.join(@gemhome, 'cache', "#{@a2_pre.full_name}.gem"))
@cmd.handle_options [@a2_pre.name, '--version', @a2_pre.version.to_s]
assert @cmd.options[:prerelease]
assert @cmd.options[:version].satisfied_by?(@a2_pre.version)
use_ui @ui do
e = assert_raises Gem::SystemExitException do
@cmd.execute
end
assert_equal 0, e.exit_code, @ui.error
end
refute_match(/Successfully installed #{@a2.full_name}$/, @ui.output)
assert_match(/Successfully installed #{@a2_pre.full_name}$/, @ui.output)
end
def test_execute_include_dependencies def test_execute_include_dependencies
@cmd.options[:include_dependencies] = true @cmd.options[:include_dependencies] = true
@cmd.options[:args] = [] @cmd.options[:args] = []
@ -57,6 +103,34 @@ class TestGemCommandsInstallCommand < RubyGemTestCase
assert out.empty?, out.inspect assert out.empty?, out.inspect
end end
def test_no_user_install
skip 'skipped on MS Windows (chmod has no effect)' if win_platform?
util_setup_fake_fetcher
@cmd.options[:user_install] = false
FileUtils.mv File.join(@gemhome, 'cache', "#{@a2.full_name}.gem"),
File.join(@tempdir)
@cmd.options[:args] = [@a2.name]
use_ui @ui do
orig_dir = Dir.pwd
begin
File.chmod 0755, @userhome
File.chmod 0555, @gemhome
Dir.chdir @tempdir
assert_raises Gem::FilePermissionError do
@cmd.execute
end
ensure
Dir.chdir orig_dir
File.chmod 0755, @gemhome
end
end
end
def test_execute_local_missing def test_execute_local_missing
util_setup_fake_fetcher util_setup_fake_fetcher
@cmd.options[:domain] = :local @cmd.options[:domain] = :local
@ -100,6 +174,29 @@ class TestGemCommandsInstallCommand < RubyGemTestCase
@ui.error @ui.error
end end
def test_execute_prerelease
util_setup_fake_fetcher(:prerelease)
util_setup_spec_fetcher @a2, @a2_pre
@fetcher.data["#{@gem_repo}gems/#{@a2.full_name}.gem"] =
read_binary(File.join(@gemhome, 'cache', "#{@a2.full_name}.gem"))
@fetcher.data["#{@gem_repo}gems/#{@a2_pre.full_name}.gem"] =
read_binary(File.join(@gemhome, 'cache', "#{@a2_pre.full_name}.gem"))
@cmd.options[:prerelease] = true
@cmd.options[:args] = [@a2_pre.name]
use_ui @ui do
e = assert_raises Gem::SystemExitException do
@cmd.execute
end
assert_equal 0, e.exit_code, @ui.error
end
refute_match(/Successfully installed #{@a2.full_name}$/, @ui.output)
assert_match(/Successfully installed #{@a2_pre.full_name}$/, @ui.output)
end
def test_execute_remote def test_execute_remote
@cmd.options[:generate_rdoc] = true @cmd.options[:generate_rdoc] = true
@cmd.options[:generate_ri] = true @cmd.options[:generate_ri] = true
@ -112,17 +209,10 @@ class TestGemCommandsInstallCommand < RubyGemTestCase
@cmd.options[:args] = [@a2.name] @cmd.options[:args] = [@a2.name]
err = ""
class << err
alias write <<
end
use_ui @ui do use_ui @ui do
e = assert_raises Gem::SystemExitException do e = assert_raises Gem::SystemExitException do
stderr, $stderr = $stderr, err capture_io do
begin
@cmd.execute @cmd.execute
ensure
$stderr = stderr
end end
end end
assert_equal 0, e.exit_code assert_equal 0, e.exit_code
@ -136,7 +226,6 @@ class TestGemCommandsInstallCommand < RubyGemTestCase
assert_equal "Installing RDoc documentation for #{@a2.full_name}...", assert_equal "Installing RDoc documentation for #{@a2.full_name}...",
out.shift out.shift
assert out.empty?, out.inspect assert out.empty?, out.inspect
assert_match /^Updating class cache with \d+ classes/, err
end end
def test_execute_two def test_execute_two

View file

@ -35,7 +35,7 @@ class TestGemCommandsPristineCommand < RubyGemTestCase
assert_equal "Restoring gem(s) to pristine condition...", out.shift assert_equal "Restoring gem(s) to pristine condition...", out.shift
assert_equal "Restored #{a.full_name}", out.shift assert_equal "Restored #{a.full_name}", out.shift
assert out.empty?, out.inspect assert_empty out, out.inspect
end end
def test_execute_all def test_execute_all
@ -63,7 +63,7 @@ class TestGemCommandsPristineCommand < RubyGemTestCase
assert_equal "Restoring gem(s) to pristine condition...", out.shift assert_equal "Restoring gem(s) to pristine condition...", out.shift
assert_equal "Restored #{a.full_name}", out.shift assert_equal "Restored #{a.full_name}", out.shift
assert out.empty?, out.inspect assert_empty out, out.inspect
end end
def test_execute_missing_cache_gem def test_execute_missing_cache_gem
@ -86,7 +86,7 @@ class TestGemCommandsPristineCommand < RubyGemTestCase
out = @ui.output.split "\n" out = @ui.output.split "\n"
assert_equal "Restoring gem\(s\) to pristine condition...", out.shift assert_equal "Restoring gem\(s\) to pristine condition...", out.shift
assert out.empty?, out.inspect assert_empty out, out.inspect
assert_equal "ERROR: Cached gem for #{a.full_name} not found, use `gem install` to restore\n", assert_equal "ERROR: Cached gem for #{a.full_name} not found, use `gem install` to restore\n",
@ui.error @ui.error

View file

@ -10,7 +10,7 @@ class TestGemCommandsQueryCommand < RubyGemTestCase
util_setup_fake_fetcher util_setup_fake_fetcher
@si = util_setup_spec_fetcher @a1, @a2, @pl1 @si = util_setup_spec_fetcher @a1, @a2, @pl1, @a3a
@fetcher.data["#{@gem_repo}Marshal.#{Gem.marshal_version}"] = proc do @fetcher.data["#{@gem_repo}Marshal.#{Gem.marshal_version}"] = proc do
raise Gem::RemoteFetcher::FetchError raise Gem::RemoteFetcher::FetchError
@ -85,6 +85,51 @@ a (2)
This is a lot of text. This is a lot of text.
pl (1) pl (1)
Platform: i386-linux
Author: A User
Homepage: http://example.com
this is a summary
EOF
assert_equal expected, @ui.output
assert_equal '', @ui.error
end
def test_execute_details_platform
@a1.platform = 'x86-linux'
@a2.summary = 'This is a lot of text. ' * 4
@a2.authors = ['Abraham Lincoln', 'Hirohito']
@a2.homepage = 'http://a.example.com/'
@a2.rubyforge_project = 'rubygems'
@a2.platform = 'universal-darwin'
@si = util_setup_spec_fetcher @a1, @a2, @pl1
@cmd.handle_options %w[-r -d]
use_ui @ui do
@cmd.execute
end
expected = <<-EOF
*** REMOTE GEMS ***
a (2, 1)
Platforms:
1: x86-linux
2: universal-darwin
Authors: Abraham Lincoln, Hirohito
Rubyforge: http://rubyforge.org/projects/rubygems
Homepage: http://a.example.com/
This is a lot of text. This is a lot of text. This is a lot of text.
This is a lot of text.
pl (1)
Platform: i386-linux
Author: A User Author: A User
Homepage: http://example.com Homepage: http://example.com
@ -207,11 +252,30 @@ RubyGems will revert to legacy indexes degrading performance.
assert_equal expected, @ui.error assert_equal expected, @ui.error
end end
def test_execute_legacy_prerelease
Gem::SpecFetcher.fetcher = nil
si = util_setup_source_info_cache @a1, @a2, @pl1
@fetcher.data["#{@gem_repo}yaml"] = YAML.dump si
@fetcher.data["#{@gem_repo}Marshal.#{Gem.marshal_version}"] =
si.dump
@fetcher.data.delete "#{@gem_repo}latest_specs.#{Gem.marshal_version}.gz"
@cmd.handle_options %w[-r --prerelease]
e = assert_raises Gem::OperationNotSupportedError do
@cmd.execute
end
assert_equal 'Prereleases not supported on legacy repositories', e.message
end
def test_execute_local_details def test_execute_local_details
@a2.summary = 'This is a lot of text. ' * 4 @a3a.summary = 'This is a lot of text. ' * 4
@a2.authors = ['Abraham Lincoln', 'Hirohito'] @a3a.authors = ['Abraham Lincoln', 'Hirohito']
@a2.homepage = 'http://a.example.com/' @a3a.homepage = 'http://a.example.com/'
@a2.rubyforge_project = 'rubygems' @a3a.rubyforge_project = 'rubygems'
@cmd.handle_options %w[--local --details] @cmd.handle_options %w[--local --details]
@ -223,10 +287,11 @@ RubyGems will revert to legacy indexes degrading performance.
*** LOCAL GEMS *** *** LOCAL GEMS ***
a (2, 1) a (3.a, 2, 1)
Author: A User Author: A User
Homepage: http://example.com Homepage: http://example.com
Installed at (2): #{@gemhome} Installed at (3.a): #{@gemhome}
(2): #{@gemhome}
(1): #{@gemhome} (1): #{@gemhome}
this is a summary this is a summary
@ -253,6 +318,7 @@ c (1.2)
this is a summary this is a summary
pl (1) pl (1)
Platform: i386-linux
Author: A User Author: A User
Homepage: http://example.com Homepage: http://example.com
Installed at: #{@gemhome} Installed at: #{@gemhome}
@ -274,7 +340,7 @@ pl (1)
end end
expected = <<-EOF expected = <<-EOF
a (2, 1) a (3.a, 2, 1)
a_evil (9) a_evil (9)
b (2) b (2)
c (1.2) c (1.2)
@ -322,5 +388,45 @@ pl (1)
assert_equal '', @ui.error assert_equal '', @ui.error
end end
def test_execute_prerelease
@cmd.handle_options %w[-r --prerelease]
use_ui @ui do
@cmd.execute
end
expected = <<-EOF
*** REMOTE GEMS ***
a (3.a)
EOF
assert_equal expected, @ui.output
assert_equal '', @ui.error
end
def test_execute_prerelease_local
@cmd.handle_options %w[-l --prerelease]
use_ui @ui do
@cmd.execute
end
expected = <<-EOF
*** LOCAL GEMS ***
a (3.a, 2, 1)
a_evil (9)
b (2)
c (1.2)
pl (1)
EOF
assert_equal expected, @ui.output
assert_equal "WARNING: prereleases are always shown locally\n", @ui.error
end
end end

View file

@ -22,5 +22,31 @@ class TestGemCommandsServerCommand < RubyGemTestCase
assert_equal File.expand_path('/nonexistent'), @cmd.options[:gemdir] assert_equal File.expand_path('/nonexistent'), @cmd.options[:gemdir]
assert_equal 9999, @cmd.options[:port] assert_equal 9999, @cmd.options[:port]
end end
def test_handle_options_port
@cmd.send :handle_options, %w[-p 0]
assert_equal 0, @cmd.options[:port]
@cmd.send :handle_options, %w[-p 65535]
assert_equal 65535, @cmd.options[:port]
@cmd.send :handle_options, %w[-p http]
assert_equal 80, @cmd.options[:port]
e = assert_raises OptionParser::InvalidArgument do
@cmd.send :handle_options, %w[-p nonexistent]
end
assert_equal 'invalid argument: -p nonexistent: no such named service',
e.message
e = assert_raises OptionParser::InvalidArgument do
@cmd.send :handle_options, %w[-p 65536]
end
assert_equal 'invalid argument: -p 65536: not a port number',
e.message
end
end end

View file

@ -11,6 +11,10 @@ class TestGemCommandsSourcesCommand < RubyGemTestCase
@new_repo = "http://beta-gems.example.com" @new_repo = "http://beta-gems.example.com"
end end
def test_initialize_proxy
assert @cmd.handles?(['--http-proxy', 'http://proxy.example.com'])
end
def test_execute def test_execute
util_setup_spec_fetcher util_setup_spec_fetcher
@cmd.handle_options [] @cmd.handle_options []
@ -175,12 +179,12 @@ Will cause RubyGems to revert to legacy indexes, degrading performance.
assert_equal expected, @ui.output assert_equal expected, @ui.output
assert_equal '', @ui.error assert_equal '', @ui.error
assert !File.exist?(cache.system_cache_file), refute File.exist?(cache.system_cache_file),
'system cache file' 'system cache file'
assert !File.exist?(cache.latest_system_cache_file), refute File.exist?(cache.latest_system_cache_file),
'latest system cache file' 'latest system cache file'
assert !File.exist?(fetcher.dir), 'cache dir removed' refute File.exist?(fetcher.dir), 'cache dir removed'
end end
def test_execute_remove def test_execute_remove

View file

@ -70,6 +70,34 @@ class TestGemCommandsSpecificationCommand < RubyGemTestCase
assert_equal '', @ui.error assert_equal '', @ui.error
end end
def test_execute_field
foo = quick_gem 'foo'
Gem.source_index.add_spec foo
@cmd.options[:args] = %w[foo name]
use_ui @ui do
@cmd.execute
end
assert_equal "--- foo\n\n", @ui.output
end
def test_execute_marshal
foo = quick_gem 'foo'
Gem.source_index.add_spec foo
@cmd.options[:args] = %w[foo]
@cmd.options[:format] = :marshal
use_ui @ui do
@cmd.execute
end
assert_equal foo, Marshal.load(@ui.output)
assert_equal '', @ui.error
end
def test_execute_remote def test_execute_remote
foo = quick_gem 'foo' foo = quick_gem 'foo'
@ -92,5 +120,21 @@ class TestGemCommandsSpecificationCommand < RubyGemTestCase
assert_match %r|name: foo|, @ui.output assert_match %r|name: foo|, @ui.output
end end
def test_execute_ruby
foo = quick_gem 'foo'
Gem.source_index.add_spec foo
@cmd.options[:args] = %w[foo]
@cmd.options[:format] = :ruby
use_ui @ui do
@cmd.execute
end
assert_match %r|Gem::Specification.new|, @ui.output
assert_match %r|s.name = %q\{foo\}|, @ui.output
assert_equal '', @ui.error
end
end end

View file

@ -53,9 +53,10 @@ class TestGemCommandsUninstallCommand < GemInstallerTestCase
end end
end end
assert_match(/\AUnknown gem foo >= 0$/, e.message) assert_match(/\Acannot uninstall, check `gem list -d foo`$/, e.message)
output = @ui.output.split "\n" output = @ui.output.split "\n"
assert output.empty?, "UI output should be empty after an uninstall error" assert_empty output, "UI output should be empty after an uninstall error"
end end
end end

View file

@ -14,7 +14,7 @@ class TestGemCommandsUnpackCommand < RubyGemTestCase
def test_execute def test_execute
util_make_gems util_make_gems
@cmd.options[:args] = %w[a] @cmd.options[:args] = %w[a b]
use_ui @ui do use_ui @ui do
Dir.chdir @tempdir do Dir.chdir @tempdir do
@ -22,7 +22,8 @@ class TestGemCommandsUnpackCommand < RubyGemTestCase
end end
end end
assert File.exist?(File.join(@tempdir, 'a-2')) assert File.exist?(File.join(@tempdir, 'a-3.a')), 'a should be installed'
assert File.exist?(File.join(@tempdir, 'b-2')), 'b should be installed'
end end
def test_execute_gem_path def test_execute_gem_path
@ -43,7 +44,7 @@ class TestGemCommandsUnpackCommand < RubyGemTestCase
end end
end end
assert File.exist?(File.join(@tempdir, 'a-2')) assert File.exist?(File.join(@tempdir, 'a-3.a'))
end end
def test_execute_gem_path_missing def test_execute_gem_path_missing
@ -80,7 +81,7 @@ class TestGemCommandsUnpackCommand < RubyGemTestCase
end end
end end
assert File.exist?(File.join(@tempdir, target, 'a-2')) assert File.exist?(File.join(@tempdir, target, 'a-3.a'))
end end
def test_execute_exact_match def test_execute_exact_match

View file

@ -8,6 +8,9 @@ class TestGemCommandsUpdateCommand < RubyGemTestCase
@cmd = Gem::Commands::UpdateCommand.new @cmd = Gem::Commands::UpdateCommand.new
@cmd.options[:generate_rdoc] = false
@cmd.options[:generate_ri] = false
util_setup_fake_fetcher util_setup_fake_fetcher
@a1_path = File.join @gemhome, 'cache', "#{@a1.full_name}.gem" @a1_path = File.join @gemhome, 'cache', "#{@a1.full_name}.gem"
@ -27,6 +30,8 @@ class TestGemCommandsUpdateCommand < RubyGemTestCase
Gem::Installer.new(@a1_path).install Gem::Installer.new(@a1_path).install
@cmd.options[:args] = [] @cmd.options[:args] = []
@cmd.options[:generate_rdoc] = true
@cmd.options[:generate_ri] = true
use_ui @ui do use_ui @ui do
@cmd.execute @cmd.execute
@ -37,8 +42,10 @@ class TestGemCommandsUpdateCommand < RubyGemTestCase
assert_equal "Updating #{@a2.name}", out.shift assert_equal "Updating #{@a2.name}", out.shift
assert_equal "Successfully installed #{@a2.full_name}", out.shift assert_equal "Successfully installed #{@a2.full_name}", out.shift
assert_equal "Gems updated: #{@a2.name}", out.shift assert_equal "Gems updated: #{@a2.name}", out.shift
assert_equal "Installing ri documentation for a-2...", out.shift
assert_equal "Installing RDoc documentation for a-2...", out.shift
assert out.empty?, out.inspect assert_empty out
end end
# before: # before:
@ -101,7 +108,7 @@ class TestGemCommandsUpdateCommand < RubyGemTestCase
assert_equal "Gems updated: #{@c2.name}, #{@b2.name}, #{@a2.name}", assert_equal "Gems updated: #{@c2.name}, #{@b2.name}, #{@a2.name}",
out.shift out.shift
assert out.empty?, out.inspect assert_empty out
end end
def test_execute_named def test_execute_named
@ -121,7 +128,7 @@ class TestGemCommandsUpdateCommand < RubyGemTestCase
assert_equal "Successfully installed #{@a2.full_name}", out.shift assert_equal "Successfully installed #{@a2.full_name}", out.shift
assert_equal "Gems updated: #{@a2.name}", out.shift assert_equal "Gems updated: #{@a2.name}", out.shift
assert out.empty?, out.inspect assert_empty out
end end
def test_execute_named_up_to_date def test_execute_named_up_to_date
@ -139,7 +146,7 @@ class TestGemCommandsUpdateCommand < RubyGemTestCase
assert_equal "Updating installed gems", out.shift assert_equal "Updating installed gems", out.shift
assert_equal "Nothing to update", out.shift assert_equal "Nothing to update", out.shift
assert out.empty?, out.inspect assert_empty out
end end
def test_execute_up_to_date def test_execute_up_to_date
@ -157,8 +164,6 @@ class TestGemCommandsUpdateCommand < RubyGemTestCase
assert_equal "Updating installed gems", out.shift assert_equal "Updating installed gems", out.shift
assert_equal "Nothing to update", out.shift assert_equal "Nothing to update", out.shift
assert out.empty?, out.inspect assert_empty out
end end
end end

View file

@ -20,6 +20,10 @@ class TestGemDependency < RubyGemTestCase
@r1_0 = Gem::Requirement.new ['> 1.0'] @r1_0 = Gem::Requirement.new ['> 1.0']
end end
def dep(name, version)
Gem::Dependency.new name, version
end
def test_initialize def test_initialize
assert_equal "pkg", @pkg1_0.name assert_equal "pkg", @pkg1_0.name
assert_equal @r1_0, @pkg1_0.version_requirements assert_equal @r1_0, @pkg1_0.version_requirements
@ -96,10 +100,6 @@ class TestGemDependency < RubyGemTestCase
end end
def test_equals_tilde def test_equals_tilde
def dep(name, version)
Gem::Dependency.new name, version
end
a0 = dep 'a', '0' a0 = dep 'a', '0'
a1 = dep 'a', '1' a1 = dep 'a', '1'
b0 = dep 'b', '0' b0 = dep 'b', '0'
@ -108,14 +108,64 @@ class TestGemDependency < RubyGemTestCase
pa0r = dep(/a/, '>= 0') pa0r = dep(/a/, '>= 0')
pab0r = dep(/a|b/, '>= 0') pab0r = dep(/a|b/, '>= 0')
assert((a0 =~ a0), 'match self') assert_match a0, a0, 'match self'
assert((pa0 =~ a0), 'match version exact') assert_match pa0, a0, 'match version exact'
assert((pa0 =~ a1), 'match version') assert_match pa0, a1, 'match version'
assert((pa0r =~ a0), 'match regex simple') assert_match pa0r, a0, 'match regex simple'
assert((pab0r =~ a0), 'match regex complex') assert_match pab0r, a0, 'match regex complex'
assert(!(pa0r =~ b0), 'fail match regex') refute_match pa0r, b0, 'fail match regex'
assert(!(pa0r =~ Object.new), 'fail match Object') refute_match pa0r, Object.new, 'fail match Object'
end
def test_equals_tilde_escape
a1 = Gem::Dependency.new 'a', '1'
pab1 = Gem::Dependency.new 'a|b', '>= 1'
pab1r = Gem::Dependency.new(/a|b/, '>= 1')
refute_match pab1, a1, 'escaped'
assert_match pab1r, a1, 'exact regexp'
end
def test_equals_tilde_object
a0 = Object.new
def a0.name() 'a' end
def a0.version() '0' end
pa0 = Gem::Dependency.new 'a', '>= 0'
assert_match pa0, a0, 'match version exact'
end
def test_equals_tilde_spec
def spec(name, version)
Gem::Specification.new do |spec|
spec.name = name
spec.version = version
end
end
a0 = spec 'a', '0'
a1 = spec 'a', '1'
b0 = spec 'b', '0'
pa0 = dep 'a', '>= 0'
pa0r = dep(/a/, '>= 0')
pab0r = dep(/a|b/, '>= 0')
assert_match pa0, a0, 'match version exact'
assert_match pa0, a1, 'match version'
assert_match pa0r, a0, 'match regex simple'
assert_match pa0r, a1, 'match regex simple'
assert_match pab0r, a0, 'match regex complex'
assert_match pab0r, b0, 'match regex complex'
refute_match pa0r, b0, 'fail match regex'
refute_match pa0r, Object.new, 'fail match Object'
end end
def test_hash def test_hash
@ -135,5 +185,6 @@ class TestGemDependency < RubyGemTestCase
refute_equal(runtime.hash, development.hash) refute_equal(runtime.hash, development.hash)
end end
end end

View file

@ -13,8 +13,10 @@ class TestGemDependencyInstaller < RubyGemTestCase
write_file File.join('gems', 'a-1', 'bin', 'a_bin') do |fp| write_file File.join('gems', 'a-1', 'bin', 'a_bin') do |fp|
fp.puts "#!/usr/bin/ruby" fp.puts "#!/usr/bin/ruby"
end end
@a1, @a1_gem = util_gem 'a', '1' do |s| s.executables << 'a_bin' end @a1, @a1_gem = util_gem 'a', '1' do |s| s.executables << 'a_bin' end
@aa1, @aa1_gem = util_gem 'aa', '1' @aa1, @aa1_gem = util_gem 'aa', '1'
@a1_pre, @a1_pre_gem = util_gem 'a', '1.a'
@b1, @b1_gem = util_gem 'b', '1' do |s| @b1, @b1_gem = util_gem 'b', '1' do |s|
s.add_dependency 'a' s.add_dependency 'a'
@ -44,8 +46,8 @@ class TestGemDependencyInstaller < RubyGemTestCase
@fetcher = Gem::FakeFetcher.new @fetcher = Gem::FakeFetcher.new
Gem::RemoteFetcher.fetcher = @fetcher Gem::RemoteFetcher.fetcher = @fetcher
si = util_setup_spec_fetcher @a1, @b1, @d1, @d2, @x1_m, @x1_o, @w1, @y1, si = util_setup_spec_fetcher(@a1, @a1_pre, @b1, @d1, @d2, @x1_m, @x1_o, @w1, @y1,
@y1_1_p, @z1 @y1_1_p, @z1)
util_clear_gems util_clear_gems
end end
@ -257,7 +259,7 @@ class TestGemDependencyInstaller < RubyGemTestCase
inst.install 'a' inst.install 'a'
end end
assert_match %r|\A#!/\S+/env #{Gem::ConfigMap[:RUBY_INSTALL_NAME]}\n|, assert_match %r|\A#!/\S+/env #{Gem::ConfigMap[:ruby_install_name]}\n|,
File.read(File.join(@gemhome, 'bin', 'a_bin')) File.read(File.join(@gemhome, 'bin', 'a_bin'))
end end
@ -356,13 +358,15 @@ class TestGemDependencyInstaller < RubyGemTestCase
FileUtils.mv @b1_gem, @tempdir FileUtils.mv @b1_gem, @tempdir
inst = nil inst = nil
Gem.source_index.gems.delete @a1.full_name Gem.source_index.remove_spec @a1.full_name
Gem.source_index.remove_spec @a1_pre.full_name
Dir.chdir @tempdir do Dir.chdir @tempdir do
e = assert_raises Gem::InstallError do e = assert_raises Gem::InstallError do
inst = Gem::DependencyInstaller.new :domain => :local inst = Gem::DependencyInstaller.new :domain => :local
inst.install 'b' inst.install 'b'
end end
assert_equal 'b requires a (>= 0, runtime)', e.message assert_equal 'b requires a (>= 0, runtime)', e.message
end end
@ -632,5 +636,16 @@ class TestGemDependencyInstaller < RubyGemTestCase
assert_equal %w[d-1 e-1], inst.gems_to_install.map { |s| s.full_name } assert_equal %w[d-1 e-1], inst.gems_to_install.map { |s| s.full_name }
end end
end def test_prerelease_uses_pre_index
installer = Gem::DependencyInstaller.new
pre_installer = Gem::DependencyInstaller.new(:prerelease => true)
dependency = Gem::Dependency.new('a', Gem::Requirement.default)
releases = installer.find_gems_with_sources(dependency).map{ |gems, *| gems }
prereleases = pre_installer.find_gems_with_sources(dependency).map{ |gems, *| gems }
assert releases.select{ |s| s.name == 'a' and s.version.to_s == '1' }.first
assert releases.select{ |s| s.name == 'a' and s.version.to_s == '1.a' }.empty?
assert_equal [@a1_pre], prereleases
end
end

View file

@ -105,7 +105,7 @@ class TestGemDependencyList < RubyGemTestCase
@deplist.add @b2 @deplist.add @b2
assert ! @deplist.ok?, 'unsatisfied dependency' refute @deplist.ok?, 'unsatisfied dependency'
@deplist.add @a1 @deplist.add @a1
@ -144,7 +144,7 @@ class TestGemDependencyList < RubyGemTestCase
@deplist.add @b2 @deplist.add @b2
assert ! @deplist.ok_to_remove?("a-1") refute @deplist.ok_to_remove?("a-1")
@deplist.add @a2 @deplist.add @a2
@ -161,7 +161,7 @@ class TestGemDependencyList < RubyGemTestCase
@deplist.remove_by_name("a-1") @deplist.remove_by_name("a-1")
assert ! @deplist.ok_to_remove?("a-2") refute @deplist.ok_to_remove?("a-2")
end end
def test_remove_by_name def test_remove_by_name
@ -169,7 +169,7 @@ class TestGemDependencyList < RubyGemTestCase
@deplist.remove_by_name "a-1" @deplist.remove_by_name "a-1"
assert ! @deplist.ok? refute @deplist.ok?
end end
def test_tsort_each_node def test_tsort_each_node
@ -181,7 +181,7 @@ class TestGemDependencyList < RubyGemTestCase
assert_equal order.shift, node.full_name assert_equal order.shift, node.full_name
end end
assert order.empty? assert_empty order
end end
def test_tsort_each_child def test_tsort_each_child
@ -193,7 +193,7 @@ class TestGemDependencyList < RubyGemTestCase
assert_equal order.shift, node.full_name assert_equal order.shift, node.full_name
end end
assert order.empty? assert_empty order
end end
# d1 -> b1 -> a1 # d1 -> b1 -> a1

View file

@ -18,7 +18,13 @@ class TestGemDocManager < RubyGemTestCase
def test_uninstall_doc_unwritable def test_uninstall_doc_unwritable
orig_mode = File.stat(@spec.installation_path).mode orig_mode = File.stat(@spec.installation_path).mode
File.chmod 0, @spec.installation_path
# File.chmod has no effect on MS Windows directories (it needs ACL).
if win_platform?
skip("test_uninstall_doc_unwritable skipped on MS Windows")
else
File.chmod(0, @spec.installation_path)
end
assert_raises Gem::FilePermissionError do assert_raises Gem::FilePermissionError do
@manager.uninstall_doc @manager.uninstall_doc

View file

@ -16,7 +16,7 @@ class TestGemExtConfigureBuilder < RubyGemTestCase
end end
def test_self_build def test_self_build
return if RUBY_PLATFORM =~ /mswin/ # HACK skip("test_self_build skipped on MS Windows (VC++)") if vc_windows?
File.open File.join(@ext, './configure'), 'w' do |configure| File.open File.join(@ext, './configure'), 'w' do |configure|
configure.puts "#!/bin/sh\necho \"#{@makefile_body}\" > Makefile" configure.puts "#!/bin/sh\necho \"#{@makefile_body}\" > Makefile"
@ -37,7 +37,7 @@ class TestGemExtConfigureBuilder < RubyGemTestCase
end end
def test_self_build_fail def test_self_build_fail
return if RUBY_PLATFORM =~ /mswin/ # HACK skip("test_self_build_fail skipped on MS Windows (VC++)") if vc_windows?
output = [] output = []
error = assert_raises Gem::InstallError do error = assert_raises Gem::InstallError do
@ -63,6 +63,10 @@ class TestGemExtConfigureBuilder < RubyGemTestCase
end end
def test_self_build_has_makefile def test_self_build_has_makefile
if vc_windows? && !nmake_found?
skip("test_self_build_has_makefile skipped - nmake not found")
end
File.open File.join(@ext, 'Makefile'), 'w' do |makefile| File.open File.join(@ext, 'Makefile'), 'w' do |makefile|
makefile.puts @makefile_body makefile.puts @makefile_body
end end
@ -72,14 +76,8 @@ class TestGemExtConfigureBuilder < RubyGemTestCase
Gem::Ext::ConfigureBuilder.build nil, nil, @dest_path, output Gem::Ext::ConfigureBuilder.build nil, nil, @dest_path, output
end end
case RUBY_PLATFORM assert_equal make_command, output[0]
when /mswin/ then assert_equal "#{make_command} install", output[2]
assert_equal 'nmake', output[0]
assert_equal 'nmake install', output[2]
else
assert_equal 'make', output[0]
assert_equal 'make install', output[2]
end
end end
end end

View file

@ -14,6 +14,10 @@ class TestGemExtExtConfBuilder < RubyGemTestCase
end end
def test_class_build def test_class_build
if vc_windows? && !nmake_found?
skip("test_class_build skipped - nmake not found")
end
File.open File.join(@ext, 'extconf.rb'), 'w' do |extconf| File.open File.join(@ext, 'extconf.rb'), 'w' do |extconf|
extconf.puts "require 'mkmf'\ncreate_makefile 'foo'" extconf.puts "require 'mkmf'\ncreate_makefile 'foo'"
end end
@ -46,6 +50,10 @@ class TestGemExtExtConfBuilder < RubyGemTestCase
end end
def test_class_build_extconf_fail def test_class_build_extconf_fail
if vc_windows? && !nmake_found?
skip("test_class_build_extconf_fail skipped - nmake not found")
end
File.open File.join(@ext, 'extconf.rb'), 'w' do |extconf| File.open File.join(@ext, 'extconf.rb'), 'w' do |extconf|
extconf.puts "require 'mkmf'" extconf.puts "require 'mkmf'"
extconf.puts "have_library 'nonexistent' or abort 'need libnonexistent'" extconf.puts "have_library 'nonexistent' or abort 'need libnonexistent'"
@ -69,6 +77,10 @@ checking for main\(\) in .*?nonexistent/m, error.message)
end end
def test_class_make def test_class_make
if vc_windows? && !nmake_found?
skip("test_class_make skipped - nmake not found")
end
output = [] output = []
makefile_path = File.join(@ext, 'Makefile') makefile_path = File.join(@ext, 'Makefile')
File.open makefile_path, 'w' do |makefile| File.open makefile_path, 'w' do |makefile|
@ -82,14 +94,8 @@ checking for main\(\) in .*?nonexistent/m, error.message)
Gem::Ext::ExtConfBuilder.make @ext, output Gem::Ext::ExtConfBuilder.make @ext, output
end end
case RUBY_PLATFORM assert_equal make_command, output[0]
when /mswin/ then assert_equal "#{make_command} install", output[2]
assert_equal 'nmake', output[0]
assert_equal 'nmake install', output[2]
else
assert_equal 'make', output[0]
assert_equal 'make install', output[2]
end
edited_makefile = <<-EOF edited_makefile = <<-EOF
RUBYARCHDIR = #{@ext}$(target_prefix) RUBYARCHDIR = #{@ext}$(target_prefix)

View file

@ -21,7 +21,7 @@ class TestGemFormat < RubyGemTestCase
gems = Dir[File.join(@gemhome, 'cache', '*.gem')] gems = Dir[File.join(@gemhome, 'cache', '*.gem')]
names = [@a1, @a2, @a_evil9, @b2, @c1_2, @pl1].map do |spec| names = [@a1, @a2, @a3a, @a_evil9, @b2, @c1_2, @pl1].map do |spec|
spec.original_name spec.original_name
end end

Some files were not shown because too many files have changed in this diff Show more