Skip to content

Commit 788a3cf

Browse files
author
José Valim
committed
Merge branch 'jv-nerves' into v1.2
2 parents 598c33d + ffb6266 commit 788a3cf

File tree

13 files changed

+190
-21
lines changed

13 files changed

+190
-21
lines changed

lib/elixir/lib/application.ex

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,14 +133,16 @@ defmodule Application do
133133
@doc """
134134
Returns the value for `key` in `app`'s specification.
135135
136-
See `spec/1` for the supporte keys. If the given
136+
See `spec/1` for the supported keys. If the given
137137
specification parameter does not exist, this function
138-
will raise.
138+
will raise. Returns `nil` if the application is not loaded.
139139
"""
140-
@spec spec(app, key) :: value
140+
@spec spec(app, key) :: value | nil
141141
def spec(app, key) when key in @application_keys do
142-
{:ok, value} = :application.get_key(app, key)
143-
value
142+
case :application.get_key(app, key) do
143+
{:ok, value} -> value
144+
:undefined -> nil
145+
end
144146
end
145147

146148
@doc """

lib/elixir/test/elixir/application_test.exs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ defmodule ApplicationTest do
3838
test "application specification" do
3939
assert is_list Application.spec(:elixir)
4040
assert Application.spec(:unknown) == nil
41+
assert Application.spec(:unknown, :description) == nil
4142

4243
assert Application.spec(:elixir, :description) == 'elixir'
4344
assert_raise FunctionClauseError, fn -> Application.spec(:elixir, :unknown) end

lib/mix/lib/mix/dep.ex

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,12 @@ defmodule Mix.Dep do
100100

101101
# Ensure all apps are atoms
102102
apps = to_app_names(given)
103-
104-
# We need to keep the order of deps, loaded/1 properly orders them
105-
deps = Enum.filter(all_deps, &(&1.app in apps))
103+
deps =
104+
if opts[:include_children] do
105+
get_deps_with_children(all_deps, apps)
106+
else
107+
get_deps(all_deps, apps)
108+
end
106109

107110
Enum.each apps, fn(app) ->
108111
unless Enum.any?(all_deps, &(&1.app == app)) do
@@ -113,6 +116,30 @@ defmodule Mix.Dep do
113116
deps
114117
end
115118

119+
defp get_deps(all_deps, apps) do
120+
Enum.filter(all_deps, &(&1.app in apps))
121+
end
122+
123+
defp get_deps_with_children(all_deps, apps) do
124+
deps = get_children(all_deps, apps)
125+
apps = deps |> Enum.map(& &1.app) |> Enum.uniq
126+
get_deps(all_deps, apps)
127+
end
128+
129+
defp get_children(_all_deps, []), do: []
130+
defp get_children(all_deps, apps) do
131+
# Current deps
132+
deps = get_deps(all_deps, apps)
133+
134+
# Children apps
135+
apps = for %{deps: children} <- deps,
136+
%{app: app} <- children,
137+
do: app
138+
139+
# Current deps + children deps
140+
deps ++ get_children(all_deps, apps)
141+
end
142+
116143
@doc """
117144
Runs the given `fun` inside the given dependency project by
118145
changing the current working directory and loading the given

lib/mix/lib/mix/tasks/app.start.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ defmodule Mix.Tasks.App.Start do
2121
* `--permanent` - start the application as permanent
2222
* `--no-compile` - do not compile even if files require compilation
2323
* `--no-protocols` - do not load consolidated protocols
24+
* `--no-archives-check` - do not check archives
2425
* `--no-deps-check` - do not check dependencies
2526
* `--no-elixir-version-check` - do not check Elixir version
2627
* `--no-start` - do not start applications after compilation
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
defmodule Mix.Tasks.Archive.Check do
2+
use Mix.Task
3+
4+
@moduledoc """
5+
Checks all archives are available.
6+
7+
Mix projects can specify required archives using
8+
the `:archives` option:
9+
10+
archives: [{:foo, "~> 1.0.0"}]
11+
12+
This task guarantees this option is respected.
13+
"""
14+
def run(_) do
15+
archives = Mix.Project.config[:archives] || []
16+
17+
Enum.each archives, fn tuple ->
18+
{archive, req} = parse_archive(tuple)
19+
_ = Application.load(archive)
20+
vsn = Application.spec(archive, :vsn)
21+
cond do
22+
is_nil(vsn) ->
23+
Mix.raise "Archive \"#{archive}\" could not be found. " <>
24+
"Please make sure the archive is installed locally."
25+
not Version.match?(List.to_string(vsn), req) ->
26+
Mix.raise "Archive \"#{archive}-#{vsn}\" does not match requirement #{req}. " <>
27+
"Please update your archive version accordingly."
28+
true ->
29+
:ok
30+
end
31+
end
32+
end
33+
34+
defp parse_archive({archive, req}) when is_atom(archive) and is_binary(req) do
35+
case Version.parse_requirement(req) do
36+
{:ok, req} ->
37+
{archive, req}
38+
:error ->
39+
Mix.raise "Invalid requirement #{req} for archive \"#{archive}\""
40+
end
41+
end
42+
43+
defp parse_archive(other) do
44+
Mix.raise """
45+
Expected archive to be in the format:
46+
47+
{app :: atom, requirement :: binary}
48+
49+
got:
50+
51+
#{inspect other}
52+
53+
"""
54+
end
55+
end

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ defmodule Mix.Tasks.Clean do
4747

