class R10K::Tarball

Attributes

checksum[RW]

@!attribute [rw] checksum

@return [String] The tarball's expected sha256 digest
name[RW]

@!attribute [rw] name

@return [String] The tarball's name
source[RW]

@!attribute [rw] source

@return [String] The tarball's source

Public Class Methods

new(name, source, checksum: nil) click to toggle source

@param name [String] The name of the tarball content @param source [String] The source for the tarball content @param checksum [String] The sha256 digest of the tarball content

# File lib/r10k/tarball.rb, line 38
def initialize(name, source, checksum: nil)
  @name = name
  @source = source
  @checksum = checksum

  # At this time, the only checksum type supported is sha256. In the future,
  # we may decide to support other algorithms if a use case arises. TBD.
  checksum_algorithm = :SHA256
end

Public Instance Methods

cache_basename() click to toggle source

@return [String] The basename of the tarball cache file.

# File lib/r10k/tarball.rb, line 64
def cache_basename
  if checksum.nil?
    sanitized_dirname(source) + '.tar.gz'
  else
    checksum + '.tar.gz'
  end
end
cache_checksum() click to toggle source
# File lib/r10k/tarball.rb, line 166
def cache_checksum
  raise R10K::Error, _("Cache not present at %{path}") % {path: cache_path} unless File.exist?(cache_path)
  file_digest(cache_path)
end
cache_dirname() click to toggle source

@return [String] Directory. Where the cache_basename file will be created.

# File lib/r10k/tarball.rb, line 49
def cache_dirname
  File.join(settings[:cache_root], 'tarball')
end
cache_path() click to toggle source

The final cache_path should match one of the templates:

- {cachedir}/{checksum}.tar.gz
- {cachedir}/{source}.tar.gz

@return [String] File. The full file path the tarball will be cached to.

# File lib/r10k/tarball.rb, line 59
def cache_path
  File.join(cache_dirname, cache_basename)
end
cache_valid?() click to toggle source

Checks the cached tarball's digest against the expected checksum. Returns false if no cached file is present. If the tarball has no expected checksum, any cached file is assumed to be valid.

@return [Boolean]

# File lib/r10k/tarball.rb, line 150
def cache_valid?
  return false unless File.exist?(cache_path)
  return true if checksum.nil?
  checksum == file_digest(cache_path)
end
get() click to toggle source

Download the tarball from @source to @cache_path

# File lib/r10k/tarball.rb, line 112
def get
  Tempfile.open(cache_basename) do |tempfile|
    tempfile.binmode
    src_uri = URI.parse(source)

    temp_digest = case src_uri.scheme
                  when 'file', nil
                    copy(src_uri.path, tempfile)
                  when %r{^[a-z]$} # Windows drive letter
                    copy(src_uri.to_s, tempfile)
                  when %r{^https?$}
                    download(src_uri, tempfile)
                  else
                    raise "Unexpected source scheme #{src_uri.scheme}"
                  end

    # Verify the download
    unless (checksum == temp_digest) || checksum.nil?
      raise 'Downloaded file does not match checksum'
    end

    # Move the download to cache_path
    FileUtils::mkdir_p(cache_dirname)
    begin
      FileUtils.mv(tempfile.path, cache_path)
    rescue Errno::EACCES
      # It may be the case that permissions don't permit moving the file
      # into place, but do permit overwriting an existing in-place file.
      FileUtils.cp(tempfile.path, cache_path)
    end
  end
end
insync?(target_dir, ignore_untracked_files: false) click to toggle source

@param target_dir [String] The directory to check if is in sync with the

tarball content

@param ignore_untracked_files [Boolean] If true, consider the target

dir to be in sync as long as all tracked content matches.

@return [Boolean]

# File lib/r10k/tarball.rb, line 91
def insync?(target_dir, ignore_untracked_files: false)
  target_tree_entries = Find.find(target_dir).map(&:to_s) - [target_dir]
  each_tarball_entry do |entry|
    found = target_tree_entries.delete(File.join(target_dir, entry.full_name.chomp('/')))
    return false if found.nil?
    next if entry.directory?
    return false unless file_digest(found) == reader_digest(entry)
  end

  if ignore_untracked_files
    # We wouldn't have gotten this far if there were discrepancies in
    # tracked content
    true
  else
    # If there are still files in target_tree_entries, then there is
    # untracked content present in the target tree. If not, we're in sync.
    target_tree_entries.empty?
  end
end
paths() click to toggle source

List all of the files contained in the tarball and their paths. This is useful for implementing R10K::Purgable

@return [Array] A normalized list of file paths contained in the archive

# File lib/r10k/tarball.rb, line 160
def paths
  names = Array.new
  each_tarball_entry { |entry| names << Pathname.new(entry).cleanpath.to_s }
  names - ['.']
end
unpack(target_dir) click to toggle source

Extract the cached tarball to the target directory.

@param target_dir [String] Where to unpack the tarball

# File lib/r10k/tarball.rb, line 75
def unpack(target_dir)
  file = File.open(cache_path, 'rb')
  reader = Zlib::GzipReader.new(file)
  begin
    Minitar.unpack(reader, target_dir)
  ensure
    reader.close
  end
end

Private Instance Methods

each_tarball_entry() { |entry| ... } click to toggle source
# File lib/r10k/tarball.rb, line 173
def each_tarball_entry(&block)
  File.open(cache_path, 'rb') do |file|
    Zlib::GzipReader.wrap(file) do |reader|
      Archive::Tar::Minitar::Input.each_entry(reader) do |entry|
        yield entry
      end
    end
  end
end