rubygems-update 2.3.0 → 2.4.0

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.

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.