rubygems-update 2.4.8 → 2.5.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 (125) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CODE_OF_CONDUCT.md +40 -0
  5. data/CVE-2015-3900.txt +40 -0
  6. data/History.txt +173 -2
  7. data/Manifest.txt +14 -1
  8. data/Rakefile +36 -1
  9. data/lib/rubygems.rb +32 -14
  10. data/lib/rubygems/basic_specification.rb +31 -9
  11. data/lib/rubygems/commands/dependency_command.rb +25 -15
  12. data/lib/rubygems/commands/environment_command.rb +2 -0
  13. data/lib/rubygems/commands/help_command.rb +0 -10
  14. data/lib/rubygems/commands/install_command.rb +1 -1
  15. data/lib/rubygems/commands/list_command.rb +1 -1
  16. data/lib/rubygems/commands/pristine_command.rb +11 -1
  17. data/lib/rubygems/commands/query_command.rb +1 -1
  18. data/lib/rubygems/commands/sources_command.rb +1 -1
  19. data/lib/rubygems/commands/update_command.rb +2 -2
  20. data/lib/rubygems/config_file.rb +4 -4
  21. data/lib/rubygems/core_ext/kernel_require.rb +2 -2
  22. data/lib/rubygems/dependency.rb +9 -6
  23. data/lib/rubygems/dependency_list.rb +3 -0
  24. data/lib/rubygems/ext/builder.rb +2 -0
  25. data/lib/rubygems/ext/ext_conf_builder.rb +6 -1
  26. data/lib/rubygems/indexer.rb +26 -91
  27. data/lib/rubygems/installer.rb +58 -26
  28. data/lib/rubygems/installer_test_case.rb +2 -2
  29. data/lib/rubygems/package.rb +18 -6
  30. data/lib/rubygems/package/old.rb +2 -2
  31. data/lib/rubygems/package/tar_reader/entry.rb +7 -1
  32. data/lib/rubygems/package/tar_test_case.rb +12 -3
  33. data/lib/rubygems/package/tar_writer.rb +19 -1
  34. data/lib/rubygems/platform.rb +3 -2
  35. data/lib/rubygems/rdoc.rb +1 -2
  36. data/lib/rubygems/remote_fetcher.rb +25 -6
  37. data/lib/rubygems/request/connection_pools.rb +8 -4
  38. data/lib/rubygems/request_set.rb +3 -4
  39. data/lib/rubygems/request_set/gem_dependency_api.rb +2 -2
  40. data/lib/rubygems/request_set/lockfile.rb +1 -1
  41. data/lib/rubygems/request_set/lockfile/parser.rb +54 -43
  42. data/lib/rubygems/request_set/lockfile/tokenizer.rb +16 -13
  43. data/lib/rubygems/resolver.rb +47 -242
  44. data/lib/rubygems/resolver/activation_request.rb +2 -1
  45. data/lib/rubygems/resolver/conflict.rb +0 -1
  46. data/lib/rubygems/resolver/dependency_request.rb +4 -1
  47. data/lib/rubygems/resolver/git_specification.rb +1 -2
  48. data/lib/rubygems/resolver/molinillo.rb +1 -0
  49. data/lib/rubygems/resolver/molinillo/lib/molinillo.rb +5 -0
  50. data/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb +266 -0
  51. data/lib/rubygems/resolver/molinillo/lib/molinillo/errors.rb +69 -0
  52. data/lib/rubygems/resolver/molinillo/lib/molinillo/gem_metadata.rb +3 -0
  53. data/lib/rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider.rb +99 -0
  54. data/lib/rubygems/resolver/molinillo/lib/molinillo/modules/ui.rb +63 -0
  55. data/lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb +430 -0
  56. data/lib/rubygems/resolver/molinillo/lib/molinillo/resolver.rb +43 -0
  57. data/lib/rubygems/resolver/molinillo/lib/molinillo/state.rb +51 -0
  58. data/lib/rubygems/resolver/specification.rb +1 -1
  59. data/lib/rubygems/specification.rb +256 -86
  60. data/lib/rubygems/stub_specification.rb +37 -29
  61. data/lib/rubygems/test_case.rb +65 -28
  62. data/lib/rubygems/test_utilities.rb +18 -18
  63. data/lib/rubygems/text.rb +0 -2
  64. data/lib/rubygems/uninstaller.rb +1 -1
  65. data/lib/rubygems/util.rb +4 -4
  66. data/lib/rubygems/util/licenses.rb +309 -0
  67. data/lib/rubygems/util/list.rb +9 -21
  68. data/lib/rubygems/version.rb +24 -14
  69. data/test/rubygems/simple_gem.rb +1 -1
  70. data/test/rubygems/test_config.rb +10 -1
  71. data/test/rubygems/test_gem.rb +58 -11
  72. data/test/rubygems/test_gem_available_set.rb +2 -1
  73. data/test/rubygems/test_gem_commands_cleanup_command.rb +6 -5
  74. data/test/rubygems/test_gem_commands_dependency_command.rb +9 -1
  75. data/test/rubygems/test_gem_commands_install_command.rb +17 -28
  76. data/test/rubygems/test_gem_commands_mirror.rb +0 -13
  77. data/test/rubygems/test_gem_commands_outdated_command.rb +2 -3
  78. data/test/rubygems/test_gem_commands_pristine_command.rb +33 -5
  79. data/test/rubygems/test_gem_commands_query_command.rb +123 -158
  80. data/test/rubygems/test_gem_commands_server_command.rb +2 -2
  81. data/test/rubygems/test_gem_commands_specification_command.rb +4 -4
  82. data/test/rubygems/test_gem_commands_stale_command.rb +2 -0
  83. data/test/rubygems/test_gem_commands_uninstall_command.rb +5 -4
  84. data/test/rubygems/test_gem_commands_unpack_command.rb +4 -6
  85. data/test/rubygems/test_gem_commands_update_command.rb +22 -52
  86. data/test/rubygems/test_gem_commands_which_command.rb +1 -0
  87. data/test/rubygems/test_gem_config_file.rb +1 -1
  88. data/test/rubygems/test_gem_dependency.rb +7 -3
  89. data/test/rubygems/test_gem_dependency_installer.rb +5 -5
  90. data/test/rubygems/test_gem_doctor.rb +1 -1
  91. data/test/rubygems/test_gem_ext_builder.rb +2 -0
  92. data/test/rubygems/test_gem_ext_configure_builder.rb +8 -4
  93. data/test/rubygems/test_gem_ext_ext_conf_builder.rb +25 -21
  94. data/test/rubygems/test_gem_indexer.rb +4 -4
  95. data/test/rubygems/test_gem_install_update_options.rb +2 -2
  96. data/test/rubygems/test_gem_installer.rb +32 -26
  97. data/test/rubygems/test_gem_package.rb +46 -1
  98. data/test/rubygems/test_gem_package_tar_reader_entry.rb +8 -1
  99. data/test/rubygems/test_gem_package_tar_writer.rb +10 -1
  100. data/test/rubygems/test_gem_package_task.rb +5 -2
  101. data/test/rubygems/test_gem_platform.rb +11 -0
  102. data/test/rubygems/test_gem_remote_fetcher.rb +64 -3
  103. data/test/rubygems/test_gem_request.rb +1 -1
  104. data/test/rubygems/test_gem_request_connection_pools.rb +10 -1
  105. data/test/rubygems/test_gem_request_set.rb +5 -8
  106. data/test/rubygems/test_gem_request_set_lockfile.rb +2 -4
  107. data/test/rubygems/test_gem_request_set_lockfile_tokenizer.rb +1 -1
  108. data/test/rubygems/test_gem_resolver.rb +12 -31
  109. data/test/rubygems/test_gem_resolver_git_specification.rb +1 -0
  110. data/test/rubygems/test_gem_resolver_installer_set.rb +7 -11
  111. data/test/rubygems/test_gem_resolver_lock_specification.rb +3 -2
  112. data/test/rubygems/test_gem_security_trust_dir.rb +2 -0
  113. data/test/rubygems/test_gem_server.rb +4 -0
  114. data/test/rubygems/test_gem_specification.rb +344 -61
  115. data/test/rubygems/test_gem_stream_ui.rb +6 -6
  116. data/test/rubygems/test_gem_stub_specification.rb +21 -6
  117. data/test/rubygems/test_gem_text.rb +2 -0
  118. data/test/rubygems/test_gem_uninstaller.rb +2 -1
  119. data/test/rubygems/test_gem_util.rb +8 -0
  120. data/test/rubygems/test_require.rb +156 -125
  121. data/util/generate_spdx_license_list.rb +21 -0
  122. data/util/update_bundled_ca_certificates.rb +2 -1
  123. metadata +42 -6
  124. metadata.gz.sig +0 -0
  125. data/lib/rubygems/util/stringio.rb +0 -34
