rubygems-update 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rubygems-update might be problematic. Click here for more details.

Files changed (152) hide show
  1. data.tar.gz.sig +0 -0
  2. data/ChangeLog +267 -1
  3. data/Rakefile +13 -7
  4. data/doc/release_notes/rel_1_2_0.rdoc +105 -0
  5. data/lib/rubygems.rb +82 -14
  6. data/lib/rubygems/command.rb +1 -1
  7. data/lib/rubygems/command_manager.rb +3 -2
  8. data/lib/rubygems/commands/cert_command.rb +1 -1
  9. data/lib/rubygems/commands/dependency_command.rb +57 -19
  10. data/lib/rubygems/commands/environment_command.rb +2 -0
  11. data/lib/rubygems/commands/fetch_command.rb +3 -1
  12. data/lib/rubygems/commands/install_command.rb +3 -3
  13. data/lib/rubygems/commands/list_command.rb +30 -28
  14. data/lib/rubygems/commands/lock_command.rb +1 -1
  15. data/lib/rubygems/commands/outdated_command.rb +5 -2
  16. data/lib/rubygems/commands/pristine_command.rb +3 -44
  17. data/lib/rubygems/commands/query_command.rb +80 -21
  18. data/lib/rubygems/commands/sources_command.rb +56 -28
  19. data/lib/rubygems/commands/specification_command.rb +4 -3
  20. data/lib/rubygems/commands/stale_command.rb +27 -0
  21. data/lib/rubygems/commands/update_command.rb +35 -22
  22. data/lib/rubygems/config_file.rb +29 -12
  23. data/lib/rubygems/custom_require.rb +1 -1
  24. data/lib/rubygems/defaults.rb +1 -1
  25. data/lib/rubygems/dependency.rb +63 -9
  26. data/lib/rubygems/dependency_installer.rb +60 -23
  27. data/lib/rubygems/dependency_list.rb +1 -1
  28. data/lib/rubygems/doc_manager.rb +5 -5
  29. data/lib/rubygems/gem_openssl.rb +1 -1
  30. data/lib/rubygems/indexer.rb +269 -84
  31. data/lib/rubygems/install_update_options.rb +6 -0
  32. data/lib/rubygems/installer.rb +35 -12
  33. data/lib/rubygems/local_remote_options.rb +26 -5
  34. data/lib/rubygems/platform.rb +15 -1
  35. data/lib/rubygems/remote_fetcher.rb +158 -90
  36. data/lib/rubygems/requirement.rb +16 -12
  37. data/lib/rubygems/rubygems_version.rb +1 -1
  38. data/lib/rubygems/security.rb +2 -2
  39. data/lib/rubygems/server.rb +239 -110
  40. data/lib/rubygems/source_index.rb +44 -18
  41. data/lib/rubygems/source_info_cache.rb +1 -1
  42. data/lib/rubygems/spec_fetcher.rb +251 -0
  43. data/lib/rubygems/specification.rb +120 -38
  44. data/lib/rubygems/test_utilities.rb +120 -0
  45. data/lib/rubygems/uninstaller.rb +11 -10
  46. data/lib/rubygems/user_interaction.rb +149 -74
  47. data/lib/rubygems/validator.rb +3 -3
  48. data/lib/rubygems/version.rb +23 -21
  49. data/setup.rb +105 -100
  50. data/test/gemutilities.rb +63 -86
  51. data/test/test_config.rb +0 -5
  52. data/test/test_gem.rb +22 -2
  53. data/test/test_gem_command_manager.rb +1 -1
  54. data/test/test_gem_commands_dependency_command.rb +125 -6
  55. data/test/test_gem_commands_environment_command.rb +1 -0
  56. data/test/test_gem_commands_fetch_command.rb +24 -4
  57. data/test/test_gem_commands_install_command.rb +6 -8
  58. data/test/{test_gem_outdated_command.rb → test_gem_commands_outdated_command.rb} +5 -2
  59. data/test/test_gem_commands_pristine_command.rb +13 -4
  60. data/test/test_gem_commands_query_command.rb +113 -37
  61. data/test/test_gem_commands_sources_command.rb +101 -31
  62. data/test/test_gem_commands_specification_command.rb +4 -1
  63. data/test/test_gem_commands_stale_command.rb +39 -0
  64. data/test/test_gem_commands_update_command.rb +17 -27
  65. data/test/test_gem_config_file.rb +38 -1
  66. data/test/test_gem_dependency.rb +51 -0
  67. data/test/test_gem_dependency_installer.rb +133 -25
  68. data/test/test_gem_gem_path_searcher.rb +4 -1
  69. data/test/test_gem_indexer.rb +124 -19
  70. data/test/test_gem_installer.rb +32 -2
  71. data/test/test_gem_local_remote_options.rb +6 -5
  72. data/test/test_gem_remote_fetcher.rb +14 -9
  73. data/test/test_gem_server.rb +207 -21
  74. data/test/test_gem_source_index.rb +203 -63
  75. data/test/test_gem_source_info_cache.rb +8 -6
  76. data/test/test_gem_source_info_cache_entry.rb +11 -9
  77. data/test/test_gem_spec_fetcher.rb +303 -0
  78. data/test/test_gem_specification.rb +91 -7
  79. data/test/test_gem_uninstaller.rb +21 -0
  80. data/test/test_gem_version.rb +14 -5
  81. data/test/test_kernel.rb +1 -1
  82. metadata +10 -73
  83. metadata.gz.sig +0 -0
  84. data/lib/rubygems/indexer/abstract_index_builder.rb +0 -88
  85. data/lib/rubygems/indexer/latest_index_builder.rb +0 -35
  86. data/lib/rubygems/indexer/marshal_index_builder.rb +0 -17
  87. data/lib/rubygems/indexer/master_index_builder.rb +0 -54
  88. data/lib/rubygems/indexer/quick_index_builder.rb +0 -50
  89. data/test/gem_installer_test_case.rbc +0 -0
  90. data/test/gem_package_tar_test_case.rbc +0 -0
  91. data/test/gemutilities.rbc +0 -0
  92. data/test/mockgemui.rbc +0 -0
  93. data/test/simple_gem.rbc +0 -0
  94. data/test/test_config.rbc +0 -0
  95. data/test/test_gem.rbc +0 -0
  96. data/test/test_gem_builder.rbc +0 -0
  97. data/test/test_gem_command.rbc +0 -0
  98. data/test/test_gem_command_manager.rbc +0 -0
  99. data/test/test_gem_commands_build_command.rbc +0 -0
  100. data/test/test_gem_commands_cert_command.rbc +0 -0
  101. data/test/test_gem_commands_check_command.rbc +0 -0
  102. data/test/test_gem_commands_contents_command.rbc +0 -0
  103. data/test/test_gem_commands_dependency_command.rbc +0 -0
  104. data/test/test_gem_commands_environment_command.rbc +0 -0
  105. data/test/test_gem_commands_fetch_command.rbc +0 -0
  106. data/test/test_gem_commands_generate_index_command.rbc +0 -0
  107. data/test/test_gem_commands_install_command.rbc +0 -0
  108. data/test/test_gem_commands_mirror_command.rbc +0 -0
  109. data/test/test_gem_commands_pristine_command.rbc +0 -0
  110. data/test/test_gem_commands_query_command.rbc +0 -0
  111. data/test/test_gem_commands_server_command.rbc +0 -0
  112. data/test/test_gem_commands_sources_command.rbc +0 -0
  113. data/test/test_gem_commands_specification_command.rbc +0 -0
  114. data/test/test_gem_commands_unpack_command.rbc +0 -0
  115. data/test/test_gem_commands_update_command.rbc +0 -0
  116. data/test/test_gem_config_file.rbc +0 -0
  117. data/test/test_gem_dependency.rbc +0 -0
  118. data/test/test_gem_dependency_installer.rbc +0 -0
  119. data/test/test_gem_dependency_list.rbc +0 -0
  120. data/test/test_gem_digest.rbc +0 -0
  121. data/test/test_gem_doc_manager.rbc +0 -0
  122. data/test/test_gem_ext_configure_builder.rbc +0 -0
  123. data/test/test_gem_ext_ext_conf_builder.rbc +0 -0
  124. data/test/test_gem_ext_rake_builder.rbc +0 -0
  125. data/test/test_gem_format.rbc +0 -0
  126. data/test/test_gem_gem_path_searcher.rbc +0 -0
  127. data/test/test_gem_gem_runner.rbc +0 -0
  128. data/test/test_gem_indexer.rbc +0 -0
  129. data/test/test_gem_install_update_options.rbc +0 -0
  130. data/test/test_gem_installer.rbc +0 -0
  131. data/test/test_gem_local_remote_options.rbc +0 -0
  132. data/test/test_gem_outdated_command.rbc +0 -0
  133. data/test/test_gem_package_tar_header.rbc +0 -0
  134. data/test/test_gem_package_tar_input.rbc +0 -0
  135. data/test/test_gem_package_tar_output.rbc +0 -0
  136. data/test/test_gem_package_tar_reader.rbc +0 -0
  137. data/test/test_gem_package_tar_reader_entry.rbc +0 -0
  138. data/test/test_gem_package_tar_writer.rbc +0 -0
  139. data/test/test_gem_platform.rbc +0 -0
  140. data/test/test_gem_remote_fetcher.rbc +0 -0
  141. data/test/test_gem_requirement.rbc +0 -0
  142. data/test/test_gem_server.rbc +0 -0
  143. data/test/test_gem_source_index.rbc +0 -0
  144. data/test/test_gem_source_info_cache.rbc +0 -0
  145. data/test/test_gem_source_info_cache_entry.rbc +0 -0
  146. data/test/test_gem_specification.rbc +0 -0
  147. data/test/test_gem_stream_ui.rbc +0 -0
  148. data/test/test_gem_uninstaller.rbc +0 -0
  149. data/test/test_gem_validator.rbc +0 -0
  150. data/test/test_gem_version.rbc +0 -0
  151. data/test/test_gem_version_option.rbc +0 -0
  152. data/test/test_kernel.rbc +0 -0
