diff --git a/src/plone/recipe/zope2instance/recipe.py b/src/plone/recipe/zope2instance/recipe.py
new file mode 100644
index 00000000..5dd6ad95
--- /dev/null
+++ b/src/plone/recipe/zope2instance/recipe.py
@@ -0,0 +1,1127 @@
+# -*- coding: utf-8 -*-
+# ##############################################################################
+#
+# Copyright (c) 2006-2008 Zope Corporation 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.
+#
+##############################################################################
+
+from plone.recipe.zope2instance import make
+from zc.recipe.egg.egg import Egg
+from zc.recipe.egg.egg import Scripts
+
+import os
+import os.path
+import re
+import shutil
+import sys
+import zc.buildout
+import zc.buildout.easy_install
+
+
+IS_WIN = sys.platform[:3].lower() == 'win'
+
+BUILDOUT15 = True
+try:
+ from zc.buildout.easy_install import sitepackage_safe_scripts
+except ImportError:
+ BUILDOUT15 = False
+
+
+def indent(snippet, amount):
+ ws = " " * amount
+ return "\n".join(ws + s if s else "" for s in snippet.split('\n'))
+
+
+class Recipe(Scripts):
+
+ def __init__(self, buildout, name, options):
+ self.egg = Egg(buildout, options['recipe'], options)
+ self.buildout, self.options, self.name = buildout, options, name
+ self.scripts = True
+
+ options['location'] = os.path.join(
+ buildout['buildout']['parts-directory'],
+ self.name,
+ )
+ options['bin-directory'] = buildout['buildout']['bin-directory']
+
+ if 'initialization' not in options:
+ options['initialization'] = ''
+
+ if 'scripts' in options:
+ if options['scripts'] == '':
+ options['scripts'] = '' # suppress script generation.
+ self.scripts = False
+
+ # Relative path support for the generated scripts
+ relative_paths = options.get(
+ 'relative-paths',
+ buildout['buildout'].get('relative-paths', 'false')
+ )
+ if relative_paths == 'true':
+ options['buildout-directory'] = buildout['buildout']['directory']
+ self._relative_paths = options['buildout-directory']
+ else:
+ self._relative_paths = ''
+
+ self._include_site_packages = options.get(
+ 'include-site-packages',
+ buildout['buildout'].get('include-site-packages', 'false')
+ ) not in ('off', 'disable', 'false')
+
+ self.wsgi = options.get('wsgi') in ('waitress', 'on')
+ # Get Scripts' attributes
+ return Scripts.__init__(self, buildout, name, options)
+
+ def install(self, update=False):
+ options = self.options
+ location = options['location']
+ installed = [location]
+
+ if not update:
+ if os.path.exists(location):
+ shutil.rmtree(location)
+
+ # We could check with pkg_resources which Zope version we have.
+ # But we support creating instances for 4 only.
+ version = '4'
+ make.make_instance(options.get('user', None), location, version)
+
+ try:
+ # Make a new zope.conf based on options in buildout.cfg
+ self.build_zope_conf()
+
+ # Install extra scripts
+ installed.extend(self.install_scripts())
+
+ # Add zcml files to package-includes
+ self.build_package_includes()
+ except:
+ # clean up
+ if os.path.exists(location):
+ shutil.rmtree(location)
+ raise
+
+ if self.scripts:
+ retval = Scripts.install(self)
+ retval.extend(installed)
+ else:
+ retval = installed
+ return retval
+
+ def update(self):
+ return self.install(update=True)
+
+ def build_zope_conf(self):
+ """Create a zope.conf file
+ """
+
+ options = self.options
+ location = options['location']
+ # Don't do this if we have a manual zope.conf
+ zope_conf_path = options.get('zope-conf', None)
+ if zope_conf_path is not None:
+ return
+
+ imports = options.get('zope-conf-imports', '')
+ if imports:
+ imports = imports.split('\n')
+ # Filter out empty lines
+ imports = [i for i in imports if i]
+ imports_lines = '\n'.join(('%%import %s' % i for i in imports))
+
+ products = options.get('products', '')
+ if products:
+ products = products.split('\n')
+ # Filter out empty directories
+ products = [p for p in products if p]
+ # Make sure we have consistent path seperators
+ products = [os.path.abspath(p) for p in products]
+
+ base_dir = self.buildout['buildout']['directory']
+ var_dir = options.get('var', os.path.join(base_dir, 'var'))
+ if not os.path.exists(var_dir):
+ os.makedirs(var_dir)
+
+ instance_home = location
+ client_home = options.get('client-home', os.path.join(var_dir,
+ self.name))
+ if not os.path.exists(client_home):
+ os.makedirs(client_home)
+
+ client_import = options.get('import-directory', os.path.join(
+ client_home, 'import'))
+ if not os.path.exists(client_import):
+ os.makedirs(client_import)
+
+ products_lines = '\n'.join(['products %s' % p for p in products])
+ module_paths = options.get('extra-paths', '')
+ if module_paths:
+ module_paths = module_paths.split('\n')
+ # Filter out empty directories
+ module_paths = [p for p in module_paths if p]
+ # Make sure we have consistent path seperators
+ module_paths = [os.path.abspath(p) for p in module_paths]
+ paths_lines = '\n'.join(['path %s' % p for p in module_paths])
+ debug_mode = options.get('debug-mode', 'off')
+ security_implementation = 'C'
+ verbose_security = options.get('verbose-security', 'off')
+ if verbose_security == 'on':
+ security_implementation = 'python'
+ port_base = options.get('port-base', '')
+ if port_base:
+ port_base = 'port-base %s' % port_base
+ http_force_connection_close = options.get('http-force-connection-close', None)
+ if http_force_connection_close is None:
+ http_force_connection_close = ''
+ else:
+ http_force_connection_close = http_force_connection_close_template % http_force_connection_close
+ http_fast_listen = options.get('http-fast-listen', None)
+ if http_fast_listen is None:
+ http_fast_listen = ''
+ else:
+ http_fast_listen = http_fast_listen_template % http_fast_listen
+ http_address = options.get('http-address', '8080')
+ if http_address:
+ http_address = http_server_template % dict(
+ http_address=http_address,
+ http_force_connection_close=http_force_connection_close,
+ http_fast_listen=http_fast_listen)
+ ftp_address = options.get('ftp-address', '')
+ if ftp_address:
+ ftp_address = ftp_server_template % ftp_address
+ webdav_address = options.get('webdav-address', '')
+ if webdav_address:
+ webdav_conn_close = options.get(
+ 'webdav-force-connection-close',
+ 'off')
+ webdav_address = webdav_server_template % (webdav_address,
+ webdav_conn_close)
+ icp_address = options.get('icp-address', '')
+ if icp_address:
+ icp_address = icp_server_template % icp_address
+ http_header_max_length = options.get('http-header-max-length', '8192')
+ if http_header_max_length:
+ http_header_max_length = 'http-header-max-length %s' % http_header_max_length
+ effective_user = options.get('effective-user', '')
+ if effective_user:
+ effective_user = 'effective-user %s' % effective_user
+ ip_address = options.get('ip-address', '')
+ if ip_address:
+ ip_address = 'ip-address %s' % ip_address
+ environment_vars = options.get('environment-vars', '')
+ if environment_vars:
+ # if the vars are all given on one line we need to do some work
+ if not '\n' in environment_vars:
+ keys = []
+ values = []
+ env_vars = environment_vars.split()
+ # split out the odd and even items into keys, values
+ for var in env_vars:
+ if divmod(env_vars.index(var) + 1, 2)[1]:
+ keys.append(var)
+ else:
+ values.append(var)
+ env_vars = zip(keys, values)
+ environment_vars = '\n'.join(["%s %s" % (env_var[0], env_var[1])
+ for env_var in env_vars])
+ environment_vars = environment_template % environment_vars
+
+ deprecation_warnings = options.get('deprecation-warnings', '')
+ if deprecation_warnings:
+ if deprecation_warnings.lower() in ('off', 'disable', 'false'):
+ deprecation_warnings = 'ignore'
+ elif deprecation_warnings.lower() in ('enable', 'on', 'true'):
+ deprecation_warnings = 'default'
+ deprecation_warnings = '\n'.join((
+ "",
+ " action %s" % deprecation_warnings,
+ " category exceptions.DeprecationWarning",
+ ""))
+
+ zope_conf_additional = options.get('zope-conf-additional', '')
+
+ # logging
+
+ mailinglogger_config = options.get('mailinglogger', '')
+ mailinglogger_import = ''
+ if mailinglogger_config:
+ mailinglogger_config = mailinglogger_config.strip()
+ mailinglogger_import = '%import mailinglogger'
+
+ default_log = os.path.sep.join(('log', self.name + '.log',))
+ event_log_name = options.get('event-log', default_log)
+
+ if event_log_name.lower() == 'disable':
+ event_log = ''
+ else:
+ event_log_level = options.get('event-log-level', 'INFO')
+ custom_event_log = options.get('event-log-custom', None)
+ # log file
+ if not custom_event_log:
+ event_file = os.path.join(var_dir, event_log_name)
+ event_log_dir = os.path.dirname(event_file)
+ if not os.path.exists(event_log_dir):
+ os.makedirs(event_log_dir)
+ event_log_rotate = ''
+ event_log_max_size = options.get('event-log-max-size', None)
+ if event_log_max_size:
+ event_log_old_files = options.get('event-log-old-files', 1)
+ event_log_rotate = '\n'.join((
+ "max-size %s" % event_log_max_size,
+ " old-files %s" % event_log_old_files))
+ event_log = event_logfile % {'event_logfile': event_file,
+ 'event_log_level': event_log_level,
+ 'event_log_rotate': event_log_rotate}
+ # custom log
+ else:
+ event_log = custom_event_log
+
+ event_log = event_log_template % {
+ 'mailinglogger_config': mailinglogger_config,
+ 'event_log_level': event_log_level,
+ 'event_log': event_log,
+ }
+
+ z_log_name = os.path.sep.join(('log', self.name + '-Z2.log'))
+ z_log_name = options.get('z2-log', z_log_name)
+ if z_log_name.lower() == 'disable':
+ access_event_log = ''
+ else:
+ z_log = os.path.join(var_dir, z_log_name)
+ z_log_dir = os.path.dirname(z_log)
+ if not os.path.exists(z_log_dir):
+ os.makedirs(z_log_dir)
+
+ z_log_level = options.get('z2-log-level', 'WARN')
+
+ # access event log
+ custom_access_event_log = options.get('access-log-custom', None)
+ # filelog directive
+ if not custom_access_event_log:
+ access_log_rotate = ''
+ access_log_max_size = options.get('access-log-max-size', None)
+ if access_log_max_size:
+ access_log_old_files = options.get('access-log-old-files', 1)
+ access_log_rotate = '\n'.join((
+ "max-size %s" % access_log_max_size,
+ " old-files %s" % access_log_old_files))
+ access_event_log = access_event_logfile % {'z_log': z_log,
+ 'access_log_rotate': access_log_rotate}
+ # custom directive
+ else:
+ access_event_log = custom_access_event_log
+
+ access_event_log = access_log_template % {
+ 'z_log_level': z_log_level,
+ 'access_event_log': access_event_log,
+ }
+
+ default_zpublisher_encoding = options.get('default-zpublisher-encoding',
+ 'utf-8')
+ if default_zpublisher_encoding:
+ default_zpublisher_encoding = 'default-zpublisher-encoding %s' %\
+ default_zpublisher_encoding
+
+ zeo_client = options.get('zeo-client', '')
+ zeo_client = zeo_client.lower() in ('yes', 'true', 'on', '1')
+ shared_blob_dir = options.get('shared-blob', 'no')
+
+ before_storage = options.get('before-storage')
+ demo_storage = options.get('demo-storage', 'off') \
+ not in ('off', 'disable', 'false')
+
+ zlib = options.get('zlib-storage')
+
+ default_blob = os.path.join(var_dir, 'blobstorage')
+ default_file = os.path.sep.join(('filestorage', 'Data.fs',))
+
+ # Don't try to use the actual blobstorage as a cache
+ if zeo_client and shared_blob_dir == 'no':
+ default_blob = os.path.join(var_dir, 'blobcache')
+
+ # Only set blob storage default if we're using a before
+ # storage, or not a demo storage (otherwise, the default
+ # would be an invalid setting)
+ if demo_storage and not before_storage:
+ default_blob = None
+
+ blob_storage = options.get('blob-storage', default_blob)
+ file_storage = options.get('file-storage', default_file)
+
+ relstorage = options.get('rel-storage')
+ if relstorage:
+ def _split(el):
+ el = el.split(None, 1)
+ return len(el) == 2 and el or None
+
+ rel_storage = dict([
+ _split(el) for el in relstorage.splitlines()
+ if _split(el) is not None])
+ type_ = rel_storage.pop('type', 'postgresql')
+
+ if type_ == 'postgresql' and not 'dsn' in rel_storage:
+ # Support zope2instance 1.4 style interpolation for
+ # postgresql
+ template = ("dbname='%(dbname)s' user='%(user)s' "
+ "host='%(host)s' password='%(password)s'")
+ dsn = template % rel_storage
+ del rel_storage['dbname']
+ del rel_storage['user']
+ del rel_storage['host']
+ del rel_storage['password']
+ rel_storage['dsn'] = dsn
+
+ def is_rs_option(name):
+ # All generic RelStorage options have a dash in their name,
+ # except the "name" option. Other options are
+ # database-specific.
+ return '-' in name or name == 'name'
+
+ opts = dict(
+ type=type_,
+ db_opts='\n'.join(' ' * 12 + ' '.join((k, v))
+ for k, v in rel_storage.items()
+ if not is_rs_option(k)),
+ rs_opts='\n'.join(' ' * 8 + ' '.join((k, v))
+ for k, v in rel_storage.items()
+ if is_rs_option(k)),
+ )
+ file_storage_snippet = rel_storage_template % opts
+ else:
+ file_storage_snippet = self.render_file_storage(
+ file_storage, blob_storage, base_dir, var_dir, zlib)
+
+ zserver_threads = options.get('zserver-threads', '2')
+ if zserver_threads:
+ zserver_threads = 'zserver-threads %s' % zserver_threads
+
+ python_check_interval = options.get('python-check-interval', '1000')
+ if python_check_interval:
+ python_check_interval = "python-check-interval %s" % python_check_interval
+
+ enable_products = options.get('enable-product-installation', 'off')
+ if enable_products:
+ enable_products = "enable-product-installation %s" % enable_products
+
+ zeo_address = options.get('zeo-address', '8100')
+ zeo_addresses = zeo_address.split(' ')
+ zeo_address_list = ''
+ for address in zeo_addresses:
+ if not address:
+ continue
+ zeo_address_list += zeo_address_list_template % dict(
+ zeo_address = address)
+
+ zodb_cache_size = options.get('zodb-cache-size', '30000')
+ if zodb_cache_size:
+ zodb_cache_size = "cache-size %s" % zodb_cache_size
+ else:
+ zodb_cache_size = ""
+ zodb_cache_size_bytes = options.get('zodb-cache-size-bytes', None)
+ if zodb_cache_size_bytes:
+ zodb_cache_size_bytes = "cache-size-bytes %s" % zodb_cache_size_bytes
+ else:
+ zodb_cache_size_bytes = ""
+ zeo_client_cache_size = options.get('zeo-client-cache-size', '128MB')
+ zeo_storage = options.get('zeo-storage', '1')
+
+ if zeo_client:
+ if relstorage:
+ raise ValueError('You cannot use both ZEO and RelStorage '
+ 'at the same time.')
+
+ zeo_client_drop_cache_rather_verify = options.get('zeo-client-drop-cache-rather-verify', '')
+ if zeo_client_drop_cache_rather_verify:
+ zeo_client_drop_cache_rather_verify = 'drop-cache-rather-verify %s' % \
+ zeo_client_drop_cache_rather_verify
+ zeo_var_dir = options.get('zeo-var',
+ os.path.join(instance_home, 'var'))
+ zeo_client_client = options.get('zeo-client-client', '')
+ zeo_client_blob_cache_size = \
+ options.get('zeo-client-blob-cache-size', '')
+ zeo_client_blob_cache_size_check = \
+ options.get('zeo-client-blob-cache-size-check', '')
+ zeo_client_min_disconnect_poll = options.get('min-disconnect-poll', "")
+ zeo_client_max_disconnect_poll = options.get('max-disconnect-poll', "")
+ zeo_client_read_only_fallback = options.get('zeo-client-read-only-fallback', 'false')
+ if zeo_client_client:
+ zeo_client_client = 'client %s' % zeo_client_client
+ if zeo_client_blob_cache_size:
+ zeo_client_blob_cache_size = \
+ 'blob-cache-size %s' % zeo_client_blob_cache_size
+ if zeo_client_blob_cache_size_check:
+ zeo_client_blob_cache_size_check = \
+ 'blob-cache-size-check %s' % \
+ zeo_client_blob_cache_size_check
+ if zeo_client_min_disconnect_poll:
+ zeo_client_min_disconnect_poll = "min-disconnect-poll %s" % zeo_client_min_disconnect_poll
+ if zeo_client_max_disconnect_poll:
+ zeo_client_max_disconnect_poll = "max-disconnect-poll %s" % zeo_client_max_disconnect_poll
+ if zeo_client_read_only_fallback:
+ zeo_client_read_only_fallback = "read-only-fallback %s" % zeo_client_read_only_fallback
+ if options.get('zeo-username', ''):
+ if not options.get('zeo-password', ''):
+ raise zc.buildout.UserError('No ZEO password specified')
+
+ zeo_authentication = zeo_authentication_template % dict(
+ realm = options.get('zeo-realm', 'ZEO'),
+ username = options.get('zeo-username'),
+ password = options.get('zeo-password'))
+ else:
+ zeo_authentication = ''
+
+ if blob_storage:
+ storage_snippet_template = zeo_blob_storage_template
+ else:
+ storage_snippet_template = zeo_storage_template
+
+ storage_snippet = storage_snippet_template % dict(
+ blob_storage = blob_storage,
+ shared_blob_dir = shared_blob_dir,
+ zeo_address_list = zeo_address_list,
+ zeo_client_cache_size = zeo_client_cache_size,
+ zeo_client_blob_cache_size=zeo_client_blob_cache_size,
+ zeo_client_blob_cache_size_check=\
+ zeo_client_blob_cache_size_check,
+ zeo_authentication = zeo_authentication,
+ zeo_client_client = zeo_client_client,
+ zeo_storage = zeo_storage,
+ zeo_var_dir=zeo_var_dir,
+ zeo_client_drop_cache_rather_verify = zeo_client_drop_cache_rather_verify,
+ zeo_client_min_disconnect_poll=zeo_client_min_disconnect_poll,
+ zeo_client_max_disconnect_poll=zeo_client_max_disconnect_poll,
+ read_only=options.get('read-only', 'false'),
+ zeo_client_read_only_fallback=zeo_client_read_only_fallback
+ )
+ else:
+ # no zeo-client
+ zeo_client_client = ''
+ storage_snippet = file_storage_snippet
+
+ if before_storage:
+ storage_snippet = (before_storage_template % before_storage) % \
+ indent(storage_snippet, 2)
+
+ if demo_storage:
+ demo_file_storage = options.get('demo-file-storage')
+ demo_blob_storage = options.get('demo-blob-storage')
+
+ if demo_file_storage or demo_blob_storage:
+ base = storage_snippet.replace('>', ' base>', 1)
+ changes = self.render_file_storage(
+ demo_file_storage, demo_blob_storage, base_dir, var_dir, zlib).\
+ replace('>', ' changes>', 1)
+
+ storage_snippet = demo_storage2_template % (base, changes)
+
+ elif 'blob-storage' in options:
+ raise ValueError(
+ "Both blob and demo storage cannot be used"
+ " at the same time (use a before storage instead)."
+ )
+ else:
+ storage_snippet = demo_storage_template % storage_snippet
+
+ if options.get('storage-wrapper'):
+ storage_snippet = indent(options['storage-wrapper'] % storage_snippet, 4)
+
+ zodb_tmp_storage = options.get('zodb-temporary-storage',
+ zodb_temporary_storage_template)
+ template = wsgi_conf_template if self.wsgi else zope_conf_template
+
+ pid_file = options.get(
+ 'pid-file',
+ os.path.join(var_dir, self.name + '.pid'))
+ pid_file_dir = os.path.dirname(pid_file)
+ if not os.path.exists(pid_file_dir):
+ os.makedirs(pid_file_dir)
+
+ lock_file = options.get(
+ 'lock-file',
+ os.path.join(var_dir, self.name + '.lock'))
+ lock_file_dir = os.path.dirname(lock_file)
+ if not os.path.exists(lock_file_dir):
+ os.makedirs(lock_file_dir)
+
+ zope_conf = template % dict(instance_home = instance_home,
+ client_home = client_home,
+ imports_lines = imports_lines,
+ paths_lines = paths_lines,
+ products_lines = products_lines,
+ debug_mode = debug_mode,
+ security_implementation = security_implementation,
+ verbose_security = verbose_security,
+ effective_user = effective_user,
+ http_header_max_length = http_header_max_length,
+ ip_address = ip_address,
+ mailinglogger_import = mailinglogger_import,
+ event_log = event_log,
+ access_event_log = access_event_log,
+ default_zpublisher_encoding = default_zpublisher_encoding,
+ storage_snippet = storage_snippet,
+ port_base = port_base,
+ http_address = http_address,
+ http_force_connection_close = http_force_connection_close,
+ http_fast_listen = http_fast_listen,
+ ftp_address = ftp_address,
+ webdav_address = webdav_address,
+ icp_address = icp_address,
+ zserver_threads = zserver_threads,
+ zodb_cache_size = zodb_cache_size,
+ zodb_cache_size_bytes = zodb_cache_size_bytes,
+ zodb_tmp_storage = zodb_tmp_storage,
+ pid_file = pid_file,
+ lock_file = lock_file,
+ environment_vars = environment_vars,
+ deprecation_warnings = deprecation_warnings,
+ python_check_interval = python_check_interval,
+ enable_products = enable_products,
+ zope_conf_additional = zope_conf_additional,)
+
+ zope_conf = '\n'.join([l for l in zope_conf.splitlines() if l.rstrip()])
+ zope_conf_path = os.path.join(location, 'etc', 'zope.conf')
+ try:
+ fd = open(zope_conf_path, 'w')
+ fd.write(zope_conf)
+ finally:
+ fd.close()
+
+ def install_scripts(self):
+ options = self.options
+ location = options['location']
+
+ # The instance control script
+ zope_conf = os.path.join(location, 'etc', 'zope.conf')
+ zope_conf_path = options.get('zope-conf', zope_conf)
+ program_name = 'interpreter'
+ program_path = os.path.join(location, 'bin', program_name)
+
+ zopectl_umask = options.get('zopectl-umask', '')
+
+ extra_paths = options.get('extra-paths', '').split()
+ requirements, ws = self.egg.working_set(['plone.recipe.zope2instance'])
+ reqs = [self.options.get('control-script', self.name)]
+ if self.wsgi:
+ reqs.extend(['plone.recipe.zope2instance.wsgi', 'waitress_main'])
+ else:
+ reqs.extend(['plone.recipe.zope2instance.ctl', 'main'])
+ reqs = [tuple(reqs)]
+
+ if options.get('relative-paths'):
+ class relative_path_str(str):
+ def __repr__(self):
+ return str(self)
+
+ zope_conf_path = relative_path_str(
+ zc.buildout.easy_install._relativitize(
+ zope_conf,
+ options['buildout-directory'] + os.sep,
+ self._relative_paths
+ )
+ )
+ program_path = relative_path_str(
+ zc.buildout.easy_install._relativitize(
+ program_path,
+ options['buildout-directory'] + os.sep,
+ self._relative_paths
+ )
+ )
+
+ options['zope-conf'] = zope_conf_path
+ arguments = ["-C", zope_conf_path, '-p', program_path] \
+ if not self.wsgi else []
+ if zopectl_umask:
+ arguments.extend(["--umask", int(zopectl_umask, 8)])
+ script_arguments = ('\n ' + repr(arguments) +
+ '\n + sys.argv[1:]')
+
+ generated = self._install_scripts(
+ options['bin-directory'], ws, reqs=reqs, extra_paths=extra_paths,
+ script_arguments=script_arguments)
+ if not self.wsgi:
+ generated.extend(self._install_scripts(
+ os.path.join(options['location'], 'bin'), ws,
+ interpreter=program_name, extra_paths=extra_paths))
+ return generated
+
+ def _install_scripts(self, dest, working_set, reqs=(), interpreter=None,
+ extra_paths=(), script_arguments=''):
+ options = self.options
+ if BUILDOUT15:
+ return sitepackage_safe_scripts(
+ dest=dest,
+ working_set=working_set,
+ executable=options['executable'],
+ site_py_dest=options['location'],
+ reqs=reqs,
+ scripts=None,
+ interpreter=interpreter,
+ extra_paths=extra_paths,
+ initialization=options['initialization'],
+ include_site_packages=self._include_site_packages,
+ exec_sitecustomize=False,
+ relative_paths=self._relative_paths,
+ script_arguments=script_arguments,
+ )
+ else:
+ if self.wsgi:
+ initialization = wsgi_initialization % options
+ else:
+ initialization = options['initialization'] % options
+ return zc.buildout.easy_install.scripts(
+ dest=dest,
+ reqs=reqs,
+ working_set=working_set,
+ executable=options['executable'],
+ extra_paths=extra_paths,
+ initialization=initialization,
+ arguments=script_arguments,
+ interpreter=interpreter,
+ relative_paths=self._relative_paths,)
+
+ def build_package_includes(self):
+ """Create ZCML slugs in etc/package-includes
+ """
+ location = self.options['location']
+ sitezcml_path = os.path.join(location, 'etc', 'site.zcml')
+ zcml = self.options.get('zcml')
+ site_zcml = self.options.get('site-zcml')
+ additional_zcml = self.options.get("zcml-additional")
+ resources = self.options.get("resources")
+ locales = self.options.get("locales")
+
+ if site_zcml:
+ open(sitezcml_path, 'w').write(site_zcml)
+ return
+
+ if zcml:
+ zcml = zcml.split()
+
+ if additional_zcml or resources or locales or zcml:
+ includes_path = os.path.join(location, 'etc', 'package-includes')
+
+ if not os.path.exists(includes_path):
+ # Zope 2.9 does not have a package-includes so we
+ # create one.
+ os.mkdir(includes_path)
+ else:
+ if zcml and '*' in zcml:
+ zcml.remove('*')
+ else:
+ shutil.rmtree(includes_path)
+ os.mkdir(includes_path)
+
+ if additional_zcml:
+ additional_zcml = additional_zcml_template % additional_zcml
+ path=os.path.join(includes_path, "999-additional-overrides.zcml")
+ open(path, "w").write(additional_zcml.strip())
+
+ if resources:
+ resources_path = resources.strip()
+ path=os.path.join(includes_path, "998-resources-configure.zcml")
+ open(path, "w").write(
+ resources_zcml % dict(directory=resources_path)
+ )
+
+ if not os.path.exists(resources_path):
+ os.mkdir(resources_path)
+
+ if locales:
+ locales_path = locales.strip()
+ path=os.path.join(includes_path, "001-locales-configure.zcml")
+ open(path, "w").write(
+ locales_zcml % dict(directory=locales_path)
+ )
+
+ if not os.path.exists(locales_path):
+ os.mkdir(locales_path)
+
+ if zcml:
+ n = 1 # 001 is reserved for an optional locales-configure
+ package_match = re.compile('\w+([.]\w+)*$').match
+ for package in zcml:
+ n += 1
+ orig = package
+ if ':' in package:
+ package, filename = package.split(':')
+ else:
+ filename = None
+
+ if '-' in package:
+ package, suff = package.split('-')
+ file_suff = suff
+ if suff not in ('configure', 'meta', 'overrides'):
+ file_suff = '%s-configure' % suff
+ else:
+ suff = file_suff = 'configure'
+
+ if filename is None:
+ filename = suff + '.zcml'
+
+ if not package_match(package):
+ raise ValueError('Invalid zcml', orig)
+
+ path = os.path.join(
+ includes_path,
+ "%3.3d-%s-%s.zcml" % (n, package, file_suff),
+ )
+ open(path, 'w').write(
+ '\n'
+ % (package, filename)
+ )
+
+ def render_file_storage(self, file_storage, blob_storage,
+ base_dir, var_dir, zlib):
+ if file_storage:
+ file_storage = os.path.join(var_dir, file_storage)
+ file_storage_dir = os.path.dirname(file_storage)
+ if not os.path.exists(file_storage_dir):
+ os.makedirs(file_storage_dir)
+ storage = file_storage_template % file_storage
+ if zlib is not None:
+ if zlib == 'active':
+ compress = 'true'
+ elif zlib == 'passive':
+ compress = 'false'
+ else:
+ raise ValueError(
+ "Valid options for ``zlib-storage`` are "\
+ "('compress', 'uncompress'). Got: %s." % zlib
+ )
+
+ storage = zlib_storage_template % (
+ compress, indent(storage, 2)
+ )
+ else:
+ storage = " "
+
+ if not blob_storage:
+ return storage
+
+ blob_storage = os.path.join(base_dir, blob_storage)
+ if not os.path.exists(blob_storage):
+ # Make it only readable for the current user, otherwise
+ # you get a ZODB warning on startup.
+ os.makedirs(blob_storage, 0o700)
+
+ storage = indent(storage, 2)
+
+ return blob_storage_template % (blob_storage, storage)
+
+
+# Storage snippets for zope.conf template
+file_storage_template="""
+ # FileStorage database
+
+ path %s
+
+"""
+
+zlib_storage_template="""
+ %%import zc.zlibstorage
+ # ZlibStorage wrapper
+
+ compress %s
+%s
+
+"""
+
+demo_storage_template="""
+ # DemoStorage
+
+%s
+
+"""
+
+before_storage_template="""
+ %%%%import zc.beforestorage
+ # BeforeStorage
+
+ before %s
+ %%s
+
+"""
+
+demo_storage2_template="""
+ # DemoStorage
+
+%s
+%s
+
+"""
+
+rel_storage_template="""
+ %%import relstorage
+
+%(rs_opts)s
+ <%(type)s>
+%(db_opts)s
+ %(type)s>
+
+"""
+
+blob_storage_template="""
+ # Blob-enabled FileStorage database
+
+ blob-dir %s
+%s
+
+"""
+
+zeo_authentication_template="""
+ realm %(realm)s
+ username %(username)s
+ password %(password)s
+""".strip()
+
+zeo_address_list_template="""
+ server %(zeo_address)s
+"""
+
+zeo_storage_template="""
+ # ZEOStorage database
+
+ read-only %(read_only)s
+ %(zeo_client_read_only_fallback)s
+ %(zeo_address_list)s
+ storage %(zeo_storage)s
+ name zeostorage
+ var %(zeo_var_dir)s
+ cache-size %(zeo_client_cache_size)s
+ %(zeo_authentication)s
+ %(zeo_client_client)s
+ %(zeo_client_min_disconnect_poll)s
+ %(zeo_client_max_disconnect_poll)s
+ %(zeo_client_drop_cache_rather_verify)s
+
+""".strip()
+
+zeo_blob_storage_template="""
+ # Blob-enabled ZEOStorage database
+
+ read-only %(read_only)s
+ %(zeo_client_read_only_fallback)s
+ blob-dir %(blob_storage)s
+ shared-blob-dir %(shared_blob_dir)s
+ %(zeo_address_list)s
+ storage %(zeo_storage)s
+ name zeostorage
+ var %(zeo_var_dir)s
+ cache-size %(zeo_client_cache_size)s
+ %(zeo_client_blob_cache_size)s
+ %(zeo_client_blob_cache_size_check)s
+ %(zeo_authentication)s
+ %(zeo_client_client)s
+ %(zeo_client_min_disconnect_poll)s
+ %(zeo_client_max_disconnect_poll)s
+ %(zeo_client_drop_cache_rather_verify)s
+
+""".strip()
+
+zodb_temporary_storage_template="""
+
+ # Temporary storage database (for sessions)
+
+ name temporary storage for sessioning
+
+ mount-point /temp_folder
+ container-class Products.TemporaryFolder.TemporaryContainer
+
+""".strip()
+
+http_force_connection_close_template="""\
+ force-connection-close %s
+""".rstrip()
+
+http_fast_listen_template="""\
+ # Set to off to defer opening of the HTTP socket until the end of the
+ # startup phase:
+ fast-listen %s
+""".rstrip()
+
+event_logfile = """
+
+ path %(event_logfile)s
+ level %(event_log_level)s
+ %(event_log_rotate)s
+
+""".strip()
+
+access_event_logfile = """
+
+ path %(z_log)s
+ format %%(message)s
+ %(access_log_rotate)s
+
+""".strip()
+
+http_server_template = """
+
+ address %(http_address)s
+%(http_force_connection_close)s
+%(http_fast_listen)s
+
+"""
+
+ftp_server_template = """
+
+ # valid key is "address"
+ address %s
+
+"""
+
+icp_server_template = """
+
+ # valid key is "address"
+ address %s
+
+"""
+
+webdav_server_template = """
+
+ address %s
+ force-connection-close %s
+
+"""
+
+environment_template = """
+
+ %s
+
+"""
+
+# The template used to build zope.conf
+zope_conf_template="""\
+%(imports_lines)s
+%%define INSTANCEHOME %(instance_home)s
+instancehome $INSTANCEHOME
+%%define CLIENTHOME %(client_home)s
+clienthome $CLIENTHOME
+%(paths_lines)s
+%(products_lines)s
+debug-mode %(debug_mode)s
+security-policy-implementation %(security_implementation)s
+verbose-security %(verbose_security)s
+%(default_zpublisher_encoding)s
+%(port_base)s
+%(effective_user)s
+%(http_header_max_length)s
+%(ip_address)s
+%(zserver_threads)s
+%(environment_vars)s
+%(deprecation_warnings)s
+
+%(mailinglogger_import)s
+
+%(event_log)s
+
+%(access_event_log)s
+
+%(http_address)s
+%(ftp_address)s
+%(webdav_address)s
+%(icp_address)s
+
+
+ # Main database
+ %(zodb_cache_size)s
+ %(zodb_cache_size_bytes)s
+%(storage_snippet)s
+ mount-point /
+
+
+%(zodb_tmp_storage)s
+
+pid-filename %(pid_file)s
+lock-filename %(lock_file)s
+%(python_check_interval)s
+%(enable_products)s
+
+%(zope_conf_additional)s
+"""
+
+wsgi_conf_template = """\
+%(imports_lines)s
+%%define INSTANCEHOME %(instance_home)s
+instancehome $INSTANCEHOME
+%%define CLIENTHOME %(client_home)s
+clienthome $CLIENTHOME
+%(paths_lines)s
+%(products_lines)s
+debug-mode %(debug_mode)s
+security-policy-implementation %(security_implementation)s
+verbose-security %(verbose_security)s
+%(default_zpublisher_encoding)s
+%(port_base)s
+%(effective_user)s
+%(environment_vars)s
+%(deprecation_warnings)s
+
+%(mailinglogger_import)s
+
+
+ # Main database
+ %(zodb_cache_size)s
+ %(zodb_cache_size_bytes)s
+%(storage_snippet)s
+ mount-point /
+
+
+%(python_check_interval)s
+
+%(zope_conf_additional)s
+"""
+
+event_log_template = """\
+
+ %(mailinglogger_config)s
+ level %(event_log_level)s
+ %(event_log)s
+
+"""
+
+access_log_template = """\
+
+ level %(z_log_level)s
+ %(access_event_log)s
+
+"""
+
+# Template used for plone.resource directory
+resources_zcml = """\
+
+
+
+
+"""
+
+# Template used for locales directory
+locales_zcml = """\
+
+
+
+"""
+
+# Template used for additional ZCML
+additional_zcml_template = """\
+
+ %s
+
+"""
+
+wsgi_initialization = """\
+from Zope2.Startup.run import make_wsgi_app
+wsgiapp = make_wsgi_app({}, '%(zope-conf)s')
+def application(*args, **kwargs):return wsgiapp(*args, **kwargs)
+"""