mirror of
https://github.com/evennia/evennia.git
synced 2026-03-30 12:37:16 +02:00
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:
parent
7eaf3d221c
commit
7fb6362dc4
9 changed files with 153 additions and 30 deletions
|
|
@ -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__':
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
124
game/migrate.py
Executable 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()
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue