Skip to main content

lib/host_kit/resources/source.ex

defmodule HostKit.Resources.Source do
  @moduledoc "Desired source checkout. Git is the first supported backend."

  @type type :: :git
  @type ref_kind :: :branch | :tag | :revision | :unknown
  @type dirty_policy :: :error | :reset | :ignore

  @type t :: %__MODULE__{
          name: atom() | String.t(),
          type: type(),
          uri: String.t(),
          ref: String.t(),
          ref_kind: ref_kind(),
          revision: String.t() | nil,
          checkout: String.t(),
          path: String.t(),
          dirty: dirty_policy(),
          depends_on: [term()],
          meta: map()
        }

  defstruct name: nil,
            type: :git,
            uri: nil,
            ref: "HEAD",
            ref_kind: :unknown,
            revision: nil,
            checkout: nil,
            path: ".",
            dirty: :error,
            depends_on: [],
            meta: %{}

  @spec new(atom() | String.t(), keyword()) :: t()
  def new(name, opts) do
    %__MODULE__{
      name: name,
      type: :git,
      uri: uri!(opts),
      ref: opts |> Keyword.get(:ref, "HEAD") |> to_string(),
      checkout: Keyword.fetch!(opts, :checkout),
      path: opts |> Keyword.get(:path, ".") |> to_string(),
      dirty: Keyword.get(opts, :dirty, :error),
      depends_on: Keyword.get(opts, :depends_on, []),
      meta: Keyword.get(opts, :meta, %{})
    }
  end

  def id(%__MODULE__{name: name}), do: {:source, name}

  def app_path(%__MODULE__{checkout: checkout, path: "."}), do: checkout
  def app_path(%__MODULE__{checkout: checkout, path: path}), do: Path.join(checkout, path)

  def identity(%__MODULE__{} = source) do
    %HostKit.Source.Identity{
      type: source.type,
      uri: source.uri,
      ref: source.ref,
      ref_kind: source.ref_kind,
      revision: source.revision,
      tree: Map.get(source.meta, :tree),
      checkout: source.checkout,
      path: source.path
    }
  end

  defp uri!(opts) do
    cond do
      uri = Keyword.get(opts, :git) -> uri
      uri = Keyword.get(opts, :url) -> uri
      github = Keyword.get(opts, :github) -> "https://github.com/#{github}.git"
      true -> raise ArgumentError, "source expects :git, :url, or :github"
    end
  end
end