diff --git a/examples/simple_umbrella_app/.formatter.exs b/examples/simple_umbrella_app/.formatter.exs new file mode 100644 index 00000000..90a08535 --- /dev/null +++ b/examples/simple_umbrella_app/.formatter.exs @@ -0,0 +1,5 @@ +# Used by "mix format" +[ + inputs: ["mix.exs", "config/*.exs"], + subdirectories: ["apps/*"] +] diff --git a/examples/simple_umbrella_app/.gitignore b/examples/simple_umbrella_app/.gitignore new file mode 100644 index 00000000..2de045d5 --- /dev/null +++ b/examples/simple_umbrella_app/.gitignore @@ -0,0 +1,23 @@ +# The directory Mix will write compiled artifacts to. +/_build/ + +# If you run "mix test --cover", coverage assets end up here. +/cover/ + +# The directory Mix downloads your dependencies sources to. +/deps/ + +# Where third-party dependencies like ExDoc output generated docs. +/doc/ + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch + +# If the VM crashes, it generates a dump, let's ignore it too. +erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). +*.ez + +# Temporary files, for example, from tests. +/tmp/ diff --git a/examples/simple_umbrella_app/README.md b/examples/simple_umbrella_app/README.md new file mode 100644 index 00000000..7810d0a4 --- /dev/null +++ b/examples/simple_umbrella_app/README.md @@ -0,0 +1,4 @@ +# SimpleUmbrellaApp + +**TODO: Add description** + diff --git a/examples/simple_umbrella_app/apps/app_a/.formatter.exs b/examples/simple_umbrella_app/apps/app_a/.formatter.exs new file mode 100644 index 00000000..d2cda26e --- /dev/null +++ b/examples/simple_umbrella_app/apps/app_a/.formatter.exs @@ -0,0 +1,4 @@ +# Used by "mix format" +[ + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/examples/simple_umbrella_app/apps/app_a/.gitignore b/examples/simple_umbrella_app/apps/app_a/.gitignore new file mode 100644 index 00000000..a9ab083e --- /dev/null +++ b/examples/simple_umbrella_app/apps/app_a/.gitignore @@ -0,0 +1,26 @@ +# The directory Mix will write compiled artifacts to. +/_build/ + +# If you run "mix test --cover", coverage assets end up here. +/cover/ + +# The directory Mix downloads your dependencies sources to. +/deps/ + +# Where third-party dependencies like ExDoc output generated docs. +/doc/ + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch + +# If the VM crashes, it generates a dump, let's ignore it too. +erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). +*.ez + +# Ignore package tarball (built via "mix hex.build"). +app_a-*.tar + +# Temporary files, for example, from tests. +/tmp/ diff --git a/examples/simple_umbrella_app/apps/app_a/README.md b/examples/simple_umbrella_app/apps/app_a/README.md new file mode 100644 index 00000000..a6d985b8 --- /dev/null +++ b/examples/simple_umbrella_app/apps/app_a/README.md @@ -0,0 +1,21 @@ +# AppA + +**TODO: Add description** + +## Installation + +If [available in Hex](https://hex.pm/docs/publish), the package can be installed +by adding `app_a` to your list of dependencies in `mix.exs`: + +```elixir +def deps do + [ + {:app_a, "~> 0.1.0"} + ] +end +``` + +Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) +and published on [HexDocs](https://hexdocs.pm). Once published, the docs can +be found at [https://hexdocs.pm/app_a](https://hexdocs.pm/app_a). + diff --git a/examples/simple_umbrella_app/apps/app_a/lib/app_a.ex b/examples/simple_umbrella_app/apps/app_a/lib/app_a.ex new file mode 100644 index 00000000..1a276188 --- /dev/null +++ b/examples/simple_umbrella_app/apps/app_a/lib/app_a.ex @@ -0,0 +1,18 @@ +defmodule AppA do + @moduledoc """ + Documentation for `AppA`. + """ + + @doc """ + Hello world. + + ## Examples + + iex> AppA.hello() + :world + + """ + def hello do + :world + end +end diff --git a/examples/simple_umbrella_app/apps/app_a/mix.exs b/examples/simple_umbrella_app/apps/app_a/mix.exs new file mode 100644 index 00000000..423509f6 --- /dev/null +++ b/examples/simple_umbrella_app/apps/app_a/mix.exs @@ -0,0 +1,33 @@ +defmodule AppA.MixProject do + use Mix.Project + + def project do + [ + app: :app_a, + version: "0.1.0", + build_path: "../../_build", + config_path: "../../config/config.exs", + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.12", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications. + def application do + [ + extra_applications: [:logger] + ] + end + + # Run "mix help deps" to learn about dependencies. + defp deps do + [ + # {:dep_from_hexpm, "~> 0.3.0"}, + # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}, + # {:sibling_app_in_umbrella, in_umbrella: true} + ] + end +end diff --git a/examples/simple_umbrella_app/apps/app_a/test/app_a_test.exs b/examples/simple_umbrella_app/apps/app_a/test/app_a_test.exs new file mode 100644 index 00000000..215429f9 --- /dev/null +++ b/examples/simple_umbrella_app/apps/app_a/test/app_a_test.exs @@ -0,0 +1,8 @@ +defmodule AppATest do + use ExUnit.Case + doctest AppA + + test "greets the world" do + assert AppA.hello() == :world + end +end diff --git a/examples/simple_umbrella_app/apps/app_a/test/test_helper.exs b/examples/simple_umbrella_app/apps/app_a/test/test_helper.exs new file mode 100644 index 00000000..869559e7 --- /dev/null +++ b/examples/simple_umbrella_app/apps/app_a/test/test_helper.exs @@ -0,0 +1 @@ +ExUnit.start() diff --git a/examples/simple_umbrella_app/apps/app_b/.formatter.exs b/examples/simple_umbrella_app/apps/app_b/.formatter.exs new file mode 100644 index 00000000..d2cda26e --- /dev/null +++ b/examples/simple_umbrella_app/apps/app_b/.formatter.exs @@ -0,0 +1,4 @@ +# Used by "mix format" +[ + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/examples/simple_umbrella_app/apps/app_b/.gitignore b/examples/simple_umbrella_app/apps/app_b/.gitignore new file mode 100644 index 00000000..91dfc02c --- /dev/null +++ b/examples/simple_umbrella_app/apps/app_b/.gitignore @@ -0,0 +1,26 @@ +# The directory Mix will write compiled artifacts to. +/_build/ + +# If you run "mix test --cover", coverage assets end up here. +/cover/ + +# The directory Mix downloads your dependencies sources to. +/deps/ + +# Where third-party dependencies like ExDoc output generated docs. +/doc/ + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch + +# If the VM crashes, it generates a dump, let's ignore it too. +erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). +*.ez + +# Ignore package tarball (built via "mix hex.build"). +app_b-*.tar + +# Temporary files, for example, from tests. +/tmp/ diff --git a/examples/simple_umbrella_app/apps/app_b/README.md b/examples/simple_umbrella_app/apps/app_b/README.md new file mode 100644 index 00000000..09a27da8 --- /dev/null +++ b/examples/simple_umbrella_app/apps/app_b/README.md @@ -0,0 +1,21 @@ +# AppB + +**TODO: Add description** + +## Installation + +If [available in Hex](https://hex.pm/docs/publish), the package can be installed +by adding `app_b` to your list of dependencies in `mix.exs`: + +```elixir +def deps do + [ + {:app_b, "~> 0.1.0"} + ] +end +``` + +Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) +and published on [HexDocs](https://hexdocs.pm). Once published, the docs can +be found at [https://hexdocs.pm/app_b](https://hexdocs.pm/app_b). + diff --git a/examples/simple_umbrella_app/apps/app_b/lib/app_b.ex b/examples/simple_umbrella_app/apps/app_b/lib/app_b.ex new file mode 100644 index 00000000..72e350d3 --- /dev/null +++ b/examples/simple_umbrella_app/apps/app_b/lib/app_b.ex @@ -0,0 +1,18 @@ +defmodule AppB do + @moduledoc """ + Documentation for `AppB`. + """ + + @doc """ + Hello world. + + ## Examples + + iex> AppB.hello() + :world + + """ + def hello do + AppA.hello() + end +end diff --git a/examples/simple_umbrella_app/apps/app_b/mix.exs b/examples/simple_umbrella_app/apps/app_b/mix.exs new file mode 100644 index 00000000..ae05dcc1 --- /dev/null +++ b/examples/simple_umbrella_app/apps/app_b/mix.exs @@ -0,0 +1,33 @@ +defmodule AppB.MixProject do + use Mix.Project + + def project do + [ + app: :app_b, + version: "0.1.0", + build_path: "../../_build", + config_path: "../../config/config.exs", + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.12", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications. + def application do + [ + extra_applications: [:logger] + ] + end + + # Run "mix help deps" to learn about dependencies. + defp deps do + [{:app_a, in_umbrella: true} + # {:dep_from_hexpm, "~> 0.3.0"}, + # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}, + # {:sibling_app_in_umbrella, in_umbrella: true} + ] + end +end diff --git a/examples/simple_umbrella_app/apps/app_b/test/app_b_test.exs b/examples/simple_umbrella_app/apps/app_b/test/app_b_test.exs new file mode 100644 index 00000000..9760862c --- /dev/null +++ b/examples/simple_umbrella_app/apps/app_b/test/app_b_test.exs @@ -0,0 +1,8 @@ +defmodule AppBTest do + use ExUnit.Case + doctest AppB + + test "greets the world" do + assert AppB.hello() == :world + end +end diff --git a/examples/simple_umbrella_app/apps/app_b/test/test_helper.exs b/examples/simple_umbrella_app/apps/app_b/test/test_helper.exs new file mode 100644 index 00000000..869559e7 --- /dev/null +++ b/examples/simple_umbrella_app/apps/app_b/test/test_helper.exs @@ -0,0 +1 @@ +ExUnit.start() diff --git a/examples/simple_umbrella_app/config/config.exs b/examples/simple_umbrella_app/config/config.exs new file mode 100644 index 00000000..ab23e800 --- /dev/null +++ b/examples/simple_umbrella_app/config/config.exs @@ -0,0 +1,18 @@ +# This file is responsible for configuring your umbrella +# and **all applications** and their dependencies with the +# help of the Config module. +# +# Note that all applications in your umbrella share the +# same configuration and dependencies, which is why they +# all use the same configuration file. If you want different +# configurations or dependencies per app, it is best to +# move said applications out of the umbrella. +import Config + +# Sample configuration: +# +# config :logger, :console, +# level: :info, +# format: "$date $time [$level] $metadata$message\n", +# metadata: [:user_id] +# diff --git a/examples/simple_umbrella_app/mix.exs b/examples/simple_umbrella_app/mix.exs new file mode 100644 index 00000000..e701a374 --- /dev/null +++ b/examples/simple_umbrella_app/mix.exs @@ -0,0 +1,21 @@ +defmodule SimpleUmbrellaApp.MixProject do + use Mix.Project + + def project do + [ + apps_path: "apps", + version: "0.1.0", + start_permanent: Mix.env() == :prod, + 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 + [{:gradient, path: "../../"}] + end +end diff --git a/examples/simple_umbrella_app/mix.lock b/examples/simple_umbrella_app/mix.lock new file mode 100644 index 00000000..7f878a50 --- /dev/null +++ b/examples/simple_umbrella_app/mix.lock @@ -0,0 +1,3 @@ +%{ + "gradualizer": {:git, "https://github.com/josefs/Gradualizer.git", "9e629ade733780113973fe672a51d9650ed0cd86", [ref: "9e629ad"]}, +} diff --git a/lib/mix/tasks/gradient.ex b/lib/mix/tasks/gradient.ex index 5f57423c..789c73c3 100644 --- a/lib/mix/tasks/gradient.ex +++ b/lib/mix/tasks/gradient.ex @@ -103,6 +103,7 @@ defmodule Mix.Tasks.Gradient do if options[:no_deps] || false do Application.put_env(:gradualizer, :options, autoimport: false) else + :ok = :code.add_paths(get_compile_paths()) IO.puts("Loading deps...") end end @@ -170,7 +171,7 @@ defmodule Mix.Tasks.Gradient do app_name = Atom.to_string(app_name) paths = - (Mix.Project.build_path() <> "/lib/" <> app_name <> "/ebin/**/*.beam") + (compile_path(app_name) <> "/**/*.beam") |> Path.wildcard() |> Enum.map(&String.to_charlist/1) @@ -178,4 +179,18 @@ defmodule Mix.Tasks.Gradient do end) |> Map.new() end + + @spec get_compile_paths() :: [charlist()] + defp get_compile_paths() do + if Mix.Project.umbrella?() do + Mix.Project.apps_paths() + |> Enum.map(fn {app_name, _} -> to_charlist(compile_path(app_name)) end) + else + [to_charlist(Mix.Project.compile_path())] + end + end + + defp compile_path(app_name) do + Mix.Project.build_path() <> "/lib/" <> to_string(app_name) <> "/ebin" + end end