Packages
geas
2.7.3
2.11.1
2.11.0
retired
2.10.1
2.10.0
retired
2.9.9
2.9.8
2.9.7
2.9.6
2.9.5
2.9.4
2.9.2
2.9.1
2.9.0
2.8.1
2.8.0
2.7.14
2.7.13
2.7.12
2.7.11
2.7.10
2.7.9
2.7.8
2.7.7
2.7.6
2.7.5
2.7.4
2.7.3
2.7.2
2.7.1
2.7.0
2.6.2
2.6.1
2.6.0
retired
2.5.1
2.5.0
retired
2.4.6
2.4.5
retired
2.4.4
retired
2.4.3
retired
2.4.2
retired
2.4.1
retired
2.4.0
2.3.0
2.2.0
Guess Erlang Application Scattering
Current section
Files
Jump to
Current section
Files
src/geas_api.hrl
-define(COMMON_DIR(Dir),
AppFile = get_app_file(Dir),
% Informations inventory
{AppName, Version , Desc} = get_app_infos(AppFile),
AppType = get_app_type(AppFile, Dir),
Native = is_native(Dir),
Arch = get_arch(Native, Dir),
Word = get_word(),
AppBeam = filename:join(Dir, atom_to_list(AppName)++".beam"),
Date = get_date(AppBeam),
Author = get_author(AppBeam),
Os = get_os(),
%Erts = get_erts_version(AppBeam),
Comp = get_compile_version(AppBeam),
Erlang = get_erlang_version(Comp)
).
%%-------------------------------------------------------------------------
%% @doc Return infos after application directory analysis
%% @since 1.0.0
%% @end
%%-------------------------------------------------------------------------
-spec info(list()) -> tuple().
info(Dir) when is_list(Dir) ->
{ok, CurPwd} = file:get_cwd(),
put(geas_cwd, CurPwd),
Conf = get_config(),
try
% Fatal tests
is_valid_dir(Dir),
is_valid_erlang_project(Dir),
% Variables
EbinDir = filename:join(Dir, "ebin"),
CsrcDir = filename:join(Dir, "c_src"),
SrcDir = filename:join(Dir, "src"),
Driver = is_using_driver(CsrcDir),
?COMMON_DIR(EbinDir) ,
InfoDir = case Conf#config.use_src of
false -> EbinDir ;
true -> SrcDir
end,
Compat = get_erlang_compat(InfoDir),
% Commands to be done in Dir
ok = file:set_cwd(Dir),
VCS = get_vcs(),
VcsVsn = get_vcs_version(VCS),
VcsUrl = get_vcs_url(VCS),
Maint = get_maintainer(VCS),
CL = get_changelog(),
RN = get_releasenotes(),
Current = case Erlang of
{_, Current_, _} -> Current_ ;
undefined -> undefined
end,
Patches = list_installed_patches(Current),
{ok,
[{name, AppName},
{version, Version},
{description, Desc},
{type, AppType},
{datetime, Date},
{native, Native},
{arch, Arch},
{os, Os},
{word, Word},
{compile, Comp},
{erlang, Erlang},
{compat, Compat},
{author, Author},
{vcs, {VCS, VcsVsn, VcsUrl}},
{maintainer, Maint},
{changelog, CL},
{releasenotes, RN},
{driver, Driver},
{patches, Patches}]}
catch
_:Reason -> {error, Reason}
after
ok = file:set_cwd(CurPwd)
end.
%%-------------------------------------------------------------------------
%% @doc Return infos on .beam file(s) only
%% @since 1.1.0
%% @end
%%-------------------------------------------------------------------------
-spec what(list()) -> tuple().
what(Dir) when is_list(Dir) ->
{ok, CurPwd} = file:get_cwd(),
put(geas_cwd, CurPwd),
try
Output = case filelib:is_regular(Dir) of
true -> what_beam(Dir);
false -> what_dir(Dir)
end,
Output
catch
_:Reason -> {error, Reason}
after
ok = file:set_cwd(CurPwd)
end.
%%-------------------------------------------------------------------------
%% @doc Return infos on .beam file(s) only
%% @end
%%-------------------------------------------------------------------------
-spec what_dir(list()) -> tuple().
what_dir(Dir) ->
?COMMON_DIR(Dir) ,
Compat = get_erlang_compat(Dir),
Current = case Erlang of
{_, Current_, _} -> Current_ ;
undefined -> undefined
end,
Patches = list_installed_patches(Current),
{ok,
[{name, AppName},
{version, Version},
{description, Desc},
{type, AppType},
{datetime, Date},
{native, Native},
{arch, Arch},
{os, Os},
{word, Word},
{compile, Comp},
{erlang, Erlang},
{compat, Compat},
{author, Author},
{patches, Patches}]}.
%%-------------------------------------------------------------------------
%% @doc what/1 on a single beam file
%% @end
%%-------------------------------------------------------------------------
-spec what_beam(list()) -> tuple().
what_beam(File) ->
try
{Name, Version} = case beam_lib:version(File) of
{ok,{N,[V]}} -> {N, V} ;
_ -> {filename:basename(File, ".beam"), undefined}
end,
AppType = get_app_type_beam(File),
Native = is_native_from_file(File),
Arch = get_arch_from_file(File),
Word = get_word(),
Date = get_date(File),
Author = get_author(File),
Os = get_os(),
%Erts = get_erts_version(AppBeam),
Comp = get_compile_version(File),
Erlang = get_erlang_version(Comp),
Compat = get_erlang_compat_file(File),
Current = case Erlang of
{_, Current_, _} -> Current_ ;
undefined -> undefined
end,
Patches = list_installed_patches(Current),
_BeamComp = beam_opcode_compat(File),
{ok,
[{name, Name},
{version, Version},
{type, AppType},
{datetime, Date},
{native, Native},
{arch, Arch},
{os, Os},
{word, Word},
{compile, Comp},
{erlang, Erlang},
{compat, Compat},
{author, Author},
{patches, Patches},
{max_opcode, get_beam_max_opcode(File)}]}
catch
_:Reason -> {error, Reason}
end.
%%-------------------------------------------------------------------------
%% @doc Give the offending modules/functions that reduce release window
%% @end
%%-------------------------------------------------------------------------
offending(File) ->
try
% check it is a file or exit
case filelib:is_regular(File) of
false -> {error, invalid_argument} ;
true -> % Apply geas:what on the beam, bring lowest and highest if necessary
{ok, L } = geas:what(File),
{compat, Compat} = lists:keyfind(compat, 1, L),
{A, B, C, D} = Compat,
MinOff = case A =/= B of
true -> get_min_offending(B, File) ;
false -> []
end,
MaxOff = case C =/= D of
true -> get_max_offending(C, File) ;
false -> []
end,
{ok, {MinOff, MaxOff}}
end
catch
_:Reason -> {error, Reason}
end.
%%-------------------------------------------------------------------------
%% @doc Give the offending min modules/functions that reduce release window
%% @end
%%-------------------------------------------------------------------------
get_min_offending(Rel, File) ->
Abs = get_abstract(File),
Mod = get_module_name_from_file(File),
Exports = lists:filter(fun({M, _F, _A}) -> (M == Mod) end, get(geas_exports)),
X = lists:usort(lists:flatten(lists:flatmap(fun(A) -> [get_remote_call(A, Exports)] end, Abs))),
% From list get the release of offending functions
R = lists:flatmap(fun(F) -> [{rel_min(F), F}] end , X),
% Extract only the release we search
R1 = lists:filter(fun({Relx, _A}) -> (Rel == Relx) end, R),
%% Extract the function
[{Rel, lists:flatmap(fun({_, FF}) -> [FF] end, R1)}].
%%-------------------------------------------------------------------------
%% @doc Give the offending max modules/functions that reduce release window
%% @end
%%-------------------------------------------------------------------------
get_max_offending(Rel, File) ->
Abs = get_abstract(File),
Mod = get_module_name_from_file(File),
Exports = lists:filter(fun({M, _F, _A}) -> (M == Mod) end, get(geas_exports)),
X = lists:usort(lists:flatten(lists:flatmap(fun(A) -> [get_remote_call(A, Exports)] end, Abs))),
% From list get the release of offending functions
R = lists:flatmap(fun(F) -> [{rel_max(F), F}] end , X),
% Extract only the release we search
R1 = lists:filter(fun({Relx, _A}) -> (Rel == Relx) end, R),
%% Extract the function
[{Rel, lists:flatmap(fun({_, FF}) -> [FF] end, R1)}].
%%-------------------------------------------------------------------------
%% @doc Compat output on stdout, mainly for erlang.mk plugin
%% @since 2.0.4
%% @end
%%-------------------------------------------------------------------------
compat(RootDir) -> compat(RootDir, print).
compat(RootDir, deps) -> {_, _, Deps} = compat(RootDir, term),
Deps;
compat(RootDir, global) -> {{_, MinGlob, MaxGlob, _}, _, _} = compat(RootDir, term),
{?GEAS_MIN_REL, MinGlob, MaxGlob, ?GEAS_MAX_REL};
compat(RootDir, term) ->
% reset at each run
put(geas_logs,[]),
put(geas_calls,[]),
put(geas_disc,[]),
put(geas_minrels,[]),
put(geas_maxrels,[]),
put(geas_exports,[]),
put(geas_attributes,[]),
% Get all .beam (or .erl) files recursively
Ext = ext_to_search(),
Dir = case get(geas_caller) of
'rebar' -> "_build";
'erlang.mk' -> "deps";
_ -> case filelib:is_dir(filename:join(RootDir, "_build")) of
true -> "_build" ;
false -> "deps"
end
end,
PP = filelib:fold_files(filename:absname(filename:join(RootDir, Dir)), Ext, true,
fun(X, Y) ->
P = filename:dirname(filename:dirname(X)),
case lists:member("_rel",re:split(P,"/",[{return,list}])) of
false ->
case filename:basename(P) of
"rebar" -> Y ; % Exclude rebar from results
"geas" -> Y ; % Exclude geas from results
"geas_rebar3" -> Y ; % Exclude geas_rebar3 from results
"samovar" -> Y ; % Exclude samovar from results
"src" ->
case lists:member(filename:dirname(P), Y) of
true -> Y ;
false -> Y ++ [filename:dirname(P)]
end;
_ ->
case lists:member(P, Y) of
true -> Y ;
false -> Y ++ [P]
end
end;
true -> Y
end
end, []),
% Get all upper project
Ps = lists:usort(PP),
?LOG(geas_logs, {debug, dir_list, Ps }),
Global = case get(geas_caller) of
'erlang.mk' -> Ps ++ [filename:absname(RootDir)];
_ -> Ps
end,
Fun =
fun(X) ->
case (catch info(X)) of
{ok, I} ->
Compat = lists:keyfind(compat, 1, I),
{compat,{MinDb, Min, Max, MaxDb}} = Compat,
N = lists:keyfind(native, 1, I),
{native, Native} = N,
A = lists:keyfind(arch, 1, I),
{arch, Arch} = A,
ArchString = case Native of
true -> atom_to_list(Arch) ;
false -> ""
end,
Left = case (MinDb =:= Min) of
true -> "" ;
false -> Min
end,
Right = case (MaxDb =:= Max) of
true -> "" ;
false -> Max
end,
Name = case filename:basename(X) of
"." -> filename:basename(filename:dirname(X)) ;
NN -> NN
end,
[{Left , ArchString, Right, Name}] ;
{error, Reason} -> ?LOG(geas_logs, {warning, compat, Reason}),
throw(3),
[]
end
end,
D = lists:keysort(4, lists:flatmap(Fun, Global)),
% Get global info
MinList = lists:usort([?GEAS_MIN_REL] ++ lists:flatmap(fun({X, _, _, _}) -> [X] end, D)),
MinGlob = highest_version(MinList) ,
ArchList = lists:usort(lists:flatmap(fun({_, X, _, _}) -> [X] end, D)),
ArchGlob = safetl(ArchList), % Assuming only one arch localy !
MaxList = lists:usort([?GEAS_MAX_REL] ++ lists:flatmap(fun({_, _, X, _}) -> [X] end, D)),
MaxGlob = lowest_version(MaxList) ,
{{?GEAS_MIN_REL, MinGlob, MaxGlob, ?GEAS_MAX_REL}, ArchGlob, D};
compat(RootDir, print) ->
compat(RootDir, print, []).
safetl([]) -> [];
safetl(X) -> tl(X).
%compat(RootDir, print, []) -> compat(RootDir, print);
compat(RootDir, print, Config) ->
put(geas_exit_code, 0),
do_log({debug, geas_rebar3, Config}),
set_config(Config),
Conf=get_config(),
do_log({debug, config, Conf}),
{{_, MinGlob, MaxGlob, _}, ArchGlob, D} = compat(RootDir, term),
% Display log if needed
Project =
case RootDir of
"." -> filename:basename(filename:dirname(filename:absname(RootDir)));
_ -> filename:basename(RootDir)
end,
geas:log(),
c:flush(),
% Display header
io:format(" ~-10s ~-10s ~-20s ~20s~n",[?GEAS_MIN_REL , ?GEAS_MAX_REL, "Geas database", get_version(geas)]),
io:format("~s~s~n",["---Min--------Arch-------Max--",string:copies("-",50)]),
lists:foreach(fun({LD, AD, RD, FD}) -> io:format(" ~-10s ~-10s ~-10s ~-20s ~20s~n",[LD, AD, RD, FD, get_version(FD)]) end, D),
io:format("~80s~n",[string:copies("-",80)]),
io:format(" ~-10s ~-10s ~-10s ~-20s ~20s~n",[MinGlob , ArchGlob, MaxGlob, "Global project", get_version(Project)]),
Rels = w2l({?GEAS_MIN_REL, MinGlob, MaxGlob, ?GEAS_MAX_REL}),
io:format("~n",[]),
% Always display current version detected and patches found
Current = get_current_erlang_version(),
io:format("C : ~ts~n",[Current]),
Patches = list_installed_patches(Current),
case Patches of
[] -> ok ;
_ -> io:format("P : ~ts~n", [string:join(Patches, " ")])
end,
% Display Recommanded Erlang release if requested
case Conf#config.tips of
false -> ok ;
true -> Rec = get_recommanded_patches(Current),
case Rec of
[] -> ok;
Rec -> io:format("R : ~ts~n", [string:join(Rec, " ")])
end
end,
case Conf#config.my_rels of
false -> {ok, SV} = geas_semver:l2s(lists:usort(Rels)),
io:format("T : ~ts~n",[SV]);
"" -> io:format("T : ~ts~n",[string:join(Rels, " ")]);
_ -> io:format("L : ~ts~n",[string:join(Rels, " ")])
end,
case Conf#config.exc_rels of
false -> ok ;
Exc -> case pickup_rel(w2l({?GEAS_MIN_REL, MinGlob, MaxGlob, ?GEAS_MAX_REL}, false), string:tokens(Exc, " ")) of
[] -> ok ;
InWindow -> io:format("E : ~ts~n",[string:join(InWindow," ")])
end
end,
% Display Discarded release due to known bugs
case erlang:get(geas_disc) of
undefined -> ok ;
Disc ->
case Conf#config.disc_rels of
true -> % Do not display if outside of window
DL = in_window(MinGlob, distinct_disc_rels(Disc), MaxGlob),
case DL of
[] -> ok ;
DL -> io:format("D : ~ts~n",[string:join(DL," ")])
end;
false -> ok
end
end,
%% Set the plugin exit code
try
% Current version is incompatible with release window
check_current_rel_vs_window(Current, Rels),
% Check versions against semver range set
check_window_vs_semver_range(Rels, Conf#config.range),
% Check versions against semver frame set
check_window_vs_semver_frame(Rels, Conf#config.frame)
catch
_:Exit when is_integer(Exit)
-> put(geas_exit_code, Exit),
case ( Exit > 0 ) of
true ->
Err = format_error(Exit),
?LOG(geas_logs, {error, Exit, Err});
false ->
ok
end;
_:Reason
-> put(geas_exit_code, -1),
?LOG(geas_logs, {error, unexpexted_error, Reason})
after
geas:log()
end,
ok.
%%-------------------------------------------------------------------------
%% @doc Offending output on stdout, mainly for erlang.mk plugin
%% @end
%%-------------------------------------------------------------------------
guilty(RootDir) ->
Ext = ext_to_search(),
Dir = case get(geas_caller) of
'rebar' -> "_build";
'erlang.mk' -> "deps";
_ -> case filelib:is_dir(filename:join(RootDir, "_build")) of
true -> "_build" ;
false -> "deps"
end
end,
DirS = dir_to_search(),
Bs1 = filelib:fold_files(filename:join(RootDir, Dir), Ext, true,
fun(X, Y) -> Y ++ [X] end, []),
Bs2 = filelib:fold_files(filename:join(RootDir, DirS), Ext, true,
fun(X, Y) -> Y ++ [X] end, []),
Bs_ = Bs1 ++ Bs2,
Bs = lists:flatmap(fun(X) -> case lists:member("_rel",re:split(X,"/",[{return,list}])) of
true -> [] ;
false -> [X]
end end, Bs_),
% Check Offendings for each beam / erl
Fun =
fun(X) -> Off = offending(X),
case Off of
{ok, []} -> [] ;
{ok, {[],[]}} -> [] ;
{ok, {[{[],[]}],[]}} -> [] ;
{ok, {[],[{[],[]}]}} -> [] ;
{ok,{[{[],[]}],[{[],[]}]}} -> [] ;
{ok,{Left,Right}} -> [{X, Left, Right}] ;
_E -> []
end
end,
All = lists:flatmap(Fun, Bs),
Fun2 =
fun({_F, L, R}) ->
io:format("~n~ts", [_F]) ,
case L of
[{Min, MinList}] -> io:format("~n~-10ts", [Min]),
LL = lists:flatmap(fun({M, F, A}) ->
[atom_to_list(M) ++ ":" ++
atom_to_list(F) ++ "/" ++
integer_to_list(A)] end, MinList),
io:format("~ts~n", [string:join(LL, ", ")]) ;
_ -> ok
end,
case R of
[{Max, MaxList}] -> io:format("~n~-10ts", [Max]),
RR = lists:flatmap(fun({M, F, A}) ->
[atom_to_list(M) ++ ":" ++
atom_to_list(F) ++ "/" ++
integer_to_list(A)] end, MaxList),
io:format("~ts~n", [string:join(RR, ", ")]) ;
_ -> ok
end
end,
lists:foreach(Fun2, lists:usort(All)) .
%%-------------------------------------------------------------------------
%% @doc Translate compat window to list
%% @since 2.0.5
%% @end
%%-------------------------------------------------------------------------
w2l({A, MinRel, MaxRel, B}) -> w2l({A, MinRel, MaxRel, B}, true).
w2l({_, MinRel, MaxRel, _}, Exc) ->
Conf = get_config(),
L = geas_db:get_rel_list(),
Lower = lists:filter(fun(X) ->
case (geas_semver:versionize(X) >= geas_semver:versionize(MinRel) ) of
true -> true ;
false -> false
end
end, L),
Res = lists:filter(fun(X) ->
case ( geas_semver:versionize(X) =< geas_semver:versionize(MaxRel) ) of
true -> true ;
false -> false
end
end, Lower),
Exclude =
case Conf#config.exc_rels of
false -> [] ;
Excs -> case Exc of
true -> string:tokens(Excs, " ") ;
_ -> []
end
end,
Local =
case Conf#config.my_rels of
false -> Res -- Exclude;
"" -> Res -- Exclude;
MyRel -> MyRelList = string:tokens(MyRel, " "),
pickup_rel(MyRelList, Res) -- Exclude
end,
case erlang:get(geas_disc) of
undefined -> Local ;
Disc ->
case Conf#config.disc_rels of
true -> Local -- distinct_disc_rels(Disc);
false -> Local
end
end.
%%-------------------------------------------------------------------------
%% @doc Set prefixe for Erlang git tag
%% @end
%%-------------------------------------------------------------------------
git_tag(X) ->
case string:substr(X, 1, 1) of
"R" -> "OTP_" ++ X;
_ -> "OTP-" ++ X
end.
%%-------------------------------------------------------------------------
%% @doc Return exit code
%% @end
%%-------------------------------------------------------------------------
exit_code()
-> get(geas_exit_code).
%%=========================================================================
%%=== Local functions ===
%%=========================================================================
%%-------------------------------------------------------------------------
%% @doc Analyze compatibility of all beam in directory
%% @end
%%-------------------------------------------------------------------------
-spec get_erlang_compat(list()) -> {list(), list(), list(), list()}.
get_erlang_compat(Dir) ->
Conf = get_config(),
NbBeams = length(filelib:wildcard("*.beam", Dir)),
Joker = case Conf#config.use_src of
_ when (NbBeams == 0) -> "**/*.erl" ;
false -> "*.beam" ;
true -> "**/*.erl"
end,
Beams = filelib:wildcard(Joker, Dir),
Fun = fun(F) ->
File = filename:join(Dir,F),
Comp = get_erlang_compat_beam(File),
Ign = case get(geas_ignore) of
undefined -> [];
I -> I
end,
Res = case lists:member(File, Ign) of
false -> Comp ;
true -> {?GEAS_MIN_REL, ?GEAS_MAX_REL, {File, []}}
end,
[Res] end,
X = lists:usort(lists:flatmap(Fun, Beams)),
{MinList, MaxList, DiscListRaw} = lists:unzip3(X),
DiscList = lists:filter(fun(XX) -> {_, T} = XX, T =/= [] end, DiscListRaw),
% Get the highest version of Min releases of all beam
MinR = highest_version(MinList),
% Get the lowest version of Max releases of all beam
MaxR = lowest_version(MaxList),
% Keep memory of releases to discard
?STORE(geas_disc, DiscList),
{?GEAS_MIN_REL , MinR, MaxR, ?GEAS_MAX_REL}.
%%-------------------------------------------------------------------------
%% @doc Analyze compatibility of a beam from file
%% @end
%%-------------------------------------------------------------------------
-spec get_erlang_compat_file(list()) -> {list(), list(), list(), list()}.
get_erlang_compat_file(File) ->
X = lists:usort(lists:flatmap(fun(F) -> [get_erlang_compat_beam(F)] end, [File])),
{MinList, MaxList, DiscListRaw} = lists:unzip3(X),
DiscList = lists:filter(fun(XX) -> {_, T} = XX, T =/= [] end, DiscListRaw),
% Get the highest version of Min releases of all beam
MinR = highest_version(MinList),
% Get the lowest version of Max releases of all beam
MaxR = lowest_version(MaxList),
% Keep memory of releases to discard
?STORE(geas_disc, DiscList),
{?GEAS_MIN_REL , MinR, MaxR, ?GEAS_MAX_REL}.
%%-------------------------------------------------------------------------
%% @doc Get module name from file
%% @end
%%-------------------------------------------------------------------------
get_module_name_from_file(File) ->
case (filelib:is_regular(File)) of
true -> erlang:list_to_atom(filename:basename(File, filename:extension(File)));
false -> ''
end.
%%-------------------------------------------------------------------------
%% @doc Analyze compatibility of a beam file
%% @end
%%-------------------------------------------------------------------------
-spec get_erlang_compat_beam(list()) -> {list(), list()}.
get_erlang_compat_beam(File) ->
% Extract all Erlang MFA in Abstract code
Abs1 = case get_abstract(File) of
AA when is_tuple(AA) -> [AA];
AA -> AA
end,
Mod = get_module_name_from_file(File),
Exports = lists:filter(fun({M, _F, _A}) -> (M == Mod) end, get(geas_exports)),
X = lists:usort(lists:flatten(lists:flatmap(fun(A) -> [get_remote_call(A, Exports)] end, Abs1))),
?STORE(geas_calls, X),
%io:format("~p~n", [X)])
% Get the min and max release for each MFA
% Get the min release compatible
Min = lists:flatmap(fun(A) -> [{rel_min(A), A}] end, X),
{MinRelss, _} = lists:unzip(Min),
MinRels = lists:filter(fun(XX) -> case XX of undefined -> false; [] -> false;_ -> true end end, lists:usort(MinRelss)),
% Get the max release compatible
Max = lists:flatmap(fun(A) -> [{rel_max(A), A}] end, X),
{MaxRelss, _} = lists:unzip(Max),
MaxRels = lists:filter(fun(XX) -> case XX of undefined -> false; [] -> false; _ -> true end end, lists:usort(MaxRelss)),
% Get the releases to discard
Fun = fun(A) ->
case rel_disc(A) of
ok -> [] ;
D -> [{A, D}]
end end,
DiscRels = lists:usort(lists:flatten(lists:flatmap(Fun, X))),
Highest = highest_version(MinRels),
Lowest = lowest_version(MaxRels),
% Some code syntax may find a Lowest version higher than Highest version, for instance :
% ./_build/default/lib/edown/ebin/edown_doclet.beam
% 18.0 edoc_lib:write_info_file/3
% 17.5 edoc_lib:write_file/5, edoc_lib:write_info_file/4
% (Due to a test if a function is existing, otherwise use another one)
case highest_version(Highest, Lowest) of
Highest when (Highest =/= []),(Lowest =/= [])
-> ?STORE(geas_ignore, [File]),
?LOG(geas_logs, {debug, {Highest, Lowest}, File}),
?LOG(geas_logs, {warning, ignoring, File});
_ -> ok
end,
?STORE(geas_minrels, Max),
?STORE(geas_maxrels, Min),
{Highest, Lowest, {File, DiscRels}}.
%%-------------------------------------------------------------------------
%% @doc Check current Erlang release against project release window
%% @end
%%-------------------------------------------------------------------------
check_current_rel_vs_window(Current, Window)
->
Start = hd(Window),
End = hd(lists:reverse(Window)),
Range = lists:flatten(">=" ++ Start ++ " <=" ++ End),
%io:format("~n~p ~p ~p ~p", [Current, Start, End, Range]),
case geas_semver:check(Current, Range) of
true -> 0 ;
false -> throw(1)
end.
%%-------------------------------------------------------------------------
%% @doc Check project release window against required semver range
%% All releases of window have to be inside range
%% @end
%%-------------------------------------------------------------------------
check_window_vs_semver_range(Window, Range)
when is_list(Range)
->
?LOG(geas_logs, {notice, range, Range}),
case lists:all(fun(Rel) -> geas_semver:check(Rel, Range) end, Window) of
false -> %
do_log({error, range, "Range does not match"}),
throw(2);
true -> 0
end;
check_window_vs_semver_range(_Window, _Range) % No range set
-> 0.
%%-------------------------------------------------------------------------
%% @doc Check project release window against required semver frame
%% Frame have to be inside release window
%% @end
%%-------------------------------------------------------------------------
check_window_vs_semver_frame(Window, Frame)
when is_list(Frame)
->
?LOG(geas_logs, {notice, frame, Frame}),
% Get all releases known at this time
All = geas_db:get_rel_list(),
% Extract all releases in the semver Frame
Ext = lists:filter(fun(Rel) -> geas_semver:check(Rel, Frame) end, All),
% Check if window is a subset of this
D1 = Window -- Ext,
D2 = Ext -- Window,
%erlang:display({Ext, Window, D1, D2}),
case ((erlang:length(D1) >= 0) and (erlang:length(D2) == 0)) of
false -> do_log({error, frame, "Frame does not match"}),
throw(5);
true -> 0
end;
check_window_vs_semver_frame(_Window, _Frame) % No frame set
-> 0.
%%-------------------------------------------------------------------------
%% @doc Format exit code to error string
%% @end
%%-------------------------------------------------------------------------
format_error(0) -> "Success" ;
format_error(1) -> "Current Erlang/OTP release is incompatible with project release window" ;
format_error(2) -> "Release window do not match the required semver version range" ;
format_error(3) -> "Beam files are incompatible with current Erlang/OTP release (May need recompilation)" ;
format_error(4) -> "Maximum opcode is higher in Beam files (May need recompilation)" ;
format_error(5) -> "Release window do not match the required semver version frame" ;
format_error(_) -> "Unexpected exit code".