module Omnibus::Digestable

Public Class Methods

included(other) click to toggle source
# File lib/omnibus/digestable.rb, line 24
def self.included(other)
  other.send(:include, Logging)
end

Public Instance Methods

digest(path, type = :md5) click to toggle source

Calculate the digest of the file at the given path. Files are read in binary chunks to prevent Ruby from exploding.

@param [String] path

the path of the file to digest

@param [Symbol] type

the type of digest to use

@return [String]

the hexdigest of the file at the path
# File lib/omnibus/digestable.rb, line 40
def digest(path, type = :md5)
  digest = digest_from_type(type)

  update_with_file_contents(digest, path)
  digest.hexdigest
end
digest_directory(path, type = :md5, options = {}) click to toggle source

Calculate the digest of a directory at the given path. Each file in the directory is read in binary chunks to prevent excess memory usage. Filesystem entries of all types are included in the digest, including directories, links, and sockets. The contents of non-file entries are represented as:

$type $path

while the contents of regular files are represented as:

file $path

and then appended by the binary contents of the file/

@param [String] path

the path of the directory to digest

@param [Symbol] type

the type of digest to use

@param [Hash] options

options to pass through to the FileSyncer when scanning for files

@return [String]

the hexdigest of the directory
# File lib/omnibus/digestable.rb, line 72
def digest_directory(path, type = :md5, options = {})
  digest = digest_from_type(type)
  log.info(log_key) { "Digesting #{path} with #{type}" }
  FileSyncer.all_files_under(path, options).each do |filename|
    # Calculate the filename relative to the given path. Since directories
    # are SHAed according to their filepath, two difference directories on
    # disk would have different SHAs even if they had the same content.
    relative = Pathname.new(filename).relative_path_from(Pathname.new(path))

    case ftype = File.ftype(filename)
    when "file"
      update_with_string(digest, "#{ftype} #{relative}")
      update_with_file_contents(digest, filename)
    else
      update_with_string(digest, "#{ftype} #{relative}")
    end
  end

  digest.hexdigest
end

Private Instance Methods

digest_from_type(type) click to toggle source

Create a new instance of the {Digest} class that corresponds to the given type.

@param [#to_s] type

the type of digest to use

@return [~Digest]

an instance of the digest class
# File lib/omnibus/digestable.rb, line 105
def digest_from_type(type)
  id = type.to_s.upcase
  instance = OpenSSL::Digest.const_get(id).new
end
update_with_file_contents(digest, filename) click to toggle source

Update the digest with the given contents of the file, reading in small chunks to reduce memory. This method will update the given digest parameter, but returns nothing.

@param [Digest] digest

the digest to update

@param [String] filename

the path to the file on disk to read

@return [void]

# File lib/omnibus/digestable.rb, line 122
def update_with_file_contents(digest, filename)
  File.open(filename) do |io|
    while (chunk = io.read(1024 * 8))
      digest.update(chunk)
    end
  end
end
update_with_string(digest, string) click to toggle source

Update the digest with the given string. This method will update the given digest parameter, but returns nothing.

@param [Digest] digest

the digest to update

@param [String] string

the string to read

@return [void]

# File lib/omnibus/digestable.rb, line 141
def update_with_string(digest, string)
  digest.update(string)
end