summaryrefslogtreecommitdiff
path: root/lib/rubygems
diff options
context:
space:
mode:
authorryan <ryan@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2011-03-01 09:41:32 +0000
committerryan <ryan@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2011-03-01 09:41:32 +0000
commit25a9b62d45ddd60a231272567c7dda9337da9b62 (patch)
treee72ba4c9c01cba5fb510eb1eafaba76d998baf4c /lib/rubygems
parent86bb0af7ea3b50f72e6845a6f5f64cb1b23fd279 (diff)
Import rubygems 1.6.0 (released version @ 58d8a0b9)
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@30996 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/rubygems')
-rw-r--r--lib/rubygems/commands/owner_command.rb5
-rw-r--r--lib/rubygems/commands/pristine_command.rb8
-rw-r--r--lib/rubygems/commands/push_command.rb12
-rw-r--r--lib/rubygems/commands/setup_command.rb11
-rw-r--r--lib/rubygems/commands/uninstall_command.rb5
-rw-r--r--lib/rubygems/commands/unpack_command.rb26
-rw-r--r--lib/rubygems/commands/update_command.rb137
-rw-r--r--lib/rubygems/config_file.rb17
-rw-r--r--lib/rubygems/custom_require.rb19
-rw-r--r--lib/rubygems/dependency.rb41
-rw-r--r--lib/rubygems/dependency_installer.rb27
-rw-r--r--lib/rubygems/dependency_list.rb38
-rw-r--r--lib/rubygems/doc_manager.rb9
-rw-r--r--lib/rubygems/gem_path_searcher.rb46
-rw-r--r--lib/rubygems/gemcutter_utilities.rb31
-rw-r--r--lib/rubygems/installer.rb18
-rw-r--r--lib/rubygems/installer_test_case.rb38
-rw-r--r--lib/rubygems/package/tar_reader/entry.rb3
-rw-r--r--lib/rubygems/remote_fetcher.rb39
-rw-r--r--lib/rubygems/requirement.rb5
-rw-r--r--lib/rubygems/security.rb1
-rw-r--r--lib/rubygems/source_index.rb5
-rw-r--r--lib/rubygems/spec_fetcher.rb6
-rw-r--r--lib/rubygems/specification.rb83
-rw-r--r--lib/rubygems/test_case.rb155
-rw-r--r--lib/rubygems/test_utilities.rb12
-rw-r--r--lib/rubygems/uninstaller.rb33
-rw-r--r--lib/rubygems/user_interaction.rb53
-rw-r--r--lib/rubygems/validator.rb2
29 files changed, 630 insertions, 255 deletions
diff --git a/lib/rubygems/commands/owner_command.rb b/lib/rubygems/commands/owner_command.rb
index 8b770e6f54..34f4efaa59 100644
--- a/lib/rubygems/commands/owner_command.rb
+++ b/lib/rubygems/commands/owner_command.rb
@@ -23,6 +23,7 @@ class Gem::Commands::OwnerCommand < Gem::Command
def initialize
super 'owner', description
add_proxy_option
+ add_key_option
defaults.merge! :add => [], :remove => []
add_option '-a', '--add EMAIL', 'Add an owner' do |value, options|
@@ -45,7 +46,7 @@ class Gem::Commands::OwnerCommand < Gem::Command
def show_owners name
response = rubygems_api_request :get, "api/v1/gems/#{name}/owners.yaml" do |request|
- request.add_field "Authorization", Gem.configuration.rubygems_api_key
+ request.add_field "Authorization", api_key
end
with_response response do |resp|
@@ -70,7 +71,7 @@ class Gem::Commands::OwnerCommand < Gem::Command
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", Gem.configuration.rubygems_api_key
+ request.add_field "Authorization", api_key
end
with_response response
diff --git a/lib/rubygems/commands/pristine_command.rb b/lib/rubygems/commands/pristine_command.rb
index 64ea8ce91c..9a0b2e9f11 100644
--- a/lib/rubygems/commands/pristine_command.rb
+++ b/lib/rubygems/commands/pristine_command.rb
@@ -79,11 +79,13 @@ revert the gem.
say "Restoring gem(s) to pristine condition..."
specs.each do |spec|
- gem = Dir[File.join(Gem.dir, 'cache', spec.file_name)].first
+ gem = spec.cache_gem
if gem.nil? then
- alert_error "Cached gem for #{spec.full_name} not found, use `gem install` to restore"
- next
+ say "Cached gem for #{spec.full_name} not found, attempting to fetch..."
+ dep = Gem::Dependency.new spec.name, spec.version
+ Gem::RemoteFetcher.fetcher.download_to_cache dep
+ gem = spec.cache_gem
end
# TODO use installer options
diff --git a/lib/rubygems/commands/push_command.rb b/lib/rubygems/commands/push_command.rb
index e72b74ebbf..c85a259564 100644
--- a/lib/rubygems/commands/push_command.rb
+++ b/lib/rubygems/commands/push_command.rb
@@ -27,7 +27,8 @@ class Gem::Commands::PushCommand < Gem::Command
def initialize
super 'push', description
add_proxy_option
-
+ add_key_option
+
add_option(
'--host HOST',
'Push to another gemcutter-compatible host'
@@ -42,17 +43,20 @@ class Gem::Commands::PushCommand < Gem::Command
end
def send_gem name
- say "Pushing gem to #{options[:host] || Gem.host}..."
-
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
+
response = rubygems_api_request(*args) do |request|
request.body = Gem.read_binary name
request.add_field "Content-Length", request.body.size
request.add_field "Content-Type", "application/octet-stream"
- request.add_field "Authorization", Gem.configuration.rubygems_api_key
+ request.add_field "Authorization", api_key
end
with_response response
diff --git a/lib/rubygems/commands/setup_command.rb b/lib/rubygems/commands/setup_command.rb
index f40733a3ed..9090353e3b 100644
--- a/lib/rubygems/commands/setup_command.rb
+++ b/lib/rubygems/commands/setup_command.rb
@@ -33,13 +33,7 @@ class Gem::Commands::SetupCommand < Gem::Command
end
add_option '--[no-]vendor',
- 'Install into vendorlibdir not sitelibdir',
- '(Requires Ruby 1.8.7)' do |vendor, options|
- if vendor and Gem.ruby_version < Gem::Version.new('1.8.7') then
- raise OptionParser::InvalidOption,
- "requires ruby 1.8.7+ (you have #{Gem.ruby_version})"
- end
-
+ 'Install into vendorlibdir not sitelibdir' do |vendor, options|
options[:site_or_vendor] = vendor ? :vendorlibdir : :sitelibdir
end
@@ -61,7 +55,7 @@ class Gem::Commands::SetupCommand < Gem::Command
end
def check_ruby_version
- required_version = Gem::Requirement.new '>= 1.8.6'
+ required_version = Gem::Requirement.new '>= 1.8.7'
unless required_version.satisfied_by? Gem.ruby_version then
alert_error "Expected Ruby version #{required_version}, is #{Gem.ruby_version}"
@@ -341,7 +335,6 @@ abort "#{deprecation_message}"
require 'rdoc/rdoc'
- args << '--quiet'
args << '--main' << 'README.rdoc'
args << '.'
args << 'README.rdoc' << 'UPGRADING.rdoc'
diff --git a/lib/rubygems/commands/uninstall_command.rb b/lib/rubygems/commands/uninstall_command.rb
index 52d5b03edb..d190777825 100644
--- a/lib/rubygems/commands/uninstall_command.rb
+++ b/lib/rubygems/commands/uninstall_command.rb
@@ -55,6 +55,11 @@ class Gem::Commands::UninstallCommand < Gem::Command
options[:user_install] = value
end
+ add_option('--[no-]format-executable',
+ 'Assume executable names match Ruby\'s prefix and suffix.') do |value, options|
+ options[:format_executable] = value
+ end
+
add_version_option
add_platform_option
end
diff --git a/lib/rubygems/commands/unpack_command.rb b/lib/rubygems/commands/unpack_command.rb
index ac1d376106..ef0d65e073 100644
--- a/lib/rubygems/commands/unpack_command.rb
+++ b/lib/rubygems/commands/unpack_command.rb
@@ -7,6 +7,7 @@
require 'rubygems/command'
require 'rubygems/installer'
require 'rubygems/version_option'
+require 'rubygems/remote_fetcher'
class Gem::Commands::UnpackCommand < Gem::Command
@@ -39,16 +40,6 @@ class Gem::Commands::UnpackCommand < Gem::Command
"#{program_name} GEMNAME"
end
- def download dependency
- found = Gem::SpecFetcher.fetcher.fetch dependency
-
- return if found.empty?
-
- spec, source_uri = found.first
-
- Gem::RemoteFetcher.fetcher.download spec, source_uri
- end
-
#--
# TODO: allow, e.g., 'gem unpack rake-0.3.1'. Find a general solution for
# this, so that it works for uninstall as well. (And check other commands
@@ -79,8 +70,9 @@ class Gem::Commands::UnpackCommand < Gem::Command
# TODO: see comments in get_path() about general service.
def find_in_cache(filename)
- Gem.path.each do |gem_dir|
- this_path = File.join gem_dir, 'cache', filename
+
+ Gem.path.each do |path|
+ this_path = Gem.cache_gem(filename, path)
return this_path if File.exist? this_path
end
@@ -111,15 +103,17 @@ class Gem::Commands::UnpackCommand < Gem::Command
selected = specs.sort_by { |s| s.version }.last
- return download(dependency) if selected.nil?
+ return Gem::RemoteFetcher.fetcher.download_to_cache(dependency) unless
+ selected
return unless dependency.name =~ /^#{selected.name}$/i
# We expect to find (basename).gem in the 'cache' directory. Furthermore,
# the name match must be exact (ignoring case).
-
- path = find_in_cache(selected.file_name)
- return download(dependency) unless path
+
+ path = find_in_cache selected.file_name
+
+ return Gem::RemoteFetcher.fetcher.download_to_cache(dependency) unless path
path
end
diff --git a/lib/rubygems/commands/update_command.rb b/lib/rubygems/commands/update_command.rb
index b2f69a5b52..b7c65eb2a4 100644
--- a/lib/rubygems/commands/update_command.rb
+++ b/lib/rubygems/commands/update_command.rb
@@ -27,8 +27,16 @@ class Gem::Commands::UpdateCommand < Gem::Command
add_install_update_options
- add_option('--system',
+ OptionParser.accept Gem::Version do |value|
+ Gem::Version.new value
+
+ value
+ end
+
+ add_option('--system [VERSION]', Gem::Version,
'Update the RubyGems system software') do |value, options|
+ value = true unless value
+
options[:system] = value
end
@@ -50,33 +58,13 @@ class Gem::Commands::UpdateCommand < Gem::Command
end
def execute
+ @installer = Gem::DependencyInstaller.new options
+ @updated = []
+
hig = {}
if options[:system] then
- say "Updating RubyGems"
-
- unless options[:args].empty? then
- raise "No gem names are allowed with the --system option"
- end
-
- rubygems_update = Gem::Specification.new
- rubygems_update.name = 'rubygems-update'
- rubygems_update.version = Gem::Version.new Gem::VERSION
- hig['rubygems-update'] = rubygems_update
-
- options[:user_install] = false
-
- Gem.source_index.refresh!
-
- update_gems = Gem.source_index.find_name 'rubygems-update'
-
- latest_update_gem = update_gems.sort_by { |s| s.version }.last
-
- say "Updating RubyGems to #{latest_update_gem.version}"
- installed = do_rubygems_update latest_update_gem.version
-
- say "RubyGems system software updated" if installed
-
+ update_rubygems
return
else
say "Updating installed gems"
@@ -92,28 +80,7 @@ class Gem::Commands::UpdateCommand < Gem::Command
gems_to_update = which_to_update hig, options[:args]
- updated = []
-
- installer = Gem::DependencyInstaller.new options
-
- gems_to_update.uniq.sort.each do |name|
- next if updated.any? { |spec| spec.name == name }
- success = false
-
- say "Updating #{name}"
- begin
- installer.install name
- success = true
- rescue Gem::InstallError => e
- alert_error "Error installing #{name}:\n\t#{e.message}"
- success = false
- end
-
- installer.installed_gems.each do |spec|
- updated << spec
- say "Successfully installed #{spec.full_name}" if success
- end
- end
+ updated = update_gems gems_to_update
if updated.empty? then
say "Nothing to update"
@@ -136,12 +103,77 @@ class Gem::Commands::UpdateCommand < Gem::Command
end
end
+ def update_gem name, version = Gem::Requirement.default
+ return if @updated.any? { |spec| spec.name == name }
+ success = false
+
+ say "Updating #{name}"
+ begin
+ @installer.install name, version
+ success = true
+ rescue Gem::InstallError => e
+ alert_error "Error installing #{name}:\n\t#{e.message}"
+ success = false
+ end
+
+ @installer.installed_gems.each do |spec|
+ @updated << spec
+ say "Successfully installed #{spec.full_name}" if success
+ end
+ end
+
+ def update_gems gems_to_update
+ gems_to_update.uniq.sort.each do |name|
+ update_gem name
+ end
+
+ @updated
+ end
+
##
- # Update the RubyGems software to +version+.
+ # Update RubyGems software to the latest version.
+
+ def update_rubygems
+ unless options[:args].empty? then
+ alert_error "Gem names are not allowed with the --system option"
+ terminate_interaction 1
+ end
+
+ options[:user_install] = false
+
+ version = options[:system]
+ if version == true then
+ version = Gem::Version.new Gem::VERSION
+ requirement = Gem::Requirement.new ">= #{Gem::VERSION}"
+ else
+ version = Gem::Version.new version
+ requirement = Gem::Requirement.new version
+ end
+
+ rubygems_update = Gem::Specification.new
+ rubygems_update.name = 'rubygems-update'
+ rubygems_update.version = version
+
+ hig = {
+ 'rubygems-update' => rubygems_update
+ }
+
+ gems_to_update = which_to_update hig, options[:args]
+
+ if gems_to_update.empty? then
+ say "Latest version currently installed. Aborting."
+ terminate_interaction
+ end
+
+ update_gem gems_to_update.first, requirement
+
+ Gem.source_index.refresh!
+
+ installed_gems = Gem.source_index.find_name 'rubygems-update', requirement
+ version = installed_gems.last.version
- def do_rubygems_update(version)
args = []
- args.push '--prefix', Gem.prefix unless Gem.prefix.nil?
+ args << '--prefix' << Gem.prefix if Gem.prefix
args << '--no-rdoc' unless options[:generate_rdoc]
args << '--no-ri' unless options[:generate_ri]
args << '--no-format-executable' if options[:no_format_executable]
@@ -154,8 +186,9 @@ class Gem::Commands::UpdateCommand < Gem::Command
# Make sure old rubygems isn't loaded
old = ENV["RUBYOPT"]
- ENV.delete("RUBYOPT")
- system setup_cmd
+ ENV.delete("RUBYOPT") if old
+ installed = system setup_cmd
+ say "RubyGems system software updated" if installed
ENV["RUBYOPT"] = old if old
end
end
diff --git a/lib/rubygems/config_file.rb b/lib/rubygems/config_file.rb
index f3593999d3..1d16cd90ce 100644
--- a/lib/rubygems/config_file.rb
+++ b/lib/rubygems/config_file.rb
@@ -130,6 +130,11 @@ class Gem::ConfigFile
attr_reader :rubygems_api_key
##
+ # Hash of RubyGems.org and alternate API keys
+
+ attr_reader :api_keys
+
+ ##
# Create the config file object. +args+ is the list of arguments
# from the command line.
#
@@ -192,7 +197,7 @@ class Gem::ConfigFile
@update_sources = @hash[:update_sources] if @hash.key? :update_sources
@verbose = @hash[:verbose] if @hash.key? :verbose
- load_rubygems_api_key
+ load_api_keys
Gem.sources = @hash[:sources] if @hash.key? :sources
handle_arguments arg_list
@@ -205,10 +210,12 @@ class Gem::ConfigFile
File.join(Gem.user_home, '.gem', 'credentials')
end
- def load_rubygems_api_key
- api_key_hash = File.exists?(credentials_path) ? load_file(credentials_path) : @hash
-
- @rubygems_api_key = api_key_hash[:rubygems_api_key] if api_key_hash.key? :rubygems_api_key
+ def load_api_keys
+ @api_keys = File.exists?(credentials_path) ? load_file(credentials_path) : @hash
+ 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
+ end
end
def rubygems_api_key=(api_key)
diff --git a/lib/rubygems/custom_require.rb b/lib/rubygems/custom_require.rb
index 88e7aa4c4c..ebe7b05558 100644
--- a/lib/rubygems/custom_require.rb
+++ b/lib/rubygems/custom_require.rb
@@ -31,8 +31,23 @@ module Kernel
# The normal <tt>require</tt> functionality of returning false if
# that file has already been loaded is preserved.
- def require(path) # :doc:
- gem_original_require path
+ def require path
+ if Gem.unresolved_deps.empty? or Gem.loaded_path? path then
+ gem_original_require path
+ else
+ specs = Gem.searcher.find_in_unresolved path
+ unless specs.empty? then
+ specs = [specs.last]
+ else
+ specs = Gem.searcher.find_in_unresolved_tree path
+ end
+
+ specs.each do |spec|
+ Gem.activate spec.name, spec.version # FIX: this is dumb
+ end
+
+ return gem_original_require path
+ end
rescue LoadError => load_error
if load_error.message.end_with?(path) and Gem.try_activate(path) then
return gem_original_require(path)
diff --git a/lib/rubygems/dependency.rb b/lib/rubygems/dependency.rb
index 4c61b6563e..e4d1bfffe8 100644
--- a/lib/rubygems/dependency.rb
+++ b/lib/rubygems/dependency.rb
@@ -33,11 +33,6 @@ class Gem::Dependency
attr_writer :prerelease
##
- # Dependency type.
-
- attr_reader :type
-
- ##
# Constructs a dependency with +name+ and +requirements+. The last
# argument can optionally be the dependency type, which defaults to
# <tt>:runtime</tt>.
@@ -72,7 +67,7 @@ class Gem::Dependency
def inspect # :nodoc:
"<%s type=%p name=%p requirements=%p>" %
- [self.class, @type, @name, requirement.to_s]
+ [self.class, self.type, self.name, requirement.to_s]
end
##
@@ -132,7 +127,18 @@ class Gem::Dependency
end
def to_s # :nodoc:
- "#{name} (#{requirement}, #{type})"
+ if type != :runtime then
+ "#{name} (#{requirement}, #{type})"
+ else
+ "#{name} (#{requirement})"
+ end
+ end
+
+ ##
+ # Dependency type.
+
+ def type
+ @type ||= :runtime
end
def == other # :nodoc:
@@ -146,7 +152,7 @@ class Gem::Dependency
# Dependencies are ordered by name.
def <=> other
- @name <=> other.name
+ self.name <=> other.name
end
##
@@ -187,5 +193,24 @@ class Gem::Dependency
requirement.satisfied_by?(spec.version)
end
+ ##
+ # Merges the requirements of +other+ into this dependency
+
+ def merge other
+ unless name == other.name then
+ raise ArgumentError,
+ "#{self} and #{other} have different names"
+ end
+
+ default = Gem::Requirement.default
+ self_req = self.requirement
+ other_req = other.requirement
+
+ return self.class.new name, self_req if other_req == default
+ return self.class.new name, other_req if self_req == default
+
+ self.class.new name, self_req.as_list.concat(other_req.as_list)
+ end
+
end
diff --git a/lib/rubygems/dependency_installer.rb b/lib/rubygems/dependency_installer.rb
index 23462fbe33..46ec63f14f 100644
--- a/lib/rubygems/dependency_installer.rb
+++ b/lib/rubygems/dependency_installer.rb
@@ -74,7 +74,7 @@ class Gem::DependencyInstaller
@installed_gems = []
@install_dir = options[:install_dir] || Gem.dir
- @cache_dir = options[:cache_dir] || @install_dir
+ @cache_dir = options[:cache_dir] || Gem.cache_dir(@install_dir)
# Set with any errors that SpecFetcher finds while search through
# gemspecs for a dep
@@ -136,17 +136,33 @@ class Gem::DependencyInstaller
def gather_dependencies
specs = @specs_and_sources.map { |spec,_| spec }
+ # these gems were listed by the user, always install them
+ keep_names = specs.map { |spec| spec.full_name }
+
dependency_list = Gem::DependencyList.new @development
dependency_list.add(*specs)
to_do = specs.dup
add_found_dependencies to_do, dependency_list unless @ignore_dependencies
+ dependency_list.specs.reject! { |spec|
+ ! keep_names.include? spec.full_name and
+ @source_index.any? { |n,_| n == spec.full_name }
+ }
+
+ unless dependency_list.ok? or @ignore_dependencies or @force then
+ reason = dependency_list.why_not_ok?.map { |k,v|
+ "#{k} requires #{v.join(", ")}"
+ }.join("; ")
+ raise Gem::DependencyError, "Unable to resolve dependencies: #{reason}"
+ end
+
@gems_to_install = dependency_list.dependency_order.reverse
end
def add_found_dependencies to_do, dependency_list
seen = {}
+ dependencies = Hash.new { |h, name| h[name] = Gem::Dependency.new name }
until to_do.empty? do
spec = to_do.shift
@@ -157,10 +173,10 @@ class Gem::DependencyInstaller
deps |= spec.development_dependencies if @development
deps.each do |dep|
+ dependencies[dep.name] = dependencies[dep.name].merge dep
+
results = find_gems_with_sources(dep).reverse
- # FIX: throw in everything that satisfies, and let
- # FIX: dependencylist reduce to the chosen few
results.reject! do |dep_spec,|
to_do.push dep_spec
@@ -172,14 +188,14 @@ class Gem::DependencyInstaller
end
results.each do |dep_spec, source_uri|
- next if seen[dep_spec.name]
@specs_and_sources << [dep_spec, source_uri]
- # FIX: this is the bug
dependency_list.add dep_spec
end
end
end
+
+ dependency_list.remove_specs_unsatisfied_by dependencies
end
##
@@ -259,7 +275,6 @@ class Gem::DependencyInstaller
@gems_to_install.each do |spec|
last = spec == @gems_to_install.last
- # HACK is this test for full_name acceptable?
next if @source_index.any? { |n,_| n == spec.full_name } and not last
# TODO: make this sorta_verbose so other users can benefit from it
diff --git a/lib/rubygems/dependency_list.rb b/lib/rubygems/dependency_list.rb
index 647bb91ae2..91c7c5ade4 100644
--- a/lib/rubygems/dependency_list.rb
+++ b/lib/rubygems/dependency_list.rb
@@ -17,6 +17,7 @@ require 'tsort'
# correct order to avoid conflicts.
class Gem::DependencyList
+ attr_reader :specs
include Enumerable
include TSort
@@ -56,6 +57,10 @@ class Gem::DependencyList
@specs.push(*gemspecs)
end
+ def clear
+ @specs.clear
+ end
+
##
# Return a list of the gem specifications in the dependency list, sorted in
# order so that no gemspec in the list depends on a gemspec earlier in the
@@ -110,11 +115,26 @@ class Gem::DependencyList
# Are all the dependencies in the list satisfied?
def ok?
- @specs.all? do |spec|
- spec.runtime_dependencies.all? do |dep|
- @specs.find { |s| s.satisfies_requirement? dep }
+ why_not_ok?(:quick).empty?
+ end
+
+ def why_not_ok? quick = false
+ unsatisfied = Hash.new { |h,k| h[k] = [] }
+ source_index = Gem.source_index
+ @specs.each do |spec|
+ spec.runtime_dependencies.each do |dep|
+ inst = source_index.any? { |_, installed_spec|
+ dep.name == installed_spec.name and
+ dep.requirement.satisfied_by? installed_spec.version
+ }
+
+ unless inst or @specs.find { |s| s.satisfies_requirement? dep } then
+ unsatisfied[spec.name] << dep
+ return unsatisfied if quick
+ end
end
end
+ unsatisfied
end
##
@@ -147,6 +167,18 @@ class Gem::DependencyList
end
##
+ # Remove everything in the DependencyList that matches but doesn't
+ # satisfy items in +dependencies+ (a hash of gem names to arrays of
+ # dependencies).
+
+ def remove_specs_unsatisfied_by dependencies
+ specs.reject! { |spec|
+ dep = dependencies[spec.name]
+ dep and not dep.requirement.satisfied_by? spec.version
+ }
+ end
+
+ ##
# Removes the gemspec matching +full_name+ from the dependency list
def remove_by_name(full_name)
diff --git a/lib/rubygems/doc_manager.rb b/lib/rubygems/doc_manager.rb
index e900396aa4..71c7d850ad 100644
--- a/lib/rubygems/doc_manager.rb
+++ b/lib/rubygems/doc_manager.rb
@@ -168,7 +168,6 @@ class Gem::DocManager
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 << '--title' << "#{@spec.full_name} Documentation"
@@ -182,6 +181,8 @@ class Gem::DocManager
# HACK more
end
+ debug_args = args.dup
+
r = RDoc::RDoc.new
old_pwd = Dir.pwd
@@ -199,10 +200,10 @@ class Gem::DocManager
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.errs.puts "... RDOC args: #{debug_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)"
+ Gem.configuration.backtrace
+ terminate_interaction 1
ensure
Dir.chdir old_pwd
end
diff --git a/lib/rubygems/gem_path_searcher.rb b/lib/rubygems/gem_path_searcher.rb
index 9dae006222..5b85cbc9fb 100644
--- a/lib/rubygems/gem_path_searcher.rb
+++ b/lib/rubygems/gem_path_searcher.rb
@@ -16,6 +16,7 @@ class Gem::GemPathSearcher
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
@@ -48,7 +49,9 @@ class Gem::GemPathSearcher
# 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
@@ -57,9 +60,39 @@ class Gem::GemPathSearcher
# 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
##
@@ -67,7 +100,18 @@ class Gem::GemPathSearcher
# +spec+.
def matching_file?(spec, path)
- !matching_files(spec, path).empty?
+ 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
##
diff --git a/lib/rubygems/gemcutter_utilities.rb b/lib/rubygems/gemcutter_utilities.rb
index 1681356805..a77a4911f2 100644
--- a/lib/rubygems/gemcutter_utilities.rb
+++ b/lib/rubygems/gemcutter_utilities.rb
@@ -7,6 +7,26 @@
require 'rubygems/remote_fetcher'
module Gem::GemcutterUtilities
+ OptionParser.accept Symbol do |value|
+ value.to_sym
+ end
+
+ ##
+ # Add the --key option
+
+ def add_key_option
+ add_option '-k', '--key KEYNAME', Symbol, 'Use the given API key' do |value,options|
+ options[:key] = value
+ end
+ end
+
+ def api_key
+ if options[:key] then
+ verify_api_key options[:key]
+ else
+ Gem.configuration.rubygems_api_key
+ end
+ end
def sign_in
return if Gem.configuration.rubygems_api_key
@@ -33,6 +53,8 @@ module Gem::GemcutterUtilities
host = ENV['RUBYGEMS_HOST'] if ENV['RUBYGEMS_HOST']
uri = URI.parse "#{host}/#{path}"
+ say "Pushing gem to #{host}..."
+
request_method = Net::HTTP.const_get method.to_s.capitalize
Gem::RemoteFetcher.fetcher.request(uri, request_method, &block)
@@ -52,4 +74,13 @@ module Gem::GemcutterUtilities
end
end
+ def verify_api_key(key)
+ 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
+ end
+ end
+
end
diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb
index 5c7c57685b..8c6aeb44c7 100644
--- a/lib/rubygems/installer.rb
+++ b/lib/rubygems/installer.rb
@@ -156,6 +156,9 @@ class Gem::Installer
Gem.ensure_gem_subdirectories @gem_home
+ # Completely remove any previous gem files
+ FileUtils.rm_rf(@gem_dir) if File.exist?(@gem_dir)
+
FileUtils.mkdir_p @gem_dir
extract_files
@@ -179,10 +182,9 @@ class Gem::Installer
write_require_paths_file_if_needed if Gem::QUICKLOADER_SUCKAGE
- # HACK remove? Isn't this done in multiple places?
- cached_gem = File.join @gem_home, "cache", @gem.split(/\//).pop
+ cached_gem = Gem.cache_gem(File.basename(@gem), @gem_home)
unless File.exist? cached_gem then
- FileUtils.cp @gem, File.join(@gem_home, "cache")
+ FileUtils.cp @gem, Gem.cache_dir(@gem_home)
end
say @spec.post_install_message unless @spec.post_install_message.nil?
@@ -235,7 +237,7 @@ class Gem::Installer
# specifications directory.
def write_spec
- rubycode = @spec.to_ruby
+ rubycode = @spec.to_ruby_for_cache
file_name = File.join @gem_home, 'specifications', @spec.spec_name
@@ -275,8 +277,10 @@ class Gem::Installer
@spec.executables.each do |filename|
filename.untaint
bin_path = File.expand_path "#{@spec.bindir}/#{filename}", @gem_dir
- mode = File.stat(bin_path).mode | 0111
- File.chmod mode, bin_path
+ if File.exist?(bin_path)
+ mode = File.stat(bin_path).mode | 0111
+ File.chmod mode, bin_path
+ end
if @wrappers then
generate_bin_script filename, bindir
@@ -298,7 +302,7 @@ class Gem::Installer
FileUtils.rm_f bin_script_path # prior install may have been --no-wrappers
- File.open bin_script_path, 'w', 0755 do |file|
+ File.open bin_script_path, 'wb', 0755 do |file|
file.print app_script_text(filename)
end
diff --git a/lib/rubygems/installer_test_case.rb b/lib/rubygems/installer_test_case.rb
index c1f86d547b..26b590786b 100644
--- a/lib/rubygems/installer_test_case.rb
+++ b/lib/rubygems/installer_test_case.rb
@@ -64,12 +64,15 @@ class Gem::InstallerTestCase < Gem::TestCase
super
@spec = quick_gem 'a'
+ util_make_exec @spec
@gem = File.join @tempdir, @spec.file_name
@installer = util_installer @spec, @gem, @gemhome
@user_spec = quick_gem 'b'
+ util_make_exec @user_spec
+
@user_gem = File.join @tempdir, @user_spec.file_name
@user_installer = util_installer @user_spec, @user_gem, Gem.user_dir
@@ -77,31 +80,38 @@ class Gem::InstallerTestCase < Gem::TestCase
@user_spec.full_name)
end
- def util_gem_bindir(version = '2')
- File.join util_gem_dir(version), "bin"
+ def util_gem_bindir spec = @spec
+ File.join util_gem_dir(spec), "bin"
end
- def util_gem_dir(version = '2')
- File.join @gemhome, "gems", "a-#{version}" # HACK
+ def util_gem_dir spec = @spec
+ File.join @gemhome, "gems", spec.full_name
end
def util_inst_bindir
File.join @gemhome, "bin"
end
- def util_make_exec(version = '2', shebang = "#!/usr/bin/ruby")
- @spec.executables = ["my_exec"]
+ def util_make_exec(spec = @spec, shebang = "#!/usr/bin/ruby")
+ spec.executables = %w[executable]
+ spec.files << 'bin/executable'
+
+ bindir = util_gem_bindir spec
+ FileUtils.mkdir_p bindir
+ exec_path = File.join bindir, 'executable'
+ open exec_path, 'w' do |io|
+ io.puts shebang
+ end
- FileUtils.mkdir_p util_gem_bindir(version)
- exec_path = File.join util_gem_bindir(version), "my_exec"
- File.open exec_path, 'w' do |f|
- f.puts shebang
+ temp_bin = File.join(@tempdir, 'bin')
+ FileUtils.mkdir_p temp_bin
+ open File.join(temp_bin, 'executable'), 'w' do |io|
+ io.puts shebang
end
end
def util_setup_gem(ui = @ui) # HACK fix use_ui to make this automatic
- @spec.files = File.join('lib', 'code.rb')
- @spec.executables << 'executable'
+ @spec.files << File.join('lib', 'code.rb')
@spec.extensions << File.join('ext', 'a', 'mkrf_conf.rb')
Dir.chdir @tempdir do
@@ -127,9 +137,7 @@ class Gem::InstallerTestCase < Gem::TestCase
def util_installer(spec, gem_path, gem_home)
util_build_gem spec
- FileUtils.mv File.join(@gemhome, 'cache', spec.file_name),
- @tempdir
-
+ FileUtils.mv Gem.cache_gem(spec.file_name), @tempdir
installer = Gem::Installer.new gem_path
installer.gem_dir = util_gem_dir
installer.gem_home = gem_home
diff --git a/lib/rubygems/package/tar_reader/entry.rb b/lib/rubygems/package/tar_reader/entry.rb
index c70248f159..d7b5280213 100644
--- a/lib/rubygems/package/tar_reader/entry.rb
+++ b/lib/rubygems/package/tar_reader/entry.rb
@@ -4,8 +4,9 @@
# File a patch instead and assign it to Ryan Davis or Eric Hodel.
######################################################################
+# -*- coding: utf-8 -*-
#++
-# Copyright (C) 2004 Mauricio Julio Fernández Pradier
+# Copyright (C) 2004 Mauricio Julio Fernández Pradier
# See LICENSE.txt for additional licensing information.
#--
diff --git a/lib/rubygems/remote_fetcher.rb b/lib/rubygems/remote_fetcher.rb
index aa63392848..520adb5827 100644
--- a/lib/rubygems/remote_fetcher.rb
+++ b/lib/rubygems/remote_fetcher.rb
@@ -78,6 +78,23 @@ class Gem::RemoteFetcher
end
##
+ # Given a name and requirement, downloads this gem into cache and returns the
+ # filename. Returns nil if the gem cannot be located.
+ #--
+ # Should probably be integrated with #download below, but that will be a
+ # larger, more emcompassing effort. -erikh
+
+ def download_to_cache dependency
+ found = Gem::SpecFetcher.fetcher.fetch dependency
+
+ return if found.empty?
+
+ spec, source_uri = found.first
+
+ download spec, source_uri
+ end
+
+ ##
# Moves the gem +spec+ from +source_uri+ to the cache dir unless it is
# already there. If the source_uri is local the gem cache dir copy is
# always replaced.
@@ -86,9 +103,9 @@ class Gem::RemoteFetcher
Gem.ensure_gem_subdirectories(install_dir) rescue nil
if File.writable?(install_dir)
- cache_dir = File.join install_dir, 'cache'
+ cache_dir = Gem.cache_dir(install_dir)
else
- cache_dir = File.join(Gem.user_dir, 'cache')
+ cache_dir = Gem.cache_dir(Gem.user_dir)
end
gem_file_name = spec.file_name
@@ -140,7 +157,7 @@ class Gem::RemoteFetcher
path = source_uri.path
path = File.dirname(path) if File.extname(path) == '.gem'
- remote_gem_path = File.join(path, 'gems', gem_file_name)
+ remote_gem_path = correct_for_windows_path(File.join(path, 'gems', gem_file_name))
FileUtils.cp(remote_gem_path, local_gem_path)
rescue Errno::EACCES
@@ -276,6 +293,14 @@ class Gem::RemoteFetcher
raise FetchError.new(e.message, uri)
end
+ def correct_for_windows_path(path)
+ if path[0].chr == '/' && path[1].chr =~ /[a-z]/i && path[2].chr == ':'
+ path = path[1..-1]
+ else
+ path
+ end
+ end
+
##
# Read the data from the (source based) URI, but if it is a file:// URI,
# read from the filesystem instead.
@@ -293,13 +318,7 @@ class Gem::RemoteFetcher
end
if uri.scheme == 'file'
- path = uri.path
-
- # Deal with leading slash on Windows paths
- if path[0].chr == '/' && path[1].chr =~ /[a-zA-Z]/ && path[2].chr == ':'
- path = path[1..-1]
- end
-
+ path = correct_for_windows_path(uri.path)
return Gem.read_binary(path)
end
diff --git a/lib/rubygems/requirement.rb b/lib/rubygems/requirement.rb
index 8af5fbd6b4..35f7d0809a 100644
--- a/lib/rubygems/requirement.rb
+++ b/lib/rubygems/requirement.rb
@@ -108,7 +108,7 @@ class Gem::Requirement
end
def as_list # :nodoc:
- requirements.map { |op, version| "#{op} #{version}" }
+ requirements.map { |op, version| "#{op} #{version}" }.sort
end
def hash # :nodoc:
@@ -137,7 +137,8 @@ class Gem::Requirement
# True if +version+ satisfies this Requirement.
def satisfied_by? version
- requirements.all? { |op, rv| OPS[op].call version, rv }
+ # #28965: syck has a bug with unquoted '=' YAML.loading as YAML::DefaultKey
+ requirements.all? { |op, rv| (OPS[op] || OPS["="]).call version, rv }
end
def to_s # :nodoc:
diff --git a/lib/rubygems/security.rb b/lib/rubygems/security.rb
index 9f3daa9453..1ff375dc4a 100644
--- a/lib/rubygems/security.rb
+++ b/lib/rubygems/security.rb
@@ -12,6 +12,7 @@
require 'rubygems/exceptions'
require 'rubygems/gem_openssl'
+require 'fileutils'
#
# = Signed Gems README
diff --git a/lib/rubygems/source_index.rb b/lib/rubygems/source_index.rb
index 7c571fff55..a6733fac31 100644
--- a/lib/rubygems/source_index.rb
+++ b/lib/rubygems/source_index.rb
@@ -131,7 +131,7 @@ class Gem::SourceIndex
# Returns an Array specifications for the latest released versions
# of each gem in this index.
- def latest_specs
+ def latest_specs(include_prerelease=false)
result = Hash.new { |h,k| h[k] = [] }
latest = {}
@@ -140,7 +140,7 @@ class Gem::SourceIndex
curr_ver = spec.version
prev_ver = latest.key?(name) ? latest[name].version : nil
- next if curr_ver.prerelease?
+ next if !include_prerelease && curr_ver.prerelease?
next unless prev_ver.nil? or curr_ver >= prev_ver or
latest[name].platform != Gem::Platform::RUBY
@@ -273,6 +273,7 @@ class Gem::SourceIndex
when Gem::Dependency then
only_platform = platform_only
requirement = gem_pattern.requirement
+
gem_pattern = if Regexp === gem_pattern.name then
gem_pattern.name
elsif gem_pattern.name.empty? then
diff --git a/lib/rubygems/spec_fetcher.rb b/lib/rubygems/spec_fetcher.rb
index c999a65cd9..ab05c2f9dd 100644
--- a/lib/rubygems/spec_fetcher.rb
+++ b/lib/rubygems/spec_fetcher.rb
@@ -76,7 +76,8 @@ class Gem::SpecFetcher
# Returns the local directory to write +uri+ to.
def cache_dir(uri)
- File.join @dir, "#{uri.host}%#{uri.port}", File.dirname(uri.path)
+ escaped_path = uri.path.sub(%r[^/([a-z]):/]i, '/\\1-/') # Correct for windows paths
+ File.join @dir, "#{uri.host}%#{uri.port}", File.dirname(escaped_path)
end
##
@@ -100,6 +101,7 @@ class Gem::SpecFetcher
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"
@@ -179,7 +181,7 @@ class Gem::SpecFetcher
def suggest_gems_from_name gem_name
gem_name = gem_name.downcase
max = gem_name.size / 2
- specs = list.values.flatten(1) # flatten(1) is 1.8.7 and up
+ specs = list.values.flatten 1
matches = specs.map { |name, version, platform|
next unless Gem::Platform.match platform
diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb
index f66288498b..a5e250a5df 100644
--- a/lib/rubygems/specification.rb
+++ b/lib/rubygems/specification.rb
@@ -339,7 +339,8 @@ class Gem::Specification
# List of dependencies that will automatically be activated at runtime.
def runtime_dependencies
- dependencies.select { |d| d.type == :runtime || d.type == nil }
+ # TODO: fix #type to return :runtime if nil
+ dependencies.select { |d| d.type == :runtime }
end
##
@@ -542,8 +543,8 @@ class Gem::Specification
def self.normalize_yaml_input(input)
result = input.respond_to?(:read) ? input.read : input
- result = "--- " + result unless result =~ /^--- /
- result
+ result = "--- " + result unless result =~ /\A--- /
+ result.gsub(/ !!null \n/, " \n")
end
##
@@ -685,6 +686,14 @@ class Gem::Specification
alias eql? == # :nodoc:
##
+ # A macro to yield cached gem path
+ #
+ def cache_gem
+ cache_name = File.join(Gem.dir, 'cache', file_name)
+ return File.exist?(cache_name) ? cache_name : nil
+ end
+
+ ##
# True if this gem has the same attributes as +other+.
def same_attributes?(other)
@@ -726,11 +735,13 @@ class Gem::Specification
end
def to_yaml(opts = {}) # :nodoc:
- return super if YAML.const_defined?(:ENGINE) && !YAML::ENGINE.syck?
-
- YAML.quick_emit object_id, opts do |out|
- out.map taguri, to_yaml_style do |map|
- encode_with map
+ if YAML.const_defined?(:ENGINE) && !YAML::ENGINE.syck? then
+ super.gsub(/ !!null \n/, " \n")
+ else
+ YAML.quick_emit object_id, opts do |out|
+ out.map taguri, to_yaml_style do |map|
+ encode_with map
+ end
end
end
end
@@ -795,21 +806,17 @@ class Gem::Specification
result << " if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then"
- unless dependencies.empty? then
- dependencies.each do |dep|
- version_reqs_param = dep.requirements_list.inspect
- dep.instance_variable_set :@type, :runtime if dep.type.nil? # HACK
- result << " s.add_#{dep.type}_dependency(%q<#{dep.name}>, #{version_reqs_param})"
- end
+ dependencies.each do |dep|
+ req = dep.requirements_list.inspect
+ dep.instance_variable_set :@type, :runtime if dep.type.nil? # HACK
+ result << " s.add_#{dep.type}_dependency(%q<#{dep.name}>, #{req})"
end
result << " else"
- unless dependencies.empty? then
- dependencies.each do |dep|
- version_reqs_param = dep.requirements_list.inspect
- result << " s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})"
- end
+ dependencies.each do |dep|
+ version_reqs_param = dep.requirements_list.inspect
+ result << " s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})"
end
result << ' end'
@@ -827,6 +834,15 @@ class Gem::Specification
result.join "\n"
end
+ def to_ruby_for_cache
+ s = dup
+ # remove large blobs that aren't used at runtime:
+ s.files = nil
+ s.extra_rdoc_files = nil
+ s.rdoc_options = nil
+ s.to_ruby
+ end
+
##
# Checks that the specification contains all required fields, and does a
# very basic sanity check.
@@ -835,6 +851,7 @@ class Gem::Specification
# checks..
def validate
+ require 'rubygems/user_interaction'
extend Gem::UserInteraction
normalize
@@ -1523,4 +1540,32 @@ class Gem::Specification
@extensions,
].flatten.uniq.compact
end
+
+ def conflicts
+ conflicts = {}
+ Gem.loaded_specs.values.each do |spec|
+ bad = self.runtime_dependencies.find_all { |dep|
+ spec.name == dep.name and not spec.satisfies_requirement? dep
+ }
+
+ conflicts[spec] = bad unless bad.empty?
+ end
+ conflicts
+ end
+
+ def traverse trail = [], &b
+ trail = trail + [self]
+ runtime_dependencies.each do |dep|
+ dep_specs = Gem.source_index.search dep, true
+ dep_specs.each do |dep_spec|
+ b[self, dep, dep_spec, trail + [dep_spec]]
+ dep_spec.traverse(trail, &b) unless
+ trail.map(&:name).include? dep_spec.name
+ end
+ end
+ end
+
+ def dependent_specs
+ runtime_dependencies.map { |dep| Gem.source_index.search dep, true }.flatten
+ end
end
diff --git a/lib/rubygems/test_case.rb b/lib/rubygems/test_case.rb
index 447a30f780..5c32bd2ddb 100644
--- a/lib/rubygems/test_case.rb
+++ b/lib/rubygems/test_case.rb
@@ -24,20 +24,8 @@ require 'uri'
require 'rubygems/package'
require 'rubygems/test_utilities'
require 'pp'
-require 'yaml'
require 'zlib'
-
-begin
- YAML::ENGINE.yamler = 'psych'
-rescue LoadError
-end if YAML.const_defined? :ENGINE
-
-begin
- gem 'rdoc'
-rescue Gem::LoadError
-end
-
-require 'rdoc/rdoc'
+Gem.load_yaml
require 'rubygems/mock_gem_ui'
@@ -99,6 +87,8 @@ class Gem::TestCase < MiniTest::Unit::TestCase
undef_method :default_test if instance_methods.include? 'default_test' or
instance_methods.include? :default_test
+ @@project_dir = Dir.pwd
+
##
# #setup prepares a sandboxed location to install gems. All installs are
# directed to a temporary directory. All install plugins are removed.
@@ -128,8 +118,6 @@ class Gem::TestCase < MiniTest::Unit::TestCase
@gemhome = File.join @tempdir, 'gemhome'
@userhome = File.join @tempdir, 'userhome'
- Gem.ensure_gem_subdirectories @gemhome
-
@orig_ruby = if ruby = ENV['RUBY'] then
Gem.class_eval { ruby, @ruby = @ruby, ruby }
ruby
@@ -137,6 +125,8 @@ class Gem::TestCase < MiniTest::Unit::TestCase
Gem.ensure_gem_subdirectories @gemhome
+ Dir.chdir @tempdir
+
@orig_ENV_HOME = ENV['HOME']
ENV['HOME'] = @userhome
Gem.instance_variable_set :@user_home, nil
@@ -146,6 +136,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase
Gem.use_paths(@gemhome)
Gem.loaded_specs.clear
+ Gem.unresolved_deps.clear
Gem.configuration.verbose = true
Gem.configuration.update_sources = true
@@ -154,6 +145,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase
@uri = URI.parse @gem_repo
Gem.sources.replace [@gem_repo]
+ Gem.searcher = nil
Gem::SpecFetcher.fetcher = nil
@orig_BASERUBY = Gem::ConfigMap[:BASERUBY]
@@ -169,17 +161,14 @@ class Gem::TestCase < MiniTest::Unit::TestCase
@marshal_version = "#{Marshal::MAJOR_VERSION}.#{Marshal::MINOR_VERSION}"
- @private_key = File.expand_path('../../../test/rubygems/private_key.pem',
- __FILE__)
- @public_cert = File.expand_path('../../../test/rubygems/public_cert.pem',
- __FILE__)
-
+ # TODO: move to installer test cases
Gem.post_build_hooks.clear
Gem.post_install_hooks.clear
Gem.post_uninstall_hooks.clear
Gem.pre_install_hooks.clear
Gem.pre_uninstall_hooks.clear
+ # TODO: move to installer test cases
Gem.post_build do |installer|
@post_build_hook_arg = installer
true
@@ -219,6 +208,8 @@ class Gem::TestCase < MiniTest::Unit::TestCase
Gem::RemoteFetcher.fetcher = nil
end
+ Dir.chdir @@project_dir
+
FileUtils.rm_rf @tempdir unless ENV['KEEP_FILES']
ENV['GEM_HOME'] = @orig_gem_home
@@ -319,14 +310,14 @@ class Gem::TestCase < MiniTest::Unit::TestCase
require 'rubygems/specification'
spec = Gem::Specification.new do |s|
- s.platform = Gem::Platform::RUBY
- s.name = name
- s.version = version
- s.author = 'A User'
- s.email = 'example@example.com'
- s.homepage = 'http://example.com'
- s.has_rdoc = true
- s.summary = "this is a summary"
+ s.platform = Gem::Platform::RUBY
+ s.name = name
+ s.version = version
+ s.author = 'A User'
+ s.email = 'example@example.com'
+ s.homepage = 'http://example.com'
+ s.has_rdoc = true
+ s.summary = "this is a summary"
s.description = "This is a test description"
yield(s) if block_given?
@@ -344,6 +335,30 @@ class Gem::TestCase < MiniTest::Unit::TestCase
return spec
end
+ def quick_spec name, version = '2'
+ require 'rubygems/specification'
+
+ spec = Gem::Specification.new do |s|
+ s.platform = Gem::Platform::RUBY
+ s.name = name
+ s.version = version
+ s.author = 'A User'
+ s.email = 'example@example.com'
+ s.homepage = 'http://example.com'
+ s.has_rdoc = true
+ s.summary = "this is a summary"
+ s.description = "This is a test description"
+
+ yield(s) if block_given?
+ end
+
+ spec.loaded_from = @gemhome
+
+ Gem.source_index.add_spec spec
+
+ return spec
+ end
+
##
# Builds a gem from +spec+ and places it in <tt>File.join @gemhome,
# 'cache'</tt>. Automatically creates files based on +spec.files+
@@ -364,7 +379,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase
end
FileUtils.mv spec.file_name,
- File.join(@gemhome, 'cache', "#{spec.original_name}.gem")
+ Gem.cache_gem("#{spec.original_name}.gem")
end
end
@@ -372,18 +387,69 @@ class Gem::TestCase < MiniTest::Unit::TestCase
# Removes all installed gems from +@gemhome+.
def util_clear_gems
- FileUtils.rm_r File.join(@gemhome, 'gems')
- FileUtils.rm_r File.join(@gemhome, 'specifications')
+ FileUtils.rm_rf File.join(@gemhome, 'gems')
+ FileUtils.rm_rf File.join(@gemhome, 'specifications')
Gem.source_index.refresh!
end
##
+ # Install the provided specs
+
+ def install_specs(*specs)
+ specs.each do |spec|
+ # TODO: inverted responsibility
+ Gem.source_index.add_spec spec
+ end
+ Gem.searcher = nil
+ end
+
+ ##
+ # Create a new spec (or gem if passed an array of files) and set it
+ # up properly. Use this instead of util_spec and util_gem.
+
+ def new_spec name, version, deps = nil, *files
+ # TODO: unfactor and deprecate util_gem and util_spec
+ spec, = unless files.empty? then
+ util_gem name, version do |s|
+ Array(deps).each do |n,v|
+ s.add_dependency n, v
+ end
+ s.files.push(*files)
+ end
+ else
+ util_spec name, version, deps
+ end
+ spec.loaded_from = File.join @gemhome, 'specifications', spec.spec_name
+ spec.loaded = false
+ spec
+ end
+
+ ##
+ # Creates a spec with +name+, +version+ and +deps+.
+
+ def util_spec(name, version, deps = nil, &block)
+ raise "deps or block, not both" if deps and block
+
+ if deps then
+ block = proc do |s|
+ deps.each do |n, req|
+ s.add_dependency n, (req || '>= 0')
+ end
+ end
+ end
+
+ quick_spec(name, version, &block)
+ end
+
+ ##
# Creates a gem with +name+, +version+ and +deps+. The specification will
# be yielded before gem creation for customization. The gem will be placed
# in <tt>File.join @tempdir, 'gems'</tt>. The specification and .gem file
# location are returned.
def util_gem(name, version, deps = nil, &block)
+ raise "deps or block, not both" if deps and block
+
if deps then
block = proc do |s|
deps.each do |n, req|
@@ -397,8 +463,9 @@ class Gem::TestCase < MiniTest::Unit::TestCase
util_build_gem spec
cache_file = File.join @tempdir, 'gems', "#{spec.original_name}.gem"
- FileUtils.mv File.join(@gemhome, 'cache', "#{spec.original_name}.gem"),
- cache_file
+ gems_dir = File.dirname cache_file
+ FileUtils.mkdir_p File.dirname cache_file
+ FileUtils.mv Gem.cache_gem("#{spec.original_name}.gem"), cache_file
FileUtils.rm File.join(@gemhome, 'specifications', spec.spec_name)
spec.loaded_from = nil
@@ -436,6 +503,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase
# Additional +prerelease+ gems may also be created:
#
# +@a2_pre+:: gem a version 2.a
+ # TODO: nuke this and fix tests. this should speed up a lot
def util_make_gems(prerelease = false)
@a1 = quick_gem 'a', '1' do |s|
@@ -459,11 +527,12 @@ Also, a list:
s.require_paths = %w[lib]
end
- @a2 = quick_gem('a', '2', &init)
- @a3a = quick_gem('a', '3.a', &init)
+ @a2 = quick_gem('a', '2', &init)
+ @a3a = quick_gem('a', '3.a', &init)
@a_evil9 = quick_gem('a_evil', '9', &init)
- @b2 = quick_gem('b', '2', &init)
- @c1_2 = quick_gem('c', '1.2', &init)
+ @b2 = quick_gem('b', '2', &init)
+ @c1_2 = quick_gem('c', '1.2', &init)
+
@pl1 = quick_gem 'pl', '1' do |s| # l for legacy
s.files = %w[lib/code.rb]
s.require_paths = %w[lib]
@@ -477,12 +546,12 @@ Also, a list:
util_build_gem @a2_pre
end
- write_file File.join(*%W[gems #{@a1.original_name} lib code.rb])
- write_file File.join(*%W[gems #{@a2.original_name} lib code.rb])
- write_file File.join(*%W[gems #{@a3a.original_name} lib code.rb])
- write_file File.join(*%W[gems #{@b2.original_name} lib code.rb])
+ write_file File.join(*%W[gems #{@a1.original_name} lib code.rb])
+ write_file File.join(*%W[gems #{@a2.original_name} lib code.rb])
+ write_file File.join(*%W[gems #{@a3a.original_name} lib code.rb])
+ write_file File.join(*%W[gems #{@b2.original_name} lib code.rb])
write_file File.join(*%W[gems #{@c1_2.original_name} lib code.rb])
- write_file File.join(*%W[gems #{@pl1.original_name} lib code.rb])
+ write_file File.join(*%W[gems #{@pl1.original_name} lib code.rb])
[@a1, @a2, @a3a, @a_evil9, @b2, @c1_2, @pl1].each do |spec|
util_build_gem spec
@@ -703,7 +772,7 @@ Also, a list:
@@ruby = rubybin
env_rake = ENV['rake']
- ruby19_rake = File.expand_path("../../../bin/rake", __FILE__)
+ ruby19_rake = File.expand_path("bin/rake", @@project_dir)
@@rake = if env_rake then
ENV["rake"]
elsif File.exist? ruby19_rake then
diff --git a/lib/rubygems/test_utilities.rb b/lib/rubygems/test_utilities.rb
index 892e4dd9e5..43f905f017 100644
--- a/lib/rubygems/test_utilities.rb
+++ b/lib/rubygems/test_utilities.rb
@@ -104,7 +104,7 @@ class Gem::FakeFetcher
def download spec, source_uri, install_dir = Gem.dir
name = spec.file_name
- path = File.join(install_dir, 'cache', name)
+ path = Gem.cache_gem(name, install_dir)
Gem.ensure_gem_subdirectories install_dir
@@ -119,6 +119,16 @@ class Gem::FakeFetcher
path
end
+ def download_to_cache dependency
+ found = Gem::SpecFetcher.fetcher.fetch dependency
+
+ return if found.empty?
+
+ spec, source_uri = found.first
+
+ download spec, source_uri
+ end
+
end
# :stopdoc:
diff --git a/lib/rubygems/uninstaller.rb b/lib/rubygems/uninstaller.rb
index df45771846..02976866b1 100644
--- a/lib/rubygems/uninstaller.rb
+++ b/lib/rubygems/uninstaller.rb
@@ -56,6 +56,7 @@ class Gem::Uninstaller
@force_all = options[:all]
@force_ignore = options[:ignore]
@bin_dir = options[:bin_dir]
+ @format_executable = options[:format_executable]
# only add user directory if install_dir is not set
@user_install = false
@@ -108,6 +109,13 @@ class Gem::Uninstaller
def uninstall_gem(spec, specs)
@spec = spec
+ unless dependencies_ok? spec
+ unless ask_if_ok(spec)
+ raise Gem::DependencyRemovalException,
+ "Uninstallation aborted due to dependent gem(s)"
+ end
+ end
+
Gem.pre_uninstall_hooks.each do |hook|
hook.call self
end
@@ -161,8 +169,8 @@ class Gem::Uninstaller
spec.executables.each do |exe_name|
say "Removing #{exe_name}"
- FileUtils.rm_f File.join(bindir, exe_name)
- FileUtils.rm_f File.join(bindir, "#{exe_name}.bat")
+ FileUtils.rm_f File.join(bindir, formatted_program_filename(exe_name))
+ FileUtils.rm_f File.join(bindir, "#{formatted_program_filename(exe_name)}.bat")
end
end
end
@@ -184,11 +192,6 @@ class Gem::Uninstaller
# uninstalled a gem, it is removed from that list.
def remove(spec, list)
- unless dependencies_ok? spec then
- raise Gem::DependencyRemovalException,
- "Uninstallation aborted due to dependent gem(s)"
- end
-
unless path_ok?(@gem_home, spec) or
(@user_install and path_ok?(Gem.user_dir, spec)) then
e = Gem::GemNotInHomeException.new \
@@ -215,11 +218,10 @@ class Gem::Uninstaller
FileUtils.rm_rf gemspec
- cache_dir = File.join spec.installation_path, 'cache'
- gem = File.join cache_dir, spec.file_name
+ gem = Gem.cache_gem(spec.file_name, spec.installation_path)
unless File.exist? gem then
- gem = File.join cache_dir, "#{original_platform_name}.gem"
+ gem = Gem.cache_gem("#{original_platform_name}.gem", spec.installation_path)
end
FileUtils.rm_rf gem
@@ -246,7 +248,7 @@ class Gem::Uninstaller
deplist = Gem::DependencyList.from_source_index @source_index
deplist.add(*@user_index.gems.values) if @user_install
- deplist.ok_to_remove?(spec.full_name) || ask_if_ok(spec)
+ deplist.ok_to_remove?(spec.full_name)
end
def ask_if_ok(spec)
@@ -263,5 +265,14 @@ class Gem::Uninstaller
return ask_yes_no(msg.join("\n"), true)
end
+ def formatted_program_filename(filename)
+ if @format_executable then
+ Gem::Installer.exec_format % File.basename(filename)
+ else
+ filename
+ end
+ end
+
+
end
diff --git a/lib/rubygems/user_interaction.rb b/lib/rubygems/user_interaction.rb
index ff5800c116..538793181e 100644
--- a/lib/rubygems/user_interaction.rb
+++ b/lib/rubygems/user_interaction.rb
@@ -182,29 +182,24 @@ class Gem::StreamUI
end
end
- qstr = case default
- when nil
- 'yn'
- when true
- 'Yn'
- else
- 'yN'
- end
+ default_answer = case default
+ when nil
+ 'yn'
+ when true
+ 'Yn'
+ else
+ 'yN'
+ end
result = nil
- while result.nil?
- result = ask("#{question} [#{qstr}]")
- result = case result
- when /^[Yy].*/
- true
- when /^[Nn].*/
- false
- when /^$/
- default
- else
- nil
- end
+ while result.nil? do
+ result = case ask "#{question} [#{default_answer}]"
+ when /^y/i then true
+ when /^n/i then false
+ when /^$/ then default
+ else nil
+ end
end
return result
@@ -531,20 +526,26 @@ end
# SilentUI is a UI choice that is absolutely silent.
class Gem::SilentUI < Gem::StreamUI
-
def initialize
-
reader, writer = nil, nil
- if Gem.win_platform?
- reader = File.open('nul', 'r')
- writer = File.open('nul', 'w')
- else
+ begin
reader = File.open('/dev/null', 'r')
writer = File.open('/dev/null', 'w')
+ rescue Errno::ENOENT
+ reader = File.open('nul', 'r')
+ writer = File.open('nul', 'w')
end
super reader, writer, writer
end
+
+ def download_reporter(*args)
+ SilentDownloadReporter.new(@outs, *args)
+ end
+
+ def progress_reporter(*args)
+ SilentProgressReporter.new(@outs, *args)
+ end
end
diff --git a/lib/rubygems/validator.rb b/lib/rubygems/validator.rb
index d2750f14ea..bc6c520d8b 100644
--- a/lib/rubygems/validator.rb
+++ b/lib/rubygems/validator.rb
@@ -94,7 +94,7 @@ class Gem::Validator
next unless gems.include? gem_spec.name unless gems.empty?
install_dir = gem_spec.installation_path
- gem_path = File.join install_dir, "cache", gem_spec.file_name
+ gem_path = Gem.cache_gem(gem_spec.file_name, install_dir)
spec_path = File.join install_dir, "specifications", gem_spec.spec_name
gem_directory = gem_spec.full_gem_path