Current section
Files
Jump to
Current section
Files
src/generate_meta_file.erl
-module(generate_meta_file).
-export([
generate/2,
spawn_load_proto_file/5
]).
%% create proto.meta file
generate(AppInfo, State) ->
AppDir = rebar_app_info:dir(AppInfo),
DepsDir = rebar_dir:deps_dir(State),
Opts = rebar_app_info:opts(AppInfo),
{ok, ProtoOpts} = dict:find(proto_opts, Opts),
MetaFileName = proplists:get_value(o_meta_file, ProtoOpts, "proto.meta"),
MetaFile = filename:join([AppDir, MetaFileName]),
Meta = read_meta_file(MetaFile),
rebar_api:debug("proto load meta : ~p~n", [{Meta}]),
{ok, GpbOpts} = dict:find(gpb_opts, Opts),
FoundProtos = find_proto_files(AppDir, DepsDir, GpbOpts),
NewMeta = load_proto_file(Meta, FoundProtos, GpbOpts, AppDir),
rebar_api:debug("proto write meta : ~p~n", [{NewMeta}]),
write_meta_file(MetaFile, NewMeta),
{ok, NewMeta}.
%% load data to form meta
load_proto_file(Meta, ProtoList, GpbOpts, AppDir) ->
RefList = [begin
Ref = make_ref(),
spawn(?MODULE, spawn_load_proto_file, [self(), Ref, HProto, GpbOpts, AppDir]),
Ref
end || HProto <- ProtoList],
rebar_api:debug("prepare receive ~p", [RefList]),
receive_load_proto_file(RefList, Meta).
receive_load_proto_file([], Meta) ->
Meta;
receive_load_proto_file([Ref|T], Meta) ->
rebar_api:debug("receiving ~p", [Ref]),
receive
{RRef, Mod, MsgNameList} when Ref == RRef ->
NewMeta = load_msg(Mod, Meta, MsgNameList),
receive_load_proto_file(T, NewMeta)
end.
spawn_load_proto_file(From, Ref, HProto, GpbOpts, AppDir) ->
ProtoBaseName = filename:basename(HProto, ".proto"),
LoadFile = filename:join([AppDir, filename:rootname(get_target(HProto, GpbOpts), ".erl")]),
{_, Ohrl} = lists:keyfind(o_hrl, 1, GpbOpts), %% need to include gpb.hrl
LoadInclude = filename:join([AppDir, filename:rootname(Ohrl)]), %% compatible with absolute path
rebar_api:debug("load module file: ~p~n", [{LoadFile, LoadInclude}]),
{ok, Mod, Bin} = compile:file(LoadFile, [binary, {i, LoadInclude}]),
code:load_binary(Mod, [], Bin),
% Mod = list_to_atom(filename:basename(get_target(HProto, GpbOpts), ".erl")),
MsgNameList = Mod:get_msg_containment(ProtoBaseName),
From ! {Ref, Mod, MsgNameList}.
load_msg(_Mod, Meta, []) ->
Meta;
load_msg(Mod, Meta, [HMsg|T]) ->
#{code_count := CodeCount} = Meta,
NewMeta = case maps:is_key(HMsg, Meta) of
false ->
AccCodeCount = CodeCount + 1,
Meta#{ code_count := AccCodeCount,
HMsg => #{msg_code => AccCodeCount,
pb_module => Mod}};
_ ->
Meta
end,
load_msg(Mod, NewMeta, T).
%% read meta file
read_meta_file(MetaFile) ->
rebar_api:debug("read meta file: ~p~n", [MetaFile]),
case file:consult(MetaFile) of
{ok, [[CodeCount|RawMeta]]} ->
Map = #{code_count => CodeCount},
lists:foldl(fun({MsgName, MsgCode, PbModule}, AccMap) ->
AccMap#{MsgName => #{msg_code => MsgCode,
pb_module => PbModule}}
end, Map, RawMeta);
_ ->
#{code_count => 0}
end.
%% write meta file
write_meta_file(MetaFile, Meta) ->
{CodeCount, Meta0} = maps:take(code_count, Meta),
List0 = lists:keysort(1, [{MsgName, MsgCode, PbModule}
|| {MsgName, #{msg_code:=MsgCode, pb_module:=PbModule}} <- maps:to_list(Meta0)]),
ok = file:write_file(MetaFile, io_lib:format("~p.~n", [[CodeCount|List0]])).
%% copy from rebar3_gbp_plugin
discover(AppDir, SourceDir, Recursive) ->
%% Convert simple extension to proper regex
SourceExtRe = "^[^._].*\\" ++ ".proto" ++ [$$],
%% Find all possible source files
rebar_utils:find_files(filename:join([AppDir, SourceDir]),
SourceExtRe, Recursive).
%% copy from rebar3_gbp_plugin
find_proto_files(AppDir, DepsDir, GpbOpts) ->
%% check if non-recursive
Recursive = proplists:get_value(recursive, GpbOpts, true),
SourceDirs = proplists:get_all_values(i, GpbOpts),
FoundProtos = lists:foldl(fun({deps, SourceDir}, Acc) ->
Acc ++ discover(DepsDir, SourceDir, Recursive);
(SourceDir, Acc) ->
Acc ++ discover(AppDir, SourceDir, Recursive)
end, [], SourceDirs),
rebar_api:debug("proto files found~s: ~p",
[case Recursive of true -> " recursively"; false -> "" end, FoundProtos]),
FoundProtos.
%% copy from rebar3_gbp_plugin
get_target(Proto, GpbOpts) ->
InputsOutputs = gpb_compile:list_io(Proto, GpbOpts),
{erl_output, Erl} = lists:keyfind(erl_output, 1, InputsOutputs),
Erl.