Просмотр исходного кода

Add option to run plugin migrations for the default plugins

Peter Justin 7 лет назад
Родитель
Сommit
4ab2b792a9
4 измененных файлов с 74 добавлено и 23 удалено
  1. 5 0
      flaskbb/app.py
  2. 28 20
      flaskbb/cli/main.py
  3. 9 0
      flaskbb/plugins/manager.py
  4. 32 3
      flaskbb/utils/populate.py

+ 5 - 0
flaskbb/app.py

@@ -58,6 +58,7 @@ from flaskbb.utils.search import (ForumWhoosheer, PostWhoosheer,
 from flaskbb.utils.settings import flaskbb_config
 from flaskbb.utils.translations import FlaskBBDomain
 
+
 logger = logging.getLogger(__name__)
 
 
@@ -424,6 +425,10 @@ def load_plugins(app):
     except (OperationalError, ProgrammingError) as exc:
         logger.debug("Database is not setup correctly or has not been "
                      "setup yet.", exc_info=exc)
+        # load plugins even though the database isn't setup correctly
+        # i.e. when creating the initial database and wanting to install
+        # the plugins migration as well
+        app.pluggy.load_setuptools_entrypoints('flaskbb_plugins')
         return
 
     for plugin in plugins:

+ 28 - 20
flaskbb/cli/main.py

@@ -8,35 +8,35 @@
     :copyright: (c) 2016 by the FlaskBB Team.
     :license: BSD, see LICENSE for more details.
 """
-import sys
+import binascii
+import logging
 import os
+import sys
 import time
-import requests
-import binascii
 import traceback
-import logging
 from datetime import datetime
 
 import click
 import click_log
+import requests
 from celery.bin.celery import CeleryCommand
-from werkzeug.utils import import_string
-from jinja2 import Environment, FileSystemLoader
 from flask import current_app
 from flask.cli import FlaskGroup, ScriptInfo, with_appcontext
-from sqlalchemy_utils.functions import database_exists
 from flask_alembic import alembic_click
+from jinja2 import Environment, FileSystemLoader
+from sqlalchemy_utils.functions import database_exists
+from werkzeug.utils import import_string
 
 from flaskbb import create_app
-from flaskbb.extensions import db, whooshee, celery, alembic
-from flaskbb.cli.utils import (prompt_save_user, prompt_config_path,
-                               write_config, get_version, FlaskBBCLIError,
-                               EmailType)
-from flaskbb.utils.populate import (create_test_data, create_welcome_forum,
-                                    create_default_groups,
-                                    create_default_settings, insert_bulk_data,
-                                    update_settings_from_fixture,
-                                    create_latest_db)
+from flaskbb.cli.utils import (EmailType, FlaskBBCLIError, get_version,
+                               prompt_config_path, prompt_save_user,
+                               write_config)
+from flaskbb.extensions import alembic, celery, db, whooshee
+from flaskbb.utils.populate import (create_default_groups,
+                                    create_default_settings, create_latest_db,
+                                    create_test_data, create_welcome_forum,
+                                    insert_bulk_data, run_plugin_migrations,
+                                    update_settings_from_fixture)
 from flaskbb.utils.translations import compile_translations
 
 
@@ -125,8 +125,10 @@ flaskbb.add_command(alembic_click, "db")
 @click.option("--email", "-e", type=EmailType(),
               help="The email address of the user.")
 @click.option("--password", "-p", help="The password of the user.")
+@click.option("--no-plugins", "-n", default=False, is_flag=True,
+              help="Don't run the migrations for the default plugins.")
 @with_appcontext
-def install(welcome, force, username, email, password):
+def install(welcome, force, username, email, password, no_plugins):
     """Installs flaskbb. If no arguments are used, an interactive setup
     will be run.
     """
@@ -154,6 +156,10 @@ def install(welcome, force, username, email, password):
         click.secho("[+] Creating welcome forum...", fg="cyan")
         create_welcome_forum()
 
+    if not no_plugins:
+        click.secho("[+] Installing default plugins...", fg="cyan")
+        run_plugin_migrations()
+
     click.secho("[+] Compiling translations...", fg="cyan")
     compile_translations()
 
@@ -187,6 +193,7 @@ def populate(bulk_data, test_data, posts, topics, force, initdb):
     if initdb:
         click.secho("[+] Initializing database...", fg="cyan")
         create_latest_db()
+        run_plugin_migrations()
 
     if test_data:
         click.secho("[+] Adding some test data...", fg="cyan")
@@ -243,9 +250,10 @@ def upgrade(all_latest, fixture, force):
         count = update_settings_from_fixture(
             fixture=settings, overwrite_group=force, overwrite_setting=force
         )
-        click.secho("[+] {settings} settings in {groups} setting groups updated.".format(
-            groups=len(count), settings=sum(len(settings) for settings in count.values())), fg="green"
-        )
+        click.secho("[+] {settings} settings in {groups} setting groups "
+                    "updated.".format(groups=len(count), settings=sum(
+                        len(settings) for settings in count.values())
+                    ), fg="green")
 
 
 @flaskbb.command("download-emojis")

+ 9 - 0
flaskbb/plugins/manager.py

@@ -16,6 +16,7 @@ from pkg_resources import (DistributionNotFound, VersionConflict,
 
 from flaskbb.utils.helpers import parse_pkg_metadata
 
+
 logger = logging.getLogger(__name__)
 
 
@@ -149,3 +150,11 @@ class FlaskBBPluginManager(pluggy.PluginManager):
     def get_disabled_plugins(self):
         """Returns a list with disabled plugins."""
         return self._disabled_plugins.keys()
+
+    def get_internal_plugins(self):
+        """Returns a set of registered internal plugins."""
+        return set(self._internal_name2plugin.values())
+
+    def get_external_plugins(self):
+        """Returns a set of registered external plugins."""
+        return set(self.get_plugins() - self.get_internal_plugins())

+ 32 - 3
flaskbb/utils/populate.py

@@ -12,12 +12,17 @@ from __future__ import unicode_literals
 
 import collections
 import logging
+import os
+
+from flask import current_app
+from sqlalchemy_utils.functions import create_database, database_exists
+from alembic.util.exc import CommandError
 
 from flaskbb.extensions import alembic, db
 from flaskbb.forum.models import Category, Forum, Post, Topic
 from flaskbb.management.models import Setting, SettingsGroup
 from flaskbb.user.models import Group, User
-from sqlalchemy_utils.functions import create_database, database_exists
+
 
 logger = logging.getLogger(__name__)
 
@@ -382,14 +387,38 @@ def insert_bulk_data(topic_count=10, post_count=100):
     return created_topics, created_posts
 
 
-def create_latest_db():
+def create_latest_db(target="default@head"):
     """Creates the database including the schema using SQLAlchemy's
     db.create_all method instead of going through all the database revisions.
     The revision will be set to 'head' which indicates the latest alembic
     revision.
+
+    :param target: The target branch. Defaults to 'default@head'.
     """
     if not database_exists(db.engine.url):
         create_database(db.engine.url)
 
     db.create_all()
-    alembic.stamp()
+    alembic.stamp(target=target)
+
+
+def run_plugin_migrations(plugins=None):
+    """Runs the migrations for a list of plugins.
+
+    :param plugins: A iterable of plugins to run the migrations for. If set
+                    to ``None``, all external plugin migrations will be run.
+    """
+    if plugins is None:
+        plugins = current_app.pluggy.get_external_plugins()
+
+    for plugin in plugins:
+        plugin_name = current_app.pluggy.get_name(plugin)
+        if not os.path.exists(os.path.join(plugin.__path__[0], "migrations")):
+            logger.debug("No migrations found for plugin %s" % plugin_name)
+            continue
+        try:
+            alembic.upgrade(target="{}@head".format(plugin_name))
+        except CommandError as exc:
+            logger.debug("Couldn't run migrations for plugin {} because of "
+                         "following exception: ".format(plugin_name),
+                         exc_info=exc)