Packages

Standalone command-line interface for hex.pm

Current section

Files

Jump to
hexer src hexer_deps.erl
Raw

src/hexer_deps.erl

%%% @doc Dependency management utilities.
%%% WARNING: This module is bound to erlang.mk
-module(hexer_deps).
-export([resolve/1]).
-type dep() :: { Name :: atom(), Version :: string()}.
-type requirement() :: { DepName :: atom(), Data :: [{binary(), any()}]}.
-export_type([requirement/0]).
%% @doc Given an app directory, resolves the app requirements.
-spec resolve(string()) -> [requirement()].
resolve(AppDir) ->
HexerMk = filename:join([AppDir, "hexer.mk"]),
try
create_hexer_mk(HexerMk),
Output = hexer_utils:cmd("cd " ++ AppDir ++ "; make -f hexer.mk list-deps"),
_ = hexer_utils:cmd("make deps"),
DepStrings =
[ string:tokens(DepLine, [$=])
|| DepLine <- string:tokens(Output, [$|, $\n])],
Deps = [create_dep_vsn_tuple(Dep, Fetch) || [Dep, Fetch] <- DepStrings],
ok = validate_hex_dependencies(Deps),
DepDirList = get_deps_dirs(AppDir),
[new_requeriment_meta(DepTuple, DepDirList) || DepTuple <- Deps]
after
_ = file:delete(HexerMk)
end.
create_hexer_mk(HexerMk) ->
Contents =
"include Makefile\n"
"\n"
"THE_DEPS = "
"$(foreach dep,"
"$(filter-out $(IGNORE_DEPS),$(DEPS)),"
"$(dep) = $(dep_$(dep))\\|)\n"
"\n"
"list-deps:\n"
"\t@echo $(THE_DEPS)\n",
ok = file:write_file(HexerMk, Contents).
-spec create_dep_vsn_tuple(string(), string()) ->
dep() | {no_hex_dependency, string()}.
create_dep_vsn_tuple(Dep, Fetch) ->
case string:tokens(Fetch, [$\s, $\t]) of
["hex", Version | _] -> {to_dep_atom(Dep), Version};
NonHexVersion -> {no_hex_dependency, string:join(NonHexVersion, " ")}
end.
to_dep_atom(Dep) ->
list_to_atom([Char || Char <- Dep, Char /= $\s]).
-spec validate_hex_dependencies([tuple()]) -> ok | {error, any()}.
validate_hex_dependencies(Deps) ->
case [{no_hex_dependency, Dep} || {no_hex_dependency, Dep} <- Deps] of
[] -> ok;
NoHexDeps ->
FormatedDeps = hexer_utils:format_deps(NoHexDeps),
Description = "Dependencies not published in hex.pm:~n ~s",
hexer_utils:error(Description, [FormatedDeps]),
throw({hexer_deps, no_hex_dependency})
end.
-spec new_requeriment_meta(dep(), list()) -> requirement().
new_requeriment_meta({DepName, Version}, DepDirList) ->
FunMatch = fun(X) -> filename:basename(X) == atom_to_list(DepName) end,
[DepPath] = lists:filter(FunMatch , DepDirList),
AppSrcPathRaw = filelib:wildcard([DepPath, "/src/*app.src"]),
AppSrcPath = string:tokens(AppSrcPathRaw, [$|, $\n]),
{ DepName,
%It's possible that DepName =/= AppName in app.src
[ {<<"app">> , get_real_app_name(AppSrcPath)}
, {<<"requirement">>, Version}
, {<<"optional">>, false}
]}.
get_real_app_name(AppSrcPath) ->
{ok, [MetaData]} = file:consult(AppSrcPath),
{ application, ApplicationName , _} = MetaData,
ApplicationName.
get_deps_dirs(AppDir) ->
PathMk = filename:join([AppDir, "allDepsDir.mk"]),
try
create_path_mk(PathMk),
Commands = ["cd ", AppDir, "; make -f allDepsDir.mk list-all-deps-dirs"],
Output = hexer_utils:cmd(Commands),
string:tokens(Output, [$\n, $\s, $\t])
after
_ = file:delete(PathMk)
end.
create_path_mk(PathMk) ->
Contents =
"include Makefile\n"
"\n"
"list-all-deps-dirs:\n"
"\t@echo $(ALL_DEPS_DIRS)\n",
ok = file:write_file(PathMk, Contents).