defmodule Mix.Tasks.Arke.ExportData do @moduledoc """ Export data from a given project in the database and save them in json file. It exports, by default, all the arkes,groups, parameters and permissions ## Examples $ mix arke.export_data --project my_project1 --p myproject2 $ mix arke.export_data --project my_project --arke ## Command line options * `--project` - The id of the project used to export data. * `--arke` - Export only the arkes * `--group` - Export only the groups * `--parameter` - Export only the parameters * `--split_file` - Write different files for arkes,groups,parameters and links * `--persistence` - The persistence to use. One of: * `arke_postgres` - via https://github.com/elixir-ecto/postgrex (Default) """ use Mix.Task alias Arke.QueryManager alias Arke.LinkManager alias Arke.Utils.ErrorGenerator, as: Error alias Arke.Boundary.{ArkeManager} alias Arke.Core.Unit @decode_keys [:arke, :parameter, :group, :link] @shortdoc "Export data from a project" @persistence_repo ["arke_postgres"] @switches [ project: :string, arke: :boolean, parameter: :boolean, splitfile: :boolean, group: :boolean, persistence: :string, ] @aliases [ p: :project, a: :arke, g: :group, sf: :splitfile, pr: :parameter, ps: :persistence, ] @impl true def run(args) do case OptionParser.parse!(args, strict: @switches, aliases: @aliases) do {[], _opts}-> Mix.Tasks.Help.run(["arke.export_data"]) {opts, []} -> persistence = parse_persistence!(opts[:persistence] || "arke_postgres") app_to_start(persistence) ++ [:arke] |> Enum.each(&Application.ensure_all_started/1) repo_module = Application.get_env(:arke, :persistence)[String.to_atom(persistence)][:repo] Mix.shell().info("--- Starting repo --- ") case start_repo!(repo_module) do {:ok, pid} -> opts |> export_data(persistence) Process.exit(pid, :normal) :ok {:error, _} -> opts |> export_data(persistence) :ok end end end defp app_to_start("arke_postgres"), do: [:ecto_sql, :postgrex] defp parse_persistence!(ps) when ps in @persistence_repo, do: ps defp parse_persistence!(ps), do: Mix.raise("Invalid persistence: `#{ps}`\nSupported persistence are: #{Enum.join(@persistence_repo, " | ")}") defp write_to_file(project,arke_id,data) do {:ok, datetime} = Arke.Utils.DatetimeHandler.now(:datetime) |> Arke.Utils.DatetimeHandler.format("{ISO:Basic:Z}") dir_path = "export/arke_export_data/#{project}/#{datetime}" arke_id_str = to_string(arke_id) path = "#{dir_path}/#{arke_id_str}.json" Mix.shell().info("--- Writing data to #{path} for #{arke_id_str} --- ") File.mkdir_p!(dir_path) {:ok, body} = Jason.encode(data) {:ok, file} = File.open(path, [:append]) IO.write(file, body) File.close(file) end defp start_repo!(nil), do: Mix.raise("Invalid repo module in arke configuration. Please provide a valid module accordingly to the persistence supported") # this is for arke_postgres defp start_repo!(repo_module) do repo_module.start_link() end defp start_manager!(nil), do: Mix.raise("Missing `init` function in arke.persistence configuration. Please provide a valid function accordingly to the persistence supported") # this is for arke_postgres defp start_manager!(function), do: function.() defp export_data(opts,persistence) do start_manager!(Application.get_env(:arke, :persistence)[String.to_atom(persistence)][:init]) project = String.to_atom(opts[:project]) || :arke_system split_file = opts[:splitfile] || false export_data = Arke.Utils.Export.get_db_structure(project, opts) if split_file do write_to_file(project,:arke,%{arke: export_data.arke}) write_to_file(project,:group,%{group: export_data.group}) write_to_file(project,:parameter,%{parameter: export_data.parameter}) write_to_file(project,:link,%{link: export_data.link}) else write_to_file(project,:all, export_data) end Mix.shell().info("--- All data has been exported. Keep in mind that if you want to use them in the `arke.seed_project` task you must move them under the `registry` folder --- ") end end