rubygems-update 0.8.6 → 0.8.8

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 (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