Packages

rabbit_common

4.3.4
4.3.4 4.2.1 4.2.0 retired 4.2.0-rc.1 retired 4.1.6 4.1.5 retired 4.1.5-rc.2 retired 4.1.5-rc.1 4.0.3 4.0.3-rc.1 4.0.2 4.0.2-rc.2 4.0.2-rc.1 4.0.1 4.0.0 4.0.0-rc.2 4.0.0-rc.1 3.13.7 3.13.6 3.13.5 3.13.4 3.13.3 3.13.2 3.13.2-rc.1 3.13.1 3.13.0 3.13.0-rc.6 3.13.0-rc.5 3.13.0-rc.4 3.13.0-rc.3 3.13.0-rc.2 3.13.0-rc.1 3.12.14 3.12.13 3.12.12 3.12.11 3.12.10 3.12.9 3.12.8 3.12.7 3.12.6 3.12.5 3.12.4 3.12.3 3.12.2 3.12.1 3.12.0 3.12.0-rc.4 3.12.0-rc.3 3.12.0-rc.2 3.12.0-rc.1 3.11.28 3.11.27 3.11.26 3.11.25 3.11.24 3.11.23 3.11.22 3.11.21 3.11.20 3.11.19 3.11.18 3.11.17 3.11.16 3.11.15 3.11.14 3.11.13 3.11.12 3.11.11 3.11.10 3.11.9 3.11.8 3.11.7 3.11.6 3.11.5 3.11.4 3.11.3 3.11.2 3.11.1 3.11.0 3.11.0-rc.2 3.11.0-rc.1 3.11.0-1 3.10.25 3.10.24 3.10.23 3.10.22 3.10.21 3.10.20 3.10.19 3.10.18 3.10.17 3.10.16 3.10.15 3.10.14 3.10.13 3.10.12 3.10.11 3.10.10 3.10.9 3.10.8 3.10.7 3.10.6 3.10.5 3.10.4 3.10.3 3.10.2 3.10.1 3.10.0 3.10.0-rc.6 3.10.0-rc.5 3.9.29 3.9.28 3.9.27 3.9.26 3.9.25 3.9.24 3.9.23 3.9.22 3.9.21 3.9.20 3.9.19 3.9.18 3.9.17 3.9.16 3.9.15 3.9.11 3.9.10 3.9.9 3.9.8 3.9.7 3.9.6 3.9.5 3.9.4 3.9.3 3.9.2 3.9.1 3.8.35 3.8.34 3.8.33 3.8.32 3.8.31 3.8.30 3.8.26 3.8.25 3.8.24 3.8.23 3.8.22 3.8.21 3.8.20 3.8.19 3.8.14 3.8.12-rc.3 3.8.12-rc.2 3.8.12-rc.1 3.8.11 3.8.10 3.8.10-rc.6 3.8.10-rc.5 3.8.10-rc.1 3.8.9 3.8.8 3.8.7 3.8.6 3.8.6-rc.2 3.8.6-rc.1 3.8.5 3.8.5-rc.2 3.8.5-rc.1 3.8.4 3.8.4-rc.3 3.8.4-rc.1 3.8.3 3.8.3-rc.2 3.8.3-rc.1 3.8.2 3.8.2-rc.1 3.8.1 3.8.1-rc.1 3.8.0 3.8.0-rc.3 3.8.0-rc.2 3.8.0-rc.1 3.7.28 3.7.27 3.7.27-rc.2 3.7.27-rc.1 3.7.26 3.7.25 3.7.25-rc.1 3.7.24 3.7.24-rc.2 3.7.24-rc.1 3.7.23 3.7.23-rc.1 3.7.22 3.7.22-rc.2 3.7.22-rc.1 3.7.21 3.7.20 3.7.20-rc.2 3.7.20-rc.1 3.7.19 3.7.18 3.7.18-rc.1 3.7.17 3.7.17-rc.3 3.7.17-rc.2 3.7.17-rc.1 retired 3.7.16 retired 3.7.16-rc.4 retired 3.7.16-rc.3 retired 3.7.16-rc.2 retired 3.7.16-rc.1 retired 3.7.16-beta.1 3.7.15 3.7.14 3.7.14-rc.2 3.7.14-rc.1 3.7.13 3.7.13-rc.2 3.7.13-rc.1 3.7.12 3.7.12-rc.2 3.7.12-rc.1 3.7.11 3.7.11-rc.2 3.7.11-rc.1 3.7.10-rc.4 3.7.10-rc.3 3.7.10-rc.2 3.7.10-rc.1 3.7.9 3.7.9-rc.3 3.7.9-rc.2 3.7.8 3.7.8-rc.4 3.7.8-rc.3 3.7.8-rc.2 3.7.8-rc.1 3.7.7 3.7.7-rc.2 3.7.7-rc.1 3.7.6 3.7.6-rc.2 3.7.6-rc.1 3.7.5 3.7.5-rc.1 3.7.4 3.7.4-rc.4 3.7.4-rc.3 3.7.4-rc.2 3.7.4-rc.1 3.7.3 3.7.3-rc.2 3.7.3-rc.1 3.7.2 3.7.1 3.7.0-rc.2 3.7.0-alpha.544 3.7.0-alpha.542 3.6.16 3.6.16-rc.1 3.6.15 3.6.15-rc.1 3.6.14 3.6.13 3.6.12 3.6.11 3.6.10 3.6.9 3.6.8 3.6.7 3.6.7-pre.1 3.5.6 3.5.0 3.4.0 3.3.5 3.0.2 0.0.0-rc.1

