src/rebar_calzone_utils.erl

% SPDX-FileCopyrightText: 2026 Dipl. Phys. Peer Stritzinger GmbH
%
% SPDX-License-Identifier: Apache-2.0

-module(rebar_calzone_utils).

% Exports
-export([sh/1]).
-export([run_escript/2]).
-export([copy_directory/3]).

%--- Macros --------------------------------------------------------------------


%--- API -----------------------------------------------------------------------

-spec sh(list()) -> ok | no_return().
sh(Command) ->
    Port = open_port({spawn, Command}, [stream, exit_status]),
    collect_output(Port).

-spec run_escript(file:name(), file:name()) -> ok | no_return().
run_escript(EscriptPath, CalzoneDir) ->
    Env = {env, [{"ERL_FLAGS", "+record mmap_recordings"}]},
    Cd = {cd, CalzoneDir},
    Options = [stream, exit_status, Env, Cd],
    Port = open_port({spawn_executable, EscriptPath}, Options),
    collect_output(Port).

copy_directory(_, _, []) ->
    ok;
copy_directory(OriginPath, DestPath, [File | Acc]) ->
    FilePath = filename:join([OriginPath, File]),
    DestFilePath = filename:join([DestPath, File]),
    case filelib:is_dir(FilePath) of
        true ->
            filelib:ensure_path(DestFilePath),
            {ok, SubFiles} = file:list_dir(FilePath),
            SubFilesPaths = lists:map(fun(SubFile) ->
                                              filename:join([File, SubFile])
                                      end, SubFiles),
            copy_directory(OriginPath, DestPath, Acc ++ SubFilesPaths);
        false ->
            case filelib:is_regular(DestFilePath) of
                true ->
                    rebar_api:debug("File ~p already present. Skipping", [DestFilePath]);
                _ ->
                    rebar_api:debug("Copying ~p to ~p", [FilePath, DestFilePath]),
                    {ok, _} = file:copy(FilePath, DestFilePath)
            end,
            copy_directory(OriginPath, DestPath, Acc)
    end.

%--- Private -------------------------------------------------------------------
-spec collect_output(port()) -> ok | no_return().
collect_output(Port) ->
    receive
        {Port, {data, Data}} ->
            rebar_api:debug("~s", [Data]),
            collect_output(Port);
        {Port, {exit_status, 0}} ->
            ok;
        {Port, {exit_status, 127}} ->
            ok;
        {Port, {exit_status, _Status}} ->
            rebar_api:error("Record failed ~p", [_Status])
    end.