defmodule Mix.Tasks.EzAuth.Install do @moduledoc """ Copies EzAuth migrations into the host application. Pass `--replace` to refresh existing EzAuth migration files in place. """ use Mix.Task @shortdoc "Copies EzAuth migrations into the host application" @impl true def run(args) do Mix.Task.run("app.config") {opts, _args} = OptionParser.parse!(args, strict: [replace: :boolean]) File.mkdir_p!(target_dir()) opts[:replace] |> copy_migrations() |> print_summary() end defp compile_template({source, index}, started_at) do name = migration_name(source) target = Path.join(target_dir(), "#{timestamp(started_at, index)}_#{name}") {target, EEx.eval_file(source, repo: EzAuth.Config.repo!())} end defp copy_migration({target, content}, replace?) do case existing_migration(target) do nil -> write_migration(target, content) path when replace? -> write_migration(path, content) path -> {:skip, path} end end defp copy_migrations(replace?) do started_at = DateTime.utc_now() source_migrations() |> Enum.with_index() |> Enum.map(&compile_template(&1, started_at)) |> Enum.map(©_migration(&1, replace?)) end defp existing_migration(target) do name = Regex.escape(migration_name(target)) pattern = Regex.compile!("^\\d{14}_#{name}$") target_dir() |> Path.join("*.exs") |> Path.wildcard() |> Enum.find(&(Path.basename(&1) =~ pattern)) end defp migration_name(path) do path |> Path.basename() |> String.replace(~r/^\d+_/, "") |> String.replace_suffix(".eex", "") end defp print_summary(results) do Enum.each(results, fn {:copy, path} -> Mix.shell().info("* copied #{Path.relative_to_cwd(path)}") {:skip, path} -> Mix.shell().info("* skipped #{Path.relative_to_cwd(path)}") end) end defp source_dir, do: Path.join(:code.priv_dir(:ez_auth), "templates/ez_auth.install") defp source_migrations do source_dir() |> Path.join("*.exs.eex") |> Path.wildcard() |> Enum.sort() end defp target_dir, do: Path.join(Mix.EctoSQL.source_repo_priv(EzAuth.Config.repo!()), "migrations") defp timestamp(datetime, offset) do datetime |> DateTime.add(offset, :second) |> Calendar.strftime("%Y%m%d%H%M%S") end defp write_migration(target, content) do File.write!(target, content) {:copy, target} end end