Browse Source

Fix fetching of private packages from orgs on hex repos (#2020)

- vendor in hex_core at v0.5.0
  - Change where repo_name should be the org and not the parent
  - Changed rebar_utils:url_append_path/2 to not explicitly add a '?',
    this is returned in the Query chunk by http_uri:parse/1 (e.g., "?foo=bar")
  - update organization_merging test to expect the sub-repo as the repo_name
  - Add tests for rebar_utils:url_append_path/2
  - Stop referencing/setting "organization" in config and use new
     organization settings (api_repository and repo_organization)
  - Do not set (assume) the read key is valid for any/every repo
  - Set repo_organization and api_repository to org
  - Update tests to check for new config opts
pull/2028/head
Bryan Paxton 6 years ago
committed by Tristan Sloughter
parent
commit
209c02ec57
37 changed files with 8536 additions and 40 deletions
  1. +3
    -0
      .gitignore
  2. +8
    -4
      bootstrap
  3. +0
    -1
      rebar.config
  4. +0
    -2
      rebar.lock
  5. +120
    -0
      src/r3_hex_api.erl
  6. +31
    -0
      src/r3_hex_api_key.erl
  7. +49
    -0
      src/r3_hex_api_package.erl
  8. +34
    -0
      src/r3_hex_api_package_owner.erl
  9. +60
    -0
      src/r3_hex_api_release.erl
  10. +46
    -0
      src/r3_hex_api_user.erl
  11. +92
    -0
      src/r3_hex_core.erl
  12. +3
    -0
      src/r3_hex_core.hrl
  13. +1966
    -0
      src/r3_hex_erl_tar.erl
  14. +405
    -0
      src/r3_hex_erl_tar.hrl
  15. +60
    -0
      src/r3_hex_filename.erl
  16. +43
    -0
      src/r3_hex_http.erl
  17. +39
    -0
      src/r3_hex_http_httpc.erl
  18. +735
    -0
      src/r3_hex_pb_names.erl
  19. +1699
    -0
      src/r3_hex_pb_package.erl
  20. +564
    -0
      src/r3_hex_pb_signed.erl
  21. +958
    -0
      src/r3_hex_pb_versions.erl
  22. +133
    -0
      src/r3_hex_registry.erl
  23. +174
    -0
      src/r3_hex_repo.erl
  24. +507
    -0
      src/r3_hex_tarball.erl
  25. +678
    -0
      src/r3_safe_erl_term.erl
  26. +79
    -0
      src/r3_safe_erl_term.xrl
  27. +0
    -1
      src/rebar.app.src
  28. +16
    -11
      src/rebar_hex_repos.erl
  29. +3
    -5
      src/rebar_packages.erl
  30. +3
    -3
      src/rebar_pkg_resource.erl
  31. +1
    -1
      src/rebar_utils.erl
  32. +1
    -1
      test/mock_pkg_resource.erl
  33. +5
    -5
      test/rebar_pkg_SUITE.erl
  34. +3
    -3
      test/rebar_pkg_alias_SUITE.erl
  35. +9
    -0
      test/rebar_pkg_repos_SUITE.erl
  36. +1
    -1
      test/rebar_test_utils.erl
  37. +8
    -2
      test/rebar_utils_SUITE.erl

+ 3
- 0
.gitignore View File

@ -21,3 +21,6 @@ priv/templates/*.dtl.erl
ebin
.edts
env
# hex_core artifact
src/r3_safe_erl_term.erl

+ 8
- 4
bootstrap View File

@ -15,6 +15,11 @@ main(_) ->
%% a changed structure from an older one
rm_rf("_build/bootstrap"),
%% We fetch a few deps from hex for boostraping,
%% so we must compile r3_safe_erl_term.xrl which
%% is part of hex_core.
compile_xrl_file("src/r3_safe_erl_term.xrl"),
%% Fetch and build deps required to build rebar3
BaseDeps = [{providers, []}
,{getopt, []}
@ -22,8 +27,7 @@ main(_) ->
,{erlware_commons, ["ec_dictionary.erl", "ec_vsn.erl"]}
,{parse_trans, ["parse_trans.erl", "parse_trans_pp.erl",
"parse_trans_codegen.erl"]}
,{certifi, []}
,{hex_core, []}],
,{certifi, []}],
Deps = get_deps(),
[fetch_and_compile(Dep, Deps) || Dep <- BaseDeps],
@ -143,7 +147,7 @@ compile(App, FirstFiles) ->
[compile_xrl_file(X) || X <- LeexFiles],
YeccFiles = filelib:wildcard(filename:join([Dir, "src", "*.yrl"])),
[compile_yrl_file(X) || X <- YeccFiles],
Sources = FirstFilesPaths ++ filelib:wildcard(filename:join([Dir, "src", "*.erl"])),
Sources = FirstFilesPaths ++ filelib:wildcard(filename:join([Dir, "src", "*.erl"])),
[compile_erl_file(X, [{i, filename:join(Dir, "include")}
,debug_info
,{outdir, filename:join(Dir, "ebin")}
@ -175,7 +179,7 @@ bootstrap_rebar3() ->
Res = symlink_or_copy(filename:absname("src"),
filename:absname("_build/default/lib/rebar/src")),
true = Res == ok orelse Res == exists,
Sources = ["src/rebar_resource_v2.erl", "src/rebar_resource.erl" | filelib:wildcard("src/*.erl")],
Sources = ["src/rebar_resource_v2.erl", "src/rebar_resource.erl" | filelib:wildcard("src/*.erl") ],
[compile_erl_file(X, [{outdir, "_build/default/lib/rebar/ebin/"}
,return | additional_defines()]) || X <- Sources],
code:add_patha(filename:absname("_build/default/lib/rebar/ebin")).

+ 0
- 1
rebar.config View File

@ -11,7 +11,6 @@
{relx, "3.28.0"},
{cf, "0.2.2"},
{cth_readable, "1.4.3"},
{hex_core, "0.4.0"},
{eunit_formatters, "0.5.0"}]}.
{post_hooks, [{"(linux|darwin|solaris|freebsd|netbsd|openbsd)",

+ 0
- 2
rebar.lock View File

@ -6,7 +6,6 @@
{<<"erlware_commons">>,{pkg,<<"erlware_commons">>,<<"1.3.1">>},0},
{<<"eunit_formatters">>,{pkg,<<"eunit_formatters">>,<<"0.5.0">>},0},
{<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},0},
{<<"hex_core">>,{pkg,<<"hex_core">>,<<"0.4.0">>},0},
{<<"parse_trans">>,{pkg,<<"parse_trans">>,<<"3.3.0">>},0},
{<<"providers">>,{pkg,<<"providers">>,<<"1.7.0">>},0},
{<<"relx">>,{pkg,<<"relx">>,<<"3.28.0">>},0},
@ -20,7 +19,6 @@
{<<"erlware_commons">>, <<"0CE192AD69BC6FD0880246D852D0ECE17631E234878011D1586E053641ED4C04">>},
{<<"eunit_formatters">>, <<"6A9133943D36A465D804C1C5B6E6839030434B8879C5600D7DDB5B3BAD4CCB59">>},
{<<"getopt">>, <<"C73A9FA687B217F2FF79F68A3B637711BB1936E712B521D8CE466B29CBF7808A">>},
{<<"hex_core">>, <<"6A0E0B1B519850344292298DA1BFA685E71534FDF4C69434993039F81078C7FA">>},
{<<"parse_trans">>, <<"09765507A3C7590A784615CFD421D101AEC25098D50B89D7AA1D66646BC571C1">>},
{<<"providers">>, <<"BBF730563914328EC2511D205E6477A94831DB7297DE313B3872A2B26C562EAB">>},
{<<"relx">>, <<"CFC26899E308FAB79B5826C4298EC052A2C1D66D03679AB76E6266D766B56545">>},

+ 120
- 0
src/r3_hex_api.erl View File

@ -0,0 +1,120 @@
%% Vendored from hex_core v0.5.0, do not edit manually
%% @hidden
-module(r3_hex_api).
-export([
delete/2,
get/2,
post/3,
put/3,
encode_query_string/1,
build_repository_path/2,
build_organization_path/2,
join_path_segments/1
]).
-define(ERL_CONTENT_TYPE, <<"application/vnd.hex+erlang">>).
get(Config, Path) ->
request(Config, get, Path, undefined).
post(Config, Path, Body) ->
request(Config, post, Path, encode_body(Body)).
put(Config, Path, Body) ->
request(Config, put, Path, encode_body(Body)).
delete(Config, Path) ->
request(Config, delete, Path, undefined).
%% @private
encode_query_string(List) ->
QueryString =
join("&",
lists:map(fun
({K, V}) when is_atom(V) ->
atom_to_list(K) ++ "=" ++ atom_to_list(V);
({K, V}) when is_binary(V) ->
atom_to_list(K) ++ "=" ++ binary_to_list(V);
({K, V}) when is_integer(V) ->
atom_to_list(K) ++ "=" ++ integer_to_list(V)
end, List)),
Encoded = http_uri:encode(QueryString),
list_to_binary(Encoded).
%% @private
build_repository_path(#{api_repository := Repo}, Path) when is_binary(Repo) ->
["repos", Repo | Path];
build_repository_path(#{api_repository := undefined}, Path) ->
Path.
%% @private
build_organization_path(#{api_organization := Org}, Path) when is_binary(Org) ->
["orgs", Org | Path];
build_organization_path(#{api_organization := undefined}, Path) ->
Path.
%% @private
join_path_segments(Segments) ->
erlang:iolist_to_binary(join(<<"/">>, lists:map(fun encode/1, Segments))).
%%====================================================================
%% Internal functions
%%====================================================================
request(Config, Method, PathSegments, Body) when is_list(PathSegments) ->
Path = join_path_segments(PathSegments),
request(Config, Method, Path, Body);
request(Config, Method, Path, Body) when is_binary(Path) and is_map(Config) ->
DefaultHeaders = make_headers(Config),
ReqHeaders = maps:merge(maps:get(http_headers, Config, #{}), DefaultHeaders),
ReqHeaders2 = put_new(<<"accept">>, ?ERL_CONTENT_TYPE, ReqHeaders),
case r3_hex_http:request(Config, Method, build_url(Path, Config), ReqHeaders2, Body) of
{ok, {Status, RespHeaders, RespBody}} = Response ->
ContentType = maps:get(<<"content-type">>, RespHeaders, <<"">>),
case binary:match(ContentType, ?ERL_CONTENT_TYPE) of
{_, _} ->
{ok, {Status, RespHeaders, binary_to_term(RespBody)}};
nomatch ->
Response
end;
Other ->
Other
end.
encode(Binary) when is_binary(Binary) ->
encode(binary_to_list(Binary));
encode(String) when is_list(String) ->
http_uri:encode(String).
build_url(Path, #{api_url := URI}) ->
<<URI/binary, "/", Path/binary>>.
encode_body({_ContentType, _Body} = Body) ->
Body;
encode_body(Body) ->
{binary_to_list(?ERL_CONTENT_TYPE), term_to_binary(Body)}.
%% TODO: copy-pasted from r3_hex_repo
make_headers(Config) ->
maps:fold(fun set_header/3, #{}, Config).
set_header(api_key, Token, Headers) when is_binary(Token) -> maps:put(<<"authorization">>, Token, Headers);
set_header(_, _, Headers) -> Headers.
put_new(Key, Value, Map) ->
case maps:find(Key, Map) of
{ok, _} -> Map;
error -> maps:put(Key, Value, Map)
end.
%% https://github.com/erlang/otp/blob/OTP-20.3/lib/stdlib/src/lists.erl#L1449:L1453
join(_Sep, []) -> [];
join(Sep, [H|T]) -> [H|join_prepend(Sep, T)].
join_prepend(_Sep, []) -> [];
join_prepend(Sep, [H|T]) -> [Sep,H|join_prepend(Sep,T)].

+ 31
- 0
src/r3_hex_api_key.erl View File

@ -0,0 +1,31 @@
%% Vendored from hex_core v0.5.0, do not edit manually
-module(r3_hex_api_key).
-export([
list/1,
get/2,
add/3,
delete/2,
delete_all/1
]).
list(Config) when is_map(Config) ->
Path = r3_hex_api:build_organization_path(Config, ["keys"]),
r3_hex_api:get(Config, Path).
get(Config, Name) when is_map(Config) ->
Path = r3_hex_api:build_organization_path(Config, ["keys", Name]),
r3_hex_api:get(Config, Path).
add(Config, Name, Permissions) when is_map(Config) ->
Path = r3_hex_api:build_organization_path(Config, ["keys"]),
Params = #{<<"name">> => Name, <<"permissions">> => Permissions},
r3_hex_api:post(Config, Path, Params).
delete(Config, Name) when is_map(Config) ->
Path = r3_hex_api:build_organization_path(Config, ["keys", Name]),
r3_hex_api:delete(Config, Path).
delete_all(Config) when is_map(Config) ->
Path = r3_hex_api:build_organization_path(Config, ["keys"]),
r3_hex_api:delete(Config, Path).

+ 49
- 0
src/r3_hex_api_package.erl View File

@ -0,0 +1,49 @@
%% Vendored from hex_core v0.5.0, do not edit manually
-module(r3_hex_api_package).
-export([get/2, search/3]).
%% @doc
%% Gets package.
%%
%% Examples:
%%
%% ```
%% > r3_hex_api_package:get(r3_hex_core:default_config(), <<"package">>).
%% {ok, {200, ..., #{
%% <<"name">> => <<"package1">>,
%% <<"meta">> => #{
%% <<"description">> => ...,
%% <<"licenses">> => ...,
%% <<"links">> => ...,
%% <<"maintainers">> => ...
%% },
%% ...,
%% <<"releases">> => [
%% #{<<"url">> => ..., <<"version">> => <<"0.5.0">>}],
%% #{<<"url">> => ..., <<"version">> => <<"1.0.0">>}],
%% ...
%% ]}}}
%% '''
%% @end
get(Config, Name) when is_binary(Name) and is_map(Config) ->
Path = r3_hex_api:build_repository_path(Config, ["packages", Name]),
r3_hex_api:get(Config, Path).
%% @doc
%% Searches packages.
%%
%% Examples:
%%
%% ```
%% > r3_hex_api_package:search(r3_hex_core:default_config(), <<"package">>, []).
%% {ok, {200, ..., [
%% #{<<"name">> => <<"package1">>, ...},
%% ...
%% ]}}
%% '''
search(Config, Query, SearchParams) when is_binary(Query) and is_list(SearchParams) and is_map(Config) ->
QueryString = r3_hex_api:encode_query_string([{search, Query} | SearchParams]),
Path = r3_hex_api:join_path_segments(r3_hex_api:build_repository_path(Config, ["packages"])),
PathQuery = <<Path/binary, "?", QueryString/binary>>,
r3_hex_api:get(Config, PathQuery).

+ 34
- 0
src/r3_hex_api_package_owner.erl View File

@ -0,0 +1,34 @@
%% Vendored from hex_core v0.5.0, do not edit manually
-module(r3_hex_api_package_owner).
-export([
add/3,
delete/3,
get/3,
list/2
]).
%% Examples:
%%
%% ```
%% > r3_hex_api_owner:list(r3_hex_core:default_config(), <<"package">>).
%% {ok, {200, ..., [
%% #{<<"username">> => <<"alice">>, ...},
%% ...
%% ]}}
%% '''
list(Config, PackageName) when is_binary(PackageName) and is_map(Config) ->
Path = r3_hex_api:build_repository_path(Config, ["packages", PackageName, "owners"]),
r3_hex_api:get(Config, Path).
get(Config, PackageName, UsernameOrEmail) when is_binary(PackageName) and is_map(Config) ->
Path = r3_hex_api:build_repository_path(Config, ["packages", PackageName, "owners", UsernameOrEmail]),
r3_hex_api:get(Config, Path).
add(Config, PackageName, UsernameOrEmail) when is_binary(PackageName) and is_map(Config) ->
Path = r3_hex_api:build_repository_path(Config, ["packages", PackageName, "owners", UsernameOrEmail]),
r3_hex_api:put(Config, Path, #{}).
delete(Config, PackageName, UsernameOrEmail) when is_binary(PackageName) and is_map(Config) ->
Path = r3_hex_api:build_repository_path(Config, ["packages", PackageName, "owners", UsernameOrEmail]),
r3_hex_api:delete(Config, Path).

+ 60
- 0
src/r3_hex_api_release.erl View File

@ -0,0 +1,60 @@
%% Vendored from hex_core v0.5.0, do not edit manually
-module(r3_hex_api_release).
-export([
delete/3,
get/3,
publish/2,
retire/4,
unretire/3
]).
%% @doc
%% Gets package release.
%%
%% Examples:
%%
%% ```
%% > r3_hex_api:get_release(<<"package">>, <<"1.0.0">>, r3_hex_core:default_config()).
%% {ok, {200, ..., #{
%% <<"version">> => <<"1.0.0">>,
%% <<"meta">> => #{
%% <<"description">> => ...,
%% <<"licenses">> => ...,
%% <<"links">> => ...,
%% <<"maintainers">> => ...
%% },
%% ...}}}
%% '''
%% @end
get(Config, Name, Version) when is_binary(Name) and is_binary(Version) and is_map(Config) ->
Path = r3_hex_api:build_repository_path(Config, ["packages", Name, "releases", Version]),
r3_hex_api:get(Config, Path).
publish(Config, Tarball) when is_binary(Tarball) and is_map(Config) ->
Path = r3_hex_api:build_repository_path(Config, ["publish"]),
TarballContentType = "application/octet-stream",
Config2 = put_header(<<"content-length">>, integer_to_binary(byte_size(Tarball)), Config),
Body = {TarballContentType, Tarball},
r3_hex_api:post(Config2, Path, Body).
delete(Config, Name, Version) when is_binary(Name) and is_binary(Version) and is_map(Config) ->
Path = r3_hex_api:build_repository_path(Config, ["packages", Name, "releases", Version]),
r3_hex_api:delete(Config, Path).
retire(Config, Name, Version, Params) when is_binary(Name) and is_binary(Version) and is_map(Config) ->
Path = r3_hex_api:build_repository_path(Config, ["packages", Name, "releases", Version, "retire"]),
r3_hex_api:post(Config, Path, Params).
unretire(Config, Name, Version) when is_binary(Name) and is_binary(Version) and is_map(Config) ->
Path = r3_hex_api:build_repository_path(Config, ["packages", Name, "releases", Version, "retire"]),
r3_hex_api:delete(Config, Path).
%%====================================================================
%% Internal functions
%%====================================================================
put_header(Name, Value, Config) ->
Headers = maps:get(http_headers, Config, #{}),
Headers2 = maps:put(Name, Value, Headers),
maps:put(http_headers, Headers2, Config).

+ 46
- 0
src/r3_hex_api_user.erl View File

@ -0,0 +1,46 @@
%% Vendored from hex_core v0.5.0, do not edit manually
-module(r3_hex_api_user).
-export([
create/4,
get/2,
me/1,
reset_password/2
]).
me(Config) when is_map(Config) ->
r3_hex_api:get(Config, ["users", "me"]).
create(Config, Username, Password, Email) ->
Params = #{
<<"username">> => Username,
<<"password">> => Password,
<<"email">> => Email
},
r3_hex_api:post(Config, ["users"], Params).
reset_password(Username, Config) when is_binary(Username) and is_map(Config) ->
r3_hex_api:post(Config, ["users", Username, "reset"], #{}).
%% @doc
%% Gets user.
%%
%% Examples:
%%
%% ```
%% > r3_hex_api_user:get(<<"user">>, r3_hex_core:default_config()).
%% {ok, {200, ..., #{
%% <<"username">> => <<"user">>,
%% <<"packages">> => [
%% #{
%% <<"name">> => ...,
%% <<"url">> => ...,
%% ...
%% },
%% ...
%% ],
%% ...}}}
%% '''
%% @end
get(Config, Username) when is_binary(Username) and is_map(Config) ->
r3_hex_api:get(Config, ["users", Username]).

+ 92
- 0
src/r3_hex_core.erl View File

@ -0,0 +1,92 @@
%% Vendored from hex_core v0.5.0, do not edit manually
%% @doc
%% hex_core entrypoint module.
%%
%% ### Config
%%
%% Most functions in the hex_core API takes a configuration. The configuration sets things
%% like HTTP client to use, and API and repository URL. Some of these configuration options
%% will likely be static for your application and some may change depending on the function
%% you call.
%%
%% ##### Options
%%
%% * `api_key' - Authentication key used when accessing the HTTP API.
%% * `api_organization' - Name of the organization endpoint in the API, this should
%% for example be set when accessing key for a specific organization.
%% * `api_repository' - Name of the repository endpoint in the API, this should
%% for example be set when accessing packages from a specific repository.
%% * `api_url' - URL to the HTTP API (default: `https://hex.pm/api').
%% * `http_adapter' - Callback module used for HTTP requests, see [`r3_hex_http'](r3_hex_http.html)
%% (default: `r3_hex_http_httpc').
%% * `http_etag' - Sets the `if-none-match' HTTP header with the given value to do a
%% conditional HTTP request.
%% * `http_adapter_config' - Configuration to pass to the HTTP adapter.
%% * `http_user_agent_fragment' - Will be appended to the `user-agent` HTTP header (default: `(httpc)').
%% * `repo_key' - Authentication key used when accessing the repository.
%% * `repo_name' - Name of the repository, used for verifying the repository signature
%% authenticity (default: `hexpm').
%% * `repo_public_key' - Public key used to verify the repository signature
%% (defaults to hexpm public key `https://hex.pm/docs/public_keys').
%% * `repo_url' - URL to the repository (default: `https://repo.hex.pm').
%% * `repo_organization' - Name of the organization repository, appends `/repos/:name'
%% to the repository URL and overrides the `repo_name' option.
%% * `repo_verify' - If `true' will verify the repository signature (default: `true').
%% * `repo_verify_origin' - If `true' will verify the repository signature origin,
%% requires protobuf messages as of hex_core v0.4.0 (default: `true').
-module(r3_hex_core).
-export([default_config/0]).
-export_type([config/0]).
%% https://hex.pm/docs/public_keys
-define(HEXPM_PUBLIC_KEY, <<"-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApqREcFDt5vV21JVe2QNB
Edvzk6w36aNFhVGWN5toNJRjRJ6m4hIuG4KaXtDWVLjnvct6MYMfqhC79HAGwyF+
IqR6Q6a5bbFSsImgBJwz1oadoVKD6ZNetAuCIK84cjMrEFRkELtEIPNHblCzUkkM
3rS9+DPlnfG8hBvGi6tvQIuZmXGCxF/73hU0/MyGhbmEjIKRtG6b0sJYKelRLTPW
XgK7s5pESgiwf2YC/2MGDXjAJfpfCd0RpLdvd4eRiXtVlE9qO9bND94E7PgQ/xqZ
J1i2xWFndWa6nfFnRxZmCStCOZWYYPlaxr+FZceFbpMwzTNs4g3d4tLNUcbKAIH4
0wIDAQAB
-----END PUBLIC KEY-----">>).
-type config() :: #{
api_key => binary() | undefined,
api_organization => binary() | undefined,
api_repository => binary() | undefined,
api_url => binary(),
http_adapter => module(),
http_etag => binary() | undefined,
http_adapter_config => map(),
http_user_agent_fragment => binary(),
repo_key => binary() | undefined,
repo_name => binary(),
repo_public_key => binary(),
repo_url => binary(),
repo_organization => binary() | undefined,
repo_verify => boolean(),
repo_verify_origin => boolean()
}.
-spec default_config() -> config().
default_config() ->
#{
api_key => undefined,
api_organization => undefined,
api_repository => undefined,
api_url => <<"https://hex.pm/api">>,
http_adapter => r3_hex_http_httpc,
http_adapter_config => #{profile => default},
http_etag => undefined,
http_user_agent_fragment => <<"(httpc)">>,
repo_key => undefined,
repo_name => <<"hexpm">>,
repo_public_key => ?HEXPM_PUBLIC_KEY,
repo_url => <<"https://repo.hex.pm">>,
repo_organization => undefined,
repo_verify => true,
repo_verify_origin => true
}.

+ 3
- 0
src/r3_hex_core.hrl View File

@ -0,0 +1,3 @@
%% Vendored from hex_core v0.5.0, do not edit manually
-define(HEX_CORE_VERSION, "0.5.0").

+ 1966
- 0
src/r3_hex_erl_tar.erl
File diff suppressed because it is too large
View File


+ 405
- 0
src/r3_hex_erl_tar.hrl View File

@ -0,0 +1,405 @@
%% Vendored from hex_core v0.5.0, do not edit manually
% Copied from https://github.com/erlang/otp/blob/OTP-20.0.1/lib/stdlib/src/erl_tar.hrl
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%% Options used when adding files to a tar archive.
-record(add_opts, {
read_info, %% Fun to use for read file/link info.
chunk_size = 0, %% For file reading when sending to sftp. 0=do not chunk
verbose = false, %% Verbose on/off.
atime = undefined,
mtime = undefined,
ctime = undefined,
uid = 0,
gid = 0}).
-type add_opts() :: #add_opts{}.
%% Options used when reading a tar archive.
-record(read_opts, {
cwd :: string(), %% Current working directory.
keep_old_files = false :: boolean(), %% Owerwrite or not.
files = all, %% Set of files to extract (or all)
output = file :: 'file' | 'memory',
open_mode = [], %% Open mode options.
verbose = false :: boolean()}). %% Verbose on/off.
-type read_opts() :: #read_opts{}.
-type add_opt() :: dereference |
verbose |
{chunks, pos_integer()}.
-type extract_opt() :: {cwd, string()} |
{files, [string()]} |
compressed |
cooked |
memory |
keep_old_files |
verbose.
-type create_opt() :: compressed |
cooked |
dereference |
verbose.
-type filelist() :: [file:filename() |
{string(), binary()} |
{string(), file:filename()}].
-type tar_time() :: non_neg_integer().
%% The tar header, once fully parsed.
-record(tar_header, {
name = "" :: string(), %% name of header file entry
mode = 8#100644 :: non_neg_integer(), %% permission and mode bits
uid = 0 :: non_neg_integer(), %% user id of owner
gid = 0 :: non_neg_integer(), %% group id of owner
size = 0 :: non_neg_integer(), %% length in bytes
mtime :: tar_time(), %% modified time
typeflag :: char(), %% type of header entry
linkname = "" :: string(), %% target name of link
uname = "" :: string(), %% user name of owner
gname = "" :: string(), %% group name of owner
devmajor = 0 :: non_neg_integer(), %% major number of character or block device
devminor = 0 :: non_neg_integer(), %% minor number of character or block device
atime :: tar_time(), %% access time
ctime :: tar_time() %% status change time
}).
-type tar_header() :: #tar_header{}.
%% Metadata for a sparse file fragment
-record(sparse_entry, {
offset = 0 :: non_neg_integer(),
num_bytes = 0 :: non_neg_integer()}).
-type sparse_entry() :: #sparse_entry{}.
%% Contains metadata about fragments of a sparse file
-record(sparse_array, {
entries = [] :: [sparse_entry()],
is_extended = false :: boolean(),
max_entries = 0 :: non_neg_integer()}).
-type sparse_array() :: #sparse_array{}.
%% A subset of tar header fields common to all tar implementations
-record(header_v7, {
name :: binary(),
mode :: binary(), %% octal
uid :: binary(), %% integer
gid :: binary(), %% integer
size :: binary(), %% integer
mtime :: binary(), %% integer
checksum :: binary(), %% integer
typeflag :: byte(), %% char
linkname :: binary()}).
-type header_v7() :: #header_v7{}.
%% The set of fields specific to GNU tar formatted archives
-record(header_gnu, {
header_v7 :: header_v7(),
magic :: binary(),
version :: binary(),
uname :: binary(),
gname :: binary(),
devmajor :: binary(), %% integer
devminor :: binary(), %% integer
atime :: binary(), %% integer
ctime :: binary(), %% integer
sparse :: sparse_array(),
real_size :: binary()}). %% integer
-type header_gnu() :: #header_gnu{}.
%% The set of fields specific to STAR-formatted archives
-record(header_star, {
header_v7 :: header_v7(),
magic :: binary(),
version :: binary(),
uname :: binary(),
gname :: binary(),
devmajor :: binary(), %% integer
devminor :: binary(), %% integer
prefix :: binary(),
atime :: binary(), %% integer
ctime :: binary(), %% integer
trailer :: binary()}).
-type header_star() :: #header_star{}.
%% The set of fields specific to USTAR-formatted archives
-record(header_ustar, {
header_v7 :: header_v7(),
magic :: binary(),
version :: binary(),
uname :: binary(),
gname :: binary(),
devmajor :: binary(), %% integer
devminor :: binary(), %% integer
prefix :: binary()}).
-type header_ustar() :: #header_ustar{}.
-type header_fields() :: header_v7() |
header_gnu() |
header_star() |
header_ustar().
%% The overall tar reader, it holds the low-level file handle,
%% its access, position, and the I/O primitives wrapper.
-record(reader, {
handle :: file:io_device() | term(),
access :: read | write | ram,
pos = 0 :: non_neg_integer(),
func :: file_op()
}).
-type reader() :: #reader{}.
%% A reader for a regular file within the tar archive,
%% It tracks its current state relative to that file.
-record(reg_file_reader, {
handle :: reader(),
num_bytes = 0,
pos = 0,
size = 0
}).
-type reg_file_reader() :: #reg_file_reader{}.
%% A reader for a sparse file within the tar archive,
%% It tracks its current state relative to that file.
-record(sparse_file_reader, {
handle :: reader(),
num_bytes = 0, %% bytes remaining
pos = 0, %% pos
size = 0, %% total size of file
sparse_map = #sparse_array{}
}).
-type sparse_file_reader() :: #sparse_file_reader{}.
%% Types for the readers
-type reader_type() :: reader() | reg_file_reader() | sparse_file_reader().
-type handle() :: file:io_device() | term().
%% Type for the I/O primitive wrapper function
-type file_op() :: fun((write | close | read2 | position,
{handle(), iodata()} | handle() | {handle(), non_neg_integer()}
| {handle(), non_neg_integer()}) ->
ok | eof | {ok, string() | binary()} | {ok, non_neg_integer()}
| {error, term()}).
%% These constants (except S_IFMT) are
%% used to determine what type of device
%% a file is. Namely, `S_IFMT band file_info.mode`
%% will equal one of these contants, and tells us
%% which type it is. The stdlib file_info record
%% does not differentiate between device types, and
%% will not allow us to differentiate between sockets
%% and named pipes. These constants are pulled from libc.
-define(S_IFMT, 61440).
-define(S_IFSOCK, 49152). %% socket
-define(S_FIFO, 4096). %% fifo/named pipe
-define(S_IFBLK, 24576). %% block device
-define(S_IFCHR, 8192). %% character device
%% Typeflag constants for the tar header
-define(TYPE_REGULAR, $0). %% regular file
-define(TYPE_REGULAR_A, 0). %% regular file
-define(TYPE_LINK, $1). %% hard link
-define(TYPE_SYMLINK, $2). %% symbolic link
-define(TYPE_CHAR, $3). %% character device node
-define(TYPE_BLOCK, $4). %% block device node
-define(TYPE_DIR, $5). %% directory
-define(TYPE_FIFO, $6). %% fifo node
-define(TYPE_CONT, $7). %% reserved
-define(TYPE_X_HEADER, $x). %% extended header
-define(TYPE_X_GLOBAL_HEADER, $g). %% global extended header
-define(TYPE_GNU_LONGNAME, $L). %% next file has a long name
-define(TYPE_GNU_LONGLINK, $K). %% next file symlinks to a file with a long name
-define(TYPE_GNU_SPARSE, $S). %% sparse file
%% Mode constants from tar spec
-define(MODE_ISUID, 4000). %% set uid
-define(MODE_ISGID, 2000). %% set gid
-define(MODE_ISVTX, 1000). %% save text (sticky bit)
-define(MODE_ISDIR, 40000). %% directory
-define(MODE_ISFIFO, 10000). %% fifo
-define(MODE_ISREG, 100000). %% regular file
-define(MODE_ISLNK, 120000). %% symbolic link
-define(MODE_ISBLK, 60000). %% block special file
-define(MODE_ISCHR, 20000). %% character special file
-define(MODE_ISSOCK, 140000). %% socket
%% Keywords for PAX extended header
-define(PAX_ATIME, <<"atime">>).
-define(PAX_CHARSET, <<"charset">>).
-define(PAX_COMMENT, <<"comment">>).
-define(PAX_CTIME, <<"ctime">>). %% ctime is not a valid pax header
-define(PAX_GID, <<"gid">>).
-define(PAX_GNAME, <<"gname">>).
-define(PAX_LINKPATH, <<"linkpath">>).
-define(PAX_MTIME, <<"mtime">>).
-define(PAX_PATH, <<"path">>).
-define(PAX_SIZE, <<"size">>).
-define(PAX_UID, <<"uid">>).
-define(PAX_UNAME, <<"uname">>).
-define(PAX_XATTR, <<"SCHILY.xattr.">>).
-define(PAX_XATTR_STR, "SCHILY.xattr.").
-define(PAX_NONE, <<"">>).
%% Tar format constants
%% Unknown format
-define(FORMAT_UNKNOWN, 0).
%% The format of the original Unix V7 tar tool prior to standardization
-define(FORMAT_V7, 1).
%% The old and new GNU formats, incompatible with USTAR.
%% This covers the old GNU sparse extension, but it does
%% not cover the GNU sparse extensions using PAX headers,
%% versions 0.0, 0.1, and 1.0; these fall under the PAX format.
-define(FORMAT_GNU, 2).
%% Schily's tar format, which is incompatible with USTAR.
%% This does not cover STAR extensions to the PAX format; these
%% fall under the PAX format.
-define(FORMAT_STAR, 3).
%% USTAR is the former standardization of tar defined in POSIX.1-1988,
%% it is incompatible with the GNU and STAR formats.
-define(FORMAT_USTAR, 4).
%% PAX is the latest standardization of tar defined in POSIX.1-2001.
%% This is an extension of USTAR and is "backwards compatible" with it.
%%
%% Some newer formats add their own extensions to PAX, such as GNU sparse
%% files and SCHILY extended attributes. Since they are backwards compatible
%% with PAX, they will be labelled as "PAX".
-define(FORMAT_PAX, 5).
%% Magic constants
-define(MAGIC_GNU, <<"ustar ">>).
-define(VERSION_GNU, <<" \x00">>).
-define(MAGIC_USTAR, <<"ustar\x00">>).
-define(VERSION_USTAR, <<"00">>).
-define(TRAILER_STAR, <<"tar\x00">>).
%% Size constants
-define(BLOCK_SIZE, 512). %% size of each block in a tar stream
-define(NAME_SIZE, 100). %% max length of the name field in USTAR format
-define(PREFIX_SIZE, 155). %% max length of the prefix field in USTAR format
%% Maximum size of a nanosecond value as an integer
-define(MAX_NANO_INT_SIZE, 9).
%% Maximum size of a 64-bit signed integer
-define(MAX_INT64, (1 bsl 63 - 1)).
-define(PAX_GNU_SPARSE_NUMBLOCKS, <<"GNU.sparse.numblocks">>).
-define(PAX_GNU_SPARSE_OFFSET, <<"GNU.sparse.offset">>).
-define(PAX_GNU_SPARSE_NUMBYTES, <<"GNU.sparse.numbytes">>).
-define(PAX_GNU_SPARSE_MAP, <<"GNU.sparse.map">>).
-define(PAX_GNU_SPARSE_NAME, <<"GNU.sparse.name">>).
-define(PAX_GNU_SPARSE_MAJOR, <<"GNU.sparse.major">>).
-define(PAX_GNU_SPARSE_MINOR, <<"GNU.sparse.minor">>).
-define(PAX_GNU_SPARSE_SIZE, <<"GNU.sparse.size">>).
-define(PAX_GNU_SPARSE_REALSIZE, <<"GNU.sparse.realsize">>).
-define(V7_NAME, 0).
-define(V7_NAME_LEN, 100).
-define(V7_MODE, 100).
-define(V7_MODE_LEN, 8).
-define(V7_UID, 108).
-define(V7_UID_LEN, 8).
-define(V7_GID, 116).
-define(V7_GID_LEN, 8).
-define(V7_SIZE, 124).
-define(V7_SIZE_LEN, 12).
-define(V7_MTIME, 136).
-define(V7_MTIME_LEN, 12).
-define(V7_CHKSUM, 148).
-define(V7_CHKSUM_LEN, 8).
-define(V7_TYPE, 156).
-define(V7_TYPE_LEN, 1).
-define(V7_LINKNAME, 157).
-define(V7_LINKNAME_LEN, 100).
-define(STAR_TRAILER, 508).
-define(STAR_TRAILER_LEN, 4).
-define(USTAR_MAGIC, 257).
-define(USTAR_MAGIC_LEN, 6).
-define(USTAR_VERSION, 263).
-define(USTAR_VERSION_LEN, 2).
-define(USTAR_UNAME, 265).
-define(USTAR_UNAME_LEN, 32).
-define(USTAR_GNAME, 297).
-define(USTAR_GNAME_LEN, 32).
-define(USTAR_DEVMAJ, 329).
-define(USTAR_DEVMAJ_LEN, 8).
-define(USTAR_DEVMIN, 337).
-define(USTAR_DEVMIN_LEN, 8).
-define(USTAR_PREFIX, 345).
-define(USTAR_PREFIX_LEN, 155).
-define(GNU_MAGIC, 257).
-define(GNU_MAGIC_LEN, 6).
-define(GNU_VERSION, 263).
-define(GNU_VERSION_LEN, 2).
%% ?BLOCK_SIZE of zero-bytes.
%% Two of these in a row mark the end of an archive.
-define(ZERO_BLOCK, <<0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0>>).
-define(BILLION, 1000000000).
-define(EPOCH, {{1970,1,1}, {0,0,0}}).

+ 60
- 0
src/r3_hex_filename.erl View File

@ -0,0 +1,60 @@
%% Vendored from hex_core v0.5.0, do not edit manually
% @private
% Excerpt from https://github.com/erlang/otp/blob/OTP-20.0.1/lib/stdlib/src/filename.erl#L761-L788
% with modifications for changing local function calls to remote function calls
% to the `filename` module, for the functions `pathtype/1`, `split/1`, and `join/1`
%
% safe_relative_path/1 was not present in earlier OTP releases.
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%
-module(r3_hex_filename).
-export([safe_relative_path/1]).
safe_relative_path(Path) ->
case filename:pathtype(Path) of
relative ->
Cs0 = filename:split(Path),
safe_relative_path_1(Cs0, []);
_ ->
unsafe
end.
safe_relative_path_1(["."|T], Acc) ->
safe_relative_path_1(T, Acc);
safe_relative_path_1([<<".">>|T], Acc) ->
safe_relative_path_1(T, Acc);
safe_relative_path_1([".."|T], Acc) ->
climb(T, Acc);
safe_relative_path_1([<<"..">>|T], Acc) ->
climb(T, Acc);
safe_relative_path_1([H|T], Acc) ->
safe_relative_path_1(T, [H|Acc]);
safe_relative_path_1([], []) ->
[];
safe_relative_path_1([], Acc) ->
filename:join(lists:reverse(Acc)).
climb(_, []) ->
unsafe;
climb(T, [_|Acc]) ->
safe_relative_path_1(T, Acc).

+ 43
- 0
src/r3_hex_http.erl View File

@ -0,0 +1,43 @@
%% Vendored from hex_core v0.5.0, do not edit manually
-module(r3_hex_http).
-export([request/5]).
-ifdef(TEST).
-export([user_agent/1]).
-endif.
-include_lib("r3_hex_core.hrl").
-type method() :: get | post | put | patch | delete.
-type status() :: non_neg_integer().
-type headers() :: #{binary() => binary()}.
-type body() :: {ContentType :: binary(), Body :: binary()} | undefined.
-type adapter_config() :: map().
-callback request(method(), URI :: binary(), headers(), body(), adapter_config()) ->
{ok, status(), headers(), binary()} |
{error, term()}.
-spec request(r3_hex_core:config(), method(), URI :: binary(), headers(), body()) ->
{ok, {status(), headers(), binary()}} | {error, term()}.
request(Config, Method, URI, Headers, Body) when is_binary(URI) and is_map(Headers) ->
Adapter = maps:get(http_adapter, Config),
UserAgentFragment = maps:get(http_user_agent_fragment, Config),
Headers2 = put_new(<<"user-agent">>, user_agent(UserAgentFragment), Headers),
AdapterConfig = maps:get(http_adapter_config, Config, #{}),
Adapter:request(Method, URI, Headers2, Body, AdapterConfig).
user_agent(UserAgentFragment) ->
OTPRelease = erlang:system_info(otp_release),
ERTSVersion = erlang:system_info(version),
OTPString = " (OTP/" ++ OTPRelease ++ ") (erts/" ++ ERTSVersion ++ ")",
iolist_to_binary(["hex_core/", ?HEX_CORE_VERSION, " ", UserAgentFragment, OTPString]).
%%====================================================================
%% Internal functions
%%====================================================================
put_new(Key, Value, Map) ->
case maps:find(Key, Map) of
{ok, _} -> Map;
error -> maps:put(Key, Value, Map)
end.

+ 39
- 0
src/r3_hex_http_httpc.erl View File

@ -0,0 +1,39 @@
%% Vendored from hex_core v0.5.0, do not edit manually
%% @hidden
-module(r3_hex_http_httpc).
-behaviour(r3_hex_http).
-export([request/5]).
%%====================================================================
%% API functions
%%====================================================================
request(Method, URI, ReqHeaders, Body, AdapterConfig) ->
Profile = maps:get(profile, AdapterConfig, default),
Request = build_request(URI, ReqHeaders, Body),
{ok, {{_, StatusCode, _}, RespHeaders, RespBody}} =
httpc:request(Method, Request, [], [{body_format, binary}], Profile),
RespHeaders2 = load_headers(RespHeaders),
{ok, {StatusCode, RespHeaders2, RespBody}}.
%%====================================================================
%% Internal functions
%%====================================================================
build_request(URI, ReqHeaders, Body) ->
build_request2(binary_to_list(URI), dump_headers(ReqHeaders), Body).
build_request2(URI, ReqHeaders, undefined) ->
{URI, ReqHeaders};
build_request2(URI, ReqHeaders, {ContentType, Body}) ->
{URI, ReqHeaders, ContentType, Body}.
dump_headers(Map) ->
maps:fold(fun(K, V, Acc) ->
[{binary_to_list(K), binary_to_list(V)} | Acc] end, [], Map).
load_headers(List) ->
lists:foldl(fun({K, V}, Acc) ->
maps:put(list_to_binary(K), list_to_binary(V), Acc) end, #{}, List).

+ 735
- 0
src/r3_hex_pb_names.erl View File

@ -0,0 +1,735 @@
%% Vendored from hex_core v0.5.0, do not edit manually
%% -*- coding: utf-8 -*-
%% Automatically generated, do not edit
%% Generated by gpb_compile version 4.3.1
-module(r3_hex_pb_names).
-export([encode_msg/2, encode_msg/3]).
-export([decode_msg/2, decode_msg/3]).
-export([merge_msgs/3, merge_msgs/4]).
-export([verify_msg/2, verify_msg/3]).
-export([get_msg_defs/0]).
-export([get_msg_names/0]).
-export([get_group_names/0]).
-export([get_msg_or_group_names/0]).
-export([get_enum_names/0]).
-export([find_msg_def/1, fetch_msg_def/1]).
-export([find_enum_def/1, fetch_enum_def/1]).
-export([enum_symbol_by_value/2, enum_value_by_symbol/2]).
-export([get_service_names/0]).
-export([get_service_def/1]).
-export([get_rpc_names/1]).
-export([find_rpc_def/2, fetch_rpc_def/2]).
-export([get_package_name/0]).
-export([gpb_version_as_string/0, gpb_version_as_list/0]).
%% enumerated types
-export_type([]).
%% message types
-type 'Names'() ::
#{packages => ['Package'()], % = 1
repository => iodata() % = 2
}.
-type 'Package'() ::
#{name => iodata() % = 1
}.
-export_type(['Names'/0, 'Package'/0]).
-spec encode_msg('Names'() | 'Package'(), atom()) -> binary().
encode_msg(Msg, MsgName) when is_atom(MsgName) ->
encode_msg(Msg, MsgName, []).
-spec encode_msg('Names'() | 'Package'(), atom(), list()) -> binary().
encode_msg(Msg, MsgName, Opts) ->
verify_msg(Msg, MsgName, Opts),
TrUserData = proplists:get_value(user_data, Opts),
case MsgName of
'Names' -> e_msg_Names(id(Msg, TrUserData), TrUserData);
'Package' ->
e_msg_Package(id(Msg, TrUserData), TrUserData)
end.
e_msg_Names(Msg, TrUserData) ->
e_msg_Names(Msg, <<>>, TrUserData).
e_msg_Names(#{repository := F2} = M, Bin, TrUserData) ->
B1 = case M of
#{packages := F1} ->
TrF1 = id(F1, TrUserData),
if TrF1 == [] -> Bin;
true -> e_field_Names_packages(TrF1, Bin, TrUserData)
end;
_ -> Bin
end,
begin
TrF2 = id(F2, TrUserData),
e_type_string(TrF2, <<B1/binary, 18>>, TrUserData)
end.
e_msg_Package(Msg, TrUserData) ->
e_msg_Package(Msg, <<>>, TrUserData).
e_msg_Package(#{name := F1}, Bin, TrUserData) ->
begin
TrF1 = id(F1, TrUserData),
e_type_string(TrF1, <<Bin/binary, 10>>, TrUserData)
end.
e_mfield_Names_packages(Msg, Bin, TrUserData) ->
SubBin = e_msg_Package(Msg, <<>>, TrUserData),
Bin2 = e_varint(byte_size(SubBin), Bin),
<<Bin2/binary, SubBin/binary>>.
e_field_Names_packages([Elem | Rest], Bin,
TrUserData) ->
Bin2 = <<Bin/binary, 10>>,
Bin3 = e_mfield_Names_packages(id(Elem, TrUserData),
Bin2, TrUserData),
e_field_Names_packages(Rest, Bin3, TrUserData);
e_field_Names_packages([], Bin, _TrUserData) -> Bin.
-compile({nowarn_unused_function,e_type_sint/3}).
e_type_sint(Value, Bin, _TrUserData) when Value >= 0 ->
e_varint(Value * 2, Bin);
e_type_sint(Value, Bin, _TrUserData) ->
e_varint(Value * -2 - 1, Bin).
-compile({nowarn_unused_function,e_type_int32/3}).
e_type_int32(Value, Bin, _TrUserData)
when 0 =< Value, Value =< 127 ->
<<Bin/binary, Value>>;
e_type_int32(Value, Bin, _TrUserData) ->
<<N:64/unsigned-native>> = <<Value:64/signed-native>>,
e_varint(N, Bin).
-compile({nowarn_unused_function,e_type_int64/3}).
e_type_int64(Value, Bin, _TrUserData)
when 0 =< Value, Value =< 127 ->
<<Bin/binary, Value>>;
e_type_int64(Value, Bin, _TrUserData) ->
<<N:64/unsigned-native>> = <<Value:64/signed-native>>,
e_varint(N, Bin).
-compile({nowarn_unused_function,e_type_bool/3}).
e_type_bool(true, Bin, _TrUserData) ->
<<Bin/binary, 1>>;
e_type_bool(false, Bin, _TrUserData) ->
<<Bin/binary, 0>>;
e_type_bool(1, Bin, _TrUserData) -> <<Bin/binary, 1>>;
e_type_bool(0, Bin, _TrUserData) -> <<Bin/binary, 0>>.
-compile({nowarn_unused_function,e_type_string/3}).
e_type_string(S, Bin, _TrUserData) ->
Utf8 = unicode:characters_to_binary(S),
Bin2 = e_varint(byte_size(Utf8), Bin),
<<Bin2/binary, Utf8/binary>>.
-compile({nowarn_unused_function,e_type_bytes/3}).
e_type_bytes(Bytes, Bin, _TrUserData)
when is_binary(Bytes) ->
Bin2 = e_varint(byte_size(Bytes), Bin),
<<Bin2/binary, Bytes/binary>>;
e_type_bytes(Bytes, Bin, _TrUserData)
when is_list(Bytes) ->
BytesBin = iolist_to_binary(Bytes),
Bin2 = e_varint(byte_size(BytesBin), Bin),
<<Bin2/binary, BytesBin/binary>>.
-compile({nowarn_unused_function,e_type_fixed32/3}).
e_type_fixed32(Value, Bin, _TrUserData) ->
<<Bin/binary, Value:32/little>>.
-compile({nowarn_unused_function,e_type_sfixed32/3}).
e_type_sfixed32(Value, Bin, _TrUserData) ->
<<Bin/binary, Value:32/little-signed>>.
-compile({nowarn_unused_function,e_type_fixed64/3}).
e_type_fixed64(Value, Bin, _TrUserData) ->
<<Bin/binary, Value:64/little>>.
-compile({nowarn_unused_function,e_type_sfixed64/3}).
e_type_sfixed64(Value, Bin, _TrUserData) ->
<<Bin/binary, Value:64/little-signed>>.
-compile({nowarn_unused_function,e_type_float/3}).
e_type_float(V, Bin, _) when is_number(V) ->
<<Bin/binary, V:32/little-float>>;
e_type_float(infinity, Bin, _) ->
<<Bin/binary, 0:16, 128, 127>>;
e_type_float('-infinity', Bin, _) ->
<<Bin/binary, 0:16, 128, 255>>;
e_type_float(nan, Bin, _) ->
<<Bin/binary, 0:16, 192, 127>>.
-compile({nowarn_unused_function,e_type_double/3}).
e_type_double(V, Bin, _) when is_number(V) ->
<<Bin/binary, V:64/little-float>>;
e_type_double(infinity, Bin, _) ->
<<Bin/binary, 0:48, 240, 127>>;
e_type_double('-infinity', Bin, _) ->
<<Bin/binary, 0:48, 240, 255>>;
e_type_double(nan, Bin, _) ->
<<Bin/binary, 0:48, 248, 127>>.
-compile({nowarn_unused_function,e_varint/3}).
e_varint(N, Bin, _TrUserData) -> e_varint(N, Bin).
-compile({nowarn_unused_function,e_varint/2}).
e_varint(N, Bin) when N =< 127 -> <<Bin/binary, N>>;
e_varint(N, Bin) ->
Bin2 = <<Bin/binary, (N band 127 bor 128)>>,
e_varint(N bsr 7, Bin2).
decode_msg(Bin, MsgName) when is_binary(Bin) ->
decode_msg(Bin, MsgName, []).
decode_msg(Bin, MsgName, Opts) when is_binary(Bin) ->
TrUserData = proplists:get_value(user_data, Opts),
decode_msg_1_catch(Bin, MsgName, TrUserData).
-ifdef('OTP_RELEASE').
decode_msg_1_catch(Bin, MsgName, TrUserData) ->
try decode_msg_2_doit(MsgName, Bin, TrUserData)
catch Class:Reason:StackTrace -> error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}})
end.
-else.
-ifdef('GPB_PATTERN_STACK').
decode_msg_1_catch(Bin, MsgName, TrUserData) ->
try decode_msg_2_doit(MsgName, Bin, TrUserData)
catch Class:Reason:StackTrace -> error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}})
end.
-else.
decode_msg_1_catch(Bin, MsgName, TrUserData) ->
try decode_msg_2_doit(MsgName, Bin, TrUserData)
catch Class:Reason ->
StackTrace = erlang:get_stacktrace(),
error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}})
end.
-endif.
-endif.
decode_msg_2_doit('Names', Bin, TrUserData) ->
id(d_msg_Names(Bin, TrUserData), TrUserData);
decode_msg_2_doit('Package', Bin, TrUserData) ->
id(d_msg_Package(Bin, TrUserData), TrUserData).
d_msg_Names(Bin, TrUserData) ->
dfp_read_field_def_Names(Bin, 0, 0, id([], TrUserData),
id('$undef', TrUserData), TrUserData).
dfp_read_field_def_Names(<<10, Rest/binary>>, Z1, Z2,
F@_1, F@_2, TrUserData) ->
d_field_Names_packages(Rest, Z1, Z2, F@_1, F@_2,
TrUserData);
dfp_read_field_def_Names(<<18, Rest/binary>>, Z1, Z2,
F@_1, F@_2, TrUserData) ->
d_field_Names_repository(Rest, Z1, Z2, F@_1, F@_2,
TrUserData);
dfp_read_field_def_Names(<<>>, 0, 0, R1, F@_2,
TrUserData) ->
S1 = #{repository => F@_2},
if R1 == '$undef' -> S1;
true -> S1#{packages => lists_reverse(R1, TrUserData)}
end;
dfp_read_field_def_Names(Other, Z1, Z2, F@_1, F@_2,
TrUserData) ->
dg_read_field_def_Names(Other, Z1, Z2, F@_1, F@_2,
TrUserData).
dg_read_field_def_Names(<<1:1, X:7, Rest/binary>>, N,
Acc, F@_1, F@_2, TrUserData)
when N < 32 - 7 ->
dg_read_field_def_Names(Rest, N + 7, X bsl N + Acc,
F@_1, F@_2, TrUserData);
dg_read_field_def_Names(<<0:1, X:7, Rest/binary>>, N,
Acc, F@_1, F@_2, TrUserData) ->
Key = X bsl N + Acc,
case Key of
10 ->
d_field_Names_packages(Rest, 0, 0, F@_1, F@_2,
TrUserData);
18 ->
d_field_Names_repository(Rest, 0, 0, F@_1, F@_2,
TrUserData);
_ ->
case Key band 7 of
0 ->
skip_varint_Names(Rest, 0, 0, F@_1, F@_2, TrUserData);
1 -> skip_64_Names(Rest, 0, 0, F@_1, F@_2, TrUserData);
2 ->
skip_length_delimited_Names(Rest, 0, 0, F@_1, F@_2,
TrUserData);
3 ->
skip_group_Names(Rest, Key bsr 3, 0, F@_1, F@_2,
TrUserData);
5 -> skip_32_Names(Rest, 0, 0, F@_1, F@_2, TrUserData)
end
end;
dg_read_field_def_Names(<<>>, 0, 0, R1, F@_2,
TrUserData) ->
S1 = #{repository => F@_2},
if R1 == '$undef' -> S1;
true -> S1#{packages => lists_reverse(R1, TrUserData)}
end.
d_field_Names_packages(<<1:1, X:7, Rest/binary>>, N,
Acc, F@_1, F@_2, TrUserData)
when N < 57 ->
d_field_Names_packages(Rest, N + 7, X bsl N + Acc, F@_1,
F@_2, TrUserData);
d_field_Names_packages(<<0:1, X:7, Rest/binary>>, N,
Acc, Prev, F@_2, TrUserData) ->
{NewFValue, RestF} = begin
Len = X bsl N + Acc,
<<Bs:Len/binary, Rest2/binary>> = Rest,
{id(d_msg_Package(Bs, TrUserData), TrUserData),
Rest2}
end,
dfp_read_field_def_Names(RestF, 0, 0,
cons(NewFValue, Prev, TrUserData), F@_2,
TrUserData).
d_field_Names_repository(<<1:1, X:7, Rest/binary>>, N,
Acc, F@_1, F@_2, TrUserData)
when N < 57 ->
d_field_Names_repository(Rest, N + 7, X bsl N + Acc,
F@_1, F@_2, TrUserData);
d_field_Names_repository(<<0:1, X:7, Rest/binary>>, N,
Acc, F@_1, _, TrUserData) ->
{NewFValue, RestF} = begin
Len = X bsl N + Acc,
<<Bytes:Len/binary, Rest2/binary>> = Rest,
{id(binary:copy(Bytes), TrUserData), Rest2}
end,
dfp_read_field_def_Names(RestF, 0, 0, F@_1, NewFValue,
TrUserData).
skip_varint_Names(<<1:1, _:7, Rest/binary>>, Z1, Z2,
F@_1, F@_2, TrUserData) ->
skip_varint_Names(Rest, Z1, Z2, F@_1, F@_2, TrUserData);
skip_varint_Names(<<0:1, _:7, Rest/binary>>, Z1, Z2,
F@_1, F@_2, TrUserData) ->
dfp_read_field_def_Names(Rest, Z1, Z2, F@_1, F@_2,
TrUserData).
skip_length_delimited_Names(<<1:1, X:7, Rest/binary>>,
N, Acc, F@_1, F@_2, TrUserData)
when N < 57 ->
skip_length_delimited_Names(Rest, N + 7, X bsl N + Acc,
F@_1, F@_2, TrUserData);
skip_length_delimited_Names(<<0:1, X:7, Rest/binary>>,
N, Acc, F@_1, F@_2, TrUserData) ->
Length = X bsl N + Acc,
<<_:Length/binary, Rest2/binary>> = Rest,
dfp_read_field_def_Names(Rest2, 0, 0, F@_1, F@_2,
TrUserData).
skip_group_Names(Bin, FNum, Z2, F@_1, F@_2,
TrUserData) ->
{_, Rest} = read_group(Bin, FNum),
dfp_read_field_def_Names(Rest, 0, Z2, F@_1, F@_2,
TrUserData).
skip_32_Names(<<_:32, Rest/binary>>, Z1, Z2, F@_1, F@_2,
TrUserData) ->
dfp_read_field_def_Names(Rest, Z1, Z2, F@_1, F@_2,
TrUserData).
skip_64_Names(<<_:64, Rest/binary>>, Z1, Z2, F@_1, F@_2,
TrUserData) ->
dfp_read_field_def_Names(Rest, Z1, Z2, F@_1, F@_2,
TrUserData).
d_msg_Package(Bin, TrUserData) ->
dfp_read_field_def_Package(Bin, 0, 0,
id('$undef', TrUserData), TrUserData).
dfp_read_field_def_Package(<<10, Rest/binary>>, Z1, Z2,
F@_1, TrUserData) ->
d_field_Package_name(Rest, Z1, Z2, F@_1, TrUserData);
dfp_read_field_def_Package(<<>>, 0, 0, F@_1, _) ->
#{name => F@_1};
dfp_read_field_def_Package(Other, Z1, Z2, F@_1,
TrUserData) ->
dg_read_field_def_Package(Other, Z1, Z2, F@_1,
TrUserData).
dg_read_field_def_Package(<<1:1, X:7, Rest/binary>>, N,
Acc, F@_1, TrUserData)
when N < 32 - 7 ->
dg_read_field_def_Package(Rest, N + 7, X bsl N + Acc,
F@_1, TrUserData);
dg_read_field_def_Package(<<0:1, X:7, Rest/binary>>, N,
Acc, F@_1, TrUserData) ->
Key = X bsl N + Acc,
case Key of
10 ->
d_field_Package_name(Rest, 0, 0, F@_1, TrUserData);
_ ->
case Key band 7 of
0 -> skip_varint_Package(Rest, 0, 0, F@_1, TrUserData);
1 -> skip_64_Package(Rest, 0, 0, F@_1, TrUserData);
2 ->
skip_length_delimited_Package(Rest, 0, 0, F@_1,
TrUserData);
3 ->
skip_group_Package(Rest, Key bsr 3, 0, F@_1,
TrUserData);
5 -> skip_32_Package(Rest, 0, 0, F@_1, TrUserData)
end
end;
dg_read_field_def_Package(<<>>, 0, 0, F@_1, _) ->
#{name => F@_1}.
d_field_Package_name(<<1:1, X:7, Rest/binary>>, N, Acc,
F@_1, TrUserData)
when N < 57 ->
d_field_Package_name(Rest, N + 7, X bsl N + Acc, F@_1,
TrUserData);
d_field_Package_name(<<0:1, X:7, Rest/binary>>, N, Acc,
_, TrUserData) ->
{NewFValue, RestF} = begin
Len = X bsl N + Acc,
<<Bytes:Len/binary, Rest2/binary>> = Rest,
{id(binary:copy(Bytes), TrUserData), Rest2}
end,
dfp_read_field_def_Package(RestF, 0, 0, NewFValue,
TrUserData).
skip_varint_Package(<<1:1, _:7, Rest/binary>>, Z1, Z2,
F@_1, TrUserData) ->
skip_varint_Package(Rest, Z1, Z2, F@_1, TrUserData);
skip_varint_Package(<<0:1, _:7, Rest/binary>>, Z1, Z2,
F@_1, TrUserData) ->
dfp_read_field_def_Package(Rest, Z1, Z2, F@_1,
TrUserData).
skip_length_delimited_Package(<<1:1, X:7, Rest/binary>>,
N, Acc, F@_1, TrUserData)
when N < 57 ->
skip_length_delimited_Package(Rest, N + 7,
X bsl N + Acc, F@_1, TrUserData);
skip_length_delimited_Package(<<0:1, X:7, Rest/binary>>,
N, Acc, F@_1, TrUserData) ->
Length = X bsl N + Acc,
<<_:Length/binary, Rest2/binary>> = Rest,
dfp_read_field_def_Package(Rest2, 0, 0, F@_1,
TrUserData).
skip_group_Package(Bin, FNum, Z2, F@_1, TrUserData) ->
{_, Rest} = read_group(Bin, FNum),
dfp_read_field_def_Package(Rest, 0, Z2, F@_1,
TrUserData).
skip_32_Package(<<_:32, Rest/binary>>, Z1, Z2, F@_1,
TrUserData) ->
dfp_read_field_def_Package(Rest, Z1, Z2, F@_1,
TrUserData).
skip_64_Package(<<_:64, Rest/binary>>, Z1, Z2, F@_1,
TrUserData) ->
dfp_read_field_def_Package(Rest, Z1, Z2, F@_1,
TrUserData).
read_group(Bin, FieldNum) ->
{NumBytes, EndTagLen} = read_gr_b(Bin, 0, 0, 0, 0, FieldNum),
<<Group:NumBytes/binary, _:EndTagLen/binary, Rest/binary>> = Bin,
{Group, Rest}.
%% Like skipping over fields, but record the total length,
%% Each field is <(FieldNum bsl 3) bor FieldType> ++ <FieldValue>
%% Record the length because varints may be non-optimally encoded.
%%
%% Groups can be nested, but assume the same FieldNum cannot be nested
%% because group field numbers are shared with the rest of the fields
%% numbers. Thus we can search just for an group-end with the same
%% field number.
%%
%% (The only time the same group field number could occur would
%% be in a nested sub message, but then it would be inside a
%% length-delimited entry, which we skip-read by length.)
read_gr_b(<<1:1, X:7, Tl/binary>>, N, Acc, NumBytes, TagLen, FieldNum)
when N < (32-7) ->
read_gr_b(Tl, N+7, X bsl N + Acc, NumBytes, TagLen+1, FieldNum);
read_gr_b(<<0:1, X:7, Tl/binary>>, N, Acc, NumBytes, TagLen,
FieldNum) ->
Key = X bsl N + Acc,
TagLen1 = TagLen + 1,
case {Key bsr 3, Key band 7} of
{FieldNum, 4} -> % 4 = group_end
{NumBytes, TagLen1};
{_, 0} -> % 0 = varint
read_gr_vi(Tl, 0, NumBytes + TagLen1, FieldNum);
{_, 1} -> % 1 = bits64
<<_:64, Tl2/binary>> = Tl,
read_gr_b(Tl2, 0, 0, NumBytes + TagLen1 + 8, 0, FieldNum);
{_, 2} -> % 2 = length_delimited
read_gr_ld(Tl, 0, 0, NumBytes + TagLen1, FieldNum);
{_, 3} -> % 3 = group_start
read_gr_b(Tl, 0, 0, NumBytes + TagLen1, 0, FieldNum);
{_, 4} -> % 4 = group_end
read_gr_b(Tl, 0, 0, NumBytes + TagLen1, 0, FieldNum);
{_, 5} -> % 5 = bits32
<<_:32, Tl2/binary>> = Tl,
read_gr_b(Tl2, 0, 0, NumBytes + TagLen1 + 4, 0, FieldNum)
end.
read_gr_vi(<<1:1, _:7, Tl/binary>>, N, NumBytes, FieldNum)
when N < (64-7) ->
read_gr_vi(Tl, N+7, NumBytes+1, FieldNum);
read_gr_vi(<<0:1, _:7, Tl/binary>>, _, NumBytes, FieldNum) ->
read_gr_b(Tl, 0, 0, NumBytes+1, 0, FieldNum).
read_gr_ld(<<1:1, X:7, Tl/binary>>, N, Acc, NumBytes, FieldNum)
when N < (64-7) ->
read_gr_ld(Tl, N+7, X bsl N + Acc, NumBytes+1, FieldNum);
read_gr_ld(<<0:1, X:7, Tl/binary>>, N, Acc, NumBytes, FieldNum) ->
Len = X bsl N + Acc,
NumBytes1 = NumBytes + 1,
<<_:Len/binary, Tl2/binary>> = Tl,
read_gr_b(Tl2, 0, 0, NumBytes1 + Len, 0, FieldNum).
merge_msgs(Prev, New, MsgName) when is_atom(MsgName) ->
merge_msgs(Prev, New, MsgName, []).
merge_msgs(Prev, New, MsgName, Opts) ->
TrUserData = proplists:get_value(user_data, Opts),
case MsgName of
'Names' -> merge_msg_Names(Prev, New, TrUserData);
'Package' -> merge_msg_Package(Prev, New, TrUserData)
end.
-compile({nowarn_unused_function,merge_msg_Names/3}).
merge_msg_Names(#{} = PMsg,
#{repository := NFrepository} = NMsg, TrUserData) ->
S1 = #{repository => NFrepository},
case {PMsg, NMsg} of
{#{packages := PFpackages},
#{packages := NFpackages}} ->
S1#{packages =>
'erlang_++'(PFpackages, NFpackages, TrUserData)};
{_, #{packages := NFpackages}} ->
S1#{packages => NFpackages};
{#{packages := PFpackages}, _} ->
S1#{packages => PFpackages};
{_, _} -> S1
end.
-compile({nowarn_unused_function,merge_msg_Package/3}).
merge_msg_Package(#{}, #{name := NFname}, _) ->
#{name => NFname}.
verify_msg(Msg, MsgName) when is_atom(MsgName) ->
verify_msg(Msg, MsgName, []).
verify_msg(Msg, MsgName, Opts) ->
TrUserData = proplists:get_value(user_data, Opts),
case MsgName of
'Names' -> v_msg_Names(Msg, [MsgName], TrUserData);
'Package' -> v_msg_Package(Msg, [MsgName], TrUserData);
_ -> mk_type_error(not_a_known_message, Msg, [])
end.
-compile({nowarn_unused_function,v_msg_Names/3}).
v_msg_Names(#{repository := F2} = M, Path,
TrUserData) ->
case M of
#{packages := F1} ->
if is_list(F1) ->
_ = [v_msg_Package(Elem, [packages | Path], TrUserData)
|| Elem <- F1],
ok;
true ->
mk_type_error({invalid_list_of, {msg, 'Package'}}, F1,
[packages | Path])
end;
_ -> ok
end,
v_type_string(F2, [repository | Path], TrUserData),
lists:foreach(fun (packages) -> ok;
(repository) -> ok;
(OtherKey) ->
mk_type_error({extraneous_key, OtherKey}, M, Path)
end,
maps:keys(M)),
ok;
v_msg_Names(M, Path, _TrUserData) when is_map(M) ->
mk_type_error({missing_fields,
[repository] -- maps:keys(M), 'Names'},
M, Path);
v_msg_Names(X, Path, _TrUserData) ->
mk_type_error({expected_msg, 'Names'}, X, Path).
-compile({nowarn_unused_function,v_msg_Package/3}).
v_msg_Package(#{name := F1} = M, Path, TrUserData) ->
v_type_string(F1, [name | Path], TrUserData),
lists:foreach(fun (name) -> ok;
(OtherKey) ->
mk_type_error({extraneous_key, OtherKey}, M, Path)
end,
maps:keys(M)),
ok;
v_msg_Package(M, Path, _TrUserData) when is_map(M) ->
mk_type_error({missing_fields, [name] -- maps:keys(M),
'Package'},
M, Path);
v_msg_Package(X, Path, _TrUserData) ->
mk_type_error({expected_msg, 'Package'}, X, Path).
-compile({nowarn_unused_function,v_type_string/3}).
v_type_string(S, Path, _TrUserData)
when is_list(S); is_binary(S) ->
try unicode:characters_to_binary(S) of
B when is_binary(B) -> ok;
{error, _, _} ->
mk_type_error(bad_unicode_string, S, Path)
catch
error:badarg ->
mk_type_error(bad_unicode_string, S, Path)
end;
v_type_string(X, Path, _TrUserData) ->
mk_type_error(bad_unicode_string, X, Path).
-compile({nowarn_unused_function,mk_type_error/3}).
-spec mk_type_error(_, _, list()) -> no_return().
mk_type_error(Error, ValueSeen, Path) ->
Path2 = prettify_path(Path),
erlang:error({gpb_type_error,
{Error, [{value, ValueSeen}, {path, Path2}]}}).
-compile({nowarn_unused_function,prettify_path/1}).
prettify_path([]) -> top_level;
prettify_path(PathR) ->
list_to_atom(string:join(lists:map(fun atom_to_list/1,
lists:reverse(PathR)),
".")).
-compile({nowarn_unused_function,id/2}).
-compile({inline,id/2}).
id(X, _TrUserData) -> X.
-compile({nowarn_unused_function,v_ok/3}).
-compile({inline,v_ok/3}).
v_ok(_Value, _Path, _TrUserData) -> ok.
-compile({nowarn_unused_function,m_overwrite/3}).
-compile({inline,m_overwrite/3}).
m_overwrite(_Prev, New, _TrUserData) -> New.
-compile({nowarn_unused_function,cons/3}).
-compile({inline,cons/3}).
cons(Elem, Acc, _TrUserData) -> [Elem | Acc].
-compile({nowarn_unused_function,lists_reverse/2}).
-compile({inline,lists_reverse/2}).
'lists_reverse'(L, _TrUserData) -> lists:reverse(L).
-compile({nowarn_unused_function,'erlang_++'/3}).
-compile({inline,'erlang_++'/3}).
'erlang_++'(A, B, _TrUserData) -> A ++ B.
get_msg_defs() ->
[{{msg, 'Names'},
[#{name => packages, fnum => 1, rnum => 2,
type => {msg, 'Package'}, occurrence => repeated,
opts => []},
#{name => repository, fnum => 2, rnum => 3,
type => string, occurrence => required, opts => []}]},
{{msg, 'Package'},
[#{name => name, fnum => 1, rnum => 2, type => string,
occurrence => required, opts => []}]}].
get_msg_names() -> ['Names', 'Package'].
get_group_names() -> [].
get_msg_or_group_names() -> ['Names', 'Package'].
get_enum_names() -> [].
fetch_msg_def(MsgName) ->
case find_msg_def(MsgName) of
Fs when is_list(Fs) -> Fs;
error -> erlang:error({no_such_msg, MsgName})
end.
-spec fetch_enum_def(_) -> no_return().
fetch_enum_def(EnumName) ->
erlang:error({no_such_enum, EnumName}).
find_msg_def('Names') ->
[#{name => packages, fnum => 1, rnum => 2,
type => {msg, 'Package'}, occurrence => repeated,
opts => []},
#{name => repository, fnum => 2, rnum => 3,
type => string, occurrence => required, opts => []}];
find_msg_def('Package') ->
[#{name => name, fnum => 1, rnum => 2, type => string,
occurrence => required, opts => []}];
find_msg_def(_) -> error.
find_enum_def(_) -> error.
-spec enum_symbol_by_value(_, _) -> no_return().
enum_symbol_by_value(E, V) ->
erlang:error({no_enum_defs, E, V}).
-spec enum_value_by_symbol(_, _) -> no_return().
enum_value_by_symbol(E, V) ->
erlang:error({no_enum_defs, E, V}).
get_service_names() -> [].
get_service_def(_) -> error.
get_rpc_names(_) -> error.
find_rpc_def(_, _) -> error.
-spec fetch_rpc_def(_, _) -> no_return().
fetch_rpc_def(ServiceName, RpcName) ->
erlang:error({no_such_rpc, ServiceName, RpcName}).
get_package_name() -> undefined.
gpb_version_as_string() ->
"4.3.1".
gpb_version_as_list() ->
[4,3,1].

+ 1699
- 0
src/r3_hex_pb_package.erl
File diff suppressed because it is too large
View File


+ 564
- 0
src/r3_hex_pb_signed.erl View File

@ -0,0 +1,564 @@
%% Vendored from hex_core v0.5.0, do not edit manually
%% -*- coding: utf-8 -*-
%% Automatically generated, do not edit
%% Generated by gpb_compile version 4.3.1
-module(r3_hex_pb_signed).
-export([encode_msg/2, encode_msg/3]).
-export([decode_msg/2, decode_msg/3]).
-export([merge_msgs/3, merge_msgs/4]).
-export([verify_msg/2, verify_msg/3]).
-export([get_msg_defs/0]).
-export([get_msg_names/0]).
-export([get_group_names/0]).
-export([get_msg_or_group_names/0]).
-export([get_enum_names/0]).
-export([find_msg_def/1, fetch_msg_def/1]).
-export([find_enum_def/1, fetch_enum_def/1]).
-export([enum_symbol_by_value/2, enum_value_by_symbol/2]).
-export([get_service_names/0]).
-export([get_service_def/1]).
-export([get_rpc_names/1]).
-export([find_rpc_def/2, fetch_rpc_def/2]).
-export([get_package_name/0]).
-export([gpb_version_as_string/0, gpb_version_as_list/0]).
%% enumerated types
-export_type([]).
%% message types
-type 'Signed'() ::
#{payload => iodata() % = 1
%% signature => iodata() % = 2
}.
-export_type(['Signed'/0]).
-spec encode_msg('Signed'(), atom()) -> binary().
encode_msg(Msg, MsgName) when is_atom(MsgName) ->
encode_msg(Msg, MsgName, []).
-spec encode_msg('Signed'(), atom(), list()) -> binary().
encode_msg(Msg, MsgName, Opts) ->
verify_msg(Msg, MsgName, Opts),
TrUserData = proplists:get_value(user_data, Opts),
case MsgName of
'Signed' ->
e_msg_Signed(id(Msg, TrUserData), TrUserData)
end.
e_msg_Signed(Msg, TrUserData) ->
e_msg_Signed(Msg, <<>>, TrUserData).
e_msg_Signed(#{payload := F1} = M, Bin, TrUserData) ->
B1 = begin
TrF1 = id(F1, TrUserData),
e_type_bytes(TrF1, <<Bin/binary, 10>>, TrUserData)
end,
case M of
#{signature := F2} ->
begin
TrF2 = id(F2, TrUserData),
e_type_bytes(TrF2, <<B1/binary, 18>>, TrUserData)
end;
_ -> B1
end.
-compile({nowarn_unused_function,e_type_sint/3}).
e_type_sint(Value, Bin, _TrUserData) when Value >= 0 ->
e_varint(Value * 2, Bin);
e_type_sint(Value, Bin, _TrUserData) ->
e_varint(Value * -2 - 1, Bin).
-compile({nowarn_unused_function,e_type_int32/3}).
e_type_int32(Value, Bin, _TrUserData)
when 0 =< Value, Value =< 127 ->
<<Bin/binary, Value>>;
e_type_int32(Value, Bin, _TrUserData) ->
<<N:64/unsigned-native>> = <<Value:64/signed-native>>,
e_varint(N, Bin).
-compile({nowarn_unused_function,e_type_int64/3}).
e_type_int64(Value, Bin, _TrUserData)
when 0 =< Value, Value =< 127 ->
<<Bin/binary, Value>>;
e_type_int64(Value, Bin, _TrUserData) ->
<<N:64/unsigned-native>> = <<Value:64/signed-native>>,
e_varint(N, Bin).
-compile({nowarn_unused_function,e_type_bool/3}).
e_type_bool(true, Bin, _TrUserData) ->
<<Bin/binary, 1>>;
e_type_bool(false, Bin, _TrUserData) ->
<<Bin/binary, 0>>;
e_type_bool(1, Bin, _TrUserData) -> <<Bin/binary, 1>>;
e_type_bool(0, Bin, _TrUserData) -> <<Bin/binary, 0>>.
-compile({nowarn_unused_function,e_type_string/3}).
e_type_string(S, Bin, _TrUserData) ->
Utf8 = unicode:characters_to_binary(S),
Bin2 = e_varint(byte_size(Utf8), Bin),
<<Bin2/binary, Utf8/binary>>.
-compile({nowarn_unused_function,e_type_bytes/3}).
e_type_bytes(Bytes, Bin, _TrUserData)
when is_binary(Bytes) ->
Bin2 = e_varint(byte_size(Bytes), Bin),
<<Bin2/binary, Bytes/binary>>;
e_type_bytes(Bytes, Bin, _TrUserData)
when is_list(Bytes) ->
BytesBin = iolist_to_binary(Bytes),
Bin2 = e_varint(byte_size(BytesBin), Bin),
<<Bin2/binary, BytesBin/binary>>.
-compile({nowarn_unused_function,e_type_fixed32/3}).
e_type_fixed32(Value, Bin, _TrUserData) ->
<<Bin/binary, Value:32/little>>.
-compile({nowarn_unused_function,e_type_sfixed32/3}).
e_type_sfixed32(Value, Bin, _TrUserData) ->
<<Bin/binary, Value:32/little-signed>>.
-compile({nowarn_unused_function,e_type_fixed64/3}).
e_type_fixed64(Value, Bin, _TrUserData) ->
<<Bin/binary, Value:64/little>>.
-compile({nowarn_unused_function,e_type_sfixed64/3}).
e_type_sfixed64(Value, Bin, _TrUserData) ->
<<Bin/binary, Value:64/little-signed>>.
-compile({nowarn_unused_function,e_type_float/3}).
e_type_float(V, Bin, _) when is_number(V) ->
<<Bin/binary, V:32/little-float>>;
e_type_float(infinity, Bin, _) ->
<<Bin/binary, 0:16, 128, 127>>;
e_type_float('-infinity', Bin, _) ->
<<Bin/binary, 0:16, 128, 255>>;
e_type_float(nan, Bin, _) ->
<<Bin/binary, 0:16, 192, 127>>.
-compile({nowarn_unused_function,e_type_double/3}).
e_type_double(V, Bin, _) when is_number(V) ->
<<Bin/binary, V:64/little-float>>;
e_type_double(infinity, Bin, _) ->
<<Bin/binary, 0:48, 240, 127>>;
e_type_double('-infinity', Bin, _) ->
<<Bin/binary, 0:48, 240, 255>>;
e_type_double(nan, Bin, _) ->
<<Bin/binary, 0:48, 248, 127>>.
-compile({nowarn_unused_function,e_varint/3}).
e_varint(N, Bin, _TrUserData) -> e_varint(N, Bin).
-compile({nowarn_unused_function,e_varint/2}).
e_varint(N, Bin) when N =< 127 -> <<Bin/binary, N>>;
e_varint(N, Bin) ->
Bin2 = <<Bin/binary, (N band 127 bor 128)>>,
e_varint(N bsr 7, Bin2).
decode_msg(Bin, MsgName) when is_binary(Bin) ->
decode_msg(Bin, MsgName, []).
decode_msg(Bin, MsgName, Opts) when is_binary(Bin) ->
TrUserData = proplists:get_value(user_data, Opts),
decode_msg_1_catch(Bin, MsgName, TrUserData).
-ifdef('OTP_RELEASE').
decode_msg_1_catch(Bin, MsgName, TrUserData) ->
try decode_msg_2_doit(MsgName, Bin, TrUserData)
catch Class:Reason:StackTrace -> error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}})
end.
-else.
-ifdef('GPB_PATTERN_STACK').
decode_msg_1_catch(Bin, MsgName, TrUserData) ->
try decode_msg_2_doit(MsgName, Bin, TrUserData)
catch Class:Reason:StackTrace -> error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}})
end.
-else.
decode_msg_1_catch(Bin, MsgName, TrUserData) ->
try decode_msg_2_doit(MsgName, Bin, TrUserData)
catch Class:Reason ->
StackTrace = erlang:get_stacktrace(),
error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}})
end.
-endif.
-endif.
decode_msg_2_doit('Signed', Bin, TrUserData) ->
id(d_msg_Signed(Bin, TrUserData), TrUserData).
d_msg_Signed(Bin, TrUserData) ->
dfp_read_field_def_Signed(Bin, 0, 0,
id('$undef', TrUserData),
id('$undef', TrUserData), TrUserData).
dfp_read_field_def_Signed(<<10, Rest/binary>>, Z1, Z2,
F@_1, F@_2, TrUserData) ->
d_field_Signed_payload(Rest, Z1, Z2, F@_1, F@_2,
TrUserData);
dfp_read_field_def_Signed(<<18, Rest/binary>>, Z1, Z2,
F@_1, F@_2, TrUserData) ->
d_field_Signed_signature(Rest, Z1, Z2, F@_1, F@_2,
TrUserData);
dfp_read_field_def_Signed(<<>>, 0, 0, F@_1, F@_2, _) ->
S1 = #{payload => F@_1},
if F@_2 == '$undef' -> S1;
true -> S1#{signature => F@_2}
end;
dfp_read_field_def_Signed(Other, Z1, Z2, F@_1, F@_2,
TrUserData) ->
dg_read_field_def_Signed(Other, Z1, Z2, F@_1, F@_2,
TrUserData).
dg_read_field_def_Signed(<<1:1, X:7, Rest/binary>>, N,
Acc, F@_1, F@_2, TrUserData)
when N < 32 - 7 ->
dg_read_field_def_Signed(Rest, N + 7, X bsl N + Acc,
F@_1, F@_2, TrUserData);
dg_read_field_def_Signed(<<0:1, X:7, Rest/binary>>, N,
Acc, F@_1, F@_2, TrUserData) ->
Key = X bsl N + Acc,
case Key of
10 ->
d_field_Signed_payload(Rest, 0, 0, F@_1, F@_2,
TrUserData);
18 ->
d_field_Signed_signature(Rest, 0, 0, F@_1, F@_2,
TrUserData);
_ ->
case Key band 7 of
0 ->
skip_varint_Signed(Rest, 0, 0, F@_1, F@_2, TrUserData);
1 -> skip_64_Signed(Rest, 0, 0, F@_1, F@_2, TrUserData);
2 ->
skip_length_delimited_Signed(Rest, 0, 0, F@_1, F@_2,
TrUserData);
3 ->
skip_group_Signed(Rest, Key bsr 3, 0, F@_1, F@_2,
TrUserData);
5 -> skip_32_Signed(Rest, 0, 0, F@_1, F@_2, TrUserData)
end
end;
dg_read_field_def_Signed(<<>>, 0, 0, F@_1, F@_2, _) ->
S1 = #{payload => F@_1},
if F@_2 == '$undef' -> S1;
true -> S1#{signature => F@_2}
end.
d_field_Signed_payload(<<1:1, X:7, Rest/binary>>, N,
Acc, F@_1, F@_2, TrUserData)
when N < 57 ->
d_field_Signed_payload(Rest, N + 7, X bsl N + Acc, F@_1,
F@_2, TrUserData);
d_field_Signed_payload(<<0:1, X:7, Rest/binary>>, N,
Acc, _, F@_2, TrUserData) ->
{NewFValue, RestF} = begin
Len = X bsl N + Acc,
<<Bytes:Len/binary, Rest2/binary>> = Rest,
{id(binary:copy(Bytes), TrUserData), Rest2}
end,
dfp_read_field_def_Signed(RestF, 0, 0, NewFValue, F@_2,
TrUserData).
d_field_Signed_signature(<<1:1, X:7, Rest/binary>>, N,
Acc, F@_1, F@_2, TrUserData)
when N < 57 ->
d_field_Signed_signature(Rest, N + 7, X bsl N + Acc,
F@_1, F@_2, TrUserData);
d_field_Signed_signature(<<0:1, X:7, Rest/binary>>, N,
Acc, F@_1, _, TrUserData) ->
{NewFValue, RestF} = begin
Len = X bsl N + Acc,
<<Bytes:Len/binary, Rest2/binary>> = Rest,
{id(binary:copy(Bytes), TrUserData), Rest2}
end,
dfp_read_field_def_Signed(RestF, 0, 0, F@_1, NewFValue,
TrUserData).
skip_varint_Signed(<<1:1, _:7, Rest/binary>>, Z1, Z2,
F@_1, F@_2, TrUserData) ->
skip_varint_Signed(Rest, Z1, Z2, F@_1, F@_2,
TrUserData);
skip_varint_Signed(<<0:1, _:7, Rest/binary>>, Z1, Z2,
F@_1, F@_2, TrUserData) ->
dfp_read_field_def_Signed(Rest, Z1, Z2, F@_1, F@_2,
TrUserData).
skip_length_delimited_Signed(<<1:1, X:7, Rest/binary>>,
N, Acc, F@_1, F@_2, TrUserData)
when N < 57 ->
skip_length_delimited_Signed(Rest, N + 7, X bsl N + Acc,
F@_1, F@_2, TrUserData);
skip_length_delimited_Signed(<<0:1, X:7, Rest/binary>>,
N, Acc, F@_1, F@_2, TrUserData) ->
Length = X bsl N + Acc,
<<_:Length/binary, Rest2/binary>> = Rest,
dfp_read_field_def_Signed(Rest2, 0, 0, F@_1, F@_2,
TrUserData).
skip_group_Signed(Bin, FNum, Z2, F@_1, F@_2,
TrUserData) ->
{_, Rest} = read_group(Bin, FNum),
dfp_read_field_def_Signed(Rest, 0, Z2, F@_1, F@_2,
TrUserData).
skip_32_Signed(<<_:32, Rest/binary>>, Z1, Z2, F@_1,
F@_2, TrUserData) ->
dfp_read_field_def_Signed(Rest, Z1, Z2, F@_1, F@_2,
TrUserData).
skip_64_Signed(<<_:64, Rest/binary>>, Z1, Z2, F@_1,
F@_2, TrUserData) ->
dfp_read_field_def_Signed(Rest, Z1, Z2, F@_1, F@_2,
TrUserData).
read_group(Bin, FieldNum) ->
{NumBytes, EndTagLen} = read_gr_b(Bin, 0, 0, 0, 0, FieldNum),
<<Group:NumBytes/binary, _:EndTagLen/binary, Rest/binary>> = Bin,
{Group, Rest}.
%% Like skipping over fields, but record the total length,
%% Each field is <(FieldNum bsl 3) bor FieldType> ++ <FieldValue>
%% Record the length because varints may be non-optimally encoded.
%%
%% Groups can be nested, but assume the same FieldNum cannot be nested
%% because group field numbers are shared with the rest of the fields
%% numbers. Thus we can search just for an group-end with the same
%% field number.
%%
%% (The only time the same group field number could occur would
%% be in a nested sub message, but then it would be inside a
%% length-delimited entry, which we skip-read by length.)
read_gr_b(<<1:1, X:7, Tl/binary>>, N, Acc, NumBytes, TagLen, FieldNum)
when N < (32-7) ->
read_gr_b(Tl, N+7, X bsl N + Acc, NumBytes, TagLen+1, FieldNum);
read_gr_b(<<0:1, X:7, Tl/binary>>, N, Acc, NumBytes, TagLen,
FieldNum) ->
Key = X bsl N + Acc,
TagLen1 = TagLen + 1,
case {Key bsr 3, Key band 7} of
{FieldNum, 4} -> % 4 = group_end
{NumBytes, TagLen1};
{_, 0} -> % 0 = varint
read_gr_vi(Tl, 0, NumBytes + TagLen1, FieldNum);
{_, 1} -> % 1 = bits64
<<_:64, Tl2/binary>> = Tl,
read_gr_b(Tl2, 0, 0, NumBytes + TagLen1 + 8, 0, FieldNum);
{_, 2} -> % 2 = length_delimited
read_gr_ld(Tl, 0, 0, NumBytes + TagLen1, FieldNum);
{_, 3} -> % 3 = group_start
read_gr_b(Tl, 0, 0, NumBytes + TagLen1, 0, FieldNum);
{_, 4} -> % 4 = group_end
read_gr_b(Tl, 0, 0, NumBytes + TagLen1, 0, FieldNum);
{_, 5} -> % 5 = bits32
<<_:32, Tl2/binary>> = Tl,
read_gr_b(Tl2, 0, 0, NumBytes + TagLen1 + 4, 0, FieldNum)
end.
read_gr_vi(<<1:1, _:7, Tl/binary>>, N, NumBytes, FieldNum)
when N < (64-7) ->
read_gr_vi(Tl, N+7, NumBytes+1, FieldNum);
read_gr_vi(<<0:1, _:7, Tl/binary>>, _, NumBytes, FieldNum) ->
read_gr_b(Tl, 0, 0, NumBytes+1, 0, FieldNum).
read_gr_ld(<<1:1, X:7, Tl/binary>>, N, Acc, NumBytes, FieldNum)
when N < (64-7) ->
read_gr_ld(Tl, N+7, X bsl N + Acc, NumBytes+1, FieldNum);
read_gr_ld(<<0:1, X:7, Tl/binary>>, N, Acc, NumBytes, FieldNum) ->
Len = X bsl N + Acc,
NumBytes1 = NumBytes + 1,
<<_:Len/binary, Tl2/binary>> = Tl,
read_gr_b(Tl2, 0, 0, NumBytes1 + Len, 0, FieldNum).
merge_msgs(Prev, New, MsgName) when is_atom(MsgName) ->
merge_msgs(Prev, New, MsgName, []).
merge_msgs(Prev, New, MsgName, Opts) ->
TrUserData = proplists:get_value(user_data, Opts),
case MsgName of
'Signed' -> merge_msg_Signed(Prev, New, TrUserData)
end.
-compile({nowarn_unused_function,merge_msg_Signed/3}).
merge_msg_Signed(#{} = PMsg,
#{payload := NFpayload} = NMsg, _) ->
S1 = #{payload => NFpayload},
case {PMsg, NMsg} of
{_, #{signature := NFsignature}} ->
S1#{signature => NFsignature};
{#{signature := PFsignature}, _} ->
S1#{signature => PFsignature};
_ -> S1
end.
verify_msg(Msg, MsgName) when is_atom(MsgName) ->
verify_msg(Msg, MsgName, []).
verify_msg(Msg, MsgName, Opts) ->
TrUserData = proplists:get_value(user_data, Opts),
case MsgName of
'Signed' -> v_msg_Signed(Msg, [MsgName], TrUserData);
_ -> mk_type_error(not_a_known_message, Msg, [])
end.
-compile({nowarn_unused_function,v_msg_Signed/3}).
v_msg_Signed(#{payload := F1} = M, Path, TrUserData) ->
v_type_bytes(F1, [payload | Path], TrUserData),
case M of
#{signature := F2} ->
v_type_bytes(F2, [signature | Path], TrUserData);
_ -> ok
end,
lists:foreach(fun (payload) -> ok;
(signature) -> ok;
(OtherKey) ->
mk_type_error({extraneous_key, OtherKey}, M, Path)
end,
maps:keys(M)),
ok;
v_msg_Signed(M, Path, _TrUserData) when is_map(M) ->
mk_type_error({missing_fields,
[payload] -- maps:keys(M), 'Signed'},
M, Path);
v_msg_Signed(X, Path, _TrUserData) ->
mk_type_error({expected_msg, 'Signed'}, X, Path).
-compile({nowarn_unused_function,v_type_bytes/3}).
v_type_bytes(B, _Path, _TrUserData) when is_binary(B) ->
ok;
v_type_bytes(B, _Path, _TrUserData) when is_list(B) ->
ok;
v_type_bytes(X, Path, _TrUserData) ->
mk_type_error(bad_binary_value, X, Path).
-compile({nowarn_unused_function,mk_type_error/3}).
-spec mk_type_error(_, _, list()) -> no_return().
mk_type_error(Error, ValueSeen, Path) ->
Path2 = prettify_path(Path),
erlang:error({gpb_type_error,
{Error, [{value, ValueSeen}, {path, Path2}]}}).
-compile({nowarn_unused_function,prettify_path/1}).
prettify_path([]) -> top_level;
prettify_path(PathR) ->
list_to_atom(string:join(lists:map(fun atom_to_list/1,
lists:reverse(PathR)),
".")).
-compile({nowarn_unused_function,id/2}).
-compile({inline,id/2}).
id(X, _TrUserData) -> X.
-compile({nowarn_unused_function,v_ok/3}).
-compile({inline,v_ok/3}).
v_ok(_Value, _Path, _TrUserData) -> ok.
-compile({nowarn_unused_function,m_overwrite/3}).
-compile({inline,m_overwrite/3}).
m_overwrite(_Prev, New, _TrUserData) -> New.
-compile({nowarn_unused_function,cons/3}).
-compile({inline,cons/3}).
cons(Elem, Acc, _TrUserData) -> [Elem | Acc].
-compile({nowarn_unused_function,lists_reverse/2}).
-compile({inline,lists_reverse/2}).
'lists_reverse'(L, _TrUserData) -> lists:reverse(L).
-compile({nowarn_unused_function,'erlang_++'/3}).
-compile({inline,'erlang_++'/3}).
'erlang_++'(A, B, _TrUserData) -> A ++ B.
get_msg_defs() ->
[{{msg, 'Signed'},
[#{name => payload, fnum => 1, rnum => 2, type => bytes,
occurrence => required, opts => []},
#{name => signature, fnum => 2, rnum => 3,
type => bytes, occurrence => optional, opts => []}]}].
get_msg_names() -> ['Signed'].
get_group_names() -> [].
get_msg_or_group_names() -> ['Signed'].
get_enum_names() -> [].
fetch_msg_def(MsgName) ->
case find_msg_def(MsgName) of
Fs when is_list(Fs) -> Fs;
error -> erlang:error({no_such_msg, MsgName})
end.
-spec fetch_enum_def(_) -> no_return().
fetch_enum_def(EnumName) ->
erlang:error({no_such_enum, EnumName}).
find_msg_def('Signed') ->
[#{name => payload, fnum => 1, rnum => 2, type => bytes,
occurrence => required, opts => []},
#{name => signature, fnum => 2, rnum => 3,
type => bytes, occurrence => optional, opts => []}];
find_msg_def(_) -> error.
find_enum_def(_) -> error.
-spec enum_symbol_by_value(_, _) -> no_return().
enum_symbol_by_value(E, V) ->
erlang:error({no_enum_defs, E, V}).
-spec enum_value_by_symbol(_, _) -> no_return().
enum_value_by_symbol(E, V) ->
erlang:error({no_enum_defs, E, V}).
get_service_names() -> [].
get_service_def(_) -> error.
get_rpc_names(_) -> error.
find_rpc_def(_, _) -> error.
-spec fetch_rpc_def(_, _) -> no_return().
fetch_rpc_def(ServiceName, RpcName) ->
erlang:error({no_such_rpc, ServiceName, RpcName}).
get_package_name() -> undefined.
gpb_version_as_string() ->
"4.3.1".
gpb_version_as_list() ->
[4,3,1].

+ 958
- 0
src/r3_hex_pb_versions.erl View File

@ -0,0 +1,958 @@
%% Vendored from hex_core v0.5.0, do not edit manually
%% -*- coding: utf-8 -*-
%% Automatically generated, do not edit
%% Generated by gpb_compile version 4.3.1
-module(r3_hex_pb_versions).
-export([encode_msg/2, encode_msg/3]).
-export([decode_msg/2, decode_msg/3]).
-export([merge_msgs/3, merge_msgs/4]).
-export([verify_msg/2, verify_msg/3]).
-export([get_msg_defs/0]).
-export([get_msg_names/0]).
-export([get_group_names/0]).
-export([get_msg_or_group_names/0]).
-export([get_enum_names/0]).
-export([find_msg_def/1, fetch_msg_def/1]).
-export([find_enum_def/1, fetch_enum_def/1]).
-export([enum_symbol_by_value/2, enum_value_by_symbol/2]).
-export([get_service_names/0]).
-export([get_service_def/1]).
-export([get_rpc_names/1]).
-export([find_rpc_def/2, fetch_rpc_def/2]).
-export([get_package_name/0]).
-export([gpb_version_as_string/0, gpb_version_as_list/0]).
%% enumerated types
-export_type([]).
%% message types
-type 'Versions'() ::
#{packages => ['Package'()], % = 1
repository => iodata() % = 2
}.
-type 'Package'() ::
#{name => iodata(), % = 1
versions => [iodata()], % = 2
retired => [integer()] % = 3, 32 bits
}.
-export_type(['Versions'/0, 'Package'/0]).
-spec encode_msg('Versions'() | 'Package'(), atom()) -> binary().
encode_msg(Msg, MsgName) when is_atom(MsgName) ->
encode_msg(Msg, MsgName, []).
-spec encode_msg('Versions'() | 'Package'(), atom(), list()) -> binary().
encode_msg(Msg, MsgName, Opts) ->
verify_msg(Msg, MsgName, Opts),
TrUserData = proplists:get_value(user_data, Opts),
case MsgName of
'Versions' ->
e_msg_Versions(id(Msg, TrUserData), TrUserData);
'Package' ->
e_msg_Package(id(Msg, TrUserData), TrUserData)
end.
e_msg_Versions(Msg, TrUserData) ->
e_msg_Versions(Msg, <<>>, TrUserData).
e_msg_Versions(#{repository := F2} = M, Bin,
TrUserData) ->
B1 = case M of
#{packages := F1} ->
TrF1 = id(F1, TrUserData),
if TrF1 == [] -> Bin;
true -> e_field_Versions_packages(TrF1, Bin, TrUserData)
end;
_ -> Bin
end,
begin
TrF2 = id(F2, TrUserData),
e_type_string(TrF2, <<B1/binary, 18>>, TrUserData)
end.
e_msg_Package(Msg, TrUserData) ->
e_msg_Package(Msg, <<>>, TrUserData).
e_msg_Package(#{name := F1} = M, Bin, TrUserData) ->
B1 = begin
TrF1 = id(F1, TrUserData),
e_type_string(TrF1, <<Bin/binary, 10>>, TrUserData)
end,
B2 = case M of
#{versions := F2} ->
TrF2 = id(F2, TrUserData),
if TrF2 == [] -> B1;
true -> e_field_Package_versions(TrF2, B1, TrUserData)
end;
_ -> B1
end,
case M of
#{retired := F3} ->
TrF3 = id(F3, TrUserData),
if TrF3 == [] -> B2;
true -> e_field_Package_retired(TrF3, B2, TrUserData)
end;
_ -> B2
end.
e_mfield_Versions_packages(Msg, Bin, TrUserData) ->
SubBin = e_msg_Package(Msg, <<>>, TrUserData),
Bin2 = e_varint(byte_size(SubBin), Bin),
<<Bin2/binary, SubBin/binary>>.
e_field_Versions_packages([Elem | Rest], Bin,
TrUserData) ->
Bin2 = <<Bin/binary, 10>>,
Bin3 = e_mfield_Versions_packages(id(Elem, TrUserData),
Bin2, TrUserData),
e_field_Versions_packages(Rest, Bin3, TrUserData);
e_field_Versions_packages([], Bin, _TrUserData) -> Bin.
e_field_Package_versions([Elem | Rest], Bin,
TrUserData) ->
Bin2 = <<Bin/binary, 18>>,
Bin3 = e_type_string(id(Elem, TrUserData), Bin2,
TrUserData),
e_field_Package_versions(Rest, Bin3, TrUserData);
e_field_Package_versions([], Bin, _TrUserData) -> Bin.
e_field_Package_retired(Elems, Bin, TrUserData)
when Elems =/= [] ->
SubBin = e_pfield_Package_retired(Elems, <<>>,
TrUserData),
Bin2 = <<Bin/binary, 26>>,
Bin3 = e_varint(byte_size(SubBin), Bin2),
<<Bin3/binary, SubBin/binary>>;
e_field_Package_retired([], Bin, _TrUserData) -> Bin.
e_pfield_Package_retired([Value | Rest], Bin,
TrUserData) ->
Bin2 = e_type_int32(id(Value, TrUserData), Bin,
TrUserData),
e_pfield_Package_retired(Rest, Bin2, TrUserData);
e_pfield_Package_retired([], Bin, _TrUserData) -> Bin.
-compile({nowarn_unused_function,e_type_sint/3}).
e_type_sint(Value, Bin, _TrUserData) when Value >= 0 ->
e_varint(Value * 2, Bin);
e_type_sint(Value, Bin, _TrUserData) ->
e_varint(Value * -2 - 1, Bin).
-compile({nowarn_unused_function,e_type_int32/3}).
e_type_int32(Value, Bin, _TrUserData)
when 0 =< Value, Value =< 127 ->
<<Bin/binary, Value>>;
e_type_int32(Value, Bin, _TrUserData) ->
<<N:64/unsigned-native>> = <<Value:64/signed-native>>,
e_varint(N, Bin).
-compile({nowarn_unused_function,e_type_int64/3}).
e_type_int64(Value, Bin, _TrUserData)
when 0 =< Value, Value =< 127 ->
<<Bin/binary, Value>>;
e_type_int64(Value, Bin, _TrUserData) ->
<<N:64/unsigned-native>> = <<Value:64/signed-native>>,
e_varint(N, Bin).
-compile({nowarn_unused_function,e_type_bool/3}).
e_type_bool(true, Bin, _TrUserData) ->
<<Bin/binary, 1>>;
e_type_bool(false, Bin, _TrUserData) ->
<<Bin/binary, 0>>;
e_type_bool(1, Bin, _TrUserData) -> <<Bin/binary, 1>>;
e_type_bool(0, Bin, _TrUserData) -> <<Bin/binary, 0>>.
-compile({nowarn_unused_function,e_type_string/3}).
e_type_string(S, Bin, _TrUserData) ->
Utf8 = unicode:characters_to_binary(S),
Bin2 = e_varint(byte_size(Utf8), Bin),
<<Bin2/binary, Utf8/binary>>.
-compile({nowarn_unused_function,e_type_bytes/3}).
e_type_bytes(Bytes, Bin, _TrUserData)
when is_binary(Bytes) ->
Bin2 = e_varint(byte_size(Bytes), Bin),
<<Bin2/binary, Bytes/binary>>;
e_type_bytes(Bytes, Bin, _TrUserData)
when is_list(Bytes) ->
BytesBin = iolist_to_binary(Bytes),
Bin2 = e_varint(byte_size(BytesBin), Bin),
<<Bin2/binary, BytesBin/binary>>.
-compile({nowarn_unused_function,e_type_fixed32/3}).
e_type_fixed32(Value, Bin, _TrUserData) ->
<<Bin/binary, Value:32/little>>.
-compile({nowarn_unused_function,e_type_sfixed32/3}).
e_type_sfixed32(Value, Bin, _TrUserData) ->
<<Bin/binary, Value:32/little-signed>>.
-compile({nowarn_unused_function,e_type_fixed64/3}).
e_type_fixed64(Value, Bin, _TrUserData) ->
<<Bin/binary, Value:64/little>>.
-compile({nowarn_unused_function,e_type_sfixed64/3}).
e_type_sfixed64(Value, Bin, _TrUserData) ->
<<Bin/binary, Value:64/little-signed>>.
-compile({nowarn_unused_function,e_type_float/3}).
e_type_float(V, Bin, _) when is_number(V) ->
<<Bin/binary, V:32/little-float>>;
e_type_float(infinity, Bin, _) ->
<<Bin/binary, 0:16, 128, 127>>;
e_type_float('-infinity', Bin, _) ->
<<Bin/binary, 0:16, 128, 255>>;
e_type_float(nan, Bin, _) ->
<<Bin/binary, 0:16, 192, 127>>.
-compile({nowarn_unused_function,e_type_double/3}).
e_type_double(V, Bin, _) when is_number(V) ->
<<Bin/binary, V:64/little-float>>;
e_type_double(infinity, Bin, _) ->
<<Bin/binary, 0:48, 240, 127>>;
e_type_double('-infinity', Bin, _) ->
<<Bin/binary, 0:48, 240, 255>>;
e_type_double(nan, Bin, _) ->
<<Bin/binary, 0:48, 248, 127>>.
-compile({nowarn_unused_function,e_varint/3}).
e_varint(N, Bin, _TrUserData) -> e_varint(N, Bin).
-compile({nowarn_unused_function,e_varint/2}).
e_varint(N, Bin) when N =< 127 -> <<Bin/binary, N>>;
e_varint(N, Bin) ->
Bin2 = <<Bin/binary, (N band 127 bor 128)>>,
e_varint(N bsr 7, Bin2).
decode_msg(Bin, MsgName) when is_binary(Bin) ->
decode_msg(Bin, MsgName, []).
decode_msg(Bin, MsgName, Opts) when is_binary(Bin) ->
TrUserData = proplists:get_value(user_data, Opts),
decode_msg_1_catch(Bin, MsgName, TrUserData).
-ifdef('OTP_RELEASE').
decode_msg_1_catch(Bin, MsgName, TrUserData) ->
try decode_msg_2_doit(MsgName, Bin, TrUserData)
catch Class:Reason:StackTrace -> error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}})
end.
-else.
-ifdef('GPB_PATTERN_STACK').
decode_msg_1_catch(Bin, MsgName, TrUserData) ->
try decode_msg_2_doit(MsgName, Bin, TrUserData)
catch Class:Reason:StackTrace -> error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}})
end.
-else.
decode_msg_1_catch(Bin, MsgName, TrUserData) ->
try decode_msg_2_doit(MsgName, Bin, TrUserData)
catch Class:Reason ->
StackTrace = erlang:get_stacktrace(),
error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}})
end.
-endif.
-endif.
decode_msg_2_doit('Versions', Bin, TrUserData) ->
id(d_msg_Versions(Bin, TrUserData), TrUserData);
decode_msg_2_doit('Package', Bin, TrUserData) ->
id(d_msg_Package(Bin, TrUserData), TrUserData).
d_msg_Versions(Bin, TrUserData) ->
dfp_read_field_def_Versions(Bin, 0, 0,
id([], TrUserData), id('$undef', TrUserData),
TrUserData).
dfp_read_field_def_Versions(<<10, Rest/binary>>, Z1, Z2,
F@_1, F@_2, TrUserData) ->
d_field_Versions_packages(Rest, Z1, Z2, F@_1, F@_2,
TrUserData);
dfp_read_field_def_Versions(<<18, Rest/binary>>, Z1, Z2,
F@_1, F@_2, TrUserData) ->
d_field_Versions_repository(Rest, Z1, Z2, F@_1, F@_2,
TrUserData);
dfp_read_field_def_Versions(<<>>, 0, 0, R1, F@_2,
TrUserData) ->
S1 = #{repository => F@_2},
if R1 == '$undef' -> S1;
true -> S1#{packages => lists_reverse(R1, TrUserData)}
end;
dfp_read_field_def_Versions(Other, Z1, Z2, F@_1, F@_2,
TrUserData) ->
dg_read_field_def_Versions(Other, Z1, Z2, F@_1, F@_2,
TrUserData).
dg_read_field_def_Versions(<<1:1, X:7, Rest/binary>>, N,
Acc, F@_1, F@_2, TrUserData)
when N < 32 - 7 ->
dg_read_field_def_Versions(Rest, N + 7, X bsl N + Acc,
F@_1, F@_2, TrUserData);
dg_read_field_def_Versions(<<0:1, X:7, Rest/binary>>, N,
Acc, F@_1, F@_2, TrUserData) ->
Key = X bsl N + Acc,
case Key of
10 ->
d_field_Versions_packages(Rest, 0, 0, F@_1, F@_2,
TrUserData);
18 ->
d_field_Versions_repository(Rest, 0, 0, F@_1, F@_2,
TrUserData);
_ ->
case Key band 7 of
0 ->
skip_varint_Versions(Rest, 0, 0, F@_1, F@_2,
TrUserData);
1 ->
skip_64_Versions(Rest, 0, 0, F@_1, F@_2, TrUserData);
2 ->
skip_length_delimited_Versions(Rest, 0, 0, F@_1, F@_2,
TrUserData);
3 ->
skip_group_Versions(Rest, Key bsr 3, 0, F@_1, F@_2,
TrUserData);
5 ->
skip_32_Versions(Rest, 0, 0, F@_1, F@_2, TrUserData)
end
end;
dg_read_field_def_Versions(<<>>, 0, 0, R1, F@_2,
TrUserData) ->
S1 = #{repository => F@_2},
if R1 == '$undef' -> S1;
true -> S1#{packages => lists_reverse(R1, TrUserData)}
end.
d_field_Versions_packages(<<1:1, X:7, Rest/binary>>, N,
Acc, F@_1, F@_2, TrUserData)
when N < 57 ->
d_field_Versions_packages(Rest, N + 7, X bsl N + Acc,
F@_1, F@_2, TrUserData);
d_field_Versions_packages(<<0:1, X:7, Rest/binary>>, N,
Acc, Prev, F@_2, TrUserData) ->
{NewFValue, RestF} = begin
Len = X bsl N + Acc,
<<Bs:Len/binary, Rest2/binary>> = Rest,
{id(d_msg_Package(Bs, TrUserData), TrUserData),
Rest2}
end,
dfp_read_field_def_Versions(RestF, 0, 0,
cons(NewFValue, Prev, TrUserData), F@_2,
TrUserData).
d_field_Versions_repository(<<1:1, X:7, Rest/binary>>,
N, Acc, F@_1, F@_2, TrUserData)
when N < 57 ->
d_field_Versions_repository(Rest, N + 7, X bsl N + Acc,
F@_1, F@_2, TrUserData);
d_field_Versions_repository(<<0:1, X:7, Rest/binary>>,
N, Acc, F@_1, _, TrUserData) ->
{NewFValue, RestF} = begin
Len = X bsl N + Acc,
<<Bytes:Len/binary, Rest2/binary>> = Rest,
{id(binary:copy(Bytes), TrUserData), Rest2}
end,
dfp_read_field_def_Versions(RestF, 0, 0, F@_1,
NewFValue, TrUserData).
skip_varint_Versions(<<1:1, _:7, Rest/binary>>, Z1, Z2,
F@_1, F@_2, TrUserData) ->
skip_varint_Versions(Rest, Z1, Z2, F@_1, F@_2,
TrUserData);
skip_varint_Versions(<<0:1, _:7, Rest/binary>>, Z1, Z2,
F@_1, F@_2, TrUserData) ->
dfp_read_field_def_Versions(Rest, Z1, Z2, F@_1, F@_2,
TrUserData).
skip_length_delimited_Versions(<<1:1, X:7,
Rest/binary>>,
N, Acc, F@_1, F@_2, TrUserData)
when N < 57 ->
skip_length_delimited_Versions(Rest, N + 7,
X bsl N + Acc, F@_1, F@_2, TrUserData);
skip_length_delimited_Versions(<<0:1, X:7,
Rest/binary>>,
N, Acc, F@_1, F@_2, TrUserData) ->
Length = X bsl N + Acc,
<<_:Length/binary, Rest2/binary>> = Rest,
dfp_read_field_def_Versions(Rest2, 0, 0, F@_1, F@_2,
TrUserData).
skip_group_Versions(Bin, FNum, Z2, F@_1, F@_2,
TrUserData) ->
{_, Rest} = read_group(Bin, FNum),
dfp_read_field_def_Versions(Rest, 0, Z2, F@_1, F@_2,
TrUserData).
skip_32_Versions(<<_:32, Rest/binary>>, Z1, Z2, F@_1,
F@_2, TrUserData) ->
dfp_read_field_def_Versions(Rest, Z1, Z2, F@_1, F@_2,
TrUserData).
skip_64_Versions(<<_:64, Rest/binary>>, Z1, Z2, F@_1,
F@_2, TrUserData) ->
dfp_read_field_def_Versions(Rest, Z1, Z2, F@_1, F@_2,
TrUserData).
d_msg_Package(Bin, TrUserData) ->
dfp_read_field_def_Package(Bin, 0, 0,
id('$undef', TrUserData), id([], TrUserData),
id([], TrUserData), TrUserData).
dfp_read_field_def_Package(<<10, Rest/binary>>, Z1, Z2,
F@_1, F@_2, F@_3, TrUserData) ->
d_field_Package_name(Rest, Z1, Z2, F@_1, F@_2, F@_3,
TrUserData);
dfp_read_field_def_Package(<<18, Rest/binary>>, Z1, Z2,
F@_1, F@_2, F@_3, TrUserData) ->
d_field_Package_versions(Rest, Z1, Z2, F@_1, F@_2, F@_3,
TrUserData);
dfp_read_field_def_Package(<<26, Rest/binary>>, Z1, Z2,
F@_1, F@_2, F@_3, TrUserData) ->
d_pfield_Package_retired(Rest, Z1, Z2, F@_1, F@_2, F@_3,
TrUserData);
dfp_read_field_def_Package(<<24, Rest/binary>>, Z1, Z2,
F@_1, F@_2, F@_3, TrUserData) ->
d_field_Package_retired(Rest, Z1, Z2, F@_1, F@_2, F@_3,
TrUserData);
dfp_read_field_def_Package(<<>>, 0, 0, F@_1, R1, R2,
TrUserData) ->
#{name => F@_1,
versions => lists_reverse(R1, TrUserData),
retired => lists_reverse(R2, TrUserData)};
dfp_read_field_def_Package(Other, Z1, Z2, F@_1, F@_2,
F@_3, TrUserData) ->
dg_read_field_def_Package(Other, Z1, Z2, F@_1, F@_2,
F@_3, TrUserData).
dg_read_field_def_Package(<<1:1, X:7, Rest/binary>>, N,
Acc, F@_1, F@_2, F@_3, TrUserData)
when N < 32 - 7 ->
dg_read_field_def_Package(Rest, N + 7, X bsl N + Acc,
F@_1, F@_2, F@_3, TrUserData);
dg_read_field_def_Package(<<0:1, X:7, Rest/binary>>, N,
Acc, F@_1, F@_2, F@_3, TrUserData) ->
Key = X bsl N + Acc,
case Key of
10 ->
d_field_Package_name(Rest, 0, 0, F@_1, F@_2, F@_3,
TrUserData);
18 ->
d_field_Package_versions(Rest, 0, 0, F@_1, F@_2, F@_3,
TrUserData);
26 ->
d_pfield_Package_retired(Rest, 0, 0, F@_1, F@_2, F@_3,
TrUserData);
24 ->
d_field_Package_retired(Rest, 0, 0, F@_1, F@_2, F@_3,
TrUserData);
_ ->
case Key band 7 of
0 ->
skip_varint_Package(Rest, 0, 0, F@_1, F@_2, F@_3,
TrUserData);
1 ->
skip_64_Package(Rest, 0, 0, F@_1, F@_2, F@_3,
TrUserData);
2 ->
skip_length_delimited_Package(Rest, 0, 0, F@_1, F@_2,
F@_3, TrUserData);
3 ->
skip_group_Package(Rest, Key bsr 3, 0, F@_1, F@_2, F@_3,
TrUserData);
5 ->
skip_32_Package(Rest, 0, 0, F@_1, F@_2, F@_3,
TrUserData)
end
end;
dg_read_field_def_Package(<<>>, 0, 0, F@_1, R1, R2,
TrUserData) ->
#{name => F@_1,
versions => lists_reverse(R1, TrUserData),
retired => lists_reverse(R2, TrUserData)}.
d_field_Package_name(<<1:1, X:7, Rest/binary>>, N, Acc,
F@_1, F@_2, F@_3, TrUserData)
when N < 57 ->
d_field_Package_name(Rest, N + 7, X bsl N + Acc, F@_1,
F@_2, F@_3, TrUserData);
d_field_Package_name(<<0:1, X:7, Rest/binary>>, N, Acc,
_, F@_2, F@_3, TrUserData) ->
{NewFValue, RestF} = begin
Len = X bsl N + Acc,
<<Bytes:Len/binary, Rest2/binary>> = Rest,
{id(binary:copy(Bytes), TrUserData), Rest2}
end,
dfp_read_field_def_Package(RestF, 0, 0, NewFValue, F@_2,
F@_3, TrUserData).
d_field_Package_versions(<<1:1, X:7, Rest/binary>>, N,
Acc, F@_1, F@_2, F@_3, TrUserData)
when N < 57 ->
d_field_Package_versions(Rest, N + 7, X bsl N + Acc,
F@_1, F@_2, F@_3, TrUserData);
d_field_Package_versions(<<0:1, X:7, Rest/binary>>, N,
Acc, F@_1, Prev, F@_3, TrUserData) ->
{NewFValue, RestF} = begin
Len = X bsl N + Acc,
<<Bytes:Len/binary, Rest2/binary>> = Rest,
{id(binary:copy(Bytes), TrUserData), Rest2}
end,
dfp_read_field_def_Package(RestF, 0, 0, F@_1,
cons(NewFValue, Prev, TrUserData), F@_3,
TrUserData).
d_field_Package_retired(<<1:1, X:7, Rest/binary>>, N,
Acc, F@_1, F@_2, F@_3, TrUserData)
when N < 57 ->
d_field_Package_retired(Rest, N + 7, X bsl N + Acc,
F@_1, F@_2, F@_3, TrUserData);
d_field_Package_retired(<<0:1, X:7, Rest/binary>>, N,
Acc, F@_1, F@_2, Prev, TrUserData) ->
{NewFValue, RestF} = {begin
<<Res:32/signed-native>> = <<(X bsl N +
Acc):32/unsigned-native>>,
id(Res, TrUserData)
end,
Rest},
dfp_read_field_def_Package(RestF, 0, 0, F@_1, F@_2,
cons(NewFValue, Prev, TrUserData), TrUserData).
d_pfield_Package_retired(<<1:1, X:7, Rest/binary>>, N,
Acc, F@_1, F@_2, F@_3, TrUserData)
when N < 57 ->
d_pfield_Package_retired(Rest, N + 7, X bsl N + Acc,
F@_1, F@_2, F@_3, TrUserData);
d_pfield_Package_retired(<<0:1, X:7, Rest/binary>>, N,
Acc, F@_1, F@_2, E, TrUserData) ->
Len = X bsl N + Acc,
<<PackedBytes:Len/binary, Rest2/binary>> = Rest,
NewSeq = d_packed_field_Package_retired(PackedBytes, 0,
0, E, TrUserData),
dfp_read_field_def_Package(Rest2, 0, 0, F@_1, F@_2,
NewSeq, TrUserData).
d_packed_field_Package_retired(<<1:1, X:7,
Rest/binary>>,
N, Acc, AccSeq, TrUserData)
when N < 57 ->
d_packed_field_Package_retired(Rest, N + 7,
X bsl N + Acc, AccSeq, TrUserData);
d_packed_field_Package_retired(<<0:1, X:7,
Rest/binary>>,
N, Acc, AccSeq, TrUserData) ->
{NewFValue, RestF} = {begin
<<Res:32/signed-native>> = <<(X bsl N +
Acc):32/unsigned-native>>,
id(Res, TrUserData)
end,
Rest},
d_packed_field_Package_retired(RestF, 0, 0,
[NewFValue | AccSeq], TrUserData);
d_packed_field_Package_retired(<<>>, 0, 0, AccSeq, _) ->
AccSeq.
skip_varint_Package(<<1:1, _:7, Rest/binary>>, Z1, Z2,
F@_1, F@_2, F@_3, TrUserData) ->
skip_varint_Package(Rest, Z1, Z2, F@_1, F@_2, F@_3,
TrUserData);
skip_varint_Package(<<0:1, _:7, Rest/binary>>, Z1, Z2,
F@_1, F@_2, F@_3, TrUserData) ->
dfp_read_field_def_Package(Rest, Z1, Z2, F@_1, F@_2,
F@_3, TrUserData).
skip_length_delimited_Package(<<1:1, X:7, Rest/binary>>,
N, Acc, F@_1, F@_2, F@_3, TrUserData)
when N < 57 ->
skip_length_delimited_Package(Rest, N + 7,
X bsl N + Acc, F@_1, F@_2, F@_3, TrUserData);
skip_length_delimited_Package(<<0:1, X:7, Rest/binary>>,
N, Acc, F@_1, F@_2, F@_3, TrUserData) ->
Length = X bsl N + Acc,
<<_:Length/binary, Rest2/binary>> = Rest,
dfp_read_field_def_Package(Rest2, 0, 0, F@_1, F@_2,
F@_3, TrUserData).
skip_group_Package(Bin, FNum, Z2, F@_1, F@_2, F@_3,
TrUserData) ->
{_, Rest} = read_group(Bin, FNum),
dfp_read_field_def_Package(Rest, 0, Z2, F@_1, F@_2,
F@_3, TrUserData).
skip_32_Package(<<_:32, Rest/binary>>, Z1, Z2, F@_1,
F@_2, F@_3, TrUserData) ->
dfp_read_field_def_Package(Rest, Z1, Z2, F@_1, F@_2,
F@_3, TrUserData).
skip_64_Package(<<_:64, Rest/binary>>, Z1, Z2, F@_1,
F@_2, F@_3, TrUserData) ->
dfp_read_field_def_Package(Rest, Z1, Z2, F@_1, F@_2,
F@_3, TrUserData).
read_group(Bin, FieldNum) ->
{NumBytes, EndTagLen} = read_gr_b(Bin, 0, 0, 0, 0, FieldNum),
<<Group:NumBytes/binary, _:EndTagLen/binary, Rest/binary>> = Bin,
{Group, Rest}.
%% Like skipping over fields, but record the total length,
%% Each field is <(FieldNum bsl 3) bor FieldType> ++ <FieldValue>
%% Record the length because varints may be non-optimally encoded.
%%
%% Groups can be nested, but assume the same FieldNum cannot be nested
%% because group field numbers are shared with the rest of the fields
%% numbers. Thus we can search just for an group-end with the same
%% field number.
%%
%% (The only time the same group field number could occur would
%% be in a nested sub message, but then it would be inside a
%% length-delimited entry, which we skip-read by length.)
read_gr_b(<<1:1, X:7, Tl/binary>>, N, Acc, NumBytes, TagLen, FieldNum)
when N < (32-7) ->
read_gr_b(Tl, N+7, X bsl N + Acc, NumBytes, TagLen+1, FieldNum);
read_gr_b(<<0:1, X:7, Tl/binary>>, N, Acc, NumBytes, TagLen,
FieldNum) ->
Key = X bsl N + Acc,
TagLen1 = TagLen + 1,
case {Key bsr 3, Key band 7} of
{FieldNum, 4} -> % 4 = group_end
{NumBytes, TagLen1};
{_, 0} -> % 0 = varint
read_gr_vi(Tl, 0, NumBytes + TagLen1, FieldNum);
{_, 1} -> % 1 = bits64
<<_:64, Tl2/binary>> = Tl,
read_gr_b(Tl2, 0, 0, NumBytes + TagLen1 + 8, 0, FieldNum);
{_, 2} -> % 2 = length_delimited
read_gr_ld(Tl, 0, 0, NumBytes + TagLen1, FieldNum);
{_, 3} -> % 3 = group_start
read_gr_b(Tl, 0, 0, NumBytes + TagLen1, 0, FieldNum);
{_, 4} -> % 4 = group_end
read_gr_b(Tl, 0, 0, NumBytes + TagLen1, 0, FieldNum);
{_, 5} -> % 5 = bits32
<<_:32, Tl2/binary>> = Tl,
read_gr_b(Tl2, 0, 0, NumBytes + TagLen1 + 4, 0, FieldNum)
end.
read_gr_vi(<<1:1, _:7, Tl/binary>>, N, NumBytes, FieldNum)
when N < (64-7) ->
read_gr_vi(Tl, N+7, NumBytes+1, FieldNum);
read_gr_vi(<<0:1, _:7, Tl/binary>>, _, NumBytes, FieldNum) ->
read_gr_b(Tl, 0, 0, NumBytes+1, 0, FieldNum).
read_gr_ld(<<1:1, X:7, Tl/binary>>, N, Acc, NumBytes, FieldNum)
when N < (64-7) ->
read_gr_ld(Tl, N+7, X bsl N + Acc, NumBytes+1, FieldNum);
read_gr_ld(<<0:1, X:7, Tl/binary>>, N, Acc, NumBytes, FieldNum) ->
Len = X bsl N + Acc,
NumBytes1 = NumBytes + 1,
<<_:Len/binary, Tl2/binary>> = Tl,
read_gr_b(Tl2, 0, 0, NumBytes1 + Len, 0, FieldNum).
merge_msgs(Prev, New, MsgName) when is_atom(MsgName) ->
merge_msgs(Prev, New, MsgName, []).
merge_msgs(Prev, New, MsgName, Opts) ->
TrUserData = proplists:get_value(user_data, Opts),
case MsgName of
'Versions' -> merge_msg_Versions(Prev, New, TrUserData);
'Package' -> merge_msg_Package(Prev, New, TrUserData)
end.
-compile({nowarn_unused_function,merge_msg_Versions/3}).
merge_msg_Versions(#{} = PMsg,
#{repository := NFrepository} = NMsg, TrUserData) ->
S1 = #{repository => NFrepository},
case {PMsg, NMsg} of
{#{packages := PFpackages},
#{packages := NFpackages}} ->
S1#{packages =>
'erlang_++'(PFpackages, NFpackages, TrUserData)};
{_, #{packages := NFpackages}} ->
S1#{packages => NFpackages};
{#{packages := PFpackages}, _} ->
S1#{packages => PFpackages};
{_, _} -> S1
end.
-compile({nowarn_unused_function,merge_msg_Package/3}).
merge_msg_Package(#{} = PMsg, #{name := NFname} = NMsg,
TrUserData) ->
S1 = #{name => NFname},
S2 = case {PMsg, NMsg} of
{#{versions := PFversions},
#{versions := NFversions}} ->
S1#{versions =>
'erlang_++'(PFversions, NFversions, TrUserData)};
{_, #{versions := NFversions}} ->
S1#{versions => NFversions};
{#{versions := PFversions}, _} ->
S1#{versions => PFversions};
{_, _} -> S1
end,
case {PMsg, NMsg} of
{#{retired := PFretired}, #{retired := NFretired}} ->
S2#{retired =>
'erlang_++'(PFretired, NFretired, TrUserData)};
{_, #{retired := NFretired}} ->
S2#{retired => NFretired};
{#{retired := PFretired}, _} ->
S2#{retired => PFretired};
{_, _} -> S2
end.
verify_msg(Msg, MsgName) when is_atom(MsgName) ->
verify_msg(Msg, MsgName, []).
verify_msg(Msg, MsgName, Opts) ->
TrUserData = proplists:get_value(user_data, Opts),
case MsgName of
'Versions' ->
v_msg_Versions(Msg, [MsgName], TrUserData);
'Package' -> v_msg_Package(Msg, [MsgName], TrUserData);
_ -> mk_type_error(not_a_known_message, Msg, [])
end.
-compile({nowarn_unused_function,v_msg_Versions/3}).
v_msg_Versions(#{repository := F2} = M, Path,
TrUserData) ->
case M of
#{packages := F1} ->
if is_list(F1) ->
_ = [v_msg_Package(Elem, [packages | Path], TrUserData)
|| Elem <- F1],
ok;
true ->
mk_type_error({invalid_list_of, {msg, 'Package'}}, F1,
[packages | Path])
end;
_ -> ok
end,
v_type_string(F2, [repository | Path], TrUserData),
lists:foreach(fun (packages) -> ok;
(repository) -> ok;
(OtherKey) ->
mk_type_error({extraneous_key, OtherKey}, M, Path)
end,
maps:keys(M)),
ok;
v_msg_Versions(M, Path, _TrUserData) when is_map(M) ->
mk_type_error({missing_fields,
[repository] -- maps:keys(M), 'Versions'},
M, Path);
v_msg_Versions(X, Path, _TrUserData) ->
mk_type_error({expected_msg, 'Versions'}, X, Path).
-compile({nowarn_unused_function,v_msg_Package/3}).
v_msg_Package(#{name := F1} = M, Path, TrUserData) ->
v_type_string(F1, [name | Path], TrUserData),
case M of
#{versions := F2} ->
if is_list(F2) ->
_ = [v_type_string(Elem, [versions | Path], TrUserData)
|| Elem <- F2],
ok;
true ->
mk_type_error({invalid_list_of, string}, F2,
[versions | Path])
end;
_ -> ok
end,
case M of
#{retired := F3} ->
if is_list(F3) ->
_ = [v_type_int32(Elem, [retired | Path], TrUserData)
|| Elem <- F3],
ok;
true ->
mk_type_error({invalid_list_of, int32}, F3,
[retired | Path])
end;
_ -> ok
end,
lists:foreach(fun (name) -> ok;
(versions) -> ok;
(retired) -> ok;
(OtherKey) ->
mk_type_error({extraneous_key, OtherKey}, M, Path)
end,
maps:keys(M)),
ok;
v_msg_Package(M, Path, _TrUserData) when is_map(M) ->
mk_type_error({missing_fields, [name] -- maps:keys(M),
'Package'},
M, Path);
v_msg_Package(X, Path, _TrUserData) ->
mk_type_error({expected_msg, 'Package'}, X, Path).
-compile({nowarn_unused_function,v_type_int32/3}).
v_type_int32(N, _Path, _TrUserData)
when -2147483648 =< N, N =< 2147483647 ->
ok;
v_type_int32(N, Path, _TrUserData) when is_integer(N) ->
mk_type_error({value_out_of_range, int32, signed, 32},
N, Path);
v_type_int32(X, Path, _TrUserData) ->
mk_type_error({bad_integer, int32, signed, 32}, X,
Path).
-compile({nowarn_unused_function,v_type_string/3}).
v_type_string(S, Path, _TrUserData)
when is_list(S); is_binary(S) ->
try unicode:characters_to_binary(S) of
B when is_binary(B) -> ok;
{error, _, _} ->
mk_type_error(bad_unicode_string, S, Path)
catch
error:badarg ->
mk_type_error(bad_unicode_string, S, Path)
end;
v_type_string(X, Path, _TrUserData) ->
mk_type_error(bad_unicode_string, X, Path).
-compile({nowarn_unused_function,mk_type_error/3}).
-spec mk_type_error(_, _, list()) -> no_return().
mk_type_error(Error, ValueSeen, Path) ->
Path2 = prettify_path(Path),
erlang:error({gpb_type_error,
{Error, [{value, ValueSeen}, {path, Path2}]}}).
-compile({nowarn_unused_function,prettify_path/1}).
prettify_path([]) -> top_level;
prettify_path(PathR) ->
list_to_atom(string:join(lists:map(fun atom_to_list/1,
lists:reverse(PathR)),
".")).
-compile({nowarn_unused_function,id/2}).
-compile({inline,id/2}).
id(X, _TrUserData) -> X.
-compile({nowarn_unused_function,v_ok/3}).
-compile({inline,v_ok/3}).
v_ok(_Value, _Path, _TrUserData) -> ok.
-compile({nowarn_unused_function,m_overwrite/3}).
-compile({inline,m_overwrite/3}).
m_overwrite(_Prev, New, _TrUserData) -> New.
-compile({nowarn_unused_function,cons/3}).
-compile({inline,cons/3}).
cons(Elem, Acc, _TrUserData) -> [Elem | Acc].
-compile({nowarn_unused_function,lists_reverse/2}).
-compile({inline,lists_reverse/2}).
'lists_reverse'(L, _TrUserData) -> lists:reverse(L).
-compile({nowarn_unused_function,'erlang_++'/3}).
-compile({inline,'erlang_++'/3}).
'erlang_++'(A, B, _TrUserData) -> A ++ B.
get_msg_defs() ->
[{{msg, 'Versions'},
[#{name => packages, fnum => 1, rnum => 2,
type => {msg, 'Package'}, occurrence => repeated,
opts => []},
#{name => repository, fnum => 2, rnum => 3,
type => string, occurrence => required, opts => []}]},
{{msg, 'Package'},
[#{name => name, fnum => 1, rnum => 2, type => string,
occurrence => required, opts => []},
#{name => versions, fnum => 2, rnum => 3,
type => string, occurrence => repeated, opts => []},
#{name => retired, fnum => 3, rnum => 4, type => int32,
occurrence => repeated, opts => [packed]}]}].
get_msg_names() -> ['Versions', 'Package'].
get_group_names() -> [].
get_msg_or_group_names() -> ['Versions', 'Package'].
get_enum_names() -> [].
fetch_msg_def(MsgName) ->
case find_msg_def(MsgName) of
Fs when is_list(Fs) -> Fs;
error -> erlang:error({no_such_msg, MsgName})
end.
-spec fetch_enum_def(_) -> no_return().
fetch_enum_def(EnumName) ->
erlang:error({no_such_enum, EnumName}).
find_msg_def('Versions') ->
[#{name => packages, fnum => 1, rnum => 2,
type => {msg, 'Package'}, occurrence => repeated,
opts => []},
#{name => repository, fnum => 2, rnum => 3,
type => string, occurrence => required, opts => []}];
find_msg_def('Package') ->
[#{name => name, fnum => 1, rnum => 2, type => string,
occurrence => required, opts => []},
#{name => versions, fnum => 2, rnum => 3,
type => string, occurrence => repeated, opts => []},
#{name => retired, fnum => 3, rnum => 4, type => int32,
occurrence => repeated, opts => [packed]}];
find_msg_def(_) -> error.
find_enum_def(_) -> error.
-spec enum_symbol_by_value(_, _) -> no_return().
enum_symbol_by_value(E, V) ->
erlang:error({no_enum_defs, E, V}).
-spec enum_value_by_symbol(_, _) -> no_return().
enum_value_by_symbol(E, V) ->
erlang:error({no_enum_defs, E, V}).
get_service_names() -> [].
get_service_def(_) -> error.
get_rpc_names(_) -> error.
find_rpc_def(_, _) -> error.
-spec fetch_rpc_def(_, _) -> no_return().
fetch_rpc_def(ServiceName, RpcName) ->
erlang:error({no_such_rpc, ServiceName, RpcName}).
get_package_name() -> undefined.
gpb_version_as_string() ->
"4.3.1".
gpb_version_as_list() ->
[4,3,1].

+ 133
- 0
src/r3_hex_registry.erl View File

@ -0,0 +1,133 @@
%% Vendored from hex_core v0.5.0, do not edit manually
-module(r3_hex_registry).
-export([
encode_names/1,
decode_names/2,
encode_versions/1,
decode_versions/2,
encode_package/1,
decode_package/3,
sign_protobuf/2,
decode_signed/1,
decode_and_verify_signed/2,
sign/2,
verify/3
]).
-include_lib("public_key/include/public_key.hrl").
-type private_key() :: public_key:rsa_private_key() | binary().
-type public_key() :: public_key:rsa_public_key() | binary().
%%====================================================================
%% API functions
%%====================================================================
%% @doc
%% Encode Names message.
encode_names(Names) ->
r3_hex_pb_names:encode_msg(Names, 'Names').
%% @doc
%% Decode message created with encode_names/1.
decode_names(Payload, no_verify) ->
#{packages := Packages} = r3_hex_pb_names:decode_msg(Payload, 'Names'),
{ok, Packages};
decode_names(Payload, Repository) ->
case r3_hex_pb_names:decode_msg(Payload, 'Names') of
#{repository := Repository, packages := Packages} ->
{ok, Packages};
_ ->
{error, unverified}
end.
%% @doc
%% Encode Versions message.
encode_versions(Versions) ->
r3_hex_pb_versions:encode_msg(Versions, 'Versions').
%% @doc
%% Decode message created with encode_versions/1.
decode_versions(Payload, no_verify) ->
#{packages := Packages} = r3_hex_pb_versions:decode_msg(Payload, 'Versions'),
{ok, Packages};
decode_versions(Payload, Repository) ->
case r3_hex_pb_versions:decode_msg(Payload, 'Versions') of
#{repository := Repository, packages := Packages} ->
{ok, Packages};
_ ->
{error, unverified}
end.
%% @doc
%% Encode Package message.
encode_package(Package) ->
r3_hex_pb_package:encode_msg(Package, 'Package').
%% @doc
%% Decode message created with encode_package/1.
decode_package(Payload, no_verify, no_verify) ->
#{releases := Releases} = r3_hex_pb_package:decode_msg(Payload, 'Package'),
{ok, Releases};
decode_package(Payload, Repository, Package) ->
case r3_hex_pb_package:decode_msg(Payload, 'Package') of
#{repository := Repository, name := Package, releases := Releases} ->
{ok, Releases};
_ ->
{error, unverified}
end.
%% @doc
%% Encode Signed message.
sign_protobuf(Payload, PrivateKey) ->
Signature = sign(Payload, PrivateKey),
r3_hex_pb_signed:encode_msg(#{payload => Payload, signature => Signature}, 'Signed').
%% @doc
%% Decode message created with sign_protobuf/2 without verification.
decode_signed(Signed) ->
r3_hex_pb_signed:decode_msg(Signed, 'Signed').
%% @doc
%% Decode message created with sign_protobuf/2 and verify it against public key.
-spec decode_and_verify_signed(map(), public_key()) -> {ok, binary()} | {error, term()}.
decode_and_verify_signed(Signed, PublicKey) ->
#{payload := Payload, signature := Signature} = decode_signed(Signed),
case verify(Payload, Signature, PublicKey) of
true -> {ok, Payload};
false -> {error, unverified};
{error, Reason} -> {error, Reason}
end.
%% @doc
%% Signs binary with given private key.
-spec sign(binary(), private_key()) -> binary().
sign(Binary, PrivateKey) ->
{ok, RSAPrivateKey} = key(PrivateKey),
public_key:sign(Binary, sha512, RSAPrivateKey).
%% @doc
%% Verifies binary against signature and a public key.
-spec verify(binary(), binary(), public_key()) -> boolean() | {error, term()}.
verify(Binary, Signature, PublicKey) ->
case key(PublicKey) of
{ok, RSAPublicKey} -> public_key:verify(Binary, sha512, Signature, RSAPublicKey);
{error, Reason} -> {error, Reason}
end.
%%====================================================================
%% Internal functions
%%====================================================================
key(#'RSAPublicKey'{} = Key) ->
{ok, Key};
key(#'RSAPrivateKey'{} = Key) ->
{ok, Key};
key(Binary) when is_binary(Binary) ->
case public_key:pem_decode(Binary) of
[Entry | _] -> {ok, public_key:pem_entry_decode(Entry)};
_ -> {error, bad_key}
end.

+ 174
- 0
src/r3_hex_repo.erl View File

@ -0,0 +1,174 @@
%% Vendored from hex_core v0.5.0, do not edit manually
-module(r3_hex_repo).
-export([
get_names/1,
get_versions/1,
get_package/2,
get_tarball/3
]).
%%====================================================================
%% API functions
%%====================================================================
%% @doc
%% Gets names resource from the repository.
%%
%% Examples:
%%
%% ```
%% > r3_hex_repo:get_names(r3_hex_core:default_config()).
%% {ok, {200, ...,
%% [
%% #{name => <<"package1">>},
%% #{name => <<"package2">>},
%% ]}}
%% '''
%% @end
get_names(Config) when is_map(Config) ->
Verify = maps:get(repo_verify_origin, Config, true),
Decoder = fun(Data) ->
case Verify of
true -> r3_hex_registry:decode_names(Data, repo_name(Config));
false -> r3_hex_registry:decode_names(Data, no_verify)
end
end,
get_protobuf(Config, <<"names">>, Decoder).
%% @doc
%% Gets versions resource from the repository.
%%
%% Examples:
%%
%% ```
%% > r3_hex_repo:get_versions(Config).
%% {ok, {200, ...,
%% [
%% #{name => <<"package1">>, retired => [],
%% versions => [<<"1.0.0">>]},
%% #{name => <<"package2">>, retired => [<<"0.5.0>>"],
%% versions => [<<"0.5.0">>, <<"1.0.0">>]},
%% ]}}
%% '''
%% @end
get_versions(Config) when is_map(Config) ->
Verify = maps:get(repo_verify_origin, Config, true),
Decoder = fun(Data) ->
case Verify of
true -> r3_hex_registry:decode_versions(Data, repo_name(Config));
false -> r3_hex_registry:decode_versions(Data, no_verify)
end
end,
get_protobuf(Config, <<"versions">>, Decoder).
%% @doc
%% Gets package resource from the repository.
%%
%% Examples:
%%
%% ```
%% > r3_hex_repo:get_package(r3_hex_core:default_config(), <<"package1">>).
%% {ok, {200, ...,
%% {
%% #{checksum => ..., version => <<"0.5.0">>, dependencies => []},
%% #{checksum => ..., version => <<"1.0.0">>, dependencies => [
%% #{package => <<"package2">>, optional => true, requirement => <<"~> 0.1">>}
%% ]},
%% ]}}
%% '''
%% @end
get_package(Config, Name) when is_binary(Name) and is_map(Config) ->
Verify = maps:get(repo_verify_origin, Config, true),
Decoder = fun(Data) ->
case Verify of
true -> r3_hex_registry:decode_package(Data, repo_name(Config), Name);
false -> r3_hex_registry:decode_package(Data, no_verify, no_verify)
end
end,
get_protobuf(Config, <<"packages/", Name/binary>>, Decoder).
%% @doc
%% Gets tarball from the repository.
%%
%% Examples:
%%
%% ```
%% > {ok, {200, _, Tarball}} = r3_hex_repo:get_tarball(<<"package1">>, <<"1.0.0">>, r3_hex_core:default_config()),
%% > {ok, #{metadata := Metadata}} = r3_hex_tarball:unpack(Tarball, memory).
%% '''
%% @end
get_tarball(Config, Name, Version) ->
ReqHeaders = make_headers(Config),
case get(Config, tarball_url(Config, Name, Version), ReqHeaders) of
{ok, {200, RespHeaders, Tarball}} ->
{ok, {200, RespHeaders, Tarball}};
Other ->
Other
end.
%%====================================================================
%% Internal functions
%%====================================================================
get(Config, URI, Headers) ->
r3_hex_http:request(Config, get, URI, Headers, undefined).
get_protobuf(Config, Path, Decoder) ->
PublicKey = maps:get(repo_public_key, Config),
ReqHeaders = make_headers(Config),
case get(Config, build_url(Config, Path), ReqHeaders) of
{ok, {200, RespHeaders, Compressed}} ->
Signed = zlib:gunzip(Compressed),
case decode(Signed, PublicKey, Decoder, Config) of
{ok, Decoded} ->
{ok, {200, RespHeaders, Decoded}};
{error, _} = Error ->
Error
end;
Other ->
Other
end.
decode(Signed, PublicKey, Decoder, Config) ->
Verify = maps:get(repo_verify, Config, true),
case Verify of
true ->
case r3_hex_registry:decode_and_verify_signed(Signed, PublicKey) of
{ok, Payload} ->
Decoder(Payload);
Other ->
Other
end;
false ->
#{payload := Payload} = r3_hex_registry:decode_signed(Signed),
Decoder(Payload)
end.
repo_name(#{repo_organization := Name}) when is_binary(Name) -> Name;
repo_name(#{repo_name := Name}) when is_binary(Name) -> Name.
tarball_url(Config, Name, Version) ->
Filename = tarball_filename(Name, Version),
build_url(Config, <<"tarballs/", Filename/binary>>).
build_url(#{repo_url := URI, repo_organization := Org}, Path) when is_binary(Org) ->
<<URI/binary, "/repos/", Org/binary, "/", Path/binary>>;
build_url(#{repo_url := URI, repo_organization := undefined}, Path) ->
<<URI/binary, "/", Path/binary>>.
tarball_filename(Name, Version) ->
<<Name/binary, "-", Version/binary, ".tar">>.
make_headers(Config) ->
maps:fold(fun set_header/3, #{}, Config).
set_header(http_etag, ETag, Headers) when is_binary(ETag) -> maps:put(<<"if-none-match">>, ETag, Headers);
set_header(repo_key, Token, Headers) when is_binary(Token) -> maps:put(<<"authorization">>, Token, Headers);
set_header(_, _, Headers) -> Headers.

+ 507
- 0
src/r3_hex_tarball.erl View File

@ -0,0 +1,507 @@
%% Vendored from hex_core v0.5.0, do not edit manually
-module(r3_hex_tarball).
-export([create/2, create_docs/1, unpack/2, format_checksum/1, format_error/1]).
-ifdef(TEST).
-export([do_decode_metadata/1, gzip/1, normalize_requirements/1]).
-endif.
-define(VERSION, <<"3">>).
-define(TARBALL_MAX_SIZE, 8 * 1024 * 1024).
-define(TARBALL_MAX_UNCOMPRESSED_SIZE, 64 * 1024 * 1024).
-define(BUILD_TOOL_FILES, [
{<<"mix.exs">>, <<"mix">>},
{<<"rebar.config">>, <<"rebar3">>},
{<<"rebar">>, <<"rebar3">>},
{<<"Makefile">>, <<"make">>},
{<<"Makefile.win">>, <<"make">>}
]).
-include_lib("kernel/include/file.hrl").
-type checksum() :: binary().
-type contents() :: #{filename() => binary()}.
-type filename() :: string().
-type files() :: [filename() | {filename(), filename()}] | contents().
-type metadata() :: map().
-type tarball() :: binary().
%%====================================================================
%% API functions
%%====================================================================
%% @doc
%% Creates a package tarball.
%%
%% Examples:
%%
%% ```
%% > Metadata = #{<<"name">> => <<"foo">>, <<"version">> => <<"1.0.0">>},
%% > Files = [{"src/foo.erl", <<"-module(foo).">>}],
%% > {ok, {Tarball, Checksum}} = r3_hex_tarball:create(Metadata, Files).
%% > Tarball.
%% <<86,69,...>>
%% > Checksum.
%% <<40,32,...>>
%% '''
%% @end
-spec create(metadata(), files()) -> {ok, {tarball(), checksum()}}.
create(Metadata, Files) ->
MetadataBinary = encode_metadata(Metadata),
ContentsTarball = create_memory_tarball(Files),
ContentsTarballCompressed = gzip(ContentsTarball),
Checksum = checksum(?VERSION, MetadataBinary, ContentsTarballCompressed),
ChecksumBase16 = encode_base16(Checksum),
OuterFiles = [
{"VERSION", ?VERSION},
{"CHECKSUM", ChecksumBase16},
{"metadata.config", MetadataBinary},
{"contents.tar.gz", ContentsTarballCompressed}
],
Tarball = create_memory_tarball(OuterFiles),
UncompressedSize = byte_size(ContentsTarball),
case(byte_size(Tarball) > ?TARBALL_MAX_SIZE) or (UncompressedSize > ?TARBALL_MAX_UNCOMPRESSED_SIZE) of
true ->
{error, {tarball, too_big}};
false ->
{ok, {Tarball, Checksum}}
end.
%% @doc
%% Creates a docs tarball.
%%
%% Examples:
%%
%% ```
%% > Files = [{"doc/index.html", <<"Docs">>}],
%% > {ok, {Tarball, Checksum}} = r3_hex_tarball:create_docs(Files).
%% > Tarball.
%% %%=> <<86,69,...>>
%% > Checksum.
%% %%=> <<40,32,...>>
%% '''
%% @end
-spec create_docs(files()) -> {ok, {tarball(), checksum()}}.
create_docs(Files) ->
UncompressedTarball = create_memory_tarball(Files),
UncompressedSize = byte_size(UncompressedTarball),
Tarball = gzip(UncompressedTarball),
Checksum = checksum(Tarball),
Size = byte_size(Tarball),
case(Size > ?TARBALL_MAX_SIZE) or (UncompressedSize > ?TARBALL_MAX_UNCOMPRESSED_SIZE) of
true ->
{error, {tarball, too_big}};
false ->
{ok, {Tarball, Checksum}}
end.
%% @doc
%% Unpacks a package tarball.
%%
%% Examples:
%%
%% ```
%% > r3_hex_tarball:unpack(Tarball, memory).
%% {ok,#{checksum => <<...>>,
%% contents => [{"src/foo.erl",<<"-module(foo).">>}],
%% metadata => #{<<"name">> => <<"foo">>, ...}}}
%%
%% > r3_hex_tarball:unpack(Tarball, "path/to/unpack").
%% {ok,#{checksum => <<...>>,
%% metadata => #{<<"name">> => <<"foo">>, ...}}}
%% '''
-spec unpack(tarball(), memory) ->
{ok, #{checksum => checksum(), metadata => metadata(), contents => contents()}} |
{error, term()};
(tarball(), filename()) ->
{ok, #{checksum => checksum(), metadata => metadata()}} |
{error, term()}.
unpack(Tarball, _) when byte_size(Tarball) > ?TARBALL_MAX_SIZE ->
{error, {tarball, too_big}};
unpack(Tarball, Output) ->
case r3_hex_erl_tar:extract({binary, Tarball}, [memory]) of
{ok, []} ->
{error, {tarball, empty}};
{ok, FileList} ->
do_unpack(maps:from_list(FileList), Output);
{error, Reason} ->
{error, {tarball, Reason}}
end.
%% @doc
%% Returns base16-encoded representation of checksum.
-spec format_checksum(checksum()) -> binary().
format_checksum(Checksum) ->
encode_base16(Checksum).
%% @doc
%% Converts an error reason term to a human-readable error message string.
-spec format_error(term()) -> string().
format_error({tarball, empty}) -> "empty tarball";
format_error({tarball, too_big}) -> "tarball is too big";
format_error({tarball, {missing_files, Files}}) -> io_lib:format("missing files: ~p", [Files]);
format_error({tarball, {invalid_files, Files}}) -> io_lib:format("invalid files: ~p", [Files]);
format_error({tarball, {bad_version, Vsn}}) -> io_lib:format("unsupported version: ~p", [Vsn]);
format_error({tarball, invalid_checksum}) -> "invalid tarball checksum";
format_error({tarball, Reason}) -> "tarball error, " ++ r3_hex_erl_tar:format_error(Reason);
format_error({inner_tarball, Reason}) -> "inner tarball error, " ++ r3_hex_erl_tar:format_error(Reason);
format_error({metadata, invalid_terms}) -> "error reading package metadata: invalid terms";
format_error({metadata, not_key_value}) -> "error reading package metadata: not in key-value format";
format_error({metadata, Reason}) -> "error reading package metadata" ++ r3_safe_erl_term:format_error(Reason);
format_error({checksum_mismatch, ExpectedChecksum, ActualChecksum}) ->
io_lib:format(
"tarball checksum mismatch~n~n" ++
"Expected (base16-encoded): ~s~n" ++
"Actual (base16-encoded): ~s",
[encode_base16(ExpectedChecksum), encode_base16(ActualChecksum)]).
%%====================================================================
%% Internal functions
%%====================================================================
checksum(Version, MetadataBinary, ContentsBinary) ->
Blob = <<Version/binary, MetadataBinary/binary, ContentsBinary/binary>>,
crypto:hash(sha256, Blob).
checksum(ContentsBinary) ->
Blob = <<ContentsBinary/binary>>,
crypto:hash(sha256, Blob).
encode_metadata(Meta) ->
Data = lists:map(
fun(MetaPair) ->
String = io_lib_pretty:print(binarify(MetaPair), [{encoding, utf8}]),
unicode:characters_to_binary([String, ".\n"])
end, maps:to_list(Meta)),
iolist_to_binary(Data).
do_unpack(Files, Output) ->
State = #{
checksum => undefined,
contents => undefined,
files => Files,
metadata => undefined,
output => Output
},
State1 = check_files(State),
State2 = check_version(State1),
State3 = check_checksum(State2),
State4 = decode_metadata(State3),
finish_unpack(State4).
finish_unpack({error, _} = Error) ->
Error;
finish_unpack(#{metadata := Metadata, files := Files, output := Output}) ->
_Version = maps:get("VERSION", Files),
Checksum = decode_base16(maps:get("CHECKSUM", Files)),
ContentsBinary = maps:get("contents.tar.gz", Files),
case unpack_tarball(ContentsBinary, Output) of
ok ->
copy_metadata_config(Output, maps:get("metadata.config", Files)),
{ok, #{checksum => Checksum, metadata => Metadata}};
{ok, Contents} ->
{ok, #{checksum => Checksum, metadata => Metadata, contents => Contents}};
{error, Reason} ->
{error, {inner_tarball, Reason}}
end.
copy_metadata_config(Output, MetadataBinary) ->
ok = file:write_file(filename:join(Output, "hex_metadata.config"), MetadataBinary).
check_files(#{files := Files} = State) ->
RequiredFiles = ["VERSION", "CHECKSUM", "metadata.config", "contents.tar.gz"],
case diff_keys(Files, RequiredFiles, []) of
ok ->
State;
{error, {missing_keys, Keys}} ->
{error, {tarball, {missing_files, Keys}}};
{error, {unknown_keys, Keys}} ->
{error, {tarball, {invalid_files, Keys}}}
end.
check_version({error, _} = Error) ->
Error;
check_version(#{files := Files} = State) ->
case maps:get("VERSION", Files) of
<<"3">> ->
State;
Version ->
{error, {tarball, {bad_version, Version}}}
end.
check_checksum({error, _} = Error) ->
Error;
check_checksum(#{files := Files} = State) ->
ChecksumBase16 = maps:get("CHECKSUM", Files),
ExpectedChecksum = decode_base16(ChecksumBase16),
Version = maps:get("VERSION", Files),
MetadataBinary = maps:get("metadata.config", Files),
ContentsBinary = maps:get("contents.tar.gz", Files),
ActualChecksum = checksum(Version, MetadataBinary, ContentsBinary),
if
byte_size(ExpectedChecksum) /= 32 ->
{error, {tarball, invalid_checksum}};
ExpectedChecksum == ActualChecksum ->
maps:put(checksum, ExpectedChecksum, State);
true ->
{error, {tarball, {checksum_mismatch, ExpectedChecksum, ActualChecksum}}}
end.
decode_metadata({error, _} = Error) ->
Error;
decode_metadata(#{files := #{"metadata.config" := Binary}} = State) when is_binary(Binary) ->
case do_decode_metadata(Binary) of
#{} = Metadata -> maps:put(metadata, normalize_metadata(Metadata), State);
Other -> Other
end.
do_decode_metadata(Binary) when is_binary(Binary) ->
{ok, String} = characters_to_list(Binary),
case r3_safe_erl_term:string(String) of
{ok, Tokens, _Line} ->
try
Terms = r3_safe_erl_term:terms(Tokens),
maps:from_list(Terms)
catch
error:function_clause ->
{error, {metadata, invalid_terms}};
error:badarg ->
{error, {metadata, not_key_value}}
end;
{error, {_Line, r3_safe_erl_term, Reason}, _Line2} ->
{error, {metadata, Reason}}
end.
characters_to_list(Binary) ->
case unicode:characters_to_list(Binary) of
List when is_list(List) ->
{ok, List};
{error, _, _} ->
case unicode:characters_to_list(Binary, latin1) of
List when is_list(List) -> {ok, List};
Other -> Other
end
end.
normalize_metadata(Metadata1) ->
Metadata2 = maybe_update_with(<<"requirements">>, fun normalize_requirements/1, Metadata1),
Metadata3 = maybe_update_with(<<"links">>, fun try_into_map/1, Metadata2),
Metadata4 = maybe_update_with(<<"extra">>, fun try_into_map/1, Metadata3),
guess_build_tools(Metadata4).
normalize_requirements(Requirements) ->
case is_list(Requirements) andalso (Requirements /= []) andalso is_list(hd(Requirements)) of
true ->
maps:from_list(lists:map(fun normalize_legacy_requirement/1, Requirements));
false ->
try_into_map(fun normalize_normal_requirement/1, Requirements)
end.
normalize_normal_requirement({Name, Requirement}) ->
{Name, try_into_map(Requirement)}.
normalize_legacy_requirement(Requirement) ->
Map = maps:from_list(Requirement),
Name = maps:get(<<"name">>, Map),
{Name, maps:without([<<"name">>], Map)}.
guess_build_tools(#{<<"build_tools">> := BuildTools} = Metadata) when is_list(BuildTools) ->
Metadata;
guess_build_tools(#{<<"files">> := Filenames} = Metadata) ->
BaseFiles = [Filename || Filename <- Filenames, filename:dirname(binary_to_list(Filename)) == "."],
BuildTools = lists:usort([Tool || {Filename, Tool} <- ?BUILD_TOOL_FILES, lists:member(Filename, BaseFiles)]),
Metadata#{<<"build_tools">> => BuildTools};
guess_build_tools(Metadata) ->
Metadata.
%%====================================================================
%% Tar Helpers
%%====================================================================
unpack_tarball(ContentsBinary, memory) ->
r3_hex_erl_tar:extract({binary, ContentsBinary}, [memory, compressed]);
unpack_tarball(ContentsBinary, Output) ->
case r3_hex_erl_tar:extract({binary, ContentsBinary}, [{cwd, Output}, compressed]) of
ok ->
[try_updating_mtime(filename:join(Output, Path)) || Path <- filelib:wildcard("**", Output)],
ok;
Other ->
Other
end.
%% let it silently fail for bad symlinks
try_updating_mtime(Path) ->
Time = calendar:universal_time(),
_ = file:write_file_info(Path, #file_info{mtime=Time}, [{time, universal}]),
ok.
create_memory_tarball(Files) ->
Path = tmp_path(),
{ok, Tar} = r3_hex_erl_tar:open(Path, [write]),
try
add_files(Tar, Files)
after
ok = r3_hex_erl_tar:close(Tar)
end,
{ok, Tarball} = file:read_file(Path),
ok = file:delete(Path),
Tarball.
tmp_path() ->
"tmp_" ++ binary_to_list(encode_base16(crypto:strong_rand_bytes(32))).
add_files(Tar, Files) when is_list(Files) ->
lists:map(fun(File) -> add_file(Tar, File) end, Files).
add_file(Tar, {Filename, Contents}) when is_list(Filename) and is_binary(Contents) ->
ok = r3_hex_erl_tar:add(Tar, Contents, Filename, tar_opts());
add_file(Tar, Filename) when is_list(Filename) ->
add_file(Tar, {Filename, Filename});
add_file(Tar, {Filename, AbsFilename}) when is_list(Filename), is_list(AbsFilename) ->
{ok, FileInfo} = file:read_link_info(AbsFilename, []),
case FileInfo#file_info.type of
symlink ->
ok = r3_hex_erl_tar:add(Tar, {Filename, AbsFilename}, tar_opts());
directory ->
case file:list_dir(AbsFilename) of
{ok, []} ->
r3_hex_erl_tar:add(Tar, {Filename, AbsFilename}, tar_opts());
{ok, _} ->
ok
end;
_ ->
Mode = FileInfo#file_info.mode,
{ok, Contents} = file:read_file(AbsFilename),
ok = r3_hex_erl_tar:add(Tar, Contents, Filename, Mode, tar_opts())
end.
tar_opts() ->
NixEpoch = calendar:datetime_to_gregorian_seconds({{1970, 1, 1}, {0, 0, 0}}),
Y2kEpoch = calendar:datetime_to_gregorian_seconds({{2000, 1, 1}, {0, 0, 0}}),
Epoch = Y2kEpoch - NixEpoch,
[{atime, Epoch}, {mtime, Epoch}, {ctime, Epoch}, {uid, 0}, {gid, 0}].
%% Reproducible gzip by not setting mtime and OS
%%
%% From https://tools.ietf.org/html/rfc1952
%%
%% +---+---+---+---+---+---+---+---+---+---+
%% |ID1|ID2|CM |FLG| MTIME |XFL|OS | (more-->)
%% +---+---+---+---+---+---+---+---+---+---+
%%
%% +=======================+
%% |...compressed blocks...| (more-->)
%% +=======================+
%%
%% +---+---+---+---+---+---+---+---+
%% | CRC32 | ISIZE |
%% +---+---+---+---+---+---+---+---+
gzip(Uncompressed) ->
Compressed = gzip_no_header(Uncompressed),
Header = <<31, 139, 8, 0, 0, 0, 0, 0, 0, 0>>,
Crc = erlang:crc32(Uncompressed),
Size = byte_size(Uncompressed),
Trailer = <<Crc:32/little, Size:32/little>>,
iolist_to_binary([Header, Compressed, Trailer]).
gzip_no_header(Uncompressed) ->
Zstream = zlib:open(),
try
zlib:deflateInit(Zstream, default, deflated, -15, 8, default),
Compressed = zlib:deflate(Zstream, Uncompressed, finish),
zlib:deflateEnd(Zstream),
iolist_to_binary(Compressed)
after
zlib:close(Zstream)
end.
%%====================================================================
%% Helpers
%%====================================================================
binarify(Binary) when is_binary(Binary) -> Binary;
binarify(Number) when is_number(Number) -> Number;
binarify(Atom) when Atom == undefined orelse is_boolean(Atom) -> Atom;
binarify(Atom) when is_atom(Atom) -> atom_to_binary(Atom, utf8);
binarify(List) when is_list(List) ->
[binarify(E) || E <- List];
binarify({Key, Value}) ->
{binarify(Key), binarify(Value)};
binarify(Map) when is_map(Map) ->
List = maps:to_list(Map),
lists:map(fun({K, V}) -> binarify({K, V}) end, List).
diff_keys(Map, RequiredKeys, OptionalKeys) ->
Keys = maps:keys(Map),
MissingKeys = RequiredKeys -- Keys,
UnknownKeys = Keys -- (RequiredKeys ++ OptionalKeys),
case {MissingKeys, UnknownKeys} of
{[], []} ->
ok;
{_, [_ | _]} ->
{error, {unknown_keys, UnknownKeys}};
_ ->
{error, {missing_keys, MissingKeys}}
end.
maybe_update_with(Key, Fun, Map) ->
case maps:find(Key, Map) of
{ok, Value} -> maps:put(Key, Fun(Value), Map);
error -> Map
end.
try_into_map(List) ->
try_into_map(fun(X) -> X end, List).
try_into_map(Fun, Input) ->
case is_list(Input) andalso lists:all(fun(E) -> is_tuple(E) andalso (tuple_size(E) == 2) end, Input) of
true -> maps:from_list(lists:map(Fun, Input));
false -> Input
end.
encode_base16(Binary) ->
<<X:256/big-unsigned-integer>> = Binary,
String = string:to_upper(lists:flatten(io_lib:format("~64.16.0b", [X]))),
list_to_binary(String).
%% Based on https://github.com/goj/base16/blob/master/src/base16.erl
%% (C) 2012, Erlang Solutions Ltd.
decode_base16(Base16) ->
<< <<(unhex(H) bsl 4 + unhex(L))>> || <<H,L>> <= Base16 >>.
unhex(D) when $0 =< D andalso D =< $9 ->
D - $0;
unhex(D) when $a =< D andalso D =< $f ->
10 + D - $a;
unhex(D) when $A =< D andalso D =< $F ->
10 + D - $A.

+ 678
- 0
src/r3_safe_erl_term.erl View File

@ -0,0 +1,678 @@
-file("/usr/local/lib/erlang/lib/parsetools-2.1.8/include/leexinc.hrl", 0).
%% The source of this file is part of leex distribution, as such it
%% has the same Copyright as the other files in the leex
%% distribution. The Copyright is defined in the accompanying file
%% COPYRIGHT. However, the resultant scanner generated by leex is the
%% property of the creator of the scanner and is not covered by that
%% Copyright.
-module(r3_safe_erl_term).
-export([string/1,string/2,token/2,token/3,tokens/2,tokens/3]).
-export([format_error/1]).
%% User code. This is placed here to allow extra attributes.
-file("/Users/starbelly/devel/erlang/rebar3/src/hex_core/r3_safe_erl_term.xrl", 26).
-export([terms/1]).
terms(Tokens) ->
terms(Tokens, []).
terms([{dot, _} = H], Buffer) ->
[buffer_to_term([H|Buffer])];
terms([{dot, _} = H|T], Buffer) ->
[buffer_to_term([H|Buffer])|terms(T, [])];
terms([H|T], Buffer) ->
terms(T, [H|Buffer]).
buffer_to_term(Buffer) ->
{ok, Term} = erl_parse:parse_term(lists:reverse(Buffer)),
Term.
unquote(TokenChars, TokenLen) ->
lists:sublist(TokenChars, 2, TokenLen - 2).
tokenize_atom(TokenChars, TokenLine) ->
try list_to_existing_atom(TokenChars) of
Atom -> {token, {atom, TokenLine, Atom}}
catch
error:badarg -> {error, "illegal atom " ++ TokenChars}
end.
escape([$\\|Cs]) ->
do_escape(Cs);
escape([C|Cs]) ->
[C|escape(Cs)];
escape([]) -> [].
do_escape([O1,O2,O3|S]) when
O1 >= $0, O1 =< $7, O2 >= $0, O2 =< $7, O3 >= $0, O3 =< $7 ->
[(O1*8 + O2)*8 + O3 - 73*$0|escape(S)];
do_escape([$^,C|Cs]) ->
[C band 31|escape(Cs)];
do_escape([C|Cs]) when C >= $\000, C =< $\s ->
escape(Cs);
do_escape([C|Cs]) ->
[escape_char(C)|escape(Cs)].
escape_char($n) -> $\n; %\n = LF
escape_char($r) -> $\r; %\r = CR
escape_char($t) -> $\t; %\t = TAB
escape_char($v) -> $\v; %\v = VT
escape_char($b) -> $\b; %\b = BS
escape_char($f) -> $\f; %\f = FF
escape_char($e) -> $\e; %\e = ESC
escape_char($s) -> $\s; %\s = SPC
escape_char($d) -> $\d; %\d = DEL
escape_char(C) -> C.
-file("/usr/local/lib/erlang/lib/parsetools-2.1.8/include/leexinc.hrl", 14).
format_error({illegal,S}) -> ["illegal characters ",io_lib:write_string(S)];
format_error({user,S}) -> S.
string(String) -> string(String, 1).
string(String, Line) -> string(String, Line, String, []).
%% string(InChars, Line, TokenChars, Tokens) ->
%% {ok,Tokens,Line} | {error,ErrorInfo,Line}.
%% Note the line number going into yystate, L0, is line of token
%% start while line number returned is line of token end. We want line
%% of token start.
string([], L, [], Ts) -> % No partial tokens!
{ok,yyrev(Ts),L};
string(Ics0, L0, Tcs, Ts) ->
case yystate(yystate(), Ics0, L0, 0, reject, 0) of
{A,Alen,Ics1,L1} -> % Accepting end state
string_cont(Ics1, L1, yyaction(A, Alen, Tcs, L0), Ts);
{A,Alen,Ics1,L1,_S1} -> % Accepting transistion state
string_cont(Ics1, L1, yyaction(A, Alen, Tcs, L0), Ts);
{reject,_Alen,Tlen,_Ics1,L1,_S1} -> % After a non-accepting state
{error,{L0,?MODULE,{illegal,yypre(Tcs, Tlen+1)}},L1};
{A,Alen,Tlen,_Ics1,L1,_S1} ->
Tcs1 = yysuf(Tcs, Alen),
L2 = adjust_line(Tlen, Alen, Tcs1, L1),
string_cont(Tcs1, L2, yyaction(A, Alen, Tcs, L0), Ts)
end.
%% string_cont(RestChars, Line, Token, Tokens)
%% Test for and remove the end token wrapper. Push back characters
%% are prepended to RestChars.
-dialyzer({nowarn_function, string_cont/4}).
string_cont(Rest, Line, {token,T}, Ts) ->
string(Rest, Line, Rest, [T|Ts]);
string_cont(Rest, Line, {token,T,Push}, Ts) ->
NewRest = Push ++ Rest,
string(NewRest, Line, NewRest, [T|Ts]);
string_cont(Rest, Line, {end_token,T}, Ts) ->
string(Rest, Line, Rest, [T|Ts]);
string_cont(Rest, Line, {end_token,T,Push}, Ts) ->
NewRest = Push ++ Rest,
string(NewRest, Line, NewRest, [T|Ts]);
string_cont(Rest, Line, skip_token, Ts) ->
string(Rest, Line, Rest, Ts);
string_cont(Rest, Line, {skip_token,Push}, Ts) ->
NewRest = Push ++ Rest,
string(NewRest, Line, NewRest, Ts);
string_cont(_Rest, Line, {error,S}, _Ts) ->
{error,{Line,?MODULE,{user,S}},Line}.
%% token(Continuation, Chars) ->
%% token(Continuation, Chars, Line) ->
%% {more,Continuation} | {done,ReturnVal,RestChars}.
%% Must be careful when re-entering to append the latest characters to the
%% after characters in an accept. The continuation is:
%% {token,State,CurrLine,TokenChars,TokenLen,TokenLine,AccAction,AccLen}
token(Cont, Chars) -> token(Cont, Chars, 1).
token([], Chars, Line) ->
token(yystate(), Chars, Line, Chars, 0, Line, reject, 0);
token({token,State,Line,Tcs,Tlen,Tline,Action,Alen}, Chars, _) ->
token(State, Chars, Line, Tcs ++ Chars, Tlen, Tline, Action, Alen).
%% token(State, InChars, Line, TokenChars, TokenLen, TokenLine,
%% AcceptAction, AcceptLen) ->
%% {more,Continuation} | {done,ReturnVal,RestChars}.
%% The argument order is chosen to be more efficient.
token(S0, Ics0, L0, Tcs, Tlen0, Tline, A0, Alen0) ->
case yystate(S0, Ics0, L0, Tlen0, A0, Alen0) of
%% Accepting end state, we have a token.
{A1,Alen1,Ics1,L1} ->
token_cont(Ics1, L1, yyaction(A1, Alen1, Tcs, Tline));
%% Accepting transition state, can take more chars.
{A1,Alen1,[],L1,S1} -> % Need more chars to check
{more,{token,S1,L1,Tcs,Alen1,Tline,A1,Alen1}};
{A1,Alen1,Ics1,L1,_S1} -> % Take what we got
token_cont(Ics1, L1, yyaction(A1, Alen1, Tcs, Tline));
%% After a non-accepting state, maybe reach accept state later.
{A1,Alen1,Tlen1,[],L1,S1} -> % Need more chars to check
{more,{token,S1,L1,Tcs,Tlen1,Tline,A1,Alen1}};
{reject,_Alen1,Tlen1,eof,L1,_S1} -> % No token match
%% Check for partial token which is error.
Ret = if Tlen1 > 0 -> {error,{Tline,?MODULE,
%% Skip eof tail in Tcs.
{illegal,yypre(Tcs, Tlen1)}},L1};
true -> {eof,L1}
end,
{done,Ret,eof};
{reject,_Alen1,Tlen1,Ics1,L1,_S1} -> % No token match
Error = {Tline,?MODULE,{illegal,yypre(Tcs, Tlen1+1)}},
{done,{error,Error,L1},Ics1};
{A1,Alen1,Tlen1,_Ics1,L1,_S1} -> % Use last accept match
Tcs1 = yysuf(Tcs, Alen1),
L2 = adjust_line(Tlen1, Alen1, Tcs1, L1),
token_cont(Tcs1, L2, yyaction(A1, Alen1, Tcs, Tline))
end.
%% token_cont(RestChars, Line, Token)
%% If we have a token or error then return done, else if we have a
%% skip_token then continue.
-dialyzer({nowarn_function, token_cont/3}).
token_cont(Rest, Line, {token,T}) ->
{done,{ok,T,Line},Rest};
token_cont(Rest, Line, {token,T,Push}) ->
NewRest = Push ++ Rest,
{done,{ok,T,Line},NewRest};
token_cont(Rest, Line, {end_token,T}) ->
{done,{ok,T,Line},Rest};
token_cont(Rest, Line, {end_token,T,Push}) ->
NewRest = Push ++ Rest,
{done,{ok,T,Line},NewRest};
token_cont(Rest, Line, skip_token) ->
token(yystate(), Rest, Line, Rest, 0, Line, reject, 0);
token_cont(Rest, Line, {skip_token,Push}) ->
NewRest = Push ++ Rest,
token(yystate(), NewRest, Line, NewRest, 0, Line, reject, 0);
token_cont(Rest, Line, {error,S}) ->
{done,{error,{Line,?MODULE,{user,S}},Line},Rest}.
%% tokens(Continuation, Chars, Line) ->
%% {more,Continuation} | {done,ReturnVal,RestChars}.
%% Must be careful when re-entering to append the latest characters to the
%% after characters in an accept. The continuation is:
%% {tokens,State,CurrLine,TokenChars,TokenLen,TokenLine,Tokens,AccAction,AccLen}
%% {skip_tokens,State,CurrLine,TokenChars,TokenLen,TokenLine,Error,AccAction,AccLen}
tokens(Cont, Chars) -> tokens(Cont, Chars, 1).
tokens([], Chars, Line) ->
tokens(yystate(), Chars, Line, Chars, 0, Line, [], reject, 0);
tokens({tokens,State,Line,Tcs,Tlen,Tline,Ts,Action,Alen}, Chars, _) ->
tokens(State, Chars, Line, Tcs ++ Chars, Tlen, Tline, Ts, Action, Alen);
tokens({skip_tokens,State,Line,Tcs,Tlen,Tline,Error,Action,Alen}, Chars, _) ->
skip_tokens(State, Chars, Line, Tcs ++ Chars, Tlen, Tline, Error, Action, Alen).
%% tokens(State, InChars, Line, TokenChars, TokenLen, TokenLine, Tokens,
%% AcceptAction, AcceptLen) ->
%% {more,Continuation} | {done,ReturnVal,RestChars}.
tokens(S0, Ics0, L0, Tcs, Tlen0, Tline, Ts, A0, Alen0) ->
case yystate(S0, Ics0, L0, Tlen0, A0, Alen0) of
%% Accepting end state, we have a token.
{A1,Alen1,Ics1,L1} ->
tokens_cont(Ics1, L1, yyaction(A1, Alen1, Tcs, Tline), Ts);
%% Accepting transition state, can take more chars.
{A1,Alen1,[],L1,S1} -> % Need more chars to check
{more,{tokens,S1,L1,Tcs,Alen1,Tline,Ts,A1,Alen1}};
{A1,Alen1,Ics1,L1,_S1} -> % Take what we got
tokens_cont(Ics1, L1, yyaction(A1, Alen1, Tcs, Tline), Ts);
%% After a non-accepting state, maybe reach accept state later.
{A1,Alen1,Tlen1,[],L1,S1} -> % Need more chars to check
{more,{tokens,S1,L1,Tcs,Tlen1,Tline,Ts,A1,Alen1}};
{reject,_Alen1,Tlen1,eof,L1,_S1} -> % No token match
%% Check for partial token which is error, no need to skip here.
Ret = if Tlen1 > 0 -> {error,{Tline,?MODULE,
%% Skip eof tail in Tcs.
{illegal,yypre(Tcs, Tlen1)}},L1};
Ts == [] -> {eof,L1};
true -> {ok,yyrev(Ts),L1}
end,
{done,Ret,eof};
{reject,_Alen1,Tlen1,_Ics1,L1,_S1} ->
%% Skip rest of tokens.
Error = {L1,?MODULE,{illegal,yypre(Tcs, Tlen1+1)}},
skip_tokens(yysuf(Tcs, Tlen1+1), L1, Error);
{A1,Alen1,Tlen1,_Ics1,L1,_S1} ->
Token = yyaction(A1, Alen1, Tcs, Tline),
Tcs1 = yysuf(Tcs, Alen1),
L2 = adjust_line(Tlen1, Alen1, Tcs1, L1),
tokens_cont(Tcs1, L2, Token, Ts)
end.
%% tokens_cont(RestChars, Line, Token, Tokens)
%% If we have an end_token or error then return done, else if we have
%% a token then save it and continue, else if we have a skip_token
%% just continue.
-dialyzer({nowarn_function, tokens_cont/4}).
tokens_cont(Rest, Line, {token,T}, Ts) ->
tokens(yystate(), Rest, Line, Rest, 0, Line, [T|Ts], reject, 0);
tokens_cont(Rest, Line, {token,T,Push}, Ts) ->
NewRest = Push ++ Rest,
tokens(yystate(), NewRest, Line, NewRest, 0, Line, [T|Ts], reject, 0);
tokens_cont(Rest, Line, {end_token,T}, Ts) ->
{done,{ok,yyrev(Ts, [T]),Line},Rest};
tokens_cont(Rest, Line, {end_token,T,Push}, Ts) ->
NewRest = Push ++ Rest,
{done,{ok,yyrev(Ts, [T]),Line},NewRest};
tokens_cont(Rest, Line, skip_token, Ts) ->
tokens(yystate(), Rest, Line, Rest, 0, Line, Ts, reject, 0);
tokens_cont(Rest, Line, {skip_token,Push}, Ts) ->
NewRest = Push ++ Rest,
tokens(yystate(), NewRest, Line, NewRest, 0, Line, Ts, reject, 0);
tokens_cont(Rest, Line, {error,S}, _Ts) ->
skip_tokens(Rest, Line, {Line,?MODULE,{user,S}}).
%%skip_tokens(InChars, Line, Error) -> {done,{error,Error,Line},Ics}.
%% Skip tokens until an end token, junk everything and return the error.
skip_tokens(Ics, Line, Error) ->
skip_tokens(yystate(), Ics, Line, Ics, 0, Line, Error, reject, 0).
%% skip_tokens(State, InChars, Line, TokenChars, TokenLen, TokenLine, Tokens,
%% AcceptAction, AcceptLen) ->
%% {more,Continuation} | {done,ReturnVal,RestChars}.
skip_tokens(S0, Ics0, L0, Tcs, Tlen0, Tline, Error, A0, Alen0) ->
case yystate(S0, Ics0, L0, Tlen0, A0, Alen0) of
{A1,Alen1,Ics1,L1} -> % Accepting end state
skip_cont(Ics1, L1, yyaction(A1, Alen1, Tcs, Tline), Error);
{A1,Alen1,[],L1,S1} -> % After an accepting state
{more,{skip_tokens,S1,L1,Tcs,Alen1,Tline,Error,A1,Alen1}};
{A1,Alen1,Ics1,L1,_S1} ->
skip_cont(Ics1, L1, yyaction(A1, Alen1, Tcs, Tline), Error);
{A1,Alen1,Tlen1,[],L1,S1} -> % After a non-accepting state
{more,{skip_tokens,S1,L1,Tcs,Tlen1,Tline,Error,A1,Alen1}};
{reject,_Alen1,_Tlen1,eof,L1,_S1} ->
{done,{error,Error,L1},eof};
{reject,_Alen1,Tlen1,_Ics1,L1,_S1} ->
skip_tokens(yysuf(Tcs, Tlen1+1), L1, Error);
{A1,Alen1,Tlen1,_Ics1,L1,_S1} ->
Token = yyaction(A1, Alen1, Tcs, Tline),
Tcs1 = yysuf(Tcs, Alen1),
L2 = adjust_line(Tlen1, Alen1, Tcs1, L1),
skip_cont(Tcs1, L2, Token, Error)
end.
%% skip_cont(RestChars, Line, Token, Error)
%% Skip tokens until we have an end_token or error then return done
%% with the original rror.
-dialyzer({nowarn_function, skip_cont/4}).
skip_cont(Rest, Line, {token,_T}, Error) ->
skip_tokens(yystate(), Rest, Line, Rest, 0, Line, Error, reject, 0);
skip_cont(Rest, Line, {token,_T,Push}, Error) ->
NewRest = Push ++ Rest,
skip_tokens(yystate(), NewRest, Line, NewRest, 0, Line, Error, reject, 0);
skip_cont(Rest, Line, {end_token,_T}, Error) ->
{done,{error,Error,Line},Rest};
skip_cont(Rest, Line, {end_token,_T,Push}, Error) ->
NewRest = Push ++ Rest,
{done,{error,Error,Line},NewRest};
skip_cont(Rest, Line, skip_token, Error) ->
skip_tokens(yystate(), Rest, Line, Rest, 0, Line, Error, reject, 0);
skip_cont(Rest, Line, {skip_token,Push}, Error) ->
NewRest = Push ++ Rest,
skip_tokens(yystate(), NewRest, Line, NewRest, 0, Line, Error, reject, 0);
skip_cont(Rest, Line, {error,_S}, Error) ->
skip_tokens(yystate(), Rest, Line, Rest, 0, Line, Error, reject, 0).
-compile({nowarn_unused_function, [yyrev/1, yyrev/2, yypre/2, yysuf/2]}).
yyrev(List) -> lists:reverse(List).
yyrev(List, Tail) -> lists:reverse(List, Tail).
yypre(List, N) -> lists:sublist(List, N).
yysuf(List, N) -> lists:nthtail(N, List).
%% adjust_line(TokenLength, AcceptLength, Chars, Line) -> NewLine
%% Make sure that newlines in Chars are not counted twice.
%% Line has been updated with respect to newlines in the prefix of
%% Chars consisting of (TokenLength - AcceptLength) characters.
-compile({nowarn_unused_function, adjust_line/4}).
adjust_line(N, N, _Cs, L) -> L;
adjust_line(T, A, [$\n|Cs], L) ->
adjust_line(T-1, A, Cs, L-1);
adjust_line(T, A, [_|Cs], L) ->
adjust_line(T-1, A, Cs, L).
%% yystate() -> InitialState.
%% yystate(State, InChars, Line, CurrTokLen, AcceptAction, AcceptLen) ->
%% {Action, AcceptLen, RestChars, Line} |
%% {Action, AcceptLen, RestChars, Line, State} |
%% {reject, AcceptLen, CurrTokLen, RestChars, Line, State} |
%% {Action, AcceptLen, CurrTokLen, RestChars, Line, State}.
%% Generated state transition functions. The non-accepting end state
%% return signal either an unrecognised character or end of current
%% input.
-file("/Users/starbelly/devel/erlang/rebar3/src/hex_core/r3_safe_erl_term.erl", 360).
yystate() -> 13.
yystate(20, [60|Ics], Line, Tlen, Action, Alen) ->
yystate(10, Ics, Line, Tlen+1, Action, Alen);
yystate(20, Ics, Line, Tlen, Action, Alen) ->
{Action,Alen,Tlen,Ics,Line,20};
yystate(19, [92|Ics], Line, Tlen, Action, Alen) ->
yystate(11, Ics, Line, Tlen+1, Action, Alen);
yystate(19, [39|Ics], Line, Tlen, Action, Alen) ->
yystate(15, Ics, Line, Tlen+1, Action, Alen);
yystate(19, [10|Ics], Line, Tlen, Action, Alen) ->
yystate(0, Ics, Line+1, Tlen+1, Action, Alen);
yystate(19, [C|Ics], Line, Tlen, Action, Alen) when C >= 0, C =< 9 ->
yystate(0, Ics, Line, Tlen+1, Action, Alen);
yystate(19, [C|Ics], Line, Tlen, Action, Alen) when C >= 11, C =< 38 ->
yystate(0, Ics, Line, Tlen+1, Action, Alen);
yystate(19, [C|Ics], Line, Tlen, Action, Alen) when C >= 40, C =< 91 ->
yystate(0, Ics, Line, Tlen+1, Action, Alen);
yystate(19, [C|Ics], Line, Tlen, Action, Alen) when C >= 93 ->
yystate(0, Ics, Line, Tlen+1, Action, Alen);
yystate(19, Ics, Line, Tlen, Action, Alen) ->
{Action,Alen,Tlen,Ics,Line,19};
yystate(18, [92|Ics], Line, Tlen, Action, Alen) ->
yystate(14, Ics, Line, Tlen+1, Action, Alen);
yystate(18, [34|Ics], Line, Tlen, Action, Alen) ->
yystate(6, Ics, Line, Tlen+1, Action, Alen);
yystate(18, [10|Ics], Line, Tlen, Action, Alen) ->
yystate(9, Ics, Line+1, Tlen+1, Action, Alen);
yystate(18, [C|Ics], Line, Tlen, Action, Alen) when C >= 0, C =< 9 ->
yystate(9, Ics, Line, Tlen+1, Action, Alen);
yystate(18, [C|Ics], Line, Tlen, Action, Alen) when C >= 11, C =< 33 ->
yystate(9, Ics, Line, Tlen+1, Action, Alen);
yystate(18, [C|Ics], Line, Tlen, Action, Alen) when C >= 35, C =< 91 ->
yystate(9, Ics, Line, Tlen+1, Action, Alen);
yystate(18, [C|Ics], Line, Tlen, Action, Alen) when C >= 93 ->
yystate(9, Ics, Line, Tlen+1, Action, Alen);
yystate(18, Ics, Line, Tlen, Action, Alen) ->
{Action,Alen,Tlen,Ics,Line,18};
yystate(17, [37|Ics], Line, Tlen, _, _) ->
yystate(8, Ics, Line, Tlen+1, 8, Tlen);
yystate(17, [10|Ics], Line, Tlen, _, _) ->
yystate(17, Ics, Line+1, Tlen+1, 8, Tlen);
yystate(17, [C|Ics], Line, Tlen, _, _) when C >= 0, C =< 9 ->
yystate(17, Ics, Line, Tlen+1, 8, Tlen);
yystate(17, [C|Ics], Line, Tlen, _, _) when C >= 11, C =< 32 ->
yystate(17, Ics, Line, Tlen+1, 8, Tlen);
yystate(17, Ics, Line, Tlen, _, _) ->
{8,Tlen,Ics,Line,17};
yystate(16, Ics, Line, Tlen, _, _) ->
{4,Tlen,Ics,Line};
yystate(15, [92|Ics], Line, Tlen, _, _) ->
yystate(11, Ics, Line, Tlen+1, 1, Tlen);
yystate(15, [39|Ics], Line, Tlen, _, _) ->
yystate(7, Ics, Line, Tlen+1, 1, Tlen);
yystate(15, [10|Ics], Line, Tlen, _, _) ->
yystate(0, Ics, Line+1, Tlen+1, 1, Tlen);
yystate(15, [C|Ics], Line, Tlen, _, _) when C >= 0, C =< 9 ->
yystate(0, Ics, Line, Tlen+1, 1, Tlen);
yystate(15, [C|Ics], Line, Tlen, _, _) when C >= 11, C =< 38 ->
yystate(0, Ics, Line, Tlen+1, 1, Tlen);
yystate(15, [C|Ics], Line, Tlen, _, _) when C >= 40, C =< 91 ->
yystate(0, Ics, Line, Tlen+1, 1, Tlen);
yystate(15, [C|Ics], Line, Tlen, _, _) when C >= 93 ->
yystate(0, Ics, Line, Tlen+1, 1, Tlen);
yystate(15, Ics, Line, Tlen, _, _) ->
{1,Tlen,Ics,Line,15};
yystate(14, [94|Ics], Line, Tlen, Action, Alen) ->
yystate(18, Ics, Line, Tlen+1, Action, Alen);
yystate(14, [93|Ics], Line, Tlen, Action, Alen) ->
yystate(9, Ics, Line, Tlen+1, Action, Alen);
yystate(14, [92|Ics], Line, Tlen, Action, Alen) ->
yystate(14, Ics, Line, Tlen+1, Action, Alen);
yystate(14, [34|Ics], Line, Tlen, Action, Alen) ->
yystate(6, Ics, Line, Tlen+1, Action, Alen);
yystate(14, [10|Ics], Line, Tlen, Action, Alen) ->
yystate(9, Ics, Line+1, Tlen+1, Action, Alen);
yystate(14, [C|Ics], Line, Tlen, Action, Alen) when C >= 0, C =< 9 ->
yystate(9, Ics, Line, Tlen+1, Action, Alen);
yystate(14, [C|Ics], Line, Tlen, Action, Alen) when C >= 11, C =< 33 ->
yystate(9, Ics, Line, Tlen+1, Action, Alen);
yystate(14, [C|Ics], Line, Tlen, Action, Alen) when C >= 35, C =< 91 ->
yystate(9, Ics, Line, Tlen+1, Action, Alen);
yystate(14, [C|Ics], Line, Tlen, Action, Alen) when C >= 95 ->
yystate(9, Ics, Line, Tlen+1, Action, Alen);
yystate(14, Ics, Line, Tlen, Action, Alen) ->
{Action,Alen,Tlen,Ics,Line,14};
yystate(13, [125|Ics], Line, Tlen, Action, Alen) ->
yystate(16, Ics, Line, Tlen+1, Action, Alen);
yystate(13, [123|Ics], Line, Tlen, Action, Alen) ->
yystate(16, Ics, Line, Tlen+1, Action, Alen);
yystate(13, [93|Ics], Line, Tlen, Action, Alen) ->
yystate(16, Ics, Line, Tlen+1, Action, Alen);
yystate(13, [91|Ics], Line, Tlen, Action, Alen) ->
yystate(16, Ics, Line, Tlen+1, Action, Alen);
yystate(13, [62|Ics], Line, Tlen, Action, Alen) ->
yystate(2, Ics, Line, Tlen+1, Action, Alen);
yystate(13, [61|Ics], Line, Tlen, Action, Alen) ->
yystate(2, Ics, Line, Tlen+1, Action, Alen);
yystate(13, [60|Ics], Line, Tlen, Action, Alen) ->
yystate(20, Ics, Line, Tlen+1, Action, Alen);
yystate(13, [47|Ics], Line, Tlen, Action, Alen) ->
yystate(4, Ics, Line, Tlen+1, Action, Alen);
yystate(13, [46|Ics], Line, Tlen, Action, Alen) ->
yystate(3, Ics, Line, Tlen+1, Action, Alen);
yystate(13, [39|Ics], Line, Tlen, Action, Alen) ->
yystate(0, Ics, Line, Tlen+1, Action, Alen);
yystate(13, [37|Ics], Line, Tlen, Action, Alen) ->
yystate(8, Ics, Line, Tlen+1, Action, Alen);
yystate(13, [35|Ics], Line, Tlen, Action, Alen) ->
yystate(16, Ics, Line, Tlen+1, Action, Alen);
yystate(13, [34|Ics], Line, Tlen, Action, Alen) ->
yystate(9, Ics, Line, Tlen+1, Action, Alen);
yystate(13, [10|Ics], Line, Tlen, Action, Alen) ->
yystate(17, Ics, Line+1, Tlen+1, Action, Alen);
yystate(13, [C|Ics], Line, Tlen, Action, Alen) when C >= 0, C =< 9 ->
yystate(17, Ics, Line, Tlen+1, Action, Alen);
yystate(13, [C|Ics], Line, Tlen, Action, Alen) when C >= 11, C =< 32 ->
yystate(17, Ics, Line, Tlen+1, Action, Alen);
yystate(13, [C|Ics], Line, Tlen, Action, Alen) when C >= 43, C =< 45 ->
yystate(16, Ics, Line, Tlen+1, Action, Alen);
yystate(13, [C|Ics], Line, Tlen, Action, Alen) when C >= 48, C =< 57 ->
yystate(12, Ics, Line, Tlen+1, Action, Alen);
yystate(13, [C|Ics], Line, Tlen, Action, Alen) when C >= 97, C =< 122 ->
yystate(5, Ics, Line, Tlen+1, Action, Alen);
yystate(13, Ics, Line, Tlen, Action, Alen) ->
{Action,Alen,Tlen,Ics,Line,13};
yystate(12, [C|Ics], Line, Tlen, _, _) when C >= 48, C =< 57 ->
yystate(12, Ics, Line, Tlen+1, 3, Tlen);
yystate(12, Ics, Line, Tlen, _, _) ->
{3,Tlen,Ics,Line,12};
yystate(11, [94|Ics], Line, Tlen, Action, Alen) ->
yystate(19, Ics, Line, Tlen+1, Action, Alen);
yystate(11, [93|Ics], Line, Tlen, Action, Alen) ->
yystate(0, Ics, Line, Tlen+1, Action, Alen);
yystate(11, [92|Ics], Line, Tlen, Action, Alen) ->
yystate(11, Ics, Line, Tlen+1, Action, Alen);
yystate(11, [39|Ics], Line, Tlen, Action, Alen) ->
yystate(15, Ics, Line, Tlen+1, Action, Alen);
yystate(11, [10|Ics], Line, Tlen, Action, Alen) ->
yystate(0, Ics, Line+1, Tlen+1, Action, Alen);
yystate(11, [C|Ics], Line, Tlen, Action, Alen) when C >= 0, C =< 9 ->
yystate(0, Ics, Line, Tlen+1, Action, Alen);
yystate(11, [C|Ics], Line, Tlen, Action, Alen) when C >= 11, C =< 38 ->
yystate(0, Ics, Line, Tlen+1, Action, Alen);
yystate(11, [C|Ics], Line, Tlen, Action, Alen) when C >= 40, C =< 91 ->
yystate(0, Ics, Line, Tlen+1, Action, Alen);
yystate(11, [C|Ics], Line, Tlen, Action, Alen) when C >= 95 ->
yystate(0, Ics, Line, Tlen+1, Action, Alen);
yystate(11, Ics, Line, Tlen, Action, Alen) ->
{Action,Alen,Tlen,Ics,Line,11};
yystate(10, Ics, Line, Tlen, _, _) ->
{5,Tlen,Ics,Line};
yystate(9, [92|Ics], Line, Tlen, Action, Alen) ->
yystate(14, Ics, Line, Tlen+1, Action, Alen);
yystate(9, [34|Ics], Line, Tlen, Action, Alen) ->
yystate(1, Ics, Line, Tlen+1, Action, Alen);
yystate(9, [10|Ics], Line, Tlen, Action, Alen) ->
yystate(9, Ics, Line+1, Tlen+1, Action, Alen);
yystate(9, [C|Ics], Line, Tlen, Action, Alen) when C >= 0, C =< 9 ->
yystate(9, Ics, Line, Tlen+1, Action, Alen);
yystate(9, [C|Ics], Line, Tlen, Action, Alen) when C >= 11, C =< 33 ->
yystate(9, Ics, Line, Tlen+1, Action, Alen);
yystate(9, [C|Ics], Line, Tlen, Action, Alen) when C >= 35, C =< 91 ->
yystate(9, Ics, Line, Tlen+1, Action, Alen);
yystate(9, [C|Ics], Line, Tlen, Action, Alen) when C >= 93 ->
yystate(9, Ics, Line, Tlen+1, Action, Alen);
yystate(9, Ics, Line, Tlen, Action, Alen) ->
{Action,Alen,Tlen,Ics,Line,9};
yystate(8, [37|Ics], Line, Tlen, _, _) ->
yystate(8, Ics, Line, Tlen+1, 8, Tlen);
yystate(8, [10|Ics], Line, Tlen, _, _) ->
yystate(17, Ics, Line+1, Tlen+1, 8, Tlen);
yystate(8, [C|Ics], Line, Tlen, _, _) when C >= 0, C =< 9 ->
yystate(8, Ics, Line, Tlen+1, 8, Tlen);
yystate(8, [C|Ics], Line, Tlen, _, _) when C >= 11, C =< 32 ->
yystate(8, Ics, Line, Tlen+1, 8, Tlen);
yystate(8, [C|Ics], Line, Tlen, _, _) when C >= 33, C =< 36 ->
yystate(8, Ics, Line, Tlen+1, 8, Tlen);
yystate(8, [C|Ics], Line, Tlen, _, _) when C >= 38 ->
yystate(8, Ics, Line, Tlen+1, 8, Tlen);
yystate(8, Ics, Line, Tlen, _, _) ->
{8,Tlen,Ics,Line,8};
yystate(7, Ics, Line, Tlen, _, _) ->
{1,Tlen,Ics,Line};
yystate(6, [92|Ics], Line, Tlen, _, _) ->
yystate(14, Ics, Line, Tlen+1, 2, Tlen);
yystate(6, [34|Ics], Line, Tlen, _, _) ->
yystate(1, Ics, Line, Tlen+1, 2, Tlen);
yystate(6, [10|Ics], Line, Tlen, _, _) ->
yystate(9, Ics, Line+1, Tlen+1, 2, Tlen);
yystate(6, [C|Ics], Line, Tlen, _, _) when C >= 0, C =< 9 ->
yystate(9, Ics, Line, Tlen+1, 2, Tlen);
yystate(6, [C|Ics], Line, Tlen, _, _) when C >= 11, C =< 33 ->
yystate(9, Ics, Line, Tlen+1, 2, Tlen);
yystate(6, [C|Ics], Line, Tlen, _, _) when C >= 35, C =< 91 ->
yystate(9, Ics, Line, Tlen+1, 2, Tlen);
yystate(6, [C|Ics], Line, Tlen, _, _) when C >= 93 ->
yystate(9, Ics, Line, Tlen+1, 2, Tlen);
yystate(6, Ics, Line, Tlen, _, _) ->
{2,Tlen,Ics,Line,6};
yystate(5, [95|Ics], Line, Tlen, _, _) ->
yystate(5, Ics, Line, Tlen+1, 0, Tlen);
yystate(5, [64|Ics], Line, Tlen, _, _) ->
yystate(5, Ics, Line, Tlen+1, 0, Tlen);
yystate(5, [C|Ics], Line, Tlen, _, _) when C >= 48, C =< 57 ->
yystate(5, Ics, Line, Tlen+1, 0, Tlen);
yystate(5, [C|Ics], Line, Tlen, _, _) when C >= 65, C =< 90 ->
yystate(5, Ics, Line, Tlen+1, 0, Tlen);
yystate(5, [C|Ics], Line, Tlen, _, _) when C >= 97, C =< 122 ->
yystate(5, Ics, Line, Tlen+1, 0, Tlen);
yystate(5, Ics, Line, Tlen, _, _) ->
{0,Tlen,Ics,Line,5};
yystate(4, Ics, Line, Tlen, _, _) ->
{7,Tlen,Ics,Line};
yystate(3, Ics, Line, Tlen, _, _) ->
{6,Tlen,Ics,Line};
yystate(2, [62|Ics], Line, Tlen, Action, Alen) ->
yystate(10, Ics, Line, Tlen+1, Action, Alen);
yystate(2, Ics, Line, Tlen, Action, Alen) ->
{Action,Alen,Tlen,Ics,Line,2};
yystate(1, Ics, Line, Tlen, _, _) ->
{2,Tlen,Ics,Line};
yystate(0, [92|Ics], Line, Tlen, Action, Alen) ->
yystate(11, Ics, Line, Tlen+1, Action, Alen);
yystate(0, [39|Ics], Line, Tlen, Action, Alen) ->
yystate(7, Ics, Line, Tlen+1, Action, Alen);
yystate(0, [10|Ics], Line, Tlen, Action, Alen) ->
yystate(0, Ics, Line+1, Tlen+1, Action, Alen);
yystate(0, [C|Ics], Line, Tlen, Action, Alen) when C >= 0, C =< 9 ->
yystate(0, Ics, Line, Tlen+1, Action, Alen);
yystate(0, [C|Ics], Line, Tlen, Action, Alen) when C >= 11, C =< 38 ->
yystate(0, Ics, Line, Tlen+1, Action, Alen);
yystate(0, [C|Ics], Line, Tlen, Action, Alen) when C >= 40, C =< 91 ->
yystate(0, Ics, Line, Tlen+1, Action, Alen);
yystate(0, [C|Ics], Line, Tlen, Action, Alen) when C >= 93 ->
yystate(0, Ics, Line, Tlen+1, Action, Alen);
yystate(0, Ics, Line, Tlen, Action, Alen) ->
{Action,Alen,Tlen,Ics,Line,0};
yystate(S, Ics, Line, Tlen, Action, Alen) ->
{Action,Alen,Tlen,Ics,Line,S}.
%% yyaction(Action, TokenLength, TokenChars, TokenLine) ->
%% {token,Token} | {end_token, Token} | skip_token | {error,String}.
%% Generated action function.
yyaction(0, TokenLen, YYtcs, TokenLine) ->
TokenChars = yypre(YYtcs, TokenLen),
yyaction_0(TokenChars, TokenLine);
yyaction(1, TokenLen, YYtcs, TokenLine) ->
TokenChars = yypre(YYtcs, TokenLen),
yyaction_1(TokenChars, TokenLen, TokenLine);
yyaction(2, TokenLen, YYtcs, TokenLine) ->
TokenChars = yypre(YYtcs, TokenLen),
yyaction_2(TokenChars, TokenLen, TokenLine);
yyaction(3, TokenLen, YYtcs, TokenLine) ->
TokenChars = yypre(YYtcs, TokenLen),
yyaction_3(TokenChars, TokenLine);
yyaction(4, TokenLen, YYtcs, TokenLine) ->
TokenChars = yypre(YYtcs, TokenLen),
yyaction_4(TokenChars, TokenLine);
yyaction(5, TokenLen, YYtcs, TokenLine) ->
TokenChars = yypre(YYtcs, TokenLen),
yyaction_5(TokenChars, TokenLine);
yyaction(6, _, _, TokenLine) ->
yyaction_6(TokenLine);
yyaction(7, _, _, TokenLine) ->
yyaction_7(TokenLine);
yyaction(8, _, _, _) ->
yyaction_8();
yyaction(_, _, _, _) -> error.
-compile({inline,yyaction_0/2}).
-file("/Users/starbelly/devel/erlang/rebar3/src/hex_core/r3_safe_erl_term.xrl", 14).
yyaction_0(TokenChars, TokenLine) ->
tokenize_atom (TokenChars, TokenLine) .
-compile({inline,yyaction_1/3}).
-file("/Users/starbelly/devel/erlang/rebar3/src/hex_core/r3_safe_erl_term.xrl", 15).
yyaction_1(TokenChars, TokenLen, TokenLine) ->
tokenize_atom (escape (unquote (TokenChars, TokenLen)), TokenLine) .
-compile({inline,yyaction_2/3}).
-file("/Users/starbelly/devel/erlang/rebar3/src/hex_core/r3_safe_erl_term.xrl", 16).
yyaction_2(TokenChars, TokenLen, TokenLine) ->
{ token, { string, TokenLine, escape (unquote (TokenChars, TokenLen)) } } .
-compile({inline,yyaction_3/2}).
-file("/Users/starbelly/devel/erlang/rebar3/src/hex_core/r3_safe_erl_term.xrl", 17).
yyaction_3(TokenChars, TokenLine) ->
{ token, { integer, TokenLine, list_to_integer (TokenChars) } } .
-compile({inline,yyaction_4/2}).
-file("/Users/starbelly/devel/erlang/rebar3/src/hex_core/r3_safe_erl_term.xrl", 18).
yyaction_4(TokenChars, TokenLine) ->
{ token, { list_to_atom (TokenChars), TokenLine } } .
-compile({inline,yyaction_5/2}).
-file("/Users/starbelly/devel/erlang/rebar3/src/hex_core/r3_safe_erl_term.xrl", 19).
yyaction_5(TokenChars, TokenLine) ->
{ token, { list_to_atom (TokenChars), TokenLine } } .
-compile({inline,yyaction_6/1}).
-file("/Users/starbelly/devel/erlang/rebar3/src/hex_core/r3_safe_erl_term.xrl", 20).
yyaction_6(TokenLine) ->
{ token, { dot, TokenLine } } .
-compile({inline,yyaction_7/1}).
-file("/Users/starbelly/devel/erlang/rebar3/src/hex_core/r3_safe_erl_term.xrl", 21).
yyaction_7(TokenLine) ->
{ token, { '/', TokenLine } } .
-compile({inline,yyaction_8/0}).
-file("/Users/starbelly/devel/erlang/rebar3/src/hex_core/r3_safe_erl_term.xrl", 22).
yyaction_8() ->
skip_token .
-file("/usr/local/lib/erlang/lib/parsetools-2.1.8/include/leexinc.hrl", 313).

+ 79
- 0
src/r3_safe_erl_term.xrl View File

@ -0,0 +1,79 @@
%% Vendored from hex_core v0.5.0, do not edit manually
%%% Author : Robert Virding
%%% Purpose : Token definitions for Erlang.
Definitions.
D = [0-9]
U = [A-Z]
L = [a-z]
A = ({U}|{L}|{D}|_|@)
WS = ([\000-\s]|%.*)
Rules.
{L}{A}* : tokenize_atom(TokenChars, TokenLine).
'(\\\^.|\\.|[^'])*' : tokenize_atom(escape(unquote(TokenChars, TokenLen)), TokenLine).
"(\\\^.|\\.|[^"])*" : {token, {string, TokenLine, escape(unquote(TokenChars, TokenLen))}}.
{D}+ : {token, {integer, TokenLine, list_to_integer(TokenChars)}}.
[\#\[\]}{,+-] : {token, {list_to_atom(TokenChars), TokenLine}}.
(<<|>>|=>) : {token, {list_to_atom(TokenChars), TokenLine}}.
\. : {token, {dot, TokenLine}}.
/ : {token, {'/', TokenLine}}.
{WS}+ : skip_token.
Erlang code.
-export([terms/1]).
terms(Tokens) ->
terms(Tokens, []).
terms([{dot, _} = H], Buffer) ->
[buffer_to_term([H|Buffer])];
terms([{dot, _} = H|T], Buffer) ->
[buffer_to_term([H|Buffer])|terms(T, [])];
terms([H|T], Buffer) ->
terms(T, [H|Buffer]).
buffer_to_term(Buffer) ->
{ok, Term} = erl_parse:parse_term(lists:reverse(Buffer)),
Term.
unquote(TokenChars, TokenLen) ->
lists:sublist(TokenChars, 2, TokenLen - 2).
tokenize_atom(TokenChars, TokenLine) ->
try list_to_existing_atom(TokenChars) of
Atom -> {token, {atom, TokenLine, Atom}}
catch
error:badarg -> {error, "illegal atom " ++ TokenChars}
end.
escape([$\\|Cs]) ->
do_escape(Cs);
escape([C|Cs]) ->
[C|escape(Cs)];
escape([]) -> [].
do_escape([O1,O2,O3|S]) when
O1 >= $0, O1 =< $7, O2 >= $0, O2 =< $7, O3 >= $0, O3 =< $7 ->
[(O1*8 + O2)*8 + O3 - 73*$0|escape(S)];
do_escape([$^,C|Cs]) ->
[C band 31|escape(Cs)];
do_escape([C|Cs]) when C >= $\000, C =< $\s ->
escape(Cs);
do_escape([C|Cs]) ->
[escape_char(C)|escape(Cs)].
escape_char($n) -> $\n; %\n = LF
escape_char($r) -> $\r; %\r = CR
escape_char($t) -> $\t; %\t = TAB
escape_char($v) -> $\v; %\v = VT
escape_char($b) -> $\b; %\b = BS
escape_char($f) -> $\f; %\f = FF
escape_char($e) -> $\e; %\e = ESC
escape_char($s) -> $\s; %\s = SPC
escape_char($d) -> $\d; %\d = DEL
escape_char(C) -> C.

+ 0
- 1
src/rebar.app.src View File

@ -30,7 +30,6 @@
relx,
cf,
inets,
hex_core,
eunit_formatters]},
{env, [
%% Default log level

+ 16
- 11
src/rebar_hex_repos.erl View File

@ -20,6 +20,7 @@
api_url => binary(),
api_key => binary(),
repo_url => binary(),
repo_key => binary(),
repo_public_key => binary(),
repo_verify => binary(),
repo_verify_origin => binary()}.
@ -68,17 +69,21 @@ repos(HexConfig) ->
merge_repos(RepoList ++ [HexDefaultConfig])
end.
%% merge repos must add a field repo_name to work with hex_core 0.4.0
%% merge repos must add a field repo_name to work with r3_hex_core 0.5.0
-spec merge_repos([repo()]) -> [repo()].
merge_repos(Repos) ->
lists:foldl(fun(R=#{name := Name}, ReposAcc) ->
%% private organizations include the parent repo before a :
lists:foldl(fun(R = #{name := Name}, ReposAcc) ->
%% private orgs are in the format of <<"parent:org">>
case rebar_string:split(Name, <<":">>) of
[Repo, Org] ->
%% hex_core uses repo_name for parent
%% We set the repo_organization and api_organization to org
%% for fetching and publishing private packages.
update_repo_list(R#{name => Name,
repo_name => Repo,
organization => Org,
repo_name => Org,
repo_organization => Org,
api_organization => Org,
api_repository => Org,
parent => Repo}, ReposAcc);
_ ->
update_repo_list(R#{repo_name => Name}, ReposAcc)
@ -86,15 +91,15 @@ merge_repos(Repos) ->
end, [], Repos).
update_organizations(Repos) ->
lists:map(fun(Repo=#{organization := Organization,
lists:map(fun(Repo=#{repo_name := RepoName,
parent := ParentName}) ->
{ok, Parent} = get_repo_config(ParentName, Repos),
ParentRepoUrl = rebar_utils:to_list(maps:get(repo_url, Parent)),
{ok, RepoUrl} =
{ok, _RepoUrl} =
rebar_utils:url_append_path(ParentRepoUrl,
filename:join("repos", rebar_utils:to_list(Organization))),
filename:join("repos", rebar_utils:to_list(RepoName))),
%% still let the organization config override this constructed repo url
maps:merge(Parent#{repo_url => rebar_utils:to_binary(RepoUrl)}, Repo);
maps:merge(Parent#{repo_url => rebar_utils:to_binary(ParentRepoUrl)}, Repo);
(Repo) ->
Repo
end, Repos).
@ -107,7 +112,7 @@ update_repo_list(R, []) ->
[R].
default_repo() ->
HexDefaultConfig = hex_core:default_config(),
HexDefaultConfig = r3_hex_core:default_config(),
HexDefaultConfig#{name => ?PUBLIC_HEX_REPO, repo_verify_origin => repo_verify_origin()}.
repo_verify_origin() ->

+ 3
- 5
src/rebar_packages.erl View File

@ -31,7 +31,7 @@ format_error({missing_package, Pkg}) ->
-spec get(rebar_hex_repos:repo(), binary()) -> {ok, map()} | {error, term()}.
get(Config, Name) ->
try hex_api_package:get(Config, Name) of
try r3_hex_api_package:get(Config, Name) of
{ok, {200, _Headers, PkgInfo}} ->
{ok, PkgInfo};
{ok, {404, _, _}} ->
@ -233,7 +233,7 @@ parse_checksum(Checksum) ->
update_package(Name, RepoConfig=#{name := Repo}, State) ->
?MODULE:verify_table(State),
try hex_repo:get_package(get_package_repo_config(RepoConfig), Name) of
try r3_hex_repo:get_package(get_package_repo_config(RepoConfig), Name) of
{ok, {200, _Headers, Releases}} ->
_ = insert_releases(Name, Releases, Repo, ?PACKAGE_TABLE),
{ok, RegistryDir} = rebar_packages:registry_dir(State),
@ -244,7 +244,7 @@ update_package(Name, RepoConfig=#{name := Repo}, State) ->
fail;
Error ->
?DEBUG("Hex get_package request failed: ~p", [Error]),
%% TODO: add better log message. hex_core should export a format_error
%% TODO: add better log message. r3_hex_core should export a format_error
?WARN("Failed to update package from repo ~ts", [Repo]),
fail
catch
@ -255,8 +255,6 @@ update_package(Name, RepoConfig=#{name := Repo}, State) ->
get_package_repo_config(RepoConfig=#{mirror_of := Repo}) ->
get_package_repo_config(maps:remove(mirror_of, RepoConfig#{name => Repo}));
get_package_repo_config(RepoConfig=#{read_key := Key}) ->
get_package_repo_config(maps:remove(read_key, RepoConfig#{repo_key => Key}));
get_package_repo_config(RepoConfig) ->
RepoConfig.

+ 3
- 3
src/rebar_pkg_resource.erl View File

@ -29,7 +29,7 @@
-spec init(atom(), rebar_state:t()) -> {ok, rebar_resource_v2:resource()}.
init(Type, State) ->
{ok, Vsn} = application:get_key(rebar, vsn),
BaseConfig = #{http_adapter => hex_http_httpc,
BaseConfig = #{http_adapter => r3_hex_http_httpc,
http_user_agent_fragment =>
<<"(rebar3/", (list_to_binary(Vsn))/binary, ") (httpc)">>,
http_adapter_config => #{profile => rebar}},
@ -148,7 +148,7 @@ format_error({bad_registry_checksum, Name, Vsn, Expected, Found}) ->
-> {ok, cached} | {ok, binary(), binary()} | error.
request(Config, Name, Version, ETag) ->
Config1 = Config#{http_etag => ETag},
try hex_repo:get_tarball(Config1, Name, Version) of
try r3_hex_repo:get_tarball(Config1, Name, Version) of
{ok, {200, #{<<"etag">> := ETag1}, Tarball}} ->
{ok, Tarball, ETag1};
{ok, {304, _Headers, _}} ->
@ -248,7 +248,7 @@ serve_from_cache(TmpDir, CachePath, Pkg) ->
Res :: ok | {error,_} | {bad_registry_checksum, integer(), integer()}.
serve_from_memory(TmpDir, Binary, {pkg, _Name, _Vsn, Hash, _RepoConfig}) ->
RegistryChecksum = list_to_integer(binary_to_list(Hash), 16),
case hex_tarball:unpack(Binary, TmpDir) of
case r3_hex_tarball:unpack(Binary, TmpDir) of
{ok, #{checksum := <<Checksum:256/big-unsigned>>}} when RegistryChecksum =/= Checksum ->
?DEBUG("Expected hash ~64.16.0B does not match checksum of fetched package ~64.16.0B",
[RegistryChecksum, Checksum]),

+ 1
- 1
src/rebar_utils.erl View File

@ -915,7 +915,7 @@ url_append_path(Url, ExtraPath) ->
case http_uri:parse(Url) of
{ok, {Scheme, UserInfo, Host, Port, Path, Query}} ->
{ok, lists:append([atom_to_list(Scheme), "://", UserInfo, Host, ":", integer_to_list(Port),
filename:join(Path, ExtraPath), "?", Query])};
filename:join(Path, ExtraPath), Query])};
_ ->
error
end.

+ 1
- 1
test/mock_pkg_resource.erl View File

@ -100,7 +100,7 @@ mock_download(Opts) ->
<<"version">> => Vsn},
Files = all_files(rebar_app_info:dir(AppInfo1)),
{ok, {Tarball, _Checksum}} = hex_tarball:create(Metadata, archive_names(Dir, Files)),
{ok, {Tarball, _Checksum}} = r3_hex_tarball:create(Metadata, archive_names(Dir, Files)),
Archive = filename:join([Dir, TarApp]),
file:write_file(Archive, Tarball),

+ 5
- 5
test/rebar_pkg_SUITE.erl View File

@ -97,7 +97,7 @@ init_per_testcase(bad_disconnect=Name, Config0) ->
{pkg, Pkg}
| Config0],
Config = mock_config(Name, Config1),
meck:expect(hex_repo, get_tarball, fun(_, _, _) ->
meck:expect(r3_hex_repo, get_tarball, fun(_, _, _) ->
{error, econnrefused}
end),
Config;
@ -281,8 +281,8 @@ mock_config(Name, Config) ->
end, AllDeps),
meck:new(hex_repo, [passthrough]),
meck:expect(hex_repo, get_package,
meck:new(r3_hex_repo, [passthrough]),
meck:expect(r3_hex_repo, get_package,
fun(_Config, PkgName) ->
Matches = ets:match_object(Tid, {{PkgName,'_'}, '_'}),
Releases =
@ -303,7 +303,7 @@ mock_config(Name, Config) ->
end),
meck:expect(rebar_state, resources,
fun(_State) ->
DefaultConfig = hex_core:default_config(),
DefaultConfig = r3_hex_core:default_config(),
[rebar_resource_v2:new(pkg, rebar_pkg_resource,
#{repos => [DefaultConfig#{name => <<"hexpm">>}],
base_config => #{}})]
@ -325,7 +325,7 @@ mock_config(Name, Config) ->
PkgFile = <<Pkg/binary, "-", Vsn/binary, ".tar">>,
{ok, PkgContents} = file:read_file(filename:join(?config(data_dir, Config), PkgFile)),
meck:expect(hex_repo, get_tarball, fun(_, _, _) when GoodCache ->
meck:expect(r3_hex_repo, get_tarball, fun(_, _, _) when GoodCache ->
{ok, {304, #{<<"etag">> => ?good_etag}, <<>>}};
(_, _, _) ->
{ok, {200, #{<<"etag">> => ?good_etag}, PkgContents}}

+ 3
- 3
test/rebar_pkg_alias_SUITE.erl View File

@ -241,8 +241,8 @@ mock_config(Name, Config) ->
end, AllDeps),
meck:new(hex_repo, [passthrough]),
meck:expect(hex_repo, get_package,
meck:new(r3_hex_repo, [passthrough]),
meck:expect(r3_hex_repo, get_package,
fun(_Config, PkgName) ->
Matches = ets:match_object(Tid, {{PkgName,'_'}, '_'}),
Releases =
@ -254,7 +254,7 @@ mock_config(Name, Config) ->
{ok, {200, #{}, Releases}}
end),
meck:expect(hex_repo, get_tarball, fun(_, _, _) ->
meck:expect(r3_hex_repo, get_tarball, fun(_, _, _) ->
{ok, {304, #{<<"etag">> => EtagGood}, <<>>}}
end),

+ 9
- 0
test/rebar_pkg_repos_SUITE.erl View File

@ -291,14 +291,23 @@ organization_merging(_Config) ->
?assertMatch({ok,
#resource{state=#{repos := [#{name := <<"hexpm:repo-1">>,
parent := <<"hexpm">>,
repo_name := <<"repo-1">>,
api_repository := <<"repo-1">>,
repo_organization := <<"repo-1">>,
read_key := <<"read key">>,
write_key := <<"write key hexpm">>},
#{name := <<"hexpm:repo-2">>,
parent := <<"hexpm">>,
repo_name := <<"repo-2">>,
api_repository := <<"repo-2">>,
repo_organization := <<"repo-2">>,
read_key := <<"read key 2">>,
repos_key := <<"repos key 2">>,
write_key := <<"write key 2">>},
#{name := <<"hexpm">>,
repo_name := <<"hexpm">>,
api_repository := undefined,
repo_organization := undefined,
write_key := <<"write key hexpm">>}]}}},
rebar_pkg_resource:init(pkg, State)),

+ 1
- 1
test/rebar_test_utils.erl View File

@ -511,7 +511,7 @@ package_app(AppDir, DestDir, PkgName, PkgVsn) ->
Files = lists:zip([filename:join("src", F) || F <- Fs], [filename:join(AppSrc,F) || F <- Fs]),
Metadata = #{<<"app">> => list_to_binary(PkgName),
<<"version">> => list_to_binary(PkgVsn)},
{ok, {Tarball, <<Checksum:256/big-unsigned-integer>>}} = hex_tarball:create(Metadata, Files),
{ok, {Tarball, <<Checksum:256/big-unsigned-integer>>}} = r3_hex_tarball:create(Metadata, Files),
Name = PkgName++"-"++PkgVsn++".tar",
Archive = filename:join(DestDir, Name),

+ 8
- 2
test/rebar_utils_SUITE.erl View File

@ -33,7 +33,8 @@
sh_does_not_miss_messages/1,
tup_merge/1,
proxy_auth/1,
is_list_of_strings/1]).
is_list_of_strings/1,
url_append_path/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
@ -49,7 +50,7 @@ all() ->
[{group, args_to_tasks},
sh_does_not_miss_messages,
tup_merge,
proxy_auth, is_list_of_strings].
proxy_auth, is_list_of_strings, url_append_path].
groups() ->
[{args_to_tasks, [], [empty_arglist,
@ -319,3 +320,8 @@ is_list_of_strings(_Config) ->
?assert(rebar_utils:is_list_of_strings([])),
?assert(rebar_utils:is_list_of_strings("")),
?assert(rebar_utils:is_list_of_strings("foo") == false).
url_append_path(_Config) ->
?assertEqual({ok, "https://repo.hex.pm:443/repos/org"}, rebar_utils:url_append_path("https://repo.hex.pm", "/repos/org")),
?assertEqual({ok, "https://repo.hex.pm:443/repos/org?foo=bar"}, rebar_utils:url_append_path("https://repo.hex.pm",
"/repos/org?foo=bar")).

Loading…
Cancel
Save