diff --git a/lib/mix/lib/mix/deps.ex b/lib/mix/lib/mix/deps.ex index da4941cce0..23eed507f5 100644 --- a/lib/mix/lib/mix/deps.ex +++ b/lib/mix/lib/mix/deps.ex @@ -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 diff --git a/lib/mix/lib/mix/deps/converger.ex b/lib/mix/lib/mix/deps/converger.ex index 57928e0003..727be26606 100644 --- a/lib/mix/lib/mix/deps/converger.ex +++ b/lib/mix/lib/mix/deps/converger.ex @@ -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 diff --git a/lib/mix/lib/mix/deps/fetcher.ex b/lib/mix/lib/mix/deps/fetcher.ex index 70b8c920f4..9f4b9d0c2d 100644 --- a/lib/mix/lib/mix/deps/fetcher.ex +++ b/lib/mix/lib/mix/deps/fetcher.ex @@ -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 diff --git a/lib/mix/lib/mix/deps/loader.ex b/lib/mix/lib/mix/deps/loader.ex index 688b580da3..08a7c83d12 100644 --- a/lib/mix/lib/mix/deps/loader.ex +++ b/lib/mix/lib/mix/deps/loader.ex @@ -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 diff --git a/lib/mix/lib/mix/deps/umbrella.ex b/lib/mix/lib/mix/deps/umbrella.ex index 6533658997..22403f53c9 100644 --- a/lib/mix/lib/mix/deps/umbrella.ex +++ b/lib/mix/lib/mix/deps/umbrella.ex @@ -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 diff --git a/lib/mix/lib/mix/task.ex b/lib/mix/lib/mix/task.ex index 6608717766..1ddaac2181 100644 --- a/lib/mix/lib/mix/task.ex +++ b/lib/mix/lib/mix/task.ex @@ -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 diff --git a/lib/mix/lib/mix/tasks/compile.elixir.ex b/lib/mix/lib/mix/tasks/compile.elixir.ex index 5d94b728b9..5f1666d6f1 100644 --- a/lib/mix/lib/mix/tasks/compile.elixir.ex +++ b/lib/mix/lib/mix/tasks/compile.elixir.ex @@ -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) diff --git a/lib/mix/lib/mix/tasks/deps.check.ex b/lib/mix/lib/mix/tasks/deps.check.ex index 2cb85e4d54..e46163693d 100644 --- a/lib/mix/lib/mix/tasks/deps.check.ex +++ b/lib/mix/lib/mix/tasks/deps.check.ex @@ -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 diff --git a/lib/mix/lib/mix/tasks/deps.compile.ex b/lib/mix/lib/mix/tasks/deps.compile.ex index 7d6d231322..a851c1bdf6 100644 --- a/lib/mix/lib/mix/tasks/deps.compile.ex +++ b/lib/mix/lib/mix/tasks/deps.compile.ex @@ -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)) diff --git a/lib/mix/lib/mix/tasks/deps.ex b/lib/mix/lib/mix/tasks/deps.ex index 9d448da65a..2abb6b9bf8 100644 --- a/lib/mix/lib/mix/tasks/deps.ex +++ b/lib/mix/lib/mix/tasks/deps.ex @@ -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 diff --git a/lib/mix/lib/mix/tasks/escriptize.ex b/lib/mix/lib/mix/tasks/escriptize.ex index 5709f84a31..221e49cb27 100644 --- a/lib/mix/lib/mix/tasks/escriptize.ex +++ b/lib/mix/lib/mix/tasks/escriptize.ex @@ -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 diff --git a/lib/mix/test/mix/deps_test.exs b/lib/mix/test/mix/deps_test.exs index 4327e9818b..05f1d4e55d 100644 --- a/lib/mix/test/mix/deps_test.exs +++ b/lib/mix/test/mix/deps_test.exs @@ -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 diff --git a/lib/mix/test/mix/rebar_test.exs b/lib/mix/test/mix/rebar_test.exs index 4a63d793cb..54e37cdad1 100644 --- a/lib/mix/test/mix/rebar_test.exs +++ b/lib/mix/test/mix/rebar_test.exs @@ -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))