Added optional support for database migrations with south. The game/migrate.py program is a simple wrapper that runs the suitable commands for setting up a database and updating it, respectively.

This commit is contained in:
Griatch 2010-10-31 18:21:23 +00:00
parent 7eaf3d221c
commit 7fb6362dc4
9 changed files with 153 additions and 30 deletions

View file

@ -162,7 +162,6 @@ def stop_server(parser, options, args):
else:
print '\n\rUnknown OS detected, can not stop. '
def main():
"""
Beginning of the program logic.
@ -176,14 +175,14 @@ def main():
dest='interactive',
help='Start in daemon mode (default)')
(options, args) = parser.parse_args()
if "start" in args:
if options.interactive:
start_interactive(parser, options, args)
else:
start_daemon(parser, options, args)
elif "stop" in args:
stop_server(parser, options, args)
stop_server(parser, options, args)
else:
parser.print_help()
if __name__ == '__main__':

View file

@ -165,7 +165,7 @@ class CmdListScripts(MuxCommand):
else:
table[1].append(script.obj.key)
table[2].append(script.key)
if not hasattr(script, 'interval') or not script.interval:
if not hasattr(script, 'interval') or script.interval < 0:
table[3].append("--")
else:
table[3].append("%ss" % script.interval)

View file

@ -95,9 +95,7 @@ from src.settings_default import *
print """
Welcome to Evennia (version %s)!
Created a fresh settings.py file for you.""" % VERSION
We created a fresh settings.py file for you.""" % VERSION
try:
from game import settings

124
game/migrate.py Executable file
View file

@ -0,0 +1,124 @@
#!/usr/bin/env python
"""
Database migration helper, using South.
Usage:
- Install South using the method suitable for your platform
http://south.aeracode.org/docs/installation.html
- You need to have a database setup, either an old one or
a fresh one. If the latter, run manage.py syncdb as normal,
entering superuser info etc.
- Start this tool and use the 'initialize' option. South will
create a migration scheme for all Evennia components.
That's all you need to do until Evennia's database scheme changes,
something which is usually announced with the update. To update
your current database automatically, follow these steps:
- Run this tool
- Select the Update option.
That is all. :)
For more advanced migrations, there might be further instructions.
"""
import os, sys
from subprocess import call
# Set the Python path up so we can get to settings.py from here.
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
os.environ['DJANGO_SETTINGS_MODULE'] = 'game.settings'
if not os.path.exists('settings.py'):
# make sure we have a settings.py file.
print " No settings.py file found. Launching manage.py ..."
import game.manage
print """
Now configure Evennia by editing your new settings.py file.
If you haven't already, you should also create/configure the
database with 'python manage.py syncdb' before continuing."""
sys.exit()
# Get the settings
from django.conf import settings
# Prepare all valid apps
APPLIST = [app.split('.')[-1] for app in settings.INSTALLED_APPS
if app.startswith("src.") or app.startswith("game.")]
def run_south(mode):
"""
Simply call manage.py with the appropriate South commands.
"""
if mode == "init":
for appname in APPLIST:
print "Initializing %s ..." % appname
call(["python", "manage.py", "convert_to_south", appname])
print "\nInitialization complete. That's all you need to do for now."
elif mode == "update":
for appname in APPLIST:
print "Updating/migrating schema for %s ..." % appname
call(["python", "manage.py", "schemamigration", appname, "--auto"])
call(["python", "manage.py", "migrate", appname])
print "\nUpdate complete."
def south_ui():
"""
Simple menu for handling migrations.
"""
string = """
Evennia Database Migration Tool
You usually don't need to use this tool unless a new version of Evennia tells you that
the database scheme changed in some way, AND you don't want to reset your database.
This tool will help you to migrate an existing database without having to manually edit
your tables and fields to match the new scheme. For that to work you must have run this
tool *before* applying the changes however.
This is a simple wrapper on top of South, a Django database scheme migration tool.
If you want more control, you can call manage.py directly using the instructions
found at http://south.aeracode.org/docs.
NOTE: Evennia is still in Alpha - there is no guarantee that database changes will still
not be too advanced to handle with this simple tool, and it is too soon to talk
of supplying custom migration schemes to new versions.
Options:
i - Initialize an existing/fresh database with migration mappings (done once)
u - Update an initialized database to the changed scheme
q - Quit
"""
while True:
print string
inp = str(raw_input(" Option > "))
inp = inp.lower()
if inp in ["q", "i", "u"]:
if inp == 'i':
run_south("init")
elif inp == 'u':
run_south("update")
sys.exit()
if __name__ == "__main__":
if not 'south' in settings.INSTALLED_APPS:
string = "\n The 'south' database migration tool does not seem to be installed."
string += "\n You can find it here: http://south.aeracide.org.\n"
print string
else:
south_ui()

