rubygems-update 0.8.6 → 0.8.8

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 (42) hide show
  1. data/ChangeLog +134 -0
  2. data/Rakefile +41 -17
  3. data/bin/gemwhich +61 -0
  4. data/examples/application/an-app.gemspec +1 -0
  5. data/lib/gemconfigure.rb +18 -0
  6. data/lib/rubygems.rb +65 -47
  7. data/lib/rubygems/cmd_manager.rb +3 -1
  8. data/lib/rubygems/command.rb +4 -0
  9. data/lib/rubygems/config_file.rb +2 -6
  10. data/lib/rubygems/custom_require.rb +2 -2
  11. data/lib/rubygems/dependency_list.rb +131 -0
  12. data/lib/rubygems/deployment.rb +265 -0
  13. data/lib/rubygems/doc_manager.rb +1 -0
  14. data/lib/rubygems/gem_commands.rb +216 -15
  15. data/lib/rubygems/installer.rb +111 -286
  16. data/lib/rubygems/remote_installer.rb +16 -6
  17. data/lib/rubygems/rubygems_version.rb +1 -1
  18. data/lib/rubygems/source_index.rb +11 -5
  19. data/lib/rubygems/specification.rb +5 -0
  20. data/lib/rubygems/version.rb +146 -129
  21. data/test/test_configfile.rb +1 -1
  22. data/test/test_dependency_list.rb +163 -0
  23. data/test/test_deployment.rb +93 -0
  24. data/test/test_remote_fetcher.rb +38 -36
  25. metadata +23 -47
  26. data/test/data/a-0.0.1.gem +0 -0
  27. data/test/data/a-0.0.2.gem +0 -0
  28. data/test/data/b-0.0.2.gem +0 -0
  29. data/test/data/c-1.2.gem +0 -0
  30. data/test/data/gemhome/cache/a-0.0.1.gem +0 -0
  31. data/test/data/gemhome/cache/a-0.0.2.gem +0 -0
  32. data/test/data/gemhome/cache/b-0.0.2.gem +0 -0
  33. data/test/data/gemhome/cache/c-1.2.gem +0 -0
  34. data/test/data/gemhome/gems/a-0.0.1/lib/code.rb +0 -1
  35. data/test/data/gemhome/gems/a-0.0.2/lib/code.rb +0 -1
  36. data/test/data/gemhome/gems/b-0.0.2/lib/code.rb +0 -1
  37. data/test/data/gemhome/gems/c-1.2/lib/code.rb +0 -1
  38. data/test/data/gemhome/specifications/a-0.0.1.gemspec +0 -8
  39. data/test/data/gemhome/specifications/a-0.0.2.gemspec +0 -8
  40. data/test/data/gemhome/specifications/b-0.0.2.gemspec +0 -8
  41. data/test/data/gemhome/specifications/c-1.2.gemspec +0 -8
  42. data/test/data/one/one-0.0.1.gem +0 -0
@@ -35,6 +35,7 @@ module Gem
35
35
  end
36
36
 
37
37
  def generate_rdoc
38
+ return if @spec.has_rdoc == false
38
39
  require 'fileutils'
39
40
  Gem::FilePermissionError.new(@doc_dir) if File.exist?(@doc_dir) && !File.writable?(@doc_dir)
40
41
  FileUtils.mkdir_p @doc_dir unless File.exist?(@doc_dir)
@@ -65,8 +65,16 @@ module Gem
65
65
  add_option('-t', '--[no-]test', 'Run unit tests prior to installation') do |value, options|
66
66
  options[:test] = value
67
67
  end
68
+ add_option('--ignore-dependencies',
69
+ 'Do not install any required dependent gems') do |value, options|
70
+ options[:ignore_dependencies] = value
71
+ end
72
+ add_option('--include-dependencies',
73
+ 'Unconditionally install the required dependent gems') do |value, options|
74
+ options[:include_dependencies] = value
75
+ end
68
76
  end
69
-
77
+
70
78
  def install_update_defaults_str
71
79
  '--rdoc --no-force --no-test'
72
80
  end
@@ -144,9 +152,12 @@ module Gem
144
152
  alert_error "Local gem file not found: #{filepattern}"
145
153
  end
146
154
  else
147
- result = Gem::Installer.new(entries.last).install(options[:force], options[:install_dir])
155
+ result = Gem::Installer.new(entries.last, options).install(
156
+ options[:force],
157
+ options[:install_dir])
148
158
  installed_gems = [result].flatten
149
- say "Successfully installed #{installed_gems[0].name}, version #{installed_gems[0].version}" if installed_gems
159
+ say "Successfully installed #{installed_gems[0].name}, " +
160
+ "version #{installed_gems[0].version}" if installed_gems
150
161
  end
