defmodule ExCheck.Manifest do @moduledoc false def convert_retry_to_only(opts) do if Keyword.get(opts, :retry) do only = opts |> get_failed_tools() |> Enum.map(&{:only, &1}) |> case do [] -> [{:only, "-"}] only -> only end opts ++ only else opts end end # sobelow_skip ["Traversal.FileModule", "DOS.StringToAtom"] def get_failed_tools(opts) do manifest_path = get_path(opts) if File.exists?(manifest_path) do manifest_path |> File.read!() |> String.split("\n") |> Enum.map(fn "FAIL " <> tool -> deserialize_tool_name_without_app(tool) _ -> nil end) |> Enum.filter(& &1) |> Enum.map(&String.to_atom/1) |> Enum.uniq() else [] end end defp deserialize_tool_name_without_app(name) do case String.split(name, "/") do [_app, tool] -> tool [tool] -> tool end end # sobelow_skip ["Traversal.FileModule"] def save(checks, opts) do lines = Enum.map(checks, &serialize_check/1) content = Enum.join(lines, "\n") <> "\n" path = get_path(opts) File.write!(path, content) end defp serialize_check({:ok, {name, _, _}, _}), do: "PASS #{serialize_tool_name(name)}" defp serialize_check({:error, {name, _, _}, _}), do: "FAIL #{serialize_tool_name(name)}" defp serialize_check({:skipped, name, _}), do: "SKIP #{serialize_tool_name(name)}" defp serialize_tool_name({tool, app}), do: "#{app}/#{tool}" defp serialize_tool_name(tool), do: tool @escape Enum.map(~c" [~#%&*{}\\:<>?/+|\"]", &<<&1::utf8>>) defp get_path(opts) do Keyword.get_lazy(opts, :manifest, fn -> app_id = File.cwd!() |> String.replace(@escape, "_") |> String.replace(~r/^_+/, "") Path.join([System.tmp_dir!(), "ex_check_ng-manifest-#{app_id}.txt"]) end) end end