diff --git a/lib/mix/lib/mix/tasks/app.start.ex b/lib/mix/lib/mix/tasks/app.start.ex index 727fec57940..9d802139c9d 100644 --- a/lib/mix/lib/mix/tasks/app.start.ex +++ b/lib/mix/lib/mix/tasks/app.start.ex @@ -30,6 +30,7 @@ defmodule Mix.Tasks.App.Start do * `--force` - forces compilation regardless of compilation times * `--temporary` - starts the application as temporary * `--permanent` - starts the application as permanent + * `--preload-modules` - preloads all modules defined in applications * `--no-compile` - does not compile even if files require compilation * `--no-protocols` - does not load consolidated protocols * `--no-archives-check` - does not check archives @@ -38,11 +39,18 @@ defmodule Mix.Tasks.App.Start do * `--no-start` - does not start applications after compilation """ + + @switches [ + permanent: :boolean, + temporary: :boolean, + preload_modules: :boolean + ] + def run(args) do Mix.Project.get!() config = Mix.Project.config() - {opts, _, _} = OptionParser.parse(args, switches: [permanent: :boolean, temporary: :boolean]) + {opts, _, _} = OptionParser.parse(args, switches: @switches) Mix.Task.run("loadpaths", args) unless "--no-compile" in args do @@ -76,6 +84,13 @@ defmodule Mix.Tasks.App.Start do end else start(Mix.Project.config(), opts) + + # If there is a build path, we will let the application + # that owns the build path do the actual check + unless config[:build_path] do + loaded = loaded_applications(opts) + check_configured(loaded) + end end :ok @@ -97,13 +112,6 @@ defmodule Mix.Tasks.App.Start do type = type(config, opts) Enum.each(apps, &ensure_all_started(&1, type)) - - # If there is a build path, we will let the application - # that owns the build path do the actual check - unless config[:build_path] do - check_configured() - end - :ok end @@ -146,25 +154,35 @@ defmodule Mix.Tasks.App.Start do end end - defp check_configured() do + defp loaded_applications(opts) do + preload_modules? = opts[:preload_modules] + + for {app, _, _} <- Application.loaded_applications() do + if modules = preload_modules? && Application.spec(app, :modules) do + :code.ensure_modules_loaded(modules) + end + + app + end + end + + defp check_configured(loaded) do configured = Mix.ProjectStack.configured_applications() - loaded = for {app, _, _} <- Application.loaded_applications(), do: app - _ = - for app <- configured -- loaded, :code.lib_dir(app) == {:error, :bad_name} do - Mix.shell().error(""" - You have configured application #{inspect(app)} in your configuration - file, but the application is not available. + for app <- configured -- loaded, :code.lib_dir(app) == {:error, :bad_name} do + Mix.shell().error(""" + You have configured application #{inspect(app)} in your configuration file, + but the application is not available. - This usually means one of: + This usually means one of: 1. You have not added the application as a dependency in a mix.exs file. 2. You are configuring an application that does not really exist. - Please ensure #{inspect(app)} exists or remove the configuration. - """) - end + Please ensure #{inspect(app)} exists or remove the configuration. + """) + end :ok end diff --git a/lib/mix/lib/mix/tasks/run.ex b/lib/mix/lib/mix/tasks/run.ex index a460d522e58..ca6e9298b6c 100644 --- a/lib/mix/lib/mix/tasks/run.ex +++ b/lib/mix/lib/mix/tasks/run.ex @@ -40,6 +40,7 @@ defmodule Mix.Tasks.Run do * `--eval`, `-e` - evaluate the given code * `--require`, `-r` - requires pattern before running the command * `--parallel`, `-p` - makes all requires parallel + * `--preload-modules` - preloads all modules defined in applications * `--no-compile` - does not compile even if files require compilation * `--no-deps-check` - does not check dependencies * `--no-archives-check` - does not check archives @@ -67,7 +68,8 @@ defmodule Mix.Tasks.Run do start: :boolean, archives_check: :boolean, elixir_version_check: :boolean, - parallel_require: :keep + parallel_require: :keep, + preload_modules: :boolean ] ) diff --git a/lib/mix/lib/mix/tasks/test.ex b/lib/mix/lib/mix/tasks/test.ex index 9c73e864d0e..d442f8ba42d 100644 --- a/lib/mix/lib/mix/tasks/test.ex +++ b/lib/mix/lib/mix/tasks/test.ex @@ -67,11 +67,12 @@ defmodule Mix.Tasks.Test do * `--no-elixir-version-check` - does not check the Elixir version from mix.exs * `--no-start` - does not start applications after compilation * `--only` - runs only tests that match the filter + * `--preload-modules` - preloads all modules defined in applications * `--raise` - raises if the test suite failed * `--seed` - seeds the random number generator used to randomize tests order; `--seed 0` disables randomization - * `--slowest` - prints timing information for the N slowest tests; automatically - sets `--trace` + * `--slowest` - prints timing information for the N slowest tests + Automatically sets `--trace` and `--preload-modules` * `--stale` - runs only tests which reference modules that changed since the last `test --stale`. You can read more about this option in the "Stale" section below. * `--timeout` - sets the timeout for the tests @@ -190,7 +191,8 @@ defmodule Mix.Tasks.Test do stale: :boolean, listen_on_stdin: :boolean, formatter: :keep, - slowest: :integer + slowest: :integer, + preload_modules: :boolean ] @cover [output: "cover", tool: Cover] @@ -235,7 +237,8 @@ defmodule Mix.Tasks.Test do # available in test_helper.exs. Then configure exunit again so # that command line options override test_helper.exs Mix.shell().print_app - Mix.Task.run("app.start", args) + app_start_args = if opts[:slowest], do: ["--preload-modules" | args], else: args + Mix.Task.run("app.start", app_start_args) # Ensure ExUnit is loaded. case Application.load(:ex_unit) do diff --git a/lib/mix/test/mix/tasks/app.start_test.exs b/lib/mix/test/mix/tasks/app.start_test.exs index 1cc51c16be5..403a2e53972 100644 --- a/lib/mix/test/mix/tasks/app.start_test.exs +++ b/lib/mix/test/mix/tasks/app.start_test.exs @@ -35,12 +35,18 @@ defmodule Mix.Tasks.App.StartTest do assert File.regular?("_build/dev/lib/app_start_sample/ebin/Elixir.A.beam") assert File.regular?("_build/dev/lib/app_start_sample/ebin/app_start_sample.app") + assert :code.is_loaded(A) refute List.keyfind(Application.started_applications(), :app_start_sample, 0) assert List.keyfind(Application.started_applications(), :logger, 0) + :code.delete(A) Mix.Tasks.App.Start.run([]) + refute :code.is_loaded(A) assert List.keyfind(Application.started_applications(), :app_start_sample, 0) assert List.keyfind(Application.started_applications(), :logger, 0) + + Mix.Tasks.App.Start.run(["--preload-modules"]) + assert :code.is_loaded(A) end end