From 31c94ffeb5f09d09ac2c86fc9e6614e38251a43d Mon Sep 17 00:00:00 2001 From: drbrain Date: Tue, 9 Jun 2009 21:38:59 +0000 Subject: Update to RubyGems 1.3.4 r2223 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@23659 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- lib/rubygems.rb | 334 +++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 293 insertions(+), 41 deletions(-) (limited to 'lib/rubygems.rb') diff --git a/lib/rubygems.rb b/lib/rubygems.rb index 3be98d3c56..a4ce9b0a80 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -8,11 +8,29 @@ require 'rubygems/rubygems_version' require 'rubygems/defaults' require 'thread' +require 'etc' 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 - attr_accessor :name, :version_requirement + + ## + # Name of gem + + attr_accessor :name + + ## + # Version requirement of gem + + attr_accessor :version_requirement + end + end module Kernel @@ -54,18 +72,102 @@ module Kernel 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: +# +# * gem help and gem help [command] +# * {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 +# gem server) +# * {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 + ## + # Configuration settings from ::RbConfig + ConfigMap = {} unless defined?(ConfigMap) + require 'rbconfig' - RbConfig = Config unless defined? ::RbConfig ConfigMap.merge!( - :BASERUBY => RbConfig::CONFIG["BASERUBY"], :EXEEXT => RbConfig::CONFIG["EXEEXT"], - :RUBY_INSTALL_NAME => RbConfig::CONFIG["RUBY_INSTALL_NAME"], :RUBY_SO_NAME => RbConfig::CONFIG["RUBY_SO_NAME"], :arch => RbConfig::CONFIG["arch"], :bindir => RbConfig::CONFIG["bindir"], @@ -79,11 +181,16 @@ module Gem :vendorlibdir => RbConfig::CONFIG["vendorlibdir"] ) + ## + # Default directories in a gem repository + DIRECTORIES = %w[cache doc gems specifications] unless defined?(DIRECTORIES) + # :stopdoc: MUTEX = Mutex.new RubyGemsPackageVersion = RubyGemsVersion + # :startdoc: ## # An Array of Regexps that match windows ruby platforms. @@ -102,6 +209,7 @@ module Gem @configuration = nil @loaded_specs = {} + @loaded_stacks = {} @platforms = [] @ruby = nil @sources = [] @@ -128,6 +236,14 @@ module Gem # Gem::Requirement and Gem::Version documentation. 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 version_requirements = Gem::Requirement.default end @@ -146,8 +262,18 @@ module Gem existing_spec = @loaded_specs[gem.name] unless matches.any? { |spec| spec.version == existing_spec.version } then - raise Gem::Exception, - "can't activate #{gem}, already activated #{existing_spec.full_name}" + sources_message = sources.map { |spec| 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 return false @@ -159,10 +285,11 @@ module Gem spec.loaded = true @loaded_specs[spec.name] = spec + @loaded_stacks[spec.name] = sources.dup # Load dependent gems first spec.runtime_dependencies.each do |dep_gem| - activate dep_gem + activate dep_gem, :sources => [spec, *sources] end # bin directory must come before library directories @@ -227,6 +354,35 @@ module Gem !Gem.source_index.search(gem).empty? 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. @@ -351,14 +507,27 @@ module Gem # # 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) + 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.map do |spec| + specs_files = specs.map do |spec| searcher.matching_files spec, path end.flatten + + (load_path_files + specs_files).flatten.uniq end ## @@ -373,7 +542,17 @@ module Gem # least on Win32). 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 if File::ALT_SEPARATOR then "C:/" @@ -477,22 +656,13 @@ module Gem # The file name and line number of the caller of the caller of this method. def self.location_of_caller - caller[1] =~ /(.*?):(\d+)$/i + caller[1] =~ /(.*?):(\d+).*?$/i file = $1 lineno = $2.to_i [file, lineno] 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. @@ -586,6 +756,33 @@ module Gem 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. @@ -628,15 +825,23 @@ module Gem private_class_method :report_activate_error - def self.required_location(gemname, libfile, *version_constraints) - version_constraints = Gem::Requirement.default if version_constraints.empty? - matches = Gem.source_index.find_name(gemname, version_constraints) + ## + # Full path to +libfile+ in +gemname+. Searches for the latest gem unless + # +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? + spec = matches.last spec.require_paths.each do |path| - result = File.join(spec.full_gem_path, path, libfile) - return result if File.exist?(result) + result = File.join spec.full_gem_path, path, libfile + return result if File.exist? result end + nil end @@ -662,7 +867,13 @@ module Gem def self.ruby_version return @ruby_version if defined? @ruby_version 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 end @@ -679,7 +890,7 @@ module Gem # Set the Gem home directory (as reported by Gem.dir). 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 end @@ -756,6 +967,31 @@ module Gem ['', '.rb', '.rbw', '.so', '.bundle', '.dll', '.sl', '.jar'] 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 # by the unit tests to provide environment isolation. @@ -786,6 +1022,9 @@ module Gem class << self + ## + # Hash of loaded Gem::Specification keyed by name + attr_reader :loaded_specs ## @@ -817,25 +1056,27 @@ module Gem end + ## + # Location of Marshal quick gemspecs on remote repositories + MARSHAL_SPEC_DIR = "quick/Marshal.#{Gem.marshal_version}/" + ## + # Location of legacy YAML quick gemspecs on remote repositories + YAML_SPEC_DIR = 'quick/' end -module RbConfig - # :stopdoc: - class << self - # Return the path to the data directory associated with the named - # package. If the package is loaded as a gem, return the gem - # specific data directory. Otherwise return a path to the share - # area as define by "#{ConfigMap[:datadir]}/#{package_name}". - def datadir(package_name) - Gem.datadir(package_name) || - File.join(Gem::ConfigMap[:datadir], package_name) - end - end - # :startdoc: +## +# Return the path to the data directory associated with the named package. If +# the package is loaded as a gem, return the gem specific data directory. +# Otherwise return a path to the share area as define by +# "#{ConfigMap[:datadir]}/#{package_name}". + +def RbConfig.datadir(package_name) + Gem.datadir(package_name) || + File.join(Gem::ConfigMap[:datadir], package_name) end require 'rubygems/exceptions' @@ -866,3 +1107,14 @@ if RUBY_VERSION < '1.9' then end 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 + -- cgit v1.2.3