summaryrefslogtreecommitdiffstats
path: root/src/libs/xpcom18a4/python/server/loader.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/xpcom18a4/python/server/loader.py')
-rwxr-xr-xsrc/libs/xpcom18a4/python/server/loader.py227
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] )