Skip to content
Reference implementation of Hex specifications
Erlang Shell
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.github/workflows Fix compatibility with OTP 18 and 17 (#84) Feb 3, 2020
doc
examples Fix example Aug 19, 2018
proto Add outer checksum (#65) Jul 27, 2019
src Release v0.6.8 Feb 4, 2020
test Safe symlinks in erl_tar Feb 3, 2020
.gitignore
CHANGELOG.md
LICENSE Change copyright to Six Colors AB (company behind hex.pm) Aug 8, 2018
README.md Release v0.6.8 Feb 4, 2020
RELEASE.md
rebar.config Improve documentation for API modules (#73) Nov 11, 2019
rebar.lock Add proper and port gzip property test from Hex Mar 3, 2018
vendor.sh

README.md

hex_core

Build Status

Reference implementation of Hex specifications: https://github.com/hexpm/specifications.

Usage

Let's use default config for now. See "Configuration" section below for customization.

Config = hex_core:default_config().

Repository

Get all package names:

> hex_repo:get_names(Config).
{ok, {200, ...,
    #{packages => [
        #{name => <<"package1">>},
        #{name => <<"package2">>},
        ...
    ]}}}

Get all package versions from repository:

> hex_repo:get_versions(Config).
{ok, {200, ...,
    [
        #{name => <<"package1">>, retired => [], versions => [<<"1.0.0">>]},
        #{name => <<"package2">>, retired => [], versions => [<<"0.5.0">>]},
    ]}}

Get package releases from repository:

> hex_repo:get_package(Config, <<"package1">>).
{ok, {200, ...,
    [
        #{checksum => ..., version => <<"0.5.0">>, dependencies => []}],
        #{checksum => ..., version => <<"1.0.0">>, dependencies => []}],
    ]}}

API

For a full list of all parameters and returned objects for the API, check out the API docs: https://github.com/hexpm/specifications/blob/master/http_api.md.

Get package from HTTP API:

> hex_api_package:get(Config, <<"package1">>).
{ok, {200, ...,
    #{
        <<"name">> => <<"package1">>,
        <<"meta">> => #{
           <<"description">> => ...,
           <<"licenses">> => ...,
           <<"links">> => ...,
           <<"maintainers">> => ...,
        },
        ...,
        <<"releases">> => [
            #{<<"url">> => ..., <<"version">> => <<"0.5.0">>}],
            #{<<"url">> => ..., <<"version">> => <<"1.0.0">>}],
            ...
        ]
    }}}

Get package tarball:

{ok, {200, _, Tarball}} = hex_repo:get_tarball(Config, <<"package1">>, <<"1.0.0">>).

Publish package tarball:

{ok, {200, _Headers, _Body} = hex_api_package:publish(Config, Tarball).

Package tarballs

Unpack package tarball:

{ok, #{outer_checksum := Checksum, contents := Contents, metadata := Metadata}} = hex_tarball:unpack(Tarball, memory).

Remember to verify the outer tarball checksum against the registry checksum returned from hex_repo:get_package(Config, Package).

Create package tarball:

{ok, #{tarball := Tarball,
       inner_checksum := InnerChecksum,
       outer_checksum := OuterChecksum}} = hex_tarball:create(Metadata, Contents).

Configuration

The default configuration, provided by hex_core:default_config/0, uses built-in httpc-based adapter and Hex.pm APIs: https://hex.pm/api and https://repo.hex.pm.

HTTP client configuration can be overridden as follows:

Config = maps:merge(hex_core:default_config(), #{
  http_adapter => my_hackney_adapter,
  http_user_agent_fragment => <<"(my_app/0.1.0) (hackney/1.12.1) ">>
}),
hex_repo:get_names(Config).

%% my_hackney_adapter.erl
-module(my_hackney_adapter).
-behaviour(hex_http).
-exports([request/3]).

request(Method, URI, ReqHeaders) ->
    %% ...

See the hex_core module for more information about the configuration.

Wrapper Module

It's recommended to write a wrapper module because a lot of decisions are left to the user, e.g.: where to get configuration from, how to handle caching, failures etc.

For a sample, see: examples/myapp_hex.erl. Here's an excerpt:

-module(myapp_hex).
-export([
    get_api_package/1,
    get_repo_tarball/2,
    get_repo_versions/0
]).

%%====================================================================
%% API functions
%%====================================================================

get_api_package(Name) ->
      case hex_api_package:get(config(), Name) of
          {ok, {200, _Headers, Payload}} ->
              {ok, Payload};

          Other ->
              Other
      end.

get_repo_versions() ->
      case hex_repo:get_versions(config()) of
          {ok, {200, _Headers, Payload}} ->
              {ok, maps:get(packages, Payload)};

          Other ->
              Other
      end.

%%====================================================================
%% Internal functions
%%====================================================================

config() ->
    Config1 = hex_core:default_config(),
    Config2 = put_http_config(Config1),
    Config3 = maybe_put_api_key(Config2),
    Config3.

put_http_config(Config) ->
    maps:put(http_user_agent_fragment, <<"(myapp/1.0.0) (httpc)">>, Config).

maybe_put_api_key(Config) ->
    case os:getenv("HEX_API_KEY") of
        false -> Config;
        Key -> maps:put(api_key, Key, Config)
    end.

Installation

Rebar3

Add to rebar.config:

{deps, [
  {hex_core, "0.6.8"}
]}

Mix

Add to mix.exs:

defp deps() do
  [
    {:hex_core, "~> 0.6.0"}
  ]
end

Development

  • Run rebar3 as dev compile to re-generate protobuf files
  • Run rebar3 as test proper for property-based tests
  • Run rebar3 as docs edoc to generate documentation
You can’t perform that action at this time.