Merge pull request #2108 from ericmj/mix-dep-struct
Convert Mix.Dep record to struct
This commit is contained in:
+52
-50
@@ -1,7 +1,6 @@
|
||||
defrecord Mix.Dep, [ scm: nil, app: nil, requirement: nil, status: nil, opts: nil,
|
||||
deps: [], extra: nil, manager: nil, from: nil ] do
|
||||
defmodule Mix.Dep do
|
||||
@moduledoc """
|
||||
This is a record that keeps information about your project
|
||||
This is a struct that keeps information about your project
|
||||
dependencies. It contains:
|
||||
|
||||
* `scm` - a module representing the source code management tool (SCM) operations;
|
||||
@@ -16,6 +15,11 @@ defrecord Mix.Dep, [ scm: nil, app: nil, requirement: nil, status: nil, opts: ni
|
||||
the information on this field is private to the scm and
|
||||
should not be relied on.
|
||||
"""
|
||||
|
||||
@type t :: map
|
||||
|
||||
defstruct [ scm: nil, app: nil, requirement: nil, status: nil, opts: nil,
|
||||
deps: [], extra: nil, manager: nil, from: nil ]
|
||||
end
|
||||
|
||||
defmodule Mix.Deps do
|
||||
@@ -33,7 +37,7 @@ defmodule Mix.Deps do
|
||||
and opts is a keyword lists that may include options for the underlying
|
||||
SCM or options used by Mix. Each set of options is documented below.
|
||||
|
||||
Inside Mix, those dependencies are converted to a `Mix.Dep` record.
|
||||
Inside Mix, those dependencies are converted to a `Mix.Dep` struct.
|
||||
This module provides conveniences to work with those dependencies
|
||||
and the dependencies are usually in two specific states: loaded and
|
||||
unloaded.
|
||||
@@ -94,7 +98,7 @@ defmodule Mix.Deps do
|
||||
defdelegate children(otps), to: Mix.Deps.Loader
|
||||
|
||||
@doc """
|
||||
Returns loaded dependencies recursively as a `Mix.Dep` record.
|
||||
Returns loaded dependencies recursively as a `Mix.Dep` struct.
|
||||
|
||||
## Exceptions
|
||||
|
||||
@@ -107,8 +111,8 @@ defmodule Mix.Deps do
|
||||
end
|
||||
|
||||
@doc """
|
||||
Receives a list of dependency names and returns loaded dependency
|
||||
records. Logs a message if the dependency could not be found.
|
||||
Receives a list of dependency names and returns loaded `Mix.Dep`s.
|
||||
Logs a message if the dependency could not be found.
|
||||
|
||||
## Exceptions
|
||||
|
||||
@@ -121,14 +125,11 @@ defmodule Mix.Deps do
|
||||
# Ensure all apps are atoms
|
||||
apps = to_app_names(given)
|
||||
|
||||
# We need to keep the order of all, which properly orders deps
|
||||
deps = Enum.filter all_deps, fn(dep) -> dep.app in apps end
|
||||
|
||||
# Now we validate the given atoms
|
||||
index = Mix.Dep.__record__(:index, :app)
|
||||
# We need to keep the order of deps, loaded/1 properly orders them
|
||||
deps = Enum.filter(all_deps, &(&1.app in apps))
|
||||
|
||||
Enum.each apps, fn(app) ->
|
||||
unless List.keyfind(all_deps, app, index) do
|
||||
unless Enum.any?(all_deps, &(&1.app == app)) do
|
||||
raise Mix.Error, message: "Unknown dependency #{app} for environment #{Mix.env}"
|
||||
end
|
||||
end
|
||||
@@ -189,7 +190,7 @@ defmodule Mix.Deps do
|
||||
"""
|
||||
def in_dependency(dep, post_config \\ [], fun)
|
||||
|
||||
def in_dependency(Mix.Dep[app: app, opts: opts], config, fun) do
|
||||
def in_dependency(%Mix.Dep{app: app, opts: opts}, config, fun) do
|
||||
# Set the app_path to be the one stored in the dependency.
|
||||
# This is important because the name of application in the
|
||||
# mix.exs file can be different than the actual name and we
|
||||
@@ -211,36 +212,36 @@ defmodule Mix.Deps do
|
||||
@doc """
|
||||
Formats the status of a dependency.
|
||||
"""
|
||||
def format_status(Mix.Dep[status: { :ok, _vsn }]),
|
||||
def format_status(%Mix.Dep{status: { :ok, _vsn }}),
|
||||
do: "ok"
|
||||
|
||||
def format_status(Mix.Dep[status: { :noappfile, path }]),
|
||||
def format_status(%Mix.Dep{status: { :noappfile, path }}),
|
||||
do: "could not find an app file at #{Path.relative_to_cwd(path)}, " <>
|
||||
"this may happen when you specified the wrong application name in your deps " <>
|
||||
"or if the dependency did not compile (which can be amended with `#{mix_env_var}mix deps.compile`)"
|
||||
|
||||
def format_status(Mix.Dep[status: { :invalidapp, path }]),
|
||||
def format_status(%Mix.Dep{status: { :invalidapp, path }}),
|
||||
do: "the app file at #{Path.relative_to_cwd(path)} is invalid"
|
||||
|
||||
def format_status(Mix.Dep[status: { :invalidvsn, vsn }]),
|
||||
def format_status(%Mix.Dep{status: { :invalidvsn, vsn }}),
|
||||
do: "the app file contains an invalid version: #{inspect vsn}"
|
||||
|
||||
def format_status(Mix.Dep[status: { :nomatchvsn, vsn }, requirement: req]),
|
||||
def format_status(%Mix.Dep{status: { :nomatchvsn, vsn }, requirement: req}),
|
||||
do: "the dependency does not match the requirement #{inspect req}, got #{inspect vsn}"
|
||||
|
||||
def format_status(Mix.Dep[status: { :lockmismatch, _ }]),
|
||||
def format_status(%Mix.Dep{status: { :lockmismatch, _ }}),
|
||||
do: "lock mismatch: the dependency is out of date"
|
||||
|
||||
def format_status(Mix.Dep[status: :lockoutdated]),
|
||||
def format_status(%Mix.Dep{status: :lockoutdated}),
|
||||
do: "lock outdated: the lock is outdated compared to the options in your mixfile"
|
||||
|
||||
def format_status(Mix.Dep[status: :nolock]),
|
||||
def format_status(%Mix.Dep{status: :nolock}),
|
||||
do: "the dependency is not locked"
|
||||
|
||||
def format_status(Mix.Dep[status: :compile]),
|
||||
def format_status(%Mix.Dep{status: :compile}),
|
||||
do: "the dependency build is outdated, please run `#{mix_env_var}mix deps.compile`"
|
||||
|
||||
def format_status(Mix.Dep[app: app, status: { :divergedreq, other }] = dep) do
|
||||
def format_status(%Mix.Dep{app: app, status: { :divergedreq, other }} = dep) do
|
||||
"the dependency #{app} defined\n" <>
|
||||
"#{dep_status(dep)}" <>
|
||||
"\n does not match the requirement specified\n" <>
|
||||
@@ -248,19 +249,19 @@ defmodule Mix.Deps do
|
||||
"\n Ensure they match or specify one of the above in your #{inspect Mix.Project.get} deps and set `override: true`"
|
||||
end
|
||||
|
||||
def format_status(Mix.Dep[app: app, status: { :diverged, other }] = dep) do
|
||||
def format_status(%Mix.Dep{app: app, status: { :diverged, other }} = dep) do
|
||||
"different specs were given for the #{app} app:\n" <>
|
||||
"#{dep_status(dep)}#{dep_status(other)}" <>
|
||||
"\n Ensure they match or specify one of the above in your #{inspect Mix.Project.get} deps and set `override: true`"
|
||||
end
|
||||
|
||||
def format_status(Mix.Dep[app: app, status: { :overridden, other }] = dep) do
|
||||
def format_status(%Mix.Dep{app: app, status: { :overridden, other }} = dep) do
|
||||
"the dependency #{app} in #{Path.relative_to_cwd(dep.from)} is overriding a child dependency:\n" <>
|
||||
"#{dep_status(dep)}#{dep_status(other)}" <>
|
||||
"\n Ensure they match or specify one of the above in your #{inspect Mix.Project.get} deps and set `override: true`"
|
||||
end
|
||||
|
||||
def format_status(Mix.Dep[status: { :unavailable, _ }, scm: scm]) do
|
||||
def format_status(%Mix.Dep{status: { :unavailable, _ }, scm: scm}) do
|
||||
if scm.fetchable? do
|
||||
"the dependency is not available, run `mix deps.get`"
|
||||
else
|
||||
@@ -268,10 +269,10 @@ defmodule Mix.Deps do
|
||||
end
|
||||
end
|
||||
|
||||
def format_status(Mix.Dep[status: { :elixirlock, _ }]),
|
||||
def format_status(%Mix.Dep{status: { :elixirlock, _ }}),
|
||||
do: "the dependency is built with an out-of-date elixir version, run `#{mix_env_var}mix deps.compile`"
|
||||
|
||||
defp dep_status(Mix.Dep[app: app, requirement: req, opts: opts, from: from]) do
|
||||
defp dep_status(%Mix.Dep{app: app, requirement: req, opts: opts, from: from}) do
|
||||
info = { app, req, Dict.drop(opts, [:dest, :lock, :env, :build]) }
|
||||
"\n > In #{Path.relative_to_cwd(from)}:\n #{inspect info}\n"
|
||||
end
|
||||
@@ -279,7 +280,7 @@ defmodule Mix.Deps do
|
||||
@doc """
|
||||
Checks the lock for the given dependency and update its status accordingly.
|
||||
"""
|
||||
def check_lock(Mix.Dep[scm: scm, app: app, opts: opts] = dep, lock) do
|
||||
def check_lock(%Mix.Dep{scm: scm, app: app, opts: opts} = dep, lock) do
|
||||
if rev = lock[app] do
|
||||
opts = Keyword.put(opts, :lock, rev)
|
||||
end
|
||||
@@ -287,42 +288,43 @@ defmodule Mix.Deps do
|
||||
if available?(dep) do
|
||||
case scm.lock_status(opts) do
|
||||
:mismatch ->
|
||||
dep.status(if rev, do: { :lockmismatch, rev }, else: :nolock).opts(opts)
|
||||
status = if rev, do: { :lockmismatch, rev }, else: :nolock
|
||||
%{dep | status: status, opts: opts}
|
||||
:outdated ->
|
||||
# Don't include the lock in the dependency if it is outdated
|
||||
dep.status(:lockoutdated)
|
||||
%{dep | status: :lockoutdated}
|
||||
:ok ->
|
||||
if vsn = old_elixir_lock(dep) do
|
||||
dep.status({ :elixirlock, vsn }).opts(opts)
|
||||
%{dep | status: { :elixirlock, vsn }, opts: opts}
|
||||
else
|
||||
dep.opts(opts)
|
||||
%{dep | opts: opts}
|
||||
end
|
||||
end
|
||||
else
|
||||
dep.opts(opts)
|
||||
%{dep | opts: opts}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns true if the dependency is ok.
|
||||
"""
|
||||
def ok?(Mix.Dep[status: { :ok, _ }]), do: true
|
||||
def ok?(Mix.Dep[]), do: false
|
||||
def ok?(%Mix.Dep{status: { :ok, _ }}), do: true
|
||||
def ok?(%Mix.Dep{}), do: false
|
||||
|
||||
@doc """
|
||||
Checks if a dependency is available. Available dependencies
|
||||
are the ones that can be loaded.
|
||||
"""
|
||||
def available?(Mix.Dep[status: { :overridden, _ }]), do: false
|
||||
def available?(Mix.Dep[status: { :diverged, _ }]), do: false
|
||||
def available?(Mix.Dep[status: { :divergedreq, _ }]), do: false
|
||||
def available?(Mix.Dep[status: { :unavailable, _ }]), do: false
|
||||
def available?(Mix.Dep[]), do: true
|
||||
def available?(%Mix.Dep{status: { :overridden, _ }}), do: false
|
||||
def available?(%Mix.Dep{status: { :diverged, _ }}), do: false
|
||||
def available?(%Mix.Dep{status: { :divergedreq, _ }}), do: false
|
||||
def available?(%Mix.Dep{status: { :unavailable, _ }}), do: false
|
||||
def available?(%Mix.Dep{}), do: true
|
||||
|
||||
@doc """
|
||||
Formats a dependency for printing.
|
||||
"""
|
||||
def format_dep(Mix.Dep[scm: scm, app: app, status: status, opts: opts]) do
|
||||
def format_dep(%Mix.Dep{scm: scm, app: app, status: status, opts: opts}) do
|
||||
version =
|
||||
case status do
|
||||
{ :ok, vsn } when vsn != nil -> "#{vsn} "
|
||||
@@ -336,7 +338,7 @@ defmodule Mix.Deps do
|
||||
Returns all load paths for the given dependency. Automatically
|
||||
derived from source paths.
|
||||
"""
|
||||
def load_paths(Mix.Dep[opts: opts] = dep) do
|
||||
def load_paths(%Mix.Dep{opts: opts} = dep) do
|
||||
build_path = Path.dirname(opts[:build])
|
||||
Enum.map source_paths(dep), fn path ->
|
||||
Path.join [build_path, Path.basename(path), "ebin"]
|
||||
@@ -349,7 +351,7 @@ defmodule Mix.Deps do
|
||||
Source paths are the directories that contains ebin files for a given
|
||||
dependency. All managers, except rebar, have only one source path.
|
||||
"""
|
||||
def source_paths(Mix.Dep[manager: :rebar, opts: opts, extra: extra]) do
|
||||
def source_paths(%Mix.Dep{manager: :rebar, opts: opts, extra: extra}) do
|
||||
# Add root dir and all sub dirs with ebin/ directory
|
||||
sub_dirs = Enum.map(extra[:sub_dirs] || [], fn path ->
|
||||
Path.join(opts[:dest], path)
|
||||
@@ -361,28 +363,28 @@ defmodule Mix.Deps do
|
||||
|> Enum.filter(fn p -> p |> Path.join("ebin") |> File.dir? end)
|
||||
end
|
||||
|
||||
def source_paths(Mix.Dep[opts: opts]) do
|
||||
def source_paths(%Mix.Dep{opts: opts}) do
|
||||
[opts[:dest]]
|
||||
end
|
||||
|
||||
@doc """
|
||||
Return `true` if dependency is a mix project.
|
||||
"""
|
||||
def mix?(Mix.Dep[manager: manager]) do
|
||||
def mix?(%Mix.Dep{manager: manager}) do
|
||||
manager == :mix
|
||||
end
|
||||
|
||||
@doc """
|
||||
Return `true` if dependency is a rebar project.
|
||||
"""
|
||||
def rebar?(Mix.Dep[manager: manager]) do
|
||||
def rebar?(%Mix.Dep{manager: manager}) do
|
||||
manager == :rebar
|
||||
end
|
||||
|
||||
@doc """
|
||||
Return `true` if dependency is a make project.
|
||||
"""
|
||||
def make?(Mix.Dep[manager: manager]) do
|
||||
def make?(%Mix.Dep{manager: manager}) do
|
||||
manager == :make
|
||||
end
|
||||
|
||||
@@ -402,7 +404,7 @@ defmodule Mix.Deps do
|
||||
end
|
||||
end
|
||||
|
||||
defp old_elixir_lock(Mix.Dep[opts: opts]) do
|
||||
defp old_elixir_lock(%Mix.Dep{opts: opts}) do
|
||||
old_vsn = Mix.Deps.Lock.elixir_vsn(opts[:build])
|
||||
if old_vsn && old_vsn != System.version do
|
||||
old_vsn
|
||||
|
||||
@@ -11,20 +11,20 @@ defmodule Mix.Deps.Converger do
|
||||
graph = :digraph.new
|
||||
|
||||
try do
|
||||
Enum.each deps, fn Mix.Dep[app: app] ->
|
||||
Enum.each(deps, fn %Mix.Dep{app: app} ->
|
||||
:digraph.add_vertex(graph, app)
|
||||
end
|
||||
end)
|
||||
|
||||
Enum.each deps, fn Mix.Dep[app: app, deps: other_deps] ->
|
||||
Enum.each other_deps, fn Mix.Dep[app: other_app] ->
|
||||
Enum.each(deps, fn %Mix.Dep{app: app, deps: other_deps} ->
|
||||
Enum.each(other_deps, fn %Mix.Dep{app: other_app} ->
|
||||
:digraph.add_edge(graph, other_app, app)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
if apps = :digraph_utils.topsort(graph) do
|
||||
Enum.map apps, fn(app) ->
|
||||
Enum.find(deps, fn(Mix.Dep[app: other_app]) -> app == other_app end)
|
||||
end
|
||||
Enum.map(apps, fn(app) ->
|
||||
Enum.find(deps, fn(%Mix.Dep{app: other_app}) -> app == other_app end)
|
||||
end)
|
||||
else
|
||||
raise Mix.Error, message: "Could not sort dependencies. There are cycles in the dependency graph."
|
||||
end
|
||||
@@ -143,7 +143,7 @@ defmodule Mix.Deps.Converger do
|
||||
Mix.Deps.Loader.load(dep)
|
||||
end
|
||||
|
||||
dep = dep.update_deps(&reject_non_fullfilled_optional(&1, current_breadths))
|
||||
dep = %{dep | deps: reject_non_fullfilled_optional(dep.deps, current_breadths)}
|
||||
{ acc, rest } = all(t, [dep|acc], upper_breadths, current_breadths, callback, rest, cache)
|
||||
all(dep.deps, acc, current_breadths, Enum.map(dep.deps, &(&1.app)) ++ current_breadths, callback, rest, cache)
|
||||
end
|
||||
@@ -164,12 +164,12 @@ defmodule Mix.Deps.Converger do
|
||||
# also check for the override option and mark the dependency
|
||||
# as overridden instead of diverged.
|
||||
defp diverged_deps(list, upper_breadths, dep) do
|
||||
Mix.Dep[app: app] = dep
|
||||
%Mix.Dep{app: app} = dep
|
||||
in_upper? = app in upper_breadths
|
||||
|
||||
{ acc, match } =
|
||||
Enum.map_reduce list, false, fn(other, match) ->
|
||||
Mix.Dep[app: other_app, opts: other_opts] = other
|
||||
%Mix.Dep{app: other_app, opts: other_opts} = other
|
||||
|
||||
cond do
|
||||
app != other_app ->
|
||||
@@ -180,30 +180,30 @@ defmodule Mix.Deps.Converger do
|
||||
{ with_matching_req(other, dep), true }
|
||||
true ->
|
||||
tag = if in_upper?, do: :overridden, else: :diverged
|
||||
{ other.status({ tag, dep }), true }
|
||||
{ %{other | status: { tag, dep }}, true }
|
||||
end
|
||||
end
|
||||
|
||||
if match, do: acc
|
||||
end
|
||||
|
||||
defp converge?(Mix.Dep[scm: scm1, opts: opts1], Mix.Dep[scm: scm2, opts: opts2]) do
|
||||
defp converge?(%Mix.Dep{scm: scm1, opts: opts1}, %Mix.Dep{scm: scm2, opts: opts2}) do
|
||||
scm1 == scm2 and scm1.equal?(opts1, opts2)
|
||||
end
|
||||
|
||||
defp reject_non_fullfilled_optional(children, upper_breadths) do
|
||||
Enum.reject children, fn Mix.Dep[app: app, opts: opts] ->
|
||||
Enum.reject children, fn %Mix.Dep{app: app, opts: opts} ->
|
||||
opts[:optional] && not(app in upper_breadths)
|
||||
end
|
||||
end
|
||||
|
||||
defp with_matching_req(Mix.Dep[] = other, Mix.Dep[] = dep) do
|
||||
defp with_matching_req(%Mix.Dep{} = other, %Mix.Dep{} = dep) do
|
||||
case other.status do
|
||||
{ :ok, vsn } when not nil?(vsn) ->
|
||||
if Mix.Deps.Loader.vsn_match?(dep.requirement, vsn, dep.app) do
|
||||
other
|
||||
else
|
||||
other.status({ :divergedreq, dep })
|
||||
%{other | status: { :divergedreq, dep }}
|
||||
end
|
||||
_ ->
|
||||
other
|
||||
|
||||
@@ -33,7 +33,7 @@ defmodule Mix.Deps.Fetcher do
|
||||
end
|
||||
|
||||
defp do_fetch(dep, { acc, lock }) do
|
||||
Mix.Dep[app: app, scm: scm, opts: opts] = dep = check_lock(dep, lock)
|
||||
%Mix.Dep{app: app, scm: scm, opts: opts} = dep = check_lock(dep, lock)
|
||||
|
||||
cond do
|
||||
# Dependencies that cannot be fetched are always compiled afterwards
|
||||
@@ -63,11 +63,11 @@ defmodule Mix.Deps.Fetcher do
|
||||
end
|
||||
end
|
||||
|
||||
defp out_of_date?(Mix.Dep[status: { :lockmismatch, _ }]), do: true
|
||||
defp out_of_date?(Mix.Dep[status: :lockoutdated]), do: true
|
||||
defp out_of_date?(Mix.Dep[status: :nolock]), do: true
|
||||
defp out_of_date?(Mix.Dep[status: { :unavailable, _ }]), do: true
|
||||
defp out_of_date?(Mix.Dep[]), do: false
|
||||
defp out_of_date?(%Mix.Dep{status: { :lockmismatch, _ }}), do: true
|
||||
defp out_of_date?(%Mix.Dep{status: :lockoutdated}), do: true
|
||||
defp out_of_date?(%Mix.Dep{status: :nolock}), do: true
|
||||
defp out_of_date?(%Mix.Dep{status: { :unavailable, _ }}), do: true
|
||||
defp out_of_date?(%Mix.Dep{}), do: false
|
||||
|
||||
defp do_finalize({ all_deps, { apps, new_lock } }, old_lock, opts) do
|
||||
# Let's get the loaded versions of deps
|
||||
@@ -101,7 +101,7 @@ defmodule Mix.Deps.Fetcher do
|
||||
defp require_compilation(deps) do
|
||||
envs = Path.wildcard("_build/*/lib")
|
||||
|
||||
for Mix.Dep[app: app] <- deps, env <- envs do
|
||||
for %Mix.Dep{app: app} <- deps, env <- envs do
|
||||
File.touch Path.join [env, app, ".compile"]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,7 +6,7 @@ defmodule Mix.Deps.Loader do
|
||||
|
||||
@doc """
|
||||
Gets all direct children of the current `Mix.Project`
|
||||
as a `Mix.Dep` record. Umbrella project dependencies
|
||||
as a `Mix.Dep` struct. Umbrella project dependencies
|
||||
are included as children.
|
||||
|
||||
By default, it will filter all dependencies that does not match
|
||||
@@ -24,7 +24,7 @@ defmodule Mix.Deps.Loader do
|
||||
# Filter deps not matching mix environment
|
||||
if env = opts[:env] do
|
||||
deps =
|
||||
Enum.filter(deps, fn Mix.Dep[opts: opts] ->
|
||||
Enum.filter(deps, fn %Mix.Dep{opts: opts} ->
|
||||
only = opts[:only]
|
||||
if only, do: env in List.wrap(only), else: true
|
||||
end)
|
||||
@@ -38,8 +38,8 @@ defmodule Mix.Deps.Loader do
|
||||
latest status and children.
|
||||
"""
|
||||
def load(dep) do
|
||||
Mix.Dep[manager: manager, scm: scm, opts: opts] = dep
|
||||
dep = dep.status(scm_status(scm, opts))
|
||||
%Mix.Dep{manager: manager, scm: scm, opts: opts} = dep
|
||||
dep = %{dep | status: scm_status(scm, opts)}
|
||||
dest = opts[:dest]
|
||||
|
||||
{ dep, children } =
|
||||
@@ -51,19 +51,19 @@ defmodule Mix.Deps.Loader do
|
||||
rebar_dep(dep)
|
||||
|
||||
mix?(dest) ->
|
||||
mix_dep(dep.manager(:mix))
|
||||
mix_dep(%{dep | manager: :mix})
|
||||
|
||||
rebar?(dest) ->
|
||||
rebar_dep(dep.manager(:rebar))
|
||||
rebar_dep(%{dep | manager: :rebar})
|
||||
|
||||
make?(dest) ->
|
||||
{ dep.manager(:make), [] }
|
||||
{ %{dep | manager: :make}, [] }
|
||||
|
||||
true ->
|
||||
{ dep, [] }
|
||||
end
|
||||
|
||||
validate_path(validate_app(dep)).deps(children)
|
||||
%{validate_path(validate_app(dep)) | deps: children}
|
||||
end
|
||||
|
||||
@doc """
|
||||
@@ -96,7 +96,7 @@ defmodule Mix.Deps.Loader do
|
||||
## Helpers
|
||||
|
||||
def to_dep(tuple, scms, from, manager \\ nil) do
|
||||
with_scm_and_app(tuple, scms).from(from).manager(manager)
|
||||
%{with_scm_and_app(tuple, scms) | from: from, manager: manager}
|
||||
end
|
||||
|
||||
defp with_scm_and_app({ app, opts }, scms) when is_atom(app) and is_list(opts) do
|
||||
@@ -119,13 +119,12 @@ defmodule Mix.Deps.Loader do
|
||||
end
|
||||
|
||||
if scm do
|
||||
Mix.Dep[
|
||||
%Mix.Dep{
|
||||
scm: scm,
|
||||
app: app,
|
||||
requirement: req,
|
||||
status: scm_status(scm, opts),
|
||||
opts: opts
|
||||
]
|
||||
opts: opts }
|
||||
else
|
||||
raise Mix.Error, message: "#{inspect Mix.Project.get} did not specify a supported scm " <>
|
||||
"for app #{inspect app}, expected one of :git, :path or :in_umbrella"
|
||||
@@ -176,7 +175,7 @@ defmodule Mix.Deps.Loader do
|
||||
|
||||
## Fetching
|
||||
|
||||
defp mix_dep(Mix.Dep[opts: opts] = dep) do
|
||||
defp mix_dep(%Mix.Dep{opts: opts} = dep) do
|
||||
Mix.Deps.in_dependency(dep, fn _ ->
|
||||
config = Mix.project
|
||||
umbrella? = Mix.Project.umbrella?
|
||||
@@ -191,15 +190,17 @@ defmodule Mix.Deps.Loader do
|
||||
end
|
||||
|
||||
children = children(env: opts[:env] || :prod)
|
||||
{ dep.manager(:mix).opts(opts).extra(umbrella: umbrella?), children }
|
||||
dep = %{dep | manager: :mix, opts: opts, extra: [umbrella: umbrella?]}
|
||||
{ dep, children }
|
||||
end)
|
||||
end
|
||||
|
||||
defp rebar_dep(Mix.Dep[] = dep) do
|
||||
defp rebar_dep(%Mix.Dep{} = dep) do
|
||||
Mix.Deps.in_dependency(dep, fn _ ->
|
||||
rebar = Mix.Rebar.load_config(".")
|
||||
extra = Dict.take(rebar, [:sub_dirs])
|
||||
{ dep.manager(:rebar).extra(extra), rebar_children(rebar) }
|
||||
dep = %{dep | manager: :rebar, extra: extra}
|
||||
{ dep, rebar_children(rebar) }
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -211,7 +212,7 @@ defmodule Mix.Deps.Loader do
|
||||
end) |> Enum.concat
|
||||
end
|
||||
|
||||
defp validate_path(Mix.Dep[scm: scm, manager: manager] = dep) do
|
||||
defp validate_path(%Mix.Dep{scm: scm, manager: manager} = dep) do
|
||||
if scm == Mix.SCM.Path and not manager in [:mix, nil] do
|
||||
raise Mix.Error, message: ":path option can only be used with mix projects, " <>
|
||||
"invalid path dependency for #{inspect dep.app}"
|
||||
@@ -220,7 +221,7 @@ defmodule Mix.Deps.Loader do
|
||||
end
|
||||
end
|
||||
|
||||
defp validate_app(Mix.Dep[opts: opts, requirement: req, app: app, status: status] = dep) do
|
||||
defp validate_app(%Mix.Dep{opts: opts, requirement: req, app: app, status: status} = dep) do
|
||||
opts_app = opts[:app]
|
||||
build = opts[:build]
|
||||
|
||||
@@ -228,13 +229,13 @@ defmodule Mix.Deps.Loader do
|
||||
not ok?(status) ->
|
||||
dep
|
||||
File.exists?(Path.join(opts[:build], ".compile")) ->
|
||||
dep.status(:compile)
|
||||
%{dep | status: :compile}
|
||||
opts_app == false ->
|
||||
dep
|
||||
true ->
|
||||
path = if is_binary(opts_app), do: opts_app, else: "ebin/#{app}.app"
|
||||
path = Path.expand(path, build)
|
||||
dep.status app_status(path, app, req)
|
||||
%{dep | status: app_status(path, app, req)}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -30,10 +30,10 @@ defmodule Mix.Deps.Umbrella do
|
||||
|
||||
Enum.map(deps, fn umbrella_dep ->
|
||||
umbrella_dep = Mix.Deps.Loader.load(umbrella_dep)
|
||||
deps = Enum.filter(umbrella_dep.deps, fn Mix.Dep[] = dep ->
|
||||
deps = Enum.filter(umbrella_dep.deps, fn dep ->
|
||||
Mix.Deps.available?(dep) and dep.app in apps
|
||||
end)
|
||||
umbrella_dep.deps(deps)
|
||||
%{umbrella_dep | deps: deps}
|
||||
end) |> Mix.Deps.Converger.topsort
|
||||
end
|
||||
|
||||
@@ -53,8 +53,13 @@ defmodule Mix.Deps.Umbrella do
|
||||
Enum.map paths, fn({ app, path }) ->
|
||||
opts = [path: path, dest: Path.expand(path),
|
||||
env: Mix.env, build: Path.join([build, "lib", app])]
|
||||
Mix.Dep[scm: Mix.SCM.Path, app: app, requirement: nil, manager: :mix,
|
||||
status: { :ok, nil }, opts: opts]
|
||||
%Mix.Dep{
|
||||
scm: Mix.SCM.Path,
|
||||
app: app,
|
||||
requirement: nil,
|
||||
manager: :mix,
|
||||
status: { :ok, nil },
|
||||
opts: opts }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -212,7 +212,7 @@ defmodule Mix.Task do
|
||||
|
||||
if umbrella? && recursive && Mix.ProjectStack.enable_recursion do
|
||||
config = [build_path: Mix.Project.build_path]
|
||||
res = for Mix.Dep[app: app, opts: opts] <- Mix.Deps.Umbrella.loaded do
|
||||
res = for %Mix.Dep{app: app, opts: opts} <- Mix.Deps.Umbrella.loaded do
|
||||
Mix.Project.in_project(app, opts[:path], config, fun)
|
||||
end
|
||||
Mix.ProjectStack.disable_recursion
|
||||
|
||||
@@ -284,7 +284,7 @@ defmodule Mix.Tasks.Compile.Elixir do
|
||||
defp path_deps_changed?(manifest) do
|
||||
manifest = Path.absname(manifest)
|
||||
|
||||
deps = Enum.filter(Mix.Deps.children([]), fn(Mix.Dep[] = dep) ->
|
||||
deps = Enum.filter(Mix.Deps.children([]), fn dep ->
|
||||
dep.scm == Mix.SCM.Path
|
||||
end)
|
||||
|
||||
|
||||
@@ -51,10 +51,10 @@ defmodule Mix.Tasks.Deps.Check do
|
||||
{ Enum.reverse(not_ok), Enum.reverse(compile) }
|
||||
end
|
||||
|
||||
defp compile?(Mix.Dep[status: { :elixirlock, _ }]), do: true
|
||||
defp compile?(Mix.Dep[status: { :noappfile, _ }]), do: true
|
||||
defp compile?(Mix.Dep[status: :compile]), do: true
|
||||
defp compile?(_), do: false
|
||||
defp compile?(%Mix.Dep{status: { :elixirlock, _ }}), do: true
|
||||
defp compile?(%Mix.Dep{status: { :noappfile, _ }}), do: true
|
||||
defp compile?(%Mix.Dep{status: :compile}), do: true
|
||||
defp compile?(%Mix.Dep{}), do: false
|
||||
|
||||
# If the build is per environment, we should be able to look
|
||||
# at all dependencies and remove the builds that no longer
|
||||
|
||||
@@ -47,8 +47,7 @@ defmodule Mix.Tasks.Deps.Compile do
|
||||
config = Mix.Project.deps_config
|
||||
|
||||
compiled =
|
||||
Enum.map deps, fn(dep) ->
|
||||
Mix.Dep[app: app, status: status, opts: opts] = dep
|
||||
Enum.map(deps, fn %Mix.Dep{app: app, status: status, opts: opts} = dep ->
|
||||
check_unavailable!(app, status)
|
||||
|
||||
unless run_opts[:quiet] || opts[:compile] == false do
|
||||
@@ -72,14 +71,14 @@ defmodule Mix.Tasks.Deps.Compile do
|
||||
unless mix?(dep), do: build_structure(dep, config)
|
||||
File.rm(Path.join(opts[:build], ".compile"))
|
||||
compiled
|
||||
end
|
||||
end)
|
||||
|
||||
if Enum.any?(compiled), do: Mix.Deps.Lock.touch
|
||||
end
|
||||
|
||||
# All available dependencies can be compiled
|
||||
# except for umbrella applications.
|
||||
defp compilable?(Mix.Dep[manager: manager, extra: extra] = dep) do
|
||||
defp compilable?(%Mix.Dep{manager: manager, extra: extra} = dep) do
|
||||
available?(dep) and (manager != :mix or !extra[:umbrella?])
|
||||
end
|
||||
|
||||
@@ -108,7 +107,7 @@ defmodule Mix.Tasks.Deps.Compile do
|
||||
end
|
||||
end
|
||||
|
||||
defp do_rebar(Mix.Dep[app: app] = dep, config) do
|
||||
defp do_rebar(%Mix.Dep{app: app} = dep, config) do
|
||||
do_command dep, rebar_cmd(app), "compile skip_deps=true deps_dir=#{inspect config[:deps_path]}"
|
||||
end
|
||||
|
||||
@@ -134,7 +133,7 @@ defmodule Mix.Tasks.Deps.Compile do
|
||||
do_command(dep, "make")
|
||||
end
|
||||
|
||||
defp do_compile(Mix.Dep[app: app, opts: opts] = dep) do
|
||||
defp do_compile(%Mix.Dep{app: app, opts: opts} = dep) do
|
||||
if command = opts[:compile] do
|
||||
Mix.shell.info("#{app}: #{command}")
|
||||
do_command(dep, command)
|
||||
@@ -143,7 +142,7 @@ defmodule Mix.Tasks.Deps.Compile do
|
||||
end
|
||||
end
|
||||
|
||||
defp do_command(Mix.Dep[app: app, opts: opts], command, extra \\ "") do
|
||||
defp do_command(%Mix.Dep{app: app, opts: opts}, command, extra \\ "") do
|
||||
File.cd! opts[:dest], fn ->
|
||||
if Mix.shell.cmd("#{command} #{extra}") != 0 do
|
||||
raise Mix.Error, message: "Could not compile dependency #{app}, #{command} command failed. " <>
|
||||
@@ -153,7 +152,7 @@ defmodule Mix.Tasks.Deps.Compile do
|
||||
true
|
||||
end
|
||||
|
||||
defp build_structure(Mix.Dep[opts: opts] = dep, config) do
|
||||
defp build_structure(%Mix.Dep{opts: opts} = dep, config) do
|
||||
build_path = Path.dirname(opts[:build])
|
||||
Enum.each Mix.Deps.source_paths(dep), fn source ->
|
||||
app = Path.join(build_path, Path.basename(source))
|
||||
|
||||
@@ -30,7 +30,7 @@ defmodule Mix.Tasks.Deps do
|
||||
shell = Mix.shell
|
||||
lock = Mix.Deps.Lock.read
|
||||
|
||||
Enum.each loaded(loaded_opts), fn(Mix.Dep[scm: scm] = dep) ->
|
||||
Enum.each loaded(loaded_opts), fn %Mix.Dep{scm: scm} = dep ->
|
||||
dep = check_lock(dep, lock)
|
||||
shell.info "* #{format_dep(dep)}"
|
||||
if formatted = scm.format_lock(dep.opts) do
|
||||
|
||||
@@ -123,9 +123,10 @@ defmodule Mix.Tasks.Escriptize do
|
||||
end
|
||||
|
||||
defp deps_tuples do
|
||||
Enum.reduce Mix.Deps.loaded(env: Mix.env) || [], [], fn(dep, acc) ->
|
||||
get_tuples(dep.opts[:build]) ++ acc
|
||||
end
|
||||
deps = Mix.Deps.loaded(env: Mix.env) || []
|
||||
Enum.reduce(deps, [], fn dep, acc ->
|
||||
get_tuples(%{dep | opts: :build}) ++ acc
|
||||
end)
|
||||
end
|
||||
|
||||
defp set_perms(filename) do
|
||||
|
||||
@@ -40,12 +40,12 @@ defmodule Mix.DepsTest do
|
||||
in_fixture "deps_status", fn ->
|
||||
deps = Mix.Deps.loaded([])
|
||||
assert length(deps) == 6
|
||||
assert Enum.find deps, &match?(Mix.Dep[app: :ok, status: { :ok, _ }], &1)
|
||||
assert Enum.find deps, &match?(Mix.Dep[app: :invalidvsn, status: { :invalidvsn, :ok }], &1)
|
||||
assert Enum.find deps, &match?(Mix.Dep[app: :invalidapp, status: { :invalidapp, _ }], &1)
|
||||
assert Enum.find deps, &match?(Mix.Dep[app: :noappfile, status: { :noappfile, _ }], &1)
|
||||
assert Enum.find deps, &match?(Mix.Dep[app: :uncloned, status: { :unavailable, _ }], &1)
|
||||
assert Enum.find deps, &match?(Mix.Dep[app: :optional, status: { :unavailable, _ }], &1)
|
||||
assert Enum.find deps, &match?(%Mix.Dep{app: :ok, status: { :ok, _ }}, &1)
|
||||
assert Enum.find deps, &match?(%Mix.Dep{app: :invalidvsn, status: { :invalidvsn, :ok }}, &1)
|
||||
assert Enum.find deps, &match?(%Mix.Dep{app: :invalidapp, status: { :invalidapp, _ }}, &1)
|
||||
assert Enum.find deps, &match?(%Mix.Dep{app: :noappfile, status: { :noappfile, _ }}, &1)
|
||||
assert Enum.find deps, &match?(%Mix.Dep{app: :uncloned, status: { :unavailable, _ }}, &1)
|
||||
assert Enum.find deps, &match?(%Mix.Dep{app: :optional, status: { :unavailable, _ }}, &1)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -54,7 +54,7 @@ defmodule Mix.DepsTest do
|
||||
|
||||
in_fixture "deps_status", fn ->
|
||||
deps = Mix.Deps.loaded([])
|
||||
assert Enum.find deps, &match?(Mix.Dep[app: :ok, status: { :ok, _ }], &1)
|
||||
assert Enum.find deps, &match?(%Mix.Dep{app: :ok, status: { :ok, _ }}, &1)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -226,7 +226,7 @@ defmodule Mix.DepsTest do
|
||||
|
||||
{ deps, _acc } = Mix.Deps.unloaded([], [env: :prod], &{ &1, &2 })
|
||||
assert length(deps) == 1
|
||||
assert Enum.find deps, &match?(Mix.Dep[app: :foo], &1)
|
||||
assert Enum.find deps, &match?(%Mix.Dep{app: :foo}, &1)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -73,10 +73,9 @@ defmodule Mix.RebarTest do
|
||||
Mix.Project.push(RebarAsDep)
|
||||
|
||||
deps = Mix.Deps.loaded([])
|
||||
assert Enum.find(deps, &match?(Mix.Dep[app: :rebar_dep], &1))
|
||||
assert Enum.find(deps, &match?(%Mix.Dep{app: :rebar_dep}, &1))
|
||||
|
||||
assert Enum.find(deps, fn dep ->
|
||||
Mix.Dep[app: app, opts: opts] = dep
|
||||
assert Enum.find(deps, fn %Mix.Dep{app: app, opts: opts} ->
|
||||
if app == :git_rebar do
|
||||
assert Enum.find(opts, &match?({:git, "../../test/fixtures/git_rebar"}, &1))
|
||||
assert Enum.find(opts, &match?({:ref, "master"}, &1))
|
||||
|
||||
Reference in New Issue
Block a user