Merge branch 'config-behaviours-runtime' into 'develop'

Config/Docs: Expand behaviour suggestions modules at runtime

Closes #1941

See merge request pleroma/pleroma!2755
This commit is contained in:
feld 2020-07-13 15:45:25 +00:00
commit 5d215fd81f
7 changed files with 47 additions and 41 deletions

View file

@ -23,18 +23,14 @@ config :pleroma, :config_description, [
key: :uploader, key: :uploader,
type: :module, type: :module,
description: "Module which will be used for uploads", description: "Module which will be used for uploads",
suggestions: [Pleroma.Uploaders.Local, Pleroma.Uploaders.S3] suggestions: {:list_behaviour_implementations, Pleroma.Uploaders.Uploader}
}, },
%{ %{
key: :filters, key: :filters,
type: {:list, :module}, type: {:list, :module},
description: description:
"List of filter modules for uploads. Module names are shortened (removed leading `Pleroma.Upload.Filter.` part), but on adding custom module you need to use full name.", "List of filter modules for uploads. Module names are shortened (removed leading `Pleroma.Upload.Filter.` part), but on adding custom module you need to use full name.",
suggestions: suggestions: {:list_behaviour_implementations, Pleroma.Upload.Filter}
Generator.list_modules_in_dir(
"lib/pleroma/upload/filter",
"Elixir.Pleroma.Upload.Filter."
)
}, },
%{ %{
key: :link_name, key: :link_name,
@ -1405,11 +1401,7 @@ config :pleroma, :config_description, [
type: [:module, {:list, :module}], type: [:module, {:list, :module}],
description: description:
"A list of MRF policies enabled. Module names are shortened (removed leading `Pleroma.Web.ActivityPub.MRF.` part), but on adding custom module you need to use full name.", "A list of MRF policies enabled. Module names are shortened (removed leading `Pleroma.Web.ActivityPub.MRF.` part), but on adding custom module you need to use full name.",
suggestions: suggestions: {:list_behaviour_implementations, Pleroma.Web.ActivityPub.MRF}
Generator.list_modules_in_dir(
"lib/pleroma/web/activity_pub/mrf",
"Elixir.Pleroma.Web.ActivityPub.MRF."
)
}, },
%{ %{
key: :transparency, key: :transparency,

View file

@ -42,6 +42,7 @@ defmodule Pleroma.Application do
Pleroma.ApplicationRequirements.verify!() Pleroma.ApplicationRequirements.verify!()
setup_instrumenters() setup_instrumenters()
load_custom_modules() load_custom_modules()
Pleroma.Docs.JSON.compile()
adapter = Application.get_env(:tesla, :adapter) adapter = Application.get_env(:tesla, :adapter)

View file

@ -6,16 +6,21 @@ defmodule Pleroma.Docs.Generator do
implementation.process(descriptions) implementation.process(descriptions)
end end
@spec list_modules_in_dir(String.t(), String.t()) :: [module()] @spec list_behaviour_implementations(behaviour :: module()) :: [module()]
def list_modules_in_dir(dir, start) do def list_behaviour_implementations(behaviour) do
with {:ok, files} <- File.ls(dir) do :code.all_loaded()
files |> Enum.filter(fn {module, _} ->
|> Enum.filter(&String.ends_with?(&1, ".ex")) # This shouldn't be needed as all modules are expected to have module_info/1,
|> Enum.map(fn filename -> # but in test enviroments some transient modules `:elixir_compiler_XX`
module = filename |> String.trim_trailing(".ex") |> Macro.camelize() # are loaded for some reason (where XX is a random integer).
String.to_atom(start <> module) if function_exported?(module, :module_info, 1) do
end) module.module_info(:attributes)
|> Keyword.get_values(:behaviour)
|> List.flatten()
|> Enum.member?(behaviour)
end end
end)
|> Enum.map(fn {module, _} -> module end)
end end
@doc """ @doc """
@ -87,6 +92,12 @@ defmodule Pleroma.Docs.Generator do
else: string else: string
end end
defp format_suggestions({:list_behaviour_implementations, behaviour}) do
behaviour
|> list_behaviour_implementations()
|> format_suggestions()
end
defp format_suggestions([]), do: [] defp format_suggestions([]), do: []
defp format_suggestions([suggestion | tail]) do defp format_suggestions([suggestion | tail]) do

View file

@ -1,5 +1,19 @@
defmodule Pleroma.Docs.JSON do defmodule Pleroma.Docs.JSON do
@behaviour Pleroma.Docs.Generator @behaviour Pleroma.Docs.Generator
@external_resource "config/description.exs"
@raw_config Pleroma.Config.Loader.read("config/description.exs")
@raw_descriptions @raw_config[:pleroma][:config_description]
@term __MODULE__.Compiled
@spec compile :: :ok
def compile do
:persistent_term.put(@term, Pleroma.Docs.Generator.convert_to_strings(@raw_descriptions))
end
@spec compiled_descriptions :: Map.t()
def compiled_descriptions do
:persistent_term.get(@term)
end
@spec process(keyword()) :: {:ok, String.t()} @spec process(keyword()) :: {:ok, String.t()}
def process(descriptions) do def process(descriptions) do
@ -13,11 +27,4 @@ defmodule Pleroma.Docs.JSON do
{:ok, path} {:ok, path}
end end
end end
def compile do
with config <- Pleroma.Config.Loader.read("config/description.exs") do
config[:pleroma][:config_description]
|> Pleroma.Docs.Generator.convert_to_strings()
end
end
end end

View file

@ -68,6 +68,11 @@ defmodule Pleroma.Docs.Markdown do
IO.write(file, " #{list_mark}`#{inspect(suggestion)}`\n") IO.write(file, " #{list_mark}`#{inspect(suggestion)}`\n")
end end
defp print_suggestions(file, {:list_behaviour_implementations, behaviour}) do
suggestions = Pleroma.Docs.Generator.list_behaviour_implementations(behaviour)
print_suggestions(file, suggestions)
end
defp print_suggestions(_file, nil), do: nil defp print_suggestions(_file, nil), do: nil
defp print_suggestions(_file, ""), do: nil defp print_suggestions(_file, ""), do: nil

View file

@ -9,8 +9,6 @@ defmodule Pleroma.Web.AdminAPI.ConfigController do
alias Pleroma.ConfigDB alias Pleroma.ConfigDB
alias Pleroma.Plugs.OAuthScopesPlug alias Pleroma.Plugs.OAuthScopesPlug
@descriptions Pleroma.Docs.JSON.compile()
plug(Pleroma.Web.ApiSpec.CastAndValidate) plug(Pleroma.Web.ApiSpec.CastAndValidate)
plug(OAuthScopesPlug, %{scopes: ["write"], admin: true} when action == :update) plug(OAuthScopesPlug, %{scopes: ["write"], admin: true} when action == :update)
@ -25,7 +23,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigController do
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.Admin.ConfigOperation defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.Admin.ConfigOperation
def descriptions(conn, _params) do def descriptions(conn, _params) do
descriptions = Enum.filter(@descriptions, &whitelisted_config?/1) descriptions = Enum.filter(Pleroma.Docs.JSON.compiled_descriptions(), &whitelisted_config?/1)
json(conn, descriptions) json(conn, descriptions)
end end

View file

@ -13,21 +13,13 @@ defmodule Pleroma.Docs.GeneratorTest do
key: :uploader, key: :uploader,
type: :module, type: :module,
description: "", description: "",
suggestions: suggestions: {:list_behaviour_implementations, Pleroma.Upload.Filter}
Generator.list_modules_in_dir(
"lib/pleroma/upload/filter",
"Elixir.Pleroma.Upload.Filter."
)
}, },
%{ %{
key: :filters, key: :filters,
type: {:list, :module}, type: {:list, :module},
description: "", description: "",
suggestions: suggestions: {:list_behaviour_implementations, Pleroma.Web.ActivityPub.MRF}
Generator.list_modules_in_dir(
"lib/pleroma/web/activity_pub/mrf",
"Elixir.Pleroma.Web.ActivityPub.MRF."
)
}, },
%{ %{
key: Pleroma.Upload, key: Pleroma.Upload,