rubygems-update 2.3.0 → 2.4.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 (71) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CONTRIBUTING +14 -2
  5. data/History.txt +63 -0
  6. data/Rakefile +68 -91
  7. data/lib/rubygems.rb +5 -3
  8. data/lib/rubygems/command_manager.rb +1 -0
  9. data/lib/rubygems/commands/contents_command.rb +23 -2
  10. data/lib/rubygems/commands/install_command.rb +8 -0
  11. data/lib/rubygems/commands/open_command.rb +1 -8
  12. data/lib/rubygems/commands/uninstall_command.rb +9 -1
  13. data/lib/rubygems/commands/update_command.rb +1 -1
  14. data/lib/rubygems/core_ext/kernel_gem.rb +8 -1
  15. data/lib/rubygems/core_ext/kernel_require.rb +12 -22
  16. data/lib/rubygems/defaults.rb +17 -5
  17. data/lib/rubygems/dependency.rb +7 -1
  18. data/lib/rubygems/dependency_installer.rb +3 -0
  19. data/lib/rubygems/ext/ext_conf_builder.rb +13 -11
  20. data/lib/rubygems/install_update_options.rb +13 -0
  21. data/lib/rubygems/installer.rb +36 -20
  22. data/lib/rubygems/installer_test_case.rb +2 -0
  23. data/lib/rubygems/local_remote_options.rb +1 -1
  24. data/lib/rubygems/name_tuple.rb +1 -1
  25. data/lib/rubygems/request_set.rb +14 -3
  26. data/lib/rubygems/request_set/gem_dependency_api.rb +12 -0
  27. data/lib/rubygems/request_set/lockfile.rb +3 -1
  28. data/lib/rubygems/resolver.rb +15 -0
  29. data/lib/rubygems/resolver/best_set.rb +28 -0
  30. data/lib/rubygems/resolver/conflict.rb +45 -7
  31. data/lib/rubygems/resolver/git_specification.rb +24 -0
  32. data/lib/rubygems/resolver/lock_specification.rb +22 -0
  33. data/lib/rubygems/source.rb +2 -0
  34. data/lib/rubygems/source/git.rb +1 -1
  35. data/lib/rubygems/source/installed.rb +2 -1
  36. data/lib/rubygems/specification.rb +16 -15
  37. data/lib/rubygems/test_case.rb +9 -5
  38. data/test/rubygems/test_gem.rb +72 -2
  39. data/test/rubygems/test_gem_commands_contents_command.rb +46 -3
  40. data/test/rubygems/test_gem_commands_install_command.rb +32 -0
  41. data/test/rubygems/test_gem_commands_uninstall_command.rb +18 -0
  42. data/test/rubygems/test_gem_dependency.rb +23 -0
  43. data/test/rubygems/test_gem_dependency_installer.rb +17 -0
  44. data/test/rubygems/test_gem_ext_builder.rb +12 -1
  45. data/test/rubygems/test_gem_ext_ext_conf_builder.rb +2 -2
  46. data/test/rubygems/test_gem_impossible_dependencies_error.rb +24 -8
  47. data/test/rubygems/test_gem_install_update_options.rb +16 -0
  48. data/test/rubygems/test_gem_installer.rb +52 -0
  49. data/test/rubygems/test_gem_local_remote_options.rb +13 -0
  50. data/test/rubygems/test_gem_package.rb +3 -1
  51. data/test/rubygems/test_gem_package_tar_header.rb +2 -0
  52. data/test/rubygems/test_gem_package_tar_reader.rb +11 -1
  53. data/test/rubygems/test_gem_package_tar_reader_entry.rb +17 -2
  54. data/test/rubygems/test_gem_package_tar_writer.rb +1 -0
  55. data/test/rubygems/test_gem_remote_fetcher.rb +24 -0
  56. data/test/rubygems/test_gem_request_set.rb +74 -4
  57. data/test/rubygems/test_gem_request_set_gem_dependency_api.rb +9 -1
  58. data/test/rubygems/test_gem_request_set_lockfile.rb +3 -1
  59. data/test/rubygems/test_gem_requirement.rb +8 -0
  60. data/test/rubygems/test_gem_resolver.rb +39 -0
  61. data/test/rubygems/test_gem_resolver_best_set.rb +57 -0
  62. data/test/rubygems/test_gem_resolver_conflict.rb +22 -10
  63. data/test/rubygems/test_gem_resolver_git_specification.rb +12 -0
  64. data/test/rubygems/test_gem_source_git.rb +6 -2
  65. data/test/rubygems/test_gem_source_installed.rb +8 -0
  66. data/test/rubygems/test_gem_source_lock.rb +2 -2
  67. data/test/rubygems/test_gem_source_vendor.rb +4 -0
  68. data/test/rubygems/test_kernel.rb +6 -0
  69. data/test/rubygems/test_require.rb +60 -0
  70. metadata +5 -5
  71. metadata.gz.sig +0 -0