@@ -7,6 +7,7 @@
7
7
  require 'rubygems'
8
8
  require 'rubygems/user_interaction'
9
9
  require 'rubygems/specification'
10
+ require 'rubygems/spec_fetcher'
10
11
 
11
12
  ##
12
13
  # The SourceIndex object indexes all the gems available from a
@@ -27,6 +28,11 @@ class Gem::SourceIndex
27
28
 
28
29
  attr_reader :gems # :nodoc:
29
30
 
31
+ ##
32
+ # Directories to use to refresh this SourceIndex when calling refresh!
33
+
34
+ attr_accessor :spec_dirs
35
+
30
36
  class << self
31
37
  include Gem::UserInteraction
32
38
 
@@ -39,7 +45,7 @@ class Gem::SourceIndex
39
45
  # +from_gems_in+. This argument is deprecated and is provided
40
46
  # just for backwards compatibility, and should not generally
41
47
  # be used.
42
- #
48
+ #
43
49
  # return::
44
50
  # SourceIndex instance
45
51
 
@@ -63,7 +69,9 @@ class Gem::SourceIndex
63
69
  # +spec_dirs+.
64
70
 
65
71
  def from_gems_in(*spec_dirs)
66
- self.new.load_gems_in(*spec_dirs)
72
+ source_index = new
73
+ source_index.spec_dirs = spec_dirs
74
+ source_index.refresh!
67
75
  end
