defmodule EexToHeex.CLI do require Logger @eex_extensions [".html.eex", ".html.leex"] @ex_extensions [".ex"] def main(args \\ []) do if length(args) < 2 do bad_usage() end cmd = Enum.at(args, 0) paths = Enum.drop(args, 1) case cmd do "check" -> check_all_templates(paths, @eex_extensions, nil, &EexToHeex.eex_to_heex/1) "check_inline" -> check_all_templates(paths, @ex_extensions, nil, &EexToHeex.ex_to_heex/1) "convert" -> convert_all_templates(paths, @eex_extensions, ".heex", &EexToHeex.eex_to_heex/1) "convert_inline" -> convert_all_templates(paths, @ex_extensions, ".ex", &EexToHeex.ex_to_heex/1) "run" -> run(paths) _ -> bad_usage() end end defp bad_usage() do IO.puts( :stderr, "Usage: `eextoheex COMMAND PATHS...` where COMMAND is 'check', 'check_inline', 'convert', 'convert_inline', or 'run'" ) System.halt(1) end defp run(paths) do Enum.map(paths, fn path -> case to_heex(path) do {:error, output, error} -> IO.puts(output) raise error {:ok, output} -> IO.puts(output) end end) end defp to_heex(path) do contents = File.read!(path) if has_extension?(path, @ex_extensions) do EexToHeex.ex_to_heex(contents) else EexToHeex.eex_to_heex(contents) end end defp check_all_templates(roots, allowed_extensions, new_extension, conversion_func) do templates_helper(roots, allowed_extensions, new_extension, conversion_func) end defp convert_all_templates(roots, allowed_extensions, new_extension, conversion_func) do templates_helper(roots, allowed_extensions, new_extension, conversion_func) end defp templates_helper(roots, allowed_extensions, new_extension, conversion_func) do eex_templates = roots |> Enum.flat_map(&ls_recursive(&1)) |> Enum.filter(&has_extension?(&1, allowed_extensions)) results = eex_templates |> Enum.map(fn filename -> input = File.read!(filename) case conversion_func.(File.read!(filename)) do {:ok, output} -> cond do has_extension?(filename, @ex_extensions) and output == input -> # Nothing at all has changed, so don't mention this file in the output. nil new_extension -> new_filename = Path.rootname(filename) <> new_extension with :ok <- File.rename(filename, new_filename), :ok <- File.write!(new_filename, output) do {:ok, filename} else {:error, err} -> Logger.error("Error moving #{filename} to #{new_filename}", err) {:ok, filename} end true -> {:ok, filename} end {:error, _output, err} -> {:error, filename, err} end end) |> Enum.filter(&(&1 != nil)) grouped = Enum.group_by(results, &elem(&1, 0)) oks = grouped[:ok] || [] errors = grouped[:error] || [] lok = length(oks) lerrs = length(errors) if lok > 0 do IO.puts("conversion worked ok for the following #{lok} templates:") IO.puts("") Enum.each(oks || [], fn {_, filename} -> IO.puts(" " <> strip_path(filename)) end) end if lerrs > 0 do IO.puts("") IO.puts("The following #{lerrs} html.eex templates could not be converted:") IO.puts("") end Enum.each(errors || [], fn {_, filename, err} -> IO.puts(" " <> strip_path(filename) <> ":") IO.puts(" #{inspect(err)}") end) end defp has_extension?(path, extensions) do Enum.any?(extensions, &String.ends_with?(path, &1)) end defp ls_recursive(path) do cond do File.regular?(path) -> [path] File.dir?(path) -> File.ls!(path) |> Enum.map(&Path.join(path, &1)) |> Enum.map(&ls_recursive/1) |> Enum.concat() true -> [] end end defp strip_path(path) do Regex.replace(~r[.*/platform/], path, "") end end