2021-12-27 19:09:21 +00:00
|
|
|
-module(rebar_compiler_mib).
|
|
|
|
|
|
|
|
-behaviour(rebar_compiler).
|
|
|
|
|
|
|
|
-export([context/1,
|
|
|
|
needed_files/4,
|
|
|
|
dependencies/3,
|
|
|
|
compile/4,
|
|
|
|
clean/2]).
|
|
|
|
|
|
|
|
-include("rebar.hrl").
|
|
|
|
-include_lib("stdlib/include/erl_compile.hrl").
|
|
|
|
|
|
|
|
context(AppInfo) ->
|
|
|
|
Dir = rebar_app_info:dir(AppInfo),
|
|
|
|
Mappings = [{".bin", filename:join([Dir, "priv", "mibs"])},
|
|
|
|
{".hrl", filename:join(Dir, "include")}],
|
|
|
|
|
|
|
|
#{src_dirs => ["mibs"],
|
|
|
|
include_dirs => [],
|
|
|
|
src_ext => ".mib",
|
|
|
|
out_mappings => Mappings}.
|
|
|
|
|
|
|
|
needed_files(_, FoundFiles, _, AppInfo) ->
|
|
|
|
RebarOpts = rebar_app_info:opts(AppInfo),
|
|
|
|
MibFirstConf = rebar_opts:get(RebarOpts, mib_first_files, []),
|
|
|
|
valid_mib_first_conf(MibFirstConf),
|
|
|
|
Dir = rebar_app_info:dir(AppInfo),
|
|
|
|
MibFirstFiles = [filename:join(Dir, File) || File <- MibFirstConf],
|
|
|
|
|
|
|
|
%% Remove first files from found files
|
|
|
|
RestFiles = [Source || Source <- FoundFiles, not lists:member(Source, MibFirstFiles)],
|
|
|
|
|
|
|
|
Opts = rebar_opts:get(rebar_app_info:opts(AppInfo), mib_opts, []),
|
|
|
|
{{MibFirstFiles, Opts}, {RestFiles, Opts}}.
|
|
|
|
|
|
|
|
valid_mib_first_conf(FileList) ->
|
|
|
|
Strs = filter_file_list(FileList),
|
|
|
|
case rebar_utils:is_list_of_strings(Strs) of
|
|
|
|
true -> true;
|
|
|
|
false -> ?ABORT("An invalid file list (~p) was provided as part of your mib_first_files directive",
|
|
|
|
[FileList])
|
|
|
|
end.
|
|
|
|
|
|
|
|
filter_file_list(FileList) ->
|
|
|
|
Atoms = lists:filter( fun(X) -> is_atom(X) end, FileList),
|
|
|
|
case Atoms of
|
|
|
|
[] ->
|
|
|
|
FileList;
|
|
|
|
_ ->
|
|
|
|
atoms_in_mib_first_files_warning(Atoms),
|
|
|
|
lists:filter( fun(X) -> not(is_atom(X)) end, FileList)
|
|
|
|
end.
|
|
|
|
|
|
|
|
atoms_in_mib_first_files_warning(Atoms) ->
|
|
|
|
W = "You have provided atoms as file entries in mib_first_files; "
|
|
|
|
"mib_first_files only expects lists of filenames as strings. "
|
|
|
|
"The following MIBs (~p) may not work as expected and it is advised "
|
2022-01-08 14:36:34 +00:00
|
|
|
"that you change these entries to string format "
|
2021-12-27 19:09:21 +00:00
|
|
|
"(e.g., \"mibs/SOME-MIB.mib\") ",
|
|
|
|
?WARN(W, [Atoms]).
|
|
|
|
|
|
|
|
|
|
|
|
dependencies(File, _Dir, SrcDirs) ->
|
|
|
|
SrcFiles = lists:append([src_files(SrcDir) || SrcDir <- SrcDirs]),
|
|
|
|
file_deps(File, SrcFiles).
|
|
|
|
|
|
|
|
compile(Source, OutDirs, _, Opts) ->
|
|
|
|
{_, BinOut} = lists:keyfind(".bin", 1, OutDirs),
|
|
|
|
{_, HrlOut} = lists:keyfind(".hrl", 1, OutDirs),
|
|
|
|
|
|
|
|
ok = rebar_file_utils:ensure_dir(BinOut),
|
|
|
|
ok = rebar_file_utils:ensure_dir(HrlOut),
|
|
|
|
Mib = filename:join(BinOut, filename:basename(Source, ".mib")),
|
|
|
|
HrlFilename = Mib ++ ".hrl",
|
|
|
|
|
|
|
|
AllOpts = [{outdir, BinOut}, {i, [BinOut]}] ++ Opts,
|
|
|
|
|
|
|
|
case snmpc:compile(Source, AllOpts) of
|
|
|
|
{ok, _} ->
|
|
|
|
MibToHrlOpts =
|
|
|
|
case proplists:get_value(verbosity, AllOpts, undefined) of
|
|
|
|
undefined ->
|
|
|
|
#options{specific = [],
|
|
|
|
cwd = rebar_dir:get_cwd()};
|
|
|
|
Verbosity ->
|
|
|
|
#options{specific = [{verbosity, Verbosity}],
|
|
|
|
cwd = rebar_dir:get_cwd()}
|
|
|
|
end,
|
|
|
|
ok = snmpc:mib_to_hrl(Mib, Mib, MibToHrlOpts),
|
|
|
|
rebar_file_utils:mv(HrlFilename, HrlOut),
|
|
|
|
ok;
|
|
|
|
{error, compilation_failed} ->
|
|
|
|
?ABORT
|
|
|
|
end.
|
|
|
|
|
|
|
|
clean(MibFiles, AppInfo) ->
|
|
|
|
AppDir = rebar_app_info:dir(AppInfo),
|
|
|
|
MIBs = [filename:rootname(filename:basename(MIB)) || MIB <- MibFiles],
|
|
|
|
rebar_file_utils:delete_each(
|
|
|
|
[filename:join([AppDir, "include", MIB++".hrl"]) || MIB <- MIBs]),
|
|
|
|
ok = rebar_file_utils:rm_rf(filename:join([AppDir, "priv/mibs/*.bin"])).
|
|
|
|
|
|
|
|
src_files(Dir) ->
|
|
|
|
%% .mib extension is assumed to be valid here
|
|
|
|
case file:list_dir(Dir) of
|
|
|
|
{ok, Files} ->
|
|
|
|
[filename:join(Dir, File)
|
|
|
|
|| File <- Files,
|
|
|
|
filename:extension(File) =:= ".mib"];
|
|
|
|
_ ->
|
|
|
|
[]
|
|
|
|
end.
|
|
|
|
|
|
|
|
file_deps(File, Files) ->
|
|
|
|
DepMods = imports_in_file(File),
|
|
|
|
lists:filter(
|
|
|
|
fun(F) ->
|
|
|
|
Mods = modules_in_file(F),
|
|
|
|
lists:any(fun(M) -> lists:member(M, Mods) end, DepMods)
|
|
|
|
end,
|
|
|
|
Files
|
|
|
|
).
|
|
|
|
|
|
|
|
modules_in_file(File) ->
|
|
|
|
{ok, Bin} = file:read_file(File),
|
|
|
|
Res = re:run(
|
|
|
|
Bin,
|
|
|
|
"^([a-zA-Z0-9_-]+)\\s+DEFINITIONS\\s+::=\\s+BEGIN",
|
|
|
|
[multiline, {capture, all_but_first, list}, global, unicode]
|
|
|
|
),
|
|
|
|
case Res of
|
|
|
|
nomatch ->
|
|
|
|
[];
|
|
|
|
{match, List} ->
|
|
|
|
lists:usort(lists:append(List))
|
|
|
|
end.
|
|
|
|
|
|
|
|
imports_in_file(File) ->
|
|
|
|
{ok, Bin} = file:read_file(File),
|
|
|
|
ImportMatch = re:run(
|
|
|
|
Bin,
|
|
|
|
"IMPORTS\\s+(.*);",
|
|
|
|
[multiline, dotall, ungreedy, {capture, all_but_first, list}, global]
|
|
|
|
),
|
|
|
|
case ImportMatch of
|
|
|
|
nomatch ->
|
|
|
|
[];
|
|
|
|
{match, ImportSections} ->
|
|
|
|
Modules = re:run(
|
|
|
|
ImportSections,
|
|
|
|
"FROM\\s+([a-zA-Z0-9_-]+)\\s+",
|
|
|
|
[multiline, {capture, all_but_first, list}, global]
|
|
|
|
),
|
|
|
|
case Modules of
|
|
|
|
nomatch ->
|
|
|
|
[];
|
|
|
|
{match, List} ->
|
|
|
|
lists:usort(lists:append(List))
|
|
|
|
end
|
|
|
|
end.
|
|
|
|
|
|
|
|
|