151
162
  rescue LocalInstallationError => e
152
163
  say " -> Local installation can't proceed: #{e.message}"
@@ -165,8 +176,17 @@ module Gem
165
176
  if remote? && installed_gems.nil?
166
177
  say "Attempting remote installation of '#{gem_name}'"
167
178
  installer = Gem::RemoteInstaller.new(options)
168
- installed_gems = installer.install(gem_name, options[:version], options[:force], options[:install_dir])
169
- say "Successfully installed #{installed_gems[0].name}, version #{installed_gems[0].version}" if installed_gems
179
+ installed_gems = installer.install(
180
+ gem_name,
181
+ options[:version],
182
+ options[:force],
183
+ options[:install_dir])
184
+ if installed_gems
185
+ installed_gems.compact!
186
+ installed_gems.each do |spec|
187
+ say "Successfully installed #{spec.full_name}"
188
+ end
189
+ end
170
190
  end
171
191
 
172
192
  unless installed_gems
@@ -203,11 +223,26 @@ module Gem
203
223
 
204
224
  def initialize
205
225
  super('uninstall', 'Uninstall a gem from the local repository', {:version=>"> 0"})
226
+ add_option('-a', '--[no-]all',
227
+ 'Uninstall all matching versions'
228
+ ) do |value, options|
229
+ options[:all] = value
230
+ end
231
+ add_option('-i', '--[no-]ignore-dependencies',
232
+ 'Ignore dependency requirements while uninstalling'
233
+ ) do |value, options|
234
+ options[:ignore] = value
235
+ end
236
+ add_option('-x', '--[no-]executables',
237
+ 'Uninstall applicable executables without confirmation'
238
+ ) do |value, options|
239
+ options[:executables] = value
240
+ end
206
241
  add_version_option('uninstall')
207
242
  end
208
243
 
209
244
  def defaults_str
210
- "--version '> 0'"
245
+ "--version '> 0' --no-force"
211
246
  end
212
247
 
213
248
  def usage
@@ -221,10 +256,108 @@ module Gem
221
256
  def execute
222
257
  gem_name = get_one_gem_name
223
258
  say "Attempting to uninstall gem '#{gem_name}'"
224
- Gem::Uninstaller.new(gem_name, options[:version]).uninstall
259
+ Gem::Uninstaller.new(gem_name, options).uninstall
225
260
  end
226
261
  end
227
262
 
263
+ ####################################################################
264
+ class DependencyCommand < Command
265
+ include VersionOption
266
+ include CommandAids
267
+
268
+ def initialize
269
+ super('dependency',
270
+ 'Show the dependencies of an installed gem',
271
+ {:version=>"> 0"})
272
+ add_version_option('uninstall')
273
+ add_option('-r', '--[no-]reverse-dependencies',
274
+ 'Include reverse dependencies in the output'
275
+ ) do |value, options|
276
+ options[:reverse_dependencies] = value
277
+ end
278
+ add_option('-p', '--pipe', "Pipe Format (name --version ver)") do |value, options|
279
+ options[:pipe_format] = value
280
+ end
281
+ end
282
+
283
+ def defaults_str
284
+ "--version '> 0' --no-reverse"
285
+ end
286
+
287
+ def usage
288
+ "#{program_name} GEMNAME"
289
+ end
290
+
291
+ def arguments
292
+ "GEMNAME name of gems to show"
293
+ end
294
+
295
+ def execute
296
+ specs = {}
297
+ srcindex = SourceIndex.from_installed_gems
298
+ options[:args] << '.' if options[:args].empty?
299
+ options[:args].each do |name|
300
+ speclist = srcindex.search(name, options[:version])
301
+ if speclist.empty?
302
+ say "No match found for #{name} (#{options[:version]})"
303
+ else
304
+ speclist.each do |spec|
305
+ specs[spec.full_name] = spec
306
+ end
307
+ end
308
+ end
309
+ reverse = Hash.new { |h, k| h[k] = [] }
310
+ if options[:reverse_dependencies]
311
+ specs.values.each do |spec|
312
+ reverse[spec.full_name] = find_reverse_dependencies(spec, srcindex)
313
+ end
314
+ end
315
+ if options[:pipe_format]
316
+ specs.values.sort.each do |spec|
317
+ unless spec.dependencies.empty?
318
+ spec.dependencies.each do |dep|
319
+ puts %{#{dep.name} --version '#{dep.version_requirements}'}
320
+ end
321
+ end
322
+ end
323
+ else
324
+ response = ''
325
+ specs.values.sort.each do |spec|
326
+ response << "Gem #{spec.full_name}\n"
327
+ unless spec.dependencies.empty?
328
+ response << " Requires\n"
329
+ spec.dependencies.each do |dep|
330
+ response << " #{dep}\n"
331
+ end
332
+ end
333
+ unless reverse[spec.full_name].empty?
334
+ response << " Used by\n"
335
+ reverse[spec.full_name].each do |sp, dep|
336
+ response << " #{sp} (#{dep})\n"
337
+ end
338
+ end
339
+ response << "\n"
340
+ end
341
+ say response
342
+ end
343
+ end
344
+
345
+ # Retuns list of [specification, dep] that are satisfied by spec.
346
+ def find_reverse_dependencies(spec, srcindex)
347
+ result = []
348
+ srcindex.each do |name, sp|
349
+ sp.dependencies.each do |dep|
350
+ if spec.name == dep.name &&
351
+ dep.version_requirements.satisfied_by?(spec.version)
352
+ result << [sp.full_name, dep]
353
+ end
354
+ end
355
+ end
356
+ result
357
+ end
358
+
359
+ end
360
+
228
361
  ####################################################################
229
362
  class CheckCommand < Command
230
363
  include CommandAids
@@ -506,7 +639,7 @@ module Gem
506
639
  {
507
640
  :generate_rdoc => true,
508
641
  :force => false,
509
- :test => false,
642
+ :test => false,
510
643
  :install_dir => Gem.dir
511
644
  })
