Skip to content

Commit cdbd480

Browse files
author
José Valim
committed
Path dependencies can only be used with mix projects, closes #1967
1 parent 0538e46 commit cdbd480

File tree

8 files changed

+75
-7
lines changed

8 files changed

+75
-7
lines changed

lib/mix/lib/mix/deps.ex

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,8 +248,13 @@ defmodule Mix.Deps do
248248
"\n Ensure they match or specify one of the above in your #{inspect Mix.Project.get} deps and set `override: true`"
249249
end
250250

251-
def format_status(Mix.Dep[status: { :unavailable, _ }]),
252-
do: "the dependency is not available, run `mix deps.get`"
251+
def format_status(Mix.Dep[status: { :unavailable, _ }, scm: scm]) do
252+
if scm.fetchable? do
253+
"the dependency is not available, run `mix deps.get`"
254+
else
255+
"the dependency is not available"
256+
end
257+
end
253258

254259
def format_status(Mix.Dep[status: { :elixirlock, _ }]),
255260
do: "the dependency is built with an out-of-date elixir version, run `mix deps.get`"

lib/mix/lib/mix/deps/retriever.ex

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ defmodule Mix.Deps.Retriever do
4646
{ dep, [] }
4747
end
4848

49-
{ validate_app(dep), children }
49+
{ validate_path(validate_app(dep)), children }
5050
end
5151

5252
@doc """
@@ -172,6 +172,15 @@ defmodule Mix.Deps.Retriever do
172172
end) |> Enum.concat
173173
end
174174

175+
defp validate_path(Mix.Dep[scm: scm, manager: manager] = dep) do
176+
if scm == Mix.SCM.Path and not manager in [:mix, nil] do
177+
raise Mix.Error, message: ":path option can only be used with mix projects, " <>
178+
"invalid path dependency for #{inspect dep.app}"
179+
else
180+
dep
181+
end
182+
end
183+
175184
defp validate_app(Mix.Dep[opts: opts, requirement: req, app: app, status: status] = dep) do
176185
opts_app = opts[:app]
177186

lib/mix/lib/mix/scm.ex

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ defmodule Mix.SCM do
88
behavior required by any SCM used by mix.
99
"""
1010

11+
@doc """
12+
Returns a boolean if the dependency can be fetched
13+
or it is meant to be previously available in the filesystem.
14+
"""
15+
defcallback fetchable? :: boolean
16+
1117
@doc """
1218
Returns a string representing the SCM. This is used
1319
when printing the dependency and not for inspection,

lib/mix/lib/mix/scm/git.ex

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ defmodule Mix.SCM.Git do
22
@behavior Mix.SCM
33
@moduledoc false
44

5+
def fetchable? do
6+
true
7+
end
8+
59
def format(opts) do
610
opts[:git]
711
end

lib/mix/lib/mix/scm/path.ex

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ defmodule Mix.SCM.Path do
22
@behavior Mix.SCM
33
@moduledoc false
44

5+
def fetchable? do
6+
false
7+
end
8+
59
def format(opts) do
610
opts[:path]
711
end

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,8 @@ defmodule Mix.Tasks.Deps.Get do
4949
Mix.Dep[app: app, scm: scm, opts: opts] = dep = check_lock(dep, lock)
5050

5151
cond do
52-
# Path dependencies are specially handled because they cannot
53-
# be fetched although they are always compiled afterwards
54-
scm == Mix.SCM.Path ->
52+
# Dependencies that cannot be fetched are always compiled afterwards
53+
not scm.fetchable? ->
5554
{ dep, { [app|acc], lock } }
5655

5756
# If the dependency is not available or we have a lock mismatch

lib/mix/test/mix/rebar_test.exs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,30 @@ Code.require_file "../test_helper.exs", __DIR__
33
defmodule Mix.RebarTest do
44
use MixTest.Case
55

6+
# Have our own path implementation that bypasses some
7+
# Path validation checks. We use this just for testing.
8+
defmodule MyPath do
9+
@behaviour Mix.SCM
10+
11+
lc { name, arity } inlist Mix.SCM.Path.__info__(:functions) do
12+
args = tl Enum.map 0..arity, &{ :"x#{&1}", [], nil }
13+
def unquote(name)(unquote_splicing(args)) do
14+
Mix.SCM.Path.unquote(name)(unquote_splicing(args))
15+
end
16+
end
17+
end
18+
19+
setup do
20+
available = Mix.SCM.available
21+
:application.set_env(:mix, :scm, [Mix.SCM.Git, MyPath])
22+
{ :ok, [scm: available] }
23+
end
24+
25+
teardown context do
26+
:application.set_env(:mix, :scm, context[:scm])
27+
:ok
28+
end
29+
630
defmodule RebarAsDep do
731
def project do
832
[ app: :rebar_as_dep,

lib/mix/test/mix/tasks/deps.path_test.exs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,21 @@ defmodule Mix.Tasks.DepsPathTest do
4141
after
4242
Mix.Project.pop
4343
end
44-
end
44+
45+
defmodule InvalidPathDepsApp do
46+
def project do
47+
[
48+
app: :rebar_as_dep,
49+
version: "0.1.0",
50+
deps: [{ :rebar_dep, path: MixTest.Case.tmp_path("rebar_dep") }]
51+
]
52+
end
53+
end
54+
55+
test "raises on non-mix path deps" do
56+
Mix.Project.push InvalidPathDepsApp
57+
assert_raise Mix.Error, %r/:path option can only be used with mix projects/, fn ->
58+
Mix.Tasks.Deps.Get.run []
59+
end
60+
end
61+
end

0 commit comments

Comments
 (0)