Skip to content

Commit

Permalink
Merge pull request #1 from alertlogic/rebar_3.7_compat
Browse files Browse the repository at this point in the history
Add rebar 3.7.x compatibility
  • Loading branch information
nalundgaard authored Dec 19, 2018
2 parents e3ae32e + e7576aa commit d2add8e
Showing 1 changed file with 153 additions and 17 deletions.
170 changes: 153 additions & 17 deletions src/rebar_raw_resource.erl
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,16 @@
% provider
do/1,
format_error/1,
init/2,
% rebar_resource_v2 callbacks
download/4,
lock/2,
make_vsn/2,
needs_update/2,
% pre-rebar3 3.7.0 rebar_resource callbacks
init/1,
% rebar_resource
download/3,
lock/2,
make_vsn/1,
needs_update/2
make_vsn/1
]).

% For development only - you *really* don't want this defined!
Expand Down Expand Up @@ -134,7 +138,7 @@
-type rebar_dep() :: {rsrc_name()} | {rsrc_name(), rsrc_spec() | rsrc_vsn()}.
-type rebar_dir() :: file:filename_all().
-type rebar_err() :: {'error', term()}.
-type rebar_rsrc() :: {rsrc_type(), rsrc_mod()}.
-type rebar_rsrc() :: {rsrc_type(), rsrc_mod()} | rebar_resource_v2:resource().
-type rebar_vsn() :: {'plain', rsrc_vsn()}.

-type rsrc_dir() :: rebar_dir().
Expand Down Expand Up @@ -194,10 +198,28 @@
% download/3 is NOT called first if the dependency is already present, and
% it's the only resource call that gets to see the rebar state.
%
% Note: This arity is the pre-rebar3 3.7.0 format of this function.
%
init(State) ->
#mod_data{} = absorb_state(State),
{'ok', rebar_state:add_resource(State, {?RTYPE, ?MODULE})}.

-spec init(Type :: rsrc_type(),
State :: rebar_state()) -> {'ok', rebar_state()}.
%
% Installs the resource handler, the provider itself does nothing.
%
% This gets called repeatedly, for each profile, and in each case we want
% to prime the process environment with any info we may need later, as
% download/4 is NOT called first if the dependency is already present, and
% it's the only resource call that gets to see the rebar state.
%
% Note: This arity is the rebar_resource_v2 format of this function.
%
init(Type, State) ->
#mod_data{} = absorb_state(State),
{'ok', rebar_resource_v2:new(Type, ?MODULE, State)}.

