defmodule Mix.Tasks.Stevedore.Copy do @shortdoc "Copy an image between transports, preserving digests" @moduledoc """ Copy an image from one transport to another. mix stevedore.copy SRC DST [options] SRC and DST are transport-prefixed references (`docker://`, `oci:`, `oci-archive:`, `docker-archive:`, `dir:`, `static:`). ## Options * `--all` — copy a whole multi-arch index * `--platform os/arch` — select one platform from an index * `--format oci|docker` — convert the manifest format * `--scheme http|https` — registry scheme (default https) ## Examples mix stevedore.copy docker://alpine:3.20 oci:./alpine:3.20 mix stevedore.copy docker://alpine:3.20 docker://ghcr.io/me/alpine:3.20 --all """ use Mix.Task alias Stevedore.CLI @switches [all: :boolean, platform: :string, format: :string, scheme: :string] @impl true def run(argv) do {opts, args, _} = OptionParser.parse(argv, switches: @switches) case args do [src, dst] -> CLI.start_app() %{digest: digest} = CLI.unwrap!(Stevedore.copy(src, dst, copy_opts(opts))) Mix.shell().info(to_string(digest)) _ -> Mix.raise( "usage: mix stevedore.copy SRC DST [--all --platform os/arch --format oci|docker]" ) end end defp copy_opts(opts) do opts |> Keyword.take([:all, :platform, :scheme]) |> maybe_format(opts[:format]) end defp maybe_format(opts, nil), do: opts defp maybe_format(opts, "oci"), do: Keyword.put(opts, :format, :oci) defp maybe_format(opts, "docker"), do: Keyword.put(opts, :format, :docker) defp maybe_format(_opts, other), do: Mix.raise("unknown --format #{other} (use oci or docker)") end