1require 'rubygems/command' 2require 'rubygems/command_manager' 3require 'rubygems/dependency_installer' 4require 'rubygems/install_update_options' 5require 'rubygems/local_remote_options' 6require 'rubygems/spec_fetcher' 7require 'rubygems/version_option' 8require 'rubygems/install_message' # must come before rdoc for messaging 9require 'rubygems/rdoc' 10 11class Gem::Commands::UpdateCommand < Gem::Command 12 13 include Gem::InstallUpdateOptions 14 include Gem::LocalRemoteOptions 15 include Gem::VersionOption 16 17 attr_reader :installer # :nodoc: 18 19 def initialize 20 super 'update', 'Update installed gems to the latest version', 21 :document => %w[rdoc ri], 22 :force => false 23 24 add_install_update_options 25 26 OptionParser.accept Gem::Version do |value| 27 Gem::Version.new value 28 29 value 30 end 31 32 add_option('--system [VERSION]', Gem::Version, 33 'Update the RubyGems system software') do |value, options| 34 value = true unless value 35 36 options[:system] = value 37 end 38 39 add_local_remote_options 40 add_platform_option 41 add_prerelease_option "as update targets" 42 43 @updated = [] 44 @installer = nil 45 end 46 47 def arguments # :nodoc: 48 "GEMNAME name of gem to update" 49 end 50 51 def defaults_str # :nodoc: 52 "--document --no-force --install-dir #{Gem.dir}" 53 end 54 55 def usage # :nodoc: 56 "#{program_name} GEMNAME [GEMNAME ...]" 57 end 58 59 def execute 60 hig = {} 61 62 if options[:system] then 63 update_rubygems 64 return 65 else 66 say "Updating installed gems" 67 68 hig = {} # highest installed gems 69 70 Gem::Specification.each do |spec| 71 if hig[spec.name].nil? or hig[spec.name].version < spec.version then 72 hig[spec.name] = spec 73 end 74 end 75 end 76 77 gems_to_update = which_to_update hig, options[:args].uniq 78 79 updated = update_gems gems_to_update 80 81 if updated.empty? then 82 say "Nothing to update" 83 else 84 say "Gems updated: #{updated.map { |spec| spec.name }.join ' '}" 85 end 86 end 87 88 def update_gem name, version = Gem::Requirement.default 89 return if @updated.any? { |spec| spec.name == name } 90 91 @installer ||= Gem::DependencyInstaller.new options 92 93 success = false 94 95 say "Updating #{name}" 96 begin 97 @installer.install name, Gem::Requirement.new(version) 98 success = true 99 rescue Gem::InstallError => e 100 alert_error "Error installing #{name}:\n\t#{e.message}" 101 success = false 102 end 103 104 @installer.installed_gems.each do |spec| 105 @updated << spec 106 end 107 end 108 109 def update_gems gems_to_update 110 gems_to_update.uniq.sort.each do |(name, version)| 111 update_gem name, version 112 end 113 114 @updated 115 end 116 117 ## 118 # Update RubyGems software to the latest version. 119 120 def update_rubygems 121 unless options[:args].empty? then 122 alert_error "Gem names are not allowed with the --system option" 123 terminate_interaction 1 124 end 125 126 options[:user_install] = false 127 128 # TODO: rename version and other variable name conflicts 129 # TODO: get rid of all this indirection on name and other BS 130 131 version = options[:system] 132 if version == true then 133 version = Gem::Version.new Gem::VERSION 134 requirement = Gem::Requirement.new ">= #{Gem::VERSION}" 135 else 136 version = Gem::Version.new version 137 requirement = Gem::Requirement.new version 138 end 139 140 rubygems_update = Gem::Specification.new 141 rubygems_update.name = 'rubygems-update' 142 rubygems_update.version = version 143 144 hig = { 145 'rubygems-update' => rubygems_update 146 } 147 148 gems_to_update = which_to_update hig, options[:args], :system 149 name, up_ver = gems_to_update.first 150 current_ver = Gem.rubygems_version 151 152 target = if options[:system] == true then 153 up_ver 154 else 155 version 156 end 157 158 if current_ver == target then 159 # if options[:system] != true and version == current_ver then 160 say "Latest version currently installed. Aborting." 161 terminate_interaction 162 end 163 164 update_gem name, target 165 166 installed_gems = Gem::Specification.find_all_by_name 'rubygems-update', requirement 167 version = installed_gems.last.version 168 169 args = [] 170 args << '--prefix' << Gem.prefix if Gem.prefix 171 # TODO use --document for >= 1.9 , --no-rdoc --no-ri < 1.9 172 args << '--no-rdoc' unless options[:document].include? 'rdoc' 173 args << '--no-ri' unless options[:document].include? 'ri' 174 args << '--no-format-executable' if options[:no_format_executable] 175 176 update_dir = File.join Gem.dir, 'gems', "rubygems-update-#{version}" 177 178 Dir.chdir update_dir do 179 say "Installing RubyGems #{version}" 180 setup_cmd = "#{Gem.ruby} setup.rb #{args.join ' '}" 181 182 # Make sure old rubygems isn't loaded 183 old = ENV["RUBYOPT"] 184 ENV.delete("RUBYOPT") if old 185 installed = system setup_cmd 186 say "RubyGems system software updated" if installed 187 ENV["RUBYOPT"] = old if old 188 end 189 end 190 191 def which_to_update highest_installed_gems, gem_names, system = false 192 result = [] 193 194 highest_installed_gems.each do |l_name, l_spec| 195 next if not gem_names.empty? and 196 gem_names.all? { |name| /#{name}/ !~ l_spec.name } 197 198 dependency = Gem::Dependency.new l_spec.name, "> #{l_spec.version}" 199 dependency.prerelease = options[:prerelease] 200 201 fetcher = Gem::SpecFetcher.fetcher 202 203 spec_tuples, _ = fetcher.search_for_dependency dependency 204 205 matching_gems = spec_tuples.select do |g,_| 206 g.name == l_name and g.match_platform? 207 end 208 209 highest_remote_gem = matching_gems.sort_by { |g,_| g.version }.last 210 211 highest_remote_gem ||= [Gem::NameTuple.null] 212 highest_remote_ver = highest_remote_gem.first.version 213 214 if system or (l_spec.version < highest_remote_ver) then 215 result << [l_spec.name, [l_spec.version, highest_remote_ver].max] 216 end 217 end 218 219 result 220 end 221 222end 223 224