summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/rubygems.rb121
-rw-r--r--lib/rubygems/commands/contents_command.rb2
-rw-r--r--lib/rubygems/commands/environment_command.rb40
-rw-r--r--lib/rubygems/commands/help_command.rb4
-rw-r--r--lib/rubygems/commands/install_command.rb15
-rw-r--r--lib/rubygems/commands/lock_command.rb21
-rw-r--r--lib/rubygems/commands/outdated_command.rb2
-rw-r--r--lib/rubygems/commands/pristine_command.rb2
-rw-r--r--lib/rubygems/commands/query_command.rb23
-rw-r--r--lib/rubygems/commands/rdoc_command.rb6
-rw-r--r--lib/rubygems/commands/specification_command.rb4
-rw-r--r--lib/rubygems/commands/unpack_command.rb2
-rw-r--r--lib/rubygems/commands/update_command.rb37
-rw-r--r--lib/rubygems/commands/which_command.rb7
-rw-r--r--lib/rubygems/config_file.rb6
-rw-r--r--lib/rubygems/defaults.rb53
-rw-r--r--lib/rubygems/dependency_installer.rb34
-rw-r--r--lib/rubygems/doc_manager.rb277
-rw-r--r--lib/rubygems/gem_path_searcher.rb54
-rw-r--r--lib/rubygems/installer.rb94
-rw-r--r--lib/rubygems/local_remote_options.rb7
-rw-r--r--lib/rubygems/package/tar_reader.rb14
-rw-r--r--lib/rubygems/platform.rb19
-rw-r--r--lib/rubygems/remote_fetcher.rb25
-rw-r--r--lib/rubygems/rubygems_version.rb2
-rw-r--r--lib/rubygems/source_index.rb29
-rw-r--r--lib/rubygems/source_info_cache.rb9
-rw-r--r--lib/rubygems/spec_fetcher.rb8
-rw-r--r--lib/rubygems/specification.rb795
-rw-r--r--lib/rubygems/test_utilities.rb20
-rw-r--r--lib/rubygems/uninstaller.rb86
31 files changed, 1207 insertions, 611 deletions
diff --git a/lib/rubygems.rb b/lib/rubygems.rb
index fde91bfd4b..40c6defb66 100644
--- a/lib/rubygems.rb
+++ b/lib/rubygems.rb
@@ -104,6 +104,11 @@ module Gem
@ruby = nil
@sources = []
+ @post_install_hooks = []
+ @post_uninstall_hooks = []
+ @pre_uninstall_hooks = []
+ @pre_install_hooks = []
+
##
# Activates an installed gem matching +gem+. The gem must satisfy
# +version_requirements+.
@@ -244,7 +249,10 @@ module Gem
def self.clear_paths
@gem_home = nil
@gem_path = nil
+ @user_home = nil
+
@@source_index = nil
+
MUTEX.synchronize do
@searcher = nil
end
@@ -261,9 +269,7 @@ module Gem
# The standard configuration object for gems.
def self.configuration
- return @configuration if @configuration
- require 'rubygems/config_file'
- @configuration = Gem::ConfigFile.new []
+ @configuration ||= Gem::ConfigFile.new []
end
##
@@ -337,6 +343,22 @@ module Gem
end
##
+ # Returns a list of paths matching +file+ that can be used by a gem to pick
+ # up features from other gems. For example:
+ #
+ # Gem.find_files('rdoc/discover').each do |path| load path end
+ #
+ # find_files does not search $LOAD_PATH for files, only gems.
+
+ def self.find_files(path)
+ specs = searcher.find_all path
+
+ specs.map do |spec|
+ searcher.matching_files spec, path
+ end.flatten
+ end
+
+ ##
# Finds the user's home directory.
#--
# Some comments from the ruby-talk list regarding finding the home
@@ -353,7 +375,7 @@ module Gem
end
if ENV['HOMEDRIVE'] && ENV['HOMEPATH'] then
- return "#{ENV['HOMEDRIVE']}:#{ENV['HOMEPATH']}"
+ return "#{ENV['HOMEDRIVE']}#{ENV['HOMEPATH']}"
end
begin
@@ -466,13 +488,11 @@ module Gem
##
# manage_gems is useless and deprecated. Don't call it anymore.
- #--
- # TODO warn w/ RubyGems 1.2.x release.
- def self.manage_gems
- #file, lineno = location_of_caller
+ def self.manage_gems # :nodoc:
+ file, lineno = location_of_caller
- #warn "#{file}:#{lineno}:Warning: Gem#manage_gems is deprecated and will be removed on or after September 2008."
+ warn "#{file}:#{lineno}:Warning: Gem::manage_gems is deprecated and will be removed on or after March 2009."
end
##
@@ -489,11 +509,7 @@ module Gem
@gem_path ||= nil
unless @gem_path then
- paths = if ENV['GEM_PATH'] then
- [ENV['GEM_PATH']]
- else
- [default_path]
- end
+ paths = [ENV['GEM_PATH'] || Gem.configuration.path || default_path]
if defined?(APPLE_GEM_HOME) and not ENV['GEM_PATH'] then
paths << APPLE_GEM_HOME
@@ -524,6 +540,40 @@ module Gem
end
##
+ # Adds a post-install hook that will be passed an Gem::Installer instance
+ # when Gem::Installer#install is called
+
+ def self.post_install(&hook)
+ @post_install_hooks << hook
+ end
+
+ ##
+ # Adds a post-uninstall hook that will be passed a Gem::Uninstaller instance
+ # and the spec that was uninstalled when Gem::Uninstaller#uninstall is
+ # called
+
+ def self.post_uninstall(&hook)
+ @post_uninstall_hooks << hook
+ end
+
+ ##
+ # Adds a pre-install hook that will be passed an Gem::Installer instance
+ # when Gem::Installer#install is called
+
+ def self.pre_install(&hook)
+ @pre_install_hooks << hook
+ end
+
+ ##
+ # Adds a pre-uninstall hook that will be passed an Gem::Uninstaller instance
+ # and the spec that will be uninstalled when Gem::Uninstaller#uninstall is
+ # called
+
+ def self.pre_uninstall(&hook)
+ @pre_uninstall_hooks << hook
+ end
+
+ ##
# The directory prefix this RubyGems was installed at.
def self.prefix
@@ -600,6 +650,9 @@ module Gem
@ruby = File.join(ConfigMap[:bindir],
ConfigMap[:ruby_install_name])
@ruby << ConfigMap[:EXEEXT]
+
+ # escape string in case path to ruby executable contain spaces.
+ @ruby.sub!(/.*\s.*/m, '"\&"')
end
@ruby
@@ -655,7 +708,13 @@ module Gem
end
@gem_path.uniq!
- @gem_path.each do |gp| ensure_gem_subdirectories(gp) end
+ @gem_path.each do |path|
+ if 0 == File.expand_path(path).index(Gem.user_home) and
+ Etc.getpwuid.uid != File::Stat.new(Gem.user_home).uid then
+ next # only create by matching user
+ end
+ ensure_gem_subdirectories path
+ end
end
private_class_method :set_paths
@@ -686,6 +745,14 @@ module Gem
end
##
+ # Need to be able to set the sources without calling
+ # Gem.sources.replace since that would cause an infinite loop.
+
+ def self.sources=(new_sources)
+ @sources = new_sources
+ end
+
+ ##
# Glob pattern for require-able path suffixes.
def self.suffix_pattern
@@ -731,6 +798,27 @@ module Gem
attr_reader :loaded_specs
+ ##
+ # The list of hooks to be run before Gem::Install#install does any work
+
+ attr_reader :post_install_hooks
+
+ ##
+ # The list of hooks to be run before Gem::Uninstall#uninstall does any
+ # work
+
+ attr_reader :post_uninstall_hooks
+
+ ##
+ # The list of hooks to be run after Gem::Install#install is finished
+
+ attr_reader :pre_install_hooks
+
+ ##
+ # The list of hooks to be run after Gem::Uninstall#uninstall is finished
+
+ attr_reader :pre_uninstall_hooks
+
# :stopdoc:
alias cache source_index # an alias for the old name
@@ -781,7 +869,10 @@ if defined?(RUBY_ENGINE) then
end
end
+require 'rubygems/config_file'
+
if RUBY_VERSION < '1.9' then
require 'rubygems/custom_require'
end
+Gem.clear_paths
diff --git a/lib/rubygems/commands/contents_command.rb b/lib/rubygems/commands/contents_command.rb
index 5060403fd8..bc75fb5c03 100644
--- a/lib/rubygems/commands/contents_command.rb
+++ b/lib/rubygems/commands/contents_command.rb
@@ -51,7 +51,7 @@ class Gem::Commands::ContentsCommand < Gem::Command
si = Gem::SourceIndex.from_gems_in(*s)
- gem_spec = si.search(/\A#{gem}\z/, version).last
+ gem_spec = si.find_name(gem, version).last
unless gem_spec then
say "Unable to find gem '#{gem}' in #{path_kind}"
diff --git a/lib/rubygems/commands/environment_command.rb b/lib/rubygems/commands/environment_command.rb
index a67c00bfd6..e672da54f0 100644
--- a/lib/rubygems/commands/environment_command.rb
+++ b/lib/rubygems/commands/environment_command.rb
@@ -18,6 +18,46 @@ class Gem::Commands::EnvironmentCommand < Gem::Command
return args.gsub(/^\s+/, '')
end
+ def description # :nodoc:
+ <<-EOF
+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:
+
+ :sources: A YAML array of remote gem repositories to install gems from
+ :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
+ :bulk_threshold: Switch to a bulk update when this many sources are out of
+ date (legacy setting)
+ :gempath: The paths in which to look for gems
+ gem_command: A string containing arguments for the specified gem command
+
+Example:
+
+ :verbose: false
+ install: --no-wrappers
+ update: --no-wrappers
+
+RubyGems' default local repository can be overriden 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
+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 are packaging RubyGems all of RubyGems' defaults are in
+lib/rubygems/defaults.rb. You may override these in
+lib/rubygems/defaults/operating_system.rb
+ EOF
+ end
+
def usage # :nodoc:
"#{program_name} [arg]"
end
diff --git a/lib/rubygems/commands/help_command.rb b/lib/rubygems/commands/help_command.rb
index 05ea3f7a71..0c4a4ec16f 100644
--- a/lib/rubygems/commands/help_command.rb
+++ b/lib/rubygems/commands/help_command.rb
@@ -20,9 +20,9 @@ Some examples of 'gem' usage.
gem install --remote rake --test --rdoc --ri
* Install 'rake', but only version 0.3.1, even if dependencies
- are not met, and into a specific directory:
+ are not met, and into a user-specific directory:
- gem install rake --version 0.3.1 --force --install-dir $HOME/.gems
+ gem install rake --version 0.3.1 --force --user-install
* List local gems whose name begins with 'D':
diff --git a/lib/rubygems/commands/install_command.rb b/lib/rubygems/commands/install_command.rb
index 923d578a15..1a6eb68a8b 100644
--- a/lib/rubygems/commands/install_command.rb
+++ b/lib/rubygems/commands/install_command.rb
@@ -38,6 +38,19 @@ class Gem::Commands::InstallCommand < Gem::Command
"--no-test --install-dir #{Gem.dir}"
end
+ def description # :nodoc:
+ <<-EOF
+The install command installs local or remote gem into a gem repository.
+
+For gems with executables ruby installs a wrapper file into the executable
+directory by deault. This can be overridden with the --no-wrappers option.
+The wrapper allows you to choose among alternate gem versions using _version_.
+
+For example `rake _0.7.3_ --version` will run rake version 0.7.3 if a newer
+version is also installed.
+ EOF
+ end
+
def usage # :nodoc:
"#{program_name} GEMNAME [GEMNAME ...] [options] -- --build-flags"
end
@@ -106,6 +119,8 @@ class Gem::Commands::InstallCommand < Gem::Command
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
diff --git a/lib/rubygems/commands/lock_command.rb b/lib/rubygems/commands/lock_command.rb
index 6be2774e92..5a43978dd9 100644
--- a/lib/rubygems/commands/lock_command.rb
+++ b/lib/rubygems/commands/lock_command.rb
@@ -58,15 +58,15 @@ lock it down to the exact version.
end
def complain(message)
- if options.strict then
- raise message
+ if options[:strict] then
+ raise Gem::Exception, message
else
say "# #{message}"
end
end
def execute
- say 'require "rubygems"'
+ say "require 'rubygems'"
locked = {}
@@ -77,15 +77,20 @@ lock it down to the exact version.
spec = Gem::SourceIndex.load_specification spec_path(full_name)
+ if spec.nil? then
+ complain "Could not find gem #{full_name}, try using the full name"
+ next
+ end
+
say "gem '#{spec.name}', '= #{spec.version}'" unless locked[spec.name]
locked[spec.name] = true
spec.runtime_dependencies.each do |dep|
next if locked[dep.name]
- candidates = Gem.source_index.search dep.name, dep.requirement_list
+ candidates = Gem.source_index.search dep
if candidates.empty? then
- complain "Unable to satisfy '#{dep}' from currently installed gems."
+ complain "Unable to satisfy '#{dep}' from currently installed gems"
else
pending << candidates.last.full_name
end
@@ -94,7 +99,11 @@ lock it down to the exact version.
end
def spec_path(gem_full_name)
- File.join Gem.path, "specifications", "#{gem_full_name }.gemspec"
+ gemspecs = Gem.path.map do |path|
+ File.join path, "specifications", "#{gem_full_name}.gemspec"
+ end
+
+ gemspecs.find { |gemspec| File.exist? gemspec }
end
end
diff --git a/lib/rubygems/commands/outdated_command.rb b/lib/rubygems/commands/outdated_command.rb
index 1cd1087dd1..9e054f988c 100644
--- a/lib/rubygems/commands/outdated_command.rb
+++ b/lib/rubygems/commands/outdated_command.rb
@@ -19,7 +19,7 @@ class Gem::Commands::OutdatedCommand < Gem::Command
locals = Gem::SourceIndex.from_installed_gems
locals.outdated.sort.each do |name|
- local = locals.search(/^#{name}$/).last
+ local = locals.find_name(name).last
dep = Gem::Dependency.new local.name, ">= #{local.version}"
remotes = Gem::SpecFetcher.fetcher.fetch dep
diff --git a/lib/rubygems/commands/pristine_command.rb b/lib/rubygems/commands/pristine_command.rb
index 3e55a1bb30..d47fe54edd 100644
--- a/lib/rubygems/commands/pristine_command.rb
+++ b/lib/rubygems/commands/pristine_command.rb
@@ -57,7 +57,7 @@ revert the gem.
end
else
gem_name = get_one_gem_name
- Gem::SourceIndex.from_installed_gems.search(gem_name,
+ Gem::SourceIndex.from_installed_gems.find_name(gem_name,
options[:version])
end
diff --git a/lib/rubygems/commands/query_command.rb b/lib/rubygems/commands/query_command.rb
index f4d6120bcd..29fe8acb79 100644
--- a/lib/rubygems/commands/query_command.rb
+++ b/lib/rubygems/commands/query_command.rb
@@ -59,7 +59,7 @@ class Gem::Commands::QueryCommand < Gem::Command
if name.source.empty? then
alert_error "You must specify a gem name"
exit_code |= 4
- elsif installed? name.source, options[:version] then
+ elsif installed? name, options[:version] then
say "true"
else
say "false"
@@ -69,12 +69,16 @@ class Gem::Commands::QueryCommand < Gem::Command
raise Gem::SystemExitException, exit_code
end
+ dep = Gem::Dependency.new name, Gem::Requirement.default
+
if local? then
- say
- say "*** LOCAL GEMS ***"
- say
+ if ui.outs.tty? or both? then
+ say
+ say "*** LOCAL GEMS ***"
+ say
+ end
- specs = Gem.source_index.search name
+ specs = Gem.source_index.search dep
spec_tuples = specs.map do |spec|
[[spec.name, spec.version, spec.original_platform, spec], :local]
@@ -84,13 +88,14 @@ class Gem::Commands::QueryCommand < Gem::Command
end
if remote? then
- say
- say "*** REMOTE GEMS ***"
- say
+ if ui.outs.tty? or both? then
+ say
+ say "*** REMOTE GEMS ***"
+ say
+ end
all = options[:all]
- dep = Gem::Dependency.new name, Gem::Requirement.default
begin
fetcher = Gem::SpecFetcher.fetcher
spec_tuples = fetcher.find_matching dep, all, false
diff --git a/lib/rubygems/commands/rdoc_command.rb b/lib/rubygems/commands/rdoc_command.rb
index f2e677c115..82180d485c 100644
--- a/lib/rubygems/commands/rdoc_command.rb
+++ b/lib/rubygems/commands/rdoc_command.rb
@@ -59,11 +59,15 @@ module Gem
if specs.empty?
fail "Failed to find gem #{gem_name} to generate RDoc for #{options[:version]}"
end
+
if options[:include_ri]
specs.each do |spec|
Gem::DocManager.new(spec).generate_ri
end
+
+ Gem::DocManager.update_ri_cache
end
+
if options[:include_rdoc]
specs.each do |spec|
Gem::DocManager.new(spec).generate_rdoc
@@ -73,6 +77,6 @@ module Gem
true
end
end
-
+
end
end
diff --git a/lib/rubygems/commands/specification_command.rb b/lib/rubygems/commands/specification_command.rb
index 689f2560c9..5aaf6d1797 100644
--- a/lib/rubygems/commands/specification_command.rb
+++ b/lib/rubygems/commands/specification_command.rb
@@ -40,6 +40,7 @@ class Gem::Commands::SpecificationCommand < Gem::Command
def execute
specs = []
gem = get_one_gem_name
+ dep = Gem::Dependency.new gem, options[:version]
if local? then
if File.exist? gem then
@@ -47,12 +48,11 @@ class Gem::Commands::SpecificationCommand < Gem::Command
end
if specs.empty? then
- specs.push(*Gem.source_index.search(/\A#{gem}\z/, options[:version]))
+ specs.push(*Gem.source_index.search(dep))
end
end
if remote? then
- dep = Gem::Dependency.new gem, options[:version]
found = Gem::SpecFetcher.fetcher.fetch dep
specs.push(*found.map { |spec,| spec })
diff --git a/lib/rubygems/commands/unpack_command.rb b/lib/rubygems/commands/unpack_command.rb
index d187f8a9ea..ef9436ae34 100644
--- a/lib/rubygems/commands/unpack_command.rb
+++ b/lib/rubygems/commands/unpack_command.rb
@@ -68,7 +68,7 @@ class Gem::Commands::UnpackCommand < Gem::Command
def get_path(gemname, version_req)
return gemname if gemname =~ /\.gem$/i
- specs = Gem::source_index.search(/\A#{gemname}\z/, version_req)
+ specs = Gem::source_index.find_name gemname, version_req
selected = specs.sort_by { |s| s.version }.last
diff --git a/lib/rubygems/commands/update_command.rb b/lib/rubygems/commands/update_command.rb
index 78baa8ba56..4490f385dc 100644
--- a/lib/rubygems/commands/update_command.rb
+++ b/lib/rubygems/commands/update_command.rb
@@ -45,6 +45,8 @@ class Gem::Commands::UpdateCommand < Gem::Command
end
def execute
+ hig = {}
+
if options[:system] then
say "Updating RubyGems"
@@ -52,16 +54,22 @@ class Gem::Commands::UpdateCommand < Gem::Command
fail "No gem names are allowed with the --system option"
end
- options[:args] = ["rubygems-update"]
+ spec = Gem::Specification.new
+ spec.name = 'rubygems-update'
+ spec.version = Gem::Version.new Gem::RubyGemsVersion
+ spec.version = Gem::Version.new '1.1.1'
+ hig['rubygems-update'] = spec
+
+ options[:user_install] = false
else
say "Updating installed gems"
- end
- hig = {} # highest installed gems
+ hig = {} # highest installed gems
- Gem.source_index.each do |name, spec|
- if hig[spec.name].nil? or hig[spec.name].version < spec.version then
- hig[spec.name] = spec
+ Gem.source_index.each do |name, spec|
+ if hig[spec.name].nil? or hig[spec.name].version < spec.version then
+ hig[spec.name] = spec
+ end
end
end
@@ -84,14 +92,14 @@ class Gem::Commands::UpdateCommand < Gem::Command
end
if gems_to_update.include? "rubygems-update" then
- latest_ruby_gem = remote_gemspecs.select do |s|
- s.name == 'rubygems-update'
- end
+ Gem.source_index.refresh!
+
+ update_gems = Gem.source_index.search 'rubygems-update'
- latest_ruby_gem = latest_ruby_gem.sort_by { |s| s.version }.last
+ latest_update_gem = update_gems.sort_by { |s| s.version }.last
- say "Updating version of RubyGems to #{latest_ruby_gem.version}"
- installed = do_rubygems_update latest_ruby_gem.version
+ say "Updating RubyGems to #{latest_update_gem.version}"
+ installed = do_rubygems_update latest_update_gem.version
say "RubyGems system software updated" if installed
else
@@ -103,6 +111,9 @@ class Gem::Commands::UpdateCommand < Gem::Command
end
end
+ ##
+ # Update the RubyGems software to +version+.
+
def do_rubygems_update(version)
args = []
args.push '--prefix', Gem.prefix unless Gem.prefix.nil?
@@ -112,8 +123,6 @@ class Gem::Commands::UpdateCommand < Gem::Command
update_dir = File.join Gem.dir, 'gems', "rubygems-update-#{version}"
- success = false
-
Dir.chdir update_dir do
say "Installing RubyGems #{version}"
setup_cmd = "#{Gem.ruby} setup.rb #{args.join ' '}"
diff --git a/lib/rubygems/commands/which_command.rb b/lib/rubygems/commands/which_command.rb
index b42244ce7d..2267e44b11 100644
--- a/lib/rubygems/commands/which_command.rb
+++ b/lib/rubygems/commands/which_command.rb
@@ -3,10 +3,10 @@ require 'rubygems/gem_path_searcher'
class Gem::Commands::WhichCommand < Gem::Command
- EXT = %w[.rb .rbw .so .dll] # HACK
+ EXT = %w[.rb .rbw .so .dll .bundle] # HACK
def initialize
- super 'which', 'Find the location of a library',
+ super 'which', 'Find the location of a library file you can require',
:search_gems_first => false, :show_all => false
add_option '-a', '--[no-]all', 'show all matching files' do |show_all, options|
@@ -52,7 +52,7 @@ class Gem::Commands::WhichCommand < Gem::Command
paths = find_paths arg, dirs
if paths.empty? then
- say "Can't find #{arg}"
+ say "Can't find ruby library file or shared library #{arg}"
else
say paths
end
@@ -84,3 +84,4 @@ class Gem::Commands::WhichCommand < Gem::Command
end
end
+
diff --git a/lib/rubygems/config_file.rb b/lib/rubygems/config_file.rb
index c093c31a1b..0a35ca9417 100644
--- a/lib/rubygems/config_file.rb
+++ b/lib/rubygems/config_file.rb
@@ -49,6 +49,9 @@ class Gem::ConfigFile
# List of arguments supplied to the config file object.
attr_reader :args
+ # Where to look for gems
+ attr_accessor :path
+
# True if we print backtraces on errors.
attr_writer :backtrace
@@ -123,9 +126,10 @@ class Gem::ConfigFile
@backtrace = @hash[:backtrace] if @hash.key? :backtrace
@benchmark = @hash[:benchmark] if @hash.key? :benchmark
@bulk_threshold = @hash[:bulk_threshold] if @hash.key? :bulk_threshold
- Gem.sources.replace @hash[:sources] if @hash.key? :sources
+ Gem.sources = @hash[:sources] if @hash.key? :sources
@verbose = @hash[:verbose] if @hash.key? :verbose
@update_sources = @hash[:update_sources] if @hash.key? :update_sources
+ @path = @hash[:gempath]
handle_arguments arg_list
end
diff --git a/lib/rubygems/defaults.rb b/lib/rubygems/defaults.rb
index 8bb9776575..7eba0cb049 100644
--- a/lib/rubygems/defaults.rb
+++ b/lib/rubygems/defaults.rb
@@ -1,36 +1,52 @@
module Gem
- # An Array of the default sources that come with RubyGems.
+ ##
+ # An Array of the default sources that come with RubyGems
+
def self.default_sources
%w[http://gems.rubyforge.org/]
end
+ ##
# Default home directory path to be used if an alternate value is not
- # specified in the environment.
+ # specified in the environment
+
def self.default_dir
if defined? RUBY_FRAMEWORK_VERSION then
File.join File.dirname(ConfigMap[:sitedir]), 'Gems',
ConfigMap[:ruby_version]
- elsif defined? RUBY_ENGINE then
- File.join ConfigMap[:libdir], RUBY_ENGINE, 'gems',
- ConfigMap[:ruby_version]
else
- File.join ConfigMap[:libdir], 'ruby', 'gems', ConfigMap[:ruby_version]
+ File.join(ConfigMap[:libdir], ruby_engine, 'gems',
+ ConfigMap[:ruby_version])
end
end
- # Default gem load path.
+ ##
+ # Path for gems in the user's home directory
+
+ def self.user_dir
+ File.join(Gem.user_home, '.gem', ruby_engine,
+ ConfigMap[:ruby_version])
+ end
+
+ ##
+ # Default gem load path
+
def self.default_path
- [File.join(ENV['HOME'], '.gem'), default_dir]
+ [user_dir, default_dir]
end
- # Deduce Ruby's --program-prefix and --program-suffix from its install name.
+ ##
+ # Deduce Ruby's --program-prefix and --program-suffix from its install name
+
def self.default_exec_format
baseruby = ConfigMap[:BASERUBY] || 'ruby'
ConfigMap[:RUBY_INSTALL_NAME].sub(baseruby, '%s') rescue '%s'
end
+ ##
# The default directory for binaries
+
def self.default_bindir
if defined? RUBY_FRAMEWORK_VERSION then # mac framework support
'/usr/bin'
@@ -39,15 +55,30 @@ module Gem
end
end
- # The default system-wide source info cache directory.
+ ##
+ # 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.
+ ##
+ # The default user-specific source info cache directory
+
def self.default_user_source_cache_dir
File.join Gem.user_home, '.gem', 'source_cache'
end
+ ##
+ # A wrapper around RUBY_ENGINE const that may not be defined
+
+ def self.ruby_engine
+ if defined? RUBY_ENGINE then
+ RUBY_ENGINE
+ else
+ 'ruby'
+ end
+ end
+
end
diff --git a/lib/rubygems/dependency_installer.rb b/lib/rubygems/dependency_installer.rb
index 8406844e79..9ae2659536 100644
--- a/lib/rubygems/dependency_installer.rb
+++ b/lib/rubygems/dependency_installer.rb
@@ -38,9 +38,17 @@ class Gem::DependencyInstaller
# :ignore_dependencies:: Don't install any dependencies.
# :install_dir:: See Gem::Installer#install.
# :security_policy:: See Gem::Installer::new and Gem::Security.
+ # :user_install:: See Gem::Installer.new
# :wrappers:: See Gem::Installer::new
def initialize(options = {})
+ if options[:install_dir] then
+ spec_dir = options[:install_dir], 'specifications'
+ @source_index = Gem::SourceIndex.from_gems_in spec_dir
+ else
+ @source_index = Gem.source_index
+ end
+
options = DEFAULT_OPTIONS.merge options
@bin_dir = options[:bin_dir]
@@ -51,19 +59,13 @@ class Gem::DependencyInstaller
@format_executable = options[:format_executable]
@ignore_dependencies = options[:ignore_dependencies]
@security_policy = options[:security_policy]
+ @user_install = options[:user_install]
@wrappers = options[:wrappers]
@installed_gems = []
@install_dir = options[:install_dir] || Gem.dir
@cache_dir = options[:cache_dir] || @install_dir
-
- if options[:install_dir] then
- spec_dir = File.join @install_dir, 'specifications'
- @source_index = Gem::SourceIndex.from_gems_in spec_dir
- else
- @source_index = Gem.source_index
- end
end
##
@@ -232,15 +234,17 @@ class Gem::DependencyInstaller
end
inst = Gem::Installer.new local_gem_path,
- :env_shebang => @env_shebang,
- :force => @force,
- :format_executable => @format_executable,
+ :bin_dir => @bin_dir,
+ :development => @development,
+ :env_shebang => @env_shebang,
+ :force => @force,
+ :format_executable => @format_executable,
:ignore_dependencies => @ignore_dependencies,
- :install_dir => @install_dir,
- :security_policy => @security_policy,
- :wrappers => @wrappers,
- :bin_dir => @bin_dir,
- :development => @development
+ :install_dir => @install_dir,
+ :security_policy => @security_policy,
+ :source_index => @source_index,
+ :user_install => @user_install,
+ :wrappers => @wrappers
spec = inst.install
diff --git a/lib/rubygems/doc_manager.rb b/lib/rubygems/doc_manager.rb
index 88d7964d85..00ef4c51e3 100644
--- a/lib/rubygems/doc_manager.rb
+++ b/lib/rubygems/doc_manager.rb
@@ -5,132 +5,194 @@
#++
require 'fileutils'
+require 'rubygems'
-module Gem
+##
+# The documentation manager generates RDoc and RI for RubyGems.
- class DocManager
+class Gem::DocManager
- include UserInteraction
+ include Gem::UserInteraction
- # Create a document manager for the given gem spec.
- #
- # spec:: The Gem::Specification object representing the gem.
- # rdoc_args:: Optional arguments for RDoc (template etc.) as a String.
- #
- def initialize(spec, rdoc_args="")
- @spec = spec
- @doc_dir = File.join(spec.installation_path, "doc", spec.full_name)
- @rdoc_args = rdoc_args.nil? ? [] : rdoc_args.split
+ @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
- # Is the RDoc documentation installed?
- def rdoc_installed?
- return File.exist?(File.join(@doc_dir, "rdoc"))
+ def self.load_rdoc
+ begin
+ gem 'rdoc'
+ rescue Gem::LoadError
+ # use built-in RDoc
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
- if @spec.has_rdoc then
- load_rdoc
- install_ri # RDoc bug, ri goes first
- end
+ begin
+ require 'rdoc/rdoc'
+ rescue LoadError => e
+ raise Gem::DocumentError,
+ "ERROR: RDoc documentation generator not installed!"
+ end
+ 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
- FileUtils.mkdir_p @doc_dir unless File.exist?(@doc_dir)
+ require 'rdoc/ri/driver'
+
+ options = {
+ :use_cache => true,
+ :use_system => true,
+ :use_site => true,
+ :use_home => true,
+ :use_gems => true,
+ :formatter => RDoc::RI::Formatter,
+ }
+
+ driver = 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="")
+ @spec = spec
+ @doc_dir = File.join(spec.installation_path, "doc", spec.full_name)
+ @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
+
+ ##
+ # 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
+ if @spec.has_rdoc then
+ setup_rdoc
+ install_ri # RDoc bug, ri goes first
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
- if @spec.has_rdoc then
- load_rdoc
- install_rdoc
- end
+ FileUtils.mkdir_p @doc_dir unless File.exist?(@doc_dir)
+ end
- FileUtils.mkdir_p @doc_dir unless File.exist?(@doc_dir)
+ ##
+ # 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
+ if @spec.has_rdoc then
+ setup_rdoc
+ install_rdoc
end
- # Load the RDoc documentation generator library.
- def load_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)
+ end
- FileUtils.mkdir_p @doc_dir unless File.exist?(@doc_dir)
+ ##
+ # Generate and install RDoc into the documentation directory
- begin
- gem 'rdoc'
- rescue Gem::LoadError
- # use built-in RDoc
- end
+ def install_rdoc
+ rdoc_dir = File.join @doc_dir, 'rdoc'
- begin
- require 'rdoc/rdoc'
- rescue LoadError => e
- raise Gem::DocumentError,
- "ERROR: RDoc documentation generator not installed!"
- end
- end
+ FileUtils.rm_rf rdoc_dir
- def install_rdoc
- rdoc_dir = File.join @doc_dir, 'rdoc'
+ say "Installing RDoc documentation for #{@spec.full_name}..."
+ run_rdoc '--op', rdoc_dir
+ end
- FileUtils.rm_rf rdoc_dir
+ ##
+ # Generate and install RI into the documentation directory
- say "Installing RDoc documentation for #{@spec.full_name}..."
- run_rdoc '--op', rdoc_dir
- end
+ def install_ri
+ ri_dir = File.join @doc_dir, 'ri'
- def install_ri
- ri_dir = File.join @doc_dir, 'ri'
+ FileUtils.rm_rf ri_dir
- FileUtils.rm_rf ri_dir
+ say "Installing ri documentation for #{@spec.full_name}..."
+ run_rdoc '--ri', '--op', ri_dir
+ end
- say "Installing ri documentation for #{@spec.full_name}..."
- run_rdoc '--ri', '--op', ri_dir
+ ##
+ # 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 << '--quiet'
+ args << @spec.require_paths.clone
+ args << @spec.extra_rdoc_files
+ args = args.flatten.map do |arg| arg.to_s end
+
+ r = RDoc::RDoc.new
+
+ old_pwd = Dir.pwd
+ Dir.chdir(@spec.full_gem_path)
+ begin
+ r.document args
+ rescue Errno::EACCES => e
+ dirname = File.dirname e.message.split("-")[1].strip
+ raise Gem::FilePermissionError.new(dirname)
+ rescue RuntimeError => ex
+ alert_error "While generating documentation for #{@spec.full_name}"
+ ui.errs.puts "... MESSAGE: #{ex}"
+ ui.errs.puts "... RDOC args: #{args.join(' ')}"
+ ui.errs.puts "\t#{ex.backtrace.join "\n\t"}" if
+ Gem.configuration.backtrace
+ ui.errs.puts "(continuing with the rest of the installation)"
+ ensure
+ Dir.chdir(old_pwd)
end
+ end
- def run_rdoc(*args)
- args << @spec.rdoc_options
- args << DocManager.configured_args
- args << '--quiet'
- args << @spec.require_paths.clone
- args << @spec.extra_rdoc_files
- args = args.flatten.map do |arg| arg.to_s end
-
- r = RDoc::RDoc.new
-
- old_pwd = Dir.pwd
- Dir.chdir(@spec.full_gem_path)
- begin
- r.document args
- rescue Errno::EACCES => e
- dirname = File.dirname e.message.split("-")[1].strip
- raise Gem::FilePermissionError.new(dirname)
- rescue RuntimeError => ex
- alert_error "While generating documentation for #{@spec.full_name}"
- ui.errs.puts "... MESSAGE: #{ex}"
- ui.errs.puts "... RDOC args: #{args.join(' ')}"
- ui.errs.puts "\t#{ex.backtrace.join "\n\t"}" if
- Gem.configuration.backtrace
- ui.errs.puts "(continuing with the rest of the installation)"
- ensure
- Dir.chdir(old_pwd)
- end
+ def setup_rdoc
+ if File.exist?(@doc_dir) && !File.writable?(@doc_dir) then
+ raise Gem::FilePermissionError.new(@doc_dir)
end
- def uninstall_doc
- raise Gem::FilePermissionError.new(@spec.installation_path) unless
- File.writable? @spec.installation_path
+ FileUtils.mkdir_p @doc_dir unless File.exist?(@doc_dir)
- original_name = [
- @spec.name, @spec.version, @spec.original_platform].join '-'
+ self.class.load_rdoc
+ end
+
+ ##
+ # Remove RDoc and RI documentation
+
+ def uninstall_doc
+ raise Gem::FilePermissionError.new(@spec.installation_path) unless
+ File.writable? @spec.installation_path
+
+ original_name = [
+ @spec.name, @spec.version, @spec.original_platform].join '-'
doc_dir = File.join @spec.installation_path, 'doc', @spec.full_name
unless File.directory? doc_dir then
@@ -146,22 +208,7 @@ module Gem
end
FileUtils.rm_rf ri_dir
- end
-
- class << self
- def configured_args
- @configured_args ||= []
- end
-
- def configured_args=(args)
- case args
- when Array
- @configured_args = args
- when String
- @configured_args = args.split
- end
- end
- end
-
end
+
end
+
diff --git a/lib/rubygems/gem_path_searcher.rb b/lib/rubygems/gem_path_searcher.rb
index dadad66289..e2b8543bb0 100644
--- a/lib/rubygems/gem_path_searcher.rb
+++ b/lib/rubygems/gem_path_searcher.rb
@@ -6,15 +6,15 @@
require 'rubygems'
-#
+##
# 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.
@@ -27,7 +27,7 @@ class Gem::GemPathSearcher
end
end
- #
+ ##
# Look in all the installed gems until a matching _path_ is found.
# Return the _gemspec_ of the gem where it was found. If no match
# is found, return nil.
@@ -46,36 +46,52 @@ class Gem::GemPathSearcher
# 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(path)
- @gemspecs.each do |spec|
- return spec if matching_file(spec, path)
+ @gemspecs.find do |spec| matching_file? spec, path end
+ end
+
+ ##
+ # Works like #find, but finds all gemspecs matching +path+.
+
+ def find_all(path)
+ @gemspecs.select do |spec|
+ matching_file? spec, path
end
- nil
end
- private
+ ##
+ # Attempts to find a matching path using the require_paths of the given
+ # +spec+.
- # Attempts to find a matching path using the require_paths of the
- # given _spec_.
- #
- # Some of the intermediate results are cached in @lib_dirs for
- # speed.
- def matching_file(spec, path) # :doc:
+ def matching_file?(spec, path)
+ !matching_files(spec, path).empty?
+ end
+
+ ##
+ # Returns files matching +path+ in +spec+.
+ #--
+ # Some of the intermediate results are cached in @lib_dirs for speed.
+
+ def matching_files(spec, path)
glob = File.join @lib_dirs[spec.object_id], "#{path}#{Gem.suffix_pattern}"
- return true unless Dir[glob].select { |f| File.file?(f.untaint) }.empty?
+ 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.
+ ##
+ # Return a list of all installed gemspecs, sorted by alphabetical order and
+ # in reverse version order.
+
def init_gemspecs
Gem.source_index.map { |_, spec| spec }.sort { |a,b|
(a.name <=> b.name).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(',')}}"
end
diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb
index 5e2e8e0f42..d9006f9fc7 100644
--- a/lib/rubygems/installer.rb
+++ b/lib/rubygems/installer.rb
@@ -20,6 +20,7 @@ require 'rubygems/require_paths_builder'
# filesystem including unpacking the gem into its gem dir, installing the
# gemspec in the specifications dir, storing the cached gem in the cache dir,
# and installing either wrappers or symlinks for executables.
+
class Gem::Installer
##
@@ -31,8 +32,36 @@ class Gem::Installer
include Gem::RequirePathsBuilder
+ ##
+ # The directory a gem's executables will be installed into
+
+ attr_reader :bin_dir
+
+ ##
+ # The gem repository the gem will be installed into
+
+ attr_reader :gem_home
+
+ ##
+ # The Gem::Specification for the gem being installed
+
+ attr_reader :spec
+
+ @home_install_warning = false
+ @path_warning = false
+
class << self
+ ##
+ # True if we've warned about ~/.gems install
+
+ attr_accessor :home_install_warning
+
+ ##
+ # True if we've warned about PATH not including Gem.bindir
+
+ attr_accessor :path_warning
+
attr_writer :exec_format
# Defaults to use Ruby's program prefix and suffix.
@@ -61,11 +90,12 @@ class Gem::Installer
@gem = gem
options = {
- :force => false,
- :install_dir => Gem.dir,
- :exec_format => false,
- :env_shebang => false,
- :bin_dir => nil
+ :bin_dir => nil,
+ :env_shebang => false,
+ :exec_format => false,
+ :force => false,
+ :install_dir => Gem.dir,
+ :source_index => Gem.source_index,
}.merge options
@env_shebang = options[:env_shebang]
@@ -78,6 +108,7 @@ class Gem::Installer
@wrappers = options[:wrappers]
@bin_dir = options[:bin_dir]
@development = options[:development]
+ @source_index = options[:source_index]
begin
@format = Gem::Format.from_file_by_path @gem, @security_policy
@@ -85,30 +116,41 @@ class Gem::Installer
raise Gem::InstallError, "invalid gem format for #{@gem}"
end
+ begin
+ FileUtils.mkdir_p @gem_home
+ rescue Errno::EACCESS, Errno::ENOTDIR
+ # We'll divert to ~/.gems below
+ end
+
if not File.writable? @gem_home or
# TODO: Shouldn't have to test for existence of bindir; tests need it.
- (@gem_home.to_s == Gem.dir and File.exist? Gem.bindir and
- not File.writable? Gem.bindir)
- if options[:user_install] == false # You explicitly don't want to use ~
+ (@gem_home.to_s == Gem.dir and File.exist? Gem.bindir and
+ not File.writable? Gem.bindir) then
+ if options[:user_install] == false then # You don't want to use ~
raise Gem::FilePermissionError, @gem_home
- elsif options[:user_install].nil?
- say "Warning: falling back to user-level install since #{@gem_home} and #{@bin_dir} aren't both writable."
+ elsif options[:user_install].nil? then
+ unless self.class.home_install_warning then
+ alert_warning "Installing to ~/.gem since #{@gem_home} and\n\t #{Gem.bindir} aren't both writable."
+ self.class.home_install_warning = true
+ end
end
options[:user_install] = true
end
- if options[:user_install]
- @gem_home = File.join(ENV['HOME'], '.gem')
+ if options[:user_install] then
+ @gem_home = Gem.user_dir
- user_bin_dir = File.join(@gem_home, 'gems', 'bin')
- if !ENV['PATH'].split(':').include?(user_bin_dir)
- say "You don't have #{user_bin_dir} in your PATH."
- say "You won't be able to run gem-installed executables until you add it."
+ user_bin_dir = File.join(@gem_home, 'bin')
+ unless ENV['PATH'].split(File::PATH_SEPARATOR).include? user_bin_dir then
+ unless self.class.path_warning then
+ alert_warning "You don't have #{user_bin_dir} in your PATH,\n\t gem executables will not run."
+ self.class.path_warning = true
+ end
end
-
- Dir.mkdir @gem_home if ! File.directory? @gem_home
+
+ FileUtils.mkdir_p @gem_home unless File.directory? @gem_home
# If it's still not writable, you've got issues.
- raise Gem::FilePermissionError, @gem_home if ! File.writable? @gem_home
+ raise Gem::FilePermissionError, @gem_home unless File.writable? @gem_home
end
@spec = @format.spec
@@ -157,6 +199,10 @@ class Gem::Installer
end
end
+ Gem.pre_install_hooks.each do |hook|
+ hook.call self
+ end
+
FileUtils.mkdir_p @gem_home unless File.directory? @gem_home
Gem.ensure_gem_subdirectories @gem_home
@@ -181,7 +227,11 @@ class Gem::Installer
@spec.loaded_from = File.join(@gem_home, 'specifications',
"#{@spec.full_name}.gemspec")
- Gem.source_index.add_spec @spec
+ @source_index.add_spec @spec
+
+ Gem.post_install_hooks.each do |hook|
+ hook.call self
+ end
return @spec
rescue Zlib::GzipFile::Error
@@ -204,10 +254,10 @@ class Gem::Installer
end
##
- # True if the gems in Gem.source_index satisfy +dependency+.
+ # True if the gems in the source_index satisfy +dependency+.
def installation_satisfies_dependency?(dependency)
- Gem.source_index.find_name(dependency.name, dependency.version_requirements).size > 0
+ @source_index.find_name(dependency.name, dependency.version_requirements).size > 0
end
##
diff --git a/lib/rubygems/local_remote_options.rb b/lib/rubygems/local_remote_options.rb
index 799b9d5893..d77d600ec6 100644
--- a/lib/rubygems/local_remote_options.rb
+++ b/lib/rubygems/local_remote_options.rb
@@ -110,6 +110,13 @@ module Gem::LocalRemoteOptions
end
##
+ # Is fetching of local and remote information enabled?
+
+ def both?
+ options[:domain] == :both
+ end
+
+ ##
# Is local fetching enabled?
def local?
diff --git a/lib/rubygems/package/tar_reader.rb b/lib/rubygems/package/tar_reader.rb
index 8359399207..4aa9c26cc9 100644
--- a/lib/rubygems/package/tar_reader.rb
+++ b/lib/rubygems/package/tar_reader.rb
@@ -46,17 +46,17 @@ class Gem::Package::TarReader
yield entry
skip = (512 - (size % 512)) % 512
+ pending = size - entry.bytes_read
- if @io.respond_to? :seek then
+ begin
# avoid reading...
- @io.seek(size - entry.bytes_read, IO::SEEK_CUR)
- else
- pending = size - entry.bytes_read
-
+ @io.seek pending, IO::SEEK_CUR
+ pending = 0
+ rescue Errno::EINVAL, NameError
while pending > 0 do
- bread = @io.read([pending, 4096].min).size
+ bytes_read = @io.read([pending, 4096].min).size
raise UnexpectedEOF if @io.eof?
- pending -= bread
+ pending -= bytes_read
end
end
diff --git a/lib/rubygems/platform.rb b/lib/rubygems/platform.rb
index 5e932cd592..3e5b5cde66 100644
--- a/lib/rubygems/platform.rb
+++ b/lib/rubygems/platform.rb
@@ -13,23 +13,6 @@ class Gem::Platform
attr_accessor :version
- DEPRECATED_CONSTS = [
- :DARWIN,
- :LINUX_586,
- :MSWIN32,
- :PPC_DARWIN,
- :WIN32,
- :X86_LINUX
- ]
-
- def self.const_missing(name) # TODO remove six months from 2007/12
- if DEPRECATED_CONSTS.include? name then
- raise NameError, "#{name} has been removed, use CURRENT instead"
- else
- super
- end
- end
-
def self.local
arch = Gem::ConfigMap[:arch]
arch = "#{arch}_60" if arch =~ /mswin32$/
@@ -73,7 +56,7 @@ class Gem::Platform
else cpu
end
- if arch.length == 2 and arch.last =~ /^\d+$/ then # for command-line
+ if arch.length == 2 and arch.last =~ /^\d+(\.\d+)?$/ then # for command-line
@os, @version = arch
return
end
diff --git a/lib/rubygems/remote_fetcher.rb b/lib/rubygems/remote_fetcher.rb
index 3c747f1d65..1570740163 100644
--- a/lib/rubygems/remote_fetcher.rb
+++ b/lib/rubygems/remote_fetcher.rb
@@ -78,7 +78,7 @@ class Gem::RemoteFetcher
if File.writable?(install_dir)
cache_dir = File.join install_dir, 'cache'
else
- cache_dir = File.join(ENV['HOME'], '.gem', 'cache')
+ cache_dir = File.join(Gem.user_dir, 'cache')
end
gem_file_name = "#{spec.full_name}.gem"
@@ -93,7 +93,7 @@ class Gem::RemoteFetcher
scheme = nil if scheme =~ /^[a-z]$/i
case scheme
- when 'http' then
+ when 'http', 'https' then
unless File.exist? local_gem_path then
begin
say "Downloading gem #{gem_file_name}" if
@@ -139,8 +139,8 @@ class Gem::RemoteFetcher
# Downloads +uri+ and returns it as a String.
def fetch_path(uri, mtime = nil, head = false)
- data = open_uri_or_path(uri, mtime, head)
- data = Gem.gunzip data if uri.to_s =~ /gz$/ and not head
+ data = open_uri_or_path uri, mtime, head
+ data = Gem.gunzip data if data and not head and uri.to_s =~ /gz$/
data
rescue FetchError
raise
@@ -216,8 +216,9 @@ class Gem::RemoteFetcher
connection = @connections[connection_id]
if uri.scheme == 'https' and not connection.started? then
- http_obj.use_ssl = true
- http_obj.verify_mode = OpenSSL::SSL::VERIFY_NONE
+ require 'net/https'
+ connection.use_ssl = true
+ connection.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
connection.start unless connection.started?
@@ -241,9 +242,10 @@ class Gem::RemoteFetcher
response = request uri, fetch_type, last_modified
case response
- when Net::HTTPOK then
+ when Net::HTTPOK, Net::HTTPNotModified then
head ? response : response.body
- when Net::HTTPRedirection then
+ when Net::HTTPMovedPermanently, Net::HTTPFound, Net::HTTPSeeOther,
+ Net::HTTPTemporaryRedirect then
raise FetchError.new('too many redirects', uri) if depth > 10
open_uri_or_path(response['Location'], last_modified, head, depth + 1)
@@ -274,6 +276,7 @@ class Gem::RemoteFetcher
request.add_field 'Keep-Alive', '30'
if last_modified then
+ last_modified = last_modified.utc
request.add_field 'If-Modified-Since', last_modified.rfc2822
end
@@ -282,9 +285,6 @@ class Gem::RemoteFetcher
retried = false
bad_response = false
- # HACK work around EOFError bug in Net::HTTP
- # NOTE Errno::ECONNABORTED raised a lot on Windows, and make impossible
- # to install gems.
begin
@requests[connection.object_id] += 1
response = connection.request request
@@ -297,6 +297,9 @@ class Gem::RemoteFetcher
bad_response = true
retry
+ # HACK work around EOFError bug in Net::HTTP
+ # NOTE Errno::ECONNABORTED raised a lot on Windows, and make impossible
+ # to install gems.
rescue EOFError, Errno::ECONNABORTED, Errno::ECONNRESET
requests = @requests[connection.object_id]
say "connection reset after #{requests} requests, retrying" if
diff --git a/lib/rubygems/rubygems_version.rb b/lib/rubygems/rubygems_version.rb
index d393e57a09..06e2104715 100644
--- a/lib/rubygems/rubygems_version.rb
+++ b/lib/rubygems/rubygems_version.rb
@@ -2,5 +2,5 @@
# This file is auto-generated by build scripts.
# See: rake update_version
module Gem
- RubyGemsVersion = '1.2.0.1824'
+ RubyGemsVersion = '1.3.0'
end
diff --git a/lib/rubygems/source_index.rb b/lib/rubygems/source_index.rb
index 1eefd8c149..c6499ed2a8 100644
--- a/lib/rubygems/source_index.rb
+++ b/lib/rubygems/source_index.rb
@@ -7,7 +7,9 @@
require 'rubygems'
require 'rubygems/user_interaction'
require 'rubygems/specification'
-require 'rubygems/spec_fetcher'
+module Gem
+ autoload(:SpecFetcher, 'rubygems/spec_fetcher')
+end
##
# The SourceIndex object indexes all the gems available from a
@@ -80,8 +82,14 @@ class Gem::SourceIndex
def load_specification(file_name)
begin
- spec_code = File.read(file_name).untaint
+ spec_code = if RUBY_VERSION < '1.9' then
+ File.read file_name
+ else
+ File.read file_name, :encoding => 'UTF-8'
+ end.untaint
+
gemspec = eval spec_code, binding, file_name
+
if gemspec.is_a?(Gem::Specification)
gemspec.loaded_from = file_name
return gemspec
@@ -93,7 +101,7 @@ class Gem::SourceIndex
alert_warning e
alert_warning spec_code
rescue Exception => e
- alert_warning(e.inspect.to_s + "\n" + spec_code)
+ alert_warning "#{e.inspect}\n#{spec_code}"
alert_warning "Invalid .gemspec format in '#{file_name}'"
end
return nil
@@ -230,7 +238,8 @@ class Gem::SourceIndex
# Find a gem by an exact match on the short name.
def find_name(gem_name, version_requirement = Gem::Requirement.default)
- search(/^#{gem_name}$/, version_requirement)
+ dep = Gem::Dependency.new(/^#{gem_name}$/, version_requirement)
+ search dep
end
##
@@ -246,7 +255,13 @@ class Gem::SourceIndex
version_requirement = nil
only_platform = false
- case gem_pattern # TODO warn after 2008/03, remove three months after
+ # TODO - Remove support and warning for legacy arguments after 2008/11
+ unless Gem::Dependency === gem_pattern
+ warn "Gem::SourceIndex#search support for #{gem_pattern.class} patterns is deprecated"
+ warn "#{caller[0]} is outdated"
+ end
+
+ case gem_pattern
when Regexp then
version_requirement = platform_only || Gem::Requirement.default
when Gem::Dependency then
@@ -270,7 +285,7 @@ class Gem::SourceIndex
specs = @gems.values.select do |spec|
spec.name =~ gem_pattern and
- version_requirement.satisfied_by? spec.version
+ version_requirement.satisfied_by? spec.version
end
if only_platform then
@@ -539,7 +554,7 @@ module Gem
# objects to load properly.
Cache = SourceIndex
- # :starddoc:
+ # :startdoc:
end
diff --git a/lib/rubygems/source_info_cache.rb b/lib/rubygems/source_info_cache.rb
index ec6928c00d..fdb30ad8d3 100644
--- a/lib/rubygems/source_info_cache.rb
+++ b/lib/rubygems/source_info_cache.rb
@@ -284,6 +284,10 @@ class Gem::SourceInfoCache
cache_data.map do |source_uri, sic_entry|
next unless Gem.sources.include? source_uri
+ # TODO - Remove this gunk after 2008/11
+ unless pattern.kind_of?(Gem::Dependency)
+ pattern = Gem::Dependency.new(pattern, Gem::Requirement.default)
+ end
sic_entry.source_index.search pattern, platform_only
end.flatten.compact
end
@@ -300,6 +304,11 @@ class Gem::SourceInfoCache
cache_data.map do |source_uri, sic_entry|
next unless Gem.sources.include? source_uri
+ # TODO - Remove this gunk after 2008/11
+ unless pattern.kind_of?(Gem::Dependency)
+ pattern = Gem::Dependency.new(pattern, Gem::Requirement.default)
+ end
+
sic_entry.source_index.search(pattern, only_platform).each do |spec|
results << [spec, source_uri]
end
diff --git a/lib/rubygems/spec_fetcher.rb b/lib/rubygems/spec_fetcher.rb
index 66b4ee36c7..a1fc82ed4f 100644
--- a/lib/rubygems/spec_fetcher.rb
+++ b/lib/rubygems/spec_fetcher.rb
@@ -167,7 +167,7 @@ class Gem::SpecFetcher
if all and @specs.include? source_uri then
list[source_uri] = @specs[source_uri]
- elsif @latest_specs.include? source_uri then
+ elsif not all and @latest_specs.include? source_uri then
list[source_uri] = @latest_specs[source_uri]
else
specs = load_specs source_uri, file
@@ -182,6 +182,10 @@ class Gem::SpecFetcher
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"
@@ -192,7 +196,7 @@ class Gem::SpecFetcher
if File.exist? local_file then
spec_dump = @fetcher.fetch_path spec_path, File.mtime(local_file)
- if spec_dump.empty? then
+ if spec_dump.nil? then
spec_dump = Gem.read_binary local_file
else
loaded = true
diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb
index f3f38e5033..2e6cdc1b04 100644
--- a/lib/rubygems/specification.rb
+++ b/lib/rubygems/specification.rb
@@ -24,6 +24,7 @@ class Date; end # for ruby_code if date.rb wasn't required
module Gem
+ ##
# == Gem::Specification
#
# The Specification class contains the metadata for a Gem. Typically
@@ -38,7 +39,7 @@ module Gem
#
# There are many <em>gemspec attributes</em>, and the best place to learn
# about them in the "Gemspec Reference" linked from the RubyGems wiki.
- #
+
class Specification
##
@@ -46,8 +47,6 @@ module Gem
attr_accessor :original_platform # :nodoc:
- # ------------------------- Specification version constants.
-
##
# The the version number of a specification that does not specify one
# (i.e. RubyGems 0.7 or earlier).
@@ -88,77 +87,98 @@ module Gem
TODAY = now - ((now.to_i + now.gmt_offset) % 86400)
# :startdoc:
- # ------------------------- Class variables.
-
+ ##
# List of Specification instances.
+
@@list = []
+ ##
# Optional block used to gather newly defined instances.
+
@@gather = nil
+ ##
# List of attribute names: [:name, :version, ...]
@@required_attributes = []
- # List of _all_ attributes and default values: [[:name, nil], [:bindir, 'bin'], ...]
+ ##
+ # List of _all_ attributes and default values:
+ #
+ # [[:name, nil],
+ # [:bindir, 'bin'],
+ # ...]
+
@@attributes = []
@@nil_attributes = []
@@non_nil_attributes = [:@original_platform]
+ ##
# List of array attributes
+
@@array_attributes = []
+ ##
# Map of attribute names to default values.
+
@@default_value = {}
- # ------------------------- Convenience class methods.
+ ##
+ # Names of all specification attributes
def self.attribute_names
@@attributes.map { |name, default| name }
end
+ ##
+ # Default values for specification attributes
+
def self.attribute_defaults
@@attributes.dup
end
+ ##
+ # The default value for specification attribute +name+
+
def self.default_value(name)
@@default_value[name]
end
+ ##
+ # Required specification attributes
+
def self.required_attributes
@@required_attributes.dup
end
+ ##
+ # Is +name+ a required attribute?
+
def self.required_attribute?(name)
@@required_attributes.include? name.to_sym
end
+ ##
+ # Specification attributes that are arrays (appendable and so-forth)
+
def self.array_attributes
@@array_attributes.dup
end
- # ------------------------- Infrastructure class methods.
+ ##
+ # A list of Specification instances that have been defined in this Ruby
+ # instance.
- # A list of Specification instances that have been defined in this Ruby instance.
def self.list
@@list
end
- # Used to specify the name and default value of a specification
- # attribute. The side effects are:
- # * the name and default value are added to the @@attributes list
- # and @@default_value map
- # * a standard _writer_ method (<tt>attribute=</tt>) is created
- # * a non-standard _reader method (<tt>attribute</tt>) is created
- #
- # The reader method behaves like this:
- # def attribute
- # @attribute ||= (copy of default value)
- # end
- #
- # This allows lazy initialization of attributes to their default
- # values.
+ ##
+ # Specifies the +name+ and +default+ for a specification attribute, and
+ # creates a reader and writer method like Module#attr_accessor.
#
+ # The reader method returns the default if the value hasn't been set.
+
def self.attribute(name, default=nil)
ivar_name = "@#{name}".intern
if default.nil? then
@@ -172,8 +192,10 @@ module Gem
attr_accessor(name)
end
- # Same as :attribute, but ensures that values assigned to the
- # attribute are array values by applying :to_a to the value.
+ ##
+ # Same as :attribute, but ensures that values assigned to the attribute
+ # are array values by applying :to_a to the value.
+
def self.array_attribute(name)
@@non_nil_attributes << ["@#{name}".intern, []]
@@ -192,51 +214,60 @@ module Gem
module_eval code, __FILE__, __LINE__ - 9
end
+ ##
# Same as attribute above, but also records this attribute as mandatory.
+
def self.required_attribute(*args)
@@required_attributes << args.first
attribute(*args)
end
- # Sometimes we don't want the world to use a setter method for a particular attribute.
+ ##
+ # Sometimes we don't want the world to use a setter method for a
+ # particular attribute.
+ #
# +read_only+ makes it private so we can still use it internally.
+
def self.read_only(*names)
names.each do |name|
private "#{name}="
end
end
- # Shortcut for creating several attributes at once (each with a default value of
- # +nil+).
+ # Shortcut for creating several attributes at once (each with a default
+ # value of +nil+).
+
def self.attributes(*args)
args.each do |arg|
attribute(arg, nil)
end
end
- # Some attributes require special behaviour when they are accessed. This allows for
- # that.
+ ##
+ # Some attributes require special behaviour when they are accessed. This
+ # allows for that.
+
def self.overwrite_accessor(name, &block)
remove_method name
define_method(name, &block)
end
- # Defines a _singular_ version of an existing _plural_ attribute
- # (i.e. one whose value is expected to be an array). This means
- # just creating a helper method that takes a single value and
- # appends it to the array. These are created for convenience, so
- # that in a spec, one can write
+ ##
+ # Defines a _singular_ version of an existing _plural_ attribute (i.e. one
+ # whose value is expected to be an array). This means just creating a
+ # helper method that takes a single value and appends it to the array.
+ # These are created for convenience, so that in a spec, one can write
#
# s.require_path = 'mylib'
#
- # instead of
+ # instead of:
#
# s.require_paths = ['mylib']
#
- # That above convenience is available courtesy of
+ # That above convenience is available courtesy of:
#
# attribute_alias_singular :require_path, :require_paths
- #
+
def self.attribute_alias_singular(singular, plural)
define_method("#{singular}=") { |val|
send("#{plural}=", [val])
@@ -320,189 +351,45 @@ module Gem
spec
end
- # REQUIRED gemspec attributes ------------------------------------
-
- required_attribute :rubygems_version, Gem::RubyGemsVersion
- required_attribute :specification_version, CURRENT_SPECIFICATION_VERSION
- required_attribute :name
- required_attribute :version
- required_attribute :date, TODAY
- required_attribute :summary
- required_attribute :require_paths, ['lib']
-
- # OPTIONAL gemspec attributes ------------------------------------
-
- attributes :email, :homepage, :rubyforge_project, :description
- attributes :autorequire, :default_executable
-
- attribute :bindir, 'bin'
- attribute :has_rdoc, false
- attribute :required_ruby_version, Gem::Requirement.default
- attribute :required_rubygems_version, Gem::Requirement.default
- attribute :platform, Gem::Platform::RUBY
-
- attribute :signing_key, nil
- attribute :cert_chain, []
- attribute :post_install_message, nil
-
- array_attribute :authors
- array_attribute :files
- array_attribute :test_files
- array_attribute :rdoc_options
- array_attribute :extra_rdoc_files
- array_attribute :executables
-
- # Array of extensions to build. See Gem::Installer#build_extensions for
- # valid values.
-
- array_attribute :extensions
- array_attribute :requirements
- array_attribute :dependencies
-
- read_only :dependencies
+ ##
+ # List of depedencies that will automatically be activated at runtime.
def runtime_dependencies
dependencies.select { |d| d.type == :runtime || d.type == nil }
end
+ ##
+ # List of dependencies that are used for development
+
def development_dependencies
dependencies.select { |d| d.type == :development }
end
- # ALIASED gemspec attributes -------------------------------------
-
- attribute_alias_singular :executable, :executables
- attribute_alias_singular :author, :authors
- attribute_alias_singular :require_path, :require_paths
- attribute_alias_singular :test_file, :test_files
-
- # DEPRECATED gemspec attributes ----------------------------------
-
- def test_suite_file
+ def test_suite_file # :nodoc:
warn 'test_suite_file deprecated, use test_files'
test_files.first
end
- def test_suite_file=(val)
+ def test_suite_file=(val) # :nodoc:
warn 'test_suite_file= deprecated, use test_files='
@test_files = [] unless defined? @test_files
@test_files << val
end
+ ##
# true when this gemspec has been loaded from a specifications directory.
# This attribute is not persisted.
- attr_writer :loaded
+ attr_accessor :loaded
+ ##
# Path this gemspec was loaded from. This attribute is not persisted.
- attr_accessor :loaded_from
-
- # Special accessor behaviours (overwriting default) --------------
-
- overwrite_accessor :version= do |version|
- @version = Version.create(version)
- end
-
- overwrite_accessor :platform do
- @new_platform
- end
-
- overwrite_accessor :platform= do |platform|
- if @original_platform.nil? or
- @original_platform == Gem::Platform::RUBY then
- @original_platform = platform
- end
-
- case platform
- when Gem::Platform::CURRENT then
- @new_platform = Gem::Platform.local
- @original_platform = @new_platform.to_s
-
- when Gem::Platform then
- @new_platform = platform
-
- # legacy constants
- when nil, Gem::Platform::RUBY then
- @new_platform = Gem::Platform::RUBY
- when 'mswin32' then # was Gem::Platform::WIN32
- @new_platform = Gem::Platform.new 'x86-mswin32'
- when 'i586-linux' then # was Gem::Platform::LINUX_586
- @new_platform = Gem::Platform.new 'x86-linux'
- when 'powerpc-darwin' then # was Gem::Platform::DARWIN
- @new_platform = Gem::Platform.new 'ppc-darwin'
- else
- @new_platform = Gem::Platform.new platform
- end
-
- @platform = @new_platform.to_s
-
- @new_platform
- end
-
- overwrite_accessor :required_ruby_version= do |value|
- @required_ruby_version = Gem::Requirement.create(value)
- end
-
- overwrite_accessor :required_rubygems_version= do |value|
- @required_rubygems_version = Gem::Requirement.create(value)
- end
-
- overwrite_accessor :date= do |date|
- # We want to end up with a Time object with one-day resolution.
- # This is the cleanest, most-readable, faster-than-using-Date
- # way to do it.
- case date
- when String then
- @date = if /\A(\d{4})-(\d{2})-(\d{2})\Z/ =~ date then
- Time.local($1.to_i, $2.to_i, $3.to_i)
- else
- require 'time'
- Time.parse date
- end
- when Time then
- @date = Time.local(date.year, date.month, date.day)
- when Date then
- @date = Time.local(date.year, date.month, date.day)
- else
- @date = TODAY
- end
- end
- overwrite_accessor :date do
- self.date = nil if @date.nil? # HACK Sets the default value for date
- @date
- end
-
- overwrite_accessor :summary= do |str|
- @summary = if str then
- str.strip.
- gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').
- gsub(/\n[ \t]*/, " ")
- end
- end
-
- overwrite_accessor :description= do |str|
- @description = if str then
- str.strip.
- gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').
- gsub(/\n[ \t]*/, " ")
- end
- end
+ attr_accessor :loaded_from
- overwrite_accessor :default_executable do
- begin
- if defined?(@default_executable) and @default_executable
- result = @default_executable
- elsif @executables and @executables.size == 1
- result = Array(@executables).first
- else
- result = nil
- end
- result
- rescue
- nil
- end
- end
+ ##
+ # Returns an array with bindir attached to each executable in the
+ # executables list
def add_bindir(executables)
return nil if executables.nil?
@@ -516,17 +403,9 @@ module Gem
return nil
end
- overwrite_accessor :files do
- result = []
- result.push(*@files) if defined?(@files)
- result.push(*@test_files) if defined?(@test_files)
- result.push(*(add_bindir(@executables)))
- result.push(*@extra_rdoc_files) if defined?(@extra_rdoc_files)
- result.push(*@extensions) if defined?(@extensions)
- result.uniq.compact
- end
-
+ ##
# Files in the Gem under one of the require_paths
+
def lib_files
@files.select do |file|
require_paths.any? do |path|
@@ -535,34 +414,25 @@ module Gem
end
end
- overwrite_accessor :test_files do
- # Handle the possibility that we have @test_suite_file but not
- # @test_files. This will happen when an old gem is loaded via
- # YAML.
- if defined? @test_suite_file then
- @test_files = [@test_suite_file].flatten
- @test_suite_file = nil
- end
- if defined?(@test_files) and @test_files then
- @test_files
- else
- @test_files = []
- end
+ ##
+ # True if this gem was loaded from disk
+
+ alias :loaded? :loaded
+
+ ##
+ # True if this gem has files in test_files
+
+ def has_unit_tests?
+ not test_files.empty?
end
- # Predicates -----------------------------------------------------
-
- def loaded?; @loaded ? true : false ; end
- def has_rdoc?; has_rdoc ? true : false ; end
- def has_unit_tests?; not test_files.empty?; end
- alias has_test_suite? has_unit_tests? # (deprecated)
-
- # Constructors ---------------------------------------------------
+ alias has_test_suite? has_unit_tests? # :nodoc: deprecated
+ ##
# Specification constructor. Assigns the default values to the
# attributes, adds this spec to the list of loaded specs (see
# Specification.list), and yields itself for further initialization.
- #
+
def initialize
@new_platform = nil
assign_defaults
@@ -575,11 +445,13 @@ module Gem
@@gather.call(self) if @@gather
end
- # Each attribute has a default value (possibly nil). Here, we
- # initialize all attributes to their default value. This is
- # done through the accessor methods, so special behaviours will
- # be honored. Furthermore, we take a _copy_ of the default so
- # each specification instance has its own empty arrays, etc.
+ ##
+ # Each attribute has a default value (possibly nil). Here, we initialize
+ # all attributes to their default value. This is done through the
+ # accessor methods, so special behaviours will be honored. Furthermore,
+ # we take a _copy_ of the default so each specification instance has its
+ # own empty arrays, etc.
+
def assign_defaults
@@nil_attributes.each do |name|
instance_variable_set name, nil
@@ -598,13 +470,14 @@ module Gem
instance_variable_set :@new_platform, Gem::Platform::RUBY
end
- # Special loader for YAML files. When a Specification object is
- # loaded from a YAML file, it bypasses the normal Ruby object
- # initialization routine (#initialize). This method makes up for
- # that and deals with gems of different ages.
+ ##
+ # Special loader for YAML files. When a Specification object is loaded
+ # from a YAML file, it bypasses the normal Ruby object initialization
+ # routine (#initialize). This method makes up for that and deals with
+ # gems of different ages.
#
# 'input' can be anything that YAML.load() accepts: String or IO.
- #
+
def self.from_yaml(input)
input = normalize_yaml_input input
spec = YAML.load input
@@ -627,6 +500,9 @@ module Gem
spec
end
+ ##
+ # Loads ruby format gemspec from +filename+
+
def self.load(filename)
gemspec = nil
fail "NESTED Specification.load calls not allowed!" if @@gather
@@ -638,22 +514,25 @@ module Gem
@@gather = nil
end
- # Make sure the yaml specification is properly formatted with dashes.
+ ##
+ # Make sure the YAML specification is properly formatted with dashes
+
def self.normalize_yaml_input(input)
result = input.respond_to?(:read) ? input.read : input
result = "--- " + result unless result =~ /^--- /
result
end
- # Instance methods -----------------------------------------------
-
- # Sets the rubygems_version to Gem::RubyGemsVersion.
- #
+ ##
+ # Sets the rubygems_version to the current RubyGems version
+
def mark_version
@rubygems_version = RubyGemsVersion
end
- # Ignore unknown attributes if the
+ ##
+ # Ignore unknown attributes while loading
+
def method_missing(sym, *a, &b) # :nodoc:
if @specification_version > CURRENT_SPECIFICATION_VERSION and
sym.to_s =~ /=$/ then
@@ -663,35 +542,39 @@ module Gem
end
end
- # Adds a development dependency to this Gem. For example,
- #
- # spec.add_development_dependency('jabber4r', '> 0.1', '<= 0.5')
+ ##
+ # Adds a development dependency named +gem+ with +requirements+ to this
+ # Gem. For example:
#
- # Development dependencies aren't installed by default, and
- # aren't activated when a gem is required.
+ # spec.add_development_dependency 'jabber4r', '> 0.1', '<= 0.5'
#
- # gem:: [String or Gem::Dependency] The Gem name/dependency.
- # requirements:: [default=">= 0"] The version requirements.
+ # Development dependencies aren't installed by default and aren't
+ # activated when a gem is required.
+
def add_development_dependency(gem, *requirements)
add_dependency_with_type(gem, :development, *requirements)
end
- # Adds a runtime dependency to this Gem. For example,
- #
- # spec.add_runtime_dependency('jabber4r', '> 0.1', '<= 0.5')
+ ##
+ # Adds a runtime dependency named +gem+ with +requirements+ to this Gem.
+ # For example:
#
- # gem:: [String or Gem::Dependency] The Gem name/dependency.
- # requirements:: [default=">= 0"] The version requirements.
+ # spec.add_runtime_dependency 'jabber4r', '> 0.1', '<= 0.5'
+
def add_runtime_dependency(gem, *requirements)
add_dependency_with_type(gem, :runtime, *requirements)
end
+ ##
+ # Adds a runtime dependency
+
alias add_dependency add_runtime_dependency
+ ##
# Returns the full name (name-version) of this Gem. Platform information
- # is included (name-version-platform) if it is specified (and not the
- # default Ruby platform).
- #
+ # is included (name-version-platform) if it is specified and not the
+ # default Ruby platform.
+
def full_name
if platform == Gem::Platform::RUBY or platform.nil? then
"#{@name}-#{@version}"
@@ -700,9 +583,10 @@ module Gem
end
end
+ ##
# Returns the full name (name-version) of this gemspec using the original
- # platform.
- #
+ # platform. For use with legacy gems.
+
def original_name # :nodoc:
if platform == Gem::Platform::RUBY or platform.nil? then
"#{@name}-#{@version}"
@@ -736,18 +620,16 @@ module Gem
File.expand_path path
end
- # Checks if this Specification meets the requirement of the supplied
- # dependency.
- #
- # dependency:: [Gem::Dependency] the dependency to check
- # return:: [Boolean] true if dependency is met, otherwise false
- #
+ ##
+ # Checks if this specification meets the requirement of +dependency+.
+
def satisfies_requirement?(dependency)
return @name == dependency.name &&
dependency.version_requirements.satisfied_by?(@version)
end
- # Comparison methods ---------------------------------------------
+ ##
+ # Returns an object you can use to sort specifications in #sort_by.
def sort_obj
[@name, @version.to_ints, @new_platform == Gem::Platform::RUBY ? -1 : 1]
@@ -757,19 +639,25 @@ module Gem
sort_obj <=> other.sort_obj
end
+ ##
# Tests specs for equality (across all attributes).
+
def ==(other) # :nodoc:
self.class === other && same_attributes?(other)
end
alias eql? == # :nodoc:
+ ##
+ # True if this gem has the same attributes as +other+.
+
def same_attributes?(other)
@@attributes.each do |name, default|
return false unless self.send(name) == other.send(name)
end
true
end
+
private :same_attributes?
def hash # :nodoc:
@@ -779,8 +667,6 @@ module Gem
}
end
- # Export methods (YAML and Ruby code) ----------------------------
-
def to_yaml(opts = {}) # :nodoc:
mark_version
@@ -825,6 +711,8 @@ module Gem
def to_ruby
mark_version
result = []
+ result << "# -*- encoding: utf-8 -*-"
+ result << nil
result << "Gem::Specification.new do |s|"
result << " s.name = #{ruby_code name}"
@@ -861,7 +749,7 @@ module Gem
result << " s.specification_version = #{specification_version}"
result << nil
- result << " if current_version >= 3 then"
+ result << " if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then"
unless dependencies.empty? then
dependencies.each do |dep|
@@ -895,16 +783,15 @@ module Gem
result.join "\n"
end
- # Validation and normalization methods ---------------------------
-
- # Checks that the specification contains all required fields, and
- # does a very basic sanity check.
+ ##
+ # Checks that the specification contains all required fields, and does a
+ # very basic sanity check.
#
- # Raises InvalidSpecificationException if the spec does not pass
- # the checks..
+ # Raises InvalidSpecificationException if the spec does not pass the
+ # checks..
+
def validate
extend Gem::UserInteraction
-
normalize
if rubygems_version != RubyGemsVersion then
@@ -959,13 +846,14 @@ module Gem
true
end
+ ##
# Normalize the list of files so that:
# * All file lists have redundancies removed.
- # * Files referenced in the extra_rdoc_files are included in the
- # package file list.
+ # * Files referenced in the extra_rdoc_files are included in the package
+ # file list.
#
- # Also, the summary and description are converted to a normal
- # format.
+ # Also, the summary and description are converted to a normal format.
+
def normalize
if defined?(@extra_rdoc_files) and @extra_rdoc_files then
@extra_rdoc_files.uniq!
@@ -975,15 +863,12 @@ module Gem
@files.uniq! if @files
end
- # Dependency methods ---------------------------------------------
-
- # Return a list of all gems that have a dependency on this
- # gemspec. The list is structured with entries that conform to:
+ ##
+ # Return a list of all gems that have a dependency on this gemspec. The
+ # list is structured with entries that conform to:
#
# [depending_gem, dependency, [list_of_gems_that_satisfy_dependency]]
- #
- # return:: [Array] [[dependent_gem, dependency, [list_of_satisfiers]]]
- #
+
def dependent_gems
out = []
Gem.source_index.each do |name,gem|
@@ -1004,8 +889,6 @@ module Gem
"#<Gem::Specification name=#{@name} version=#{@version}>"
end
- private
-
def add_dependency_with_type(dependency, type, *requirements)
requirements = if requirements.empty? then
Gem::Requirement.default
@@ -1022,6 +905,8 @@ module Gem
dependencies << dependency
end
+ private :add_dependency_with_type
+
def find_all_satisfiers(dep)
Gem.source_index.each do |name,gem|
if(gem.satisfies_requirement?(dep)) then
@@ -1030,8 +915,12 @@ module Gem
end
end
- # Return a string containing a Ruby code representation of the
- # given object.
+ private :find_all_satisfiers
+
+ ##
+ # Return a string containing a Ruby code representation of the given
+ # object.
+
def ruby_code(obj)
case obj
when String then '%q{' + obj + '}'
@@ -1046,6 +935,326 @@ module Gem
else raise Exception, "ruby_code case not handled: #{obj.class}"
end
end
+
+ private :ruby_code
+
+ # :section: Required gemspec attributes
+
+ ##
+ # The version of RubyGems used to create this gem
+
+ required_attribute :rubygems_version, Gem::RubyGemsVersion
+
+ ##
+ # The Gem::Specification version of this gemspec
+
+ required_attribute :specification_version, CURRENT_SPECIFICATION_VERSION
+
+ ##
+ # This gem's name
+
+ required_attribute :name
+
+ ##
+ # This gem's version
+
+ required_attribute :version
+
+ ##
+ # The date this gem was created
+
+ required_attribute :date, TODAY
+
+ ##
+ # A short summary of this gem's description. Displayed in `gem list -d`.
+
+ required_attribute :summary
+
+ ##
+ # Paths in the gem to add to $LOAD_PATH when this gem is activated
+
+ required_attribute :require_paths, ['lib']
+
+ # :section: Optional gemspec attributes
+
+ ##
+ # A contact email for this gem
+
+ attribute :email
+
+ ##
+ # The URL of this gem's home page
+
+ attribute :homepage
+
+ ##
+ # The rubyforge project this gem lives under. i.e. RubyGems'
+ # rubyforge_project is "rubygems".
+
+ attribute :rubyforge_project
+
+ ##
+ # A long description of this gem
+
+ attribute :description
+
+ ##
+ # Autorequire was used by old RubyGems to automatically require a file.
+ # It no longer is supported.
+
+ attribute :autorequire
+
+ ##
+ # The default executable for this gem.
+
+ attribute :default_executable
+
+ ##
+ # The path in the gem for executable scripts
+
+ attribute :bindir, 'bin'
+
+ ##
+ # True if this gem is RDoc-compliant
+
+ attribute :has_rdoc, false
+
+ ##
+ # True if this gem supports RDoc
+
+ alias :has_rdoc? :has_rdoc
+
+ ##
+ # The ruby of version required by this gem
+
+ attribute :required_ruby_version, Gem::Requirement.default
+
+ ##
+ # The RubyGems version required by this gem
+
+ attribute :required_rubygems_version, Gem::Requirement.default
+
+ ##
+ # The platform this gem runs on. See Gem::Platform for details.
+
+ attribute :platform, Gem::Platform::RUBY
+
+ ##
+ # The key used to sign this gem. See Gem::Security for details.
+
+ attribute :signing_key, nil
+
+ ##
+ # The certificate chain used to sign this gem. See Gem::Security for
+ # details.
+
+ attribute :cert_chain, []
+
+ ##
+ # A message that gets displayed after the gem is installed
+
+ attribute :post_install_message, nil
+
+ ##
+ # The list of authors who wrote this gem
+
+ array_attribute :authors
+
+ ##
+ # Files included in this gem
+
+ array_attribute :files
+
+ ##
+ # Test files included in this gem
+
+ array_attribute :test_files
+
+ ##
+ # An ARGV-style array of options to RDoc
+
+ array_attribute :rdoc_options
+
+ ##
+ # Extra files to add to RDoc
+
+ array_attribute :extra_rdoc_files
+
+ ##
+ # Executables included in the gem
+
+ array_attribute :executables
+
+ ##
+ # Extensions to build when installing the gem. See
+ # Gem::Installer#build_extensions for valid values.
+
+ array_attribute :extensions
+
+ ##
+ # An array or things required by this gem. Not used by anything
+ # presently.
+
+ array_attribute :requirements
+
+ ##
+ # A list of Gem::Dependency objects this gem depends on. Only appendable.
+
+ array_attribute :dependencies
+
+ read_only :dependencies
+
+ # :section: Aliased gemspec attributes
+
+ ##
+ # Singular accessor for executables
+
+ attribute_alias_singular :executable, :executables
+
+ ##
+ # Singular accessor for authors
+
+ attribute_alias_singular :author, :authors
+
+ ##
+ # Singular accessor for require_paths
+
+ attribute_alias_singular :require_path, :require_paths
+
+ ##
+ # Singular accessor for test_files
+
+ attribute_alias_singular :test_file, :test_files
+
+ overwrite_accessor :version= do |version|
+ @version = Version.create(version)
+ end
+
+ overwrite_accessor :platform do
+ @new_platform
+ end
+
+ overwrite_accessor :platform= do |platform|
+ if @original_platform.nil? or
+ @original_platform == Gem::Platform::RUBY then
+ @original_platform = platform
+ end
+
+ case platform
+ when Gem::Platform::CURRENT then
+ @new_platform = Gem::Platform.local
+ @original_platform = @new_platform.to_s
+
+ when Gem::Platform then
+ @new_platform = platform
+
+ # legacy constants
+ when nil, Gem::Platform::RUBY then
+ @new_platform = Gem::Platform::RUBY
+ when 'mswin32' then # was Gem::Platform::WIN32
+ @new_platform = Gem::Platform.new 'x86-mswin32'
+ when 'i586-linux' then # was Gem::Platform::LINUX_586
+ @new_platform = Gem::Platform.new 'x86-linux'
+ when 'powerpc-darwin' then # was Gem::Platform::DARWIN
+ @new_platform = Gem::Platform.new 'ppc-darwin'
+ else
+ @new_platform = Gem::Platform.new platform
+ end
+
+ @platform = @new_platform.to_s
+
+ @new_platform
+ end
+
+ overwrite_accessor :required_ruby_version= do |value|
+ @required_ruby_version = Gem::Requirement.create(value)
+ end
+
+ overwrite_accessor :required_rubygems_version= do |value|
+ @required_rubygems_version = Gem::Requirement.create(value)
+ end
+
+ overwrite_accessor :date= do |date|
+ # We want to end up with a Time object with one-day resolution.
+ # This is the cleanest, most-readable, faster-than-using-Date
+ # way to do it.
+ case date
+ when String then
+ @date = if /\A(\d{4})-(\d{2})-(\d{2})\Z/ =~ date then
+ Time.local($1.to_i, $2.to_i, $3.to_i)
+ else
+ require 'time'
+ Time.parse date
+ end
+ when Time then
+ @date = Time.local(date.year, date.month, date.day)
+ when Date then
+ @date = Time.local(date.year, date.month, date.day)
+ else
+ @date = TODAY
+ end
+ end
+
+ overwrite_accessor :date do
+ self.date = nil if @date.nil? # HACK Sets the default value for date
+ @date
+ end
+
+ overwrite_accessor :summary= do |str|
+ @summary = if str then
+ str.strip.
+ gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').
+ gsub(/\n[ \t]*/, " ")
+ end
+ end
+
+ overwrite_accessor :description= do |str|
+ @description = if str then
+ str.strip.
+ gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').
+ gsub(/\n[ \t]*/, " ")
+ end
+ end
+
+ overwrite_accessor :default_executable do
+ begin
+ if defined?(@default_executable) and @default_executable
+ result = @default_executable
+ elsif @executables and @executables.size == 1
+ result = Array(@executables).first
+ else
+ result = nil
+ end
+ result
+ rescue
+ nil
+ end
+ end
+
+ overwrite_accessor :test_files do
+ # Handle the possibility that we have @test_suite_file but not
+ # @test_files. This will happen when an old gem is loaded via
+ # YAML.
+ if defined? @test_suite_file then
+ @test_files = [@test_suite_file].flatten
+ @test_suite_file = nil
+ end
+ if defined?(@test_files) and @test_files then
+ @test_files
+ else
+ @test_files = []
+ end
+ end
+
+ overwrite_accessor :files do
+ result = []
+ result.push(*@files) if defined?(@files)
+ result.push(*@test_files) if defined?(@test_files)
+ result.push(*(add_bindir(@executables)))
+ result.push(*@extra_rdoc_files) if defined?(@extra_rdoc_files)
+ result.push(*@extensions) if defined?(@extensions)
+ result.uniq.compact
+ end
end
diff --git a/lib/rubygems/test_utilities.rb b/lib/rubygems/test_utilities.rb
index e8709b9be3..8b23d3236e 100644
--- a/lib/rubygems/test_utilities.rb
+++ b/lib/rubygems/test_utilities.rb
@@ -34,16 +34,20 @@ class Gem::FakeFetcher
path = path.to_s
@paths << path
raise ArgumentError, 'need full URI' unless path =~ %r'^http://'
- data = @data[path]
- if data.nil? then
- raise Gem::RemoteFetcher::FetchError.new('no data', path)
+ unless @data.key? path then
+ raise Gem::RemoteFetcher::FetchError.new("no data for #{path}", path)
end
+ data = @data[path]
+
if data.respond_to?(:call) then
data.call
else
- data = Gem.gunzip data if path.to_s =~ /gz$/ unless data.empty?
+ if path.to_s =~ /gz$/ and not data.nil? and not data.empty? then
+ data = Gem.gunzip data
+ end
+
data
end
end
@@ -51,13 +55,15 @@ class Gem::FakeFetcher
def fetch_size(path)
path = path.to_s
@paths << path
+
raise ArgumentError, 'need full URI' unless path =~ %r'^http://'
- data = @data[path]
- if data.nil? then
- raise Gem::RemoteFetcher::FetchError.new("no data for #{path}", nil)
+ unless @data.key? path then
+ raise Gem::RemoteFetcher::FetchError.new("no data for #{path}", path)
end
+ data = @data[path]
+
data.respond_to?(:call) ? data.call : data.length
end
diff --git a/lib/rubygems/uninstaller.rb b/lib/rubygems/uninstaller.rb
index 2ad961972b..5f19da5e82 100644
--- a/lib/rubygems/uninstaller.rb
+++ b/lib/rubygems/uninstaller.rb
@@ -18,9 +18,23 @@ class Gem::Uninstaller
include Gem::UserInteraction
##
- # Constructs an Uninstaller instance
- #
- # gem:: [String] The Gem name to uninstall
+ # The directory a gem's executables will be installed into
+
+ attr_reader :bin_dir
+
+ ##
+ # The gem repository the gem will be installed into
+
+ attr_reader :gem_home
+
+ ##
+ # The Gem::Specification for the gem being uninstalled, only set during
+ # #uninstall_gem
+
+ attr_reader :spec
+
+ ##
+ # Constructs an uninstaller that will uninstall +gem+
def initialize(gem, options = {})
@gem = gem
@@ -31,42 +45,63 @@ class Gem::Uninstaller
@force_all = options[:all]
@force_ignore = options[:ignore]
@bin_dir = options[:bin_dir]
+
+ spec_dir = File.join @gem_home, 'specifications'
+ @source_index = Gem::SourceIndex.from_gems_in spec_dir
end
##
- # Performs the uninstall of the Gem. This removes the spec, the
- # Gem directory, and the cached .gem file,
+ # Performs the uninstall of the gem. This removes the spec, the Gem
+ # directory, and the cached .gem file.
def uninstall
- list = Gem.source_index.search(/^#{@gem}$/, @version)
+ list = @source_index.find_name @gem, @version
if list.empty? then
raise Gem::InstallError, "Unknown gem #{@gem} #{@version}"
- elsif list.size > 1 && @force_all
- remove_all(list.dup)
- remove_executables(list.last)
- elsif list.size > 1
- say
+
+ elsif list.size > 1 and @force_all then
+ remove_all list.dup
+
+ elsif list.size > 1 then
gem_names = list.collect {|gem| gem.full_name} + ["All versions"]
- gem_name, index =
- choose_from_list("Select gem to uninstall:", gem_names)
- if index == list.size
- remove_all(list.dup)
- remove_executables(list.last)
- elsif index >= 0 && index < list.size
- to_remove = list[index]
- remove(to_remove, list)
- remove_executables(to_remove)
+
+ say
+ gem_name, index = choose_from_list "Select gem to uninstall:", gem_names
+
+ if index == list.size then
+ remove_all list.dup
+ elsif index >= 0 && index < list.size then
+ uninstall_gem list[index], list.dup
else
say "Error: must enter a number [1-#{list.size+1}]"
end
else
- remove(list[0], list.dup)
- remove_executables(list.last)
+ uninstall_gem list.first, list.dup
end
end
##
+ # Uninstalls gem +spec+
+
+ def uninstall_gem(spec, specs)
+ @spec = spec
+
+ Gem.pre_uninstall_hooks.each do |hook|
+ hook.call self
+ end
+
+ specs.each { |s| remove_executables s }
+ remove spec, specs
+
+ Gem.post_uninstall_hooks.each do |hook|
+ hook.call self
+ end
+
+ @spec = nil
+ end
+
+ ##
# Removes installed executables and batch files (windows only) for
# +gemspec+.
@@ -76,7 +111,7 @@ class Gem::Uninstaller
if gemspec.executables.size > 0 then
bindir = @bin_dir ? @bin_dir : (Gem.bindir @gem_home)
- list = Gem.source_index.search(gemspec.name).delete_if { |spec|
+ list = @source_index.find_name(gemspec.name).delete_if { |spec|
spec.version == gemspec.version
}
@@ -118,7 +153,7 @@ class Gem::Uninstaller
# NOTE: removes uninstalled gems from +list+.
def remove_all(list)
- list.dup.each { |spec| remove spec, list }
+ list.dup.each { |spec| uninstall_gem spec, list }
end
##
@@ -185,8 +220,7 @@ class Gem::Uninstaller
def dependencies_ok?(spec)
return true if @force_ignore
- source_index = Gem::SourceIndex.from_installed_gems
- deplist = Gem::DependencyList.from_source_index source_index
+ deplist = Gem::DependencyList.from_source_index @source_index
deplist.ok_to_remove?(spec.full_name) || ask_if_ok(spec)
end