Skip to main content

src/rebar3_otter__clean.erl

-module(rebar3_otter__clean).
-moduledoc """
Provider that cleans Rust NIF build artifacts.

Removes the installed shared libraries from `priv/native/` and
removes each configured crate's pinned `target/` directory.
""".

-behaviour(provider).

-export([init/1, do/1, format_error/1]).

%%------------------------------------------------------------------------------

-define(PROVIDER, otter_clean).
-define(DEPS, []).


%%%=============================================================================
%%% Callbacks

-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) ->
  Provider = providers:create([
    {name, ?PROVIDER},
    {module, ?MODULE},
    {namespace, default},
    {bare, true},
    {deps, ?DEPS},
    {short_desc, "Clean Rust NIF build artifacts"},
    {desc, "Removes compiled NIF shared libraries and each crate's pinned target/ directory"}
  ]),
  {ok, rebar_state:add_provider(State, Provider)}.

-spec do(rebar_state:t()) -> {ok, rebar_state:t()}.
do(State) ->
  lists:foreach(fun clean_app/1, rebar_state:project_apps(State)),
  {ok, State}.

-spec format_error(term()) -> string() | iolist().
format_error(Other) ->
  io_lib:format("~p", [Other]).


%%%=============================================================================
%%% Private

-spec clean_app(rebar_app_info:t()) -> ok.
clean_app(App) ->
  Raw = rebar_app_info:get(App, otter_crates, []),
  case rebar3_otter__config:validate(Raw) of
    {ok, Crates} ->
      AppDir = rebar_app_info:dir(App),
      lists:foreach(fun(Crate) -> clean_crate(Crate, AppDir) end, Crates);
    {error, Reason} ->
      %% Same pre-hook quirk as in rebar3_otter__compile: halt directly.
      rebar_api:abort("~s", [rebar3_otter__config:format_error(Reason)])
  end.

-spec clean_crate(rebar3_otter__config:crate(), string()) -> ok.
clean_crate(#{name := Name, path := Path}, AppDir) ->
  CratePath = filename:join(AppDir, Path),
  OutFile = filename:join([AppDir, "priv", "native",
                           rebar3_otter__cargo:nif_filename(Name)]),
  case filelib:is_regular(OutFile) of
    true ->
      rebar_api:info("Removing ~s", [OutFile]),
      _ = file:delete(OutFile);
    false ->
      ok
  end,
  rebar3_otter__cargo:clean(CratePath).