%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
|
|
%% ex: ts=4 sw=4 et
|
|
-module(rebar_resource_v2).
|
|
|
|
-export([new/3,
|
|
find_resource_state/2,
|
|
format_source/1,
|
|
lock/2,
|
|
download/3,
|
|
needs_update/2,
|
|
make_vsn/3,
|
|
format_error/1]).
|
|
|
|
-export_type([resource/0,
|
|
source/0,
|
|
type/0,
|
|
location/0,
|
|
ref/0,
|
|
resource_state/0]).
|
|
|
|
-include("rebar.hrl").
|
|
-include_lib("providers/include/providers.hrl").
|
|
|
|
-type resource() :: #resource{}.
|
|
-type source() :: {type(), location(), ref()} | {type(), location(), ref(), binary()}.
|
|
-type type() :: atom().
|
|
-type location() :: string().
|
|
-type ref() :: any().
|
|
-type resource_state() :: term().
|
|
|
|
-callback init(type(), rebar_state:t()) -> {ok, resource()}.
|
|
-callback lock(rebar_app_info:t(), resource_state()) -> source().
|
|
-callback download(file:filename_all(), rebar_app_info:t(), resource_state(), rebar_state:t()) ->
|
|
ok | {error, any()}.
|
|
-callback needs_update(rebar_app_info:t(), resource_state()) -> boolean().
|
|
-callback make_vsn(rebar_app_info:t(), resource_state()) ->
|
|
{plain, string()} | {error, string()}.
|
|
|
|
-spec new(type(), module(), term()) -> resource().
|
|
new(Type, Module, State) ->
|
|
#resource{type=Type,
|
|
module=Module,
|
|
state=State,
|
|
implementation=?MODULE}.
|
|
|
|
-spec find_resource(type(), [resource()]) -> {ok, resource()} | {error, not_found}.
|
|
find_resource(Type, Resources) ->
|
|
case ec_lists:find(fun(#resource{type=T}) -> T =:= Type end, Resources) of
|
|
error when is_atom(Type) ->
|
|
case code:which(Type) of
|
|
non_existing ->
|
|
{error, not_found};
|
|
_ ->
|
|
{ok, rebar_resource:new(Type, Type, #{})}
|
|
end;
|
|
error ->
|
|
{error, not_found};
|
|
{ok, Resource} ->
|
|
{ok, Resource}
|
|
end.
|
|
|
|
find_resource_state(Type, Resources) ->
|
|
case lists:keyfind(Type, #resource.type, Resources) of
|
|
false ->
|
|
{error, not_found};
|
|
#resource{state=State} ->
|
|
State
|
|
end.
|
|
|
|
format_source({pkg, Name, Vsn, _Hash, _}) -> {pkg, Name, Vsn};
|
|
format_source(Source) -> Source.
|
|
|
|
lock(AppInfo, State) ->
|
|
resource_run(lock, rebar_app_info:source(AppInfo), [AppInfo], State).
|
|
|
|
resource_run(Function, Source, Args, State) ->
|
|
Resources = rebar_state:resources(State),
|
|
case get_resource_type(Source, Resources) of
|
|
{ok, #resource{type=_,
|
|
module=Module,
|
|
state=ResourceState,
|
|
implementation=?MODULE}} ->
|
|
erlang:apply(Module, Function, Args++[ResourceState]);
|
|
{ok, #resource{type=_,
|
|
module=Module,
|
|
state=_,
|
|
implementation=rebar_resource}} ->
|
|
erlang:apply(rebar_resource, Function, [Module | Args])
|
|
end.
|
|
|
|
download(TmpDir, AppInfo, State) ->
|
|
resource_run(download, rebar_app_info:source(AppInfo), [TmpDir, AppInfo, State], State).
|
|
|
|
needs_update(AppInfo, State) ->
|
|
resource_run(needs_update, rebar_app_info:source(AppInfo), [AppInfo], State).
|
|
|
|
%% this is a special case since it is used for project apps as well, not just deps
|
|
make_vsn(AppInfo, VcsType, State) ->
|
|
Resources = rebar_state:resources(State),
|
|
case is_resource_type(VcsType, Resources) of
|
|
true ->
|
|
case find_resource(VcsType, Resources) of
|
|
{ok, #resource{type=_,
|
|
module=Module,
|
|
state=ResourceState,
|
|
implementation=?MODULE}} ->
|
|
Module:make_vsn(AppInfo, ResourceState);
|
|
{ok, #resource{type=_,
|
|
module=Module,
|
|
state=_,
|
|
implementation=rebar_resource}} ->
|
|
rebar_resource:make_vsn(Module, AppInfo)
|
|
end;
|
|
false ->
|
|
unknown
|
|
end.
|
|
|
|
format_error({no_resource, Location, Type}) ->
|
|
io_lib:format("Cannot handle dependency ~ts.~n"
|
|
" No module found for resource type ~p.", [Location, Type]);
|
|
format_error({no_resource, Source}) ->
|
|
io_lib:format("Cannot handle dependency ~ts.~n"
|
|
" No module found for unknown resource type.", [Source]).
|
|
|
|
is_resource_type(Type, Resources) ->
|
|
lists:any(fun(#resource{type=T}) -> T =:= Type end, Resources).
|
|
|
|
-spec get_resource_type(term(), [resource()]) -> {ok, resource()}.
|
|
get_resource_type({Type, Location}, Resources) ->
|
|
get_resource(Type, Location, Resources);
|
|
get_resource_type({Type, Location, _}, Resources) ->
|
|
get_resource(Type, Location, Resources);
|
|
get_resource_type({Type, _, _, Location}, Resources) ->
|
|
get_resource(Type, Location, Resources);
|
|
get_resource_type(Location={Type, _, _, _, _}, Resources) ->
|
|
get_resource(Type, Location, Resources);
|
|
get_resource_type(Source, _) ->
|
|
throw(?PRV_ERROR({no_resource, Source})).
|
|
|
|
-spec get_resource(type(), term(), [resource()]) -> {ok, resource()}.
|
|
get_resource(Type, Location, Resources) ->
|
|
case find_resource(Type, Resources) of
|
|
{error, not_found} ->
|
|
throw(?PRV_ERROR({no_resource, Location, Type}));
|
|
{ok, Resource} ->
|
|
{ok, Resource}
|
|
end.
|