Skip to content

Commit 49fe9b0

Browse files
author
José Valim
committed
Copy dev build if the environments match
1 parent c8425ed commit 49fe9b0

File tree

6 files changed

+145
-13
lines changed

6 files changed

+145
-13
lines changed

lib/mix/lib/mix/deps/lock.ex

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,30 @@ defmodule Mix.Deps.Lock do
1818
"""
1919
def touch(manifest_path // Mix.Project.manifest_path) do
2020
File.mkdir_p!(manifest_path)
21-
File.write!(Path.join(manifest_path, @manifest), System.version)
21+
File.write!(Path.join(manifest_path, @manifest), "#{System.version}\n#{Mix.env}")
2222
end
2323

2424
@doc """
25-
Returns the elixir lock version.
25+
Returns the elixir version in the lock manifest.
2626
"""
2727
def elixir_vsn(manifest_path // Mix.Project.manifest_path) do
28+
read_manifest(manifest_path) |> elem(0)
29+
end
30+
31+
@doc """
32+
Returns the mix env version in the lock manifest.
33+
"""
34+
def mix_env(manifest_path // Mix.Project.manifest_path) do
35+
read_manifest(manifest_path) |> elem(1)
36+
end
37+
38+
defp read_manifest(manifest_path) do
2839
case File.read(manifest(manifest_path)) do
29-
{ :ok, contents } -> contents
30-
{ :error, _ } -> nil
40+
{ :ok, contents } ->
41+
destructure [vsn, env], String.split(contents, "\n")
42+
{ vsn, env }
43+
{ :error, _ } ->
44+
{ nil, nil }
3145
end
3246
end
3347

lib/mix/lib/mix/tasks/deps.check.ex

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,15 @@ defmodule Mix.Tasks.Deps.Check do
4141
config = Mix.project
4242
if config[:build_per_environment] do
4343
paths = Mix.Project.build_path(config)
44-
|> Path.join("lib/*")
44+
|> Path.join("lib/*/ebin")
4545
|> Path.wildcard
46-
|> List.delete(Mix.Project.app_path(config))
46+
|> List.delete(Mix.Project.compile_path(config))
4747

48-
to_prune = Enum.reduce(all, paths, &(&2 -- Mix.Deps.source_paths(&1)))
48+
to_prune = Enum.reduce(all, paths, &(&2 -- Mix.Deps.load_paths(&1)))
4949

5050
Enum.map(to_prune, fn path ->
5151
Code.delete_path(path)
52-
File.rm_rf!(path)
52+
File.rm_rf!(path |> Path.dirname)
5353
end)
5454
end
5555
end

lib/mix/lib/mix/tasks/deps.compile.ex

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,23 @@ defmodule Mix.Tasks.Deps.Compile do
8484
:ok
8585
end
8686

87-
defp do_mix(Mix.Dep[opts: opts] = dep, config) do
87+
defp do_mix(Mix.Dep[app: app, opts: opts] = dep, config) do
8888
# Set the app_path to be the one stored in the dependency.
8989
# This is important because the name of application in the
9090
# mix.exs file can be different than the actual name and we
9191
# choose to respect the one in the mix.exs.
9292
config = Keyword.put(config, :app_path, opts[:build])
9393

9494
Mix.Deps.in_dependency dep, config, fn _ ->
95+
case dev_compilation(app, config) do
96+
{ source, target } ->
97+
File.rm_rf!(target)
98+
File.mkdir_p!(target)
99+
File.cp_r!(source, Path.dirname(target))
100+
false ->
101+
:ok
102+
end
103+
95104
try do
96105
res = Mix.Task.run("compile", ["--no-deps"])
97106
:ok in List.wrap(res)
@@ -106,6 +115,21 @@ defmodule Mix.Tasks.Deps.Compile do
106115
end
107116
end
108117

118+
# In case we have build per environments and the dependency was already
119+
# compiled for development and the target is stale compared to the
120+
# development (source) one, we simply copy the source to target and do
121+
# the compilation on top of it.
122+
defp dev_compilation(app, config) do
123+
if config[:build_per_environment] do
124+
source = config[:build_path] |> Path.dirname |> Path.join("dev/lib/#{app}")
125+
target = Mix.Project.manifest_path(config)
126+
source != target && Mix.Deps.Lock.mix_env(source) == to_string(Mix.env) &&
127+
not Mix.Utils.stale?([target], [source]) && { source, target }
128+
else
129+
false
130+
end
131+
end
132+
109133
defp do_rebar(Mix.Dep[app: app] = dep, config) do
110134
do_command dep, rebar_cmd(app), "compile skip_deps=true deps_dir=#{inspect config[:deps_path]}"
111135
end
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
SAMPLE

lib/mix/test/mix/deps/lock_test.exs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,16 @@ defmodule Mix.Deps.LockTest do
3030
refute File.regular? "_build/shared/lib/sample/.compile.lock"
3131
end
3232
end
33+
34+
test "stores version and env in manifest" do
35+
in_fixture "no_mixfile", fn ->
36+
assert nil? Mix.Deps.Lock.elixir_vsn
37+
assert nil? Mix.Deps.Lock.mix_env
38+
39+
Mix.Deps.Lock.touch
40+
41+
assert Mix.Deps.Lock.elixir_vsn == System.version
42+
assert Mix.Deps.Lock.mix_env == "dev"
43+
end
44+
end
3345
end

lib/mix/test/mix/tasks/deps_test.exs

Lines changed: 85 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@ defmodule Mix.Tasks.DepsTest do
2727
end
2828
end
2929

30+
defmodule PerEnvironemtDepsApp do
31+
def project do
32+
[ app: :sample, version: "0.1.0", build_per_environment: true,
33+
deps: [
34+
{ :ok, "0.1.0", path: "deps/ok" }
35+
]
36+
]
37+
end
38+
end
39+
3040
defmodule ReqDepsApp do
3141
def project do
3242
[ app: :req_deps, version: "0.1.0",
@@ -155,19 +165,20 @@ defmodule Mix.Tasks.DepsTest do
155165
end
156166

157167
test "compiles and prunes builds per environment" do
158-
Mix.ProjectStack.post_config [build_per_environment: true]
159-
Mix.Project.push SuccessfulDepsApp
168+
Mix.Project.push PerEnvironemtDepsApp
160169

161170
in_fixture "deps_status", fn ->
162171
Mix.Tasks.Deps.Compile.run []
172+
Mix.Tasks.Deps.Check.run []
163173
assert File.exists?("_build/dev/lib/ok/ebin/ok.app")
174+
assert File.exists?("_build/dev/lib/ok/priv/sample")
164175

165176
Mix.Tasks.Compile.run []
166177
assert File.exists?("_build/dev/lib/sample/ebin/sample.app")
167178

168-
Mix.ProjectStack.post_config [build_per_environment: true, deps: []]
179+
Mix.ProjectStack.post_config [deps: []]
169180
Mix.Project.pop
170-
Mix.Project.push SuccessfulDepsApp
181+
Mix.Project.push PerEnvironemtDepsApp
171182

172183
Mix.Tasks.Deps.Check.run []
173184
refute File.exists?("_build/dev/lib/ok/ebin/ok.app")
@@ -177,6 +188,76 @@ defmodule Mix.Tasks.DepsTest do
177188
Mix.Project.pop
178189
end
179190

191+
test "copies dev dependency when building per environment" do
192+
Mix.Project.push PerEnvironemtDepsApp
193+
194+
in_fixture "deps_status", fn ->
195+
File.mkdir_p!("deps/ok/lib")
196+
File.write!("deps/ok/lib/empty.ex", "")
197+
198+
Mix.Tasks.Deps.Compile.run []
199+
assert File.exists?("_build/dev/lib/ok/ebin/ok.app")
200+
assert_received { :mix_shell, :info, ["Generated ok.app"] }
201+
202+
Mix.Task.clear
203+
Mix.env(:test)
204+
Mix.Project.pop
205+
Mix.Project.push PerEnvironemtDepsApp
206+
207+
Mix.Tasks.Deps.Compile.run []
208+
assert File.exists?("_build/test/lib/ok/ebin/ok.app")
209+
assert File.read!("_build/test/lib/ok/priv/sample") == "SAMPLE"
210+
# We don't get a message becaused we copied the contents over
211+
refute_received { :mix_shell, :info, ["Generated ok.app"] }
212+
end
213+
after
214+
Mix.env(:dev)
215+
Mix.Project.pop
216+
end
217+
218+
test "does not choke when another environment is compiled first than dep" do
219+
Mix.Project.push PerEnvironemtDepsApp
220+
Mix.env(:test)
221+
222+
in_fixture "deps_status", fn ->
223+
File.mkdir_p!("deps/ok/lib")
224+
File.write!("deps/ok/lib/empty.ex", "")
225+
226+
Mix.Tasks.Deps.Compile.run []
227+
assert File.exists?("_build/test/lib/ok/ebin/ok.app")
228+
assert File.read!("_build/test/lib/ok/priv/sample") == "SAMPLE"
229+
assert_received { :mix_shell, :info, ["Generated ok.app"] }
230+
end
231+
after
232+
Mix.env(:dev)
233+
Mix.Project.pop
234+
end
235+
236+
test "does not copy if environments do not match" do
237+
Mix.ProjectStack.post_config(deps: [{ :ok, "0.1.0", path: "deps/ok", env: Mix.env }])
238+
Mix.Project.push PerEnvironemtDepsApp
239+
240+
in_fixture "deps_status", fn ->
241+
File.mkdir_p!("deps/ok/lib")
242+
File.write!("deps/ok/lib/empty.ex", "")
243+
244+
Mix.Tasks.Deps.Compile.run []
245+
assert File.exists?("_build/dev/lib/ok/ebin/ok.app")
246+
assert_received { :mix_shell, :info, ["Generated ok.app"] }
247+
248+
Mix.Task.clear
249+
Mix.env(:test)
250+
Mix.Project.pop
251+
Mix.Project.push PerEnvironemtDepsApp
252+
253+
Mix.Tasks.Deps.Compile.run []
254+
assert_received { :mix_shell, :info, ["Generated ok.app"] }
255+
end
256+
after
257+
Mix.env(:dev)
258+
Mix.Project.pop
259+
end
260+
180261
test "unlocks all deps" do
181262
Mix.Project.push DepsApp
182263
in_fixture "no_mixfile", fn ->

0 commit comments

Comments
 (0)