4848
# Loadpaths without checks because compilers may be defined in deps.
4949
defp loadpaths! do
50-
Mix.Task.run "loadpaths", ["--no-elixir-version-check", "--no-deps-check"]
50+
Mix.Task.run "loadpaths", ["--no-elixir-version-check", "--no-deps-check", "--no-archives-check"]
5151
Mix.Task.reenable "loadpaths"
5252
end
5353
end

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,10 @@ defmodule Mix.Tasks.Compile do
4141
4242
## Command line options
4343
44-
* `--list` - list all enabled compilers
45-
* `--no-deps-check` - skip checking of dependencies
46-
* `--force` - force compilation
44+
* `--list` - list all enabled compilers
45+
* `--no-archives-check` - skip checking of archives
46+
* `--no-deps-check` - skip checking of dependencies
47+
* `--force` - force compilation
4748
4849
"""
4950
@spec run(OptionParser.argv) :: :ok | :noop
@@ -96,7 +97,7 @@ defmodule Mix.Tasks.Compile do
9697

9798
# Loadpaths without checks because compilers may be defined in deps.
9899
defp loadpaths! do
99-
Mix.Task.run "loadpaths", ["--no-elixir-version-check", "--no-deps-check"]
100+
Mix.Task.run "loadpaths", ["--no-elixir-version-check", "--no-deps-check", "--no-archives-check"]
100101
Mix.Task.reenable "loadpaths"
101102
end
102103

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

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ defmodule Mix.Tasks.Deps.Compile do
66
@moduledoc """
77
Compiles dependencies.
88
9-
By default, compile all dependencies. A list of dependencies can
10-
be given to force the compilation of specific dependencies.
9+
By default, compile all dependencies. A list of dependencies
10+
can be given to force the compilation of specific dependencies.
1111
1212
This task attempts to detect if the project contains one of
1313
the following files and act accordingly:
@@ -22,23 +22,31 @@ defmodule Mix.Tasks.Deps.Compile do
2222
2323
{:some_dependency, "0.1.0", compile: "command to compile"}
2424
25+
If a list of dependencies is given, Mix will attempt to compile
26+
them as is. For example, if project `a` depends on `b`, calling
27+
`mix deps.compile a` will compile `a` even if `b` is out of
28+
date. This is to allow parts of the dependency tree to be
29+
recompiled without propagating those changes upstream. To ensure
30+
`b` is included in the compilation step, pass `--include-children`.
2531
"""
2632

2733
import Mix.Dep, only: [loaded: 1, available?: 1, loaded_by_name: 2,
2834
format_dep: 1, make?: 1, mix?: 1]
2935

36+
@switches [include_children: :boolean]
37+
3038
@spec run(OptionParser.argv) :: :ok
3139
def run(args) do
3240
Mix.Project.get!
3341

34-
case OptionParser.parse(args) do
42+
case OptionParser.parse(args, switches: @switches) do
3543
{_, [], _} ->
36-
# Because this command is invoked explicitly with
44+
# Because this command may be invoked explicitly with
3745
# deps.compile, we simply try to compile any available
3846
# dependency.
3947
compile(Enum.filter(loaded(env: Mix.env), &available?/1))
40-
{_, tail, _} ->
41-
compile(loaded_by_name(tail, env: Mix.env))
48+
{opts, tail, _} ->
49+
compile(loaded_by_name(tail, [env: Mix.env] ++ opts))
4250
end
4351
end
4452

@@ -47,7 +55,7 @@ defmodule Mix.Tasks.Deps.Compile do
4755
shell = Mix.shell
4856
config = Mix.Project.deps_config
4957

50-
Mix.Task.run "deps.loadpaths"
58+
Mix.Task.run "deps.precompile"
5159

5260
compiled =
5361
Enum.map(deps, fn %Mix.Dep{app: app, status: status, opts: opts, scm: scm} = dep ->
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
defmodule Mix.Tasks.Deps.Precompile do
2+
use Mix.Task
3+
4+
@moduledoc """
5+
Extension point for precompiling dependencies.
6+
7+
This is a task that can be aliased by projects
8+
that need to execute certain tasks to before
9+
compiling dependencies:
10+
11+
aliases: ["deps.precompile": ["nerves.precompile", "deps.precompile"]]
12+
13+
By default, this task has a single responsibility
14+
of loading all dependencies paths.
15+
"""
16+
def run(_) do
17+
Mix.Task.run "deps.loadpaths"
18+
end
19+
end

lib/mix/lib/mix/tasks/help.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ defmodule Mix.Tasks.Help do
109109

110110
# Loadpaths without checks because tasks may be defined in deps.
111111
defp loadpaths! do
112-
Mix.Task.run "loadpaths", ["--no-elixir-version-check", "--no-deps-check"]
112+
Mix.Task.run "loadpaths", ["--no-elixir-version-check", "--no-deps-check", "--no-archives-check"]
113113
Mix.Task.reenable "loadpaths"
114114
end
115115

0 commit comments

Comments
 (0)