68
76
 
69
77
  ##
@@ -79,6 +87,8 @@ class Gem::SourceIndex
79
87
  return gemspec
80
88
  end
81
89
  alert_warning "File '#{file_name}' does not evaluate to a gem specification"
90
+ rescue SignalException, SystemExit
91
+ raise
82
92
  rescue SyntaxError => e
83
93
  alert_warning e
84
94
  alert_warning spec_code
@@ -100,6 +110,7 @@ class Gem::SourceIndex
100
110
 
101
111
  def initialize(specifications={})
102
112
  @gems = specifications
113
+ @spec_dirs = nil
103
114
  end
104
115
 
105
116
  ##
@@ -121,8 +132,8 @@ class Gem::SourceIndex
121
132
  end
122
133
 
123
134
  ##
124
- # Returns a Hash of name => Specification of the latest versions of each
125
- # gem in this index.
135
+ # Returns an Array specifications for the latest versions of each gem in
136
+ # this index.
126
137
 
127
138
  def latest_specs
128
139
  result = Hash.new { |h,k| h[k] = [] }
@@ -241,7 +252,9 @@ class Gem::SourceIndex
241
252
  when Gem::Dependency then
242
253
  only_platform = platform_only
243
254
  version_requirement = gem_pattern.version_requirements
244
- gem_pattern = if gem_pattern.name.empty? then
255
+ gem_pattern = if Regexp === gem_pattern.name then
256
+ gem_pattern.name
257
+ elsif gem_pattern.name.empty? then
245
258
  //
246
259
  else
247
260
  /^#{Regexp.escape gem_pattern.name}$/
@@ -271,29 +284,41 @@ class Gem::SourceIndex
271
284
 
