Log message for revision 40775: - Another checkpoint. Enough majik to render the quickstart page, not much else.
Changed: _U Zope/branches/publication-refactor/lib/python/ U Zope/branches/publication-refactor/lib/python/Products/Five/configure.zcml U Zope/branches/publication-refactor/lib/python/Products/Five/meta.zcml U Zope/branches/publication-refactor/lib/python/ZPublisher/Publication.py U Zope/branches/publication-refactor/lib/python/Zope2/Startup/__init__.py U Zope/branches/publication-refactor/lib/python/Zope2/Startup/handlers.py U Zope/branches/publication-refactor/lib/python/Zope2/Startup/zopeschema.xml -=- Property changes on: Zope/branches/publication-refactor/lib/python ___________________________________________________________________ Name: svn:externals - ZConfig svn://svn.zope.org/repos/main/ZConfig/tags/ZConfig-2.3.1 BTrees svn://svn.zope.org/repos/main/ZODB/tags/3.6.0b4/src/BTrees persistent svn://svn.zope.org/repos/main/ZODB/tags/3.6.0b4/src/persistent ThreadedAsync svn://svn.zope.org/repos/main/ZODB/tags/3.6.0b4/src/ThreadedAsync transaction svn://svn.zope.org/repos/main/ZODB/tags/3.6.0b4/src/transaction ZEO svn://svn.zope.org/repos/main/ZODB/tags/3.6.0b4/src/ZEO ZODB svn://svn.zope.org/repos/main/ZODB/tags/3.6.0b4/src/ZODB ZopeUndo svn://svn.zope.org/repos/main/ZODB/tags/3.6.0b4/src/ZopeUndo zdaemon -r 39732 svn://svn.zope.org/repos/main/zdaemon/trunk/src/zdaemon pytz -r 40549 svn://svn.zope.org/repos/main/Zope3/trunk/src/pytz zodbcode -r 40549 svn://svn.zope.org/repos/main/Zope3/trunk/src/zodbcode ClientCookie -r 40549 svn://svn.zope.org/repos/main/Zope3/trunk/src/ClientCookie mechanize -r 40549 svn://svn.zope.org/repos/main/Zope3/trunk/src/mechanize + ZConfig svn://svn.zope.org/repos/main/ZConfig/tags/ZConfig-2.3.1 BTrees svn://svn.zope.org/repos/main/ZODB/tags/3.6.0b4/src/BTrees persistent svn://svn.zope.org/repos/main/ZODB/tags/3.6.0b4/src/persistent ThreadedAsync svn://svn.zope.org/repos/main/ZODB/tags/3.6.0b4/src/ThreadedAsync transaction svn://svn.zope.org/repos/main/ZODB/tags/3.6.0b4/src/transaction ZEO svn://svn.zope.org/repos/main/ZODB/tags/3.6.0b4/src/ZEO ZODB svn://svn.zope.org/repos/main/ZODB/tags/3.6.0b4/src/ZODB ZopeUndo svn://svn.zope.org/repos/main/ZODB/tags/3.6.0b4/src/ZopeUndo zdaemon -r 39732 svn://svn.zope.org/repos/main/zdaemon/trunk/src/zdaemon pytz -r 40549 svn://svn.zope.org/repos/main/Zope3/trunk/src/pytz zodbcode -r 40549 svn://svn.zope.org/repos/main/Zope3/trunk/src/zodbcode ClientCookie -r 40549 svn://svn.zope.org/repos/main/Zope3/trunk/src/ClientCookie mechanize -r 40549 svn://svn.zope.org/repos/main/Zope3/trunk/src/mechanize twisted svn://svn.twistedmatrix.com/svn/Twisted/branches/releases/2.1.x/twisted Modified: Zope/branches/publication-refactor/lib/python/Products/Five/configure.zcml =================================================================== --- Zope/branches/publication-refactor/lib/python/Products/Five/configure.zcml 2005-12-13 17:56:02 UTC (rev 40774) +++ Zope/branches/publication-refactor/lib/python/Products/Five/configure.zcml 2005-12-14 00:10:45 UTC (rev 40775) @@ -15,6 +15,14 @@ <include package="zope.app.event" /> <include package="zope.app.traversing" /> + <publisher + name="Zope2-HTTP" + factory="ZPublisher.Publication.Zope2HTTPFactory" + methods="*" + mimetypes="*" + priority="0" + /> + <!-- do 'traditional' traversing by default; needed by ZPT --> <adapter for="*" Modified: Zope/branches/publication-refactor/lib/python/Products/Five/meta.zcml =================================================================== --- Zope/branches/publication-refactor/lib/python/Products/Five/meta.zcml 2005-12-13 17:56:02 UTC (rev 40774) +++ Zope/branches/publication-refactor/lib/python/Products/Five/meta.zcml 2005-12-14 00:10:45 UTC (rev 40775) @@ -172,4 +172,7 @@ <!-- load the i18n:registerTranslations directive --> <include package="zope.app.i18n" file="meta.zcml" /> + <!-- load the zope:publisher directive --> + <include package="zope.app.publication" file="meta.zcml" /> + </configure> Modified: Zope/branches/publication-refactor/lib/python/ZPublisher/Publication.py =================================================================== --- Zope/branches/publication-refactor/lib/python/ZPublisher/Publication.py 2005-12-13 17:56:02 UTC (rev 40774) +++ Zope/branches/publication-refactor/lib/python/ZPublisher/Publication.py 2005-12-14 00:10:45 UTC (rev 40775) @@ -12,14 +12,22 @@ ############################################################################## __version__='$Revision$'[11:-2] +import re import sys import transaction + from zope.event import notify +from zope.component import queryUtility from zope.interface import implements from zope.publisher.interfaces import IRequest, IPublication from zope.publisher.interfaces import NotFound, IPublicationRequest +from zope.publisher.browser import BrowserRequest +from zope.publisher.browser import BrowserResponse +from zope.publisher.http import StrResult from zope.app.publication.interfaces import EndRequestEvent from zope.app.publication.interfaces import BeforeTraverseEvent +from zope.app.publication.interfaces import IBrowserRequestFactory +from zope.app.publication.interfaces import IRequestPublicationFactory from ZPublisher.Publish import Retry from ZPublisher.Publish import get_module_info, call_object @@ -27,6 +35,8 @@ from ZPublisher.mapply import mapply from ZPublisher.BaseRequest import RequestContainer +_marker = object() + class ZopePublication(object): """Base Zope2 publication specification. """ @@ -83,11 +93,7 @@ # If the top object has a __bobo_traverse__ method, then use it # to possibly traverse to an alternate top-level object. if hasattr(ob, '__bobo_traverse__'): - try: - ob = ob.__bobo_traverse__(request) - except: - # XXX Blind except? Yuck! - pass + ob = ob.__bobo_traverse__(request) if hasattr(ob, '__of__'): # Try to bind the top-level object to the request @@ -109,9 +115,12 @@ else: # It's a Zope 2 request. args = request.args - return mapply(ob, args, - request, call_object, 1, missing_name, - dont_publish_class, request, bind=1) + result = mapply(ob, args, + request, call_object, 1, missing_name, + dont_publish_class, request, bind=1) + if isinstance(request, Zope2BrowserRequest): + return StrResult(str(result)) + return result def afterCall(self, request, ob): # Last part of ZPublisher.Publish.{publish, publish_module_standard}, @@ -154,12 +163,13 @@ exc_info[2], ) except Retry: - if not retry_allowed: - return self.err_hook(object, request, - sys.exc_info()[0], - sys.exc_info()[1], - sys.exc_info()[2], - ) + if retry_allowed: + raise + return self.err_hook(object, request, + sys.exc_info()[0], + sys.exc_info()[1], + sys.exc_info()[2], + ) finally: self._abort() @@ -213,6 +223,13 @@ TypeError, AttributeError): raise NotFound(ob, name) + def getDefaultTraversal(self, request, ob): + if hasattr(ob, '__browser_default__'): + return object.__browser_default__(request) + if getattr(ob, 'index_html', None): + return ob, ['index_html'] + return ob, [] + _publications = {} def get_publication(module_name=None): if module_name is None: @@ -221,3 +238,166 @@ _publications[module_name] = ZopePublication(db=None, module_name=module_name) return _publications[module_name] + +tr = {'environ': '_environ', + 'TraversalRequestNameStack': '_traversal_stack', + 'RESPONSE': 'response'} + +class Zope2BrowserResponse(BrowserResponse): + + def badRequestError(self, name): + raise KeyError, name + + def _headers(self): + return dict(self.getHeaders()) + + headers = property(_headers) + +class Zope2BrowserRequest(BrowserRequest): + + def __init__(self, *args, **kw): + self.other = {'PARENTS':[]} + self._lazies = {} + self._file = None + self._urls = [] + BrowserRequest.__init__(self, *args, **kw) + + def _createResponse(self): + return Zope2BrowserResponse() + + def set_lazy(self, name, func): + self._lazies[name] = func + + _hold = BrowserRequest.hold + + def __getitem__(self, key, default=_marker): + v = self.get(key, default) + if v is _marker: + raise KeyError, key + return v + + def __getattr__(self, key, default=_marker): + v = self.get(key, default) + if v is _marker: + raise AttributeError, key + return v + + def traverse(self, object): + ob = super(BrowserRequest, self).traverse(object) + self.other['PARENTS'].append(ob) + return ob + + def set(self, key, value): + self.other[key] = value + + def get(self, key, default=None, returnTaints=0, + URLmatch=re.compile('URL(PATH)?([0-9]+)$').match, + BASEmatch=re.compile('BASE(PATH)?([0-9]+)$').match, + ): + """Get a variable value + + Return a value for the required variable name. + The value will be looked up from one of the request data + categories. The search order is environment variables, + other variables, form data, and then cookies. + + """ + from ZPublisher.HTTPRequest import isCGI_NAME, hide_key + + if (key in ('other', '_file', + '_lazies', '_urls') or tr.has_key(key)): + key = tr.get(key, key) + return object.__getattribute__(self, key) + + if key == 'REQUEST': return self + + other = self.other + if other.has_key(key): + return other[key] + + if key[:1]=='U': + match = URLmatch(key) + if match is not None: + pathonly, n = match.groups() + path = self._traversed_names + n = len(path) - int(n) + if n < 0: + raise KeyError, key + if pathonly: + path = [''] + path[:n] + else: + path = [other['SERVER_URL']] + path[:n] + URL = '/'.join(path) + if other.has_key('PUBLISHED'): + # Don't cache URLs until publishing traversal is done. + other[key] = URL + self._urls = self._urls + (key,) + return URL + + if isCGI_NAME(key) or key[:5] == 'HTTP_': + environ = self.environ + if environ.has_key(key) and (not hide_key(key)): + return environ[key] + return '' + + if key[:1]=='B': + match = BASEmatch(key) + if match is not None: + pathonly, n = match.groups() + path = self._traversed_names + n = int(n) + if n: + n = n - 1 + if len(path) < n: + raise KeyError, key + + v = path[:n] + else: + v = [''] + if pathonly: + v.insert(0, '') + else: + v.insert(0, other['SERVER_URL']) + URL = '/'.join(v) + if other.has_key('PUBLISHED'): + # Don't cache URLs until publishing traversal is done. + other[key] = URL + self._urls = self._urls + (key,) + return URL + + if key=='BODY' and self._file is not None: + p=self._file.tell() + self._file.seek(0) + v=self._file.read() + self._file.seek(p) + self.other[key]=v + return v + + if key=='BODYFILE' and self._file is not None: + v=self._file + self.other[key]=v + return v + + if self._lazies: + v = self._lazies.get(key, _marker) + if v is not _marker: + if callable(v): v = v() + self[key] = v # Promote lazy value + del self._lazies[key] + return v + + v = super(Zope2BrowserRequest, self).get(key, _marker) + if v is not _marker: return v + + return default + + +class Zope2HTTPFactory(object): + + implements(IRequestPublicationFactory) + + def canHandle(self, environment): + return True + + def __call__(self): + return Zope2BrowserRequest, ZopePublication Modified: Zope/branches/publication-refactor/lib/python/Zope2/Startup/__init__.py =================================================================== --- Zope/branches/publication-refactor/lib/python/Zope2/Startup/__init__.py 2005-12-13 17:56:02 UTC (rev 40774) +++ Zope/branches/publication-refactor/lib/python/Zope2/Startup/__init__.py 2005-12-14 00:10:45 UTC (rev 40775) @@ -20,12 +20,11 @@ import socket from re import compile from socket import gethostbyaddr +import twisted.internet.reactor import ZConfig - from ZConfig.components.logger import loghandler - logger = logging.getLogger("Zope") started = False @@ -106,10 +105,11 @@ def run(self): # the mainloop. try: - import ZServer - import Lifetime - Lifetime.loop() - sys.exit(ZServer.exit_code) + #import ZServer + #import Lifetime + #Lifetime.loop() + #sys.exit(ZServer.exit_code) + twisted.internet.reactor.run() finally: self.shutdown() Modified: Zope/branches/publication-refactor/lib/python/Zope2/Startup/handlers.py =================================================================== --- Zope/branches/publication-refactor/lib/python/Zope2/Startup/handlers.py 2005-12-13 17:56:02 UTC (rev 40774) +++ Zope/branches/publication-refactor/lib/python/Zope2/Startup/handlers.py 2005-12-14 00:10:45 UTC (rev 40775) @@ -1,8 +1,15 @@ import os import sys +import time +import logging from re import compile from socket import gethostbyaddr +import twisted.internet +import zope.event +import zope.app.appsetup.interfaces +import zope.app.twisted.main + # top-level key handlers @@ -133,7 +140,7 @@ "'catalog-getObject-raises' option will be removed in Zope 2.10:\n", DeprecationWarning) - from Products.ZCatalog import CatalogBrains + from Products.ZCatalog import CatalogBrains CatalogBrains.GETOBJECT_RAISES = bool(value) return value @@ -143,7 +150,8 @@ def root_handler(config): """ Mutate the configuration with defaults and perform fixups of values that require knowledge about configuration - values outside of their context. """ + values outside of their context. + """ # Set environment variables for k,v in config.environment.items(): @@ -165,7 +173,7 @@ instanceprod = os.path.join(config.instancehome, 'Products') if instanceprod not in config.products: config.products.append(instanceprod) - + import Products L = [] for d in config.products + Products.__path__: @@ -190,6 +198,26 @@ config.cgi_environment, config.port_base) + if not config.twisted_servers: + config.twisted_servers = [] + else: + db = object() # config.db_tab.getDatabase(mount_point='/') + zope.event.notify(zope.app.appsetup.interfaces.DatabaseOpened(db)) + + # Set number of threads (reuse zserver_threads variable) + twisted.internet.reactor.suggestThreadPoolSize(config.zserver_threads) + + # Create a root service + rootService = zope.app.twisted.main.ZopeService() + + for server in config.twisted_servers: + service = server.create(db) + service.setServiceParent(rootService) + + rootService.startService() + twisted.internet.reactor.addSystemEventTrigger( + 'before', 'shutdown', rootService.stopService) + # set up trusted proxies if config.trusted_proxies: import ZPublisher.HTTPRequest @@ -217,3 +245,29 @@ if isIp_(host): return [host] return gethostbyaddr(host)[2] +# XXX Need to find a better place for this. + +import twisted.web2.wsgi +import twisted.web2.server +import twisted.web2.log + +try: + from twisted.web2.http import HTTPFactory +except ImportError: + from twisted.web2.channel.http import HTTPFactory + +from zope.component import provideUtility +from zope.app import wsgi +from zope.app.twisted.server import ServerType, SSLServerType +from zope.app.twisted.interfaces import IServerType + +def createHTTPFactory(db): + resource = twisted.web2.wsgi.WSGIResource( + wsgi.WSGIPublisherApplication(db)) + resource = twisted.web2.log.LogWrapperResource(resource) + + return HTTPFactory(twisted.web2.server.Site(resource)) + +http = ServerType(createHTTPFactory, 8080) + +provideUtility(http, IServerType, 'Zope2-HTTP') Modified: Zope/branches/publication-refactor/lib/python/Zope2/Startup/zopeschema.xml =================================================================== --- Zope/branches/publication-refactor/lib/python/Zope2/Startup/zopeschema.xml 2005-12-13 17:56:02 UTC (rev 40774) +++ Zope/branches/publication-refactor/lib/python/Zope2/Startup/zopeschema.xml 2005-12-14 00:10:45 UTC (rev 40775) @@ -11,6 +11,12 @@ <import package="tempstorage"/> <import package="Zope2.Startup" file="warnfilter.xml"/> + <sectiontype name="server" datatype="zope.app.twisted.server.ServerFactory"> + <key name="type" required="yes" /> + <key name="address" datatype="inet-address" /> + <key name="backlog" datatype="integer" default="50" /> + </sectiontype> + <sectiontype name="logger" datatype=".LoggerFactory"> <description> This "logger" type only applies to access and request ("trace") @@ -791,7 +797,9 @@ <metadefault>on</metadefault> </key> + <multisection type="server" name="*" attribute="twisted_servers" /> <multisection type="ZServer.server" name="*" attribute="servers"/> + <key name="port-base" datatype="integer" default="0"> <description> Base port number that gets added to the specific port numbers _______________________________________________ Zope-Checkins maillist - Zope-Checkins@zope.org http://mail.zope.org/mailman/listinfo/zope-checkins