@@ -61,11 +61,6 @@ class Gem::Installer
61
61
 
62
62
  attr_reader :options
63
63
 
64
- ##
65
- # Sets the specification for .gem-less installs.
66
-
67
- attr_writer :spec
68
-
69
64
  @path_warning = false
70
65
 
71
66
  @install_lock = Mutex.new
@@ -99,6 +94,46 @@ class Gem::Installer
99
94
 
100
95
  end
101
96
 
97
+ ##
98
+ # Construct an installer object for the gem file located at +path+
99
+
100
+ def self.at path, options = {}
101
+ security_policy = options[:security_policy]
102
+ package = Gem::Package.new path, security_policy
103
+ new package, options
104
+ end
105
+
106
+ class FakePackage
107
+ attr_accessor :spec
108
+
109
+ def initialize(spec)
110
+ @spec = spec
111
+ end
112
+
113
+ def extract_files destination_dir, pattern = '*'
114
+ FileUtils.mkdir_p destination_dir
115
+
116
+ spec.files.each do |file|
117
+ file = File.join destination_dir, file
118
+ next if File.exist? file
119
+ FileUtils.mkdir_p File.dirname(file)
120
+ File.open file, 'w' do |fp| fp.puts "# #{file}" end
121
+ end
122
+ end
123
+
124
+ def copy_to path
125
+ end
126
+ end
127
+
128
+ ##
129
+ # Construct an installer object for an ephemeral gem (one where we don't
130
+ # actually have a .gem file, just a spec)
131
+
132
+ def self.for_spec spec, options = {}
133
+ # FIXME: we should have a real Package class for this
134
+ new FakePackage.new(spec), options
135
+ end
136
+
102
137
  ##