512
645
  add_install_update_options
@@ -564,7 +697,11 @@ module Gem
564
697
  say "Updating version of RubyGems"
565
698
  do_rubygems_update
566
699
  end
567
- say "All gems up to date"
700
+ if(options[:system]) then
701
+ say "RubyGems system software updated"
702
+ else
703
+ say "Gems: [#{gems_to_update.uniq.sort.collect{|g| g.to_s}.join(', ')}] updated"
704
+ end
568
705
  end
569
706
 
570
707
  def do_rubygems_update
@@ -589,9 +726,77 @@ module Gem
589
726
  end
590
727
  result
591
728
  end
729
+ end
592
730
 
593
- def command_manager
594
- Gem::CommandManager.instance
731
+ ####################################################################
732
+ class CleanupCommand < Command
733
+ def initialize
734
+ super(
735
+ 'cleanup',
736
+ 'Cleanup old versions of installed gems in the local repository',
737
+ {
738
+ :force => false,
739
+ :test => false,
740
+ :install_dir => Gem.dir
741
+ })
742
+ add_option('-d', '--dryrun', "") do |value, options|
743
+ options[:dryrun] = true
744
+ end
745
+ end
746
+
747
+ def defaults_str
748
+ "--no-dryrun"
749
+ end
750
+
751
+ def arguments
752
+ "GEMNAME(s) name of gem(s) to cleanup"
753
+ end
754
+
755
+ def execute
756
+ say "Cleaning up installed gems..."
757
+ srcindex = Gem::SourceIndex.from_installed_gems
758
+ primary_gems = {}
759
+ srcindex.each do |name, spec|
760
+ if primary_gems[spec.name].nil? or primary_gems[spec.name].version < spec.version
761
+ primary_gems[spec.name] = spec
762
+ end
763
+ end
764
+ gems_to_cleanup = []
765
+ if ! options[:args].empty?
766
+ options[:args].each do |gem_name|
767
+ specs = Gem.cache.search(/^#{gem_name}$/i)
768
+ specs.each do |spec|
769
+ gems_to_cleanup << spec
770
+ end
771
+ end
772
+ else
773
+ srcindex.each do |name, spec|
774
+ gems_to_cleanup << spec
775
+ end
776
+ end
777
+ gems_to_cleanup = gems_to_cleanup.select { |spec|
778
+ primary_gems[spec.name].version != spec.version
779
+ }
780
+ uninstall_command = command_manager['uninstall']
781
+ deplist = DependencyList.new
782
+ gems_to_cleanup.uniq.each do |spec| deplist.add(spec) end
783
+ deplist.dependency_order.each do |spec|
784
+ if options[:dryrun]
785
+ say "Dry Run Mode: Would uninstall #{spec.full_name}"
786
+ else
787
+ say "Attempting uninstall on #{spec.full_name}"
788
+ options[:args] = [spec.name]
789
+ options[:version] = "= #{spec.version}"
790
+ options[:executables] = true
791
+ uninstall_command.merge_options(options)
792
+ begin
793
+ uninstall_command.execute
794
+ rescue Gem::DependencyRemovalException => ex
795
+ say "Unable to uninstall #{spec.full_name} ... continuing with remaining gems"
796
+ end
797
+ end
798
+ end
799
+ say "Clean Up Complete"
595
800
  end
596
801
  end
597
802
 
@@ -882,10 +1087,6 @@ module Gem
882
1087
  say Gem::HELP
883
1088
  end
884
1089
  end
885
-
886
- def command_manager
887
- Gem::CommandManager.instance
888
- end
889
1090
  end
890
1091
 
891
1092
  end # module
@@ -1,6 +1,7 @@
1
1
  require 'pathname'
2
2
  require 'rbconfig'
3
3
  require 'rubygems/format'
4
+ require 'rubygems/dependency_list'
4
5
 
5
6
  module Gem
6
7
 
@@ -19,8 +20,9 @@ module Gem
19
20
  #
20
21
  # gem:: [String] The file name of the gem
21
22
  #
22
- def initialize(gem)
23
+ def initialize(gem, options={})
23
24
  @gem = gem
25
+ @options = options
24
26
  end
25
27
 
26
28
  ##
@@ -37,11 +39,10 @@ module Gem
37
39
  # force:: [default = false] if false will fail if a required Gem is not installed,
38
40
  # or if the Ruby version is too low for the gem
39
41
  # 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
  #
42
43
  # return:: [Gem::Specification] The specification for the newly installed Gem.
43
44
  #
44
- def install(force=false, install_dir=Gem.dir, install_stub=false)
45
+ def install(force=false, install_dir=Gem.dir, ignore_this_parameter=false)
45
46
  require 'fileutils'
46
47
  format = Gem::Format.from_file_by_path(@gem)
47
48
  unless force
@@ -53,10 +54,12 @@ module Gem
53
54
  end
54
55
  end
55
56
  # 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
57
+ unless @options[:ignore_dependencies]
58
+ spec.dependencies.each do |dep_gem|
59
+ # TODO: Does this take account of *versions*?
60
+ require_gem_with_options(dep_gem, [], :auto_require=>false)
61
+ end
62
+ end
60
63
  end
61
64
 
62
65
  raise Gem::FilePermissionError.new(install_dir) unless File.writable?(install_dir)
@@ -67,7 +70,6 @@ module Gem
67
70
 
68
71
  extract_files(directory, format)
69
72
  generate_bin_scripts(format.spec, install_dir)
70
- #generate_library_stubs(format.spec) if install_stub
71
73
  build_extensions(directory, format.spec)
72
74
 
73
75
  # Build spec/cache/doc dir.
@@ -106,7 +108,8 @@ module Gem
106
108
  end
107
109
 
108
110
  ##
109
- # Writes the .gemspec specification (in Ruby) to the supplied spec_path.
111
+ # Writes the .gemspec specification (in Ruby) to the supplied
112
+ # spec_path.
110
113
  #
111
114
  # spec:: [Gem::Specification] The Gem specification to output
112
115
  # spec_path:: [String] The location (path) to write the gemspec to
@@ -151,15 +154,19 @@ module Gem
151
154
  end
152
155
  end
153
156
 
154
- def shebang(spec, install_dir, file_name)
155
- first_line = ""
156
- File.open(File.join(install_dir, "gems", spec.full_name, spec.bindir,file_name), "rb") do |file|
157
+ def shebang(spec, install_dir, bin_file_name)
158
+ path = File.join(install_dir, "gems", spec.full_name, spec.bindir, bin_file_name)
159
+ File.open(path, "rb") do |file|
157
160
  first_line = file.readlines("\n").first
158
- end
159
- if first_line =~ /^#!/ then
160
- first_line.sub(/\A\#!\s*\S*ruby\S*/, "#!" + File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])) #Thanks RPA
161
- else
162
- "\#!#{File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])}"
161
+ path_to_ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
162
+ if first_line =~ /^#!/
163
+ # Preserve extra words on shebang line, like "-w". Thanks RPA.
164
+ shebang = first_line.sub(/\A\#!\s*\S*ruby\S*/, "#!" + path_to_ruby)
165
+ else
166
+ # Create a plain shebang line.
167
+ shebang = "#!" + path_to_ruby
168
+ end
169
+ return shebang.strip # Avoid nasty ^M issues.
163
170
  end
164
171
  end
165
172
 
@@ -190,19 +197,6 @@ TEXT
190
197
  text
191
198
  end
192
199
 
193
- ##
194
- # Creates a file in the site_ruby directory that acts as a stub for the gem. Thus, if
195
- # 'package' is installed as a gem, the user can just type <tt>require 'package'</tt> and
196
- # the gem (latest version) will be loaded. This is like a backwards compatibility so that
197
- # gems and non-gems can interact.
198
- #
199
- # Which files are stubified? Those included in the gem's 'autorequire' and 'library_stubs'
200
- # attributes.
201
- #
202
- def generate_library_stubs(spec)
203
- LibraryStubs.new(spec).generate
204
- end
205
-
206
200
  def build_extensions(directory, spec)
207
201
  return unless spec.extensions.size > 0
208
202
  say "Building native extensions. This could take a while..."
@@ -259,196 +253,6 @@ TEXT
259
253
  end # class Installer
260
254
 
261
255
 
262
- #
263
- # This class represents a single library stub, which is characterised by a
264
- #
265
- class LibraryStub
266
- SITELIBDIR = Pathname.new(Config::CONFIG['sitelibdir'])
267
-
268
- #
269
- # The 'autorequire' attribute in a gemspec is a special case: it represents a require
270
- # target, not a relative path. We therefore offer this method of creating a library stub
271
- # for the autorequire file.
272
- #
273
- # If the given spec doesn't have an 'autorequire' value, we return +nil+.
274
- #
275
- def self.from_autorequire(gemspec, require_paths)
276
- require_target = gemspec.autorequire
277
- return nil if require_target.nil?
278
- gem_relpath = find_gem_relpath(require_paths, require_target, gemspec)
279
- LibraryStub.new(gemspec.name, require_paths, gem_relpath, true)
280
- end
281
-
282
- #
283
- # require_paths::
284
- # ([Pathname]) The require paths in the gemspec.
285
- # gem_relpath::
286
- # (String) The path to the library file, relative to the root of the gem.
287
- # autorequire::
288
- # (Boolean) Whether this stub represents the gem's autorequire file.
289
- #
290
- def initialize(gem_name, require_paths, gem_relpath, autorequire=false)
291
- @gem_name = gem_name
292
- @lib_relpath = find_lib_relpath(require_paths, gem_relpath)
293
- @require_target = @lib_relpath.to_s.sub(/\.rb\Z/, '')
294
- @stub_path = SITELIBDIR.join(@lib_relpath)
295
- @autorequire = autorequire
296
- end
297
-
298
- #
299
- # The powerhouse of the class. No exceptions should result from calling this.
300
- #
301
- def generate
302
- if @stub_path.exist?
303
- # The stub path is inhabited by a file. If it's a gem stub, we'll overwrite it (just
304
- # to be sure). If it's a genuine library, we'll leave it alone and issue a warning.
305
- unless library_stub?(@stub_path)
306
- alert_warning(
307
- ["Library file '#{target_path}'",
308
- "already exists; not overwriting. If you want to force a",
309
- "library stub, delete the file and reinstall."].join("\n")
310
- )
311
- return
312
- end
313
- end
314
-
315
- unless @stub_path.dirname.exist?
316
- @stub_path.dirname.mkpath
317
- end
318
- @stub_path.open('w', 0644) do |io|
319
- io.write(library_stub_content())
320
- end
321
- end
322
-
323
- # Two LibraryStub objects are equal if they have the same gem name and relative (gem) path.
324
- def ==(other)
325
- LibraryStub === other and @gem_name == other.gem_name and
326
- @gem_relpath == other.gem_relpath
327
- end
328
-
329
- private
330
-
331
- #
332
- # require_paths::
333
- # ([Pathname]) The require paths in the gemspec.
334
- # require_target::
335
- # (String) The subject of an intended 'require' statement.
336
- # gemspec::
337
- # (Gem::Specification)
338
- #
339
- # The aim of this method is to resolve the require_target into a path relative to the root
340
- # of the gem. We try each require path in turn, and see if the require target exists under
341
- # that directory.
342
- #
343
- # If no match is found, we return +nil+.
344
- #
345
- def self.find_gem_relpath(require_paths, require_target, gemspec)
346
- require_target << '.rb' unless require_target =~ /\.rb\Z/
347
- gem_files = gemspec.files.map { |path| Pathname.new(path).cleanpath }
348
- require_paths.each do |require_path|
349
- possible_lib_path = require_path.join(require_target)
350
- if gem_files.include?(possible_lib_path)
351
- return possible_lib_path.to_s
352
- end
353
- end
354
- nil # If we get this far, there was no match.
355
- end
356
-
357
- #
358
- # require_paths::
359
- # ([Pathname]) The require paths in the gemspec.
360
- # gem_relpath::
361
- # (String) The path to the library file, relative to the root of the gem.
362
- #
363
- # Returns: the path (Pathname) to the same file, relative to the gem's library path
364
- # (typically 'lib'). Thus 'lib/rake/rdoctask.rb' becomes 'rake/rdoctask.rb'. The gemspec
365
- # may contain several library paths, though that would be unusual, so we must deal with
366
- # that possibility here.
367
- #
368
- # If there is no such relative path, we return +nil+.
369
- #
370
- def find_lib_relpath(require_paths, gem_relpath)
371
- require_paths.each do |require_path|
372
- begin
373
- return Pathname.new(gem_relpath).relative_path_from(require_path)
374
- rescue ArgumentError
375
- next
376
- end
377
- nil # If we get this far, there was no match.
378
- end
379
- end
380
-
381
- # Returns a string suitable for placing in a stub file.
382
- def library_stub_content
383
- content = %{
384
- #
385
- # This file was generated by RubyGems.
386
- #
387
- # The library '#{@gem_name}' is installed as part of a gem, and
388
- # this file is here so you can 'require' it easily (i.e.
389
- # without having to know it's a gem).
390
- #
391
- # gem: #{@gem_name}
392
- # stub: #{@lib_relpath}
393
- #
394
-
395
- require 'rubygems'
396
- $".delete('#{@lib_relpath}')
397
- require_gem '#{@gem_name}'
398
- }.gsub(/^[ \t]+/, '')
399
- unless @autorequire
400
- content << %{require '#{@require_target}'\n}
401
- end
402
- content << %{
403
- # (end of stub)
404
- }.gsub(/^[ \t]+/, '')
405
- end
406
-
407
- # Returns true iff the contents of the given _path_ (a Pathname) appear to be a RubyGems
408
- # library stub.
409
- def library_stub?(path)
410
- lines = path.readlines
411
- lines.grep(/^# This file was generated by RubyGems/) and
412
- lines.grep(/is installed as part of a gem, and/)
413
- end
414
-
415
- end # class LibraryStub
416
-
417
-
418
- #
419
- # This class contains the logic to generate all library stubs, including the autorequire, for
420
- # a single gemspec.
421
- #
422
- # LibraryStubs.new(gemspec).generate
423
- #
424
- class LibraryStubs
425
- SITELIBDIR = Pathname.new(Config::CONFIG['sitelibdir'])
426
-
427
- def initialize(spec)
428
- @spec = spec
429
- end
430
-
431
- def generate
432
- require_paths = @spec.require_paths.map { |p| Pathname.new(p) }
433
- stubs = @spec.library_stubs.map {
434
- |stub| LibraryStub.new(@spec.name, require_paths, stub)
435
- }
436
- stubs << LibraryStub.from_autorequire(@spec, require_paths)
437
- stubs = stubs.compact.uniq
438
- unless stubs.empty?
439
- if FileTest.writable?(SITELIBDIR)
440
- stubs.each do |stub| stub.generate end
441
- else
442
- alert_warning(
443
- ["Can't install library stub for gem '#{spec.name}'",
444
- "(Don't have write permissions on '#{sitelibdir}' directory.)"].join("\n")
445
- )
446
- end
447
- end
448
- end
449
- end # class LibraryStubs
450
-
451
-
452
256
  ##
453
257
  # The Uninstaller class uninstalls a Gem
454
258
  #
@@ -461,30 +265,39 @@ TEXT
461
265
  #
462
266
  # gem:: [String] The Gem name to uninstall
463
267
  #
464
- def initialize(gem, version="> 0")
268
+ def initialize(gem, options)
465
269
  @gem = gem
466
- @version = version
270
+ @version = options[:version] || "> 0"
271
+ @force_executables = options[:executables]
272
+ @force_all = options[:all]
273
+ @force_ignore = options[:ignore]
467
274
  end
468
275
 
469
276
  ##
470
- # Performs the uninstall of the Gem. This removes the spec, the Gem directory, and the
471
- # cached .gem file,
277
+ # Performs the uninstall of the Gem. This removes the spec, the
278
+ # Gem directory, and the cached .gem file,
472
279
  #
473
- # Application and library stubs are removed according to what is still installed.
280
+ # Application stubs are (or should be) removed according to what
281
+ # is still installed.
474
282
  #
475
- # XXX: Application stubs refer to specific gem versions, which means things may get
476
- # inconsistent after an uninstall (i.e. referring to a version that no longer exists).
283
+ # XXX: Application stubs refer to specific gem versions, which
284
+ # means things may get inconsistent after an uninstall
285
+ # (i.e. referring to a version that no longer exists).
477
286
  #
478
287
  def uninstall
479
288
  require 'fileutils'
480
- list = Gem::SourceIndex.from_installed_gems.search(@gem, @version)
289
+ Gem.source_index.refresh!
290
+ list = Gem.source_index.search(@gem, @version)
481
291
  if list.size == 0
482
292
  raise "Unknown RubyGem: #{@gem} (#{@version})"
483
- elsif list.size > 1
293
+ elsif list.size > 1 && @force_all
294
+ remove_all(list.dup)
295
+ remove_executables(list.last)
296
+ elsif list.size > 1
484
297
  say
485
- gem_list = list.collect {|gem| gem.full_name}
486
- gem_list << "All versions"
487
- gem_name, index = choose_from_list("Select RubyGem to uninstall:", gem_list)
298
+ gem_names = list.collect {|gem| gem.full_name} + ["All versions"]
299
+ gem_name, index =
300
+ choose_from_list("Select RubyGem to uninstall:", gem_names)
488
301
  if index == list.size
489
302
  remove_all(list.dup)
490
303
  remove_executables(list.last)
@@ -495,18 +308,20 @@ TEXT
495
308
  say "Error: must enter a number [1-#{list.size+1}]"
496
309
  end
497
310
  else
311
+ remove(list[0], list.dup)
498
312
  remove_executables(list.last)
499
- remove(list[0], list)
500
313
  end
501
314
  end
502
315
 
503
- #
504
- # Remove executables and batch files (windows only) for the gem as it is being installed
316
+ ##
317
+ # Remove executables and batch files (windows only) for the gem as
318
+ # it is being installed
505
319
  #
506
320
  # gemspec::[Specification] the gem whose executables need to be removed.
321
+ #
507
322
  def remove_executables(gemspec)
508
323
  return if gemspec.nil?
509
- if(gemspec.executables.size > 0) then
324
+ if(gemspec.executables.size > 0)
510
325
  raise Gem::FilePermissionError.new(Config::CONFIG['bindir']) unless
511
326
  File.writable?(Config::CONFIG['bindir'])
512
327
  list = Gem.source_index.search(gemspec.name).delete_if { |spec|
@@ -519,7 +334,10 @@ TEXT
519
334
  end
520
335
  end
521
336
  return if executables.size == 0
522
- answer = ask_yes_no("Remove executables and scripts for\n'#{gemspec.executables.join(", ")}' in addition to the gem?", true)
337
+ answer = @force_executables || ask_yes_no(
338
+ "Remove executables and scripts for\n" +
339
+ "'#{gemspec.executables.join(", ")}' in addition to the gem?",
340
+ true)
523
341
  unless answer
524
342
  say "Executables and scripts will remain installed."
525
343
  return
@@ -537,8 +355,8 @@ TEXT
537
355
  #
538
356
  # list:: the list of all gems to remove
539
357
  #
540
- # Warning: this method modifies the +list+ parameter. Once it has uninstalled a gem, it is
541
- # removed from that list.
358
+ # Warning: this method modifies the +list+ parameter. Once it has
359
+ # uninstalled a gem, it is removed from that list.
542
360
  #
543
361
  def remove_all(list)
544
362
  list.dup.each { |gem| remove(gem, list) }
@@ -548,85 +366,92 @@ TEXT
548
366
  # spec:: the spec of the gem to be uninstalled
549
367
  # list:: the list of all such gems
550
368
  #
551
- # Warning: this method modifies the +list+ parameter. Once it has uninstalled a gem, it is
552
- # removed from that list.
369
+ # Warning: this method modifies the +list+ parameter. Once it has
370
+ # uninstalled a gem, it is removed from that list.
553
371
  #
554
372
  def remove(spec, list)
555
- if(has_dependents?(spec)) then
556
- raise DependencyRemovalException.new("Uninstallation aborted due to dependent gem(s)")
373
+ if( ! ok_to_remove?(spec)) then
374
+ raise DependencyRemovalException.new(
375
+ "Uninstallation aborted due to dependent gem(s)")
557
376
  end
558
- raise Gem::FilePermissionError.new(spec.installation_path) unless File.writable?(spec.installation_path)
377
+ raise Gem::FilePermissionError.new(spec.installation_path) unless
378
+ File.writable?(spec.installation_path)
559
379
  FileUtils.rm_rf spec.full_gem_path
560
- FileUtils.rm_rf File.join(spec.installation_path, 'specifications', "#{spec.full_name}.gemspec")
561
- FileUtils.rm_rf File.join(spec.installation_path, 'cache', "#{spec.full_name}.gem")
380
+ FileUtils.rm_rf File.join(
381
+ spec.installation_path,
382
+ 'specifications',
383
+ "#{spec.full_name}.gemspec")
384
+ FileUtils.rm_rf File.join(
385
+ spec.installation_path,
386
+ 'cache',
387
+ "#{spec.full_name}.gem")
562
388
  DocManager.new(spec).uninstall_doc
563
389
  #remove_stub_files(spec, list - [spec])
564
390
  say "Successfully uninstalled #{spec.name} version #{spec.version}"
565
391
  list.delete(spec)
566
392
  end
567
393
 
568
- def has_dependents?(spec)
394
+ def ok_to_remove?(spec)
395
+ return true if @force_ignore
396
+ srcindex= Gem::SourceIndex.from_installed_gems
397
+ deplist = Gem::DependencyList.from_source_index(srcindex)
398
+ deplist.ok_to_remove?(spec.full_name) ||
399
+ ask_if_ok(spec)
400
+ end
401
+
402
+ def ask_if_ok(spec)
403
+ msg = ['']
404
+ msg << 'You have requested to uninstall the gem:'
405
+ msg << "\t#{spec.full_name}"
569
406
  spec.dependent_gems.each do |gem,dep,satlist|
570
- msg = ['You have requested to uninstall the gem:']
571
- satlist.each do |sat|
572
- msg << "\t#{sat.name}-#{sat.version}"
573
- end
574
- msg << "#{gem.name}-#{gem.version} depends on [#{dep.name} (#{dep.version_requirements})]"
575
- msg << 'If you remove this gem, the dependency will not be met.'
576
- msg << 'Uninstall anyway?'
577
- return !ask_yes_no(msg.join("\n"), false)
407
+ msg <<
408
+ ("#{gem.name}-#{gem.version} depends on " +
409
+ "[#{dep.name} (#{dep.version_requirements})]")
578
410
  end
579
- false
411
+ msg << 'If you remove this gems, one or more dependencies will not be met.'
412
+ msg << 'Continue with Uninstall?'
413
+ return ask_yes_no(msg.join("\n"), true)
580
414
  end
581
415
 
582
416
  private
583
417
 
584
418
  ##
585
- # Remove application and library stub files. These are detected by the line
586
- # # This file was generated by RubyGems.
419
+ # Remove application stub files. These are detected by the line
420
+ # # This file was generated by RubyGems.
587
421
  #
588
422
  # spec:: the spec of the gem that is being uninstalled
589
- # other_specs:: any other installed specs for this gem (i.e. different versions)
423
+ # other_specs:: any other installed specs for this gem
424
+ # (i.e. different versions)
590
425
  #
591
- # Both parameters are necessary to ensure that the correct files are uninstalled. It is
592
- # assumed that +other_specs+ contains only *installed* gems, except the one that's about to
593
- # be uninstalled.
426
+ # Both parameters are necessary to ensure that the correct files
427
+ # are uninstalled. It is assumed that +other_specs+ contains only
428
+ # *installed* gems, except the one that's about to be uninstalled.
594
429
  #
595
430
  def remove_stub_files(spec, other_specs)
596
431
  remove_app_stubs(spec, other_specs)
597
- remove_lib_stub(spec, other_specs)
598
432
  end
599
433
 
600
434
  def remove_app_stubs(spec, other_specs)
601
- # App stubs are tricky, because each version of an app gem could install different
602
- # applications. We need to make sure that what we delete isn't needed by any remaining
603
- # versions of the gem.
435
+ # App stubs are tricky, because each version of an app gem could
436
+ # install different applications. We need to make sure that
437
+ # what we delete isn't needed by any remaining versions of the
438
+ # gem.
604
439
  #
605
- # There's extra trickiness, too, because app stubs 'require_gem' a specific version of
606
- # the gem. If we uninstall the latest gem, we should ensure that there is a sensible app
607
- # stub(s) installed after the removal of the current one.
440
+ # There's extra trickiness, too, because app stubs 'require_gem'
441
+ # a specific version of the gem. If we uninstall the latest
442
+ # gem, we should ensure that there is a sensible app stub(s)
443
+ # installed after the removal of the current one.
608
444
  #
609
445
  # Perhaps the best way to approach this is:
610
- # * remove all application stubs for this gemspec
611
- # * regenerate the app stubs for the latest remaining version
612
- # (you always want to have the latest version of an app, don't you?)
446
+ # * remove all application stubs for this gemspec
447
+ # * regenerate the app stubs for the latest remaining version
448
+ # (you always want to have the latest version of an app,
449
+ # don't you?)
613
450
  #
614
- # The Installer class doesn't really support this approach very well at the moment.
451
+ # The Installer class doesn't really support this approach very
452
+ # well at the moment.
615
453
  end
616
454
 
617
- def remove_lib_stub(spec, other_specs)
618
- # Library stubs are a bit easier than application stubs. They do not refer to a specific
619
- # version; they just load the latest version of the library available as a gem. The only
620
- # corner case is that different versions of the same gem may have different autorequire
621
- # settings, which means they will have different library stubs.
622
- #
623
- # I suppose our policy should be: when you uninstall a library, make sure all the
624
- # remaining versions of that gem are still supported by stubs. Of course, the user may
625
- # have expressed a preference in the past not to have library stubs installed.
626
- #
627
- # Mixing the segregated world of gem installations with the global namespace of the
628
- # site_ruby directory certainly brings some tough issues.
629
- end
630
455
  end # class Uninstaller
631
456
 
632
457
  end # module Gem