rubygems-update 0.8.3
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 +2335 -0
- data/README +54 -0
- data/Rakefile +293 -0
- data/Releases +98 -0
- data/TODO +7 -0
- data/bin/gem +11 -0
- data/bin/gem_server +111 -0
- data/bin/generate_yaml_index.rb +58 -0
- data/bin/update_rubygems +18 -0
- data/doc/doc.css +73 -0
- data/doc/makedoc.rb +4 -0
- data/examples/application/an-app.gemspec +26 -0
- data/examples/application/bin/myapp +3 -0
- data/examples/application/lib/somefunctionality.rb +3 -0
- data/gemspecs/README +4 -0
- data/gemspecs/cgikit-1.1.0.gemspec +18 -0
- data/gemspecs/jabber4r.gemspec +26 -0
- data/gemspecs/linguistics.gemspec +22 -0
- data/gemspecs/ook.gemspec +21 -0
- data/gemspecs/progressbar.gemspec +22 -0
- data/gemspecs/redcloth.gemspec +22 -0
- data/gemspecs/rublog.gemspec +23 -0
- data/gemspecs/ruby-doom.gemspec +21 -0
- data/gemspecs/rubyjdwp.gemspec +21 -0
- data/gemspecs/statistics.gemspec +21 -0
- data/lib/rubygems.rb +353 -0
- data/lib/rubygems/builder.rb +54 -0
- data/lib/rubygems/cmd_manager.rb +127 -0
- data/lib/rubygems/command.rb +191 -0
- data/lib/rubygems/config_file.rb +57 -0
- data/lib/rubygems/doc_manager.rb +94 -0
- data/lib/rubygems/format.rb +65 -0
- data/lib/rubygems/gem_commands.rb +925 -0
- data/lib/rubygems/gem_runner.rb +23 -0
- data/lib/rubygems/installer.rb +621 -0
- data/lib/rubygems/loadpath_manager.rb +108 -0
- data/lib/rubygems/old_format.rb +150 -0
- data/lib/rubygems/open-uri.rb +604 -0
- data/lib/rubygems/package.rb +740 -0
- data/lib/rubygems/remote_installer.rb +499 -0
- data/lib/rubygems/rubygems_version.rb +6 -0
- data/lib/rubygems/source_index.rb +130 -0
- data/lib/rubygems/specification.rb +613 -0
- data/lib/rubygems/user_interaction.rb +176 -0
- data/lib/rubygems/validator.rb +148 -0
- data/lib/rubygems/version.rb +279 -0
- data/lib/ubygems.rb +4 -0
- data/pkgs/sources/lib/sources.rb +6 -0
- data/pkgs/sources/sources.gemspec +14 -0
- data/post-install.rb +75 -0
- data/redist/session.gem +433 -0
- data/scripts/buildtests.rb +25 -0
- data/scripts/gemdoc.rb +62 -0
- data/scripts/runtest.rb +17 -0
- data/scripts/specdoc.rb +164 -0
- data/setup.rb +1360 -0
- data/test/bogussources.rb +5 -0
- data/test/data/legacy/keyedlist-0.4.0.ruby +11 -0
- data/test/data/legacy/keyedlist-0.4.0.yaml +16 -0
- data/test/data/lib/code.rb +1 -0
- data/test/data/one/README.one +1 -0
- data/test/data/one/lib/one.rb +3 -0
- data/test/data/one/one.gemspec +17 -0
- data/test/data/one/one.yaml +40 -0
- data/test/functional.rb +145 -0
- data/test/gemenvironment.rb +45 -0
- data/test/gemutilities.rb +18 -0
- data/test/insure_session.rb +46 -0
- data/test/mock/gems/gems/sources-0.0.1/lib/sources.rb +5 -0
- data/test/mock/gems/specifications/sources-0.0.1.gemspec +8 -0
- data/test/mockgemui.rb +45 -0
- data/test/onegem.rb +23 -0
- data/test/simple_gem.rb +66 -0
- data/test/test_builder.rb +13 -0
- data/test/test_cached_fetcher.rb +60 -0
- data/test/test_check_command.rb +28 -0
- data/test/test_command.rb +130 -0
- data/test/test_configfile.rb +36 -0
- data/test/test_format.rb +70 -0
- data/test/test_gemloadpaths.rb +45 -0
- data/test/test_gempaths.rb +115 -0
- data/test/test_loadmanager.rb +40 -0
- data/test/test_local_cache.rb +157 -0
- data/test/test_package.rb +600 -0
- data/test/test_parse_commands.rb +179 -0
- data/test/test_process_commands.rb +21 -0
- data/test/test_remote_fetcher.rb +162 -0
- data/test/test_remote_installer.rb +154 -0
- data/test/test_source_index.rb +58 -0
- data/test/test_specification.rb +286 -0
- data/test/test_validator.rb +53 -0
- data/test/test_version_comparison.rb +204 -0
- data/test/testgem.rc +6 -0
- data/test/user_capture.rb +1 -0
- data/test/yaml_data.rb +59 -0
- metadata +151 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
module Gem
|
4
|
+
|
5
|
+
class GemRunner
|
6
|
+
|
7
|
+
def run(args)
|
8
|
+
do_configuration(args)
|
9
|
+
Gem::CommandManager.instance.run(@cfg)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def do_configuration(args)
|
15
|
+
@cfg = Gem::ConfigFile.new(args)
|
16
|
+
Gem.use_paths(@cfg[:gemhome], @cfg[:gempath])
|
17
|
+
Command.extra_args = @cfg[:gem]
|
18
|
+
DocManager.configured_args = @cfg[:rdoc]
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,621 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'rbconfig'
|
3
|
+
require 'rubygems/format'
|
4
|
+
|
5
|
+
module Gem
|
6
|
+
|
7
|
+
class DependencyRemovalException < Gem::Exception; end
|
8
|
+
|
9
|
+
##
|
10
|
+
# The installer class processes RubyGem .gem files and installs the
|
11
|
+
# files contained in the .gem into the Gem.path.
|
12
|
+
#
|
13
|
+
class Installer
|
14
|
+
|
15
|
+
include UserInteraction
|
16
|
+
|
17
|
+
##
|
18
|
+
# Constructs an Installer instance
|
19
|
+
#
|
20
|
+
# gem:: [String] The file name of the gem
|
21
|
+
#
|
22
|
+
def initialize(gem)
|
23
|
+
@gem = gem
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# Installs the gem in the Gem.path. This will fail (unless
|
28
|
+
# force=true) if a Gem has a requirement on another Gem that is
|
29
|
+
# not installed. The installation will install in the following
|
30
|
+
# structure:
|
31
|
+
#
|
32
|
+
# Gem.path/
|
33
|
+
# specifications/<gem-version>.gemspec #=> the extracted YAML gemspec
|
34
|
+
# gems/<gem-version>/... #=> the extracted Gem files
|
35
|
+
# cache/<gem-version>.gem #=> a cached copy of the installed Gem
|
36
|
+
#
|
37
|
+
# force:: [default = false] if false will fail if a required Gem is not installed,
|
38
|
+
# or if the Ruby version is too low for the gem
|
39
|
+
# install_dir:: [default = Gem.dir] directory that Gem is to be installed in
|
40
|
+
# install_stub:: [default = false] causes the installation of a library stub in the +site_ruby+ directory
|
41
|
+
#
|
42
|
+
# return:: [Gem::Specification] The specification for the newly installed Gem.
|
43
|
+
#
|
44
|
+
def install(force=false, install_dir=Gem.dir, install_stub=false)
|
45
|
+
require 'fileutils'
|
46
|
+
format = Gem::Format.from_file_by_path(@gem)
|
47
|
+
unless force
|
48
|
+
spec = format.spec
|
49
|
+
# Check the Ruby version.
|
50
|
+
if (rrv = spec.required_ruby_version)
|
51
|
+
unless rrv.satisfied_by?(Gem::Version.new(RUBY_VERSION))
|
52
|
+
raise "#{spec.name} requires Ruby version #{rrv}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
# Check the dependent gems.
|
56
|
+
spec.dependencies.each do |dep_gem|
|
57
|
+
# XXX: Does this take account of *versions*?
|
58
|
+
require_gem(dep_gem, false) #no autorequire
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
raise Gem::FilePermissionError.new(install_dir) unless File.writable?(install_dir)
|
63
|
+
|
64
|
+
# Build spec dir.
|
65
|
+
directory = File.join(install_dir, "gems", format.spec.full_name)
|
66
|
+
FileUtils.mkdir_p directory
|
67
|
+
|
68
|
+
extract_files(directory, format)
|
69
|
+
generate_bin_scripts(format.spec, install_dir)
|
70
|
+
#generate_library_stubs(format.spec) if install_stub
|
71
|
+
build_extensions(directory, format.spec)
|
72
|
+
|
73
|
+
# Build spec/cache/doc dir.
|
74
|
+
build_support_directories(install_dir)
|
75
|
+
|
76
|
+
# Write the spec and cache files.
|
77
|
+
write_spec(format.spec, File.join(install_dir, "specifications"))
|
78
|
+
unless(File.exist?(File.join(File.join(install_dir, "cache"), @gem.split(/\//).pop)))
|
79
|
+
FileUtils.cp(@gem, File.join(install_dir, "cache"))
|
80
|
+
end
|
81
|
+
|
82
|
+
format.spec.loaded_from = File.join(install_dir, 'specifications', format.spec.full_name+".gemspec")
|
83
|
+
return format.spec
|
84
|
+
end
|
85
|
+
|
86
|
+
#
|
87
|
+
# Unpacks the gem into the given directory.
|
88
|
+
#
|
89
|
+
def unpack(directory)
|
90
|
+
format = Gem::Format.from_file_by_path(@gem)
|
91
|
+
extract_files(directory, format)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Given a root gem directory, build supporting directories for gem
|
95
|
+
# if they do not already exist
|
96
|
+
def build_support_directories(install_dir)
|
97
|
+
unless File.exist? File.join(install_dir, "specifications")
|
98
|
+
FileUtils.mkdir_p File.join(install_dir, "specifications")
|
99
|
+
end
|
100
|
+
unless File.exist? File.join(install_dir, "cache")
|
101
|
+
FileUtils.mkdir_p File.join(install_dir, "cache")
|
102
|
+
end
|
103
|
+
unless File.exist? File.join(install_dir, "doc")
|
104
|
+
FileUtils.mkdir_p File.join(install_dir, "doc")
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
##
|
109
|
+
# Writes the .gemspec specification (in Ruby) to the supplied spec_path.
|
110
|
+
#
|
111
|
+
# spec:: [Gem::Specification] The Gem specification to output
|
112
|
+
# spec_path:: [String] The location (path) to write the gemspec to
|
113
|
+
#
|
114
|
+
def write_spec(spec, spec_path)
|
115
|
+
rubycode = spec.to_ruby
|
116
|
+
File.open(File.join(spec_path, spec.full_name+".gemspec"), "w") do |file|
|
117
|
+
file.puts rubycode
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
##
|
122
|
+
# Creates windows .cmd files for easy running of commands
|
123
|
+
#
|
124
|
+
def generate_windows_script(bindir, filename)
|
125
|
+
if Config::CONFIG["arch"] =~ /dos|win32/i
|
126
|
+
script_name = filename + ".cmd"
|
127
|
+
File.open(File.join(bindir, File.basename(script_name)), "w") do |file|
|
128
|
+
file.puts "@ruby \"#{File.join(bindir,filename)}\" %*"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
##
|
134
|
+
# Creates the scripts to run the applications in the gem.
|
135
|
+
#
|
136
|
+
def generate_bin_scripts(spec, install_dir=Gem.dir)
|
137
|
+
if spec.executables && ! spec.executables.empty?
|
138
|
+
bindir = if(install_dir == Gem.default_dir)
|
139
|
+
Config::CONFIG['bindir']
|
140
|
+
else
|
141
|
+
File.join(install_dir, "bin")
|
142
|
+
end
|
143
|
+
Dir.mkdir(bindir) unless File.exist?(bindir)
|
144
|
+
raise Gem::FilePermissionError.new(bindir) unless File.writable?(bindir)
|
145
|
+
spec.executables.each do |filename|
|
146
|
+
File.open(File.join(bindir, File.basename(filename)), "w", 0755) do |file|
|
147
|
+
file.print(app_script_text(spec.name, spec.version.version, filename))
|
148
|
+
end
|
149
|
+
generate_windows_script(bindir, filename)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
##
|
155
|
+
# Returns the text for an application file.
|
156
|
+
#
|
157
|
+
def app_script_text(name, version, filename)
|
158
|
+
text = <<-TEXT
|
159
|
+
#!#{File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])}
|
160
|
+
|
161
|
+
#
|
162
|
+
# This file was generated by RubyGems.
|
163
|
+
#
|
164
|
+
# The application '#{name}' is installed as part of a gem, and
|
165
|
+
# this file is here to facilitate running it.
|
166
|
+
#
|
167
|
+
|
168
|
+
require 'rubygems'
|
169
|
+
version = "> 0"
|
170
|
+
if ARGV.size > 0 && ARGV[0][0]==95 && ARGV[0][-1]==95
|
171
|
+
if Gem::Version.correct?(ARGV[0][1..-2])
|
172
|
+
version = ARGV[0][1..-2]
|
173
|
+
ARGV.shift
|
174
|
+
end
|
175
|
+
end
|
176
|
+
require_gem '#{name}', version
|
177
|
+
load '#{filename}'
|
178
|
+
TEXT
|
179
|
+
text
|
180
|
+
end
|
181
|
+
|
182
|
+
##
|
183
|
+
# Creates a file in the site_ruby directory that acts as a stub for the gem. Thus, if
|
184
|
+
# 'package' is installed as a gem, the user can just type <tt>require 'package'</tt> and
|
185
|
+
# the gem (latest version) will be loaded. This is like a backwards compatibility so that
|
186
|
+
# gems and non-gems can interact.
|
187
|
+
#
|
188
|
+
# Which files are stubified? Those included in the gem's 'autorequire' and 'library_stubs'
|
189
|
+
# attributes.
|
190
|
+
#
|
191
|
+
def generate_library_stubs(spec)
|
192
|
+
LibraryStubs.new(spec).generate
|
193
|
+
end
|
194
|
+
|
195
|
+
def build_extensions(directory, spec)
|
196
|
+
return unless spec.extensions.size > 0
|
197
|
+
say "Building native extensions. This could take a while..."
|
198
|
+
start_dir = Dir.pwd
|
199
|
+
dest_path = File.join(directory, spec.require_paths[0])
|
200
|
+
spec.extensions.each do |extension|
|
201
|
+
Dir.chdir File.join(directory, File.dirname(extension))
|
202
|
+
results = ["ruby #{File.basename(extension)} #{ARGV.join(" ")}"]
|
203
|
+
results << `ruby #{File.basename(extension)} #{ARGV.join(" ")}`
|
204
|
+
if File.exist?('Makefile')
|
205
|
+
mf = File.read('Makefile')
|
206
|
+
mf = mf.gsub(/^RUBYARCHDIR\s*=\s*\$.*/, "RUBYARCHDIR = #{dest_path}")
|
207
|
+
mf = mf.gsub(/^RUBYLIBDIR\s*=\s*\$.*/, "RUBYLIBDIR = #{dest_path}")
|
208
|
+
File.open('Makefile', 'wb') {|f| f.print mf}
|
209
|
+
make_program = ENV['make']
|
210
|
+
unless make_program
|
211
|
+
make_program = (/mswin/ =~ RUBY_PLATFORM) ? 'nmake' : 'make'
|
212
|
+
end
|
213
|
+
results << "#{make_program}"
|
214
|
+
results << `#{make_program}`
|
215
|
+
results << "#{make_program} install"
|
216
|
+
results << `#{make_program} install`
|
217
|
+
say results.join("\n")
|
218
|
+
else
|
219
|
+
File.open(File.join(Dir.pwd, 'gem_make.out'), 'wb') {|f| f.puts results.join("\n")}
|
220
|
+
raise "ERROR: Failed to build gem native extension.\nGem files will remain installed in #{directory} for inspection.\n #{results.join('\n')}\n\nResults logged to #{File.join(Dir.pwd, 'gem_make.out')}"
|
221
|
+
end
|
222
|
+
File.open('gem_make.out', 'wb') {|f| f.puts results.join("\n")}
|
223
|
+
end
|
224
|
+
Dir.chdir start_dir
|
225
|
+
end
|
226
|
+
|
227
|
+
##
|
228
|
+
# Reads the YAML file index and then extracts each file
|
229
|
+
# into the supplied directory, building directories for the
|
230
|
+
# extracted files as needed.
|
231
|
+
#
|
232
|
+
# directory:: [String] The root directory to extract files into
|
233
|
+
# file:: [IO] The IO that contains the file data
|
234
|
+
#
|
235
|
+
def extract_files(directory, format)
|
236
|
+
require 'fileutils'
|
237
|
+
wd = Dir.getwd
|
238
|
+
Dir.chdir directory do
|
239
|
+
format.file_entries.each do |entry, file_data|
|
240
|
+
path = entry['path']
|
241
|
+
FileUtils.mkdir_p File.dirname(path)
|
242
|
+
File.open(path, "wb") do |out|
|
243
|
+
out.write file_data
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end # class Installer
|
249
|
+
|
250
|
+
|
251
|
+
#
|
252
|
+
# This class represents a single library stub, which is characterised by a
|
253
|
+
#
|
254
|
+
class LibraryStub
|
255
|
+
SITELIBDIR = Pathname.new(Config::CONFIG['sitelibdir'])
|
256
|
+
|
257
|
+
#
|
258
|
+
# The 'autorequire' attribute in a gemspec is a special case: it represents a require
|
259
|
+
# target, not a relative path. We therefore offer this method of creating a library stub
|
260
|
+
# for the autorequire file.
|
261
|
+
#
|
262
|
+
# If the given spec doesn't have an 'autorequire' value, we return +nil+.
|
263
|
+
#
|
264
|
+
def self.from_autorequire(gemspec, require_paths)
|
265
|
+
require_target = gemspec.autorequire
|
266
|
+
return nil if require_target.nil?
|
267
|
+
gem_relpath = find_gem_relpath(require_paths, require_target, gemspec)
|
268
|
+
LibraryStub.new(gemspec.name, require_paths, gem_relpath, true)
|
269
|
+
end
|
270
|
+
|
271
|
+
#
|
272
|
+
# require_paths::
|
273
|
+
# ([Pathname]) The require paths in the gemspec.
|
274
|
+
# gem_relpath::
|
275
|
+
# (String) The path to the library file, relative to the root of the gem.
|
276
|
+
# autorequire::
|
277
|
+
# (Boolean) Whether this stub represents the gem's autorequire file.
|
278
|
+
#
|
279
|
+
def initialize(gem_name, require_paths, gem_relpath, autorequire=false)
|
280
|
+
@gem_name = gem_name
|
281
|
+
@lib_relpath = find_lib_relpath(require_paths, gem_relpath)
|
282
|
+
@require_target = @lib_relpath.to_s.sub(/\.rb\Z/, '')
|
283
|
+
@stub_path = SITELIBDIR.join(@lib_relpath)
|
284
|
+
@autorequire = autorequire
|
285
|
+
end
|
286
|
+
|
287
|
+
#
|
288
|
+
# The powerhouse of the class. No exceptions should result from calling this.
|
289
|
+
#
|
290
|
+
def generate
|
291
|
+
if @stub_path.exist?
|
292
|
+
# The stub path is inhabited by a file. If it's a gem stub, we'll overwrite it (just
|
293
|
+
# to be sure). If it's a genuine library, we'll leave it alone and issue a warning.
|
294
|
+
unless library_stub?(@stub_path)
|
295
|
+
alert_warning(
|
296
|
+
["Library file '#{target_path}'",
|
297
|
+
"already exists; not overwriting. If you want to force a",
|
298
|
+
"library stub, delete the file and reinstall."].join("\n")
|
299
|
+
)
|
300
|
+
return
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
unless @stub_path.dirname.exist?
|
305
|
+
@stub_path.dirname.mkpath
|
306
|
+
end
|
307
|
+
@stub_path.open('w', 0644) do |io|
|
308
|
+
io.write(library_stub_content())
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
# Two LibraryStub objects are equal if they have the same gem name and relative (gem) path.
|
313
|
+
def ==(other)
|
314
|
+
LibraryStub === other and @gem_name == other.gem_name and
|
315
|
+
@gem_relpath == other.gem_relpath
|
316
|
+
end
|
317
|
+
|
318
|
+
private
|
319
|
+
|
320
|
+
#
|
321
|
+
# require_paths::
|
322
|
+
# ([Pathname]) The require paths in the gemspec.
|
323
|
+
# require_target::
|
324
|
+
# (String) The subject of an intended 'require' statement.
|
325
|
+
# gemspec::
|
326
|
+
# (Gem::Specification)
|
327
|
+
#
|
328
|
+
# The aim of this method is to resolve the require_target into a path relative to the root
|
329
|
+
# of the gem. We try each require path in turn, and see if the require target exists under
|
330
|
+
# that directory.
|
331
|
+
#
|
332
|
+
# If no match is found, we return +nil+.
|
333
|
+
#
|
334
|
+
def self.find_gem_relpath(require_paths, require_target, gemspec)
|
335
|
+
require_target << '.rb' unless require_target =~ /\.rb\Z/
|
336
|
+
gem_files = gemspec.files.map { |path| Pathname.new(path).cleanpath }
|
337
|
+
require_paths.each do |require_path|
|
338
|
+
possible_lib_path = require_path.join(require_target)
|
339
|
+
if gem_files.include?(possible_lib_path)
|
340
|
+
return possible_lib_path.to_s
|
341
|
+
end
|
342
|
+
end
|
343
|
+
nil # If we get this far, there was no match.
|
344
|
+
end
|
345
|
+
|
346
|
+
#
|
347
|
+
# require_paths::
|
348
|
+
# ([Pathname]) The require paths in the gemspec.
|
349
|
+
# gem_relpath::
|
350
|
+
# (String) The path to the library file, relative to the root of the gem.
|
351
|
+
#
|
352
|
+
# Returns: the path (Pathname) to the same file, relative to the gem's library path
|
353
|
+
# (typically 'lib'). Thus 'lib/rake/rdoctask.rb' becomes 'rake/rdoctask.rb'. The gemspec
|
354
|
+
# may contain several library paths, though that would be unusual, so we must deal with
|
355
|
+
# that possibility here.
|
356
|
+
#
|
357
|
+
# If there is no such relative path, we return +nil+.
|
358
|
+
#
|
359
|
+
def find_lib_relpath(require_paths, gem_relpath)
|
360
|
+
require_paths.each do |require_path|
|
361
|
+
begin
|
362
|
+
return Pathname.new(gem_relpath).relative_path_from(require_path)
|
363
|
+
rescue ArgumentError
|
364
|
+
next
|
365
|
+
end
|
366
|
+
nil # If we get this far, there was no match.
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
# Returns a string suitable for placing in a stub file.
|
371
|
+
def library_stub_content
|
372
|
+
content = %{
|
373
|
+
#
|
374
|
+
# This file was generated by RubyGems.
|
375
|
+
#
|
376
|
+
# The library '#{@gem_name}' is installed as part of a gem, and
|
377
|
+
# this file is here so you can 'require' it easily (i.e.
|
378
|
+
# without having to know it's a gem).
|
379
|
+
#
|
380
|
+
# gem: #{@gem_name}
|
381
|
+
# stub: #{@lib_relpath}
|
382
|
+
#
|
383
|
+
|
384
|
+
require 'rubygems'
|
385
|
+
$".delete('#{@lib_relpath}')
|
386
|
+
require_gem '#{@gem_name}'
|
387
|
+
}.gsub(/^[ \t]+/, '')
|
388
|
+
unless @autorequire
|
389
|
+
content << %{require '#{@require_target}'\n}
|
390
|
+
end
|
391
|
+
content << %{
|
392
|
+
# (end of stub)
|
393
|
+
}.gsub(/^[ \t]+/, '')
|
394
|
+
end
|
395
|
+
|
396
|
+
# Returns true iff the contents of the given _path_ (a Pathname) appear to be a RubyGems
|
397
|
+
# library stub.
|
398
|
+
def library_stub?(path)
|
399
|
+
lines = path.readlines
|
400
|
+
lines.grep(/^# This file was generated by RubyGems/) and
|
401
|
+
lines.grep(/is installed as part of a gem, and/)
|
402
|
+
end
|
403
|
+
|
404
|
+
end # class LibraryStub
|
405
|
+
|
406
|
+
|
407
|
+
#
|
408
|
+
# This class contains the logic to generate all library stubs, including the autorequire, for
|
409
|
+
# a single gemspec.
|
410
|
+
#
|
411
|
+
# LibraryStubs.new(gemspec).generate
|
412
|
+
#
|
413
|
+
class LibraryStubs
|
414
|
+
SITELIBDIR = Pathname.new(Config::CONFIG['sitelibdir'])
|
415
|
+
|
416
|
+
def initialize(spec)
|
417
|
+
@spec = spec
|
418
|
+
end
|
419
|
+
|
420
|
+
def generate
|
421
|
+
require_paths = @spec.require_paths.map { |p| Pathname.new(p) }
|
422
|
+
stubs = @spec.library_stubs.map {
|
423
|
+
|stub| LibraryStub.new(@spec.name, require_paths, stub)
|
424
|
+
}
|
425
|
+
stubs << LibraryStub.from_autorequire(@spec, require_paths)
|
426
|
+
stubs = stubs.compact.uniq
|
427
|
+
unless stubs.empty?
|
428
|
+
if FileTest.writable?(SITELIBDIR)
|
429
|
+
stubs.each do |stub| stub.generate end
|
430
|
+
else
|
431
|
+
alert_warning(
|
432
|
+
["Can't install library stub for gem '#{spec.name}'",
|
433
|
+
"(Don't have write permissions on '#{sitelibdir}' directory.)"].join("\n")
|
434
|
+
)
|
435
|
+
end
|
436
|
+
end
|
437
|
+
end
|
438
|
+
end # class LibraryStubs
|
439
|
+
|
440
|
+
|
441
|
+
##
|
442
|
+
# The Uninstaller class uninstalls a Gem
|
443
|
+
#
|
444
|
+
class Uninstaller
|
445
|
+
|
446
|
+
include UserInteraction
|
447
|
+
|
448
|
+
##
|
449
|
+
# Constructs an Uninstaller instance
|
450
|
+
#
|
451
|
+
# gem:: [String] The Gem name to uninstall
|
452
|
+
#
|
453
|
+
def initialize(gem, version="> 0")
|
454
|
+
@gem = gem
|
455
|
+
@version = version
|
456
|
+
end
|
457
|
+
|
458
|
+
##
|
459
|
+
# Performs the uninstall of the Gem. This removes the spec, the Gem directory, and the
|
460
|
+
# cached .gem file,
|
461
|
+
#
|
462
|
+
# Application and library stubs are removed according to what is still installed.
|
463
|
+
#
|
464
|
+
# XXX: Application stubs refer to specific gem versions, which means things may get
|
465
|
+
# inconsistent after an uninstall (i.e. referring to a version that no longer exists).
|
466
|
+
#
|
467
|
+
def uninstall
|
468
|
+
require 'fileutils'
|
469
|
+
list = Gem::SourceIndex.from_installed_gems.search(@gem, @version)
|
470
|
+
if list.size == 0
|
471
|
+
raise "Unknown RubyGem: #{@gem} (#{@version})"
|
472
|
+
elsif list.size > 1
|
473
|
+
say
|
474
|
+
gem_list = list.collect {|gem| gem.full_name}
|
475
|
+
gem_list << "All versions"
|
476
|
+
gem_name, index = choose_from_list("Select RubyGem to uninstall:", gem_list)
|
477
|
+
if index == list.size
|
478
|
+
remove_all(list.dup)
|
479
|
+
remove_executables(list.last)
|
480
|
+
elsif index >= 0 && index < list.size
|
481
|
+
remove(list[index], list)
|
482
|
+
remove_executables(list[index])
|
483
|
+
else
|
484
|
+
say "Error: must enter a number [1-#{list.size+1}]"
|
485
|
+
end
|
486
|
+
else
|
487
|
+
remove_executables(list.last)
|
488
|
+
remove(list[0], list)
|
489
|
+
end
|
490
|
+
end
|
491
|
+
|
492
|
+
#
|
493
|
+
# Remove executables and batch files (windows only) for the gem as it is being installed
|
494
|
+
#
|
495
|
+
# gemspec::[Specification] the gem whose executables need to be removed.
|
496
|
+
def remove_executables(gemspec)
|
497
|
+
return if gemspec.nil?
|
498
|
+
if(gemspec.executables.size > 0) then
|
499
|
+
raise Gem::FilePermissionError.new(Config::CONFIG['bindir']) unless
|
500
|
+
File.writable?(Config::CONFIG['bindir'])
|
501
|
+
list = Gem.source_index.search(gemspec.name).delete_if { |spec|
|
502
|
+
spec.version == gemspec.version
|
503
|
+
}
|
504
|
+
executables = gemspec.executables.clone
|
505
|
+
list.each do |spec|
|
506
|
+
spec.executables.each do |exe_name|
|
507
|
+
executables.delete(exe_name)
|
508
|
+
end
|
509
|
+
end
|
510
|
+
return if executables.size == 0
|
511
|
+
answer = ask_yes_no("Remove executables and scripts for\n'#{gemspec.executables.join(", ")}' in addition to the gem?", true)
|
512
|
+
unless answer
|
513
|
+
say "Executables and scripts will remain installed."
|
514
|
+
return
|
515
|
+
else
|
516
|
+
bindir = Config::CONFIG['bindir']
|
517
|
+
gemspec.executables.each do |exe_name|
|
518
|
+
say "Removing #{exe_name}"
|
519
|
+
File.unlink(File.join(bindir, exe_name)) rescue nil
|
520
|
+
File.unlink(File.join(bindir, exe_name + ".cmd")) rescue nil
|
521
|
+
end
|
522
|
+
end
|
523
|
+
end
|
524
|
+
end
|
525
|
+
|
526
|
+
#
|
527
|
+
# list:: the list of all gems to remove
|
528
|
+
#
|
529
|
+
# Warning: this method modifies the +list+ parameter. Once it has uninstalled a gem, it is
|
530
|
+
# removed from that list.
|
531
|
+
#
|
532
|
+
def remove_all(list)
|
533
|
+
list.dup.each { |gem| remove(gem, list) }
|
534
|
+
end
|
535
|
+
|
536
|
+
#
|
537
|
+
# spec:: the spec of the gem to be uninstalled
|
538
|
+
# list:: the list of all such gems
|
539
|
+
#
|
540
|
+
# Warning: this method modifies the +list+ parameter. Once it has uninstalled a gem, it is
|
541
|
+
# removed from that list.
|
542
|
+
#
|
543
|
+
def remove(spec, list)
|
544
|
+
if(has_dependents?(spec)) then
|
545
|
+
raise DependencyRemovalException.new("Uninstallation aborted due to dependent gem(s)")
|
546
|
+
end
|
547
|
+
raise Gem::FilePermissionError.new(spec.installation_path) unless File.writable?(spec.installation_path)
|
548
|
+
FileUtils.rm_rf spec.full_gem_path
|
549
|
+
FileUtils.rm_rf File.join(spec.installation_path, 'specifications', "#{spec.full_name}.gemspec")
|
550
|
+
FileUtils.rm_rf File.join(spec.installation_path, 'cache', "#{spec.full_name}.gem")
|
551
|
+
DocManager.new(spec).uninstall_doc
|
552
|
+
#remove_stub_files(spec, list - [spec])
|
553
|
+
say "Successfully uninstalled #{spec.name} version #{spec.version}"
|
554
|
+
list.delete(spec)
|
555
|
+
end
|
556
|
+
|
557
|
+
def has_dependents?(spec)
|
558
|
+
spec.dependent_gems.each do |gem,dep,satlist|
|
559
|
+
msg = ['You have requested to uninstall the gem:']
|
560
|
+
satlist.each do |sat|
|
561
|
+
msg << "\t#{sat.name}-#{sat.version}"
|
562
|
+
end
|
563
|
+
msg << "#{gem.name}-#{gem.version} depends on [#{dep.name} (#{dep.version_requirements})]"
|
564
|
+
msg << 'If you remove this gem, the dependency will not be met.'
|
565
|
+
msg << 'Uninstall anyway?'
|
566
|
+
return !ask_yes_no(msg.join("\n"), false)
|
567
|
+
end
|
568
|
+
false
|
569
|
+
end
|
570
|
+
|
571
|
+
private
|
572
|
+
|
573
|
+
##
|
574
|
+
# Remove application and library stub files. These are detected by the line
|
575
|
+
# # This file was generated by RubyGems.
|
576
|
+
#
|
577
|
+
# spec:: the spec of the gem that is being uninstalled
|
578
|
+
# other_specs:: any other installed specs for this gem (i.e. different versions)
|
579
|
+
#
|
580
|
+
# Both parameters are necessary to ensure that the correct files are uninstalled. It is
|
581
|
+
# assumed that +other_specs+ contains only *installed* gems, except the one that's about to
|
582
|
+
# be uninstalled.
|
583
|
+
#
|
584
|
+
def remove_stub_files(spec, other_specs)
|
585
|
+
remove_app_stubs(spec, other_specs)
|
586
|
+
remove_lib_stub(spec, other_specs)
|
587
|
+
end
|
588
|
+
|
589
|
+
def remove_app_stubs(spec, other_specs)
|
590
|
+
# App stubs are tricky, because each version of an app gem could install different
|
591
|
+
# applications. We need to make sure that what we delete isn't needed by any remaining
|
592
|
+
# versions of the gem.
|
593
|
+
#
|
594
|
+
# There's extra trickiness, too, because app stubs 'require_gem' a specific version of
|
595
|
+
# the gem. If we uninstall the latest gem, we should ensure that there is a sensible app
|
596
|
+
# stub(s) installed after the removal of the current one.
|
597
|
+
#
|
598
|
+
# Perhaps the best way to approach this is:
|
599
|
+
# * remove all application stubs for this gemspec
|
600
|
+
# * regenerate the app stubs for the latest remaining version
|
601
|
+
# (you always want to have the latest version of an app, don't you?)
|
602
|
+
#
|
603
|
+
# The Installer class doesn't really support this approach very well at the moment.
|
604
|
+
end
|
605
|
+
|
606
|
+
def remove_lib_stub(spec, other_specs)
|
607
|
+
# Library stubs are a bit easier than application stubs. They do not refer to a specific
|
608
|
+
# version; they just load the latest version of the library available as a gem. The only
|
609
|
+
# corner case is that different versions of the same gem may have different autorequire
|
610
|
+
# settings, which means they will have different library stubs.
|
611
|
+
#
|
612
|
+
# I suppose our policy should be: when you uninstall a library, make sure all the
|
613
|
+
# remaining versions of that gem are still supported by stubs. Of course, the user may
|
614
|
+
# have expressed a preference in the past not to have library stubs installed.
|
615
|
+
#
|
616
|
+
# Mixing the segregated world of gem installations with the global namespace of the
|
617
|
+
# site_ruby directory certainly brings some tough issues.
|
618
|
+
end
|
619
|
+
end # class Uninstaller
|
620
|
+
|
621
|
+
end # module Gem
|