plugins.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. # -*- coding: utf-8 -*-
  2. """
  3. flaskbb.cli.plugins
  4. ~~~~~~~~~~~~~~~~~~~
  5. This module contains all plugin commands.
  6. :copyright: (c) 2016 by the FlaskBB Team.
  7. :license: BSD, see LICENSE for more details.
  8. """
  9. import sys
  10. import click
  11. from flask import current_app
  12. from flask.cli import with_appcontext
  13. from flaskbb.extensions import db
  14. from flaskbb.cli.main import flaskbb
  15. from flaskbb.cli.utils import validate_plugin, check_cookiecutter
  16. from flaskbb.plugins.models import PluginRegistry, PluginStore
  17. from flaskbb.plugins.utils import remove_zombie_plugins_from_db
  18. @flaskbb.group()
  19. def plugins():
  20. """Plugins command sub group. If you want to run migrations or do some
  21. i18n stuff checkout the corresponding command sub groups."""
  22. pass
  23. @plugins.command("list")
  24. @with_appcontext
  25. def list_plugins():
  26. """Lists all installed plugins."""
  27. enabled_plugins = current_app.pluggy.list_plugin_distinfo()
  28. if len(enabled_plugins) > 0:
  29. click.secho("[+] Enabled Plugins:", fg="blue", bold=True)
  30. for plugin in enabled_plugins:
  31. p_mod = plugin[0]
  32. p_dist = plugin[1]
  33. click.secho("\t- {}\t({}), version {}".format(
  34. current_app.pluggy.get_name(p_mod).title(), p_dist.key,
  35. p_dist.version), bold=True
  36. )
  37. disabled_plugins = current_app.pluggy.list_disabled_plugins()
  38. if len(disabled_plugins) > 0:
  39. click.secho("[+] Disabled Plugins:", fg="yellow", bold=True)
  40. for plugin in disabled_plugins:
  41. p_mod = plugin[0]
  42. p_dist = plugin[1]
  43. click.secho("\t- {}\t({}), version {}".format(
  44. p_mod.title(), p_dist.key,
  45. p_dist.version), bold=True
  46. )
  47. @plugins.command("enable")
  48. @click.argument("plugin_name")
  49. @with_appcontext
  50. def enable_plugin(plugin_name):
  51. """Enables a plugin."""
  52. validate_plugin(plugin_name)
  53. plugin = PluginRegistry.query.filter_by(name=plugin_name).first_or_404()
  54. if plugin.enabled:
  55. click.secho("Plugin '{}' is already enabled.".format(plugin.name))
  56. plugin.enabled = True
  57. plugin.save()
  58. click.secho("[+] Plugin '{}' enabled.".format(plugin.name), fg="green")
  59. @plugins.command("disable")
  60. @click.argument("plugin_name")
  61. @with_appcontext
  62. def disable_plugin(plugin_name):
  63. """Disables a plugin."""
  64. validate_plugin(plugin_name)
  65. plugin = PluginRegistry.query.filter_by(name=plugin_name).first_or_404()
  66. if not plugin.enabled:
  67. click.secho("Plugin '{}' is already disabled.".format(plugin.name))
  68. plugin.enabled = False
  69. plugin.save()
  70. click.secho("[+] Plugin '{}' disabled.".format(plugin.name), fg="green")
  71. @plugins.command("install")
  72. @click.argument("plugin_name")
  73. @click.option("--force", "-f", default=False, is_flag=True,
  74. help="Overwrites existing settings")
  75. def install(plugin_name, force):
  76. """Installs a plugin (no migrations)."""
  77. validate_plugin(plugin_name)
  78. plugin = PluginRegistry.query.filter_by(name=plugin_name).first_or_404()
  79. if not plugin.enabled:
  80. click.secho("[+] Can't install disabled plugin. "
  81. "Enable '{}' Plugin first.".format(plugin.name), fg="red")
  82. sys.exit(0)
  83. if plugin.is_installable:
  84. plugin_module = current_app.pluggy.get_plugin(plugin.name)
  85. plugin.add_settings(plugin_module.SETTINGS, force)
  86. click.secho("[+] Plugin has been installed.", fg="green")
  87. else:
  88. click.secho("[+] Nothing to install.", fg="green")
  89. @plugins.command("uninstall")
  90. @click.argument("plugin_name")
  91. def uninstall(plugin_name):
  92. """Uninstalls a plugin (no migrations)."""
  93. validate_plugin(plugin_name)
  94. plugin = PluginRegistry.query.filter_by(name=plugin_name).first_or_404()
  95. if plugin.is_installed:
  96. PluginStore.query.filter_by(plugin_id=plugin.id).delete()
  97. db.session.commit()
  98. click.secho("[+] Plugin has been uninstalled.", fg="green")
  99. else:
  100. click.secho("[+] Nothing to uninstall.", fg="green")
  101. @plugins.command("cleanup")
  102. @with_appcontext
  103. def cleanup():
  104. """Removes zombie plugins from FlaskBB.
  105. A zombie plugin is a plugin
  106. which exists in the database but isn't installed in the env anymore.
  107. """
  108. deleted_plugins = remove_zombie_plugins_from_db()
  109. if len(deleted_plugins) > 0:
  110. click.secho("[+] Removed following zombie plugins from FlaskBB: ",
  111. fg="green", nl=False)
  112. click.secho("{}".format(", ".join(deleted_plugins)))
  113. else:
  114. click.secho("[+] No zombie plugins found.", fg="green")
  115. @plugins.command("new")
  116. @click.argument("plugin_name", callback=check_cookiecutter)
  117. @click.option("--template", "-t", type=click.STRING,
  118. default="https://github.com/sh4nks/cookiecutter-flaskbb-plugin",
  119. help="Path to a cookiecutter template or to a valid git repo.")
  120. @click.option("--out-dir", "-o", type=click.STRING,
  121. help="The location for the new FlaskBB plugin.")
  122. def new_plugin(plugin_name, template, out_dir):
  123. """Creates a new plugin based on the cookiecutter plugin
  124. template. Defaults to this template:
  125. https://github.com/sh4nks/cookiecutter-flaskbb-plugin.
  126. It will either accept a valid path on the filesystem
  127. or a URL to a Git repository which contains the cookiecutter template.
  128. """
  129. from cookiecutter.main import cookiecutter # noqa
  130. cookiecutter(template, output_dir=out_dir)
  131. click.secho("[+] Created new plugin {} in {}".format(plugin_name, out_dir),
  132. fg="green", bold=True)