Packages

A toolkit to work with umbrella projects

Current section

Files

Jump to
brolly lib mix tasks brolly.tree.ex
Raw

lib/mix/tasks/brolly.tree.ex

defmodule Mix.Tasks.Brolly.Tree do
use Mix.Task
@shortdoc "Prints the dependency tree for the umbrella project"
@switches [base_dir: :string, reverse: :boolean, format: :string]
@aliases [b: :base_dir, r: :reverse, f: :format]
@default_opts [base_dir: ".", reverse: false, format: "plain"]
@plain_indent 4
def run(args) do
{opts, args, _} = OptionParser.parse(args, aliases: @aliases, switches: @switches)
opts = Keyword.merge(@default_opts, opts)
project = case args do
[] -> nil
[project_name] -> String.to_atom(project_name)
end
dep_tree = dep_tree(project, opts)
case opts[:format] do
"plain" ->
formatted_deps = plain_format_deps(dep_tree, @plain_indent, [])
[project | formatted_deps]
|> Enum.join("\n")
|> Mix.shell().info()
"dot" ->
formatted_deps = dot_format_deps(dep_tree, nil, [])
content =
[~s(digraph "dependency tree" {), formatted_deps, "}"]
|> List.flatten()
|> Enum.join("\n")
File.write!("brolly_tree.dot", content)
"""
Generated "brolly_tree.dot" in the current directory.
To generate a PNG:
dot -Tpng brolly_tree.dot -o brolly_tree.png
For more options see http://www.graphviz.org/.
"""
|> String.trim_trailing()
|> Mix.shell().info()
end
end
defp dep_tree(app, opts), do: dep_tree(app, opts[:reverse], opts[:base_dir])
defp dep_tree(app, true, base_dir), do: Brolly.reverse_dep_tree!(app, base_dir)
defp dep_tree(app, false, base_dir), do: Brolly.dep_tree!(app, base_dir)
defp plain_format_deps([], _, acc), do: acc
defp plain_format_deps([{dep, deps} | tail], depth, acc) do
dep_list = [
"#{String.duplicate(" ", depth)}#{dep}" |
plain_format_deps(deps, depth + @plain_indent, [])
]
plain_format_deps(tail, depth, dep_list ++ acc)
end
defp plain_format_deps([dep | tail], depth, acc) do
plain_format_deps(tail, depth, ["#{String.duplicate(" ", depth)}#{dep}" | acc])
end
defp dot_format_deps([], _, acc), do: acc |> Enum.sort() |> Enum.dedup()
defp dot_format_deps([{dep, deps} | tail], from, acc) do
dep_list = [
dot_line(dep, from) |
dot_format_deps(deps, dep, [])
]
dot_format_deps(tail, nil, dep_list ++ acc)
end
defp dot_format_deps([dep | tail], from, acc) do
dot_format_deps(tail, from, [dot_line(dep, from) | acc])
end
defp dot_line(dep, nil), do: ~s( "#{dep}")
defp dot_line(dep, from), do: ~s( "#{from}" -> "#{dep}")
end