[IMP] wsgi: modules can be pre-loaded and expose a WSGI handler.
An option --load is added to list the modules to pre-load. sys.path and sys.modules are initialized when the config is parsed. bzr revid: vmt@openerp.com-20110902133136-4v7fgptyd0g1kc5s
This commit is contained in:
parent
79d0e39c4c
commit
8ca1a87201
|
@ -259,6 +259,16 @@ if __name__ == "__main__":
|
|||
if config["stop_after_init"]:
|
||||
sys.exit(0)
|
||||
|
||||
for m in openerp.conf.server_wide_modules:
|
||||
__import__(m)
|
||||
# Register a WSGI entry point if any.
|
||||
info = openerp.modules.module.load_information_from_description_file(m)
|
||||
if info['wsgi']:
|
||||
openerp.wsgi.register_wsgi_handler(getattr(sys.modules[m], info['wsgi']))
|
||||
|
||||
openerp.wsgi.serve()
|
||||
|
||||
|
||||
setup_pid_file()
|
||||
setup_signal_handlers()
|
||||
start_services()
|
||||
|
|
|
@ -22,10 +22,15 @@
|
|||
|
||||
""" Addons module.
|
||||
|
||||
This module only serves to contain OpenERP addons. For the code to
|
||||
manage those addons, see openerp.modules. This module conveniently
|
||||
reexports some symbols from openerp.modules. Importing them from here
|
||||
is deprecated.
|
||||
This module serves to contain all OpenERP addons, across all configured addons
|
||||
paths. For the code to manage those addons, see openerp.modules.
|
||||
|
||||
Addons are made available here (i.e. under openerp.addons) after
|
||||
openerp.tools.config.parse_config() is called (so that the addons paths
|
||||
are known).
|
||||
|
||||
This module also conveniently reexports some symbols from openerp.modules.
|
||||
Importing them from here is deprecated.
|
||||
|
||||
"""
|
||||
|
||||
|
|
|
@ -25,5 +25,10 @@ import res
|
|||
import publisher_warranty
|
||||
import report
|
||||
|
||||
def YEAH(environ, start_response):
|
||||
response = 'YEAH.\n'
|
||||
start_response('200 OK', [('Content-Type', 'text/plain'), ('Content-Length', str(len(response)))])
|
||||
return [response]
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
|
|
@ -93,6 +93,7 @@
|
|||
'test/test_ir_rule.yml', # <-- These tests modify/add/delete ir_rules.
|
||||
'test/test_ir_values.yml',
|
||||
],
|
||||
'wsgi': 'YEAH',
|
||||
'installable': True,
|
||||
'active': True,
|
||||
'certificate': '0076807797149',
|
||||
|
|
|
@ -28,8 +28,21 @@ parsing, configuration file loading and saving, ...) in this module
|
|||
and provide real Python variables, e.g. addons_paths is really a list
|
||||
of paths.
|
||||
|
||||
To initialize properly this module, openerp.tools.config.parse_config()
|
||||
must be used.
|
||||
|
||||
"""
|
||||
|
||||
import deprecation
|
||||
|
||||
# Paths to search for OpenERP addons.
|
||||
addons_paths = []
|
||||
|
||||
# List of server-wide modules to load. Those modules are supposed to provide
|
||||
# features not necessarily tied to a particular database. This is in contrast
|
||||
# to modules that are always bound to a specific database when they are
|
||||
# installed (i.e. the majority of OpenERP addons). This is set with the --load
|
||||
# command-line option.
|
||||
server_wide_modules = []
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -58,16 +58,16 @@ class Graph(dict):
|
|||
|
||||
"""
|
||||
|
||||
def add_node(self, name, deps):
|
||||
def add_node(self, name, info):
|
||||
max_depth, father = 0, None
|
||||
for n in [Node(x, self) for x in deps]:
|
||||
for n in [Node(x, self, None) for x in info['depends']]:
|
||||
if n.depth >= max_depth:
|
||||
father = n
|
||||
max_depth = n.depth
|
||||
if father:
|
||||
return father.add_child(name)
|
||||
return father.add_child(name, info)
|
||||
else:
|
||||
return Node(name, self)
|
||||
return Node(name, self, info)
|
||||
|
||||
def update_from_db(self, cr):
|
||||
if not len(self):
|
||||
|
@ -120,7 +120,7 @@ class Graph(dict):
|
|||
continue
|
||||
later.clear()
|
||||
current.remove(package)
|
||||
node = self.add_node(package, deps)
|
||||
node = self.add_node(package, info)
|
||||
node.data = info
|
||||
for kind in ('init', 'demo', 'update'):
|
||||
if package in tools.config[kind] or 'all' in tools.config[kind] or kind in force:
|
||||
|
@ -154,12 +154,13 @@ class Graph(dict):
|
|||
|
||||
|
||||
class Singleton(object):
|
||||
def __new__(cls, name, graph):
|
||||
def __new__(cls, name, graph, info):
|
||||
if name in graph:
|
||||
inst = graph[name]
|
||||
else:
|
||||
inst = object.__new__(cls)
|
||||
inst.name = name
|
||||
inst.info = info
|
||||
graph[name] = inst
|
||||
return inst
|
||||
|
||||
|
@ -167,19 +168,21 @@ class Singleton(object):
|
|||
class Node(Singleton):
|
||||
""" One module in the modules dependency graph.
|
||||
|
||||
Node acts as a per-module singleton.
|
||||
Node acts as a per-module singleton. A node is constructed via
|
||||
Graph.add_module() or Graph.add_modules(). Some of its fields are from
|
||||
ir_module_module (setted by Graph.update_from_db()).
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, name, graph):
|
||||
def __init__(self, name, graph, info):
|
||||
self.graph = graph
|
||||
if not hasattr(self, 'children'):
|
||||
self.children = []
|
||||
if not hasattr(self, 'depth'):
|
||||
self.depth = 0
|
||||
|
||||
def add_child(self, name):
|
||||
node = Node(name, self.graph)
|
||||
def add_child(self, name, info):
|
||||
node = Node(name, self.graph, info)
|
||||
node.depth = self.depth + 1
|
||||
if node not in self.children:
|
||||
self.children.append(node)
|
||||
|
|
|
@ -31,7 +31,6 @@ import openerp.osv as osv
|
|||
import openerp.tools as tools
|
||||
import openerp.tools.osutil as osutil
|
||||
from openerp.tools.safe_eval import safe_eval as eval
|
||||
import openerp.pooler as pooler
|
||||
from openerp.tools.translate import _
|
||||
|
||||
import openerp.netsvc as netsvc
|
||||
|
@ -58,6 +57,11 @@ loaded = []
|
|||
logger = netsvc.Logger()
|
||||
|
||||
def initialize_sys_path():
|
||||
""" Add all addons paths in sys.path.
|
||||
|
||||
This ensures something like ``import crm`` works even if the addons are
|
||||
not in the PYTHONPATH.
|
||||
"""
|
||||
global ad_paths
|
||||
|
||||
if ad_paths:
|
||||
|
@ -250,6 +254,7 @@ def load_information_from_description_file(module):
|
|||
info['license'] = info.get('license') or 'AGPL-3'
|
||||
info.setdefault('installable', True)
|
||||
info.setdefault('active', False)
|
||||
info.setdefault('wsgi', None) # WSGI entry point, given as a string
|
||||
for kind in ['data', 'demo', 'test',
|
||||
'init_xml', 'update_xml', 'demo_xml']:
|
||||
info.setdefault(kind, [])
|
||||
|
@ -290,23 +295,22 @@ def init_module_models(cr, module_name, obj_list):
|
|||
t[1](cr, *t[2])
|
||||
cr.commit()
|
||||
|
||||
# Import hook to write a addon m in both sys.modules['m'] and
|
||||
# sys.modules['openerp.addons.m']. Otherwise it could be loaded twice
|
||||
# if imported twice using different names.
|
||||
#class MyImportHook(object):
|
||||
# def find_module(self, module_name, package_path):
|
||||
# print ">>>", module_name, package_path
|
||||
# def load_module(self, module_name):
|
||||
# raise ImportError("Restricted")
|
||||
|
||||
def load_module(module_name):
|
||||
""" Load a Python module found on the addons paths."""
|
||||
fm = imp.find_module(module_name, ad_paths)
|
||||
try:
|
||||
imp.load_module(module_name, *fm)
|
||||
finally:
|
||||
if fm[0]:
|
||||
fm[0].close()
|
||||
|
||||
#sys.meta_path.append(MyImportHook())
|
||||
|
||||
def register_module_classes(m):
|
||||
""" Register module named m, if not already registered.
|
||||
|
||||
This will load the module and register all of its models. (Actually, the
|
||||
explicit constructor call of each of the models inside the module will
|
||||
register them.)
|
||||
This loads the module and register all of its models, thanks to either
|
||||
the MetaModel metaclass, or the explicit instantiation of the model.
|
||||
|
||||
"""
|
||||
|
||||
|
@ -326,7 +330,7 @@ def register_module_classes(m):
|
|||
try:
|
||||
zip_mod_path = mod_path + '.zip'
|
||||
if not os.path.isfile(zip_mod_path):
|
||||
load_module(m)
|
||||
__import__(m)
|
||||
else:
|
||||
zimp = zipimport.zipimporter(zip_mod_path)
|
||||
zimp.load_module(m)
|
||||
|
|
|
@ -24,6 +24,7 @@ import optparse
|
|||
import os
|
||||
import sys
|
||||
import openerp
|
||||
import openerp.conf
|
||||
import openerp.loglevels as loglevels
|
||||
import logging
|
||||
import openerp.release as release
|
||||
|
@ -101,8 +102,10 @@ class configmanager(object):
|
|||
group.add_option("-P", "--import-partial", dest="import_partial", my_default='',
|
||||
help="Use this for big data importation, if it crashes you will be able to continue at the current state. Provide a filename to store intermediate importation states.")
|
||||
group.add_option("--pidfile", dest="pidfile", help="file where the server pid will be stored")
|
||||
group.add_option("--load", dest="server_wide_modules", help="Comma-separated list of server-wide modules")
|
||||
parser.add_option_group(group)
|
||||
|
||||
# XML-RPC / HTTP
|
||||
group = optparse.OptionGroup(parser, "XML-RPC Configuration")
|
||||
group.add_option("--xmlrpc-interface", dest="xmlrpc_interface", my_default='',
|
||||
help="Specify the TCP IP address for the XML-RPC protocol. The empty string binds to all interfaces.")
|
||||
|
@ -112,6 +115,7 @@ class configmanager(object):
|
|||
help="disable the XML-RPC protocol")
|
||||
parser.add_option_group(group)
|
||||
|
||||
# XML-RPC / HTTPS
|
||||
title = "XML-RPC Secure Configuration"
|
||||
if not self.has_ssl:
|
||||
title += " (disabled as ssl is unavailable)"
|
||||
|
@ -258,9 +262,26 @@ class configmanager(object):
|
|||
self.options[option.dest] = option.my_default
|
||||
self.casts[option.dest] = option
|
||||
|
||||
self.parse_config()
|
||||
self.parse_config(None, False)
|
||||
|
||||
def parse_config(self, args=None):
|
||||
def parse_config(self, args=None, complete=True):
|
||||
""" Parse the configuration file (if any) and the command-line
|
||||
arguments.
|
||||
|
||||
This method initializes openerp.tools.config and openerp.conf (the
|
||||
former should be removed in the furture) with library-wide
|
||||
configuration values.
|
||||
|
||||
This method must be called before proper usage of this library can be
|
||||
made.
|
||||
|
||||
Typical usage of this method:
|
||||
|
||||
openerp.tools.config.parse_config(sys.argv[1:])
|
||||
|
||||
:param complete: this is a hack used in __init__(), leave it to True.
|
||||
|
||||
"""
|
||||
if args is None:
|
||||
args = []
|
||||
opt, args = self.parser.parse_args(args)
|
||||
|
@ -417,6 +438,17 @@ class configmanager(object):
|
|||
if opt.save:
|
||||
self.save()
|
||||
|
||||
openerp.conf.addons_paths = self.options['addons_path'].split(',')
|
||||
openerp.conf.server_wide_modules = \
|
||||
map(lambda m: m.strip(), opt.server_wide_modules.split(',')) if \
|
||||
opt.server_wide_modules else []
|
||||
if complete:
|
||||
openerp.modules.module.initialize_sys_path()
|
||||
openerp.modules.loading.open_openerp_namespace()
|
||||
# openerp.addons.__path__.extend(openerp.conf.addons_paths) # This
|
||||
# is not compatible with initialize_sys_path(): import crm and
|
||||
# import openerp.addons.crm load twice the module.
|
||||
|
||||
def _generate_pgpassfile(self):
|
||||
"""
|
||||
Generate the pgpass file with the parameters from the command line (db_host, db_user,
|
||||
|
|
|
@ -95,11 +95,31 @@ def legacy_wsgi_xmlrpc(environ, start_response):
|
|||
def wsgi_jsonrpc(environ, start_response):
|
||||
pass
|
||||
|
||||
def wsgi_modules(environ, start_response):
|
||||
""" WSGI handler dispatching to addons-provided entry points."""
|
||||
pass
|
||||
|
||||
# WSGI handlers provided by modules loaded with the --load command-line option.
|
||||
module_handlers = []
|
||||
|
||||
def register_wsgi_handler(handler):
|
||||
""" Register a WSGI handler.
|
||||
|
||||
Handlers are tried in the order they are added. We might provide a way to
|
||||
register a handler for specific routes later.
|
||||
"""
|
||||
module_handlers.append(handler)
|
||||
|
||||
def application(environ, start_response):
|
||||
""" WSGI entry point."""
|
||||
|
||||
# Try all handlers until one returns some result (i.e. not None).
|
||||
wsgi_handlers = [wsgi_xmlrpc, wsgi_jsonrpc, legacy_wsgi_xmlrpc]
|
||||
wsgi_handlers = [
|
||||
wsgi_xmlrpc,
|
||||
wsgi_jsonrpc,
|
||||
legacy_wsgi_xmlrpc,
|
||||
wsgi_modules,
|
||||
] + module_handlers
|
||||
for handler in wsgi_handlers:
|
||||
result = handler(environ, start_response)
|
||||
if result is None:
|
||||
|
|
Loading…
Reference in New Issue