class Rum::Manifest

Rum Runner Manifest for managing Docker commands.

Attributes

image[R]

Access Docker image object.

Public Class Methods

new(name:, path:nil, home:nil, env:nil, &block) click to toggle source

Initialize new manifest with name, build path, and home path for caching build digests. Evaluates &block if given.

Example:

Manifest.new(name: "my_image", path: ".", home: ".docker")
# File lib/rumrunner/manifest.rb, line 28
def initialize(name:, path:nil, home:nil, env:nil, &block)
  @path  = path || ENV["RUM_PATH"] || "."
  @home  = home || ENV["RUM_HOME"] || ".docker"
  @env   = env  || []
  @image = Docker::Image.parse(name)
  instance_eval(&block) if block_given?
end

Public Instance Methods

application() click to toggle source

Get application

# File lib/rumrunner/manifest.rb, line 38
def application
  Rake.application
end
artifact(*args, &block) click to toggle source

Defines +docker run+ task for redirecting a file from a running instance of the dependent stage's container to the local file system.

Example:

artifact :name => [:stage]
# File lib/rumrunner/manifest.rb, line 131
def artifact(*args, &block)
  name, _, deps = Rake.application.resolve_args(args)

  target  = deps.first
  image   = Docker::Image.parse("#{@image}-#{target}")
  iidfile = File.join(home, *image)
  path    = File.split(name).first
  deps    = [iidfile]

  unless path == "."
    directory path
    deps << path
  end

  artifact_file(name, deps, iidfile, &block)

  artifact_clobber(name, path)
end
build(*args, &block) click to toggle source

Defines generic +docker build+ task.

Example:

build :name
build :name => [:deps]
# File lib/rumrunner/manifest.rb, line 61
def build(*args, &block)
  task(*args) do
    sh Docker::Build.new(options: build_options, path: path, &block).to_s
  end
end
default(*args, &block) click to toggle source

Defines the default task for rum executable.

Example:

default :task_or_file
default :task_or_file => [:deps]
# File lib/rumrunner/manifest.rb, line 49
def default(*args, &block)
  name = Rake.application.resolve_args(args).first
  task :default => name
end
install() click to toggle source

Install any remaining tasks for the manifest.

# File lib/rumrunner/manifest.rb, line 177
def install
  install_default unless Rake::Task.task_defined?(:default)
  install_clean

  self
end
run(*args, &block) click to toggle source

Defines generic +docker run+ task.

Example:

run :name
run :name => [:deps]
# File lib/rumrunner/manifest.rb, line 74
def run(*args, &block)
  name, _, deps = Rake.application.resolve_args(args)

  images   = deps.map{|dep| Docker::Image.parse("#{@image}-#{dep}") }
  iidfiles = images.map{|image| File.join(home, *image) }

  task name => iidfiles do |t|
    image = t.prereqs.empty? ? to_s : File.read(t.prereqs.first)
    sh Docker::Run.new(options: run_options, image: image, &block).to_s
  end
end
shell(*args, &block) click to toggle source

Defines +docker run+ task for shelling into the given stage.

Example:

shell :stage
shell :stage => [:deps]
# File lib/rumrunner/manifest.rb, line 157
def shell(*args, &block)
  target  = Rake.application.resolve_args(args).first
  name    = task_name shell: target
  image   = Docker::Image.parse("#{@image}-#{target}")
  iidfile = File.join(home, *image)

  Rake::Task[name].clear if Rake::Task.task_defined?(name)

  desc "Shell into `#{target}` stage"
  task name, [:shell] => iidfile do |t,args|
    digest = File.read(iidfile)
    shell  = args.any? ? args.to_a.join(" ") : "/bin/sh"
    run    = Docker::Run.new(options: run_options, image: digest, &block)
    run.with_defaults(entrypoint: shell, interactive:true, rm: true, tty: true)
    sh run.to_s
  end
end
stage(*args, &block) click to toggle source

Defines +docker build+ task for the given stage.

Example:

stage :name
stage :name => [:deps]
# File lib/rumrunner/manifest.rb, line 93
def stage(*args, &block)
  name, _, deps = Rake.application.resolve_args(args)

  # Assemble image/iidfile from manifest/stage name
  image   = Docker::Image.parse("#{@image}-#{name}")
  iidfile = File.join(home, *image)
  iidpath = File.split(iidfile).first

  # Ensure path to iidfile exists
  iiddeps = if deps.empty?
    directory iidpath
    iidpath
  else
    images = deps.map{|x| Docker::Image.parse("#{@image}-#{x}") }
    images.map{|x| File.join(home, *x) }
  end

  # Build stage and save digest in iidfile
  stage_file(iidfile, iiddeps, tag: image, target: name, &block)

  # Shortcut to build stage by name
  stage_task(name, iidfile)

  # Shell into stage
  stage_shell(name, iidfile)

  # Clean stage
  stage_clean(name, iidfile, deps)
