Skip to main content

lib/mix/tasks/permit_ex.install.ex

defmodule Mix.Tasks.PermitEx.Install do
  @moduledoc """
  Installs PermitEx migrations into the host application.

      mix permit_ex.install
      mix permit_ex.install --migrations-path priv/repo/migrations
  """

  use Mix.Task

  @shortdoc "Copies PermitEx migrations"

  @switches [migrations_path: :string]

  @impl Mix.Task
  def run(args) do
    Mix.Project.get!()

    {opts, _} = OptionParser.parse!(args, strict: @switches)
    target_dir = Keyword.get(opts, :migrations_path, Path.join(["priv", "repo", "migrations"]))

    File.mkdir_p!(target_dir)

    case existing_migration(target_dir) do
      {:ok, path} ->
        Mix.shell().info("Migration already exists: #{path}")

      :none ->
        path = write_migration(target_dir)
        Mix.shell().info("Created #{path}")
        Mix.shell().info("Run `mix ecto.migrate` to apply it.")
    end
  end

  defp existing_migration(dir) do
    case Path.wildcard(Path.join(dir, "*_create_permit_ex_tables.exs")) do
      [path | _] -> {:ok, path}
      [] -> :none
    end
  end

  defp write_migration(dir) do
    filename = "#{timestamp()}_create_permit_ex_tables.exs"
    path = Path.join(dir, filename)
    module = "CreatePermitExTables"

    contents =
      template_path()
      |> File.read!()
      |> EEx.eval_string(module: module)

    File.write!(path, contents)
    Mix.Task.run("format", [path])
    path
  end

  defp template_path do
    :permit_ex
    |> :code.priv_dir()
    |> to_string()
    |> Path.join("templates/create_permit_ex_tables.exs")
  end

  defp timestamp do
    {{year, month, day}, {hour, minute, second}} = :calendar.universal_time()

    [year, month, day, hour, minute, second]
    |> Enum.map_join(&(&1 |> Integer.to_string() |> String.pad_leading(2, "0")))
  end
end