rubygems-update 0.8.3

Sign up to get free protection for your applications and to get access to all the features.

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