end

Private Instance Methods

artifact_clobber(name, path) click to toggle source

Install clobber tasks for cleaning up generated files

# File lib/rumrunner/manifest.rb, line 295
def artifact_clobber(name, path)
  desc "Remove any generated files"
  task :clobber => :clean do
    rm_rf name
    rm_rf path unless path == "."
  end
end
artifact_file(name, deps, iidfile, &block) click to toggle source

Install file task for artifact

# File lib/rumrunner/manifest.rb, line 283
def artifact_file(name, deps, iidfile, &block)
  desc "Build `#{name}`"
  file name => deps do
    digest = File.read(iidfile)
    run = Docker::Run.new(options: run_options, image: digest, cmd: [name], &block)
    run.with_defaults(rm: true, entrypoint: "cat")
    sh "#{run} > #{name}"
  end
end
build_options() click to toggle source

Get the shared build options for the Manifest.

# File lib/rumrunner/manifest.rb, line 188
def build_options
  Docker::Options.new(build_arg: @env) unless @env.empty?
end
install_clean() click to toggle source

Install :clean task for removing temporary Docker images and iidfiles.

# File lib/rumrunner/manifest.rb, line 201
def install_clean
  desc "Remove any temporary images and products"
  task :clean do
    Dir[File.join(home, "**/*")].reverse.each do |name|
      sh "docker", "image", "rm", "--force", File.read(name) if File.file?(name)
      rm_rf name
    end
    rm_rf home if Dir.exist?(home)
  end
end
install_default() click to toggle source

Install :default task that builds the image

# File lib/rumrunner/manifest.rb, line 214
def install_default
  iidfile = File.join(home, *image)
  file iidfile do |t|
    tsfile = "#{t.name}@#{Time.now.utc.to_i}"
    build  = Docker::Build.new(options: build_options, path: path)
    build.with_defaults(iidfile: tsfile, tag: tag || :latest)
    sh build.to_s
    cp tsfile, iidfile
  end
  task :default => iidfile
end
run_options() click to toggle source

Get the shared run options for the Manifest.

# File lib/rumrunner/manifest.rb, line 194
def run_options
  Docker::Options.new(env: @env) unless @env.empty?
end
stage_clean(name, iidfile, deps) click to toggle source

Install clean tasks for cleaning up stage image and iidfile

# File lib/rumrunner/manifest.rb, line 264
def stage_clean(name, iidfile, deps)
  # Clean stage image
  desc "Remove any temporary images and products through `#{name}` stage"
  task task_name(clean: name) do
    if File.exist?(iidfile)
      sh "docker", "image", "rm", "--force", File.read(iidfile)
      rm_rf iidfile
    end
  end

  # Add stage to general clean
  task :clean => task_name(clean: name)

  # Ensure subsequent stages are cleaned before this one
  deps.each{|dep| task task_name(clean: dep) => task_name(clean: name) }
end
stage_file(iidfile, iiddeps, tag:, target:, &block) click to toggle source

Install file task for stage and save digest in iidfile

# File lib/rumrunner/manifest.rb, line 228
def stage_file(iidfile, iiddeps, tag:, target:, &block)
  file iidfile => iiddeps do |t|
    tsfile = "#{t.name}@#{Time.now.utc.to_i}"
    build  = Docker::Build.new(options: build_options, path: path, &block)
    build.with_defaults(iidfile: tsfile, tag: tag, target: target)
    sh build.to_s
    cp tsfile, iidfile
  end
end
stage_shell(name, iidfile) click to toggle source

Install shell task for shelling into stage

# File lib/rumrunner/manifest.rb, line 247
def stage_shell(name, iidfile)
  desc "Shell into `#{name}` stage"
  task task_name(shell: name), [:shell] => iidfile do |t,args|
    digest = File.read(t.prereqs.first)
    shell  = args.any? ? args.to_a.join(" ") : "/bin/sh"
    run    = Docker::Run.new(options: run_options)
      .entrypoint(shell)
      .interactive(true)
      .rm(true)
      .tty(true)
      .image(digest)
    sh run.to_s
  end
end
stage_task(name, iidfile) click to toggle source

Install alias task for building stage

# File lib/rumrunner/manifest.rb, line 240
def stage_task(name, iidfile)
  desc "Build `#{name}` stage"
  task name => iidfile
end
task_name(verb_stage) click to toggle source

Get name of support task

# File lib/rumrunner/manifest.rb, line 305
def task_name(verb_stage)
  case ENV["RUM_TASK_NAMES"]&.upcase
  when "STAGE_FIRST"
    verb_stage.first.reverse
  when "VERB_FIRST"
    verb_stage.first
  else
    verb_stage.first
  end.join(":").to_sym
end