Current section
Files
Jump to
Current section
Files
lib/mix/tasks/build_release.ex
defmodule Mix.Tasks.Build.Release do
use Mix.Task
@shortdoc "build a tar.gz release in a container and then copy into the current directory"
def run(args) do
unless File.exists?("./Dockerfile") do
Mix.shell().error(
"No Dockerfile found, please create one before using mix build.release. You can find examples in the README at https://github.com/shareup/build_release#readme"
)
Kernel.exit({:shutdown, 1})
end
{app, version} = app_and_version()
tag = "#{app}:#{version}"
name = "#{app}_#{version}"
file = "#{name}.tar.gz"
with :ok <- cmd("docker image build -t #{tag} ."),
:ok <- cmd("docker container run -dit --rm --name #{name} #{tag}"),
:ok <- cmd("docker cp #{name}:/release.tar.gz ./#{file}") do
cleanup(tag, name, args)
Mix.shell().info("\n\nCopied file #{file} to .")
else
{:error, code} ->
Mix.shell().error("\n\nDocker command failed (#{code}). Trying to cleanup...\n\n")
cleanup(tag, name, args)
end
end
defp cleanup(tag, name, args) do
cmd("docker container stop #{name}")
cmd("docker container rm #{name}")
if Enum.member?(args, "--cleanup-image") do
cmd("docker image rm #{tag}")
end
end
@spec cmd(String.t(), keyword) :: :ok | {:error, integer}
defp cmd(string, opts \\ []) do
case Mix.shell().cmd(string, opts) do
0 -> :ok
code -> {:error, code}
end
end
@spec app_and_version() :: {term, String.t()} | no_return
@spec app_and_version(keyword) :: {term, String.t()} | no_return
defp app_and_version,
do: app_and_version(Mix.Project.get().project())
defp app_and_version(project) do
with {:ok, app} <- Keyword.fetch(project, :app),
{:ok, version} <- Keyword.fetch(project, :version) do
{app, version}
else
:error ->
raise "Could not determine the app and/or version of this project"
end
end
end