Work toward farmware/celeryscript stuff

* Fix logger erros
* Fix migrations
* Fix compile errors
* Fix tzdata child_spec
pull/974/head
connor rigby 2018-08-15 05:59:02 -07:00 committed by Connor Rigby
parent bdb11b2ea8
commit 10a4379568
No known key found for this signature in database
GPG Key ID: 29A88B24B70456E0
33 changed files with 250 additions and 102 deletions

View File

@ -79,18 +79,6 @@ defmodule Farmbot.CeleryScript.RunTime.InstructionSet do
@doc "Set environment variables for a Farmware."
simple_io_instruction(:set_user_env)
@doc "(Re)Install Farmware written and developed by Farmbot, Inc."
simple_io_instruction(:install_first_party_farmware)
@doc "Install a Farmware from the web."
simple_io_instruction(:install_farmware)
@doc "Remove a Farmware."
simple_io_instruction(:remove_farmware)
@doc "Update a Farmware."
simple_io_instruction(:update_farmware)
@doc "Force the bot's state to be dispatched."
simple_io_instruction(:read_status)

View File

@ -61,10 +61,6 @@ defmodule Farmbot.CeleryScript.RunTime.InstructionSetTest do
io_test("take_photo")
io_test("config_update")
io_test("set_user_env")
io_test("install_first_party_farmware")
io_test("install_farmware")
io_test("remove_farmware")
io_test("update_farmware")
io_test("read_status")
io_test("sync")
io_test("power_off")

View File

@ -10,6 +10,8 @@ defmodule Farmbot.Asset do
Device,
FarmEvent,
FarmwareEnv,
FarmwareInstallation,
Peripheral,
PinBinding,
Point,
@ -30,6 +32,8 @@ defmodule Farmbot.Asset do
@device_fields ~W(id name timezone)
@farm_events_fields ~W(calendar end_time executable_id executable_type id repeat start_time time_unit)
@farmware_envs_fields ~W(id key value)
@farmware_installations_fields ~W(id url first_party)
@peripherals_fields ~W(id label mode pin)
@pin_bindings_fields ~W(id pin_num sequence_id special_action)
@points_fields ~W(id meta name pointer_type tool_id x y z)
@ -45,6 +49,8 @@ defmodule Farmbot.Asset do
def to_asset(body, Device), do: resource_decode(body, @device_fields, Device)
def to_asset(body, FarmEvent), do: resource_decode(body, @farm_events_fields, FarmEvent)
def to_asset(body, FarmwareEnv), do: resource_decode(body, @farmware_envs_fields, FarmwareEnv)
def to_asset(body, FarmwareInstallation), do: resource_decode(body, @farmware_installations_fields, FarmwareInstallation)
def to_asset(body, Peripheral), do: resource_decode(body, @peripherals_fields, Peripheral)
def to_asset(body, PinBinding), do: resource_decode(body, @pin_bindings_fields, PinBinding)
def to_asset(body, Point), do: resource_decode(body, @points_fields, Point)
@ -66,6 +72,8 @@ defmodule Farmbot.Asset do
def string_to_atom({k, v}), do: {String.to_atom(k), v}
def into_struct(data, kind), do: struct(kind, data)
# TODO(Connor) - 2018-08-05 *_sync should upload dirty artifacts
# before applying sync commands?
def fragment_sync(verbosity \\ 1) do
Farmbot.Logger.busy verbosity, "Syncing"
Farmbot.Registry.dispatch(__MODULE__, {:sync_status, :syncing})
@ -161,7 +169,7 @@ defmodule Farmbot.Asset do
# When `body` is nil, it means an object was deleted.
def do_apply_sync_cmd(%{body: nil, remote_id: id, kind: kind}) do
mod = Module.concat(["Farmbot", "Asset", kind])
case Repo.get(mod, id) do
case Repo.one(from m in mod, where: m.id == ^id) do
nil ->
:ok
@ -175,7 +183,7 @@ defmodule Farmbot.Asset do
not_struct = strip_struct(obj)
mod = Module.concat(["Farmbot", "Asset", kind])
# We need to check if this object exists in the database.
case Repo.get(mod, id) do
case Repo.one(from m in mod, where: m.id == ^id) do
# If it does not, just return the newly created object.
nil ->
change = mod.changeset(struct(mod, not_struct), not_struct)
@ -273,8 +281,11 @@ defmodule Farmbot.Asset do
end
def clear_all_data do
# remote assets.
Repo.delete_all(Device)
Repo.delete_all(FarmEvent)
Repo.delete_all(FarmwareEnv)
Repo.delete_all(FarmwareInstallation)
Repo.delete_all(Peripheral)
Repo.delete_all(PinBinding)
Repo.delete_all(Point)
@ -282,6 +293,8 @@ defmodule Farmbot.Asset do
Repo.delete_all(Sensor)
Repo.delete_all(Sequence)
Repo.delete_all(Tool)
# Interanal assets.
Repo.delete_all(PersistentRegimen)
Repo.delete_all(SyncCmd)
:ok

