<commit_before>#
# Copyright (c) 2006-2007 rPath, Inc.  All Rights Reserved.
#
"""
Generic plugin library.  Loads plugins from the given paths, unless they
are disabled.

Plugins can import each other by using the given pluginPrefix - the importer
hook will find other plugins in whatever directory they are installed.

TODO: add support for a requires syntax for plugins, and versioning of
plugin APIs.
"""
import imp
import os
import sys
import traceback

from conary.lib import log

class Plugin(object):
    """
        Basic plugin.  Should be derived from by plugins.
    """
    types = []
    def __init__(self, name, path, pluginManager):
        self.name = name
        self.path = path
        self.pluginManager = pluginManager
        self.enabled = True

    def unload(self):
        pass

class PluginManager(object):
    """
        The plugin manager loads available plugins and then
        stores them for later so that they are available for calling
        hooks in them.

        Unless the store and remove methods are overridden,
        plugins have types which can be used to call to hooks on only
        particular classes.

        Parameters for initialization:
        @param pluginDirs: directories to search for plugins

        @param disabledPlugins: a list of plugin names to not be loaded.

        @param pluginPrefix: when plugins access themselves and other
            plugins internally, they do so through import statements 
            underneath a particular prefix.  This defines the prefix.

        @param pluginClass: the class from which plugins should derive.
            This class is checked before instantiating plugins in a loaded
            plugin module.

        @param supportedTypes: the different types which plugins 
            are allowed to be.  Defaults to empty, effectively disabling
            types.
    """

    def __init__(self, pluginDirs=None, disabledPlugins=None,
                 pluginPrefix='__plugins__', pluginClass=Plugin):
        if pluginDirs is None:
            pluginDirs = []
        if disabledPlugins is None:
            disabledPlugins = []

        self.pluginDirs = pluginDirs
        self.pluginPrefix = pluginPrefix
        self.pluginClass = pluginClass

        self.plugins = []
        self.pluginsByType = {}
        self.pluginsByName = {}
        self.disabledPlugins = disabledPlugins

        self.loader = PluginImporter(self.pluginDirs, self.pluginPrefix,
                                     logger=self)

    def installImporter(self):
        self.loader.install()

    def uninstallImporter(self):
        self.loader.uninstall()

    def disableAllPlugins(self):
        for plugin in self.plugins:
            plugin.enabled = False

    def hasPlugin(self, name):
        return name in self.pluginsByName

    def enablePlugin(self, name):
        self.pluginsByName[name].enabled = True

    def disablePlugin(self, name):
        self.pluginsByName[name].enabled = False

    def getPluginsByType(self, pluginType):
        return sorted(self.pluginsByType.get(pluginType, []), 
                      key=lambda x: x.name)

    def getPlugin(self, name):
        return self.pluginsByName[name]

    def warning(self, txt, *args, **kw):
        log.warning(txt, *args, **kw)

    def loadFailed(self, path, txt):
        self.warning('Failed to import plugin %s: %s' % (path, txt))

    def isValidPluginFileName(self, dir, fileName):
        if fileName.startswith('.') or fileName.startswith('~'):
            return False
        path = dir + '/' + fileName
        if os.path.isdir(path):
            if (os.path.exists(path + '/__init__.py') 
                or os.path.exists(path + '/__init__.pyc')):
                return True
        elif path.endswith('.py') or path.endswith('.pyc'):
            return True
        return False

    def loadPlugins(self):
        self.loader.install()
        for dir in self.pluginDirs:
            if not os.path.isdir(dir):
                continue
            pluginFiles = {}
            for fileName in os.listdir(dir):
                if not self.isValidPluginFileName(dir, fileName):
                    continue
                if fileName.endswith('.pyc'):
                    pluginFileName = fileName[:-1]
                else:
                    pluginFileName = fileName
                if pluginFileName in pluginFiles:
                    otherFileName = pluginFiles[pluginFileName]
                    otherFileMtime = os.stat(dir + '/' + otherFileName).st_mtime
                    thisFileMtime = os.stat(dir + '/' + fileName).st_mtime
                    if otherFileMtime > thisFileMtime:
                        continue
                pluginFiles[pluginFileName] = fileName
            pluginFiles = pluginFiles.values()
            for fileName in pluginFiles:
                plugin = self.loadPluginFromFileName(dir, fileName)
                if plugin is not None:
                    self.storePlugin(plugin)
        self.loader.uninstall()

    def unloadPlugin(self, name):
        plugin = self.pluginsByName.pop(name)
        plugin.unload()
        for type in plugin.types + ['all']:
            self.pluginsByType[type].remove(plugin)

    def storePlugin(self, plugin):
        self.pluginsByName[plugin.name] = plugin
        self.plugins.append(plugin)
        for type in plugin.types + ['all']:
            self.pluginsByType.setdefault(type, []).append(plugin)

    def getPluginNameFromFile(self, fileName):
        # module names cannot have .'s in them - cut off the extension 
        # whatever it is.
        return fileName.split('.', 1)[0]

    def validatePlugin(self, plugin):
        return plugin<commit_msg>Make sure plugins with the same name aren't loaded twice<commit_after>#
# Copyright (c) 2006-2007 rPath, Inc.  All Rights Reserved.
#
"""
Generic plugin library.  Loads plugins from the given paths, unless they
are disabled.

Plugins can import each other by using the given pluginPrefix - the importer
hook will find other plugins in whatever directory they are installed.

TODO: add support for a requires syntax for plugins, and versioning of
plugin APIs.
"""
import imp
import os
import sys
import traceback

