defmodule BuildPipeline.TerminalMessages do
alias IO.ANSI
def pending(%{runners: runners, terminal_width: terminal_width}) do
runners
|> Enum.sort(fn {_, %{order: order_1}}, {_, %{order: order_2}} -> order_1 <= order_2 end)
|> Enum.map(fn {_pid, %{command: command}} ->
message = "#{command} [Pending]"
truncated_msg =
if String.length(message) > terminal_width do
String.slice(message, 0..(terminal_width - 1))
else
message
end
%{message: "#{ANSI.light_magenta()}#{truncated_msg}", line_update: false}
end)
end
def running(%{mode: :normal, runners: runners}, runner_pid) do
%{command: command} = Map.fetch!(runners, runner_pid)
%{
ansi_prefix: ANSI.magenta(),
prefix: command,
suffix: "[Running]",
runner_pid: runner_pid,
line_update: true
}
end
def running(%{mode: :verbose, runners: runners}, runner_pid) do
%{command: command} = Map.fetch!(runners, runner_pid)
%{
message: "#{ANSI.magenta()}#{command} [Running]",
line_update: false
}
end
def running(%{mode: :debug, runners: runners}, runner_pid) do
%{command: command} = Map.fetch!(runners, runner_pid)
message = """
#{ANSI.magenta()}---------------------------------------------------------------------
#{command} [Running]
---------------------------------------------------------------------#{ANSI.reset()}
"""
%{message: message, line_update: false}
end
def succeeded(%{mode: :normal}, runner, runner_pid) do
%{command: command, duration_in_microseconds: duration_in_microseconds} = runner
%{
ansi_prefix: ANSI.green(),
prefix: command,
suffix: "[Succeeded in #{duration_message(duration_in_microseconds)}] ✔ ",
runner_pid: runner_pid,
line_update: true
}
end
def succeeded(%{mode: mode}, runner, _runner_pid) when mode in [:verbose, :debug] do
%{command: command, duration_in_microseconds: duration_in_microseconds, output: output} =
runner
message = """
#{ANSI.green()}---------------------------------------------------------------------
#{command} [Succeeded in #{duration_message(duration_in_microseconds)}] ✔
#{ANSI.reset()}#{output}
#{ANSI.green()}---------------------------------------------------------------------#{ANSI.reset()}
"""
%{line_update: false, message: message}
end
def failed(%{mode: :verbose} = _server_state, runner, _runner_pid) do
%{command: command, duration_in_microseconds: duration_in_microseconds, output: output} =
runner
message = """
#{ANSI.red()}---------------------------------------------------------------------
#{command} [Failed in #{duration_message(duration_in_microseconds)}] ✘
#{ANSI.reset()}#{output}
#{ANSI.red()}---------------------------------------------------------------------#{ANSI.reset()}
"""
%{line_update: false, message: message}
end
def failed(%{mode: :debug} = _server_state, runner, _runner_pid) do
%{command: command, duration_in_microseconds: duration_in_microseconds} = runner
message = """
#{ANSI.red()}---------------------------------------------------------------------
#{command} [Failed in #{duration_message(duration_in_microseconds)}] ✘
#{ANSI.red()}---------------------------------------------------------------------#{ANSI.reset()}
"""
%{line_update: false, message: message}
end
def failed(%{mode: :normal} = _server_state, runner, runner_pid) do
%{command: command, duration_in_microseconds: duration_in_microseconds} = runner
%{
ansi_prefix: ANSI.red(),
prefix: command,
suffix: "[Failed in #{duration_message(duration_in_microseconds)}] ✘ ",
runner_pid: runner_pid,
line_update: true
}
end
def abort(%{mode: mode, runners: runners} = _server_state) do
runners
|> Enum.reject(fn {_runner_pid, %{status: status}} -> status == :complete end)
|> Enum.map(fn {runner_pid, %{command: command}} ->
abort_message(mode, command, runner_pid)
end)
end
def failed_output(%{mode: mode}, _runner) when mode in [:verbose, :debug] do
[]
end
def failed_output(%{mode: :normal}, %{output: output}) do
%{
message: output,
line_update: false
}
end
defp abort_message(mode, command, _) when mode in [:verbose, :debug] do
%{
message: "#{ANSI.magenta()}#{ANSI.crossed_out()}#{command} [Aborted]",
line_update: false
}
end
defp abort_message(:normal, command, runner_pid) do
%{
ansi_prefix: "#{ANSI.magenta()}#{ANSI.crossed_out()}",
prefix: command,
suffix: "[Aborted]",
runner_pid: runner_pid,
line_update: true
}
end
defp duration_message(duration_in_microseconds) do
cond do
duration_in_microseconds < 1000 ->
"#{duration_in_microseconds} μs"
duration_in_microseconds < 1_000_000 ->
"#{round(duration_in_microseconds / 1000)} ms"
duration_in_microseconds < 60_000_000 ->
"#{Float.round(duration_in_microseconds / 1_000_000, 1)} s"
true ->
"#{Float.round(duration_in_microseconds / 60_000_000, 1)} min"
end
end
end