bring back farmware repos.

This commit is contained in:
connor rigby 2017-10-31 13:36:06 -07:00
parent ff37b75093
commit 43deb4aaf3
20 changed files with 168 additions and 67 deletions

View file

@ -38,6 +38,9 @@ config :farmbot, :behaviour,
firmware_handler: Farmbot.Firmware.StubHandler,
http_adapter: Farmbot.HTTP.HTTPoisonAdapter
config :farmbot, :farmware,
first_part_farmware_manifest_url: "https://raw.githubusercontent.com/FarmBot-Labs/farmware_manifests/master/manifest.json"
case target do
"host" ->
import_config("host/#{env}.exs")

View file

@ -121,9 +121,10 @@ defmodule Farmbot.Bootstrap.Supervisor do
ConfigStorage.update_config_value(:string, "authorization", "last_shutdown_reason", nil)
children = [
supervisor(Farmbot.BotState.Supervisor, [token, [name: Farmbot.BotState.Supervisor]]),
supervisor(Farmbot.HTTP.Supervisor, [token, [name: Farmbot.HTTP.Supervisor]]),
supervisor(Farmbot.Repo.Supervisor, [token, [name: Farmbot.Repo.Supervisor]])
supervisor(Farmbot.BotState.Supervisor, []),
supervisor(Farmbot.HTTP.Supervisor, []),
supervisor(Farmbot.Repo.Supervisor, []),
supervisor(Farmbot.Farmware.Supervisor, [])
]
opts = [strategy: :one_for_all]

View file

@ -22,8 +22,9 @@ defmodule Farmbot.BotState do
user_env: %{},
process_info: %{}
def start_link(opts) do
GenStage.start_link(__MODULE__, [], opts)
@doc false
def start_link() do
GenStage.start_link(__MODULE__, [], [name: __MODULE__])
end
def init([]) do

View file

@ -2,15 +2,16 @@ defmodule Farmbot.BotState.Supervisor do
@moduledoc false
use Supervisor
def start_link(token, opts) do
Supervisor.start_link(__MODULE__, token, opts)
@doc false
def start_link() do
Supervisor.start_link(__MODULE__, [], [name: __MODULE__])
end
def init(_token) do
def init([]) do
children = [
supervisor(Farmbot.Firmware.Supervisor, [[name: Farmbot.Firmware.Supervisor]]),
worker(Farmbot.BotState, [[name: Farmbot.BotState]]),
worker(Farmbot.Logger, [[name: Farmbot.Logger]]),
supervisor(Farmbot.Firmware.Supervisor, []),
worker(Farmbot.BotState, []),
worker(Farmbot.Logger, []),
supervisor(Farmbot.BotState.Transport.Supervisor, [])
]

View file

@ -4,9 +4,9 @@ defmodule Farmbot.BotState.Transport.GenMQTT do
require Logger
alias Farmbot.BotState.Transport.GenMQTT.Client
@doc "Start the MQTT Transport."
def start_link(opts) do
GenStage.start_link(__MODULE__, [], opts)
@doc false
def start_link do
GenStage.start_link(__MODULE__, [], [name: __MODULE__])
end
def init([]) do

View file

@ -4,13 +4,13 @@ defmodule Farmbot.BotState.Transport.Supervisor do
use Supervisor
def start_link do
Supervisor.start_link(__MODULE__, [], name: __MODULE__)
Supervisor.start_link(__MODULE__, [], [name: __MODULE__])
end
def init([]) do
:farmbot
|> Application.get_env(:transport)
|> Enum.map(&worker(&1, [[name: &1]]))
|> Enum.map(&worker(&1, []))
|> supervise(strategy: :one_for_one)
end
end

View file