Modules shared by rabbitmq-server and rabbitmq-erlang-client

Current section

Files

Jump to
rabbit_common src rabbit_semver.erl
Raw

src/rabbit_semver.erl

%%% vi:ts=4 sw=4 et
%%% Imported from https://github.com/erlware/erlware_commons.git
%%% Commit 09168347525916e291c8aa6e3073e260e5f4a116
%%% - We export normalize/1.
%%% - We add a few more testcases around string/binary comparison.
%%%-------------------------------------------------------------------
%%% @copyright (C) 2011, Erlware LLC
%%% @doc
%%% Helper functions for working with semver versioning strings.
%%% See https://semver.org/ for the spec.
%%% @end
%%%-------------------------------------------------------------------
-module(rabbit_semver).
-export([parse/1,
format/1,
normalize_then_format/1,
eql/2,
gt/2,
gte/2,
lt/2,
lte/2,
pes/2,
normalize/1,
between/3]).
%% For internal use by the rabbit_semver_parser peg
-export([internal_parse_version/1]).
-export_type([semver/0,
version_string/0,
any_version/0]).
%%%===================================================================
%%% Public Types
%%%===================================================================
-type version_element() :: non_neg_integer() | binary().
-type major_minor_patch_minpatch() ::
version_element()
| {version_element(), version_element()}
| {version_element(), version_element(), version_element()}
| {version_element(), version_element(),
version_element(), version_element()}.
-type alpha_part() :: integer() | binary() | string().
-type alpha_info() :: {PreRelease::[alpha_part()],
BuildVersion::[alpha_part()]}.
-type semver() :: {major_minor_patch_minpatch(), alpha_info()}.
-type version_string() :: string() | binary().
-type any_version() :: version_string() | semver().
%%%===================================================================
%%% API
%%%===================================================================
%% @doc Parse a version string or binary into a semver tuple.
-spec parse(any_version()) -> semver().
parse(Version) when is_list(Version) ->
case rabbit_semver_parser:parse(Version) of
{fail, _} ->
{iolist_to_binary(Version), {[],[]}};
Good ->
Good
end;
parse(Version) when is_binary(Version) ->
case rabbit_semver_parser:parse(Version) of
{fail, _} ->
{Version, {[],[]}};
Good ->
Good
end;
parse(Version) ->
Version.
-spec format(semver()) -> iolist().
format({Maj, {AlphaPart, BuildPart}})
when is_integer(Maj);
is_binary(Maj) ->
[format_version_part(Maj),
format_vsn_rest(<<"-">>, AlphaPart),
format_vsn_rest(<<"+">>, BuildPart)];
format({{Maj, Min}, {AlphaPart, BuildPart}}) ->
[format_version_part(Maj), ".",
format_version_part(Min),
format_vsn_rest(<<"-">>, AlphaPart),
format_vsn_rest(<<"+">>, BuildPart)];
format({{Maj, Min, Patch}, {AlphaPart, BuildPart}}) ->
[format_version_part(Maj), ".",
format_version_part(Min), ".",
format_version_part(Patch),
format_vsn_rest(<<"-">>, AlphaPart),
format_vsn_rest(<<"+">>, BuildPart)];
format({{Maj, Min, Patch, MinPatch}, {AlphaPart, BuildPart}}) ->
[format_version_part(Maj), ".",
format_version_part(Min), ".",
format_version_part(Patch), ".",
format_version_part(MinPatch),
format_vsn_rest(<<"-">>, AlphaPart),
format_vsn_rest(<<"+">>, BuildPart)].
-spec normalize_then_format(any_version()) -> binary().
normalize_then_format(Version) ->
{{Maj, Min, Patch, MinPatch}, _} = normalize(parse(Version)),
iolist_to_binary(format({{Maj, Min, Patch, MinPatch}, {[], []}})).
-spec format_version_part(integer() | binary()) -> iolist().
format_version_part(Vsn) when is_integer(Vsn) ->
integer_to_list(Vsn);
format_version_part(Vsn) when is_binary(Vsn) ->
Vsn.
%% @doc Test for equality between semver versions.
-spec eql(any_version(), any_version()) -> boolean().
eql(VsnA, VsnB) ->
NVsnA = normalize(parse(VsnA)),
NVsnB = normalize(parse(VsnB)),
NVsnA =:= NVsnB.
%% @doc Test that VsnA is greater than VsnB.
-spec gt(any_version(), any_version()) -> boolean().
gt(VsnA, VsnB) ->
gt_normalized(normalize(parse(VsnA)), normalize(parse(VsnB))).
-spec gt_normalized(semver(), semver()) -> boolean().
gt_normalized({MMPA, {AlphaA, PatchA}}, {MMPB, {AlphaB, PatchB}}) ->
(MMPA > MMPB)
orelse
((MMPA =:= MMPB)
andalso
((AlphaA =:= [] andalso AlphaB =/= [])
orelse
((not (AlphaB =:= [] andalso AlphaA =/= []))
andalso
(AlphaA > AlphaB))))
orelse
((MMPA =:= MMPB)
andalso
(AlphaA =:= AlphaB)
andalso
((PatchB =:= [] andalso PatchA =/= [])
orelse
PatchA > PatchB)).
%% @doc Test that VsnA is greater than or equal to VsnB.
-spec gte(any_version(), any_version()) -> boolean().
gte(VsnA, VsnB) ->
NVsnA = normalize(parse(VsnA)),
NVsnB = normalize(parse(VsnB)),
NVsnA =:= NVsnB orelse gt_normalized(NVsnA, NVsnB).
%% @doc Test that VsnA is less than VsnB.
-spec lt(any_version(), any_version()) -> boolean().
lt(VsnA, VsnB) ->
lt_normalized(normalize(parse(VsnA)), normalize(parse(VsnB))).
-spec lt_normalized(semver(), semver()) -> boolean().
lt_normalized({MMPA, {AlphaA, PatchA}}, {MMPB, {AlphaB, PatchB}}) ->
(MMPA < MMPB)
orelse
((MMPA =:= MMPB)
andalso
((AlphaB =:= [] andalso AlphaA =/= [])
orelse
((not (AlphaA =:= [] andalso AlphaB =/= []))
andalso
(AlphaA < AlphaB))))
orelse
((MMPA =:= MMPB)
andalso
(AlphaA =:= AlphaB)
andalso
((PatchA =:= [] andalso PatchB =/= [])
orelse
PatchA < PatchB)).
%% @doc Test that VsnA is less than or equal to VsnB.
-spec lte(any_version(), any_version()) -> boolean().
lte(VsnA, VsnB) ->
NVsnA = normalize(parse(VsnA)),
NVsnB = normalize(parse(VsnB)),
NVsnA =:= NVsnB orelse lt_normalized(NVsnA, NVsnB).
%% @doc Test that VsnMatch is greater than or equal to Vsn1 and
%% less than or equal to Vsn2.
-spec between(any_version(), any_version(), any_version()) -> boolean().
between(Vsn1, Vsn2, VsnMatch) ->
NVsn1 = normalize(parse(Vsn1)),
NVsn2 = normalize(parse(Vsn2)),
NVsnMatch = normalize(parse(VsnMatch)),
(NVsnMatch =:= NVsn1 orelse gt_normalized(NVsnMatch, NVsn1)) andalso
(NVsnMatch =:= NVsn2 orelse lt_normalized(NVsnMatch, NVsn2)).
%% @doc Pessimistic version constraint check (the ~> operator).
%%
%% "~> 2.6" matches versions >= 2.6.0 and < 3.0.0
%% "~> 2.6.5" matches versions >= 2.6.5 and < 2.7.0
-spec pes(any_version(), any_version()) -> boolean().
pes(VsnA, VsnB) ->
internal_pes(parse(VsnA), parse(VsnB)).
%%%===================================================================
%%% Friend Functions
%%%===================================================================
%% @doc Callback for the PEG parser to build a semver tuple from parsed tokens.
-spec internal_parse_version(iolist()) -> semver().
internal_parse_version([MMP, AlphaPart, BuildPart, _]) ->
{parse_major_minor_patch_minpatch(MMP), {parse_alpha_part(AlphaPart),
parse_alpha_part(BuildPart)}}.
-spec parse_major_minor_patch_minpatch(iolist()) -> major_minor_patch_minpatch().
parse_major_minor_patch_minpatch([MajVsn, [], [], []]) ->
strip_maj_version(MajVsn);
parse_major_minor_patch_minpatch([MajVsn, [<<".">>, MinVsn], [], []]) ->
{strip_maj_version(MajVsn), MinVsn};
parse_major_minor_patch_minpatch([MajVsn,
[<<".">>, MinVsn],
[<<".">>, PatchVsn], []]) ->
{strip_maj_version(MajVsn), MinVsn, PatchVsn};
parse_major_minor_patch_minpatch([MajVsn,
[<<".">>, MinVsn],
[<<".">>, PatchVsn],
[<<".">>, MinPatch]]) ->
{strip_maj_version(MajVsn), MinVsn, PatchVsn, MinPatch}.
-spec parse_alpha_part(iolist()) -> [alpha_part()].
parse_alpha_part([]) ->
[];
parse_alpha_part([_, AV1, Rest]) ->
[iolist_to_binary(AV1) |
[format_alpha_part(Part) || Part <- Rest]].
%% Per semver spec, numeric identifiers must be compared as integers.
-spec format_alpha_part(iolist()) -> integer() | binary().
format_alpha_part([<<".">>, AlphaPart]) ->
Bin = iolist_to_binary(AlphaPart),
try
binary_to_integer(Bin)
catch
error:badarg ->
Bin
end.
%%%===================================================================
%%% Internal Functions
%%%===================================================================
-spec strip_maj_version(iolist()) -> version_element().
strip_maj_version([<<"v">>, MajVsn]) ->
MajVsn;
strip_maj_version([[], MajVsn]) ->
MajVsn;
strip_maj_version(MajVsn) ->
MajVsn.
-spec to_list(integer() | binary() | string()) -> string() | binary().
to_list(Detail) when is_integer(Detail) ->
integer_to_list(Detail);
to_list(Detail) when is_list(Detail); is_binary(Detail) ->
Detail.
-spec format_vsn_rest(binary() | string(), [integer() | binary()]) -> iolist().
format_vsn_rest(_TypeMark, []) ->
[];
format_vsn_rest(TypeMark, [Head | Rest]) ->
[TypeMark, Head |
[[".", to_list(Detail)] || Detail <- Rest]].
%% @doc Normalize a semver tuple to a 4-part version for comparison.
-spec normalize(semver()) -> semver().
normalize({Vsn, {Alpha, Build}}) when is_binary(Vsn) ->
case extract_version_from_build(Build) of
{ok, ExtractedVsn} ->
{normalize_version(ExtractedVsn), {Alpha, Build}};
none ->
{{Vsn, 0, 0, 0}, {Alpha, Build}}
end;
normalize({Vsn, Rest}) when is_integer(Vsn) ->
{{Vsn, 0, 0, 0}, Rest};
normalize({{Maj, Min}, Rest}) ->
{{Maj, Min, 0, 0}, Rest};
normalize({{Maj, Min, Patch}, Rest}) ->
{{Maj, Min, Patch, 0}, Rest};
normalize({{_, _, _, _}, {_, _}} = Vsn) ->
Vsn.
-spec normalize_version(major_minor_patch_minpatch()) ->
{version_element(), non_neg_integer(), non_neg_integer(), non_neg_integer()}.
normalize_version(Vsn) when is_integer(Vsn) ->
{Vsn, 0, 0, 0};
normalize_version({Maj, Min}) ->
{Maj, Min, 0, 0};
normalize_version({Maj, Min, Patch}) ->
{Maj, Min, Patch, 0};
normalize_version({Maj, Min, Patch, MinPatch}) ->
{Maj, Min, Patch, MinPatch}.
%% Extracts version from build metadata for prefixed versions like
%% "tanzu+rabbitmq.v3.13.12.dev" where the actual version is embedded.
-spec extract_version_from_build([alpha_part()]) ->
{ok, major_minor_patch_minpatch()} | none.
extract_version_from_build([]) ->
none;
extract_version_from_build([<<"v", Rest/binary>> | T]) ->
try
Major = binary_to_integer(Rest),
build_version_tuple(Major, T)
catch
error:badarg ->
extract_version_from_build(T)
end;
extract_version_from_build([_ | T]) ->
extract_version_from_build(T).
-spec build_version_tuple(non_neg_integer(), [alpha_part()]) ->
{ok, major_minor_patch_minpatch()}.
build_version_tuple(Major, [Minor, Patch, MinPatch | _])
when is_integer(Minor), is_integer(Patch), is_integer(MinPatch) ->
{ok, {Major, Minor, Patch, MinPatch}};
build_version_tuple(Major, [Minor, Patch | _])
when is_integer(Minor), is_integer(Patch) ->
{ok, {Major, Minor, Patch}};
build_version_tuple(Major, [Minor | _]) when is_integer(Minor) ->
{ok, {Major, Minor}};
build_version_tuple(Major, _) ->
{ok, Major}.
-spec internal_pes(semver(), semver()) -> boolean().
internal_pes(VsnA, {{LM, LMI}, _})
when is_integer(LM), is_integer(LMI) ->
gte(VsnA, {{LM, LMI, 0}, {[], []}}) andalso
lt(VsnA, {{LM + 1, 0, 0, 0}, {[], []}});
internal_pes(VsnA, {{LM, LMI, LP}, _})
when is_integer(LM), is_integer(LMI), is_integer(LP) ->
gte(VsnA, {{LM, LMI, LP}, {[], []}}) andalso
lt(VsnA, {{LM, LMI + 1, 0, 0}, {[], []}});
internal_pes(VsnA, {{LM, LMI, LP, LMP}, _})
when is_integer(LM), is_integer(LMI), is_integer(LP), is_integer(LMP) ->
gte(VsnA, {{LM, LMI, LP, LMP}, {[], []}}) andalso
lt(VsnA, {{LM, LMI, LP + 1, 0}, {[], []}});
internal_pes(Vsn, LVsn) ->
gte(Vsn, LVsn).