defmodule Mix.Tasks.Arch.Explore.Xrefs do use Mix.Task alias Archeometer.Explore.Project @moduledoc """ Mix Task to analyze internal dependencies between modules and store them into a Archeometer database. Usage: mix arch.explore.xrefs [options] The following options are accepted: * `--include-deps` - Wildcard glob style to filter dependencies For more information see: [Basic usage guide](guides/introduction/basic_usage.md#include-dependencies-in-the-analysis) """ @shortdoc "Runs cross reference analysis" @impl Mix.Task def run(argv) do case get_args(argv) do {:error, error} -> Mix.shell().error("Error: #{error}") print_help() [ include_deps: deps_filter ] -> if Archeometer.Repo.db_ready?(:basic) do Mix.shell().info("Starting cross reference analysis..") xrefs = append_deps(deps_filter) |> Archeometer.Explore.XRef.compile_xrefs() Mix.shell().info("Saving cross references...") Archeometer.Util.DumpStats.save_xrefs(xrefs) Mix.shell().info("Done!") else Mix.shell().error("Please run static analysis first") end end end defp get_args(argv) do {opts, _args, invalid} = OptionParser.parse( argv, strict: [ include_deps: :keep ] ) case invalid do [] -> deps_filter = Keyword.get_values(opts, :include_deps) validate_options(deps_filter) _ -> {:error, :wrong_arguments} end end defp validate_options(deps_filter) do case Project.filter_deps(deps_filter) do [] -> {:error, "Filter doesn't match any dependency"} _ -> [ include_deps: deps_filter ] end end defp append_deps(deps_filter) do deps = Project.filter_deps(deps_filter) if deps, do: Keyword.keys(deps), else: [] end defp print_help() do Mix.shell().info(""" Usage: mix arch.explore.xrefs [opts] opts: --include-deps 'deps_filter' Where `deps_filter` is a glob Unix-like pattern, matches dependencies name. --include-deps can be used more than once. - `*` matches none or many tokens - `?` matches exactly one token - `[abc]` matches a set of tokens - `[a-z]` matches a range of tokens - `[!...]` matches anything but a set of tokens """) end end