103
138
  # Constructs an Installer instance that will install the gem located at
104
139
  # +gem+. +options+ is a Hash with the following keys:
@@ -122,17 +157,22 @@ class Gem::Installer
122
157
  # :build_args:: An Array of arguments to pass to the extension builder
123
158
  # process. If not set, then Gem::Command.build_args is used
124
159
 
125
- def initialize(gem, options={})
160
+ def initialize(package, options={})
126
161
  require 'fileutils'
127
162
 
128
- @gem = gem
129
163
  @options = options
130
- @package = Gem::Package.new @gem
164
+ if package.is_a? String
165
+ security_policy = options[:security_policy]
166
+ @package = Gem::Package.new package, security_policy
167
+ if $VERBOSE
168
+ warn "constructing an Installer object with a string is deprecated. Please use Gem::Installer.at (called from: #{caller.first})"
169
+ end
170
+ else
171
+ @package = package
172
+ end
131
173
 
132
174
  process_options
133
175
 
134
- @package.security_policy = @security_policy
135
-
136
176
  if options[:user_install] and not options[:unpack] then
137
177
  @gem_home = Gem.user_dir
138
178
  @bin_dir = Gem.bindir gem_home unless options[:bin_dir]
@@ -211,7 +251,7 @@ class Gem::Installer
211
251
  # Lazy accessor for the installer's spec.
212
252
 
213
253
  def spec
