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.
- data/ChangeLog +134 -0
- data/Rakefile +41 -17
- data/bin/gemwhich +61 -0
- data/examples/application/an-app.gemspec +1 -0
- data/lib/gemconfigure.rb +18 -0
- data/lib/rubygems.rb +65 -47
- data/lib/rubygems/cmd_manager.rb +3 -1
- data/lib/rubygems/command.rb +4 -0
- data/lib/rubygems/config_file.rb +2 -6
- data/lib/rubygems/custom_require.rb +2 -2
- data/lib/rubygems/dependency_list.rb +131 -0
- data/lib/rubygems/deployment.rb +265 -0
- data/lib/rubygems/doc_manager.rb +1 -0
- data/lib/rubygems/gem_commands.rb +216 -15
- data/lib/rubygems/installer.rb +111 -286
- data/lib/rubygems/remote_installer.rb +16 -6
- data/lib/rubygems/rubygems_version.rb +1 -1
- data/lib/rubygems/source_index.rb +11 -5
- data/lib/rubygems/specification.rb +5 -0
- data/lib/rubygems/version.rb +146 -129
- data/test/test_configfile.rb +1 -1
- data/test/test_dependency_list.rb +163 -0
- data/test/test_deployment.rb +93 -0
- data/test/test_remote_fetcher.rb +38 -36
- metadata +23 -47
- data/test/data/a-0.0.1.gem +0 -0
- data/test/data/a-0.0.2.gem +0 -0
- data/test/data/b-0.0.2.gem +0 -0
- data/test/data/c-1.2.gem +0 -0
- data/test/data/gemhome/cache/a-0.0.1.gem +0 -0
- data/test/data/gemhome/cache/a-0.0.2.gem +0 -0
- data/test/data/gemhome/cache/b-0.0.2.gem +0 -0
- data/test/data/gemhome/cache/c-1.2.gem +0 -0
- data/test/data/gemhome/gems/a-0.0.1/lib/code.rb +0 -1
- data/test/data/gemhome/gems/a-0.0.2/lib/code.rb +0 -1
- data/test/data/gemhome/gems/b-0.0.2/lib/code.rb +0 -1
- data/test/data/gemhome/gems/c-1.2/lib/code.rb +0 -1
- data/test/data/gemhome/specifications/a-0.0.1.gemspec +0 -8
- data/test/data/gemhome/specifications/a-0.0.2.gemspec +0 -8
- data/test/data/gemhome/specifications/b-0.0.2.gemspec +0 -8
- data/test/data/gemhome/specifications/c-1.2.gemspec +0 -8
- data/test/data/one/one-0.0.1.gem +0 -0
data/lib/rubygems/doc_manager.rb
CHANGED
@@ -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(
|
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},
|
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(
|
169
|
-
|
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
|
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
|
-
|
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
|
-
|
594
|
-
|
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
|
data/lib/rubygems/installer.rb
CHANGED
@@ -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,
|
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
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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
|
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,
|
155
|
-
|
156
|
-
File.open(
|
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
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
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,
|
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
|
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
|
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
|
476
|
-
# inconsistent after an uninstall
|
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
|
-
|
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
|
-
|
486
|
-
|
487
|
-
|
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
|
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)
|
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 =
|
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
|
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
|
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(
|
556
|
-
raise DependencyRemovalException.new(
|
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
|
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(
|
561
|
-
|
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
|
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
|
571
|
-
|
572
|
-
|
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
|
-
|
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
|
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
|
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
|
592
|
-
# assumed that +other_specs+ contains only
|
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
|
602
|
-
# applications. We need to make sure that
|
603
|
-
# versions of the
|
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'
|
606
|
-
# the gem. If we uninstall the latest
|
607
|
-
#
|
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
|
-
#
|
611
|
-
#
|
612
|
-
# (you always want to have the latest version of an app,
|
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
|
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
|