View File

@ -8,7 +8,9 @@ defmodule Farmbot.Asset.Device do
use Ecto.Schema
import Ecto.Changeset
@primary_key {:local_id, :binary_id, autogenerate: true}
schema "devices" do
field(:id, :integer)
field(:name, :string)
field(:timezone, :string)
end

View File

@ -29,7 +29,9 @@ defmodule Farmbot.Asset.FarmEvent do
import Ecto.Changeset
require Farmbot.Logger
@primary_key {:local_id, :binary_id, autogenerate: true}
schema "farm_events" do
field(:id, :integer)
field(:start_time, :string)
field(:end_time, :string)
field(:repeat, :integer)

View File

@ -8,7 +8,9 @@ defmodule Farmbot.Asset.FarmwareEnv do
use Ecto.Schema
import Ecto.Changeset
schema "farmware_env" do
@primary_key {:local_id, :binary_id, autogenerate: true}
schema "farmware_envs" do
field(:id, :integer)
field(:key, :string)
field(:value, JSONType)
end

View File

@ -7,7 +7,10 @@ defmodule Farmbot.Asset.FarmwareInstallation do
use Ecto.Schema
import Ecto.Changeset
@primary_key {:local_id, :binary_id, autogenerate: true}
schema "farmware_installations" do
field(:id, :integer)
field(:first_party, :boolean)
field(:url, :string)
end

View File

@ -7,7 +7,9 @@ defmodule Farmbot.Asset.Peripheral do
use Ecto.Schema
import Ecto.Changeset
@primary_key {:local_id, :binary_id, autogenerate: true}
schema "peripherals" do
field(:id, :integer)
field(:pin, :integer)
field(:mode, :integer)
field(:label, :string)

View File

@ -5,7 +5,9 @@ defmodule Farmbot.Asset.PinBinding do
use Ecto.Schema
import Ecto.Changeset
@primary_key {:local_id, :binary_id, autogenerate: true}
schema "pin_bindings" do
field(:id, :integer)
field(:pin_num, :integer)
field(:sequence_id, :integer)
field(:special_action, :string)

View File

@ -7,7 +7,9 @@ defmodule Farmbot.Asset.Point do
alias Farmbot.EctoTypes.ModuleType
alias Farmbot.EctoTypes.TermType
@primary_key {:local_id, :binary_id, autogenerate: true}
schema "points" do
field(:id, :integer)
field(:name, :string)
field(:tool_id, :integer)
field(:x, :float)

View File

@ -11,7 +11,9 @@ defmodule Farmbot.Asset.Regimen do
use Ecto.Schema
import Ecto.Changeset
@primary_key {:local_id, :binary_id, autogenerate: true}
schema "regimens" do
field(:id, :integer)
field(:name, :string)
field(:farm_event_id, :integer, virtual: true)
field(:regimen_items, TermType)

View File

@ -7,7 +7,9 @@ defmodule Farmbot.Asset.Sensor do
use Ecto.Schema
import Ecto.Changeset
@primary_key {:local_id, :binary_id, autogenerate: true}
schema "sensors" do
field(:id, :integer)
field(:pin, :integer)
field(:mode, :integer)
field(:label, :string)

View File

@ -9,7 +9,9 @@ defmodule Farmbot.Asset.Sequence do
import Ecto.Changeset
require Farmbot.Logger
@primary_key {:local_id, :binary_id, autogenerate: true}
schema "sequences" do
field(:id, :integer)
field(:name, :string)
field(:kind, :string)
field(:args, TermType)

View File