214
- @spec ||= @package.spec
254
+ @package.spec
215
255
  rescue Gem::Package::Error => e
216
256
  raise Gem::InstallError, "invalid gem: #{e.message}"
217
257
  end
@@ -230,7 +270,7 @@ class Gem::Installer
230
270
  def install
231
271
  pre_install_checks
232
272
 
233
- FileUtils.rm_f File.join gem_home, 'specifications', @spec.spec_name
273
+ FileUtils.rm_f File.join gem_home, 'specifications', spec.spec_name
234
274
 
235
275
  run_pre_install_hooks
236
276
 
@@ -239,12 +279,12 @@ class Gem::Installer
239
279
 
240
280
  FileUtils.mkdir_p gem_dir
241
281
 
242
- spec.loaded_from = spec_file
243
-
244
282
  if @options[:install_as_default]
283
+ spec.loaded_from = default_spec_file
245
284
  extract_bin
246
285
  write_default_spec
247
286
  else
287
+ spec.loaded_from = spec_file
248
288
  extract_files
249
289
 
250
290
  build_extensions
@@ -258,7 +298,7 @@ class Gem::Installer
258
298
 
259
299
  say spec.post_install_message unless spec.post_install_message.nil?
260
300
 
261
- Gem::Installer.install_lock.synchronize { Gem::Specification.add_spec spec }
301
+ Gem::Installer.install_lock.synchronize { Gem::Specification.reset }
262
302
 
263
303
  run_post_install_hooks
264
304
 
@@ -363,7 +403,7 @@ class Gem::Installer
363
403
  #
364
404
 
365
405
  def default_spec_file
366
- File.join gem_home, "specifications/default", "#{spec.full_name}.gemspec"
406
+ File.join Gem::Specification.default_specifications_dir, "#{spec.full_name}.gemspec"
367
407
  end
368
408
 
369
409
  ##
@@ -595,7 +635,6 @@ class Gem::Installer
595
635
  @gem_home = options[:install_dir] || Gem.dir
596
636
  @ignore_dependencies = options[:ignore_dependencies]
597
637
  @format_executable = options[:format_executable]
598
- @security_policy = options[:security_policy]
599
638
  @wrappers = options[:wrappers]
600
639
  @only_install_dir = options[:only_install_dir]
601
640
 
@@ -661,7 +700,7 @@ class Gem::Installer
661
700
 
662
701
  require 'rubygems'
663
702
 
664
- version = "#{Gem::Requirement.default}"
703
+ version = "#{Gem::Requirement.default}.a"
665
704
 
666
705
  if ARGV.first
667
706
  str = ARGV.first
@@ -764,11 +803,6 @@ TEXT
764
803
  def pre_install_checks
765
804
  verify_gem_home options[:unpack]
766
805
 
767
- # If we're forcing the install then disable security unless the security
768
- # policy says that we only install signed gems.
769
- @security_policy = nil if
770
- @force and @security_policy and not @security_policy.only_signed
771
-
772
806
  ensure_loadable_spec
773
807
 
774
808
  if options[:install_as_default]
@@ -811,9 +845,7 @@ TEXT
811
845
 
812
846
  def write_cache_file
813
847
  cache_file = File.join gem_home, 'cache', spec.file_name
814
-
815
- FileUtils.cp @gem, cache_file unless File.exist? cache_file
848
+ @package.copy_to cache_file
816
849
  end
817
850
 
818
851
  end
819
-
@@ -176,7 +176,7 @@ class Gem::InstallerTestCase < Gem::TestCase
176
176
  end
177
177
  end
178
178
 
179
- @installer = Gem::Installer.new @gem
179
+ @installer = Gem::Installer.at @gem
180
180
  end
181
181
 
182
182
  ##
@@ -184,7 +184,7 @@ class Gem::InstallerTestCase < Gem::TestCase
184
184
  # +user+ is true a user-install will be performed.
185
185
 
186
186
  def util_installer(spec, gem_home, user=false)
