Packages
rebar3_hex
0.3.0
7.1.0
7.0.11
7.0.10
7.0.9
7.0.8
7.0.7
7.0.6
7.0.5
7.0.4
7.0.3
7.0.2
7.0.1
7.0.0
6.11.9
6.11.8
6.11.7
6.11.6
6.11.5
6.11.4
6.11.3
6.11.2
6.11.1
6.11.0
6.10.3
6.10.2
6.10.1
6.10.0
6.9.6
6.9.5
6.9.4
6.9.3
6.9.2
6.9.1
6.9.0
6.8.0
6.7.0
6.6.0
6.5.0
6.4.0
6.3.0
6.2.0
6.1.0
6.0.0
4.1.0
4.0.0
3.1.0
3.0.0
2.5.1
2.5.0
2.4.0
2.3.0
2.2.0
2.1.0
2.0.0
1.20.0
1.19.0
1.18.0
1.17.0
1.16.0
1.15.0
1.14.0
1.13.0
1.12.0
1.11.0
1.10.0
1.9.1
1.9.0
1.8.1
1.8.0
1.7.2
1.7.1
1.7.0
1.6.3
1.6.1
1.6.0
1.5.0
1.4.0
1.3.0
1.2.0
1.1.0
0.9.0
0.8.0
0.7.0
0.6.0
0.5.1
0.5.0
0.4.0
0.3.0
0.2.0
0.1.0
Hex.pm plugin for rebar3
Current section
Files
Jump to
Current section
Files
src/rebar3_hex_pkg.erl
-module(rebar3_hex_pkg).
-behaviour(provider).
-export([init/1,
do/1,
format_error/1]).
-export([publish/6]).
-include("rebar3_hex.hrl").
-include_lib("providers/include/providers.hrl").
-define(PROVIDER, publish).
-define(DEPS, [{default, app_discovery}]).
-define(ENDPOINT, "packages").
%% ===================================================================
%% Public API
%% ===================================================================
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) ->
Provider = providers:create([
{name, ?PROVIDER},
{module, ?MODULE},
{namespace, hex},
{bare, false},
{deps, ?DEPS},
{example, "rebar3 hex publish"},
{short_desc, "."},
{desc, ""},
{opts, [{revert, undefined, "revert", string, "Revert given version."}]}
]),
State1 = rebar_state:add_provider(State, Provider),
{ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
[App] = rebar_state:project_apps(State),
AppDir = rebar_app_info:dir(App),
Name = rebar_app_info:name(App),
{Args, _} = rebar_state:command_parsed_args(State),
Revert = proplists:get_value(revert, Args, undefined),
case Revert of
undefined ->
Version = rebar_app_info:original_vsn(App),
Deps = rebar_state:get(State, {locks, default}, []),
TopLevel = [{N, V} || {_,{pkg,N,V},0} <- Deps],
Excluded = [binary_to_list(N) || {N,{T,_,_},0} <- Deps, T =/= pkg],
AppDetails = rebar_app_info:app_details(App),
case publish(AppDir, Name, Version, TopLevel, Excluded, AppDetails) of
ok ->
{ok, State};
Error ->
Error
end;
Version ->
case delete(Name, Version) of
ok ->
{ok, State};
Error ->
Error
end
end.
-spec format_error(any()) -> iolist().
format_error(undefined_server_error) ->
"Unknown server error";
format_error(Error) ->
Message = proplists:get_value(<<"message">>, Error, ""),
Errors = proplists:get_value(<<"errors">>, Error, ""),
ErrorString = errors_to_string(Errors),
io_lib:format("Hex Error: ~s~n\t~s", [Message, ErrorString]).
%% ===================================================================
%% Public API
%% ===================================================================
publish(AppDir, Name, Version, Deps, Excluded, AppDetails) ->
Description = list_to_binary(proplists:get_value(description, AppDetails, "")),
FilePaths = proplists:get_value(files, AppDetails, ?DEFAULT_FILES),
Files = rebar3_hex_utils:expand_paths(FilePaths, AppDir),
Contributors = proplists:get_value(contributors, AppDetails, []),
Licenses = proplists:get_value(licenses, AppDetails, []),
Links = proplists:get_value(links, AppDetails, []),
Optional = [{app, Name}
,{requirements, Deps}
,{contributors, Contributors}
,{precompiled, false}
,{parameters, []}
,{description, Description}
,{files, Files}
,{licenses, Licenses}
,{links, Links}
,{build_tools, [<<"rebar">>]}],
OptionalFiltered = [{Key, Value} || {Key, Value} <- Optional, Value =/= []],
Meta = [{name, Name}, {version, Version} | OptionalFiltered],
MetaString = [{<<"meta">>, rebar3_hex_utils:binarify(Meta)}],
{ok, Auth} = rebar3_hex_config:auth(),
case create_package(Auth, Name, MetaString) of
ok ->
ec_talk:say("Publishing ~s ~s", [Name, Version]),
ec_talk:say(" Dependencies:~n ~s", [format_deps(Deps)]),
ec_talk:say(" Excluded dependencies (not part of the Hex package):~n ~s", [string:join(Excluded, "\n ")]),
ec_talk:say(" Included files:~n ~s", [string:join(Files, "\n ")]),
case ec_talk:ask_default("Proceed?", boolean, "Y") of
true ->
upload_package(Auth, Name, Version, Meta, Files);
_ ->
ec_talk:say("Goodbye..."),
ok
end;
{error, Error} ->
?PRV_ERROR(Error)
end.
%% Internal functions
delete(Name, Version) ->
{ok, Auth} = rebar3_hex_config:auth(),
case rebar3_hex_http:delete(filename:join([?ENDPOINT, Name, "releases", Version]), Auth) of
ok ->
rebar_api:info("Successfully deleted package ~s ~s", [Name, Version]),
ok;
{error, _} ->
rebar_api:error("Unable to delete package ~s ~s", [Name, Version])
end.
create_package(Auth, Name, MetaString) ->
rebar3_hex_http:put(filename:join([?ENDPOINT, Name]), Auth, MetaString).
upload_package(Auth, Name, Version, Meta, Files) ->
{ok, Tar} = rebar3_hex_tar:create(Name, Version, Meta, Files),
case rebar3_hex_http:post(filename:join([?ENDPOINT, Name, "releases"])
,Auth
,Tar
,integer_to_list(byte_size(Tar))) of
ok ->
rebar_api:info("Published ~s ~s", [Name, Version]),
ok;
{error, _, Error} ->
?PRV_ERROR(Error)
end.
errors_to_string(Value) when is_binary(Value) ->
Value;
errors_to_string({Key, Value}) ->
io_lib:format("~s: ~s", [Key, errors_to_string(Value)]);
errors_to_string(Errors) when is_list(Errors) ->
lists:flatten([io_lib:format("~s", [errors_to_string(Values)]) || Values <- Errors]).
format_deps(Deps) ->
string:join([binary_to_list(<<N/binary, " ", V/binary>>) || {N, V} <- Deps], "\n ").