Skip to content

Commit 9d149a3

Browse files
committed
Merge pull request #2079 from ericmj/mix-dep-only
Add `:only` dep option to filter on environments
2 parents 00b1aad + 9158cad commit 9d149a3

File tree

17 files changed

+176
-52
lines changed

17 files changed

+176
-52
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* [IEx] Allow prompt configuration with the `:prompt` option
88
* [Kernel] Support `ERL_PATH` in `bin/elixir`
99
* [Map] Add a Map module and support R17 maps and structs
10+
* [Mix] Add dependency option `:only` to specify its environment
1011
* [Regex] Regexes no longer need the "g" option when there is a need to use named captures
1112
* [StringIO] Add a `StringIO` module that allows a String to be used as IO device
1213
* [System] Add `System.delete_env/1` to remove a variable from the environment

lib/mix/lib/mix/deps.ex

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ defmodule Mix.Deps do
5050
* `:compile` - A command to compile the dependency, defaults to a mix,
5151
rebar or make command
5252
* `:optional` - The dependency is optional and used only to specify requirements
53+
* `:only` - The dependency will only belong to the given environments, use when
54+
declaring dev or test only dependencies
5355
5456
## Git options (`:git`)
5557
@@ -87,7 +89,7 @@ defmodule Mix.Deps do
8789
This function raises an exception if any of the dependencies
8890
provided in the project are in the wrong format.
8991
"""
90-
defdelegate children(), to: Mix.Deps.Loader
92+
defdelegate children(otps), to: Mix.Deps.Loader
9193

9294
@doc """
9395
Returns loaded dependencies recursively as a `Mix.Dep` record.
@@ -97,8 +99,8 @@ defmodule Mix.Deps do
9799
This function raises an exception if any of the dependencies
98100
provided in the project are in the wrong format.
99101
"""
100-
def loaded do
101-
{ deps, _ } = Mix.Deps.Converger.all(nil, fn(dep, acc) -> { dep, acc } end)
102+
def loaded(opts) do
103+
{ deps, _ } = Mix.Deps.Converger.all(nil, opts, fn(dep, acc) -> { dep, acc } end)
102104
Mix.Deps.Converger.topsort(deps)
103105
end
104106

@@ -111,7 +113,9 @@ defmodule Mix.Deps do
111113
This function raises an exception if any of the dependencies
112114
provided in the project are in the wrong format.
113115
"""
114-
def loaded_by_name(given, all_deps \\ loaded) do
116+
def loaded_by_name(given, all_deps \\ nil, opts) do
117+
all_deps = all_deps || loaded(opts)
118+
115119
# Ensure all apps are atoms
116120
apps = to_app_names(given)
117121

@@ -141,29 +145,31 @@ defmodule Mix.Deps do
141145
The callback expects the current dependency and the accumulator
142146
as arguments. The accumulator is returned as result.
143147
148+
See `Mix.Deps.Converger.all/3` for options.
149+
144150
## Exceptions
145151
146152
This function raises an exception if any of the dependencies
147153
provided in the project are in the wrong format.
148154
"""
149-
def unloaded(acc, callback) do
150-
{ deps, acc } = Mix.Deps.Converger.all(acc, callback)
155+
def unloaded(acc, opts, callback) do
156+
{ deps, acc } = Mix.Deps.Converger.all(acc, opts, callback)
151157
{ Mix.Deps.Converger.topsort(deps), acc }
152158
end
153159

154160
@doc """
155161
Receives a list of dependency names and maps and reduces over
156-
them.
162+
them. See `unloaded`.
157163
158164
## Exceptions
159165
160166
This function raises an exception if any of the dependencies
161167
provided in the project are in the wrong format.
162168
"""
163-
def unloaded_by_name(given, acc, callback) do
169+
def unloaded_by_name(given, acc, opts, callback) do
164170
names = to_app_names(given)
165171

166-
unloaded(acc, fn(dep, acc) ->
172+
unloaded(acc, opts, fn(dep, acc) ->
167173
if dep.app in names do
168174
callback.(dep, acc)
169175
else
@@ -254,7 +260,7 @@ defmodule Mix.Deps do
254260

255261
def format_status(Mix.Dep[status: { :unavailable, _ }, scm: scm]) do
256262
if scm.fetchable? do
257-
"the dependency is not available, run `#{mix_env_var}mix deps.get`"
263+
"the dependency is not available, run `mix deps.get`"
258264
else
259265
"the dependency is not available"
260266
end

lib/mix/lib/mix/deps/converger.ex

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,11 @@ defmodule Mix.Deps.Converger do
3838
including nested dependencies. There is a callback
3939
that is invoked for each dependency and must return
4040
an updated dependency in case some processing is done.
41+
42+
See `Mix.Deps.Loader.children/1` for options.
4143
"""
42-
def all(rest, callback) do
43-
main = Mix.Deps.Loader.children
44+
def all(rest, opts, callback) do
45+
main = Mix.Deps.Loader.children(opts)
4446
apps = Enum.map(main, &(&1.app))
4547
converger = Mix.RemoteConverger.get
4648

