Current section
Files
Jump to
Current section
Files
lib/mix/tasks/archeometer.report.html.ex
defmodule Mix.Tasks.Arch.Report.Html do
@moduledoc """
Mix Task to generate a static HTML report.
Usage:
mix arch.report.html [options]
Options:
* `--limit` - Restricts the maximum number of items in the queries displayed in the report, Default is 10.
For more information see:
[Basic usage guide](guides/introduction/basic_usage.md#include-dependencies-in-the-analysis)
Report is generated at `reports/dev/static/html`.
"""
@shortdoc "Generates a code analysis HTML report"
require Logger
require EEx
use Mix.Task
use Archeometer.Repo
import Archeometer.Query
alias Archeometer.Reports.PageDefinition
alias Archeometer.Reports.Page
alias Archeometer.Reports.Render
alias Archeometer.Reports.Config
alias Archeometer.Schema.Application
@impl Mix.Task
def run(argv) do
prepare_paths()
copy_assets()
apps_in_db =
Archeometer.Repo.all(
from(a in Application,
select: [name: a.name]
)
)
|> Map.get(:rows)
|> List.flatten()
case parse_args(argv) do
{:ok, args} ->
_run(args, apps_in_db)
copy_images()
Mix.shell().info("HTML report ready at '#{report_path(:html)}'")
{:error, error} ->
Mix.shell().error("Error: #{inspect(error)}")
print_help()
end
end
defp _run(args, [app]) do
create_app_page(app, args)
end
@index_page_name :index
defp _run(args, apps_in_db) do
page_names = [to_string(@index_page_name) | apps_in_db]
project_apps =
Archeometer.Explore.Project.apps()
|> Enum.map(&to_string/1)
extra_deps = Enum.filter(apps_in_db, &(&1 not in project_apps))
@index_page_name
|> to_string()
|> PageDefinition.Project.definition()
|> create_page(page_names, limit: args.limit, extra_deps: extra_deps)
apps_in_db
|> Enum.each(&create_app_page(&1, args, page_names))
end
defp create_app_page(app, args, page_names \\ []) do
app
|> to_string()
|> PageDefinition.Application.definition()
|> create_page(page_names, limit: args.limit)
end
defp create_page(%Page.Definition{} = page_def, page_names, opts) do
page_fname = page_def.id
limit = Keyword.get(opts, :limit, 10)
extra_deps = Keyword.get(opts, :extra_deps, [])
page_def
|> render_page(page_names, app: page_def.id, limit: limit, extra_deps: extra_deps)
|> write_to_file(page_fname <> ".html")
end
defp render_page(%Page.Definition{} = page_def, page_names, bindings) do
page_def
|> Page.process(bindings, default_db_name())
|> Render.Html.render(page_names)
end
defp write_to_file(str, fname) do
path = Path.expand(fname, report_path(:html))
File.write!(path, str)
end
defp prepare_paths() do
report_path = report_path(:html)
[
Path.expand("img/", report_path),
Path.expand("js/", report_path),
Path.expand("css/", report_path)
]
|> Enum.each(fn path -> File.mkdir_p!(path) end)
report_path(:img) |> File.mkdir_p!()
end
defp copy_assets() do
template_base_path = Archeometer.Util.PathHelper.template_path("report")
report_path = report_path(:html)
["css", "js"]
|> Enum.each(fn subdir ->
src_path = Path.expand(subdir, template_base_path)
dest_path = Path.expand(subdir, report_path)
File.cp_r!(src_path, dest_path)
end)
end
defp copy_images() do
src_path = report_path(:img)
report_path = report_path(:html)
dest_path = Path.expand("img", report_path)
File.cp_r!(src_path, dest_path)
end
defp report_path(:html), do: Config.report_path(:html)
defp report_path(:img), do: Config.report_path(:img)
defp parse_args(argv) do
{opts, _data, invalid_switches} =
OptionParser.parse(
argv,
strict: [limit: :integer]
)
case invalid_switches do
[] ->
limit = Keyword.get(opts, :limit, 10)
validate_options(limit)
_ ->
{:error, :wrong_argument}
end
end
defp validate_options(limit) do
if limit <= 0 do
{:error, :invalid_limit}
else
{:ok, %{limit: limit}}
end
end
defp print_help() do
Mix.shell().info("""
Usage: mix arch.report.html [opts]
opts: --limit 'integer'
""")
end
end