from conary.lib import log

class Plugin(object):
    """
        Basic plugin.  Should be derived from by plugins.
    """
    types = []
    def __init__(self, name, path, pluginManager):
        self.name = name
        self.path = path
        self.pluginManager = pluginManager
        self.enabled = True

    def unload(self):
        pass

class PluginManager(object):
    """
        The plugin manager loads available plugins and then
        stores them for later so that they are available for calling
        hooks in them.

        Unless the store and remove methods are overridden,
        plugins have types which can be used to call to hooks on only
        particular classes.

        Parameters for initialization:
        @param pluginDirs: directories to search for plugins

        @param disabledPlugins: a list of plugin names to not be loaded.

        @param pluginPrefix: when plugins access themselves and other
            plugins internally, they do so through import statements 
            underneath a particular prefix.  This defines the prefix.

        @param pluginClass: the class from which plugins should derive.
            This class is checked before instantiating plugins in a loaded
            plugin module.

        @param supportedTypes: the different types which plugins 
            are allowed to be.  Defaults to empty, effectively disabling
            types.
    """

    def __init__(self, pluginDirs=None, disabledPlugins=None,
                 pluginPrefix='__plugins__', pluginClass=Plugin):
        if pluginDirs is None:
            pluginDirs = []
        if disabledPlugins is None:
            disabledPlugins = []

        self.pluginDirs = pluginDirs
        self.pluginPrefix = pluginPrefix
        self.pluginClass = pluginClass

        self.plugins = []
        self.pluginsByType = {}
        self.pluginsByName = {}
        self.disabledPlugins = disabledPlugins

        self.loader = PluginImporter(self.pluginDirs, self.pluginPrefix,
                                     logger=self)

    def installImporter(self):
        self.loader.install()

    def uninstallImporter(self):
        self.loader.uninstall()

    def disableAllPlugins(self):
        for plugin in self.plugins:
            plugin.enabled = False

    def hasPlugin(self, name):
        return name in self.pluginsByName

    def enablePlugin(self, name):
        self.pluginsByName[name].enabled = True

    def disablePlugin(self, name):
        self.pluginsByName[name].enabled = False

    def getPluginsByType(self, pluginType):
        return sorted(self.pluginsByType.get(pluginType, []), 
                      key=lambda x: x.name)

    def getPlugin(self, name):
        return self.pluginsByName[name]

    def warning(self, txt, *args, **kw):
        log.warning(txt, *args, **kw)

    def loadFailed(self, path, txt):
        self.warning('Failed to import plugin %s: %s' % (path, txt))

    def isValidPluginFileName(self, dir, fileName):
        if fileName.startswith('.') or fileName.startswith('~'):
            return False
        path = dir + '/' + fileName
        if os.path.isdir(path):
            if (os.path.exists(path + '/__init__.py') 
                or os.path.exists(path + '/__init__.pyc')):
                return True
        elif path.endswith('.py') or path.endswith('.pyc'):
            return True
        return False

    def loadPlugins(self):
        self.loader.install()
        for dir in self.pluginDirs:
            if not os.path.isdir(dir):
                continue
            pluginFiles = {}
            for fileName in os.listdir(dir):
                if not self.isValidPluginFileName(dir, fileName):
                    continue
                if fileName.endswith('.pyc'):
                    pluginFileName = fileName[:-1]
                else:
                    pluginFileName = fileName
                if pluginFileName in pluginFiles:
                    otherFileName = pluginFiles[pluginFileName]
                    otherFileMtime = os.stat(dir + '/' + otherFileName).st_mtime
                    thisFileMtime = os.stat(dir + '/' + fileName).st_mtime
                    if otherFileMtime > thisFileMtime:
                        continue
                pluginFiles[pluginFileName] = fileName
            pluginFiles = pluginFiles.values()
            for fileName in pluginFiles:
                plugin = self.loadPluginFromFileName(dir, fileName)
                if plugin is not None:
                    self.storePlugin(plugin)
        self.loader.uninstall()

    def unloadPlugin(self, name):
        plugin = self.pluginsByName.pop(name)
        plugin.unload()
        for type in plugin.types + ['all']:
            self.pluginsByType[type].remove(plugin)

    def storePlugin(self, plugin):
        if plugin.name in self.pluginsByName:
            oldPlugin = self.pluginsByName[plugin.name]
            self.plugins.remove(oldPlugin)
            for type in oldPlugin.types + ['all']:
                self.pluginsByType.setdefault(type, []).remove(oldPlugin)
        self.pluginsByName[plugin.name] = plugin
        self.plugins.append(plugin)
        for type in plugin.types + ['all']:
            self.pluginsByType.setdefault(type, []).append(plugin)

    def getPluginNameFromFile(self, fileName):
        # module names cannot have .'s in them - cut off the extension 
        # whatever it is.
        return fileName.split('.', 1)[0]

    def validatePlugin(self, plugin):
        return plugin
{'fraction_non_alphanumeric': 0.08234994481704729, 'fraction_numerical': 0.0018677307071907632, 'mean_word_length': 2.0661114003123373, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1643418', 'n_tokens_mistral': 3052, 'n_tokens_neox': 2957, 'n_words': 956}