Skip to content

Commit

Permalink
Raise on conflicting .formatter.exs files (elixir-lang#8323)
Browse files Browse the repository at this point in the history
Warn on conflicting .formatter.exs files
  • Loading branch information
fertapric authored and josevalim committed Oct 25, 2018
1 parent f01de95 commit 04372bf
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 3 deletions.
26 changes: 23 additions & 3 deletions lib/mix/lib/mix/tasks/format.ex
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ defmodule Mix.Tasks.Format do

dot_formatter
|> expand_dot_inputs([], formatter_opts_and_subs, %{})
|> Enum.uniq()
|> Enum.map(fn {file, {_dot_formatter, formatter_opts}} -> {file, formatter_opts} end)
end

defp expand_args(files_and_patterns, _dot_formatter, {formatter_opts, subs}) do
Expand Down Expand Up @@ -360,15 +360,35 @@ defmodule Mix.Tasks.Format do
map =
for input <- List.wrap(formatter_opts[:inputs]),
file <- Path.wildcard(Path.join(prefix ++ [input]), match_dot: true),
do: {file, formatter_opts},
do: {expand_relative_to_cwd(file), {dot_formatter, formatter_opts}},
into: %{}

Enum.reduce(subs, Map.merge(acc, map), fn {sub, formatter_opts_and_subs}, acc ->
acc =
Map.merge(acc, map, fn file, {dot_formatter1, _}, {dot_formatter2, formatter_opts} ->
Mix.shell().error(
"Both #{dot_formatter1} and #{dot_formatter2} specify the file " <>
"#{Path.relative_to_cwd(file)} in their :inputs option. To resolve the " <>
"conflict, the configuration in #{dot_formatter1} will be ignored. " <>
"Please change the list of :inputs in one of the formatter files so only " <>
"one of them matches #{Path.relative_to_cwd(file)}"
)

{dot_formatter2, formatter_opts}
end)

Enum.reduce(subs, acc, fn {sub, formatter_opts_and_subs}, acc ->
sub_formatter = Path.join(sub, ".formatter.exs")
expand_dot_inputs(sub_formatter, [sub], formatter_opts_and_subs, acc)
end)
end

defp expand_relative_to_cwd(path) do
case File.cwd() do
{:ok, cwd} -> Path.expand(path, cwd)
_ -> path
end
end

defp find_formatter_opts_for_file(split, {formatter_opts, subs}) do
Enum.find_value(subs, formatter_opts, fn {sub, formatter_opts_and_subs} ->
if List.starts_with?(split, Path.split(sub)) do
Expand Down
42 changes: 42 additions & 0 deletions lib/mix/test/mix/tasks/format_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,48 @@ defmodule Mix.Tasks.FormatTest do
end)
end

test "prints an error on conflicting .formatter.exs files", context do
in_tmp(context.test, fn ->
File.write!(".formatter.exs", """
[inputs: "lib/**/*.{ex,exs}", subdirectories: ["lib", "foo"]]
""")

File.mkdir_p!("lib")

File.write!("lib/.formatter.exs", """
[inputs: "a.ex", locals_without_parens: [my_fun: 2]]
""")

File.mkdir_p!("foo")

File.write!("foo/.formatter.exs", """
[inputs: "../lib/a.ex", locals_without_parens: [my_fun: 2]]
""")

File.write!("lib/a.ex", """
my_fun :foo, :bar
other_fun :baz
""")

Mix.Tasks.Format.run([])

message1 =
"Both .formatter.exs and lib/.formatter.exs specify the file lib/a.ex in their " <>
":inputs option. To resolve the conflict, the configuration in .formatter.exs " <>
"will be ignored. Please change the list of :inputs in one of the formatter files " <>
"so only one of them matches lib/a.ex"

message2 =
"Both lib/.formatter.exs and foo/.formatter.exs specify the file lib/a.ex in their " <>
":inputs option. To resolve the conflict, the configuration in lib/.formatter.exs " <>
"will be ignored. Please change the list of :inputs in one of the formatter files " <>
"so only one of them matches lib/a.ex"

assert_received {:mix_shell, :error, [^message1]}
assert_received {:mix_shell, :error, [^message2]}
end)
end

test "raises on invalid arguments", context do
in_tmp(context.test, fn ->
assert_raise Mix.Error, ~r"Expected one or more files\/patterns to be given", fn ->
Expand Down

0 comments on commit 04372bf

Please sign in to comment.