272
285
  ##
273
286
  # Replaces the gems in the source index from specifications in the
274
- # installed_spec_directories,
287
+ # directories this source index was created from. Raises an exception if
288
+ # this source index wasn't created from a directory (via from_gems_in or
289
+ # from_installed_gems, or having spec_dirs set).
275
290
 
276
291
  def refresh!
277
- load_gems_in(*self.class.installed_spec_directories)
292
+ raise 'source index not created from disk' if @spec_dirs.nil?
293
+ load_gems_in(*@spec_dirs)
278
294
  end
279
295
 
280
296
  ##
281
297
  # Returns an Array of Gem::Specifications that are not up to date.
282
298
 
283
299
  def outdated
284
- dep = Gem::Dependency.new '', Gem::Requirement.default
285
-
286
- remotes = Gem::SourceInfoCache.search dep, true
287
-
288
300
  outdateds = []
289
301
 
290
302
  latest_specs.each do |local|
291
- name = local.name
292
- remote = remotes.select { |spec| spec.name == name }.
293
- sort_by { |spec| spec.version.to_ints }.
294
- last
303
+ dependency = Gem::Dependency.new local.name, ">= #{local.version}"
304
+
305
+ begin
306
+ fetcher = Gem::SpecFetcher.fetcher
307
+ remotes = fetcher.find_matching dependency
308
+ remotes = remotes.map { |(name, version,_),_| version }
309
+ rescue Gem::RemoteFetcher::FetchError => e
310
+ raise unless fetcher.warn_legacy e do
311
+ require 'rubygems/source_info_cache'
312
+
313
+ specs = Gem::SourceInfoCache.search_with_source dependency, true
314
+
315
+ remotes = specs.map { |spec,| spec.version }
316
+ end
317
+ end
318
+
319
+ latest = remotes.sort.last
295
320
 
296
- outdateds << name if remote and local.version < remote.version
321
+ outdateds << local.name if latest and local.version < latest
297
322
  end
298
323
 
299
324
  outdateds
@@ -387,7 +412,8 @@ class Gem::SourceIndex
387
412
  end
388
413
 
389
414
  def fetch_bulk_index(source_uri)
390
- say "Bulk updating Gem source index for: #{source_uri}"
415
+ say "Bulk updating Gem source index for: #{source_uri}" if
416
+ Gem.configuration.verbose
391
417
 
392
418
  index = fetch_index_from(source_uri)
393
419
  if index.nil? then
@@ -447,7 +473,7 @@ class Gem::SourceIndex
447
473
 
448
474
  def unzip(string)
449
475
  require 'zlib'
450
- Zlib::Inflate.inflate(string)
476
+ Gem.inflate string
451
477
  end
452
478
 
453
479
  ##
@@ -8,7 +8,7 @@ require 'rubygems/user_interaction'
8
8
  # SourceInfoCache stores a copy of the gem index for each gem source.
9
9
  #
10
10
  # There are two possible cache locations, the system cache and the user cache:
11
- # * The system cache is prefered if it is writable or can be created.
11
+ # * The system cache is preferred if it is writable or can be created.
12
12
  # * The user cache is used otherwise
13
13
  #
14
14
  # Once a cache is selected, it will be used for all operations.
