defmodule Mix.Tasks.Arch.Report do
@moduledoc """
Mix Task to generate a project analysis report. The format of the report
can be static html pages or [Livebook](https://livebook.dev/) notebooks.
Usage:
mix arch.report [options]
Options:
* `--format` - Report format. Supported formats are `html` and `livemd`.
Default is `html`.
* `--limit` - Restricts the maximum number of results displayed from the
queries in the report, Default is 10.
* `--db` - Database filename
For more information see:
[Basic usage guide](guides/introduction/basic_usage.md)
Report is generated at `reports/dev/static/html`.
"""
@shortdoc "Generates an analysis report for the project"
@supported_formats ~w(html livemd)
require Logger
require EEx
use Mix.Task
use Archeometer.Repo
import Archeometer.Query
import Archeometer.Reports.Utils
@impl Mix.Task
def run(argv) do
case parse_args(argv) do
{:ok, %{format: format, limit: limit, db_name: db_name}} ->
cfg = %{
modules: apps(db_name),
root_page_def: &Archeometer.Reports.PageDefinition.Project.definition/1,
module_page_def: &Archeometer.Reports.PageDefinition.Application.definition/1,
renderer: Archeometer.Reports.Render.Html,
db_name: db_name,
limit: limit
}
case format do
"html" ->
Archeometer.Reports.Generator.generate(cfg)
Mix.shell().info("HTML report ready at '#{report_path(:html)}'")
"livemd" ->
Archeometer.Reports.LiveBookGenerator.generate(cfg)
Mix.shell().info("Livebook report ready at '#{report_path(:livemd)}'")
end
{:error, error} ->
Mix.shell().error("Error: #{inspect(error)}")
print_help()
end
end
defp apps(db_name) do
Archeometer.Repo.all(
from(a in Archeometer.Schema.App,
select: [name: a.name]
),
[],
db_name
)
|> Map.get(:rows)
|> List.flatten()
end
defp parse_args(argv) do
{opts, _data, invalid_switches} =
OptionParser.parse(
argv,
strict: [
format: :string,
limit: :integer,
db: :string
]
)
case invalid_switches do
[] ->
format = Keyword.get(opts, :format, "html")
limit = Keyword.get(opts, :limit, 10)
db_name = Keyword.get(opts, :db, default_db_name())
validate_options(format, limit, db_name)
_ ->
{:error, :wrong_argument}
end
end
defp validate_options(format, limit, db_name) do
cond do
format not in @supported_formats ->
{:error, :invalid_format}
limit <= 0 ->
{:error, :invalid_limit}
not Archeometer.Repo.db_ready?(:full, db_name) ->
{:error, "Database is not existent or doesn't have the required tables."}
true ->
{:ok, %{format: format, limit: limit, db_name: db_name}}
end
end
defp print_help() do
Mix.shell().info("""
Usage: mix arch.report [opts]
opts: --format format (html) --limit 'integer' --db db_file_name
""")
end
end