Commit | Line | Data |
---|---|---|
70b44584 | 1 | # GNU MediaGoblin -- federated, autonomous media hosting |
3ea1cf36 | 2 | # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. |
70b44584 CAW |
3 | # |
4 | # This program is free software: you can redistribute it and/or modify | |
5 | # it under the terms of the GNU Affero General Public License as published by | |
6 | # the Free Software Foundation, either version 3 of the License, or | |
7 | # (at your option) any later version. | |
8 | # | |
9 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU Affero General Public License for more details. | |
13 | # | |
14 | # You should have received a copy of the GNU Affero General Public License | |
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | ||
f46e2a4d JW |
17 | import logging |
18 | ||
c2059c4a | 19 | import six |
3ea1cf36 CAW |
20 | from sqlalchemy.orm import sessionmaker |
21 | ||
6eddc3b7 | 22 | from mediagoblin.db.open import setup_connection_and_db_from_config |
2064ad94 | 23 | from mediagoblin.db.migration_tools import MigrationManager, AlembicMigrationManager |
70b44584 CAW |
24 | from mediagoblin.init import setup_global_and_app_config |
25 | from mediagoblin.tools.common import import_component | |
26 | ||
f46e2a4d JW |
27 | _log = logging.getLogger(__name__) |
28 | logging.basicConfig() | |
7468c390 CAW |
29 | ## Let's not set the level as debug by default to avoid confusing users :) |
30 | # _log.setLevel(logging.DEBUG) | |
70b44584 | 31 | |
70b44584 | 32 | |
3ea1cf36 CAW |
33 | def dbupdate_parse_setup(subparser): |
34 | pass | |
35 | ||
36 | ||
70b44584 | 37 | class DatabaseData(object): |
08cd10d8 | 38 | def __init__(self, name, models, foundations, migrations): |
70b44584 CAW |
39 | self.name = name |
40 | self.models = models | |
08cd10d8 | 41 | self.foundations = foundations |
70b44584 CAW |
42 | self.migrations = migrations |
43 | ||
3ea1cf36 | 44 | def make_migration_manager(self, session): |
70b44584 | 45 | return MigrationManager( |
08cd10d8 | 46 | self.name, self.models, self.foundations, self.migrations, session) |
70b44584 CAW |
47 | |
48 | ||
58a94757 | 49 | def gather_database_data(plugins): |
70b44584 | 50 | """ |
8da8c0ac BB |
51 | Gather all database data relevant to the extensions installed. |
52 | ||
70b44584 CAW |
53 | Gather all database data relevant to the extensions we have |
54 | installed so we can do migrations and table initialization. | |
55 | ||
56 | Returns a list of DatabaseData objects. | |
57 | """ | |
58 | managed_dbdata = [] | |
59 | ||
60 | # Add main first | |
b0c8328e | 61 | from mediagoblin.db.models import MODELS as MAIN_MODELS |
95369884 | 62 | from mediagoblin.db.migrations import MIGRATIONS as MAIN_MIGRATIONS |
08cd10d8 | 63 | from mediagoblin.db.models import FOUNDATIONS as MAIN_FOUNDATIONS |
70b44584 CAW |
64 | |
65 | managed_dbdata.append( | |
66 | DatabaseData( | |
08cd10d8 | 67 | u'__main__', MAIN_MODELS, MAIN_FOUNDATIONS, MAIN_MIGRATIONS)) |
70b44584 | 68 | |
f46e2a4d JW |
69 | for plugin in plugins: |
70 | try: | |
71 | models = import_component('{0}.models:MODELS'.format(plugin)) | |
72 | except ImportError as exc: | |
73 | _log.debug('No models found for {0}: {1}'.format( | |
74 | plugin, | |
75 | exc)) | |
76 | ||
77 | models = [] | |
78 | except AttributeError as exc: | |
8da8c0ac BB |
79 | _log.warning('Could not find MODELS in {0}.models, have you ' |
80 | 'forgotten to add it? ({1})'.format(plugin, exc)) | |
0ae38290 | 81 | models = [] |
f46e2a4d JW |
82 | |
83 | try: | |
84 | migrations = import_component('{0}.migrations:MIGRATIONS'.format( | |
85 | plugin)) | |
86 | except ImportError as exc: | |
87 | _log.debug('No migrations found for {0}: {1}'.format( | |
88 | plugin, | |
89 | exc)) | |
90 | ||
91 | migrations = {} | |
92 | except AttributeError as exc: | |
8da8c0ac BB |
93 | _log.debug('Could not find MIGRATIONS in {0}.migrations, have you' |
94 | 'forgotten to add it? ({1})'.format(plugin, exc)) | |
0ae38290 | 95 | migrations = {} |
f46e2a4d | 96 | |
08cd10d8 | 97 | try: |
8da8c0ac BB |
98 | foundations = import_component( |
99 | '{0}.models:FOUNDATIONS'.format(plugin)) | |
08cd10d8 | 100 | except ImportError as exc: |
31de493e | 101 | foundations = {} |
08cd10d8 | 102 | except AttributeError as exc: |
08cd10d8 | 103 | foundations = {} |
104 | ||
f46e2a4d JW |
105 | if models: |
106 | managed_dbdata.append( | |
8da8c0ac | 107 | DatabaseData(plugin, models, foundations, migrations)) |
f46e2a4d | 108 | |
70b44584 CAW |
109 | return managed_dbdata |
110 | ||
111 | ||
65f20ca4 | 112 | def run_alembic_migrations(db, app_config, global_config): |
8da8c0ac | 113 | """Initialize a database and runs all Alembic migrations.""" |
65f20ca4 BP |
114 | Session = sessionmaker(bind=db.engine) |
115 | manager = AlembicMigrationManager(Session()) | |
116 | manager.init_or_migrate() | |
117 | ||
118 | ||
f46e2a4d | 119 | def run_dbupdate(app_config, global_config): |
70b44584 CAW |
120 | """ |
121 | Initialize or migrate the database as specified by the config file. | |
122 | ||
123 | Will also initialize or migrate all extensions (media types, and | |
124 | in the future, plugins) | |
125 | """ | |
4a698535 EL |
126 | # Set up the database |
127 | db = setup_connection_and_db_from_config(app_config, migrations=True) | |
4930c2ad | 128 | # Run the migrations |
4a698535 | 129 | run_all_migrations(db, app_config, global_config) |
c2059c4a CAW |
130 | |
131 | # TODO: Make this happen regardless of python 2 or 3 once ensured | |
132 | # to be "safe"! | |
133 | if six.PY3: | |
134 | run_alembic_migrations(db, app_config, global_config) | |
4a698535 EL |
135 | |
136 | ||
137 | def run_all_migrations(db, app_config, global_config): | |
8da8c0ac BB |
138 | """Initialize or migrates a database. |
139 | ||
31de493e | 140 | Initializes or migrates a database that already has a |
6db23bd9 EL |
141 | connection setup and also initializes or migrates all |
142 | extensions based on the config files. | |
143 | ||
144 | It can be used to initialize an in-memory database for | |
145 | testing. | |
4a698535 | 146 | """ |
70b44584 | 147 | # Gather information from all media managers / projects |
f46e2a4d | 148 | dbdatas = gather_database_data( |
8da8c0ac | 149 | list(global_config.get('plugins', {}).keys())) |
70b44584 | 150 | |
3ea1cf36 | 151 | Session = sessionmaker(bind=db.engine) |
70b44584 CAW |
152 | |
153 | # Setup media managers for all dbdata, run init/migrate and print info | |
154 | # For each component, create/migrate tables | |
155 | for dbdata in dbdatas: | |
3ea1cf36 | 156 | migration_manager = dbdata.make_migration_manager(Session()) |
70b44584 | 157 | migration_manager.init_or_migrate() |
d693f6bd CAW |
158 | |
159 | ||
160 | def dbupdate(args): | |
161 | global_config, app_config = setup_global_and_app_config(args.conf_file) | |
f46e2a4d | 162 | run_dbupdate(app_config, global_config) |