rubygems-update 0.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of rubygems-update might be problematic. Click here for more details.

Files changed (96) hide show
  1. data/ChangeLog +2335 -0
  2. data/README +54 -0
  3. data/Rakefile +293 -0
  4. data/Releases +98 -0
  5. data/TODO +7 -0
  6. data/bin/gem +11 -0
  7. data/bin/gem_server +111 -0
  8. data/bin/generate_yaml_index.rb +58 -0
  9. data/bin/update_rubygems +18 -0
  10. data/doc/doc.css +73 -0
  11. data/doc/makedoc.rb +4 -0
  12. data/examples/application/an-app.gemspec +26 -0
  13. data/examples/application/bin/myapp +3 -0
  14. data/examples/application/lib/somefunctionality.rb +3 -0
  15. data/gemspecs/README +4 -0
  16. data/gemspecs/cgikit-1.1.0.gemspec +18 -0
  17. data/gemspecs/jabber4r.gemspec +26 -0
  18. data/gemspecs/linguistics.gemspec +22 -0
  19. data/gemspecs/ook.gemspec +21 -0
  20. data/gemspecs/progressbar.gemspec +22 -0
  21. data/gemspecs/redcloth.gemspec +22 -0
  22. data/gemspecs/rublog.gemspec +23 -0
  23. data/gemspecs/ruby-doom.gemspec +21 -0
  24. data/gemspecs/rubyjdwp.gemspec +21 -0
  25. data/gemspecs/statistics.gemspec +21 -0
  26. data/lib/rubygems.rb +353 -0
  27. data/lib/rubygems/builder.rb +54 -0
  28. data/lib/rubygems/cmd_manager.rb +127 -0
  29. data/lib/rubygems/command.rb +191 -0
  30. data/lib/rubygems/config_file.rb +57 -0
  31. data/lib/rubygems/doc_manager.rb +94 -0
  32. data/lib/rubygems/format.rb +65 -0
  33. data/lib/rubygems/gem_commands.rb +925 -0
  34. data/lib/rubygems/gem_runner.rb +23 -0
  35. data/lib/rubygems/installer.rb +621 -0
  36. data/lib/rubygems/loadpath_manager.rb +108 -0
  37. data/lib/rubygems/old_format.rb +150 -0
  38. data/lib/rubygems/open-uri.rb +604 -0
  39. data/lib/rubygems/package.rb +740 -0
  40. data/lib/rubygems/remote_installer.rb +499 -0
  41. data/lib/rubygems/rubygems_version.rb +6 -0
  42. data/lib/rubygems/source_index.rb +130 -0
  43. data/lib/rubygems/specification.rb +613 -0
  44. data/lib/rubygems/user_interaction.rb +176 -0
  45. data/lib/rubygems/validator.rb +148 -0
  46. data/lib/rubygems/version.rb +279 -0
  47. data/lib/ubygems.rb +4 -0
  48. data/pkgs/sources/lib/sources.rb +6 -0
  49. data/pkgs/sources/sources.gemspec +14 -0
  50. data/post-install.rb +75 -0
  51. data/redist/session.gem +433 -0
  52. data/scripts/buildtests.rb +25 -0
  53. data/scripts/gemdoc.rb +62 -0
  54. data/scripts/runtest.rb +17 -0
  55. data/scripts/specdoc.rb +164 -0
  56. data/setup.rb +1360 -0
  57. data/test/bogussources.rb +5 -0
  58. data/test/data/legacy/keyedlist-0.4.0.ruby +11 -0
  59. data/test/data/legacy/keyedlist-0.4.0.yaml +16 -0
  60. data/test/data/lib/code.rb +1 -0
  61. data/test/data/one/README.one +1 -0
  62. data/test/data/one/lib/one.rb +3 -0
  63. data/test/data/one/one.gemspec +17 -0
  64. data/test/data/one/one.yaml +40 -0
  65. data/test/functional.rb +145 -0
  66. data/test/gemenvironment.rb +45 -0
  67. data/test/gemutilities.rb +18 -0
  68. data/test/insure_session.rb +46 -0
  69. data/test/mock/gems/gems/sources-0.0.1/lib/sources.rb +5 -0
  70. data/test/mock/gems/specifications/sources-0.0.1.gemspec +8 -0
  71. data/test/mockgemui.rb +45 -0
  72. data/test/onegem.rb +23 -0
  73. data/test/simple_gem.rb +66 -0
  74. data/test/test_builder.rb +13 -0
  75. data/test/test_cached_fetcher.rb +60 -0
  76. data/test/test_check_command.rb +28 -0
  77. data/test/test_command.rb +130 -0
  78. data/test/test_configfile.rb +36 -0
  79. data/test/test_format.rb +70 -0
  80. data/test/test_gemloadpaths.rb +45 -0
  81. data/test/test_gempaths.rb +115 -0
  82. data/test/test_loadmanager.rb +40 -0
  83. data/test/test_local_cache.rb +157 -0
  84. data/test/test_package.rb +600 -0
  85. data/test/test_parse_commands.rb +179 -0
  86. data/test/test_process_commands.rb +21 -0
  87. data/test/test_remote_fetcher.rb +162 -0
  88. data/test/test_remote_installer.rb +154 -0
  89. data/test/test_source_index.rb +58 -0
  90. data/test/test_specification.rb +286 -0
  91. data/test/test_validator.rb +53 -0
  92. data/test/test_version_comparison.rb +204 -0
  93. data/test/testgem.rc +6 -0
  94. data/test/user_capture.rb +1 -0
  95. data/test/yaml_data.rb +59 -0
  96. metadata +151 -0
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module Gem
4
+
5
+ class GemRunner
6
+
7
+ def run(args)
8
+ do_configuration(args)
9
+ Gem::CommandManager.instance.run(@cfg)
10
+ end
11
+
12
+ private
13
+
14
+ def do_configuration(args)
15
+ @cfg = Gem::ConfigFile.new(args)
16
+ Gem.use_paths(@cfg[:gemhome], @cfg[:gempath])
17
+ Command.extra_args = @cfg[:gem]
18
+ DocManager.configured_args = @cfg[:rdoc]
19
+ end
20
+
21
+ end
22
+
23
+ end
@@ -0,0 +1,621 @@
1
+ require 'pathname'
2
+ require 'rbconfig'
3
+ require 'rubygems/format'
4
+
5
+ module Gem
6
+
7
+ class DependencyRemovalException < Gem::Exception; end
8
+
9
+ ##
10
+ # The installer class processes RubyGem .gem files and installs the
11
+ # files contained in the .gem into the Gem.path.
12
+ #
13
+ class Installer
14
+
15
+ include UserInteraction
16
+
17
+ ##
18
+ # Constructs an Installer instance
19
+ #
20
+ # gem:: [String] The file name of the gem
21
+ #
22
+ def initialize(gem)
23
+ @gem = gem
24
+ end
25
+
26
+ ##
27
+ # Installs the gem in the Gem.path. This will fail (unless
28
+ # force=true) if a Gem has a requirement on another Gem that is
29
+ # not installed. The installation will install in the following
30
+ # structure:
31
+ #
32
+ # Gem.path/
33
+ # specifications/<gem-version>.gemspec #=> the extracted YAML gemspec
34
+ # gems/<gem-version>/... #=> the extracted Gem files
35
+ # cache/<gem-version>.gem #=> a cached copy of the installed Gem
36
+ #
37
+ # force:: [default = false] if false will fail if a required Gem is not installed,
38
+ # or if the Ruby version is too low for the gem
39
+ # install_dir:: [default = Gem.dir] directory that Gem is to be installed in
40
+ # install_stub:: [default = false] causes the installation of a library stub in the +site_ruby+ directory
41
+ #
42
+ # return:: [Gem::Specification] The specification for the newly installed Gem.
43
+ #
44
+ def install(force=false, install_dir=Gem.dir, install_stub=false)
45
+ require 'fileutils'
46
+ format = Gem::Format.from_file_by_path(@gem)
47
+ unless force
48
+ spec = format.spec
49
+ # Check the Ruby version.
50
+ if (rrv = spec.required_ruby_version)
51
+ unless rrv.satisfied_by?(Gem::Version.new(RUBY_VERSION))
52
+ raise "#{spec.name} requires Ruby version #{rrv}"
53
+ end
54
+ end
55
+ # Check the dependent gems.
56
+ spec.dependencies.each do |dep_gem|
57
+ # XXX: Does this take account of *versions*?
58
+ require_gem(dep_gem, false) #no autorequire
59
+ end
60
+ end
61
+
62
+ raise Gem::FilePermissionError.new(install_dir) unless File.writable?(install_dir)
63
+
64
+ # Build spec dir.
65
+ directory = File.join(install_dir, "gems", format.spec.full_name)
66
+ FileUtils.mkdir_p directory
67
+
68
+ extract_files(directory, format)
69
+ generate_bin_scripts(format.spec, install_dir)
70
+ #generate_library_stubs(format.spec) if install_stub
71
+ build_extensions(directory, format.spec)
72
+
73
+ # Build spec/cache/doc dir.
74
+ build_support_directories(install_dir)
75
+
76
+ # Write the spec and cache files.
77
+ write_spec(format.spec, File.join(install_dir, "specifications"))
78
+ unless(File.exist?(File.join(File.join(install_dir, "cache"), @gem.split(/\//).pop)))
79
+ FileUtils.cp(@gem, File.join(install_dir, "cache"))
80
+ end
81
+
82
+ format.spec.loaded_from = File.join(install_dir, 'specifications', format.spec.full_name+".gemspec")
83
+ return format.spec
84
+ end
85
+
86
+ #
87
+ # Unpacks the gem into the given directory.
88
+ #
89
+ def unpack(directory)
90
+ format = Gem::Format.from_file_by_path(@gem)
91
+ extract_files(directory, format)
92
+ end
93
+
94
+ # Given a root gem directory, build supporting directories for gem
95
+ # if they do not already exist
96
+ def build_support_directories(install_dir)
97
+ unless File.exist? File.join(install_dir, "specifications")
98
+ FileUtils.mkdir_p File.join(install_dir, "specifications")
99
+ end
100
+ unless File.exist? File.join(install_dir, "cache")
101
+ FileUtils.mkdir_p File.join(install_dir, "cache")
102
+ end
103
+ unless File.exist? File.join(install_dir, "doc")
104
+ FileUtils.mkdir_p File.join(install_dir, "doc")
105
+ end
106
+ end
107
+
108
+ ##
109
+ # Writes the .gemspec specification (in Ruby) to the supplied spec_path.
110
+ #
111
+ # spec:: [Gem::Specification] The Gem specification to output
112
+ # spec_path:: [String] The location (path) to write the gemspec to
113
+ #
114
+ def write_spec(spec, spec_path)
115
+ rubycode = spec.to_ruby
116
+ File.open(File.join(spec_path, spec.full_name+".gemspec"), "w") do |file|
117
+ file.puts rubycode
118
+ end
119
+ end
120
+
121
+ ##
122
+ # Creates windows .cmd files for easy running of commands
123
+ #
124
+ def generate_windows_script(bindir, filename)
125
+ if Config::CONFIG["arch"] =~ /dos|win32/i
126
+ script_name = filename + ".cmd"
127
+ File.open(File.join(bindir, File.basename(script_name)), "w") do |file|
128
+ file.puts "@ruby \"#{File.join(bindir,filename)}\" %*"
129
+ end
130
+ end
131
+ end
132
+
133
+ ##
134
+ # Creates the scripts to run the applications in the gem.
135
+ #
136
+ def generate_bin_scripts(spec, install_dir=Gem.dir)
137
+ if spec.executables && ! spec.executables.empty?
138
+ bindir = if(install_dir == Gem.default_dir)
139
+ Config::CONFIG['bindir']
140
+ else
141
+ File.join(install_dir, "bin")
142
+ end
143
+ Dir.mkdir(bindir) unless File.exist?(bindir)
144
+ raise Gem::FilePermissionError.new(bindir) unless File.writable?(bindir)
145
+ spec.executables.each do |filename|
146
+ File.open(File.join(bindir, File.basename(filename)), "w", 0755) do |file|
147
+ file.print(app_script_text(spec.name, spec.version.version, filename))
148
+ end
149
+ generate_windows_script(bindir, filename)
150
+ end
151
+ end
152
+ end
153
+
154
+ ##
155
+ # Returns the text for an application file.
156
+ #
157
+ def app_script_text(name, version, filename)
158
+ text = <<-TEXT
159
+ #!#{File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])}
160
+
161
+ #
162
+ # This file was generated by RubyGems.
163
+ #
164
+ # The application '#{name}' is installed as part of a gem, and
165
+ # this file is here to facilitate running it.
166
+ #
167
+
168
+ require 'rubygems'
169
+ version = "> 0"
170
+ if ARGV.size > 0 && ARGV[0][0]==95 && ARGV[0][-1]==95
171
+ if Gem::Version.correct?(ARGV[0][1..-2])
172
+ version = ARGV[0][1..-2]
173
+ ARGV.shift
174
+ end
175
+ end
176
+ require_gem '#{name}', version
177
+ load '#{filename}'
178
+ TEXT
179
+ text
180
+ end
181
+
182
+ ##
183
+ # Creates a file in the site_ruby directory that acts as a stub for the gem. Thus, if
184
+ # 'package' is installed as a gem, the user can just type <tt>require 'package'</tt> and
185
+ # the gem (latest version) will be loaded. This is like a backwards compatibility so that
186
+ # gems and non-gems can interact.
187
+ #
188
+ # Which files are stubified? Those included in the gem's 'autorequire' and 'library_stubs'
189
+ # attributes.
190
+ #
191
+ def generate_library_stubs(spec)
192
+ LibraryStubs.new(spec).generate
193
+ end
194
+
195
+ def build_extensions(directory, spec)
196
+ return unless spec.extensions.size > 0
197
+ say "Building native extensions. This could take a while..."
198
+ start_dir = Dir.pwd
199
+ dest_path = File.join(directory, spec.require_paths[0])
200
+ spec.extensions.each do |extension|
201
+ Dir.chdir File.join(directory, File.dirname(extension))
202
+ results = ["ruby #{File.basename(extension)} #{ARGV.join(" ")}"]
203
+ results << `ruby #{File.basename(extension)} #{ARGV.join(" ")}`
204
+ if File.exist?('Makefile')
205
+ mf = File.read('Makefile')
206
+ mf = mf.gsub(/^RUBYARCHDIR\s*=\s*\$.*/, "RUBYARCHDIR = #{dest_path}")
207
+ mf = mf.gsub(/^RUBYLIBDIR\s*=\s*\$.*/, "RUBYLIBDIR = #{dest_path}")
208
+ File.open('Makefile', 'wb') {|f| f.print mf}
209
+ make_program = ENV['make']
210
+ unless make_program
211
+ make_program = (/mswin/ =~ RUBY_PLATFORM) ? 'nmake' : 'make'
212
+ end
213
+ results << "#{make_program}"
214
+ results << `#{make_program}`
215
+ results << "#{make_program} install"
216
+ results << `#{make_program} install`
217
+ say results.join("\n")
218
+ else
219
+ File.open(File.join(Dir.pwd, 'gem_make.out'), 'wb') {|f| f.puts results.join("\n")}
220
+ raise "ERROR: Failed to build gem native extension.\nGem files will remain installed in #{directory} for inspection.\n #{results.join('\n')}\n\nResults logged to #{File.join(Dir.pwd, 'gem_make.out')}"
221
+ end
222
+ File.open('gem_make.out', 'wb') {|f| f.puts results.join("\n")}
223
+ end
224
+ Dir.chdir start_dir
225
+ end
226
+
227
+ ##
228
+ # Reads the YAML file index and then extracts each file
229
+ # into the supplied directory, building directories for the
230
+ # extracted files as needed.
231
+ #
232
+ # directory:: [String] The root directory to extract files into
233
+ # file:: [IO] The IO that contains the file data
234
+ #
235
+ def extract_files(directory, format)
236
+ require 'fileutils'
237
+ wd = Dir.getwd
238
+ Dir.chdir directory do
239
+ format.file_entries.each do |entry, file_data|
240
+ path = entry['path']
241
+ FileUtils.mkdir_p File.dirname(path)
242
+ File.open(path, "wb") do |out|
243
+ out.write file_data
244
+ end
245
+ end
246
+ end
247
+ end
248
+ end # class Installer
249
+
250
+
251
+ #
252
+ # This class represents a single library stub, which is characterised by a
253
+ #
254
+ class LibraryStub
255
+ SITELIBDIR = Pathname.new(Config::CONFIG['sitelibdir'])
256
+
257
+ #
258
+ # The 'autorequire' attribute in a gemspec is a special case: it represents a require
259
+ # target, not a relative path. We therefore offer this method of creating a library stub
260
+ # for the autorequire file.
261
+ #
262
+ # If the given spec doesn't have an 'autorequire' value, we return +nil+.
263
+ #
264
+ def self.from_autorequire(gemspec, require_paths)
265
+ require_target = gemspec.autorequire
266
+ return nil if require_target.nil?
267
+ gem_relpath = find_gem_relpath(require_paths, require_target, gemspec)
268
+ LibraryStub.new(gemspec.name, require_paths, gem_relpath, true)
269
+ end
270
+
271
+ #
272
+ # require_paths::
273
+ # ([Pathname]) The require paths in the gemspec.
274
+ # gem_relpath::
275
+ # (String) The path to the library file, relative to the root of the gem.
276
+ # autorequire::
277
+ # (Boolean) Whether this stub represents the gem's autorequire file.
278
+ #
279
+ def initialize(gem_name, require_paths, gem_relpath, autorequire=false)
280
+ @gem_name = gem_name
281
+ @lib_relpath = find_lib_relpath(require_paths, gem_relpath)
282
+ @require_target = @lib_relpath.to_s.sub(/\.rb\Z/, '')
283
+ @stub_path = SITELIBDIR.join(@lib_relpath)
284
+ @autorequire = autorequire
285
+ end
286
+
287
+ #
288
+ # The powerhouse of the class. No exceptions should result from calling this.
289
+ #
290
+ def generate
291
+ if @stub_path.exist?
292
+ # The stub path is inhabited by a file. If it's a gem stub, we'll overwrite it (just
293
+ # to be sure). If it's a genuine library, we'll leave it alone and issue a warning.
294
+ unless library_stub?(@stub_path)
295
+ alert_warning(
296
+ ["Library file '#{target_path}'",
297
+ "already exists; not overwriting. If you want to force a",
298
+ "library stub, delete the file and reinstall."].join("\n")
299
+ )
300
+ return
301
+ end
302
+ end
303
+
304
+ unless @stub_path.dirname.exist?
305
+ @stub_path.dirname.mkpath
306
+ end
307
+ @stub_path.open('w', 0644) do |io|
308
+ io.write(library_stub_content())
309
+ end
310
+ end
311
+
312
+ # Two LibraryStub objects are equal if they have the same gem name and relative (gem) path.
313
+ def ==(other)
314
+ LibraryStub === other and @gem_name == other.gem_name and
315
+ @gem_relpath == other.gem_relpath
316
+ end
317
+
318
+ private
319
+
320
+ #
321
+ # require_paths::
322
+ # ([Pathname]) The require paths in the gemspec.
323
+ # require_target::
324
+ # (String) The subject of an intended 'require' statement.
325
+ # gemspec::
326
+ # (Gem::Specification)
327
+ #
328
+ # The aim of this method is to resolve the require_target into a path relative to the root
329
+ # of the gem. We try each require path in turn, and see if the require target exists under
330
+ # that directory.
331
+ #
332
+ # If no match is found, we return +nil+.
333
+ #
334
+ def self.find_gem_relpath(require_paths, require_target, gemspec)
335
+ require_target << '.rb' unless require_target =~ /\.rb\Z/
336
+ gem_files = gemspec.files.map { |path| Pathname.new(path).cleanpath }
337
+ require_paths.each do |require_path|
338
+ possible_lib_path = require_path.join(require_target)
339
+ if gem_files.include?(possible_lib_path)
340
+ return possible_lib_path.to_s
341
+ end
342
+ end
343
+ nil # If we get this far, there was no match.
344
+ end
345
+
346
+ #
347
+ # require_paths::
348
+ # ([Pathname]) The require paths in the gemspec.
349
+ # gem_relpath::
350
+ # (String) The path to the library file, relative to the root of the gem.
351
+ #
352
+ # Returns: the path (Pathname) to the same file, relative to the gem's library path
353
+ # (typically 'lib'). Thus 'lib/rake/rdoctask.rb' becomes 'rake/rdoctask.rb'. The gemspec
354
+ # may contain several library paths, though that would be unusual, so we must deal with
355
+ # that possibility here.
356
+ #
357
+ # If there is no such relative path, we return +nil+.
358
+ #
359
+ def find_lib_relpath(require_paths, gem_relpath)
360
+ require_paths.each do |require_path|
361
+ begin
362
+ return Pathname.new(gem_relpath).relative_path_from(require_path)
363
+ rescue ArgumentError
364
+ next
365
+ end
366
+ nil # If we get this far, there was no match.
367
+ end
368
+ end
369
+
370
+ # Returns a string suitable for placing in a stub file.
371
+ def library_stub_content
372
+ content = %{
373
+ #
374
+ # This file was generated by RubyGems.
375
+ #
376
+ # The library '#{@gem_name}' is installed as part of a gem, and
377
+ # this file is here so you can 'require' it easily (i.e.
378
+ # without having to know it's a gem).
379
+ #
380
+ # gem: #{@gem_name}
381
+ # stub: #{@lib_relpath}
382
+ #
383
+
384
+ require 'rubygems'
385
+ $".delete('#{@lib_relpath}')
386
+ require_gem '#{@gem_name}'
387
+ }.gsub(/^[ \t]+/, '')
388
+ unless @autorequire
389
+ content << %{require '#{@require_target}'\n}
390
+ end
391
+ content << %{
392
+ # (end of stub)
393
+ }.gsub(/^[ \t]+/, '')
394
+ end
395
+
396
+ # Returns true iff the contents of the given _path_ (a Pathname) appear to be a RubyGems
397
+ # library stub.
398
+ def library_stub?(path)
399
+ lines = path.readlines
400
+ lines.grep(/^# This file was generated by RubyGems/) and
401
+ lines.grep(/is installed as part of a gem, and/)
402
+ end
403
+
404
+ end # class LibraryStub
405
+
406
+
407
+ #
408
+ # This class contains the logic to generate all library stubs, including the autorequire, for
409
+ # a single gemspec.
410
+ #
411
+ # LibraryStubs.new(gemspec).generate
412
+ #
413
+ class LibraryStubs
414
+ SITELIBDIR = Pathname.new(Config::CONFIG['sitelibdir'])
415
+
416
+ def initialize(spec)
417
+ @spec = spec
418
+ end
419
+
420
+ def generate
421
+ require_paths = @spec.require_paths.map { |p| Pathname.new(p) }
422
+ stubs = @spec.library_stubs.map {
423
+ |stub| LibraryStub.new(@spec.name, require_paths, stub)
424
+ }
425
+ stubs << LibraryStub.from_autorequire(@spec, require_paths)
426
+ stubs = stubs.compact.uniq
427
+ unless stubs.empty?
428
+ if FileTest.writable?(SITELIBDIR)
429
+ stubs.each do |stub| stub.generate end
430
+ else
431
+ alert_warning(
432
+ ["Can't install library stub for gem '#{spec.name}'",
433
+ "(Don't have write permissions on '#{sitelibdir}' directory.)"].join("\n")
434
+ )
435
+ end
436
+ end
437
+ end
438
+ end # class LibraryStubs
439
+
440
+
441
+ ##
442
+ # The Uninstaller class uninstalls a Gem
443
+ #
444
+ class Uninstaller
445
+
446
+ include UserInteraction
447
+
448
+ ##
449
+ # Constructs an Uninstaller instance
450
+ #
451
+ # gem:: [String] The Gem name to uninstall
452
+ #
453
+ def initialize(gem, version="> 0")
454
+ @gem = gem
455
+ @version = version
456
+ end
457
+
458
+ ##
459
+ # Performs the uninstall of the Gem. This removes the spec, the Gem directory, and the
460
+ # cached .gem file,
461
+ #
462
+ # Application and library stubs are removed according to what is still installed.
463
+ #
464
+ # XXX: Application stubs refer to specific gem versions, which means things may get
465
+ # inconsistent after an uninstall (i.e. referring to a version that no longer exists).
466
+ #
467
+ def uninstall
468
+ require 'fileutils'
469
+ list = Gem::SourceIndex.from_installed_gems.search(@gem, @version)
470
+ if list.size == 0
471
+ raise "Unknown RubyGem: #{@gem} (#{@version})"
472
+ elsif list.size > 1
473
+ say
474
+ gem_list = list.collect {|gem| gem.full_name}
475
+ gem_list << "All versions"
476
+ gem_name, index = choose_from_list("Select RubyGem to uninstall:", gem_list)
477
+ if index == list.size
478
+ remove_all(list.dup)
479
+ remove_executables(list.last)
480
+ elsif index >= 0 && index < list.size
481
+ remove(list[index], list)
482
+ remove_executables(list[index])
483
+ else
484
+ say "Error: must enter a number [1-#{list.size+1}]"
485
+ end
486
+ else
487
+ remove_executables(list.last)
488
+ remove(list[0], list)
489
+ end
490
+ end
491
+
492
+ #
493
+ # Remove executables and batch files (windows only) for the gem as it is being installed
494
+ #
495
+ # gemspec::[Specification] the gem whose executables need to be removed.
496
+ def remove_executables(gemspec)
497
+ return if gemspec.nil?
498
+ if(gemspec.executables.size > 0) then
499
+ raise Gem::FilePermissionError.new(Config::CONFIG['bindir']) unless
500
+ File.writable?(Config::CONFIG['bindir'])
501
+ list = Gem.source_index.search(gemspec.name).delete_if { |spec|
502
+ spec.version == gemspec.version
503
+ }
504
+ executables = gemspec.executables.clone
505
+ list.each do |spec|
506
+ spec.executables.each do |exe_name|
507
+ executables.delete(exe_name)
508
+ end
509
+ end
510
+ return if executables.size == 0
511
+ answer = ask_yes_no("Remove executables and scripts for\n'#{gemspec.executables.join(", ")}' in addition to the gem?", true)
512
+ unless answer
513
+ say "Executables and scripts will remain installed."
514
+ return
515
+ else
516
+ bindir = Config::CONFIG['bindir']
517
+ gemspec.executables.each do |exe_name|
518
+ say "Removing #{exe_name}"
519
+ File.unlink(File.join(bindir, exe_name)) rescue nil
520
+ File.unlink(File.join(bindir, exe_name + ".cmd")) rescue nil
521
+ end
522
+ end
523
+ end
524
+ end
525
+
526
+ #
527
+ # list:: the list of all gems to remove
528
+ #
529
+ # Warning: this method modifies the +list+ parameter. Once it has uninstalled a gem, it is
530
+ # removed from that list.
531
+ #
532
+ def remove_all(list)
533
+ list.dup.each { |gem| remove(gem, list) }
534
+ end
535
+
536
+ #
537
+ # spec:: the spec of the gem to be uninstalled
538
+ # list:: the list of all such gems
539
+ #
540
+ # Warning: this method modifies the +list+ parameter. Once it has uninstalled a gem, it is
541
+ # removed from that list.
542
+ #
543
+ def remove(spec, list)
544
+ if(has_dependents?(spec)) then
545
+ raise DependencyRemovalException.new("Uninstallation aborted due to dependent gem(s)")
546
+ end
547
+ raise Gem::FilePermissionError.new(spec.installation_path) unless File.writable?(spec.installation_path)
548
+ FileUtils.rm_rf spec.full_gem_path
549
+ FileUtils.rm_rf File.join(spec.installation_path, 'specifications', "#{spec.full_name}.gemspec")
550
+ FileUtils.rm_rf File.join(spec.installation_path, 'cache', "#{spec.full_name}.gem")
551
+ DocManager.new(spec).uninstall_doc
552
+ #remove_stub_files(spec, list - [spec])
553
+ say "Successfully uninstalled #{spec.name} version #{spec.version}"
554
+ list.delete(spec)
555
+ end
556
+
557
+ def has_dependents?(spec)
558
+ spec.dependent_gems.each do |gem,dep,satlist|
559
+ msg = ['You have requested to uninstall the gem:']
560
+ satlist.each do |sat|
561
+ msg << "\t#{sat.name}-#{sat.version}"
562
+ end
563
+ msg << "#{gem.name}-#{gem.version} depends on [#{dep.name} (#{dep.version_requirements})]"
564
+ msg << 'If you remove this gem, the dependency will not be met.'
565
+ msg << 'Uninstall anyway?'
566
+ return !ask_yes_no(msg.join("\n"), false)
567
+ end
568
+ false
569
+ end
570
+
571
+ private
572
+
573
+ ##
574
+ # Remove application and library stub files. These are detected by the line
575
+ # # This file was generated by RubyGems.
576
+ #
577
+ # spec:: the spec of the gem that is being uninstalled
578
+ # other_specs:: any other installed specs for this gem (i.e. different versions)
579
+ #
580
+ # Both parameters are necessary to ensure that the correct files are uninstalled. It is
581
+ # assumed that +other_specs+ contains only *installed* gems, except the one that's about to
582
+ # be uninstalled.
583
+ #
584
+ def remove_stub_files(spec, other_specs)
585
+ remove_app_stubs(spec, other_specs)
586
+ remove_lib_stub(spec, other_specs)
587
+ end
588
+
589
+ def remove_app_stubs(spec, other_specs)
590
+ # App stubs are tricky, because each version of an app gem could install different
591
+ # applications. We need to make sure that what we delete isn't needed by any remaining
592
+ # versions of the gem.
593
+ #
594
+ # There's extra trickiness, too, because app stubs 'require_gem' a specific version of
595
+ # the gem. If we uninstall the latest gem, we should ensure that there is a sensible app
596
+ # stub(s) installed after the removal of the current one.
597
+ #
598
+ # Perhaps the best way to approach this is:
599
+ # * remove all application stubs for this gemspec
600
+ # * regenerate the app stubs for the latest remaining version
601
+ # (you always want to have the latest version of an app, don't you?)
602
+ #
603
+ # The Installer class doesn't really support this approach very well at the moment.
604
+ end
605
+
606
+ def remove_lib_stub(spec, other_specs)
607
+ # Library stubs are a bit easier than application stubs. They do not refer to a specific
608
+ # version; they just load the latest version of the library available as a gem. The only
609
+ # corner case is that different versions of the same gem may have different autorequire
610
+ # settings, which means they will have different library stubs.
611
+ #
612
+ # I suppose our policy should be: when you uninstall a library, make sure all the
613
+ # remaining versions of that gem are still supported by stubs. Of course, the user may
614
+ # have expressed a preference in the past not to have library stubs installed.
615
+ #
616
+ # Mixing the segregated world of gem installations with the global namespace of the
617
+ # site_ruby directory certainly brings some tough issues.
618
+ end
619
+ end # class Uninstaller
620
+
621
+ end # module Gem