View file

@ -129,7 +129,7 @@ class ObjectDB(TypedObject):
# comma-separated list of alias-names of this object. Note that default
# searches only search aliases in the same location as caller.
db_aliases = models.ForeignKey(Alias, db_index=True, blank=True, null=True)
db_aliases = models.ForeignKey(Alias, blank=True, null=True, db_index=True)
# If this is a character object, the player is connected here.
db_player = models.ForeignKey("players.PlayerDB", blank=True, null=True)
# The location in the game world. Since this one is likely

View file

@ -48,7 +48,7 @@ class ScriptHandler(object):
interval = "inf"
next_repeat = "inf"
repeats = "inf"
if script.interval:
if script.interval > 0:
interval = script.interval
if script.repeats:
repeats = script.repeats

View file

@ -441,8 +441,8 @@ try:
except ImportError:
pass
# South handles automatic database scheme migrations when evennia updates
#try:
# import south
# INSTALLED_APPS = INSTALLED_APPS + ('south',)
#except ImportError:
# pass
try:
import south
INSTALLED_APPS = INSTALLED_APPS + ('south',)
except ImportError:
pass

View file

@ -4,17 +4,17 @@ from django.db.models.base import Model, ModelBase
from manager import SharedMemoryManager
TCACHE = {}
TCACHE = {} # test cache, for debugging /Griatch
class SharedMemoryModelBase(ModelBase):
def __new__(cls, name, bases, attrs):
super_new = super(ModelBase, cls).__new__
parents = [b for b in bases if isinstance(b, SharedMemoryModelBase)]
if not parents:
# If this isn't a subclass of Model, don't do anything special.
return super_new(cls, name, bases, attrs)
return super(SharedMemoryModelBase, cls).__new__(cls, name, bases, attrs)
#def __new__(cls, name, bases, attrs):
# super_new = super(ModelBase, cls).__new__
# parents = [b for b in bases if isinstance(b, SharedMemoryModelBase)]
# if not parents:
# # If this isn't a subclass of Model, don't do anything special.
# print "not a subclass of Model", name, bases
# return super_new(cls, name, bases, attrs)
# return super(SharedMemoryModelBase, cls).__new__(cls, name, bases, attrs)
def __call__(cls, *args, **kwargs):
"""
@ -49,6 +49,9 @@ class SharedMemoryModel(Model):
# subclass now?
__metaclass__ = SharedMemoryModelBase
class Meta:
abstract = True
def _get_cache_key(cls, args, kwargs):
"""
This method is used by the caching subsystem to infer the PK value from the constructor arguments.

View file

@ -21,22 +21,21 @@ def reload_modules():
"""
Reload modules that don't have any variables that can be reset.
Note that python reloading is a tricky art and strange things have
been known to happen if debugging and reloading a lot while
working with src/ modules. A cold reboot is often needed
eventually.
been known to happen if debugging and reloading a lot. A server
cold reboot is often needed eventually.
"""
# We protect e.g. src/ from reload since reloading it in a running
# server can create unexpected results (and besides, we should
# never need to do that anyway. Updating src requires a server
# reboot).
# server can create unexpected results (and besides, non-evennia devs
# should never need to do that anyway). Updating src requires a server
# reboot.
protected_dirs = ('src.',)
# flag 'dangerous' typeclasses (those which retain a memory
# reference, notably Scripts with a timer component) for
# non-reload, since these cannot be safely cleaned from memory
# without causing havoc. A server reboot is required for updating
# these.
# these (or killing all running, timed scripts).
unsafe_modules = []
for scriptobj in ScriptDB.objects.get_all_scripts():
if (scriptobj.interval > -1) and scriptobj.typeclass_path: