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