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
# NOTE: This function really needs some refactoring once the functionality is deemed to be OK!
cfg = Mix.Project.config
app = cfg[:app]
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_image = cfg[:build_image] || "msaraiva/elixir-dev:#{elixir_version}"
tag = "#{docker_repo}/#{app}:#{calculate_version(args)}"
cwd = System.cwd
{_, 0} = System.cmd("rm", ["-rf", "rel/#{app}"], into: IO.stream(:stdio, :line))
# To be sure, but not doing this also seems to break the release config reading
# as the app spec can't be found.
Mix.Task.run("compile")
release_config = Mix.Releases.Config.read!("rel/config.exs")
environments_to_build = release_config.environments |> Map.keys
# Build the deployment tarballs with distillery under Docker.
# We need to make sure that we clean out native stuff in case they
# transfer from host to target system.
Enum.map(environments_to_build, fn(env) ->
build_args = ["run", "-v", "#{cwd}:#{cwd}", "-e", "MIX_ENV=#{env}", build_image,
"sh", "-c",
"cd #{cwd}; set -evx; mix deps.get; find . -name '*.so' -o -name '*.o' | xargs rm -f; mix do deps.compile, release; echo -e '\\0033\\0143'"]
{_, 0} = System.cmd("docker", build_args, into: IO.stream(:stdio, :line))
end)
# Get the tarballs we just built and feed them and some assorted
# stuff to the Dockerfile template.
release_path = "rel/#{app}/releases/"
base_version = String.replace(cfg[:version], "-#{Mix.env}", "")
{:ok, entries} = File.ls(release_path)
release_tars = entries
|> Enum.filter(fn(e) -> String.starts_with?(e, base_version) end)
|> Enum.map(fn(e) -> release_path <> e <> "/#{app}.tar.gz" end)
add_dist_tars = "ADD " <> Enum.join(release_tars, " ") <> " #{app}/"
cmd_for_mix_env = "/#{app}/releases/#{base_version}-${MIX_ENV}/#{app}.sh"
docker_file = EEx.eval_file(System.cwd <> "/Dockerfile.deploy.eex", [
add_dist_tars: add_dist_tars,
cmd_for_mix_env: cmd_for_mix_env])
File.write!("Dockerfile", docker_file)
# Build/tag and push the deployment docker file
{_, 0} = System.cmd("docker", ["build", "-t", tag, "."], into: IO.stream(:stdio, :line))
{_, 0} = System.cmd("docker", ["push", tag], into: IO.stream(:stdio, :line))
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
end