Skip to content

Commit 57af576

Browse files
author
José Valim
committed
Load all umbrella children from the fetcher, closes #4069
1 parent 2cf5bbe commit 57af576

File tree

7 files changed

+64
-18
lines changed

7 files changed

+64
-18
lines changed

lib/mix/lib/mix/dep.ex

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ defmodule Mix.Dep do
7272
This function raises an exception if any of the dependencies
7373
provided in the project are in the wrong format.
7474
"""
75-
defdelegate children(), to: Mix.Dep.Loader
75+
def children do
76+
Mix.Dep.Loader.children(Mix.env)
77+
end
7678

7779
@doc """
7880
Returns loaded dependencies recursively as a `Mix.Dep` struct.
@@ -83,7 +85,7 @@ defmodule Mix.Dep do
8385
provided in the project are in the wrong format.
8486
"""
8587
def loaded(opts) do
86-
Mix.Dep.Converger.converge(nil, nil, opts, &{&1, &2, &3}) |> elem(0)
88+
Mix.Dep.Converger.converge(children(), nil, nil, opts, &{&1, &2, &3}) |> elem(0)
8789
end
8890

8991
@doc """

lib/mix/lib/mix/dep/converger.ex

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,12 @@ defmodule Mix.Dep.Converger do
4343
4444
See `Mix.Dep.Loader.children/1` for options.
4545
"""
46-
def converge(acc, lock, opts, callback) do
47-
{deps, acc, lock} = all(acc, lock, opts, callback)
46+
def converge(deps, acc, lock, opts, callback) do
47+
{deps, acc, lock} = all(deps, acc, lock, opts, callback)
4848
{topsort(deps), acc, lock}
4949
end
5050

51-
defp all(acc, lock, opts, callback) do
52-
deps = Mix.Dep.Loader.children()
51+
defp all(deps, acc, lock, opts, callback) do
5352
deps = Enum.map(deps, &(%{&1 | top_level: true}))
5453
lock_given? = !!lock
5554

lib/mix/lib/mix/dep/fetcher.ex

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ defmodule Mix.Dep.Fetcher do
1313
Fetches all dependencies.
1414
"""
1515
def all(old_lock, new_lock, opts) do
16-
result = Mix.Dep.Converger.converge([], new_lock, opts, &do_fetch/3)
16+
deps = Mix.Dep.Loader.children(nil) # We do not use environments on the fetcher
17+
result = Mix.Dep.Converger.converge(deps, [], new_lock, opts, &do_fetch/3)
1718
{apps, _deps} = do_finalize(result, old_lock, opts)
1819
apps
1920
end
@@ -23,7 +24,8 @@ defmodule Mix.Dep.Fetcher do
2324
"""
2425
def by_name(names, old_lock, new_lock, opts) do
2526
fetcher = fetch_by_name(names, new_lock)
26-
result = Mix.Dep.Converger.converge([], new_lock, opts, fetcher)
27+
deps = Mix.Dep.Loader.children(nil) # We do not use environments on the fetcher
28+
result = Mix.Dep.Converger.converge(deps, [], new_lock, opts, fetcher)
2729
{apps, deps} = do_finalize(result, old_lock, opts)
2830

2931
# Check if all given dependencies are loaded or fail

lib/mix/lib/mix/dep/loader.ex

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ defmodule Mix.Dep.Loader do
1414
By default, it will filter all dependencies that does not match
1515
current environment, behaviour can be overridden via options.
1616
"""
17-
def children() do
18-
mix_children([]) ++ Mix.Dep.Umbrella.unloaded
17+
def children(env) do
18+
mix_children([]) ++ Mix.Dep.Umbrella.unloaded(env)
1919
end
2020

