1require 'rubygems/command' 2 3## 4# Installs RubyGems itself. This command is ordinarily only available from a 5# RubyGems checkout or tarball. 6 7class Gem::Commands::SetupCommand < Gem::Command 8 HISTORY_HEADER = /^===\s*[\d.]+\s*\/\s*\d{4}-\d{2}-\d{2}\s*$/ 9 VERSION_MATCHER = /^===\s*([\d.]+)\s*\/\s*\d{4}-\d{2}-\d{2}\s*$/ 10 11 def initialize 12 require 'tmpdir' 13 14 super 'setup', 'Install RubyGems', 15 :format_executable => true, :document => %w[ri], 16 :site_or_vendor => :sitelibdir, 17 :destdir => '', :prefix => '', :previous_version => '' 18 19 add_option '--previous-version=VERSION', 20 'Previous version of rubygems', 21 'Used for changelog processing' do |version, options| 22 options[:previous_version] = version 23 end 24 25 add_option '--prefix=PREFIX', 26 'Prefix path for installing RubyGems', 27 'Will not affect gem repository location' do |prefix, options| 28 options[:prefix] = File.expand_path prefix 29 end 30 31 add_option '--destdir=DESTDIR', 32 'Root directory to install RubyGems into', 33 'Mainly used for packaging RubyGems' do |destdir, options| 34 options[:destdir] = File.expand_path destdir 35 end 36 37 add_option '--[no-]vendor', 38 'Install into vendorlibdir not sitelibdir' do |vendor, options| 39 options[:site_or_vendor] = vendor ? :vendorlibdir : :sitelibdir 40 end 41 42 add_option '--[no-]format-executable', 43 'Makes `gem` match ruby', 44 'If ruby is ruby18, gem will be gem18' do |value, options| 45 options[:format_executable] = value 46 end 47 48 add_option '--[no-]document [TYPES]', Array, 49 'Generate documentation for RubyGems.', 50 'List the documentation types you wish to', 51 'generate. For example: rdoc,ri' do |value, options| 52 options[:document] = case value 53 when nil then %w[rdoc ri] 54 when false then [] 55 else value 56 end 57 end 58 59 add_option '--[no-]rdoc', 60 'Generate RDoc documentation for RubyGems' do |value, options| 61 if value then 62 options[:document] << 'rdoc' 63 else 64 options[:document].delete 'rdoc' 65 end 66 67 options[:document].uniq! 68 end 69 70 add_option '--[no-]ri', 71 'Generate RI documentation for RubyGems' do |value, options| 72 if value then 73 options[:document] << 'ri' 74 else 75 options[:document].delete 'ri' 76 end 77 78 options[:document].uniq! 79 end 80 81 @verbose = nil 82 end 83 84 def check_ruby_version 85 required_version = Gem::Requirement.new '>= 1.8.7' 86 87 unless required_version.satisfied_by? Gem.ruby_version then 88 alert_error "Expected Ruby version #{required_version}, is #{Gem.ruby_version}" 89 terminate_interaction 1 90 end 91 end 92 93 def defaults_str # :nodoc: 94 "--format-executable --document ri" 95 end 96 97 def description # :nodoc: 98 <<-EOF 99Installs RubyGems itself. 100 101RubyGems installs RDoc for itself in GEM_HOME. By default this is: 102 #{Gem.dir} 103 104If you prefer a different directory, set the GEM_HOME environment variable. 105 106RubyGems will install the gem command with a name matching ruby's 107prefix and suffix. If ruby was installed as `ruby18`, gem will be 108installed as `gem18`. 109 110By default, this RubyGems will install gem as: 111 #{Gem.default_exec_format % 'gem'} 112 EOF 113 end 114 115 def execute 116 @verbose = Gem.configuration.really_verbose 117 118 install_destdir = options[:destdir] 119 120 unless install_destdir.empty? then 121 ENV['GEM_HOME'] ||= File.join(install_destdir, 122 Gem.default_dir.gsub(/^[a-zA-Z]:/, '')) 123 end 124 125 check_ruby_version 126 127 require 'fileutils' 128 if Gem.configuration.really_verbose then 129 extend FileUtils::Verbose 130 else 131 extend FileUtils 132 end 133 134 lib_dir, bin_dir = make_destination_dirs install_destdir 135 136 install_lib lib_dir 137 138 install_executables bin_dir 139 140 remove_old_bin_files bin_dir 141 142 remove_old_lib_files lib_dir 143 144 say "RubyGems #{Gem::VERSION} installed" 145 146 uninstall_old_gemcutter 147 148 documentation_success = install_rdoc 149 150 say 151 if @verbose then 152 say "-" * 78 153 say 154 end 155 156 if options[:previous_version].empty? 157 options[:previous_version] = Gem::VERSION.sub(/[0-9]+$/, '0') 158 end 159 160 options[:previous_version] = Gem::Version.new(options[:previous_version]) 161 162 show_release_notes 163 164 say 165 say "-" * 78 166 say 167 168 say "RubyGems installed the following executables:" 169 say @bin_file_names.map { |name| "\t#{name}\n" } 170 say 171 172 unless @bin_file_names.grep(/#{File::SEPARATOR}gem$/) then 173 say "If `gem` was installed by a previous RubyGems installation, you may need" 174 say "to remove it by hand." 175 say 176 end 177 178 if documentation_success 179 if options[:document].include? 'rdoc' then 180 say "Rdoc documentation was installed. You may now invoke:" 181 say " gem server" 182 say "and then peruse beautifully formatted documentation for your gems" 183 say "with your web browser." 184 say "If you do not wish to install this documentation in the future, use the" 185 say "--no-document flag, or set it as the default in your ~/.gemrc file. See" 186 say "'gem help env' for details." 187 say 188 end 189 190 if options[:document].include? 'ri' then 191 say "Ruby Interactive (ri) documentation was installed. ri is kind of like man " 192 say "pages for ruby libraries. You may access it like this:" 193 say " ri Classname" 194 say " ri Classname.class_method" 195 say " ri Classname#instance_method" 196 say "If you do not wish to install this documentation in the future, use the" 197 say "--no-document flag, or set it as the default in your ~/.gemrc file. See" 198 say "'gem help env' for details." 199 say 200 end 201 end 202 end 203 204 def install_executables(bin_dir) 205 say "Installing gem executable" if @verbose 206 207 @bin_file_names = [] 208 209 Dir.chdir 'bin' do 210 bin_files = Dir['*'] 211 212 bin_files.delete 'update_rubygems' 213 214 bin_files.each do |bin_file| 215 bin_file_formatted = if options[:format_executable] then 216 Gem.default_exec_format % bin_file 217 else 218 bin_file 219 end 220 221 dest_file = File.join bin_dir, bin_file_formatted 222 bin_tmp_file = File.join Dir.tmpdir, "#{bin_file}.#{$$}" 223 224 begin 225 bin = File.readlines bin_file 226 bin[0] = "#!#{Gem.ruby}\n" 227 228 File.open bin_tmp_file, 'w' do |fp| 229 fp.puts bin.join 230 end 231 232 install bin_tmp_file, dest_file, :mode => 0755 233 @bin_file_names << dest_file 234 ensure 235 rm bin_tmp_file 236 end 237 238 next unless Gem.win_platform? 239 240 begin 241 bin_cmd_file = File.join Dir.tmpdir, "#{bin_file}.bat" 242 243 File.open bin_cmd_file, 'w' do |file| 244 file.puts <<-TEXT 245@ECHO OFF 246IF NOT "%~f0" == "~f0" GOTO :WinNT 247@"#{File.basename(Gem.ruby).chomp('"')}" "#{dest_file}" %1 %2 %3 %4 %5 %6 %7 %8 %9 248GOTO :EOF 249:WinNT 250@"#{File.basename(Gem.ruby).chomp('"')}" "%~dpn0" %* 251TEXT 252 end 253 254 install bin_cmd_file, "#{dest_file}.bat", :mode => 0755 255 ensure 256 rm bin_cmd_file 257 end 258 end 259 end 260 end 261 262 def install_file file, dest_dir 263 dest_file = File.join dest_dir, file 264 dest_dir = File.dirname dest_file 265 mkdir_p dest_dir unless File.directory? dest_dir 266 267 install file, dest_file, :mode => 0644 268 end 269 270 def install_lib(lib_dir) 271 say "Installing RubyGems" if @verbose 272 273 lib_files = rb_files_in 'lib' 274 pem_files = pem_files_in 'lib' 275 276 Dir.chdir 'lib' do 277 lib_files.each do |lib_file| 278 install_file lib_file, lib_dir 279 end 280 281 pem_files.each do |pem_file| 282 install_file pem_file, lib_dir 283 end 284 end 285 end 286 287 def install_rdoc 288 gem_doc_dir = File.join Gem.dir, 'doc' 289 rubygems_name = "rubygems-#{Gem::VERSION}" 290 rubygems_doc_dir = File.join gem_doc_dir, rubygems_name 291 292 begin 293 Gem.ensure_gem_subdirectories Gem.dir 294 rescue SystemCallError 295 # ignore 296 end 297 298 if File.writable? gem_doc_dir and 299 (not File.exist? rubygems_doc_dir or 300 File.writable? rubygems_doc_dir) then 301 say "Removing old RubyGems RDoc and ri" if @verbose 302 Dir[File.join(Gem.dir, 'doc', 'rubygems-[0-9]*')].each do |dir| 303 rm_rf dir 304 end 305 306 require 'rubygems/rdoc' 307 308 fake_spec = Gem::Specification.new 'rubygems', Gem::VERSION 309 def fake_spec.full_gem_path 310 File.expand_path '../../../..', __FILE__ 311 end 312 313 generate_ri = options[:document].include? 'ri' 314 generate_rdoc = options[:document].include? 'rdoc' 315 316 rdoc = Gem::RDoc.new fake_spec, generate_rdoc, generate_ri 317 rdoc.generate 318 319 return true 320 elsif @verbose then 321 say "Skipping RDoc generation, #{gem_doc_dir} not writable" 322 say "Set the GEM_HOME environment variable if you want RDoc generated" 323 end 324 325 return false 326 end 327 328 def make_destination_dirs(install_destdir) 329 lib_dir, bin_dir = Gem.default_rubygems_dirs 330 331 unless lib_dir 332 lib_dir, bin_dir = generate_default_dirs(install_destdir) 333 end 334 335 mkdir_p lib_dir 336 mkdir_p bin_dir 337 338 return lib_dir, bin_dir 339 end 340 341 def generate_default_dirs(install_destdir) 342 prefix = options[:prefix] 343 site_or_vendor = options[:site_or_vendor] 344 345 if prefix.empty? then 346 lib_dir = Gem::ConfigMap[site_or_vendor] 347 bin_dir = Gem::ConfigMap[:bindir] 348 else 349 # Apple installed RubyGems into libdir, and RubyGems <= 1.1.0 gets 350 # confused about installation location, so switch back to 351 # sitelibdir/vendorlibdir. 352 if defined?(APPLE_GEM_HOME) and 353 # just in case Apple and RubyGems don't get this patched up proper. 354 (prefix == Gem::ConfigMap[:libdir] or 355 # this one is important 356 prefix == File.join(Gem::ConfigMap[:libdir], 'ruby')) then 357 lib_dir = Gem::ConfigMap[site_or_vendor] 358 bin_dir = Gem::ConfigMap[:bindir] 359 else 360 lib_dir = File.join prefix, 'lib' 361 bin_dir = File.join prefix, 'bin' 362 end 363 end 364 365 unless install_destdir.empty? then 366 lib_dir = File.join install_destdir, lib_dir.gsub(/^[a-zA-Z]:/, '') 367 bin_dir = File.join install_destdir, bin_dir.gsub(/^[a-zA-Z]:/, '') 368 end 369 370 [lib_dir, bin_dir] 371 end 372 373 def pem_files_in dir 374 Dir.chdir dir do 375 Dir[File.join('**', '*pem')] 376 end 377 end 378 379 def rb_files_in dir 380 Dir.chdir dir do 381 Dir[File.join('**', '*rb')] 382 end 383 end 384 385 def remove_old_bin_files(bin_dir) 386 old_bin_files = { 387 'gem_mirror' => 'gem mirror', 388 'gem_server' => 'gem server', 389 'gemlock' => 'gem lock', 390 'gemri' => 'ri', 391 'gemwhich' => 'gem which', 392 'index_gem_repository.rb' => 'gem generate_index', 393 } 394 395 old_bin_files.each do |old_bin_file, new_name| 396 old_bin_path = File.join bin_dir, old_bin_file 397 next unless File.exist? old_bin_path 398 399 deprecation_message = "`#{old_bin_file}` has been deprecated. Use `#{new_name}` instead." 400 401 File.open old_bin_path, 'w' do |fp| 402 fp.write <<-EOF 403#!#{Gem.ruby} 404 405abort "#{deprecation_message}" 406 EOF 407 end 408 409 next unless Gem.win_platform? 410 411 File.open "#{old_bin_path}.bat", 'w' do |fp| 412 fp.puts %{@ECHO.#{deprecation_message}} 413 end 414 end 415 end 416 417 def remove_old_lib_files lib_dir 418 rubygems_dir = File.join lib_dir, 'rubygems' 419 lib_files = rb_files_in 'lib/rubygems' 420 421 old_lib_files = rb_files_in rubygems_dir 422 423 to_remove = old_lib_files - lib_files 424 425 to_remove.delete_if do |file| 426 file.start_with? 'defaults' 427 end 428 429 Dir.chdir rubygems_dir do 430 to_remove.each do |file| 431 FileUtils.rm_f file 432 433 warn "unable to remove old file #{file} please remove it by hand" if 434 File.exist? file 435 end 436 end 437 end 438 439 def show_release_notes 440 release_notes = File.join Dir.pwd, 'History.txt' 441 442 release_notes = 443 if File.exist? release_notes then 444 history = File.read release_notes 445 446 history.force_encoding Encoding::UTF_8 if 447 Object.const_defined? :Encoding 448 449 history = history.sub(/^# coding:.*?^=/m, '') 450 451 text = history.split(HISTORY_HEADER) 452 text.shift # correct an off-by-one generated by split 453 version_lines = history.scan(HISTORY_HEADER) 454 versions = history.scan(VERSION_MATCHER).flatten.map do |x| 455 Gem::Version.new(x) 456 end 457 458 history_string = "" 459 460 until versions.length == 0 or 461 versions.shift < options[:previous_version] do 462 history_string += version_lines.shift + text.shift 463 end 464 465 history_string 466 else 467 "Oh-no! Unable to find release notes!" 468 end 469 470 say release_notes 471 end 472 473 def uninstall_old_gemcutter 474 require 'rubygems/uninstaller' 475 476 ui = Gem::Uninstaller.new('gemcutter', :all => true, :ignore => true, 477 :version => '< 0.4') 478 ui.uninstall 479 rescue Gem::InstallError 480 end 481 482end 483 484