- %% -*- 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]).
-
- -export([hex_to_index/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, true},
- {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) ->
- try
- RegistryDir = rebar_packages:registry_dir(State),
- filelib:ensure_dir(filename:join(RegistryDir, "dummy")),
- HexFile = filename:join(RegistryDir, "registry"),
- ?INFO("Updating package registry...", []),
- TmpDir = ec_file:insecure_mkdtemp(),
- TmpFile = filename:join(TmpDir, "packages.gz"),
-
- Url = rebar_state:get(State, rebar_packages_cdn, ?DEFAULT_HEX_REGISTRY),
- {ok, _RequestId} = httpc:request(get, {Url, []},
- [], [{stream, TmpFile}, {sync, true}],
- rebar),
- {ok, Data} = file:read_file(TmpFile),
- Unzipped = zlib:gunzip(Data),
- ok = file:write_file(HexFile, Unzipped),
- ?INFO("Writing registry to ~s", [HexFile]),
- hex_to_index(State),
- ok
- catch
- _E:C ->
- ?DEBUG("Error creating package index: ~p ~p", [C, erlang:get_stacktrace()]),
- throw(?PRV_ERROR(package_index_write))
- end,
-
- {ok, State}.
-
- -spec format_error(any()) -> iolist().
- format_error(package_index_write) ->
- "Failed to write package index.".
-
- is_supported(<<"make">>) -> true;
- is_supported(<<"rebar">>) -> true;
- is_supported(<<"rebar3">>) -> true;
- is_supported(_) -> false.
-
- hex_to_index(State) ->
- RegistryDir = rebar_packages:registry_dir(State),
- HexFile = filename:join(RegistryDir, "registry"),
- try ets:file2tab(HexFile) of
- {ok, Registry} ->
- try
- PackageIndex = filename:join(RegistryDir, "packages.idx"),
- ?INFO("Generating package index...", []),
- (catch ets:delete(?PACKAGE_TABLE)),
- ets:new(?PACKAGE_TABLE, [named_table, public]),
- ets:foldl(fun({{Pkg, PkgVsn}, [Deps, Checksum, BuildTools | _]}, _) when is_list(BuildTools) ->
- case lists:any(fun is_supported/1, BuildTools) of
- true ->
- DepsList = update_deps_list(Deps, Registry, State),
- ets:insert(?PACKAGE_TABLE, {{Pkg, PkgVsn}, DepsList, Checksum});
- false ->
- true
- end;
- ({Pkg, [Vsns]}, _) when is_binary(Pkg) ->
- ets:insert(?PACKAGE_TABLE, {Pkg, Vsns});
- (_, _) ->
- true
- end, true, Registry),
-
- ets:insert(?PACKAGE_TABLE, {package_index_version, ?PACKAGE_INDEX_VERSION}),
- ?INFO("Writing index to ~s", [PackageIndex]),
- ets:tab2file(?PACKAGE_TABLE, PackageIndex),
- true
- after
- catch ets:delete(Registry)
- end;
- {error, Reason} ->
- ?DEBUG("Error loading package registry: ~p", [Reason]),
- false
- catch
- _:_ ->
- fail
- end.
-
- update_deps_list(Deps, HexRegistry, State) ->
- lists:foldl(fun([Dep, DepVsn, false, _AppName | _], DepsListAcc) ->
- case DepVsn of
- <<"~> ", Vsn/binary>> ->
- case rebar_packages:find_highest_matching(Dep, Vsn, HexRegistry, State) of
- {ok, HighestDepVsn} ->
- [{Dep, HighestDepVsn} | DepsListAcc];
- none ->
- ?WARN("Missing registry entry for package ~s. Try to fix with `rebar3 update`", [Dep]),
- DepsListAcc
- end;
- Vsn ->
- [{Dep, Vsn} | DepsListAcc]
- end;
- ([_Dep, _DepVsn, true, _AppName | _], DepsListAcc) ->
- DepsListAcc
- end, [], Deps).
|