Make mix tasks work in a release

This commit is contained in:
rinpatch 2019-06-08 17:40:40 +03:00
parent 4b98a7ce4e
commit d7ec0898e5
7 changed files with 128 additions and 58 deletions

View File

@ -10,19 +10,51 @@ def start_pleroma do
end end
def get_option(options, opt, prompt, defval \\ nil, defname \\ nil) do def get_option(options, opt, prompt, defval \\ nil, defname \\ nil) do
Keyword.get(options, opt) || Keyword.get(options, opt) || shell_prompt(prompt, defval, defname)
case Mix.shell().prompt("#{prompt} [#{defname || defval}]") do
"\n" ->
case defval do
nil -> get_option(options, opt, prompt, defval)
defval -> defval
end
opt ->
opt |> String.trim()
end
end end
def shell_prompt(prompt, defval \\ nil, defname \\ nil) do
prompt_message = "#{prompt} [#{defname || defval}]"
input =
if mix_shell?(),
do: Mix.shell().prompt(prompt_message),
else: :io.get_line(prompt_message)
case input do
"\n" ->
case defval do
nil ->
shell_prompt(prompt, defval, defname)
defval ->
defval
end
input ->
String.trim(input)
end
end
def shell_yes?(message) do
shell_prompt(message, "Yn") in ~w(Yn Y y)
end
def shell_info(message) do
if mix_shell?(),
do: Mix.shell().info(message),
else: IO.puts(message)
end
def shell_error(message) do
if mix_shell?(),
do: Mix.shell().error(message),
else: IO.puts(:stderr, message)
end
@doc "Performs a safe check whether `Mix.shell/0` is available (does not raise if Mix is not loaded)"
def mix_shell?, do: :erlang.function_exported(Mix, :shell, 0)
def escape_sh_path(path) do def escape_sh_path(path) do
~S(') <> String.replace(path, ~S('), ~S(\')) <> ~S(') ~S(') <> String.replace(path, ~S('), ~S(\')) <> ~S(')
end end

View File

