defmodule Mix.Tasks.Arch.Apps.Xref do
@moduledoc """
Mix Task to generate a dependency graph for the applications within an umbrella.
Usage:
mix arch.apps.xref [options]
The following options are accepted:
* `--format` - Can be one of `dot`, `png` or `svg`
* `--out` - Output filename
"""
@shortdoc "Generates a dependency graph of applications"
require Logger
require EEx
use Mix.Task
@supported_formats ["png", "dot", "mermaid", "svg"]
@impl Mix.Task
def run(argv) do
case parse_args(argv) do
{:ok, [format: format, out: out_file, db: db]} ->
Archeometer.Analysis.Apps.Xref.gen_graph(format, db)
|> write(out_file)
Mix.shell().info("Graph ready at: '#{out_file}'")
{:error, error} ->
Mix.shell().error("Error: #{error}")
print_help()
end
end
defp parse_args(argv) do
{opts, _, invalid_switches} =
OptionParser.parse(
argv,
strict: [
format: :string,
out: :string,
db: :string
]
)
case invalid_switches do
[] ->
format = Keyword.get(opts, :format, "dot")
out_fname = Keyword.get(opts, :out, "console")
db_name = Keyword.get(opts, :db, Archeometer.Repo.default_db_name())
case validate_options(%{format: format, out: out_fname, db: db_name}) do
:ok ->
{:ok,
[
format: format,
out: out_fname,
db: db_name
]}
{:error, error} ->
{:error, error}
end
_ ->
{:error, :wrong_arguments}
end
end
defp validate_options(%{format: format, out: out_fname, db: db_name}) do
cond do
not Archeometer.Repo.db_ready?(:full, db_name) ->
{:error, "Database is not existent or doesn't have the required tables."}
format not in @supported_formats ->
{:error, :unsupported_output_format}
format == "png" and out_fname == "console" ->
{:error, :png_not_writable_to_console}
true ->
:ok
end
end
defp print_help() do
Mix.shell().info("""
Usage: mix arch.apps.xref [opts]
opts: --format (dot, png), --out out_fname
""")
end
defp write(content, "console") do
Mix.shell().info(content)
end
defp write(content, out_fname) do
File.write!(out_fname, content)
end
end