Skip to content

Commit

Permalink
Implement resource v2 callback compatibiity
Browse files Browse the repository at this point in the history
Implement rebar_resource_v2 compatible callbacks in order to make the plugin compatible with all known versions of rebar3, following the guide at https://www.rebar3.org/v3/docs/custom-dep-resources#section-resources-compatible-with-all-versions
  • Loading branch information
nalundgaard committed Nov 26, 2018
1 parent 1468599 commit 577cae6
Showing 1 changed file with 75 additions and 17 deletions.
92 changes: 75 additions & 17 deletions src/rebar_raw_resource.erl
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@
% provider
do/1,
format_error/1,
init/1,
init/1, init/2,
% rebar_resource
download/3,
download/3, download/4,
lock/2,
make_vsn/1,
make_vsn/1, make_vsn/2,
needs_update/2
]).

Expand Down Expand Up @@ -194,10 +194,26 @@
% 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/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.
%
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,11 +241,13 @@ 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.
% 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) ->
Expand All @@ -254,42 +272,72 @@ 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.
%
download(TmpDir, AppInfo, _ResourceState, RebarState) ->
download(TmpDir, rebar_app_info:source(AppInfo), RebarState).

-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.
%
lock(Path, {?RTYPE, Loc, #mod_ref{res = Res, ref = Prev} = Rec}) ->
%% pre-rebar3 3.7.0 format
lock(Path, Source) when not(erlang:is_tuple(Path)) ->
lock_(Path, Source);
%% rebar_resource_v2 format
lock(AppInfo, _ResourceState) ->
%% extract info for dir extract info for source
lock_(rebar_app_info:dir(AppInfo), rebar_app_info:source(AppInfo)).

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}),
{?RTYPE, Loc, Rec#mod_ref{ref = Ref}};

lock(Path, {?RTYPE, Spec}) ->
lock(Path, {?RTYPE, Spec, []});
lock_(Path, {?RTYPE, Spec}) ->
lock_(Path, {?RTYPE, Spec, []});

lock(Path, {?RTYPE, Spec, Opts}) ->
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}}.

-spec needs_update(Path :: rsrc_dir(), Spec :: this_spec())
-spec needs_update(Path :: rsrc_dir(), SpecOrResourceState :: this_spec())
-> 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.
%
needs_update(Path, {?RTYPE, Loc, #mod_ref{res = Res, ref = Ref}}) ->
%% pre-rebar3 3.7.0 format
needs_update(Dir, {_Type, _Path, _Ref} = Spec) ->
needs_update_(Dir, Spec);
%% rebar_resource_v2 compatible format
needs_update(AppInfo, _ResourceState) ->
needs_update_(rebar_app_info:dir(AppInfo), rebar_app_info:source(AppInfo)).

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});

needs_update(Path, {?RTYPE, Spec, _}) ->
needs_update(Path, {?RTYPE, Spec});
needs_update_(Path, {?RTYPE, Spec, _}) ->
needs_update_(Path, {?RTYPE, Spec});

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).
Expand All @@ -306,6 +354,16 @@ make_vsn(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.
%
make_vsn(Dir, _ResourceState) ->
make_vsn(Dir).

%% ===================================================================
%% Internal
%% ===================================================================
Expand Down

0 comments on commit 577cae6

Please sign in to comment.