* lib/rubygems*: Updated to RubyGems 2.0

* test/rubygems*:  ditto.

* common.mk (prelude):  Updated for RubyGems 2.0 source rearrangement.

* tool/change_maker.rb:  Allow invalid UTF-8 characters in source
  files.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37976 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
drbrain 2012-11-29 06:52:18 +00:00
Родитель 3f606b7063
Коммит 9694bb8cac
214 изменённых файлов: 14049 добавлений и 7085 удалений

Просмотреть файл

@ -1,3 +1,13 @@
Thu Nov 29 15:51:54 2012 Eric Hodel <drbrain@segment7.net>
* lib/rubygems*: Updated to RubyGems 2.0
* test/rubygems*: ditto.
* common.mk (prelude): Updated for RubyGems 2.0 source rearrangement.
* tool/change_maker.rb: Allow invalid UTF-8 characters in source
files.
Thu Nov 29 15:38:14 2012 Koichi Sasada <ko1@atdot.net>
* include/ruby/debug.h: provide rb_tracearg_*() APIs,

Просмотреть файл

@ -887,7 +887,8 @@ $(MINIPRELUDE_C): $(srcdir)/tool/compile_prelude.rb $(srcdir)/prelude.rb
$(Q) $(BASERUBY) -I$(srcdir) $(srcdir)/tool/compile_prelude.rb $(srcdir)/prelude.rb $@
prelude.c: $(srcdir)/tool/compile_prelude.rb $(RBCONFIG) \
$(srcdir)/lib/rubygems/defaults.rb $(srcdir)/lib/rubygems/custom_require.rb \
$(srcdir)/lib/rubygems/defaults.rb \
$(srcdir)/lib/rubygems/core_ext/kernel_gem.rb \
$(PRELUDE_SCRIPTS) $(PREP)
$(ECHO) generating $@
$(Q) $(COMPILE_PRELUDE) $(PRELUDE_SCRIPTS) $@

Просмотреть файл

@ -5,32 +5,6 @@
# See LICENSE.txt for permissions.
#++
module Gem
QUICKLOADER_SUCKAGE = RUBY_VERSION =~ /^1\.9\.1/
# Only MRI 1.9.2 has the custom prelude.
GEM_PRELUDE_SUCKAGE = RUBY_VERSION =~ /^1\.9\.2/ && RUBY_ENGINE == "ruby"
end
if Gem::GEM_PRELUDE_SUCKAGE and defined?(Gem::QuickLoader) then
Gem::QuickLoader.remove
$LOADED_FEATURES.delete Gem::QuickLoader.path_to_full_rubygems_library
if $LOADED_FEATURES.any? do |path| path.end_with? '/rubygems.rb' end then
# TODO path does not exist here
raise LoadError, "another rubygems is already loaded from #{path}"
end
class << Gem
remove_method :try_activate if Gem.respond_to?(:try_activate, true)
end
end
require 'rubygems/defaults'
require 'rbconfig'
require "rubygems/deprecate"
##
# RubyGems is the Ruby standard for publishing and managing third party
# libraries.
@ -72,8 +46,8 @@ require "rubygems/deprecate"
# 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.
# For Ruby implementers, provide lib/rubygems/defaults/#{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.
@ -83,8 +57,8 @@ require "rubygems/deprecate"
# == Bugs
#
# You can submit bugs to the
# {RubyGems bug tracker}[http://rubyforge.org/tracker/?atid=575&group_id=126]
# on RubyForge
# {RubyGems bug tracker}[https://github.com/rubygems/rubygems/issues]
# on GitHub
#
# == Credits
#
@ -112,7 +86,8 @@ require "rubygems/deprecate"
# * Daniel Berger -- djberg96(at)gmail.com
# * Phil Hagelberg -- technomancy(at)gmail.com
# * Ryan Davis -- ryand-ruby(at)zenspider.com
# * Evan Phoenix -- evan@phx.io
# * Evan Phoenix -- evan(at)fallingsnow.net
# * Steve Klabnik -- steve(at)steveklabnik.com
#
# (If your name is missing, PLEASE let us know!)
#
@ -120,49 +95,22 @@ require "rubygems/deprecate"
#
# -The RubyGems Team
require 'rbconfig'
module Gem
VERSION = '1.8.24'
VERSION = '2.0.a'
end
##
# 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.
# Must be first since it unloads the prelude from 1.9.2
require 'rubygems/compatibility'
class LoadError < ::LoadError
# Name of gem
attr_accessor :name
# Version requirement of gem
attr_accessor :requirement
end
# :stopdoc:
RubyGemsVersion = VERSION
RbConfigPriorities = %w[
EXEEXT RUBY_SO_NAME arch bindir datadir libdir ruby_install_name
ruby_version rubylibprefix sitedir sitelibdir vendordir vendorlibdir
]
unless defined?(ConfigMap)
##
# Configuration settings from ::RbConfig
ConfigMap = Hash.new do |cm, key|
cm[key] = RbConfig::CONFIG[key.to_s]
end
else
RbConfigPriorities.each do |key|
ConfigMap[key.to_sym] = RbConfig::CONFIG[key]
end
end
RubyGemsPackageVersion = VERSION
require 'rubygems/defaults'
require 'rubygems/deprecate'
require 'rubygems/errors'
module Gem
RUBYGEMS_DIR = File.dirname File.expand_path(__FILE__)
# :startdoc:
##
# An Array of Regexps that match windows ruby platforms.
@ -175,11 +123,13 @@ module Gem
/wince/i,
]
@@source_index = nil
GEM_DEP_FILES = %w!gem.deps.rb Gemfile Isolate!
@@win_platform = nil
@configuration = nil
@loaded_specs = {}
@path_to_default_spec_map = {}
@platforms = []
@ruby = nil
@sources = nil
@ -198,12 +148,13 @@ module Gem
# activated. Returns false if it can't find the path in a gem.
def self.try_activate path
# TODO: deprecate when 1.9.3 comes out.
# finds the _latest_ version... regardless of loaded specs and their deps
# if another gem had a requirement that would mean we shouldn't
# activate the latest version, then either it would alreaby be activated
# or if it was ambigious (and thus unresolved) the code in our custom
# require will try to activate the more specific version.
# TODO: use find_all and bork if ambiguous
spec = Gem::Specification.find_by_path path
spec = Gem::Specification.find_inactive_by_path path
return false unless spec
begin
@ -215,77 +166,43 @@ module Gem
return true
end
##
# Activates an installed gem matching +dep+. The gem must satisfy
# +requirements+.
#
# Returns true if the gem is activated, false if it is already
# loaded, or an exception otherwise.
#
# Gem#activate adds the library paths in +dep+ to $LOAD_PATH. Before a Gem
# is activated its required Gems are activated. If the version information
# is omitted, the highest version Gem of the supplied name is loaded. If a
# Gem is not found that meets the version requirements or a required Gem is
# not found, a Gem::LoadError is raised.
#
# More information on version requirements can be found in the
# Gem::Requirement and Gem::Version documentation.
def self.needs
rs = Gem::RequestSet.new
def self.activate(dep, *requirements)
raise ArgumentError, "Deprecated use of Gem.activate(dep)" if
Gem::Dependency === dep
yield rs
Gem::Specification.find_by_name(dep, *requirements).activate
finish_resolve rs
end
def self.activate_dep dep, *requirements # :nodoc:
dep.to_spec.activate
def self.finish_resolve(request_set=Gem::RequestSet.new)
request_set.import Gem::Specification.unresolved_deps.values
request_set.resolve_current.each do |s|
s.full_spec.activate
end
end
def self.activate_spec spec # :nodoc:
spec.activate
end
def self.detect_gemdeps
if path = ENV['RUBYGEMS_GEMDEPS']
path = path.dup.untaint
def self.unresolved_deps
@unresolved_deps ||= Hash.new { |h, n| h[n] = Gem::Dependency.new n }
end
if path == "-"
path = GEM_DEP_FILES.find { |f| File.exists?(f) }
##
# An Array of all possible load paths for all versions of all gems in the
# Gem installation.
return unless path
end
def self.all_load_paths
result = []
return unless File.exists? path
Gem.path.each do |gemdir|
each_load_path all_partials(gemdir) do |load_path|
result << load_path
rs = Gem::RequestSet.new
rs.load_gemdeps path
rs.resolve_current.map do |s|
sp = s.full_spec
sp.activate
sp
end
end
result
end
##
# Return all the partial paths in +gemdir+.
def self.all_partials(gemdir)
Dir[File.join(gemdir, "gems/*")]
end
private_class_method :all_partials
##
# See if a given gem is available.
def self.available?(dep, *requirements)
requirements = Gem::Requirement.default if requirements.empty?
unless dep.respond_to?(:name) and dep.respond_to?(:requirement) then
dep = Gem::Dependency.new dep, requirements
end
not dep.matching_specs(true).empty?
end
##
@ -343,11 +260,10 @@ module Gem
# mainly used by the unit tests to provide test isolation.
def self.clear_paths
@@source_index = nil
@paths = nil
@user_home = nil
@searcher = nil
Gem::Specification.reset
Gem::Security.reset if const_defined? :Security
end
##
@ -377,7 +293,8 @@ module Gem
# package is not available as a gem, return nil.
def self.datadir(gem_name)
# TODO: deprecate
# TODO: deprecate and move to Gem::Specification
# and drop the extra ", gem_name" which is uselessly redundant
spec = @loaded_specs[gem_name]
return nil if spec.nil?
File.join spec.full_gem_path, "data", gem_name
@ -391,10 +308,12 @@ module Gem
Zlib::Deflate.deflate data
end
# DOC: needs doc'd or :nodoc'd
def self.paths
@paths ||= Gem::PathSupport.new
end
# DOC: needs doc'd or :nodoc'd
def self.paths=(env)
clear_paths
@paths = Gem::PathSupport.new env
@ -450,7 +369,7 @@ module Gem
require 'fileutils'
%w[cache doc gems specifications].each do |name|
%w[cache build_info doc gems specifications].each do |name|
subdir = File.join dir, name
next if File.exist? subdir
FileUtils.mkdir_p subdir rescue nil # in case of perms issues -- lame
@ -566,13 +485,28 @@ module Gem
Zlib::Inflate.inflate data
end
##
# Top level install helper method. Allows you to install gems interactively:
#
# % irb
# >> Gem.install "minitest"
# Fetching: minitest-3.0.1.gem (100%)
# => [#<Gem::Specification:0x1013b4528 @name="minitest", ...>]
def self.install name, version = Gem::Requirement.default
require "rubygems/dependency_installer"
inst = Gem::DependencyInstaller.new
inst.install name, version
inst.installed_gems
end
##
# Get the default RubyGems API host. This is normally
# <tt>https://rubygems.org</tt>.
def self.host
# TODO: move to utils
@host ||= "https://rubygems.org"
@host ||= Gem::DEFAULT_HOST
end
## Set the default RubyGems API host.
@ -582,43 +516,6 @@ module Gem
@host = host
end
##
# Return a list of all possible load paths for the latest version for all
# gems in the Gem installation.
def self.latest_load_paths
result = []
Gem.path.each do |gemdir|
each_load_path(latest_partials(gemdir)) do |load_path|
result << load_path
end
end
result
end
##
# Return only the latest partial paths in the given +gemdir+.
def self.latest_partials(gemdir)
latest = {}
all_partials(gemdir).each do |gp|
base = File.basename gp
if base.to_s =~ /(.*)-((\d+\.)*\d+)/ then
name, version = $1, $2
ver = Gem::Version.new(version)
if latest[name].nil? || ver > latest[name][0]
latest[name] = [ver, gp]
end
end
end
latest.collect { |k,v| v[1] }
end
private_class_method :latest_partials
##
# The index to insert activated gem paths into the $LOAD_PATH.
#
@ -629,16 +526,6 @@ module Gem
def self.load_path_insert_index
index = $LOAD_PATH.index ConfigMap[:sitelibdir]
if QUICKLOADER_SUCKAGE then
$LOAD_PATH.each_with_index do |path, i|
if path.instance_variables.include?(:@gem_prelude_index) or
path.instance_variables.include?('@gem_prelude_index') then
index = i
break
end
end
end
index
end
@ -711,27 +598,6 @@ module Gem
"#{Marshal::MAJOR_VERSION}.#{Marshal::MINOR_VERSION}"
end
##
# Get the appropriate cache path.
#
# Pass a string to use a different base path, or nil/false (default) for
# Gem.dir.
#
def self.cache_dir(custom_dir=false)
File.join(custom_dir || Gem.dir, "cache")
end
##
# Given a gem path, find the gem in cache.
#
# Pass a string as the second argument to use a different base path, or
# nil/false (default) for Gem.dir.
def self.cache_gem(filename, user_dir=false)
cache_dir(user_dir).add(filename)
end
##
# Set array of platforms this RubyGems supports (primarily for testing).
@ -769,6 +635,15 @@ module Gem
@post_install_hooks << hook
end
##
# Adds a post-installs hook that will be passed a Gem::DependencyInstaller
# and a list of installed specifications when
# Gem::DependencyInstaller#install is complete
def self.done_installing(&hook)
@done_installing_hooks << hook
end
##
# Adds a hook that will get run after Gem::Specification.reset is
# run.
@ -828,39 +703,10 @@ module Gem
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 = Gem::Path.path(gem.full_gem_path).add(gem.require_paths.last)
over_paths = over.require_paths.map do |path|
Gem::Path.path(over.full_gem_path).add(path).to_s
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 available gems from disk.
def self.refresh
Gem::Specification.reset
@source_index = nil
@searcher = nil
end
##
@ -870,50 +716,6 @@ module Gem
File.open path, binary_mode do |f| f.read end
end
##
# Report a load error during activation. The message of load error
# depends on whether it was a version mismatch or if there are not gems of
# any version by the requested name.
def self.report_activate_error(gem)
matches = Gem::Specification.find_by_name(gem.name)
if matches.empty? then
error = Gem::LoadError.new(
"Could not find RubyGem #{gem.name} (#{gem.requirement})\n")
else
error = Gem::LoadError.new(
"RubyGem version error: " +
"#{gem.name}(#{matches.first.version} not #{gem.requirement})\n")
end
error.name = gem.name
error.requirement = gem.requirement
raise error
end
private_class_method :report_activate_error
##
# 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::Specification.find_all_by_name gemname, *requirements
return nil if matches.empty?
spec = matches.last
spec.require_paths.each do |path|
result = Gem::Path.path(spec.full_gem_path).add(path, libfile)
return result if result.exist?
end
nil
end
##
# The path to the running Ruby interpreter.
@ -928,6 +730,7 @@ module Gem
@ruby
end
# DOC: needs doc'd or :nodoc'd
def self.latest_spec_for name
dependency = Gem::Dependency.new name
fetcher = Gem::SpecFetcher.fetcher
@ -942,13 +745,16 @@ module Gem
match and fetcher.fetch_spec(*match)
end
# DOC: needs doc'd or :nodoc'd
def self.latest_version_for name
spec = latest_spec_for name
spec and spec.version
end
# DOC: needs doc'd or :nodoc'd
def self.latest_rubygems_version
latest_version_for "rubygems-update"
latest_version_for("rubygems-update") or
raise "Can't find 'rubygems-update' in any repo. Check `gem source list`."
end
##
@ -968,36 +774,34 @@ module Gem
end
##
# The GemPathSearcher object used to search for matching installed gems.
# A Gem::Version for the currently running RubyGems
def self.searcher
@searcher ||= Gem::GemPathSearcher.new
def self.rubygems_version
return @rubygems_version if defined? @rubygems_version
@rubygems_version = Gem::Version.new Gem::VERSION
end
##
# Returns the Gem::SourceIndex of specifications that are in the Gem.path
def self.source_index
@@source_index ||= Gem::Deprecate.skip_during do
SourceIndex.new Gem::Specification.dirs
end
end
##
# Returns an Array of sources to fetch remote gems from. If the sources
# list is empty, attempts to load the "sources" gem, then uses
# default_sources if it is not installed.
# Returns an Array of sources to fetch remote gems from. Uses
# default_sources if the sources list is empty.
def self.sources
@sources ||= default_sources
@sources ||= Gem::SourceList.from(default_sources)
end
##
# Need to be able to set the sources without calling
# Gem.sources.replace since that would cause an infinite loop.
#
# DOC: This comment is not documentation about the method itself, it's
# more of a code comment about the implementation.
def self.sources= new_sources
@sources = new_sources
if !new_sources
@sources = nil
else
@sources = Gem::SourceList.from(new_sources)
end
end
##
@ -1007,12 +811,6 @@ module Gem
@suffix_pattern ||= "{#{suffixes.join(',')}}"
end
def self.loaded_path? path
# TODO: ruby needs a feature to let us query what's loaded in 1.8 and 1.9
re = /(^|\/)#{Regexp.escape path}#{Regexp.union(*Gem.suffixes)}$/
$LOADED_FEATURES.any? { |s| s =~ re }
end
##
# Suffixes for require-able paths.
@ -1067,7 +865,7 @@ module Gem
# The home directory for the user.
def self.user_home
@user_home ||= find_home
@user_home ||= find_home.untaint
end
##
@ -1126,6 +924,9 @@ module Gem
load_plugin_files files
end
# FIX: Almost everywhere else we use the `def self.` way of defining class
# methods, and then we switch over to `class << self` here. Pick one or the
# other.
class << self
##
@ -1134,29 +935,73 @@ module Gem
attr_reader :loaded_specs
##
# The list of hooks to be run before Gem::Install#install finishes
# installation
# Register a Gem::Specification for default gem
def register_default_spec(spec)
spec.files.each do |file|
@path_to_default_spec_map[file] = spec
end
end
##
# Find a Gem::Specification of default gem from +path+
def find_unresolved_default_spec(path)
Gem.suffixes.each do |suffix|
spec = @path_to_default_spec_map["#{path}#{suffix}"]
return spec if spec
end
nil
end
##
# Remove needless Gem::Specification of default gem from
# unresolved default gem list
def remove_unresolved_default_spec(spec)
spec.files.each do |file|
@path_to_default_spec_map.delete(file)
end
end
##
# Clear default gem related varibles. It is for test
def clear_default_specs
@path_to_default_spec_map.clear
end
##
# The list of hooks to be run after Gem::Installer#install extracts files
# and builds extensions
attr_reader :post_build_hooks
##
# The list of hooks to be run before Gem::Install#install does any work
# The list of hooks to be run after Gem::Installer#install completes
# installation
attr_reader :post_install_hooks
##
# The list of hooks to be run after Gem::DependencyInstaller installs a
# set of gems
attr_reader :done_installing_hooks
##
# The list of hooks to be run after Gem::Specification.reset is run.
attr_reader :post_reset_hooks
##
# The list of hooks to be run before Gem::Uninstall#uninstall does any
# work
# The list of hooks to be run after Gem::Uninstaller#uninstall completes
# installation
attr_reader :post_uninstall_hooks
##
# The list of hooks to be run after Gem::Install#install is finished
# The list of hooks to be run before Gem::Installer#install does any work
attr_reader :pre_install_hooks
@ -1166,15 +1011,12 @@ module Gem
attr_reader :pre_reset_hooks
##
# The list of hooks to be run after Gem::Uninstall#uninstall is finished
# The list of hooks to be run before Gem::Uninstaller#uninstall does any
# work
attr_reader :pre_uninstall_hooks
end
def self.cache # :nodoc:
source_index
end
##
# Location of Marshal quick gemspecs on remote repositories
@ -1184,77 +1026,21 @@ module Gem
autoload :Requirement, 'rubygems/requirement'
autoload :Dependency, 'rubygems/dependency'
autoload :DependencyList, 'rubygems/dependency_list'
autoload :GemPathSearcher, 'rubygems/gem_path_searcher'
autoload :SourceList, 'rubygems/source_list'
autoload :SpecFetcher, 'rubygems/spec_fetcher'
autoload :Specification, 'rubygems/specification'
autoload :Cache, 'rubygems/source_index'
autoload :SourceIndex, 'rubygems/source_index'
autoload :PathSupport, 'rubygems/path_support'
autoload :Platform, 'rubygems/platform'
autoload :Builder, 'rubygems/builder'
autoload :ConfigFile, 'rubygems/config_file'
end
autoload :DependencyResolver, 'rubygems/dependency_resolver'
autoload :RequestSet, 'rubygems/request_set'
module Kernel
remove_method :gem if 'method' == defined? gem # from gem_prelude.rb on 1.9
##
# Use Kernel#gem to activate a specific version of +gem_name+.
#
# +requirements+ is a list of version requirements that the
# specified gem must match, most commonly "= example.version.number". See
# Gem::Requirement for how to specify a version requirement.
#
# If you will be activating the latest version of a gem, there is no need to
# call Kernel#gem, Kernel#require will do the right thing for you.
#
# Kernel#gem returns true if the gem was activated, otherwise false. If the
# gem could not be found, didn't match the version requirements, or a
# different version was already activated, an exception will be raised.
#
# Kernel#gem should be called *before* any require statements (otherwise
# RubyGems may load a conflicting library version).
#
# In older RubyGems versions, the environment variable GEM_SKIP could be
# used to skip activation of specified gems, for example to test out changes
# that haven't been installed yet. Now RubyGems defers to -I and the
# RUBYLIB environment variable to skip activation of a gem.
#
# Example:
#
# GEM_SKIP=libA:libB ruby -I../libA -I../libB ./mycode.rb
def gem(gem_name, *requirements) # :doc:
skip_list = (ENV['GEM_SKIP'] || "").split(/:/)
raise Gem::LoadError, "skipping #{gem_name}" if skip_list.include? gem_name
spec = Gem::Dependency.new(gem_name, *requirements).to_spec
spec.activate if spec
end
private :gem
end
##
# 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) # :nodoc:
warn "#{Gem.location_of_caller.join ':'}:Warning: " \
"RbConfig.datadir is deprecated and will be removed on or after " \
"August 2011. " \
"Use Gem::datadir."
require 'rbconfig/datadir'
Gem.datadir(package_name) || File.join(Gem::ConfigMap[:datadir], package_name)
require "rubygems/specification"
end
require 'rubygems/exceptions'
# REFACTOR: This should be pulled out into some kind of hacks file.
gem_preluded = Gem::GEM_PRELUDE_SUCKAGE and defined? Gem
unless gem_preluded then # TODO: remove guard after 1.9.2 dropped
begin
@ -1277,29 +1063,10 @@ unless gem_preluded then # TODO: remove guard after 1.9.2 dropped
end
##
# Enables the require hook for RubyGems.
# Loads the default specs.
Gem::Specification.load_defaults
require 'rubygems/custom_require'
require 'rubygems/core_ext/kernel_gem'
require 'rubygems/core_ext/kernel_require'
module Gem
class << self
extend Gem::Deprecate
deprecate :activate_dep, "Specification#activate", 2011, 6
deprecate :activate_spec, "Specification#activate", 2011, 6
deprecate :cache, "Gem::source_index", 2011, 8
deprecate :activate, "Specification#activate", 2011, 10
deprecate :all_load_paths, :none, 2011, 10
deprecate :all_partials, :none, 2011, 10
deprecate :latest_load_paths, :none, 2011, 10
deprecate :promote_load_path, :none, 2011, 10
deprecate :available?, "Specification::find_by_name", 2011, 11
deprecate :cache_dir, "Specification#cache_dir", 2011, 11
deprecate :cache_gem, "Specification#cache_file", 2011, 11
deprecate :default_system_source_cache_dir, :none, 2011, 11
deprecate :default_user_source_cache_dir, :none, 2011, 11
deprecate :report_activate_error, :none, 2011, 11
deprecate :required_location, :none, 2011, 11
deprecate :searcher, "Specification", 2011, 11
deprecate :source_index, "Specification", 2011, 11
end
end
Gem.detect_gemdeps

Просмотреть файл

@ -0,0 +1,95 @@
module Gem
class AvailableSet
Tuple = Struct.new(:spec, :source)
def initialize
@set = []
@sorted = nil
end
attr_reader :set
def add(spec, source)
@set << Tuple.new(spec, source)
@sorted = nil
self
end
def <<(o)
case o
when AvailableSet
s = o.set
when Array
s = o.map do |sp,so|
if !sp.kind_of?(Specification) or !so.kind_of?(Source)
raise TypeError, "Array must be in [[spec, source], ...] form"
end
Tuple.new(sp,so)
end
else
raise TypeError, "Must be an AvailableSet"
end
@set += s
@sorted = nil
self
end
def empty?
@set.empty?
end
def all_specs
@set.map { |t| t.spec }
end
def match_platform!
@set.reject! { |t| !Gem::Platform.match(t.spec.platform) }
@sorted = nil
self
end
def sorted
@sorted ||= @set.sort do |a,b|
i = b.spec <=> a.spec
i != 0 ? i : (a.source <=> b.source)
end
end
def size
@set.size
end
def source_for(spec)
f = @set.find { |t| t.spec == spec }
f.source
end
def pick_best!
return self if empty?
@set = [sorted.first]
@sorted = nil
self
end
def remove_installed!(dep)
@set.reject! do |t|
# already locally installed
Gem::Specification.any? do |installed_spec|
dep.name == installed_spec.name and
dep.requirement.satisfied_by? installed_spec.version
end
end
@sorted = nil
self
end
def inject_into_list(dep_list)
@set.each { |t| dep_list.add t.spec }
end
end
end

Просмотреть файл

@ -1,99 +0,0 @@
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
# See LICENSE.txt for permissions.
#++
require 'rubygems'
require 'rubygems/user_interaction'
Gem.load_yaml
require 'rubygems/package'
##
# The Builder class processes RubyGem specification files
# to produce a .gem file.
class Gem::Builder
include Gem::UserInteraction
##
# Constructs a builder instance for the provided specification
#
# spec:: [Gem::Specification] The specification instance
def initialize(spec)
@spec = spec
end
##
# Builds the gem from the specification. Returns the name of the file
# written.
def build(skip_validation=false)
@spec.mark_version
@spec.validate unless skip_validation
@signer = sign
write_package
say success if Gem.configuration.verbose
File.basename @spec.cache_file
end
def success
<<-EOM
Successfully built RubyGem
Name: #{@spec.name}
Version: #{@spec.version}
File: #{File.basename @spec.cache_file}
EOM
end
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
signer = nil
if @spec.respond_to?(:signing_key) and @spec.signing_key then
require 'rubygems/security'
signer = Gem::Security::Signer.new @spec.signing_key, @spec.cert_chain
@spec.signing_key = nil
@spec.cert_chain = signer.cert_chain.map { |cert| cert.to_s }
end
signer
end
def write_package
file_name = File.basename @spec.cache_file
open file_name, 'wb' do |gem_io|
Gem::Package.open gem_io, 'w', @signer do |pkg|
yaml = @spec.to_yaml
pkg.metadata = yaml
@spec.files.each do |file|
next if File.directory?(file)
next if file == file_name # Don't add gem onto itself
stat = File.stat(file)
mode = stat.mode & 0777
size = stat.size
pkg.add_file_simple file, mode, size do |tar_io|
tar_io.write open(file, "rb") { |f| f.read }
end
end
end
end
end
end

Просмотреть файл

@ -9,7 +9,7 @@ require 'rubygems/user_interaction'
##
# Base class for all Gem commands. When creating a new gem command, define
# #new, #execute, #arguments, #defaults_str, #description and #usage
# #initialize, #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
@ -150,8 +150,9 @@ class Gem::Command
def show_lookup_failure(gem_name, version, errors, domain)
if errors and !errors.empty?
alert_error "Could not find a valid gem '#{gem_name}' (#{version}), here is why:"
errors.each { |x| say " #{x.wordy}" }
msg = "Could not find a valid gem '#{gem_name}' (#{version}), here is why:\n"
errors.each { |x| msg << " #{x.wordy}\n" }
alert_error msg
else
alert_error "Could not find a valid gem '#{gem_name}' (#{version}) in any repository"
end
@ -179,6 +180,15 @@ class Gem::Command
args.select { |arg| arg !~ /^-/ }
end
##
# Get all [gem, version] from the command line.
#
# An argument in the form gem:ver is pull apart into the gen name and version,
# respectively.
def get_all_gem_names_and_versions
get_all_gem_names.map { |name| name.split(":", 2) }
end
##
# Get a single gem name from the command line. Fail if there is no gem name
# or if there is more than one gem name given.
@ -268,8 +278,18 @@ class Gem::Command
# Invoke the command with the given list of arguments.
def invoke(*args)
invoke_with_build_args args, nil
end
##
# Invoke the command with the given list of normal arguments
# and additional build arguments.
def invoke_with_build_args(args, build_args)
handle_options args
options[:build_args] = build_args
if options[:help] then
show_help
elsif @when_invoked then
@ -344,7 +364,7 @@ class Gem::Command
def handle_options(args)
args = add_extra_args(args)
@options = @defaults.clone
@options = Marshal.load Marshal.dump @defaults # deep copy
parser.parse!(args)
@options[:args] = args
end
@ -372,18 +392,23 @@ class Gem::Command
private
##
# Create on demand parser.
def add_parser_description # :nodoc:
return unless description
def parser
create_option_parser if @parser.nil?
@parser
end
def create_option_parser
@parser = OptionParser.new
formatted = description.split("\n\n").map do |chunk|
wrap chunk, 80 - 4
end.join "\n"
@parser.separator nil
@parser.separator " Description:"
formatted.split("\n").each do |line|
@parser.separator " #{line.rstrip}"
end
end
def add_parser_options # :nodoc:
@parser.separator nil
regular_options = @option_groups.delete :options
configure_options "", regular_options
@ -392,45 +417,56 @@ class Gem::Command
@parser.separator nil
configure_options group_name, option_list
end
end
##
# Adds a section with +title+ and +content+ to the parser help view. Used
# for adding command arguments and default arguments.
def add_parser_run_info title, content
return if content.empty?
@parser.separator nil
@parser.separator " #{title}:"
content.split(/\n/).each do |line|
@parser.separator " #{line}"
end
end
def add_parser_summary # :nodoc:
return unless @summary
@parser.separator nil
@parser.separator " Summary:"
wrap(@summary, 80 - 4).split("\n").each do |line|
@parser.separator " #{line.strip}"
end
end
##
# Create on demand parser.
def parser
create_option_parser if @parser.nil?
@parser
end
##
# Creates an option parser and fills it in with the help info for the
# command.
def create_option_parser
@parser = OptionParser.new
add_parser_options
@parser.separator nil
configure_options "Common", Gem::Command.common_options
unless arguments.empty?
@parser.separator nil
@parser.separator " Arguments:"
arguments.split(/\n/).each do |arg_desc|
@parser.separator " #{arg_desc}"
end
end
if @summary then
@parser.separator nil
@parser.separator " Summary:"
wrap(@summary, 80 - 4).split("\n").each do |line|
@parser.separator " #{line.strip}"
end
end
if description then
formatted = description.split("\n\n").map do |chunk|
wrap chunk, 80 - 4
end.join "\n"
@parser.separator nil
@parser.separator " Description:"
formatted.split("\n").each do |line|
@parser.separator " #{line.rstrip}"
end
end
unless defaults_str.empty?
@parser.separator nil
@parser.separator " Defaults:"
defaults_str.split(/\n/).each do |line|
@parser.separator " #{line}"
end
end
add_parser_run_info "Arguments", arguments
add_parser_summary
add_parser_description
add_parser_run_info "Defaults", defaults_str
end
def configure_options(header, option_list)
@ -521,7 +557,7 @@ basic help message containing pointers to more information.
http://localhost:8808/
with info about installed gems
Further information:
http://rubygems.rubyforge.org
http://guides.rubygems.org
HELP
# :startdoc:
@ -529,7 +565,7 @@ basic help message containing pointers to more information.
end
##
# This is where Commands will be placed in the namespace
# \Commands will be placed in this namespace
module Gem::Commands
end

Просмотреть файл

@ -18,12 +18,15 @@ require 'rubygems/user_interaction'
# # file rubygems_plugin.rb
# require 'rubygems/command_manager'
#
# Gem::CommandManager.instance.register_command :edit
#
# You should put the implementation of your command in rubygems/commands.
#
# # file rubygems/commands/edit_command.rb
# 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
@ -37,6 +40,14 @@ class Gem::CommandManager
@command_manager ||= new
end
##
# Returns self. Allows a CommandManager instance to stand
# in for the class itself.
def instance
self
end
##
# Reset the authoritative instance of the command manager.
@ -63,6 +74,7 @@ class Gem::CommandManager
register_command :install
register_command :list
register_command :lock
register_command :mirror
register_command :outdated
register_command :owner
register_command :pristine
@ -78,13 +90,14 @@ class Gem::CommandManager
register_command :unpack
register_command :update
register_command :which
register_command :yank
end
##
# Register the Symbol +command+ as a gem command.
def register_command(command)
@commands[command] = false
def register_command(command, obj=false)
@commands[command] = obj
end
##
@ -95,7 +108,7 @@ class Gem::CommandManager
end
##
# Return the registered command from the command name.
# Returns a Command instance for +command_name+
def [](command_name)
command_name = command_name.intern
@ -104,56 +117,69 @@ class Gem::CommandManager
end
##
# Return a sorted list of all command names (as strings).
# Return a sorted list of all command names as strings.
def command_names
@commands.keys.collect {|key| key.to_s}.sort
end
##
# Run the config specified by +args+.
# Run the command specified by +args+.
def run(args)
process_args(args)
def run(args, build_args=nil)
process_args(args, build_args)
rescue StandardError, Timeout::Error => ex
alert_error "While executing gem ... (#{ex.class})\n #{ex.to_s}"
ui.errs.puts "\t#{ex.backtrace.join "\n\t"}" if
Gem.configuration.backtrace
ui.backtrace ex
if Gem.configuration.really_verbose and \
ex.kind_of?(Gem::Exception) and ex.source_exception
e = ex.source_exception
ui.errs.puts "Because of: (#{e.class})\n #{e.to_s}"
ui.backtrace e
end
terminate_interaction(1)
rescue Interrupt
alert_error "Interrupted"
terminate_interaction(1)
end
def process_args(args)
def process_args(args, build_args=nil)
args = args.to_str.split(/\s+/) if args.respond_to?(:to_str)
if args.size == 0
if args.empty? then
say Gem::Command::HELP
terminate_interaction(1)
terminate_interaction 1
end
case args[0]
when '-h', '--help'
case args.first
when '-h', '--help' then
say Gem::Command::HELP
terminate_interaction(0)
when '-v', '--version'
terminate_interaction 0
when '-v', '--version' then
say Gem::VERSION
terminate_interaction(0)
when /^-/
alert_error "Invalid option: #{args[0]}. See 'gem --help'."
terminate_interaction(1)
terminate_interaction 0
when /^-/ then
alert_error "Invalid option: #{args.first}. See 'gem --help'."
terminate_interaction 1
else
cmd_name = args.shift.downcase
cmd = find_command(cmd_name)
cmd.invoke(*args)
cmd = find_command cmd_name
cmd.invoke_with_build_args args, build_args
end
end
def find_command(cmd_name)
possibilities = find_command_possibilities cmd_name
if possibilities.size > 1 then
raise "Ambiguous command #{cmd_name} matches [#{possibilities.join(', ')}]"
elsif possibilities.size < 1 then
raise "Unknown command #{cmd_name}"
raise Gem::CommandLineError,
"Ambiguous command #{cmd_name} " \
"matches [#{possibilities.join(', ')}]"
elsif possibilities.empty? then
raise Gem::CommandLineError, "Unknown command #{cmd_name}"
end
self[possibilities.first]
@ -162,7 +188,11 @@ class Gem::CommandManager
def find_command_possibilities(cmd_name)
len = cmd_name.length
command_names.select { |n| cmd_name == n[0, len] }
found = command_names.select { |name| cmd_name == name[0, len] }
exact = found.find { |name| name == cmd_name }
exact ? [exact] : found
end
private
@ -170,23 +200,20 @@ class Gem::CommandManager
def load_and_instantiate(command_name)
command_name = command_name.to_s
const_name = command_name.capitalize.gsub(/_(.)/) { $1.upcase } << "Command"
commands = Gem::Commands
retried = false
load_error = nil
begin
commands.const_get(const_name).new
rescue NameError
raise if retried
retried = true
begin
require "rubygems/commands/#{command_name}_command"
rescue Exception => e
alert_error "Loading command: #{command_name} (#{e.class})\n #{e}"
ui.errs.puts "\t#{e.backtrace.join "\n\t"}" if
Gem.configuration.backtrace
rescue LoadError => e
load_error = e
end
retry
Gem::Commands.const_get(const_name).new
rescue Exception => e
e = load_error if load_error
alert_error "Loading command: #{command_name} (#{e.class})\n\t#{e}"
ui.backtrace e
end
end

Просмотреть файл

@ -1,5 +1,5 @@
require 'rubygems/command'
require 'rubygems/builder'
require 'rubygems/package'
class Gem::Commands::BuildCommand < Gem::Command
@ -22,11 +22,11 @@ class Gem::Commands::BuildCommand < Gem::Command
def execute
gemspec = get_one_gem_name
if File.exist? gemspec
spec = load_gemspec gemspec
if File.exist? gemspec then
spec = Gem::Specification.load gemspec
if spec then
Gem::Builder.new(spec).build options[:force]
Gem::Package.build spec, options[:force]
else
alert_error "Error loading gemspec. Aborting."
terminate_interaction 1
@ -37,23 +37,5 @@ class Gem::Commands::BuildCommand < Gem::Command
end
end
def load_gemspec filename
if yaml?(filename)
open(filename) do |f|
begin
Gem::Specification.from_yaml(f)
rescue Gem::EndOfYAMLException
nil
end
end
else
Gem::Specification.load(filename) # can return nil
end
end
def yaml?(filename)
line = open(filename) { |f| line = f.gets }
result = line =~ %r{!ruby/object:Gem::Specification}
result
end
end

Просмотреть файл

@ -4,82 +4,224 @@ require 'rubygems/security'
class Gem::Commands::CertCommand < Gem::Command
def initialize
super 'cert', 'Manage RubyGems certificates and signing settings'
super 'cert', 'Manage RubyGems certificates and signing settings',
:add => [], :remove => [], :list => [], :build => [], :sign => []
add_option('-a', '--add CERT',
'Add a trusted certificate.') do |value, options|
cert = OpenSSL::X509::Certificate.new(File.read(value))
Gem::Security.add_trusted_cert(cert)
say "Added '#{cert.subject.to_s}'"
end
add_option('-l', '--list',
'List trusted certificates.') do |value, options|
glob_str = File::join(Gem::Security::OPT[:trust_dir], '*.pem')
Dir::glob(glob_str) do |path|
begin
cert = OpenSSL::X509::Certificate.new(File.read(path))
# this could probably be formatted more gracefully
say cert.subject.to_s
rescue OpenSSL::X509::CertificateError
next
end
OptionParser.accept OpenSSL::X509::Certificate do |certificate|
begin
OpenSSL::X509::Certificate.new File.read certificate
rescue Errno::ENOENT
raise OptionParser::InvalidArgument, "#{certificate}: does not exist"
rescue OpenSSL::X509::CertificateError
raise OptionParser::InvalidArgument,
"#{certificate}: invalid X509 certificate"
end
end
add_option('-r', '--remove STRING',
'Remove trusted certificates containing',
'STRING.') do |value, options|
trust_dir = Gem::Security::OPT[:trust_dir]
glob_str = File::join(trust_dir, '*.pem')
Dir::glob(glob_str) do |path|
begin
cert = OpenSSL::X509::Certificate.new(File.read(path))
if cert.subject.to_s.downcase.index(value)
say "Removed '#{cert.subject.to_s}'"
File.unlink(path)
end
rescue OpenSSL::X509::CertificateError
next
end
OptionParser.accept OpenSSL::PKey::RSA do |key_file|
begin
key = OpenSSL::PKey::RSA.new File.read key_file
rescue Errno::ENOENT
raise OptionParser::InvalidArgument, "#{key_file}: does not exist"
rescue OpenSSL::PKey::RSAError
raise OptionParser::InvalidArgument, "#{key_file}: invalid RSA key"
end
raise OptionParser::InvalidArgument,
"#{key_file}: private key not found" unless key.private?
key
end
add_option('-a', '--add CERT', OpenSSL::X509::Certificate,
'Add a trusted certificate.') do |cert, options|
options[:add] << cert
end
add_option('-l', '--list [FILTER]',
'List trusted certificates where the',
'subject contains FILTER') do |filter, options|
filter ||= ''
options[:list] << filter
end
add_option('-r', '--remove FILTER',
'Remove trusted certificates where the',
'subject contains FILTER') do |filter, options|
options[:remove] << filter
end
add_option('-b', '--build EMAIL_ADDR',
'Build private key and self-signed',
'certificate for EMAIL_ADDR.') do |value, options|
vals = Gem::Security.build_self_signed_cert(value)
FileUtils.chmod 0600, vals[:key_path]
say "Public Cert: #{vals[:cert_path]}"
say "Private Key: #{vals[:key_path]}"
say "Don't forget to move the key file to somewhere private..."
'certificate for EMAIL_ADDR') do |email_address, options|
options[:build] << email_address
end
add_option('-C', '--certificate CERT',
'Certificate for --sign command.') do |value, options|
cert = OpenSSL::X509::Certificate.new(File.read(value))
add_option('-C', '--certificate CERT', OpenSSL::X509::Certificate,
'Signing certificate for --sign') do |cert, options|
options[:issuer_cert] = cert
end
add_option('-K', '--private-key KEY',
'Private key for --sign command.') do |value, options|
key = OpenSSL::PKey::RSA.new(File.read(value))
options[:issuer_key] = key
add_option('-K', '--private-key KEY', OpenSSL::PKey::RSA,
'Key for --sign or --build') do |key, options|
options[:key] = key
end
add_option('-s', '--sign NEWCERT',
'Sign a certificate with my key and',
'certificate.') do |value, options|
cert = OpenSSL::X509::Certificate.new(File.read(value))
my_cert = options[:issuer_cert]
my_key = options[:issuer_key]
cert = Gem::Security.sign_cert(cert, my_key, my_cert)
File.open(value, 'wb') { |file| file.write(cert.to_pem) }
add_option('-s', '--sign CERT',
'Signs CERT with the key from -K',
'and the certificate from -C') do |cert_file, options|
raise OptionParser::InvalidArgument, "#{cert_file}: does not exist" unless
File.file? cert_file
options[:sign] << cert_file
end
end
def execute
options[:add].each do |certificate|
Gem::Security.trust_dir.trust_cert certificate
say "Added '#{certificate.subject}'"
end
options[:remove].each do |filter|
certificates_matching filter do |certificate, path|
FileUtils.rm path
say "Removed '#{certificate.subject}'"
end
end
options[:list].each do |filter|
certificates_matching filter do |certificate, _|
# this could probably be formatted more gracefully
say certificate.subject.to_s
end
end
options[:build].each do |name|
build name
end
unless options[:sign].empty? then
load_default_cert unless options[:issuer_cert]
load_default_key unless options[:key]
end
options[:sign].each do |cert_file|
sign cert_file
end
end
def build name
key = options[:key] || Gem::Security.create_key
cert = Gem::Security.create_cert_email name, key
key_path = Gem::Security.write key, "gem-private_key.pem"
cert_path = Gem::Security.write cert, "gem-public_cert.pem"
say "Certificate: #{cert_path}"
say "Private Key: #{key_path}"
say "Don't forget to move the key file to somewhere private!"
end
def certificates_matching filter
return enum_for __method__, filter unless block_given?
Gem::Security.trusted_certificates.select do |certificate, _|
subject = certificate.subject.to_s
subject.downcase.index filter
end.sort_by do |certificate, _|
certificate.subject.to_a.map { |name, data,| [name, data] }
end.each do |certificate, path|
yield certificate, path
end
end
def description # :nodoc:
<<-EOF
The cert command manages signing keys and certificates for creating signed
gems. Your signing certificate and private key are typically stored in
~/.gem/gem-public_cert.pem and ~/.gem/gem-private_key.pem respectively.
To build a certificate for signing gems:
gem cert --build you@example
If you already have an RSA key, or are creating a new certificate for an
existing key:
gem cert --build you@example --private-key /path/to/key.pem
If you wish to trust a certificate you can add it to the trust list with:
gem cert --add /path/to/cert.pem
You can list trusted certificates with:
gem cert --list
or:
gem cert --list cert_subject_substring
If you wish to remove a previously trusted certificate:
gem cert --remove cert_subject_substring
To sign another gem author's certificate:
gem cert --sign /path/to/other_cert.pem
For further reading on signing gems see `ri Gem::Security`.
EOF
end
def load_default_cert
cert_file = File.join Gem.user_home, 'gem-public_cert.pem'
cert = File.read cert_file
options[:issuer_cert] = OpenSSL::X509::Certificate.new cert
rescue Errno::ENOENT
alert_error \
"--certificate not specified and ~/.gem/gem-public_cert.pem does not exist"
terminate_interaction 1
rescue OpenSSL::X509::CertificateError
alert_error \
"--certificate not specified and ~/.gem/gem-public_cert.pem is not valid"
terminate_interaction 1
end
def load_default_key
key_file = File.join Gem.user_home, 'gem-private_key.pem'
key = File.read key_file
options[:key] = OpenSSL::PKey::RSA.new key
rescue Errno::ENOENT
alert_error \
"--private-key not specified and ~/.gem/gem-private_key.pem does not exist"
terminate_interaction 1
rescue OpenSSL::PKey::RSAError
alert_error \
"--private-key not specified and ~/.gem/gem-private_key.pem is not valid"
terminate_interaction 1
end
def sign cert_file
cert = File.read cert_file
cert = OpenSSL::X509::Certificate.new cert
permissions = File.stat(cert_file).mode & 0777
issuer_cert = options[:issuer_cert]
issuer_key = options[:key]
cert = Gem::Security.sign cert, issuer_key, issuer_cert
Gem::Security.write cert, cert_file, permissions
end
end

Просмотреть файл

@ -8,13 +8,7 @@ class Gem::Commands::CheckCommand < Gem::Command
def initialize
super 'check', 'Check installed gems',
:verify => false, :alien => false
add_option( '--verify FILE',
'Verify gem file against its internal',
'checksum') do |value, options|
options[:verify] = value
end
:alien => true
add_option('-a', '--alien', "Report 'unmanaged' or rogue files in the",
"gem repository") do |value, options|
@ -25,40 +19,21 @@ class Gem::Commands::CheckCommand < Gem::Command
end
def execute
if options[:alien]
say "Performing the 'alien' operation"
say
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"
val.each do |error_entry|
say " #{error_entry.path}:"
say " #{error_entry.problem}"
end
else
say "#{key} is error-free" if Gem.configuration.verbose
end
say
end
end
say "Checking gems..."
say
gems = get_all_gem_names rescue []
if options[:verify]
gem_name = options[:verify]
unless gem_name
alert_error "Must specify a .gem file with --verify NAME"
return
end
unless File.exist?(gem_name)
alert_error "Unknown file: #{gem_name}."
return
end
say "Verifying gem: '#{gem_name}'"
begin
Gem::Validator.new.verify_gem_file(gem_name)
rescue Exception
alert_error "#{gem_name} is invalid."
Gem::Validator.new.alien(gems).sort.each do |key, val|
unless val.empty? then
say "#{key} has #{val.size} problems"
val.each do |error_entry|
say " #{error_entry.path}:"
say " #{error_entry.problem}"
end
else
say "#{key} is error-free" if Gem.configuration.verbose
end
say
end
end

Просмотреть файл

@ -26,6 +26,9 @@ class Gem::Commands::CleanupCommand < Gem::Command
<<-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.
Older gems that are required to satisify the dependencies of gems
are not removed.
EOF
end
@ -56,6 +59,8 @@ installed elsewhere in GEM_PATH the cleanup command won't touch it.
primary_gems[spec.name].version != spec.version
}
full = Gem::DependencyList.from_specs
deplist = Gem::DependencyList.new
gems_to_cleanup.uniq.each do |spec| deplist.add spec end
@ -64,6 +69,8 @@ installed elsewhere in GEM_PATH the cleanup command won't touch it.
original_path = Gem.path
deps.each do |spec|
next unless full.ok_to_remove?(spec.full_name)
if options[:dryrun] then
say "Dry Run Mode: Would uninstall #{spec.full_name}"
else

Просмотреть файл

@ -1,3 +1,4 @@
require 'English'
require 'rubygems/command'
require 'rubygems/version_option'
@ -80,19 +81,36 @@ class Gem::Commands::ContentsCommand < Gem::Command
terminate_interaction 1 if gem_names.length == 1
end
gem_path = spec.full_gem_path
extra = "/{#{spec.require_paths.join ','}}" if options[:lib_only]
glob = "#{gem_path}#{extra}/**/*"
files = Dir[glob]
if spec.default_gem?
files = spec.files.map do |file|
case file
when /\A#{spec.bindir}\//
[Gem::ConfigMap[:bindir], $POSTMATCH]
when /\.so\z/
[Gem::ConfigMap[:archdir], file]
else
[Gem::ConfigMap[:rubylibdir], file]
end
end
else
gem_path = spec.full_gem_path
extra = "/{#{spec.require_paths.join ','}}" if options[:lib_only]
glob = "#{gem_path}#{extra}/**/*"
prefix_re = /#{Regexp.escape(gem_path)}\//
files = Dir[glob].map do |file|
[gem_path, file.sub(prefix_re, "")]
end
end
gem_path = File.join gem_path, '' # add trailing / if missing
files.sort.each do |prefix, basename|
absolute_path = File.join(prefix, basename)
next if File.directory? absolute_path
files.sort.each do |file|
next if File.directory? file
file = file.sub gem_path, '' unless options[:prefix]
say file
if options[:prefix]
say absolute_path
else
say basename
end
end
end
end

Просмотреть файл

@ -71,14 +71,9 @@ class Gem::Commands::DependencyCommand < Gem::Command
if remote? and not options[:reverse_dependencies] then
fetcher = Gem::SpecFetcher.fetcher
# REFACTOR: fetcher.find_specs_matching => specs
specs_and_sources = fetcher.find_matching(dependency,
dependency.specific?, true,
dependency.prerelease?)
ss, _ = fetcher.spec_for_dependency dependency
specs.concat specs_and_sources.map { |spec_tuple, source_uri|
fetcher.fetch_spec spec_tuple, URI.parse(source_uri)
}
ss.each { |s,o| specs << s }
end
if specs.empty? then

Просмотреть файл

@ -24,33 +24,38 @@ class Gem::Commands::EnvironmentCommand < Gem::Command
The RubyGems environment can be controlled through command line arguments,
gemrc files, environment variables and built-in defaults.
Command line argument defaults and some RubyGems defaults can be set in
~/.gemrc file for individual users and a /etc/gemrc for all users. A gemrc
is a YAML file with the following YAML keys:
Command line argument defaults and some RubyGems defaults can be set in a
~/.gemrc file for individual users and a /etc/gemrc for all users. These
files are YAML files with the following YAML keys:
:sources: A YAML array of remote gem repositories to install gems from
:verbose: Verbosity of the gem command. false, true, and :really are the
:verbose: Verbosity of the gem command. false, true, and :really are the
levels
:update_sources: Enable/disable automatic updating of repository metadata
:backtrace: Print backtrace when RubyGems encounters an error
:gempath: The paths in which to look for gems
gem_command: A string containing arguments for the specified gem command
:disable_default_gem_server: Force specification of gem server host on push
<gem_command>: A string containing arguments for the specified gem command
Example:
:verbose: false
install: --no-wrappers
update: --no-wrappers
:disable_default_gem_server: true
RubyGems' default local repository can be overridden with the GEM_PATH and
GEM_HOME environment variables. GEM_HOME sets the default repository to
install into. GEM_PATH allows multiple local repositories to be searched for
GEM_HOME environment variables. GEM_HOME sets the default repository to
install into. GEM_PATH allows multiple local repositories to be searched for
gems.
If you are behind a proxy server, RubyGems uses the HTTP_PROXY,
HTTP_PROXY_USER and HTTP_PROXY_PASS environment variables to discover the
proxy server.
If you would like to push gems to a private gem server the RUBYGEMS_HOST
environment variable can be set to the URI for that server.
If you are packaging RubyGems all of RubyGems' defaults are in
lib/rubygems/defaults.rb. You may override these in
lib/rubygems/defaults/operating_system.rb
@ -74,7 +79,7 @@ lib/rubygems/defaults/operating_system.rb
when /^gempath/, /^path/, /^GEM_PATH/ then
out << Gem.path.join(File::PATH_SEPARATOR)
when /^remotesources/ then
out << Gem.sources.join("\n")
out << Gem.sources.to_a.join("\n")
when /^platform/ then
out << Gem.platforms.join(File::PATH_SEPARATOR)
when nil then

Просмотреть файл

@ -34,7 +34,6 @@ class Gem::Commands::FetchCommand < Gem::Command
def execute
version = options[:version] || Gem::Requirement.default
all = Gem::Requirement.default != version
platform = Gem.platforms.last
gem_names = get_all_gem_names
@ -43,32 +42,20 @@ class Gem::Commands::FetchCommand < Gem::Command
dep = Gem::Dependency.new gem_name, version
dep.prerelease = options[:prerelease]
specs_and_sources, errors =
Gem::SpecFetcher.fetcher.fetch_with_errors(dep, all, true,
dep.prerelease?)
specs_and_sources, errors = Gem::SpecFetcher.fetcher.spec_for_dependency dep
if platform then
filtered = specs_and_sources.select { |s,| s.platform == platform }
specs_and_sources = filtered unless filtered.empty?
end
spec, source_uri = specs_and_sources.sort_by { |s,| s.version }.last
spec, source = specs_and_sources.sort_by { |s,| s.version }.first
if spec.nil? then
show_lookup_failure gem_name, version, errors, options[:domain]
next
end
file = "#{spec.full_name}.gem"
remote_path = URI.parse(source_uri) + "gems/#{file}"
fetch = Gem::RemoteFetcher.fetcher
gem = fetch.fetch_path remote_path.to_s
File.open file, "wb" do |f|
f.write gem
end
source.download spec
say "Downloaded #{spec.full_name}"
end

Просмотреть файл

@ -11,29 +11,16 @@ class Gem::Commands::GenerateIndexCommand < Gem::Command
def initialize
super 'generate_index',
'Generates the index files for a gem server directory',
:directory => '.', :build_legacy => true, :build_modern => true
:directory => '.', :build_modern => true
add_option '-d', '--directory=DIRNAME',
'repository base dir containing gems subdir' do |dir, options|
options[:directory] = File.expand_path dir
end
add_option '--[no-]legacy',
'Generate Marshal.4.8' 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
'Generate indexes for RubyGems',
'(always true)' do |value, options|
options[:build_modern] = value
end
@ -42,27 +29,10 @@ class Gem::Commands::GenerateIndexCommand < Gem::Command
'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
def defaults_str # :nodoc:
"--directory . --legacy --modern"
"--directory . --modern"
end
def description # :nodoc:
@ -85,25 +55,15 @@ When done, it will generate a set of files like this:
prerelease_specs.<version>.gz # prerelease specs index
quick/Marshal.<version>/<gemname>.gemspec.rz # Marshal quick index file
# these files support legacy RubyGems
Marshal.<version>
Marshal.<version>.Z # Marshal full index
The .Z and .rz extension files are compressed with the inflate algorithm.
The .rz extension files are compressed with the inflate algorithm.
The Marshal version number comes from ruby's Marshal::MAJOR_VERSION and
Marshal::MINOR_VERSION constants. It is used to ensure compatibility.
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
end
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
# This is always true becasue it's the only way now.
options[:build_modern] = true
if not File.exist?(options[:directory]) or
not File.directory?(options[:directory]) then

Просмотреть файл

@ -37,7 +37,7 @@ Some examples of 'gem' usage.
* Create a gem:
See http://rubygems.rubyforge.org/wiki/wiki.pl?CreateAGemInTenMinutes
See http://guides.rubygems.org/make-your-own-gem/
* See information about RubyGems:

Просмотреть файл

@ -1,10 +1,11 @@
require 'rubygems/command'
require 'rubygems/doc_manager'
require 'rubygems/install_update_options'
require 'rubygems/dependency_installer'
require 'rubygems/local_remote_options'
require 'rubygems/validator'
require 'rubygems/version_option'
require 'rubygems/install_message' # must come before rdoc for messaging
require 'rubygems/rdoc'
##
# Gem installer command line tool
@ -13,14 +14,14 @@ require 'rubygems/version_option'
class Gem::Commands::InstallCommand < Gem::Command
attr_reader :installed_specs # :nodoc:
include Gem::VersionOption
include Gem::LocalRemoteOptions
include Gem::InstallUpdateOptions
def initialize
defaults = Gem::DependencyInstaller::DEFAULT_OPTIONS.merge({
:generate_rdoc => true,
:generate_ri => true,
:format_executable => false,
:version => Gem::Requirement.default,
})
@ -32,6 +33,14 @@ class Gem::Commands::InstallCommand < Gem::Command
add_platform_option
add_version_option
add_prerelease_option "to be installed. (Only for listed gems)"
add_option(:"Install/Update", '-g', '--file FILE',
'Read from a gem dependencies API file and',
'install the listed gems') do |v,o|
o[:gemdeps] = v
end
@installed_specs = nil
end
def arguments # :nodoc:
@ -39,7 +48,7 @@ class Gem::Commands::InstallCommand < Gem::Command
end
def defaults_str # :nodoc:
"--both --version '#{Gem::Requirement.default}' --rdoc --ri --no-force\n" \
"--both --version '#{Gem::Requirement.default}' --document --no-force\n" \
"--install-dir #{Gem.dir}"
end
@ -100,31 +109,73 @@ to write the specification by hand. For example:
"#{program_name} GEMNAME [GEMNAME ...] [options] -- --build-flags"
end
def execute
if options[:include_dependencies] then
alert "`gem install -y` is now default and will be removed"
alert "use --ignore-dependencies to install only the gems you list"
def install_from_gemdeps(gf)
require 'rubygems/request_set'
rs = Gem::RequestSet.new
rs.load_gemdeps gf
rs.resolve
specs = rs.install options do |req, inst|
s = req.full_spec
if inst
say "Installing #{s.name} (#{s.version})"
else
say "Using #{s.name} (#{s.version})"
end
end
installed_gems = []
@installed_specs = specs
raise Gem::SystemExitException, 0
end
def execute
if gf = options[:gemdeps] then
install_from_gemdeps gf
return
end
@installed_specs = []
ENV.delete 'GEM_PATH' if options[:install_dir].nil? and RUBY_VERSION > '1.9'
if options[:install_dir] and options[:user_install]
alert_error "Use --install-dir or --user-install but not both"
terminate_interaction 1
end
exit_code = 0
get_all_gem_names.each do |gem_name|
if options[:version] != Gem::Requirement.default &&
get_all_gem_names.size > 1 then
alert_error "Can't use --version w/ multiple gems. Use name:ver instead."
terminate_interaction 1
end
get_all_gem_names_and_versions.each do |gem_name, gem_version|
gem_version ||= options[:version]
begin
next if options[:conservative] and
not Gem::Dependency.new(gem_name, options[:version]).matching_specs.empty?
not Gem::Dependency.new(gem_name, gem_version).matching_specs.empty?
inst = Gem::DependencyInstaller.new options
inst.install gem_name, options[:version]
inst.install gem_name, Gem::Requirement.create(gem_version)
inst.installed_gems.each do |spec|
say "Successfully installed #{spec.full_name}"
@installed_specs.push(*inst.installed_gems)
next unless errs = inst.errors
errs.each do |x|
next unless Gem::SourceFetchProblem === x
msg = "Unable to pull data from '#{x.source.uri}': #{x.error.message}"
alert_warning msg
end
installed_gems.push(*inst.installed_gems)
rescue Gem::InstallError => e
alert_error "Error installing #{gem_name}:\n\t#{e.message}"
exit_code |= 1
@ -135,27 +186,9 @@ to write the specification by hand. For example:
end
end
unless installed_gems.empty? then
gems = installed_gems.length == 1 ? 'gem' : 'gems'
say "#{installed_gems.length} #{gems} installed"
# NOTE: *All* of the RI documents must be generated first. For some
# reason, RI docs cannot be generated after any RDoc documents are
# generated.
if options[:generate_ri] then
installed_gems.each do |gem|
Gem::DocManager.new(gem, options[:rdoc_args]).generate_ri
end
Gem::DocManager.update_ri_cache
end
if options[:generate_rdoc] then
installed_gems.each do |gem|
Gem::DocManager.new(gem, options[:rdoc_args]).generate_rdoc
end
end
unless @installed_specs.empty? then
gems = @installed_specs.length == 1 ? 'gem' : 'gems'
say "#{@installed_specs.length} #{gems} installed"
end
raise Gem::SystemExitException, exit_code

Просмотреть файл

@ -7,8 +7,9 @@ require 'rubygems/commands/query_command'
class Gem::Commands::ListCommand < Gem::Commands::QueryCommand
def initialize
super 'list', 'Display gems whose name starts with STRING'
def initialize(name = 'list',
summary = 'Display gems whose name starts with STRING')
super name, summary
remove_option('--name-matches')
end
@ -26,8 +27,9 @@ class Gem::Commands::ListCommand < Gem::Commands::QueryCommand
end
def execute
string = get_one_optional_argument || ''
options[:name] = /^#{string}/i
name = get_one_optional_argument || ''
options[:name] = /^#{name}/i
super
end

Просмотреть файл

@ -30,7 +30,7 @@ generated.
Example:
gemlock rails-1.0.0 > lockdown.rb
gem lock rails-1.0.0 > lockdown.rb
will produce in lockdown.rb:

Просмотреть файл

@ -0,0 +1,17 @@
require 'rubygems/command'
class Gem::Commands::MirrorCommand < Gem::Command
def initialize
super('mirror', 'Mirror all gem files (requires rubygems-mirror)')
begin
Gem::Specification.find_by_name('rubygems-mirror').activate
rescue Gem::LoadError
# no-op
end
end
def execute
alert_error "Install the rubygems-mirror gem for the mirror command"
end
end

Просмотреть файл

@ -19,12 +19,15 @@ class Gem::Commands::OutdatedCommand < Gem::Command
Gem::Specification.outdated.sort.each do |name|
local = Gem::Specification.find_all_by_name(name).max
dep = Gem::Dependency.new local.name, ">= #{local.version}"
remotes = Gem::SpecFetcher.fetcher.fetch dep
remotes, _ = Gem::SpecFetcher.fetcher.spec_for_dependency dep
next if remotes.empty?
remote = remotes.last.first
say "#{local.name} (#{local.version} < #{remote.version})"
remotes.sort! { |a,b| a[0].version <=> b[0].version }
highest = remotes.last.first
say "#{local.name} (#{local.version} < #{highest.version})"
end
end
end

Просмотреть файл

@ -14,6 +14,10 @@ class Gem::Commands::OwnerCommand < Gem::Command
"GEM gem to manage owners for"
end
def usage # :nodoc:
"#{program_name} GEM"
end
def initialize
super 'owner', description
add_proxy_option
@ -63,12 +67,16 @@ class Gem::Commands::OwnerCommand < Gem::Command
def manage_owners method, name, owners
owners.each do |owner|
response = rubygems_api_request method, "api/v1/gems/#{name}/owners" do |request|
request.set_form_data 'email' => owner
request.add_field "Authorization", api_key
end
begin
response = rubygems_api_request method, "api/v1/gems/#{name}/owners" do |request|
request.set_form_data 'email' => owner
request.add_field "Authorization", api_key
end
with_response response
with_response response
rescue
# ignore
end
end
end

Просмотреть файл

@ -1,5 +1,5 @@
require 'rubygems/command'
require 'rubygems/format'
require 'rubygems/package'
require 'rubygems/installer'
require 'rubygems/version_option'
@ -24,6 +24,11 @@ class Gem::Commands::PristineCommand < Gem::Command
options[:extensions] = value
end
add_option('--only-executables',
'Only restore executables') do |value, options|
options[:only_executables] = value
end
add_version_option('restore to', 'pristine condition')
end
@ -78,6 +83,11 @@ extensions.
say "Restoring gems to pristine condition..."
specs.each do |spec|
if spec.default_gem?
say "Skipped #{spec.full_name}, it is a default gem"
next
end
unless spec.extensions.empty? or options[:extensions] then
say "Skipped #{spec.full_name}, it needs to compile an extension"
next
@ -101,8 +111,13 @@ extensions.
:wrappers => true,
:force => true,
:install_dir => spec.base_dir,
:env_shebang => installer_env_shebang)
installer.install
:env_shebang => installer_env_shebang,
:build_args => spec.build_args)
if options[:only_executables] then
installer.generate_bin
else
installer.install
end
say "Restored #{spec.full_name}"
end

Просмотреть файл

@ -1,6 +1,7 @@
require 'rubygems/command'
require 'rubygems/local_remote_options'
require 'rubygems/gemcutter_utilities'
require 'rubygems/package'
class Gem::Commands::PushCommand < Gem::Command
include Gem::LocalRemoteOptions
@ -39,13 +40,23 @@ class Gem::Commands::PushCommand < Gem::Command
def send_gem name
args = [:post, "api/v1/gems"]
args << options[:host] if options[:host]
if Gem.latest_rubygems_version < Gem::Version.new(Gem::VERSION) then
alert_error "Using beta/unreleased version of rubygems. Not pushing."
terminate_interaction 1
end
host = options[:host]
unless host
if gem_data = Gem::Package.new(name) then
host = gem_data.spec.metadata['default_gem_server']
end
end
args << host if host
say "Pushing gem to #{host || Gem.host}..."
response = rubygems_api_request(*args) do |request|
request.body = Gem.read_binary name
request.add_field "Content-Length", request.body.size

Просмотреть файл

@ -21,6 +21,10 @@ class Gem::Commands::QueryCommand < Gem::Command
options[:installed] = value
end
add_option('-I', 'Equivalent to --no-installed') do |value, options|
options[:installed] = false
end
add_version_option command, "for use with --installed"
add_option('-n', '--name-matches REGEXP',
@ -80,6 +84,7 @@ class Gem::Commands::QueryCommand < Gem::Command
req = Gem::Requirement.default
# TODO: deprecate for real
dep = Gem::Deprecate.skip_during { Gem::Dependency.new name, req }
dep.prerelease = prerelease
if local? then
if prerelease and not both? then
@ -97,7 +102,7 @@ class Gem::Commands::QueryCommand < Gem::Command
}
spec_tuples = specs.map do |spec|
[[spec.name, spec.version, spec.original_platform, spec], :local]
[spec.name_tuple, spec]
end
output_query_results spec_tuples
@ -110,13 +115,27 @@ class Gem::Commands::QueryCommand < Gem::Command
say
end
all = options[:all]
fetcher = Gem::SpecFetcher.fetcher
spec_tuples = fetcher.find_matching dep, all, false, prerelease
spec_tuples += fetcher.find_matching dep, false, false, true if
prerelease and all
type = if options[:all]
if options[:prerelease]
:complete
else
:released
end
elsif options[:prerelease]
:prerelease
else
:latest
end
if options[:name].source.empty?
spec_tuples = fetcher.detect(type) { true }
else
spec_tuples = fetcher.detect(type) do |gem_name, ver, plat|
options[:name] === gem_name
end
end
output_query_results spec_tuples
end
@ -135,32 +154,30 @@ class Gem::Commands::QueryCommand < Gem::Command
output = []
versions = Hash.new { |h,name| h[name] = [] }
spec_tuples.each do |spec_tuple, source_uri|
versions[spec_tuple.first] << [spec_tuple, source_uri]
spec_tuples.each do |spec_tuple, source|
versions[spec_tuple.name] << [spec_tuple, source]
end
versions = versions.sort_by do |(name,_),_|
name.downcase
versions = versions.sort_by do |(n,_),_|
n.downcase
end
versions.each do |gem_name, matching_tuples|
matching_tuples = matching_tuples.sort_by do |(_, version,_),_|
version
end.reverse
matching_tuples = matching_tuples.sort_by { |n,_| n.version }.reverse
platforms = Hash.new { |h,version| h[version] = [] }
matching_tuples.map do |(_, version, platform,_),_|
platforms[version] << platform if platform
matching_tuples.map do |n,_|
platforms[n.version] << n.platform if n.platform
end
seen = {}
matching_tuples.delete_if do |(_, version,_),_|
if seen[version] then
matching_tuples.delete_if do |n,_|
if seen[n.version] then
true
else
seen[version] = true
seen[n.version] = true
false
end
end
@ -169,7 +186,7 @@ class Gem::Commands::QueryCommand < Gem::Command
if options[:versions] then
list = if platforms.empty? or options[:details] then
matching_tuples.map { |(_, version,_),_| version }.uniq
matching_tuples.map { |n,_| n.version }.uniq
else
platforms.sort.reverse.map do |version, pls|
if pls == [Gem::Platform::RUBY] then
@ -188,12 +205,11 @@ class Gem::Commands::QueryCommand < Gem::Command
if options[:details] then
detail_tuple = matching_tuples.first
spec = if detail_tuple.first.length == 4 then
detail_tuple.first.last
else
uri = URI.parse detail_tuple.last
Gem::SpecFetcher.fetcher.fetch_spec detail_tuple.first, uri
end
spec = detail_tuple.last
unless spec.kind_of? Gem::Specification
spec = spec.fetch_spec detail_tuple.first
end
entry << "\n"
@ -243,9 +259,9 @@ class Gem::Commands::QueryCommand < Gem::Command
entry << "\n" << " Installed at: #{loaded_from}"
else
label = 'Installed at'
matching_tuples.each do |(_,version,_,s),|
matching_tuples.each do |n,s|
loaded_from = File.dirname File.dirname(s.loaded_from)
entry << "\n" << " #{label} (#{version}): #{loaded_from}"
entry << "\n" << " #{label} (#{n.version}): #{loaded_from}"
label = ' ' * label.length
end
end

Просмотреть файл

@ -1,6 +1,6 @@
require 'rubygems/command'
require 'rubygems/version_option'
require 'rubygems/doc_manager'
require 'rubygems/rdoc'
class Gem::Commands::RdocCommand < Gem::Command
include Gem::VersionOption
@ -8,7 +8,7 @@ class Gem::Commands::RdocCommand < Gem::Command
def initialize
super 'rdoc', 'Generates RDoc for pre-installed gems',
:version => Gem::Requirement.default,
:include_rdoc => true, :include_ri => true, :overwrite => false
:include_rdoc => false, :include_ri => true, :overwrite => false
add_option('--all',
'Generate RDoc/RI documentation for all',
@ -39,7 +39,7 @@ class Gem::Commands::RdocCommand < Gem::Command
end
def defaults_str # :nodoc:
"--version '#{Gem::Requirement.default}' --rdoc --ri --no-overwrite"
"--version '#{Gem::Requirement.default}' --ri --no-overwrite"
end
def description # :nodoc:
@ -54,37 +54,32 @@ The rdoc command builds RDoc and RI documentation for installed gems. Use
end
def execute
if options[:all] then
specs = Gem::SourceIndex.from_installed_gems.collect { |name, spec|
spec
}
else
gem_name = get_one_gem_name
dep = Gem::Dependency.new gem_name, options[:version]
specs = Gem::SourceIndex.from_installed_gems.search dep
specs = if options[:all] then
Gem::Specification.to_a
else
get_all_gem_names.map do |name|
Gem::Specification.find_by_name name, options[:version]
end.flatten.uniq
end
if specs.empty? then
alert_error 'No matching gems found'
terminate_interaction 1
end
if specs.empty?
raise "Failed to find gem #{gem_name} to generate RDoc for #{options[:version]}"
end
specs.each do |spec|
doc = Gem::RDoc.new spec, options[:include_rdoc], options[:include_ri]
if options[:include_ri]
specs.sort.each do |spec|
doc = Gem::DocManager.new(spec)
doc.generate_ri if options[:overwrite] || !doc.ri_installed?
end
doc.force = options[:overwrite]
Gem::DocManager.update_ri_cache
end
if options[:include_rdoc]
specs.sort.each do |spec|
doc = Gem::DocManager.new(spec)
doc.generate_rdoc if options[:overwrite] || !doc.rdoc_installed?
begin
doc.generate
rescue Errno::ENOENT => e
e.message =~ / - /
alert_error "Unable to document #{spec.full_name}, #{$'} is missing, skipping"
terminate_interaction 1 if specs.length == 1
end
end
true
end
end

Просмотреть файл

@ -1,30 +1,16 @@
require 'rubygems/command'
require 'rubygems/commands/query_command'
require 'rubygems/commands/list_command'
class Gem::Commands::SearchCommand < Gem::Commands::QueryCommand
class Gem::Commands::SearchCommand < Gem::Commands::ListCommand
def initialize
super 'search', 'Display all gems whose name contains STRING'
remove_option '--name-matches'
end
def arguments # :nodoc:
"STRING fragment of gem name to search for"
@defaults[:domain] = :remote
end
def defaults_str # :nodoc:
"--local --no-details"
end
def usage # :nodoc:
"#{program_name} [STRING]"
end
def execute
string = get_one_optional_argument
options[:name] = /#{string}/i
super
"--remote --no-details"
end
end

Просмотреть файл

@ -78,7 +78,7 @@ You can set up a shortcut to gem server documentation using the URL:
end
def execute
options[:gemdir] << Gem.dir if options[:gemdir].empty?
options[:gemdir] = Gem.path if options[:gemdir].empty?
Gem::Server.run options
end

Просмотреть файл

@ -5,14 +5,22 @@ require 'rubygems/command'
# RubyGems checkout or tarball.
class Gem::Commands::SetupCommand < Gem::Command
HISTORY_HEADER = /^===\s*[\d.]+\s*\/\s*\d{4}-\d{2}-\d{2}\s*$/
VERSION_MATCHER = /^===\s*([\d.]+)\s*\/\s*\d{4}-\d{2}-\d{2}\s*$/
def initialize
require 'tmpdir'
super 'setup', 'Install RubyGems',
:format_executable => true, :rdoc => true, :ri => true,
:format_executable => true, :document => %w[ri],
:site_or_vendor => :sitelibdir,
:destdir => '', :prefix => ''
:destdir => '', :prefix => '', :previous_version => ''
add_option '--previous-version=VERSION',
'Previous version of rubygems',
'Used for changelog processing' do |version, options|
options[:previous_version] = version
end
add_option '--prefix=PREFIX',
'Prefix path for installing RubyGems',
@ -37,14 +45,37 @@ class Gem::Commands::SetupCommand < Gem::Command
options[:format_executable] = value
end
add_option '--[no-]document [TYPES]', Array,
'Generate documentation for RubyGems.',
'List the documentation types you wish to',
'generate. For example: rdoc,ri' do |value, options|
options[:document] = case value
when nil then %w[rdoc ri]
when false then []
else value
end
end
add_option '--[no-]rdoc',
'Generate RDoc documentation for RubyGems' do |value, options|
options[:rdoc] = value
if value then
options[:document] << 'rdoc'
else
options[:document].delete 'rdoc'
end
options[:document].uniq!
end
add_option '--[no-]ri',
'Generate RI documentation for RubyGems' do |value, options|
options[:ri] = value
if value then
options[:document] << 'ri'
else
options[:document].delete 'ri'
end
options[:document].uniq!
end
end
@ -58,7 +89,7 @@ class Gem::Commands::SetupCommand < Gem::Command
end
def defaults_str # :nodoc:
"--format-executable --rdoc --ri"
"--format-executable --document ri"
end
def description # :nodoc:
@ -110,7 +141,7 @@ By default, this RubyGems will install gem as:
uninstall_old_gemcutter
install_rdoc
documentation_success = install_rdoc
say
if @verbose then
@ -118,14 +149,30 @@ By default, this RubyGems will install gem as:
say
end
if options[:previous_version].empty?
options[:previous_version] = Gem::VERSION.sub(/[0-9]+$/, '0')
end
options[:previous_version] = Gem::Version.new(options[:previous_version])
release_notes = File.join Dir.pwd, 'History.txt'
release_notes = if File.exist? release_notes then
open release_notes do |io|
text = io.gets '==='
text << io.gets('===')
text[0...-3].sub(/^# coding:.*?^=/m, '')
history = File.read release_notes
history = history.sub(/^# coding:.*?^=/m, '')
text = history.split(HISTORY_HEADER)
text.shift # correct an off-by-one generated by split
version_lines = history.scan(HISTORY_HEADER)
versions = history.scan(VERSION_MATCHER).flatten.map { |x| Gem::Version.new(x) }
history_string = ""
until versions.length == 0 or versions.shift < options[:previous_version]
history_string += version_lines.shift + text.shift
end
history_string
else
"Oh-no! Unable to find release notes!"
end
@ -145,6 +192,31 @@ By default, this RubyGems will install gem as:
say "to remove it by hand."
say
end
if documentation_success
if options[:document].include? 'rdoc' then
say "Rdoc documentation was installed. You may now invoke:"
say " gem server"
say "and then peruse beautifully formatted documentation for your gems"
say "with your web browser."
say "If you do not wish to install this documentation in the future, use the"
say "--no-document flag, or set it as the default in your ~/.gemrc file. See"
say "'gem help env' for details."
say
end
if options[:document].include? 'ri' then
say "Ruby Interactive (ri) documentation was installed. ri is kind of like man "
say "pages for ruby libraries. You may access it like this:"
say " ri Classname"
say " ri Classname.class_method"
say " ri Classname#instance_method"
say "If you do not wish to install this documentation in the future, use the"
say "--no-document flag, or set it as the default in your ~/.gemrc file. See"
say "'gem help env' for details."
say
end
end
end
def install_executables(bin_dir)
@ -165,7 +237,7 @@ By default, this RubyGems will install gem as:
end
dest_file = File.join bin_dir, bin_file_formatted
bin_tmp_file = File.join Dir.tmpdir, bin_file
bin_tmp_file = File.join Dir.tmpdir, "#{bin_file}.#{$$}"
begin
bin = File.readlines bin_file
@ -209,10 +281,7 @@ TEXT
say "Installing RubyGems" if @verbose
Dir.chdir 'lib' do
lib_files = Dir[File.join('**', '*rb')]
# Be sure to include our SSL ca bundles
lib_files += Dir[File.join('**', '*pem')]
lib_files = Dir[File.join('**', '*rb')]
lib_files.each do |lib_file|
dest_file = File.join lib_dir, lib_file
@ -229,6 +298,12 @@ TEXT
rubygems_name = "rubygems-#{Gem::VERSION}"
rubygems_doc_dir = File.join gem_doc_dir, rubygems_name
begin
Gem.ensure_gem_subdirectories Gem.dir
rescue SystemCallError
# ignore
end
if File.writable? gem_doc_dir and
(not File.exist? rubygems_doc_dir or
File.writable? rubygems_doc_dir) then
@ -237,21 +312,26 @@ TEXT
rm_rf dir
end
if options[:ri] then
ri_dir = File.join rubygems_doc_dir, 'ri'
say "Installing #{rubygems_name} ri into #{ri_dir}" if @verbose
run_rdoc '--ri', '--op', ri_dir
require 'rubygems/rdoc'
fake_spec = Gem::Specification.new 'rubygems', Gem::VERSION
def fake_spec.full_gem_path
File.expand_path '../../../..', __FILE__
end
if options[:rdoc] then
rdoc_dir = File.join rubygems_doc_dir, 'rdoc'
say "Installing #{rubygems_name} rdoc into #{rdoc_dir}" if @verbose
run_rdoc '--op', rdoc_dir
end
generate_ri = options[:document].include? 'ri'
generate_rdoc = options[:document].include? 'rdoc'
rdoc = Gem::RDoc.new fake_spec, generate_rdoc, generate_ri
rdoc.generate
return true
elsif @verbose then
say "Skipping RDoc generation, #{gem_doc_dir} not writable"
say "Set the GEM_HOME environment variable if you want RDoc generated"
end
return false
end
def make_destination_dirs(install_destdir)
@ -331,23 +411,6 @@ abort "#{deprecation_message}"
end
end
def run_rdoc(*args)
begin
gem 'rdoc'
rescue Gem::LoadError
end
require 'rdoc/rdoc'
args << '--main' << 'README.rdoc' << '--quiet'
args << '.'
args << 'README.rdoc' << 'UPGRADING.rdoc'
args << 'LICENSE.txt' << 'MIT.txt' << 'History.txt'
r = RDoc::RDoc.new
r.document args
end
def uninstall_old_gemcutter
require 'rubygems/uninstaller'

Просмотреть файл

@ -48,7 +48,7 @@ class Gem::Commands::SourcesCommand < Gem::Command
options[:update])
if options[:clear_all] then
path = Gem::SpecFetcher.fetcher.dir
path = File.join Gem.user_home, '.gem', 'specs'
FileUtils.rm_rf path
unless File.exist? path then
@ -64,16 +64,19 @@ class Gem::Commands::SourcesCommand < Gem::Command
end
end
if options[:add] then
source_uri = options[:add]
uri = URI.parse source_uri
if source_uri = options[:add] then
source = Gem::Source.new source_uri
begin
Gem::SpecFetcher.fetcher.load_specs uri, 'specs'
Gem.sources << source_uri
Gem.configuration.write
if Gem.sources.include? source_uri then
say "source #{source_uri} already present in the cache"
else
source.load_specs :released
Gem.sources << source
Gem.configuration.write
say "#{source_uri} added to sources"
say "#{source_uri} added to sources"
end
rescue URI::Error, ArgumentError
say "#{source_uri} is not a URI"
terminate_interaction 1
@ -97,12 +100,9 @@ class Gem::Commands::SourcesCommand < Gem::Command
end
if options[:update] then
fetcher = Gem::SpecFetcher.fetcher
Gem.sources.each do |update_uri|
update_uri = URI.parse update_uri
fetcher.load_specs update_uri, 'specs'
fetcher.load_specs update_uri, 'latest_specs'
Gem.sources.each_source do |src|
src.load_specs :released
src.load_specs :latest
end
say "source cache successfully updated"
@ -112,8 +112,8 @@ class Gem::Commands::SourcesCommand < Gem::Command
say "*** CURRENT SOURCES ***"
say
Gem.sources.each do |source|
say source
Gem.sources.each do |src|
say src
end
end
end

Просмотреть файл

@ -1,7 +1,7 @@
require 'rubygems/command'
require 'rubygems/local_remote_options'
require 'rubygems/version_option'
require 'rubygems/format'
require 'rubygems/package'
class Gem::Commands::SpecificationCommand < Gem::Command
@ -17,6 +17,7 @@ class Gem::Commands::SpecificationCommand < Gem::Command
add_version_option('examine')
add_platform_option
add_prerelease_option
add_option('--all', 'Output specifications for all versions of',
'the gem') do |value, options|
@ -62,13 +63,13 @@ FIELD name of gemspec field to show
"Please specify a gem name or file on the command line"
end
case options[:version]
case v = options[:version]
when String
req = Gem::Requirement.parse options[:version]
req = Gem::Requirement.create v
when Gem::Requirement
req = options[:version]
req = v
else
raise Gem::CommandLineError, "Unsupported version type: #{options[:version]}"
raise Gem::CommandLineError, "Unsupported version type: '#{v}'"
end
if !req.none? and options[:all]
@ -79,7 +80,7 @@ FIELD name of gemspec field to show
if options[:all]
dep = Gem::Dependency.new gem
else
dep = Gem::Dependency.new gem, options[:version]
dep = Gem::Dependency.new gem, req
end
field = get_one_optional_argument
@ -89,7 +90,7 @@ FIELD name of gemspec field to show
if local? then
if File.exist? gem then
specs << Gem::Format.from_file_by_path(gem).spec rescue nil
specs << Gem::Package.new(gem).spec rescue nil
end
if specs.empty? then
@ -98,17 +99,14 @@ FIELD name of gemspec field to show
end
if remote? then
found = Gem::SpecFetcher.fetcher.fetch dep, true
if dep.prerelease? or options[:prerelease]
found += Gem::SpecFetcher.fetcher.fetch dep, false, true, true
end
dep.prerelease = options[:prerelease]
found, _ = Gem::SpecFetcher.fetcher.spec_for_dependency dep
specs.push(*found.map { |spec,| spec })
end
if specs.empty? then
alert_error "Unknown gem '#{gem}'"
alert_error "No gem matching '#{dep}' found"
terminate_interaction 1
end

Просмотреть файл

@ -13,7 +13,8 @@ class Gem::Commands::UninstallCommand < Gem::Command
def initialize
super 'uninstall', 'Uninstall gems from the local repository',
:version => Gem::Requirement.default, :user_install => true
:version => Gem::Requirement.default, :user_install => true,
:check_dev => false
add_option('-a', '--[no-]all',
'Uninstall all matching versions'
@ -27,6 +28,12 @@ class Gem::Commands::UninstallCommand < Gem::Command
options[:ignore] = value
end
add_option('-D', '--[no-]-check-development',
'Check development dependencies while uninstalling',
'(default: false)') do |value, options|
options[:check_dev] = value
end
add_option('-x', '--[no-]executables',
'Uninstall applicable executables without',
'confirmation') do |value, options|
@ -54,6 +61,12 @@ class Gem::Commands::UninstallCommand < Gem::Command
options[:format_executable] = value
end
add_option('--[no-]force',
'Uninstall all versions of the named gems',
'ignoring dependencies') do |value, options|
options[:force] = value
end
add_version_option
add_platform_option
end
@ -73,19 +86,23 @@ class Gem::Commands::UninstallCommand < Gem::Command
end
def execute
original_path = Gem.path
# REFACTOR: stolen from cleanup_command
deplist = Gem::DependencyList.new
get_all_gem_names.uniq.each do |name|
Gem::Specification.find_all_by_name(name).each do |spec|
deplist.add spec
end
end
get_all_gem_names.each do |gem_name|
deps = deplist.strongly_connected_components.flatten.reverse
deps.map(&:name).uniq.each do |gem_name|
begin
Gem::Uninstaller.new(gem_name, options).uninstall
rescue Gem::InstallError => e
alert e.message
rescue Gem::GemNotInHomeException => e
spec = e.spec
alert("In order to remove #{spec.name}, please execute:\n" \
"\tgem uninstall #{spec.name} --install-dir=#{spec.installation_path}")
ensure
Gem.use_paths(*original_path)
end
end
end

Просмотреть файл

@ -69,8 +69,10 @@ class Gem::Commands::UnpackCommand < Gem::Command
else
basename = File.basename path, '.gem'
target_dir = File.expand_path basename, options[:target]
FileUtils.mkdir_p target_dir
Gem::Installer.new(path, :unpack => true).unpack target_dir
package = Gem::Package.new path
package.extract_files target_dir
say "Unpacked gem: '#{target_dir}'"
end
end
@ -134,9 +136,11 @@ class Gem::Commands::UnpackCommand < Gem::Command
##
# Extracts the Gem::Specification and raw metadata from the .gem file at
# +path+.
#--
# TODO move to Gem::Package as #raw_spec or something
def get_metadata path
format = Gem::Format.from_file_by_path path
format = Gem::Package.new path
spec = format.spec
metadata = nil

Просмотреть файл

@ -1,10 +1,12 @@
require 'rubygems/command'
require 'rubygems/command_manager'
require 'rubygems/dependency_installer'
require 'rubygems/install_update_options'
require 'rubygems/local_remote_options'
require 'rubygems/spec_fetcher'
require 'rubygems/version_option'
require 'rubygems/commands/install_command'
require 'rubygems/install_message' # must come before rdoc for messaging
require 'rubygems/rdoc'
class Gem::Commands::UpdateCommand < Gem::Command
@ -13,11 +15,9 @@ class Gem::Commands::UpdateCommand < Gem::Command
include Gem::VersionOption
def initialize
super 'update',
'Update the named gems (or all installed gems) in the local repository',
:generate_rdoc => true,
:generate_ri => true,
:force => false
super 'update', 'Update installed gems to the latest version',
:document => %w[rdoc ri],
:force => false
add_install_update_options
@ -37,6 +37,9 @@ class Gem::Commands::UpdateCommand < Gem::Command
add_local_remote_options
add_platform_option
add_prerelease_option "as update targets"
@updated = []
@installer = Gem::DependencyInstaller.new options
end
def arguments # :nodoc:
@ -44,7 +47,7 @@ class Gem::Commands::UpdateCommand < Gem::Command
end
def defaults_str # :nodoc:
"--rdoc --ri --no-force --install-dir #{Gem.dir}"
"--document --no-force --install-dir #{Gem.dir}"
end
def usage # :nodoc:
@ -52,9 +55,6 @@ class Gem::Commands::UpdateCommand < Gem::Command
end
def execute
@installer = Gem::DependencyInstaller.new options
@updated = []
hig = {}
if options[:system] then
@ -79,21 +79,7 @@ class Gem::Commands::UpdateCommand < Gem::Command
if updated.empty? then
say "Nothing to update"
else
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
say "Gems updated: #{updated.map { |spec| spec.name }.join ' '}"
end
end
@ -112,7 +98,6 @@ class Gem::Commands::UpdateCommand < Gem::Command
@installer.installed_gems.each do |spec|
@updated << spec
say "Successfully installed #{spec.full_name}" if success
end
end
@ -178,8 +163,9 @@ class Gem::Commands::UpdateCommand < Gem::Command
args = []
args << '--prefix' << Gem.prefix if Gem.prefix
args << '--no-rdoc' unless options[:generate_rdoc]
args << '--no-ri' unless options[:generate_ri]
# TODO use --document for >= 1.9 , --no-rdoc --no-ri < 1.9
args << '--no-rdoc' unless options[:document].include? 'rdoc'
args << '--no-ri' unless options[:document].include? 'ri'
args << '--no-format-executable' if options[:no_format_executable]
update_dir = File.join Gem.dir, 'gems', "rubygems-update-#{version}"
@ -205,20 +191,20 @@ class Gem::Commands::UpdateCommand < Gem::Command
gem_names.all? { |name| /#{name}/ !~ l_spec.name }
dependency = Gem::Dependency.new l_spec.name, "> #{l_spec.version}"
dependency.prerelease = options[:prerelease]
fetcher = Gem::SpecFetcher.fetcher
spec_tuples = fetcher.find_matching dependency
matching_gems = spec_tuples.select do |(name, _, platform),|
name == l_name and Gem::Platform.match platform
spec_tuples, _ = fetcher.search_for_dependency dependency
matching_gems = spec_tuples.select do |g,_|
g.name == l_name and g.match_platform?
end
highest_remote_gem = matching_gems.sort_by do |(_, version),|
version
end.last
highest_remote_gem = matching_gems.sort_by { |g,_| g.version }.last
highest_remote_gem ||= [[nil, Gem::Version.new(0), nil]] # "null" object
highest_remote_ver = highest_remote_gem.first[1]
highest_remote_gem ||= [Gem::NameTuple.null]
highest_remote_ver = highest_remote_gem.first.version
if system or (l_spec.version < highest_remote_ver) then
result << [l_spec.name, [l_spec.version, highest_remote_ver].max]

Просмотреть файл

@ -0,0 +1,98 @@
require 'rubygems/command'
require 'rubygems/local_remote_options'
require 'rubygems/version_option'
require 'rubygems/gemcutter_utilities'
class Gem::Commands::YankCommand < Gem::Command
include Gem::LocalRemoteOptions
include Gem::VersionOption
include Gem::GemcutterUtilities
def description # :nodoc:
'Remove a specific gem version release from RubyGems.org'
end
def arguments # :nodoc:
"GEM name of gem"
end
def usage # :nodoc:
"#{program_name} GEM -v VERSION [-p PLATFORM] [--undo] [--key KEY_NAME]"
end
def initialize
super 'yank', description
add_version_option("remove")
add_platform_option("remove")
add_option('--undo') do |value, options|
options[:undo] = true
end
add_option('-k', '--key KEY_NAME',
'Use API key from your gem credentials file') do |value, options|
options[:key] = value
end
end
def execute
sign_in
version = get_version_from_requirements(options[:version])
platform = get_platform_from_requirements(options)
api_key = Gem.configuration.rubygems_api_key
api_key = Gem.configuration.api_keys[options[:key].to_sym] if options[:key]
if version then
if options[:undo] then
unyank_gem(version, platform, api_key)
else
yank_gem(version, platform, api_key)
end
else
say "A version argument is required: #{usage}"
terminate_interaction
end
end
def yank_gem(version, platform, api_key)
say "Yanking gem from #{self.host}..."
yank_api_request(:delete, version, platform, "api/v1/gems/yank", api_key)
end
def unyank_gem(version, platform, api_key)
say "Unyanking gem from #{host}..."
yank_api_request(:put, version, platform, "api/v1/gems/unyank", api_key)
end
private
def yank_api_request(method, version, platform, api, api_key)
name = get_one_gem_name
response = rubygems_api_request(method, api) do |request|
request.add_field("Authorization", api_key)
data = {
'gem_name' => name,
'version' => version,
}
data['platform'] = platform if platform
request.set_form_data data
end
say response.body
end
def get_version_from_requirements(requirements)
requirements.requirements.first[1].version
rescue
nil
end
def get_platform_from_requirements(requirements)
Gem.platforms[1].to_s if requirements.key? :added_platform
end
end

Просмотреть файл

@ -0,0 +1,51 @@
# This file contains all sorts of little compatibility hacks that we've
# had to introduce over the years. Quarantining them into one file helps
# us know when we can get rid of them.
# Ruby 1.9.x has introduced some things that are awkward, and we need to
# support them, so we define some constants to use later.
module Gem
# Only MRI 1.9.2 has the custom prelude.
GEM_PRELUDE_SUCKAGE = RUBY_VERSION =~ /^1\.9\.2/ and RUBY_ENGINE == "ruby"
end
# Gem::QuickLoader exists in the gem prelude code in ruby 1.9.2 itself.
# We gotta get rid of it if it's there, before we do anything else.
if Gem::GEM_PRELUDE_SUCKAGE and defined?(Gem::QuickLoader) then
Gem::QuickLoader.remove
$LOADED_FEATURES.delete Gem::QuickLoader.path_to_full_rubygems_library
if $LOADED_FEATURES.any? do |path| path.end_with? '/rubygems.rb' end then
# TODO path does not exist here
raise LoadError, "another rubygems is already loaded from #{path}"
end
class << Gem
remove_method :try_activate if Gem.respond_to?(:try_activate, true)
end
end
module Gem
RubyGemsVersion = VERSION
RbConfigPriorities = %w[
EXEEXT RUBY_SO_NAME arch bindir datadir libdir ruby_install_name
ruby_version rubylibprefix sitedir sitelibdir vendordir vendorlibdir
rubylibdir
]
unless defined?(ConfigMap)
##
# Configuration settings from ::RbConfig
ConfigMap = Hash.new do |cm, key|
cm[key] = RbConfig::CONFIG[key.to_s]
end
else
RbConfigPriorities.each do |key|
ConfigMap[key.to_sym] = RbConfig::CONFIG[key]
end
end
RubyGemsPackageVersion = VERSION
end

Просмотреть файл

@ -5,9 +5,9 @@
#++
##
# Gem::ConfigFile RubyGems options and gem command options from ~/.gemrc.
# Gem::ConfigFile RubyGems options and gem command options from gemrc.
#
# ~/.gemrc is a YAML file that uses strings to match gem command arguments and
# gemrc is a YAML file that uses strings to match gem command arguments and
# symbols to match RubyGems options.
#
# Gem command arguments use a String key that matches the command name and
@ -21,16 +21,19 @@
# RubyGems options use symbol keys. Valid options are:
#
# +:backtrace+:: See #backtrace
# +:benchmark+:: See #benchmark
# +:sources+:: Sets Gem::sources
# +:verbose+:: See #verbose
require 'rbconfig'
#
# gemrc files may exist in various locations and are read and merged in
# the following order:
#
# - system wide (/etc/gemrc)
# - per user (~/.gemrc)
# - per environment (gemrc files listed in the GEMRC environment variable)
class Gem::ConfigFile
DEFAULT_BACKTRACE = false
DEFAULT_BENCHMARK = false
DEFAULT_BULK_THRESHOLD = 1000
DEFAULT_VERBOSITY = true
DEFAULT_UPDATE_SOURCES = true
@ -96,11 +99,6 @@ class Gem::ConfigFile
attr_writer :backtrace
##
# True if we are benchmarking this run.
attr_accessor :benchmark
##
# Bulk threshold value. If the number of missing gems are above this
# threshold value, then a bulk download technique is used. (deprecated)
@ -131,6 +129,10 @@ class Gem::ConfigFile
attr_reader :api_keys
##
# True if we want to force specification of gem server when pushing a gem
attr_accessor :disable_default_gem_server
# openssl verify mode value, used for remote https connection
attr_reader :ssl_verify_mode
@ -158,29 +160,29 @@ class Gem::ConfigFile
# <tt>--debug</tt>::
# Enable Ruby level debug messages. Handled early for the same reason as
# --backtrace.
#--
# TODO: parse options upstream, pass in options directly
def initialize(arg_list)
def initialize(args)
@config_file_name = nil
need_config_file_name = false
arg_list = arg_list.map do |arg|
arg_list = []
args.each do |arg|
if need_config_file_name then
@config_file_name = arg
need_config_file_name = false
nil
elsif arg =~ /^--config-file=(.*)/ then
@config_file_name = $1
nil
elsif arg =~ /^--config-file$/ then
need_config_file_name = true
nil
else
arg
arg_list << arg
end
end.compact
end
@backtrace = DEFAULT_BACKTRACE
@benchmark = DEFAULT_BENCHMARK
@bulk_threshold = DEFAULT_BULK_THRESHOLD
@verbose = DEFAULT_VERBOSITY
@update_sources = DEFAULT_UPDATE_SOURCES
@ -189,19 +191,25 @@ class Gem::ConfigFile
platform_config = Marshal.load Marshal.dump(PLATFORM_DEFAULTS)
system_config = load_file SYSTEM_WIDE_CONFIG_FILE
user_config = load_file config_file_name.dup.untaint
environment_config = (ENV['GEMRC'] || '').split(/[:;]/).inject({}) do |result, file|
result.merge load_file file
end
@hash = operating_system_config.merge platform_config
@hash = @hash.merge system_config
@hash = @hash.merge user_config
@hash = @hash.merge environment_config
# HACK these override command-line args, which is bad
@backtrace = @hash[:backtrace] if @hash.key? :backtrace
@benchmark = @hash[:benchmark] if @hash.key? :benchmark
@bulk_threshold = @hash[:bulk_threshold] if @hash.key? :bulk_threshold
@home = @hash[:gemhome] if @hash.key? :gemhome
@path = @hash[:gempath] if @hash.key? :gempath
@update_sources = @hash[:update_sources] if @hash.key? :update_sources
@verbose = @hash[:verbose] if @hash.key? :verbose
@backtrace = @hash[:backtrace] if @hash.key? :backtrace
@bulk_threshold = @hash[:bulk_threshold] if @hash.key? :bulk_threshold
@home = @hash[:gemhome] if @hash.key? :gemhome
@path = @hash[:gempath] if @hash.key? :gempath
@update_sources = @hash[:update_sources] if @hash.key? :update_sources
@verbose = @hash[:verbose] if @hash.key? :verbose
@disable_default_gem_server = @hash[:disable_default_gem_server] if @hash.key? :disable_default_gem_server
@ssl_verify_mode = @hash[:ssl_verify_mode] if @hash.key? :ssl_verify_mode
@ssl_ca_cert = @hash[:ssl_ca_cert] if @hash.key? :ssl_ca_cert
@ -224,6 +232,7 @@ class Gem::ConfigFile
else
@hash
end
if @api_keys.key? :rubygems_api_key then
@rubygems_api_key = @api_keys[:rubygems_api_key]
@api_keys[:rubygems] = @api_keys.delete :rubygems_api_key unless @api_keys.key? :rubygems
@ -238,7 +247,8 @@ class Gem::ConfigFile
Gem.load_yaml
File.open(credentials_path, 'w') do |f|
permissions = 0600 & (~File.umask)
File.open(credentials_path, 'w', permissions) do |f|
f.write config.to_yaml
end
@ -249,13 +259,21 @@ class Gem::ConfigFile
Gem.load_yaml
return {} unless filename and File.exist? filename
begin
YAML.load(File.read(filename))
content = YAML.load(File.read(filename))
unless content.kind_of? Hash
warn "Failed to load #{config_file_name} because it doesn't contain valid YAML hash"
return {}
end
return content
rescue ArgumentError
warn "Failed to load #{config_file_name}"
rescue Errno::EACCES
warn "Failed to load #{config_file_name} due to permissions problem."
end or {}
end
{}
end
# True if the backtrace option has been specified, or debug is on.
@ -273,13 +291,11 @@ class Gem::ConfigFile
hash = @hash.dup
hash.delete :update_sources
hash.delete :verbose
hash.delete :benchmark
hash.delete :backtrace
hash.delete :bulk_threshold
yield :update_sources, @update_sources
yield :verbose, @verbose
yield :benchmark, @benchmark
yield :backtrace, @backtrace
yield :bulk_threshold, @bulk_threshold
@ -296,8 +312,6 @@ class Gem::ConfigFile
case arg
when /^--(backtrace|traceback)$/ then
@backtrace = true
when /^--bench(mark)?$/ then
@benchmark = true
when /^--debug$/ then
$DEBUG = true
else
@ -309,25 +323,41 @@ class Gem::ConfigFile
# Really verbose mode gives you extra output.
def really_verbose
case verbose
when true, false, nil then false
else true
when true, false, nil then
false
else
true
end
end
# to_yaml only overwrites things you can't override on the command line.
def to_yaml # :nodoc:
yaml_hash = {}
yaml_hash[:backtrace] = @hash.key?(:backtrace) ? @hash[:backtrace] :
DEFAULT_BACKTRACE
yaml_hash[:benchmark] = @hash.key?(:benchmark) ? @hash[:benchmark] :
DEFAULT_BENCHMARK
yaml_hash[:bulk_threshold] = @hash.key?(:bulk_threshold) ?
@hash[:bulk_threshold] : DEFAULT_BULK_THRESHOLD
yaml_hash[:sources] = Gem.sources
yaml_hash[:update_sources] = @hash.key?(:update_sources) ?
@hash[:update_sources] : DEFAULT_UPDATE_SOURCES
yaml_hash[:verbose] = @hash.key?(:verbose) ? @hash[:verbose] :
DEFAULT_VERBOSITY
yaml_hash[:backtrace] = if @hash.key?(:backtrace)
@hash[:backtrace]
else
DEFAULT_BACKTRACE
end
yaml_hash[:bulk_threshold] = if @hash.key?(:bulk_threshold)
@hash[:bulk_threshold]
else
DEFAULT_BULK_THRESHOLD
end
yaml_hash[:sources] = Gem.sources.to_a
yaml_hash[:update_sources] = if @hash.key?(:update_sources)
@hash[:update_sources]
else
DEFAULT_UPDATE_SOURCES
end
yaml_hash[:verbose] = if @hash.key?(:verbose)
@hash[:verbose]
else
DEFAULT_VERBOSITY
end
keys = yaml_hash.keys.map { |key| key.to_s }
keys << 'debug'
@ -361,15 +391,13 @@ class Gem::ConfigFile
def ==(other) # :nodoc:
self.class === other and
@backtrace == other.backtrace and
@benchmark == other.benchmark and
@bulk_threshold == other.bulk_threshold and
@verbose == other.verbose and
@update_sources == other.update_sources and
@hash == other.hash
@backtrace == other.backtrace and
@bulk_threshold == other.bulk_threshold and
@verbose == other.verbose and
@update_sources == other.update_sources and
@hash == other.hash
end
protected
attr_reader :hash
protected :hash
end

Просмотреть файл

@ -0,0 +1,53 @@
module Kernel
# REFACTOR: This should be pulled out into some kind of hacks file.
remove_method :gem if 'method' == defined? gem # from gem_prelude.rb on 1.9
##
# Use Kernel#gem to activate a specific version of +gem_name+.
#
# +requirements+ is a list of version requirements that the
# specified gem must match, most commonly "= example.version.number". See
# Gem::Requirement for how to specify a version requirement.
#
# If you will be activating the latest version of a gem, there is no need to
# call Kernel#gem, Kernel#require will do the right thing for you.
#
# Kernel#gem returns true if the gem was activated, otherwise false. If the
# gem could not be found, didn't match the version requirements, or a
# different version was already activated, an exception will be raised.
#
# Kernel#gem should be called *before* any require statements (otherwise
# RubyGems may load a conflicting library version).
#
# In older RubyGems versions, the environment variable GEM_SKIP could be
# used to skip activation of specified gems, for example to test out changes
# that haven't been installed yet. Now RubyGems defers to -I and the
# RUBYLIB environment variable to skip activation of a gem.
#
# Example:
#
# GEM_SKIP=libA:libB ruby -I../libA -I../libB ./mycode.rb
def gem(gem_name, *requirements) # :doc:
skip_list = (ENV['GEM_SKIP'] || "").split(/:/)
raise Gem::LoadError, "skipping #{gem_name}" if skip_list.include? gem_name
if gem_name.kind_of? Gem::Dependency
unless Gem::Deprecate.skip
warn "#{Gem.location_of_caller.join ':'}:Warning: Kernel.gem no longer "\
"accepts a Gem::Dependency object, please pass the name "\
"and requirements directly"
end
requirements = gem_name.requirement
gem_name = gem_name.name
end
spec = Gem::Dependency.new(gem_name, *requirements).to_spec
spec.activate if spec
end
private :gem
end

Просмотреть файл

@ -0,0 +1,119 @@
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
# See LICENSE.txt for permissions.
#++
module Kernel
if defined?(gem_original_require) then
# Ruby ships with a custom_require, override its require
remove_method :require
else
##
# The Kernel#require from before RubyGems was loaded.
alias gem_original_require require
private :gem_original_require
end
##
# When RubyGems is required, Kernel#require is replaced with our own which
# is capable of loading gems on demand.
#
# When you call <tt>require 'x'</tt>, this is what happens:
# * If the file can be loaded from the existing Ruby loadpath, it
# is.
# * Otherwise, installed gems are searched for a file that matches.
# If it's found in gem 'y', that gem is activated (added to the
# loadpath).
#
# The normal <tt>require</tt> functionality of returning false if
# that file has already been loaded is preserved.
def require path
spec = Gem.find_unresolved_default_spec(path)
if spec
Gem.remove_unresolved_default_spec(spec)
gem(spec.name)
end
# If there are no unresolved deps, then we can use just try
# normal require handle loading a gem from the rescue below.
if Gem::Specification.unresolved_deps.empty? then
return gem_original_require(path)
end
# If +path+ is for a gem that has already been loaded, don't
# bother trying to find it in an unresolved gem, just go straight
# to normal require.
#--
# TODO request access to the C implementation of this to speed up RubyGems
spec = Gem::Specification.find { |s|
s.activated? and s.contains_requirable_file? path
}
return gem_original_require(path) if spec
# Attempt to find +path+ in any unresolved gems...
found_specs = Gem::Specification.find_in_unresolved path
# If there are no directly unresolved gems, then try and find +path+
# in any gems that are available via the currently unresolved gems.
# For example, given:
#
# a => b => c => d
#
# If a and b are currently active with c being unresolved and d.rb is
# requested, then find_in_unresolved_tree will find d.rb in d because
# it's a dependency of c.
#
if found_specs.empty? then
found_specs = Gem::Specification.find_in_unresolved_tree path
found_specs.each do |found_spec|
found_spec.activate
end
# We found +path+ directly in an unresolved gem. Now we figure out, of
# the possible found specs, which one we should activate.
else
# Check that all the found specs are just different
# versions of the same gem
names = found_specs.map(&:name).uniq
if names.size > 1 then
raise Gem::LoadError, "#{path} found in multiple gems: #{names.join ', '}"
end
# Ok, now find a gem that has no conflicts, starting
# at the highest version.
valid = found_specs.select { |s| s.conflicts.empty? }.last
unless valid then
le = Gem::LoadError.new "unable to find a version of '#{names.first}' to activate"
le.name = names.first
raise le
end
valid.activate
end
gem_original_require path
rescue LoadError => load_error
if load_error.message.start_with?("Could not find") or
(load_error.message.end_with?(path) and Gem.try_activate(path)) then
return gem_original_require(path)
end
raise load_error
end
private :require
end

Просмотреть файл

@ -1,69 +0,0 @@
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
# See LICENSE.txt for permissions.
#++
module Kernel
if defined?(gem_original_require) then
# Ruby ships with a custom_require, override its require
remove_method :require
else
##
# The Kernel#require from before RubyGems was loaded.
alias gem_original_require require
private :gem_original_require
end
##
# When RubyGems is required, Kernel#require is replaced with our own which
# is capable of loading gems on demand.
#
# When you call <tt>require 'x'</tt>, this is what happens:
# * If the file can be loaded from the existing Ruby loadpath, it
# is.
# * Otherwise, installed gems are searched for a file that matches.
# If it's found in gem 'y', that gem is activated (added to the
# loadpath).
#
# The normal <tt>require</tt> functionality of returning false if
# that file has already been loaded is preserved.
def require path
if Gem.unresolved_deps.empty? then
gem_original_require path
else
spec = Gem::Specification.find { |s|
s.activated? and s.contains_requirable_file? path
}
unless spec then
found_specs = Gem::Specification.find_in_unresolved path
unless found_specs.empty? then
found_specs = [found_specs.last]
else
found_specs = Gem::Specification.find_in_unresolved_tree path
end
found_specs.each do |found_spec|
found_spec.activate
end
end
return gem_original_require path
end
rescue LoadError => load_error
if load_error.message.start_with?("Could not find") or
(load_error.message.end_with?(path) and Gem.try_activate(path)) then
return gem_original_require(path)
end
raise load_error
end
private :require
end

Просмотреть файл

@ -1,8 +1,8 @@
module Gem
# TODO: move this whole file back into rubygems.rb
DEFAULT_HOST = "https://rubygems.org"
@post_install_hooks ||= []
@done_installing_hooks ||= []
@post_uninstall_hooks ||= []
@pre_uninstall_hooks ||= []
@pre_install_hooks ||= []
@ -61,7 +61,7 @@ module Gem
# Default gem load path
def self.default_path
if File.exist? Gem.user_home then
if Gem.user_home && File.exist?(Gem.user_home) then
[user_dir, default_dir]
else
[default_dir]
@ -93,24 +93,6 @@ module Gem
end
end
##
# The default system-wide source info cache directory
def self.default_system_source_cache_dir
File.join(Gem.dir, 'source_cache')
end
##
# The default user-specific source info cache directory
def self.default_user_source_cache_dir
#
# NOTE Probably an argument for moving this to per-ruby supported dirs like
# user_dir
#
File.join(Gem.user_home, '.gem', 'source_cache')
end
##
# A wrapper around RUBY_ENGINE const that may not be defined

Просмотреть файл

@ -1,8 +1,8 @@
require "rubygems/requirement"
##
# The Dependency class holds a Gem name and a Gem::Requirement.
require "rubygems/requirement"
class Gem::Dependency
##
@ -11,6 +11,9 @@ class Gem::Dependency
# When this list is updated, be sure to change
# Gem::Specification::CURRENT_SPECIFICATION_VERSION as well.
# REFACTOR: This type of constant, TYPES, indicates we might want
# two classes, used via inheretance or duck typing.
TYPES = [
:development,
:runtime,
@ -32,18 +35,23 @@ class Gem::Dependency
# <tt>:runtime</tt>.
def initialize name, *requirements
if Regexp === name then
case name
when String then # ok
when Regexp then
msg = ["NOTE: Dependency.new w/ a regexp is deprecated.",
"Dependency.new called from #{Gem.location_of_caller.join(":")}"]
warn msg.join("\n") unless Gem::Deprecate.skip
else
raise ArgumentError,
"dependency name must be a String, was #{name.inspect}"
end
type = Symbol === requirements.last ? requirements.pop : :runtime
requirements = requirements.first if 1 == requirements.length # unpack
unless TYPES.include? type
raise ArgumentError, "Valid types are #{TYPES.inspect}, "
+ "not #{type.inspect}"
raise ArgumentError, "Valid types are #{TYPES.inspect}, " +
"not #{type.inspect}"
end
@name = name
@ -66,8 +74,13 @@ class Gem::Dependency
end
def inspect # :nodoc:
"<%s type=%p name=%p requirements=%p>" %
[self.class, self.type, self.name, requirement.to_s]
if @prerelease
"<%s type=%p name=%p requirements=%p prerelease=ok>" %
[self.class, self.type, self.name, requirement.to_s]
else
"<%s type=%p name=%p requirements=%p>" %
[self.class, self.type, self.name, requirement.to_s]
end
end
##
@ -77,6 +90,14 @@ class Gem::Dependency
@prerelease || requirement.prerelease?
end
##
# Is this dependency simply asking for the latest version
# of a gem?
def latest_version?
@requirement.none?
end
def pretty_print q # :nodoc:
q.group 1, 'Gem::Dependency.new(', ')' do
q.pp name
@ -113,6 +134,8 @@ class Gem::Dependency
# Children, define explicit marshal and unmarshal behavior for
# public classes. Marshal formats are part of your public API.
# REFACTOR: See above
if defined?(@version_requirement) && @version_requirement
version = @version_requirement.instance_variable_get :@version
@version_requirement = nil
@ -122,6 +145,7 @@ class Gem::Dependency
@requirement = @version_requirements if defined?(@version_requirements)
end
# DOC: this method needs documentation or :nodoc''d
def requirements_list
requirement.as_list
end
@ -179,13 +203,24 @@ class Gem::Dependency
requirement.satisfied_by? version
end
def match? name, version
# DOC: this method needs either documented or :nodoc'd
def match? obj, version=nil
if !version
name = obj.name
version = obj.version
else
name = obj
end
return false unless self.name === name
return true if requirement.none?
requirement.satisfied_by? Gem::Version.new(version)
end
# DOC: this method needs either documented or :nodoc'd
def matches_spec? spec
return false unless name === spec.name
return true if requirement.none?
@ -212,6 +247,8 @@ class Gem::Dependency
self.class.new name, self_req.as_list.concat(other_req.as_list)
end
# DOC: this method needs either documented or :nodoc'd
def matching_specs platform_only = false
matches = Gem::Specification.find_all { |spec|
self.name === spec.name and # TODO: == instead of ===
@ -234,14 +271,26 @@ class Gem::Dependency
@requirement.specific?
end
# DOC: this method needs either documented or :nodoc'd
def to_specs
matches = matching_specs true
# TODO: check Gem.activated_spec[self.name] in case matches falls outside
if matches.empty? then
specs = Gem::Specification.all_names.join ", "
error = Gem::LoadError.new "Could not find #{name} (#{requirement}) amongst [#{specs}]"
specs = Gem::Specification.find_all { |s|
s.name == name
}.map { |x| x.full_name }
if specs.empty?
total = Gem::Specification.to_a.size
error = Gem::LoadError.new \
"Could not find '#{name}' (#{requirement}) among #{total} total gem(s)"
else
error = Gem::LoadError.new \
"Could not find '#{name}' (#{requirement}) - did find: [#{specs.join ','}]"
end
error.name = self.name
error.requirement = self.requirement
raise error
@ -252,6 +301,8 @@ class Gem::Dependency
matches
end
# DOC: this method needs either documented or :nodoc'd
def to_spec
matches = self.to_specs

Просмотреть файл

@ -1,8 +1,12 @@
require 'rubygems'
require 'rubygems/dependency_list'
require 'rubygems/package'
require 'rubygems/installer'
require 'rubygems/spec_fetcher'
require 'rubygems/user_interaction'
require 'rubygems/source_local'
require 'rubygems/source_specific_file'
require 'rubygems/available_set'
##
# Installs a gem along with all its dependencies from local and remote gems.
@ -14,8 +18,14 @@ class Gem::DependencyInstaller
attr_reader :gems_to_install
attr_reader :installed_gems
##
# Documentation types. For use by the Gem.done_installing hook
attr_reader :document
DEFAULT_OPTIONS = {
:env_shebang => false,
:document => %w[ri],
:domain => :both, # HACK dup
:force => false,
:format_executable => false, # HACK dup
@ -23,7 +33,8 @@ class Gem::DependencyInstaller
:prerelease => false,
:security_policy => nil, # HACK NoSecurity requires OpenSSL. AlmostNo? Low?
:wrappers => true,
}
:build_docs_in_background => false,
}.freeze
##
# Creates a new installer instance.
@ -47,6 +58,7 @@ class Gem::DependencyInstaller
if options[:install_dir] then
@gem_home = options[:install_dir]
# HACK shouldn't change the global settings
Gem::Specification.dirs = @gem_home
Gem.ensure_gem_subdirectories @gem_home
options[:install_dir] = @gem_home # FIX: because we suck and reuse below
@ -55,7 +67,9 @@ class Gem::DependencyInstaller
options = DEFAULT_OPTIONS.merge options
@bin_dir = options[:bin_dir]
@dev_shallow = options[:dev_shallow]
@development = options[:development]
@document = options[:document]
@domain = options[:domain]
@env_shebang = options[:env_shebang]
@force = options[:force]
@ -65,8 +79,14 @@ class Gem::DependencyInstaller
@security_policy = options[:security_policy]
@user_install = options[:user_install]
@wrappers = options[:wrappers]
@build_docs_in_background = options[:build_docs_in_background]
# Indicates that we should not try to update any deps unless
# we absolutely must.
@minimal_deps = options[:minimal_deps]
@installed_gems = []
@toplevel_specs = nil
@install_dir = options[:install_dir] || Gem.dir
@cache_dir = options[:cache_dir] || @install_dir
@ -76,6 +96,24 @@ class Gem::DependencyInstaller
@errors = nil
end
attr_reader :errors
##
# Indicated, based on the requested domain, if local
# gems should be considered.
def consider_local?
@domain == :both or @domain == :local
end
##
# Indicated, based on the requested domain, if remote
# gems should be considered.
def consider_remote?
@domain == :both or @domain == :remote
end
##
# Returns a list of pairs of gemspecs and source_uris that match
# Gem::Dependency +dep+ from both local (Dir.pwd) and remote (Gem.sources)
@ -83,35 +121,34 @@ class Gem::DependencyInstaller
# local gems preferred over remote gems.
def find_gems_with_sources(dep)
# Reset the errors
@errors = nil
gems_and_sources = []
set = Gem::AvailableSet.new
if @domain == :both or @domain == :local then
Dir[File.join(Dir.pwd, "#{dep.name}-[0-9]*.gem")].each do |gem_file|
spec = Gem::Format.from_file_by_path(gem_file).spec
gems_and_sources << [spec, gem_file] if spec.name == dep.name
if consider_local?
sl = Gem::Source::Local.new
if spec = sl.find_gem(dep.name)
if dep.matches_spec? spec
set.add spec, sl
end
end
end
if @domain == :both or @domain == :remote then
if consider_remote?
begin
# REFACTOR: all = dep.requirement.needs_all?
requirements = dep.requirement.requirements.map do |req, ver|
req
found, errors = Gem::SpecFetcher.fetcher.spec_for_dependency dep
if @errors
@errors += errors
else
@errors = errors
end
all = !dep.prerelease? &&
# we only need latest if there's one requirement and it is
# guaranteed to match the newest specs
(requirements.length > 1 or
(requirements.first != ">=" and requirements.first != ">"))
found, @errors = Gem::SpecFetcher.fetcher.fetch_with_errors dep, all, true, dep.prerelease?
gems_and_sources.push(*found)
set << found
rescue Gem::RemoteFetcher::FetchError => e
# FIX if there is a problem talking to the network, we either need to always tell
# the user (no really_verbose) or fail hard, not silently tell them that we just
# couldn't find their requested gem.
if Gem.configuration.really_verbose then
say "Error fetching remote data:\t\t#{e.message}"
say "Falling back to local-only install"
@ -120,9 +157,7 @@ class Gem::DependencyInstaller
end
end
gems_and_sources.sort_by do |gem, source|
[gem, source =~ /^http:\/\// ? 0 : 1] # local gems win
end
set
end
##
@ -130,17 +165,22 @@ class Gem::DependencyInstaller
# remote sources unless the ignore_dependencies was given.
def gather_dependencies
specs = @specs_and_sources.map { |spec,_| spec }
specs = @available.all_specs
# these gems were listed by the user, always install them
keep_names = specs.map { |spec| spec.full_name }
if @dev_shallow
@toplevel_specs = keep_names
end
dependency_list = Gem::DependencyList.new @development
dependency_list.add(*specs)
to_do = specs.dup
add_found_dependencies to_do, dependency_list unless @ignore_dependencies
# REFACTOR maybe abstract away using Gem::Specification.include? so
# that this isn't dependent only on the currently installed gems
dependency_list.specs.reject! { |spec|
not keep_names.include?(spec.full_name) and
Gem::Specification.include?(spec)
@ -162,32 +202,43 @@ class Gem::DependencyInstaller
until to_do.empty? do
spec = to_do.shift
# HACK why is spec nil?
next if spec.nil? or seen[spec.name]
seen[spec.name] = true
deps = spec.runtime_dependencies
deps |= spec.development_dependencies if @development
if @development
if @dev_shallow
if @toplevel_specs.include? spec.full_name
deps |= spec.development_dependencies
end
else
deps |= spec.development_dependencies
end
end
deps.each do |dep|
dependencies[dep.name] = dependencies[dep.name].merge dep
results = find_gems_with_sources(dep).reverse
results.reject! do |dep_spec,|
to_do.push dep_spec
# already locally installed
Gem::Specification.any? do |installed_spec|
dep.name == installed_spec.name and
dep.requirement.satisfied_by? installed_spec.version
end
if @minimal_deps
next if Gem::Specification.any? do |installed_spec|
dep.name == installed_spec.name and
dep.requirement.satisfied_by? installed_spec.version
end
end
results.each do |dep_spec, source_uri|
@specs_and_sources << [dep_spec, source_uri]
results = find_gems_with_sources(dep)
dependency_list.add dep_spec
results.sorted.each do |t|
to_do.push t.spec
end
results.remove_installed! dep
@available << results
results.inject_into_list dependency_list
end
end
@ -202,42 +253,36 @@ class Gem::DependencyInstaller
def find_spec_by_name_and_version(gem_name,
version = Gem::Requirement.default,
prerelease = false)
spec_and_source = nil
glob = if File::ALT_SEPARATOR then
gem_name.gsub File::ALT_SEPARATOR, File::SEPARATOR
else
gem_name
end
set = Gem::AvailableSet.new
local_gems = Dir["#{glob}*"].sort.reverse
if consider_local?
if File.exists? gem_name
src = Gem::Source::SpecificFile.new(gem_name)
set.add src.spec, src
else
local = Gem::Source::Local.new
local_gems.each do |gem_file|
next unless gem_file =~ /gem$/
begin
spec = Gem::Format.from_file_by_path(gem_file).spec
spec_and_source = [spec, gem_file]
break
rescue SystemCallError, Gem::Package::FormatError
if s = local.find_gem(gem_name, version)
set.add s, local
end
end
end
unless spec_and_source then
if set.empty?
dep = Gem::Dependency.new gem_name, version
# HACK Dependency objects should be immutable
dep.prerelease = true if prerelease
spec_and_sources = find_gems_with_sources(dep).reverse
spec_and_source = spec_and_sources.find { |spec, source|
Gem::Platform.match spec.platform
}
set = find_gems_with_sources(dep)
set.match_platform!
end
if spec_and_source.nil? then
raise Gem::GemNotFoundException.new(
"Could not find a valid gem '#{gem_name}' (#{version}) locally or in a repository",
gem_name, version, @errors)
if set.empty?
raise Gem::SpecificGemNotFoundException.new(gem_name, version, @errors)
end
@specs_and_sources = [spec_and_source]
@available = set
end
##
@ -258,33 +303,49 @@ class Gem::DependencyInstaller
if String === dep_or_name then
find_spec_by_name_and_version dep_or_name, version, @prerelease
else
dep_or_name.prerelease = @prerelease
@specs_and_sources = [find_gems_with_sources(dep_or_name).last]
dep = dep_or_name.dup
dep.prerelease = @prerelease
@available = find_gems_with_sources(dep).pick_best!
end
@installed_gems = []
gather_dependencies
# REFACTOR is the last gem always the one that the user requested?
# This code assumes that but is that actually validated by the code?
last = @gems_to_install.size - 1
@gems_to_install.each_with_index do |spec, index|
# REFACTOR more current spec set hardcoding, should be abstracted?
next if Gem::Specification.include?(spec) and index != last
# TODO: make this sorta_verbose so other users can benefit from it
say "Installing gem #{spec.full_name}" if Gem.configuration.really_verbose
_, source_uri = @specs_and_sources.assoc spec
source = @available.source_for spec
begin
local_gem_path = Gem::RemoteFetcher.fetcher.download spec, source_uri,
@cache_dir
# REFACTOR make the fetcher to use configurable
local_gem_path = source.download spec, @cache_dir
rescue Gem::RemoteFetcher::FetchError
# TODO I doubt all fetch errors are recoverable, we should at least
# report the errors probably.
next if @force
raise
end
if @development
if @dev_shallow
is_dev = @toplevel_specs.include? spec.full_name
else
is_dev = true
end
end
inst = Gem::Installer.new local_gem_path,
:bin_dir => @bin_dir,
:development => @development,
:development => is_dev,
:env_shebang => @env_shebang,
:force => @force,
:format_executable => @format_executable,
@ -299,6 +360,33 @@ class Gem::DependencyInstaller
@installed_gems << spec
end
# Since this is currently only called for docs, we can be lazy and just say
# it's documentation. Ideally the hook adder could decide whether to be in
# the background or not, and what to call it.
in_background "Installing documentation" do
start = Time.now
Gem.done_installing_hooks.each do |hook|
hook.call self, @installed_gems
end
finish = Time.now
say "Done installing documentation for #{@installed_gems.map(&:name).join(', ')} (#{(finish-start).to_i} sec)."
end unless Gem.done_installing_hooks.empty?
@installed_gems
end
def in_background what
fork_happened = false
if @build_docs_in_background and Process.respond_to?(:fork)
begin
Process.fork do
yield
end
fork_happened = true
say "#{what} in a background process."
rescue NotImplementedError
end
end
yield unless fork_happened
end
end

Просмотреть файл

@ -10,6 +10,10 @@ require 'rubygems/deprecate'
##
# Gem::DependencyList is used for installing and uninstalling gems in the
# correct order to avoid conflicts.
#--
# TODO: It appears that all but topo-sort functionality is being duplicated
# (or is planned to be duplicated) elsewhere in rubygems. Is the majority of
# this class necessary anymore? Especially #ok?, #why_not_ok?
class Gem::DependencyList
attr_reader :specs
@ -27,19 +31,10 @@ class Gem::DependencyList
def self.from_specs
list = new
list.add(*Gem::Specification.map)
list.add(*Gem::Specification.to_a)
list
end
##
# Creates a DependencyList from a Gem::SourceIndex +source_index+
def self.from_source_index(ignored=nil)
warn "NOTE: DependencyList.from_source_index ignores it's arg" if ignored
from_specs
end
##
# Creates a new DependencyList. If +development+ is true, development
# dependencies will be included.
@ -143,7 +138,7 @@ class Gem::DependencyList
# If removing the gemspec creates breaks a currently ok dependency, then it
# is NOT ok to remove the gemspec.
def ok_to_remove?(full_name)
def ok_to_remove?(full_name, check_dev=true)
gem_to_remove = find_name full_name
siblings = @specs.find_all { |s|
@ -154,7 +149,9 @@ class Gem::DependencyList
deps = []
@specs.each do |spec|
spec.dependencies.each do |dep|
check = check_dev ? spec.dependencies : spec.runtime_dependencies
check.each do |dep|
deps << dep if gem_to_remove.satisfies_requirement?(dep)
end
end
@ -213,7 +210,7 @@ class Gem::DependencyList
@specs.each(&block)
end
def tsort_each_child(node, &block)
def tsort_each_child(node)
specs = @specs.sort.reverse
dependencies = node.runtime_dependencies
@ -242,11 +239,6 @@ class Gem::DependencyList
def active_count(specs, ignored)
specs.count { |spec| ignored[spec.full_name].nil? }
end
end
class Gem::DependencyList
class << self
extend Gem::Deprecate
deprecate :from_source_index, "from_specs", 2011, 11
end
end

Просмотреть файл

@ -0,0 +1,562 @@
require 'rubygems'
require 'rubygems/dependency'
require 'rubygems/exceptions'
require 'uri'
require 'net/http'
module Gem
# Raised when a DependencyConflict reaches the toplevel.
# Indicates which dependencies were incompatible.
#
class DependencyResolutionError < Gem::Exception
def initialize(conflict)
@conflict = conflict
a, b = conflicting_dependencies
super "unable to resolve conflicting dependencies '#{a}' and '#{b}'"
end
attr_reader :conflict
def conflicting_dependencies
@conflict.conflicting_dependencies
end
end
# Raised when a dependency requests a gem for which there is
# no spec.
#
class UnsatisfiableDepedencyError < Gem::Exception
def initialize(dep)
super "unable to find any gem matching dependency '#{dep}'"
@dependency = dep
end
attr_reader :dependency
end
# Raised when dependencies conflict and create the inability to
# find a valid possible spec for a request.
#
class ImpossibleDependenciesError < Gem::Exception
def initialize(request, conflicts)
s = conflicts.size == 1 ? "" : "s"
super "detected #{conflicts.size} conflict#{s} with dependency '#{request.dependency}'"
@request = request
@conflicts = conflicts
end
def dependency
@request.dependency
end
attr_reader :conflicts
end
# Given a set of Gem::Dependency objects as +needed+ and a way
# to query the set of available specs via +set+, calculates
# a set of ActivationRequest objects which indicate all the specs
# that should be activated to meet the all the requirements.
#
class DependencyResolver
# Represents a specification retrieved via the rubygems.org
# API. This is used to avoid having to load the full
# Specification object when all we need is the name, version,
# and dependencies.
#
class APISpecification
def initialize(set, api_data)
@set = set
@name = api_data[:name]
@version = Gem::Version.new api_data[:number]
@dependencies = api_data[:dependencies].map do |name, ver|
Gem::Dependency.new name, ver.split(/\s*,\s*/)
end
end
attr_reader :name, :version, :dependencies
def full_name
"#{@name}-#{@version}"
end
end
# The global rubygems pool, available via the rubygems.org API.
# Returns instances of APISpecification.
#
class APISet
def initialize
@data = Hash.new { |h,k| h[k] = [] }
end
# Return data for all versions of the gem +name+.
#
def versions(name)
if @data.key?(name)
return @data[name]
end
u = URI.parse "http://rubygems.org/api/v1/dependencies?gems=#{name}"
str = Net::HTTP.get(u)
Marshal.load(str).each do |ver|
@data[ver[:name]] << ver
end
@data[name]
end
# Return an array of APISpecification objects matching
# DependencyRequest +req+.
#
def find_all(req)
res = []
versions(req.name).each do |ver|
if req.dependency.match? req.name, ver[:number]
res << APISpecification.new(self, ver)
end
end
res
end
# A hint run by the resolver to allow the Set to fetch
# data for DependencyRequests +reqs+.
#
def prefetch(reqs)
names = reqs.map { |r| r.dependency.name }
needed = names.find_all { |d| !@data.key?(d) }
return if needed.empty?
u = URI.parse "http://rubygems.org/api/v1/dependencies?gems=#{needed.join ','}"
str = Net::HTTP.get(u)
Marshal.load(str).each do |ver|
@data[ver[:name]] << ver
end
end
end
# Represents a possible Specification object returned
# from IndexSet. Used to delay needed to download full
# Specification objects when only the +name+ and +version+
# are needed.
#
class IndexSpecification
def initialize(set, name, version, source, plat)
@set = set
@name = name
@version = version
@source = source
@platform = plat
@spec = nil
end
attr_reader :name, :version, :source
def full_name
"#{@name}-#{@version}"
end
def spec
@spec ||= @set.load_spec(@name, @version, @source)
end
def dependencies
spec.dependencies
end
end
# The global rubygems pool represented via the traditional
# source index.
#
class IndexSet
def initialize
@f = Gem::SpecFetcher.fetcher
@all = Hash.new { |h,k| h[k] = [] }
list, _ = @f.available_specs(:released)
list.each do |uri, specs|
specs.each do |n|
@all[n.name] << [uri, n]
end
end
@specs = {}
end
# Return an array of IndexSpecification objects matching
# DependencyRequest +req+.
#
def find_all(req)
res = []
name = req.dependency.name
@all[name].each do |uri, n|
if req.dependency.match? n
res << IndexSpecification.new(self, n.name, n.version,
uri, n.platform)
end
end
res
end
# No prefetching needed since we load the whole index in
# initially.
#
def prefetch(gems)
end
# Called from IndexSpecification to get a true Specification
# object.
#
def load_spec(name, ver, source)
key = "#{name}-#{ver}"
@specs[key] ||= source.fetch_spec(Gem::NameTuple.new(name, ver))
end
end
# A set which represents the installed gems. Respects
# all the normal settings that control where to look
# for installed gems.
#
class CurrentSet
def find_all(req)
req.dependency.matching_specs
end
def prefetch(gems)
end
end
# Create DependencyResolver object which will resolve
# the tree starting with +needed+ Depedency objects.
#
# +set+ is an object that provides where to look for
# specifications to satisify the Dependencies. This
# defaults to IndexSet, which will query rubygems.org.
#
def initialize(needed, set=IndexSet.new)
@set = set || IndexSet.new # Allow nil to mean IndexSet
@needed = needed
@conflicts = nil
end
# Provide a DependencyResolver that queries only against
# the already installed gems.
#
def self.for_current_gems(needed)
new needed, CurrentSet.new
end
# Contains all the conflicts encountered while doing resolution
#
attr_reader :conflicts
# Proceed with resolution! Returns an array of ActivationRequest
# objects.
#
def resolve
@conflicts = []
needed = @needed.map { |n| DependencyRequest.new(n, nil) }
res = resolve_for needed, []
if res.kind_of? DependencyConflict
raise DependencyResolutionError.new(res)
end
res
end
# Used internally to indicate that a dependency conflicted
# with a spec that would be activated.
#
class DependencyConflict
def initialize(dependency, activated, failed_dep=dependency)
@dependency = dependency
@activated = activated
@failed_dep = failed_dep
end
attr_reader :dependency, :activated
# Return the Specification that listed the dependency
#
def requester
@failed_dep.requester
end
def for_spec?(spec)
@dependency.name == spec.name
end
# Return the 2 dependency objects that conflicted
#
def conflicting_dependencies
[@failed_dep.dependency, @activated.request.dependency]
end
end
# Used Internally. Wraps a Depedency object to also track
# which spec contained the Dependency.
#
class DependencyRequest
def initialize(dep, act)
@dependency = dep
@requester = act
end
attr_reader :dependency, :requester
def name
@dependency.name
end
def matches_spec?(spec)
@dependency.matches_spec? spec
end
def to_s
@dependency.to_s
end
def ==(other)
case other
when Dependency
@dependency == other
when DependencyRequest
@dependency == other.dep && @requester == other.requester
else
false
end
end
end
# Specifies a Specification object that should be activated.
# Also contains a dependency that was used to introduce this
# activation.
#
class ActivationRequest
def initialize(spec, req, others_possible=true)
@spec = spec
@request = req
@others_possible = others_possible
end
attr_reader :spec, :request
# Indicate if this activation is one of a set of possible
# requests for the same Dependency request.
#
def others_possible?
@others_possible
end
# Return the ActivationRequest that contained the dependency
# that we were activated for.
#
def parent
@request.requester
end
def name
@spec.name
end
def full_name
@spec.full_name
end
def version
@spec.version
end
def full_spec
Gem::Specification === @spec ? @spec : @spec.spec
end
def download(path)
if @spec.respond_to? :source
source = @spec.source
else
source = Gem.sources.first
end
source.download full_spec, path
end
def ==(other)
case other
when Gem::Specification
@spec == other
when ActivationRequest
@spec == other.spec && @request == other.request
else
false
end
end
##
# Indicates if the requested gem has already been installed.
def installed?
this_spec = full_spec
Gem::Specification.any? do |s|
s == this_spec
end
end
end
def requests(s, act)
reqs = []
s.dependencies.each do |d|
next unless d.type == :runtime
reqs << DependencyRequest.new(d, act)
end
@set.prefetch(reqs)
reqs
end
# The meat of the algorithm. Given +needed+ DependencyRequest objects
# and +specs+ being a list to ActivationRequest, calculate a new list
# of ActivationRequest objects.
#
def resolve_for(needed, specs)
until needed.empty?
dep = needed.shift
# If there is already a spec activated for the requested name...
if existing = specs.find { |s| dep.name == s.name }
# then we're done since this new dep matches the
# existing spec.
next if dep.matches_spec? existing
# There is a conflict! We return the conflict
# object which will be seen by the caller and be
# handled at the right level.
# If the existing activation indicates that there
# are other possibles for it, then issue the conflict
# on the dep for the activation itself. Otherwise, issue
# it on the requester's request itself.
#
if existing.others_possible?
conflict = DependencyConflict.new(dep, existing)
else
depreq = existing.request.requester.request
conflict = DependencyConflict.new(depreq, existing, dep)
end
@conflicts << conflict
return conflict
end
# Get a list of all specs that satisfy dep
possible = @set.find_all(dep)
case possible.size
when 0
# If there are none, then our work here is done.
raise UnsatisfiableDepedencyError.new(dep)
when 1
# If there is one, then we just add it to specs
# and process the specs dependencies by adding
# them to needed.
spec = possible.first
act = ActivationRequest.new(spec, dep, false)
specs << act
# Put the deps for at the beginning of needed
# rather than the end to match the depth first
# searching done by the multiple case code below.
#
# This keeps the error messages consistent.
needed = requests(spec, act) + needed
else
# There are multiple specs for this dep. This is
# the case that this class is built to handle.
# Sort them so that we try the highest versions
# first.
possible = possible.sort_by { |s| s.version }
# We track the conflicts seen so that we can report them
# to help the user figure out how to fix the situation.
conflicts = []
# To figure out which to pick, we keep resolving
# given each one being activated and if there isn't
# a conflict, we know we've found a full set.
#
# We use an until loop rather than #reverse_each
# to keep the stack short since we're using a recursive
# algorithm.
#
until possible.empty?
s = possible.pop
# Recursively call #resolve_for with this spec
# and add it's dependencies into the picture...
act = ActivationRequest.new(s, dep)
try = requests(s, act) + needed
res = resolve_for(try, specs + [act])
# While trying to resolve these dependencies, there may
# be a conflict!
if res.kind_of? DependencyConflict
# The conflict might be created not by this invocation
# but rather one up the stack, so if we can't attempt
# to resolve this conflict (conflict isn't with the spec +s+)
# then just return it so the caller can try to sort it out.
return res unless res.for_spec? s
# Otherwise, this is a conflict that we can attempt to fix
conflicts << [s, res]
# Optimization:
#
# Because the conflict indicates the dependency that trigger
# it, we can prune possible based on this new information.
#
# This cuts down on the number of iterations needed.
possible.delete_if { |x| !res.dependency.matches_spec? x }
else
# No conflict, return the specs
return res
end
end
# We tried all possibles and nothing worked, so we let the user
# know and include as much information about the problem since
# the user is going to have to take action to fix this.
raise ImpossibleDependenciesError.new(dep, conflicts)
end
end
specs
end
end
end

Просмотреть файл

@ -20,51 +20,51 @@
# end
# end
module Gem
module Deprecate
module Gem::Deprecate
def self.skip # :nodoc:
@skip ||= false
end
def self.skip= v # :nodoc:
@skip = v
end
##
# Temporarily turn off warnings. Intended for tests only.
def skip_during
Gem::Deprecate.skip, original = true, Gem::Deprecate.skip
yield
ensure
Gem::Deprecate.skip = original
end
##
# Simple deprecation method that deprecates +name+ by wrapping it up
# in a dummy method. It warns on each call to the dummy method
# telling the user of +repl+ (unless +repl+ is :none) and the
# year/month that it is planned to go away.
def deprecate name, repl, year, month
class_eval {
old = "_deprecated_#{name}"
alias_method old, name
define_method name do |*args, &block| # TODO: really works on 1.8.7?
klass = self.kind_of? Module
target = klass ? "#{self}." : "#{self.class}#"
msg = [ "NOTE: #{target}#{name} is deprecated",
repl == :none ? " with no replacement" : ", use #{repl}",
". It will be removed on or after %4d-%02d-01." % [year, month],
"\n#{target}#{name} called from #{Gem.location_of_caller.join(":")}",
]
warn "#{msg.join}." unless Gem::Deprecate.skip
send old, *args, &block
end
}
end
module_function :deprecate, :skip_during
def self.skip # :nodoc:
@skip ||= false
end
def self.skip= v # :nodoc:
@skip = v
end
##
# Temporarily turn off warnings. Intended for tests only.
def skip_during
Gem::Deprecate.skip, original = true, Gem::Deprecate.skip
yield
ensure
Gem::Deprecate.skip = original
end
##
# Simple deprecation method that deprecates +name+ by wrapping it up
# in a dummy method. It warns on each call to the dummy method
# telling the user of +repl+ (unless +repl+ is :none) and the
# year/month that it is planned to go away.
def deprecate name, repl, year, month
class_eval {
old = "_deprecated_#{name}"
alias_method old, name
define_method name do |*args, &block| # TODO: really works on 1.8.7?
klass = self.kind_of? Module
target = klass ? "#{self}." : "#{self.class}#"
msg = [ "NOTE: #{target}#{name} is deprecated",
repl == :none ? " with no replacement" : "; use #{repl} instead",
". It will be removed on or after %4d-%02d-01." % [year, month],
"\n#{target}#{name} called from #{Gem.location_of_caller.join(":")}",
]
warn "#{msg.join}." unless Gem::Deprecate.skip
send old, *args, &block
end
}
end
module_function :deprecate, :skip_during
end

Просмотреть файл

@ -1,243 +0,0 @@
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
# See LICENSE.txt for permissions.
#++
require 'rubygems'
##
# The documentation manager generates RDoc and RI for RubyGems.
class Gem::DocManager
include Gem::UserInteraction
@configured_args = []
def self.configured_args
@configured_args ||= []
end
def self.configured_args=(args)
case args
when Array
@configured_args = args
when String
@configured_args = args.split
end
end
##
# Load RDoc from a gem if it is available, otherwise from Ruby's stdlib
def self.load_rdoc
begin
gem 'rdoc'
rescue Gem::LoadError
# use built-in RDoc
end
begin
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
raise Gem::DocumentError,
"ERROR: RDoc documentation generator not installed: #{e}"
end
end
def self.rdoc_version
@rdoc_version
end
##
# Updates the RI cache for RDoc 2 if it is installed
def self.update_ri_cache
load_rdoc rescue return
return unless defined? RDoc::VERSION # RDoc 1 does not have VERSION
require 'rdoc/ri/driver'
options = {
:use_cache => true,
:use_system => true,
:use_site => true,
:use_home => true,
:use_gems => true,
:formatter => RDoc::RI::Formatter,
}
RDoc::RI::Driver.new(options).class_cache
end
##
# Create a document manager for +spec+. +rdoc_args+ contains arguments for
# RDoc (template etc.) as a String.
def initialize(spec, rdoc_args="")
require 'fileutils'
@spec = spec
@doc_dir = spec.doc_dir
@rdoc_args = rdoc_args.nil? ? [] : rdoc_args.split
end
##
# Is the RDoc documentation installed?
def rdoc_installed?
File.exist?(File.join(@doc_dir, "rdoc"))
end
##
# Is the RI documentation installed?
def ri_installed?
File.exist?(File.join(@doc_dir, "ri"))
end
##
# Generate the RI documents for this gem spec.
#
# Note that if both RI and RDoc documents are generated from the same
# process, the RI docs should be done first (a likely bug in RDoc will cause
# RI docs generation to fail if run after RDoc).
def generate_ri
setup_rdoc
install_ri # RDoc bug, ri goes first
FileUtils.mkdir_p @doc_dir unless File.exist?(@doc_dir)
end
##
# Generate the RDoc documents for this gem spec.
#
# Note that if both RI and RDoc documents are generated from the same
# process, the RI docs should be done first (a likely bug in RDoc will cause
# RI docs generation to fail if run after RDoc).
def generate_rdoc
setup_rdoc
install_rdoc
FileUtils.mkdir_p @doc_dir unless File.exist?(@doc_dir)
end
##
# Generate and install RDoc into the documentation directory
def install_rdoc
rdoc_dir = File.join @doc_dir, 'rdoc'
FileUtils.rm_rf rdoc_dir
say "Installing RDoc documentation for #{@spec.full_name}..."
run_rdoc '--op', rdoc_dir
end
##
# Generate and install RI into the documentation directory
def install_ri
ri_dir = File.join @doc_dir, 'ri'
FileUtils.rm_rf ri_dir
say "Installing ri documentation for #{@spec.full_name}..."
run_rdoc '--ri', '--op', ri_dir
end
##
# Run RDoc with +args+, which is an ARGV style argument list
def run_rdoc(*args)
args << @spec.rdoc_options
args << self.class.configured_args
args << @spec.require_paths.clone
args << @spec.extra_rdoc_files
args << '--title' << "#{@spec.full_name} Documentation"
args << '--quiet'
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
debug_args = args.dup
r = RDoc::RDoc.new
old_pwd = Dir.pwd
Dir.chdir @spec.full_gem_path
say "rdoc #{args.join ' '}" if Gem.configuration.really_verbose
begin
r.document args
rescue Errno::EACCES => e
dirname = File.dirname e.message.split("-")[1].strip
raise Gem::FilePermissionError.new(dirname)
rescue Interrupt => e
raise e
rescue Exception => ex
alert_error "While generating documentation for #{@spec.full_name}"
ui.errs.puts "... MESSAGE: #{ex}"
ui.errs.puts "... RDOC args: #{debug_args.join(' ')}"
ui.errs.puts "\t#{ex.backtrace.join "\n\t"}" if
Gem.configuration.backtrace
terminate_interaction 1
ensure
Dir.chdir old_pwd
end
end
def setup_rdoc
if File.exist?(@doc_dir) && !File.writable?(@doc_dir) then
raise Gem::FilePermissionError.new(@doc_dir)
end
FileUtils.mkdir_p @doc_dir unless File.exist?(@doc_dir)
self.class.load_rdoc
end
##
# Remove RDoc and RI documentation
def uninstall_doc
base_dir = @spec.base_dir
raise Gem::FilePermissionError.new base_dir unless File.writable? base_dir
# TODO: ok... that's twice... ugh
old_name = [
@spec.name, @spec.version, @spec.original_platform].join '-'
doc_dir = @spec.doc_dir
unless File.directory? doc_dir then
doc_dir = File.join File.dirname(doc_dir), old_name
end
ri_dir = @spec.ri_dir
unless File.directory? ri_dir then
ri_dir = File.join File.dirname(ri_dir), old_name
end
FileUtils.rm_rf doc_dir
FileUtils.rm_rf ri_dir
end
end

Просмотреть файл

@ -1,35 +1,88 @@
class Gem::ErrorReason; end
# Generated when trying to lookup a gem to indicate that the gem
# was found, but that it isn't usable on the current platform.
##
# This file contains all the various exceptions and other errors that are used
# inside of RubyGems.
#
# fetch and install read these and report them to the user to aid
# in figuring out why a gem couldn't be installed.
#
class Gem::PlatformMismatch < Gem::ErrorReason
# DOC: Confirm _all_
attr_reader :name
attr_reader :version
attr_reader :platforms
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.
def initialize(name, version)
@name = name
@version = version
@platforms = []
class LoadError < ::LoadError
# Name of gem
attr_accessor :name
# Version requirement of gem
attr_accessor :requirement
end
def add_platform(platform)
@platforms << platform
end
# FIX: does this need to exist? The subclass is the only other reference
# I can find.
class ErrorReason; end
def wordy
prefix = "Found #{@name} (#{@version})"
# Generated when trying to lookup a gem to indicate that the gem
# was found, but that it isn't usable on the current platform.
#
# fetch and install read these and report them to the user to aid
# in figuring out why a gem couldn't be installed.
#
class PlatformMismatch < ErrorReason
if @platforms.size == 1
"#{prefix}, but was for platform #{@platforms[0]}"
else
"#{prefix}, but was for platforms #{@platforms.join(' ,')}"
##
# the name of the gem
attr_reader :name
##
# the version
attr_reader :version
##
# The platforms that are mismatched
attr_reader :platforms
def initialize(name, version)
@name = name
@version = version
@platforms = []
end
##
# append a platform to the list of mismatched platforms.
#
# Platforms are added via this instead of injected via the constructor
# so that we can loop over a list of mismatches and just add them rather
# than perform some kind of calculation mismatch summary before creation.
def add_platform(platform)
@platforms << platform
end
##
# A wordy description of the error.
def wordy
"Found %s (%), but was for platform%s %s" %
[@name,
@version,
@platforms.size == 1 ? 's' : '',
@platforms.join(' ,')]
end
end
##
# An error that indicates we weren't able to fetch some
# data from a source
class SourceFetchProblem < ErrorReason
def initialize(source, error)
@source = source
@error = error
end
attr_reader :source, :error
def wordy
"Unable to download data from #{@source.uri} - #{@error.message}"
end
end
end

Просмотреть файл

@ -1,7 +1,14 @@
# TODO: the documentation in here is terrible.
#
# Each exception needs a brief description and the scenarios where it is
# likely to be raised
##
# Base exception class for RubyGems. All exception raised by RubyGems are a
# subclass of this one.
class Gem::Exception < RuntimeError; end
class Gem::Exception < RuntimeError
attr_accessor :source_exception
end
class Gem::CommandLineError < Gem::Exception; end
@ -24,11 +31,18 @@ class Gem::EndOfYAMLException < Gem::Exception; end
##
# Signals that a file permission error is preventing the user from
# installing in the requested directories.
# operating on the given directory.
class Gem::FilePermissionError < Gem::Exception
def initialize(path)
super("You don't have write permissions into the #{path} directory.")
attr_reader :directory
def initialize directory
@directory = directory
super "You don't have write permissions for the #{directory} directory."
end
end
##
@ -37,9 +51,12 @@ class Gem::FormatException < Gem::Exception
attr_accessor :file_path
end
class Gem::GemNotFoundException < Gem::Exception
def initialize(msg, name=nil, version=nil, errors=nil)
super msg
class Gem::GemNotFoundException < Gem::Exception; end
class Gem::SpecificGemNotFoundException < Gem::GemNotFoundException
def initialize(name, version, errors=nil)
super "Could not find a valid gem '#{name}' (#{version}) locally or in a repository"
@name = name
@version = version
@errors = errors
@ -89,3 +106,4 @@ class Gem::SystemExitException < SystemExit
end
end

Просмотреть файл

@ -16,7 +16,7 @@ class Gem::Ext::Builder
raise Gem::InstallError, "Makefile not found:\n\n#{results.join "\n"}"
end
mf = File.read('Makefile')
mf = Gem.read_binary 'Makefile'
mf = mf.gsub(/^RUBYARCHDIR\s*=\s*\$[^$]*/, "RUBYARCHDIR = #{dest_path}")
mf = mf.gsub(/^RUBYLIBDIR\s*=\s*\$[^$]*/, "RUBYLIBDIR = #{dest_path}")
@ -24,18 +24,14 @@ class Gem::Ext::Builder
# try to find make program from Ruby configure arguments first
RbConfig::CONFIG['configure_args'] =~ /with-make-prog\=(\w+)/
make_program = $1 || ENV['make']
make_program = $1 || ENV['MAKE'] || ENV['make']
unless make_program then
make_program = (/mswin/ =~ RUBY_PLATFORM) ? 'nmake' : 'make'
end
['', ' install'].each do |target|
cmd = "#{make_program}#{target}"
results << cmd
results << `#{cmd} #{redirector}`
raise Gem::InstallError, "make#{target} failed:\n\n#{results}" unless
$?.success?
run(cmd, results, "make#{target}")
end
end
@ -43,12 +39,20 @@ class Gem::Ext::Builder
'2>&1'
end
def self.run(command, results)
results << command
results << `#{command} #{redirector}`
def self.run(command, results, command_name = nil)
verbose = Gem.configuration.really_verbose
if verbose
puts(command)
system(command)
else
results << command
results << `#{command} #{redirector}`
end
unless $?.success? then
raise Gem::InstallError, "#{class_name} failed:\n\n#{results.join "\n"}"
results << "Building has failed. See above output for more information on the failure." if verbose
raise Gem::InstallError, "#{command_name || class_name} failed:\n\n#{results.join "\n"}"
end
end

Просмотреть файл

@ -8,10 +8,10 @@ require 'rubygems/ext/builder'
class Gem::Ext::ConfigureBuilder < Gem::Ext::Builder
def self.build(extension, directory, dest_path, results)
def self.build(extension, directory, dest_path, results, args=[])
unless File.exist?('Makefile') then
cmd = "sh ./configure --prefix=#{dest_path}"
cmd << " #{Gem::Command.build_args.join ' '}" unless Gem::Command.build_args.empty?
cmd << " #{args.join ' '}" unless args.empty?
run cmd, results
end

Просмотреть файл

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

Просмотреть файл

@ -9,10 +9,10 @@ require 'rubygems/command'
class Gem::Ext::RakeBuilder < Gem::Ext::Builder
def self.build(extension, directory, dest_path, results)
def self.build(extension, directory, dest_path, results, args=[])
if File.basename(extension) =~ /mkrf_conf/i then
cmd = "#{Gem.ruby} #{File.basename extension}"
cmd << " #{Gem::Command.build_args.join " "}" unless Gem::Command.build_args.empty?
cmd << " #{args.join " "}" unless args.empty?
run cmd, results
end

Просмотреть файл

@ -1,82 +0,0 @@
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
# See LICENSE.txt for permissions.
#++
require 'rubygems/package'
##
# Gem::Format knows the guts of the RubyGem .gem file format and provides the
# capability to read gem files
class Gem::Format
attr_accessor :spec
attr_accessor :file_entries
attr_accessor :gem_path
##
# Constructs a Format representing the gem's data which came from +gem_path+
def initialize(gem_path)
@gem_path = gem_path
end
##
# Reads the gem +file_path+ using +security_policy+ and returns a Format
# representing the data in the gem
def self.from_file_by_path(file_path, security_policy = nil)
unless File.file?(file_path)
raise Gem::Exception, "Cannot load gem at [#{file_path}] in #{Dir.pwd}"
end
start = File.read file_path, 20
if start.nil? or start.length < 20 then
nil
elsif start.include?("MD5SUM =") # old version gems
require 'rubygems/old_format'
Gem::OldFormat.from_file_by_path file_path
else
begin
open file_path, Gem.binary_mode do |io|
from_io io, file_path, security_policy
end
rescue Gem::Package::TarInvalidError => e
message = "corrupt gem (#{e.class}: #{e.message})"
raise Gem::Package::FormatError.new(message, file_path)
end
end
end
##
# Reads a gem from +io+ at +gem_path+ using +security_policy+ and returns a
# Format representing the data from the gem
def self.from_io(io, gem_path="(io)", security_policy = nil)
format = new gem_path
Gem::Package.open io, 'r', security_policy do |pkg|
format.spec = pkg.metadata
format.file_entries = []
pkg.each do |entry|
size = entry.header.size
mode = entry.header.mode
format.file_entries << [{
"size" => size, "mode" => mode, "path" => entry.full_name,
},
entry.read
]
end
end
format
end
end

Просмотреть файл

@ -1,90 +0,0 @@
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
# See LICENSE.txt for permissions.
#++
#--
# Some system might not have OpenSSL installed, therefore the core
# library file openssl might not be available. We localize testing
# for the presence of OpenSSL in this file.
#++
module Gem
class << self
##
# Is SSL (used by the signing commands) available on this
# platform?
def ssl_available?
@ssl_available
end
##
# Is SSL available?
attr_writer :ssl_available
##
# Ensure that SSL is available. Throw an exception if it is not.
def ensure_ssl_available
unless ssl_available?
raise Gem::Exception, "SSL is not installed on this system"
end
end
end
end
# :stopdoc:
begin
require 'openssl'
# Reference a constant defined in the .rb portion of ssl (just to
# make sure that part is loaded too).
Gem.ssl_available = !!OpenSSL::Digest::SHA1
class OpenSSL::X509::Certificate
# Check the validity of this certificate.
def check_validity(issuer_cert = nil, time = Time.now)
ret = if @not_before && @not_before > time
[false, :expired, "not valid before '#@not_before'"]
elsif @not_after && @not_after < time
[false, :expired, "not valid after '#@not_after'"]
elsif issuer_cert && !verify(issuer_cert.public_key)
[false, :issuer, "#{issuer_cert.subject} is not issuer"]
else
[true, :ok, 'Valid certificate']
end
# return hash
{ :is_valid => ret[0], :error => ret[1], :desc => ret[2] }
end
end
rescue LoadError, StandardError
Gem.ssl_available = false
end
module Gem::SSL
# We make our own versions of the constants here. This allows us
# to reference the constants, even though some systems might not
# have SSL installed in the Ruby core package.
#
# These constants are only used during load time. At runtime, any
# method that makes a direct reference to SSL software must be
# protected with a Gem.ensure_ssl_available call.
if Gem.ssl_available? then
PKEY_RSA = OpenSSL::PKey::RSA
DIGEST_SHA1 = OpenSSL::Digest::SHA1
else
PKEY_RSA = :rsa
DIGEST_SHA1 = :sha1
end
end

Просмотреть файл

@ -1,172 +0,0 @@
require "rubygems"
require "rubygems/deprecate"
##
# GemPathSearcher has the capability to find loadable files inside
# gems. It generates data up front to speed up searches later.
class Gem::GemPathSearcher
##
# Initialise the data we need to make searches later.
def initialize
# We want a record of all the installed gemspecs, in the order we wish to
# examine them.
# TODO: remove this stupid method
@gemspecs = init_gemspecs
# Map gem spec to glob of full require_path directories. Preparing this
# information may speed up searches later.
@lib_dirs = {}
@gemspecs.each do |spec|
@lib_dirs[spec.object_id] = lib_dirs_for spec
end
end
##
# Look in all the installed gems until a matching +glob+ is found.
# Return the _gemspec_ of the gem where it was found. If no match
# is found, return nil.
#
# The gems are searched in alphabetical order, and in reverse
# version order.
#
# For example:
#
# find('log4r') # -> (log4r-1.1 spec)
# find('log4r.rb') # -> (log4r-1.1 spec)
# find('rake/rdoctask') # -> (rake-0.4.12 spec)
# find('foobarbaz') # -> nil
#
# Matching paths can have various suffixes ('.rb', '.so', and
# others), which may or may not already be attached to _file_.
# This method doesn't care about the full filename that matches;
# only that there is a match.
def find(glob)
# HACK violation of encapsulation
@gemspecs.find do |spec|
# TODO: inverted responsibility
matching_file? spec, glob
end
end
# Looks through the available gemspecs and finds the first
# one that contains +file+ as a requirable file.
def find_spec_for_file(file)
@gemspecs.find do |spec|
return spec if spec.contains_requirable_file?(file)
end
end
def find_active(glob)
# HACK violation of encapsulation
@gemspecs.find do |spec|
# TODO: inverted responsibility
spec.loaded? and matching_file? spec, glob
end
end
##
# Works like #find, but finds all gemspecs matching +glob+.
def find_all(glob)
# HACK violation of encapsulation
@gemspecs.select do |spec|
# TODO: inverted responsibility
matching_file? spec, glob
end || []
end
def find_in_unresolved(glob)
# HACK violation
specs = Gem.unresolved_deps.values.map { |dep|
Gem.source_index.search dep, true
}.flatten
specs.select do |spec|
# TODO: inverted responsibility
matching_file? spec, glob
end || []
end
def find_in_unresolved_tree glob
# HACK violation
# TODO: inverted responsibility
specs = Gem.unresolved_deps.values.map { |dep|
Gem.source_index.search dep, true
}.flatten
specs.reverse_each do |spec|
trails = matching_paths(spec, glob)
next if trails.empty?
return trails.map(&:reverse).sort.first.reverse
end
[]
end
##
# Attempts to find a matching path using the require_paths of the given
# +spec+.
def matching_file?(spec, path)
not matching_files(spec, path).empty?
end
def matching_paths(spec, path)
trails = []
spec.traverse do |from_spec, dep, to_spec, trail|
next unless to_spec.conflicts.empty?
trails << trail unless matching_files(to_spec, path).empty?
end
trails
end
##
# Returns files matching +path+ in +spec+.
#--
# Some of the intermediate results are cached in @lib_dirs for speed.
def matching_files(spec, path)
return [] unless @lib_dirs[spec.object_id] # case no paths
glob = File.join @lib_dirs[spec.object_id], "#{path}#{Gem.suffix_pattern}"
Dir[glob].select { |f| File.file? f.untaint }
end
##
# Return a list of all installed gemspecs, sorted by alphabetical order and
# in reverse version order. (bar-2, bar-1, foo-2)
def init_gemspecs
Gem::Specification.sort { |a, b|
names = a.name <=> b.name
next names if names.nonzero?
b.version <=> a.version
}
end
##
# Returns library directories glob for a gemspec. For example,
# '/usr/local/lib/ruby/gems/1.8/gems/foobar-1.0/{lib,ext}'
def lib_dirs_for(spec)
"#{spec.full_gem_path}/{#{spec.require_paths.join(',')}}" if
spec.require_paths
end
extend Gem::Deprecate
deprecate :initialize, :none, 2011, 10
deprecate :find, :none, 2011, 10
deprecate :find_active, :none, 2011, 10
deprecate :find_all, :none, 2011, 10
deprecate :find_in_unresolved, :none, 2011, 10
deprecate :find_in_unresolved_tree, :none, 2011, 10
deprecate :find_spec_for_file, :none, 2011, 10
end

Просмотреть файл

@ -4,10 +4,9 @@
# See LICENSE.txt for permissions.
#++
require "rubygems"
require 'rubygems'
require 'rubygems/command_manager'
require 'rubygems/config_file'
require 'rubygems/doc_manager'
##
# Load additional plugins from $LOAD_PATH
@ -29,25 +28,21 @@ class Gem::GemRunner
# TODO: nuke these options
@command_manager_class = options[:command_manager] || Gem::CommandManager
@config_file_class = options[:config_file] || Gem::ConfigFile
@doc_manager_class = options[:doc_manager] || Gem::DocManager
end
##
# Run the gem command with the following arguments.
def run(args)
start_time = Time.now
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.
# TODO use slice!
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
@ -62,14 +57,7 @@ class Gem::GemRunner
Gem::Command.add_specific_extra_args command_name, config_args
end
cmd.run Gem.configuration.args
end_time = Time.now
if Gem.configuration.benchmark then
printf "\nExecution time: %0.2f seconds.\n", end_time - start_time
puts "Press Enter to finish"
STDIN.gets
end
cmd.run Gem.configuration.args, build_args
end
private
@ -78,7 +66,6 @@ class Gem::GemRunner
Gem.configuration = @config_file_class.new(args)
Gem.use_paths Gem.configuration[:gemhome], Gem.configuration[:gempath]
Gem::Command.extra_args = Gem.configuration[:gem]
@doc_manager_class.configured_args = Gem.configuration[:rdoc]
end
end

Просмотреть файл

@ -1,6 +1,7 @@
require 'rubygems/remote_fetcher'
module Gem::GemcutterUtilities
# TODO: move to Gem::Command
OptionParser.accept Symbol do |value|
value.to_sym
end
@ -19,6 +20,8 @@ module Gem::GemcutterUtilities
def api_key
if options[:key] then
verify_api_key options[:key]
elsif Gem.configuration.api_keys.key?(host)
Gem.configuration.api_keys[host]
else
Gem.configuration.rubygems_api_key
end
@ -44,12 +47,24 @@ module Gem::GemcutterUtilities
end
end
def rubygems_api_request(method, path, host = Gem.host, &block)
require 'net/http'
host = ENV['RUBYGEMS_HOST'] if ENV['RUBYGEMS_HOST']
uri = URI.parse "#{host}/#{path}"
attr_writer :host
def host
configured_host = Gem.host unless
Gem.configuration.disable_default_gem_server
say "Pushing gem to #{host}..."
@host ||= ENV['RUBYGEMS_HOST'] || configured_host
end
def rubygems_api_request(method, path, host = nil, &block)
require 'net/http'
self.host = host if host
unless self.host
alert_error "You must specify a gem server"
terminate_interaction 1 # TODO: question this
end
uri = URI.parse "#{self.host}/#{path}"
request_method = Net::HTTP.const_get method.to_s.capitalize
@ -66,7 +81,7 @@ module Gem::GemcutterUtilities
end
else
say resp.body
terminate_interaction 1
terminate_interaction 1 # TODO: question this
end
end
@ -74,8 +89,8 @@ module Gem::GemcutterUtilities
if Gem.configuration.api_keys.key? key then
Gem.configuration.api_keys[key]
else
alert_error "No such API key. You can add it with gem keys --add #{key}"
terminate_interaction 1
alert_error "No such API key. Please add it to your configuration (done automatically on initial `gem push`)."
terminate_interaction 1 # TODO: question this
end
end

Просмотреть файл

@ -1,5 +1,5 @@
require 'rubygems'
require 'rubygems/format'
require 'rubygems/package'
require 'time'
begin
@ -15,11 +15,6 @@ class Gem::Indexer
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
@ -63,15 +58,10 @@ class Gem::Indexer
"\n\tgem install builder"
end
options = { :build_legacy => true, :build_modern => true }.merge options
options = { :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
@directory = File.join(Dir.tmpdir, "gem_generate_index_#{$$}")
@ -99,8 +89,6 @@ class Gem::Indexer
@dest_prerelease_specs_index =
File.join(@dest_directory, "prerelease_specs.#{Gem.marshal_version}")
@rss_index = File.join @directory, 'index.rss'
@files = []
end
@ -109,6 +97,8 @@ class Gem::Indexer
# searching, downloading and related activities and do not need deployment
# specific information (e.g. list of files). So we abbreviate the spec,
# making it much smaller for quicker downloads.
#--
# TODO move to Gem::Specification
def abbreviate(spec)
spec.files = []
@ -123,37 +113,15 @@ class Gem::Indexer
# Build various indicies
def build_indicies
# Marshal gemspecs are used by both modern and legacy RubyGems
Gem::Specification.dirs = []
Gem::Specification.add_specs(*map_gems_to_specs(gem_file_list))
build_marshal_gemspecs
build_legacy_indicies if @build_legacy
build_modern_indicies if @build_modern
build_rss
compress_indicies
end
##
# Builds indicies for RubyGems older than 1.2.x
def build_legacy_indicies
index = collect_specs
say "Generating Marshal master index"
Gem.time 'Generated Marshal master index' do
open @marshal_index, 'wb' do |io|
io.write index.dump
end
end
@files << @marshal_index
@files << "#{@marshal_index}.Z"
end
##
# Builds Marshal quick index gemspecs.
@ -238,104 +206,6 @@ class Gem::Indexer
"#{@prerelease_specs_index}.gz"]
end
##
# Builds an RSS feed for past two days gem releases according to the gem's
# date.
def build_rss
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::VERSION}</generator>
<docs>http://cyber.law.harvard.edu/rss/rss.html</docs>
HEADER
today = Gem::Specification::TODAY
yesterday = today - 86400
index = Gem::Specification.select do |spec|
spec_date = spec.date
# TODO: remove this and make YAML based specs properly normalized
spec_date = Time.parse(spec_date.to_s) if Date === spec_date
spec_date >= yesterday && spec_date <= today
end
index.sort_by { |spec| [-spec.date.to_i, spec] }.each do |spec|
file_name = File.basename spec.cache_file
gem_path = CGI.escapeHTML "http://#{@rss_gems_host}/gems/#{file_name}"
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
def map_gems_to_specs gems
gems.map { |gemfile|
if File.size(gemfile) == 0 then
@ -344,7 +214,7 @@ class Gem::Indexer
end
begin
spec = Gem::Format.from_file_by_path(gemfile).spec
spec = Gem::Package.new(gemfile).spec
spec.loaded_from = gemfile
# HACK: fuck this shit - borks all tests that use pl1
@ -373,21 +243,6 @@ class Gem::Indexer
}.compact
end
##
# Collect specifications from .gem files from the gem directory.
def collect_specs(gems = gem_file_list)
Gem::Deprecate.skip_during do
index = Gem::SourceIndex.new
map_gems_to_specs(gems).each do |spec|
index.add_spec spec, spec.original_name
end
index
end
end
##
# Compresses indicies on disk
#--
@ -397,11 +252,6 @@ class Gem::Indexer
say "Compressing indicies"
Gem.time 'Compressed indicies' do
if @build_legacy then
compress @marshal_index, 'Z'
paranoid @marshal_index, 'Z'
end
if @build_modern then
gzip @specs_index
gzip @latest_specs_index
@ -559,12 +409,9 @@ class Gem::Indexer
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.
# Perform an in-place update of the repository from newly added gems.
def update_index
@build_legacy = false
make_temp_directories
specs_mtime = File.stat(@dest_specs_index).mtime
@ -584,6 +431,9 @@ class Gem::Indexer
specs = map_gems_to_specs updated_gems
prerelease, released = specs.partition { |s| s.version.prerelease? }
Gem::Specification.dirs = []
Gem::Specification.add_specs(*specs)
files = build_marshal_gemspecs
Gem.time 'Updated indexes' do

Просмотреть файл

@ -0,0 +1,12 @@
require 'rubygems'
require 'rubygems/user_interaction'
##
# A default post-install hook that displays "Successfully installed
# some_gem-1.0"
Gem.post_install do |installer|
ui = Gem::DefaultUserInteraction.ui
ui.say "Successfully installed #{installer.spec.full_name}"
end

Просмотреть файл

@ -22,6 +22,7 @@ module Gem::InstallUpdateOptions
# Add the install/update options to the option parser.
def add_install_update_options
# TODO: use @parser.accept
OptionParser.accept Gem::Security::Policy do |value|
require 'rubygems/security'
@ -39,21 +40,49 @@ module Gem::InstallUpdateOptions
end
add_option(:"Install/Update", '-n', '--bindir DIR',
'Directory where binary files are',
'located') do |value, options|
'Directory where binary files are',
'located') do |value, options|
options[:bin_dir] = File.expand_path(value)
end
add_option(:"Install/Update", '-d', '--[no-]rdoc',
'Generate RDoc documentation for the gem on',
'install') do |value, options|
options[:generate_rdoc] = value
add_option(:"Install/Update", '--[no-]document [TYPES]', Array,
'Generate documentation for installed gems',
'List the documentation types you wish to',
'generate. For example: rdoc,ri') do |value, options|
options[:document] = case value
when nil then %w[ri]
when false then []
else value
end
end
add_option(:"Install/Update", '--[no-]ri',
'Generate RI documentation for the gem on',
'install') do |value, options|
options[:generate_ri] = value
add_option(:"Install/Update", '-N', '--no-document',
'Disable documentation generation') do |value, options|
options[:document] = []
end
add_option(:Deprecated, '--[no-]rdoc',
'Generate RDoc for installed gems',
'Use --document instead') do |value, options|
if value then
options[:document] << 'rdoc'
else
options[:document].delete 'rdoc'
end
options[:document].uniq!
end
add_option(:Deprecated, '--[no-]ri',
'Generate ri data for installed gems.',
'Use --document instead') do |value, options|
if value then
options[:document] << 'ri'
else
options[:document].delete 'ri'
end
options[:document].uniq!
end
add_option(:"Install/Update", '-E', '--[no-]env-shebang',
@ -85,12 +114,6 @@ module Gem::InstallUpdateOptions
options[:ignore_dependencies] = value
end
add_option(:"Install/Update", '-y', '--include-dependencies',
'Unconditionally install the required',
'dependent gems') do |value, options|
options[:include_dependencies] = value
end
add_option(:"Install/Update", '--[no-]format-executable',
'Make installed executable names match ruby.',
'If ruby is ruby18, foo_exec will be',
@ -105,15 +128,30 @@ module Gem::InstallUpdateOptions
end
add_option(:"Install/Update", "--development",
"Install any additional development",
"Install additional development",
"dependencies") do |value, options|
options[:development] = true
options[:dev_shallow] = true
end
add_option(:"Install/Update", "--development-all",
"Install development dependencies for all",
"gems (including dev deps themselves)") do |value, options|
options[:development] = true
options[:dev_shallow] = false
end
add_option(:"Install/Update", "--conservative",
"Don't attempt to upgrade gems already",
"meeting version requirement") do |value, options|
options[:conservative] = true
options[:minimal_deps] = true
end
add_option(:"Install/Update", "--minimal-deps",
"Don't upgrade any dependencies that already",
"meet version requirements") do |value, options|
options[:minimal_deps] = true
end
end
@ -121,7 +159,7 @@ module Gem::InstallUpdateOptions
# Default options for the gem install command.
def install_update_defaults_str
'--rdoc --no-force --wrappers'
'--document=rdoc,ri --wrappers'
end
end

Просмотреть файл

@ -4,15 +4,13 @@
# See LICENSE.txt for permissions.
#++
require 'rubygems/format'
require 'rubygems/exceptions'
require 'rubygems/package'
require 'rubygems/ext'
require 'rubygems/require_paths_builder'
require 'rubygems/user_interaction'
##
# The installer class processes RubyGem .gem files and installs the files
# contained in the .gem into the Gem.path.
# The installer installs the files contained in the .gem into the Gem.home.
#
# 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
@ -39,8 +37,7 @@ class Gem::Installer
include Gem::UserInteraction
include Gem::RequirePathsBuilder if Gem::QUICKLOADER_SUCKAGE
# DOC: Missing docs or :nodoc:.
attr_reader :gem
##
@ -67,6 +64,7 @@ class Gem::Installer
attr_accessor :path_warning
# DOC: Missing docs or :nodoc:.
attr_writer :exec_format
# Defaults to use Ruby's program prefix and suffix.
@ -80,24 +78,36 @@ class Gem::Installer
# Constructs an Installer instance that will install the gem located at
# +gem+. +options+ is a Hash with the following keys:
#
# :bin_dir:: Where to put a bin wrapper if needed.
# :development:: Whether or not development dependencies should be installed.
# :env_shebang:: Use /usr/bin/env in bin wrappers.
# :force:: Overrides all version checks and security policy checks, except
# for a signed-gems-only policy.
# :ignore_dependencies:: Don't raise if a dependency is missing.
# :install_dir:: The directory to install the gem into.
# :format_executable:: Format the executable the same as the ruby executable.
# If your ruby is ruby18, foo_exec will be installed as
# foo_exec18.
# :ignore_dependencies:: Don't raise if a dependency is missing.
# :install_dir:: The directory to install the gem into.
# :security_policy:: Use the specified security policy. See Gem::Security
# :user_install:: Indicate that the gem should be unpacked into the users
# personal gem directory.
# :only_install_dir:: Only validate dependencies against what is in the
# install_dir
# :wrappers:: Install wrappers if true, symlinks if false.
# :build_args:: An Array of arguments to pass to the extension builder
# process. If not set, then Gem::Command.build_args is used
def initialize(gem, options={})
require 'fileutils'
@gem = gem
@options = options
@package = Gem::Package.new @gem
process_options
@package.security_policy = @security_policy
if options[:user_install] and not options[:unpack] then
@gem_home = Gem.user_dir
check_that_user_bin_dir_is_in_path
@ -105,28 +115,79 @@ class Gem::Installer
end
##
# Lazy accessor for the spec's gem directory.
# Checks if +filename+ exists in +@bin_dir+.
#
# If +@force+ is set +filename+ is overwritten.
#
# If +filename+ exists and is a RubyGems wrapper for different gem the user
# is consulted.
#
# If +filename+ exists and +@bin_dir+ is Gem.default_bindir (/usr/local) the
# user is consulted.
#
# Otherwise +filename+ is overwritten.
def gem_dir
@gem_dir ||= spec.gem_dir.dup.untaint
def check_executable_overwrite filename # :nodoc:
return if @force
generated_bin = File.join @bin_dir, filename
return unless File.exist? generated_bin
ruby_executable = false
existing = nil
open generated_bin, 'rb' do |io|
next unless io.gets =~ /^#!/ # shebang
io.gets # blankline
# TODO detect a specially formatted comment instead of trying
# to run a regexp against ruby code.
next unless io.gets =~ /This file was generated by RubyGems/
ruby_executable = true
existing = io.read.slice(/^gem (['"])(.*?)(\1),/, 2)
end
return if spec.name == existing
# somebody has written to RubyGems' directory, overwrite, too bad
return if Gem.default_bindir != @bin_dir and not ruby_executable
question = "#{spec.name}'s executable \"#{filename}\" conflicts with "
if ruby_executable then
question << existing
return if ask_yes_no "#{question}\nOverwrite the executable?", false
conflict = "installed executable from #{existing}"
else
question << generated_bin
return if ask_yes_no "#{question}\nOverwrite the executable?", false
conflict = generated_bin
end
raise Gem::InstallError,
"\"#{filename}\" from #{spec.name} conflicts with #{conflict}"
end
##
# Lazy accessor for the installer's Gem::Format instance.
# Lazy accessor for the spec's gem directory.
def format
begin
@format ||= Gem::Format.from_file_by_path gem, @security_policy
rescue Gem::Package::FormatError
raise Gem::InstallError, "invalid gem format for #{gem}"
end
def gem_dir
@gem_dir ||= File.join(gem_home, "gems", spec.full_name)
end
##
# Lazy accessor for the installer's spec.
def spec
@spec ||= format.spec
@spec ||= @package.spec
rescue Gem::Package::Error => e
raise Gem::InstallError, "invalid gem: #{e.message}"
end
##
@ -141,11 +202,7 @@ class Gem::Installer
# specifications/<gem-version>.gemspec #=> the Gem::Specification
def install
current_home = Gem.dir
current_path = Gem.paths.path
verify_gem_home(options[:unpack])
Gem.use_paths gem_home, current_path # HACK: shouldn't need Gem.paths.path
# If we're forcing the install then disable security unless the security
# policy says that we only install signed gems.
@ -158,31 +215,65 @@ class Gem::Installer
ensure_dependencies_met unless @ignore_dependencies
end
Gem.pre_install_hooks.each do |hook|
result = hook.call self
if result == false then
location = " at #{$1}" if hook.inspect =~ /@(.*:\d+)/
message = "pre-install hook#{location} failed for #{spec.full_name}"
raise Gem::InstallError, message
end
end
run_pre_install_hooks
Gem.ensure_gem_subdirectories gem_home
# Completely remove any previous gem files
FileUtils.rm_rf(gem_dir) if File.exist? gem_dir
FileUtils.rm_rf(gem_dir)
FileUtils.mkdir_p gem_dir
extract_files
build_extensions
Gem.post_build_hooks.each do |hook|
result = hook.call self
run_post_build_hooks
if result == false then
generate_bin
write_spec
unless @build_args.empty?
File.open spec.build_info_file, "w" do |f|
@build_args.each { |a| f.puts a }
end
end
# TODO should be always cache the file? Other classes have options
# to controls if caching is done.
cache_file = File.join(gem_home, "cache", "#{spec.full_name}.gem")
FileUtils.cp gem, cache_file unless File.exist? cache_file
say spec.post_install_message unless spec.post_install_message.nil?
spec.loaded_from = spec_file
Gem::Specification.add_spec spec unless Gem::Specification.include? spec
run_post_install_hooks
spec
# TODO This rescue is in the wrong place. What is raising this exception?
# move this rescue to arround the code that actually might raise it.
rescue Zlib::GzipFile::Error
raise Gem::InstallError, "gzip error installing #{gem}"
end
def run_pre_install_hooks # :nodoc:
Gem.pre_install_hooks.each do |hook|
if hook.call(self) == false then
location = " at #{$1}" if hook.inspect =~ /@(.*:\d+)/
message = "pre-install hook#{location} failed for #{spec.full_name}"
raise Gem::InstallError, message
end
end
end
def run_post_build_hooks # :nodoc:
Gem.post_build_hooks.each do |hook|
if hook.call(self) == false then
FileUtils.rm_rf gem_dir
location = " at #{$1}" if hook.inspect =~ /@(.*:\d+)/
@ -191,32 +282,29 @@ class Gem::Installer
raise Gem::InstallError, message
end
end
end
generate_bin
write_spec
write_require_paths_file_if_needed if Gem::QUICKLOADER_SUCKAGE
cache_file = spec.cache_file
FileUtils.cp gem, cache_file unless File.exist? cache_file
say spec.post_install_message unless spec.post_install_message.nil?
spec.loaded_from = spec.spec_file
Gem::Specification.add_spec spec unless Gem::Specification.include? spec
def run_post_install_hooks # :nodoc:
Gem.post_install_hooks.each do |hook|
hook.call self
end
end
return spec
rescue Zlib::GzipFile::Error
raise Gem::InstallError, "gzip error installing #{gem}"
ensure
# conditional since we might be here because we're erroring out early.
if current_path
Gem.use_paths current_home, current_path
##
#
# Return an Array of Specifications contained within the gem_home
# we'll be installing into.
def installed_specs
@specs ||= begin
specs = []
Dir[File.join(gem_home, "specifications", "*.gemspec")].each do |path|
spec = Gem::Specification.load path.untaint
specs << spec if spec
end
specs
end
end
@ -235,9 +323,11 @@ class Gem::Installer
end
##
# True if the gems in the source_index satisfy +dependency+.
# True if the gems in the system satisfy +dependency+.
def installation_satisfies_dependency?(dependency)
return true if installed_specs.detect { |s| dependency.matches_spec? s }
return false if @only_install_dir
not dependency.matching_specs.empty?
end
@ -246,18 +336,23 @@ class Gem::Installer
def unpack(directory)
@gem_dir = directory
@format = Gem::Format.from_file_by_path gem, @security_policy
extract_files
end
##
# The location of of the spec file that is installed.
#
def spec_file
File.join gem_home, "specifications", "#{spec.full_name}.gemspec"
end
##
# Writes the .gemspec specification (in Ruby) to the gem home's
# specifications directory.
def write_spec
file_name = spec.spec_file.untaint
File.open(file_name, "w") do |file|
File.open(spec_file, "w") do |file|
file.puts spec.to_ruby_for_cache
end
end
@ -277,34 +372,34 @@ class Gem::Installer
end
end
# DOC: Missing docs or :nodoc:.
def generate_bin
return if spec.executables.nil? or spec.executables.empty?
# If the user has asked for the gem to be installed in a directory that is
# the system gem directory, then use the system bin directory, else create
# (or use) a new bin dir under the gem_home.
bindir = @bin_dir || Gem.bindir(gem_home)
Dir.mkdir bindir unless File.exist? bindir
raise Gem::FilePermissionError.new(bindir) unless File.writable? bindir
Dir.mkdir @bin_dir unless File.exist? @bin_dir
raise Gem::FilePermissionError.new(@bin_dir) unless File.writable? @bin_dir
spec.executables.each do |filename|
filename.untaint
bin_path = File.expand_path File.join(gem_dir, spec.bindir, filename)
bin_path = File.join gem_dir, spec.bindir, filename
unless File.exist? bin_path
warn "Hey?!?! Where did #{bin_path} go??"
unless File.exist? bin_path then
# TODO change this to a more useful warning
warn "#{bin_path} maybe `gem pristine #{spec.name}` will fix it?"
next
end
mode = File.stat(bin_path).mode | 0111
FileUtils.chmod mode, bin_path
check_executable_overwrite filename
if @wrappers then
generate_bin_script filename, bindir
generate_bin_script filename, @bin_dir
else
generate_bin_symlink filename, bindir
generate_bin_symlink filename, @bin_dir
end
end
end
@ -358,10 +453,21 @@ class Gem::Installer
##
# Generates a #! line for +bin_file_name+'s wrapper copying arguments if
# necessary.
#
# If the :custom_shebang config is set, then it is used as a template
# for how to create the shebang used for to run a gem's executables.
#
# The template supports 4 expansions:
#
# $env the path to the unix env utility
# $ruby the path to the currently running ruby interpreter
# $exec the path to the gem's executable
# $name the name of the gem the executable is for
#
def shebang(bin_file_name)
ruby_name = Gem::ConfigMap[:ruby_install_name] if @env_shebang
path = spec.bin_file bin_file_name
path = File.join gem_dir, spec.bindir, bin_file_name
first_line = File.open(path, "rb") {|file| file.gets}
if /\A#!/ =~ first_line then
@ -371,7 +477,25 @@ class Gem::Installer
shebang.strip! # Avoid nasty ^M issues.
end
if not ruby_name then
if which = Gem.configuration[:custom_shebang]
# replace bin_file_name with "ruby" to avoid endless loops
which = which.gsub(/ #{bin_file_name}$/," #{Gem::ConfigMap[:ruby_install_name]}")
which = which.gsub(/\$(\w+)/) do
case $1
when "env"
@env_path ||= ENV_PATHS.find {|env_path| File.executable? env_path }
when "ruby"
"#{Gem.ruby}#{opts}"
when "exec"
bin_file_name
when "name"
spec.name
end
end
"#!#{which}"
elsif not ruby_name then
"#!#{Gem.ruby}#{opts}"
elsif opts then
"#!/bin/sh\n'exec' #{ruby_name.dump} '-x' \"$0\" \"$@\"\n#{shebang}"
@ -382,6 +506,7 @@ class Gem::Installer
end
end
# DOC: Missing docs or :nodoc:.
def ensure_required_ruby_version_met
if rrv = spec.required_ruby_version then
unless rrv.satisfied_by? Gem.ruby_version then
@ -390,9 +515,10 @@ class Gem::Installer
end
end
# DOC: Missing docs or :nodoc:.
def ensure_required_rubygems_version_met
if rrgv = spec.required_rubygems_version then
unless rrgv.satisfied_by? Gem::Version.new(Gem::VERSION) then
unless rrgv.satisfied_by? Gem.rubygems_version then
raise Gem::InstallError,
"#{spec.name} requires RubyGems version #{rrgv}. " +
"Try 'gem update --system' to update RubyGems itself."
@ -400,6 +526,7 @@ class Gem::Installer
end
end
# DOC: Missing docs or :nodoc:.
def ensure_dependencies_met
deps = spec.runtime_dependencies
deps |= spec.development_dependencies if @development
@ -409,13 +536,14 @@ class Gem::Installer
end
end
# DOC: Missing docs or :nodoc:.
def process_options
@options = {
:bin_dir => nil,
:env_shebang => false,
:exec_format => false,
:force => false,
:install_dir => Gem.dir,
:only_install_dir => false
}.merge options
@env_shebang = options[:env_shebang]
@ -425,13 +553,18 @@ class Gem::Installer
@format_executable = options[:format_executable]
@security_policy = options[:security_policy]
@wrappers = options[:wrappers]
@bin_dir = options[:bin_dir]
@only_install_dir = options[:only_install_dir]
# If the user has asked for the gem to be installed in a directory that is
# the system gem directory, then use the system bin directory, else create
# (or use) a new bin dir under the gem_home.
@bin_dir = options[:bin_dir] || Gem.bindir(gem_home)
@development = options[:development]
raise "NOTE: Installer option :source_index is dead" if
options[:source_index]
@build_args = options[:build_args] || Gem::Command.build_args
end
# DOC: Missing docs or :nodoc:.
def check_that_user_bin_dir_is_in_path
user_bin_dir = @bin_dir || Gem.bindir(gem_home)
user_bin_dir.gsub!(File::SEPARATOR, File::ALT_SEPARATOR) if File::ALT_SEPARATOR
@ -449,6 +582,7 @@ class Gem::Installer
end
end
# DOC: Missing docs or :nodoc:.
def verify_gem_home(unpack = false)
FileUtils.mkdir_p gem_home
raise Gem::FilePermissionError, gem_home unless
@ -499,7 +633,6 @@ GOTO :EOF
:WinNT
@"#{ruby}" "%~dpn0" %*
TEXT
end
##
@ -508,7 +641,14 @@ TEXT
def build_extensions
return if spec.extensions.empty?
say "Building native extensions. This could take a while..."
if @build_args.empty?
say "Building native extensions. This could take a while..."
else
say "Building native extensions with: '#{@build_args.join(' ')}'"
say "This could take a while..."
end
dest_path = File.join gem_dir, spec.require_paths.first
ran_rake = false # only run rake once
@ -516,6 +656,9 @@ TEXT
break if ran_rake
results = []
extension ||= ""
extension_dir = File.join gem_dir, File.dirname(extension)
builder = case extension
when /extconf/ then
Gem::Ext::ExtConfBuilder
@ -525,43 +668,41 @@ TEXT
ran_rake = true
Gem::Ext::RakeBuilder
else
results = ["No builder for extension '#{extension}'"]
nil
message = "No builder for extension '#{extension}'"
extension_build_error extension_dir, message
end
extension_dir = begin
File.join gem_dir, File.dirname(extension)
rescue TypeError # extension == nil
gem_dir
end
begin
Dir.chdir extension_dir do
results = builder.build(extension, gem_dir, dest_path, results)
results = builder.build(extension, gem_dir, dest_path,
results, @build_args)
say results.join("\n") if Gem.configuration.really_verbose
end
rescue
results = results.join "\n"
extension_build_error(extension_dir, results.join("\n"))
end
end
end
gem_make_out = File.join extension_dir, 'gem_make.out'
##
# Logs the build +output+ in +build_dir+, then raises ExtensionBuildError.
open gem_make_out, 'wb' do |io| io.puts results end
def extension_build_error(build_dir, output)
gem_make_out = File.join build_dir, 'gem_make.out'
message = <<-EOF
open gem_make_out, 'wb' do |io| io.puts output end
message = <<-EOF
ERROR: Failed to build gem native extension.
#{results}
#{output}
Gem files will remain installed in #{gem_dir} for inspection.
Results logged to #{gem_make_out}
EOF
raise ExtensionBuildError, message
end
end
raise ExtensionBuildError, message
end
##
@ -570,36 +711,7 @@ EOF
# Ensures that files can't be installed outside the gem directory.
def extract_files
raise ArgumentError, "format required to extract from" if @format.nil?
@format.file_entries.each do |entry, file_data|
path = entry['path'].untaint
if path.start_with? "/" then # for extra sanity
raise Gem::InstallError, "attempt to install file into #{entry['path']}"
end
path = File.expand_path File.join(gem_dir, path)
unless path.start_with? gem_dir then
msg = "attempt to install file into %p under %s" %
[entry['path'], gem_dir]
raise Gem::InstallError, msg
end
FileUtils.rm_rf(path) if File.exist? path
dir = File.dirname path
FileUtils.mkdir_p dir unless File.exist? dir
File.open(path, "wb") do |out|
out.write file_data
end
FileUtils.chmod entry['mode'], path
say path if Gem.configuration.really_verbose
end
@package.extract_files gem_dir
end
##

Просмотреть файл

@ -6,11 +6,26 @@ class Gem::Installer
##
# Available through requiring rubygems/installer_test_case
attr_writer :bin_dir
##
# Available through requiring rubygems/installer_test_case
attr_writer :build_args
##
# Available through requiring rubygems/installer_test_case
attr_writer :gem_dir
##
# Available through requiring rubygems/installer_test_case
attr_writer :force
##
# Available through requiring rubygems/installer_test_case
attr_writer :format
##
@ -54,47 +69,68 @@ end
class Gem::InstallerTestCase < Gem::TestCase
##
# Creates the following instance variables:
#
# @spec::
# a spec named 'a', intended for regular installs
# @user_spec::
# a spec named 'b', intended for user installs
# @gem::
# the path to a built gem from @spec
# @user_spec::
# the path to a built gem from @user_spec
#
# @installer::
# a Gem::Installer for the @spec that installs into @gemhome
# @user_installer::
# a Gem::Installer for the @user_spec that installs into Gem.user_dir
def setup
super
@installer_tmp = File.join @tempdir, 'installer'
FileUtils.mkdir_p @installer_tmp
@spec = quick_gem 'a' do |spec|
util_make_exec spec
end
Gem.use_paths @installer_tmp
Gem.ensure_gem_subdirectories @installer_tmp
@user_spec = quick_gem 'b' do |spec|
util_make_exec spec
end
@spec = quick_gem 'a'
util_make_exec @spec
util_build_gem @spec
@gem = @spec.cache_file
@user_spec = quick_gem 'b'
util_make_exec @user_spec
util_build_gem @user_spec
@user_gem = @user_spec.cache_file
Gem.use_paths @gemhome
@gem = @spec.cache_file
@user_gem = @user_spec.cache_file
@installer = util_installer @spec, @gemhome
@user_installer = util_installer @user_spec, Gem.user_dir, :user
Gem.use_paths @gemhome
end
def util_gem_bindir spec = @spec
def util_gem_bindir spec = @spec # :nodoc:
# TODO: deprecate
spec.bin_dir
end
def util_gem_dir spec = @spec
def util_gem_dir spec = @spec # :nodoc:
# TODO: deprecate
spec.gem_dir
end
##
# The path where installed executables live
def util_inst_bindir
File.join @gemhome, "bin"
end
##
# Adds an executable named "executable" to +spec+ with the given +shebang+.
#
# The executable is also written to the bin dir in @tmpdir and the installed
# gem directory for +spec+.
def util_make_exec(spec = @spec, shebang = "#!/usr/bin/ruby")
spec.executables = %w[executable]
spec.files << 'bin/executable'
@ -110,6 +146,14 @@ class Gem::InstallerTestCase < Gem::TestCase
end
end
##
# Builds the @spec gem and returns an installer for it. The built gem
# includes:
#
# bin/executable
# lib/code.rb
# ext/a/mkrf_conf.rb
def util_setup_gem(ui = @ui) # HACK fix use_ui to make this automatic
@spec.files << File.join('lib', 'code.rb')
@spec.extensions << File.join('ext', 'a', 'mkrf_conf.rb')
@ -129,16 +173,24 @@ class Gem::InstallerTestCase < Gem::TestCase
end
use_ui ui do
FileUtils.rm @gem
FileUtils.rm_f @gem
@gem = Gem::Builder.new(@spec).build
@gem = Gem::Package.build @spec
end
end
@installer = Gem::Installer.new @gem
end
##
# Creates an installer for +spec+ that will install into +gem_home+. If
# +user+ is true a user-install will be performed.
def util_installer(spec, gem_home, user=false)
Gem::Installer.new spec.cache_file, :user_install => user
Gem::Installer.new(spec.cache_file,
:install_dir => gem_home,
:user_install => user)
end
end

Просмотреть файл

@ -6,6 +6,17 @@ require 'rubygems/user_interaction'
# retrieval during tests.
class Gem::MockGemUi < Gem::StreamUI
##
# Raised when you haven't provided enough input to your MockGemUi
class InputEOFError < RuntimeError
def initialize question
super "Out of input for MockGemUi on #{question.inspect}"
end
end
class TermError < RuntimeError
attr_reader :exit_code
@ -44,6 +55,12 @@ class Gem::MockGemUi < Gem::StreamUI
@terminated = false
end
def ask question
raise InputEOFError, question if @ins.eof?
super
end
def input
@ins.string
end

110
lib/rubygems/name_tuple.rb Normal file
Просмотреть файл

@ -0,0 +1,110 @@
##
#
# Represents a gem of name +name+ at +version+ of +platform+. These
# wrap the data returned from the indexes.
require 'rubygems/platform'
class Gem::NameTuple
def initialize(name, version, platform="ruby")
@name = name
@version = version
unless platform.kind_of? Gem::Platform
platform = "ruby" if !platform or platform.empty?
end
@platform = platform
end
attr_reader :name, :version, :platform
##
# Turn an array of [name, version, platform] into an array of
# NameTuple objects.
def self.from_list list
list.map { |t| new(*t) }
end
##
# Turn an array of NameTuple objects back into an array of
# [name, version, platform] tuples.
def self.to_basic list
list.map { |t| t.to_a }
end
##
# A null NameTuple, ie name=nil, version=0
def self.null
new nil, Gem::Version.new(0), nil
end
##
# Indicate if this NameTuple matches the current platform.
def match_platform?
Gem::Platform.match @platform
end
##
# Indicate if this NameTuple is for a prerelease version.
def prerelease?
@version.prerelease?
end
##
# Return the name that the gemspec file would be
def spec_name
case @platform
when nil, 'ruby', ''
"#{@name}-#{@version}.gemspec"
else
"#{@name}-#{@version}-#{@platform}.gemspec"
end
end
##
# Convert back to the [name, version, platform] tuple
def to_a
[@name, @version, @platform]
end
def to_s
"#<Gem::NameTuple #{@name}, #{@version}, #{@platform}>"
end
def <=> other
to_a <=> other.to_a
end
include Comparable
##
# Compare with +other+. Supports another NameTuple or an Array
# in the [name, version, platform] format.
def == other
case other
when self.class
@name == other.name and
@version == other.version and
@platform == other.platform
when Array
to_a == other
else
false
end
end
alias_method :eql?, :==
def hash
to_a.hash
end
end

Просмотреть файл

@ -1,153 +0,0 @@
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
# See LICENSE.txt for permissions.
#++
require 'rubygems'
##
# The format class knows the guts of the RubyGem .gem file format and provides
# the capability to read gem files
class Gem::OldFormat
attr_accessor :spec, :file_entries, :gem_path
##
# Constructs an instance of a Format object, representing the gem's data
# structure.
#
# gem:: [String] The file name of the gem
def initialize(gem_path)
require 'fileutils'
require 'zlib'
Gem.load_yaml
@gem_path = gem_path
end
##
# Reads the named gem file and returns a Format object, representing the
# data from the gem file
#
# file_path:: [String] Path to the gem file
def self.from_file_by_path(file_path)
unless File.exist?(file_path)
raise Gem::Exception, "Cannot load gem file [#{file_path}]"
end
File.open(file_path, 'rb') do |file|
from_io(file, file_path)
end
end
##
# Reads a gem from an io stream and returns a Format object, representing
# the data from the gem file
#
# io:: [IO] Stream from which to read the gem
def self.from_io(io, gem_path="(io)")
format = self.new(gem_path)
skip_ruby(io)
format.spec = read_spec(io)
format.file_entries = []
read_files_from_gem(io) do |entry, file_data|
format.file_entries << [entry, file_data]
end
format
end
private
##
# Skips the Ruby self-install header. After calling this method, the
# IO index will be set after the Ruby code.
#
# file:: [IO] The IO to process (skip the Ruby code)
def self.skip_ruby(file)
end_seen = false
loop {
line = file.gets
if(line == nil || line.chomp == "__END__") then
end_seen = true
break
end
}
if end_seen == false then
raise Gem::Exception.new("Failed to find end of ruby script while reading gem")
end
end
##
# Reads the specification YAML from the supplied IO and constructs
# a Gem::Specification from it. After calling this method, the
# IO index will be set after the specification header.
#
# file:: [IO] The IO to process
def self.read_spec(file)
yaml = ''
read_until_dashes file do |line|
yaml << line
end
Gem::Specification.from_yaml yaml
rescue YAML::Error => e
raise Gem::Exception, "Failed to parse gem specification out of gem file"
rescue ArgumentError => e
raise Gem::Exception, "Failed to parse gem specification out of gem file"
end
##
# Reads lines from the supplied IO until a end-of-yaml (---) is
# reached
#
# file:: [IO] The IO to process
# block:: [String] The read line
def self.read_until_dashes(file)
while((line = file.gets) && line.chomp.strip != "---") do
yield line
end
end
##
# Reads the embedded file data from a gem file, yielding an entry
# containing metadata about the file and the file contents themselves
# for each file that's archived in the gem.
# NOTE: Many of these methods should be extracted into some kind of
# Gem file read/writer
#
# gem_file:: [IO] The IO to process
def self.read_files_from_gem(gem_file)
errstr = "Error reading files from gem"
header_yaml = ''
begin
self.read_until_dashes(gem_file) do |line|
header_yaml << line
end
header = YAML.load(header_yaml)
raise Gem::Exception, errstr unless header
header.each do |entry|
file_data = ''
self.read_until_dashes(gem_file) do |line|
file_data << line
end
yield [entry, Zlib::Inflate.inflate(file_data.strip.unpack("m")[0])]
end
rescue Zlib::DataError
raise Gem::Exception, errstr
end
end
end

Просмотреть файл

@ -3,16 +3,54 @@
# Copyright (C) 2004 Mauricio Julio Fernández Pradier
# See LICENSE.txt for additional licensing information.
#++
#
# Example using a Gem::Package
#
# Builds a .gem file given a Gem::Specification. A .gem file is a tarball
# which contains a data.tar.gz and metadata.gz, and possibly signatures.
#
# require 'rubygems'
# require 'rubygems/package'
#
# spec = Gem::Specification.new do |s|
# s.summary = "Ruby based make-like utility."
# s.name = 'rake'
# s.version = PKG_VERSION
# s.requirements << 'none'
# 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::Package.build spec
#
# Reads a .gem file.
#
# require 'rubygems'
# require 'rubygems/package'
#
# the_gem = Gem::Package.new(path_to_dot_gem)
# the_gem.contents # get the files in the gem
# the_gem.extract_files destination_directory # extract the gem into a directory
# the_gem.spec # get the spec out of the gem
# the_gem.verify # check the gem is OK (contains valid gem specification, contains a not corrupt contents archive)
#
# #files are the files in the .gem tar file, not the ruby files in the gem
# #extract_files and #contents automatically call #verify
require 'rubygems/security'
require 'rubygems/specification'
require 'rubygems/user_interaction'
require 'zlib'
module Gem::Package
class Gem::Package
include Gem::UserInteraction
class Error < Gem::Exception; end
class Error < StandardError; end
class NonSeekableIO < Error; end
class ClosedIO < Error; end
class BadCheckSum < Error; end
class TooLongFileName < Error; end
class FormatError < Error
attr_reader :path
@ -26,57 +64,489 @@ module Gem::Package
end
class PathError < Error
def initialize destination, destination_dir
super "installing into parent path %s of %s is not allowed" %
[destination, destination_dir]
end
end
class NonSeekableIO < Error; end
class TooLongFileName < Error; end
##
# Raised when a tar file is corrupt
class TarInvalidError < Error; end
# FIX: zenspider said: does it really take an IO?
# passed to a method called open?!? that seems stupid.
def self.open(io, mode = "r", signer = nil, &block)
tar_type = case mode
when 'r' then TarInput
when 'w' then TarOutput
else
raise "Unknown Package open mode"
end
attr_accessor :build_time # :nodoc:
tar_type.open(io, signer, &block)
##
# Checksums for the contents of the package
attr_reader :checksums
##
# The files in this package. This is not the contents of the gem, just the
# files in the top-level container.
attr_reader :files
##
# The security policy used for verifying the contents of this package.
attr_accessor :security_policy
##
# Sets the Gem::Specification to use to build this package.
attr_writer :spec
def self.build spec, skip_validation=false
gem_file = spec.file_name
package = new gem_file
package.spec = spec
package.build skip_validation
gem_file
end
def self.pack(src, destname, signer = nil)
TarOutput.open(destname, signer) do |outp|
dir_class.chdir(src) do
outp.metadata = (file_class.read("RPA/metadata") rescue nil)
find_class.find('.') do |entry|
case
when file_class.file?(entry)
entry.sub!(%r{\./}, "")
next if entry =~ /\ARPA\//
stat = File.stat(entry)
outp.add_file_simple(entry, stat.mode, stat.size) do |os|
file_class.open(entry, "rb") do |f|
os.write(f.read(4096)) until f.eof?
end
end
when file_class.dir?(entry)
entry.sub!(%r{\./}, "")
next if entry == "RPA"
outp.mkdir(entry, file_class.stat(entry).mode)
else
raise "Don't know how to pack this yet!"
end
##
# Creates a new Gem::Package for the file at +gem+.
#
# If +gem+ is an existing file in the old format a Gem::Package::Old will be
# returned.
def self.new gem
return super unless Gem::Package == self
return super unless File.exist? gem
start = File.read gem, 20
return super unless start
return super unless start.include? 'MD5SUM ='
Gem::Package::Old.new gem
end
##
# Creates a new package that will read or write to the file +gem+.
def initialize gem # :notnew:
@gem = gem
@build_time = Time.now
@checksums = {}
@contents = nil
@digests = Hash.new { |h, algorithm| h[algorithm] = {} }
@files = nil
@security_policy = nil
@signatures = {}
@signer = nil
@spec = nil
end
##
# Adds a checksum for each entry in the gem to checksums.yaml.gz.
def add_checksums tar
Gem.load_yaml
checksums_by_algorithm = Hash.new { |h, algorithm| h[algorithm] = {} }
@checksums.each do |name, digests|
digests.each do |algorithm, digest|
checksums_by_algorithm[algorithm][name] = digest.hexdigest
end
end
tar.add_file_signed 'checksums.yaml.gz', 0444, @signer do |io|
gzip_to io do |gz_io|
YAML.dump checksums_by_algorithm, gz_io
end
end
end
##
# Adds the files listed in the packages's Gem::Specification to data.tar.gz
# and adds this file to the +tar+.
def add_contents tar # :nodoc:
digests = tar.add_file_signed 'data.tar.gz', 0444, @signer do |io|
gzip_to io do |gz_io|
Gem::Package::TarWriter.new gz_io do |data_tar|
add_files data_tar
end
end
end
@checksums['data.tar.gz'] = digests
end
##
# Adds files included the package's Gem::Specification to the +tar+ file
def add_files tar # :nodoc:
@spec.files.each do |file|
stat = File.stat file
tar.add_file_simple file, stat.mode, stat.size do |dst_io|
open file, 'rb' do |src_io|
dst_io.write src_io.read 16384 until src_io.eof?
end
end
end
end
##
# Adds the package's Gem::Specification to the +tar+ file
def add_metadata tar # :nodoc:
digests = tar.add_file_signed 'metadata.gz', 0444, @signer do |io|
gzip_to io do |gz_io|
gz_io.write @spec.to_yaml
end
end
@checksums['metadata.gz'] = digests
end
##
# Builds this package based on the specification set by #spec=
def build skip_validation = false
require 'rubygems/security'
@spec.validate unless skip_validation
@spec.mark_version
setup_signer
open @gem, 'wb' do |gem_io|
Gem::Package::TarWriter.new gem_io do |gem|
add_metadata gem
add_contents gem
add_checksums gem
end
end
say <<-EOM
Successfully built RubyGem
Name: #{@spec.name}
Version: #{@spec.version}
File: #{File.basename @spec.cache_file}
EOM
ensure
@signer = nil
end
##
# A list of file names contained in this gem
def contents
return @contents if @contents
verify unless @spec
@contents = []
open @gem, 'rb' do |io|
gem_tar = Gem::Package::TarReader.new io
gem_tar.each do |entry|
next unless entry.full_name == 'data.tar.gz'
open_tar_gz entry do |pkg_tar|
pkg_tar.each do |contents_entry|
@contents << contents_entry.full_name
end
end
return @contents
end
end
end
##
# Creates a digest of the TarEntry +entry+ from the digest algorithm set by
# the security policy.
def digest entry # :nodoc:
return unless @checksums
@checksums.each_key do |algorithm|
digester = OpenSSL::Digest.new algorithm
digester << entry.read(16384) until entry.eof?
entry.rewind
@digests[algorithm][entry.full_name] = digester
end
@digests
end
##
# Extracts the files in this package into +destination_dir+
def extract_files destination_dir
verify unless @spec
FileUtils.mkdir_p destination_dir
open @gem, 'rb' do |io|
reader = Gem::Package::TarReader.new io
reader.each do |entry|
next unless entry.full_name == 'data.tar.gz'
extract_tar_gz entry, destination_dir
return # ignore further entries
end
end
end
##
# Extracts all the files in the gzipped tar archive +io+ into
# +destination_dir+.
#
# If an entry in the archive contains a relative path above
# +destination_dir+ or an absolute path is encountered an exception is
# raised.
def extract_tar_gz io, destination_dir # :nodoc:
open_tar_gz io do |tar|
tar.each do |entry|
destination = install_location entry.full_name, destination_dir
FileUtils.rm_rf destination
FileUtils.mkdir_p File.dirname destination
open destination, 'wb', entry.header.mode do |out|
out.write entry.read
out.fsync rescue nil # for filesystems without fsync(2)
end
say destination if Gem.configuration.really_verbose
end
end
end
##
# Gzips content written to +gz_io+ to +io+.
#--
# Also sets the gzip modification time to the package build time to ease
# testing.
def gzip_to io # :yields: gz_io
gz_io = Zlib::GzipWriter.new io, Zlib::BEST_COMPRESSION
gz_io.mtime = @build_time
yield gz_io
ensure
gz_io.close
end
##
# Returns the full path for installing +filename+.
#
# If +filename+ is not inside +destination_dir+ an exception is raised.
def install_location filename, destination_dir # :nodoc:
raise Gem::Package::PathError.new(filename, destination_dir) if
filename.start_with? '/'
destination = File.join destination_dir, filename
destination = File.expand_path destination
raise Gem::Package::PathError.new(destination, destination_dir) unless
destination.start_with? destination_dir
destination.untaint
destination
end
##
# Loads a Gem::Specification from the TarEntry +entry+
def load_spec entry # :nodoc:
case entry.full_name
when 'metadata' then
@spec = Gem::Specification.from_yaml entry.read
when 'metadata.gz' then
args = [entry]
args << { :external_encoding => Encoding::UTF_8 } if
Object.const_defined? :Encoding
Zlib::GzipReader.wrap(*args) do |gzio|
@spec = Gem::Specification.from_yaml gzio.read
end
end
end
##
# Opens +io+ as a gzipped tar archive
def open_tar_gz io # :nodoc:
Zlib::GzipReader.wrap io do |gzio|
tar = Gem::Package::TarReader.new gzio
yield tar
end
end
##
# Reads and loads checksums.yaml.gz from the tar file +gem+
def read_checksums gem
Gem.load_yaml
@checksums = gem.seek 'checksums.yaml.gz' do |entry|
Zlib::GzipReader.wrap entry do |gz_io|
YAML.load gz_io.read
end
end
end
##
# Prepares the gem for signing and checksum generation. If a signing
# certificate and key are not present only checksum generation is set up.
def setup_signer
if @spec.signing_key then
@signer = Gem::Security::Signer.new @spec.signing_key, @spec.cert_chain
@spec.signing_key = nil
@spec.cert_chain = @signer.cert_chain.map { |cert| cert.to_s }
else
@signer = Gem::Security::Signer.new nil, nil
@spec.cert_chain = @signer.cert_chain.map { |cert| cert.to_pem } if
@signer.cert_chain
end
end
##
# The spec for this gem.
#
# If this is a package for a built gem the spec is loaded from the
# gem and returned. If this is a package for a gem being built the provided
# spec is returned.
def spec
verify unless @spec
@spec
end
##
# Verifies that this gem:
#
# * Contains a valid gem specification
# * Contains a contents archive
# * The contents archive is not corrupt
#
# After verification the gem specification from the gem is available from
# #spec
def verify
@files = []
@spec = nil
open @gem, 'rb' do |io|
Gem::Package::TarReader.new io do |reader|
read_checksums reader
verify_files reader
end
end
verify_checksums @digests, @checksums
@security_policy.verify_signatures @spec, @digests, @signatures if
@security_policy
true
rescue Errno::ENOENT => e
raise Gem::Package::FormatError.new e.message
rescue Gem::Package::TarInvalidError => e
raise Gem::Package::FormatError.new e.message, @gem
end
##
# Verifies the +checksums+ against the +digests+. This check is not
# cryptographically secure. Missing checksums are ignored.
def verify_checksums digests, checksums # :nodoc:
return unless checksums
checksums.sort.each do |algorithm, gem_digests|
gem_digests.sort.each do |file_name, gem_hexdigest|
computed_digest = digests[algorithm][file_name]
unless computed_digest.hexdigest == gem_hexdigest then
raise Gem::Package::FormatError.new \
"#{algorithm} checksum mismatch for #{file_name}", @gem
end
end
end
end
##
# Verifies the files of the +gem+
def verify_files gem
gem.each do |entry|
file_name = entry.full_name
@files << file_name
case file_name
when /\.sig$/ then
@signatures[$`] = entry.read if @security_policy
next
when 'checksums.yaml.gz' then
next # already handled
else
digest entry
end
case file_name
when /^metadata(.gz)?$/ then
load_spec entry
when 'data.tar.gz' then
verify_gz entry
end
end
unless @spec then
raise Gem::Package::FormatError.new 'package metadata is missing', @gem
end
unless @files.include? 'data.tar.gz' then
raise Gem::Package::FormatError.new \
'package content (data.tar.gz) is missing', @gem
end
end
##
# Verifies that +entry+ is a valid gzipped file.
def verify_gz entry # :nodoc:
Zlib::GzipReader.wrap entry do |gzio|
gzio.read 16384 until gzio.eof? # gzip checksum verification
end
rescue Zlib::GzipFile::Error => e
raise Gem::Package::FormatError.new(e.message, entry.full_name)
end
end
require 'rubygems/package/f_sync_dir'
require 'rubygems/package/digest_io'
require 'rubygems/package/old'
require 'rubygems/package/tar_header'
require 'rubygems/package/tar_input'
require 'rubygems/package/tar_output'
require 'rubygems/package/tar_reader'
require 'rubygems/package/tar_reader/entry'
require 'rubygems/package/tar_writer'

Просмотреть файл

@ -0,0 +1,64 @@
##
# IO wrapper that creates digests of contents written to the IO it wraps.
class Gem::Package::DigestIO
##
# Collected digests for wrapped writes.
#
# {
# 'SHA1' => #<OpenSSL::Digest: [...]>,
# 'SHA512' => #<OpenSSL::Digest: [...]>,
# }
attr_reader :digests
##
# Wraps +io+ and updates digest for each of the digest algorithms in
# the +digests+ Hash. Returns the digests hash. Example:
#
# io = StringIO.new
# digests = {
# 'SHA1' => OpenSSL::Digest.new('SHA1'),
# 'SHA512' => OpenSSL::Digest.new('SHA512'),
# }
#
# Gem::Package::DigestIO.wrap io, digests do |digest_io|
# digest_io.write "hello"
# end
#
# digests['SHA1'].hexdigest #=> "aaf4c61d[...]"
# digests['SHA512'].hexdigest #=> "9b71d224[...]"
def self.wrap io, digests
digest_io = new io, digests
yield digest_io
return digests
end
##
# Creates a new DigestIO instance. Using ::wrap is recommended, see the
# ::wrap documentation for documentation of +io+ and +digests+.
def initialize io, digests
@io = io
@digests = digests
end
##
# Writes +data+ to the underlying IO and updates the digests
def write data
result = @io.write data
@digests.each do |_, digest|
digest << data
end
result
end
end

Просмотреть файл

@ -1,23 +0,0 @@
# -*- coding: utf-8 -*-
#--
# Copyright (C) 2004 Mauricio Julio Fernández Pradier
# See LICENSE.txt for additional licensing information.
#++
module Gem::Package::FSyncDir
private
##
# make sure this hits the disc
def fsync_dir(dirname)
dir = open dirname, 'r'
dir.fsync
rescue # ignore IOError if it's an unpatched (old) Ruby
ensure
dir.close if dir rescue nil
end
end

147
lib/rubygems/package/old.rb Normal file
Просмотреть файл

@ -0,0 +1,147 @@
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
# See LICENSE.txt for permissions.
#++
##
# The format class knows the guts of the ancient .gem file format and provides
# the capability to read such ancient gems.
#
# Please pretend this doesn't exist.
class Gem::Package::Old < Gem::Package
undef_method :spec=
##
# Creates a new old-format package reader for +gem+. Old-format packages
# cannot be written.
def initialize gem
require 'fileutils'
require 'zlib'
Gem.load_yaml
@gem = gem
@contents = nil
@spec = nil
end
##
# A list of file names contained in this gem
def contents
return @contents if @contents
open @gem, 'rb' do |io|
read_until_dashes io # spec
header = file_list io
@contents = header.map { |file| file['path'] }
end
end
##
# Extracts the files in this package into +destination_dir+
def extract_files destination_dir
errstr = "Error reading files from gem"
open @gem, 'rb' do |io|
read_until_dashes io # spec
header = file_list io
raise Gem::Exception, errstr unless header
header.each do |entry|
full_name = entry['path']
destination = install_location full_name, destination_dir
file_data = ''
read_until_dashes io do |line|
file_data << line
end
file_data = file_data.strip.unpack("m")[0]
file_data = Zlib::Inflate.inflate file_data
raise Gem::Package::FormatError, "#{full_name} in #{@gem} is corrupt" if
file_data.length != entry['size'].to_i
FileUtils.rm_rf destination
FileUtils.mkdir_p File.dirname destination
open destination, 'wb', entry['mode'] do |out|
out.write file_data
end
say destination if Gem.configuration.really_verbose
end
end
rescue Zlib::DataError
raise Gem::Exception, errstr
end
##
# Reads the file list section from the old-format gem +io+
def file_list io # :nodoc:
header = ''
read_until_dashes io do |line|
header << line
end
YAML.load header
end
##
# Reads lines until a "---" separator is found
def read_until_dashes io # :nodoc:
while (line = io.gets) && line.chomp.strip != "---" do
yield line if block_given?
end
end
##
# Skips the Ruby self-install header in +io+.
def skip_ruby io # :nodoc:
loop do
line = io.gets
return if line.chomp == '__END__'
break unless line
end
raise Gem::Exception, "Failed to find end of ruby script while reading gem"
end
##
# The specification for this gem
def spec
return @spec if @spec
yaml = ''
open @gem, 'rb' do |io|
skip_ruby io
read_until_dashes io do |line|
yaml << line
end
end
@spec = Gem::Specification.from_yaml yaml
rescue YAML::SyntaxError => e
raise Gem::Exception, "Failed to parse gem specification out of gem file"
rescue ArgumentError => e
raise Gem::Exception, "Failed to parse gem specification out of gem file"
end
end

Просмотреть файл

@ -102,61 +102,24 @@ class Gem::Package::TarHeader
fields = header.unpack UNPACK_FORMAT
name = fields.shift
mode = fields.shift.oct
uid = fields.shift.oct
gid = fields.shift.oct
size = fields.shift.oct
mtime = fields.shift.oct
checksum = fields.shift.oct
typeflag = fields.shift
linkname = fields.shift
magic = fields.shift
version = fields.shift.oct
uname = fields.shift
gname = fields.shift
devmajor = fields.shift.oct
devminor = fields.shift.oct
prefix = fields.shift
new :name => fields.shift,
:mode => fields.shift.oct,
:uid => fields.shift.oct,
:gid => fields.shift.oct,
:size => fields.shift.oct,
:mtime => fields.shift.oct,
:checksum => fields.shift.oct,
:typeflag => fields.shift,
:linkname => fields.shift,
:magic => fields.shift,
:version => fields.shift.oct,
:uname => fields.shift,
:gname => fields.shift,
:devmajor => fields.shift.oct,
:devminor => fields.shift.oct,
:prefix => fields.shift,
new :name => name,
:mode => mode,
:uid => uid,
:gid => gid,
:size => size,
:mtime => mtime,
:checksum => checksum,
:typeflag => typeflag,
:linkname => linkname,
:magic => magic,
:version => version,
:uname => uname,
:gname => gname,
:devmajor => devmajor,
:devminor => devminor,
:prefix => prefix,
:empty => empty
# HACK unfactor for Rubinius
#new :name => fields.shift,
# :mode => fields.shift.oct,
# :uid => fields.shift.oct,
# :gid => fields.shift.oct,
# :size => fields.shift.oct,
# :mtime => fields.shift.oct,
# :checksum => fields.shift.oct,
# :typeflag => fields.shift,
# :linkname => fields.shift,
# :magic => fields.shift,
# :version => fields.shift.oct,
# :uname => fields.shift,
# :gname => fields.shift,
# :devmajor => fields.shift.oct,
# :devminor => fields.shift.oct,
# :prefix => fields.shift,
# :empty => empty
:empty => empty
end
##

Просмотреть файл

@ -1,235 +0,0 @@
# -*- coding: iso-8859-1 -*-
#++
# Copyright (C) 2004 Mauricio Julio Fernández Pradier
# See LICENSE.txt for additional licensing information.
#--
require 'zlib'
Gem.load_yaml
class Gem::Package::TarInput
include Gem::Package::FSyncDir
include Enumerable
attr_reader :metadata
private_class_method :new
def self.open(io, security_policy = nil, &block)
is = new io, security_policy
yield is
ensure
is.close if is
end
def initialize(io, security_policy = nil)
@io = io
@tarreader = Gem::Package::TarReader.new @io
has_meta = false
data_sig, meta_sig, data_dgst, meta_dgst = nil, nil, nil, nil
dgst_algo = security_policy ? Gem::Security::OPT[:dgst_algo] : nil
@tarreader.each do |entry|
case entry.full_name
when "metadata"
@metadata = load_gemspec entry.read
has_meta = true
when "metadata.gz"
begin
# if we have a security_policy, then pre-read the metadata file
# and calculate it's digest
sio = nil
if security_policy
Gem.ensure_ssl_available
sio = StringIO.new(entry.read)
meta_dgst = dgst_algo.digest(sio.string)
sio.rewind
end
# Ruby 1.8 doesn't have encoding and YAML is UTF-8
args = [sio || entry]
args << { :external_encoding => Encoding::UTF_8 } if
Object.const_defined?(:Encoding)
gzis = Zlib::GzipReader.new(*args)
# YAML wants an instance of IO
@metadata = load_gemspec(gzis)
has_meta = true
ensure
gzis.close unless gzis.nil?
end
when 'metadata.gz.sig'
meta_sig = entry.read
when 'data.tar.gz.sig'
data_sig = entry.read
when 'data.tar.gz'
if security_policy
Gem.ensure_ssl_available
data_dgst = dgst_algo.digest(entry.read)
end
end
end
if security_policy then
Gem.ensure_ssl_available
# map trust policy from string to actual class (or a serialized YAML
# file, if that exists)
if String === security_policy then
if Gem::Security::Policies.key? security_policy then
# load one of the pre-defined security policies
security_policy = Gem::Security::Policies[security_policy]
elsif File.exist? security_policy then
# FIXME: this doesn't work yet
security_policy = YAML.load File.read(security_policy)
else
raise Gem::Exception, "Unknown trust policy '#{security_policy}'"
end
end
if data_sig && data_dgst && meta_sig && meta_dgst then
# the user has a trust policy, and we have a signed gem
# file, so use the trust policy to verify the gem signature
begin
security_policy.verify_gem(data_sig, data_dgst, @metadata.cert_chain)
rescue Exception => e
raise "Couldn't verify data signature: #{e}"
end
begin
security_policy.verify_gem(meta_sig, meta_dgst, @metadata.cert_chain)
rescue Exception => e
raise "Couldn't verify metadata signature: #{e}"
end
elsif security_policy.only_signed
raise Gem::Exception, "Unsigned gem"
else
# FIXME: should display warning here (trust policy, but
# either unsigned or badly signed gem file)
end
end
@tarreader.rewind
unless has_meta then
path = io.path if io.respond_to? :path
error = Gem::Package::FormatError.new 'no metadata found', path
raise error
end
end
def close
@io.close
@tarreader.close
end
def each(&block)
@tarreader.each do |entry|
next unless entry.full_name == "data.tar.gz"
is = zipped_stream entry
begin
Gem::Package::TarReader.new is do |inner|
inner.each(&block)
end
ensure
is.close if is
end
end
@tarreader.rewind
end
def extract_entry(destdir, entry, expected_md5sum = nil)
if entry.directory? then
dest = File.join destdir, entry.full_name
if File.directory? dest then
FileUtils.chmod entry.header.mode, dest, :verbose => false
else
FileUtils.mkdir_p dest, :mode => entry.header.mode, :verbose => false
end
fsync_dir dest
fsync_dir File.join(dest, "..")
return
end
# it's a file
md5 = Digest::MD5.new if expected_md5sum
destdir = File.join destdir, File.dirname(entry.full_name)
FileUtils.mkdir_p destdir, :mode => 0755, :verbose => false
destfile = File.join destdir, File.basename(entry.full_name)
FileUtils.chmod 0600, destfile, :verbose => false rescue nil # Errno::ENOENT
open destfile, "wb", entry.header.mode do |os|
loop do
data = entry.read 4096
break unless data
# HACK shouldn't we check the MD5 before writing to disk?
md5 << data if expected_md5sum
os.write(data)
end
os.fsync
end
FileUtils.chmod entry.header.mode, destfile, :verbose => false
fsync_dir File.dirname(destfile)
fsync_dir File.join(File.dirname(destfile), "..")
if expected_md5sum && expected_md5sum != md5.hexdigest then
raise Gem::Package::BadCheckSum
end
end
# Attempt to YAML-load a gemspec from the given _io_ parameter. Return
# nil if it fails.
def load_gemspec(io)
Gem::Specification.from_yaml io
rescue Gem::Exception
nil
end
##
# Return an IO stream for the zipped entry.
#
# NOTE: Originally this method used two approaches, Return a GZipReader
# directly, or read the GZipReader into a string and return a StringIO on
# the string. The string IO approach was used for versions of ZLib before
# 1.2.1 to avoid buffer errors on windows machines. Then we found that
# errors happened with 1.2.1 as well, so we changed the condition. Then
# we discovered errors occurred with versions as late as 1.2.3. At this
# point (after some benchmarking to show we weren't seriously crippling
# the unpacking speed) we threw our hands in the air and declared that
# this method would use the String IO approach on all platforms at all
# times. And that's the way it is.
#
# Revisited. Here's the beginning of the long story.
# http://osdir.com/ml/lang.ruby.gems.devel/2007-06/msg00045.html
#
# StringIO wraping has never worked as a workaround by definition. Skipping
# initial 10 bytes and passing -MAX_WBITS to Zlib::Inflate luckily works as
# gzip reader, but it only works if the GZip header is 10 bytes long (see
# below) and it does not check inflated stream consistency (CRC value in the
# Gzip trailer.)
#
# RubyGems generated Gzip Header: 10 bytes
# magic(2) + method(1) + flag(1) + mtime(4) + exflag(1) + os(1) +
# orig_name(0) + comment(0)
#
# Ideally, it must return a GZipReader without meaningless buffering. We
# have lots of CRuby committers around so let's fix windows build when we
# received an error.
def zipped_stream(entry)
Zlib::GzipReader.new entry
end
end

Просмотреть файл

@ -1,146 +0,0 @@
# -*- coding: utf-8 -*-
#--
# Copyright (C) 2004 Mauricio Julio Fernández Pradier
# See LICENSE.txt for additional licensing information.
#++
##
# TarOutput is a wrapper to TarWriter that builds gem-format tar file.
#
# Gem-format tar files contain the following files:
# [data.tar.gz] A gzipped tar file containing the files that compose the gem
# which will be extracted into the gem/ dir on installation.
# [metadata.gz] A YAML format Gem::Specification.
# [data.tar.gz.sig] A signature for the gem's data.tar.gz.
# [metadata.gz.sig] A signature for the gem's metadata.gz.
#
# See TarOutput::open for usage details.
class Gem::Package::TarOutput
##
# Creates a new TarOutput which will yield a TarWriter object for the
# data.tar.gz portion of a gem-format tar file.
#
# See #initialize for details on +io+ and +signer+.
#
# See #add_gem_contents for details on adding metadata to the tar file.
def self.open(io, signer = nil, &block) # :yield: data_tar_writer
tar_outputter = new io, signer
tar_outputter.add_gem_contents(&block)
tar_outputter.add_metadata
tar_outputter.add_signatures
ensure
tar_outputter.close
end
##
# Creates a new TarOutput that will write a gem-format tar file to +io+. If
# +signer+ is given, the data.tar.gz and metadata.gz will be signed and
# the signatures will be added to the tar file.
def initialize(io, signer)
@io = io
@signer = signer
@tar_writer = Gem::Package::TarWriter.new @io
@metadata = nil
@data_signature = nil
@meta_signature = nil
end
##
# Yields a TarWriter for the data.tar.gz inside a gem-format tar file.
# The yielded TarWriter has been extended with a #metadata= method for
# attaching a YAML format Gem::Specification which will be written by
# add_metadata.
def add_gem_contents
@tar_writer.add_file "data.tar.gz", 0644 do |inner|
sio = @signer ? StringIO.new : nil
Zlib::GzipWriter.wrap(sio || inner) do |os|
Gem::Package::TarWriter.new os do |data_tar_writer|
# :stopdoc:
def data_tar_writer.metadata() @metadata end
def data_tar_writer.metadata=(metadata) @metadata = metadata end
# :startdoc:
yield data_tar_writer
@metadata = data_tar_writer.metadata
end
end
# if we have a signing key, then sign the data
# digest and return the signature
if @signer then
require 'rubygems/security'
digest = Gem::Security::OPT[:dgst_algo].digest sio.string
@data_signature = @signer.sign digest
inner.write sio.string
end
end
self
end
##
# Adds metadata.gz to the gem-format tar file which was saved from a
# previous #add_gem_contents call.
def add_metadata
return if @metadata.nil?
@tar_writer.add_file "metadata.gz", 0644 do |io|
begin
sio = @signer ? StringIO.new : nil
gzos = Zlib::GzipWriter.new(sio || io)
gzos.write @metadata
ensure
gzos.flush
gzos.finish
# if we have a signing key, then sign the metadata digest and return
# the signature
if @signer then
require 'rubygems/security'
digest = Gem::Security::OPT[:dgst_algo].digest sio.string
@meta_signature = @signer.sign digest
io.write sio.string
end
end
end
end
##
# Adds data.tar.gz.sig and metadata.gz.sig to the gem-format tar files if
# a Gem::Security::Signer was sent to initialize.
def add_signatures
if @data_signature then
@tar_writer.add_file 'data.tar.gz.sig', 0644 do |io|
io.write @data_signature
end
end
if @meta_signature then
@tar_writer.add_file 'metadata.gz.sig', 0644 do |io|
io.write @meta_signature
end
end
end
##
# Closes the TarOutput.
def close
@tar_writer.close
end
end

Просмотреть файл

@ -9,7 +9,7 @@
class Gem::Package::TarReader
include Gem::Package
include Enumerable
##
# Raised if the tar IO is not seekable
@ -52,9 +52,9 @@ class Gem::Package::TarReader
# Iterates over files in the tarball yielding each entry
def each
loop do
return if @io.eof?
return enum_for __method__ unless block_given?
until @io.eof? do
header = Gem::Package::TarHeader.from @io
return if header.empty?
@ -100,6 +100,23 @@ class Gem::Package::TarReader
end
end
##
# Seeks through the tar file until it finds the +entry+ with +name+ and
# yields it. Rewinds the tar file to the beginning when the block
# terminates.
def seek name # :yields: entry
found = find do |entry|
entry.full_name == name
end
return unless found
return yield found
ensure
rewind
end
end
require 'rubygems/package/tar_reader/entry'

Просмотреть файл

@ -40,12 +40,12 @@ class Gem::Package::TarWriter
# number of bytes will be more than #limit
def write(data)
if data.size + @written > @limit
if data.bytesize + @written > @limit
raise FileOverflow, "You tried to feed more data than fits in the file."
end
@io.write data
@written += data.size
data.size
@written += data.bytesize
data.bytesize
end
end
@ -129,6 +129,62 @@ class Gem::Package::TarWriter
self
end
##
# Adds +name+ with permissions +mode+ to the tar, yielding +io+ for writing
# the file. The +digest_algorithm+ is written to a read-only +name+.sum
# file following the given file contents containing the digest name and
# hexdigest separated by a tab.
#
# The created digest object is returned.
def add_file_digest name, mode, digest_algorithms # :yields: io
digests = digest_algorithms.map do |digest_algorithm|
digest = digest_algorithm.new
[digest.name, digest]
end
digests = Hash[*digests.flatten]
add_file name, mode do |io|
Gem::Package::DigestIO.wrap io, digests do |digest_io|
yield digest_io
end
end
digests
end
##
# Adds +name+ with permissions +mode+ to the tar, yielding +io+ for writing
# the file. The +signer+ is used to add a digest file using its
# digest_algorithm per add_file_digest and a cryptographic signature in
# +name+.sig. If the signer has no key only the checksum file is added.
#
# Returns the digest.
def add_file_signed name, mode, signer
digest_algorithms = [
signer.digest_algorithm,
OpenSSL::Digest::SHA512,
].uniq
digests = add_file_digest name, mode, digest_algorithms do |io|
yield io
end
signature_digest = digests.values.find do |digest|
digest.name == signer.digest_name
end
signature = signer.sign signature_digest.digest
add_file_simple "#{name}.sig", 0444, signature.length do |io|
io.write signature
end if signature
digests
end
##
# Add file +name+ with permissions +mode+ +size+ bytes long. Yields an IO
# to write the file to.
@ -211,9 +267,9 @@ class Gem::Package::TarWriter
# Splits +name+ into a name and prefix that can fit in the TarHeader
def split_name(name) # :nodoc:
raise Gem::Package::TooLongFileName if name.size > 256
raise Gem::Package::TooLongFileName if name.bytesize > 256
if name.size <= 100 then
if name.bytesize <= 100 then
prefix = ""
else
parts = name.split(/\//)
@ -222,14 +278,14 @@ class Gem::Package::TarWriter
loop do
nxt = parts.pop
break if newname.size + 1 + nxt.size > 100
break if newname.bytesize + 1 + nxt.bytesize > 100
newname = nxt + "/" + newname
end
prefix = (parts + [nxt]).join "/"
name = newname
if name.size > 100 or prefix.size > 155 then
if name.bytesize > 100 or prefix.bytesize > 155 then
raise Gem::Package::TooLongFileName
end
end

Просмотреть файл

@ -20,6 +20,7 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
require 'rubygems'
require 'rubygems/package'
begin
gem 'rake'
rescue Gem::LoadError
@ -43,13 +44,10 @@ require 'rake/packagetask'
# 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
@ -113,7 +111,8 @@ class Gem::PackageTask < Rake::PackageTask
file gem_path => [package_dir, gem_dir] + @gem_spec.files do
chdir(gem_dir) do
when_writing "Creating #{gem_spec.file_name}" do
Gem::Builder.new(gem_spec).build
Gem::Package.build gem_spec
verbose trace do
mv gem_file, '..'
end

Просмотреть файл

@ -1,4 +1,5 @@
##
#
# Gem::PathSupport facilitates the GEM_HOME and GEM_PATH environment settings
# to the rest of RubyGems.
#
@ -42,16 +43,18 @@ class Gem::PathSupport
# Set the Gem search path (as reported by Gem.path).
def path=(gpaths)
gem_path = [@home]
# FIX: it should be [home, *path], not [*path, home]
gem_path = []
# FIX: I can't tell wtf this is doing.
gpaths ||= (ENV['GEM_PATH'] || "").empty? ? nil : ENV["GEM_PATH"]
if gpaths then
if gpaths.kind_of?(Array) then
gem_path.push(*gpaths)
if gpaths
if gpaths.kind_of?(Array)
gem_path = gpaths.dup
else
gem_path.push(*gpaths.split(File::PATH_SEPARATOR))
gem_path = gpaths.split(File::PATH_SEPARATOR)
end
if File::ALT_SEPARATOR then
@ -59,10 +62,14 @@ class Gem::PathSupport
this_path.gsub File::ALT_SEPARATOR, File::SEPARATOR
end
end
else
gem_path.push(*Gem.default_path)
gem_path << APPLE_GEM_HOME if defined?(APPLE_GEM_HOME)
gem_path << @home
else
gem_path = Gem.default_path + [@home]
if defined?(APPLE_GEM_HOME)
gem_path << APPLE_GEM_HOME
end
end
@path = gem_path.uniq

Просмотреть файл

@ -21,7 +21,8 @@ class Gem::Platform
def self.match(platform)
Gem.platforms.any? do |local_platform|
platform.nil? or local_platform == platform or
platform.nil? or
local_platform == platform or
(local_platform != Gem::Platform::RUBY and local_platform =~ platform)
end
end
@ -65,28 +66,28 @@ class Gem::Platform
@cpu, os = nil, cpu if os.nil? # legacy jruby
@os, @version = case os
when /aix(\d+)/ then [ 'aix', $1 ]
when /cygwin/ then [ 'cygwin', nil ]
when /darwin(\d+)?/ then [ 'darwin', $1 ]
when /^macruby$/ then [ 'macruby', nil ]
when /freebsd(\d+)/ then [ 'freebsd', $1 ]
when /hpux(\d+)/ then [ 'hpux', $1 ]
when /^java$/, /^jruby$/ then [ 'java', nil ]
when /^java([\d.]*)/ then [ 'java', $1 ]
when /^dotnet$/ then [ 'dotnet', nil ]
when /^dotnet([\d.]*)/ then [ 'dotnet', $1 ]
when /linux/ then [ 'linux', $1 ]
when /mingw32/ then [ 'mingw32', nil ]
when /aix(\d+)?/ then [ 'aix', $1 ]
when /cygwin/ then [ 'cygwin', nil ]
when /darwin(\d+)?/ then [ 'darwin', $1 ]
when /^macruby$/ then [ 'macruby', nil ]
when /freebsd(\d+)?/ then [ 'freebsd', $1 ]
when /hpux(\d+)?/ then [ 'hpux', $1 ]
when /^java$/, /^jruby$/ then [ 'java', nil ]
when /^java([\d.]*)/ then [ 'java', $1 ]
when /^dotnet$/ then [ 'dotnet', nil ]
when /^dotnet([\d.]*)/ then [ 'dotnet', $1 ]
when /linux/ then [ 'linux', $1 ]
when /mingw32/ then [ 'mingw32', nil ]
when /(mswin\d+)(\_(\d+))?/ then
os, version = $1, $3
@cpu = 'x86' if @cpu.nil? and os =~ /32$/
[os, version]
when /(netbsd[a-z]*)(\d+)/ then [ $1, $2 ]
when /openbsd(\d+\.\d+)/ then [ 'openbsd', $1 ]
when /solaris(\d+\.\d+)/ then [ 'solaris', $1 ]
when /netbsdelf/ then [ 'netbsdelf', nil ]
when /openbsd(\d+\.\d+)?/ then [ 'openbsd', $1 ]
when /solaris(\d+\.\d+)?/ then [ 'solaris', $1 ]
# test
when /^(\w+_platform)(\d+)/ then [ $1, $2 ]
else [ 'unknown', nil ]
when /^(\w+_platform)(\d+)?/ then [ $1, $2 ]
else [ 'unknown', nil ]
end
when Gem::Platform then
@cpu = arch.cpu
@ -109,10 +110,6 @@ class Gem::Platform
to_a.compact.join '-'
end
def empty?
to_s.empty?
end
##
# Is +other+ equal to this platform? Two platforms are equal if they have
# the same CPU, OS and version.
@ -186,9 +183,5 @@ class Gem::Platform
# This will be replaced with Gem::Platform::local.
CURRENT = 'current'
extend Gem::Deprecate
deprecate :empty?, :none, 2011, 11
end

316
lib/rubygems/rdoc.rb Normal file
Просмотреть файл

@ -0,0 +1,316 @@
require 'rubygems'
require 'rubygems/user_interaction'
require 'fileutils'
begin
gem 'rdoc'
rescue Gem::LoadError
# swallow
else
# This will force any deps that 'rdoc' might have
# (such as json) that are ambigious to be activated, which
# is important because we end up using Specification.reset
# and we don't want the warning it pops out.
Gem.finish_resolve
end
loaded_hook = false
begin
require 'rdoc/rubygems_hook'
loaded_hook = true
module Gem
RDoc = RDoc::RubygemsHook
end
rescue LoadError
end
##
# Gem::RDoc provides methods to generate RDoc and ri data for installed gems.
# It works for RDoc 1.0.1 (in Ruby 1.8) up to RDoc 3.6.
#
# This implementation is considered obsolete. The RDoc project is the
# appropriate location to find this functionality. This file provides the
# hooks to load RDoc generation code from the "rdoc" gem and a fallback in
# case the installed version of RDoc does not have them.
class Gem::RDoc # :nodoc: all
include Gem::UserInteraction
@rdoc_version = nil
@specs = []
##
# Force installation of documentation?
attr_accessor :force
##
# Generate rdoc?
attr_accessor :generate_rdoc
##
# Generate ri data?
attr_accessor :generate_ri
class << self
##
# Loaded version of RDoc. Set by ::load_rdoc
attr_reader :rdoc_version
end
##
# Post installs hook that generates documentation for each specification in
# +specs+
def self.generation_hook installer, specs
types = installer.document
generate_rdoc = types.include? 'rdoc'
generate_ri = types.include? 'ri'
specs.each do |spec|
new(spec, generate_rdoc, generate_ri).generate
end
end
##
# Loads the RDoc generator
def self.load_rdoc
return if @rdoc_version
begin
require 'rdoc/rdoc'
@rdoc_version = if ::RDoc.const_defined? :VERSION then
Gem::Version.new ::RDoc::VERSION
else
Gem::Version.new '1.0.1'
end
rescue LoadError => e
raise Gem::DocumentError, "RDoc is not installed: #{e}"
end
end
##
# Creates a new documentation generator for +spec+. RDoc and ri data
# generation can be enabled or disabled through +generate_rdoc+ and
# +generate_ri+ respectively.
#
# Only +generate_ri+ is enabled by default.
def initialize spec, generate_rdoc = false, generate_ri = true
@doc_dir = spec.doc_dir
@file_info = nil
@force = false
@rdoc = nil
@spec = spec
@generate_rdoc = generate_rdoc
@generate_ri = generate_ri
@rdoc_dir = spec.doc_dir 'rdoc'
@ri_dir = spec.doc_dir 'ri'
end
##
# Removes legacy rdoc arguments from +args+
def delete_legacy_args args
args.delete '--inline-source'
args.delete '--promiscuous'
args.delete '-p'
args.delete '--one-file'
end
##
# Generates documentation using the named +generator+ ("darkfish" or "ri")
# and following the given +options+.
#
# Documentation will be generated into +destination+
def document generator, options, destination
options = options.dup
options.exclude ||= [] # TODO maybe move to RDoc::Options#finish
options.setup_generator generator
options.op_dir = destination
options.finish
@rdoc.options = options
@rdoc.generator = options.generator.new options
say "Installing #{generator} documentation for #{@spec.full_name}"
FileUtils.mkdir_p options.op_dir
Dir.chdir options.op_dir do
begin
@rdoc.class.current = @rdoc
@rdoc.generator.generate @file_info
ensure
@rdoc.class.current = nil
end
end
end
##
# Generates RDoc and ri data
def generate
return unless @generate_ri or @generate_rdoc
setup
if Gem::Requirement.new('< 3').satisfied_by? self.class.rdoc_version then
generate_legacy
else
::RDoc::TopLevel.reset # TODO ::RDoc::RDoc.reset
::RDoc::Parser::C.reset
options = ::RDoc::Options.new
options.default_title = "#{@spec.full_name} Documentation"
options.files = []
options.files.push(*@spec.require_paths)
options.files.push(*@spec.extra_rdoc_files)
args = @spec.rdoc_options
case config_args = Gem.configuration[:rdoc]
when String then
args = args.concat config_args.split
when Array then
args = args.concat config_args
end
delete_legacy_args args
options.parse args
options.quiet = !Gem.configuration.really_verbose
@rdoc = new_rdoc
@rdoc.options = options
Dir.chdir @spec.full_gem_path do
@file_info = @rdoc.parse_files options.files
end
document 'ri', options, @ri_dir if
@generate_ri and (@force or not File.exist? @ri_dir)
document 'darkfish', options, @rdoc_dir if
@generate_rdoc and (@force or not File.exist? @rdoc_dir)
end
end
##
# Generates RDoc and ri data for legacy RDoc versions. This method will not
# exist in future versions.
def generate_legacy
if @generate_rdoc then
FileUtils.rm_rf @rdoc_dir
say "Installing RDoc documentation for #{@spec.full_name}"
legacy_rdoc '--op', @rdoc_dir
end
if @generate_ri then
FileUtils.rm_rf @ri_dir
say "Installing ri documentation for #{@spec.full_name}"
legacy_rdoc '--ri', '--op', @ri_dir
end
end
##
# Generates RDoc using a legacy version of RDoc from the ARGV-like +args+.
# This method will not exist in future versions.
def legacy_rdoc *args
args << @spec.rdoc_options
args << '--quiet'
args << @spec.require_paths.clone
args << @spec.extra_rdoc_files
args << '--title' << "#{@spec.full_name} Documentation"
args = args.flatten.map do |arg| arg.to_s end
delete_legacy_args args if
Gem::Requirement.new('>= 2.4.0') =~ self.class.rdoc_version
r = new_rdoc
say "rdoc #{args.join ' '}" if Gem.configuration.really_verbose
Dir.chdir @spec.full_gem_path do
begin
r.document args
rescue Errno::EACCES => e
dirname = File.dirname e.message.split("-")[1].strip
raise Gem::FilePermissionError, dirname
rescue Interrupt => e
raise e
rescue Exception => ex
alert_error "While generating documentation for #{@spec.full_name}"
ui.errs.puts "... MESSAGE: #{ex}"
ui.errs.puts "... RDOC args: #{args.join(' ')}"
ui.backtrace ex
ui.errs.puts "(continuing with the rest of the installation)"
ensure
end
end
end
##
# #new_rdoc creates a new RDoc instance. This method is provided only to
# make testing easier.
def new_rdoc
::RDoc::RDoc.new
end
##
# Is rdoc documentation installed?
def rdoc_installed?
File.exist? @rdoc_dir
end
##
# Removes generated RDoc and ri data
def remove
base_dir = @spec.base_dir
raise Gem::FilePermissionError, base_dir unless File.writable? base_dir
FileUtils.rm_rf @rdoc_dir
FileUtils.rm_rf @ri_dir
end
##
# Is ri data installed?
def ri_installed?
File.exist? @ri_dir
end
##
# Prepares the spec for documentation generation
def setup
self.class.load_rdoc
raise Gem::FilePermissionError, @doc_dir if
File.exist?(@doc_dir) and not File.writable?(@doc_dir)
FileUtils.mkdir_p @doc_dir unless File.exist? @doc_dir
end
end unless loaded_hook
Gem.done_installing(&Gem::RDoc.method(:generation_hook))

Просмотреть файл

@ -1,6 +1,7 @@
require 'rubygems'
require 'rubygems/user_interaction'
require 'uri'
require 'resolv'
##
# RemoteFetcher handles the details of fetching gems and gem information from
@ -8,8 +9,6 @@ require 'uri'
class Gem::RemoteFetcher
BuiltinSSLCerts = File.expand_path("./ssl_certs/*.pem", File.dirname(__FILE__))
include Gem::UserInteraction
##
@ -34,6 +33,13 @@ class Gem::RemoteFetcher
end
##
# A FetchError that indicates that the reason for not being
# able to fetch data was that the host could not be contacted
class UnknownHostError < FetchError
end
@fetcher = nil
##
@ -53,8 +59,11 @@ class Gem::RemoteFetcher
# * nil: respect environment variables (HTTP_PROXY, HTTP_PROXY_USER,
# HTTP_PROXY_PASS)
# * <tt>:no_proxy</tt>: ignore environment variables and _don't_ use a proxy
#
# +dns+: An object to use for DNS resolution of the API endpoint.
# By default, use Resolv::DNS.
def initialize(proxy = nil)
def initialize(proxy=nil, dns=Resolv::DNS.new)
require 'net/http'
require 'stringio'
require 'time'
@ -72,6 +81,27 @@ class Gem::RemoteFetcher
else URI.parse(proxy)
end
@user_agent = user_agent
@env_no_proxy = get_no_proxy_from_env
@dns = dns
end
##
#
# Given a source at +uri+, calculate what hostname to actually
# connect to query the data for it.
def api_endpoint(uri)
host = uri.host
begin
res = @dns.getresource "_rubygems._tcp.#{host}",
Resolv::DNS::Resource::IN::SRV
rescue Resolv::ResolvError
uri
else
URI.parse "#{res.target}#{uri.path}"
end
end
##
@ -82,14 +112,13 @@ class Gem::RemoteFetcher
# larger, more emcompassing effort. -erikh
def download_to_cache dependency
found = Gem::SpecFetcher.fetcher.fetch dependency, true, true,
dependency.prerelease?
found, _ = Gem::SpecFetcher.fetcher.spec_for_dependency dependency
return if found.empty?
spec, source_uri = found.sort_by { |(s,_)| s.version }.last
spec, source = found.sort_by { |(s,_)| s.version }.last
download spec, source_uri
download spec, source.uri.to_s
end
##
@ -100,11 +129,14 @@ class Gem::RemoteFetcher
def download(spec, source_uri, install_dir = Gem.dir)
Gem.ensure_gem_subdirectories(install_dir) rescue nil
if File.writable?(install_dir)
cache_dir = File.join install_dir, "cache"
else
cache_dir = File.join Gem.user_dir, "cache"
end
cache_dir =
if Dir.pwd == install_dir then # see fetch_command
install_dir
elsif File.writable? install_dir then
File.join install_dir, "cache"
else
File.join Gem.user_dir, "cache"
end
gem_file_name = File.basename spec.cache_file
local_gem_path = File.join cache_dir, gem_file_name
@ -123,6 +155,8 @@ class Gem::RemoteFetcher
# URI.parse gets confused by MS Windows paths with forward slashes.
scheme = nil if scheme =~ /^[a-z]$/i
# REFACTOR: split this up and dispatch on scheme (eg download_http)
# REFACTOR: be sure to clean up fake fetcher when you do this... cleaner
case scheme
when 'http', 'https' then
unless File.exist? local_gem_path then
@ -132,7 +166,7 @@ class Gem::RemoteFetcher
remote_gem_path = source_uri + "gems/#{gem_file_name}"
gem = self.fetch_path remote_gem_path
self.cache_update_path remote_gem_path, local_gem_path
rescue Gem::RemoteFetcher::FetchError
raise if spec.original_platform == spec.platform
@ -143,11 +177,7 @@ class Gem::RemoteFetcher
remote_gem_path = source_uri + "gems/#{alternate_name}"
gem = self.fetch_path remote_gem_path
end
File.open local_gem_path, 'wb' do |fp|
fp.write gem
self.cache_update_path remote_gem_path, local_gem_path
end
end
when 'file' then
@ -184,7 +214,7 @@ class Gem::RemoteFetcher
say "Using local gem #{local_gem_path}" if
Gem.configuration.really_verbose
else
raise Gem::InstallError, "unsupported URI scheme #{source_uri.scheme}"
raise ArgumentError, "unsupported URI scheme #{source_uri.scheme}"
end
local_gem_path
@ -232,18 +262,54 @@ class Gem::RemoteFetcher
uri = URI.parse uri unless URI::Generic === uri
raise ArgumentError, "bad uri: #{uri}" unless uri
raise ArgumentError, "uri scheme is invalid: #{uri.scheme.inspect}" unless
uri.scheme
unless uri.scheme
raise ArgumentError, "uri scheme is invalid: #{uri.scheme.inspect}"
end
data = send "fetch_#{uri.scheme}", uri, mtime, head
data = Gem.gunzip data if data and not head and uri.to_s =~ /gz$/
if data and !head and uri.to_s =~ /gz$/
begin
data = Gem.gunzip data
rescue Zlib::GzipFile::Error
raise FetchError.new("server did not return a valid file", uri.to_s)
end
end
data
rescue FetchError
raise
rescue Timeout::Error
raise FetchError.new('timed out', uri.to_s)
raise UnknownHostError.new('timed out', uri.to_s)
rescue IOError, SocketError, SystemCallError => e
raise FetchError.new("#{e.class}: #{e}", uri.to_s)
if e.message =~ /getaddrinfo/
raise UnknownHostError.new('no such name', uri.to_s)
else
raise FetchError.new("#{e.class}: #{e}", uri.to_s)
end
end
##
# Downloads +uri+ to +path+ if necessary. If no path is given, it just
# passes the data.
def cache_update_path(uri, path = nil)
mtime = path && File.stat(path).mtime rescue nil
if mtime && Net::HTTPNotModified === fetch_path(uri, mtime, true)
Gem.read_binary(path)
else
data = fetch_path(uri)
if path
open(path, 'wb') do |io|
io.write data
end
end
data
end
end
##
@ -273,6 +339,17 @@ class Gem::RemoteFetcher
URI
end
##
# Returns list of no_proxy entries (if any) from the environment
def get_no_proxy_from_env
env_no_proxy = ENV['no_proxy'] || ENV['NO_PROXY']
return [] if env_no_proxy.nil? or env_no_proxy.empty?
env_no_proxy.split(/\s*,\s*/)
end
##
# Returns an HTTP proxy URI if one is set in the environment variables.
@ -296,7 +373,7 @@ class Gem::RemoteFetcher
# Normalize the URI by adding "http://" if it is missing.
def normalize_uri(uri)
(uri =~ /^(https?|ftp|file):/) ? uri : "http://#{uri}"
(uri =~ /^(https?|ftp|file):/i) ? uri : "http://#{uri}"
end
##
@ -306,7 +383,7 @@ class Gem::RemoteFetcher
def connection_for(uri)
net_http_args = [uri.host, uri.port]
if @proxy_uri then
if @proxy_uri and not no_proxy?(uri.host) then
net_http_args += [
@proxy_uri.host,
@proxy_uri.port,
@ -319,37 +396,23 @@ class Gem::RemoteFetcher
@connections[connection_id] ||= Net::HTTP.new(*net_http_args)
connection = @connections[connection_id]
if https?(uri) and !connection.started? then
if https?(uri) and not connection.started? then
configure_connection_for_https(connection)
# Don't refactor this with the else branch. We don't want the
# http-only code path to not depend on anything in OpenSSL.
#
begin
connection.start
rescue OpenSSL::SSL::SSLError, Errno::EHOSTDOWN => e
raise FetchError.new(e.message, uri)
end
else
begin
connection.start unless connection.started?
rescue Errno::EHOSTDOWN => e
raise FetchError.new(e.message, uri)
end
end
connection.start unless connection.started?
connection
rescue OpenSSL::SSL::SSLError, Errno::EHOSTDOWN => e
raise FetchError.new(e.message, uri)
end
def configure_connection_for_https(connection)
require 'net/https'
connection.use_ssl = true
connection.verify_mode =
Gem.configuration.ssl_verify_mode || OpenSSL::SSL::VERIFY_PEER
store = OpenSSL::X509::Store.new
if Gem.configuration.ssl_ca_cert
if File.directory? Gem.configuration.ssl_ca_cert
store.add_path Gem.configuration.ssl_ca_cert
@ -360,12 +423,12 @@ class Gem::RemoteFetcher
store.set_default_paths
add_rubygems_trusted_certs(store)
end
connection.cert_store = store
end
def add_rubygems_trusted_certs(store)
Dir.glob(BuiltinSSLCerts).each do |ssl_cert_file|
pattern = File.expand_path("./ssl_certs/*.pem", File.dirname(__FILE__))
Dir.glob(pattern).each do |ssl_cert_file|
store.add_file ssl_cert_file
end
end
@ -378,13 +441,13 @@ class Gem::RemoteFetcher
end
end
##
# Read the data from the (source based) URI, but if it is a file:// URI,
# read from the filesystem instead.
def open_uri_or_path(uri, last_modified = nil, head = false, depth = 0)
raise "NO: Use fetch_path instead"
# TODO: deprecate for fetch_path
def no_proxy? host
host = host.downcase
@env_no_proxy.each do |pattern|
pattern = pattern.downcase
return true if host[-pattern.length, pattern.length ] == pattern
end
return false
end
##

182
lib/rubygems/request_set.rb Normal file
Просмотреть файл

@ -0,0 +1,182 @@
require 'rubygems'
require 'rubygems/dependency'
require 'rubygems/dependency_resolver'
require 'rubygems/dependency_list'
require 'rubygems/installer'
require 'tsort'
module Gem
class RequestSet
include TSort
def initialize(*deps)
@dependencies = deps
yield self if block_given?
end
attr_reader :dependencies
# Declare that a gem of name +name+ with +reqs+ requirements
# is needed.
#
def gem(name, *reqs)
@dependencies << Gem::Dependency.new(name, reqs)
end
# Add +deps+ Gem::Depedency objects to the set.
#
def import(deps)
@dependencies += deps
end
# Resolve the requested dependencies and return an Array of
# Specification objects to be activated.
#
def resolve(set=nil)
r = Gem::DependencyResolver.new(@dependencies, set)
@requests = r.resolve
end
# Resolve the requested dependencies against the gems
# available via Gem.path and return an Array of Specification
# objects to be activated.
#
def resolve_current
resolve DependencyResolver::CurrentSet.new
end
# Load a dependency management file.
#
def load_gemdeps(path)
gf = GemDepedencyAPI.new(self, path)
gf.load
end
def specs
@specs ||= @requests.map { |r| r.full_spec }
end
def tsort_each_node(&block)
@requests.each(&block)
end
def tsort_each_child(node)
node.spec.dependencies.each do |dep|
next if dep.type == :development
match = @requests.find { |r| dep.match? r.spec.name, r.spec.version }
if match
begin
yield match
rescue TSort::Cyclic
end
else
raise Gem::DependencyError, "Unresolved depedency found during sorting - #{dep}"
end
end
end
def sorted_requests
@sorted ||= strongly_connected_components.flatten
end
def specs_in(dir)
Dir["#{dir}/specifications/*.gemspec"].map do |g|
Gem::Specification.load g
end
end
def install_into(dir, force=true, &b)
existing = force ? [] : specs_in(dir)
dir = File.expand_path dir
installed = []
sorted_requests.each do |req|
if existing.find { |s| s.full_name == req.spec.full_name }
b.call req, nil if b
next
end
path = req.download(dir)
inst = Gem::Installer.new path, :install_dir => dir,
:only_install_dir => true
b.call req, inst if b
inst.install
installed << req
end
installed
end
def install(options, &b)
if dir = options[:install_dir]
return install_into(dir, false, &b)
end
cache_dir = options[:cache_dir] || Gem.dir
specs = []
sorted_requests.each do |req|
if req.installed?
b.call req, nil if b
next
end
path = req.download cache_dir
inst = Gem::Installer.new path, options
b.call req, inst if b
specs << inst.install
end
specs
end
# A semi-compatible DSL for Bundler's Gemfile format
#
class GemDepedencyAPI
def initialize(set, path)
@set = set
@path = path
end
def load
instance_eval File.read(@path).untaint, @path, 1
end
# DSL
def source(url)
end
def gem(name, *reqs)
# Ignore the opts for now.
reqs.pop if reqs.last.kind_of?(Hash)
@set.gem name, *reqs
end
def platform(what)
if what == :ruby
yield
end
end
alias_method :platforms, :platform
def group(*what)
end
end
end
end

Просмотреть файл

@ -1,18 +0,0 @@
require 'rubygems'
# TODO: remove after 1.9.1 dropped
module Gem::RequirePathsBuilder
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")
file_name = File.join(gem_home, 'gems', "#{@spec.full_name}", ".require_paths")
file_name.untaint
File.open(file_name, "w") do |file|
spec.require_paths.each do |path|
file.puts path
end
file.puts spec.bindir if spec.bindir
end
end
end if Gem::QUICKLOADER_SUCKAGE

Просмотреть файл

@ -1,5 +1,3 @@
require "rubygems/version"
##
# A Requirement is a set of one or more version restrictions. It supports a
# few (<tt>=, !=, >, <, >=, <=, ~></tt>) different restriction operators.
@ -13,14 +11,16 @@ require "rubygems/version"
require "rubygems/version"
require "rubygems/deprecate"
class Gem::Requirement
include Comparable
# If we're being loaded after yaml was already required, then
# load our yaml + workarounds now.
Gem.load_yaml if defined? ::YAML
class Gem::Requirement
OPS = { #:nodoc:
"=" => 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 },
"<=" => lambda { |v, r| v <= r },
"~>" => lambda { |v, r| v >= r && v.release < r.bump }
@ -29,6 +29,10 @@ class Gem::Requirement
quoted = OPS.keys.map { |k| Regexp.quote k }.join "|"
PATTERN = /\A\s*(#{quoted})?\s*(#{Gem::Version::VERSION_PATTERN})\s*\z/
DefaultRequirement = [">=", Gem::Version.new(0)]
class BadRequirementError < ArgumentError; end
##
# Factory method to create a Gem::Requirement object. Input may be
# a Version, a String, or nil. Intended to simplify client code.
@ -36,6 +40,9 @@ class Gem::Requirement
# If the input is "weird", the default version requirement is
# returned.
# REFACTOR: There's no reason that this can't be unified with .new.
# .new is the standard Ruby factory method.
def self.create input
case input
when Gem::Requirement then
@ -53,10 +60,6 @@ class Gem::Requirement
##
# A default "version requirement" can surely _only_ be '>= 0'.
#--
# This comment once said:
#
# "A default "version requirement" can surely _only_ be '> 0'."
def self.default
new '>= 0'
@ -74,14 +77,23 @@ class Gem::Requirement
# parse("1.0") # => ["=", "1.0"]
# parse(Gem::Version.new("1.0")) # => ["=, "1.0"]
# REFACTOR: Little two element arrays like this have no real semantic
# value. I'd love to see something like this:
# Constraint = Struct.new(:operator, :version); (or similar)
# and have a Requirement be a list of Constraints.
def self.parse obj
return ["=", obj] if Gem::Version === obj
unless PATTERN =~ obj.to_s
raise ArgumentError, "Illformed requirement [#{obj.inspect}]"
raise BadRequirementError, "Illformed requirement [#{obj.inspect}]"
end
[$1 || "=", Gem::Version.new($2)]
if $1 == ">=" && $2 == "0"
DefaultRequirement
else
[$1 || "=", Gem::Version.new($2)]
end
end
##
@ -101,13 +113,23 @@ class Gem::Requirement
requirements.compact!
requirements.uniq!
requirements << ">= 0" if requirements.empty?
@none = (requirements == ">= 0")
@requirements = requirements.map! { |r| self.class.parse r }
if requirements.empty?
@requirements = [DefaultRequirement]
else
@requirements = requirements.map! { |r| self.class.parse r }
end
end
##
# true if this gem has no requirements.
# FIX: maybe this should be using #default ?
def none?
@none ||= (to_s == ">= 0")
if @requirements.size == 1
@requirements[0] == DefaultRequirement
else
false
end
end
def as_list # :nodoc:
@ -135,6 +157,7 @@ class Gem::Requirement
instance_variable_set "@#{ivar}", val
end
Gem.load_yaml
fix_syck_default_key_in_requirements
end
@ -142,6 +165,18 @@ class Gem::Requirement
yaml_initialize coder.tag, coder.map
end
def to_yaml_properties
["@requirements"]
end
def encode_with(coder)
coder.add 'requirements', @requirements
end
##
# A requirement is a prerelease if any of the versions inside of it
# are prereleases
def prerelease?
requirements.any? { |r| r.last.prerelease? }
end
@ -156,6 +191,8 @@ class Gem::Requirement
# True if +version+ satisfies this Requirement.
def satisfied_by? version
raise ArgumentError, "Need a Gem::Version: #{version.inspect}" unless
Gem::Version === version
# #28965: syck has a bug with unquoted '=' YAML.loading as YAML::DefaultKey
requirements.all? { |op, rv| (OPS[op] || OPS["="]).call version, rv }
end
@ -176,12 +213,14 @@ class Gem::Requirement
as_list.join ", "
end
def <=> other # :nodoc:
to_s <=> other.to_s
# DOC: this should probably be :nodoc'd
def == other
Gem::Requirement === other and to_s == other.to_s
end
private
# DOC: this should probably be :nodoc'd
def fix_syck_default_key_in_requirements
Gem.load_yaml
@ -194,11 +233,9 @@ class Gem::Requirement
end
end
# :stopdoc:
# Gem::Version::Requirement is used in a lot of old YAML specs. It's aliased
# here for backwards compatibility. I'd like to remove this, maybe in RubyGems
# 2.0.
::Gem::Version::Requirement = ::Gem::Requirement
# :startdoc:
# This is needed for compatibility with older yaml
# gemspecs.
class Gem::Version
Requirement = Gem::Requirement
end

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,115 @@
module Gem::Security
##
# No security policy: all package signature checks are disabled.
NoSecurity = Policy.new(
'No Security',
:verify_data => false,
:verify_signer => false,
:verify_chain => false,
:verify_root => false,
:only_trusted => false,
:only_signed => false
)
##
# AlmostNo security policy: only verify that the signing certificate is the
# one that actually signed the data. Make no attempt to verify the signing
# certificate chain.
#
# This policy is basically useless. better than nothing, but can still be
# easily spoofed, and is not recommended.
AlmostNoSecurity = Policy.new(
'Almost No Security',
:verify_data => true,
:verify_signer => false,
:verify_chain => false,
:verify_root => false,
:only_trusted => false,
:only_signed => false
)
##
# Low security policy: only verify that the signing certificate is actually
# the gem signer, and that the signing certificate is valid.
#
# This policy is better than nothing, but can still be easily spoofed, and
# is not recommended.
LowSecurity = Policy.new(
'Low Security',
:verify_data => true,
:verify_signer => true,
:verify_chain => false,
:verify_root => false,
:only_trusted => false,
:only_signed => false
)
##
# Medium security policy: verify the signing certificate, verify the signing
# certificate chain all the way to the root certificate, and only trust root
# certificates that we have explicitly allowed trust for.
#
# This security policy is reasonable, but it allows unsigned packages, so a
# malicious person could simply delete the package signature and pass the
# gem off as unsigned.
MediumSecurity = Policy.new(
'Medium Security',
:verify_data => true,
:verify_signer => true,
:verify_chain => true,
:verify_root => true,
:only_trusted => true,
:only_signed => false
)
##
# High security policy: only allow signed gems to be installed, verify the
# signing certificate, verify the signing certificate chain all the way to
# the root certificate, and only trust root certificates that we have
# explicitly allowed trust for.
#
# This security policy is significantly more difficult to bypass, and offers
# a reasonable guarantee that the contents of the gem have not been altered.
HighSecurity = Policy.new(
'High Security',
:verify_data => true,
:verify_signer => true,
:verify_chain => true,
:verify_root => true,
:only_trusted => true,
:only_signed => true
)
##
# Policy used to verify a certificate and key when signing a gem
SigningPolicy = Policy.new(
'Signing Policy',
:verify_data => false,
:verify_signer => true,
:verify_chain => true,
:verify_root => true,
:only_trusted => false,
:only_signed => false
)
##
# Hash of configured security policies
Policies = {
'NoSecurity' => NoSecurity,
'AlmostNoSecurity' => AlmostNoSecurity,
'LowSecurity' => LowSecurity,
'MediumSecurity' => MediumSecurity,
'HighSecurity' => HighSecurity,
# SigningPolicy is not intended for use by `gem -P` so do not list it
}
end

Просмотреть файл

@ -0,0 +1,227 @@
##
# A Gem::Security::Policy object encapsulates the settings for verifying
# signed gem files. This is the base class. You can either declare an
# instance of this or use one of the preset security policies in
# Gem::Security::Policies.
class Gem::Security::Policy
attr_reader :name
attr_accessor :only_signed
attr_accessor :only_trusted
attr_accessor :verify_chain
attr_accessor :verify_data
attr_accessor :verify_root
attr_accessor :verify_signer
##
# Create a new Gem::Security::Policy object with the given mode and
# options.
def initialize name, policy = {}, opt = {}
@name = name
@opt = opt
# Default to security
@only_signed = true
@only_trusted = true
@verify_chain = true
@verify_data = true
@verify_root = true
@verify_signer = true
policy.each_pair do |key, val|
case key
when :verify_data then @verify_data = val
when :verify_signer then @verify_signer = val
when :verify_chain then @verify_chain = val
when :verify_root then @verify_root = val
when :only_trusted then @only_trusted = val
when :only_signed then @only_signed = val
end
end
end
##
# Verifies each certificate in +chain+ has signed the following certificate
# and is valid for the given +time+.
def check_chain chain, time
chain.each_cons 2 do |issuer, cert|
check_cert cert, issuer, time
end
true
rescue Gem::Security::Exception => e
raise Gem::Security::Exception, "invalid signing chain: #{e.message}"
end
##
# Verifies that +data+ matches the +signature+ created by +public_key+ and
# the +digest+ algorithm.
def check_data public_key, digest, signature, data
raise Gem::Security::Exception, "invalid signature" unless
public_key.verify digest.new, signature, data.digest
true
end
##
# Ensures that +signer+ is valid for +time+ and was signed by the +issuer+.
# If the +issuer+ is +nil+ no verification is performed.
def check_cert signer, issuer, time
message = "certificate #{signer.subject}"
if not_before = signer.not_before and not_before > time then
raise Gem::Security::Exception,
"#{message} not valid before #{not_before}"
end
if not_after = signer.not_after and not_after < time then
raise Gem::Security::Exception, "#{message} not valid after #{not_after}"
end
if issuer and not signer.verify issuer.public_key then
raise Gem::Security::Exception,
"#{message} was not issued by #{issuer.subject}"
end
true
end
##
# Ensures the public key of +key+ matches the public key in +signer+
def check_key signer, key
raise Gem::Security::Exception,
"certificate #{signer.subject} does not match the signing key" unless
signer.public_key.to_pem == key.public_key.to_pem
true
end
##
# Ensures the root certificate in +chain+ is self-signed and valid for
# +time+.
def check_root chain, time
root = chain.first
raise Gem::Security::Exception,
"root certificate #{root.subject} is not self-signed " \
"(issuer #{root.issuer})" if
root.issuer.to_s != root.subject.to_s # HACK to_s is for ruby 1.8
check_cert root, root, time
end
##
# Ensures the root of +chain+ has a trusted certificate in +trust_dir+ and
# the digests of the two certificates match according to +digester+
def check_trust chain, digester, trust_dir
root = chain.first
path = Gem::Security.trust_dir.cert_path root
unless File.exist? path then
message = "root cert #{root.subject} is not trusted"
message << " (root of signing cert #{chain.last.subject})" if
chain.length > 1
raise Gem::Security::Exception, message
end
save_cert = OpenSSL::X509::Certificate.new File.read path
save_dgst = digester.digest save_cert.public_key.to_s
pkey_str = root.public_key.to_s
cert_dgst = digester.digest pkey_str
raise Gem::Security::Exception,
"trusted root certificate #{root.subject} checksum " \
"does not match signing root certificate checksum" unless
save_dgst == cert_dgst
true
end
def inspect # :nodoc:
"[Policy: %s - data: %p signer: %p chain: %p root: %p " \
"signed-only: %p trusted-only: %p]" % [
@name, @verify_chain, @verify_data, @verify_root, @verify_signer,
@only_signed, @only_trusted,
]
end
##
# Verifies the certificate +chain+ is valid, the +digests+ match the
# signatures +signatures+ created by the signer depending on the +policy+
# settings.
#
# If +key+ is given it is used to validate the signing certificate.
def verify chain, key = nil, digests = {}, signatures = {}
if @only_signed and signatures.empty? then
raise Gem::Security::Exception,
"unsigned gems are not allowed by the #{name} policy"
end
opt = @opt
digester = Gem::Security::DIGEST_ALGORITHM
trust_dir = opt[:trust_dir]
time = Time.now
signer_digests = digests.find do |algorithm, file_digests|
file_digests.values.first.name == Gem::Security::DIGEST_NAME
end
signer_digests = digests.values.first || {}
signer = chain.last
check_key signer, key if key
check_cert signer, nil, time if @verify_signer
check_chain chain, time if @verify_chain
check_root chain, time if @verify_root
check_trust chain, digester, trust_dir if @only_trusted
signer_digests.each do |file, digest|
signature = signatures[file]
raise Gem::Security::Exception, "missing signature for #{file}" unless
signature
check_data signer.public_key, digester, signature, digest if @verify_data
end
true
end
##
# Extracts the certificate chain from the +spec+ and calls #verify to ensure
# the signatures and certificate chain is valid according to the policy..
def verify_signatures spec, digests, signatures
chain = spec.cert_chain.map do |cert_pem|
OpenSSL::X509::Certificate.new cert_pem
end
verify chain, nil, digests, signatures
true
end
alias to_s name # :nodoc:
end

Просмотреть файл

@ -0,0 +1,136 @@
##
# Basic OpenSSL-based package signing class.
class Gem::Security::Signer
##
# The chain of certificates for signing including the signing certificate
attr_accessor :cert_chain
##
# The private key for the signing certificate
attr_accessor :key
##
# The digest algorithm used to create the signature
attr_reader :digest_algorithm
##
# The name of the digest algorithm, used to pull digests out of the hash by
# name.
attr_reader :digest_name # :nodoc:
##
# Creates a new signer with an RSA +key+ or path to a key, and a certificate
# +chain+ containing X509 certificates, encoding certificates or paths to
# certificates.
def initialize key, cert_chain
@cert_chain = cert_chain
@key = key
unless @key then
default_key = File.join Gem.user_home, 'gem-private_key.pem'
@key = default_key if File.exist? default_key
end
unless @cert_chain then
default_cert = File.join Gem.user_home, 'gem-public_cert.pem'
@cert_chain = [default_cert] if File.exist? default_cert
end
@digest_algorithm = Gem::Security::DIGEST_ALGORITHM
@digest_name = Gem::Security::DIGEST_NAME
@key = OpenSSL::PKey::RSA.new File.read @key if
@key and not OpenSSL::PKey::RSA === @key
if @cert_chain then
@cert_chain = @cert_chain.compact.map do |cert|
next cert if OpenSSL::X509::Certificate === cert
cert = File.read cert if File.exist? cert
OpenSSL::X509::Certificate.new cert
end
load_cert_chain
end
end
##
# Loads any missing issuers in the cert chain from the trusted certificates.
#
# If the issuer does not exist it is ignored as it will be checked later.
def load_cert_chain # :nodoc:
return if @cert_chain.empty?
while @cert_chain.first.issuer.to_s != @cert_chain.first.subject.to_s do
issuer = Gem::Security.trust_dir.issuer_of @cert_chain.first
break unless issuer # cert chain is verified later
@cert_chain.unshift issuer
end
end
##
# Sign data with given digest algorithm
def sign data
return unless @key
if @cert_chain.length == 1 and @cert_chain.last.not_after < Time.now then
re_sign_key
end
Gem::Security::SigningPolicy.verify @cert_chain, @key
@key.sign @digest_algorithm.new, data
end
##
# Attempts to re-sign the private key if the signing certificate is expired.
#
# The key will be re-signed if:
# * The expired certificate is self-signed
# * The expired certificate is saved at ~/.gem/gem-public_cert.pem
# * There is no file matching the expiry date at
# ~/.gem/gem-public_cert.pem.expired.%Y%m%d%H%M%S
#
# If the signing certificate can be re-signed the expired certificate will
# be saved as ~/.gem/gem-pubilc_cert.pem.expired.%Y%m%d%H%M%S where the
# expiry time (not after) is used for the timestamp.
def re_sign_key # :nodoc:
old_cert = @cert_chain.last
disk_cert_path = File.join Gem.user_home, 'gem-public_cert.pem'
disk_cert = File.read disk_cert_path rescue nil
disk_key =
File.read File.join(Gem.user_home, 'gem-private_key.pem') rescue nil
if disk_key == @key.to_pem and disk_cert == old_cert.to_pem then
expiry = old_cert.not_after.strftime '%Y%m%d%H%M%S'
old_cert_file = "gem-public_cert.pem.expired.#{expiry}"
old_cert_path = File.join Gem.user_home, old_cert_file
unless File.exist? old_cert_path then
Gem::Security.write old_cert, old_cert_path
cert = Gem::Security.re_sign old_cert, @key
Gem::Security.write cert, disk_cert_path
@cert_chain = [cert]
end
end
end
end

Просмотреть файл

@ -0,0 +1,104 @@
class Gem::Security::TrustDir
DEFAULT_PERMISSIONS = {
:trust_dir => 0700,
:trusted_cert => 0600,
}
def initialize dir, permissions = DEFAULT_PERMISSIONS
@dir = dir
@permissions = permissions
@digester = Gem::Security::DIGEST_ALGORITHM
end
attr_reader :dir
##
# Returns the path to the trusted +certificate+
def cert_path certificate
name_path certificate.subject
end
##
# Enumerates trusted certificates.
def each_certificate
return enum_for __method__ unless block_given?
glob = File.join @dir, '*.pem'
Dir[glob].each do |certificate_file|
begin
certificate = load_certificate certificate_file
yield certificate, certificate_file
rescue OpenSSL::X509::CertificateError
next # HACK warn
end
end
end
##
# Returns the issuer certificate of the given +certificate+ if it exists in
# the trust directory.
def issuer_of certificate
path = name_path certificate.issuer
return unless File.exist? path
load_certificate path
end
##
# Returns the path to the trusted certificate with the given ASN.1 +name+
def name_path name
digest = @digester.hexdigest name.to_s
File.join @dir, "cert-#{digest}.pem"
end
##
# Loads the given +certificate_file+
def load_certificate certificate_file
pem = File.read certificate_file
OpenSSL::X509::Certificate.new pem
end
##
# Add a certificate to trusted certificate list.
def trust_cert certificate
verify
destination = cert_path certificate
open destination, 'wb', @permissions[:trusted_cert] do |io|
io.write certificate.to_pem
end
end
##
# Make sure the trust directory exists. If it does exist, make sure it's
# actually a directory. If not, then create it with the appropriate
# permissions.
def verify
if File.exist? @dir then
raise Gem::Security::Exception,
"trust directory #{@dir} is not a directory" unless
File.directory? @dir
FileUtils.chmod 0700, @dir
else
FileUtils.mkdir_p @dir, :mode => @permissions[:trust_dir]
end
end
end

Просмотреть файл

@ -3,7 +3,7 @@ require 'zlib'
require 'erb'
require 'rubygems'
require 'rubygems/doc_manager'
require 'rubygems/rdoc'
##
# Gem::Server and allows users to serve gems for consumption by
@ -17,9 +17,6 @@ require 'rubygems/doc_manager'
# * "/quick/" - Individual gemspecs
# * "/gems" - Direct access to download the installable gems
# * "/rdoc?q=" - Search for installed rdoc documentation
# * legacy indexes:
# * "/Marshal.#{Gem.marshal_version}" - Full SourceIndex dump of metadata
# for installed gems
#
# == Usage
#
@ -430,53 +427,25 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
options[:launch], options[:addresses]).run
end
##
# Only the first directory in gem_dirs is used for serving gems
def initialize(gem_dirs, port, daemon, launch = nil, addresses = nil)
Gem::RDoc.load_rdoc
Socket.do_not_reverse_lookup = true
@gem_dirs = Array gem_dirs
@port = port
@daemon = daemon
@launch = launch
@gem_dirs = Array gem_dirs
@port = port
@daemon = daemon
@launch = launch
@addresses = addresses
logger = WEBrick::Log.new nil, WEBrick::BasicLog::FATAL
logger = WEBrick::Log.new nil, WEBrick::BasicLog::FATAL
@server = WEBrick::HTTPServer.new :DoNotListen => true, :Logger => logger
@spec_dirs = @gem_dirs.map do |gem_dir|
spec_dir = File.join gem_dir, 'specifications'
unless File.directory? spec_dir then
raise ArgumentError, "#{gem_dir} does not appear to be a gem repository"
end
spec_dir
end
@spec_dirs = @gem_dirs.map { |gem_dir| File.join gem_dir, 'specifications' }
@spec_dirs.reject! { |spec_dir| !File.directory? spec_dir }
Gem::Specification.dirs = @gem_dirs
end
def Marshal(req, res)
Gem::Specification.reset
add_date res
index = Gem::Deprecate.skip_during { Marshal.dump Gem.source_index }
if req.request_method == 'HEAD' then
res['content-length'] = index.length
return
end
if req.path =~ /Z$/ then
res['content-type'] = 'application/x-deflate'
index = Gem.deflate index
else
res['content-type'] = 'application/octet-stream'
end
res.body << index
@have_rdoc_4_plus = nil
end
def add_date res
@ -485,6 +454,19 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
end.max
end
def doc_root gem_name
if have_rdoc_4_plus? then
"/doc_root/#{gem_name}/"
else
"/doc_root/#{gem_name}/rdoc/index.html"
end
end
def have_rdoc_4_plus?
@have_rdoc_4_plus ||=
Gem::Requirement.new('>= 4').satisfied_by? Gem::RDoc.rdoc_version
end
def latest_specs(req, res)
Gem::Specification.reset
@ -614,14 +596,14 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
"authors" => spec.authors.sort.join(", "),
"date" => spec.date.to_s,
"dependencies" => deps,
"doc_path" => "/doc_root/#{spec.full_name}/rdoc/index.html",
"doc_path" => doc_root(spec.full_name),
"executables" => executables,
"only_one_executable" => (executables && executables.size == 1),
"full_name" => spec.full_name,
"has_deps" => !deps.empty?,
"homepage" => spec.homepage,
"name" => spec.name,
"rdoc_installed" => Gem::DocManager.new(spec).rdoc_installed?,
"rdoc_installed" => Gem::RDoc.new(spec).rdoc_installed?,
"summary" => spec.summary,
"version" => spec.version.to_s,
}
@ -630,7 +612,7 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
specs << {
"authors" => "Chad Fowler, Rich Kilmer, Jim Weirich, Eric Hodel and others",
"dependencies" => [],
"doc_path" => "/doc_root/rubygems-#{Gem::VERSION}/rdoc/index.html",
"doc_path" => doc_root("rubygems-#{Gem::VERSION}"),
"executables" => [{"executable" => 'gem', "is_last" => true}],
"only_one_executable" => true,
"full_name" => "rubygems-#{Gem::VERSION}",
@ -730,15 +712,15 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
when 1
new_path = File.basename(found_gems[0])
res.status = 302
res['Location'] = "/doc_root/#{new_path}/rdoc/index.html"
res['Location'] = doc_root new_path
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",
:name => base_name,
:url => doc_root(new_path),
:summary => ''
}
end
@ -756,9 +738,6 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
WEBrick::Daemon.start if @daemon
@server.mount_proc "/Marshal.#{Gem.marshal_version}", method(:Marshal)
@server.mount_proc "/Marshal.#{Gem.marshal_version}.Z", method(:Marshal)
@server.mount_proc "/specs.#{Gem.marshal_version}", method(:specs)
@server.mount_proc "/specs.#{Gem.marshal_version}.gz", method(:specs)
@ -779,10 +758,21 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
@server.mount_proc "/rdoc", method(:rdoc)
paths = { "/gems" => "/cache/", "/doc_root" => "/doc/" }
paths.each do |mount_point, mount_dir|
@server.mount(mount_point, WEBrick::HTTPServlet::FileHandler,
File.join(@gem_dirs.first, mount_dir), true)
file_handlers = {
'/gems' => '/cache/',
}
if have_rdoc_4_plus? then
@server.mount '/doc_root', RDoc::Servlet, '/doc_root'
else
file_handlers['/doc_root'] = '/doc/'
end
@gem_dirs.each do |gem_dir|
file_handlers.each do |mount_point, mount_dir|
@server.mount(mount_point, WEBrick::HTTPServlet::FileHandler,
File.join(gem_dir, mount_dir), true)
end
end
trap("INT") { @server.shutdown; exit! }

144
lib/rubygems/source.rb Normal file
Просмотреть файл

@ -0,0 +1,144 @@
require 'uri'
require 'fileutils'
class Gem::Source
FILES = {
:released => 'specs',
:latest => 'latest_specs',
:prerelease => 'prerelease_specs',
}
def initialize(uri)
unless uri.kind_of? URI
uri = URI.parse(uri.to_s)
end
@uri = uri
@api_uri = nil
end
attr_reader :uri
def api_uri
require 'rubygems/remote_fetcher'
@api_uri ||= Gem::RemoteFetcher.fetcher.api_endpoint uri
end
def <=>(other)
if !@uri
return 0 unless other.uri
return -1
end
return 1 if !other.uri
@uri.to_s <=> other.uri.to_s
end
include Comparable
def ==(other)
case other
when self.class
@uri == other.uri
else
false
end
end
alias_method :eql?, :==
def hash
@uri.hash
end
##
# Returns the local directory to write +uri+ to.
def cache_dir(uri)
# Correct for windows paths
escaped_path = uri.path.sub(/^\/([a-z]):\//i, '/\\1-/')
root = File.join Gem.user_home, '.gem', 'specs'
File.join root, "#{uri.host}%#{uri.port}", File.dirname(escaped_path)
end
def update_cache?
@update_cache ||= File.stat(Gem.user_home).uid == Process.uid
end
def fetch_spec(name)
fetcher = Gem::RemoteFetcher.fetcher
spec_file_name = name.spec_name
uri = @uri + "#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}"
cache_dir = cache_dir uri
local_spec = File.join cache_dir, spec_file_name
if File.exist? local_spec then
spec = Gem.read_binary local_spec
spec = Marshal.load(spec) rescue nil
return spec if spec
end
uri.path << '.rz'
spec = fetcher.fetch_path uri
spec = Gem.inflate spec
if update_cache? then
FileUtils.mkdir_p cache_dir
open local_spec, 'wb' do |io|
io.write spec
end
end
# TODO: Investigate setting Gem::Specification#loaded_from to a URI
Marshal.load spec
end
##
# Loads +type+ kind of specs fetching from +@uri+ if the on-disk cache is
# out of date.
#
# +type+ is one of the following:
#
# :released => Return the list of all released specs
# :latest => Return the list of only the highest version of each gem
# :prerelease => Return the list of all prerelease only specs
#
def load_specs(type)
file = FILES[type]
fetcher = Gem::RemoteFetcher.fetcher
file_name = "#{file}.#{Gem.marshal_version}"
spec_path = @uri + "#{file_name}.gz"
cache_dir = cache_dir spec_path
local_file = File.join(cache_dir, file_name)
retried = false
FileUtils.mkdir_p cache_dir if update_cache?
spec_dump = fetcher.cache_update_path(spec_path, local_file)
begin
Gem::NameTuple.from_list Marshal.load(spec_dump)
rescue ArgumentError
if update_cache? && !retried
FileUtils.rm local_file
retried = true
retry
else
raise Gem::Exception.new("Invalid spec cache file in #{local_file}")
end
end
end
def download(spec, dir=Dir.pwd)
fetcher = Gem::RemoteFetcher.fetcher
fetcher.download spec, @uri.to_s, dir
end
end

Просмотреть файл

@ -1,406 +0,0 @@
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
# See LICENSE.txt for permissions.
#++
require 'rubygems/specification'
require 'rubygems/deprecate'
##
# The SourceIndex object indexes all the gems available from a
# particular source (e.g. a list of gem directories, or a remote
# source). A SourceIndex maps a gem full name to a gem
# specification.
#
# NOTE:: The class used to be named Cache, but that became
# confusing when cached source fetchers where introduced. The
# constant Gem::Cache is an alias for this class to allow old
# YAMLized source index objects to load properly.
class Gem::SourceIndex
include Enumerable
attr_reader :gems # :nodoc:
##
# Directories to use to refresh this SourceIndex when calling refresh!
attr_accessor :spec_dirs
##
# Factory method to construct a source index instance for a given
# path.
#
# deprecated::
# If supplied, from_installed_gems will act just like
# +from_gems_in+. This argument is deprecated and is provided
# just for backwards compatibility, and should not generally
# be used.
#
# return::
# SourceIndex instance
def self.from_installed_gems(*deprecated)
if deprecated.empty?
from_gems_in(*installed_spec_directories)
else
warn "NOTE: from_installed_gems(arg) is deprecated. From #{caller.first}"
from_gems_in(*deprecated) # HACK warn
end
end
##
# Returns a list of directories from Gem.path that contain specifications.
def self.installed_spec_directories
# TODO: move to Gem::Utils
Gem.path.collect { |dir| File.join(dir, "specifications") }
end
##
# Creates a new SourceIndex from the ruby format gem specifications in
# +spec_dirs+.
def self.from_gems_in(*spec_dirs)
new spec_dirs
end
##
# Loads a ruby-format specification from +file_name+ and returns the
# loaded spec.
def self.load_specification(file_name)
Gem::Deprecate.skip_during do
Gem::Specification.load Gem::Path.new(file_name)
end
end
##
# Constructs a source index instance from the provided specifications, which
# is a Hash of gem full names and Gem::Specifications.
def initialize specs_or_dirs = []
@gems = {}
@spec_dirs = nil
case specs_or_dirs
when Hash then
specs_or_dirs.each do |full_name, spec|
add_spec spec
end
when Array, String then
self.spec_dirs = Array(specs_or_dirs)
refresh!
else
arg = specs_or_dirs.inspect
warn "NOTE: SourceIndex.new(#{arg}) is deprecated; From #{caller.first}."
end
end
def all_gems
gems
end
def prerelease_gems
@gems.reject { |name, gem| !gem.version.prerelease? }
end
def released_gems
@gems.reject { |name, gem| gem.version.prerelease? }
end
##
# Reconstruct the source index from the specifications in +spec_dirs+.
def load_gems_in(*spec_dirs)
@gems.clear
spec_dirs.reverse_each do |spec_dir|
spec_files = Dir[File.join(spec_dir, "*.gemspec")]
spec_files.each do |spec_file|
gemspec = Gem::Deprecate.skip_during do
Gem::Specification.load spec_file
end
add_spec gemspec if gemspec
end
end
self
end
##
# Returns an Array specifications for the latest released versions
# of each gem in this index.
def latest_specs(include_prerelease=false)
result = Hash.new { |h,k| h[k] = [] }
latest = {}
sort.each do |_, spec|
name = spec.name
curr_ver = spec.version
prev_ver = latest.key?(name) ? latest[name].version : nil
next if !include_prerelease && curr_ver.prerelease?
next unless prev_ver.nil? or curr_ver >= prev_ver or
latest[name].platform != Gem::Platform::RUBY
if prev_ver.nil? or
(curr_ver > prev_ver and spec.platform == Gem::Platform::RUBY) then
result[name].clear
latest[name] = spec
end
if spec.platform != Gem::Platform::RUBY then
result[name].delete_if do |result_spec|
result_spec.platform == spec.platform
end
end
result[name] << spec
end
result.values.flatten
end
##
# An array including only the prerelease gemspecs
def prerelease_specs
prerelease_gems.values
end
##
# An array including only the released gemspecs
def released_specs
released_gems.values
end
##
# Add a gem specification to the source index.
def add_spec(gem_spec, name = gem_spec.full_name)
# No idea why, but the Indexer wants to insert them using original_name
# instead of full_name. So we make it an optional arg.
@gems[name] = gem_spec
end
##
# Add gem specifications to the source index.
def add_specs(*gem_specs)
Gem::Deprecate.skip_during do
gem_specs.each do |spec|
add_spec spec
end
end
end
##
# Remove a gem specification named +full_name+.
def remove_spec(full_name)
@gems.delete full_name
end
##
# Iterate over the specifications in the source index.
def each(&block) # :yields: gem.full_name, gem
@gems.each(&block)
end
##
# The gem specification given a full gem spec name.
def specification(full_name)
@gems[full_name]
end
##
# The signature for the source index. Changes in the signature indicate a
# change in the index.
def index_signature
require 'digest'
Digest::SHA256.new.hexdigest(@gems.keys.sort.join(',')).to_s
end
##
# The signature for the given gem specification.
def gem_signature(gem_full_name)
require 'digest'
Digest::SHA256.new.hexdigest(@gems[gem_full_name].to_yaml).to_s
end
def size
@gems.size
end
alias length size
##
# Find a gem by an exact match on the short name.
def find_name(gem_name, requirement = Gem::Requirement.default)
dep = Gem::Dependency.new gem_name, requirement
Gem::Deprecate.skip_during do
search dep
end
end
##
# Search for a gem by Gem::Dependency +gem_pattern+. If +only_platform+
# is true, only gems matching Gem::Platform.local will be returned. An
# Array of matching Gem::Specification objects is returned.
#
# For backwards compatibility, a String or Regexp pattern may be passed as
# +gem_pattern+, and a Gem::Requirement for +platform_only+. This
# behavior is deprecated and will be removed.
def search(gem_pattern, platform_or_requirement = false)
requirement = nil
only_platform = false # FIX: WTF is this?!?
# TODO - Remove support and warning for legacy arguments after 2008/11
unless Gem::Dependency === gem_pattern
warn "#{Gem.location_of_caller.join ':'}:Warning: Gem::SourceIndex#search support for #{gem_pattern.class} patterns is deprecated, use #find_name"
end
case gem_pattern
when Regexp then
requirement = platform_or_requirement || Gem::Requirement.default
when Gem::Dependency then
only_platform = platform_or_requirement
requirement = gem_pattern.requirement
gem_pattern = if Regexp === gem_pattern.name then
gem_pattern.name
elsif gem_pattern.name.empty? then
//
else
/^#{Regexp.escape gem_pattern.name}$/
end
else
requirement = platform_or_requirement || Gem::Requirement.default
gem_pattern = /#{gem_pattern}/i
end
unless Gem::Requirement === requirement then
requirement = Gem::Requirement.create requirement
end
specs = @gems.values.select do |spec|
spec.name =~ gem_pattern and
requirement.satisfied_by? spec.version
end
if only_platform then
specs = specs.select do |spec|
Gem::Platform.match spec.platform
end
end
specs.sort_by { |s| s.sort_obj }
end
##
# Replaces the gems in the source index from specifications in the
# directories this source index was created from. Raises an exception if
# this source index wasn't created from a directory (via from_gems_in or
# from_installed_gems, or having spec_dirs set).
def refresh!
raise 'source index not created from disk' if @spec_dirs.nil?
load_gems_in(*@spec_dirs)
end
##
# Returns an Array of Gem::Specifications that are not up to date.
def outdated
outdateds = []
latest_specs.each do |local|
dependency = Gem::Dependency.new local.name, ">= #{local.version}"
fetcher = Gem::SpecFetcher.fetcher
remotes = fetcher.find_matching dependency
remotes = remotes.map { |(_, version, _), _| version }
latest = remotes.sort.last
outdateds << local.name if latest and local.version < latest
end
outdateds
end
def ==(other) # :nodoc:
self.class === other and @gems == other.gems
end
def dump
Marshal.dump(self)
end
end
# :stopdoc:
module Gem
##
# Cache is an alias for SourceIndex to allow older YAMLized source index
# objects to load properly.
Cache = SourceIndex
end
class Gem::SourceIndex
extend Gem::Deprecate
deprecate :all_gems, :none, 2011, 10
deprecate :==, :none, 2011, 11 # noisy
deprecate :add_specs, :none, 2011, 11 # noisy
deprecate :each, :none, 2011, 11
deprecate :gems, :none, 2011, 11
deprecate :load_gems_in, :none, 2011, 11
deprecate :refresh!, :none, 2011, 11
deprecate :spec_dirs=, "Specification.dirs=", 2011, 11 # noisy
deprecate :add_spec, "Specification.add_spec", 2011, 11
deprecate :find_name, "Specification.find_by_name", 2011, 11
deprecate :gem_signature, :none, 2011, 11
deprecate :index_signature, :none, 2011, 11
deprecate :initialize, :none, 2011, 11
deprecate :latest_specs, "Specification.latest_specs", 2011, 11
deprecate :length, "Specification.all.length", 2011, 11
deprecate :outdated, :none, 2011, 11
deprecate :prerelease_gems, :none, 2011, 11
deprecate :prerelease_specs, :none, 2011, 11
deprecate :released_gems, :none, 2011, 11
deprecate :released_specs, :none, 2011, 11
deprecate :remove_spec, "Specification.remove_spec", 2011, 11
deprecate :search, :none, 2011, 11
deprecate :size, "Specification.all.size", 2011, 11
deprecate :spec_dirs, "Specification.dirs", 2011, 11
deprecate :specification, "Specification.find", 2011, 11
class << self
extend Gem::Deprecate
deprecate :from_gems_in, :none, 2011, 10
deprecate :from_installed_gems, :none, 2011, 10
deprecate :installed_spec_directories, "Specification.dirs", 2011, 11
deprecate :load_specification, :none, 2011, 10
end
end
# :startdoc:

Просмотреть файл

@ -0,0 +1,87 @@
require 'rubygems/source'
class Gem::SourceList
def initialize
@sources = []
end
attr_reader :sources
def self.from(ary)
list = new
if ary
ary.each do |x|
list << x
end
end
return list
end
def initialize_copy(other)
@sources = @sources.dup
end
def <<(obj)
src = case obj
when URI
Gem::Source.new(obj)
when Gem::Source
obj
else
Gem::Source.new(URI.parse(obj))
end
@sources << src
src
end
def replace(other)
@sources.clear
other.each do |x|
self << x
end
self
end
def each
@sources.each { |s| yield s.uri.to_s }
end
def each_source(&b)
@sources.each(&b)
end
def ==(other)
to_a == other
end
def to_a
@sources.map { |x| x.uri.to_s }
end
alias_method :to_ary, :to_a
def first
@sources.first
end
def include?(other)
if other.kind_of? Gem::Source
@sources.include? other
else
@sources.find { |x| x.uri.to_s == other.to_s }
end
end
def delete(uri)
if uri.kind_of? Gem::Source
@sources.delete uri
else
@sources.delete_if { |x| x.uri.to_s == uri.to_s }
end
end
end

Просмотреть файл

@ -0,0 +1,92 @@
require 'rubygems/source'
class Gem::Source::Local < Gem::Source
def initialize
@uri = nil
end
def load_specs(type)
names = []
@specs = {}
Dir["*.gem"].each do |file|
begin
pkg = Gem::Package.new(file)
rescue SystemCallError, Gem::Package::FormatError
# ignore
else
tup = pkg.spec.name_tuple
@specs[tup] = [File.expand_path(file), pkg]
case type
when :released
unless pkg.spec.version.prerelease?
names << pkg.spec.name_tuple
end
when :prerelease
if pkg.spec.version.prerelease?
names << pkg.spec.name_tuple
end
when :latest
tup = pkg.spec.name_tuple
cur = names.find { |x| x.name == tup.name }
if !cur
names << tup
elsif cur.version < tup.version
names.delete cur
names << tup
end
else
names << pkg.spec.name_tuple
end
end
end
names
end
def find_gem(gem_name, version=Gem::Requirement.default,
prerelease=false)
load_specs :complete
found = []
@specs.each do |n, data|
if n.name == gem_name
s = data[1].spec
if version.satisfied_by?(s.version)
if prerelease
found << s
elsif !s.version.prerelease?
found << s
end
end
end
end
found.sort_by { |s| s.version }.last
end
def fetch_spec(name)
load_specs :complete
if data = @specs[name]
data.last.spec
else
raise Gem::Exception, "Unable to find spec for '#{name}'"
end
end
def download(spec, cache_dir=nil)
load_specs :complete
@specs.each do |name, data|
return data[0] if data[1].spec == spec
end
raise Gem::Exception, "Unable to find file for '#{spec.full_name}'"
end
end

Просмотреть файл

@ -0,0 +1,28 @@
class Gem::Source::SpecificFile < Gem::Source
def initialize(file)
@uri = nil
@path = ::File.expand_path(file)
@package = Gem::Package.new @path
@spec = @package.spec
@name = @spec.name_tuple
end
attr_reader :spec
def load_specs(*a)
[@name]
end
def fetch_spec(name)
return @spec if name == @name
raise Gem::Exception, "Unable to find '#{name}'"
@spec
end
def download(spec, dir=nil)
return @path if spec == @spec
raise Gem::Exception, "Unable to download '#{spec.full_name}'"
end
end

Просмотреть файл

@ -2,6 +2,7 @@ require 'rubygems/remote_fetcher'
require 'rubygems/user_interaction'
require 'rubygems/errors'
require 'rubygems/text'
require 'rubygems/name_tuple'
##
# SpecFetcher handles metadata updates from remote gem repositories.
@ -11,17 +12,6 @@ class Gem::SpecFetcher
include Gem::UserInteraction
include Gem::Text
FILES = {
:all => 'specs',
:latest => 'latest_specs',
:prerelease => 'prerelease_specs',
}
##
# The SpecFetcher cache dir.
attr_reader :dir # :nodoc:
##
# Cache of latest specs
@ -48,8 +38,6 @@ class Gem::SpecFetcher
end
def initialize
require 'fileutils'
@dir = File.join Gem.user_home, '.gem', 'specs'
@update_cache = File.stat(Gem.user_home).uid == Process.uid
@ -60,99 +48,40 @@ class Gem::SpecFetcher
@caches = {
:latest => @latest_specs,
:prerelease => @prerelease_specs,
:all => @specs
:released => @specs,
}
@fetcher = Gem::RemoteFetcher.fetcher
end
##
# Returns the local directory to write +uri+ to.
#
# Find and fetch gem name tuples that match +dependency+.
#
# If +matching_platform+ is false, gems for all platforms are returned.
def cache_dir(uri)
# Correct for windows paths
escaped_path = uri.path.sub(/^\/([a-z]):\//i, '/\\1-/')
File.join @dir, "#{uri.host}%#{uri.port}", File.dirname(escaped_path)
end
##
# Fetch specs matching +dependency+. If +all+ is true, all matching
# (released) versions are returned. If +matching_platform+ is
# false, all platforms are returned. If +prerelease+ is true,
# prerelease versions are included.
def fetch_with_errors(dependency,
all = false,
matching_platform = true,
prerelease = false)
specs_and_sources, errors = find_matching_with_errors(dependency,
all,
matching_platform,
prerelease)
ss = specs_and_sources.map do |spec_tuple, source_uri|
[fetch_spec(spec_tuple, URI.parse(source_uri)), source_uri]
end
return [ss, errors]
end
def fetch(*args)
fetch_with_errors(*args).first
end
def fetch_spec(spec, source_uri)
source_uri = URI.parse source_uri if String === source_uri
spec = spec - [nil, 'ruby', '']
spec_file_name = "#{spec.join '-'}.gemspec"
uri = source_uri + "#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}"
cache_dir = cache_dir uri
local_spec = File.join cache_dir, spec_file_name
if File.exist? local_spec then
spec = Gem.read_binary local_spec
else
uri.path << '.rz'
spec = @fetcher.fetch_path uri
spec = Gem.inflate spec
if @update_cache then
FileUtils.mkdir_p cache_dir
open local_spec, 'wb' do |io|
io.write spec
end
end
end
# TODO: Investigate setting Gem::Specification#loaded_from to a URI
Marshal.load spec
end
##
# Find spec names that match +dependency+. If +all+ is true, all
# matching released versions are returned. If +matching_platform+
# is false, gems for all platforms are returned.
def find_matching_with_errors(dependency,
all = false,
matching_platform = true,
prerelease = false)
def search_for_dependency(dependency, matching_platform=true)
found = {}
rejected_specs = {}
list(all, prerelease).each do |source_uri, specs|
found[source_uri] = specs.select do |spec_name, version, spec_platform|
if dependency.match?(spec_name, version)
if matching_platform and !Gem::Platform.match(spec_platform)
pm = (rejected_specs[dependency] ||= Gem::PlatformMismatch.new(spec_name, version))
pm.add_platform spec_platform
if dependency.prerelease?
type = :complete
elsif dependency.latest_version?
type = :latest
else
type = :released
end
list, errors = available_specs(type)
list.each do |source, specs|
found[source] = specs.select do |tup|
if dependency.match?(tup)
if matching_platform and !Gem::Platform.match(tup.platform)
pm = (
rejected_specs[dependency] ||= \
Gem::PlatformMismatch.new(tup.name, tup.version))
pm.add_platform tup.platform
false
else
true
@ -161,43 +90,82 @@ class Gem::SpecFetcher
end
end
errors = rejected_specs.values
errors += rejected_specs.values
specs_and_sources = []
tuples = []
found.each do |source_uri, specs|
uri_str = source_uri.to_s
specs_and_sources.concat(specs.map { |spec| [spec, uri_str] })
found.each do |source, specs|
specs.each do |s|
tuples << [s, source]
end
end
[specs_and_sources, errors]
tuples = tuples.sort_by { |x| x[0] }
return [tuples, errors]
end
def find_matching(*args)
find_matching_with_errors(*args).first
##
# Return all gem name tuples who's names match +obj+
def detect(type=:complete)
tuples = []
list, _ = available_specs(type)
list.each do |source, specs|
specs.each do |tup|
if yield(tup)
tuples << [tup, source]
end
end
end
tuples
end
##
# Find and fetch specs that match +dependency+.
#
# If +matching_platform+ is false, gems for all platforms are returned.
def spec_for_dependency(dependency, matching_platform=true)
tuples, errors = search_for_dependency(dependency, matching_platform)
specs = []
tuples.each do |tup, source|
begin
spec = source.fetch_spec(tup)
rescue Gem::RemoteFetcher::FetchError => e
errors << Gem::SourceFetchProblem.new(source, e)
else
specs << [spec, source]
end
end
return [specs, errors]
end
##
# Suggests a gem based on the supplied +gem_name+. Returns a string
# of the gem name if an approximate match can be found or nil
# otherwise. NOTE: for performance reasons only gems which exactly
# match the first character of +gem_name+ are considered.
# Suggests gems based on the supplied +gem_name+. Returns an array of
# alternative gem names.
def suggest_gems_from_name gem_name
gem_name = gem_name.downcase
gem_name = gem_name.downcase.tr('_-', '')
max = gem_name.size / 2
specs = list.values.flatten 1
names = available_specs(:complete).first.values.flatten(1)
matches = specs.map { |name, version, platform|
next unless Gem::Platform.match platform
matches = names.map { |n|
next unless n.match_platform?
distance = levenshtein_distance gem_name, name.downcase
distance = levenshtein_distance gem_name, n.name.downcase.tr('_-', '')
next if distance >= max
return [name] if distance == 0
return [n.name] if distance == 0
[name, distance]
[n.name, distance]
}.compact
matches = matches.uniq.sort_by { |name, dist| dist }
@ -206,92 +174,46 @@ class Gem::SpecFetcher
end
##
# Returns a list of gems available for each source in Gem::sources. If
# +all+ is true, all released versions are returned instead of only latest
# versions. If +prerelease+ is true, include prerelease versions.
# Returns a list of gems available for each source in Gem::sources.
#
# +type+ can be one of 3 values:
# :released => Return the list of all released specs
# :complete => Return the list of all specs
# :latest => Return the list of only the highest version of each gem
# :prerelease => Return the list of all prerelease only specs
#
def list(all = false, prerelease = false)
# TODO: make type the only argument
type = if all
:all
elsif prerelease
:prerelease
else
:latest
end
def available_specs(type)
errors = []
list = {}
list = {}
file = FILES[type]
cache = @caches[type]
Gem.sources.each do |source_uri|
source_uri = URI.parse source_uri
unless cache.include? source_uri
cache[source_uri] = load_specs source_uri, file
end
list[source_uri] = cache[source_uri]
end
if type == :all
list.values.map do |gems|
gems.reject! { |g| !g[1] || g[1].prerelease? }
end
end
list
end
##
# Loads specs in +file+, fetching from +source_uri+ if the on-disk cache is
# out of date.
def load_specs(source_uri, file)
file_name = "#{file}.#{Gem.marshal_version}"
spec_path = source_uri + "#{file_name}.gz"
cache_dir = cache_dir spec_path
local_file = File.join(cache_dir, file_name)
loaded = false
if File.exist? local_file then
Gem.sources.each_source do |source|
begin
spec_dump =
@fetcher.fetch_path(spec_path, File.mtime(local_file))
names = case type
when :latest
tuples_for source, :latest
when :released
tuples_for source, :released
when :complete
tuples_for(source, :prerelease) + tuples_for(source, :released)
when :prerelease
tuples_for(source, :prerelease)
else
raise Gem::Exception, "Unknown type - :#{type}"
end
rescue Gem::RemoteFetcher::FetchError => e
alert_warning "Error fetching data: #{e.message}"
end
loaded = true if spec_dump
spec_dump ||= Gem.read_binary local_file
else
spec_dump = @fetcher.fetch_path spec_path
loaded = true
end
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
begin
FileUtils.mkdir_p cache_dir
open local_file, 'wb' do |io|
io << spec_dump
end
rescue
errors << Gem::SourceFetchProblem.new(source, e)
else
list[source] = names
end
end
specs
[list, errors]
end
def tuples_for(source, type)
cache = @caches[type]
cache[source.uri] ||= source.load_specs(type)
end
end

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,90 @@
This CA certificate is for verifying HTTPS connection to;
- https://rubygems.org/ (obtained by RubyGems team)
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=SE, O=AddTrust AB, OU=AddTrust External TTP Network, CN=AddTrust External CA Root
Validity
Not Before: May 30 10:48:38 2000 GMT
Not After : May 30 10:48:38 2020 GMT
Subject: C=SE, O=AddTrust AB, OU=AddTrust External TTP Network, CN=AddTrust External CA Root
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:b7:f7:1a:33:e6:f2:00:04:2d:39:e0:4e:5b:ed:
1f:bc:6c:0f:cd:b5:fa:23:b6:ce:de:9b:11:33:97:
a4:29:4c:7d:93:9f:bd:4a:bc:93:ed:03:1a:e3:8f:
cf:e5:6d:50:5a:d6:97:29:94:5a:80:b0:49:7a:db:
2e:95:fd:b8:ca:bf:37:38:2d:1e:3e:91:41:ad:70:
56:c7:f0:4f:3f:e8:32:9e:74:ca:c8:90:54:e9:c6:
5f:0f:78:9d:9a:40:3c:0e:ac:61:aa:5e:14:8f:9e:
87:a1:6a:50:dc:d7:9a:4e:af:05:b3:a6:71:94:9c:
71:b3:50:60:0a:c7:13:9d:38:07:86:02:a8:e9:a8:
69:26:18:90:ab:4c:b0:4f:23:ab:3a:4f:84:d8:df:
ce:9f:e1:69:6f:bb:d7:42:d7:6b:44:e4:c7:ad:ee:
6d:41:5f:72:5a:71:08:37:b3:79:65:a4:59:a0:94:
37:f7:00:2f:0d:c2:92:72:da:d0:38:72:db:14:a8:
45:c4:5d:2a:7d:b7:b4:d6:c4:ee:ac:cd:13:44:b7:
c9:2b:dd:43:00:25:fa:61:b9:69:6a:58:23:11:b7:
a7:33:8f:56:75:59:f5:cd:29:d7:46:b7:0a:2b:65:
b6:d3:42:6f:15:b2:b8:7b:fb:ef:e9:5d:53:d5:34:
5a:27
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
AD:BD:98:7A:34:B4:26:F7:FA:C4:26:54:EF:03:BD:E0:24:CB:54:1A
X509v3 Key Usage:
Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Authority Key Identifier:
keyid:AD:BD:98:7A:34:B4:26:F7:FA:C4:26:54:EF:03:BD:E0:24:CB:54:1A
DirName:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
serial:01
Signature Algorithm: sha1WithRSAEncryption
b0:9b:e0:85:25:c2:d6:23:e2:0f:96:06:92:9d:41:98:9c:d9:
84:79:81:d9:1e:5b:14:07:23:36:65:8f:b0:d8:77:bb:ac:41:
6c:47:60:83:51:b0:f9:32:3d:e7:fc:f6:26:13:c7:80:16:a5:
bf:5a:fc:87:cf:78:79:89:21:9a:e2:4c:07:0a:86:35:bc:f2:
de:51:c4:d2:96:b7:dc:7e:4e:ee:70:fd:1c:39:eb:0c:02:51:
14:2d:8e:bd:16:e0:c1:df:46:75:e7:24:ad:ec:f4:42:b4:85:
93:70:10:67:ba:9d:06:35:4a:18:d3:2b:7a:cc:51:42:a1:7a:
63:d1:e6:bb:a1:c5:2b:c2:36:be:13:0d:e6:bd:63:7e:79:7b:
a7:09:0d:40:ab:6a:dd:8f:8a:c3:f6:f6:8c:1a:42:05:51:d4:
45:f5:9f:a7:62:21:68:15:20:43:3c:99:e7:7c:bd:24:d8:a9:
91:17:73:88:3f:56:1b:31:38:18:b4:71:0f:9a:cd:c8:0e:9e:
8e:2e:1b:e1:8c:98:83:cb:1f:31:f1:44:4c:c6:04:73:49:76:
60:0f:c7:f8:bd:17:80:6b:2e:e9:cc:4c:0e:5a:9a:79:0f:20:
0a:2e:d5:9e:63:26:1e:55:92:94:d8:82:17:5a:7b:d0:bc:c7:
8f:4e:86:04
-----BEGIN CERTIFICATE-----
MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
-----END CERTIFICATE-----

Просмотреть файл

@ -0,0 +1,90 @@
This CA certificate is for verifying HTTPS connection to;
- https://d2chzxaqi4y7f8.cloudfront.net/ (prepared by AWS)
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 927650371 (0x374ad243)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=US, O=Entrust.net, OU=www.entrust.net/CPS incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Secure Server Certification Authority
Validity
Not Before: May 25 16:09:40 1999 GMT
Not After : May 25 16:39:40 2019 GMT
Subject: C=US, O=Entrust.net, OU=www.entrust.net/CPS incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Secure Server Certification Authority
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (1024 bit)
Modulus:
00:cd:28:83:34:54:1b:89:f3:0f:af:37:91:31:ff:
af:31:60:c9:a8:e8:b2:10:68:ed:9f:e7:93:36:f1:
0a:64:bb:47:f5:04:17:3f:23:47:4d:c5:27:19:81:
26:0c:54:72:0d:88:2d:d9:1f:9a:12:9f:bc:b3:71:
d3:80:19:3f:47:66:7b:8c:35:28:d2:b9:0a:df:24:
da:9c:d6:50:79:81:7a:5a:d3:37:f7:c2:4a:d8:29:
92:26:64:d1:e4:98:6c:3a:00:8a:f5:34:9b:65:f8:
ed:e3:10:ff:fd:b8:49:58:dc:a0:de:82:39:6b:81:
b1:16:19:61:b9:54:b6:e6:43
Exponent: 3 (0x3)
X509v3 extensions:
Netscape Cert Type:
SSL CA, S/MIME CA, Object Signing CA
X509v3 CRL Distribution Points:
Full Name:
DirName: C = US, O = Entrust.net, OU = www.entrust.net/CPS incorp. by ref. (limits liab.), OU = (c) 1999 Entrust.net Limited, CN = Entrust.net Secure Server Certification Authority, CN = CRL1
Full Name:
URI:http://www.entrust.net/CRL/net1.crl
X509v3 Private Key Usage Period:
Not Before: May 25 16:09:40 1999 GMT, Not After: May 25 16:09:40 2019 GMT
X509v3 Key Usage:
Certificate Sign, CRL Sign
X509v3 Authority Key Identifier:
keyid:F0:17:62:13:55:3D:B3:FF:0A:00:6B:FB:50:84:97:F3:ED:62:D0:1A
X509v3 Subject Key Identifier:
F0:17:62:13:55:3D:B3:FF:0A:00:6B:FB:50:84:97:F3:ED:62:D0:1A
X509v3 Basic Constraints:
CA:TRUE
1.2.840.113533.7.65.0:
0
..V4.0....
Signature Algorithm: sha1WithRSAEncryption
90:dc:30:02:fa:64:74:c2:a7:0a:a5:7c:21:8d:34:17:a8:fb:
47:0e:ff:25:7c:8d:13:0a:fb:e4:98:b5:ef:8c:f8:c5:10:0d:
f7:92:be:f1:c3:d5:d5:95:6a:04:bb:2c:ce:26:36:65:c8:31:
c6:e7:ee:3f:e3:57:75:84:7a:11:ef:46:4f:18:f4:d3:98:bb:
a8:87:32:ba:72:f6:3c:e2:3d:9f:d7:1d:d9:c3:60:43:8c:58:
0e:22:96:2f:62:a3:2c:1f:ba:ad:05:ef:ab:32:78:87:a0:54:
73:19:b5:5c:05:f9:52:3e:6d:2d:45:0b:f7:0a:93:ea:ed:06:
f9:b2
-----BEGIN CERTIFICATE-----
MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC
VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u
ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc
KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u
ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1
MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE
ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j
b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF
bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg
U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA
A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/
I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3
wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC
AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb
oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5
BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p
dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk
MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp
b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu
dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0
MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi
E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa
MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI
hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN
95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd
2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=
-----END CERTIFICATE-----

Просмотреть файл

@ -0,0 +1,57 @@
This CA certificate is for verifying HTTPS connection to;
- https://s3.amazon.com/ (prepared by AWS)
Certificate:
Data:
Version: 1 (0x0)
Serial Number:
7d:d9:fe:07:cf:a8:1e:b7:10:79:67:fb:a7:89:34:c6
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority - G2, OU=(c) 1998 VeriSign, Inc. - For authorized use only, OU=VeriSign Trust Network
Validity
Not Before: May 18 00:00:00 1998 GMT
Not After : Aug 1 23:59:59 2028 GMT
Subject: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority - G2, OU=(c) 1998 VeriSign, Inc. - For authorized use only, OU=VeriSign Trust Network
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (1024 bit)
Modulus:
00:cc:5e:d1:11:5d:5c:69:d0:ab:d3:b9:6a:4c:99:
1f:59:98:30:8e:16:85:20:46:6d:47:3f:d4:85:20:
84:e1:6d:b3:f8:a4:ed:0c:f1:17:0f:3b:f9:a7:f9:
25:d7:c1:cf:84:63:f2:7c:63:cf:a2:47:f2:c6:5b:
33:8e:64:40:04:68:c1:80:b9:64:1c:45:77:c7:d8:
6e:f5:95:29:3c:50:e8:34:d7:78:1f:a8:ba:6d:43:
91:95:8f:45:57:5e:7e:c5:fb:ca:a4:04:eb:ea:97:
37:54:30:6f:bb:01:47:32:33:cd:dc:57:9b:64:69:
61:f8:9b:1d:1c:89:4f:5c:67
Exponent: 65537 (0x10001)
Signature Algorithm: sha1WithRSAEncryption
51:4d:cd:be:5c:cb:98:19:9c:15:b2:01:39:78:2e:4d:0f:67:
70:70:99:c6:10:5a:94:a4:53:4d:54:6d:2b:af:0d:5d:40:8b:
64:d3:d7:ee:de:56:61:92:5f:a6:c4:1d:10:61:36:d3:2c:27:
3c:e8:29:09:b9:11:64:74:cc:b5:73:9f:1c:48:a9:bc:61:01:
ee:e2:17:a6:0c:e3:40:08:3b:0e:e7:eb:44:73:2a:9a:f1:69:
92:ef:71:14:c3:39:ac:71:a7:91:09:6f:e4:71:06:b3:ba:59:
57:26:79:00:f6:f8:0d:a2:33:30:28:d4:aa:58:a0:9d:9d:69:
91:fd
-----BEGIN CERTIFICATE-----
MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg
UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4
pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0
13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID
AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk
U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i
F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY
oJ2daZH9
-----END CERTIFICATE-----

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше