summaryrefslogtreecommitdiff
path: root/lib/bundler/compact_index_client/updater.rb
diff options
context:
space:
mode:
authorhsbt <hsbt@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-09-08 08:45:41 +0000
committerhsbt <hsbt@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-09-08 08:45:41 +0000
commit8598f8c2dc78c6d1ae87cb6ae19c34ba2cb29241 (patch)
tree0bbd28f684e745cb212761b7c74fe08668f85cc8 /lib/bundler/compact_index_client/updater.rb
parentf2e04b77aa8a363d7e36ce5a9cdb60714a537a3c (diff)
Merge bundler to standard libraries.
rubygems 2.7.x depends bundler-1.15.x. This is preparation for rubygems and bundler migration. * lib/bundler.rb, lib/bundler/*: files of bundler-1.15.4 * spec/bundler/*: rspec examples of bundler-1.15.4. I applied patches. * https://github.com/bundler/bundler/pull/6007 * Exclude not working examples on ruby repository. * Fake ruby interpriter instead of installed ruby. * Makefile.in: Added test task named `test-bundler`. This task is only working macOS/linux yet. I'm going to support Windows environment later. * tool/sync_default_gems.rb: Added sync task for bundler. [Feature #12733][ruby-core:77172] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59779 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/bundler/compact_index_client/updater.rb')
-rw-r--r--lib/bundler/compact_index_client/updater.rb106
1 files changed, 106 insertions, 0 deletions
diff --git a/lib/bundler/compact_index_client/updater.rb b/lib/bundler/compact_index_client/updater.rb
new file mode 100644
index 0000000000..dc26095040
--- /dev/null
+++ b/lib/bundler/compact_index_client/updater.rb
@@ -0,0 +1,106 @@
+# frozen_string_literal: true
+require "fileutils"
+require "stringio"
+require "tmpdir"
+require "zlib"
+
+module Bundler
+ class CompactIndexClient
+ class Updater
+ class MisMatchedChecksumError < Error
+ def initialize(path, server_checksum, local_checksum)
+ @path = path
+ @server_checksum = server_checksum
+ @local_checksum = local_checksum
+ end
+
+ def message
+ "The checksum of /#{@path} does not match the checksum provided by the server! Something is wrong " \
+ "(local checksum is #{@local_checksum.inspect}, was expecting #{@server_checksum.inspect})."
+ end
+ end
+
+ def initialize(fetcher)
+ @fetcher = fetcher
+ end
+
+ def update(local_path, remote_path, retrying = nil)
+ headers = {}
+
+ Dir.mktmpdir("bundler-compact-index-") do |local_temp_dir|
+ local_temp_path = Pathname.new(local_temp_dir).join(local_path.basename)
+
+ # first try to fetch any new bytes on the existing file
+ if retrying.nil? && local_path.file?
+ FileUtils.cp local_path, local_temp_path
+ headers["If-None-Match"] = etag_for(local_temp_path)
+ headers["Range"] =
+ if local_temp_path.size.nonzero?
+ # Subtract a byte to ensure the range won't be empty.
+ # Avoids 416 (Range Not Satisfiable) responses.
+ "bytes=#{local_temp_path.size - 1}-"
+ else
+ "bytes=#{local_temp_path.size}-"
+ end
+ else
+ # Fastly ignores Range when Accept-Encoding: gzip is set
+ headers["Accept-Encoding"] = "gzip"
+ end
+
+ response = @fetcher.call(remote_path, headers)
+ return nil if response.is_a?(Net::HTTPNotModified)
+
+ content = response.body
+ if response["Content-Encoding"] == "gzip"
+ content = Zlib::GzipReader.new(StringIO.new(content)).read
+ end
+
+ SharedHelpers.filesystem_access(local_temp_path) do
+ if response.is_a?(Net::HTTPPartialContent) && local_temp_path.size.nonzero?
+ local_temp_path.open("a") {|f| f << slice_body(content, 1..-1) }
+ else
+ local_temp_path.open("w") {|f| f << content }
+ end
+ end
+
+ response_etag = (response["ETag"] || "").gsub(%r{\AW/}, "")
+ if etag_for(local_temp_path) == response_etag
+ SharedHelpers.filesystem_access(local_path) do
+ FileUtils.mv(local_temp_path, local_path)
+ end
+ return nil
+ end
+
+ if retrying
+ raise MisMatchedChecksumError.new(remote_path, response_etag, etag_for(local_temp_path))
+ end
+
+ update(local_path, remote_path, :retrying)
+ end
+ end
+
+ def etag_for(path)
+ sum = checksum_for_file(path)
+ sum ? %("#{sum}") : nil
+ end
+
+ def slice_body(body, range)
+ if body.respond_to?(:byteslice)
+ body.byteslice(range)
+ else # pre-1.9.3
+ body.unpack("@#{range.first}a#{range.end + 1}").first
+ end
+ end
+
+ def checksum_for_file(path)
+ return nil unless path.file?
+ # This must use IO.read instead of Digest.file().hexdigest
+ # because we need to preserve \n line endings on windows when calculating
+ # the checksum
+ SharedHelpers.filesystem_access(path, :read) do
+ Digest::MD5.hexdigest(IO.read(path))
+ end
+ end
+ end
+ end
+end