-spec do(State :: rebar_state:t()) -> {'ok', rebar_state()}.
%
% Fulfills the `provider' contract, does nothing ... for now.
Expand Down Expand Up @@ -225,14 +247,18 @@ format_error(Error) ->
%% Resource API
%% ===================================================================

-spec download(
Dest :: rsrc_dir(), From :: this_spec(), State :: rebar_state())
-> {'ok', term()} | rebar_err().
-spec download(Dest :: rsrc_dir(),
From :: this_spec(),
State :: rebar_state())
-> {'ok', term()} | rebar_err().
%
% Download the specified resource using its underlying handler.
%
download(Dest, {?RTYPE, Loc,
#mod_ref{res = Res, ref = Ref, opt = Opts}}, State) ->
% Note: This arity is the pre-rebar3 3.7.0 format of this function.
%
download(Dest,
{?RTYPE, Loc, #mod_ref{res = Res, ref = Ref, opt = Opts}},
State) ->
download(Dest, {?RTYPE, {Res, Loc, Ref}, Opts}, State);

download(Dest, {?RTYPE, Spec}, State) ->
Expand All @@ -254,13 +280,60 @@ download(Dest, {?RTYPE, Spec, Opts}, State) ->
Err
end.

-spec lock(Path :: rsrc_dir(), Spec :: this_spec())
-> rebar_lock() | no_return().
-spec download(Dest :: rsrc_dir(),
AppInfo :: rebar_app_info:t(),
ResourceState :: term(),
State :: rebar_state())
-> {'ok', term()} | rebar_err().
%
% Download the specified resource using its underlying handler.
%
% Note: This arity is the rebar_resource_v2 format of this function.
%
download(Dest, AppInfo0, ResourceState, RebarState) ->
Name = term_to_atom(rebar_app_info:name(AppInfo0)),
{Spec, Opts} = case rebar_app_info:source(AppInfo0) of
{?RTYPE, Loc0, #mod_ref{res = Res0, ref = Ref, opt = Opts0}} ->
{{Res0, Loc0, Ref}, Opts0};
{?RTYPE, S, O} ->
{S, O};
{?RTYPE, S} ->
{S, []}
end,
{Res, _Loc} = parse_ext_spec(Spec),
#mod_res{mod = Mod} = lookup_res(mod_data(), Res),
AppInfo = rebar_app_info:source(AppInfo0, Spec),
case Mod:download(Dest, AppInfo, ResourceState, RebarState) of
ok ->
case lists:keytake(vsn, 1, Opts) of
false ->
% because download has not put the downloaded app into
% its final location, configure the app dir to be the
% Dest provided.
TmpAppInfo = rebar_app_info:dir(AppInfo, Dest),
{plain, Vsn} = Mod:make_vsn(TmpAppInfo, []),
ensure_app(Dest, Mod, Name, [{vsn, Vsn} |Opts], ok);
{value, _, _} ->
ensure_app(Dest, Mod, Name, Opts, ok)
end;
Err -> Err
end.

-spec lock(Path :: rsrc_dir(),
Spec :: this_spec())
-> rebar_lock() | no_return();
(AppInfo :: rebar_app_info:t(),
ResourceState :: term())
-> rebar_lock() | no_return().
%
% Pass through to the underlying resource handler.
% Note that the callback doesn't allow an error tuple to be returned, so an
% exception is our only option if we can't look up the mapping.
%
% Note: this function is common to the pre-rebar3 3.7.0 and rebar_resource_v2
% formats, and as such has heads for each.
%
%% pre-rebar3 3.7.0 format
lock(Path, {?RTYPE, Loc, #mod_ref{res = Res, ref = Prev} = Rec}) ->
#mod_res{mod = Mod} = lookup_res(mod_data(), Res),
{Res, Loc, Ref} = Mod:lock(Path, {Res, Loc, Prev}),
Expand All @@ -273,15 +346,35 @@ lock(Path, {?RTYPE, Spec, Opts}) ->
{Res, _} = parse_ext_spec(Spec),
#mod_res{mod = Mod} = lookup_res(mod_data(), Res),
{Res, Loc, Ref} = Mod:lock(Path, Spec),
{?RTYPE, Loc, #mod_ref{res = Res, ref = Ref, opt = Opts}};
%% rebar_resource_v2 format
lock(AppInfo, _ResourceState) ->
{Spec, Opts} = case rebar_app_info:source(AppInfo) of
{?RTYPE, Loc0, #mod_ref{res = Res0, ref = Ref0, opt = Opts0}} ->
{{Res0, Loc0, Ref0}, Opts0};
{?RTYPE, S, O} -> {S, O};
{?RTYPE, S} -> {S, []}
end,
{Res, _Loc} = parse_ext_spec(Spec),
#mod_res{mod = Mod} = lookup_res(mod_data(), Res),
{Res, Loc, Ref} = Mod:lock(rebar_app_info:source(AppInfo, Spec), []),
{?RTYPE, Loc, #mod_ref{res = Res, ref = Ref, opt = Opts}}.

-spec needs_update(Path :: rsrc_dir(), Spec :: this_spec())
-> boolean() | no_return().
-spec needs_update(Path :: rsrc_dir(),
SpecOrResourceState :: this_spec())
-> boolean() | no_return();
(AppInfo :: rebar_app_info:t(),
State :: rebar_state())
-> boolean() | no_return().
%
% Pass through to the underlying resource handler.
% Note that the callback doesn't allow an error tuple to be returned, so an
% exception is our only option if we can't look up the mapping.
%
% Note: this function is common to the pre-rebar3 3.7.0 and rebar_resource_v2
% formats, and as such has heads for each.
%
%% pre-rebar3 3.7.0 format
needs_update(Path, {?RTYPE, Loc, #mod_ref{res = Res, ref = Ref}}) ->
#mod_res{mod = Mod} = lookup_res(mod_data(), Res),
Mod:needs_update(Path, {Res, Loc, Ref});
Expand All @@ -292,20 +385,55 @@ needs_update(Path, {?RTYPE, Spec, _}) ->
needs_update(Path, {?RTYPE, Spec}) ->
{Res, _} = parse_ext_spec(Spec),
#mod_res{mod = Mod} = lookup_res(mod_data(), Res),
Mod:needs_update(Path, Spec).
Mod:needs_update(Path, Spec);
%% rebar_resource_v2 format
needs_update(AppInfo, State) ->
{Mod, SourceSpec} = case rebar_app_info:source(AppInfo) of
{?RTYPE, Loc, #mod_ref{res = Res, ref = Ref}} ->
#mod_res{mod = M} = lookup_res(mod_data(), Res),
{M, {Res, Loc, Ref}};
{?RTYPE, Spec, _} ->
{Res, _} = parse_ext_spec(Spec),
#mod_res{mod = M} = lookup_res(mod_data(), Res),
{M, Spec};
{?RTYPE, Spec} ->
{Res, _} = parse_ext_spec(Spec),
#mod_res{mod = M} = lookup_res(mod_data(), Res),
{M, Spec}
end,
Mod:needs_update(rebar_app_info:source(AppInfo, SourceSpec), State).

-spec make_vsn(Path :: rsrc_dir())
-> rebar_vsn() | {'error', string()} | no_return().
%
% Pass through to the underlying resource handler.
% The weird error tuple spec comes from the rebar_resource behavior.
% Note: This arity is the pre-rebar3 3.7.0 format of this function.
%
make_vsn(Path) ->
Data = mod_data(),
#mod_dep{res = Res} = lookup_dep(Data, path_name(Path)),
#mod_res{mod = Mod} = lookup_res(Data, Res),
Mod:make_vsn(Path).

-spec make_vsn(Path :: rsrc_dir(),
State :: rebar_state())
-> rebar_vsn() | {'error', string()} | no_return().
%
% Pass through to the underlying resource handler.
% The weird error tuple spec comes from the rebar_resource behavior.
% Note: This arity is the rebar_resource_v2 format of this function.
%
make_vsn(AppInfo0, _ResourceState) ->
Spec = case rebar_app_info:source(AppInfo0) of
{?RTYPE, Loc0, #mod_ref{res = Res0, ref = Ref}} -> {Res0, Loc0, Ref};
{?RTYPE, S, _} -> S;
{?RTYPE, S} -> S
end,
{Res, _Loc} = parse_ext_spec(Spec),
#mod_res{mod = Mod} = lookup_res(mod_data(), Res),
Mod:make_vsn(rebar_app_info:source(AppInfo0, Spec), []).

%% ===================================================================
%% Internal
%% ===================================================================
Expand Down Expand Up @@ -390,6 +518,14 @@ absorb_profiles(Data, [], _) ->
%
% Allow for whatever may come through to handle future extensions.
%
% rebar_resource_v2 format
absorb_resources(Data, [Res | Resources]) when ?is_rec_type(Res, resource, 3) ->
absorb_resources(
map_res(Data, #mod_res{
res = term_to_atom(erlang:element(2, Res)),
mod = erlang:element(3, Res)}),
Resources);
% pre-rebar3 3.7.0 format
absorb_resources(Data, [Res | Resources]) when ?is_min_tuple(Res, 2) ->
absorb_resources(
map_res(Data, #mod_res{
Expand Down Expand Up @@ -472,9 +608,9 @@ ensure_app(Path, Mod, Name, Opts, Result) ->
" {applications, [kernel, stdlib]}\n"
"]}.\n",
[?MODULE, Name, Desc, Vsn]),
case filelib:ensure_dir(BApp) of
case filelib:ensure_dir(SApp) of
'ok' ->
case file:write_file(BApp, Data) of
case file:write_file(SApp, Data) of
'ok' ->
Result;
Err ->
Expand Down

0 comments on commit d2add8e

Please sign in to comment.