Change how FarmwareManifests are built
parent
1e7ae7a744
commit
2124c19fcd
|
@ -2,22 +2,50 @@ defmodule FarmbotCore.Asset.FarmwareInstallation.Manifest do
|
|||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
@primary_key false
|
||||
@acceptable_manifest_version_requirement "2.0.0"
|
||||
@acceptable_farmware_tools_version_requirement "2.0.0"
|
||||
|
||||
alias FarmbotCore.Project
|
||||
|
||||
defmodule Config do
|
||||
use Ecto.Schema
|
||||
@primary_key false
|
||||
|
||||
embedded_schema do
|
||||
field(:label, :string)
|
||||
field(:value, :string)
|
||||
field(:order, :integer)
|
||||
end
|
||||
|
||||
def view(config) do
|
||||
%{
|
||||
label: config.label,
|
||||
value: config.value,
|
||||
order: config.order
|
||||
}
|
||||
end
|
||||
|
||||
def changeset(config, params) do
|
||||
config
|
||||
|> cast(params, [:label, :value, :order])
|
||||
|> validate_required([:label, :value, :order])
|
||||
end
|
||||
end
|
||||
|
||||
embedded_schema do
|
||||
field(:package, :string)
|
||||
field(:language, :string)
|
||||
field(:author, :string)
|
||||
field(:description, :string)
|
||||
field(:version, :string)
|
||||
field(:url, :string)
|
||||
field(:zip, :string)
|
||||
field(:executable, :string)
|
||||
field(:args, {:array, :string})
|
||||
field(:farmware_tools_version, :string, default: "latest")
|
||||
# new field
|
||||
field(:os_version_requirement, :string, default: "~> 8.0")
|
||||
field(:args, :string)
|
||||
field(:config, :map, default: %{})
|
||||
field(:package_version, :string)
|
||||
field(:farmware_manifest_version_requirement, :string)
|
||||
field(:farmware_tools_version_requirement, :string, default: ">= 0.0.0")
|
||||
field(:farmbot_os_version_requirement, :string, default: "~> 8.0")
|
||||
end
|
||||
|
||||
def view(manifest) do
|
||||
|
@ -26,14 +54,15 @@ defmodule FarmbotCore.Asset.FarmwareInstallation.Manifest do
|
|||
language: manifest.language,
|
||||
author: manifest.author,
|
||||
description: manifest.description,
|
||||
version: manifest.version,
|
||||
url: manifest.url,
|
||||
zip: manifest.zip,
|
||||
executable: manifest.executable,
|
||||
args: manifest.args,
|
||||
farmware_tools_version: manifest.farmware_tools_version,
|
||||
# new field
|
||||
os_version_requirement: manifest.os_version_requirement
|
||||
config: Map.new(manifest.config, fn({key, config_data}) -> {key, Config.view(config_data)} end),
|
||||
package_version: manifest.package_version,
|
||||
farmware_tools_version_requirement: manifest.farmware_tools_version_requirement,
|
||||
farmware_manifest_version_requirement: manifest.farmware_manifest_version_requirement,
|
||||
farmbot_os_version_requirement: manifest.farmbot_os_version_requirement,
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -44,20 +73,38 @@ defmodule FarmbotCore.Asset.FarmwareInstallation.Manifest do
|
|||
:language,
|
||||
:author,
|
||||
:description,
|
||||
:version,
|
||||
:url,
|
||||
:zip,
|
||||
:executable,
|
||||
:args,
|
||||
:os_version_requirement,
|
||||
:farmware_tools_version
|
||||
:config,
|
||||
:package_version,
|
||||
:farmware_tools_version_requirement,
|
||||
:farmware_manifest_version_requirement,
|
||||
:farmbot_os_version_requirement,
|
||||
])
|
||||
|> validate_required([:package, :executable, :args, :zip, :version])
|
||||
|> validate_required_os_version()
|
||||
|> validate_required([
|
||||
:package,
|
||||
:author,
|
||||
:zip,
|
||||
:executable,
|
||||
:args,
|
||||
:package_version,
|
||||
:farmware_manifest_version_requirement,
|
||||
:farmbot_os_version_requirement
|
||||
])
|
||||
|> validate_farmbot_os_version_requirement()
|
||||
|> validate_farmware_manifest_version_requirement()
|
||||
|> validate_farmware_tools_version_requirement()
|
||||
|> validate_package_version()
|
||||
|> validate_config()
|
||||
|> validate_url()
|
||||
|> validate_zip()
|
||||
end
|
||||
|
||||
defp validate_required_os_version(changeset) do
|
||||
req = get_field(changeset, :os_version_requirement)
|
||||
defp validate_farmbot_os_version_requirement(%{valid?: false} = change), do: change
|
||||
defp validate_farmbot_os_version_requirement(changeset) do
|
||||
req = get_field(changeset, :farmbot_os_version_requirement)
|
||||
cur = Project.version()
|
||||
|
||||
match =
|
||||
|
@ -72,7 +119,98 @@ defmodule FarmbotCore.Asset.FarmwareInstallation.Manifest do
|
|||
changeset
|
||||
|
||||
_ ->
|
||||
add_error(changeset, :os_version_requirement, "Version requirement not met")
|
||||
add_error(changeset, :farmbot_os_version_requirement, "Version requirement not met")
|
||||
end
|
||||
end
|
||||
|
||||
defp validate_farmware_manifest_version_requirement(%{valid?: false} = change), do: change
|
||||
defp validate_farmware_manifest_version_requirement(changeset) do
|
||||
req = get_field(changeset, :farmware_manifest_version_requirement)
|
||||
match =
|
||||
try do
|
||||
Version.match?(@acceptable_manifest_version_requirement, req)
|
||||
rescue
|
||||
Version.InvalidRequirementError -> :invalid_version
|
||||
end
|
||||
|
||||
case match do
|
||||
true ->
|
||||
changeset
|
||||
|
||||
_ ->
|
||||
add_error(changeset, :farmware_manifest_version_requirement, "Version requirement not met")
|
||||
end
|
||||
end
|
||||
|
||||
# Validates the version of farmware_tools required
|
||||
defp validate_farmware_tools_version_requirement(%{valid?: false} = change), do: change
|
||||
defp validate_farmware_tools_version_requirement(changeset) do
|
||||
req = get_field(changeset, :farmware_tools_version_requirement)
|
||||
match =
|
||||
try do
|
||||
Version.match?(@acceptable_farmware_tools_version_requirement, req)
|
||||
rescue
|
||||
Version.InvalidRequirementError -> :invalid_version
|
||||
end
|
||||
|
||||
case match do
|
||||
true ->
|
||||
changeset
|
||||
|
||||
_ ->
|
||||
add_error(changeset, :farmware_tools_version_requirement, "Version requirement not met")
|
||||
end
|
||||
end
|
||||
|
||||
defp validate_package_version(%{valid?: false} = change), do: change
|
||||
defp validate_package_version(changeset) do
|
||||
version = get_field(changeset, :package_version)
|
||||
case Version.parse(version) do
|
||||
{:ok, _} -> changeset
|
||||
:error ->
|
||||
add_error(changeset, :package_version, "not a valid semver string")
|
||||
end
|
||||
end
|
||||
|
||||
defp validate_config(%{valid?: false} = change), do: change
|
||||
defp validate_config(changeset) do
|
||||
config = get_field(changeset, :config)
|
||||
Enum.reduce(config, changeset, fn
|
||||
{name, %{} = params}, changeset when is_binary(name) ->
|
||||
case Config.changeset(%Config{}, params) do
|
||||
%{valid?: true} = config_changeset ->
|
||||
validated_config_data = Ecto.Changeset.apply_changes(config_changeset)
|
||||
new_config = Map.put(config, name, validated_config_data)
|
||||
put_change(changeset, :config, new_config)
|
||||
%{valid?: false} ->
|
||||
add_error(changeset, :config, "invalid config item")
|
||||
end
|
||||
{_, _}, changeset ->
|
||||
add_error(changeset, :config, "invalid config item")
|
||||
end)
|
||||
end
|
||||
|
||||
defp validate_url(%{valid?: false} = change), do: change
|
||||
defp validate_url(changeset) do
|
||||
# `url` is optional
|
||||
url = get_field(changeset, :url)
|
||||
if url do
|
||||
parse_uri(url, changeset, :url)
|
||||
else
|
||||
changeset
|
||||
end
|
||||
end
|
||||
|
||||
defp validate_zip(%{valid?: false} = change), do: change
|
||||
defp validate_zip(changeset) do
|
||||
zip = get_field(changeset, :zip)
|
||||
parse_uri(zip, changeset, :zip)
|
||||
end
|
||||
|
||||
defp parse_uri(url, changeset, key) do
|
||||
case URI.parse(url) do
|
||||
%{scheme: s} when s in ["file", "https", "http"] -> changeset
|
||||
_ -> add_error(changeset, key, "invalid uri")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -71,11 +71,15 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.FarmwareInstallation do
|
|||
# Installed is newer than remote.
|
||||
:gt ->
|
||||
success_log(updated, "up to date.")
|
||||
BotState.report_farmware_installed(updated.manifest.package, Manifest.view(updated.manifest))
|
||||
|
||||
{:noreply, updated}
|
||||
|
||||
# No difference between installed and remote.
|
||||
:eq ->
|
||||
success_log(updated, "up to date.")
|
||||
BotState.report_farmware_installed(updated.manifest.package, Manifest.view(updated.manifest))
|
||||
|
||||
{:noreply, updated}
|
||||
|
||||
# Installed version is older than remote
|
||||
|
@ -86,6 +90,7 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.FarmwareInstallation do
|
|||
:ok <- install_zip(updated, zip_binary),
|
||||
:ok <- install_farmware_tools(updated),
|
||||
:ok <- write_manifest(updated) do
|
||||
BotState.report_farmware_installed(updated.manifest.package, Manifest.view(updated.manifest))
|
||||
{:noreply, updated}
|
||||
else
|
||||
er ->
|
||||
|
|
|
@ -81,8 +81,6 @@ defmodule FarmbotCore.BotState.FileSystem do
|
|||
def serialize_state(%{} = bot_state, prefix, acc) do
|
||||
Enum.reduce(bot_state, acc, fn {key, value}, acc ->
|
||||
cond do
|
||||
# :( Please FIXME
|
||||
key == :farmwares -> acc
|
||||
is_map(value) && map_size(value) == 0 -> [Path.join(prefix, to_string(key)) | acc]
|
||||
is_list(value) -> raise("Arrays can not be serialized to filesystem nodes")
|
||||
is_map(value) -> serialize_state(value, Path.join(prefix, to_string(key)), acc)
|
||||
|
|
|
@ -18,7 +18,7 @@ defmodule FarmbotCore.BotStateNG do
|
|||
embeds_one(:informational_settings, InformationalSettings, on_replace: :update)
|
||||
embeds_one(:configuration, Configuration, on_replace: :update)
|
||||
field(:user_env, {:map, {:string, :any}}, default: %{})
|
||||
field(:farmwares, {:map, {:string, :map}}, default: %{})
|
||||
field(:process_info, {:map, {:string, :any}}, default: %{farmwares: %{}})
|
||||
field(:pins, {:map, {:integer, :map}}, default: %{})
|
||||
field(:jobs, {:map, {:string, :map}}, default: %{})
|
||||
end
|
||||
|
@ -35,7 +35,7 @@ defmodule FarmbotCore.BotStateNG do
|
|||
|
||||
def changeset(bot_state, params \\ %{}) do
|
||||
bot_state
|
||||
|> cast(params, [:user_env, :pins, :jobs, :farmwares])
|
||||
|> cast(params, [:user_env, :pins, :jobs, :process_info])
|
||||
|> cast_embed(:mcu_params, [])
|
||||
|> cast_embed(:location_data, [])
|
||||
|> cast_embed(:informational_settings, [])
|
||||
|
@ -47,8 +47,8 @@ defmodule FarmbotCore.BotStateNG do
|
|||
mcu_params: McuParams.view(bot_state.mcu_params),
|
||||
location_data: LocationData.view(bot_state.location_data),
|
||||
informational_settings: InformationalSettings.view(bot_state.informational_settings),
|
||||
process_info: %{farmwares: bot_state.farmwares},
|
||||
configuration: Configuration.view(bot_state.configuration),
|
||||
process_info: bot_state.process_info,
|
||||
user_env: bot_state.user_env,
|
||||
pins: bot_state.pins,
|
||||
jobs: bot_state.jobs
|
||||
|
@ -67,16 +67,15 @@ defmodule FarmbotCore.BotStateNG do
|
|||
put_change(cs, :pins, new_pins)
|
||||
end
|
||||
|
||||
# :( Please FIXME
|
||||
@doc "Add or update a farmware to state.farmwares"
|
||||
def add_or_update_farmware(state, name, %{} = manifest) do
|
||||
cs = changeset(state, %{})
|
||||
|
||||
new_farmwares =
|
||||
cs
|
||||
|> get_field(:farmwares)
|
||||
|> Map.put(name, manifest)
|
||||
put_change(cs, :farmwares, new_farmwares)
|
||||
|> get_field(:process_info)
|
||||
|> Map.get(:farmwares)
|
||||
put_change(cs, :process_info, %{farmwares: new_farmwares})
|
||||
end
|
||||
|
||||
def set_user_env(state, key, value) do
|
||||
|
|
|
@ -20,15 +20,6 @@ defmodule FarmbotCore.BotStateNG.ChangeGenerator do
|
|||
|> changes(path, acc)
|
||||
end
|
||||
|
||||
# :( Please FIXME
|
||||
def changes([{:farmwares, farmwares} | rest], path, acc) do
|
||||
acc = Enum.reduce(farmwares, acc, fn
|
||||
{farmware_name, manifest}, acc ->
|
||||
[{add_paths(path, "process_info.farmwares.#{farmware_name}"), manifest} | acc]
|
||||
end)
|
||||
changes(rest, path, acc)
|
||||
end
|
||||
|
||||
def changes([{key, change} | rest], path, acc) do
|
||||
cond do
|
||||
is_number(change) ->
|
||||
|
|
Loading…
Reference in New Issue