Class: Cutlass::App

Inherits:
Object
  • Object
show all
Defined in:
lib/cutlass/app.rb

Overview

Top level class for interacting with a “pack” app

Cutlass::App.new(
  path_to_rails_app,
  buildpacks: "heroku/ruby",
  builder: "heroku/buildpacks:18"
).transaction do |app|
  app.pack_build

  expect(result.stdout).to include("Successfully built image")
end

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source_path_name, config: {}, warn_io: $stderr, builder: Cutlass.default_builder, image_name: Cutlass.default_image_name, buildpacks: Cutlass.default_buildpack_paths, exception_on_failure: true) ⇒ App

Returns a new instance of App.



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/cutlass/app.rb', line 18

def initialize(
  source_path_name,
  config: {},
  warn_io: $stderr,
  builder: Cutlass.default_builder,
  image_name: Cutlass.default_image_name,
  buildpacks: Cutlass.default_buildpack_paths,
  exception_on_failure: true
)
  @tmpdir = nil
  @source_path = nil

  @builds = []
  @on_teardown = []

  @config = config
  @warn_io = warn_io
  @builder = builder
  @image_name = image_name
  @buildpacks = Array(buildpacks).map { |buildpack| buildpack == :default ? Cutlass.default_buildpack_paths : buildpack }.flatten
  @source_path_name = source_path_name
  @exception_on_failure = exception_on_failure
end

Instance Attribute Details

#builderObject (readonly)

Returns the value of attribute builder.



16
17
18
# File 'lib/cutlass/app.rb', line 16

def builder
  @builder
end

#buildpacksObject (readonly)

Returns the value of attribute buildpacks.



16
17
18
# File 'lib/cutlass/app.rb', line 16

def buildpacks
  @buildpacks
end

#buildsObject (readonly)

Returns the value of attribute builds.



16
17
18
# File 'lib/cutlass/app.rb', line 16

def builds
  @builds
end

#configObject (readonly)

Returns the value of attribute config.



16
17
18
# File 'lib/cutlass/app.rb', line 16

def config
  @config
end

#exception_on_failureObject (readonly)

Returns the value of attribute exception_on_failure.



16
17
18
# File 'lib/cutlass/app.rb', line 16

def exception_on_failure
  @exception_on_failure
end

#image_nameObject (readonly)

Returns the value of attribute image_name.



16
17
18
# File 'lib/cutlass/app.rb', line 16

def image_name
  @image_name
end

#tmpdirObject (readonly)

Returns the value of attribute tmpdir.



16
17
18
# File 'lib/cutlass/app.rb', line 16

def tmpdir
  @tmpdir
end

Instance Method Details

#fail?Boolean

Returns:

  • (Boolean)


54
55
56
# File 'lib/cutlass/app.rb', line 54

def fail?
  last_build.fail?
end

#in_dirObject



133
134
135
136
137
138
139
140
141
142
143
# File 'lib/cutlass/app.rb', line 133

def in_dir
  Dir.mktmpdir do |dir|
    @tmpdir = Pathname(dir)

    FileUtils.copy_entry(source_path, @tmpdir)

    Dir.chdir(@tmpdir) do
      yield @tmpdir
    end
  end
end

#last_buildObject



58
59
60
61
62
# File 'lib/cutlass/app.rb', line 58

def last_build
  raise "You must `pack_build` first" if builds.empty?

  builds.last
end

#on_teardown(&block) ⇒ Object



171
172
173
# File 'lib/cutlass/app.rb', line 171

def on_teardown(&block)
  @on_teardown << block
end

#pack_build {|build| ... } ⇒ Object

Yields:

  • (build)


106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/cutlass/app.rb', line 106

def pack_build
  build = PackBuild.new(
    config: config,
    app_dir: @tmpdir,
    builder: builder,
    buildpacks: buildpacks,
    image_name: image_name,
    exception_on_failure: exception_on_failure
  )
  on_teardown { build.teardown }

  @builds << build
  build.call

  yield build if block_given?
end

#run(command, exception_on_failure: true) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/cutlass/app.rb', line 64

def run(command, exception_on_failure: true)
  command = docker_command(command)
  result = BashResult.run(command)

  raise(<<~EOM) if result.failed? && exception_on_failure
    Command "#{command}" failed

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

  result
end

#run_multi(command, exception_on_failure: true) ⇒ Object



83
84
85
86
87
88
89
90
91
# File 'lib/cutlass/app.rb', line 83

def run_multi(command, exception_on_failure: true)
  raise "No block given" unless block_given?

  thread = Thread.new do
    yield run(command, exception_on_failure: exception_on_failure)
  end

  on_teardown { thread.join }
end

#start_container(env: {}, expose_ports: [], memory: nil) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/cutlass/app.rb', line 93

def start_container(env: {}, expose_ports: [], memory: nil)
  raise "No block given" unless block_given?

  ContainerBoot.new(
    image_id: last_build.image_id,
    env: env,
    expose_ports: expose_ports,
    memory: memory
  ).call do |container|
    yield container
  end
end

#stderrObject



46
47
48
# File 'lib/cutlass/app.rb', line 46

def stderr
  last_build.stderr
end

#stdoutObject



42
43
44
# File 'lib/cutlass/app.rb', line 42

def stdout
  last_build.stdout
end

#success?Boolean

Returns:

  • (Boolean)


50
51
52
# File 'lib/cutlass/app.rb', line 50

def success?
  last_build.success?
end

#teardownObject



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/cutlass/app.rb', line 145

def teardown
  errors = []
  @on_teardown.reverse_each do |callback|
    # Attempt to run all teardown callbacks

    callback.call
  rescue => e
    errors << e

    @warn_io.puts <<~EOM

      Error in teardown #{callback.inspect}

      It will be raised after all teardown blocks have completed

      #{e.message}

      #{e.backtrace.join($/)}
    EOM
  end
ensure
  errors.each do |e|
    raise e
  end
end

#transactionObject



123
124
125
126
127
128
129
130
131
# File 'lib/cutlass/app.rb', line 123

def transaction
  raise "No block given" unless block_given?

  in_dir do
    yield self
  ensure
    teardown
  end
end