@@ -100,7 +100,7 @@ module Gem::LocalRemoteOptions
100
100
  def add_source_option
101
101
  accept_uri_http
102
102
 
103
- add_option(:"Local/Remote", '--source URL', URI::HTTP,
103
+ add_option(:"Local/Remote", '-s', '--source URL', URI::HTTP,
104
104
  'Add URL as a remote source for gems') do |source, options|
105
105
 
106
106
  source << '/' if source !~ /\/\z/
@@ -53,7 +53,7 @@ class Gem::NameTuple
53
53
  "#{@name}-#{@version}"
54
54
  else
55
55
  "#{@name}-#{@version}-#{@platform}"
56
- end
56
+ end.untaint
57
57
  end
58
58
 
59
59
  ##
@@ -82,6 +82,7 @@ class Gem::RequestSet
82
82
  @dependencies = deps
83
83
 
84
84
  @always_install = []
85
+ @conservative = false
85
86
  @dependency_names = {}
86
87
  @development = false
87
88
  @development_shallow = false
@@ -191,15 +192,16 @@ class Gem::RequestSet
191
192
 
192
193
  @install_dir = options[:install_dir] || Gem.dir
193
194
  @remote = options[:domain] != :local
195
+ @conservative = true if options[:conservative]
194
196
 
195
- gem_deps_api = load_gemdeps gemdeps, options[:without_groups]
197
+ gem_deps_api = load_gemdeps gemdeps, options[:without_groups], true
196
198
 
197
199
  resolve
198
200
 
199
201
  if options[:explain]
200
202
  puts "Gems to install:"
201
203
 
202
- specs.sorted_requests.each do |spec|
204
+ sorted_requests.each do |spec|
203
205
  puts " #{spec.full_name}"
204
206
  end
205
207
 
@@ -256,7 +258,7 @@ class Gem::RequestSet
256
258
  ##
257
259
  # Load a dependency management file.
258
260
 
259
- def load_gemdeps path, without_groups = []
261
+ def load_gemdeps path, without_groups = [], installing = false
260
262
  @git_set = Gem::Resolver::GitSet.new
261
263
  @vendor_set = Gem::Resolver::VendorSet.new
262
264
 
@@ -266,6 +268,7 @@ class Gem::RequestSet
266
268
  lockfile.parse
267
269
 
268
270
  gf = Gem::RequestSet::GemDependencyAPI.new self, path
271
+ gf.installing = installing
269
272
  gf.without_groups = without_groups if without_groups
270
273
  gf.load
271
274
  end
@@ -288,6 +291,14 @@ class Gem::RequestSet
288
291
  resolver.ignore_dependencies = @ignore_dependencies
289
292
  resolver.soft_missing = @soft_missing
290
293
 
294
+ if @conservative
295
+ installed_gems = {}
296
+ Gem::Specification.find_all do |spec|
297
+ (installed_gems[spec.name] ||= []) << spec
298
+ end
299
+ resolver.skip_gems = installed_gems
300
+ end
301
+
291
302
  @resolver = resolver
292
303
 
293
304
  @requests = resolver.resolve
@@ -200,6 +200,7 @@ class Gem::RequestSet::GemDependencyAPI
200
200
  @dependencies = {}
201
201
  @default_sources = true
202
202
  @git_set = @set.git_set
203
+ @installing = false
203
204
  @requires = Hash.new { |h, name| h[name] = [] }
204
205
  @vendor_set = @set.vendor_set
205
206
  @gem_sources = {}
@@ -246,6 +247,15 @@ class Gem::RequestSet::GemDependencyAPI
246
247
  end
247
248
  end
248
249
 
250
+ ##
251
+ # Changes the behavior of gem dependency file loading to installing mode.
252
+ # In installing mode certain restrictions are ignored such as ruby version
253
+ # mismatch checks.
254
+
255
+ def installing= installing # :nodoc:
256
+ @installing = installing
257
+ end
258
+
249
259
  ##
250
260
  # Loads the gem dependency file and returns self.
251
261
 
@@ -682,6 +692,8 @@ class Gem::RequestSet::GemDependencyAPI
682
692
  'you must specify engine_version along with the ruby engine' if
683
693
  engine and not engine_version
684
694
 
695
+ return true if @installing
696
+
685
697
  unless RUBY_VERSION == version then
686
698
  message = "Your Ruby version is #{RUBY_VERSION}, " +
687
699
  "but your #{gem_deps_file} requires #{version}"
@@ -55,6 +55,8 @@ class Gem::RequestSet::Lockfile
55
55
  @gem_deps_file = File.expand_path(gem_deps_file)
56
56
  @gem_deps_dir = File.dirname(@gem_deps_file)
57
57
 
58
+ @gem_deps_file.untaint unless gem_deps_file.tainted?
59
+
58
60
  @current_token = nil
59
61
  @line = 0
60
62
  @line_pos = 0
@@ -403,7 +405,7 @@ class Gem::RequestSet::Lockfile
403
405
  else
404
406
  dependency = parse_dependency name, data
405
407
 
406
- last_spec.spec.dependencies << dependency
408
+ last_spec.add_dependency dependency
407
409
  end
408
410
 
409
411
  get :r_paren
@@ -49,6 +49,12 @@ class Gem::Resolver
49
49
 
50
50
  attr_reader :stats
51
51
 
52
+ ##
53
+ # Hash of gems to skip resolution. Keyed by gem name, with arrays of
54
+ # gem specifications as values.
55
+
56
+ attr_accessor :skip_gems
57
+
52
58
  ##
53
59
  # When a missing dependency, don't stop. Just go on and record what was
54
60
  # missing.
@@ -109,6 +115,7 @@ class Gem::Resolver
109
115
  @development_shallow = false
110
116
  @ignore_dependencies = false
111
117
  @missing = []
118
+ @skip_gems = {}
112
119
  @soft_missing = false
113
120
  @stats = Gem::Resolver::Stats.new
114
121
  end
@@ -200,6 +207,14 @@ class Gem::Resolver
200
207
 
201
208
  def find_possible dependency # :nodoc:
202
209
  all = @set.find_all dependency
210
+
211
+ if (skip_dep_gems = skip_gems[dependency.name]) && !skip_dep_gems.empty?
212
+ matching = all.select do |api_spec|
213
+ skip_dep_gems.any?{|s| api_spec.version == s.version}
214
+ end
215
+ all = matching unless matching.empty?
216
+ end
217
+
203
218
  matching_platform = select_local_platforms all
204
219
 
205
220
  return matching_platform, all
@@ -28,6 +28,10 @@ class Gem::Resolver::BestSet < Gem::Resolver::ComposedSet
28
28
  pick_sets if @remote and @sets.empty?
29
29
 
30
30
  super
31
+ rescue Gem::RemoteFetcher::FetchError => e
32
+ replace_failed_api_set e
33
+
34
+ retry
31
35
  end
32
36
 
33
37
  def prefetch reqs # :nodoc:
@@ -46,5 +50,29 @@ class Gem::Resolver::BestSet < Gem::Resolver::ComposedSet
46
50
  end
47
51
  end
48
52
 
53
+ ##
54
+ # Replaces a failed APISet for the URI in +error+ with an IndexSet.
55
+ #
56
+ # If no matching APISet can be found the original +error+ is raised.
57
+ #
58
+ # The calling method must retry the exception to repeat the lookup.
59
+
60
+ def replace_failed_api_set error # :nodoc:
61
+ uri = error.uri
62
+ uri = URI uri unless URI === uri
63
+ uri.query = nil
64
+
65
+ raise error unless api_set = @sets.find { |set|
66
+ Gem::Resolver::APISet === set and set.dep_uri == uri
67
+ }
68
+
69
+ index_set = Gem::Resolver::IndexSet.new api_set.source
70
+
71
+ @sets.map! do |set|
72
+ next set unless set == api_set
73
+ index_set
74
+ end
75
+ end
76
+
49
77
  end
50
78
 
@@ -52,11 +52,40 @@ class Gem::Resolver::Conflict
52
52
 
53
53
  def explanation
54
54
  activated = @activated.spec.full_name
55
- requirement = @failed_dep.dependency.requirement
55
+ dependency = @failed_dep.dependency
56
+ requirement = dependency.requirement
57
+ alternates = dependency.matching_specs.map { |spec| spec.full_name }
56
58
 
57
- " Activated %s via:\n %s\n instead of (%s) via:\n %s\n" % [
58
- activated, request_path(@activated).join(', '),
59
- requirement, request_path(requester).join(', '),
59
+ unless alternates.empty? then
60
+ matching = <<-MATCHING.chomp
61
+
62
+ Gems matching %s:
63
+ %s
64
+ MATCHING
65
+
66
+ matching = matching % [
67
+ dependency,
68
+ alternates.join(', '),
69
+ ]
70
+ end
71
+
72
+ explanation = <<-EXPLANATION
73
+ Activated %s
74
+ which does not match conflicting dependency (%s)
75
+
76
+ Conflicting dependency chains:
77
+ %s
78
+
79
+ versus:
80
+ %s
81
+ %s
82
+ EXPLANATION
83
+
84
+ explanation % [
85
+ activated, requirement,
86
+ request_path(@activated).reverse.join(" depends on\n "),
87
+ request_path(@failed_dep).reverse.join(" depends on\n "),
88
+ matching,
60
89
  ]
61
90
  end
62
91
 
@@ -95,10 +124,19 @@ class Gem::Resolver::Conflict
95
124
  path = []
96
125
 
97
126
  while current do
98
- requirement = current.request.dependency.requirement
99
- path << "#{current.spec.full_name} (#{requirement})"
127
+ case current
128
+ when Gem::Resolver::ActivationRequest then
129
+ path <<
130
+ "#{current.request.dependency}, #{current.spec.version} activated"
131
+
132
+ current = current.parent
133
+ when Gem::Resolver::DependencyRequest then
134
+ path << "#{current.dependency}"
100
135
 
101
- current = current.parent
136
+ current = current.requester
137
+ else
138
+ raise Gem::Exception, "[BUG] unknown request class #{current.class}"
139
+ end
102
140
  end
103
141
 
104
142
  path = ['user request (gem command or Gemfile)'] if path.empty?
@@ -12,6 +12,10 @@ class Gem::Resolver::GitSpecification < Gem::Resolver::SpecSpecification
12
12
  @source == other.source
13
13
  end
14
14
 
15
+ def add_dependency dependency # :nodoc:
16
+ spec.dependencies << dependency
17
+ end
18
+
15
19
  ##
16
20
  # Installing a git gem only involves building the extensions and generating
17
21
  # the executables.
@@ -31,5 +35,25 @@ class Gem::Resolver::GitSpecification < Gem::Resolver::SpecSpecification
31
35
  installer.run_post_install_hooks
32
36
  end
33
37
 
38
+ def pretty_print q # :nodoc:
39
+ q.group 2, '[GitSpecification', ']' do
40
+ q.breakable
41
+ q.text "name: #{name}"
42
+
43
+ q.breakable
44
+ q.text "version: #{version}"
45
+
46
+ q.breakable
47
+ q.text 'dependencies:'
48
+ q.breakable
49
+ q.pp dependencies
50
+
51
+ q.breakable
52
+ q.text "source:"
53
+ q.breakable
54
+ q.pp @source
55
+ end
56
+ end
57
+
34
58
  end
35
59
 
@@ -41,6 +41,28 @@ class Gem::Resolver::LockSpecification < Gem::Resolver::Specification
41
41
  @dependencies << dependency
42
42
  end
43
43
 
44
+ def pretty_print q # :nodoc:
45
+ q.group 2, '[LockSpecification', ']' do
46
+ q.breakable
47
+ q.text "name: #{@name}"
48
+
49
+ q.breakable
50
+ q.text "version: #{@version}"
51
+
52
+ unless @platform == Gem::Platform::RUBY then
53
+ q.breakable
54
+ q.text "platform: #{@platform}"
55
+ end
56
+
57
+ unless @dependencies.empty? then
58
+ q.breakable
59
+ q.text 'dependencies:'
60
+ q.breakable
61
+ q.pp @dependencies
62
+ end
63
+ end
64
+ end
65
+
44
66
  ##
45
67
  # A specification constructed from the lockfile is returned
46
68
 
@@ -104,6 +104,8 @@ class Gem::Source
104
104
  def cache_dir(uri)
105
105
  # Correct for windows paths
106
106
  escaped_path = uri.path.sub(/^\/([a-z]):\//i, '/\\1-/')
107
+ escaped_path.untaint
108
+
107
109
  File.join Gem.spec_cache_dir, "#{uri.host}%#{uri.port}", File.dirname(escaped_path)
108
110
  end
109
111
 
@@ -67,7 +67,7 @@ class Gem::Source::Git < Gem::Source
67
67
  case other
68
68
  when Gem::Source::Git then
69
69
  0
70
- when Gem::Source::Installed,
70
+ when Gem::Source::Vendor,
71
71
  Gem::Source::Lock then
72
72
  -1
73
73
  when Gem::Source then
@@ -12,7 +12,8 @@ class Gem::Source::Installed < Gem::Source
12
12
 
13
13
  def <=> other
14
14
  case other
15
- when Gem::Source::Lock,
15
+ when Gem::Source::Git,
16
+ Gem::Source::Lock,
16
17
  Gem::Source::Vendor then
17
18
  -1
18
19
  when Gem::Source::Installed then
@@ -14,12 +14,6 @@ require 'rubygems/basic_specification'
14
14
  require 'rubygems/stub_specification'
15
15
  require 'rubygems/util/stringio'
16
16
 
17
- # :stopdoc:
18
- # date.rb can't be loaded for `make install` due to miniruby
19
- # Date is needed for old gems that stored #date as Date instead of Time.
20
- class Date; end
21
- # :startdoc:
22
-
23
17
  ##
24
18
  # The Specification class contains the information for a Gem. Typically
25
19
  # defined in a .gemspec file or a Rakefile, and looks like this:
@@ -375,7 +369,9 @@ class Gem::Specification < Gem::BasicSpecification
375
369
  ##
376
370
  # A long description of this gem
377
371
  #
378
- # The description should be more detailed than the summary.
372
+ # The description should be more detailed than the summary but not
373
+ # excessively long. A few paragraphs is a recommended length with no
374
+ # examples or formatting.
379
375
  #
380
376
  # Usage:
381
377
  #
@@ -656,7 +652,7 @@ class Gem::Specification < Gem::BasicSpecification
656
652
  # spec.test_files = Dir.glob('test/tc_*.rb')
657
653
  # spec.test_files = ['tests/test-suite.rb']
658
654
 
659
- def test_files= files
655
+ def test_files= files # :nodoc:
660
656
  @test_files = Array files
661
657
  end
662
658
 
@@ -1515,6 +1511,11 @@ class Gem::Specification < Gem::BasicSpecification
1515
1511
  @date ||= TODAY
1516
1512
  end
1517
1513
 
1514
+ DateLike = Object.new # :nodoc:
1515
+ def DateLike.===(obj) # :nodoc:
1516
+ defined?(::Date) and Date === obj
1517
+ end
1518
+
1518
1519
  DateTimeFormat = # :nodoc:
1519
1520
  /\A
1520
1521
  (\d{4})-(\d{2})-(\d{2})
@@ -1544,7 +1545,7 @@ class Gem::Specification < Gem::BasicSpecification
1544
1545
  raise(Gem::InvalidSpecificationException,
1545
1546
  "invalid date format in specification: #{date.inspect}")
1546
1547
  end
1547
- when Time, Date then
1548
+ when Time, DateLike then
1548
1549
  Time.utc(date.year, date.month, date.day)
1549
1550
  else
1550
1551
  TODAY
@@ -1798,7 +1799,7 @@ class Gem::Specification < Gem::BasicSpecification
1798
1799
  ##
1799
1800
  # True if this gem has files in test_files
1800
1801
 
1801
- def has_unit_tests?
1802
+ def has_unit_tests? # :nodoc:
1802
1803
  not test_files.empty?
1803
1804
  end
1804
1805
 
@@ -2154,7 +2155,7 @@ class Gem::Specification < Gem::BasicSpecification
2154
2155
  seg = obj.keys.sort.map { |k| "#{k.to_s.dump} => #{obj[k].to_s.dump}" }
2155
2156
  "{ #{seg.join(', ')} }"
2156
2157
  when Gem::Version then obj.to_s.dump
2157
- when Date then obj.strftime('%Y-%m-%d').dump
2158
+ when DateLike then obj.strftime('%Y-%m-%d').dump
2158
2159
  when Time then obj.strftime('%Y-%m-%d').dump
2159
2160
  when Numeric then obj.inspect
2160
2161
  when true, false, nil then obj.inspect
@@ -2242,14 +2243,14 @@ class Gem::Specification < Gem::BasicSpecification
2242
2243
  ##
2243
2244
  # Singular accessor for #test_files
2244
2245
 
2245
- def test_file
2246
+ def test_file # :nodoc:
2246
2247
  val = test_files and val.first
2247
2248
  end
2248
2249
 
2249
2250
  ##
2250
2251
  # Singular mutator for #test_files
2251
2252
 
2252
- def test_file= file
2253
+ def test_file= file # :nodoc:
2253
2254
  self.test_files = [file]
2254
2255
  end
2255
2256
 
@@ -2257,7 +2258,7 @@ class Gem::Specification < Gem::BasicSpecification
2257
2258
  # Test files included in this gem. You cannot append to this accessor, you
2258
2259
  # must assign to it.
2259
2260
 
2260
- def test_files
2261
+ def test_files # :nodoc:
2261
2262
  # Handle the possibility that we have @test_suite_file but not
2262
2263
  # @test_files. This will happen when an old gem is loaded via
2263
2264
  # YAML.
@@ -2387,7 +2388,7 @@ class Gem::Specification < Gem::BasicSpecification
2387
2388
 
2388
2389
  def to_yaml(opts = {}) # :nodoc:
2389
2390
  if (YAML.const_defined?(:ENGINE) && !YAML::ENGINE.syck?) ||
2390
- !defined?(Syck) && defined?(Psych) then
2391
+ (defined?(Psych) && YAML == Psych) then
2391
2392
  # Because the user can switch the YAML engine behind our
2392
2393
  # back, we have to check again here to make sure that our
2393
2394
  # psych code was properly loaded, and load it if not.