defmodule Mix.Tasks.Compile.NervesPackage do use Mix.Task import Mix.Nerves.IO require Logger @moduledoc """ Build a Nerves Artifact from a Nerves Package """ @shortdoc "Nerves Package Compiler" @recursive true @impl true def run(_args) do debug_info("Compile.NervesPackage start") if Nerves.Env.enabled?() do config = Mix.Project.config() bootstrap_started?() |> bootstrap_check() Nerves.Env.ensure_loaded(Mix.Project.config()[:app]) package = Nerves.Env.package(config[:app]) toolchain = Nerves.Env.toolchain() ret = if Nerves.Artifact.stale?(package) do Nerves.Artifact.build(package, toolchain) :ok else :noop end debug_info("Compile.NervesPackage end") ret else debug_info("Compile.NervesPackage disabled") :noop end end @doc false def bootstrap_check(true), do: :ok def bootstrap_check(false) do error = """ Compiling Nerves packages requires nerves_bootstrap to be started, which ought to happen in your generated `config.exs`. Please ensure that MIX_TARGET is set in your environment. """ <> if in_umbrella?(File.cwd!()) do """ When compiling from an Umbrella project you must also ensure: * You are compiling from an application directory, not the root of the Umbrella * The Umbrella config (/config/config.exs) imports the generated Nerves config from your Nerves application (import_config "../apps/your_nerves_app/config/config.exs") """ else "" end Mix.raise(error) end defp bootstrap_started?() do Application.started_applications() |> Enum.map(&Tuple.to_list/1) |> Enum.map(&List.first/1) |> Enum.member?(:nerves_bootstrap) end defp in_umbrella?(app_path) do umbrella = Path.expand(Path.join([app_path, "..", ".."])) mix_path = Path.join(umbrella, "mix.exs") apps_path = Path.join(umbrella, "apps") File.exists?(mix_path) && File.exists?(apps_path) end end