Current section

Files

Jump to
oaspec src oaspec_ffi.erl
Raw

src/oaspec_ffi.erl

-module(oaspec_ffi).
-export([find_executable/1, run_executable/2, is_stdout_tty/0, no_color_set/0]).
%% Find an executable on PATH. Returns {ok, Path} or {error, nil}.
-spec find_executable(binary()) -> {ok, binary()} | {error, nil}.
find_executable(Name) ->
case os:find_executable(binary_to_list(Name)) of
false -> {error, nil};
Path -> {ok, list_to_binary(Path)}
end.
%% Run an executable with arguments. Returns the exit code as an integer.
%% Uses spawn_executable to avoid shell injection.
-spec run_executable(binary(), list(binary())) -> integer().
run_executable(Executable, Args) ->
Port = open_port(
{spawn_executable, binary_to_list(Executable)},
[exit_status, stderr_to_stdout, binary, {args, [binary_to_list(A) || A <- Args]}]
),
collect_exit(Port).
collect_exit(Port) ->
receive
{Port, {data, _}} ->
collect_exit(Port);
{Port, {exit_status, Code}} ->
Code
after 60000 ->
catch port_close(Port),
1
end.
%% Detect whether standard_io is connected to a terminal. io:getopts/1
%% reports a `terminal' flag for interactive sessions; non-TTY (pipe,
%% redirection, escript captured stdout) returns false or omits the key.
-spec is_stdout_tty() -> boolean().
is_stdout_tty() ->
case io:getopts(standard_io) of
{ok, Opts} ->
case lists:keyfind(terminal, 1, Opts) of
{terminal, true} -> true;
_ -> false
end;
_ -> false
end.
%% Honor the NO_COLOR convention (https://no-color.org/): an unset or
%% empty value means "do not opt out"; any non-empty value means "no
%% color".
-spec no_color_set() -> boolean().
no_color_set() ->
case os:getenv("NO_COLOR") of
false -> false;
"" -> false;
_ -> true
end.