Skip to content

Commit cde13f3

Browse files
committed
Start integrating verl
1 parent 4fc2643 commit cde13f3

File tree

10 files changed

+128
-189
lines changed

10 files changed

+128
-189
lines changed

apps/rebar/src/rebar.hrl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
-type ms_field() :: '$1' | '_' | {'$1', '$2'}.
4646

4747
%% TODO: change package and requirement keys to be required (:=) after dropping support for OTP-18
48-
-record(package, {key :: {unicode:unicode_binary() | ms_field(), unicode:unicode_binary() | ms_field() | ec_semver:semver(),
48+
-record(package, {key :: {unicode:unicode_binary() | ms_field(), unicode:unicode_binary() | ms_field() | verl:version(),
4949
unicode:unicode_binary() | ms_field()},
5050
inner_checksum :: binary() | ms_field(),
5151
outer_checksum :: binary() | ms_field(),

apps/rebar/src/rebar_app_utils.erl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ update_source(AppInfo, {pkg, PkgName, PkgVsn, OldHash, Hash}, State) ->
328328
dependencies=Deps,
329329
retired=Retired} = Package,
330330
maybe_warn_retired(PkgName, PkgVsn1, Hash, Retired),
331-
PkgVsn2 = list_to_binary(lists:flatten(ec_semver:format(PkgVsn1))),
331+
PkgVsn2 = list_to_binary(lists:flatten(rebar_verl:format_version(PkgVsn1))),
332332
AppInfo1 = rebar_app_info:source(AppInfo, {pkg, PkgName, PkgVsn2, OldHash1, Hash1, RepoConfig}),
333333
rebar_app_info:update_opts_deps(AppInfo1, Deps);
334334
not_found ->
@@ -364,7 +364,7 @@ maybe_warn_retired(_, _, Hash, _) when is_binary(Hash) ->
364364
maybe_warn_retired(Name, Vsn, _, R=#{reason := Reason}) ->
365365
Message = maps:get(message, R, ""),
366366
?WARN("Warning: package ~s-~s is retired: (~s) ~s",
367-
[Name, ec_semver:format(Vsn), retire_reason(Reason), Message]);
367+
[Name, rebar_verl:format_version(Vsn), retire_reason(Reason), Message]);
368368
maybe_warn_retired(_, _, _, _) ->
369369
ok.
370370

apps/rebar/src/rebar_packages.erl

Lines changed: 48 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
,resolve_version/6]).
1212

1313
-ifdef(TEST).
14-
-export([new_package_table/0, find_highest_matching_/5, cmp_/4, cmpl_/4, valid_vsn/1]).
14+
-export([new_package_table/0, find_highest_matching_/5, valid_vsn/1]).
1515
-endif.
1616

1717
-export_type([package/0]).
@@ -55,31 +55,37 @@ get_all_names(State) ->
5555
_='_'},
5656
[], ['$1']}])).
5757

