diff options
Diffstat (limited to '')
-rwxr-xr-x | src/libs/xpcom18a4/python/server/loader.py | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/src/libs/xpcom18a4/python/server/loader.py b/src/libs/xpcom18a4/python/server/loader.py new file mode 100755 index 00000000..ebd42b61 --- /dev/null +++ b/src/libs/xpcom18a4/python/server/loader.py @@ -0,0 +1,227 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is +# Activestate Tool Corp. +# Portions created by the Initial Developer are Copyright (C) 2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond <MarkH@ActiveState.com> +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +import xpcom +from xpcom import components, logger +from . import module +import glob +import os +from xpcom.client import Component + +# Until we get interface constants. +When_Startup = 0 +When_Component = 1 +When_Timer = 2 + +def _has_good_attr(object, attr): + # Actually allows "None" to be specified to disable inherited attributes. + return getattr(object, attr, None) is not None + +def FindCOMComponents(py_module): + # For now, just run over all classes looking for likely candidates. + comps = [] + for name, object in list(py_module.__dict__.items()): + try: + if (type(object) == type or issubclass(object, object)) and \ + _has_good_attr(object, "_com_interfaces_") and \ + _has_good_attr(object, "_reg_clsid_") and \ + _has_good_attr(object, "_reg_contractid_"): + comps.append(object) + except TypeError: + # The issubclass call raises TypeError when the obj is not a class. + pass; + return comps + +def register_self(klass, compMgr, location, registryLocation, componentType): + pcl = PythonComponentLoader + from xpcom import _xpcom + svc = _xpcom.GetServiceManager().getServiceByContractID("@mozilla.org/categorymanager;1", components.interfaces.nsICategoryManager) + svc.addCategoryEntry("component-loader", pcl._reg_component_type_, pcl._reg_contractid_, 1, 1) + +class PythonComponentLoader: + _com_interfaces_ = components.interfaces.nsIComponentLoader + _reg_clsid_ = "{63B68B1E-3E62-45f0-98E3-5E0B5797970C}" # Never copy these! + _reg_contractid_ = "moz.pyloader.1" + _reg_desc_ = "Python component loader" + # Optional function which performs additional special registration + # Appears that no special unregistration is needed for ComponentLoaders, hence no unregister function. + _reg_registrar_ = (register_self,None) + # Custom attributes for ComponentLoader registration. + _reg_component_type_ = "script/python" + + def __init__(self): + self.com_modules = {} # Keyed by module's FQN as obtained from nsIFile.path + self.moduleFactory = module.Module + self.num_modules_this_register = 0 + + def _getCOMModuleForLocation(self, componentFile): + fqn = componentFile.path + mod = self.com_modules.get(fqn) + if mod is not None: + return mod + import ihooks, sys + base_name = os.path.splitext(os.path.basename(fqn))[0] + loader = ihooks.ModuleLoader() + + module_name_in_sys = "component:%s" % (base_name,) + stuff = loader.find_module(base_name, [componentFile.parent.path]) + assert stuff is not None, "Couldnt find the module '%s'" % (base_name,) + py_mod = loader.load_module( module_name_in_sys, stuff ) + + # Make and remember the COM module. + comps = FindCOMComponents(py_mod) + mod = self.moduleFactory(comps) + + self.com_modules[fqn] = mod + return mod + + def getFactory(self, clsid, location, type): + # return the factory + assert type == self._reg_component_type_, "Being asked to create an object not of my type:%s" % (type,) + # FIXME: how to do this without obsolete component manager? + cmo = components.manager.queryInterface(components.interfaces.nsIComponentManagerObsolete) + file_interface = cmo.specForRegistryLocation(location) + # delegate to the module. + m = self._getCOMModuleForLocation(file_interface) + return m.getClassObject(components.manager, clsid, components.interfaces.nsIFactory) + + def init(self, comp_mgr, registry): + # void + self.comp_mgr = comp_mgr + logger.debug("Python component loader init() called") + + # Called when a component of the appropriate type is registered, + # to give the component loader an opportunity to do things like + # annotate the registry and such. + def onRegister (self, clsid, type, className, proId, location, replace, persist): + logger.debug("Python component loader - onRegister() called") + + def autoRegisterComponents (self, when, directory): + directory_path = directory.path + self.num_modules_this_register = 0 + logger.debug("Auto-registering all Python components in '%s'", directory_path) + + # ToDo - work out the right thing here + # eg - do we recurse? + # - do we support packages? + entries = directory.directoryEntries + while entries.HasMoreElements(): + entry = entries.GetNext(components.interfaces.nsIFile) + if os.path.splitext(entry.path)[1]==".py": + try: + self.autoRegisterComponent(when, entry) + # Handle some common user errors + except xpcom.COMException as details: + from xpcom import nsError + # If the interface name does not exist, suppress the traceback + if details.errno==nsError.NS_ERROR_NO_INTERFACE: + logger.error("Registration of '%s' failed\n %s", + entry.leafName, details.message) + else: + logger.exception("Registration of '%s' failed!", entry.leafName) + except SyntaxError as details: + # Syntax error in source file - no useful traceback here either. + logger.error("Registration of '%s' failed\n %s", + entry.leafName, details) + except: + # All other exceptions get the full traceback. + logger.exception("Registration of '%s' failed.", entry.leafName) + + def autoRegisterComponent (self, when, componentFile): + # bool return + + # Check if we actually need to do anything + modtime = componentFile.lastModifiedTime + loader_mgr = components.manager.queryInterface(components.interfaces.nsIComponentLoaderManager) + if not loader_mgr.hasFileChanged(componentFile, None, modtime): + return 1 + + if self.num_modules_this_register == 0: + # New components may have just installed new Python + # modules into the main python directory (including new .pth files) + # So we ask Python to re-process our site directory. + # Note that the pyloader does the equivalent when loading. + try: + from xpcom import _xpcom + import site + NS_XPCOM_CURRENT_PROCESS_DIR="XCurProcD" + dirname = _xpcom.GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR) + dirname.append("python") + site.addsitedir(dirname.path) + except: + logger.exception("PyXPCOM loader failed to process site directory before component registration") + + self.num_modules_this_register += 1 + + # auto-register via the module. + m = self._getCOMModuleForLocation(componentFile) + m.registerSelf(components.manager, componentFile, None, self._reg_component_type_) + loader_mgr = components.manager.queryInterface(components.interfaces.nsIComponentLoaderManager) + loader_mgr.saveFileInfo(componentFile, None, modtime) + return 1 + + def autoUnregisterComponent (self, when, componentFile): + # bool return + # auto-unregister via the module. + m = self._getCOMModuleForLocation(componentFile) + loader_mgr = components.manager.queryInterface(components.interfaces.nsIComponentLoaderManager) + try: + m.unregisterSelf(components.manager, componentFile) + finally: + loader_mgr.removeFileInfo(componentFile, None) + return 1 + + def registerDeferredComponents (self, when): + # bool return + logger.debug("Python component loader - registerDeferred() called") + return 0 # no more to register + + def unloadAll (self, when): + # This is called at shutdown time - don't get too upset if an error + # results from logging due to the logfile being closed + try: + logger.debug("Python component loader being asked to unload all components!") + except: + # Evil blank except, but restricting to just catching IOError + # failure means custom logs could still screw us + pass + self.comp_mgr = None + self.com_modules = {} + +def MakePythonComponentLoaderModule(serviceManager, nsIFile): + from . import module + return module.Module( [PythonComponentLoader] ) |