class Bundler::CompactIndexClient::CacheFile - bundler: Ruby Standard Library Documentation

# class Bundler::CompactIndexClient::CacheFile

write cache files in a way that is robust to concurrent modifications if digests are given, the checksums will be verified

### Constants

DEFAULT_FILE_MODE

### Attributes

original_path[R]
path[R]

### Public Class Methods

copy(path) { |file| ... } click to toggle source

Initialize with a copy of the original file, then yield the instance.

    # File bundler/compact_index_client/cache_file.rb, line 24
    def self.copy(path, &block)
      new(path) do |file|
        file.initialize_digests

        SharedHelpers.filesystem_access(path, :read) do
          path.open("rb") do |s|
            file.open {|f| IO.copy_stream(s, f) }
          end
        end

        yield file
      end
    end

new(original_path) { |self| ... } click to toggle source

    # File bundler/compact_index_client/cache_file.rb, line 49
    def initialize(original_path, &block)
      @original_path = original_path
      @perm = original_path.file? ? original_path.stat.mode : DEFAULT_FILE_MODE
      @path = original_path.sub(/$/, ".#{$$}.tmp")
      return unless block_given?
      begin
        yield self
      ensure
        close
      end
    end

write(path, data, digests = nil) click to toggle source

Write data to a temp file, then replace the original file with it verifying the digests if given.

    # File bundler/compact_index_client/cache_file.rb, line 39
    def self.write(path, data, digests = nil)
      return unless data
      new(path) do |file|
        file.digests = digests
        file.write(data)
      end
    end

### Public Instance Methods

append(data) click to toggle source

Returns false without appending when no digests since appending is too error prone to do without digests.

    # File bundler/compact_index_client/cache_file.rb, line 104
    def append(data)
      return false unless digests?
      open("a") {|f| f.write data }
      verify && commit
    end

close() click to toggle source

Remove the temp file without replacing the original file. The file is permanently closed.

    # File bundler/compact_index_client/cache_file.rb, line 141
    def close
      return if @closed
      FileUtils.remove_file(path) if @path&.file?
      @closed = true
    end

commit() click to toggle source

Replace the original file with the temp file without verifying digests. The file is permanently closed.

    # File bundler/compact_index_client/cache_file.rb, line 131
    def commit
      raise ClosedError, "Cannot commit closed file" if @closed
      SharedHelpers.filesystem_access(original_path, :write) do
        FileUtils.mv(path, original_path)
      end
      @closed = true
    end

commit!() click to toggle source

    # File bundler/compact_index_client/cache_file.rb, line 116
    def commit!
      verify || raise(DigestMismatchError.new(@base64digests, @expected_digests))
      commit
    end

digests=(expected_digests) click to toggle source

set the digests that will be verified at the end

    # File bundler/compact_index_client/cache_file.rb, line 77
    def digests=(expected_digests)
      @expected_digests = expected_digests

      if @expected_digests.nil?
        @digests = nil
      elsif @digests
        @digests = @digests.slice(*@expected_digests.keys)
      else
        initialize_digests(@expected_digests.keys)
      end
    end

digests?() click to toggle source

    # File bundler/compact_index_client/cache_file.rb, line 89
    def digests?
      @digests&.any?
    end

initialize_digests(keys = nil) click to toggle source

initialize the digests using CompactIndexClient::SUPPORTED_DIGESTS, or a subset based on keys.

    # File bundler/compact_index_client/cache_file.rb, line 66
    def initialize_digests(keys = nil)
      @digests = keys ? SUPPORTED_DIGESTS.slice(*keys) : SUPPORTED_DIGESTS.dup
      @digests.transform_values! {|algo_class| SharedHelpers.digest(algo_class).new }
    end

open(write_mode = "wb", perm = @perm) { |digests? ? digest_io: f| ... } click to toggle source

Open the temp file for writing, reusing original permissions, yielding the IO object.

    # File bundler/compact_index_client/cache_file.rb, line 94
    def open(write_mode = "wb", perm = @perm, &block)
      raise ClosedError, "Cannot reopen closed file" if @closed
      SharedHelpers.filesystem_access(path, :write) do
        path.open(write_mode, perm) do |f|
          yield digests? ? Gem::Package::DigestIO.new(f, @digests) : f
        end
      end
    end

reset_digests() click to toggle source

reset the digests so they don’t contain any previously read data

    # File bundler/compact_index_client/cache_file.rb, line 72
    def reset_digests
      @digests&.each_value(&:reset)
    end

size() click to toggle source

    # File bundler/compact_index_client/cache_file.rb, line 61
    def size
      path.size
    end

verify() click to toggle source

Verify the digests, returning true on match, false on mismatch.

    # File bundler/compact_index_client/cache_file.rb, line 122
    def verify
      return true unless @expected_digests && digests?
      @base64digests = @digests.transform_values!(&:base64digest)
      @digests = nil
      @base64digests.all? {|algo, digest| @expected_digests[algo] == digest }
    end

write(data) click to toggle source

    # File bundler/compact_index_client/cache_file.rb, line 110
    def write(data)
      reset_digests
      open {|f| f.write data }
      commit!
    end