@ -5,7 +5,9 @@ defmodule Farmbot.Asset.Tool do
use Ecto.Schema
import Ecto.Changeset
@primary_key {:local_id, :binary_id, autogenerate: true}
schema "tools" do
field(:id, :integer)
field(:name, :string)
end

View File

@ -23,10 +23,6 @@ defmodule Farmbot.Core.CeleryScript.IOLayer do
@callback take_photo(args, body) :: :ok | {:error, String.t}
@callback config_update(args, body) :: :ok | {:error, String.t}
@callback set_user_env(args, body) :: :ok | {:error, String.t}
@callback install_first_party_farmware(args, body) :: :ok | {:error, String.t}
@callback install_farmware(args, body) :: :ok | {:error, String.t}
@callback remove_farmware(args, body) :: :ok | {:error, String.t}
@callback update_farmware(args, body) :: :ok | {:error, String.t}
@callback read_status(args, body) :: :ok | {:error, String.t}
@callback sync(args, body) :: :ok | {:error, String.t}
@callback power_off(args, body) :: :ok | {:error, String.t}

View File

@ -12,8 +12,6 @@ defmodule Farmbot.Core.CeleryScript.StubIOLayer do
def factory_reset(_args, _body), do: {:error, "Stubbed"}
def find_home(_args, _body), do: {:error, "Stubbed"}
def home(_args, _body), do: {:error, "Stubbed"}
def install_farmware(_args, _body), do: {:error, "Stubbed"}
def install_first_party_farmware(_args, _body), do: {:error, "Stubbed"}
def move_absolute(_args, _body), do: {:error, "Stubbed"}
def move_relative(_args, _body), do: {:error, "Stubbed"}
def power_off(_args, _body), do: {:error, "Stubbed"}
@ -26,8 +24,6 @@ defmodule Farmbot.Core.CeleryScript.StubIOLayer do
def sync(_args, _body), do: {:error, "Stubbed"}
def take_photo(_args, _body), do: {:error, "Stubbed"}
def toggle_pin(_args, _body), do: {:error, "Stubbed"}
def remove_farmware(_args, _body), do: {:error, "Stubbed"}
def update_farmware(_args, _body), do: {:error, "Stubbed"}
def wait(_args, _body), do: {:error, "Stubbed"}
def write_pin(_args, _body), do: {:error, "Stubbed"}
def zero(_args, _body), do: {:error, "Stubbed"}

View File

@ -6,10 +6,24 @@ defmodule Farmbot.JSON.JasonParser do
def encode(data), do: Jason.encode(data)
require Protocol
# Bot State
Protocol.derive Jason.Encoder, Farmbot.BotState
Protocol.derive Jason.Encoder, Farmbot.BotState.Configuration
Protocol.derive Jason.Encoder, Farmbot.BotState.InformationalSettings
Protocol.derive Jason.Encoder, Farmbot.BotState.LocationData
Protocol.derive Jason.Encoder, Farmbot.BotState.McuParams
Protocol.derive Jason.Encoder, Farmbot.BotState.Pin
# Assets
Protocol.derive Jason.Encoder, Farmbot.Asset.Device
Protocol.derive Jason.Encoder, Farmbot.Asset.FarmEvent
Protocol.derive Jason.Encoder, Farmbot.Asset.FarmwareEnv
Protocol.derive Jason.Encoder, Farmbot.Asset.FarmwareInstallation
Protocol.derive Jason.Encoder, Farmbot.Asset.Peripheral
Protocol.derive Jason.Encoder, Farmbot.Asset.PinBinding
Protocol.derive Jason.Encoder, Farmbot.Asset.Point
Protocol.derive Jason.Encoder, Farmbot.Asset.Regimen
Protocol.derive Jason.Encoder, Farmbot.Asset.Sensor
Protocol.derive Jason.Encoder, Farmbot.Asset.Sequence
Protocol.derive Jason.Encoder, Farmbot.Asset.Tool
end

View File

@ -2,12 +2,12 @@ defmodule Farmbot.Asset.Repo.Migrations.CreateFarmwareEnvTable do
use Ecto.Migration
def change do
create table("farmware_env", primary_key: false) do
create table("farmware_envs", primary_key: false) do
add(:id, :integer)
add(:key, :string)
add(:value, :text)
end
create(unique_index("farmware_env", [:id]))
create(unique_index("farmware_envs", [:id]))
end
end

