From 0dc342de848a642ecce8db697b8fecd83a63e117 Mon Sep 17 00:00:00 2001 From: yugui Date: Mon, 25 Aug 2008 15:02:05 +0000 Subject: added tag v1_9_0_4 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/tags/v1_9_0_4@18845 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- trunk/lib/rubygems/uninstaller.rb | 208 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 trunk/lib/rubygems/uninstaller.rb (limited to 'trunk/lib/rubygems/uninstaller.rb') diff --git a/trunk/lib/rubygems/uninstaller.rb b/trunk/lib/rubygems/uninstaller.rb new file mode 100644 index 0000000000..2ad961972b --- /dev/null +++ b/trunk/lib/rubygems/uninstaller.rb @@ -0,0 +1,208 @@ +#-- +# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others. +# All rights reserved. +# See LICENSE.txt for permissions. +#++ + +require 'fileutils' +require 'rubygems' +require 'rubygems/dependency_list' +require 'rubygems/doc_manager' +require 'rubygems/user_interaction' + +## +# An Uninstaller. + +class Gem::Uninstaller + + include Gem::UserInteraction + + ## + # Constructs an Uninstaller instance + # + # gem:: [String] The Gem name to uninstall + + def initialize(gem, options = {}) + @gem = gem + @version = options[:version] || Gem::Requirement.default + gem_home = options[:install_dir] || Gem.dir + @gem_home = File.expand_path gem_home + @force_executables = options[:executables] + @force_all = options[:all] + @force_ignore = options[:ignore] + @bin_dir = options[:bin_dir] + end + + ## + # 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) + + 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 + 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) + else + say "Error: must enter a number [1-#{list.size+1}]" + end + else + remove(list[0], list.dup) + remove_executables(list.last) + end + end + + ## + # Removes installed executables and batch files (windows only) for + # +gemspec+. + + def remove_executables(gemspec) + return if gemspec.nil? + + 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| + spec.version == gemspec.version + } + + executables = gemspec.executables.clone + + list.each do |spec| + spec.executables.each do |exe_name| + executables.delete(exe_name) + end + end + + return if executables.size == 0 + + answer = if @force_executables.nil? then + ask_yes_no("Remove executables:\n" \ + "\t#{gemspec.executables.join(", ")}\n\nin addition to the gem?", + true) # " # appease ruby-mode - don't ask + else + @force_executables + end + + unless answer then + say "Executables and scripts will remain installed." + else + raise Gem::FilePermissionError, bindir unless File.writable? bindir + + gemspec.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") + end + end + end + end + + ## + # Removes all gems in +list+. + # + # NOTE: removes uninstalled gems from +list+. + + def remove_all(list) + list.dup.each { |spec| remove spec, list } + end + + ## + # spec:: the spec of the gem to be uninstalled + # list:: the list of all such gems + # + # Warning: this method modifies the +list+ parameter. Once it has + # 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? spec then + e = Gem::GemNotInHomeException.new \ + "Gem is not installed in directory #{@gem_home}" + e.spec = spec + + raise e + end + + raise Gem::FilePermissionError, spec.installation_path unless + File.writable?(spec.installation_path) + + FileUtils.rm_rf spec.full_gem_path + + original_platform_name = [ + spec.name, spec.version, spec.original_platform].join '-' + + spec_dir = File.join spec.installation_path, 'specifications' + gemspec = File.join spec_dir, "#{spec.full_name}.gemspec" + + unless File.exist? gemspec then + gemspec = File.join spec_dir, "#{original_platform_name}.gemspec" + end + + FileUtils.rm_rf gemspec + + cache_dir = File.join spec.installation_path, 'cache' + gem = File.join cache_dir, "#{spec.full_name}.gem" + + unless File.exist? gem then + gem = File.join cache_dir, "#{original_platform_name}.gem" + end + + FileUtils.rm_rf gem + + Gem::DocManager.new(spec).uninstall_doc + + say "Successfully uninstalled #{spec.full_name}" + + list.delete spec + end + + def path_ok?(spec) + full_path = File.join @gem_home, 'gems', spec.full_name + original_path = File.join @gem_home, 'gems', spec.original_name + + full_path == spec.full_gem_path || original_path == spec.full_gem_path + end + + 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.ok_to_remove?(spec.full_name) || ask_if_ok(spec) + end + + def ask_if_ok(spec) + msg = [''] + msg << 'You have requested to uninstall the gem:' + msg << "\t#{spec.full_name}" + spec.dependent_gems.each do |gem,dep,satlist| + msg << + ("#{gem.name}-#{gem.version} depends on " + + "[#{dep.name} (#{dep.version_requirements})]") + end + msg << 'If you remove this gems, one or more dependencies will not be met.' + msg << 'Continue with Uninstall?' + return ask_yes_no(msg.join("\n"), true) + end + +end + -- cgit v1.2.3