@@ -0,0 +1,251 @@
1
+ require 'zlib'
2
+
3
+ require 'rubygems'
4
+ require 'rubygems/remote_fetcher'
5
+ require 'rubygems/user_interaction'
6
+
7
+ ##
8
+ # SpecFetcher handles metadata updates from remote gem repositories.
9
+
10
+ class Gem::SpecFetcher
11
+
12
+ include Gem::UserInteraction
13
+
14
+ ##
15
+ # The SpecFetcher cache dir.
16
+
17
+ attr_reader :dir # :nodoc:
18
+
19
+ ##
20
+ # Cache of latest specs
21
+
22
+ attr_reader :latest_specs # :nodoc:
23
+
24
+ ##
25
+ # Cache of all spces
26
+
27
+ attr_reader :specs # :nodoc:
28
+
29
+ @fetcher = nil
30
+
31
+ def self.fetcher
32
+ @fetcher ||= new
33
+ end
34
+
35
+ def self.fetcher=(fetcher) # :nodoc:
36
+ @fetcher = fetcher
37
+ end
38
+
39
+ def initialize
40
+ @dir = File.join Gem.user_home, '.gem', 'specs'
41
+ @update_cache = File.stat(Gem.user_home).uid == Process.uid
42
+
43
+ @specs = {}
44
+ @latest_specs = {}
45
+
46
+ @fetcher = Gem::RemoteFetcher.fetcher
47
+ end
48
+
49
+ ##
50
+ # Retuns the local directory to write +uri+ to.
51
+
52
+ def cache_dir(uri)
53
+ File.join @dir, "#{uri.host}%#{uri.port}", File.dirname(uri.path)
54
+ end
55
+
56
+ ##
57
+ # Fetch specs matching +dependency+. If +all+ is true, all matching
58
+ # versions are returned. If +matching_platform+ is false, all platforms are
59
+ # returned.
60
+
61
+ def fetch(dependency, all = false, matching_platform = true)
62
+ specs_and_sources = find_matching dependency, all, matching_platform
63
+
64
+ specs_and_sources.map do |spec_tuple, source_uri|
65
+ [fetch_spec(spec_tuple, URI.parse(source_uri)), source_uri]
66
+ end
67
+
68
+ rescue Gem::RemoteFetcher::FetchError => e
69
+ raise unless warn_legacy e do
70
+ require 'rubygems/source_info_cache'
71
+
72
+ return Gem::SourceInfoCache.search_with_source(dependency,
73
+ matching_platform, all)
74
+ end
75
+ end
76
+
77
+ def fetch_spec(spec, source_uri)
78
+ spec = spec - [nil, 'ruby', '']
79
+ spec_file_name = "#{spec.join '-'}.gemspec"
80
+
81
+ uri = source_uri + "#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}"
82
+
83
+ cache_dir = cache_dir uri
84
+
85
+ local_spec = File.join cache_dir, spec_file_name
86
+
87
+ if File.exist? local_spec then
88
+ spec = Gem.read_binary local_spec
89
+ else
90
+ uri.path << '.rz'
91
+
92
+ spec = @fetcher.fetch_path uri
93
+ spec = Gem.inflate spec
94
+
95
+ if @update_cache then
96
+ FileUtils.mkdir_p cache_dir
97
+
98
+ open local_spec, 'wb' do |io|
99
+ io.write spec
100
+ end
101
+ end
102
+ end
103
+
104
+ # TODO: Investigate setting Gem::Specification#loaded_from to a URI
105
+ Marshal.load spec
106
+ end
107
+
108
+ ##
109
+ # Find spec names that match +dependency+. If +all+ is true, all matching
110
+ # versions are returned. If +matching_platform+ is false, gems for all
111
+ # platforms are returned.
112
+
113
+ def find_matching(dependency, all = false, matching_platform = true)
114
+ found = {}
115
+
116
+ list(all).each do |source_uri, specs|
117
+ found[source_uri] = specs.select do |spec_name, version, spec_platform|
118
+ dependency =~ Gem::Dependency.new(spec_name, version) and
119
+ (not matching_platform or Gem::Platform.match(spec_platform))
120
+ end
121
+ end
122
+
123
+ specs_and_sources = []
124
+
125
+ found.each do |source_uri, specs|
126
+ uri_str = source_uri.to_s
127
+ specs_and_sources.push(*specs.map { |spec| [spec, uri_str] })
128
+ end
129
+
130
+ specs_and_sources
131
+ end
132
+
133
+ ##
134
+ # Returns Array of gem repositories that were generated with RubyGems less
135
+ # than 1.2.
136
+
137
+ def legacy_repos
138
+ Gem.sources.reject do |source_uri|
139
+ source_uri = URI.parse source_uri
140
+ spec_path = source_uri + "specs.#{Gem.marshal_version}.gz"
141
+
142
+ begin
143
+ @fetcher.fetch_size spec_path
144
+ rescue Gem::RemoteFetcher::FetchError
145
+ begin
146
+ @fetcher.fetch_size(source_uri + 'yaml') # re-raise if non-repo
147
+ rescue Gem::RemoteFetcher::FetchError
148
+ alert_error "#{source_uri} does not appear to be a repository"
149
+ raise
150
+ end
151
+ false
152
+ end
153
+ end
154
+ end
155
+
156
+ ##
157
+ # Returns a list of gems available for each source in Gem::sources. If
158
+ # +all+ is true, all versions are returned instead of only latest versions.
159
+
160
+ def list(all = false)
161
+ list = {}
162
+
163
+ file = all ? 'specs' : 'latest_specs'
164
+
165
+ Gem.sources.each do |source_uri|
166
+ source_uri = URI.parse source_uri
167
+
168
+ if all and @specs.include? source_uri then
169
+ list[source_uri] = @specs[source_uri]
170
+ elsif @latest_specs.include? source_uri then
171
+ list[source_uri] = @latest_specs[source_uri]
172
+ else
173
+ specs = load_specs source_uri, file
174
+
175
+ cache = all ? @specs : @latest_specs
176
+
177
+ cache[source_uri] = specs
178
+ list[source_uri] = specs
179
+ end
180
+ end
181
+
182
+ list
183
+ end
184
+
185
+ def load_specs(source_uri, file)
186
+ file_name = "#{file}.#{Gem.marshal_version}.gz"
187
+
188
+ spec_path = source_uri + file_name
189
+
190
+ cache_dir = cache_dir spec_path
191
+
192
+ local_file = File.join(cache_dir, file_name).chomp '.gz'
193
+
194
+ if File.exist? local_file then
195
+ local_size = File.stat(local_file).size
196
+
197
+ remote_file = spec_path.dup
198
+ remote_file.path = remote_file.path.chomp '.gz'
199
+ remote_size = @fetcher.fetch_size remote_file
200
+
201
+ spec_dump = Gem.read_binary local_file if remote_size == local_size
202
+ end
203
+
204
+ unless spec_dump then
205
+ loaded = true
206
+
207
+ spec_dump_gz = @fetcher.fetch_path spec_path
208
+ spec_dump = Gem.gunzip spec_dump_gz
209
+ end
210
+
211
+ specs = Marshal.load spec_dump
212
+
213
+ if loaded and @update_cache then
214
+ begin
215
+ FileUtils.mkdir_p cache_dir
216
+
217
+ open local_file, 'wb' do |io|
218
+ Marshal.dump specs, io
219
+ end
220
+ rescue
221
+ end
222
+ end
223
+
224
+ specs
225
+ end
226
+
227
+ ##
228
+ # Warn about legacy repositories if +exception+ indicates only legacy
229
+ # repositories are available, and yield to the block. Returns false if the
230
+ # exception indicates some other FetchError.
231
+
232
+ def warn_legacy(exception)
233
+ uri = exception.uri.to_s
234
+ if uri =~ /specs\.#{Regexp.escape Gem.marshal_version}\.gz$/ then
235
+ alert_warning <<-EOF
236
+ RubyGems 1.2+ index not found for:
237
+ \t#{legacy_repos.join "\n\t"}
238
+
239
+ RubyGems will revert to legacy indexes degrading performance.
240
+ EOF
241
+
242
+ yield
243
+
244
+ return true
245
+ end
246
+
247
+ false
248
+ end
249
+
250
+ end
251
+
@@ -6,6 +6,7 @@
6
6
 