View File

@ -5,9 +5,9 @@ defmodule Farmbot.Asset.Repo.Migrations.CreateFarmwareInstallationsTable do
create table("farmware_installations", primary_key: false) do
add(:id, :integer)
add(:url, :string)
add(:first_party, :boolean)
end
create(unique_index("farmware_installations", [:id]))
end
create(unique_index("farmware_installations", [:id, :url]))
end
end

View File

@ -0,0 +1,65 @@
defmodule Farmbot.Asset.Repo.Migrations.AddLocalIdAndDirtyFields do
use Ecto.Migration
def change do
alter table("devices") do
add(:local_id, :uuid, primary: true)
add(:dirty, :boolean, default: false)
end
alter table("farm_events") do
add(:local_id, :uuid, primary: true)
add(:dirty, :boolean, default: false)
end
alter table("farmware_installations") do
add(:local_id, :uuid, primary: true)
add(:dirty, :boolean, default: false)
end
alter table("farmware_envs") do
add(:local_id, :uuid, primary: true)
add(:dirty, :boolean, default: false)
end
alter table("peripherals") do
add(:local_id, :uuid, primary: true)
add(:dirty, :boolean, default: false)
end
alter table("pin_bindings") do
add(:local_id, :uuid, primary: true)
add(:dirty, :boolean, default: false)
end
alter table("points") do
add(:local_id, :uuid, primary: true)
add(:dirty, :boolean, default: false)
end
alter table("regimens") do
add(:local_id, :uuid, primary: true)
add(:dirty, :boolean, default: false)
end
alter table("sensors") do
add(:local_id, :uuid, primary: true)
add(:dirty, :boolean, default: false)
end
alter table("sequences") do
add(:local_id, :uuid, primary: true)
add(:dirty, :boolean, default: false)
end
alter table("tools") do
add(:local_id, :uuid, primary: true)
add(:dirty, :boolean, default: false)
end
# TODO(Connor) - 2018-08-15 All things without a UUID will probably need one?
# However first HTTP sync will wipe out all assets, and redownload them
# So i guess not?
end
end

View File

@ -1,7 +1,6 @@
defmodule Farmbot.System.ConfigStorage.Migrations.AddIgnoreFwConfig do
use Ecto.Migration
import Farmbot.Config
import Farmbot.Config.MigrationHelpers
def change do
create_settings_config("ignore_fw_config", :bool, false)
end

View File

@ -1,16 +1,21 @@
defmodule Farmbot.HTTP.Error do
@moduledoc "Some Farmbot HTTP Adapter error."
alias Farmbot.HTTP.{Response}
alias Farmbot.HTTP.{Response, Error}
defexception [:message, :response]
@doc false
def exception(desc) when is_atom(desc) or is_binary(desc) do
%__MODULE__{message: String.trim(desc)}
%Error{message: String.trim(desc)}
end
def exception(%Response{status_code: code, body: body} = resp) do
%__MODULE__{message: "HTTP Request failed (#{code}) body: #{body}", response: resp}
case Farmbot.JSON.decode(body) do
{:ok, %{"error" => reason}} ->
%Error{message: "HTTP Request failed (#{code}) #{reason}", response: resp}
_ ->
%Error{message: "HTTP Request failed (#{code})", response: resp}
end
end
end

View File

@ -1,14 +1,19 @@
defmodule Farmbot.HTTP.Helpers do
@moduledoc """
Helpful stuff.
"""
@moduledoc false
@doc """
Helper for checking status codes
"""
@doc "Helper for checking status codes"
defmacro is_2xx(number) do
quote do
unquote(number) > 199 and unquote(number) < 300
end
end
# Defines a function to fetch and decode an api resource.
@doc "Helper to define fetch and decode resource function in Farmbot.HTTP"
defmacro fadr(plural, kind) do
quote do
def unquote(plural)(),
do: fetch_and_decode("/api/#{unquote(plural)}.json", unquote(kind))
end
end
end

View File

