def sync_app_plugins(delete_removed=False, verbosity=1): """ We need to do a complicated dance to sync the current registered and unregistered implicit plugins and points with the instances in the DB. Plugins and points which are removed (or can no longer be found) are marked REMOVED (sometimes only to be re-enabed shortly there after). There is the option to delete all entries which are marked removed, but this should be done carefully. Other apps may have relations to the plugins and points for user preferences and customizaiton settings. We do not want to blindly delete these in a chain delete, as they may need to be migrated to a renamed plugin or point which has now been created as part of the sync. The process: 1. for each registered Plugin Point 1.1. if no instance exists, create it enabled. 1.2. mark it registered 1.2. if it was 'removed' then mark it enabled 2. For each non-removed, registered instance for which there was no reg 2.1. mark removed 2.2. mark plugins removed 3. for each registered plugin 3.1. if there is no point, create it as unregistered 3.2. if there is no plugin, create it as reg and enabled, w/template 3.3. test the template load 3.4. if the plugin was marked REMOVED 3.4.1. mark it enabled 3.4.2. if its point is REMOVED and it is not marked reg, enable it 4. for each registered plugin for which there is no registration 4.1. mark it removed 5. for each non-REMOVED point, get all unregistered plugins via load: 5.1. if plugin instance does not exist, create unregistered and enable 5.2. if it does exist and is marked REMOVED, mark unreg-enabled w/ point 6. for each unreg-non-removed point 6.1. if all plugins are REMOVED, mark REMOVED. 7. if asked to delete the removed, do so. """ from app_plugins.library import libraries from app_plugins.models import Plugin, PluginPoint, REMOVED, ENABLED from app_plugins.models import construct_template_path instances = dict((p.label, p) for p in PluginPoint.objects.all()) ## section 1 - registered plugin points for app_label, lib in libraries.iteritems(): for label in lib.plugin_points: pp = instances.pop(label, None) if pp is None: if verbosity > 1: print "Creating registered PluginPoint:", label pp = PluginPoint(label=label) pp.registered = True if pp.status == REMOVED: if verbosity > 1: print "Updating registered PluginPoint:", label # re-enable a previously removed plugin point and its plugins pp.status = ENABLED for p in Plugin.objects.filter(point=pp, status=REMOVED): p.status = ENABLED p.save() pp.save() # search for unregistered plugins we do not yet know about? ## section 2 - removed plugin points for pp in instances.itervalues(): # don't remove pps with active plugins! if pp.status != REMOVED and not pp.plugin_set.exclude( status=REMOVED).count(): pp.status = REMOVED pp.save() for p in pp.plugin_set.all(): p.status = REMOVED p.save() instances = dict((p.label, p) for p in Plugin.objects.all()) ## section 3 - registered plugins for app_label, lib in libraries.iteritems(): for label in lib.plugins: p = instances.pop(label, None) # Don't forget the dot in label! Strip it out. # We could increment slice index by 1, but I'm # not sure if some labels/libs will have no app_name # and thus no joining dot?? point_label = label[len(lib.app_name):].strip('.') if p is None: p = Plugin() p.label = label if verbosity > 1: print "Creating registered Plugin:", label try: point = PluginPoint.objects.get(label=point_label) p.point = point if point.status == REMOVED: # point was removed at some point... point.status = ENABLED if point.registered: point.registered = False point.save() except PluginPoint.DoesNotExist: if verbosity > 1: print "Creating unregistered PluginPoint:", point_label point = PluginPoint(label=point_label) point.save() p.point = point p.registered = True if p.status == REMOVED: # re-enable a previously removed plugin if verbosity > 1: print "Updating registered Plugin:", p.label p.status = ENABLED options = lib.get_plugin_call(point_label).options default = construct_template_path(lib.app_name, point_label, options.get('ext', '.html')) # raise an error if it does not exist... template = options.get('template', default) loader.find_template_source(template) p.template = template p.save() ## section 4 - initial marking of unregistered known plugins for p in instances.itervalues(): if p.status != REMOVED: p.status = REMOVED p.save() ## section 5 - unregistered plugins instances = dict((p.label, p) for p in Plugin.objects.all()) for pp in PluginPoint.objects.exclude(status=REMOVED): ext = pp.get_options().get('ext', '.html') name = pp.label for app in settings.INSTALLED_APPS: label = u'.'.join([app, name]) template = construct_template_path(app, name, ext) bFound = True try: loader.find_template_source(template) except TemplateDoesNotExist: bFound = False p = instances.get(label, None) if p is None: if bFound: if verbosity > 1: print "Creating unregistered Plugin:", label p = Plugin(point=pp, label=label, template=template) else: if p.status == REMOVED and bFound: p.status = ENABLED p.template = template p.registered = False #if verbosity > 1: # print "Updating unregistered Plugin:", label elif not p.registered and not bFound and p.status != REMOVED: p.status = REMOVED else: p = None if p is not None: p.save() ## section 6 - removed unregistered plugin points for pp in PluginPoint.objects.filter(registered=False).exclude( status=REMOVED): if not pp.plugin_set.exclude(status=REMOVED).count(): if verbosity > 1: print "Removing unregistered PluginPoint:", pp.label pp.status = REMOVED pp.save() ## section 7 - delete removed if delete_removed: count = Plugin.objects.filter(status=REMOVED).count() if count: if verbosity > 1: print "Deleting %d Removed Plugins" % count Plugin.objects.filter(status=REMOVED).delete() count = PluginPoints.objects.filter(status=REMOVED).count() if count: if verbosity > 1: print "Deleting %d Removed PluginPoint" % count PluginPoints.objects.filter(status=REMOVED).delete()
def sync_app_plugins(delete_removed=False, verbosity=1): """ We need to do a complicated dance to sync the current registered and unregistered implicit plugins and points with the instances in the DB. Plugins and points which are removed (or can no longer be found) are marked REMOVED (sometimes only to be re-enabed shortly there after). There is the option to delete all entries which are marked removed, but this should be done carefully. Other apps may have relations to the plugins and points for user preferences and customizaiton settings. We do not want to blindly delete these in a chain delete, as they may need to be migrated to a renamed plugin or point which has now been created as part of the sync. The process: 1. for each registered Plugin Point 1.1. if no instance exists, create it enabled. 1.2. mark it registered 1.2. if it was 'removed' then mark it enabled 2. For each non-removed, registered instance for which there was no reg 2.1. mark removed 2.2. mark plugins removed 3. for each registered plugin 3.1. if there is no point, create it as unregistered 3.2. if there is no plugin, create it as reg and enabled, w/template 3.3. test the template load 3.4. if the plugin was marked REMOVED 3.4.1. mark it enabled 3.4.2. if its point is REMOVED and it is not marked reg, enable it 4. for each registered plugin for which there is no registration 4.1. mark it removed 5. for each non-REMOVED point, get all unregistered plugins via load: 5.1. if plugin instance does not exist, create unregistered and enable 5.2. if it does exist and is marked REMOVED, mark unreg-enabled w/ point 6. for each unreg-non-removed point 6.1. if all plugins are REMOVED, mark REMOVED. 7. if asked to delete the removed, do so. """ from app_plugins.library import libraries from app_plugins.models import Plugin, PluginPoint, REMOVED, ENABLED from app_plugins.models import construct_template_path instances = dict((p.label, p) for p in PluginPoint.objects.all()) ## section 1 - registered plugin points for app_label, lib in libraries.iteritems(): for label in lib.plugin_points: pp = instances.pop(label, None) if pp is None: if verbosity > 1: print "Creating registered PluginPoint:", label pp = PluginPoint(label=label) pp.registered = True if pp.status == REMOVED: if verbosity > 1: print "Updating registered PluginPoint:", label # re-enable a previously removed plugin point and its plugins pp.status = ENABLED for p in Plugin.objects.filter(point=pp, status=REMOVED): p.status = ENABLED p.save() pp.save() # search for unregistered plugins we do not yet know about? ## section 2 - removed plugin points for pp in instances.itervalues(): # don't remove pps with active plugins! if pp.status != REMOVED and not pp.plugin_set.exclude(status=REMOVED).count(): pp.status = REMOVED pp.save() for p in pp.plugin_set.all(): p.status = REMOVED p.save() instances = dict((p.label, p) for p in Plugin.objects.all()) ## section 3 - registered plugins for app_label, lib in libraries.iteritems(): for label in lib.plugins: p = instances.pop(label, None) # Don't forget the dot in label! Strip it out. # We could increment slice index by 1, but I'm # not sure if some labels/libs will have no app_name # and thus no joining dot?? point_label = label[len(lib.app_name):].strip('.') if p is None: p = Plugin() p.label = label if verbosity > 1: print "Creating registered Plugin:", label try: point = PluginPoint.objects.get(label=point_label) p.point = point if point.status == REMOVED: # point was removed at some point... point.status = ENABLED if point.registered: point.registered = False point.save() except PluginPoint.DoesNotExist: if verbosity > 1: print "Creating unregistered PluginPoint:", point_label point = PluginPoint(label=point_label) point.save() p.point = point p.registered = True if p.status == REMOVED: # re-enable a previously removed plugin if verbosity > 1: print "Updating registered Plugin:", p.label p.status = ENABLED options = lib.get_plugin_call(point_label).options default = construct_template_path(lib.app_name, point_label, options.get('ext', '.html')) # raise an error if it does not exist... template = options.get('template', default) loader.find_template_source(template) p.template = template p.save() ## section 4 - initial marking of unregistered known plugins for p in instances.itervalues(): if p.status != REMOVED: p.status = REMOVED p.save() ## section 5 - unregistered plugins instances = dict((p.label, p) for p in Plugin.objects.all()) for pp in PluginPoint.objects.exclude(status=REMOVED): ext = pp.get_options().get('ext', '.html') name = pp.label for app in settings.INSTALLED_APPS: label = u'.'.join([app, name]) template = construct_template_path(app, name, ext) bFound = True try: loader.find_template_source(template) except TemplateDoesNotExist: bFound = False p = instances.get(label, None) if p is None: if bFound: if verbosity > 1: print "Creating unregistered Plugin:", label p = Plugin(point=pp, label=label, template=template) else: if p.status == REMOVED and bFound: p.status = ENABLED p.template = template p.registered = False #if verbosity > 1: # print "Updating unregistered Plugin:", label elif not p.registered and not bFound and p.status != REMOVED: p.status = REMOVED else: p = None if p is not None: p.save() ## section 6 - removed unregistered plugin points for pp in PluginPoint.objects.filter(registered=False).exclude(status=REMOVED): if not pp.plugin_set.exclude(status=REMOVED).count(): if verbosity > 1: print "Removing unregistered PluginPoint:", pp.label pp.status = REMOVED pp.save() ## section 7 - delete removed if delete_removed: count = Plugin.objects.filter(status=REMOVED).count() if count: if verbosity > 1: print "Deleting %d Removed Plugins" % count Plugin.objects.filter(status=REMOVED).delete() count = PluginPoints.objects.filter(status=REMOVED).count() if count: if verbosity > 1: print "Deleting %d Removed PluginPoint" % count PluginPoints.objects.filter(status=REMOVED).delete()