New upstream version 3.18.0

This commit is contained in:
Philipp Huebner 2022-01-08 15:36:34 +01:00
parent 36bc1e1299
commit b15a9b3527
62 changed files with 776 additions and 348 deletions

View File

@ -6,7 +6,7 @@ FROM erlang:20.3.8.1-alpine as builder
# "The LABEL instruction adds metadata to an image." # "The LABEL instruction adds metadata to an image."
LABEL stage=builder LABEL stage=builder
# Install git for fetching non-hex depenencies. Also allows rebar3 # Install git for fetching non-hex dependencies. Also allows rebar3
# to find it's own git version. # to find it's own git version.
# Add any other Alpine libraries needed to compile the project here. # Add any other Alpine libraries needed to compile the project here.
# See https://wiki.alpinelinux.org/wiki/Local_APK_cache for details # See https://wiki.alpinelinux.org/wiki/Local_APK_cache for details

View File

@ -1,6 +1,6 @@
bbmustache bbmustache
=========== ===========
[![Build Status](https://travis-ci.org/soranoba/bbmustache.svg?branch=master)](https://travis-ci.org/soranoba/bbmustache) [![CircleCI](https://circleci.com/gh/soranoba/bbmustache/tree/master.svg?style=svg)](https://circleci.com/gh/soranoba/bbmustache/tree/master)
[![hex.pm version](https://img.shields.io/hexpm/v/bbmustache.svg)](https://hex.pm/packages/bbmustache) [![hex.pm version](https://img.shields.io/hexpm/v/bbmustache.svg)](https://hex.pm/packages/bbmustache)
Binary pattern match Based Mustache template engine for Erlang/OTP. Binary pattern match Based Mustache template engine for Erlang/OTP.

View File

@ -2,6 +2,7 @@
{erl_opts, [ {erl_opts, [
{platform_define, "^[0-9]+", namespaced_types}, {platform_define, "^[0-9]+", namespaced_types},
{platform_define, "^20", unicode_supported},
warnings_as_errors, warnings_as_errors,
warn_export_all, warn_export_all,
warn_untyped_record warn_untyped_record
@ -16,6 +17,7 @@
{edoc_opts, [ {edoc_opts, [
{doclet, edown_doclet}, {doclet, edown_doclet},
{app_default, "http://www.erlang.org/doc/man"},
{dialyzer_specs, all}, {dialyzer_specs, all},
{report_missing_type, true}, {report_missing_type, true},
{report_type_mismatch, true}, {report_type_mismatch, true},
@ -38,7 +40,7 @@
{deps, {deps,
[ [
{jsone, "1.4.6"}, {jsone, "1.4.6"},
{mustache_spec, ".*", {git, "git://github.com/soranoba/spec.git", {tag, "v1.1.3-erl"}}} {mustache_spec, ".*", {git, "git://github.com/soranoba/spec.git", {tag, "v1.2.1-erl"}}}
]}, ]},
{plugins, [rebar3_raw_deps]} {plugins, [rebar3_raw_deps]}
]}, ]},
@ -52,7 +54,7 @@
]}, ]},
{doc, [{deps, {doc, [{deps,
[ [
{edown, ".*", {git, "git://github.com/uwiger/edown.git", {branch, "master"}}} {edown, ".*", {git, "git://github.com/uwiger/edown.git", {tag, "0.8.3"}}}
]} ]}
]}, ]},
{bench, [{deps, {bench, [{deps,

View File

@ -1,6 +1,6 @@
{application,bbmustache, {application,bbmustache,
[{description,"Binary pattern match Based Mustache template engine for Erlang/OTP"}, [{description,"Binary pattern match Based Mustache template engine for Erlang/OTP"},
{vsn,"1.10.0"}, {vsn,"1.12.2"},
{registered,[]}, {registered,[]},
{applications,[kernel,stdlib]}, {applications,[kernel,stdlib]},
{maintainers,["Hinagiku Soranoba"]}, {maintainers,["Hinagiku Soranoba"]},

View File

@ -70,23 +70,11 @@
%% %%
%% In addition, `.' have a special meaning. <br /> %% In addition, `.' have a special meaning. <br />
%% (1) `parent.child' ... find the child in the parent. <br /> %% (1) `parent.child' ... find the child in the parent. <br />
%% (2) `.' ... It means this. However, the type of correspond is only `[integer() | float() | binary() | string() | atom()]'. Otherwise, the behavior is undefined. %% (2) `.' ... It means current context.
%% %%
-type source() :: binary(). -type source() :: binary().
%% If you use lamda expressions, the original text is necessary. %% If you use lamda expressions, the original text is necessary.
%%
%% ```
%% e.g.
%% template:
%% {{#lamda}}a{{b}}c{{/lamda}}
%% parse result:
%% {'#', <<"lamda">>, [<<"a">>, {'n', <<"b">>}, <<"c">>], <<"a{{b}}c">>}
%% '''
%%
%% NOTE:
%% Since the binary reference is used internally, it is not a capacitively large waste.
%% However, the greater the number of tags used, it should use the wasted memory.
-type tag() :: {n, [key()]} -type tag() :: {n, [key()]}
| {'&', [key()]} | {'&', [key()]}
@ -94,6 +82,19 @@
| {'^', [key()], [tag()]} | {'^', [key()], [tag()]}
| {'>', key(), Indent :: source()} | {'>', key(), Indent :: source()}
| binary(). % plain text | binary(). % plain text
%% Tag is the internal data structure of the result of parsing the mustache template.
%%
%% ```
%% e.g.
%% template:
%% {{#lamda}}a{{b}}c{{/lamda}}
%% parse result:
%% {'#', [<<"lamda">>], [<<"a">>, {'n', <<"b">>}, <<"c">>], <<"a{{b}}c">>}
%% '''
%%
%% NOTE:
%% Since the binary reference is used internally, it is not a capacitively large waste.
%% However, the greater the number of tags used, it uses the wasted memory.
-record(?MODULE, -record(?MODULE,
{ {
@ -235,7 +236,7 @@ compile(Template, Data) ->
%% All keys MUST be same type. %% All keys MUST be same type.
-spec compile(template(), data(), [compile_option()]) -> binary(). -spec compile(template(), data(), [compile_option()]) -> binary().
compile(#?MODULE{data = Tags} = T, Data, Options) -> compile(#?MODULE{data = Tags} = T, Data, Options) ->
Ret = compile_impl(Tags, Data, [], T#?MODULE{options = Options, data = []}), Ret = compile_impl(Tags, Data, [], T#?MODULE{options = Options, data = [], context_stack = [Data]}),
iolist_to_binary(lists:reverse(Ret)). iolist_to_binary(lists:reverse(Ret)).
%% @doc Default value serializer for templtated values %% @doc Default value serializer for templtated values
@ -246,10 +247,12 @@ default_value_serializer(Float) when is_float(Float) ->
%% NOTE: It is the same behaviour as io_lib:format("~p", [Float]), but it is fast than. %% NOTE: It is the same behaviour as io_lib:format("~p", [Float]), but it is fast than.
%% http://www.cs.indiana.edu/~dyb/pubs/FP-Printing-PLDI96.pdf %% http://www.cs.indiana.edu/~dyb/pubs/FP-Printing-PLDI96.pdf
io_lib_format:fwrite_g(Float); io_lib_format:fwrite_g(Float);
default_value_serializer(Atom) when is_atom(Atom) ->
list_to_binary(atom_to_list(Atom));
default_value_serializer(X) when is_map(X); is_tuple(X) -> default_value_serializer(X) when is_map(X); is_tuple(X) ->
error(unsupported_term, [X]); error(unsupported_term, [X]);
default_value_serializer(X) when X =:= null; X =:= nil ->
[];
default_value_serializer(X) when is_atom(X) ->
unicode:characters_to_binary(atom_to_list(X));
default_value_serializer(X) -> default_value_serializer(X) ->
X. X.
@ -272,7 +275,7 @@ compile_impl([], _, Result, _) ->
Result; Result;
compile_impl([{n, Keys} | T], Data, Result, State) -> compile_impl([{n, Keys} | T], Data, Result, State) ->
ValueSerializer = proplists:get_value(value_serializer, State#?MODULE.options, fun default_value_serializer/1), ValueSerializer = proplists:get_value(value_serializer, State#?MODULE.options, fun default_value_serializer/1),
Value = iolist_to_binary(ValueSerializer(get_data_recursive(Keys, Data, <<>>, State))), Value = unicode:characters_to_binary(ValueSerializer(get_data_recursive(Keys, Data, <<>>, State))),
EscapeFun = proplists:get_value(escape_fun, State#?MODULE.options, fun escape/1), EscapeFun = proplists:get_value(escape_fun, State#?MODULE.options, fun escape/1),
compile_impl(T, Data, ?ADD(EscapeFun(Value), Result), State); compile_impl(T, Data, ?ADD(EscapeFun(Value), Result), State);
compile_impl([{'&', Keys} | T], Data, Result, State) -> compile_impl([{'&', Keys} | T], Data, Result, State) ->
@ -280,24 +283,27 @@ compile_impl([{'&', Keys} | T], Data, Result, State) ->
compile_impl(T, Data, ?ADD(ValueSerializer(get_data_recursive(Keys, Data, <<>>, State)), Result), State); compile_impl(T, Data, ?ADD(ValueSerializer(get_data_recursive(Keys, Data, <<>>, State)), Result), State);
compile_impl([{'#', Keys, Tags, Source} | T], Data, Result, State) -> compile_impl([{'#', Keys, Tags, Source} | T], Data, Result, State) ->
Value = get_data_recursive(Keys, Data, false, State), Value = get_data_recursive(Keys, Data, false, State),
NestedState = State#?MODULE{context_stack = [Data | State#?MODULE.context_stack]}, NestedState = State#?MODULE{context_stack = [Value | State#?MODULE.context_stack]},
case is_recursive_data(Value) of case {is_falsy(Value), is_recursive_data(Value)} of
true -> {true, _} -> compile_impl(T, Data, Result, State);
{_, true} ->
compile_impl(T, Data, compile_impl(Tags, Value, Result, NestedState), State); compile_impl(T, Data, compile_impl(Tags, Value, Result, NestedState), State);
_ when is_list(Value) -> _ when is_list(Value) ->
compile_impl(T, Data, lists:foldl(fun(X, Acc) -> compile_impl(Tags, X, Acc, NestedState) end, NextResult = lists:foldl(fun(X, Acc) ->
Result, Value), State); %% It doesn't need to add Value to context_stack because List is not context.
_ when Value =:= false -> LoopState = State#?MODULE{context_stack = [X | State#?MODULE.context_stack]},
compile_impl(T, Data, Result, State); compile_impl(Tags, X, Acc, LoopState)
_ when is_function(Value, 2) -> end, Result, Value),
compile_impl(T, Data, NextResult, State);
_ when is_function(Value, 2) ->
Ret = Value(Source, fun(Text) -> render(Text, Data, State#?MODULE.options) end), Ret = Value(Source, fun(Text) -> render(Text, Data, State#?MODULE.options) end),
compile_impl(T, Data, ?ADD(Ret, Result), State); compile_impl(T, Data, ?ADD(Ret, Result), State);
_ -> _ ->
compile_impl(T, Data, compile_impl(Tags, Data, Result, State), State) compile_impl(T, Data, compile_impl(Tags, Value, Result, NestedState), State)
end; end;
compile_impl([{'^', Keys, Tags} | T], Data, Result, State) -> compile_impl([{'^', Keys, Tags} | T], Data, Result, State) ->
Value = get_data_recursive(Keys, Data, false, State), Value = get_data_recursive(Keys, Data, false, State),
case Value =:= [] orelse Value =:= false of case is_falsy(Value) of
true -> compile_impl(T, Data, compile_impl(Tags, Data, Result, State), State); true -> compile_impl(T, Data, compile_impl(Tags, Data, Result, State), State);
false -> compile_impl(T, Data, Result, State) false -> compile_impl(T, Data, Result, State)
end; end;
@ -504,6 +510,11 @@ split_tag(#state{start = StartDelimiter, stop = StopDelimiter}, Bin) ->
end end
end. end.
%% @doc Returns true if treated as false. Otherwise it returns false.
-spec is_falsy(term()) -> boolean().
is_falsy(Value) ->
Value =:= [] orelse Value =:= false orelse Value =:= nil orelse Value =:= null orelse Value =:= <<"">>.
%% @doc if it is standalone line, remove spaces from edge. %% @doc if it is standalone line, remove spaces from edge.
-spec standalone(#state{}, binary(), [tag()]) -> {#state{}, StashPre :: binary(), Post :: binary(), [tag()]}. -spec standalone(#state{}, binary(), [tag()]) -> {#state{}, StashPre :: binary(), Post :: binary(), [tag()]}.
standalone(#state{standalone = false} = State, Post, [Pre | Result]) -> standalone(#state{standalone = false} = State, Post, [Pre | Result]) ->
@ -632,7 +643,7 @@ convert_keytype(KeyBin, #?MODULE{options = Options}) ->
%% @doc fetch the value of the specified `Keys' from {@link data/0} %% @doc fetch the value of the specified `Keys' from {@link data/0}
%% %%
%% - If `Keys' is `[<<".">>]', it returns `Data'. %% - If `Keys' is `[<<".">>]', it returns current context.
%% - If raise_on_context_miss enabled, it raise an exception when missing `Keys'. Otherwise, it returns `Default'. %% - If raise_on_context_miss enabled, it raise an exception when missing `Keys'. Otherwise, it returns `Default'.
-spec get_data_recursive([key()], data(), Default :: term(), template()) -> term(). -spec get_data_recursive([key()], data(), Default :: term(), template()) -> term().
get_data_recursive(Keys, Data, Default, Template) -> get_data_recursive(Keys, Data, Default, Template) ->
@ -649,8 +660,8 @@ get_data_recursive(Keys, Data, Default, Template) ->
-spec get_data_recursive_impl([key()], data(), template()) -> {ok, term()} | error. -spec get_data_recursive_impl([key()], data(), template()) -> {ok, term()} | error.
get_data_recursive_impl([], Data, _) -> get_data_recursive_impl([], Data, _) ->
{ok, Data}; {ok, Data};
get_data_recursive_impl([<<".">>], Data, _) -> get_data_recursive_impl([<<".">>], _, #?MODULE{context_stack = [Context | _]}) ->
{ok, Data}; {ok, Context};
get_data_recursive_impl([Key | RestKey] = Keys, Data, #?MODULE{context_stack = Stack} = State) -> get_data_recursive_impl([Key | RestKey] = Keys, Data, #?MODULE{context_stack = Stack} = State) ->
case is_recursive_data(Data) andalso find_data(convert_keytype(Key, State), Data) of case is_recursive_data(Data) andalso find_data(convert_keytype(Key, State), Data) of
{ok, ChildData} -> {ok, ChildData} ->

View File

@ -188,48 +188,6 @@ l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3
smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
-----END CERTIFICATE----- -----END CERTIFICATE-----
# Issuer: CN=QuoVadis Root Certification Authority O=QuoVadis Limited OU=Root Certification Authority
# Subject: CN=QuoVadis Root Certification Authority O=QuoVadis Limited OU=Root Certification Authority
# Label: "QuoVadis Root CA"
# Serial: 985026699
# MD5 Fingerprint: 27:de:36:fe:72:b7:00:03:00:9d:f4:f0:1e:6c:04:24
# SHA1 Fingerprint: de:3f:40:bd:50:93:d3:9b:6c:60:f6:da:bc:07:62:01:00:89:76:c9
# SHA256 Fingerprint: a4:5e:de:3b:bb:f0:9c:8a:e1:5c:72:ef:c0:72:68:d6:93:a2:1c:99:6f:d5:1e:67:ca:07:94:60:fd:6d:88:73
-----BEGIN CERTIFICATE-----
MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC
TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0
aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0
aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz
MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw
IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR
dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp
li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D
rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ
WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug
F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU
xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC
Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv
dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw
ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl
IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh
c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy
ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh
Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI
KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T
KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq
y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p
dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD
VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL
MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk
fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8
7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R
cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y
mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW
xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK
SnQ2+Q==
-----END CERTIFICATE-----
# Issuer: CN=QuoVadis Root CA 2 O=QuoVadis Limited # Issuer: CN=QuoVadis Root CA 2 O=QuoVadis Limited
# Subject: CN=QuoVadis Root CA 2 O=QuoVadis Limited # Subject: CN=QuoVadis Root CA 2 O=QuoVadis Limited
# Label: "QuoVadis Root CA 2" # Label: "QuoVadis Root CA 2"
@ -345,33 +303,6 @@ JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot
RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw== RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw==
-----END CERTIFICATE----- -----END CERTIFICATE-----
# Issuer: CN=Sonera Class2 CA O=Sonera
# Subject: CN=Sonera Class2 CA O=Sonera
# Label: "Sonera Class 2 Root CA"
# Serial: 29
# MD5 Fingerprint: a3:ec:75:0f:2e:88:df:fa:48:01:4e:0b:5c:48:6f:fb
# SHA1 Fingerprint: 37:f7:6d:e6:07:7c:90:c5:b1:3e:93:1a:b7:41:10:b4:f2:e4:9a:27
# SHA256 Fingerprint: 79:08:b4:03:14:c1:38:10:0b:51:8d:07:35:80:7f:fb:fc:f8:51:8a:00:95:33:71:05:ba:38:6b:15:3d:d9:27
-----BEGIN CERTIFICATE-----
MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP
MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx
MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV
BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o
Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt
5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s
3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej
vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu
8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw
DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG
MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil
zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/
3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD
FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6
Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2
ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M
-----END CERTIFICATE-----
# Issuer: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com # Issuer: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com
# Subject: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com # Subject: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com
# Label: "XRamp Global CA Root" # Label: "XRamp Global CA Root"
@ -1593,35 +1524,6 @@ LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT
LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==
-----END CERTIFICATE----- -----END CERTIFICATE-----
# Issuer: O=Trustis Limited OU=Trustis FPS Root CA
# Subject: O=Trustis Limited OU=Trustis FPS Root CA
# Label: "Trustis FPS Root CA"
# Serial: 36053640375399034304724988975563710553
# MD5 Fingerprint: 30:c9:e7:1e:6b:e6:14:eb:65:b2:16:69:20:31:67:4d
# SHA1 Fingerprint: 3b:c0:38:0b:33:c3:f6:a6:0c:86:15:22:93:d9:df:f5:4b:81:c0:04
# SHA256 Fingerprint: c1:b4:82:99:ab:a5:20:8f:e9:63:0a:ce:55:ca:68:a0:3e:da:5a:51:9c:88:02:a0:d3:a6:73:be:8f:8e:55:7d
-----BEGIN CERTIFICATE-----
MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBF
MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQL
ExNUcnVzdGlzIEZQUyBSb290IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTEx
MzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1RydXN0aXMgTGltaXRlZDEc
MBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQRUN+
AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihH
iTHcDnlkH5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjj
vSkCqPoc4Vu5g6hBSLwacY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA
0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zto3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlB
OrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEAAaNTMFEwDwYDVR0TAQH/
BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAdBgNVHQ4E
FgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01
GX2cGE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmW
zaD+vkAMXBJV+JOCyinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP4
1BIy+Q7DsdwyhEQsb8tGD+pmQQ9P8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZE
f1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHVl/9D7S3B2l0pKoU/rGXuhg8F
jZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYliB6XzCGcKQEN
ZetX2fNXlrtIzYE=
-----END CERTIFICATE-----
# Issuer: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 # Issuer: CN=Buypass Class 2 Root CA O=Buypass AS-983163327
# Subject: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 # Subject: CN=Buypass Class 2 Root CA O=Buypass AS-983163327
# Label: "Buypass Class 2 Root CA" # Label: "Buypass Class 2 Root CA"
@ -4207,3 +4109,254 @@ DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ
7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8 7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8
+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A= +RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A=
-----END CERTIFICATE----- -----END CERTIFICATE-----
# Issuer: CN=GLOBALTRUST 2020 O=e-commerce monitoring GmbH
# Subject: CN=GLOBALTRUST 2020 O=e-commerce monitoring GmbH
# Label: "GLOBALTRUST 2020"
# Serial: 109160994242082918454945253
# MD5 Fingerprint: 8a:c7:6f:cb:6d:e3:cc:a2:f1:7c:83:fa:0e:78:d7:e8
# SHA1 Fingerprint: d0:67:c1:13:51:01:0c:aa:d0:c7:6a:65:37:31:16:26:4f:53:71:a2
# SHA256 Fingerprint: 9a:29:6a:51:82:d1:d4:51:a2:e3:7f:43:9b:74:da:af:a2:67:52:33:29:f9:0f:9a:0d:20:07:c3:34:e2:3c:9a
-----BEGIN CERTIFICATE-----
MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkG
A1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkw
FwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYx
MDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9u
aXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMIICIjANBgkq
hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWiD59b
RatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9Z
YybNpyrOVPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3
QWPKzv9pj2gOlTblzLmMCcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPw
yJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCmfecqQjuCgGOlYx8ZzHyyZqjC0203b+J+
BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKAA1GqtH6qRNdDYfOiaxaJ
SaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9ORJitHHmkH
r96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj0
4KlGDfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9Me
dKZssCz3AwyIDMvUclOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIw
q7ejMZdnrY8XD2zHc+0klGvIg5rQmjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2
nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
AQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1UdIwQYMBaAFNwu
H9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA
VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJC
XtzoRlgHNQIw4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd
6IwPS3BD0IL/qMy/pJTAvoe9iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf
+I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS8cE54+X1+NZK3TTN+2/BT+MAi1bi
kvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2HcqtbepBEX4tdJP7
wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxSvTOB
TI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6C
MUO+1918oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn
4rnvyOL2NSl6dPrFf4IFYqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+I
aFvowdlxfv1k7/9nR4hYJS8+hge9+6jlgqispdNpQ80xiEmEU5LAsTkbOYMBMMTy
qfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg==
-----END CERTIFICATE-----
# Issuer: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz
# Subject: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz
# Label: "ANF Secure Server Root CA"
# Serial: 996390341000653745
# MD5 Fingerprint: 26:a6:44:5a:d9:af:4e:2f:b2:1d:b6:65:b0:4e:e8:96
# SHA1 Fingerprint: 5b:6e:68:d0:cc:15:b6:a0:5f:1e:c1:5f:ae:02:fc:6b:2f:5d:6f:74
# SHA256 Fingerprint: fb:8f:ec:75:91:69:b9:10:6b:1e:51:16:44:c6:18:c5:13:04:37:3f:6c:06:43:08:8d:8b:ef:fd:1b:99:75:99
-----BEGIN CERTIFICATE-----
MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNV
BAUTCUc2MzI4NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlk
YWQgZGUgQ2VydGlmaWNhY2lvbjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNV
BAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3QgQ0EwHhcNMTkwOTA0MTAwMDM4WhcN
MzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEwMQswCQYDVQQGEwJF
UzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQwEgYD
VQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9v
dCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCj
cqQZAZ2cC4Ffc0m6p6zzBE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9q
yGFOtibBTI3/TO80sh9l2Ll49a2pcbnvT1gdpd50IJeh7WhM3pIXS7yr/2WanvtH
2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcvB2VSAKduyK9o7PQUlrZX
H1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXsezx76W0OL
zc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyR
p1RMVwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQz
W7i1o0TJrH93PB0j7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/
SiOL9V8BY9KHcyi1Swr1+KuCLH5zJTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJn
LNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe8TZBAQIvfXOn3kLMTOmJDVb3
n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVOHj1tyRRM4y5B
u8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj
o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAO
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC
AgEATh65isagmD9uw2nAalxJUqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L
9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzxj6ptBZNscsdW699QIyjlRRA96Gej
rw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDtdD+4E5UGUcjohybK
pFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM5gf0
vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjq
OknkJjCb5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ
/zo1PqVUSlJZS2Db7v54EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ9
2zg/LFis6ELhDtjTO0wugumDLmsx2d1Hhk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI
+PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGyg77FGr8H6lnco4g175x2
MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3r5+qPeoo
tt7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw=
-----END CERTIFICATE-----
# Issuer: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority
# Subject: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority
# Label: "Certum EC-384 CA"
# Serial: 160250656287871593594747141429395092468
# MD5 Fingerprint: b6:65:b3:96:60:97:12:a1:ec:4e:e1:3d:a3:c6:c9:f1
# SHA1 Fingerprint: f3:3e:78:3c:ac:df:f4:a2:cc:ac:67:55:69:56:d7:e5:16:3c:e1:ed
# SHA256 Fingerprint: 6b:32:80:85:62:53:18:aa:50:d1:73:c9:8d:8b:da:09:d5:7e:27:41:3d:11:4c:f7:87:a0:f5:d0:6c:03:0c:f6
-----BEGIN CERTIFICATE-----
MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQsw
CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScw
JQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMT
EENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2MDcyNDU0WhcNNDMwMzI2MDcyNDU0
WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBT
LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAX
BgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATE
KI6rGFtqvm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7Tm
Fy8as10CW4kjPMIRBSqniBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68Kj
QjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI0GZnQkdjrzife81r1HfS+8
EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjADVS2m5hjEfO/J
UG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0QoSZ/6vn
nvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k=
-----END CERTIFICATE-----
# Issuer: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority
# Subject: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority
# Label: "Certum Trusted Root CA"
# Serial: 40870380103424195783807378461123655149
# MD5 Fingerprint: 51:e1:c2:e7:fe:4c:84:af:59:0e:2f:f4:54:6f:ea:29
# SHA1 Fingerprint: c8:83:44:c0:18:ae:9f:cc:f1:87:b7:8f:22:d1:c5:d7:45:84:ba:e5
# SHA256 Fingerprint: fe:76:96:57:38:55:77:3e:37:a9:5e:7a:d4:d9:cc:96:c3:01:57:c1:5d:31:76:5b:a9:b1:57:04:e1:ae:78:fd
-----BEGIN CERTIFICATE-----
MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6
MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu
MScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNV
BAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwHhcNMTgwMzE2MTIxMDEzWhcNNDMw
MzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEg
U3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRo
b3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqG
SIb3DQEBAQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZ
n0EGze2jusDbCSzBfN8pfktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/q
p1x4EaTByIVcJdPTsuclzxFUl6s1wB52HO8AU5853BSlLCIls3Jy/I2z5T4IHhQq
NwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2fJmItdUDmj0VDT06qKhF
8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGtg/BKEiJ3
HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGa
mqi4NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi
7VdNIuJGmj8PkTQkfVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSF
ytKAQd8FqKPVhJBPC/PgP5sZ0jeJP/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0P
qafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSYnjYJdmZm/Bo/6khUHL4wvYBQ
v3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHKHRzQ+8S1h9E6
Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1
vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQAD
ggIBAEii1QALLtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4
WxmB82M+w85bj/UvXgF2Ez8sALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvo
zMrnadyHncI013nR03e4qllY/p0m+jiGPp2Kh2RX5Rc64vmNueMzeMGQ2Ljdt4NR
5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8CYyqOhNf6DR5UMEQ
GfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA4kZf
5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq
0Uc9NneoWWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7D
P78v3DSk+yshzWePS/Tj6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTM
qJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmTOPQD8rv7gmsHINFSH5pkAnuYZttcTVoP
0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZckbxJF0WddCajJFdr60qZf
E2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb
-----END CERTIFICATE-----
# Issuer: CN=TunTrust Root CA O=Agence Nationale de Certification Electronique
# Subject: CN=TunTrust Root CA O=Agence Nationale de Certification Electronique
# Label: "TunTrust Root CA"
# Serial: 108534058042236574382096126452369648152337120275
# MD5 Fingerprint: 85:13:b9:90:5b:36:5c:b6:5e:b8:5a:f8:e0:31:57:b4
# SHA1 Fingerprint: cf:e9:70:84:0f:e0:73:0f:9d:f6:0c:7f:2c:4b:ee:20:46:34:9c:bb
# SHA256 Fingerprint: 2e:44:10:2a:b5:8c:b8:54:19:45:1c:8e:19:d9:ac:f3:66:2c:af:bc:61:4b:6a:53:96:0a:30:f7:d0:e2:eb:41
-----BEGIN CERTIFICATE-----
MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQEL
BQAwYTELMAkGA1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUg
Q2VydGlmaWNhdGlvbiBFbGVjdHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJv
b3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQwNDI2MDg1NzU2WjBhMQswCQYDVQQG
EwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBDZXJ0aWZpY2F0aW9u
IEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIwDQYJ
KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZ
n56eY+hz2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd
2JQDoOw05TDENX37Jk0bbjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgF
VwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZ
GoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAdgjH8KcwAWJeRTIAAHDOF
li/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViWVSHbhlnU
r8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2
eY8fTpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIb
MlEsPvLfe/ZdeikZjuXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISg
jwBUFfyRbVinljvrS5YnzWuioYasDXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB
7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwSVXAkPcvCFDVDXSdOvsC9qnyW
5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI04Y+oXNZtPdE
ITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0
90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+z
xiD2BkewhpMl0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYu
QEkHDVneixCwSQXi/5E/S7fdAo74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4
FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRYYdZ2vyJ/0Adqp2RT8JeNnYA/u8EH
22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJpadbGNjHh/PqAulxP
xOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65xxBzn
dFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5
Xc0yGYuPjCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7b
nV2UqL1g52KAdoGDDIzMMEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQ
CvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9zZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZH
u/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3rAZ3r2OvEhJn7wAzMMujj
d9qDRIueVSjAi1jTkD5OGwDxFa2DK5o=
-----END CERTIFICATE-----
# Issuer: CN=HARICA TLS RSA Root CA 2021 O=Hellenic Academic and Research Institutions CA
# Subject: CN=HARICA TLS RSA Root CA 2021 O=Hellenic Academic and Research Institutions CA
# Label: "HARICA TLS RSA Root CA 2021"
# Serial: 76817823531813593706434026085292783742
# MD5 Fingerprint: 65:47:9b:58:86:dd:2c:f0:fc:a2:84:1f:1e:96:c4:91
# SHA1 Fingerprint: 02:2d:05:82:fa:88:ce:14:0c:06:79:de:7f:14:10:e9:45:d7:a5:6d
# SHA256 Fingerprint: d9:5d:0e:8e:da:79:52:5b:f9:be:b1:1b:14:d2:10:0d:32:94:98:5f:0c:62:d9:fa:bd:9c:d9:99:ec:cb:7b:1d
-----BEGIN CERTIFICATE-----
MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBs
MQswCQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl
c2VhcmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0Eg
Um9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUzOFoXDTQ1MDIxMzEwNTUzN1owbDEL
MAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl
YXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNBIFJv
b3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569l
mwVnlskNJLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE
4VGC/6zStGndLuwRo0Xua2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uv
a9of08WRiFukiZLRgeaMOVig1mlDqa2YUlhu2wr7a89o+uOkXjpFc5gH6l8Cct4M
pbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K5FrZx40d/JiZ+yykgmvw
Kh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEvdmn8kN3b
LW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcY
AuUR0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqB
AGMUuTNe3QvboEUHGjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYq
E613TBoYm5EPWNgGVMWX+Ko/IIqmhaZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHr
W2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQCPxrvrNQKlr9qEgYRtaQQJKQ
CoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8GA1UdEwEB/wQF
MAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE
AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAU
X15QvWiWkKQUEapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3
f5Z2EMVGpdAgS1D0NTsY9FVqQRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxaja
H6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxDQpSbIPDRzbLrLFPCU3hKTwSUQZqP
JzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcRj88YxeMn/ibvBZ3P
zzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5vZSt
jBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0
/L5H9MG0qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pT
BGIBnfHAT+7hOtSLIBD6Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79
aPib8qXPMThcFarmlwDB31qlpzmq6YR/PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YW
xw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnnkf3/W9b3raYvAwtt41dU
63ZTGI0RmLo=
-----END CERTIFICATE-----
# Issuer: CN=HARICA TLS ECC Root CA 2021 O=Hellenic Academic and Research Institutions CA
# Subject: CN=HARICA TLS ECC Root CA 2021 O=Hellenic Academic and Research Institutions CA
# Label: "HARICA TLS ECC Root CA 2021"
# Serial: 137515985548005187474074462014555733966
# MD5 Fingerprint: ae:f7:4c:e5:66:35:d1:b7:9b:8c:22:93:74:d3:4b:b0
# SHA1 Fingerprint: bc:b0:c1:9d:e9:98:92:70:19:38:57:e9:8d:a7:b4:5d:6e:ee:01:48
# SHA256 Fingerprint: 3f:99:cc:47:4a:cf:ce:4d:fe:d5:87:94:66:5e:47:8d:15:47:73:9f:2e:78:0f:1b:b4:ca:9b:13:30:97:d4:01
-----BEGIN CERTIFICATE-----
MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQsw
CQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2Vh
cmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9v
dCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoXDTQ1MDIxMzExMDEwOVowbDELMAkG
A1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj
aCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJvb3Qg
Q0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7
KKrxcm1lAEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9Y
STHMmE5gEYd103KUkE+bECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUw
AwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQD
AgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAircJRQO9gcS3ujwLEXQNw
SaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/QwCZ61IygN
nxS2PFOiTAZpffpskcYqSUXm7LcT4Tps
-----END CERTIFICATE-----

View File

@ -1,6 +1,6 @@
{application,certifi, {application,certifi,
[{description,"CA bundle adapted from Mozilla by https://certifi.io"}, [{description,"CA bundle adapted from Mozilla by https://certifi.io"},
{vsn,"2.6.1"}, {vsn,"2.8.0"},
{registered,[]}, {registered,[]},
{applications,[kernel,stdlib]}, {applications,[kernel,stdlib]},
{env,[]}, {env,[]},

View File

@ -10,9 +10,9 @@ reproducible_module_test() ->
cacerts_test_() -> cacerts_test_() ->
Certs = [Cert1, Cert2, Cert3 | _] = certifi:cacerts(), Certs = [Cert1, Cert2, Cert3 | _] = certifi:cacerts(),
[?_assertEqual(127, length(Certs)) [?_assertEqual(128, length(Certs))
,?_assertMatch(<<48,130,2,11,48,130,1,145,160,3,2,1,2,2,18,17,210,187,186,51,_/binary>>, Cert1) ,?_assertMatch(<<48,130,5,192,48,130,3,168,160,3,2,1,2,2,16,30,191,89,80,184,_/binary>>, Cert1)
,?_assertMatch(<<48,130,5,90,48,130,3,66,160,3,2,1,2,2,18,17,210,187,185,215,_/binary>>, Cert2) ,?_assertMatch(<<48,130,2,101,48,130,1,235,160,3,2,1,2,2,16,120,143,39,92,_/binary>>, Cert2)
,?_assertMatch(<< 48,130,2,110,48,130,1,243,160,3,2,1,2,2,16,98,246,50,108, _ / binary>>, Cert3) ,?_assertMatch(<<48,130,5,239,48,130,3,215,160,3,2,1,2,2,8,13,211,227,188,_/binary>>, Cert3)
,?_assertMatch(<<48,130,3,117,48,130,2,93,160,3,2,1,2,2,11,4,0,0,0,0,1,21,75,90,195,148,48,13,6,_/binary>>, lists:last(Certs)) ,?_assertMatch(<<48,130,3,117,48,130,2,93,160,3,2,1,2,2,11,4,0,0,0,0,1,21,75,90,195,148,48,13,6,_/binary>>, lists:last(Certs))
]. ].

View File

@ -1,6 +1,9 @@
providers providers [![GitHub Actions CI][ci-img]][ci]
===== =====
[ci]: https://github.com/tsloughter/providers
[ci-img]: https://github.com/tsloughter/providers/workflows/build/badge.svg
An Erlang providers library. An Erlang providers library.
Build Build

View File

@ -1,5 +1,5 @@
{erl_opts, [{platform_define, "R14", no_callback_support} {erl_opts, [{platform_define, "R14", no_callback_support}
,debug_info]}. ,debug_info]}.
{deps, [{getopt, "1.0.1"}]}. {deps, [{getopt, "1.0.1"}, {erlware_commons, "1.4.0"}]}.

View File

@ -1,6 +1,14 @@
{"1.1.0", {"1.2.0",
[{<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},0}]}. [{<<"cf">>,{pkg,<<"cf">>,<<"0.3.1">>},1},
{<<"erlware_commons">>,{pkg,<<"erlware_commons">>,<<"1.4.0">>},0},
{<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},0}]}.
[ [
{pkg_hash,[ {pkg_hash,[
{<<"getopt">>, <<"C73A9FA687B217F2FF79F68A3B637711BB1936E712B521D8CE466B29CBF7808A">>}]} {<<"cf">>, <<"5CB902239476E141EA70A740340233782D363A31EEA8AD37049561542E6CD641">>},
{<<"erlware_commons">>, <<"F9EE38412E1413944BE78736DDB9BDB4C0664ABA5133563F4F3B359A8ED0AD52">>},
{<<"getopt">>, <<"C73A9FA687B217F2FF79F68A3B637711BB1936E712B521D8CE466B29CBF7808A">>}]},
{pkg_hash_ext,[
{<<"cf">>, <<"315E8D447D3A4B02BCDBFA397AD03BBB988A6E0AA6F44D3ADD0F4E3C3BF97672">>},
{<<"erlware_commons">>, <<"185ECF5CF43BAB3A013DDB3614CE7BBA7F6C7A827904E64E57DA54FCDFDCE2E6">>},
{<<"getopt">>, <<"53E1AB83B9CEB65C9672D3E7A35B8092E9BDC9B3EE80721471A161C10C59959C">>}]}
]. ].

View File

@ -1,6 +1,6 @@
{application,providers, {application,providers,
[{description,"Providers provider."}, [{description,"Providers provider."},
{vsn,"1.8.1"}, {vsn,"1.9.0"},
{registered,[]}, {registered,[]},
{applications,[kernel,stdlib,getopt]}, {applications,[kernel,stdlib,getopt]},
{licenses,["Apache 2.0"]}, {licenses,["Apache 2.0"]},

View File

@ -155,7 +155,7 @@ help(#provider{opts=Opts
case Opts of case Opts of
[] -> [] ->
io:format("Usage: rebar3 ~s~p~n", [StrNS, Name]); io:format("Usage: rebar3 ~ts~ts~n", [StrNS, Name]);
_ -> _ ->
getopt:usage(Opts, "rebar3 " ++ StrNS ++ atom_to_list(Name), "", []) getopt:usage(Opts, "rebar3 " ++ StrNS ++ atom_to_list(Name), "", [])
end. end.
@ -172,7 +172,7 @@ help(Name, Providers, Namespace) when is_atom(Name) ->
help(Provider). help(Provider).
format_error({provider_not_found, Namespace, ProviderName}) -> format_error({provider_not_found, Namespace, ProviderName}) ->
io_lib:format("Unable to resolve provider ~s in namespace ~s", [ProviderName, Namespace]). io_lib:format("Unable to resolve provider ~ts in namespace ~ts", [ProviderName, Namespace]).
%% @doc format an error produced from a provider. %% @doc format an error produced from a provider.
-spec format_error(t(), Reason::term()) -> iolist(). -spec format_error(t(), Reason::term()) -> iolist().
@ -311,7 +311,7 @@ namespace_help(Dict, [NS|Namespaces]) ->
if Help =:= [] -> if Help =:= [] ->
no_public_providers; no_public_providers;
NS =/= default -> NS =/= default ->
io:format("~n~p <task>:~n", [NS]), io:format("~n~ts <task>:~n", [NS]),
display_help(Help); display_help(Help);
NS =:= default -> NS =:= default ->
display_help(Help) display_help(Help)
@ -323,5 +323,5 @@ display_help(Help) ->
lists:foreach(fun({Name, ShortDesc}) -> lists:foreach(fun({Name, ShortDesc}) ->
Length = length(Name), Length = length(Name),
Spacing = lists:duplicate(Longest - Length + 8, " "), Spacing = lists:duplicate(Longest - Length + 8, " "),
io:format("~s~s~s~n", [Name, Spacing, ShortDesc]) io:format("~ts~ts~ts~n", [Name, Spacing, ShortDesc])
end, Help). end, Help).

View File

@ -208,8 +208,8 @@ find_erts_dir() {
__erts_version="$("$__erl" -boot no_dot_erlang -sasl errlog_type error -noshell -eval "$erts_version_code")" __erts_version="$("$__erl" -boot no_dot_erlang -sasl errlog_type error -noshell -eval "$erts_version_code")"
ERTS_DIR="${__erl_root}/erts-${__erts_version}" ERTS_DIR="${__erl_root}/erts-${__erts_version}"
if [ -d "$ERTS_DIR" ]; then if [ -d "$ERTS_DIR" ]; then
ERTS_VSN=${__erts_version}
echo "Exact ERTS version (${ERTS_VSN}) match not found, instead using ${__erts_version}. The release may fail to run." 1>&2 echo "Exact ERTS version (${ERTS_VSN}) match not found, instead using ${__erts_version}. The release may fail to run." 1>&2
ERTS_VSN=${__erts_version}
else else
echo "Can not run the release. There is no ERTS bundled with the release or found on the system." echo "Can not run the release. There is no ERTS bundled with the release or found on the system."
exit 1 exit 1
@ -328,8 +328,8 @@ erl_rpc() {
DYNAMIC_NAME="-r" DYNAMIC_NAME="-r"
fi fi
if [ "$ERL_DIST_PORT" ]; then if [ "$ADDRESS" ]; then
result=$("$ERL_RPC" "${DYNAMIC_NAME}" -c "${COOKIE}" -address "${ERL_DIST_PORT}" -timeout "${RELX_RPC_TIMEOUT}" -a "${command}") result=$("$ERL_RPC" "${DYNAMIC_NAME}" -c "${COOKIE}" -address "${ADDRESS}" -timeout "${RELX_RPC_TIMEOUT}" -a "${command}")
else else
result=$("$ERL_RPC" "$NAME_TYPE" "$NAME" "${DYNAMIC_NAME}" -c "${COOKIE}" -timeout "${RELX_RPC_TIMEOUT}" -a "${command}") result=$("$ERL_RPC" "$NAME_TYPE" "$NAME" "${DYNAMIC_NAME}" -c "${COOKIE}" -timeout "${RELX_RPC_TIMEOUT}" -a "${command}")
fi fi
@ -352,7 +352,7 @@ erl_eval() {
command=$* command=$*
if [ "$ERL_DIST_PORT" ]; then if [ "$ERL_DIST_PORT" ]; then
result=$(echo "${command}" | "$ERL_RPC" "${DYNAMIC_NAME}" -c "${COOKIE}" -address "${ERL_DIST_PORT}" -timeout "${RELX_RPC_TIMEOUT}" -e) result=$(echo "${command}" | "$ERL_RPC" "${DYNAMIC_NAME}" -c "${COOKIE}" -address "${ADDRESS}" -timeout "${RELX_RPC_TIMEOUT}" -e)
else else
result=$(echo "${command}" | "$ERL_RPC" "$NAME_TYPE" "$NAME" "${DYNAMIC_NAME}" -c "${COOKIE}" -timeout "${RELX_RPC_TIMEOUT}" -e) result=$(echo "${command}" | "$ERL_RPC" "$NAME_TYPE" "$NAME" "${DYNAMIC_NAME}" -c "${COOKIE}" -timeout "${RELX_RPC_TIMEOUT}" -e)
fi fi
@ -410,6 +410,22 @@ relx_escript() {
"$ERTS_DIR/bin/escript" "$ROOTDIR/$scriptpath" "$@" "$ERTS_DIR/bin/escript" "$ROOTDIR/$scriptpath" "$@"
} }
# Convert {127,0,0,1} to 127.0.0.1 (inet:ntoa/1)
addr_tuple_to_str() {
addr="$1"
saved_IFS="$IFS"
IFS="{,}'\" "
# shellcheck disable=SC2086
eval set -- $addr
IFS="$saved_IFS"
case $# in
4) printf '%u.%u.%u.%u' "$@";;
8) printf '%.4x:%.4x:%.4x:%.4x:%.4x:%.4x:%.4x:%.4x' "$@";;
*) echo "Cannot parse IP address tuple: '$addr'" 1>&2;;
esac
}
make_out_file_path() { make_out_file_path() {
# Use output directory provided in the RELX_OUT_FILE_PATH environment variable # Use output directory provided in the RELX_OUT_FILE_PATH environment variable
# (default to the current location of vm.args and sys.config) # (default to the current location of vm.args and sys.config)
@ -435,6 +451,7 @@ replace_os_vars() {
slen=split(var,arr,":-") slen=split(var,arr,":-")
v=arr[1] v=arr[1]
e=ENVIRON[v] e=ENVIRON[v]
gsub("&","\\\\\\&",e)
if(slen > 1 && e=="") { if(slen > 1 && e=="") {
i=index(var, ":-"arr[2]) i=index(var, ":-"arr[2])
def=substr(var,i+2) def=substr(var,i+2)
@ -596,7 +613,7 @@ RELX_CONFIG_PATH=$(check_replace_os_vars sys.config "$RELX_CONFIG_PATH")
# - nonexisting -args_files # - nonexisting -args_files
# - circular dependencies of -args_files # - circular dependencies of -args_files
# - relative paths in -args_file parameters # - relative paths in -args_file parameters
# - multiple/mixed occurences of -name and -sname parameters # - multiple/mixed occurrences of -name and -sname parameters
# - missing -name or -sname parameters # - missing -name or -sname parameters
# If all checks pass, extract the target node name # If all checks pass, extract the target node name
set +e set +e
@ -673,8 +690,17 @@ EPMD_MODULE="$(grep '^-epmd_module' "$VMARGS_PATH" || true)"
if [ "$EPMD_MODULE" ]; then if [ "$EPMD_MODULE" ]; then
DIST_ARGS="${DIST_ARGS} ${EPMD_MODULE}" DIST_ARGS="${DIST_ARGS} ${EPMD_MODULE}"
fi fi
INET_DIST_USE_INTERFACE="$(grep '^-kernel *inet_dist_use_interface' "$VMARGS_PATH" || true)"
if [ "$INET_DIST_USE_INTERFACE" ]; then
DIST_ARGS="${DIST_ARGS} ${INET_DIST_USE_INTERFACE}"
fi
if [ "$ERL_DIST_PORT" ]; then if [ "$ERL_DIST_PORT" ]; then
if [ "$INET_DIST_USE_INTERFACE" ]; then
ADDRESS="$(addr_tuple_to_str "${INET_DIST_USE_INTERFACE#*inet_dist_use_interface }"):$ERL_DIST_PORT"
else
ADDRESS="$ERL_DIST_PORT"
fi
if [ "11.1" = "$(printf "%s\n11.1" "${ERTS_VSN}" | sort -V | head -n1)" ] ; then if [ "11.1" = "$(printf "%s\n11.1" "${ERTS_VSN}" | sort -V | head -n1)" ] ; then
# unless set by the user, set start_epmd to false when ERL_DIST_PORT is used # unless set by the user, set start_epmd to false when ERL_DIST_PORT is used
if [ ! "$START_EPMD" ]; then if [ ! "$START_EPMD" ]; then
@ -683,6 +709,13 @@ if [ "$ERL_DIST_PORT" ]; then
EXTRA_DIST_ARGS="-erl_epmd_port ${ERL_DIST_PORT}" EXTRA_DIST_ARGS="-erl_epmd_port ${ERL_DIST_PORT}"
fi fi
else else
ERL_DIST_PORT_WARNING="ERL_DIST_PORT is set and used to set the port, but doing so on ERTS version ${ERTS_VSN} means remsh/rpc will not work for this release"
if ! command -v logger > /dev/null 2>&1
then
echo "WARNING: ${ERL_DIST_PORT_WARNING}"
else
logger -p warning -t "${REL_NAME}[$$]" "${ERL_DIST_PORT_WARNING}"
fi
EXTRA_DIST_ARGS="-kernel inet_dist_listen_min ${ERL_DIST_PORT} -kernel inet_dist_listen_max ${ERL_DIST_PORT}" EXTRA_DIST_ARGS="-kernel inet_dist_listen_min ${ERL_DIST_PORT} -kernel inet_dist_listen_max ${ERL_DIST_PORT}"
fi fi
fi fi

View File

@ -45,6 +45,7 @@
%% used in tests %% used in tests
{rlx_app_info, new, 5}, {rlx_app_info, new, 5},
{rlx_app_info, new, 6}, {rlx_app_info, new, 6},
{rlx_app_info, new, 7},
{rlx_file_utils, type, 1}, {rlx_file_utils, type, 1},
{rlx_file_utils, write, 2}, {rlx_file_utils, write, 2},
{rlx_release, applications, 1}, {rlx_release, applications, 1},

View File

@ -1,8 +1,8 @@
{application,relx, {application,relx,
[{description,"Release assembler for Erlang/OTP Releases"}, [{description,"Release assembler for Erlang/OTP Releases"},
{vsn,"4.5.0"}, {vsn,"4.6.0"},
{modules,[]}, {modules,[]},
{registered,[]}, {registered,[]},
{applications,[kernel,stdlib,bbmustache]}, {applications,[kernel,stdlib,bbmustache]},
{licenses,["Apache-2"]}, {licenses,["Apache-2.0"]},
{links,[{"Github","https://github.com/erlware/relx"}]}]}. {links,[{"Github","https://github.com/erlware/relx"}]}]}.

View File

@ -184,7 +184,7 @@ pick_release(State) ->
pick_release_version(undefined, State) -> pick_release_version(undefined, State) ->
pick_release(State); pick_release(State);
pick_release_version(RelName, State) -> pick_release_version(RelName, State) ->
%% Here we will just get the lastest version for name RelName and run that. %% Here we will just get the latest version for name RelName and run that.
AllReleases = maps:to_list(rlx_state:configured_releases(State)), AllReleases = maps:to_list(rlx_state:configured_releases(State)),
SpecificReleases = [Rel || Rel={{PossibleRelName, _}, _} <- AllReleases, PossibleRelName =:= RelName], SpecificReleases = [Rel || Rel={{PossibleRelName, _}, _} <- AllReleases, PossibleRelName =:= RelName],
case lists:sort(fun release_sort/2, SpecificReleases) of case lists:sort(fun release_sort/2, SpecificReleases) of
@ -202,7 +202,7 @@ release_sort({{RelName, RelVsnA}, _},
rlx_util:parsed_vsn_lte(rlx_util:parse_vsn(RelVsnB), rlx_util:parse_vsn(RelVsnA)); rlx_util:parsed_vsn_lte(rlx_util:parse_vsn(RelVsnB), rlx_util:parse_vsn(RelVsnA));
release_sort({{RelA, _}, _}, {{RelB, _}, _}) -> release_sort({{RelA, _}, _}, {{RelB, _}, _}) ->
%% The release names are different. When the releases are named differently %% The release names are different. When the releases are named differently
%% we can not just take the lastest version. You *must* provide a default %% we can not just take the latest version. You *must* provide a default
%% release name at least. So we throw an error here that the top can catch %% release name at least. So we throw an error here that the top can catch
%% and return %% and return
error(?RLX_ERROR({multiple_release_names, RelA, RelB})). error(?RLX_ERROR({multiple_release_names, RelA, RelB})).

View File

@ -38,11 +38,13 @@
-export([new/5, -export([new/5,
new/6, new/6,
new/7,
name/1, name/1,
vsn/1, vsn/1,
dir/1, dir/1,
applications/1, applications/1,
included_applications/1, included_applications/1,
optional_applications/1,
link/1, link/1,
link/2, link/2,
format_error/1, format_error/1,
@ -57,6 +59,7 @@
applications := [atom()], applications := [atom()],
included_applications := [atom()], included_applications := [atom()],
optional_applications := [atom()],
dir := file:name() | undefined, dir := file:name() | undefined,
link := boolean() | undefined, link := boolean() | undefined,
@ -73,15 +76,23 @@
-spec new(atom(), string(), file:name(), [atom()], [atom()]) -> t(). -spec new(atom(), string(), file:name(), [atom()], [atom()]) -> t().
new(Name, Vsn, Dir, Applications, IncludedApplications) -> new(Name, Vsn, Dir, Applications, IncludedApplications) ->
new(Name, Vsn, Dir, Applications, IncludedApplications, dep). new(Name, Vsn, Dir, Applications, IncludedApplications, [], dep).
-spec new(atom(), string(), file:name(), [atom()], [atom()], app_type()) -> t(). -spec new(atom(), string(), file:name(), [atom()], [atom()], [atom()] | atom()) -> t().
new(Name, Vsn, Dir, Applications, IncludedApplications, AppType) -> new(Name, Vsn, Dir, Applications, IncludedApplications, OptionalApplications)
when is_list(OptionalApplications) ->
new(Name, Vsn, Dir, Applications, IncludedApplications, OptionalApplications, dep);
new(Name, Vsn, Dir, Applications, IncludedApplications, AppType) when is_atom(AppType) ->
new(Name, Vsn, Dir, Applications, IncludedApplications, [], AppType).
-spec new(atom(), string(), file:name(), [atom()], [atom()], [atom()], app_type()) -> t().
new(Name, Vsn, Dir, Applications, IncludedApplications, OptionalApplications, AppType) ->
#{name => Name, #{name => Name,
vsn => Vsn, vsn => Vsn,
applications => Applications, applications => Applications,
included_applications => IncludedApplications, included_applications => IncludedApplications,
optional_applications => OptionalApplications,
dir => Dir, dir => Dir,
link => false, link => false,
@ -108,6 +119,10 @@ applications(#{applications := Deps}) ->
included_applications(#{included_applications := Deps}) -> included_applications(#{included_applications := Deps}) ->
Deps. Deps.
-spec optional_applications(t()) -> [atom()].
optional_applications(#{included_applications := Deps}) ->
Deps.
-spec link(t()) -> boolean(). -spec link(t()) -> boolean().
link(#{link := Link}) -> link(#{link := Link}) ->
Link. Link.

View File

@ -129,13 +129,20 @@ rewrite_app_file(State, App, TargetDir) ->
Name = rlx_app_info:name(App), Name = rlx_app_info:name(App),
Applications = rlx_app_info:applications(App), Applications = rlx_app_info:applications(App),
IncludedApplications = rlx_app_info:included_applications(App), IncludedApplications = rlx_app_info:included_applications(App),
OptionalApplications = rlx_app_info:optional_applications(App),
%% TODO: should really read this in when creating rlx_app:t() and keep it %% TODO: should really read this in when creating rlx_app:t() and keep it
AppFile = filename:join([TargetDir, "ebin", [Name, ".app"]]), AppFile = filename:join([TargetDir, "ebin", [Name, ".app"]]),
{ok, [{application, AppName, AppData0}]} = file:consult(AppFile), ?log_debug("Rewriting .app file: ~s", [AppFile]),
[{application, AppName, AppData0}] = case file:consult(AppFile) of
{ok, AppTerms} ->
AppTerms;
{error, ConsultError} ->
erlang:error(?RLX_ERROR({consult_app_file, AppFile, ConsultError}))
end,
%% maybe replace excluded apps %% maybe replace excluded apps
AppData1 = maybe_exclude_apps(Applications, IncludedApplications, AppData1 = maybe_exclude_apps(Applications, IncludedApplications, OptionalApplications,
AppData0, rlx_state:exclude_apps(State)), AppData0, rlx_state:exclude_apps(State)),
AppData2 = maybe_exclude_modules(AppData1, proplists:get_value(Name, AppData2 = maybe_exclude_modules(AppData1, proplists:get_value(Name,
@ -150,17 +157,23 @@ rewrite_app_file(State, App, TargetDir) ->
erlang:error(?RLX_ERROR({rewrite_app_file, AppFile, Error})) erlang:error(?RLX_ERROR({rewrite_app_file, AppFile, Error}))
end. end.
maybe_exclude_apps(_Applications, _IncludedApplications, AppData, []) -> maybe_exclude_apps(_Applications, _IncludedApplications, _OptionalApplications, AppData, []) ->
AppData; AppData;
maybe_exclude_apps(Applications, IncludedApplications, AppData, ExcludeApps) -> maybe_exclude_apps(Applications, IncludedApplications, OptionalApplications, AppData, ExcludeApps) ->
AppData1 = lists:keyreplace(applications, AppData1 = lists:keyreplace(applications,
1, 1,
AppData, AppData,
{applications, Applications -- ExcludeApps}), {applications, Applications -- ExcludeApps}),
lists:keyreplace(included_applications, AppData2 = lists:keyreplace(included_applications,
1,
AppData1,
{included_applications, IncludedApplications -- ExcludeApps}),
%% not absolutely necessary since they are already seen as optional, but may as well
lists:keyreplace(optional_applications,
1, 1,
AppData1, AppData2,
{included_applications, IncludedApplications -- ExcludeApps}). {optional_applications, OptionalApplications -- ExcludeApps}).
maybe_exclude_modules(AppData, []) -> maybe_exclude_modules(AppData, []) ->
AppData; AppData;
@ -829,7 +842,7 @@ copy_to_start(RelDir, Name) ->
ok -> ok ->
ok; ok;
{error, Reason} -> {error, Reason} ->
%% it isn't absolutely necesary for start.boot to exist so just warn %% it isn't absolutely necessary for start.boot to exist so just warn
?log_warn("Unable to copy boot file ~s to start.boot: ~p", [BootFile, Reason]), ?log_warn("Unable to copy boot file ~s to start.boot: ~p", [BootFile, Reason]),
ok ok
end. end.
@ -1086,5 +1099,11 @@ format_error({strip_release, Reason}) ->
format_error({rewrite_app_file, AppFile, Error}) -> format_error({rewrite_app_file, AppFile, Error}) ->
io_lib:format("Unable to rewrite .app file ~s due to ~p", io_lib:format("Unable to rewrite .app file ~s due to ~p",
[AppFile, Error]); [AppFile, Error]);
format_error({consult_app_file, AppFile, enoent}) ->
io_lib:format("Unable to consult .app file ~ts (file not found).",
[AppFile]);
format_error({consult_app_file, AppFile, Error}) ->
io_lib:format("Unable to consult .app file ~ts due to ~ts",
[AppFile, file:format_error(Error)]);
format_error({create_RELEASES, Reason}) -> format_error({create_RELEASES, Reason}) ->
io_lib:format("Unable to create RELEASES file needed by release_handler: ~p", [Reason]). io_lib:format("Unable to create RELEASES file needed by release_handler: ~p", [Reason]).

View File

@ -214,7 +214,7 @@ generate_state_vars(Release, State) ->
{vm_args, rlx_state:vm_args(State)}, {vm_args, rlx_state:vm_args(State)},
{sys_config, rlx_state:sys_config(State)}, {sys_config, rlx_state:sys_config(State)},
{root_dir, rlx_state:root_dir(State)} {root_dir, rlx_state:root_dir(State)}
%% include a var for each application. makes it easier to copy a file from an applcation %% include a var for each application. makes it easier to copy a file from an application
| [{rlx_app_info:name(AppInfo), rlx_app_info:dir(AppInfo)} | [{rlx_app_info:name(AppInfo), rlx_app_info:dir(AppInfo)}
|| AppInfo <- rlx_release:applications(Release)]]. || AppInfo <- rlx_release:applications(Release)]].

View File

@ -44,34 +44,63 @@ solve_release(Release, State0) ->
{false, [SystemLibs | LibDirs]} {false, [SystemLibs | LibDirs]}
end, end,
Pkgs = subset(Goals, AllApps, LibDirs1, CheckCodeLibDirs), ExcludeApps = rlx_state:exclude_apps(State1),
Pkgs1 = remove_exclude_apps(Pkgs, State1), Pkgs = subset(Goals, AllApps, LibDirs1, CheckCodeLibDirs, ExcludeApps),
set_resolved(Release, Pkgs1, State1) set_resolved(Release, Pkgs, State1)
end. end.
%% find the app_info records for each application and its deps needed for the release %% find the app_info records for each application and its deps needed for the release
subset(Apps, World, LibDirs, CheckCodeLibDirs) -> subset(Goals, World, LibDirs, CheckCodeLibDirs, ExcludeApps) ->
subset(Apps, World, sets:new(), LibDirs, CheckCodeLibDirs, []). {Apps, _} = fold_apps(Goals, World, sets:new(), LibDirs, CheckCodeLibDirs, [], ExcludeApps),
Apps.
subset([], _World, _Seen, _LibDirs, _CheckCodeLibDirs, Acc) -> subset(Goal, World, Seen, LibDirs, CheckCodeLibDirs, OptionalApplications, ExcludeApps) ->
Acc;
subset([Goal | Rest], World, Seen, LibDirs, CheckCodeLibDirs, Acc) ->
{Name, Vsn} = name_version(Goal), {Name, Vsn} = name_version(Goal),
case sets:is_element(Name, Seen) of case sets:is_element(Name, Seen) of
true -> true ->
subset(Rest, World, Seen, LibDirs, CheckCodeLibDirs, Acc); {[], Seen};
_ -> _ ->
AppInfo=#{applications := Applications, case find_app(Name, Vsn, World, LibDirs, CheckCodeLibDirs) of
included_applications := IncludedApplications} = not_found ->
find_app(Name, Vsn, World, LibDirs, CheckCodeLibDirs), case lists:member(Name, OptionalApplications) of
subset(Rest ++ Applications ++ IncludedApplications, true ->
World, %% don't add to Seen since optional applications are only
sets:add_element(Name, Seen), %% per-application and not global, so another app could
LibDirs, %% depend on this dependency
CheckCodeLibDirs, {[], Seen};
Acc ++ [AppInfo]) false ->
erlang:error(?RLX_ERROR({app_not_found, Name, Vsn}))
end;
AppInfo=#{applications := Applications,
included_applications := IncludedApplications,
optional_applications := OptionalApplications0} ->
{Apps, Seen2} = fold_apps(Applications ++ IncludedApplications ++ OptionalApplications0,
World,
sets:add_element(Name, Seen),
LibDirs,
CheckCodeLibDirs,
OptionalApplications0,
ExcludeApps),
%% don't add excluded apps
%% TODO: should an excluded app's deps also be excluded?
case lists:member(Name, ExcludeApps) of
true ->
{Apps, Seen2};
false ->
%% place the deps of the App before it
{Apps ++ [AppInfo], Seen2}
end
end
end. end.
fold_apps(Apps, World, Seen, LibDirs, CheckCodeLibDirs, OptionalApplications, ExcludeApps) ->
lists:foldl(fun(App, {AppAcc, SeenAcc}) ->
{NewApps, SeenAcc1} = subset(App, World, SeenAcc, LibDirs,
CheckCodeLibDirs, OptionalApplications, ExcludeApps),
%% put new apps after the existing list to keep the user defined order
{AppAcc ++ NewApps, SeenAcc1}
end, {[], Seen}, Apps).
set_resolved(Release0, Pkgs, State) -> set_resolved(Release0, Pkgs, State) ->
case rlx_release:realize(Release0, Pkgs) of case rlx_release:realize(Release0, Pkgs) of
@ -100,19 +129,6 @@ name_version(Name) when is_atom(Name) ->
name_version({Name, #{vsn := Vsn}}) -> name_version({Name, #{vsn := Vsn}}) ->
{Name, Vsn}. {Name, Vsn}.
remove_exclude_apps(AllApps, State) ->
ExcludeApps = rlx_state:exclude_apps(State),
lists:foldl(fun(AppName, Acc) ->
find_and_remove(AppName, Acc)
end, AllApps, ExcludeApps).
find_and_remove(_, []) ->
[];
find_and_remove(ExcludeName, [#{name := Name} | Rest]) when ExcludeName =:= Name ->
Rest;
find_and_remove(ExcludeName, [H | Rest]) ->
[H | find_and_remove(ExcludeName, Rest)].
%% Applications are first searched for in the `Apps' variable which is a map %% Applications are first searched for in the `Apps' variable which is a map
%% of application name to `rlx_app_info' map. This variable is passed to `relx' %% of application name to `rlx_app_info' map. This variable is passed to `relx'
%% function calls to build the release or tarball %% function calls to build the release or tarball
@ -144,7 +160,7 @@ search_for_app(Name, Vsn, LibDirs, CheckCodeLibDirs) ->
%% app not found in any lib dir we are configured to search %% app not found in any lib dir we are configured to search
%% and user set a custom `system_libs' directory so we do %% and user set a custom `system_libs' directory so we do
%% not look in `code:lib_dir' %% not look in `code:lib_dir'
erlang:error(?RLX_ERROR({app_not_found, Name, Vsn})); not_found;
AppInfo -> AppInfo ->
case check_app(Name, Vsn, AppInfo) of case check_app(Name, Vsn, AppInfo) of
true -> true ->
@ -175,13 +191,13 @@ find_app_in_dir(Name, Vsn, [Dir | Rest]) ->
find_app_in_code_path(Name, Vsn) -> find_app_in_code_path(Name, Vsn) ->
case code:lib_dir(Name) of case code:lib_dir(Name) of
{error, bad_name} -> {error, bad_name} ->
erlang:error(?RLX_ERROR({app_not_found, Name, Vsn})); not_found;
Dir -> Dir ->
case to_app(Name, Vsn, filename:join([Dir, "ebin", [Name, ".app"]])) of case to_app(Name, Vsn, filename:join([Dir, "ebin", [Name, ".app"]])) of
{true, AppInfo} -> {true, AppInfo} ->
AppInfo; AppInfo;
false -> false ->
erlang:error(?RLX_ERROR({app_not_found, Name, Vsn})) not_found
end end
end. end.
@ -200,6 +216,7 @@ to_app(Name, Vsn, AppFilePath) ->
end, end,
Applications = proplists:get_value(applications, AppData, []), Applications = proplists:get_value(applications, AppData, []),
IncludedApplications = proplists:get_value(included_applications, AppData, []), IncludedApplications = proplists:get_value(included_applications, AppData, []),
OptionalApplications = proplists:get_value(optional_applications, AppData, []),
case lists:keyfind(vsn, 1, AppData) of case lists:keyfind(vsn, 1, AppData) of
{_, Vsn1} when Vsn =:= undefined ; {_, Vsn1} when Vsn =:= undefined ;
@ -209,6 +226,7 @@ to_app(Name, Vsn, AppFilePath) ->
applications => Applications, applications => Applications,
included_applications => IncludedApplications, included_applications => IncludedApplications,
optional_applications => OptionalApplications,
dir => filename:dirname(filename:dirname(AppFilePath)), dir => filename:dirname(filename:dirname(AppFilePath)),
link => false}}; link => false}};

View File

@ -66,7 +66,7 @@ parse_vsn(Vsn) ->
"(\\+[0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*)?$", [{capture, [1,2,4,6,8], list}]) of "(\\+[0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*)?$", [{capture, [1,2,4,6,8], list}]) of
%% OTP application's leave out patch version when it is .0 %% OTP application's leave out patch version when it is .0
%% this regex currently drops prerelease and build if the patch version is left out %% this regex currently drops prerelease and build if the patch version is left out
%% so 3.11-0+meta would reutrn {{3,11,0},{[], []}} intsead of {{3,1,0},{"0","meta"}} %% so 3.11-0+meta would return {{3,11,0},{[], []}} intsead of {{3,1,0},{"0","meta"}}
{match, [Major, Minor, [], PreRelease, Build]} -> {match, [Major, Minor, [], PreRelease, Build]} ->
{{list_to_integer(Major), list_to_integer(Minor), 0}, {PreRelease, Build}}; {{list_to_integer(Major), list_to_integer(Minor), 0}, {PreRelease, Build}};
{match, [Major, Minor, Patch, PreRelease, Build]} -> {match, [Major, Minor, Patch, PreRelease, Build]} ->

View File

@ -44,7 +44,7 @@ main(_) ->
bootstrap_rebar3(), bootstrap_rebar3(),
%% Build rebar.app from rebar.app.src %% Build rebar.app from rebar.app.src
{ok, App} = rebar_app_info:new(rebar, "3.17.0", filename:absname("_build/default/lib/rebar/")), {ok, App} = rebar_app_info:new(rebar, "3.18.0", filename:absname("_build/default/lib/rebar/")),
rebar_otp_app:compile(rebar_state:new(), App), rebar_otp_app:compile(rebar_state:new(), App),
%% Because we are compiling files that are loaded already we want to silence %% Because we are compiling files that are loaded already we want to silence

Binary file not shown.

View File

@ -61,7 +61,7 @@ end
## ##
## plugins <task>: ## plugins <task>:
## list List local and global plugins for this project ## list List local and global plugins for this project
## upgrade Uprade plugins ## upgrade Upgrade plugins
## ##
## Run 'rebar3 help <TASK>' for details. ## Run 'rebar3 help <TASK>' for details.
# general options # general options
@ -190,7 +190,7 @@ complete -f -c 'rebar3' -n '__fish_rebar3_using_command tar' -l system_libs
complete -f -c 'rebar3' -n '__fish_rebar3_using_command tar' -l version -d "Print relx version" complete -f -c 'rebar3' -n '__fish_rebar3_using_command tar' -l version -d "Print relx version"
complete -f -c 'rebar3' -n '__fish_rebar3_using_command tar' -s r -l root -d "The project root directory" complete -f -c 'rebar3' -n '__fish_rebar3_using_command tar' -s r -l root -d "The project root directory"
complete -f -c 'rebar3' -n '__fish_rebar3_needs_command' -a tree -d "Print depdency tree." complete -f -c 'rebar3' -n '__fish_rebar3_needs_command' -a tree -d "Print dependency tree."
complete -f -c 'rebar3' -n '__fish_rebar3_needs_command tree' -s v -l verbose -d "Print repo and branch/tag/ref for git and hg deps." complete -f -c 'rebar3' -n '__fish_rebar3_needs_command tree' -s v -l verbose -d "Print repo and branch/tag/ref for git and hg deps."

View File

@ -18,9 +18,9 @@ C_SRC_OUTPUT ?= $(CURDIR)/../priv/$(PROJECT).so
UNAME_SYS := $(shell uname -s) UNAME_SYS := $(shell uname -s)
ifeq ($(UNAME_SYS), Darwin) ifeq ($(UNAME_SYS), Darwin)
CC ?= cc CC ?= cc
CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes
CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall CXXFLAGS ?= -O3 -finline-functions -Wall
LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress LDFLAGS ?= -flat_namespace -undefined suppress
else ifeq ($(UNAME_SYS), FreeBSD) else ifeq ($(UNAME_SYS), FreeBSD)
CC ?= cc CC ?= cc
CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes

View File

@ -3,11 +3,11 @@
{deps, [{erlware_commons, "1.5.0"}, {deps, [{erlware_commons, "1.5.0"},
{ssl_verify_fun, "1.1.6"}, {ssl_verify_fun, "1.1.6"},
{certifi, "2.6.1"}, {certifi, "2.8.0"},
{providers, "1.8.1"}, {providers, "1.9.0"},
{getopt, "1.0.1"}, {getopt, "1.0.1"},
{bbmustache, "1.10.0"}, {bbmustache, "1.12.2"},
{relx, "4.5.0"}, {relx, "4.6.0"},
{cf, "0.3.1"}, {cf, "0.3.1"},
{cth_readable, "1.5.1"}, {cth_readable, "1.5.1"},
{eunit_formatters, "0.5.0"}]}. {eunit_formatters, "0.5.0"}]}.
@ -23,7 +23,7 @@
{escript_name, rebar3}. {escript_name, rebar3}.
{escript_wrappers_windows, ["cmd", "powershell"]}. {escript_wrappers_windows, ["cmd", "powershell"]}.
{escript_comment, "%%Rebar3 3.17.0\n"}. {escript_comment, "%%Rebar3 3.18.0\n"}.
{escript_emu_args, "%%! +sbtu +A1\n"}. {escript_emu_args, "%%! +sbtu +A1\n"}.
%% escript_incl_priv is for internal rebar-private use only. %% escript_incl_priv is for internal rebar-private use only.
%% Do not use outside rebar. Config interface is not stable. %% Do not use outside rebar. Config interface is not stable.

View File

@ -1,35 +1,35 @@
{"1.2.0", {"1.2.0",
[{<<"bbmustache">>,{pkg,<<"bbmustache">>,<<"1.10.0">>},0}, [{<<"bbmustache">>,{pkg,<<"bbmustache">>,<<"1.12.2">>},0},
{<<"certifi">>,{pkg,<<"certifi">>,<<"2.6.1">>},0}, {<<"certifi">>,{pkg,<<"certifi">>,<<"2.8.0">>},0},
{<<"cf">>,{pkg,<<"cf">>,<<"0.3.1">>},0}, {<<"cf">>,{pkg,<<"cf">>,<<"0.3.1">>},0},
{<<"cth_readable">>,{pkg,<<"cth_readable">>,<<"1.5.1">>},0}, {<<"cth_readable">>,{pkg,<<"cth_readable">>,<<"1.5.1">>},0},
{<<"erlware_commons">>,{pkg,<<"erlware_commons">>,<<"1.5.0">>},0}, {<<"erlware_commons">>,{pkg,<<"erlware_commons">>,<<"1.5.0">>},0},
{<<"eunit_formatters">>,{pkg,<<"eunit_formatters">>,<<"0.5.0">>},0}, {<<"eunit_formatters">>,{pkg,<<"eunit_formatters">>,<<"0.5.0">>},0},
{<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},0}, {<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},0},
{<<"providers">>,{pkg,<<"providers">>,<<"1.8.1">>},0}, {<<"providers">>,{pkg,<<"providers">>,<<"1.9.0">>},0},
{<<"relx">>,{pkg,<<"relx">>,<<"4.5.0">>},0}, {<<"relx">>,{pkg,<<"relx">>,<<"4.6.0">>},0},
{<<"ssl_verify_fun">>,{pkg,<<"ssl_verify_fun">>,<<"1.1.6">>},0}]}. {<<"ssl_verify_fun">>,{pkg,<<"ssl_verify_fun">>,<<"1.1.6">>},0}]}.
[ [
{pkg_hash,[ {pkg_hash,[
{<<"bbmustache">>, <<"DDC927463F0E95D66CDAC889153AF08015D609124D6D79006C248AD2DE7F6ECD">>}, {<<"bbmustache">>, <<"0CABDCE0DB9FE6D3318131174B9F2B351328A4C0AFBEB3E6E99BB0E02E9B621D">>},
{<<"certifi">>, <<"DBAB8E5E155A0763EEA978C913CA280A6B544BFA115633FA20249C3D396D9493">>}, {<<"certifi">>, <<"D4FB0A6BB20B7C9C3643E22507E42F356AC090A1DCEA9AB99E27E0376D695EBA">>},
{<<"cf">>, <<"5CB902239476E141EA70A740340233782D363A31EEA8AD37049561542E6CD641">>}, {<<"cf">>, <<"5CB902239476E141EA70A740340233782D363A31EEA8AD37049561542E6CD641">>},
{<<"cth_readable">>, <<"F511EFCFDE04A48B014A9197FFF1B4C4860E4E35CDB8E2F3AE3C4178E20299B1">>}, {<<"cth_readable">>, <<"F511EFCFDE04A48B014A9197FFF1B4C4860E4E35CDB8E2F3AE3C4178E20299B1">>},
{<<"erlware_commons">>, <<"918C56D8FB3BE52AF0DF138ED6E0755E764AD4467CD7D025761F7D0A17D3DEC1">>}, {<<"erlware_commons">>, <<"918C56D8FB3BE52AF0DF138ED6E0755E764AD4467CD7D025761F7D0A17D3DEC1">>},
{<<"eunit_formatters">>, <<"6A9133943D36A465D804C1C5B6E6839030434B8879C5600D7DDB5B3BAD4CCB59">>}, {<<"eunit_formatters">>, <<"6A9133943D36A465D804C1C5B6E6839030434B8879C5600D7DDB5B3BAD4CCB59">>},
{<<"getopt">>, <<"C73A9FA687B217F2FF79F68A3B637711BB1936E712B521D8CE466B29CBF7808A">>}, {<<"getopt">>, <<"C73A9FA687B217F2FF79F68A3B637711BB1936E712B521D8CE466B29CBF7808A">>},
{<<"providers">>, <<"70B4197869514344A8A60E2B2A4EF41CA03DEF43CFB1712ECF076A0F3C62F083">>}, {<<"providers">>, <<"46F6645B0C677B1029E02B013BFD69092A2232854DAF359F2378FA42AC0BEC0D">>},
{<<"relx">>, <<"2BF90A855023023EDD000641033D1AB9F4EBD4314D1739F691E16FE03CB35B85">>}, {<<"relx">>, <<"939DB831A63CC35A7850C99DCC758FE9F3900E32E1DAB7CBB34E5306CAF53168">>},
{<<"ssl_verify_fun">>, <<"CF344F5692C82D2CD7554F5EC8FD961548D4FD09E7D22F5B62482E5AEAEBD4B0">>}]}, {<<"ssl_verify_fun">>, <<"CF344F5692C82D2CD7554F5EC8FD961548D4FD09E7D22F5B62482E5AEAEBD4B0">>}]},
{pkg_hash_ext,[ {pkg_hash_ext,[
{<<"bbmustache">>, <<"43EFFA3FD4BB9523157AF5A9E2276C493495B8459FC8737144AA186CB13CE2EE">>}, {<<"bbmustache">>, <<"688B33A4D5CC2D51F575ADF0B3683FC40A38314A2F150906EDCFC77F5B577B3B">>},
{<<"certifi">>, <<"524C97B4991B3849DD5C17A631223896272C6B0AF446778BA4675A1DFF53BB7E">>}, {<<"certifi">>, <<"6AC7EFC1C6F8600B08D625292D4BBF584E14847CE1B6B5C44D983D273E1097EA">>},
{<<"cf">>, <<"315E8D447D3A4B02BCDBFA397AD03BBB988A6E0AA6F44D3ADD0F4E3C3BF97672">>}, {<<"cf">>, <<"315E8D447D3A4B02BCDBFA397AD03BBB988A6E0AA6F44D3ADD0F4E3C3BF97672">>},
{<<"cth_readable">>, <<"686541A22EFE6CA5A41A047B39516C2DD28FB3CADE5F24A2F19145B3967F9D80">>}, {<<"cth_readable">>, <<"686541A22EFE6CA5A41A047B39516C2DD28FB3CADE5F24A2F19145B3967F9D80">>},
{<<"erlware_commons">>, <<"3E7C6FB2BA4C29B0DD5DFE9D031B66449E2088ECEC1A81465BD9FDE05ED7D0DB">>}, {<<"erlware_commons">>, <<"3E7C6FB2BA4C29B0DD5DFE9D031B66449E2088ECEC1A81465BD9FDE05ED7D0DB">>},
{<<"eunit_formatters">>, <<"D6C8BA213424944E6E05BBC097C32001CDD0ABE3925D02454F229B20D68763C9">>}, {<<"eunit_formatters">>, <<"D6C8BA213424944E6E05BBC097C32001CDD0ABE3925D02454F229B20D68763C9">>},
{<<"getopt">>, <<"53E1AB83B9CEB65C9672D3E7A35B8092E9BDC9B3EE80721471A161C10C59959C">>}, {<<"getopt">>, <<"53E1AB83B9CEB65C9672D3E7A35B8092E9BDC9B3EE80721471A161C10C59959C">>},
{<<"providers">>, <<"E45745ADE9C476A9A469EA0840E418AB19360DC44F01A233304E118A44486BA0">>}, {<<"providers">>, <<"D287E874406A1505608642B0A3DB5B68D6ADA3F2AB001AEC87E7F4D7C79FC017">>},
{<<"relx">>, <<"DDB58F20CCE6CA63F5A2725E925816DD7213476698A3F3C3CB4FA8C272202C52">>}, {<<"relx">>, <<"2FF8131C63093C621C6B37DC52D1B2848A938886584B4B701D35BDBE4377F509">>},
{<<"ssl_verify_fun">>, <<"BDB0D2471F453C88FF3908E7686F86F9BE327D065CC1EC16FA4540197EA04680">>}]} {<<"ssl_verify_fun">>, <<"BDB0D2471F453C88FF3908E7686F86F9BE327D065CC1EC16FA4540197EA04680">>}]}
]. ].

View File

@ -3,7 +3,7 @@
{application, rebar, {application, rebar,
[{description, "Rebar: Erlang Build Tool"}, [{description, "Rebar: Erlang Build Tool"},
{vsn, "3.17.0"}, {vsn, "3.18.0"},
{modules, []}, {modules, []},
{registered, []}, {registered, []},
{applications, [kernel, {applications, [kernel,

View File

@ -160,18 +160,19 @@ run_aux(State, RawArgs) ->
State4 = rebar_state:set(State3, base_dir, State4 = rebar_state:set(State3, base_dir,
filename:join(filename:absname(rebar_state:dir(State3)), BaseDir)), filename:join(filename:absname(rebar_state:dir(State3)), BaseDir)),
State5 = case os:getenv("REBAR_CACHE_DIR") of
false ->
State4;
ConfigFile ->
rebar_state:set(State4, global_rebar_dir, ConfigFile)
end,
{ok, Providers} = application:get_env(rebar, providers), {ok, Providers} = application:get_env(rebar, providers),
%% Providers can modify profiles stored in opts, so set default after initializing providers %% Providers can modify profiles stored in opts, so set default after initializing providers
State5 = rebar_state:create_logic_providers(Providers, State4), State6 = rebar_state:create_logic_providers(Providers, State5),
%% Initializing project_plugins which can override default providers %% Initializing project_plugins which can override default providers
State6 = rebar_plugins:project_plugins_install(State5), State7 = rebar_plugins:project_plugins_install(State6),
State7 = rebar_plugins:top_level_install(State6), State8 = rebar_plugins:top_level_install(State7),
State8 = case os:getenv("REBAR_CACHE_DIR") of
false ->
State7;
ConfigFile ->
rebar_state:set(State7, global_rebar_dir, ConfigFile)
end,
State9 = rebar_state:default(State8, rebar_state:opts(State8)), State9 = rebar_state:default(State8, rebar_state:opts(State8)),

View File

@ -58,7 +58,7 @@ error(Str, Args) -> ?ERROR(Str, Args).
expand_env_variable(InStr, VarName, RawVarValue) -> expand_env_variable(InStr, VarName, RawVarValue) ->
rebar_utils:expand_env_variable(InStr, VarName, RawVarValue). rebar_utils:expand_env_variable(InStr, VarName, RawVarValue).
%% @doc returns the sytem architecture, in strings like %% @doc returns the system architecture, in strings like
%% `"19.0.4-x86_64-unknown-linux-gnu-64"'. %% `"19.0.4-x86_64-unknown-linux-gnu-64"'.
-spec get_arch() -> string(). -spec get_arch() -> string().
get_arch() -> get_arch() ->

View File

@ -54,7 +54,7 @@ do(State, LibDirs) ->
end, State, lists:reverse(CurrentProfiles)), end, State, lists:reverse(CurrentProfiles)),
%% Handle sub project apps deps %% Handle sub project apps deps
%% Sort apps so we get the same merged deps config everytime %% Sort apps so we get the same merged deps config every time
SortedApps = rebar_utils:sort_deps(Apps), SortedApps = rebar_utils:sort_deps(Apps),
lists:foldl(fun(AppInfo, StateAcc) -> lists:foldl(fun(AppInfo, StateAcc) ->
Name = rebar_app_info:name(AppInfo), Name = rebar_app_info:name(AppInfo),
@ -415,6 +415,7 @@ create_app_info(AppInfo, AppDir, AppFile) ->
AppVsn = proplists:get_value(vsn, AppDetails), AppVsn = proplists:get_value(vsn, AppDetails),
Applications = proplists:get_value(applications, AppDetails, []), Applications = proplists:get_value(applications, AppDetails, []),
IncludedApplications = proplists:get_value(included_applications, AppDetails, []), IncludedApplications = proplists:get_value(included_applications, AppDetails, []),
OptionalApplications = proplists:get_value(optional_applications, AppDetails, []),
AppInfo1 = rebar_app_info:name( AppInfo1 = rebar_app_info:name(
rebar_app_info:vsn( rebar_app_info:vsn(
rebar_app_info:original_vsn( rebar_app_info:original_vsn(
@ -422,14 +423,15 @@ create_app_info(AppInfo, AppDir, AppFile) ->
AppInfo2 = rebar_app_info:applications( AppInfo2 = rebar_app_info:applications(
rebar_app_info:app_details(AppInfo1, AppDetails), Applications), rebar_app_info:app_details(AppInfo1, AppDetails), Applications),
AppInfo3 = rebar_app_info:included_applications(AppInfo2, IncludedApplications), AppInfo3 = rebar_app_info:included_applications(AppInfo2, IncludedApplications),
Valid = case rebar_app_utils:validate_application_info(AppInfo3) =:= true AppInfo4 = rebar_app_info:optional_applications(AppInfo3, OptionalApplications),
andalso rebar_app_info:has_all_artifacts(AppInfo3) =:= true of Valid = case rebar_app_utils:validate_application_info(AppInfo4) =:= true
andalso rebar_app_info:has_all_artifacts(AppInfo4) =:= true of
true -> true ->
true; true;
_ -> _ ->
false false
end, end,
rebar_app_info:dir(rebar_app_info:valid(AppInfo3, Valid), AppDir); rebar_app_info:dir(rebar_app_info:valid(AppInfo4, Valid), AppDir);
_Invalid -> _Invalid ->
throw({error, {?MODULE, {cannot_read_app_file, AppFile}}}) throw({error, {?MODULE, {cannot_read_app_file, AppFile}}})
catch catch
@ -438,7 +440,7 @@ create_app_info(AppInfo, AppDir, AppFile) ->
end. end.
%% @doc Read in and parse the .app file if it is availabe. Do the same for %% @doc Read in and parse the .app file if it is available. Do the same for
%% the .app.src file if it exists. %% the .app.src file if it exists.
-spec try_handle_resource_files(AppInfo, AppDir, ResourceFiles, valid | invalid | all) -> -spec try_handle_resource_files(AppInfo, AppDir, ResourceFiles, valid | invalid | all) ->
{true, AppInfo} | false when {true, AppInfo} | false when
@ -463,7 +465,7 @@ try_handle_resource_files(_AppInfo, _AppDir, [], _Validate) ->
false. false.
%% @doc Read in and parse the .app file if it is availabe. Do the same for %% @doc Read in and parse the .app file if it is available. Do the same for
%% the .app.src file if it exists. %% the .app.src file if it exists.
-spec try_handle_app_file(AppInfo, AppDir, File, AppSrcFile, valid | invalid | all) -> -spec try_handle_app_file(AppInfo, AppDir, File, AppSrcFile, valid | invalid | all) ->
{true, AppInfo} | false when {true, AppInfo} | false when

View File

@ -32,6 +32,8 @@
applications/2, applications/2,
included_applications/1, included_applications/1,
included_applications/2, included_applications/2,
optional_applications/1,
optional_applications/2,
profiles/1, profiles/1,
profiles/2, profiles/2,
deps/1, deps/1,
@ -94,6 +96,7 @@
app_details=[] :: list(), app_details=[] :: list(),
applications=[] :: list(), applications=[] :: list(),
included_applications=[] :: [atom()], included_applications=[] :: [atom()],
optional_applications=[] :: [atom()],
deps=[] :: list(), deps=[] :: list(),
profiles=[default] :: [atom()], profiles=[default] :: [atom()],
default=dict:new() :: rebar_dict(), default=dict:new() :: rebar_dict(),
@ -119,7 +122,7 @@
%% API %% API
%% ============================================================================ %% ============================================================================
%% @doc Build a new, empty, app info value. This is not of a lot of use and you %% @doc Build a new, empty, app info value. This is not of a lot of use and you
%% probably wont be doing this much. %% probably won't be doing this much.
-spec new() -> t(). -spec new() -> t().
new() -> new() ->
#app_info_t{}. #app_info_t{}.
@ -181,6 +184,7 @@ new(Parent, AppName, Vsn, Dir, Deps) ->
vsn := app_vsn(), vsn := app_vsn(),
applications := [atom()], applications := [atom()],
included_applications := [atom()], included_applications := [atom()],
optional_applications := [atom()],
dir := file:name(), dir := file:name(),
out_dir := file:name(), out_dir := file:name(),
ebin_dir := file:name(), ebin_dir := file:name(),
@ -189,12 +193,14 @@ app_to_map(#app_info_t{name=Name,
vsn=Vsn, vsn=Vsn,
applications=Applications, applications=Applications,
included_applications=IncludedApplications, included_applications=IncludedApplications,
optional_applications=OptionalApplications,
out_dir=OutDir, out_dir=OutDir,
ebin_dir=EbinDir}) -> ebin_dir=EbinDir}) ->
#{name => ec_cnv:to_atom(Name), #{name => ec_cnv:to_atom(Name),
vsn => Vsn, vsn => Vsn,
applications => Applications, applications => Applications,
included_applications => IncludedApplications, included_applications => IncludedApplications,
optional_applications => OptionalApplications,
dir => OutDir, dir => OutDir,
out_dir => OutDir, out_dir => OutDir,
ebin_dir => EbinDir, ebin_dir => EbinDir,
@ -468,6 +474,17 @@ included_applications(#app_info_t{included_applications=Applications}) ->
included_applications(AppInfo=#app_info_t{}, Applications) -> included_applications(AppInfo=#app_info_t{}, Applications) ->
AppInfo#app_info_t{included_applications=Applications}. AppInfo#app_info_t{included_applications=Applications}.
%% @doc returns the list of optional_applications the app depends on.
-spec optional_applications(t()) -> list().
optional_applications(#app_info_t{optional_applications=Applications}) ->
Applications.
%% @doc sets the list of optional applications the app depends on.
%% Should be obtained from the app file.
-spec optional_applications(t(), list()) -> t().
optional_applications(AppInfo=#app_info_t{}, Applications) ->
AppInfo#app_info_t{optional_applications=Applications}.
%% @doc returns the list of active profiles %% @doc returns the list of active profiles
-spec profiles(t()) -> list(). -spec profiles(t()) -> list().
profiles(#app_info_t{profiles=Profiles}) -> profiles(#app_info_t{profiles=Profiles}) ->

View File

@ -63,7 +63,7 @@ needed_files(Graph, FoundFiles, _, AppInfo) ->
NeededErlFiles = case needed_files(Graph, ErlOpts, RebarOpts, OutDir, EbinDir, ParseTransforms) of NeededErlFiles = case needed_files(Graph, ErlOpts, RebarOpts, OutDir, EbinDir, ParseTransforms) of
[] -> [] ->
needed_files(Graph, ErlOpts, RebarOpts, OutDir, EbinDir, Rest); needed_files(Graph, ErlOpts, RebarOpts, OutDir, EbinDir, Rest);
_ -> _ ->
%% at least one parse transform in the opts needs updating, so recompile all %% at least one parse transform in the opts needs updating, so recompile all
FoundFiles FoundFiles
end, end,
@ -258,6 +258,7 @@ target_base(OutDir, Source) ->
filename:join(OutDir, filename:basename(Source, ".erl")). filename:join(OutDir, filename:basename(Source, ".erl")).
opts_changed(Graph, NewOpts, Target, TargetBase) -> opts_changed(Graph, NewOpts, Target, TargetBase) ->
ModuleName = list_to_atom(filename:basename(TargetBase)),
{ok, CompileVsn} = application:get_key(compiler, vsn), {ok, CompileVsn} = application:get_key(compiler, vsn),
TotalOpts = case erlang:function_exported(compile, env_compiler_options, 0) of TotalOpts = case erlang:function_exported(compile, env_compiler_options, 0) of
true -> [{compiler_version, CompileVsn}] ++ NewOpts ++ compile:env_compiler_options(); true -> [{compiler_version, CompileVsn}] ++ NewOpts ++ compile:env_compiler_options();
@ -272,10 +273,10 @@ opts_changed(Graph, NewOpts, Target, TargetBase) ->
_ -> [] _ -> []
end end
end, end,
lists:any(fun effects_code_generation/1, lists:any(fun(Option) -> effects_code_generation(ModuleName, Option) end,
lists:usort(TotalOpts) -- lists:usort(TargetOpts)). lists:usort(TotalOpts) -- lists:usort(TargetOpts)).
effects_code_generation(Option) -> effects_code_generation(ModuleName, Option) ->
case Option of case Option of
beam -> false; beam -> false;
report_warnings -> false; report_warnings -> false;
@ -288,6 +289,7 @@ effects_code_generation(Option) ->
verbose -> false; verbose -> false;
{cwd,_} -> false; {cwd,_} -> false;
{outdir, _} -> false; {outdir, _} -> false;
{parse_transform, ModuleName} -> false;
no_spawn_compiler_process -> false; no_spawn_compiler_process -> false;
_ -> true _ -> true
end. end.
@ -334,7 +336,7 @@ atoms_in_erl_first_files_warning(Atoms) ->
W = "You have provided atoms as file entries in erl_first_files; " W = "You have provided atoms as file entries in erl_first_files; "
"erl_first_files only expects lists of filenames as strings. " "erl_first_files only expects lists of filenames as strings. "
"The following modules (~p) may not work as expected and it is advised " "The following modules (~p) may not work as expected and it is advised "
"that you change these entires to string format " "that you change these entries to string format "
"(e.g., \"src/module.erl\") ", "(e.g., \"src/module.erl\") ",
?WARN(W, [Atoms]). ?WARN(W, [Atoms]).

View File

@ -56,7 +56,7 @@ atoms_in_mib_first_files_warning(Atoms) ->
W = "You have provided atoms as file entries in mib_first_files; " W = "You have provided atoms as file entries in mib_first_files; "
"mib_first_files only expects lists of filenames as strings. " "mib_first_files only expects lists of filenames as strings. "
"The following MIBs (~p) may not work as expected and it is advised " "The following MIBs (~p) may not work as expected and it is advised "
"that you change these entires to string format " "that you change these entries to string format "
"(e.g., \"mibs/SOME-MIB.mib\") ", "(e.g., \"mibs/SOME-MIB.mib\") ",
?WARN(W, [Atoms]). ?WARN(W, [Atoms]).

View File

@ -32,10 +32,16 @@ needed_files(_, FoundFiles, Mappings, AppInfo) ->
dependencies(_, _, _) -> dependencies(_, _, _) ->
[]. [].
compile(Source, [{_, OutDir}], _, Opts) -> compile(Source, [{_, OutDir}], _, Opts0) ->
BaseName = filename:basename(Source, ".yrl"), Opts = case proplists:get_value(parserfile, Opts0) of
Target = filename:join([OutDir, BaseName]), undefined ->
AllOpts = [{parserfile, Target}, {return, true} | Opts], BaseName = filename:basename(Source, ".yrl"),
Target = filename:join([OutDir, BaseName]),
[{parserfile, Target} | Opts0];
_ ->
Opts0
end,
AllOpts = [{return, true} | Opts],
case yecc:file(Source, AllOpts) of case yecc:file(Source, AllOpts) of
{ok, _} -> {ok, _} ->
ok; ok;

View File

@ -68,7 +68,7 @@ process_namespace(State, Command) ->
not_found -> not_found ->
case providers:get_providers_by_namespace(Command, Providers) of case providers:get_providers_by_namespace(Command, Providers) of
[] -> [] ->
{error, io_lib:format("Command ~p not found", [Command])}; {error, io_lib:format("Command ~ts not found", [atom_to_list(Command)])};
_ -> _ ->
%% Replay 'do' as a command of that namespace %% Replay 'do' as a command of that namespace
{ok, rebar_state:namespace(State, Command), do} {ok, rebar_state:namespace(State, Command), do}
@ -98,10 +98,10 @@ process_command(State, Command) ->
not_found when Command =/= do -> not_found when Command =/= do ->
case Namespace of case Namespace of
default -> default ->
{error, io_lib:format("Command ~p not found", [Command])}; {error, io_lib:format("Command ~ts not found", [atom_to_list(Command)])};
_ -> _ ->
{error, io_lib:format("Command ~p not found in namespace ~p", {error, io_lib:format("Command ~ts not found in namespace ~ts",
[Command, Namespace])} [atom_to_list(Command), atom_to_list(Namespace)])}
end; end;
not_found when Command =:= do, Namespace =/= default -> not_found when Command =:= do, Namespace =/= default ->
do([{default, do} | TargetProviders], State); do([{default, do} | TargetProviders], State);
@ -120,7 +120,7 @@ process_command(State, Command) ->
State2 = rebar_state:command_parsed_args(State1, Args), State2 = rebar_state:command_parsed_args(State1, Args),
do(TargetProviders, State2); do(TargetProviders, State2);
{error, {invalid_option, Option}} -> {error, {invalid_option, Option}} ->
{error, io_lib:format("Invalid option ~ts on task ~p", [Option, Command])}; {error, io_lib:format("Invalid option ~ts on task ~ts", [Option, atom_to_list(Command)])};
{error, {invalid_option_arg, {Option, Arg}}} -> {error, {invalid_option_arg, {Option, Arg}}} ->
{error, io_lib:format("Invalid argument ~ts to option ~ts", [Arg, Option])}; {error, io_lib:format("Invalid argument ~ts to option ~ts", [Arg, Option])};
{error, {missing_option_arg, Option}} -> {error, {missing_option_arg, Option}} ->
@ -137,7 +137,7 @@ process_command(State, Command) ->
do([], State) -> do([], State) ->
{ok, State}; {ok, State};
do([ProviderName | Rest], State) -> do([ProviderName | Rest], State) ->
?DEBUG("Running provider: ~p", [friendly_provider(ProviderName)]), ?DEBUG("Running provider: ~tp", [friendly_provider(ProviderName)]),
%% Special providers like 'as', 'do' or some hooks may be passed %% Special providers like 'as', 'do' or some hooks may be passed
%% as a tuple {Namespace, Name}, otherwise not. Handle them %% as a tuple {Namespace, Name}, otherwise not. Handle them
%% on a per-need basis. %% on a per-need basis.

View File

@ -8,7 +8,7 @@
%%% out the cody bits %%% out the cody bits
%%% * red: things that went bad, i.e. the wrong argument in a %%% * red: things that went bad, i.e. the wrong argument in a
%%% call. It allows to quickly catching where in the code %%% call. It allows to quickly catching where in the code
%%% ane error is. %%% and error is.
%%% * green: the 'good' stuff, i.e. what was expected as an argument %%% * green: the 'good' stuff, i.e. what was expected as an argument
%%% the 'red vs green' resambles the diff view 'remove vs add' %%% the 'red vs green' resambles the diff view 'remove vs add'
%%% * blue: argument positions. %%% * blue: argument positions.
@ -412,14 +412,14 @@ highlight([N | Nr], N, r, [Arg | Rest]) ->
highlight(Ns, N, C, [Arg | Rest]) -> highlight(Ns, N, C, [Arg | Rest]) ->
[Arg | highlight(Ns, N + 1, C, Rest)]. [Arg | highlight(Ns, N + 1, C, Rest)].
%% Arugments to functions and constraints are passed as %% Arguments to functions and constraints are passed as
%% strings not as data, this function pulls them apart %% strings not as data, this function pulls them apart
%% to allow interacting with them separately and not %% to allow interacting with them separately and not
%% as one bug chunk of data. %% as one bug chunk of data.
separate_args([$( | S]) -> separate_args([$( | S]) ->
separate_args([], S, "", []). separate_args([], S, "", []).
%% We strip this space since dialyzer is inconsistant in adding or not adding %% We strip this space since dialyzer is inconsistent in adding or not adding
%% it .... %% it ....
separate_args([], [$,, $\s | R], Arg, Args) -> separate_args([], [$,, $\s | R], Arg, Args) ->
separate_args([], R, [], [lists:reverse(Arg) | Args]); separate_args([], R, [], [lists:reverse(Arg) | Args]);

View File

@ -292,8 +292,8 @@ all_src_dirs(Opts, SrcDefault, ExtraDefault) ->
%%% @doc %%% @doc
%%% Return the list of options for the given src directory %%% Return the list of options for the given src directory
%%% If the same option is given multiple times for a directory in the %%% If the same option is given multiple times for a directory in the
%%% config, the priority order is: first occurence of `src_dirs' %%% config, the priority order is: first occurrence of `src_dirs'
%%% followed by first occurence of `extra_src_dirs'. %%% followed by first occurrence of `extra_src_dirs'.
-spec src_dir_opts(rebar_dict(), file:filename_all()) -> [{atom(),term()}]. -spec src_dir_opts(rebar_dict(), file:filename_all()) -> [{atom(),term()}].
src_dir_opts(Opts, Dir) -> src_dir_opts(Opts, Dir) ->
RawSrcDirs = raw_src_dirs(src_dirs, Opts, []), RawSrcDirs = raw_src_dirs(src_dirs, Opts, []),

View File

@ -831,7 +831,7 @@ atoms_in_erl_first_files_warning(Atoms) ->
W = "You have provided atoms as file entries in erl_first_files; " W = "You have provided atoms as file entries in erl_first_files; "
"erl_first_files only expects lists of filenames as strings. " "erl_first_files only expects lists of filenames as strings. "
"The following modules (~p) may not work as expected and it is advised " "The following modules (~p) may not work as expected and it is advised "
"that you change these entires to string format " "that you change these entries to string format "
"(e.g., \"src/module.erl\") ", "(e.g., \"src/module.erl\") ",
?WARN(W, [Atoms]). ?WARN(W, [Atoms]).

View File

@ -17,7 +17,7 @@
make_vsn_/1, make_vsn_/1,
git_vsn/0]). git_vsn/0]).
%% For backward compatibilty %% For backward compatibility
-export ([download/3]). -export ([download/3]).
-include("rebar.hrl"). -include("rebar.hrl").
@ -141,7 +141,7 @@ download(TmpDir, AppInfo, State, _) ->
{error, Error} {error, Error}
end. end.
%% For backward compatibilty %% For backward compatibility
download(Dir, AppInfo, State) -> download(Dir, AppInfo, State) ->
download_(Dir, AppInfo, State). download_(Dir, AppInfo, State).
@ -180,7 +180,16 @@ maybe_warn_local_url(Url) ->
end. end.
%% Use different git clone commands depending on git --version %% Use different git clone commands depending on git --version
git_clone(branch, GitVsn, Url, Dir, Branch) when GitVsn >= {1,7,10}; GitVsn =:= undefined -> git_clone(branch, GitVsn, Url, Dir, Branch) when GitVsn >= {2,3,0}; GitVsn =:= undefined ->
rebar_utils:sh(?FMT("git clone ~ts ~ts ~ts -b ~ts --single-branch",
[git_clone_options(),
rebar_utils:escape_chars(Url),
rebar_utils:escape_chars(filename:basename(Dir)),
rebar_utils:escape_chars(Branch)]),
[{cd, filename:dirname(Dir)},
{env, [{"GIT_TERMINAL_PROMPT", "0"}]}]),
ok;
git_clone(branch, GitVsn, Url, Dir, Branch) when GitVsn >= {1,7,10} ->
rebar_utils:sh(?FMT("git clone ~ts ~ts ~ts -b ~ts --single-branch", rebar_utils:sh(?FMT("git clone ~ts ~ts ~ts -b ~ts --single-branch",
[git_clone_options(), [git_clone_options(),
rebar_utils:escape_chars(Url), rebar_utils:escape_chars(Url),
@ -196,7 +205,16 @@ git_clone(branch, _GitVsn, Url, Dir, Branch) ->
rebar_utils:escape_chars(Branch)]), rebar_utils:escape_chars(Branch)]),
[{cd, filename:dirname(Dir)}]), [{cd, filename:dirname(Dir)}]),
ok; ok;
git_clone(tag, GitVsn, Url, Dir, Tag) when GitVsn >= {1,7,10}; GitVsn =:= undefined -> git_clone(tag, GitVsn, Url, Dir, Tag) when GitVsn >= {2,3,0}; GitVsn =:= undefined ->
rebar_utils:sh(?FMT("git clone ~ts ~ts ~ts -b ~ts --single-branch",
[git_clone_options(),
rebar_utils:escape_chars(Url),
rebar_utils:escape_chars(filename:basename(Dir)),
rebar_utils:escape_chars(Tag)]),
[{cd, filename:dirname(Dir)},
{env, [{"GIT_TERMINAL_PROMPT", "0"}]}]),
ok;
git_clone(tag, GitVsn, Url, Dir, Tag) when GitVsn >= {1,7,10} ->
rebar_utils:sh(?FMT("git clone ~ts ~ts ~ts -b ~ts --single-branch", rebar_utils:sh(?FMT("git clone ~ts ~ts ~ts -b ~ts --single-branch",
[git_clone_options(), [git_clone_options(),
rebar_utils:escape_chars(Url), rebar_utils:escape_chars(Url),
@ -335,11 +353,17 @@ get_patch_count(Dir, RawRef) ->
Ref = re:replace(RawRef, "\\s", "", [global, unicode]), Ref = re:replace(RawRef, "\\s", "", [global, unicode]),
Cmd = io_lib:format("git rev-list --count ~ts..HEAD", Cmd = io_lib:format("git rev-list --count ~ts..HEAD",
[rebar_utils:escape_chars(Ref)]), [rebar_utils:escape_chars(Ref)]),
{ok, PatchLines} = rebar_utils:sh(Cmd, {ok, Output} = rebar_utils:sh(Cmd,
[{use_stdout, false}, [{use_stdout, false},
{cd, Dir}, {cd, Dir},
{debug_abort_on_error, AbortMsg}]), {debug_abort_on_error, AbortMsg}]),
{ok, list_to_integer(rebar_string:trim(PatchLines))}. case rebar_string:split(Output, "\n") of
[PatchLines, []] ->
{ok, list_to_integer(PatchLines)};
[Warning, PatchLines] ->
?WARN("Extra message from git rev-list: ~ts", [Warning]),
{ok, list_to_integer(rebar_string:trim(PatchLines))}
end.
parse_tags(Dir) -> parse_tags(Dir) ->
@ -390,4 +414,3 @@ check_type_support() ->
ok ok
end end
end. end.

View File

@ -11,7 +11,7 @@
make_vsn/2]). make_vsn/2]).
%% For backward compatibilty %% For backward compatibility
-export([ download/3 -export([ download/3
]). ]).
@ -77,7 +77,7 @@ download(TmpDir, AppInfo, State, _) ->
{error, Error} {error, Error}
end. end.
%% For backward compatibilty %% For backward compatibility
download(Dir, AppInfo, State) -> download(Dir, AppInfo, State) ->
download_(Dir, AppInfo, State). download_(Dir, AppInfo, State).

View File

@ -428,7 +428,7 @@ cmp_(BestMatch, MinVsn, [Vsn | R], CmpFun) ->
end. end.
%% We need to treat this differently since we want a version that is LOWER but %% We need to treat this differently since we want a version that is LOWER but
%% the higest possible one. %% the highest possible one.
cmpl(Dep, Vsn, Repo, HexRegistry, State, CmpFun) -> cmpl(Dep, Vsn, Repo, HexRegistry, State, CmpFun) ->
case get_package_versions(Dep, Vsn, Repo, HexRegistry, State) of case get_package_versions(Dep, Vsn, Repo, HexRegistry, State) of
[] -> [] ->

View File

@ -135,7 +135,7 @@ format_error({bad_registry_checksum, Name, Vsn, Expected, Found}) ->
%% Download the pkg belonging to the given address. If the etag of the pkg %% Download the pkg belonging to the given address. If the etag of the pkg
%% is the same what we stored in the etag file previously return {ok, cached}, %% is the same what we stored in the etag file previously return {ok, cached},
%% if the file has changed (so the etag is not the same anymore) return %% if the file has changed (so the etag is not the same anymore) return
%% {ok, Contents, NewEtag}, otherwise if some error occured return error. %% {ok, Contents, NewEtag}, otherwise if some error occurred return error.
%% @end %% @end
%%------------------------------------------------------------------------------ %%------------------------------------------------------------------------------
-spec request(rebar_hex_repos:repo(), binary(), binary(), false | binary()) -spec request(rebar_hex_repos:repo(), binary(), binary(), false | binary())

View File

@ -340,7 +340,7 @@ build_custom_builder_app(AppInfo, State) ->
ProjectBuilders = rebar_state:project_builders(State), ProjectBuilders = rebar_state:project_builders(State),
case lists:keyfind(Type, 1, ProjectBuilders) of case lists:keyfind(Type, 1, ProjectBuilders) of
{_, Module} -> {_, Module} ->
%% load plugins since thats where project builders would be, %% load plugins since that's where project builders would be,
%% prevents parallelism at this level. %% prevents parallelism at this level.
rebar_paths:set_paths([deps, plugins], State), rebar_paths:set_paths([deps, plugins], State),
Res = Module:build(AppInfo), Res = Module:build(AppInfo),

View File

@ -25,16 +25,18 @@ init(State) ->
{deps, ?DEPS}, {deps, ?DEPS},
{example, "rebar3 plugins upgrade <plugin>"}, {example, "rebar3 plugins upgrade <plugin>"},
{short_desc, "Upgrade plugins"}, {short_desc, "Upgrade plugins"},
{desc, "List or upgrade plugins"}, {desc, "List or upgrade plugins. Use the -a/--all option to upgrade"
" all plugins."},
{opts, [{plugin, undefined, undefined, string, {opts, [{plugin, undefined, undefined, string,
"Plugin to upgrade"}]}])), "Plugin to upgrade"},
{all, $a, "all", undefined, "Upgrade all plugins."}]}])),
{ok, State1}. {ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) -> do(State) ->
{Args, _} = rebar_state:command_parsed_args(State), case handle_args(State) of
case proplists:get_value(plugin, Args, none) of {false, undefined} -> throw(?PRV_ERROR(no_arg));
none -> {true, _} ->
{_, LocalPluginsNames} = rebar_prv_plugins:list_local_plugins(State), {_, LocalPluginsNames} = rebar_prv_plugins:list_local_plugins(State),
lists:foldl( lists:foldl(
fun (LocalPluginName, {ok, StateAcc}) -> fun (LocalPluginName, {ok, StateAcc}) ->
@ -42,16 +44,23 @@ do(State) ->
end, end,
{ok, State}, {ok, State},
LocalPluginsNames); LocalPluginsNames);
Plugin -> {false, Plugin} -> upgrade(Plugin, State)
upgrade(Plugin, State)
end. end.
-spec format_error(any()) -> iolist(). -spec format_error(any()) -> iolist().
format_error({not_found, Plugin}) -> format_error({not_found, Plugin}) ->
io_lib:format("Plugin to upgrade not found: ~ts", [Plugin]); io_lib:format("Plugin to upgrade not found: ~ts", [Plugin]);
format_error(no_arg) ->
"Specify a plugin to upgrade, or --all to upgrade them all";
format_error(Reason) -> format_error(Reason) ->
io_lib:format("~p", [Reason]). io_lib:format("~p", [Reason]).
handle_args(State) ->
{Args, _} = rebar_state:command_parsed_args(State),
All = proplists:get_value(all, Args, false),
Plugin = proplists:get_value(plugin, Args),
{All, Plugin}.
upgrade(Plugin, State) -> upgrade(Plugin, State) ->
Profiles = rebar_state:current_profiles(State), Profiles = rebar_state:current_profiles(State),
case find_plugin(Plugin, Profiles, State) of case find_plugin(Plugin, Profiles, State) of

View File

@ -26,12 +26,12 @@ init(State) ->
{deps, ?DEPS}, {deps, ?DEPS},
{example, ""}, {example, ""},
{short_desc, "Unlock dependencies."}, {short_desc, "Unlock dependencies."},
{desc, "Unlock project dependencies. Mentioning no application " {desc, "Unlock project dependencies. Use the --all option "
"will unlock all dependencies. To unlock specific dependencies, " "to unlock all dependencies. To unlock specific dependencies, "
"their name can be listed in the command."}, "their name can be listed in the command."},
{opts, [ {opts, [{all, $a, "all", undefined, "Unlock all dependencies and remove the lock file."},
{package, undefined, undefined, string, {package, undefined, undefined, string,
"List of packages to unlock. If not specified, all dependencies are unlocked."} "List of packages to unlock."}
]} ]}
]) ])
), ),
@ -57,24 +57,41 @@ format_error({file, Reason}) ->
io_lib:format("Lock file editing failed for reason ~p", [Reason]); io_lib:format("Lock file editing failed for reason ~p", [Reason]);
format_error(unknown_lock_format) -> format_error(unknown_lock_format) ->
"Lock file format unknown"; "Lock file format unknown";
format_error(no_arg) ->
"Specify a list of dependencies to unlock, or --all to unlock them all";
format_error(Reason) -> format_error(Reason) ->
io_lib:format("~p", [Reason]). io_lib:format("~p", [Reason]).
handle_unlocks(State, Locks, LockFile) -> handle_unlocks(State, Locks, LockFile) ->
{Args, _} = rebar_state:command_parsed_args(State), case handle_args(State) of
Names = parse_names(rebar_utils:to_binary(proplists:get_value(package, Args, <<"">>))), %% a list of dependencies or --all is required
case [Lock || Lock = {Name, _, _} <- Locks, not lists:member(Name, Names)] of {false, []} ->
[] -> throw(?PRV_ERROR(no_arg));
%% if --all is specified, delete the lock file
{true, _} ->
file:delete(LockFile), file:delete(LockFile),
{ok, []}; {ok, []};
_ when Names =:= [] -> % implicitly all locks %% otherwise, unlock the given list of dependency names. if none are left, delete the lock file
file:delete(LockFile), {false, Names} ->
{ok, []}; case [Lock || Lock = {Name, _, _} <- Locks, not lists:member(Name, Names)] of
NewLocks -> [] ->
rebar_config:write_lock_file(LockFile, NewLocks), file:delete(LockFile),
{ok, NewLocks} {ok, []};
_ when Names =:= [] -> % implicitly all locks
file:delete(LockFile),
{ok, []};
NewLocks ->
rebar_config:write_lock_file(LockFile, NewLocks),
{ok, NewLocks}
end
end. end.
handle_args(State) ->
{Args, _} = rebar_state:command_parsed_args(State),
All = proplists:get_value(all, Args, false),
Names = parse_names(rebar_utils:to_binary(proplists:get_value(package, Args, <<"">>))),
{All, Names}.
parse_names(Bin) -> parse_names(Bin) ->
case lists:usort(re:split(Bin, <<" *, *">>, [trim, unicode])) of case lists:usort(re:split(Bin, <<" *, *">>, [trim, unicode])) of
[<<"">>] -> []; % nothing submitted [<<"">>] -> []; % nothing submitted

View File

@ -32,12 +32,12 @@ init(State) ->
{deps, ?DEPS}, {deps, ?DEPS},
{example, "rebar3 upgrade [cowboy[,ranch]]"}, {example, "rebar3 upgrade [cowboy[,ranch]]"},
{short_desc, "Upgrade dependencies."}, {short_desc, "Upgrade dependencies."},
{desc, "Upgrade project dependencies. Mentioning no application " {desc, "Upgrade project dependencies. Use the -a/--all option to "
"will upgrade all dependencies. To upgrade specific dependencies, " "upgrade all dependencies. To upgrade specific dependencies, "
"their names can be listed in the command."}, "their names can be listed in the command."},
{opts, [ {opts, [{all, $a, "all", undefined, "Upgrade all dependencies."},
{package, undefined, undefined, string, {package, undefined, undefined, string,
"List of packages to upgrade. If not specified, all dependencies are upgraded."} "List of packages to upgrade."}
]}])), ]}])),
{ok, State1}. {ok, State1}.
@ -56,7 +56,6 @@ do(State) ->
end. end.
do_(State) -> do_(State) ->
{Args, _} = rebar_state:command_parsed_args(State),
Locks = rebar_state:get(State, {locks, default}, []), Locks = rebar_state:get(State, {locks, default}, []),
%% We have 3 sources of dependencies to upgrade from: %% We have 3 sources of dependencies to upgrade from:
%% 1. the top-level rebar.config (in `deps', dep name is an atom) %% 1. the top-level rebar.config (in `deps', dep name is an atom)
@ -81,8 +80,12 @@ do_(State) ->
ProfileDeps = rebar_state:get(State, {deps, default}, []), ProfileDeps = rebar_state:get(State, {deps, default}, []),
Deps = [Dep || Dep <- TopDeps ++ ProfileDeps, % TopDeps > ProfileDeps Deps = [Dep || Dep <- TopDeps ++ ProfileDeps, % TopDeps > ProfileDeps
is_atom(Dep) orelse is_atom(element(1, Dep))], is_atom(Dep) orelse is_atom(element(1, Dep))],
Names = parse_names(rebar_utils:to_binary(proplists:get_value(package, Args, <<"">>)), Locks), Names = case handle_args(State) of
{false, undefined} -> throw(?PRV_ERROR(no_arg));
{true, _} -> [Name || {Name, _, 0} <- Locks];
{false, Packages} -> Bin = rebar_utils:to_binary(Packages),
lists:usort(re:split(Bin, <<" *, *">>, [trim, unicode]))
end,
DepsDict = deps_dict(rebar_state:all_deps(State)), DepsDict = deps_dict(rebar_state:all_deps(State)),
AltDeps = find_non_default_deps(Deps, State), AltDeps = find_non_default_deps(Deps, State),
FilteredNames = cull_default_names_if_profiles(Names, Deps, State), FilteredNames = cull_default_names_if_profiles(Names, Deps, State),
@ -127,9 +130,17 @@ format_error({transitive_dependency, Name}) ->
format_error({checkout_dependency, Name}) -> format_error({checkout_dependency, Name}) ->
io_lib:format("Dependency ~ts is a checkout dependency under _checkouts/ and checkouts cannot be upgraded.", io_lib:format("Dependency ~ts is a checkout dependency under _checkouts/ and checkouts cannot be upgraded.",
[Name]); [Name]);
format_error(no_arg) ->
"Specify a list of dependencies to upgrade, or --all to upgrade them all";
format_error(Reason) -> format_error(Reason) ->
io_lib:format("~p", [Reason]). io_lib:format("~p", [Reason]).
handle_args(State) ->
{Args, _} = rebar_state:command_parsed_args(State),
All = proplists:get_value(all, Args, false),
Package = proplists:get_value(package, Args),
{All, Package}.
%% fetch updates for package deps that have been unlocked for upgrade %% fetch updates for package deps that have been unlocked for upgrade
update_pkg_deps([], _, _) -> update_pkg_deps([], _, _) ->
ok; ok;
@ -160,15 +171,6 @@ update_package(Name, RepoConfig, State) ->
ok ok
end. end.
parse_names(Bin, Locks) ->
case lists:usort(re:split(Bin, <<" *, *">>, [trim, unicode])) of
%% Nothing submitted, use *all* apps
[<<"">>] -> [Name || {Name, _, 0} <- Locks];
[] -> [Name || {Name, _, 0} <- Locks];
%% Regular options
Other -> Other
end.
%% Find alternative deps in non-default profiles since they may %% Find alternative deps in non-default profiles since they may
%% need to be passed through (they are never locked) %% need to be passed through (they are never locked)
find_non_default_deps(Deps, State) -> find_non_default_deps(Deps, State) ->

View File

@ -118,6 +118,8 @@ format_error(all_relup) ->
"Option --all can not be applied to `relup` command"; "Option --all can not be applied to `relup` command";
format_error({config_file, Filename, Error}) -> format_error({config_file, Filename, Error}) ->
io_lib:format("Failed to read config file ~ts: ~p", [Filename, Error]); io_lib:format("Failed to read config file ~ts: ~p", [Filename, Error]);
format_error({release_not_found, Relname}) ->
io_lib:format("No releases exists in the system for ~s!", [Relname]);
format_error(Error) -> format_error(Error) ->
io_lib:format("~p", [Error]). io_lib:format("~p", [Error]).
@ -154,8 +156,9 @@ rel_handler({ok, _}, _) ->
ok. ok.
releases_to_build(Provider, Opts, RelxState)-> releases_to_build(Provider, Opts, RelxState)->
case proplists:get_value(all, Opts, undefined) of case {proplists:get_value(all, Opts, undefined),
undefined -> proplists:get_value(relnames, Opts, undefined)} of
{undefined, undefined} ->
case proplists:get_value(relname, Opts, undefined) of case proplists:get_value(relname, Opts, undefined) of
undefined -> undefined ->
[undefined]; [undefined];
@ -167,10 +170,20 @@ releases_to_build(Provider, Opts, RelxState)->
[{list_to_atom(R), RelVsn}] [{list_to_atom(R), RelVsn}]
end end
end; end;
true when Provider =:= relup -> {true, _} when Provider =:= relup ->
erlang:error(?PRV_ERROR(all_relup)); erlang:error(?PRV_ERROR(all_relup));
true -> {true, _} ->
highest_unique_releases(rlx_state:configured_releases(RelxState)) highest_unique_releases(rlx_state:configured_releases(RelxState));
{_, Filter} ->
Releases = highest_unique_releases(rlx_state:configured_releases(RelxState)),
WantReleases = [list_to_atom(Rel) || Rel <- string:split(Filter, ",", all)],
[
case proplists:lookup(Relname, Releases) of
none -> erlang:error(?PRV_ERROR({release_not_found, Relname}));
Rel -> Rel
end
|| Relname <- WantReleases
]
end. end.
%% takes a map of relx configured releases and returns a list of the highest %% takes a map of relx configured releases and returns a list of the highest
@ -249,9 +262,10 @@ app_info_to_relx(#{name := Name,
vsn := Vsn, vsn := Vsn,
applications := Applications, applications := Applications,
included_applications := IncludedApplications, included_applications := IncludedApplications,
optional_applications := OptionalApplications,
dir := Dir, dir := Dir,
link := false}, AppType) -> link := false}, AppType) ->
rlx_app_info:new(Name, Vsn, Dir, Applications, IncludedApplications, AppType). rlx_app_info:new(Name, Vsn, Dir, Applications, IncludedApplications, OptionalApplications, AppType).
-spec opt_spec_list() -> [getopt:option_spec()]. -spec opt_spec_list() -> [getopt:option_spec()].
opt_spec_list() -> opt_spec_list() ->
@ -280,4 +294,5 @@ opt_spec_list() ->
{sys_config, undefined, "sys_config", string, "Path to a file to use for sys.config"}, {sys_config, undefined, "sys_config", string, "Path to a file to use for sys.config"},
{system_libs, undefined, "system_libs", string, "Boolean or path to dir of Erlang system libs"}, {system_libs, undefined, "system_libs", string, "Boolean or path to dir of Erlang system libs"},
{version, undefined, "version", undefined, "Print relx version"}, {version, undefined, "version", undefined, "Print relx version"},
{root_dir, $r, "root", string, "The project root directory"}]. {root_dir, $r, "root", string, "The project root directory"},
{relnames, $m, "relnames", string, "Like --all, but only build the releases in the list, e.g. --relnames rel1,rel2"}].

View File

@ -481,8 +481,9 @@ add_provider(State=#state_t{providers=Providers, allow_provider_overrides=false}
case lists:any(fun(P) -> case lists:any(fun(P) ->
case {providers:impl(P), providers:namespace(P)} of case {providers:impl(P), providers:namespace(P)} of
{Name, Namespace} -> {Name, Namespace} ->
?DEBUG("Not adding provider ~p ~p from module ~p because it already exists from module ~p", ?DEBUG("Not adding provider ~ts ~ts from module ~ts because it already exists from module ~ts",
[Namespace, Name, Module, providers:module(P)]), [atom_to_list(Namespace), atom_to_list(Name),
atom_to_list(Module), atom_to_list(providers:module(P))]),
true; true;
_ -> _ ->
false false

View File

@ -90,7 +90,7 @@ get_template_vars(TemplateTerms, State) ->
%% Provide a way to merge a set of variables with another one. The left-hand %% Provide a way to merge a set of variables with another one. The left-hand
%% set of variables takes precedence over the right-hand set. %% set of variables takes precedence over the right-hand set.
%% In the case where left-hand variable description contains overriden defaults, but %% In the case where left-hand variable description contains overridden defaults, but
%% the right-hand one contains additional data such as documentation, the resulting %% the right-hand one contains additional data such as documentation, the resulting
%% variable description will contain the widest set of information possible. %% variable description will contain the widest set of information possible.
override_vars([], General) -> General; override_vars([], General) -> General;

View File

@ -97,7 +97,7 @@ sort_deps(Deps) ->
%% We need a sort stable, based on the name. So that for multiple deps on %% We need a sort stable, based on the name. So that for multiple deps on
%% the same level with the same name, we keep the order the parents had. %% the same level with the same name, we keep the order the parents had.
%% `lists:keysort/2' is documented as stable in the stdlib. %% `lists:keysort/2' is documented as stable in the stdlib.
%% The list of deps is revered when we get it. For the proper stable %% The list of deps is reversed when we get it. For the proper stable
%% result, re-reverse it. %% result, re-reverse it.
lists:keysort(?APP_NAME_INDEX, lists:reverse(Deps)). lists:keysort(?APP_NAME_INDEX, lists:reverse(Deps)).
@ -129,7 +129,7 @@ is_arch(ArchRegex) ->
false false
end. end.
%% @doc returns the sytem architecture, in strings like %% @doc returns the system architecture, in strings like
%% `"19.0.4-x86_64-unknown-linux-gnu-64"'. %% `"19.0.4-x86_64-unknown-linux-gnu-64"'.
-spec get_arch() -> string(). -spec get_arch() -> string().
get_arch() -> get_arch() ->

View File

@ -36,7 +36,7 @@
%% Options used when reading a tar archive. %% Options used when reading a tar archive.
-record(read_opts, { -record(read_opts, {
cwd :: string(), %% Current working directory. cwd :: string(), %% Current working directory.
keep_old_files = false :: boolean(), %% Owerwrite or not. keep_old_files = false :: boolean(), %% Overwrite or not.
files = all, %% Set of files to extract (or all) files = all, %% Set of files to extract (or all)
output = file :: 'file' | 'memory', output = file :: 'file' | 'memory',
open_mode = [], %% Open mode options. open_mode = [], %% Open mode options.
@ -202,7 +202,7 @@
%% These constants (except S_IFMT) are %% These constants (except S_IFMT) are
%% used to determine what type of device %% used to determine what type of device
%% a file is. Namely, `S_IFMT band file_info.mode` %% a file is. Namely, `S_IFMT band file_info.mode`
%% will equal one of these contants, and tells us %% will equal one of these constants, and tells us
%% which type it is. The stdlib file_info record %% which type it is. The stdlib file_info record
%% does not differentiate between device types, and %% does not differentiate between device types, and
%% will not allow us to differentiate between sockets %% will not allow us to differentiate between sockets

View File

@ -1,4 +1,4 @@
{alias, [{help, [version]}, % should be skipped, but be overriden by plugin {alias, [{help, [version]}, % should be skipped, but be overridden by plugin
{test, [compile, {eunit, "-c"}, cover]}]}. {test, [compile, {eunit, "-c"}, cover]}]}.
{plugins, [rebar_alias]}. % should be overridden {plugins, [rebar_alias]}. % should be overridden

View File

@ -24,7 +24,7 @@ command(Config) ->
Name = rebar_test_utils:create_random_name("alias_command_"), Name = rebar_test_utils:create_random_name("alias_command_"),
Vsn = rebar_test_utils:create_random_vsn(), Vsn = rebar_test_utils:create_random_vsn(),
rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
RebarConfig = [{alias, [{test, [compile, unlock]}]}], RebarConfig = [{alias, [{test, [compile, {unlock,"-a"}]}]}],
%% compile job ran %% compile job ran
rebar_test_utils:run_and_check(Config, RebarConfig, rebar_test_utils:run_and_check(Config, RebarConfig,
@ -64,7 +64,7 @@ many(Config) ->
Vsn = rebar_test_utils:create_random_vsn(), Vsn = rebar_test_utils:create_random_vsn(),
rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
RebarConfig = [{alias, [{test, [{eunit,"-c"}, cover]}, RebarConfig = [{alias, [{test, [{eunit,"-c"}, cover]},
{nolock, [compile, unlock]}]}], {nolock, [compile, {unlock,"-a"}]}]}],
%% test job ran (compiled and succeeded) %% test job ran (compiled and succeeded)
rebar_test_utils:run_and_check(Config, RebarConfig, rebar_test_utils:run_and_check(Config, RebarConfig,

View File

@ -40,6 +40,7 @@ all() ->
include_file_relative_to_working_directory_test, include_file_in_src_test, include_file_relative_to_working_directory_test, include_file_in_src_test,
include_file_in_src_test_multiapp, include_file_in_src_test_multiapp,
recompile_when_parse_transform_as_opt_changes, recompile_when_parse_transform_as_opt_changes,
dont_recompile_when_parse_transform_as_opt_unchanged,
recompile_when_parse_transform_inline_changes, recompile_when_parse_transform_inline_changes,
regex_filter_skip, regex_filter_regression, regex_filter_skip, regex_filter_regression,
recursive, no_recursive, extra_recursion, recursive, no_recursive, extra_recursion,
@ -2720,6 +2721,48 @@ recompile_when_parse_transform_as_opt_changes(Config) ->
?assert(ModTime =/= NewModTime). ?assert(ModTime =/= NewModTime).
dont_recompile_when_parse_transform_as_opt_unchanged(Config) ->
AppDir = ?config(apps, Config),
Name = rebar_test_utils:create_random_name("parse_transform_opt_"),
Vsn = rebar_test_utils:create_random_vsn(),
rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
ok = filelib:ensure_dir(filename:join([AppDir, "src", "dummy"])),
ModSrc = <<"-module(example).\n"
"-export([foo/2]).\n"
"foo(_, _) -> ok.">>,
ok = file:write_file(filename:join([AppDir, "src", "example.erl"]),
ModSrc),
ParseTransform = <<"-module(example_parse_transform).\n"
"-export([parse_transform/2]).\n"
"parse_transform(AST, _) -> AST.">>,
ok = file:write_file(filename:join([AppDir, "src", "example_parse_transform.erl"]),
ParseTransform),
RebarConfig = [{erl_opts, [{parse_transform, example_parse_transform}]}],
rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name}]}),
EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
{ok, Files} = rebar_utils:list_dir(EbinDir),
ModTime = [filelib:last_modified(filename:join([EbinDir, F]))
|| F <- Files, filename:basename(F, ".beam") == "example"],
timer:sleep(1000),
rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name}]}),
{ok, NewFiles} = rebar_utils:list_dir(EbinDir),
NewModTime = [filelib:last_modified(filename:join([EbinDir, F]))
|| F <- NewFiles, filename:basename(F, ".beam") == "example"],
?assert(ModTime =:= NewModTime).
recursive(Config) -> recursive(Config) ->
AppDir = ?config(apps, Config), AppDir = ?config(apps, Config),

View File

@ -53,7 +53,7 @@ groups() ->
mv_file_dir_same, mv_file_dir_diff, mv_no_clobber]}]. mv_file_dir_same, mv_file_dir_diff, mv_no_clobber]}].
init_per_group(reset_dir, Config) -> init_per_group(reset_dir, Config) ->
TmpDir = rebar_file_utils:system_tmpdir(["rebar_file_utils_SUITE", "resetable"]), TmpDir = rebar_file_utils:system_tmpdir(["rebar_file_utils_SUITE", "resettable"]),
[{tmpdir, TmpDir} | Config]; [{tmpdir, TmpDir} | Config];
init_per_group(tmpdir, Config) -> init_per_group(tmpdir, Config) ->
PreviousTmpDir = os:getenv("TMPDIR"), PreviousTmpDir = os:getenv("TMPDIR"),

View File

@ -89,7 +89,7 @@ diff_alias(Config) ->
{ok, [{Vsn, LockData}|_]} = file:consult(Lockfile), {ok, [{Vsn, LockData}|_]} = file:consult(Lockfile),
%% So does an upgrade %% So does an upgrade
rebar_test_utils:run_and_check( rebar_test_utils:run_and_check(
Config, RebarConfig, ["upgrade"], Config, RebarConfig, ["upgrade", "--all"],
{ok, [{lock, "fakelib"},{dep, "fakelib"}]} {ok, [{lock, "fakelib"},{dep, "fakelib"}]}
), ),
{ok, [{Vsn, LockData}|_]} = file:consult(Lockfile). {ok, [{Vsn, LockData}|_]} = file:consult(Lockfile).
@ -128,7 +128,7 @@ transitive_alias(Config) ->
?assertNot(filelib:is_dir(PkgName)), ?assertNot(filelib:is_dir(PkgName)),
%% So does an upgrade %% So does an upgrade
rebar_test_utils:run_and_check( rebar_test_utils:run_and_check(
Config, RebarConfig, ["upgrade"], Config, RebarConfig, ["upgrade", "--all"],
{ok, [{lock, "topdep"},{dep, "topdep"}, {ok, [{lock, "topdep"},{dep, "topdep"},
{lock,"transitive_app"},{dep,"transitive_app"}]} {lock,"transitive_app"},{dep,"transitive_app"}]}
), ),

View File

@ -12,6 +12,7 @@
list/1, list/1,
upgrade/1, upgrade/1,
upgrade_project_plugin/1, upgrade_project_plugin/1,
upgrade_no_args/1,
sub_app_plugins/1, sub_app_plugins/1,
sub_app_plugin_overrides/1, sub_app_plugin_overrides/1,
project_plugins/1, project_plugins/1,
@ -191,7 +192,7 @@ upgrade(Config) ->
{{iolist_to_binary(PkgName), <<"0.1.1">>}, []}]} {{iolist_to_binary(PkgName), <<"0.1.1">>}, []}]}
]), ]),
%% beam file to verify plugin is acutally compiled %% beam file to verify plugin is actually compiled
PluginBeam = filename:join([AppDir, "_build", "default", "plugins", PluginBeam = filename:join([AppDir, "_build", "default", "plugins",
PkgName, "ebin", [PkgName, ".beam"]]), PkgName, "ebin", [PkgName, ".beam"]]),
@ -220,7 +221,7 @@ upgrade(Config) ->
), ),
rebar_test_utils:run_and_check( rebar_test_utils:run_and_check(
Config, RConf, ["plugins", "upgrade"], Config, RConf, ["plugins", "upgrade", "--all"],
{ok, [{app, Name, valid}, {file, PluginBeam}, {plugin, PkgName}]} {ok, [{app, Name, valid}, {file, PluginBeam}, {plugin, PkgName}]}
). ).
@ -263,6 +264,13 @@ upgrade_project_plugin(Config) ->
{ok, [{app, Name}, {plugin, PkgName, <<"0.1.3">>}]} {ok, [{app, Name}, {plugin, PkgName, <<"0.1.3">>}]}
). ).
upgrade_no_args(Config) ->
try rebar_test_utils:run_and_check(Config, [], ["plugins", "upgrade"], return)
catch {error, {rebar_prv_plugins_upgrade, no_arg}} ->
ok
end,
ok.
sub_app_plugins(Config) -> sub_app_plugins(Config) ->
AppDir = ?config(apps, Config), AppDir = ?config(apps, Config),

View File

@ -49,7 +49,7 @@ release(Config) ->
config_file(Config) -> config_file(Config) ->
AppDir = ?config(apps, Config), AppDir = ?config(apps, Config),
Name = list_to_atom(?config(name, Config)), Name = list_to_atom(?config(name, Config)),
%% Relase build fails if no relx config exists %% Release build fails if no relx config exists
?assertError({error, {relx, no_releases_in_system}}, ?assertError({error, {relx, no_releases_in_system}},
rebar_test_utils:run_and_check(Config, [], ["release"], result)), rebar_test_utils:run_and_check(Config, [], ["release"], result)),
%% Write relx.config %% Write relx.config

View File

@ -3,7 +3,7 @@
-include_lib("eunit/include/eunit.hrl"). -include_lib("eunit/include/eunit.hrl").
-compile(export_all). -compile(export_all).
all() -> [pkgunlock, unlock, unlock_all]. all() -> [pkgunlock, unlock, unlock_all, unlock_no_args].
init_per_testcase(pkgunlock, Config0) -> init_per_testcase(pkgunlock, Config0) ->
Config = rebar_test_utils:init_rebar_state(Config0, "pkgunlock"), Config = rebar_test_utils:init_rebar_state(Config0, "pkgunlock"),
@ -54,11 +54,18 @@ unlock(Config) ->
unlock_all(Config) -> unlock_all(Config) ->
[_|_] = read_locks(Config), [_|_] = read_locks(Config),
{ok, State} = rebar_test_utils:run_and_check(Config, [], ["unlock"], return), {ok, State} = rebar_test_utils:run_and_check(Config, [], ["unlock", "--all"], return),
?assertEqual({error, enoent}, read_locks(Config)), ?assertEqual({error, enoent}, read_locks(Config)),
?assertEqual([], rebar_state:get(State, {locks, default})), ?assertEqual([], rebar_state:get(State, {locks, default})),
ok. ok.
unlock_no_args(Config) ->
try rebar_test_utils:run_and_check(Config, [], ["unlock"], return)
catch {error, {rebar_prv_unlock, no_arg}} ->
ok
end,
ok.
read_locks(Config) -> read_locks(Config) ->
case file:consult(?config(lockfile, Config)) of case file:consult(?config(lockfile, Config)) of
{ok, _} -> {ok, _} ->

View File

@ -3,7 +3,7 @@
-include_lib("eunit/include/eunit.hrl"). -include_lib("eunit/include/eunit.hrl").
-compile(export_all). -compile(export_all).
all() -> [{group, git}, {group, pkg}, novsn_pkg]. all() -> [{group, git}, {group, pkg}, novsn_pkg, upgrade_no_args].
groups() -> groups() ->
[{all, [], [top_a, top_b, top_c, top_d1, top_d2, top_e, [{all, [], [top_a, top_b, top_c, top_d1, top_d2, top_e,
@ -53,6 +53,8 @@ init_per_testcase(novsn_pkg, Config0) ->
end}, end},
{expected, {ok, [{dep, "fakeapp", "1.1.0"}, {lock, "fakeapp", "1.1.0"}]}} {expected, {ok, [{dep, "fakeapp", "1.1.0"}, {lock, "fakeapp", "1.1.0"}]}}
| Config]; | Config];
init_per_testcase(upgrade_no_args, Config0) ->
rebar_test_utils:init_rebar_state(Config0, "upgrade_no_args_");
init_per_testcase(Case, Config) -> init_per_testcase(Case, Config) ->
DepsType = ?config(deps_type, Config), DepsType = ?config(deps_type, Config),
{Deps, UpDeps, ToUp, Expectations} = upgrades(Case), {Deps, UpDeps, ToUp, Expectations} = upgrades(Case),
@ -543,6 +545,9 @@ mock_deps(pkg, OldDeps, Deps, Upgrades) ->
{_, PkgDeps} = rebar_test_utils:flat_deps(Deps++OldDeps), {_, PkgDeps} = rebar_test_utils:flat_deps(Deps++OldDeps),
mock_pkg_resource:mock([{pkgdeps, PkgDeps}, {upgrade, Upgrades}]). mock_pkg_resource:mock([{pkgdeps, PkgDeps}, {upgrade, Upgrades}]).
normalize_unlocks({[], Locks}) ->
{"--all",
normalize_unlocks_expect(Locks)};
normalize_unlocks({App, Locks}) -> normalize_unlocks({App, Locks}) ->
{iolist_to_binary(App), {iolist_to_binary(App),
normalize_unlocks_expect(Locks)}; normalize_unlocks_expect(Locks)};
@ -646,7 +651,7 @@ compile_upgrade_parity(Config) ->
Lockfile = filename:join([AppDir, "rebar.lock"]), Lockfile = filename:join([AppDir, "rebar.lock"]),
rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, []}), rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, []}),
{ok, CompileLockData1} = file:read_file(Lockfile), {ok, CompileLockData1} = file:read_file(Lockfile),
rebar_test_utils:run_and_check(Config, RebarConfig, ["upgrade"], {ok, []}), rebar_test_utils:run_and_check(Config, RebarConfig, ["upgrade", "--all"], {ok, []}),
{ok, UpgradeLockData} = file:read_file(Lockfile), {ok, UpgradeLockData} = file:read_file(Lockfile),
rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, []}), rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, []}),
{ok, CompileLockData2} = file:read_file(Lockfile), {ok, CompileLockData2} = file:read_file(Lockfile),
@ -781,7 +786,7 @@ novsn_pkg(Config) ->
Expectation = ?config(expected, Config), Expectation = ?config(expected, Config),
apply(?config(mock_update, Config), []), apply(?config(mock_update, Config), []),
rebar_test_utils:run_and_check( rebar_test_utils:run_and_check(
Config, RebarConfig, ["upgrade"], Expectation Config, RebarConfig, ["upgrade", "--all"], Expectation
), ),
ok. ok.
@ -808,3 +813,10 @@ rewrite_locks({ok, Expectations}, Config) ->
end, [], Locks), end, [], Locks),
ct:pal("rewriting locks from ~p to~n~p", [Locks, NewLocks]), ct:pal("rewriting locks from ~p to~n~p", [Locks, NewLocks]),
file:write_file(LockFile, io_lib:format("~p.~n", [NewLocks])). file:write_file(LockFile, io_lib:format("~p.~n", [NewLocks])).
upgrade_no_args(Config) ->
try rebar_test_utils:run_and_check(Config, [], ["upgrade"], return)
catch {error, {rebar_prv_upgrade, no_arg}} ->
ok
end,
ok.