@ -5,6 +5,7 @@ defmodule Farmbot.HTTP do
use GenServer
alias Farmbot.HTTP.{Adapter, Error, Response}
import Farmbot.HTTP.Helpers
alias Farmbot.JSON
@adapter Application.get_env(:farmbot_ext, :behaviour)[:http_adapter]
@ -19,6 +20,8 @@ defmodule Farmbot.HTTP do
alias Farmbot.Asset.{
Device,
FarmEvent,
FarmwareEnv,
FarmwareInstallation,
Peripheral,
PinBinding,
Point,
@ -28,21 +31,63 @@ defmodule Farmbot.HTTP do
Tool,
}
def device, do: fetch_and_decode("/api/device.json", Device)
def farm_events, do: fetch_and_decode("/api/farm_events.json", FarmEvent)
def peripherals, do: fetch_and_decode("/api/peripherals.json", Peripheral)
def pin_bindings, do: fetch_and_decode("/api/pin_bindings.json", PinBinding)
def points, do: fetch_and_decode("/api/points.json", Point)
def regimens, do: fetch_and_decode("/api/regimens.json", Regimen)
def sensors, do: fetch_and_decode("/api/sensors.json", Sensor)
def sequences, do: fetch_and_decode("/api/sequences.json", Sequence)
def tools, do: fetch_and_decode("/api/tools.json", Tool)
fadr :device, Device
fadr :farm_events, FarmEvent
fadr :farmware_installations, FarmwareInstallation
# TODO(Connor) - 2018-08-15 Make this a macro if/when it starts
# happening more often.
def new_farmware_installation(%FarmwareInstallation{} = data) do
json = JSON.encode!(data)
case post("/api/farmware_installations", json) do
{:error, reason} -> {:error, reason}
{:ok, %{body: body, status_code: code}} when is_2xx(code) ->
r = body |> JSON.decode!() |> Farmbot.Asset.to_asset(FarmwareInstallation)
{:ok, r}
end
end
fadr :farmware_envs, FarmwareEnv
# TODO(Connor) - 2018-08-15 Make this a macro if/when it starts
# happening more often.
def new_farmware_env(%FarmwareEnv{} = data) do
json = JSON.encode!(data)
case post("/api/farmware_env", json) do
{:error, reason} -> {:error, reason}
{:ok, %{body: body, status_code: code}} when is_2xx(code) ->
r = body |> JSON.decode!() |> Farmbot.Asset.to_asset(FarmwareEnv)
{:ok, r}
end
end
fadr :peripherals, Peripheral
fadr :pin_bindings, PinBinding
fadr :points, Point
fadr :regimens, Regimen
fadr :sensors, Sensor
fadr :sequences, Sequence
fadr :tools, Tool
# These aren't synced.
def fbos_config, do: fetch("/api/fbos_config")
def firmware_config, do: fetch("/api/firmware_config")
@doc "Fetches data and decodes as JSON."
def fetch(url) do
url
|> get!([{"content-type", "Application/JSON"}])
|> case do
%{body: body, status_code: code} when is_2xx(code) -> body
_ -> raise "[#{url}] HTTP Error"
end
|> JSON.decode!()
end
@doc "Fetches a url and decodes as a Farmbot struct."
def fetch_and_decode(url, kind) do
url
|> get!()
|> Map.fetch!(:body)
|> JSON.decode!()
|> fetch()
|> Farmbot.Asset.to_asset(kind)
end

View File

@ -68,19 +68,11 @@ defmodule Farmbot.OS.IOLayer do
{:error, "config_update depreciated since 6.1.0"}
end
def set_user_env(_args, _body) do
IO.inspect {:error, "not implemented: set_user_env"}
def set_user_env(_args, pairs) do
IO.puts "not implemented: set_user_env(#{inspect pairs})"
:ok
end
def install_first_party_farmware(args, body), do: Farmware.first_party(args, body)
def install_farmware(args, body), do: Farmware.install(args, body)
def remove_farmware(args, body), do: Farmware.remove(args, body)
def update_farmware(args, body), do: Farmware.update(args, body)
def execute_script(args, body), do: Farmware.execute(args, body)
def take_photo(_args, body) do

View File

@ -1,14 +1,11 @@
defmodule Farmbot.OS.IOLayer.Farmware do
require Farmbot.Logger
alias Farmbot.OS.IOLayer.Farmware.Server
@fpf_url "https://raw.githubusercontent.com/FarmBot-Labs/farmware_manifests/master/manifest.json"
def first_party(_args, []) do
{:error, "not implemented"}
end
def install(%{url: u_rl}, []) do
def install(%{url: _url}, []) do
{:error, "not implemented"}
end

