Packages

Standalone command-line interface for hex.pm

Current section

Files

Jump to
hexer src hexer_package.erl
Raw

src/hexer_package.erl

%%% @doc Package publishing utilities
-module(hexer_package).
-export([publish/0]).
%%------------------------------------------------------------------------------
%% API
%%------------------------------------------------------------------------------
%% @doc Publishes the app package.
-spec publish() -> ok | {error, any()}.
publish() ->
hexer_utils:print("Publishing..."),
%% We need the following information to build the package:
%% - App Directory
%% - Name
%% - Version
%% - AppDetails from *.app.src
%% - Deps
%% We assume the app's dir is the current directory.
AppDir = ".",
#{ name := Name
, version := Version
, details := Details
} = hexer_utils:load_app_info(),
Deps = hexer_deps:resolve(AppDir),
ok = validate_app_details(Details),
publish(AppDir, Name, Version, Deps, Details).
%%------------------------------------------------------------------------------
%% Internal Functions
%%------------------------------------------------------------------------------
-spec validate_app_details(map()) -> ok | {error, any()}.
validate_app_details(Details) ->
case maps:is_key(contributors, Details) of
true ->
throw({hexer_package, has_contributors});
false ->
ok
end.
-spec publish( string()
, atom()
, string()
, [hexer_deps:dep()]
, hexer_utils:details()
) -> ok | {error, any()}.
publish(AppDir, Name, Version, Deps, Details) ->
Description = list_to_binary(maps:get(description, Details, "")),
FilePaths = maps:get(files, Details, default_files()),
Files = hexer_utils:find_all(FilePaths, AppDir),
Filenames = [list_to_binary(F) || {F, _} <- Files],
Maintainers = maps:get(maintainers, Details, []),
Licenses = maps:get(licenses, Details, []),
Links = maps:get(links, Details, []),
PackageName = maps:get(pkg_name, Details, Name),
BuildTools = maps:get(build_tools, Details, []),
Optional = #{ app => Name
, requirements => Deps
, maintainers => Maintainers
, precompiled => false
, parameters => []
, description => Description
, files => Filenames
, licenses => Licenses
, links => Links
, build_tools => BuildTools
},
EmptyValue = fun(_, "") -> false; (_, _) -> true end,
OptionalFiltered = maps:filter(EmptyValue, Optional),
Mandatory = #{name => PackageName, version => Version},
Meta = maps:merge(Mandatory, OptionalFiltered),
{ok, APIKey} = hexer_config:api_key(),
hexer_utils:print("Publishing ~s ~s", [PackageName, Version]),
hexer_utils:print(" Dependencies:~n ~s", [hexer_utils:format_deps(Deps)]),
hexer_utils:print(" Included files:", []),
lists:foreach(
fun(Filename) ->
hexer_utils:print(" ~s", [Filename])
end, Filenames),
hexer_utils:print( "Before publishing, please read Hex CoC: "
"https://hex.pm/docs/codeofconduct"
, []
),
case hexer_utils:prompt("Proceed?", boolean) of
true ->
upload_package(APIKey, Name, Version, Meta, Files);
_ ->
hexer_utils:print("Goodbye...")
end.
-spec upload_package(
string(), atom(), string(), map(), [{string(), string()}]) ->
ok | {error, any()}.
upload_package(APIKey, Name, Version, Meta, Files) ->
{ok, Tar} = hexer_utils:create_tar(Name, Version, Meta, Files),
case hexer_server:publish_package(APIKey, atom_to_list(Name), Tar) of
ok -> hexer_utils:print("Published ~s ~s", [Name, Version]);
{error, Error} -> throw(Error)
end.
-spec default_files() -> [string()].
default_files() ->
[ "src", "c_src", "include", "priv"
, "rebar.config.script", "rebar.config", "rebar.lock"
, "Makefile", "Emakefile", "erlang.mk"
, "README*", "readme*"
, "LICENSE*", "license*"
].