From b948b8188dd59c40105f5a9f3a89e98f52b47029 Mon Sep 17 00:00:00 2001 From: Kouhei Sutou Date: Sun, 11 Nov 2012 19:25:05 +0900 Subject: [PATCH] Reject uninstalling a default gem Note: Gem::Specification#default_gem? is suitable name? Should it be private? --- lib/rubygems/specification.rb | 10 +++++++++- lib/rubygems/test_case.rb | 1 + lib/rubygems/uninstaller.rb | 16 ++++++++++++++-- .../test_gem_commands_uninstall_command.rb | 19 +++++++++++++++++++ 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb index a3d621d16179..8f6ebe94ee1d 100644 --- a/lib/rubygems/specification.rb +++ b/lib/rubygems/specification.rb @@ -612,6 +612,10 @@ def test_files= files attr_accessor :specification_version class << self + def default_specifications_dir + File.join(Gem.default_dir, "specifications", "default") + end + private def each_spec(search_dirs) # :nodoc: search_dirs.each { |dir| @@ -625,7 +629,7 @@ def each_spec(search_dirs) # :nodoc: end def each_default(&block) # :nodoc: - each_spec([File.join(Gem.default_dir, "specifications", "default")], + each_spec([default_specifications_dir], &block) end @@ -2508,6 +2512,10 @@ def reset_nil_attributes_to_default instance_variable_set "@#{attribute}", value end + + def default_gem? + loaded_from && + File.dirname(loaded_from) == self.class.default_specifications_dir end extend Gem::Deprecate diff --git a/lib/rubygems/test_case.rb b/lib/rubygems/test_case.rb index 1bf9c73d6acd..8cf5faf6a185 100644 --- a/lib/rubygems/test_case.rb +++ b/lib/rubygems/test_case.rb @@ -516,6 +516,7 @@ def new_spec name, version, deps = nil, *files def new_default_spec(name, version, deps = nil, *files) spec = new_spec(name, version, deps) + spec.loaded_from = File.join(@default_spec_dir, spec.spec_name) spec.files = files lib_dir = File.join(@tempdir, "default_gems", "lib") diff --git a/lib/rubygems/uninstaller.rb b/lib/rubygems/uninstaller.rb index 9fdcf0e866f9..b1500b07480a 100644 --- a/lib/rubygems/uninstaller.rb +++ b/lib/rubygems/uninstaller.rb @@ -74,14 +74,26 @@ def initialize(gem, options = {}) def uninstall list = Gem::Specification.find_all_by_name(@gem, @version) + default_specs, list = list.partition do |spec| + spec.default_gem? + end + list, other_repo_specs = list.partition do |spec| @gem_home == spec.base_dir or (@user_install and spec.base_dir == Gem.user_dir) end if list.empty? then - raise Gem::InstallError, "gem #{@gem.inspect} is not installed" if - other_repo_specs.empty? + if other_repo_specs.empty? + if default_specs.empty? + raise Gem::InstallError, "gem #{@gem.inspect} is not installed" + else + message = + "gem #{@gem.inspect} cannot be uninstalled " + + "because it is a default gem" + raise Gem::InstallError, message + end + end other_repos = other_repo_specs.map { |spec| spec.base_dir }.uniq diff --git a/test/rubygems/test_gem_commands_uninstall_command.rb b/test/rubygems/test_gem_commands_uninstall_command.rb index 9a2b615fa267..964ce85cc34b 100644 --- a/test/rubygems/test_gem_commands_uninstall_command.rb +++ b/test/rubygems/test_gem_commands_uninstall_command.rb @@ -174,5 +174,24 @@ def test_execute_with_force_ignores_dependencies assert Gem::Specification.find_all_by_name('dep_x').length > 0 assert Gem::Specification.find_all_by_name('x').length == 0 end + + def test_execute_default_gem + default_gem_spec = new_default_spec("default", "2.0.0.0", + nil, "default/gem.rb") + install_default_specs(default_gem_spec) + + ui = Gem::MockGemUi.new + + @cmd.options[:args] = %w[default] + @cmd.options[:executables] = true + + use_ui ui do + e = assert_raises Gem::InstallError do + @cmd.execute + end + assert_equal "gem \"default\" cannot be uninstalled because it is a default gem", + e.message + end + end end