Skip to content

Commit 2472bb7

Browse files
author
José Valim
committed
Ensure mix compiler is able to handle nested directories
Signed-off-by: José Valim <[email protected]>
1 parent 04b9174 commit 2472bb7

File tree

2 files changed

+46
-10
lines changed

2 files changed

+46
-10
lines changed

lib/mix/lib/mix/compilers/elixir.ex

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ defmodule Mix.Compilers.Elixir do
1414
have changed at runtime.
1515
"""
1616
def compile(manifest, srcs, skip, exts, dest, force, on_start) do
17-
all = Mix.Utils.extract_files(srcs -- skip, exts)
18-
{all_entries, skip_entries} = read_manifest(manifest, dest, skip)
17+
keep = srcs -- skip
18+
all = Mix.Utils.extract_files(keep, exts)
19+
{all_entries, skip_entries} = read_manifest(manifest, dest, keep)
1920

2021
removed =
2122
for {_b, _m, source, _d, _f, _bin} <- all_entries, not(source in all), do: source
@@ -181,21 +182,21 @@ defmodule Mix.Compilers.Elixir do
181182

182183
# Reads the manifest returning the results as tuples.
183184
# The beam files are read, removed and stored in memory.
184-
defp read_manifest(manifest, dest, skip_paths) do
185+
defp read_manifest(manifest, dest, keep_paths) do
185186
initial = {[], []}
186187

187188
case File.read(manifest) do
188189
{:ok, contents} ->
189-
skip_paths = Enum.map(skip_paths, &(&1 <> "/"))
190+
keep_paths = Enum.map(keep_paths, &(&1 <> "/"))
190191
Enum.reduce String.split(contents, "\n"), initial, fn x, acc ->
191-
read_manifest_entry(String.split(x, "\t"), acc, dest, skip_paths)
192+
read_manifest_entry(String.split(x, "\t"), acc, dest, keep_paths)
192193
end
193194
{:error, _} ->
194195
initial
195196
end
196197
end
197198

198-
defp read_manifest_entry([_beam, module, source|deps], {keep, skip}, dest, skip_paths) do
199+
defp read_manifest_entry([_beam, module, source|deps], {keep, skip}, dest, keep_paths) do
199200
{deps, files} =
200201
case Enum.split_while(deps, &(&1 != "Elixir")) do
201202
{deps, ["Elixir"|files]} -> {deps, files}
@@ -208,10 +209,10 @@ defmodule Mix.Compilers.Elixir do
208209
entry = {Path.join(dest, module <> ".beam"), module, source,
209210
deps, files, nil}
210211

211-
if String.starts_with?(source, skip_paths) do
212-
{keep, [entry|skip]}
213-
else
212+
if String.starts_with?(source, keep_paths) do
214213
{[entry|keep], skip}
214+
else
215+
{keep, [entry|skip]}
215216
end
216217
end
217218

lib/mix/test/mix/tasks/compile.elixir_test.exs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,20 +172,27 @@ defmodule Mix.Tasks.Compile.ElixirTest do
172172

173173
defmodule SourcePathsProject do
174174
def project do
175-
[app: :source_paths, elixirc_paths: ["web", "lib"]]
175+
[app: :source_paths, elixirc_paths: ["web", "lib", "lib/foo"]]
176176
end
177177
end
178178

179179
test "use custom source paths" do
180180
Mix.Project.push SourcePathsProject
181181

182182
in_fixture "no_mixfile", fn ->
183+
File.mkdir_p! "web"
184+
File.write! "web/ab.ex", """
185+
defmodule AB, do: :ok
186+
"""
187+
183188
# Nothing to compile with the custom source paths
184189
assert Mix.Tasks.Compile.Elixir.run(["--elixirc-paths", "web"])
190+
assert_received {:mix_shell, :info, ["Compiled web/ab.ex"]}
185191
refute_received {:mix_shell, :info, ["Compiled lib/a.ex"]}
186192

187193
assert Mix.Tasks.Compile.Elixir.run(["--elixirc-paths", "lib"])
188194
assert_received {:mix_shell, :info, ["Compiled lib/a.ex"]}
195+
refute_received {:mix_shell, :info, ["Compiled web/ab.ex"]}
189196

190197
# Compiling just web does not remove lib artifacts
191198
assert Mix.Tasks.Compile.Elixir.run(["--elixirc-paths", "web"])
@@ -195,4 +202,32 @@ defmodule Mix.Tasks.Compile.ElixirTest do
195202
refute_received {:mix_shell, :info, ["Compiled lib/a.ex"]}
196203
end
197204
end
205+
206+
test "use custom source paths in subdirs" do
207+
Mix.Project.push SourcePathsProject
208+
209+
in_fixture "no_mixfile", fn ->
210+
File.mkdir_p! "lib/foo"
211+
File.write! "lib/foo/ab.ex", """
212+
defmodule AB, do: :ok
213+
"""
214+
215+
# Nested file (and nested file only) is compiled just once
216+
assert Mix.Tasks.Compile.Elixir.run(["--elixirc-paths", "lib/foo"])
217+
assert_received {:mix_shell, :info, ["Compiled lib/foo/ab.ex"]}
218+
refute_received {:mix_shell, :info, ["Compiled lib/a.ex"]}
219+
refute_received {:mix_shell, :info, ["Compiled lib/foo/ab.ex"]}
220+
221+
assert Mix.Tasks.Compile.Elixir.run(["--elixirc-paths", "lib"])
222+
assert_received {:mix_shell, :info, ["Compiled lib/a.ex"]}
223+
refute_received {:mix_shell, :info, ["Compiled lib/foo/ab.ex"]}
224+
225+
# Compiling just lib/foo does not remove lib artifacts
226+
assert Mix.Tasks.Compile.Elixir.run(["--elixirc-paths", "lib/foo"])
227+
refute_received {:mix_shell, :info, ["Compiled lib/a.ex"]}
228+
229+
assert Mix.Tasks.Compile.Elixir.run(["--elixirc-paths", "lib"])
230+
refute_received {:mix_shell, :info, ["Compiled lib/a.ex"]}
231+
end
232+
end
198233
end

0 commit comments

Comments
 (0)