lib/mix/lib/mix/deps/fetcher.ex

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,24 @@ defmodule Mix.Deps.Fetcher do
1111

1212
@doc """
1313
Fetches all dependencies.
14+
15+
See `Mix.Deps.unloaded/3` for options.
1416
"""
15-
def all(old_lock, new_lock) do
16-
{ apps, _deps } = do_finalize Mix.Deps.unloaded({ [], new_lock }, &do_fetch/2), old_lock
17+
def all(old_lock, new_lock, opts) do
18+
deps = Mix.Deps.unloaded({ [], new_lock }, opts, &do_fetch/2)
19+
{ apps, _deps } = do_finalize(deps, old_lock, opts)
1720
apps
1821
end
1922

2023
@doc """
2124
Fetches the dependencies with the given names and their children recursively.
25+
26+
See `Mix.Deps.unloaded_by_name/4` for options.
2227
"""
23-
def by_name(names, old_lock, new_lock) do
24-
{ apps, deps } = do_finalize Mix.Deps.unloaded_by_name(names, { [], new_lock }, &do_fetch/2), old_lock
25-
Mix.Deps.loaded_by_name(names, deps) # Check all given dependencies are loaded or fail
28+
def by_name(names, old_lock, new_lock, opts) do
29+
deps = Mix.Deps.unloaded_by_name(names, { [], new_lock }, opts, &do_fetch/2)
30+
{ apps, deps } = do_finalize(deps, old_lock, opts)
31+
Mix.Deps.loaded_by_name(names, deps, opts) # Check all given dependencies are loaded or fail
2632
apps
2733
end
2834

@@ -63,9 +69,9 @@ defmodule Mix.Deps.Fetcher do
6369
defp out_of_date?(Mix.Dep[status: { :unavailable, _ }]), do: true
6470
defp out_of_date?(Mix.Dep[]), do: false
6571

66-
defp do_finalize({ all_deps, { apps, new_lock } }, old_lock) do
72+
defp do_finalize({ all_deps, { apps, new_lock } }, old_lock, opts) do
6773
# Let's get the loaded versions of deps
68-
deps = Mix.Deps.loaded_by_name(apps, all_deps)
74+
deps = Mix.Deps.loaded_by_name(apps, all_deps, opts)
6975

7076
# Do not mark dependencies that are not available
7177
deps = Enum.filter(deps, &available?/1)

lib/mix/lib/mix/deps/loader.ex

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,29 @@ defmodule Mix.Deps.Loader do
88
Gets all direct children of the current `Mix.Project`
99
as a `Mix.Dep` record. Umbrella project dependencies
1010
are included as children.
11+
12+
By default, it will filter all dependencies that does not match
13+
current environment, behaviour can be overriden via options.
14+
15+
## Options
16+
17+
* `:env` - Filter dependencies on given environments
1118
"""
12-
def children do
19+
def children(opts) do
1320
scms = Mix.SCM.available
1421
from = Path.absname("mix.exs")
15-
Enum.map(Mix.project[:deps] || [], &to_dep(&1, scms, from)) ++
16-
Mix.Deps.Umbrella.unloaded
22+
deps = Enum.map(Mix.project[:deps] || [], &to_dep(&1, scms, from))
23+
24+
# Filter deps not matching mix environment
25+
if env = opts[:env] do
26+
deps =
27+
Enum.filter(deps, fn Mix.Dep[opts: opts] ->
28+
only = opts[:only]
29+
if only, do: env in List.wrap(only), else: true
30+
end)
31+
end
32+
33+
deps ++ Mix.Deps.Umbrella.unloaded
1734
end
1835

1936
@doc """
@@ -173,6 +190,7 @@ defmodule Mix.Deps.Loader do
173190
"are running on v#{System.version}, please run mix deps.update #{dep.app} to update it"
174191
end
175192

193+
children = children(env: opts[:env] || :prod)
176194
{ dep.manager(:mix).opts(opts).extra(umbrella: umbrella?), children }
177195
end)
178196
end

lib/mix/lib/mix/tasks/compile.elixir.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ defmodule Mix.Tasks.Compile.Elixir do
284284
defp path_deps_changed?(manifest) do
285285
manifest = Path.absname(manifest)
286286

