blob: 80c7a4b1eac29a7eb488b2003f7e3b5e55bcfbec [file] [log] [blame]
#!/usr/bin/env escript
%% -*- erlang -*-
%%% Run with 'escript app_deps.erl'
%%% Change the path in filelib:wildcard/1 as required to capture
%%% all your dependencies.
%%%
%%% Rectangular nodes will represent library apps (no processes
%%% involved) and the circular nodes will represent regular apps.
%%% An arrow going from 'A -> B' means 'A depends on B'.
%%%
%%% This script depends on graphviz being present on the system.
-module(app_deps).
-export([main/1]).
main(_) ->
AppFiles = filelib:wildcard("deps/*/ebin/*.app")
++
filelib:wildcard("apps/*/ebin/*.app")
++
filelib:wildcard("ebin/*.app")
++
filelib:wildcard("_build/default/lib/*/ebin/*.app"),
to_graphviz(read_deps(AppFiles)).
read_deps(AppFiles) ->
[{App,
proplists:get_value(applications, Props, []),
apptype(Props)}
|| {ok, [{_,App,Props}]} <-
[file:consult(AppFile) || AppFile <- AppFiles]].
apptype(Props) ->
case proplists:get_value(mod, Props) of
undefined -> library;
_ -> regular
end.
to_graphviz(Deps) ->
AllApps = lists:usort(lists:flatten(
[[{App,Type},DepList] || {App,DepList,Type} <- Deps]
)),
Bytes = ["digraph G { ",
"K=0.25; ratio=0.75; overlap=\"9:prism\"; ",
[io_lib:format("~p [shape=box] ", [App])
|| App <- libapps(AllApps -- [kernel,stdlib])],
[[io_lib:format("~p->~p ", [App,Dep])
|| Dep <- DepList -- [kernel, stdlib]]
|| {App, DepList, _} <- Deps],
"}"],
file:write_file("app-deps.dot", Bytes),
os:cmd("dot app-deps.dot -Tpng -o app-deps.png").
libapps([]) -> [];
libapps([{App,library}|Apps]) -> [App|libapps(Apps)];
libapps([{_,_}|Apps]) -> libapps(Apps);
libapps([App|Apps]) ->
Dir = case code:lib_dir(App) of
{error, _} -> ""; % not an OTP app
DirPath -> DirPath
end,
Path = filename:join([Dir, "ebin", atom_to_list(App)++".app"]),
case lists:prefix(code:lib_dir(), Path) of
false ->
[App|libapps(Apps)]; % not OTP app, we don't care
true -> % deps of OTP deps: we don't care either.
{ok, [{_,App,Props}]} = file:consult(Path),
case apptype(Props) of
library -> [App | libapps(Apps)];
regular -> libapps(Apps)
end
end.