class Cutlass::LocalBuildpack

Converts a buildpack in a local directory into an image that pack can use natively

MY_BUILDPACK = LocalBuildpack.new(directory: "/tmp/muh_buildpack").call
puts MY_BUILDPACK.name #=> "docker:://cutlass_local_buildpack_abcd123"

Cutlass.config do |config|
  config.default_buildapacks = [MY_BUILDPACK]
end

Note: Make sure that any built images are torn down in in your test suite

config.after(:suite) do
  MY_BUILDPACK.teardown

  Cutlass::CleanTestEnv.check
end

Attributes

image_name[R]

Public Class Methods

new(directory:) click to toggle source
# File lib/cutlass/local_buildpack.rb, line 28
def initialize(directory:)
  @built = false
  @directory = Pathname(directory)
  @image_name = "cutlass_local_buildpack_#{SecureRandom.hex(10)}"

  @mutex_file = Tempfile.new
end

Public Instance Methods

built?() click to toggle source
# File lib/cutlass/local_buildpack.rb, line 118
def built?
  @built
end
call() click to toggle source
# File lib/cutlass/local_buildpack.rb, line 60
def call
  file_lock do
    return if built?
    raise "must be directory: #{@directory}" unless @directory.directory?
    @built = true

    call_build_sh
    call_pack_buildpack_package
  end

  self
end
exist?() click to toggle source
# File lib/cutlass/local_buildpack.rb, line 44
def exist?
  @directory.exist?
end
file_lock() { || ... } click to toggle source
# File lib/cutlass/local_buildpack.rb, line 36
def file_lock
  file = File.open(@mutex_file.path, File::CREAT)
  file.flock(File::LOCK_EX)
  yield
ensure
  file.close
end
name() click to toggle source
# File lib/cutlass/local_buildpack.rb, line 55
def name
  call
  "docker://#{image_name}"
end
teardown() click to toggle source
# File lib/cutlass/local_buildpack.rb, line 48
def teardown
  return unless built?

  image = Docker::Image.get(image_name)
  image.remove(force: true)
end

Private Instance Methods

call_build_sh() click to toggle source
# File lib/cutlass/local_buildpack.rb, line 93
            def call_build_sh
      build_sh = @directory.join("build.sh")
      return unless build_sh.exist?

      command = "cd #{@directory} && bash #{build_sh}"
      result = BashResult.run(command)

      puts command if Cutlass.debug?
      puts result.stdout if Cutlass.debug?
      puts result.stderr if Cutlass.debug?

      if result.success?
        @directory = @directory.join("target")
        raise "Expected #{build_sh} to produce a directory #{@directory} but it did not" unless @directory.exist?
        return
      end

      raise <<~EOM
        Buildpack build step failed!

        stdout: #{result.stdout}
        stderr: #{result.stderr}
      EOM
    end
call_pack_buildpack_package() click to toggle source
# File lib/cutlass/local_buildpack.rb, line 73
            def call_pack_buildpack_package
      raise "must contain package.toml: #{@directory}" unless @directory.join("package.toml").exist?

      command = "pack buildpack package #{image_name} --config #{@directory.join("package.toml")} --format=image"
      result = BashResult.run(command)

      puts command if Cutlass.debug?
      puts result.stdout if Cutlass.debug?
      puts result.stderr if Cutlass.debug?

      return if result.success?
      raise <<~EOM
        While packaging meta-buildpack: pack exited with status code #{result.status},
        indicating an error and failed build!

        stdout: #{result.stdout}
        stderr: #{result.stderr}
      EOM
    end