defmodule Mix.Tasks.Arch.Collect.Ecto do
@moduledoc """
Mix Task to collect information of Ecto schema modules and
their relationships.
Usage:
mix arch.collect.ecto [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 "Dumps ecto schemas and associations into Archeometer DB"
use Mix.Task
alias Archeometer.Collect.Ecto
alias Archeometer.Util.DumpStats
alias Archeometer.Collect.Project
@impl Mix.Task
def run(argv) do
case get_args(argv) do
[
include_deps: deps_filter
] ->
if Archeometer.Repo.db_ready?(:full) do
Mix.shell().info("Starting ecto schemas analysis...\n")
Mix.shell().info("Listing ecto schemas...")
schema_modules = Ecto.ecto_schemas(append_deps(deps_filter))
Mix.shell().info("Saving ecto schemas...")
schema_modules
|> Enum.map(&Macro.to_string/1)
|> DumpStats.add_ecto_schemas()
Ecto.clear_references()
Mix.shell().info("Saving ecto associations...")
schema_modules
|> Ecto.get_associations()
|> DumpStats.add_ecto_associations()
Mix.shell().info("Done!")
else
Mix.shell().error("Please run 'mix arch.collect' first")
print_help()
{:error, :no_static_analysis_found}
end
{:validate_error, error_type} ->
Mix.shell().error("Error: #{error_type}")
{:error, error_type}
{:error, error_type} ->
Mix.shell().error("Error: #{error_type}")
print_help()
{:error, error_type}
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
[] ->
{:validate_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.collect.ecto [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