@ -155,17 +155,17 @@ def run(["gen" | rest]) do
dbpass: dbpass dbpass: dbpass
) )
Mix.shell().info( Common.shell_info(
"Writing config to #{config_path}. You should rename it to config/prod.secret.exs or config/dev.secret.exs." "Writing config to #{config_path}. You should rename it to config/prod.secret.exs or config/dev.secret.exs."
) )
File.write(config_path, result_config) File.write(config_path, result_config)
Mix.shell().info("Writing #{psql_path}.") Common.shell_info("Writing #{psql_path}.")
File.write(psql_path, result_psql) File.write(psql_path, result_psql)
write_robots_txt(indexable) write_robots_txt(indexable)
Mix.shell().info( Common.shell_info(
"\n" <> "\n" <>
""" """
To get started: To get started:
@ -179,7 +179,7 @@ def run(["gen" | rest]) do
end end
) )
else else
Mix.shell().error( Common.shell_error(
"The task would have overwritten the following files:\n" <> "The task would have overwritten the following files:\n" <>
(Enum.map(paths, &"- #{&1}\n") |> Enum.join("")) <> (Enum.map(paths, &"- #{&1}\n") |> Enum.join("")) <>
"Rerun with `--force` to overwrite them." "Rerun with `--force` to overwrite them."
@ -204,10 +204,10 @@ defp write_robots_txt(indexable) do
if File.exists?(robots_txt_path) do if File.exists?(robots_txt_path) do
File.cp!(robots_txt_path, "#{robots_txt_path}.bak") File.cp!(robots_txt_path, "#{robots_txt_path}.bak")
Mix.shell().info("Backing up existing robots.txt to #{robots_txt_path}.bak") Common.shell_info("Backing up existing robots.txt to #{robots_txt_path}.bak")
end end
File.write(robots_txt_path, robots_txt) File.write(robots_txt_path, robots_txt)
Mix.shell().info("Writing #{robots_txt_path}.") Common.shell_info("Writing #{robots_txt_path}.")
end end
end end

View File

@ -30,7 +30,7 @@ def run(["follow", target]) do
# put this task to sleep to allow the genserver to push out the messages # put this task to sleep to allow the genserver to push out the messages
:timer.sleep(500) :timer.sleep(500)
else else
{:error, e} -> Mix.shell().error("Error while following #{target}: #{inspect(e)}") {:error, e} -> Common.shell_error("Error while following #{target}: #{inspect(e)}")
end end
end end
@ -41,7 +41,7 @@ def run(["unfollow", target]) do
# put this task to sleep to allow the genserver to push out the messages # put this task to sleep to allow the genserver to push out the messages
:timer.sleep(500) :timer.sleep(500)
else else
{:error, e} -> Mix.shell().error("Error while following #{target}: #{inspect(e)}") {:error, e} -> Common.shell_error("Error while following #{target}: #{inspect(e)}")
end end
end end
end end

View File

@ -38,10 +38,10 @@ def run(["migrate_local", target_uploader | args]) do
Pleroma.Config.put([Upload, :uploader], uploader) Pleroma.Config.put([Upload, :uploader], uploader)
end end
Mix.shell().info("Migrating files from local #{local_path} to #{to_string(uploader)}") Common.shell_info("Migrating files from local #{local_path} to #{to_string(uploader)}")
if delete? do if delete? do
Mix.shell().info( Common.shell_info(
"Attention: uploaded files will be deleted, hope you have backups! (--delete ; cancel with ^C)" "Attention: uploaded files will be deleted, hope you have backups! (--delete ; cancel with ^C)"
) )
@ -78,7 +78,7 @@ def run(["migrate_local", target_uploader | args]) do
|> Enum.filter(& &1) |> Enum.filter(& &1)
total_count = length(uploads) total_count = length(uploads)
Mix.shell().info("Found #{total_count} uploads") Common.shell_info("Found #{total_count} uploads")
uploads uploads
|> Task.async_stream( |> Task.async_stream(
@ -90,7 +90,7 @@ def run(["migrate_local", target_uploader | args]) do
:ok :ok
error -> error ->
Mix.shell().error("failed to upload #{inspect(upload.path)}: #{inspect(error)}") Common.shell_error("failed to upload #{inspect(upload.path)}: #{inspect(error)}")
end end
end, end,
timeout: 150_000 timeout: 150_000
@ -99,10 +99,10 @@ def run(["migrate_local", target_uploader | args]) do
# credo:disable-for-next-line Credo.Check.Warning.UnusedEnumOperation # credo:disable-for-next-line Credo.Check.Warning.UnusedEnumOperation
|> Enum.reduce(0, fn done, count -> |> Enum.reduce(0, fn done, count ->
count = count + length(done) count = count + length(done)
Mix.shell().info("Uploaded #{count}/#{total_count} files") Common.shell_info("Uploaded #{count}/#{total_count} files")
count count
end) end)
Mix.shell().info("Done!") Common.shell_info("Done!")
end end
end end

View File

@ -115,7 +115,7 @@ def run(["new", nickname, email | rest]) do
admin? = Keyword.get(options, :admin, false) admin? = Keyword.get(options, :admin, false)
assume_yes? = Keyword.get(options, :assume_yes, false) assume_yes? = Keyword.get(options, :assume_yes, false)
Mix.shell().info(""" Common.shell_info("""
A user will be created with the following information: A user will be created with the following information:
- nickname: #{nickname} - nickname: #{nickname}
- email: #{email} - email: #{email}
@ -128,7 +128,7 @@ def run(["new", nickname, email | rest]) do
- admin: #{if(admin?, do: "true", else: "false")} - admin: #{if(admin?, do: "true", else: "false")}
""") """)
proceed? = assume_yes? or Mix.shell().yes?("Continue?") proceed? = assume_yes? or Common.shell_yes?("Continue?")
if proceed? do if proceed? do
Common.start_pleroma() Common.start_pleroma()
@ -145,7 +145,7 @@ def run(["new", nickname, email | rest]) do
changeset = User.register_changeset(%User{}, params, need_confirmation: false) changeset = User.register_changeset(%User{}, params, need_confirmation: false)
{:ok, _user} = User.register(changeset) {:ok, _user} = User.register(changeset)
Mix.shell().info("User #{nickname} created") Common.shell_info("User #{nickname} created")
if moderator? do if moderator? do
run(["set", nickname, "--moderator"]) run(["set", nickname, "--moderator"])
@ -159,7 +159,7 @@ def run(["new", nickname, email | rest]) do
run(["reset_password", nickname]) run(["reset_password", nickname])
end end
else else
Mix.shell().info("User will not be created.") Common.shell_info("User will not be created.")
end end
end end
@ -168,10 +168,10 @@ def run(["rm", nickname]) do
with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do
User.perform(:delete, user) User.perform(:delete, user)
Mix.shell().info("User #{nickname} deleted.") Common.shell_info("User #{nickname} deleted.")
else else
_ -> _ ->
Mix.shell().error("No local user #{nickname}") Common.shell_error("No local user #{nickname}")
end end
end end
@ -181,12 +181,12 @@ def run(["toggle_activated", nickname]) do
with %User{} = user <- User.get_cached_by_nickname(nickname) do with %User{} = user <- User.get_cached_by_nickname(nickname) do
{:ok, user} = User.deactivate(user, !user.info.deactivated) {:ok, user} = User.deactivate(user, !user.info.deactivated)
Mix.shell().info( Common.shell_info(
"Activation status of #{nickname}: #{if(user.info.deactivated, do: "de", else: "")}activated" "Activation status of #{nickname}: #{if(user.info.deactivated, do: "de", else: "")}activated"
) )
else else
_ -> _ ->
Mix.shell().error("No user #{nickname}") Common.shell_error("No user #{nickname}")
end end
end end
@ -195,7 +195,7 @@ def run(["reset_password", nickname]) do
with %User{local: true} = user <- User.get_cached_by_nickname(nickname), with %User{local: true} = user <- User.get_cached_by_nickname(nickname),
{:ok, token} <- Pleroma.PasswordResetToken.create_token(user) do {:ok, token} <- Pleroma.PasswordResetToken.create_token(user) do
Mix.shell().info("Generated password reset token for #{user.nickname}") Common.shell_info("Generated password reset token for #{user.nickname}")
IO.puts( IO.puts(
"URL: #{ "URL: #{
@ -208,7 +208,7 @@ def run(["reset_password", nickname]) do
) )
else else
_ -> _ ->
Mix.shell().error("No local user #{nickname}") Common.shell_error("No local user #{nickname}")
end end
end end
@ -216,7 +216,7 @@ def run(["unsubscribe", nickname]) do
Common.start_pleroma() Common.start_pleroma()
with %User{} = user <- User.get_cached_by_nickname(nickname) do with %User{} = user <- User.get_cached_by_nickname(nickname) do
Mix.shell().info("Deactivating #{user.nickname}") Common.shell_info("Deactivating #{user.nickname}")
User.deactivate(user) User.deactivate(user)
{:ok, friends} = User.get_friends(user) {:ok, friends} = User.get_friends(user)
@ -224,7 +224,7 @@ def run(["unsubscribe", nickname]) do
Enum.each(friends, fn friend -> Enum.each(friends, fn friend ->
user = User.get_cached_by_id(user.id) user = User.get_cached_by_id(user.id)
Mix.shell().info("Unsubscribing #{friend.nickname} from #{user.nickname}") Common.shell_info("Unsubscribing #{friend.nickname} from #{user.nickname}")
User.unfollow(user, friend) User.unfollow(user, friend)
end) end)
@ -233,11 +233,11 @@ def run(["unsubscribe", nickname]) do
user = User.get_cached_by_id(user.id) user = User.get_cached_by_id(user.id)
if Enum.empty?(user.following) do if Enum.empty?(user.following) do
Mix.shell().info("Successfully unsubscribed all followers from #{user.nickname}") Common.shell_info("Successfully unsubscribed all followers from #{user.nickname}")
end end
else else
_ -> _ ->
Mix.shell().error("No user #{nickname}") Common.shell_error("No user #{nickname}")
end end
end end
@ -274,7 +274,7 @@ def run(["set", nickname | rest]) do
end end
else else
_ -> _ ->
Mix.shell().error("No local user #{nickname}") Common.shell_error("No local user #{nickname}")
end end
end end
@ -284,10 +284,10 @@ def run(["tag", nickname | tags]) do
with %User{} = user <- User.get_cached_by_nickname(nickname) do with %User{} = user <- User.get_cached_by_nickname(nickname) do
user = user |> User.tag(tags) user = user |> User.tag(tags)
Mix.shell().info("Tags of #{user.nickname}: #{inspect(tags)}") Common.shell_info("Tags of #{user.nickname}: #{inspect(tags)}")
else else
_ -> _ ->
Mix.shell().error("Could not change user tags for #{nickname}") Common.shell_error("Could not change user tags for #{nickname}")
end end
end end
@ -297,10 +297,10 @@ def run(["untag", nickname | tags]) do
with %User{} = user <- User.get_cached_by_nickname(nickname) do with %User{} = user <- User.get_cached_by_nickname(nickname) do
user = user |> User.untag(tags) user = user |> User.untag(tags)
Mix.shell().info("Tags of #{user.nickname}: #{inspect(tags)}") Common.shell_info("Tags of #{user.nickname}: #{inspect(tags)}")
else else
_ -> _ ->
Mix.shell().error("Could not change user tags for #{nickname}") Common.shell_error("Could not change user tags for #{nickname}")
end end
end end
@ -326,7 +326,7 @@ def run(["invite" | rest]) do
with {:ok, val} <- options[:expires_at], with {:ok, val} <- options[:expires_at],
options = Map.put(options, :expires_at, val), options = Map.put(options, :expires_at, val),
{:ok, invite} <- UserInviteToken.create_invite(options) do {:ok, invite} <- UserInviteToken.create_invite(options) do
Mix.shell().info( Common.shell_info(
"Generated user invite token " <> String.replace(invite.invite_type, "_", " ") "Generated user invite token " <> String.replace(invite.invite_type, "_", " ")
) )
@ -340,14 +340,14 @@ def run(["invite" | rest]) do
IO.puts(url) IO.puts(url)
else else
error -> error ->
Mix.shell().error("Could not create invite token: #{inspect(error)}") Common.shell_error("Could not create invite token: #{inspect(error)}")
end end
end end
def run(["invites"]) do def run(["invites"]) do
Common.start_pleroma() Common.start_pleroma()
Mix.shell().info("Invites list:") Common.shell_info("Invites list:")
UserInviteToken.list_invites() UserInviteToken.list_invites()
|> Enum.each(fn invite -> |> Enum.each(fn invite ->
@ -361,7 +361,7 @@ def run(["invites"]) do
" | Max use: #{max_use} Left use: #{max_use - invite.uses}" " | Max use: #{max_use} Left use: #{max_use - invite.uses}"
end end
Mix.shell().info( Common.shell_info(
"ID: #{invite.id} | Token: #{invite.token} | Token type: #{invite.invite_type} | Used: #{ "ID: #{invite.id} | Token: #{invite.token} | Token type: #{invite.invite_type} | Used: #{
invite.used invite.used
}#{expire_info}#{using_info}" }#{expire_info}#{using_info}"
@ -374,9 +374,9 @@ def run(["revoke_invite", token]) do
with {:ok, invite} <- UserInviteToken.find_by_token(token), with {:ok, invite} <- UserInviteToken.find_by_token(token),
{:ok, _} <- UserInviteToken.update_invite(invite, %{used: true}) do {:ok, _} <- UserInviteToken.update_invite(invite, %{used: true}) do
Mix.shell().info("Invite for token #{token} was revoked.") Common.shell_info("Invite for token #{token} was revoked.")
else else
_ -> Mix.shell().error("No invite found with token #{token}") _ -> Common.shell_error("No invite found with token #{token}")
end end
end end
@ -385,10 +385,10 @@ def run(["delete_activities", nickname]) do
with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do
{:ok, _} = User.delete_user_activities(user) {:ok, _} = User.delete_user_activities(user)
Mix.shell().info("User #{nickname} statuses deleted.") Common.shell_info("User #{nickname} statuses deleted.")
else else
_ -> _ ->
Mix.shell().error("No local user #{nickname}") Common.shell_error("No local user #{nickname}")
end end
end end
@ -400,10 +400,10 @@ def run(["toggle_confirmed", nickname]) do
message = if user.info.confirmation_pending, do: "needs", else: "doesn't need" message = if user.info.confirmation_pending, do: "needs", else: "doesn't need"
Mix.shell().info("#{nickname} #{message} confirmation.") Common.shell_info("#{nickname} #{message} confirmation.")
else else
_ -> _ ->
Mix.shell().error("No local user #{nickname}") Common.shell_error("No local user #{nickname}")
end end
end end
@ -416,7 +416,7 @@ defp set_moderator(user, value) do
{:ok, user} = User.update_and_set_cache(user_cng) {:ok, user} = User.update_and_set_cache(user_cng)
Mix.shell().info("Moderator status of #{user.nickname}: #{user.info.is_moderator}") Common.shell_info("Moderator status of #{user.nickname}: #{user.info.is_moderator}")
user user
end end
@ -429,7 +429,7 @@ defp set_admin(user, value) do
{:ok, user} = User.update_and_set_cache(user_cng) {:ok, user} = User.update_and_set_cache(user_cng)
Mix.shell().info("Admin status of #{user.nickname}: #{user.info.is_admin}") Common.shell_info("Admin status of #{user.nickname}: #{user.info.is_admin}")
user user
end end
@ -442,7 +442,7 @@ defp set_locked(user, value) do
{:ok, user} = User.update_and_set_cache(user_cng) {:ok, user} = User.update_and_set_cache(user_cng)
Mix.shell().info("Locked status of #{user.nickname}: #{user.info.locked}") Common.shell_info("Locked status of #{user.nickname}: #{user.info.locked}")
user user
end end
end end

View File

@ -0,0 +1,38 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.ReleaseTasks do
def run(args) do
[task | args] = String.split(args)
case task do
"migrate" -> migrate(args)
task -> mix_task(task, args)
end
end
defp mix_task(task, args) do
# Modules are not loaded before application starts
Mix.Tasks.Pleroma.Common.start_pleroma()
{:ok, modules} = :application.get_key(:pleroma, :modules)
module =
Enum.find(modules, fn module ->
module = Module.split(module)
match?(["Mix", "Tasks", "Pleroma" | _], module) and
String.downcase(List.last(module)) == task
end)
if module do
module.run(args)
else
IO.puts("The task #{task} does not exist")
end
end
defp migrate(_args) do
:noop
end
end

View File

@ -2,4 +2,4 @@
# XXX: This should be removed when elixir's releases get custom command support # XXX: This should be removed when elixir's releases get custom command support
SCRIPT=$(readlink -f "$0") SCRIPT=$(readlink -f "$0")
SCRIPTPATH=$(dirname "$SCRIPT") SCRIPTPATH=$(dirname "$SCRIPT")
$SCRIPTPATH/pleroma eval 'Pleroma.ReleaseTasks.mix_task("'"$*"'")' $SCRIPTPATH/pleroma eval 'Pleroma.ReleaseTasks.run("'"$*"'")'