@ -3,8 +3,7 @@ defmodule Farmbot.Farmware do
defmodule Meta do
@moduledoc "Metadata about a Farmware."
defstruct [:author,:language,:description]
defstruct [:author, :language,:description]
end
defstruct [

View file

@ -1,5 +1,5 @@
defmodule Farmbot.Farmware.Installer do
@moduledoc "Install Farmware from a URL."
@moduledoc "Handles installation of Farmwares and syncronization of Farmware Repos."
alias Farmbot.Farmware
alias Farmbot.Farmware.Installer.Repository
@ -25,18 +25,36 @@ defmodule Farmbot.Farmware.Installer do
install_path(name, version)
end
@doc "Enable a repo from a url."
def enable_repo(url_or_repo_struct, acc \\ [])
@doc "Add a repository to the database."
def add_repo(url) do
with {:ok, %{status_code: code, body: body}} when code > 199 and code < 300 <- HTTP.get(url),
{:ok, json_map} <- Poison.decode(body),
{:ok, manifest} <- Repository.new(json_map)
do
Repository.changeset(manifest, %{url: url}) |> Farmbot.System.ConfigStorage.insert()
end
rescue
e in Sqlite.DbConnection.Error ->
st = System.stacktrace
if String.contains?(Exception.message(e), "UNIQUE constraint") do
{:error, :repo_already_exists}
else
reraise e, st
end
end
def enable_repo(url, _acc) when is_binary(url) do
Logger.info "Enabling repo from: #{url}"
@doc "Enable a repo from a url or struct."
def sync_repo(url_or_repo_struct, acc \\ [])
def sync_repo(url, _acc) when is_binary(url) do
Logger.info "Syncing repo from: #{url}"
with {:ok, %{status_code: code, body: body}} when code > 199 and code < 300 <- HTTP.get(url),
{:ok, json_map} <- Poison.decode(body),
{:ok, repo} <- Repository.new(json_map)
do
case enable_repo(repo, []) do
case sync_repo(repo, []) do
[] ->
Logger.info "Successfully enabled repo."
Logger.info "Successfully synced repo."
:ok
list_of_entries ->
Logger.error "Failed to enable some entries: #{inspect list_of_entries}"
@ -45,14 +63,14 @@ defmodule Farmbot.Farmware.Installer do
end
end
def enable_repo(repo = %Repository{manifests: [entry = %Repository.Entry{manifest_url: manifest_url} | entries]}, acc) do
def sync_repo(repo = %Repository{manifests: [entry = %Repository.Entry{manifest: manifest_url} | entries]}, acc) do
case install(manifest_url) do
:ok -> enable_repo(%{repo | manifests: entries}, acc)
{:error, _err} -> enable_repo(%{repo | manifests: entries}, [entry | acc])
:ok -> sync_repo(%{repo | manifests: entries}, acc)
{:error, _err} -> sync_repo(%{repo | manifests: entries}, [entry | acc])
end
end
def enable_repo(%Repository{manifests: []}, acc), do: acc
def sync_repo(%Repository{manifests: []}, acc), do: acc
@doc "Install a farmware from a URL."
def install(url) do

View file

@ -1,21 +0,0 @@
defmodule Farmbot.Farmware.Installer.Repository do
@moduledoc "A Repository is a way of enabling multiple farmware's at a time."
defmodule Entry do
@moduledoc "An entry in the Repository."
defstruct [:name, :manifest_url]
end
defstruct [manifests: []]
@doc "Turn a list into a Repo."
def new(list, acc \\ struct(__MODULE__))
def new([%{"name" => name, "manifest" => mani_url} | rest], %__MODULE__{manifests: manifests} = acc) do
entry = struct(Entry, name: name, manifest_url: mani_url)
new(rest, %{acc | manifests: [entry | manifests]})
end
def new([], acc), do: {:ok, acc}
end

View file

@ -0,0 +1,4 @@
defmodule Farmbot.Farmware.Installer.Repository.Entry do
@moduledoc "An entry in the Repository."
defstruct [:name, :manifest]
end

View file

@ -0,0 +1,18 @@
defmodule Farmbot.Farmware.Installer.Repository.ManifestType do
@moduledoc false
@behaviour Ecto.Type
alias Farmbot.Farmware.Installer.Repository.Entry
def type, do: :text
# try to encode as json here.
def cast(data) do
Poison.encode(data)
end
def load(text) do
Poison.decode(text, as: [struct(Entry)])
end
def dump(data), do: cast(data)
end

View file

@ -0,0 +1,33 @@
defmodule Farmbot.Farmware.Installer.Repository do
@moduledoc "A Repository is a way of enabling multiple farmware's at a time."
alias Farmbot.Farmware.Installer.Repository.{Entry, ManifestType}
use Ecto.Schema
import Ecto.Changeset
schema "farmware_repositories" do
field :manifests, ManifestType
field :url, :string
end
@required_fields [:url, :manifests]
def changeset(%__MODULE__{} = repo, params \\ %{}) do
repo
|> cast(params, @required_fields)
|> validate_required(@required_fields)
|> unique_constraint(:url)
end
@doc "Turn a list into a Repo."
def new(list, acc \\ struct(__MODULE__))
def new([%{"name" => name, "manifest" => mani_url} | rest], %__MODULE__{manifests: manifests} = acc) do
entry = struct(Entry, name: name, manifest: mani_url)
new(rest, %{acc | manifests: [entry | manifests || []]})
end
def new([], acc), do: {:ok, acc}
end

View file

@ -0,0 +1,28 @@
defmodule Farmbot.Farmware.Installer.Repository.SyncTask do
@moduledoc "Init module for installing first party farmware repo. Requires internet."
use Task, restart: :transient
require Logger
alias Farmbot.System.ConfigStorage
alias Farmbot.Farmware.Installer
alias Farmbot.Farmware.Installer.Repository
@fpf_url Application.get_env(:farmbot, :farmware)[:first_part_farmware_manifest_url] || raise "First party farmware url needs to be configured"
@doc false
def start_link(_) do
Task.start_link(__MODULE__, :sync_all, [])
end
def sync_all do
Logger.debug "Syncing all repos. This may take a while."
import Ecto.Query
unless Farmbot.System.ConfigStorage.one(from r in Repository, where: r.url == @fpf_url) do
Installer.add_repo(@fpf_url)
end
repos = ConfigStorage.all(Repository)
for repo <- repos do
Installer.sync_repo(repo)
end
end
end

View file

@ -1,3 +1,13 @@
defmodule Farmbot.Farmware.Supervisor do
@moduledoc false
use Supervisor
@doc false
def start_link do
Supervisor.start_link(__MODULE__, [], [name: __MODULE__])
end
def init([]) do
Supervisor.init([Farmbot.Farmware.Installer.Repository.SyncTask], strategy: :one_for_one)
end
end

View file

@ -4,11 +4,11 @@ defmodule Farmbot.HTTP.Supervisor do
use Supervisor
@doc false
def start_link(token, opts \\ []) do
Supervisor.start_link(__MODULE__, token, opts)
def start_link() do
Supervisor.start_link(__MODULE__, [], [name: __MODULE__])
end
def init(_token) do
def init([]) do
children = [
worker(Farmbot.HTTP, [])
]

View file

@ -3,9 +3,9 @@ defmodule Farmbot.Logger do
use GenStage
alias Farmbot.Log
@doc "Start Logging Services."
def start_link(opts \\ []) do
GenStage.start_link(__MODULE__, [], opts)
@doc false
def start_link() do
GenStage.start_link(__MODULE__, [], [name: __MODULE__])
end
def init([]) do

View file

@ -1,15 +1,16 @@
defmodule Farmbot.Repo.Supervisor do
@moduledoc "Hey!"
@moduledoc false
@repos [Farmbot.Repo.A, Farmbot.Repo.B]
use Supervisor
def start_link(token, opts \\ []) do
Supervisor.start_link(__MODULE__, token, opts)
@doc false
def start_link() do
Supervisor.start_link(__MODULE__, [], [name: __MODULE__])
end
def init(_token) do
def init([]) do
@repos
|> Enum.map(fn repo ->
supervisor(repo, [])

View file

@ -1,7 +0,0 @@
defmodule Farmbot.System.ConfigStorage.Migrations.AddDevicesTable do
use Ecto.Migration
def change do
end
end

View file

@ -0,0 +1,12 @@
defmodule Farmbot.System.ConfigStorage.Migrations.AddDevicesTable do
use Ecto.Migration
def change do
create table("farmware_repositories") do
add(:manifests, :text)
add(:url, :string)
end
create(unique_index("farmware_repositories", [:url]))
end
end

0
shell Normal file → Executable file
View file