7
7
  require 'rubygems'
8
8
  require 'rubygems/version'
9
+ require 'rubygems/requirement'
9
10
  require 'rubygems/platform'
10
11
 
11
12
  # :stopdoc:
@@ -16,6 +17,9 @@ if RUBY_VERSION < '1.9' then
16
17
  t - ((t.to_f + t.gmt_offset) % 86400)
17
18
  end unless defined? Time.today
18
19
  end
20
+
21
+ class Date; end # for ruby_code if date.rb wasn't required
22
+
19
23
  # :startdoc:
20
24
 
21
25
  module Gem
@@ -37,22 +41,34 @@ module Gem
37
41
  #
38
42
  class Specification
39
43
 
44
+ ##
40
45
  # Allows deinstallation of gems with legacy platforms.
46
+
41
47
  attr_accessor :original_platform # :nodoc:
42
48
 
43
- # ------------------------- Specification version contstants.
49
+ # ------------------------- Specification version constants.
44
50
 
51
+ ##
45
52
  # The the version number of a specification that does not specify one
46
53
  # (i.e. RubyGems 0.7 or earlier).
54
+
47
55
  NONEXISTENT_SPECIFICATION_VERSION = -1
48
56
 
57
+ ##
49
58
  # The specification version applied to any new Specification instances
50
59
  # created. This should be bumped whenever something in the spec format
51
60
  # changes.
61
+ #--
62
+ # When updating this number, be sure to also update #to_ruby.
63
+ #
64
+ # NOTE RubyGems < 1.2 cannot load specification versions > 2.
65
+
52
66
  CURRENT_SPECIFICATION_VERSION = 2
53
67
 
