Skip to main content

lib/mix/tasks/git_hoox.install.ex

defmodule Mix.Tasks.GitHoox.Install do
  @shortdoc "Install git_hoox shims into .git/hooks/"

  @moduledoc """
  Install git_hoox shims.

      mix git_hoox.install              # refuse if user hook exists
      mix git_hoox.install --force      # backup + overwrite shims (and config)
      mix git_hoox.install --dry-run    # plan only, write nothing
      mix git_hoox.install --scaffold   # also write a starter .git_hoox.exs

  Detects `core.hooksPath` and worktrees via `git rev-parse --git-path hooks`.
  """

  use Mix.Task

  @switches [force: :boolean, dry_run: :boolean, scaffold: :boolean]
  @aliases [f: :force, n: :dry_run, s: :scaffold]

  @impl Mix.Task
  @spec run([String.t()]) :: :ok
  def run(argv) do
    {opts, _, _} = OptionParser.parse(argv, switches: @switches, aliases: @aliases)

    case GitHoox.Installer.install(opts) do
      {:ok, plan} ->
        report(plan, opts)
        maybe_scaffold(opts)
        :ok

      {:error, reason} ->
        Mix.raise(format_error(reason))
    end
  end

  defp report(plan, opts) do
    if Keyword.get(opts, :dry_run, false) do
      Enum.each(plan, &print_plan_entry/1)
    else
      Mix.shell().info("git_hoox installed (#{length(plan)} shims)")
    end

    :ok
  end

  defp print_plan_entry({_hook, path, action}) do
    Mix.shell().info("[#{action}] #{path}")
  end

  defp maybe_scaffold(opts) do
    cond do
      not Keyword.get(opts, :scaffold, false) ->
        :ok

      Keyword.get(opts, :dry_run, false) ->
        Mix.shell().info("[scaffold] .git_hoox.exs (dry-run, not written)")
        :ok

      true ->
        case GitHoox.Installer.scaffold(opts) do
          {:ok, path} ->
            Mix.shell().info("git_hoox: wrote #{path}")

          {:error, {:config_exists, path}} ->
            Mix.shell().error("git_hoox: #{path} already exists. Re-run with --force to overwrite.")
        end
    end
  end

  defp format_error({:exists, path, msg}), do: "#{msg}\n  #{path}"
  defp format_error(other), do: "git_hoox install failed: #{inspect(other)}"
end