diff --git a/game/evennia.py b/game/evennia.py index 136ba787af..6b34172417 100755 --- a/game/evennia.py +++ b/game/evennia.py @@ -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__': diff --git a/game/gamesrc/commands/default/system.py b/game/gamesrc/commands/default/system.py index 1f337be084..c8dd9e0193 100644 --- a/game/gamesrc/commands/default/system.py +++ b/game/gamesrc/commands/default/system.py @@ -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) diff --git a/game/manage.py b/game/manage.py index 328e0c1599..93610f900d 100755 --- a/game/manage.py +++ b/game/manage.py @@ -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 diff --git a/game/migrate.py b/game/migrate.py new file mode 100755 index 0000000000..ead37f0748 --- /dev/null +++ b/game/migrate.py @@ -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() + diff --git a/src/objects/models.py b/src/objects/models.py index 42cf1a8f1e..3472412965 100644 --- a/src/objects/models.py +++ b/src/objects/models.py @@ -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 diff --git a/src/scripts/scripthandler.py b/src/scripts/scripthandler.py index 031c90bcce..608409e897 100644 --- a/src/scripts/scripthandler.py +++ b/src/scripts/scripthandler.py @@ -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 diff --git a/src/settings_default.py b/src/settings_default.py index bad65fe3d3..eaefaa050b 100644 --- a/src/settings_default.py +++ b/src/settings_default.py @@ -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 diff --git a/src/utils/idmapper/base.py b/src/utils/idmapper/base.py index f4cc200f7d..37d635b859 100755 --- a/src/utils/idmapper/base.py +++ b/src/utils/idmapper/base.py @@ -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. diff --git a/src/utils/reloads.py b/src/utils/reloads.py index d7d7e05239..78c56c9368 100644 --- a/src/utils/reloads.py +++ b/src/utils/reloads.py @@ -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: