class Drydock::Instructions::Copy

The concrete implementation of the COPY instruction. **Do not use this class directly.**

@see Project#copy

Attributes

chain[R]
chmod[RW]
ignorefile[RW]
no_cache[RW]
recursive[RW]
source_path[R]
target_path[R]

Public Instance Methods

run!() click to toggle source

@raise [InvalidInstructionError] when the ‘source_path` does not exist @raise [InvalidInstructionError] when the `source_path` is an empty directory

with nothing to copy

@raise [InvalidInstructionError] when the ‘target_path` does not exist in the

container

@raise [InvalidInstructionError] when the ‘target_path` exists in the container,

but is not actually a directory
# File lib/drydock/instructions/copy.rb, line 29
def run!
  if source_path.start_with?('/')
    Drydock.logger.warn("#{source_path.inspect} is an absolute path; we recommend relative paths")
  end

  fail InvalidInstructionError, "#{source_path} does not exist" unless File.exist?(source_path)

  buffer = build_tar_from_source!
  digest = calculate_digest(buffer)
  write_to_container(buffer, digest)
end

Private Instance Methods

build_tar_from_source!() click to toggle source
# File lib/drydock/instructions/copy.rb, line 43
def build_tar_from_source!
  buffer = StringIO.new
  log_info("Processing #{source_files.size} files in tree")

  TarWriter.new(buffer) do |tar|
    source_files.each do |source_file|
      File.open(source_file, 'r') do |input|
        stat = input.stat
        mode = chmod || stat.mode
        tar.add_entry(source_file, mode: mode, mtime: stat.mtime) do |tar_file|
          tar_file.write(input.read)
        end
      end
    end
  end

  buffer.rewind
  buffer
end
calculate_digest(buffer) click to toggle source
# File lib/drydock/instructions/copy.rb, line 63
def calculate_digest(buffer)
  Digest::MD5.hexdigest(buffer.read).tap do |digest|
    log_info("Tree digest is md5:#{digest}")
    buffer.rewind
  end
end
log_info(msg, indent: 0) click to toggle source
# File lib/drydock/instructions/copy.rb, line 70
def log_info(msg, indent: 0)
  Drydock.logger.info(indent: indent, message: msg)
end
source_files() click to toggle source

Retrieve all files inside {#source_path} not matching the {#ignorefile} rules.

# File lib/drydock/instructions/copy.rb, line 75
def source_files
  files =
    if File.directory?(source_path)
      FileManager.find(source_path, ignorefile, prepend_path: true, recursive: recursive).sort
    else
      [source_path]
    end

  fail InvalidInstructionError, "#{source_path} is empty or does not match a path" if files.empty?

  files
end
write_to_container(buffer, digest) click to toggle source

Create a new container on the ‘chain`, and then write the contents of `buffer`, whose digest is `digest`.

# File lib/drydock/instructions/copy.rb, line 91
def write_to_container(buffer, digest)
  label = "# COPY #{recursive ? 'dir' : 'file'}:md5:#{digest} TO #{target_path}"

  chain.run(label, no_cache: no_cache) do |container|
    target_stat = container.archive_head(target_path)

    # TODO(rpasay): cannot autocreate the target, because `container` here is already dead
    unless target_stat
      fail InvalidInstructionError, "Target path #{target_path.inspect} does not exist"
    end

    unless target_stat.directory?
      Drydock.logger.debug(target_stat)
      fail InvalidInstructionError,
          "Target path #{target_path.inspect} exists, " +
          "but is not a directory in the container"
    end

    container.archive_put(target_path) do |output|
      output.write(buffer.read)
    end
  end
end