[Checkins] SVN: zc.zope3recipes/trunk/ - Added support for using Paste Deployment to specify a WSGI stack
Jim Fulton
jim at zope.com
Sun Jan 15 16:15:14 UTC 2012
Log message for revision 124047:
- Added support for using Paste Deployment to specify a WSGI stack
over a zope.app-based application,
Changed:
U zc.zope3recipes/trunk/README.txt
U zc.zope3recipes/trunk/setup.py
U zc.zope3recipes/trunk/zc/zope3recipes/README.txt
U zc.zope3recipes/trunk/zc/zope3recipes/recipes.py
U zc.zope3recipes/trunk/zc/zope3recipes/tests.py
-=-
Modified: zc.zope3recipes/trunk/README.txt
===================================================================
--- zc.zope3recipes/trunk/README.txt 2012-01-15 08:35:49 UTC (rev 124046)
+++ zc.zope3recipes/trunk/README.txt 2012-01-15 16:15:13 UTC (rev 124047)
@@ -21,6 +21,13 @@
********
===================
+0.16.0 (2012/01/15)
+===================
+
+- Added support for using Paste Deployment to specify a WSGI stack
+ over a zope.app-based application,
+
+===================
0.15.0 (2011/12/12)
===================
Modified: zc.zope3recipes/trunk/setup.py
===================================================================
--- zc.zope3recipes/trunk/setup.py 2012-01-15 08:35:49 UTC (rev 124046)
+++ zc.zope3recipes/trunk/setup.py 2012-01-15 16:15:13 UTC (rev 124047)
@@ -1,3 +1,18 @@
+##############################################################################
+#
+# Copyright Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+name, version = "zc.zope3recipes", "0"
+
import os
from setuptools import setup, find_packages
@@ -4,10 +19,9 @@
def read(*rnames):
return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
-name = "zc.zope3recipes"
setup(
name = name,
- version = '0',
+ version = version,
author = "Jim Fulton",
author_email = "jim at zope.com",
description = "ZC Buildout recipe for defining Zope 3 applications",
@@ -44,7 +58,7 @@
],
},
extras_require = dict(
- tests = ['zdaemon', 'zc.recipe.filestorage'],
+ tests = ['zdaemon', 'zc.recipe.filestorage', 'PasteScript'],
),
classifiers=[
"Development Status :: 5 - Production/Stable",
Modified: zc.zope3recipes/trunk/zc/zope3recipes/README.txt
===================================================================
--- zc.zope3recipes/trunk/zc/zope3recipes/README.txt 2012-01-15 08:35:49 UTC (rev 124046)
+++ zc.zope3recipes/trunk/zc/zope3recipes/README.txt 2012-01-15 16:15:13 UTC (rev 124047)
@@ -3029,3 +3029,219 @@
<BLANKLINE>
# print "starting debugzope..."
execfile(debugzope)
+
+Paste-deployment support
+========================
+
+You can use paste-deployment to control WSGI servers and middleware.
+You indicate this by specifying ``paste`` in the ``servers`` option:
+
+ >>> write('buildout.cfg',
+ ... '''
+ ... [buildout]
+ ... develop = demo1 demo2
+ ... parts = instance
+ ...
+ ... [zope3]
+ ... location = %(zope3)s
+ ...
+ ... [myapp]
+ ... recipe = zc.zope3recipes:application
+ ... servers = paste
+ ... site.zcml = <include package="demo2" />
+ ... <principal
+ ... id="zope.manager"
+ ... title="Manager"
+ ... login="jim"
+ ... password_manager="SHA1"
+ ... password="40bd001563085fc35165329ea1ff5c5ecbdbbeef"
+ ... />
+ ... <grant
+ ... role="zope.Manager"
+ ... principal="zope.manager"
+ ... />
+ ... eggs = demo2
+ ...
+ ... [instance]
+ ... recipe = zc.zope3recipes:instance
+ ... application = myapp
+ ... zope.conf =
+ ... threads 1
+ ... ${database:zconfig}
+ ...
+ ...
+ ... [database]
+ ... recipe = zc.recipe.filestorage
+ ... ''' % globals())
+
+When we run the buildout, we'll get a paste-based runzope script and
+paste-based instance start scripts.
+
+.. test
+
+ >>> print system(join('bin', 'buildout')),
+ Develop: '/sample-buildout/demo1'
+ Develop: '/sample-buildout/demo2'
+ Uninstalling run-foo.
+ Uninstalling instance.
+ Uninstalling myapp.
+ Installing database.
+ Installing myapp.
+ Generated script '/sample-buildout/parts/myapp/runzope'.
+ Generated script '/sample-buildout/parts/myapp/debugzope'.
+ Installing instance.
+ Generated script '/sample-buildout/bin/instance'.
+
+
+ >>> cat('parts', 'myapp', 'runzope')
+ #!/usr/local/python/2.6/bin/python2.6
+ <BLANKLINE>
+ import sys
+ sys.path[0:0] = [
+ '/sample-buildout/demo2',
+ '/sample-buildout/eggs/PasteScript-1.7.4.2-py2.6.egg',
+ '/sample-buildout/eggs/setuptools-0.6c12dev_r88846-py2.6.egg',
+ '/sample-buildout/eggs/PasteDeploy-1.5.0-py2.6.egg',
+ '/sample-buildout/eggs/Paste-1.7.5.1-py2.6.egg',
+ '/sample-buildout/demo1',
+ ]
+ <BLANKLINE>
+ <BLANKLINE>
+ import paste.script.command
+ <BLANKLINE>
+ if __name__ == '__main__':
+ paste.script.command.run(['serve']+sys.argv[1:])
+
+
+ >>> cat('parts', 'instance', 'zope.conf')
+ site-definition /sample-buildout/parts/myapp/site.zcml
+ <BLANKLINE>
+ <zodb>
+ <filestorage>
+ path /sample-buildout/parts/database/Data.fs
+ </filestorage>
+ </zodb>
+ <BLANKLINE>
+ <logger accesslog>
+ level info
+ name accesslog
+ propagate false
+ <BLANKLINE>
+ <logfile>
+ format %(message)s
+ path /sample-buildout/parts/instance/access.log
+ </logfile>
+ </logger>
+ <BLANKLINE>
+ <eventlog>
+ <logfile>
+ formatter zope.exceptions.log.Formatter
+ path STDOUT
+ </logfile>
+ </eventlog>
+
+ >>> cat('parts', 'instance', 'zdaemon.conf')
+ <runner>
+ daemon on
+ directory /sample-buildout/parts/instance
+ program /sample-buildout/parts/myapp/runzope /sample-buildout/parts/instance/paste.ini
+ socket-name /sample-buildout/parts/instance/zdaemon.sock
+ transcript /sample-buildout/parts/instance/z3.log
+ </runner>
+ <BLANKLINE>
+ <eventlog>
+ <logfile>
+ path /sample-buildout/parts/instance/z3.log
+ </logfile>
+ </eventlog>
+
+We also get a paste.ini file in the instance directory, which defines
+the application and server and is used when running paste::
+
+ >>> cat('parts', 'instance', 'paste.ini')
+ [app:main]
+ use = egg:zope.app.wsgi
+ config_file = /sample-buildout/parts/instance/zope.conf
+ filter-with = translogger
+ <BLANKLINE>
+ [filter:translogger]
+ use = egg:Paste#translogger
+ setup_console_handler = False
+ logger_name = accesslog
+ <BLANKLINE>
+ [server:main]
+ use = egg:zope.server
+ host =
+ port = 8080
+ threads = 1
+
+Note that the threads setting made in zope.conf was moved to paste.ini
+
+Note too that past:translogger was used to provide an access log.
+
+If you don't want to use zope.server, or if you want to control the
+server configuration yourself, you can provide a paste.init option::
+
+ >>> write('buildout.cfg',
+ ... '''
+ ... [buildout]
+ ... develop = demo1 demo2
+ ... parts = instance
+ ...
+ ... [zope3]
+ ... location = %(zope3)s
+ ...
+ ... [myapp]
+ ... recipe = zc.zope3recipes:application
+ ... servers = paste
+ ... site.zcml = <include package="demo2" />
+ ... <principal
+ ... id="zope.manager"
+ ... title="Manager"
+ ... login="jim"
+ ... password_manager="SHA1"
+ ... password="40bd001563085fc35165329ea1ff5c5ecbdbbeef"
+ ... />
+ ... <grant
+ ... role="zope.Manager"
+ ... principal="zope.manager"
+ ... />
+ ... eggs = demo2
+ ...
+ ... [instance]
+ ... recipe = zc.zope3recipes:instance
+ ... application = myapp
+ ... zope.conf =
+ ... threads 1
+ ... ${database:zconfig}
+ ... paste.ini = test and not working :)
+ ...
+ ...
+ ... [database]
+ ... recipe = zc.recipe.filestorage
+ ... ''' % globals())
+
+.. test
+
+ >>> print system(join('bin', 'buildout')),
+ Develop: '/sample-buildout/demo1'
+ Develop: '/sample-buildout/demo2'
+ Uninstalling instance.
+ Updating database.
+ Updating myapp.
+ Installing instance.
+ Generated script '/sample-buildout/bin/instance'.
+
+In this example, we gave useless text in the paste.ini option and we
+got a nonsense paste.ini file::
+
+ >>> cat('parts', 'instance', 'paste.ini')
+ [app:main]
+ use = egg:zope.app.wsgi
+ config_file = /sample-buildout/parts/instance/zope.conf
+ <BLANKLINE>
+ test and not working :)
+
+This illustrates that the recipe doesn't care what you provide. It
+uses it with the application definition instead of supplying
+zope.server and paste.translogger definition.
Modified: zc.zope3recipes/trunk/zc/zope3recipes/recipes.py
===================================================================
--- zc.zope3recipes/trunk/zc/zope3recipes/recipes.py 2012-01-15 08:35:49 UTC (rev 124046)
+++ zc.zope3recipes/trunk/zc/zope3recipes/recipes.py 2012-01-15 16:15:13 UTC (rev 124047)
@@ -14,14 +14,17 @@
"""Collected Zope 3 recipes
"""
-import os, sys, shutil
+import cStringIO
import logging
+import os
+import pkg_resources
import pprint
+import re
+import shutil
+import sys
import zc.buildout
+import ZConfig.schemaless
import zc.recipe.egg
-import pkg_resources
-import ZConfig.schemaless
-import cStringIO
this_loc = pkg_resources.working_set.find(
pkg_resources.Requirement.parse('zc.zope3recipes')).location
@@ -30,6 +33,7 @@
# name (module, http-name)
'twisted': ('zope.app.twisted.main', 'HTTP'),
'zserver': ('zope.app.server.main', 'WSGI-HTTP'),
+ 'paste': ('zope.app.server.main', ''),
}
WIN = False
@@ -51,7 +55,11 @@
options['servers'] = options.get('servers', 'twisted')
if options['servers'] not in server_types:
raise ValueError(
- 'servers setting must be one of "twisted" or "zserver"')
+ 'servers setting must be one of %s' %
+ repr(sorted(server_types))[1:-1]
+ )
+ if options['servers'] == 'paste':
+ options['eggs'] += '\n PasteScript\n'
options['scripts'] = ''
self.egg = zc.recipe.egg.Egg(buildout, name, options)
@@ -74,14 +82,27 @@
self.egg.install()
requirements, ws = self.egg.working_set()
+ server_module = server_types[options['servers']][0]
+
# install subprograms and ctl scripts
- server_module = server_types[options['servers']][0]
+ if options['servers'] == 'paste':
+ reqs = ['PasteScript']
+ scripts = dict(paster='runzope')
+ arguments = "['serve']+sys.argv[1:]"
+ else:
+ reqs = [('runzope', server_module, 'main')]
+ scripts = None
+ arguments = ''
+
extra_paths = options.get('extra-paths', '')
initialization = options.get('initialization') or ''
+
zc.buildout.easy_install.scripts(
- [('runzope', server_module, 'main')],
+ reqs,
ws, options['executable'], dest,
+ scripts=scripts,
extra_paths=extra_paths.split(),
+ arguments=arguments,
initialization=initialization,
relative_paths=self.egg._relative_paths,
)
@@ -222,6 +243,8 @@
self.name+'-zope.conf')
zdaemon_conf_path = os.path.join(options['etc-directory'],
self.name+'-zdaemon.conf')
+ paste_ini_path = os.path.join(options['etc-directory'],
+ self.name+'-paste.ini')
event_log_path = os.path.join(options['log-directory'],
self.name+'-z3.log')
access_log_path = os.path.join(options['log-directory'],
@@ -250,6 +273,7 @@
else:
zope_conf_path = os.path.join(run_directory, 'zope.conf')
zdaemon_conf_path = os.path.join(run_directory, 'zdaemon.conf')
+ paste_ini_path = os.path.join(run_directory, 'paste.ini')
event_log_path = os.path.join(run_directory, 'z3.log')
access_log_path = os.path.join(run_directory, 'access.log')
socket_path = os.path.join(run_directory, 'zdaemon.sock')
@@ -272,21 +296,76 @@
os.path.join(app_loc, 'site.zcml')
]
+ threads = None
server_type = server_types[options['servers']][1]
- for address in options.get('address', '').split():
- zope_conf.sections.append(
- ZConfig.schemaless.Section(
- 'server',
- data=dict(type=[server_type], address=[address]))
- )
- if not [s for s in zope_conf.sections
- if ('server' in s.type)]:
- zope_conf.sections.append(
- ZConfig.schemaless.Section(
- 'server',
- data=dict(type=[server_type], address=['8080']))
- )
+ if server_type:
+ for address in options.get('address', '').split():
+ zope_conf.sections.append(
+ ZConfig.schemaless.Section(
+ 'server',
+ data=dict(type=[server_type], address=[address]))
+ )
+ if not [s for s in zope_conf.sections
+ if ('server' in s.type)]:
+ zope_conf.sections.append(
+ ZConfig.schemaless.Section(
+ 'server',
+ data=dict(type=[server_type], address=['8080']))
+ )
+ program_args = '-C '+zope_conf_path
+ else: # paste
+ paste_ini = options.get('paste.ini', '')
+ if not paste_ini:
+ address = options.get('address', '8080').split()
+ if not len(address) == 1:
+ raise zc.buildout.UserError(
+ "If you don't specify a paste.ini option, "
+ "you must specify exactly one address.")
+ [address] = address
+ if ':' in address:
+ host, port = address.rsplit(':', 1)
+ port = int(port)
+ elif re.match('\d+$', address):
+ host = ''
+ port = int(address)
+ else:
+ host = address
+ port = 8080
+ threads = zope_conf.pop('threads', None)
+ threads = threads and threads[0] or 4
+
+ paste_ini = (
+ "filter-with = translogger\n"
+ "\n"
+ "[filter:translogger]\n"
+ "use = egg:Paste#translogger\n"
+ "setup_console_handler = False\n"
+ "logger_name = accesslog\n"
+ "\n"
+ ""
+ "[server:main]\n"
+ "use = egg:zope.server\n"
+ "host = %s\n"
+ "port = %s\n"
+ "threads = %s\n"
+ % (host, port, threads)
+ )
+
+ paste_ini = (
+ "[app:main]\n"
+ "use = egg:zope.app.wsgi\n"
+ "config_file = %s\n"
+ % zope_conf_path) + paste_ini
+
+ creating.append(paste_ini_path)
+ f = open(paste_ini_path, 'w')
+ f.write(paste_ini)
+ f.close()
+
+ program_args = paste_ini_path
+
+
if not [s for s in zope_conf.sections if s.type == 'zodb']:
raise zc.buildout.UserError(
'No database sections have been defined.')
@@ -294,6 +373,18 @@
if not [s for s in zope_conf.sections if s.type == 'accesslog']:
zope_conf.sections.append(access_log(access_log_path))
+ if not server_type: # paste
+ for s in zope_conf.sections:
+ if s.type != 'accesslog':
+ continue
+ s.type = 'logger'
+ s.name = 'accesslog'
+ s['name'] = [s.name]
+ s['level'] = ['info']
+ s['propagate'] = ['false']
+ for formatter in s.sections:
+ formatter['format'] = ['%(message)s']
+
if not [s for s in zope_conf.sections if s.type == 'eventlog']:
zope_conf.sections.append(event_log('STDOUT'))
@@ -303,9 +394,8 @@
cStringIO.StringIO(zdaemon_conf))
defaults = {
- 'program': "%s -C %s" % (os.path.join(app_loc, 'runzope'),
- zope_conf_path,
- ),
+ 'program': "%s %s" % (os.path.join(app_loc, 'runzope'),
+ program_args),
'daemon': 'on',
'transcript': event_log_path,
'socket-name': socket_path,
@@ -436,10 +526,7 @@
return ZConfig.schemaless.Section(
'eventlog', '', None,
[ZConfig.schemaless.Section(
- 'logfile',
- '',
- dict(path=[path])),
- ])
+ 'logfile', '', dict(path=[path]))])
logrotate_template = """%(logfile)s {
Modified: zc.zope3recipes/trunk/zc/zope3recipes/tests.py
===================================================================
--- zc.zope3recipes/trunk/zc/zope3recipes/tests.py 2012-01-15 08:35:49 UTC (rev 124046)
+++ zc.zope3recipes/trunk/zc/zope3recipes/tests.py 2012-01-15 16:15:13 UTC (rev 124047)
@@ -209,6 +209,9 @@
zc.buildout.testing.install_develop('zc.zope3recipes', test)
zc.buildout.testing.install('zope.exceptions', test)
zc.buildout.testing.install('zope.interface', test)
+ zc.buildout.testing.install('PasteScript', test)
+ zc.buildout.testing.install('PasteDeploy', test)
+ zc.buildout.testing.install('Paste', test)
zc.buildout.testing.install('zope.testing', test)
zc.buildout.testing.install('zc.recipe.egg', test)
zc.buildout.testing.install('zdaemon', test)
More information about the checkins
mailing list