diff --git a/mixins.py b/mixins.py index e4ddb81258..d26c38c376 100644 --- a/mixins.py +++ b/mixins.py @@ -1,18 +1,20 @@ - +""" +The ReloadMixin class is meant as an example, but should work +for basic purposes as a mixin inheritance. +""" class ReloadMixin(): + """ + This class is a generic reload mixin providing the two + methods required to cache and reload an object. + """ def cache(self, reloader, do_save=True): - cache_dict = {} if do_save: if self.save and callable(self.save): self.save() else: - raise ValueError("This object does not have a save function, you must pass save=False for this object type.") + raise ValueError("This object does not have a save function, you must pass do_save=False for this object type.") - for key, value in self.__dict__.iteritems(): - if not callable(value): - cache_dict[key] = value - - reloader(self, cache_dict) + reloader.cache_object(self) def reload(self, cache): for key, value in cache.iteritems(): diff --git a/reload/__init__.py b/reload/__init__.py new file mode 100644 index 0000000000..b5fc2d28f6 --- /dev/null +++ b/reload/__init__.py @@ -0,0 +1,5 @@ +""" +Reloader module for handling @reload. +""" + +from managers import ReloadManager as manager diff --git a/reload/config.py b/reload/config.py new file mode 100644 index 0000000000..bfce26855f --- /dev/null +++ b/reload/config.py @@ -0,0 +1,27 @@ +""" +Configuration file for the reload system to add custom +modules to be reloaded at @reload. +""" + +# All of these are reloaded after the built-in system modules and default +# model modules are reloaded. + +# These are custom modules that have classes requiring state-saving. +# These modules are reloaded before those in no_cache. +cache = { + # This should be a dict of lists of tuples + # with the module name as a key, a list of tuples + # with the class name as the first element of the + # tuple, and True or False if this is a model + # for the database, like so: + # + # 'modulename' : [ ('ModelA', True), ('ClassA', False) ], + # 'anothermod' : [ ('ClassB', False), ('ClassC', False) ], + } + +# This is a list of modules that need to be reloaded at @reload. There +# is no state-saving, and these are reloaded after those cached above. +no_cache = [ + # 'modulename', + # 'anothermod', + ] diff --git a/reload/managers.py b/reload/managers.py new file mode 100644 index 0000000000..45cb48fb1b --- /dev/null +++ b/reload/managers.py @@ -0,0 +1,51 @@ +import functions_general + +class ReloadManager(object): + objects_cache = {} + failed = [] + + models = {} + + def __init__(self, server): + self.server = server + + def do_cache(self): + for module, info in self.models.iteritems(): + module_obj = __import__(module) + for ituple in info: + mclass = getattr(module_obj, info[0]) + for instance in mclass.__instances__(): + instance.cache(self, do_save=ituple[1]) + + def do_reload(self): + self.do_cache() + self.server.reload() + self.reload_objects() + + def cache_object(self, obj): + obj_dict = {} + for key, value in obj.__dict__.iteritems(): + if not callable(obj[key]): + obj_dict[key] = value + + self.objects_cache[obj] = obj_dict + + def reload_objects(self): + for obj, cache in self.objects_cache.iteritems(): + try: + obj.reload(cache) + except: + functions_general.log_errmsg("Failed to reload cache for object: %s." % (obj,)) + self.failed.append(obj) + raise + + self.objects_cache = {} + + for obj in self.failed: + try: + obj.__dict__.update(cache) + except: + functions_general.log_errmsg("Failed to update object %s, giving up." %s (obj,)) + raise + + self.failed = [] diff --git a/server.py b/server.py index 281379571d..a0c6b72c49 100755 --- a/server.py +++ b/server.py @@ -21,29 +21,6 @@ import initial_setup class EvenniaService(service.Service): - class RollbackImporter(object): - def __init__(self): - "Creates an instance and installs as the global importer" - self.previousModules = sys.modules.copy() - self.realImport = __builtin__.__import__ - __builtin__.__import__ = self._import - self.newModules = {} - - def _import(self, name, globals=None, locals=None, fromlist=[]): - result = apply(self.realImport, (name, globals, locals, fromlist)) - self.NewModules[name] = 1 - return result - - def uninstall(self): - for modname in self.newModules.keys(): - if not self.previousModules.has_key(modname): - # Force reload when modname next imported - del(sys.modules[modname]) - __builtin__.__import__ = self.realImport - - def reloadAll(self): - pass - def __init__(self, filename="blah"): log.startLogging(open(settings.LOGFILE, 'w')) self.cmd_alias_list = {}