Packages
nerves_bootstrap
1.15.0
1.16.0
1.15.3
1.15.2
1.15.1
1.15.0
1.14.5
1.14.4
1.14.3
1.14.2
1.14.0
1.13.1
1.13.0
1.12.2
1.12.1
1.12.0
1.11.5
1.11.4
1.11.3
1.11.2
1.11.1
1.11.0
1.10.6
1.10.5
1.10.4
1.10.3
1.10.2
1.10.1
1.10.0
1.9.0
1.8.1
1.8.0
1.7.1
1.7.0
1.6.3
1.6.2
1.6.1
1.6.0
1.5.3
1.5.2
1.5.1
1.5.0
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.0
1.0.1
1.0.0
1.0.0-rc.4
1.0.0-rc.3
1.0.0-rc.2
1.0.0-rc.1
1.0.0-rc.0
0.8.2
0.8.1
0.8.0
0.7.1
0.7.0
0.6.4
0.6.3
Nerves mix integration bootstrap and new project generator
Current section
Files
Jump to
Current section
Files
lib/nerves_bootstrap/update_checker.ex
# SPDX-FileCopyrightText: 2025 Frank Hunleth
#
# SPDX-License-Identifier: Apache-2.0
#
defmodule Nerves.Bootstrap.UpdateChecker do
@moduledoc false
@bootstrap_vsn Mix.Project.config()[:version]
@check_interval_seconds 86400
@doc """
Check for a nerves_bootstrap release
"""
@spec check() :: :ok
def check() do
if should_check?() do
do_check()
mark_checked()
else
:ok
end
end
defp do_check() do
Hex.start()
{:ok, {200, resp, _}} = Hex.API.Package.get("hexpm", "nerves_bootstrap")
current_version = Version.parse!(@bootstrap_vsn)
release_versions =
resp
|> Map.get("releases")
|> Enum.map(&Map.get(&1, "version"))
|> Enum.map(&Version.parse!/1)
case select_update(release_versions, current_version) do
nil ->
:ok
latest_version ->
render_update_message(current_version, latest_version)
end
rescue
_e -> :ok
end
@spec select_update([Version.t()], Version.t()) :: Version.t() | nil
def select_update(releases, current_version) do
req = Version.parse_requirement!("> #{current_version}")
allow_pre = current_version.pre != []
releases
|> Enum.filter(&Version.match?(&1, req, allow_pre: allow_pre))
|> Enum.sort(&(Version.compare(&1, &2) == :gt))
|> List.first()
end
@spec render_update_message(Version.t(), Version.t()) :: :ok
def render_update_message(current_version, latest_version) do
upgrade =
if latest_version.pre == [] do
"mix local.nerves"
else
"mix archive.install hex nerves_bootstrap #{latest_version}"
end
Mix.shell().info([
:yellow,
"""
A new version of Nerves bootstrap is available (#{current_version} < #{latest_version}).
You can update by running
#{upgrade}
""",
:reset
])
end
@doc false
@spec should_check?() :: boolean()
def should_check?() do
case File.stat(check_file_path()) do
{:ok, %{mtime: mtime}} ->
mtime_unix = mtime |> NaiveDateTime.from_erl!() |> DateTime.from_naive!("Etc/UTC")
now = DateTime.utc_now()
seconds_passed = DateTime.diff(now, mtime_unix)
# Check if time as passed or there's something really off with the time
seconds_passed >= @check_interval_seconds or seconds_passed < -@check_interval_seconds
{:error, _} ->
true
end
end
@doc false
@spec mark_checked() :: :ok
def mark_checked() do
path = check_file_path()
File.mkdir_p!(Path.dirname(path))
File.touch!(path)
end
defp check_file_path() do
Path.join(data_dir(), "nerves_bootstrap_update_check")
end
# Match Nerves library's handling
defp data_dir() do
case System.get_env("XDG_DATA_HOME") do
directory when is_binary(directory) -> Path.join(directory, "nerves")
nil -> Path.expand("~/.nerves")
end
end
end