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