diff --git a/lib/mix/lib/mix/tasks/deps.compile.ex b/lib/mix/lib/mix/tasks/deps.compile.ex index 0d2658a000a..93d99373f26 100644 --- a/lib/mix/lib/mix/tasks/deps.compile.ex +++ b/lib/mix/lib/mix/tasks/deps.compile.ex @@ -30,36 +30,36 @@ defmodule Mix.Tasks.Deps.Compile do `b` is included in the compilation step, pass `--include-children`. """ - import Mix.Dep, only: [loaded: 1, available?: 1, loaded_by_name: 2, - make?: 1, mix?: 1] + import Mix.Dep, only: [loaded: 1, available?: 1, loaded_by_name: 2, make?: 1, mix?: 1] @switches [include_children: :boolean, force: :boolean] - @spec run(OptionParser.argv) :: :ok + @spec run(OptionParser.argv()) :: :ok def run(args) do unless "--no-archives-check" in args do - Mix.Task.run "archive.check", args + Mix.Task.run("archive.check", args) end - Mix.Project.get! + Mix.Project.get!() case OptionParser.parse(args, switches: @switches) do {opts, [], _} -> # Because this command may be invoked explicitly with # deps.compile, we simply try to compile any available # dependency. - compile(Enum.filter(loaded(env: Mix.env), &available?/1), opts) + compile(Enum.filter(loaded(env: Mix.env()), &available?/1), opts) + {opts, tail, _} -> - compile(loaded_by_name(tail, [env: Mix.env] ++ opts), opts) + compile(loaded_by_name(tail, [env: Mix.env()] ++ opts), opts) end end @doc false def compile(deps, options \\ []) do - shell = Mix.shell - config = Mix.Project.deps_config + shell = Mix.shell() + config = Mix.Project.deps_config() - Mix.Task.run "deps.precompile" + Mix.Task.run("deps.precompile") compiled = Enum.map(deps, fn %Mix.Dep{app: app, status: status, opts: opts, scm: scm} = dep -> @@ -67,22 +67,31 @@ defmodule Mix.Tasks.Deps.Compile do maybe_clean(app, options) - compiled? = cond do - not is_nil(opts[:compile]) -> - do_compile dep, config - mix?(dep) -> - do_mix dep, config - make?(dep) -> - do_make dep, config - dep.manager == :rebar -> - do_rebar dep, config - dep.manager == :rebar3 -> - do_rebar3 dep, config - true -> - shell.error "Could not compile #{inspect app}, no \"mix.exs\", \"rebar.config\" or \"Makefile\" " <> - "(pass :compile as an option to customize compilation, set it to \"false\" to do nothing)" - false - end + compiled? = + cond do + not is_nil(opts[:compile]) -> + do_compile(dep, config) + + mix?(dep) -> + do_mix(dep, config) + + make?(dep) -> + do_make(dep, config) + + dep.manager == :rebar -> + do_rebar(dep, config) + + dep.manager == :rebar3 -> + do_rebar3(dep, config) + + true -> + shell.error( + "Could not compile #{inspect(app)}, no \"mix.exs\", \"rebar.config\" or \"Makefile\" " <> + "(pass :compile as an option to customize compilation, set it to \"false\" to do nothing)" + ) + + false + end unless mix?(dep), do: build_structure(dep, config) # We should touch fetchable dependencies even if they @@ -92,12 +101,12 @@ defmodule Mix.Tasks.Deps.Compile do compiled? and fetchable? end) - if true in compiled, do: Mix.Dep.Lock.touch_manifest, else: :ok + if true in compiled, do: Mix.Dep.Lock.touch_manifest(), else: :ok end defp maybe_clean(app, opts) do if Keyword.get(opts, :force, false) do - File.rm_rf! Path.join [Mix.Project.build_path, "lib", Atom.to_string(app)] + File.rm_rf!(Path.join([Mix.Project.build_path(), "lib", Atom.to_string(app)])) end end @@ -112,8 +121,10 @@ defmodule Mix.Tasks.Deps.Compile do end defp check_unavailable!(app, {:unavailable, _}) do - Mix.raise "Cannot compile dependency #{inspect app} because " <> - "it isn't available, run \"mix deps.get\" first" + Mix.raise( + "Cannot compile dependency #{inspect(app)} because " <> + "it isn't available, run \"mix deps.get\" first" + ) end defp check_unavailable!(_, _) do @@ -121,56 +132,69 @@ defmodule Mix.Tasks.Deps.Compile do end defp do_mix(dep, _config) do - Mix.Dep.in_dependency dep, fn _ -> - if req = old_elixir_req(Mix.Project.config) do - Mix.shell.error "warning: the dependency #{inspect dep.app} requires Elixir #{inspect req} " <> - "but you are running on v#{System.version}" + Mix.Dep.in_dependency(dep, fn _ -> + if req = old_elixir_req(Mix.Project.config()) do + Mix.shell().error( + "warning: the dependency #{inspect(dep.app)} requires Elixir #{inspect(req)} " <> + "but you are running on v#{System.version()}" + ) end # Force recompilation on compile status if dep.status == :compile do - Mix.Dep.Lock.touch_manifest + Mix.Dep.Lock.touch_manifest() end try do - res = Mix.Task.run("compile", ["--no-deps", "--no-archives-check", - "--no-elixir-version-check", "--no-warnings-as-errors"]) + options = [ + "--no-deps", + "--no-archives-check", + "--no-elixir-version-check", + "--no-warnings-as-errors" + ] + + res = Mix.Task.run("compile", options) + match?({:ok, _}, res) catch kind, reason -> - stacktrace = System.stacktrace + stacktrace = System.stacktrace() app = dep.app - Mix.shell.error "could not compile dependency #{inspect app}, \"mix compile\" failed. " <> - "You can recompile this dependency with \"mix deps.compile #{app}\", update it " <> - "with \"mix deps.update #{app}\" or clean it with \"mix deps.clean #{app}\"" + + Mix.shell().error( + "could not compile dependency #{inspect(app)}, \"mix compile\" failed. " <> + "You can recompile this dependency with \"mix deps.compile #{app}\", update it " <> + "with \"mix deps.update #{app}\" or clean it with \"mix deps.clean #{app}\"" + ) + :erlang.raise(kind, reason, stacktrace) end - end + end) end defp do_rebar(dep, config) do lib_path = Path.join(config[:env_path], "lib") - cmd = "#{rebar_cmd(dep)} compile skip_deps=true deps_dir=#{inspect lib_path}" - do_command dep, config, cmd, false + cmd = "#{rebar_cmd(dep)} compile skip_deps=true deps_dir=#{inspect(lib_path)}" + do_command(dep, config, cmd, false) end defp do_rebar3(%Mix.Dep{opts: opts} = dep, config) do - dep_path = opts[:build] + dep_path = opts[:build] config_path = Path.join(dep_path, "mix.rebar.config") - lib_path = Path.join(config[:env_path], "lib/*/ebin") + lib_path = Path.join(config[:env_path], "lib/*/ebin") env = [{"REBAR_CONFIG", config_path}, {"TERM", "dumb"}] - cmd = "#{rebar_cmd(dep)} bare compile --paths #{inspect lib_path}" + cmd = "#{rebar_cmd(dep)} bare compile --paths #{inspect(lib_path)}" File.mkdir_p!(dep_path) File.write!(config_path, rebar_config(dep)) - do_command dep, config, cmd, false, env + do_command(dep, config, cmd, false, env) end defp rebar_config(dep) do dep.extra - |> Mix.Rebar.dependency_config - |> Mix.Rebar.serialize_config + |> Mix.Rebar.dependency_config() + |> Mix.Rebar.serialize_config() end defp rebar_cmd(%Mix.Dep{manager: manager} = dep) do @@ -178,17 +202,28 @@ defmodule Mix.Tasks.Deps.Compile do end defp handle_rebar_not_found(%Mix.Dep{app: app, manager: manager}) do - shell = Mix.shell - shell.info "Could not find \"#{manager}\", which is needed to build dependency #{inspect app}" - shell.info "I can install a local copy which is just used by Mix" + shell = Mix.shell() + + shell.info( + "Could not find \"#{manager}\", which is needed to build dependency #{inspect(app)}" + ) - unless shell.yes?("Shall I install #{manager}? (if running non-interactively, use \"mix local.rebar --force\")") do - Mix.raise "Could not find \"#{manager}\" to compile " <> - "dependency #{inspect app}, please ensure \"#{manager}\" is available" + shell.info("I can install a local copy which is just used by Mix") + + install_question = + "Shall I install #{manager}? (if running non-interactively, " <> + "use \"mix local.rebar --force\")" + + unless shell.yes?(install_question) do + error_message = + "Could not find \"#{manager}\" to compile " <> + "dependency #{inspect(app)}, please ensure \"#{manager}\" is available" + + Mix.raise(error_message) end (Mix.Tasks.Local.Rebar.run([]) && Mix.Rebar.local_rebar_cmd(manager)) || - Mix.raise "\"#{manager}\" installation failed" + Mix.raise("\"#{manager}\" installation failed") end defp do_make(dep, config) do @@ -200,11 +235,13 @@ defmodule Mix.Tasks.Deps.Compile do makefile_win? = makefile_win?(dep) command = - case :os.type do + case :os.type() do {:win32, _} when makefile_win? -> "nmake /F Makefile.win" + {:unix, type} when type in [:freebsd, :openbsd] -> "gmake" + _ -> "make" end @@ -227,34 +264,40 @@ defmodule Mix.Tasks.Deps.Compile do defp do_command(%Mix.Dep{app: app, opts: opts}, config, command, print_app?, env \\ []) do File.cd!(opts[:dest], fn -> env = [{"ERL_LIBS", Path.join(config[:env_path], "lib")}] ++ env + if Mix.Shell.cmd(command, env: env, into: %Mix.Shell{print_app?: print_app?}) != 0 do - Mix.raise "Could not compile dependency #{inspect app}, \"#{command}\" command failed. " <> - "You can recompile this dependency with \"mix deps.compile #{app}\", update it " <> - "with \"mix deps.update #{app}\" or clean it with \"mix deps.clean #{app}\"" + Mix.raise( + "Could not compile dependency #{inspect(app)}, \"#{command}\" command failed. " <> + "You can recompile this dependency with \"mix deps.compile #{app}\", update it " <> + "with \"mix deps.update #{app}\" or clean it with \"mix deps.clean #{app}\"" + ) end end) + true end defp build_structure(%Mix.Dep{opts: opts} = dep, config) do build_path = Path.dirname(opts[:build]) - Enum.each Mix.Dep.source_paths(dep), fn {source, base} -> + + Enum.each(Mix.Dep.source_paths(dep), fn {source, base} -> app = Path.join(build_path, base) build_structure(source, app, config) Code.prepend_path(Path.join(app, "ebin")) - end + end) end defp build_structure(dest, build, config) do - File.cd! dest, fn -> + File.cd!(dest, fn -> config = Keyword.put(config, :app_path, build) Mix.Project.build_structure(config, symlink_ebin: true) - end + end) end defp old_elixir_req(config) do req = config[:elixir] - if req && not Version.match?(System.version, req) do + + if req && not Version.match?(System.version(), req) do req end end