summaryrefslogtreecommitdiff
path: root/src/rebar_prv_update.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/rebar_prv_update.erl')
-rw-r--r--src/rebar_prv_update.erl122
1 files changed, 110 insertions, 12 deletions
diff --git a/src/rebar_prv_update.erl b/src/rebar_prv_update.erl
index 0e3b9a0..5e1e253 100644
--- a/src/rebar_prv_update.erl
+++ b/src/rebar_prv_update.erl
@@ -11,6 +11,10 @@
-export([hex_to_index/1]).
+-ifdef(TEST).
+-export([cmp_/6, cmpl_/6, valid_vsn/1]).
+-endif.
+
-include("rebar.hrl").
-include_lib("providers/include/providers.hrl").
@@ -99,7 +103,7 @@ hex_to_index(State) ->
ets:foldl(fun({{Pkg, PkgVsn}, [Deps, Checksum, BuildTools | _]}, _) when is_list(BuildTools) ->
case lists:any(fun is_supported/1, BuildTools) of
true ->
- DepsList = update_deps_list(Deps, Registry, State),
+ DepsList = update_deps_list(Pkg, PkgVsn, Deps, Registry, State),
ets:insert(?PACKAGE_TABLE, {{Pkg, PkgVsn}, DepsList, Checksum});
false ->
true
@@ -137,20 +141,114 @@ hex_to_index(State) ->
fail
end.
-update_deps_list(Deps, HexRegistry, State) ->
+update_deps_list(Pkg, PkgVsn, Deps, HexRegistry, State) ->
lists:foldl(fun([Dep, DepVsn, false, _AppName | _], DepsListAcc) ->
- case DepVsn of
- <<"~> ", Vsn/binary>> ->
- case rebar_packages:find_highest_matching(Dep, Vsn, HexRegistry, State) of
- {ok, HighestDepVsn} ->
- [{Dep, HighestDepVsn} | DepsListAcc];
- none ->
- ?WARN("Missing registry entry for package ~s. Try to fix with `rebar3 update`", [Dep]),
- DepsListAcc
- end;
- Vsn ->
+ Dep1 = {Pkg, PkgVsn, Dep},
+ case {valid_vsn(DepVsn), DepVsn} of
+ %% Those are all not perfectly implemented!
+ %% and doubled since spaces seem not to be
+ %% enforced
+ {false, Vsn} ->
+ ?WARN("[~s:~s], Bad dependency version for ~s: ~s.",
+ [Pkg, PkgVsn, Dep, Vsn]),
+ DepsListAcc;
+ {_, <<"~>", Vsn/binary>>} ->
+ highest_matching(Dep1, rm_ws(Vsn), HexRegistry,
+ State, DepsListAcc);
+ {_, <<">=", Vsn/binary>>} ->
+ cmp(Dep1, rm_ws(Vsn), HexRegistry, State,
+ DepsListAcc, fun ec_semver:gte/2);
+ {_, <<">", Vsn/binary>>} ->
+ cmp(Dep1, rm_ws(Vsn), HexRegistry, State,
+ DepsListAcc, fun ec_semver:gt/2);
+ {_, <<"<=", Vsn/binary>>} ->
+ cmpl(Dep1, rm_ws(Vsn), HexRegistry, State,
+ DepsListAcc, fun ec_semver:lte/2);
+ {_, <<"<", Vsn/binary>>} ->
+ cmpl(Dep1, rm_ws(Vsn), HexRegistry, State,
+ DepsListAcc, fun ec_semver:lt/2);
+ {_, <<"==", Vsn/binary>>} ->
+ [{Dep, Vsn} | DepsListAcc];
+ {_, Vsn} ->
[{Dep, Vsn} | DepsListAcc]
end;
([_Dep, _DepVsn, true, _AppName | _], DepsListAcc) ->
DepsListAcc
end, [], Deps).
+
+rm_ws(<<" ", R/binary>>) ->
+ rm_ws(R);
+rm_ws(R) ->
+ R.
+
+valid_vsn(Vsn) ->
+ %% Regepx from https://github.com/sindresorhus/semver-regex/blob/master/index.js
+ SemVerRegExp = "v?(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(\\.(0|[1-9][0-9]*))?"
+ "(-[0-9a-z-]+(\\.[0-9a-z-]+)*)?(\\+[0-9a-z-]+(\\.[0-9a-z-]+)*)?",
+ SupportedVersions = "^(>=?|<=?|~>|==)?\\s*" ++ SemVerRegExp ++ "$",
+ re:run(Vsn, SupportedVersions) =/= nomatch.
+
+highest_matching({Pkg, PkgVsn, Dep}, Vsn, HexRegistry, State, DepsListAcc) ->
+ case rebar_packages:find_highest_matching(Pkg, PkgVsn, Dep, Vsn, HexRegistry, State) of
+ {ok, HighestDepVsn} ->
+ [{Dep, HighestDepVsn} | DepsListAcc];
+ none ->
+ ?WARN("[~s:~s] Missing registry entry for package ~s. Try to fix with `rebar3 update`",
+ [Pkg, PkgVsn, Dep]),
+ DepsListAcc
+ end.
+
+cmp({_Pkg, _PkgVsn, Dep} = Dep1, Vsn, HexRegistry, State, DepsListAcc, CmpFun) ->
+ {ok, Vsns} = rebar_packages:find_all(Dep, HexRegistry, State),
+ cmp_(undefined, Vsn, Vsns, DepsListAcc, Dep1, CmpFun).
+
+
+cmp_(undefined, _MinVsn, [], DepsListAcc, {Pkg, PkgVsn, Dep}, _CmpFun) ->
+ ?WARN("[~s:~s] Missing registry entry for package ~s. Try to fix with `rebar3 update`",
+ [Pkg, PkgVsn, Dep]),
+ DepsListAcc;
+cmp_(HighestDepVsn, _MinVsn, [], DepsListAcc, {_Pkg, _PkgVsn, Dep}, _CmpFun) ->
+ [{Dep, HighestDepVsn} | DepsListAcc];
+
+cmp_(BestMatch, MinVsn, [Vsn | R], DepsListAcc, Dep, CmpFun) ->
+ case CmpFun(Vsn, MinVsn) of
+ true ->
+ cmp_(Vsn, Vsn, R, DepsListAcc, Dep, CmpFun);
+ false ->
+ cmp_(BestMatch, MinVsn, R, DepsListAcc, Dep, CmpFun)
+ end.
+
+%% We need to treat this differently since we want a version that is LOWER but
+%% the higest possible one.
+cmpl({_Pkg, _PkgVsn, Dep} = Dep1, Vsn, HexRegistry, State, DepsListAcc, CmpFun) ->
+ {ok, Vsns} = rebar_packages:find_all(Dep, HexRegistry, State),
+ cmpl_(undefined, Vsn, Vsns, DepsListAcc, Dep1, CmpFun).
+
+cmpl_(undefined, _MaxVsn, [], DepsListAcc, {Pkg, PkgVsn, Dep}, _CmpFun) ->
+ ?WARN("[~s:~s] Missing registry entry for package ~s. Try to fix with `rebar3 update`",
+ [Pkg, PkgVsn, Dep]),
+ DepsListAcc;
+
+cmpl_(HighestDepVsn, _MaxVsn, [], DepsListAcc, {_Pkg, _PkgVsn, Dep}, _CmpFun) ->
+ [{Dep, HighestDepVsn} | DepsListAcc];
+
+cmpl_(undefined, MaxVsn, [Vsn | R], DepsListAcc, Dep, CmpFun) ->
+ case CmpFun(Vsn, MaxVsn) of
+ true ->
+ cmpl_(Vsn, MaxVsn, R, DepsListAcc, Dep, CmpFun);
+ false ->
+ cmpl_(undefined, MaxVsn, R, DepsListAcc, Dep, CmpFun)
+ end;
+
+cmpl_(BestMatch, MaxVsn, [Vsn | R], DepsListAcc, Dep, CmpFun) ->
+ case CmpFun(Vsn, MaxVsn) of
+ true ->
+ case ec_semver:gte(Vsn, BestMatch) of
+ true ->
+ cmpl_(Vsn, MaxVsn, R, DepsListAcc, Dep, CmpFun);
+ false ->
+ cmpl_(BestMatch, MaxVsn, R, DepsListAcc, Dep, CmpFun)
+ end;
+ false ->
+ cmpl_(BestMatch, MaxVsn, R, DepsListAcc, Dep, CmpFun)
+ end.