View File

@ -1,3 +0,0 @@
defmodule Farmbot.OS.IOLayer.Farmware.Server do
# use GenServer
end

View File

@ -6,6 +6,8 @@ defmodule Farmbot.OS.IOLayer.Sync do
alias Farmbot.Asset.{
Device,
FarmEvent,
# FarmwareEnv,
# FarmwareInstallation,
Peripheral,
PinBinding,
Point,
@ -29,6 +31,11 @@ defmodule Farmbot.OS.IOLayer.Sync do
[
Task.Supervisor.async_nolink(pid, fn -> {Device, HTTP.device() |> List.wrap() |> list_to_sync_cmds()} end),
Task.Supervisor.async_nolink(pid, fn -> {FarmEvent, HTTP.farm_events() |> list_to_sync_cmds()} end),
# These aren't a thing yet.
# Task.Supervisor.async_nolink(pid, fn -> {FarmwareEnv, HTTP.farmware_envs() |> list_to_sync_cmds()} end),
# Task.Supervisor.async_nolink(pid, fn -> {FarmwareInstallation, HTTP.farmware_installations() |> list_to_sync_cmds()} end),
Task.Supervisor.async_nolink(pid, fn -> {Peripheral, HTTP.peripherals() |> list_to_sync_cmds()} end),
Task.Supervisor.async_nolink(pid, fn -> {PinBinding, HTTP.pin_bindings() |> list_to_sync_cmds()} end),
Task.Supervisor.async_nolink(pid, fn -> {Point, HTTP.points() |> list_to_sync_cmds()} end),
@ -52,9 +59,7 @@ defmodule Farmbot.OS.IOLayer.Sync do
end
def to_sync_cmd(%kind{} = data) do
kind = Module.split(kind)
|> List.last()
kind = Module.split(kind) |> List.last()
Farmbot.Asset.new_sync_cmd(data.id, kind, data)
end
end

View File

@ -12,7 +12,8 @@ defmodule Farmbot.OS do
{Farmbot.Platform.Supervisor, []},
{Farmbot.System.UpdateTimer, []},
{Farmbot.System.ExtStart, []},
{Farmbot.EasterEggs, [] },
{Farmbot.EasterEggs, []},
{Farmbot.FarmwareMigration, []}
]
opts = [strategy: :one_for_one, name: __MODULE__]
Supervisor.start_link(children, opts)

View File

@ -2,16 +2,31 @@ defmodule Farmbot.FarmwareMigration do
# TODO(Connor) 2018-08-14 Delete this after 6.5.0 is released
import Farmbot.Config, only: [get_config_value: 3, update_config_value: 4]
require Farmbot.Logger
alias Farmbot.CeleryScript.AST
alias Farmbot.Asset.{FarmwareEnv, FarmwareInstallation}
@doc false
def child_spec(_) do
%{
id: __MODULE__,
start: {__MODULE__, :migrate, []},
type: :worker,
restart: :transient,
shutdown: 500
}
end
@data_path Application.get_env(:farmbot_ext, :data_path)
@farmware_dir Path.join(@data_path, "farmware")
def migrate do
File.mkdir_p(@farmware_dir)
if get_config_value(:bool, "settings", "firmware_needs_migration") do
Farmbot.Logger.busy 1, "Starting Farmware migration."
migrate_user_env()
migrate_farmware_installations()
update_config_value(:bool, "settings", "firmware_needs_migration", false)
Farmbot.Logger.success 1, "Farmware migrated to the API."
else
Farmbot.Logger.debug 3, "Farmware has already been migrated."
end
@ -27,30 +42,35 @@ defmodule Farmbot.FarmwareMigration do
LEFT JOIN string_values sv on sv.id == c.string_value_id
WHERE g.group_name == "settings"
"""
%{rows: [[value]]} = Ecto.Adapters.SQL.query!(Farmbot.Config.Repo, qry, [])
%{rows: [[value]]} = Ecto.Adapters.SQL.query!(Farmbot.Config.Repo, full_qry, [])
Ecto.Adapters.SQL.query!(Farmbot.System.ConfigStorage, qry, [])
data = Farmbot.JSON.decode!(value)
pairs = Enum.map(data, fn({key, value}) ->
%AST{kind: :pair, args: %{key: key, value: value}, body: []}
value
|> Farmbot.JSON.decode!()
|> Enum.map(fn({key, val}) ->
%FarmwareEnv{key: key, value: val}
end)
body = %AST{kind: :set_user_env, args: %{}, body: pairs}
rpc = %AST{kind: :rpc_request, args: %{label: "migrate_user_env"}, body: body}
Farmbot.Core.CeleryScript.rpc_request(rpc, &log_results/1)
|> Enum.each(fn(env) ->
case Farmbot.HTTP.new_farmware_env(env) do
{:ok, _} ->
Farmbot.Logger.success 1, "migration task: migrate_user_env '#{env.key}' completed."
{:error, _} ->
Farmbot.Logger.error 1, "migration task: migrate_user_env: '#{env.key}' failed."
end
end)
update_config_value(:string, "settings", "user_env", nil)
end
def migrate_farmware_installations do
# Migrate first party stuff.
qry = "SELECT manifests FROM farmware_repositories"
%{rows: rows} = Ecto.Adapters.SQL.query!(Farmbot.Config, qry, [])
%{rows: rows} = Ecto.Adapters.SQL.query!(Farmbot.Config.Repo, qry, [])
repos = Enum.map(rows, &Farmbot.JSON.decode/1)
migrated = repos |> Enum.map(&migrate_repo/1) |> List.flatten()
drop_qry = "DROP TABLE [IF EXISTS] farmware_repositories"
Ecto.Adapters.SQL.query!(Farmbot.Config, qry, [])
Ecto.Adapters.SQL.query!(Farmbot.Config.Repo, qry, [])
# Migrate installed farmwares.
@farmware_dir
@ -65,11 +85,11 @@ defmodule Farmbot.FarmwareMigration do
end
def migrate_repo(list, acc \\ [])
def migrate_repo([]), do: :ok
def migrate_repo([], acc), do: Enum.reverse(acc)
def migrate_repo([%{"manifest" => url, "name" => name} | rest], acc) do
first_party? = match?("https://raw.githubusercontent.com/FarmBot-Labs/farmware_manifests/master/" <> _, url)
data = Farmbot.JSON.encode(%{first_party: first_party?, url: url})
case Farmbot.HTTP.post("/api/farmware_installations/", data) do
data = %FarmwareInstallation{url: url, first_party: first_party?}
case Farmbot.HTTP.new_farmware_installation(data) do
{:ok, _} ->
Farmbot.Logger.success 1, "migration task: migrate_farmware '#{name}' completed."
{:error, _} ->
@ -77,13 +97,4 @@ defmodule Farmbot.FarmwareMigration do
end
migrate_repo(rest, [name | acc])
end
defp log_results(%AST{kind: :rpc_ok, args: %{label: label}}) do
Farmbot.Logger.success 1, "migration task: #{label} completed."
end
defp log_results(%AST{kind: :rpc_error, args: %{label: label}, body: [expl]}) do
%AST{kind: :explanation, args: %{message: message}} = message
Farmbot.Logger.error 1, "migration task: #{label} failed: #{message}"
end
end

View File

@ -2,6 +2,7 @@ defmodule Farmbot.System do
@moduledoc """
Common functionality that should be implemented by a system
"""
require Farmbot.Logger
require Farmbot.Logger

View File

@ -22,7 +22,6 @@ defmodule Farmbot.Target.Bootstrap.Configurator.Router do
end
@version Farmbot.Project.version()
@data_path Application.get_env(:farmbot_ext, :data_path)
@log_db Application.get_env(:logger_backend_ecto, LoggerBackendEcto.Repo)[:database]
@log_db || Mix.raise("LoggerBackendEcto probably not configured properly.")

View File

@ -4,8 +4,8 @@ defmodule Farmbot.Target.Network.TzdataTask do
@fb_data_dir Path.join(Application.get_env(:farmbot_ext, :data_path), "tmp_downloads")
@timer_ms round(1.2e+6) # 20 minutes
def start_link(_, _) do
GenServer.start_link(__MODULE__, [], [name: __MODULE__])
def start_link(args) do
GenServer.start_link(__MODULE__, args, [name: __MODULE__])
end
def init([]) do