68
+ ##
54
69
  # An informal list of changes to the specification. The highest-valued
55
70
  # key should be equal to the CURRENT_SPECIFICATION_VERSION.
71
+
56
72
  SPECIFICATION_VERSION_HISTORY = {
57
73
  -1 => ['(RubyGems versions up to and including 0.7 did not have versioned specifications)'],
58
74
  1 => [
@@ -231,10 +247,12 @@ module Gem
231
247
  }
232
248
  end
233
249
 
250
+ ##
234
251
  # Dump only crucial instance variables.
235
- #
252
+ #--
236
253
  # MAINTAIN ORDER!
237
- def _dump(limit) # :nodoc:
254
+
255
+ def _dump(limit)
238
256
  Marshal.dump [
239
257
  @rubygems_version,
240
258
  @specification_version,
@@ -256,7 +274,9 @@ module Gem
256
274
  ]
257
275
  end
258
276
 
277
+ ##
259
278
  # Load custom marshal format, re-initializing defaults as needed
279
+
260
280
  def self._load(str)
261
281
  array = Marshal.load str
262
282
 
@@ -265,9 +285,15 @@ module Gem
265
285
 
266
286
  current_version = CURRENT_SPECIFICATION_VERSION
267
287
 
268
- field_count = MARSHAL_FIELDS[spec.specification_version]
288
+ field_count = if spec.specification_version > current_version then
289
+ spec.instance_variable_set :@specification_version,
290
+ current_version
291
+ MARSHAL_FIELDS[current_version]
292
+ else
293
+ MARSHAL_FIELDS[spec.specification_version]
294
+ end
269
295
 
270
- if field_count.nil? or array.size < field_count then
296
+ if array.size < field_count then
271
297
  raise TypeError, "invalid Gem::Specification format #{array.inspect}"
272
298
  end
273
299
 
@@ -335,6 +361,14 @@ module Gem
335
361
 
336
362
  read_only :dependencies
337
363
 
364
+ def runtime_dependencies
365
+ dependencies.select { |d| d.type == :runtime || d.type == nil }
366
+ end
367
+
368
+ def development_dependencies
369
+ dependencies.select { |d| d.type == :development }
370
+ end
371
+
338
372
  # ALIASED gemspec attributes -------------------------------------
339
373
 
340
374
  attribute_alias_singular :executable, :executables
@@ -629,27 +663,31 @@ module Gem
629
663
  end
630
664
  end
631
665
 
632
- # Adds a dependency to this Gem. For example,
666
+ # Adds a development dependency to this Gem. For example,
667
+ #
668
+ # spec.add_development_dependency('jabber4r', '> 0.1', '<= 0.5')
633
669
  #
634
- # spec.add_dependency('jabber4r', '> 0.1', '<= 0.5')
670
+ # Development dependencies aren't installed by default, and
671
+ # aren't activated when a gem is required.
635
672
  #
636
673
  # gem:: [String or Gem::Dependency] The Gem name/dependency.
637
674
  # requirements:: [default=">= 0"] The version requirements.
675
+ def add_development_dependency(gem, *requirements)
676
+ add_dependency_with_type(gem, :development, *requirements)
677
+ end
678
+
679
+ # Adds a runtime dependency to this Gem. For example,
638
680
  #
639
- def add_dependency(gem, *requirements)
640
- requirements = if requirements.empty? then
641
- Gem::Requirement.default
642
- else
643
- requirements.flatten
644
- end
681
+ # spec.add_runtime_dependency('jabber4r', '> 0.1', '<= 0.5')
682
+ #
683
+ # gem:: [String or Gem::Dependency] The Gem name/dependency.
684
+ # requirements:: [default=">= 0"] The version requirements.
685
+ def add_runtime_dependency(gem, *requirements)
686
+ add_dependency_with_type(gem, :runtime, *requirements)
687
+ end
645
688
 
646
- unless gem.respond_to?(:name) && gem.respond_to?(:version_requirements)
647
- gem = Dependency.new(gem, requirements)
648
- end
689
+ alias add_dependency add_runtime_dependency
649
690
 
650
- dependencies << gem
651
- end
652
-
653
691
  # Returns the full name (name-version) of this Gem. Platform information
654
692
  # is included (name-version-platform) if it is specified (and not the
655
693
  # default Ruby platform).
@@ -673,30 +711,31 @@ module Gem
673
711
  end
674
712
  end
675
713
 
714
+ ##
676
715
  # The full path to the gem (install path + full name).
677
- #
678
- # return:: [String] the full gem path
679
- #
716
+
680
717
  def full_gem_path
681
718
  path = File.join installation_path, 'gems', full_name
682
719
  return path if File.directory? path
683
720
  File.join installation_path, 'gems', original_name
684
721
  end
685
-
722
+
723
+ ##
686
724
  # The default (generated) file name of the gem.
725
+
687
726
  def file_name
688
727
  full_name + ".gem"
689
728
  end
690
-
691
- # The root directory that the gem was installed into.
692
- #
693
- # return:: [String] the installation path
694
- #
729
+
730
+ ##
731
+ # The directory that this gem was installed into.
732
+
695
733
  def installation_path
696
- (File.dirname(@loaded_from).split(File::SEPARATOR)[0..-2]).
697
- join(File::SEPARATOR)
734
+ path = File.dirname(@loaded_from).split(File::SEPARATOR)[0..-2]
735
+ path = path.join File::SEPARATOR
736
+ File.expand_path path
698
737
  end
699
-
738
+
700
739
  # Checks if this Specification meets the requirement of the supplied
701
740
  # dependency.
702
741
  #
@@ -778,9 +817,11 @@ module Gem
778
817
  self.platform = Gem::Platform.new @platform
779
818
  end
780
819
 
820
+ ##
781
821
  # Returns a Ruby code representation of this specification, such that it
782
822
  # can be eval'ed and reconstruct the same specification later. Attributes
783
823
  # that still have their default values are omitted.
824
+
784
825
  def to_ruby
785
826
  mark_version
786
827
  result = []
@@ -792,8 +833,6 @@ module Gem
792
833
  result << " s.platform = #{ruby_code original_platform}"
793
834
  end
794
835
  result << ""
795
- result << " s.specification_version = #{specification_version} if s.respond_to? :specification_version="
796
- result << ""
797
836
  result << " s.required_rubygems_version = #{ruby_code required_rubygems_version} if s.respond_to? :required_rubygems_version="
798
837
 
799
838
  handled = [
@@ -816,15 +855,42 @@ module Gem
816
855
  end
817
856
  end
818
857
 
819
- result << "" unless dependencies.empty?
858
+ result << nil
859
+ result << " if s.respond_to? :specification_version then"
860
+ result << " current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION"
861
+ result << " s.specification_version = #{specification_version}"
862
+ result << nil
863
+
864
+ result << " if current_version >= 3 then"
865
+
866
+ unless dependencies.empty? then
867
+ dependencies.each do |dep|
868
+ version_reqs_param = dep.requirements_list.inspect
869
+ dep.instance_variable_set :@type, :runtime if dep.type.nil? # HACK
870
+ result << " s.add_#{dep.type}_dependency(%q<#{dep.name}>, #{version_reqs_param})"
871
+ end
872
+ end
873
+
874
+ result << " else"
820
875
 
821
- dependencies.each do |dep|
822
- version_reqs_param = dep.requirements_list.inspect
823
- result << " s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})"
876
+ unless dependencies.empty? then
877
+ dependencies.each do |dep|
878
+ version_reqs_param = dep.requirements_list.inspect
879
+ result << " s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})"
880
+ end
824
881
  end
825
882
 
883
+ result << ' end'
884
+
885
+ result << " else"
886
+ dependencies.each do |dep|
887
+ version_reqs_param = dep.requirements_list.inspect
888
+ result << " s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})"
889
+ end
890
+ result << " end"
891
+
826
892
  result << "end"
827
- result << ""
893
+ result << nil
828
894
 
829
895
  result.join "\n"
830
896
  end
@@ -940,6 +1006,22 @@ module Gem
940
1006
 
941
1007
  private
942
1008
 
1009
+ def add_dependency_with_type(dependency, type, *requirements)
1010
+ requirements = if requirements.empty? then
1011
+ Gem::Requirement.default
1012
+ else
1013
+ requirements.flatten
1014
+ end
1015
+
1016
+ unless dependency.respond_to?(:name) &&
1017
+ dependency.respond_to?(:version_requirements)
1018
+
1019
+ dependency = Dependency.new(dependency, requirements, type)
1020
+ end
1021
+
1022
+ dependencies << dependency
1023
+ end
1024
+
943
1025
  def find_all_satisfiers(dep)
944
1026
  Gem.source_index.each do |name,gem|
945
1027
  if(gem.satisfies_requirement?(dep)) then