diff --git a/lib/hex/mix.ex b/lib/hex/mix.ex index 6c252275..9f88b66d 100644 --- a/lib/hex/mix.ex +++ b/lib/hex/mix.ex @@ -26,32 +26,22 @@ defmodule Hex.Mix do in the original list of dependencies as they were likely filtered out due to options like `:only`. """ - def deps_to_requests(deps, overridden) do - apps = Enum.map(deps, & &1.app) - - hex_deps_to_requests(deps, apps, overridden, _top_level? = true) ++ - Enum.flat_map(deps, fn dep -> - if dep.scm != Hex.SCM and dep.deps != [] do - [ - %{ - repo: nil, - name: Atom.to_string(dep.app), - requirement: nil, - app: Atom.to_string(dep.app), - from: Path.relative_to_cwd(dep.from), - dependencies: hex_deps_to_requests(dep.deps, apps, overridden, _top_level? = false) - } - ] - else - [] - end - end) + def deps_to_requests(all_deps, overridden) do + all_apps = Enum.map(all_deps, & &1.app) + + hex_deps_to_requests(all_deps, all_apps, overridden) ++ + non_hex_deps_to_requests(all_deps, all_deps, all_apps, overridden) end - defp hex_deps_to_requests(deps, apps, overridden, top_level?) do + defp deps_to_requests(deps, all_deps, all_apps, overridden) do + hex_deps_to_requests(deps, all_apps, overridden) ++ + non_hex_deps_to_requests(deps, all_deps, all_apps, overridden) + end + + defp hex_deps_to_requests(deps, all_apps, overridden) do Enum.flat_map(deps, fn dep -> - if dep.scm == Hex.SCM and dep.app in apps and (dep.top_level or dep.app not in overridden) and - dep.top_level == top_level? do + if dep.scm == Hex.SCM and dep.app in all_apps and + (dep.top_level or dep.app not in overridden) do [ %{ repo: dep.opts[:repo], @@ -68,6 +58,42 @@ defmodule Hex.Mix do end) end + defp non_hex_deps_to_requests(deps, all_deps, all_apps, overridden) do + Enum.flat_map(deps, fn dep -> + if has_non_hex_deps?(dep, all_apps) do + collect_non_hex_deps(dep, all_deps, all_apps, overridden) + else + [] + end + end) + end + + defp has_non_hex_deps?(dep, all_apps) do + dep.scm != Hex.SCM and dep.deps != [] and dep.app in all_apps + end + + defp collect_non_hex_deps(dep, all_deps, all_apps, overridden) do + sub_apps = Enum.map(dep.deps, & &1.app) + sub_deps = Enum.filter(dep.deps, &(&1.app in sub_apps)) + + dependencies = deps_to_requests(sub_deps, all_deps, all_apps, overridden) + + if dependencies != [] do + [ + %{ + repo: nil, + name: Atom.to_string(dep.app), + requirement: nil, + app: Atom.to_string(dep.app), + from: Path.relative_to_cwd(dep.from), + dependencies: dependencies + } + ] + else + [] + end + end + @doc """ Returns all top level dependencies. """ diff --git a/lib/hex/remote_converger.ex b/lib/hex/remote_converger.ex index 7b61ad32..3a300990 100644 --- a/lib/hex/remote_converger.ex +++ b/lib/hex/remote_converger.ex @@ -343,6 +343,8 @@ defmodule Hex.RemoteConverger do * #{dependency.from} defined application :#{dependency.label} """) end + + dependency end) verify_otp_app_names(dependencies, map) diff --git a/mix.exs b/mix.exs index cec8790e..bbe9957b 100644 --- a/mix.exs +++ b/mix.exs @@ -11,6 +11,7 @@ defmodule Hex.MixProject do aliases: aliases(), preferred_cli_env: ["deps.get": :test], config_path: config_path(), + compilers: [:leex] ++ Mix.compilers(), deps: deps(Mix.env()), elixirc_options: elixirc_options(Mix.env()), elixirc_paths: elixirc_paths(Mix.env()) diff --git a/test/fixtures/umbrella/apps/my_app1/mix.exs b/test/fixtures/umbrella/apps/my_app1/mix.exs new file mode 100644 index 00000000..2dddc9db --- /dev/null +++ b/test/fixtures/umbrella/apps/my_app1/mix.exs @@ -0,0 +1,19 @@ +defmodule Umbrella.MyApp1.Fixture.MixProject do + use Mix.Project + + def project do + [ + app: :my_app1, + version: "0.1.0", + build_path: "../../_build", + config_path: "../../config/config.exs", + deps_path: "../../deps", + lockfile: "../../mix.lock", + deps: deps() + ] + end + + defp deps do + [{:postgrex, ">= 0.0.0"}] + end +end diff --git a/test/fixtures/umbrella/apps/my_app2/mix.exs b/test/fixtures/umbrella/apps/my_app2/mix.exs new file mode 100644 index 00000000..66c0c4a9 --- /dev/null +++ b/test/fixtures/umbrella/apps/my_app2/mix.exs @@ -0,0 +1,19 @@ +defmodule Umbrella.MyApp2.Fixture.MixProject do + use Mix.Project + + def project do + [ + app: :my_app2, + version: "0.1.0", + build_path: "../../_build", + config_path: "../../config/config.exs", + deps_path: "../../deps", + lockfile: "../../mix.lock", + deps: deps() + ] + end + + defp deps do + [{:my_app1, in_umbrella: true}] + end +end diff --git a/test/fixtures/umbrella/apps/my_app3/mix.exs b/test/fixtures/umbrella/apps/my_app3/mix.exs new file mode 100644 index 00000000..736fc69d --- /dev/null +++ b/test/fixtures/umbrella/apps/my_app3/mix.exs @@ -0,0 +1,19 @@ +defmodule Umbrella.MyApp3.Fixture.MixProject do + use Mix.Project + + def project do + [ + app: :my_app3, + version: "0.1.0", + build_path: "../../_build", + config_path: "../../config/config.exs", + deps_path: "../../deps", + lockfile: "../../mix.lock", + deps: deps() + ] + end + + defp deps do + [] + end +end diff --git a/test/fixtures/umbrella/mix.exs b/test/fixtures/umbrella/mix.exs new file mode 100644 index 00000000..75f25e46 --- /dev/null +++ b/test/fixtures/umbrella/mix.exs @@ -0,0 +1,20 @@ +defmodule Umbrella.Fixture.MixProject do + use Mix.Project + + def project do + [ + apps_path: "apps", + version: "0.1.0", + deps: deps() + ] + end + + # Dependencies listed here are available only for this + # project and cannot be accessed from applications inside + # the apps folder. + # + # Run "mix help deps" for examples and options. + defp deps do + [] + end +end diff --git a/test/hex/mix_task_test.exs b/test/hex/mix_task_test.exs index 2b7be5bb..5eb58358 100644 --- a/test/hex/mix_task_test.exs +++ b/test/hex/mix_task_test.exs @@ -1031,4 +1031,26 @@ defmodule Hex.MixTaskTest do ]} end) end + + test "deps.get umbrella" do + in_fixture("umbrella", fn -> + Code.eval_file("mix.exs") + Mix.Task.run("deps.get") + + assert_received {:mix_shell, :info, ["* Getting postgrex (Hex package)"]} + assert_received {:mix_shell, :info, ["* Getting ex_doc (Hex package)"]} + + assert %{ + ex_doc: {:hex, :ex_doc, "0.1.0", _, _, _, _, _}, + postgrex: {:hex, :postgrex, "0.2.1", _, _, _, _, _} + } = Mix.Dep.Lock.read() + end) + after + purge([ + Umbrella.Fixture.MixProject, + Umbrella.MyApp1.Fixture.MixProject, + Umbrella.MyApp2.Fixture.MixProject, + Umbrella.MyApp3.Fixture.MixProject + ]) + end end