187
- Gem::Installer.new(spec.cache_file,
187
+ Gem::Installer.at(spec.cache_file,
188
188
  :install_dir => gem_home,
189
189
  :user_install => user)
190
190
  end
@@ -123,7 +123,7 @@ class Gem::Package
123
123
  # If +gem+ is an existing file in the old format a Gem::Package::Old will be
124
124
  # returned.
125
125
 
126
- def self.new gem
126
+ def self.new gem, security_policy = nil
127
127
  gem = if gem.is_a?(Gem::Package::Source)
128
128
  gem
129
129
  elsif gem.respond_to? :read
@@ -132,7 +132,7 @@ class Gem::Package
132
132
  Gem::Package::FileSource.new gem
133
133
  end
134
134
 
135
- return super(gem) unless Gem::Package == self
135
+ return super unless Gem::Package == self
136
136
  return super unless gem.present?
137
137
 
138
138
  return super unless gem.start
@@ -144,7 +144,7 @@ class Gem::Package
144
144
  ##
145
145
  # Creates a new package that will read or write to the file +gem+.
146
146
 
147
- def initialize gem # :notnew:
147
+ def initialize gem, security_policy # :notnew:
148
148
  @gem = gem
149
149
 
150
150
  @build_time = Time.now
@@ -152,12 +152,19 @@ class Gem::Package
152
152
  @contents = nil
153
153
  @digests = Hash.new { |h, algorithm| h[algorithm] = {} }
154
154
  @files = nil
155
- @security_policy = nil
155
+ @security_policy = security_policy
156
156
  @signatures = {}
157
157
  @signer = nil
158
158
  @spec = nil
159
159
  end
160
160
 
161
+ ##
162
+ # Copies this package to +path+ (if possible)
163
+
164
+ def copy_to path
165
+ FileUtils.cp @gem.path, path unless File.exist? path
166
+ end
167
+
161
168
  ##
162
169
  # Adds a checksum for each entry in the gem to checksums.yaml.gz.
163
170
 
@@ -200,7 +207,11 @@ class Gem::Package
200
207
 
201
208
  def add_files tar # :nodoc:
202
209
  @spec.files.each do |file|
203
- stat = File.stat file
210
+ stat = File.lstat file
211
+
212
+ if stat.symlink?
213
+ tar.add_symlink file, File.readlink(file), stat.mode
214
+ end
204
215
 
205
216
  next unless stat.file?
206
217
 
@@ -371,6 +382,8 @@ EOM
371
382
  FileUtils.chmod entry.header.mode, destination
372
383
  end if entry.file?
373
384
 
385
+ File.symlink(install_location(entry.header.linkname, destination_dir), destination) if entry.symlink?
386
+
374
387
  verbose destination
375
388
  end
376
389
  end
@@ -611,4 +624,3 @@ require 'rubygems/package/tar_header'
611
624
  require 'rubygems/package/tar_reader'
612
625
  require 'rubygems/package/tar_reader/entry'
613
626
  require 'rubygems/package/tar_writer'
614
-
@@ -18,14 +18,14 @@ class Gem::Package::Old < Gem::Package
18
18
  # Creates a new old-format package reader for +gem+. Old-format packages
19
19
  # cannot be written.
20
20
 
21
- def initialize gem
21
+ def initialize gem, security_policy
22
22
  require 'fileutils'
23
23
  require 'zlib'
24
24
  Gem.load_yaml
25
25
 
26
26
  @contents = nil
27
27
  @gem = gem
28
- @security_policy = nil
28
+ @security_policy = security_policy
29
29
  @spec = nil
30
30
  end
31
31
 
@@ -102,6 +102,13 @@ class Gem::Package::TarReader::Entry
102
102
  @header.typeflag == "0"
103
103
  end
104
104
 
105
+ ##
106
+ # Is this tar entry a symlink?
107
+
108
+ def symlink?
109
+ @header.typeflag == "2"
110
+ end
111
+
105
112
  ##
106
113
  # The position in the tar entry
107
114
 
@@ -144,4 +151,3 @@ class Gem::Package::TarReader::Entry
144
151
  end
145
152
 
146
153
  end
147
-
@@ -71,7 +71,7 @@ class Gem::Package::TarTestCase < Gem::TestCase
71
71
  SP(Z(to_oct(sum, 6)))
72
72
  end
73
73
 
74
- def header(type, fname, dname, length, mode, mtime, checksum = nil)
74
+ def header(type, fname, dname, length, mode, mtime, checksum = nil, linkname = "")
75
75
  checksum ||= " " * 8
76
76
 
77
77
  arr = [ # struct tarfile_entry_posix
@@ -83,7 +83,7 @@ class Gem::Package::TarTestCase < Gem::TestCase
83
83
  Z(to_oct(mtime, 11)), # char mtime[12]; 0 padded, octal, null
84
84
  checksum, # char checksum[8]; 0 padded, octal, null, space
85
85
  type, # char typeflag[1]; file: "0" dir: "5"
86
- "\0" * 100, # char linkname[100]; ASCII + (Z unless filled)
86
+ ASCIIZ(linkname, 100), # char linkname[100]; ASCII + (Z unless filled)
87
87
  "ustar\0", # char magic[6]; "ustar\0"
88
88
  "00", # char version[2]; "00"
89
89
  ASCIIZ("wheel", 32), # char uname[32]; ASCIIZ
@@ -117,6 +117,12 @@ class Gem::Package::TarTestCase < Gem::TestCase
117
117
  header("0", fname, dname, length, mode, mtime, checksum)
118
118
  end
119
119
 
120
+ def tar_symlink_header(fname, prefix, mode, mtime, linkname)
121
+ h = header("2", fname, prefix, 0, mode, mtime, nil, linkname)
122
+ checksum = calc_checksum(h)
123
+ header("2", fname, prefix, 0, mode, mtime, checksum, linkname)
124
+ end
125
+
120
126
  def to_oct(n, pad_size)
121
127
  "%0#{pad_size}o" % n
122
128
  end
@@ -133,5 +139,8 @@ class Gem::Package::TarTestCase < Gem::TestCase
133
139
  util_entry tar_dir_header("foo", "bar", 0, Time.now)
134
140
  end
135
141
 
136
- end
142
+ def util_symlink_entry
143
+ util_entry tar_symlink_header("foo", "bar", 0, Time.now, "link")
144
+ end
137
145
 
146
+ end
@@ -233,6 +233,25 @@ class Gem::Package::TarWriter
233
233
  self
234
234
  end
235
235
 
236
+ ##
237
+ # Adds symlink +name+ with permissions +mode+, linking to +target+.
238
+
239
+ def add_symlink(name, target, mode)
240
+ check_closed
241
+
242
+ name, prefix = split_name name
243
+
244
+ header = Gem::Package::TarHeader.new(:name => name, :mode => mode,
245
+ :size => 0, :typeflag => "2",
246
+ :linkname => target,
247
+ :prefix => prefix,
248
+ :mtime => Time.now).to_s
249
+
250
+ @io.write header
251
+
252
+ self
253
+ end
254
+
236
255
  ##
237
256
  # Raises IOError if the TarWriter is closed
238
257
 
@@ -323,4 +342,3 @@ class Gem::Package::TarWriter
323
342
  end
324
343
 
325
344
  end
326
-
@@ -95,6 +95,7 @@ class Gem::Platform
95
95
  [os, version]
96
96
  when /netbsdelf/ then [ 'netbsdelf', nil ]
97
97
  when /openbsd(\d+\.\d+)?/ then [ 'openbsd', $1 ]
98
+ when /bitrig(\d+\.\d+)?/ then [ 'bitrig', $1 ]
98
99
  when /solaris(\d+\.\d+)?/ then [ 'solaris', $1 ]
99
100
  # test
100
101
  when /^(\w+_platform)(\d+)?/ then [ $1, $2 ]
@@ -147,8 +148,8 @@ class Gem::Platform
147
148
  return nil unless Gem::Platform === other
148
149
 
149
150
  # cpu
150
- (@cpu == 'universal' or other.cpu == 'universal' or @cpu == other.cpu or
151
- (@cpu == 'arm' and other.cpu =~ /\Aarm/)) and
151
+ ([nil,'universal'].include?(@cpu) or [nil, 'universal'].include?(other.cpu) or @cpu == other.cpu or
152
+ (@cpu == 'arm' and other.cpu =~ /\Aarm/)) and
152
153
 
153
154
  # os
154
155
  @os == other.os and
@@ -20,7 +20,7 @@ begin
20
20
  require 'rdoc/rubygems_hook'
21
21
  loaded_hook = true
22
22
  module Gem
23
- RDoc = RDoc::RubygemsHook
23
+ RDoc = ::RDoc::RubygemsHook
24
24
  end
25
25
  rescue LoadError
26
26
  end
@@ -332,4 +332,3 @@ class Gem::RDoc # :nodoc: all
332
332
  end unless loaded_hook
333
333
 
334
334
  Gem.done_installing(&Gem::RDoc.method(:generation_hook))
335
-
@@ -51,6 +51,8 @@ class Gem::RemoteFetcher
51
51
  @fetcher ||= self.new Gem.configuration[:http_proxy]
52
52
  end
53
53
 
54
+ attr_accessor :headers
55
+
54
56
  ##
55
57
  # Initialize a remote fetcher using the source URI and possible proxy
56
58
  # information.
@@ -64,8 +66,11 @@ class Gem::RemoteFetcher
64
66
  #
65
67
  # +dns+: An object to use for DNS resolution of the API endpoint.
66
68
  # By default, use Resolv::DNS.
69
+ #
70
+ # +headers+: A set of additional HTTP headers to be sent to the server when
71
+ # fetching the gem.
67
72
 
68
- def initialize(proxy=nil, dns=Resolv::DNS.new)
73
+ def initialize(proxy=nil, dns=Resolv::DNS.new, headers={})
69
74
  require 'net/http'
70
75
  require 'stringio'
71
76
  require 'time'
@@ -79,6 +84,7 @@ class Gem::RemoteFetcher
79
84
  @cert_files = Gem::Request.get_cert_files
80
85
 
81
86
  @dns = dns
87
+ @headers = headers
82
88
  end
83
89
 
84
90
  ##
@@ -91,7 +97,8 @@ class Gem::RemoteFetcher
91
97
  begin
92
98
  res = @dns.getresource "_rubygems._tcp.#{host}",
93
99
  Resolv::DNS::Resource::IN::SRV
94
- rescue Resolv::ResolvError
100
+ rescue Resolv::ResolvError => e
101
+ verbose "Getting SRV record failed: #{e}"
95
102
  uri
96
103
  else
97
104
  target = res.target.to_s.strip
@@ -234,7 +241,9 @@ class Gem::RemoteFetcher
234
241
 
235
242
  def fetch_http uri, last_modified = nil, head = false, depth = 0
236
243
  fetch_type = head ? Net::HTTP::Head : Net::HTTP::Get
237
- response = request uri, fetch_type, last_modified
244
+ response = request uri, fetch_type, last_modified do |req|
245
+ headers.each { |k,v| req.add_field(k,v) }
246
+ end
238
247
 
239
248
  case response
240
249
  when Net::HTTPOK, Net::HTTPNotModified then
@@ -312,9 +321,19 @@ class Gem::RemoteFetcher
312
321
  end
313
322
 
314
323
  if update and path
315
- open(path, 'wb') do |io|
316
- io.flock(File::LOCK_EX)
317
- io.write data
324
+ begin
325
+ open(path, 'wb') do |io|
326
+ io.flock(File::LOCK_EX)
327
+ io.write data
328
+ end
329
+ rescue Errno::ENOLCK # NFS
330
+ if Thread.main != Thread.current
331
+ raise
332
+ else
333
+ open(path, 'wb') do |io|
334
+ io.write data
335
+ end
336
+ end
318
337
  end
319
338
  end
320
339