defmodule Mix.Tasks.HostKit.Instance do @moduledoc """ Manages lifecycle for a declared HostKit instance. This task is backend-neutral at the CLI boundary: it loads an `instance` declaration, then delegates to the instance's declared backend. Backend-specific operational knobs stay in backend configuration or environment. """ use Mix.Task @shortdoc "Manage a declared HostKit instance" @impl true def run(args) do Mix.Task.run("app.start") {opts, positional} = OptionParser.parse!(args, strict: [ require: :keep ] ) case positional do [command, name | rest] when command in ["status", "ensure", "destroy"] -> path = List.first(rest) || "infra/config.exs" project = HostKit.load!(path, require: Keyword.get_values(opts, :require)) instance = fetch_instance!(project, name) run_command(command, instance) _other -> Mix.raise("expected: mix host_kit.instance status|ensure|destroy INSTANCE [config.exs]") end end defp fetch_instance!(project, name) do case HostKit.Project.fetch_instance(project, name) do {:ok, instance} -> instance :error -> Mix.raise("instance #{inspect(name)} is not declared in #{inspect(project.name)}") end end defp run_command("status", instance) do case HostKit.Instance.Backend.read(instance, []) do {:ok, %HostKit.Instance{} = actual} -> IO.puts("present #{format_instance(actual)}") {:ok, nil} -> IO.puts("absent #{format_instance(instance)}") {:error, reason} -> Mix.raise("could not read instance #{instance.name}: #{inspect(reason)}") end end defp run_command("ensure", instance) do case HostKit.Instance.Backend.apply(instance, []) do :ok -> IO.puts("ensured #{format_instance(instance)}") {:error, reason} -> Mix.raise("could not ensure instance #{instance.name}: #{inspect(reason)}") end end defp run_command("destroy", instance) do case HostKit.Instance.Backend.delete(instance, []) do :ok -> IO.puts("destroyed #{format_instance(instance)}") {:error, reason} -> Mix.raise("could not destroy instance #{instance.name}: #{inspect(reason)}") end end defp format_instance(%HostKit.Instance{} = instance) do "#{instance.name} backend=#{instance.backend || "none"} lifecycle=#{instance.lifecycle}" end end