287-
deps = Enum.filter(Mix.Deps.children, fn(Mix.Dep[] = dep) ->
287+
deps = Enum.filter(Mix.Deps.children([]), fn(Mix.Dep[] = dep) ->
288288
dep.scm == Mix.SCM.Path
289289
end)
290290

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
defmodule Mix.Tasks.Deps.Check do
22
use Mix.Task
33

4-
import Mix.Deps, only: [loaded: 0, loaded_by_name: 1, format_dep: 1,
4+
import Mix.Deps, only: [loaded: 1, loaded_by_name: 2, format_dep: 1,
55
format_status: 1, check_lock: 2, ok?: 1]
66

77
@moduledoc """
@@ -20,7 +20,7 @@ defmodule Mix.Tasks.Deps.Check do
2020
def run(args) do
2121
{ opts, _, _ } = OptionParser.parse(args, switches: [quiet: :boolean])
2222
lock = Mix.Deps.Lock.read
23-
all = Enum.map loaded, &check_lock(&1, lock)
23+
all = Enum.map(loaded(env: Mix.env), &check_lock(&1, lock))
2424

2525
prune_deps(all)
2626
{ not_ok, compile } = partition_deps(all, [], [])
@@ -34,7 +34,7 @@ defmodule Mix.Tasks.Deps.Check do
3434
Mix.Tasks.Deps.Compile.compile(compile, opts)
3535
show_not_ok compile
3636
|> Enum.map(& &1.app)
37-
|> loaded_by_name
37+
|> loaded_by_name(env: Mix.env)
3838
|> Enum.filter(&(not ok?(&1)))
3939
end
4040
end

lib/mix/lib/mix/tasks/deps.clean.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ defmodule Mix.Tasks.Deps.Clean do
1515
Mix.Project.get! # Require the project to be available
1616

1717
{ opts, args, _ } = OptionParser.parse(args, switches: [unlock: :boolean, all: :boolean])
18-
loaded = Mix.Deps.loaded
18+
loaded = Mix.Deps.loaded(env: Mix.env)
1919

2020
cond do
2121
opts[:all] ->

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,17 @@ defmodule Mix.Tasks.Deps.Compile do
2727
2828
"""
2929

30-
import Mix.Deps, only: [loaded: 0, available?: 1, loaded_by_name: 1,
30+
import Mix.Deps, only: [loaded: 1, available?: 1, loaded_by_name: 2,
3131
format_dep: 1, make?: 1, mix?: 1, rebar?: 1]
3232

3333
def run(args) do
3434
Mix.Project.get! # Require the project to be available
3535

3636
case OptionParser.parse(args, switches: [quiet: :boolean]) do
3737
{ opts, [], _ } ->
38-
compile(Enum.filter(loaded, &compilable?/1), opts)
38+
compile(Enum.filter(loaded(env: Mix.env), &compilable?/1), opts)
3939
{ opts, tail, _ } ->
40-
compile(loaded_by_name(tail), opts)
40+
compile(loaded_by_name(tail, env: Mix.env), opts)
4141
end
4242
end
4343

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

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
defmodule Mix.Tasks.Deps do
22
use Mix.Task
33

4-
import Mix.Deps, only: [loaded: 0, format_dep: 1, format_status: 1, check_lock: 2]
4+
import Mix.Deps, only: [loaded: 1, format_dep: 1, format_status: 1, check_lock: 2]
55

66
@shortdoc "List dependencies and their status"
77

@@ -13,14 +13,24 @@ defmodule Mix.Tasks.Deps do
1313
[locked at REF]
1414
STATUS
1515
16+
## Command line options
17+
18+
* `--all` - check all dependencies, regardless of specified environment
1619
"""
17-
def run(_) do
20+
def run(args) do
1821
Mix.Project.get! # Require the project to be available
22+
{ opts, _, _ } = OptionParser.parse(args)
23+
24+
if opts[:all] do
25+
loaded_opts = []
26+
else
27+
loaded_opts = [env: Mix.env]
28+
end
1929

2030
shell = Mix.shell
2131
lock = Mix.Deps.Lock.read
2232

23-
Enum.each loaded, fn(Mix.Dep[scm: scm] = dep) ->
33+
Enum.each loaded(loaded_opts), fn(Mix.Dep[scm: scm] = dep) ->
2434
dep = check_lock(dep, lock)
2535
shell.info "* #{format_dep(dep)}"
2636
if formatted = scm.format_lock(dep.opts) do

0 commit comments

Comments
 (0)