New migration utility code.... I haven't tested this! ;)
I think it's looking right though. - Provides MigrationManager which should have plenty of utilities for doing migrations hopefully correctly :) - Provides RegisterMigration which should be able to decorate migrations and register them in doing so
This commit is contained in:
parent
9980c5f4f4
commit
51dcfb5682
@ -37,6 +37,11 @@ from mongokit import ObjectId
|
|||||||
from mediagoblin.db.indexes import ACTIVE_INDEXES, DEPRECATED_INDEXES
|
from mediagoblin.db.indexes import ACTIVE_INDEXES, DEPRECATED_INDEXES
|
||||||
|
|
||||||
|
|
||||||
|
################
|
||||||
|
# Indexing tools
|
||||||
|
################
|
||||||
|
|
||||||
|
|
||||||
def add_new_indexes(database, active_indexes=ACTIVE_INDEXES):
|
def add_new_indexes(database, active_indexes=ACTIVE_INDEXES):
|
||||||
"""
|
"""
|
||||||
Add any new indexes to the database.
|
Add any new indexes to the database.
|
||||||
@ -99,3 +104,134 @@ def remove_deprecated_indexes(database, deprecated_indexes=DEPRECATED_INDEXES):
|
|||||||
indexes_removed.append((collection_name, index_name))
|
indexes_removed.append((collection_name, index_name))
|
||||||
|
|
||||||
return indexes_removed
|
return indexes_removed
|
||||||
|
|
||||||
|
|
||||||
|
#################
|
||||||
|
# Migration tools
|
||||||
|
#################
|
||||||
|
|
||||||
|
# The default migration registry...
|
||||||
|
#
|
||||||
|
# Don't set this yourself! RegisterMigration will automatically fill
|
||||||
|
# this with stuff via decorating methods in migrations.py
|
||||||
|
|
||||||
|
MIGRATIONS = {}
|
||||||
|
|
||||||
|
|
||||||
|
class RegisterMigration(object):
|
||||||
|
def __init__(self, migration_number, migration_registry=MIGRATIONS):
|
||||||
|
self.migration_number = migration_number
|
||||||
|
self.migration_registry = migration_registry
|
||||||
|
|
||||||
|
def __call__(self, migration):
|
||||||
|
self.migration_registry[self.migration_number] = migration
|
||||||
|
return migration
|
||||||
|
|
||||||
|
|
||||||
|
class MigrationManager(object):
|
||||||
|
"""
|
||||||
|
Migration handling tool.
|
||||||
|
|
||||||
|
Takes information about a database, lets you update the database
|
||||||
|
to the latest migrations, etc.
|
||||||
|
"""
|
||||||
|
def __init__(self, database, migration_registry=MIGRATIONS):
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
- database: database we're going to migrate
|
||||||
|
- migration_registry: where we should find all migrations to
|
||||||
|
run
|
||||||
|
"""
|
||||||
|
self.database = database
|
||||||
|
self.migration_registry = migration_registry
|
||||||
|
self._sorted_migrations = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sorted_migrations(self):
|
||||||
|
"""
|
||||||
|
Sort migrations if necessary and store in self._sorted_migrations
|
||||||
|
"""
|
||||||
|
if not self._sorted_migrations:
|
||||||
|
self._sorted_migrations = sorted(
|
||||||
|
self.migration_registry.items(),
|
||||||
|
# sort on the key... the migration number
|
||||||
|
key=lambda migration_tuple: migration_tuple[0])
|
||||||
|
|
||||||
|
return self._sorted_migrations
|
||||||
|
|
||||||
|
def latest_migration(self):
|
||||||
|
"""
|
||||||
|
Return a tuple like:
|
||||||
|
(migration_number, migration_func)
|
||||||
|
|
||||||
|
Where migration_number is the number of the latest migration
|
||||||
|
and migration func is the actual function that would be run.
|
||||||
|
"""
|
||||||
|
return self.sorted_migrations[-1]
|
||||||
|
|
||||||
|
def set_current_migration(self, migration_number=None):
|
||||||
|
"""
|
||||||
|
Set the migration in the database to migration_number
|
||||||
|
"""
|
||||||
|
# Add the mediagoblin migration if necessary
|
||||||
|
self.database['app_metadata'].update(
|
||||||
|
{'_id': 'mediagoblin'},
|
||||||
|
{'$set': {'current_migration': migration_number}},
|
||||||
|
upsert=True)
|
||||||
|
|
||||||
|
def database_current_migration(self, install_if_missing=True):
|
||||||
|
"""
|
||||||
|
Return the current migration in the database.
|
||||||
|
"""
|
||||||
|
mgoblin_metadata = self.database['app_metadata'].find_one(
|
||||||
|
{'_id': 'mediagoblin'})
|
||||||
|
if not mgoblin_metadata:
|
||||||
|
if install_if_missing:
|
||||||
|
latest_migration = self.latest_migration()
|
||||||
|
self.set_current_migration(latest_migration)
|
||||||
|
return latest_migration
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return mgoblin_metadata['current_migration']
|
||||||
|
|
||||||
|
def database_at_latest_migration(self):
|
||||||
|
"""
|
||||||
|
See if the database is at the latest migration.
|
||||||
|
Returns a boolean.
|
||||||
|
"""
|
||||||
|
current_migration = self.database_current_migration()
|
||||||
|
return current_migration == self.latest_migration()
|
||||||
|
|
||||||
|
def migrations_to_run(self):
|
||||||
|
"""
|
||||||
|
Get a list of migrations to run still, if any.
|
||||||
|
"""
|
||||||
|
db_current_migration = self.database_current_migration()
|
||||||
|
return [
|
||||||
|
(migration_number, migration_func)
|
||||||
|
for migration_number, migration_func in self.sorted_migrations
|
||||||
|
if migration_number > db_current_migration]
|
||||||
|
|
||||||
|
def iteratively_migrate(self):
|
||||||
|
"""
|
||||||
|
Iteratively run all migrations.
|
||||||
|
|
||||||
|
Useful if you need to print some message about each migration
|
||||||
|
after you run it.
|
||||||
|
|
||||||
|
Each time you loop over this, it'll return the migration
|
||||||
|
number and migration function.
|
||||||
|
"""
|
||||||
|
for migration_number, migration_func in self.migrations_to_run():
|
||||||
|
migration_func(self.database)
|
||||||
|
self.set_current_migration(migration_number)
|
||||||
|
yield migration_number, migration_func
|
||||||
|
|
||||||
|
def run_outdated_migrations(self):
|
||||||
|
"""
|
||||||
|
Install all migrations that need to be installed, quietly.
|
||||||
|
"""
|
||||||
|
for migration_number, migration_func in self.iteratively_migrate():
|
||||||
|
# No need to say anything... we're just migrating iteratively.
|
||||||
|
pass
|
||||||
|
Loading…
x
Reference in New Issue
Block a user