2121
@doc """
@@ -236,7 +236,10 @@ defmodule Mix.Dep.Loader do
236236
opts = Keyword.put_new(opts, :app, false)
237237
end
238238

239-
deps = mix_children(env: opts[:env] || :prod) ++ Mix.Dep.Umbrella.unloaded
239+
# env may be nil and we should respect it
240+
env = Keyword.get(opts, :env, :prod)
241+
deps = mix_children(env: env) ++ Mix.Dep.Umbrella.unloaded(env)
242+
240243
{%{dep | opts: opts}, deps}
241244
end)
242245
end

lib/mix/lib/mix/dep/umbrella.ex

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,13 @@ defmodule Mix.Dep.Umbrella do
33

44
@doc """
55
Gets all umbrella dependencies in unloaded format.
6+
7+
The environment is required and usually is set to
8+
`Mix.env` (i.e. the same environment as the parent
9+
project). However, it may be nil when invoked by
10+
the fetcher so all deps are fetched recursively.
611
"""
7-
def unloaded do
12+
def unloaded(env) do
813
config = Mix.Project.config
914

1015
if apps_path = config[:apps_path] do
@@ -14,7 +19,7 @@ defmodule Mix.Dep.Umbrella do
1419
paths
1520
|> extract_umbrella
1621
|> filter_umbrella(config[:apps])
17-
|> to_umbrella_dep(build, Path.absname("mix.exs"))
22+
|> to_umbrella_dep(build, Path.absname("mix.exs"), env)
1823
else
1924
[]
2025
end
@@ -24,7 +29,7 @@ defmodule Mix.Dep.Umbrella do
2429
Gets all umbrella dependencies in the loaded format.
2530
"""
2631
def loaded do
27-
deps = unloaded
32+
deps = unloaded(Mix.env)
2833
apps = Enum.map(deps, &(&1.app))
2934

3035
Enum.map(deps, fn umbrella_dep ->
@@ -48,10 +53,10 @@ defmodule Mix.Dep.Umbrella do
4853
for {app, _} = pair <- pairs, app in apps, do: pair
4954
end
5055

51-
defp to_umbrella_dep(paths, build, from) do
56+
defp to_umbrella_dep(paths, build, from, env) do
5257
Enum.map paths, fn({app, path}) ->
5358
opts = [path: path, dest: Path.expand(path), from_umbrella: true,
54-
env: Mix.env, build: Path.join([build, "lib", Atom.to_string(app)])]
59+
env: env, build: Path.join([build, "lib", Atom.to_string(app)])]
5560
%Mix.Dep{
5661
scm: Mix.SCM.Path,
5762
app: app,

lib/mix/test/mix/dep_test.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ defmodule Mix.DepTest do
8585
Mix.Project.push DepsApp
8686

8787
{_, true, _} =
88-
Mix.Dep.Converger.converge(false, [], nil, fn dep, acc, lock ->
88+
Mix.Dep.Converger.converge(Mix.Dep.children, false, [], nil, fn dep, acc, lock ->
8989
assert is_nil(dep.manager)
9090
{dep, acc or true, lock}
9191
end)

lib/mix/test/mix/umbrella_test.exs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ defmodule Mix.UmbrellaTest do
3434
end
3535
end
3636

37-
test "compiles umbrella with protocol consolidation (via build embedded)" do
37+
test "compiles umbrella with protocol consolidation" do
3838
in_fixture "umbrella_dep/deps/umbrella", fn ->
3939
Mix.Project.in_project(:umbrella, ".", [build_embedded: true], fn _ ->
4040
assert_raise Mix.Error, ~r"Cannot execute task because the project was not yet compiled", fn ->
@@ -98,6 +98,41 @@ defmodule Mix.UmbrellaTest do
9898
end
9999
end
100100

101+
test "loads umbrella child dependencies in all environments" do
102+
in_fixture "umbrella_dep/deps/umbrella", fn ->
103+
Mix.Project.in_project :umbrella, ".", fn _ ->
104+
File.write! "apps/bar/mix.exs", """
105+
defmodule Bar.Mix do
106+
use Mix.Project
107+
108+
def project do
109+
[app: :bar,
110+
version: "0.1.0",
111+
deps: [{:git_repo, git: MixTest.Case.fixture_path("git_repo"), only: :other}]]
112+
end
113+
end
114+
"""
115+
116+
# Should work across all environments
117+
Mix.Tasks.Deps.Get.run []
118+
assert_received {:mix_shell, :info, ["* Getting git_repo" <> _]}
119+
120+
# Works on the current environment only
121+
Mix.Tasks.Deps.run []
122+
refute_received {:mix_shell, :info, ["* git_repo " <> _]}
123+
124+
# Works on the other environment only
125+
Mix.env(:other)
126+
Mix.Tasks.Deps.run []
127+
assert_received {:mix_shell, :info, ["* git_repo " <> _]}
128+
end
129+
end
130+
after
131+
Mix.env(:test)
132+
end
133+
134+
## Umbrellas as a dependency
135+
101136
test "list deps for umbrella as dependency" do
102137
in_fixture("umbrella_dep", fn ->
103138
Mix.Project.in_project(:umbrella_dep, ".", fn _ ->

0 commit comments

Comments
 (0)