58-
-spec get_package_versions(unicode:unicode_binary(), ec_semver:semver(),
58+
-spec get_package_versions(unicode:unicode_binary(), verl:semver(),
5959
unicode:unicode_binary(),
6060
ets:tid(), rebar_state:t()) -> [vsn()].
61-
get_package_versions(Dep, {_, AlphaInfo}, Repo, Table, State) ->
62-
?MODULE:verify_table(State),
63-
AllowPreRelease = rebar_state:get(State, deps_allow_prerelease, false)
64-
orelse AlphaInfo =/= {[],[]},
65-
ets:select(Table, [{#package{key={Dep, {'$1', '$2'}, Repo},
66-
_='_'},
67-
[{'==', '$2', {{[],[]}}} || not AllowPreRelease], [{{'$1', '$2'}}]}]).
61+
get_package_versions(Dep, DepVsn, Repo, Table, State) ->
62+
_AllowPreRelease = rebar_state:get(State, deps_allow_prerelease, false),
63+
case rebar_verl:parse_requirement(DepVsn) of
64+
{error, _} ->
65+
none;
66+
{ok, #{matchspec := [{Head, [Match], _}]}} ->
67+
?MODULE:verify_table(State),
68+
Vsns = ets:select(Table, [{#package{key={Dep, Head, Repo}, _='_'},
69+
[Match], [{Head}]}]),
70+
handle_vsns(Vsns)
71+
end.
6872

6973
-spec get_package(unicode:unicode_binary(), unicode:unicode_binary(),
7074
binary() | undefined | '_',
7175
[unicode:unicode_binary()] | ['_'], ets:tab(), rebar_state:t())
7276
-> {ok, #package{}} | not_found.
7377
get_package(Dep, Vsn, undefined, Repos, Table, State) ->
7478
get_package(Dep, Vsn, '_', Repos, Table, State);
79+
get_package(Dep, Vsn, Hash, Repos, Table, State) when is_binary(Vsn) ->
80+
get_package(Dep, r3_verl:parse(Vsn), Hash, Repos, Table, State);
7581
get_package(Dep, Vsn, Hash, Repos, Table, State) ->
7682
?MODULE:verify_table(State),
77-
MatchingPackages = ets:select(Table, [{#package{key={Dep, ec_semver:parse(Vsn), Repo},
83+
MatchingPackages = ets:select(Table, [{#package{key={Dep, Vsn, Repo},
7884
_='_'}, [], ['$_']} || Repo <- Repos]),
7985
PackagesWithProperHash = lists:filter(
8086
fun(#package{key = {_Dep, _Vsn, Repo}, outer_checksum = PkgChecksum}) ->
8187
if (PkgChecksum =/= Hash) andalso (Hash =/= '_') ->
82-
?WARN("Checksum mismatch for package ~ts-~ts from repo ~ts", [Dep, Vsn, Repo]),
88+
?WARN("Checksum mismatch for package ~ts-~ts from repo ~ts", [Dep, rebar_verl:format_version(Vsn), Repo]),
8389
false;
8490
true ->
8591
true
@@ -174,7 +180,8 @@ package_dir(Repo, State) ->
174180
%% `~> 2.1.3-dev` | `>= 2.1.3-dev and < 2.2.0`
175181
%% `~> 2.0` | `>= 2.0.0 and < 3.0.0`
176182
%% `~> 2.1` | `>= 2.1.0 and < 3.0.0`
177-
find_highest_matching(Dep, Constraint, Repo, Table, State) ->
183+
find_highest_matching(Dep, Version, Repo, Table, State) ->
184+
Constraint = verl:add_highest_matching_prefix(Version),
178185
try find_highest_matching_(Dep, Constraint, Repo, Table, State) of
179186
none ->
180187
handle_missing_package(Dep, Repo, State,
@@ -192,39 +199,26 @@ find_highest_matching(Dep, Constraint, Repo, Table, State) ->
192199
end.
193200

194201
find_highest_matching_(Dep, Constraint, #{name := Repo}, Table, State) ->
195-
try get_package_versions(Dep, Constraint, Repo, Table, State) of
196-
[Vsn] ->
197-
handle_single_vsn(Vsn, Constraint);
198-
Vsns ->
199-
case handle_vsns(Constraint, Vsns) of
200-
none ->
201-
none;
202-
FoundVsn ->
203-
{ok, FoundVsn}
204-
end
202+
try
203+
get_package_versions(Dep, Constraint, Repo, Table, State)
205204
catch
206205
error:badarg ->
207206
none
208207
end.
209208

210-
handle_vsns(Constraint, Vsns) ->
211-
lists:foldl(fun(Version, Highest) ->
212-
case ec_semver:pes(Version, Constraint) andalso
213-
(Highest =:= none orelse ec_semver:gt(Version, Highest)) of
214-
true ->
215-
Version;
216-
false ->
217-
Highest
218-
end
219-
end, none, Vsns).
220-
221-
handle_single_vsn(Vsn, Constraint) ->
222-
case ec_semver:pes(Vsn, Constraint) of
223-
true ->
224-
{ok, Vsn};
225-
false ->
226-
none
227-
end.
209+
handle_vsns([]) -> none;
210+
handle_vsns(Vsns) ->
211+
Vsn =
212+
lists:foldl(
213+
fun(Version, Highest) ->
214+
case (Highest =:= none orelse r3_verl:compare(Version, Highest) =:= gt) of
215+
true ->
216+
Version;
217+
false ->
218+
Highest
219+
end
220+
end, none, Vsns),
221+
{ok, Vsn}.
228222

229223
verify_table(State) ->
230224
ets:info(?PACKAGE_TABLE, named_table) =:= true orelse load_and_verify_version(State).
@@ -282,8 +276,12 @@ unverified_repo_message() ->
282276
"You can disable this check by setting REBAR_NO_VERIFY_REPO_ORIGIN=1".
283277

284278
insert_releases(Name, Releases, Repo, Table) ->
279+
Parse = fun (V) ->
280+
{ok, Res} = verl:parse(V),
281+
Res
282+
end,
285283
[true = ets:insert(Table,
286-
#package{key={Name, ec_semver:parse(Version), Repo},
284+
#package{key={Name, Parse(Version), Repo},
287285
inner_checksum=parse_checksum(InnerChecksum),
288286
outer_checksum=parse_checksum(OuterChecksum),
289287
retired=maps:get(retired, Release, false),
@@ -313,7 +311,7 @@ resolve_version(Dep, DepVsn, _OldHash, Hash, HexRegistry, State) when is_binary(
313311
{ok, Package, RepoConfig};
314312
_ ->
315313
Fun = fun(Repo) ->
316-
case resolve_version_(Dep, DepVsn, Repo, HexRegistry, State) of
314+
case get_package_versions(Dep, DepVsn, Repo, HexRegistry, State) of
317315
none ->
318316
not_found;
319317
{ok, Vsn} ->
@@ -324,7 +322,7 @@ resolve_version(Dep, DepVsn, _OldHash, Hash, HexRegistry, State) when is_binary(
324322
end;
325323
resolve_version(Dep, undefined, _OldHash, Hash, HexRegistry, State) ->
326324
Fun = fun(Repo) ->
327-
case highest_matching(Dep, {0,{[],[]}}, Repo, HexRegistry, State) of
325+
case get_latest_version(Dep, Repo, HexRegistry, State) of
328326
none ->
329327
not_found;
330328
{ok, Vsn} ->
@@ -338,7 +336,7 @@ resolve_version(Dep, DepVsn, _OldHash, Hash, HexRegistry, State) ->
338336
{error, {invalid_vsn, DepVsn}};
339337
_ ->
340338
Fun = fun(Repo) ->
341-
case resolve_version_(Dep, DepVsn, Repo, HexRegistry, State) of
339+
case get_package_versions(Dep, DepVsn, Repo, HexRegistry, State) of
342340
none ->
343341
not_found;
344342
{ok, Vsn} ->
@@ -373,92 +371,11 @@ handle_missing_no_exception(Fun, Dep, State) ->
373371
Result
374372
end.
375373

376-
resolve_version_(Dep, DepVsn, Repo, HexRegistry, State) ->
377-
case DepVsn of
378-
<<"~>", Vsn/binary>> ->
379-
highest_matching(Dep, rm_ws(Vsn), Repo, HexRegistry, State);
380-
<<">=", Vsn/binary>> ->
381-
cmp(Dep, rm_ws(Vsn), Repo, HexRegistry, State, fun ec_semver:gte/2);
382-
<<">", Vsn/binary>> ->
383-
cmp(Dep, rm_ws(Vsn), Repo, HexRegistry, State, fun ec_semver:gt/2);
384-
<<"<=", Vsn/binary>> ->
385-
cmpl(Dep, rm_ws(Vsn), Repo, HexRegistry, State, fun ec_semver:lte/2);
386-
<<"<", Vsn/binary>> ->
387-
cmpl(Dep, rm_ws(Vsn), Repo, HexRegistry, State, fun ec_semver:lt/2);
388-
<<"==", Vsn/binary>> ->
389-
{ok, Vsn};
390-
Vsn ->
391-
{ok, Vsn}
392-
end.
393-
394-
rm_ws(<<" ", R/binary>>) ->
395-
ec_semver:parse(rm_ws(R));
396-
rm_ws(R) ->
397-
ec_semver:parse(R).
398-
399374
valid_vsn(Vsn) ->
400-
%% Regepx from https://github.com/sindresorhus/semver-regex/blob/master/index.js
401-
SemVerRegExp = "v?(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(\\.(0|[1-9][0-9]*))?"
402-
"(-[0-9a-z-]+(\\.[0-9a-z-]+)*)?(\\+[0-9a-z-]+(\\.[0-9a-z-]+)*)?",
403-
SupportedVersions = "^(>=?|<=?|~>|==)?\\s*" ++ SemVerRegExp ++ "$",
404-
re:run(Vsn, SupportedVersions, [unicode]) =/= nomatch.
405-
406-
highest_matching(Dep, Vsn, Repo, HexRegistry, State) ->
407-
find_highest_matching_(Dep, Vsn, #{name => Repo}, HexRegistry, State).
408-
409-
cmp(Dep, Vsn, Repo, HexRegistry, State, CmpFun) ->
410-
case get_package_versions(Dep, Vsn, Repo, HexRegistry, State) of
411-
[] ->
412-
none;
413-
Vsns ->
414-
cmp_(undefined, Vsn, Vsns, CmpFun)
415-
end.
416-
417-
cmp_(undefined, MinVsn, [], _CmpFun) ->
418-
{ok, MinVsn};
419-
cmp_(HighestDepVsn, _MinVsn, [], _CmpFun) ->
420-
{ok, HighestDepVsn};
421-
422-
cmp_(BestMatch, MinVsn, [Vsn | R], CmpFun) ->
423-
case CmpFun(Vsn, MinVsn) of
424-
true ->
425-
cmp_(Vsn, Vsn, R, CmpFun);
426-
false ->
427-
cmp_(BestMatch, MinVsn, R, CmpFun)
428-
end.
429-
430-
%% We need to treat this differently since we want a version that is LOWER but
431-
%% the highest possible one.
432-
cmpl(Dep, Vsn, Repo, HexRegistry, State, CmpFun) ->
433-
case get_package_versions(Dep, Vsn, Repo, HexRegistry, State) of
434-
[] ->
435-
none;
436-
Vsns ->
437-
cmpl_(undefined, Vsn, Vsns, CmpFun)
438-
end.
439-
440-
cmpl_(undefined, MaxVsn, [], _CmpFun) ->
441-
{ok, MaxVsn};
442-
cmpl_(HighestDepVsn, _MaxVsn, [], _CmpFun) ->
443-
{ok, HighestDepVsn};
444-
445-
cmpl_(undefined, MaxVsn, [Vsn | R], CmpFun) ->
446-
case CmpFun(Vsn, MaxVsn) of
447-
true ->
448-
cmpl_(Vsn, MaxVsn, R, CmpFun);
449-
false ->
450-
cmpl_(undefined, MaxVsn, R, CmpFun)
451-
end;
375+
rebar_verl:valid_requirement(Vsn).
452376

453-
cmpl_(BestMatch, MaxVsn, [Vsn | R], CmpFun) ->
454-
case CmpFun(Vsn, MaxVsn) of
455-
true ->
456-
case ec_semver:gte(Vsn, BestMatch) of
457-
true ->
458-
cmpl_(Vsn, MaxVsn, R, CmpFun);
459-
false ->
460-
cmpl_(BestMatch, MaxVsn, R, CmpFun)
461-
end;
462-
false ->
463-
cmpl_(BestMatch, MaxVsn, R, CmpFun)
464-
end.
377+
get_latest_version(Dep, Repo, HexRegistry, State) ->
378+
verify_table(State),
379+
Vsns = ets:select(HexRegistry, [{#package{key={'$1', '$2', '$3'}, _='_'},
380+
[{'==', '$1', Dep}, {'==', '$3', Repo}], ['$2']}]),
381+
handle_vsns(Vsns).

apps/rebar/src/rebar_verl.erl

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
2+
%% ex: ts=4 sw=4 et
3+
-module(rebar_verl).
4+
5+
-export([
6+
parse_requirement/1,
7+
valid_requirement/1,
8+
parse_version/1,
9+
format_version/1
10+
]).
11+
12+
parse_requirement(Vsn) ->
13+
Vsn1 =
14+
case verl:parse(Vsn) of
15+
{ok, _} ->
16+
list_to_binary([<<"=> ">>, Vsn]);
17+
_ ->
18+
Vsn
19+
end,
20+
21+
verl:parse_requirement(Vsn1).
22+
23+
valid_requirement(Vsn) ->
24+
case verl:parse(Vsn) of
25+
{ok, _} ->
26+
true;
27+
_ ->
28+
case verl:parse_requirement(Vsn) of
29+
{ok, _} ->
30+
true;
31+
_ ->
32+
false
33+
end
34+
end.
35+
36+
parse_version(Vsn) ->
37+
{ok, Res} = verl:parse(Vsn),
38+
Res.
39+
40+
format_version(#{major := Major, minor := Minor, patch := Patch, pre := Pre, build := Build}) ->
41+
Base = io_lib:format("~p.~p.~p", [Major, Minor, Patch]),
42+
WithPre = case Pre of
43+
[] ->
44+
Base;
45+
_ ->
46+
[Base, [$-, Pre]]
47+
end,
48+
WithBuild = case Build of
49+
undefined ->
50+
WithPre;
51+
_ ->
52+
[WithPre, io_lib:format("+~p", [Build])]
53+
end,
54+
WithBuild.
55+

apps/rebar/test/mock_pkg_resource.erl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,21 +173,23 @@ to_index(AllDeps, Dict, Repos) ->
173173
DKB <- [ec_cnv:to_binary(DK)],
174174
DVB <- [ec_cnv:to_binary(DV)]],
175175
Repo = rebar_test_utils:random_element(Repos),
176+
{ok, ParsedV} = verl:parse(V),
176177

177-
ets:insert(?PACKAGE_TABLE, #package{key={N, ec_semver:parse(V), Repo},
178+
ets:insert(?PACKAGE_TABLE, #package{key={N, ParsedV, Repo},
178179
dependencies=parse_deps(DepsList),
179180
retired=false,
180181
inner_checksum = <<"inner_checksum">>,
181182
outer_checksum = <<"checksum">>})
182183
end, ok, Dict),
183184

184185
lists:foreach(fun({{Name, Vsn}, _}) ->
186+
{ok, ParsedV} = verl:parse(Vsn),
185187
case lists:any(fun(R) ->
186-
ets:member(?PACKAGE_TABLE, {ec_cnv:to_binary(Name), ec_semver:parse(Vsn), R})
188+
ets:member(?PACKAGE_TABLE, {ec_cnv:to_binary(Name), ParsedV, R})
187189
end, Repos) of
188190
false ->
189191
Repo = rebar_test_utils:random_element(Repos),
190-
ets:insert(?PACKAGE_TABLE, #package{key={ec_cnv:to_binary(Name), ec_semver:parse(Vsn), Repo},
192+
ets:insert(?PACKAGE_TABLE, #package{key={ec_cnv:to_binary(Name), ParsedV, Repo},
191193
dependencies=[],
192194
retired=false,
193195
inner_checksum = <<"inner_checksum">>,

0 commit comments

Comments
 (0)