Packages
nerves
1.3.3
1.15.0
1.14.3
1.14.2
1.14.1
1.14.0
1.13.2
1.13.1
1.13.0
1.12.0
1.11.3
1.11.2
1.11.1
1.11.0
1.10.5
1.10.4
1.10.3
1.10.2
1.10.1
1.10.0
1.9.3
1.9.2
retired
1.9.1
1.9.0
1.8.0
1.7.17
1.7.16
1.7.15
1.7.14
retired
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
retired
1.7.1
retired
1.7.0
retired
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.1
1.2.0
1.1.1
1.1.0
1.0.1
1.0.0
1.0.0-rc.2
1.0.0-rc.1
1.0.0-rc.0
0.11.0
0.10.1
0.10.0
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.3
0.8.2
0.8.1
0.8.0
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.4.0-rc.0
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.0
Craft and deploy bulletproof embedded software
Current section
Files
Jump to
Current section
Files
lib/mix/nerves/utils.ex
defmodule Mix.Nerves.Utils do
@fwup_semver "~> 1.2.5 or ~> 1.3"
def shell(cmd, args, opts \\ []) do
stream = opts[:stream] || IO.binstream(:standard_io, :line)
std_err = opts[:stderr_to_stdout] || true
opts = Keyword.drop(opts, [:into, :stderr_to_stdout, :stream])
System.cmd(cmd, args, [into: stream, stderr_to_stdout: std_err] ++ opts)
end
def preflight do
{_, type} = :os.type()
check_requirements("fwup")
check_requirements("mksquashfs")
check_host_requirements(type)
Mix.Task.run("nerves.loadpaths")
end
def check_requirements("mksquashfs") do
case System.find_executable("mksquashfs") do
nil ->
Mix.raise("""
Squash FS Tools are required to be installed on your system.
Please see https://hexdocs.pm/nerves/installation.html#host-specific-tools
for installation instructions
""")
_ ->
:ok
end
end
def check_requirements("fwup") do
case System.find_executable("fwup") do
nil ->
Mix.raise("""
fwup is required to create and burn firmware.
Please see https://hexdocs.pm/nerves/installation.html#fwup
for installation instructions
""")
_ ->
with {vsn, 0} <- System.cmd("fwup", ["--version"]),
vsn = String.trim(vsn),
{:ok, req} = Version.parse_requirement(@fwup_semver),
true <- Version.match?(vsn, req) do
:ok
else
false ->
{vsn, 0} = System.cmd("fwup", ["--version"])
Mix.raise("""
fwup #{@fwup_semver} is required for Nerves.
You are running #{vsn}.
Please see https://hexdocs.pm/nerves/installation.html#fwup
for installation instructions
""")
error ->
Mix.raise("""
Nerves encountered an error while checking host requirements for fwup
#{inspect(error)}
Please open a bug report for this issue on github.com/nerves-project/nerves
""")
end
end
end
def check_host_requirements(:darwin) do
case System.find_executable("gstat") do
nil ->
Mix.raise("""
gstat is required to create and burn firmware.
Please see https://hexdocs.pm/nerves/installation.html#host-specific-tools
for installation instructions
""")
_ ->
:ok
end
end
def check_host_requirements(_), do: nil
def debug_info(msg) do
if System.get_env("NERVES_DEBUG") == "1" do
Mix.shell().info(msg)
end
end
def check_nerves_system_is_set! do
var_name = "NERVES_SYSTEM"
System.get_env(var_name) || raise_env_var_missing(var_name)
end
def check_nerves_toolchain_is_set! do
var_name = "NERVES_TOOLCHAIN"
System.get_env(var_name) || raise_env_var_missing(var_name)
end
def get_devs do
{result, 0} =
if Nerves.Utils.WSL.running_on_wsl?() do
Nerves.Utils.WSL.get_fwup_devices()
else
System.cmd("fwup", ["--detect"])
end
if result == "" do
Mix.raise("Could not auto detect your SD card")
end
result
|> String.trim()
|> String.split("\n")
|> Enum.map(&String.split(&1, ","))
end
def prompt_dev() do
case get_devs() do
[[dev, bytes]] ->
choice =
Mix.shell().yes?("Use #{bytes_to_gigabytes(bytes)} GiB memory card found at #{dev}?")
if choice do
dev
else
Mix.raise("Aborted")
end
devs ->
choices =
devs
|> Enum.zip(0..length(devs))
|> Enum.reduce([], fn {[dev, bytes], idx}, acc ->
["#{idx}) #{bytes_to_gigabytes(bytes)} GiB found at #{dev}" | acc]
end)
|> Enum.reverse()
choice =
Mix.shell().prompt(
"Discovered devices:\n#{Enum.join(choices, "\n")}\nWhich device do you want to burn to?"
)
|> String.trim()
idx =
case Integer.parse(choice) do
{idx, _} -> idx
_ -> Mix.raise("Invalid selection #{choice}")
end
case Enum.fetch(devs, idx) do
{:ok, [dev, _]} -> dev
_ -> Mix.raise("Invalid selection #{choice}")
end
end
end
def bytes_to_gigabytes(bytes) when is_binary(bytes) do
{bytes, _} = Integer.parse(bytes)
bytes_to_gigabytes(bytes)
end
def bytes_to_gigabytes(bytes) do
gb = bytes / 1024 / 1024 / 1024
Float.round(gb, 2)
end
def set_provisioning(nil), do: :ok
def set_provisioning(app) when is_atom(app) do
Application.load(app)
Application.get_env(app, :nerves_provisioning)
|> set_provisioning()
end
def set_provisioning(provisioning) when is_binary(provisioning) do
path = Path.expand(provisioning)
System.put_env("NERVES_PROVISIONING", path)
end
def set_provisioning(_) do
Mix.raise("""
Unexpected Mix config for :nerves, :firmware, :provisioning.
Provisioning should be a relative string path to a provisioning.conf
based off the root of the project or an atom of an application that
provides a provisioning.conf.
For example:
config :nerves, :firmware,
provisioning: "config/provisioning.conf"
or
config :nerves, :firmware,
provisioning: :nerves_hub
""")
end
defp raise_env_var_missing(name) do
Mix.raise("""
Environment variable $#{name} is not set.
This variable is usually set for you by Nerves when you specify the
$MIX_TARGET. For examples please see
https://hexdocs.pm/nerves/getting-started.html#create-the-firmware-bundle
""")
end
end