class Bundler::CompactIndexClient::Updater

Public Class Methods

new(fetcher) click to toggle source
# File lib/bundler/vendor/compact_index_client/lib/compact_index_client/updater.rb, line 22
def initialize(fetcher)
  @fetcher = fetcher
end

Public Instance Methods

checksum_for_file(path) click to toggle source
# File lib/bundler/vendor/compact_index_client/lib/compact_index_client/updater.rb, line 72
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
  Digest::MD5.hexdigest(IO.read(path))
end
etag_for(path) click to toggle source
# File lib/bundler/vendor/compact_index_client/lib/compact_index_client/updater.rb, line 67
def etag_for(path)
  sum = checksum_for_file(path)
  sum ? %Q("#{sum}") : nil
end
update(local_path, remote_path, retrying = nil) click to toggle source
# File lib/bundler/vendor/compact_index_client/lib/compact_index_client/updater.rb, line 26
def update(local_path, remote_path, retrying = nil)
  headers = {}

  Dir.mktmpdir(local_path.basename.to_s, local_path.dirname) do |local_temp_dir|
    local_temp_path = Pathname.new(local_temp_dir).join(local_path.basename)

    # download new file if retrying
    if retrying.nil? && local_path.file?
      FileUtils.cp local_path, local_temp_path
      headers["If-None-Match"] = etag_for(local_temp_path)
      headers["Range"] = "bytes=#{local_temp_path.size}-"
    else
      # Fastly ignores Range when Accept-Encoding: gzip is set
      headers["Accept-Encoding"] = "gzip"
    end

    response = @fetcher.call(remote_path, headers)
    return if response.is_a?(Net::HTTPNotModified)

    content = response.body
    if response["Content-Encoding"] == "gzip"
      content = Zlib::GzipReader.new(StringIO.new(content)).read
    end

    mode = response.is_a?(Net::HTTPPartialContent) ? "a" : "w"
    local_temp_path.open(mode) {|f| f << content }

    response_etag = response["ETag"]
    if etag_for(local_temp_path) == response_etag
      FileUtils.mv(local_temp_path, local_path)
      return
    end

    if retrying.nil?
      update(local_path, remote_path, :retrying)
    else
      raise MisMatchedChecksumError.new(remote_path, response_etag, etag_for(local_temp_path))
    end
  end
end