Current section

Files

Jump to
docker_distiller lib mix tasks publish.ex
Raw

lib/mix/tasks/publish.ex

defmodule Mix.Tasks.Publish do
@shortdoc "Build a docker image, tag it with app name and version, and publish it"
use Mix.Task
def run(args) do
cfg = Mix.Project.config
app = cfg[:app]
version = cfg[:version]
docker_repo = cfg[:docker_repo]
docker_repo != nil or raise ":docker_repo must be set in mix.exs. This is to protect against accidentally publishing in public repos"
elixir_version = System.version
build_dockerfile = cfg[:build_dockerfile] || nil
path_in_container = cfg[:path_in_container] || "/opt/app/"
hex_dir = System.get_env("HOME") <> "/.hex"
if build_dockerfile != nil and cfg[:build_image] != nil do
raise "Only specify one of 'build_dockerfile' or 'build_image'"
end
# Optionally allow users to use a local dockerfile as the build_image
build_image =
if build_dockerfile do
build_image_tag = "docker_distiller_build_image"
{_, 0} = System.cmd("docker", ["build", "-t", build_image_tag, "-f", build_dockerfile, "."], into: IO.stream(:stdio, :line))
build_image_tag
else
cfg[:build_image] || "bitwalker/alpine-elixir:#{elixir_version}"
end
tag = "#{docker_repo}/#{app}:#{calculate_version(args)}"
cwd = System.cwd
run_cmd("rm", ["-rf", "deps", "_build"])
run_cmd("mix", ["deps.get"])
build_args = ["run",
"-v", "#{cwd}:#{cwd}",
"-v", "#{hex_dir}:/root/.hex",
"-e", "MIX_ENV=deploy",
build_image,
"sh", "-c",
"cd #{cwd}; set -evx; find . -name '*.so' -o -name '*.o' | xargs rm -f; mix compile; mix release"]
run_cmd("docker", build_args)
# Get the tarball we just built and feed it and some assorted
# stuff to the Dockerfile template.
dist_tar = "_build/deploy/rel/#{app}/releases/#{version}/#{app}.tar.gz"
add_dist_tar = "ADD #{dist_tar} #{path_in_container}#{app}/"
cmd_to_run = "#{path_in_container}#{app}/bin/#{app}"
docker_file = EEx.eval_file(System.cwd <> "/Dockerfile.deploy.eex", [
add_dist_tar: add_dist_tar,
cmd_to_run: cmd_to_run])
File.write!("Dockerfile", docker_file)
# Build/tag and push the deployment docker file
run_cmd("docker", ["build", "-t", tag, "."])
run_cmd("docker", ["push", tag])
end
@spec calculate_version([String.t]) :: String.t
def calculate_version(args) do
{opts, _, _ } = OptionParser.parse(
args,
switches: [
tag_version: :string,
]
)
case opts[:tag_version] do
nil ->
{rev, 0} = System.cmd("git", ["rev-parse", "--short", "HEAD"])
String.replace_trailing(rev, "\n", "")
v -> v
end
end
def run_cmd(cmd, args) do
IO.puts("Running: #{cmd} with #{inspect args}")
{_, 0} = System.cmd(cmd, args, into: IO.stream(:stdio, :line))
end
end