- %% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
- %% ex: ts=4 sw=4 et
-
- -module(rebar_prv_update).
-
- -behaviour(provider).
-
- -export([init/1,
- do/1,
- format_error/1]).
-
- -include("rebar.hrl").
- -include_lib("providers/include/providers.hrl").
-
- -define(PROVIDER, update).
- -define(DEPS, []).
-
- %% ===================================================================
- %% Public API
- %% ===================================================================
-
- -spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
- init(State) ->
- State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER},
- {module, ?MODULE},
- {bare, false},
- {deps, ?DEPS},
- {example, "rebar3 update"},
- {short_desc, "Update package index."},
- {desc, "Update package index."},
- {opts, []}])),
- {ok, State1}.
-
- -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
- do(State) ->
- ?INFO("Updating package index...", []),
- try
- Dir = rebar_dir:global_cache_dir(State),
- RegistryDir = filename:join(Dir, "packages"),
- filelib:ensure_dir(filename:join(RegistryDir, "dummy")),
- HexFile = filename:join(RegistryDir, "registry"),
- TmpDir = ec_file:insecure_mkdtemp(),
- TmpFile = filename:join(TmpDir, "packages.gz"),
-
- Url = rebar_state:get(State, rebar_packages_cdn, "https://s3.amazonaws.com/s3.hex.pm/registry.ets.gz"),
- {ok, _RequestId} = httpc:request(get, {Url, []},
- [], [{stream, TmpFile}, {sync, true}]),
- {ok, Data} = file:read_file(TmpFile),
- Unzipped = zlib:gunzip(Data),
- ok = file:write_file(HexFile, Unzipped),
- {Dict, Graph} = hex_to_graph(HexFile),
- write_registry(Dict, Graph, State),
- ok
- catch
- _E:_C ->
- throw(?PRV_ERROR(package_index_write))
- end,
-
- {ok, State}.
-
- -spec format_error(any()) -> iolist().
- format_error(package_index_write) ->
- "Failed to write package index.".
-
- write_registry(Dict, {digraph, Edges, Vertices, Neighbors, _}, State) ->
- Dir = rebar_dir:global_cache_dir(State),
- RegistryDir = filename:join(Dir, "packages"),
- filelib:ensure_dir(filename:join(RegistryDir, "dummy")),
- ets:tab2file(Edges, filename:join(RegistryDir, "edges")),
- ets:tab2file(Vertices, filename:join(RegistryDir, "vertices")),
- ets:tab2file(Neighbors, filename:join(RegistryDir, "neighbors")),
- file:write_file(filename:join(RegistryDir, "dict"), term_to_binary(Dict)).
-
- hex_to_graph(Filename) ->
- {ok, T} = ets:file2tab(Filename),
- Graph = digraph:new(),
- ets:foldl(fun({Pkg, [Versions]}, ok) when is_binary(Pkg), is_list(Versions) ->
- lists:foreach(fun(Version) ->
- digraph:add_vertex(Graph, {Pkg, Version}, 1)
- end, Versions);
- (_, ok) ->
- ok
- end, ok, T),
-
- Dict1 = ets:foldl(fun({{Pkg, PkgVsn}, [Deps | _]}, Dict) ->
- DepsList = update_graph(Pkg, PkgVsn, Deps, T, Graph),
- dict:store({Pkg, PkgVsn}, DepsList, Dict);
- (_, Dict) ->
- Dict
- end, dict:new(), T),
- {Dict1, Graph}.
-
- update_graph(Pkg, PkgVsn, Deps, HexRegistry, Graph) ->
- lists:foldl(fun([Dep, DepVsn, false, _AppName | _], DepsListAcc) ->
- case DepVsn of
- <<"~> ", Vsn/binary>> ->
- HighestDepVsn = rebar_packages:find_highest_matching(Dep, Vsn, HexRegistry),
- digraph:add_edge(Graph, {Pkg, PkgVsn}, {Dep, HighestDepVsn}),
- [{Dep, DepVsn} | DepsListAcc];
- Vsn ->
- digraph:add_edge(Graph, {Pkg, PkgVsn}, {Dep, Vsn}),
- [{Dep, Vsn} | DepsListAcc]
- end;
- ([_Dep, _DepVsn, true, _AppName | _], DepsListAcc) ->
- DepsListAcc
- end, [], Deps).
|