summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordrbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-12-23 00:35:09 +0000
committerdrbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-12-23 00:35:09 +0000
commit6fe32d72667945605ef710395706e04491bfd86a (patch)
tree7fe4b8f779ff75067b45f48502864fb05787cee7
parentc47c095b9740e7c19d6fdca29ab661c1089221d4 (diff)
* lib/rubygems/commands/check_command.rb: Added --doctor and --dry-run
options to clean up after failed uninstallation. * test/rubygems/test_gem_commands_check_command.rb: Test for above. * lib/rubygems/commands/push_command.rb: Allow pushes from RubyGems 2.0.0.preview3 * lib/rubygems/commands/update_command.rb: Use Gem.ruby_version * lib/rubygems/dependency.rb: Update style. * lib/rubygems/installer.rb: Ensure installed gem specifications will be useable. Refactor. * test/rubygems/test_gem_installer.rb: ditto. * lib/rubygems/validator.rb: Fixed bug with unreadable files. * lib/rubygems.rb: Fixed broken methods. * test/rubygems/test_gem.rb: Test for above. * test/rubygems/test_gem_commands_push_command.rb: Fixed overridden Gem.latest_rubygems_version git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38564 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog25
-rw-r--r--lib/rubygems.rb57
-rw-r--r--lib/rubygems/commands/check_command.rb60
-rw-r--r--lib/rubygems/commands/push_command.rb12
-rw-r--r--lib/rubygems/commands/update_command.rb2
-rw-r--r--lib/rubygems/dependency.rb10
-rw-r--r--lib/rubygems/doctor.rb124
-rw-r--r--lib/rubygems/installer.rb104
-rw-r--r--lib/rubygems/validator.rb7
-rw-r--r--test/rubygems/test_gem.rb39
-rw-r--r--test/rubygems/test_gem_commands_check_command.rb50
-rw-r--r--test/rubygems/test_gem_commands_push_command.rb25
-rw-r--r--test/rubygems/test_gem_doctor.rb168
-rw-r--r--test/rubygems/test_gem_installer.rb209
14 files changed, 739 insertions, 153 deletions
diff --git a/ChangeLog b/ChangeLog
index a2e2cfcc3e..e1069d6f92 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+Sun Dec 23 09:34:07 2012 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems/commands/check_command.rb: Added --doctor and --dry-run
+ options to clean up after failed uninstallation.
+ * test/rubygems/test_gem_commands_check_command.rb: Test for above.
+
+ * lib/rubygems/commands/push_command.rb: Allow pushes from RubyGems
+ 2.0.0.preview3
+
+ * lib/rubygems/commands/update_command.rb: Use Gem.ruby_version
+
+ * lib/rubygems/dependency.rb: Update style.
+
+ * lib/rubygems/installer.rb: Ensure installed gem specifications will
+ be useable. Refactor.
+ * test/rubygems/test_gem_installer.rb: ditto.
+
+ * lib/rubygems/validator.rb: Fixed bug with unreadable files.
+
+ * lib/rubygems.rb: Fixed broken methods.
+ * test/rubygems/test_gem.rb: Test for above.
+
+ * test/rubygems/test_gem_commands_push_command.rb: Fixed overridden
+ Gem.latest_rubygems_version
+
Sun Dec 23 01:52:01 2012 Akinori MUSHA <knu@iDaemons.org>
* io.c (rb_io_lines, rb_io_bytes, rb_io_chars, rb_io_codepoints):
diff --git a/lib/rubygems.rb b/lib/rubygems.rb
index 29bbb586b5..77d1650056 100644
--- a/lib/rubygems.rb
+++ b/lib/rubygems.rb
@@ -98,7 +98,7 @@
require 'rbconfig'
module Gem
- VERSION = '2.0.0.preview2.2'
+ VERSION = '2.0.0.preview3'
end
# Must be first since it unloads the prelude from 1.9.2
@@ -123,7 +123,22 @@ module Gem
/wince/i,
]
- GEM_DEP_FILES = %w!gem.deps.rb Gemfile Isolate!
+ GEM_DEP_FILES = %w[
+ gem.deps.rb
+ Gemfile
+ Isolate
+ ]
+
+ ##
+ # Subdirectories in a gem repository
+
+ REPOSITORY_SUBDIRECTORIES = %w[
+ build_info
+ cache
+ doc
+ gems
+ specifications
+ ]
@@win_platform = nil
@@ -388,7 +403,7 @@ module Gem
require 'fileutils'
- %w[cache build_info doc gems specifications].each do |name|
+ REPOSITORY_SUBDIRECTORIES.each do |name|
subdir = File.join dir, name
next if File.exist? subdir
FileUtils.mkdir_p subdir rescue nil # in case of perms issues -- lame
@@ -750,34 +765,36 @@ module Gem
@ruby
end
- # DOC: needs doc'd or :nodoc'd
+ ##
+ # Returns the latest release-version specification for the gem +name+.
+
def self.latest_spec_for name
- dependency = Gem::Dependency.new name
- fetcher = Gem::SpecFetcher.fetcher
- spec_tuples = fetcher.find_matching dependency
+ dependency = Gem::Dependency.new name
+ fetcher = Gem::SpecFetcher.fetcher
+ spec_tuples, = fetcher.spec_for_dependency dependency
- match = spec_tuples.select { |(n, _, p), _|
- n == name and Gem::Platform.match p
- }.sort_by { |(_, version, _), _|
- version
- }.last
+ spec, = spec_tuples.first
- match and fetcher.fetch_spec(*match)
+ spec
end
- # DOC: needs doc'd or :nodoc'd
- def self.latest_version_for name
- spec = latest_spec_for name
- spec and spec.version
- end
+ ##
+ # Returns the latest release version of RubyGems.
- # DOC: needs doc'd or :nodoc'd
def self.latest_rubygems_version
- latest_version_for("rubygems-update") or
+ latest_version_for('rubygems-update') or
raise "Can't find 'rubygems-update' in any repo. Check `gem source list`."
end
##
+ # Returns the version of the latest release-version of gem +name+
+
+ def self.latest_version_for name
+ spec = latest_spec_for name
+ spec and spec.version
+ end
+
+ ##
# A Gem::Version for the currently running ruby.
def self.ruby_version
diff --git a/lib/rubygems/commands/check_command.rb b/lib/rubygems/commands/check_command.rb
index 4bdfcfa645..d7677d47a1 100644
--- a/lib/rubygems/commands/check_command.rb
+++ b/lib/rubygems/commands/check_command.rb
@@ -1,25 +1,44 @@
require 'rubygems/command'
require 'rubygems/version_option'
require 'rubygems/validator'
+require 'rubygems/doctor'
class Gem::Commands::CheckCommand < Gem::Command
include Gem::VersionOption
def initialize
- super 'check', 'Check installed gems',
- :alien => true
+ super 'check', 'Check a gem repository for added or missing files',
+ :alien => true, :doctor => false, :dry_run => false, :gems => true
- add_option('-a', '--alien', "Report 'unmanaged' or rogue files in the",
- "gem repository") do |value, options|
- options[:alien] = true
+ add_option('-a', '--[no-]alien',
+ 'Report "unmanaged" or rogue files in the',
+ 'gem repository') do |value, options|
+ options[:alien] = value
+ end
+
+ add_option('--[no-]doctor',
+ 'Clean up uninstalled gems and broken',
+ 'specifications') do |value, options|
+ options[:doctor] = value
+ end
+
+ add_option('--[no-]dry-run',
+ 'Do not remove files, only report what',
+ 'would be removed') do |value, options|
+ options[:dry_run] = value
+ end
+
+ add_option('--[no-]gems',
+ 'Check installed gems for problems') do |value, options|
+ options[:gems] = value
end
add_version_option 'check'
end
- def execute
- say "Checking gems..."
+ def check_gems
+ say 'Checking gems...'
say
gems = get_all_gem_names rescue []
@@ -37,4 +56,31 @@ class Gem::Commands::CheckCommand < Gem::Command
end
end
+ def doctor
+ say 'Checking for files from uninstalled gems...'
+ say
+
+ Gem.path.each do |gem_repo|
+ doctor = Gem::Doctor.new gem_repo, options[:dry_run]
+ doctor.doctor
+ end
+ end
+
+ def execute
+ check_gems if options[:gems]
+ doctor if options[:doctor]
+ end
+
+ def arguments # :nodoc:
+ 'GEMNAME name of gem to check'
+ end
+
+ def defaults_str # :nodoc:
+ '--gems --alien'
+ end
+
+ def usage # :nodoc:
+ "#{program_name} [OPTIONS] [GEMNAME ...]"
+ end
+
end
diff --git a/lib/rubygems/commands/push_command.rb b/lib/rubygems/commands/push_command.rb
index 0667b47dc1..ce70836823 100644
--- a/lib/rubygems/commands/push_command.rb
+++ b/lib/rubygems/commands/push_command.rb
@@ -40,9 +40,17 @@ class Gem::Commands::PushCommand < Gem::Command
def send_gem name
args = [:post, "api/v1/gems"]
+ latest_rubygems_version = Gem.latest_rubygems_version
- if Gem.latest_rubygems_version < Gem::Version.new(Gem::VERSION) then
- alert_error "Using beta/unreleased version of rubygems. Not pushing."
+ if latest_rubygems_version < Gem.rubygems_version and
+ Gem.rubygems_version.prerelease? and
+ Gem::Version.new('2.0.0.preview3') != Gem.rubygems_version then
+ alert_error <<-ERROR
+You are using a beta release of RubyGems (#{Gem::VERSION}) which is not
+allowed to push gems. Please downgrade or upgrade to a release version.
+
+The latest released RubyGems version is #{latest_rubygems_version}
+ ERROR
terminate_interaction 1
end
diff --git a/lib/rubygems/commands/update_command.rb b/lib/rubygems/commands/update_command.rb
index 02f9657435..be76c4c7cd 100644
--- a/lib/rubygems/commands/update_command.rb
+++ b/lib/rubygems/commands/update_command.rb
@@ -142,7 +142,7 @@ class Gem::Commands::UpdateCommand < Gem::Command
gems_to_update = which_to_update hig, options[:args], :system
name, up_ver = gems_to_update.first
- current_ver = Gem::Version.new Gem::VERSION
+ current_ver = Gem.rubygems_version
target = if options[:system] == true then
up_ver
diff --git a/lib/rubygems/dependency.rb b/lib/rubygems/dependency.rb
index 217189bf8e..1e3cc168a8 100644
--- a/lib/rubygems/dependency.rb
+++ b/lib/rubygems/dependency.rb
@@ -10,14 +10,14 @@ class Gem::Dependency
#--
# When this list is updated, be sure to change
# Gem::Specification::CURRENT_SPECIFICATION_VERSION as well.
-
+ #
# REFACTOR: This type of constant, TYPES, indicates we might want
- # two classes, used via inheretance or duck typing.
+ # two classes, used via inheritance or duck typing.
TYPES = [
- :development,
- :runtime,
- ]
+ :development,
+ :runtime,
+ ]
##
# Dependency name or regular expression.
diff --git a/lib/rubygems/doctor.rb b/lib/rubygems/doctor.rb
new file mode 100644
index 0000000000..198c758b00
--- /dev/null
+++ b/lib/rubygems/doctor.rb
@@ -0,0 +1,124 @@
+require 'rubygems'
+require 'rubygems/user_interaction'
+require 'pathname'
+
+##
+# Cleans up after a partially-failed uninstall or for an invalid
+# Gem::Specification.
+#
+# If a specification was removed by hand this will remove any remaining files.
+#
+# If a corrupt specification was installed this will clean up warnings by
+# removing the bogus specification.
+
+class Gem::Doctor
+
+ include Gem::UserInteraction
+
+ ##
+ # Maps a gem subdirectory to the files that are expected to exist in the
+ # subdirectory.
+
+ REPOSITORY_EXTENSION_MAP = { # :nodoc:
+ 'build_info' => '.info',
+ 'cache' => '.gem',
+ 'doc' => '',
+ 'gems' => '',
+ 'specifications' => '.gemspec'
+ }
+
+ raise 'Update REPOSITORY_EXTENSION_MAP' unless
+ Gem::REPOSITORY_SUBDIRECTORIES == REPOSITORY_EXTENSION_MAP.keys.sort
+
+ ##
+ # Creates a new Gem::Doctor that will clean up +gem_repository+. Only one
+ # gem repository may be cleaned at a time.
+ #
+ # If +dry_run+ is true no files or directories will be removed.
+
+ def initialize gem_repository, dry_run = false
+ @gem_repository = Pathname(gem_repository)
+ @dry_run = dry_run
+
+ @installed_specs = nil
+ end
+
+ ##
+ # Specs installed in this gem repository
+
+ def installed_specs # :nodoc:
+ @installed_specs ||= Gem::Specification.map { |s| s.full_name }
+ end
+
+ ##
+ # Are we doctoring a gem repository?
+
+ def gem_repository?
+ not installed_specs.empty?
+ end
+
+ ##
+ # Cleans up uninstalled files and invalid gem specifications
+
+ def doctor
+ @orig_home = Gem.dir
+ @orig_path = Gem.path
+
+ say "Checking #{@gem_repository}"
+
+ Gem.use_paths @gem_repository.to_s
+
+ unless gem_repository? then
+ say 'This directory does not appear to be a RubyGems repository, ' +
+ 'skipping'
+ say
+ return
+ end
+
+ doctor_children
+
+ say
+ ensure
+ Gem.use_paths @orig_home, *@orig_path
+ end
+
+ ##
+ # Cleans up children of this gem repository
+
+ def doctor_children # :nodoc:
+ REPOSITORY_EXTENSION_MAP.each do |sub_directory, extension|
+ doctor_child sub_directory, extension
+ end
+ end
+
+ ##
+ # Removes files in +sub_directory+ with +extension+
+
+ def doctor_child sub_directory, extension # :nodoc:
+ directory = @gem_repository + sub_directory
+
+ directory.each_child do |child|
+ next unless child.exist?
+
+ basename = child.basename(extension).to_s
+ next if installed_specs.include? basename
+ next if /^rubygems-\d/ =~ basename
+ next if 'specifications' == sub_directory and 'default' == basename
+
+ type = child.directory? ? 'directory' : 'file'
+
+ action = if @dry_run then
+ 'Extra'
+ else
+ child.rmtree
+ 'Removed'
+ end
+
+ say "#{action} #{type} #{sub_directory}/#{child.basename}"
+ end
+ rescue Errno::ENOENT
+ # ignore
+ end
+
+end
+
diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb
index 6c2e6ce5a3..7f9975678f 100644
--- a/lib/rubygems/installer.rb
+++ b/lib/rubygems/installer.rb
@@ -202,47 +202,24 @@ class Gem::Installer
# specifications/<gem-version>.gemspec #=> the Gem::Specification
def install
- verify_gem_home(options[:unpack])
-
- # If we're forcing the install then disable security unless the security
- # policy says that we only install signed gems.
- @security_policy = nil if @force and @security_policy and
- not @security_policy.only_signed
-
- unless @force
- ensure_required_ruby_version_met
- ensure_required_rubygems_version_met
- ensure_dependencies_met unless @ignore_dependencies
- end
+ pre_install_checks
run_pre_install_hooks
- Gem.ensure_gem_subdirectories gem_home
-
# Completely remove any previous gem files
- FileUtils.rm_rf(gem_dir)
+ FileUtils.rm_rf gem_dir
FileUtils.mkdir_p gem_dir
extract_files
- build_extensions
+ build_extensions
+ write_build_info_file
run_post_build_hooks
generate_bin
write_spec
-
- unless @build_args.empty?
- File.open spec.build_info_file, "w" do |f|
- @build_args.each { |a| f.puts a }
- end
- end
-
- # TODO should be always cache the file? Other classes have options
- # to controls if caching is done.
- cache_file = File.join(gem_home, "cache", "#{spec.full_name}.gem")
-
- FileUtils.cp gem, cache_file unless File.exist? cache_file
+ write_cache_file
say spec.post_install_message unless spec.post_install_message.nil?
@@ -255,7 +232,7 @@ class Gem::Installer
spec
# TODO This rescue is in the wrong place. What is raising this exception?
- # move this rescue to arround the code that actually might raise it.
+ # move this rescue to around the code that actually might raise it.
rescue Zlib::GzipFile::Error
raise Gem::InstallError, "gzip error installing #{gem}"
end
@@ -506,6 +483,21 @@ class Gem::Installer
end
end
+ ##
+ # Ensures the Gem::Specification written out for this gem is loadable upon
+ # installation.
+
+ def ensure_loadable_spec
+ ruby = spec.to_ruby_for_cache
+
+ begin
+ eval ruby
+ rescue StandardError, SyntaxError => e
+ raise Gem::InstallError,
+ "The specification for #{spec.full_name} is corrupt (#{e.class})"
+ end
+ end
+
# DOC: Missing docs or :nodoc:.
def ensure_required_ruby_version_met
if rrv = spec.required_ruby_version then
@@ -736,5 +728,59 @@ EOF
def dir
gem_dir.to_s
end
+
+ ##
+ # Performs various checks before installing the gem such as the install
+ # repository is writable and its directories exist, required ruby and
+ # rubygems versions are met and that dependencies are installed.
+ #
+ # Version and dependency checks are skipped if this install is forced.
+ #
+ # The dependent check will be skipped this install is ignoring dependencies.
+
+ def pre_install_checks
+ verify_gem_home options[:unpack]
+
+ # If we're forcing the install then disable security unless the security
+ # policy says that we only install signed gems.
+ @security_policy = nil if
+ @force and @security_policy and not @security_policy.only_signed
+
+ ensure_loadable_spec
+
+ Gem.ensure_gem_subdirectories gem_home
+
+ return true if @force
+
+ ensure_required_ruby_version_met
+ ensure_required_rubygems_version_met
+ ensure_dependencies_met unless @ignore_dependencies
+
+ true
+ end
+
+ ##
+ # Writes the file containing the arguments for building this gem's
+ # extensions.
+
+ def write_build_info_file
+ return if @build_args.empty?
+
+ open spec.build_info_file, 'w' do |io|
+ @build_args.each do |arg|
+ io.puts arg
+ end
+ end
+ end
+
+ ##
+ # Writes the .gem file to the cache directory
+
+ def write_cache_file
+ cache_file = File.join gem_home, 'cache', spec.file_name
+
+ FileUtils.cp @gem, cache_file unless File.exist? cache_file
+ end
+
end
diff --git a/lib/rubygems/validator.rb b/lib/rubygems/validator.rb
index f66b2c1f43..e5183d401f 100644
--- a/lib/rubygems/validator.rb
+++ b/lib/rubygems/validator.rb
@@ -58,13 +58,11 @@ class Gem::Validator
public
ErrorData = Struct.new :path, :problem do
-
def <=> other
return nil unless self.class === other
[path, problem] <=> [other.path, other.problem]
end
-
end
##
@@ -121,7 +119,6 @@ class Gem::Validator
File.readable? File.join(gem_directory, file_name)
}
- unreadable.map! { |entry, _| entry['path'] }
unreadable.sort.each do |path|
errors[gem_name][path] = "Unreadable file"
end
@@ -153,7 +150,9 @@ class Gem::Validator
end
errors.each do |name, subhash|
- errors[name] = subhash.map { |path, msg| ErrorData.new(path, msg) }.sort
+ errors[name] = subhash.map do |path, msg|
+ ErrorData.new path, msg
+ end.sort
end
errors
diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb
index 20e411a7e4..9efb056546 100644
--- a/test/rubygems/test_gem.rb
+++ b/test/rubygems/test_gem.rb
@@ -774,6 +774,45 @@ class TestGem < Gem::TestCase
assert_equal cwd, $LOAD_PATH.shift
end
+ def test_self_latest_spec_for
+ a1 = quick_spec 'a', 1
+ a2 = quick_spec 'a', 2
+ a3a = quick_spec 'a', '3.a'
+
+ util_setup_fake_fetcher
+ util_setup_spec_fetcher a1, a2, a3a
+
+ spec = Gem.latest_spec_for 'a'
+
+ assert_equal a2, spec
+ end
+
+ def test_self_latest_rubygems_version
+ r1 = quick_spec 'rubygems-update', '1.8.23'
+ r2 = quick_spec 'rubygems-update', '1.8.24'
+ r3 = quick_spec 'rubygems-update', '2.0.0.preview3'
+
+ util_setup_fake_fetcher
+ util_setup_spec_fetcher r1, r2, r3
+
+ version = Gem.latest_rubygems_version
+
+ assert_equal Gem::Version.new('1.8.24'), version
+ end
+
+ def test_self_latest_version_for
+ a1 = quick_spec 'a', 1
+ a2 = quick_spec 'a', 2
+ a3a = quick_spec 'a', '3.a'
+
+ util_setup_fake_fetcher
+ util_setup_spec_fetcher a1, a2, a3a
+
+ version = Gem.latest_version_for 'a'
+
+ assert_equal Gem::Version.new(2), version
+ end
+
def test_self_loaded_specs
foo = quick_spec 'foo'
install_gem foo
diff --git a/test/rubygems/test_gem_commands_check_command.rb b/test/rubygems/test_gem_commands_check_command.rb
index a71c1ebb92..b28748623e 100644
--- a/test/rubygems/test_gem_commands_check_command.rb
+++ b/test/rubygems/test_gem_commands_check_command.rb
@@ -9,10 +9,60 @@ class TestGemCommandsCheckCommand < Gem::TestCase
@cmd = Gem::Commands::CheckCommand.new
end
+ def gem name
+ spec = quick_gem name do |gem|
+ gem.files = %W[lib/#{name}.rb Rakefile]
+ end
+
+ write_file File.join(*%W[gems #{spec.full_name} lib #{name}.rb])
+ write_file File.join(*%W[gems #{spec.full_name} Rakefile])
+
+ spec
+ end
+
def test_initialize
assert_equal "check", @cmd.command
assert_equal "gem check", @cmd.program_name
assert_match(/Check/, @cmd.summary)
end
+ def test_handle_options
+ @cmd.handle_options %w[--no-alien --no-gems --doctor --dry-run]
+
+ assert @cmd.options[:doctor]
+ refute @cmd.options[:alien]
+ assert @cmd.options[:dry_run]
+ refute @cmd.options[:gems]
+ end
+
+ def test_handle_options_defaults
+ @cmd.handle_options []
+
+ assert @cmd.options[:alien]
+ assert @cmd.options[:gems]
+ refute @cmd.options[:doctor]
+ refute @cmd.options[:dry_run]
+ end
+
+ def test_doctor
+ a = gem 'a'
+ b = gem 'b'
+
+ FileUtils.rm b.spec_file
+
+ assert_path_exists b.gem_dir
+ refute_path_exists b.spec_file
+
+ Gem.use_paths @gemhome
+
+ capture_io do
+ use_ui @ui do
+ @cmd.doctor
+ end
+ end
+
+ refute_path_exists b.gem_dir
+ refute_path_exists b.spec_file
+ end
+
end
diff --git a/test/rubygems/test_gem_commands_push_command.rb b/test/rubygems/test_gem_commands_push_command.rb
index 5ff940bf42..41324b524e 100644
--- a/test/rubygems/test_gem_commands_push_command.rb
+++ b/test/rubygems/test_gem_commands_push_command.rb
@@ -1,14 +1,6 @@
require 'rubygems/test_case'
require 'rubygems/commands/push_command'
-module Gem
- class << self; remove_method :latest_rubygems_version; end
-
- def self.latest_rubygems_version
- Gem::Version.new Gem::VERSION
- end
-end
-
class TestGemCommandsPushCommand < Gem::TestCase
def setup
@@ -33,6 +25,23 @@ class TestGemCommandsPushCommand < Gem::TestCase
Gem::RemoteFetcher.fetcher = @fetcher
@cmd = Gem::Commands::PushCommand.new
+
+ class << Gem
+ alias_method :orig_latest_rubygems_version, :latest_rubygems_version
+
+ def latest_rubygems_version
+ Gem.rubygems_version
+ end
+ end
+ end
+
+ def teardown
+ super
+
+ class << Gem
+ remove_method :latest_rubygems_version
+ alias_method :latest_rubygems_version, :orig_latest_rubygems_version
+ end
end
def send_battery
diff --git a/test/rubygems/test_gem_doctor.rb b/test/rubygems/test_gem_doctor.rb
new file mode 100644
index 0000000000..ef702bcd67
--- /dev/null
+++ b/test/rubygems/test_gem_doctor.rb
@@ -0,0 +1,168 @@
+require 'rubygems/test_case'
+require 'rubygems/doctor'
+
+class TestGemDoctor < Gem::TestCase
+
+ def gem name
+ spec = quick_gem name do |gem|
+ gem.files = %W[lib/#{name}.rb Rakefile]
+ end
+
+ write_file File.join(*%W[gems #{spec.full_name} lib #{name}.rb])
+ write_file File.join(*%W[gems #{spec.full_name} Rakefile])
+
+ spec
+ end
+
+ def test_doctor
+ a = gem 'a'
+ b = gem 'b'
+ c = gem 'c'
+
+ Gem.use_paths @userhome, @gemhome
+
+ FileUtils.rm b.spec_file
+
+ open c.spec_file, 'w' do |io|
+ io.write 'this will raise an exception when evaluated.'
+ end
+
+ assert_path_exists File.join(a.gem_dir, 'Rakefile')
+ assert_path_exists File.join(a.gem_dir, 'lib', 'a.rb')
+
+ assert_path_exists b.gem_dir
+ refute_path_exists b.spec_file
+
+ assert_path_exists c.gem_dir
+ assert_path_exists c.spec_file
+
+ doctor = Gem::Doctor.new @gemhome
+
+ capture_io do
+ use_ui @ui do
+ doctor.doctor
+ end
+ end
+
+ assert_path_exists File.join(a.gem_dir, 'Rakefile')
+ assert_path_exists File.join(a.gem_dir, 'lib', 'a.rb')
+
+ refute_path_exists b.gem_dir
+ refute_path_exists b.spec_file
+
+ refute_path_exists c.gem_dir
+ refute_path_exists c.spec_file
+
+ expected = <<-OUTPUT
+Checking #{@gemhome}
+Removed directory gems/b-2
+Removed directory gems/c-2
+Removed file specifications/c-2.gemspec
+
+ OUTPUT
+
+ assert_equal expected, @ui.output
+
+ assert_equal Gem.dir, @userhome
+ assert_equal Gem.path, [@gemhome, @userhome]
+ end
+
+ def test_doctor_dry_run
+ a = gem 'a'
+ b = gem 'b'
+ c = gem 'c'
+
+ Gem.use_paths @userhome, @gemhome
+
+ FileUtils.rm b.spec_file
+
+ open c.spec_file, 'w' do |io|
+ io.write 'this will raise an exception when evaluated.'
+ end
+
+ assert_path_exists File.join(a.gem_dir, 'Rakefile')
+ assert_path_exists File.join(a.gem_dir, 'lib', 'a.rb')
+
+ assert_path_exists b.gem_dir
+ refute_path_exists b.spec_file
+
+ assert_path_exists c.gem_dir
+ assert_path_exists c.spec_file
+
+ doctor = Gem::Doctor.new @gemhome, true
+
+ capture_io do
+ use_ui @ui do
+ doctor.doctor
+ end
+ end
+
+ assert_path_exists File.join(a.gem_dir, 'Rakefile')
+ assert_path_exists File.join(a.gem_dir, 'lib', 'a.rb')
+
+ assert_path_exists b.gem_dir
+ refute_path_exists b.spec_file
+
+ assert_path_exists c.gem_dir
+ assert_path_exists c.spec_file
+
+ expected = <<-OUTPUT
+Checking #{@gemhome}
+Extra directory gems/b-2
+Extra directory gems/c-2
+Extra file specifications/c-2.gemspec
+
+ OUTPUT
+
+ assert_equal expected, @ui.output
+
+ assert_equal Gem.dir, @userhome
+ assert_equal Gem.path, [@gemhome, @userhome]
+ end
+
+ def test_doctor_non_gem_home
+ other_dir = File.join @tempdir, 'other', 'dir'
+
+ FileUtils.mkdir_p other_dir
+
+ doctor = Gem::Doctor.new @tempdir
+
+ capture_io do
+ use_ui @ui do
+ doctor.doctor
+ end
+ end
+
+ assert_path_exists other_dir
+
+ expected = <<-OUTPUT
+Checking #{@tempdir}
+This directory does not appear to be a RubyGems repository, skipping
+
+ OUTPUT
+
+ assert_equal expected, @ui.output
+ end
+
+ def test_doctor_child_missing
+ doctor = Gem::Doctor.new @gemhome
+
+ doctor.doctor_child 'missing', ''
+
+ assert true # count
+ end
+
+ def test_gem_repository_eh
+ doctor = Gem::Doctor.new @gemhome
+
+ refute doctor.gem_repository?, 'no gems installed'
+
+ quick_spec 'a'
+
+ doctor = Gem::Doctor.new @gemhome
+
+ assert doctor.gem_repository?, 'gems installed'
+ end
+
+end
+
diff --git a/test/rubygems/test_gem_installer.rb b/test/rubygems/test_gem_installer.rb
index 0683001f33..98f1878dfb 100644
--- a/test/rubygems/test_gem_installer.rb
+++ b/test/rubygems/test_gem_installer.rb
@@ -245,6 +245,34 @@ load Gem.bin_path('a', 'executable', version)
assert_equal 'a requires b (> 2)', e.message
end
+ def test_ensure_loadable_spec
+ a, a_gem = util_gem 'a', 2 do |s|
+ s.add_dependency 'garbage ~> 5'
+ end
+
+ installer = Gem::Installer.new a_gem
+
+ e = assert_raises Gem::InstallError do
+ installer.ensure_loadable_spec
+ end
+
+ assert_equal "The specification for #{a.full_name} is corrupt " +
+ "(SyntaxError)", e.message
+ end
+
+ def test_ensure_loadable_spec_security_policy
+ a, a_gem = util_gem 'a', 2 do |s|
+ s.add_dependency 'garbage ~> 5'
+ end
+
+ policy = Gem::Security::HighSecurity
+ installer = Gem::Installer.new a_gem, :security_policy => policy
+
+ assert_raises Gem::Security::Exception do
+ installer.ensure_loadable_spec
+ end
+ end
+
def test_extract_files
@installer.extract_files
@@ -818,45 +846,6 @@ load Gem.bin_path('a', 'executable', version)
"code.rb from prior install of same gem shouldn't remain here")
end
- def test_install_check_dependencies
- @spec.add_dependency 'b', '> 5'
- util_setup_gem
-
- use_ui @ui do
- assert_raises Gem::InstallError do
- @installer.install
- end
- end
- end
-
- def test_install_check_dependencies_install_dir
- gemhome2 = "#{@gemhome}2"
- @spec.add_dependency 'd'
-
- quick_gem 'd', 2
-
- FileUtils.mv @gemhome, gemhome2
-
- # Don't leak any already activated gems into the installer, require
- # that it work everything out on it's own.
- Gem::Specification.reset
-
- util_setup_gem
-
- @installer = Gem::Installer.new @gem, :install_dir => gemhome2
-
- gem_home = Gem.dir
-
- build_rake_in do
- use_ui @ui do
- @installer.install
- end
- end
-
- assert File.exist?(File.join(gemhome2, 'gems', @spec.full_name))
- assert_equal gem_home, Gem.dir
- end
-
def test_install_force
use_ui @ui do
installer = Gem::Installer.new old_ruby_required, :force => true
@@ -867,30 +856,6 @@ load Gem.bin_path('a', 'executable', version)
assert File.exist?(gem_dir)
end
- def test_install_ignore_dependencies
- Dir.mkdir util_inst_bindir
- @spec.add_dependency 'b', '> 5'
- util_setup_gem
- @installer.ignore_dependencies = true
-
- build_rake_in do
- use_ui @ui do
- assert_equal @spec, @installer.install
- end
- end
-
- gemdir = File.join @gemhome, 'gems', @spec.full_name
- assert File.exist?(gemdir)
-
- exe = File.join(gemdir, 'bin', 'executable')
- assert File.exist?(exe)
- exe_mode = File.stat(exe).mode & 0111
- assert_equal 0111, exe_mode, "0%o" % exe_mode unless win_platform?
- assert File.exist?(File.join(gemdir, 'lib', 'code.rb'))
-
- assert File.exist?(File.join(@gemhome, 'specifications', @spec.spec_name))
- end
-
def test_install_missing_dirs
FileUtils.rm_f File.join(Gem.dir, 'cache')
FileUtils.rm_f File.join(Gem.dir, 'docs')
@@ -999,18 +964,78 @@ load Gem.bin_path('a', 'executable', version)
assert_match %r|I am a shiny gem!|, @ui.output
end
- def test_install_wrong_ruby_version
+ def test_installation_satisfies_dependency_eh
+ quick_spec 'a'
+
+ dep = Gem::Dependency.new 'a', '>= 2'
+ assert @installer.installation_satisfies_dependency?(dep)
+
+ dep = Gem::Dependency.new 'a', '> 2'
+ refute @installer.installation_satisfies_dependency?(dep)
+ end
+
+ def test_pre_install_checks_dependencies
+ @spec.add_dependency 'b', '> 5'
+ util_setup_gem
+
+ use_ui @ui do
+ assert_raises Gem::InstallError do
+ @installer.install
+ end
+ end
+ end
+
+ def test_pre_install_checks_dependencies_ignore
+ @spec.add_dependency 'b', '> 5'
+ @installer.ignore_dependencies = true
+
+ build_rake_in do
+ use_ui @ui do
+ assert @installer.pre_install_checks
+ end
+ end
+ end
+
+ def test_pre_install_checks_dependencies_install_dir
+ gemhome2 = "#{@gemhome}2"
+ @spec.add_dependency 'd'
+
+ quick_gem 'd', 2
+
+ gem = File.join @gemhome, @spec.file_name
+
+ FileUtils.mv @gemhome, gemhome2
+ FileUtils.mkdir @gemhome
+
+ FileUtils.mv File.join(gemhome2, 'cache', @spec.file_name), gem
+
+ # Don't leak any already activated gems into the installer, require
+ # that it work everything out on it's own.
+ Gem::Specification.reset
+
+ installer = Gem::Installer.new gem, :install_dir => gemhome2
+
+ gem_home = Gem.dir
+
+ build_rake_in do
+ use_ui @ui do
+ assert installer.pre_install_checks
+ end
+ end
+ end
+
+ def test_pre_install_checks_ruby_version
use_ui @ui do
installer = Gem::Installer.new old_ruby_required
e = assert_raises Gem::InstallError do
- installer.install
+ installer.pre_install_checks
end
assert_equal 'old_ruby_required requires Ruby version = 1.4.6.',
e.message
end
end
- def test_install_wrong_rubygems_version
+ def test_pre_install_checks_wrong_rubygems_version
spec = quick_spec 'old_rubygems_required', '1' do |s|
s.required_rubygems_version = '< 0'
end
@@ -1022,23 +1047,13 @@ load Gem.bin_path('a', 'executable', version)
use_ui @ui do
@installer = Gem::Installer.new gem
e = assert_raises Gem::InstallError do
- @installer.install
+ @installer.pre_install_checks
end
assert_equal 'old_rubygems_required requires RubyGems version < 0. ' +
"Try 'gem update --system' to update RubyGems itself.", e.message
end
end
- def test_installation_satisfies_dependency_eh
- quick_spec 'a'
-
- dep = Gem::Dependency.new 'a', '>= 2'
- assert @installer.installation_satisfies_dependency?(dep)
-
- dep = Gem::Dependency.new 'a', '> 2'
- refute @installer.installation_satisfies_dependency?(dep)
- end
-
def test_shebang
util_make_exec @spec, "#!/usr/bin/ruby"
@@ -1190,6 +1205,46 @@ load Gem.bin_path('a', 'executable', version)
assert File.exist?(File.join(dest, 'bin', 'executable'))
end
+ def test_write_build_args
+ refute_path_exists @spec.build_info_file
+
+ @installer.build_args = %w[
+ --with-libyaml-dir /usr/local/Cellar/libyaml/0.1.4
+ ]
+
+ @installer.write_build_info_file
+
+ assert_path_exists @spec.build_info_file
+
+ expected = "--with-libyaml-dir\n/usr/local/Cellar/libyaml/0.1.4\n"
+
+ assert_equal expected, File.read(@spec.build_info_file)
+ end
+
+ def test_write_build_args_empty
+ refute_path_exists @spec.build_info_file
+
+ @installer.write_build_info_file
+
+ refute_path_exists @spec.build_info_file
+ end
+
+ def test_write_cache_file
+ cache_file = File.join @gemhome, 'cache', @spec.file_name
+ gem = File.join @gemhome, @spec.file_name
+
+ FileUtils.mv cache_file, gem
+ refute_path_exists cache_file
+
+ installer = Gem::Installer.new gem
+ installer.spec = @spec
+ installer.gem_home = @gemhome
+
+ installer.write_cache_file
+
+ assert_path_exists cache_file
+ end
+
def test_write_spec
FileUtils.rm @spec.spec_file
refute File.exist?(@spec.spec_file)