Example #1
0
    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 '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')

        # Get Scripts' attributes
        return Scripts.__init__(self, buildout, name, options)
Example #2
0
    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 = True
        self.wsgi_config = os.path.join(options['location'], 'etc', 'wsgi.ini')
        wsgi_opt = options.get('wsgi', 'on')
        if six.PY2 and wsgi_opt.lower() in ('off', 'false', '0'):
            self.wsgi = False
        elif wsgi_opt.lower() not in ('on', 'true', '1'):
            self.wsgi_config = wsgi_opt

        # Get Scripts' attributes
        return Scripts.__init__(self, buildout, name, options)
Example #3
0
    def _get_working_set(self):
        relative_path = self.options.get('relative-paths', '')
        if relative_path.lower() == 'true':
            relative_path = self.buildout['buildout']['directory']

        egg = Egg(self.buildout, self.options['recipe'], self.options)
        extra_paths = self.options.get('extra-paths', '').split('\n')

        ws = egg.working_set()[1]
        retval = [dist.location for dist in ws]
        retval.extend(extra_paths)

        if relative_path:
            eggs_dir = self.buildout['buildout'].get('eggs-directory', '.')
            base_dir = self.buildout['buildout'].get('directory', '.')
            common = os.path.commonprefix([eggs_dir, base_dir])
            rel_eggs_dir = eggs_dir.replace(common, '.')
            for i, loc in enumerate(retval):
                if loc.startswith(os.path.realpath(eggs_dir)):
                    retval[i] = loc.replace(os.path.realpath(eggs_dir), rel_eggs_dir)
                elif loc.startswith(os.path.realpath(base_dir)):
                    retval[i] = loc.replace(os.path.realpath(base_dir), '.')
        return retval
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')

        # 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)

            # Which Zope2 version do we have?
            dist = pkg_resources.get_distribution('Zope2')
            parsed = dist.parsed_version
            major, minor = parsed[0:2]
            major = int(major)
            # We support creating instances for 2.12, 2.13 and 4.0
            if major >= 4:
                major = 2
                minor = 13
            elif major == 2:
                minor = int(minor)
                if minor > 13:
                    minor = 13
            version = str(major) + str(minor)
            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

        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
        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((
                "<warnfilter>",
                "  action %s" % deprecation_warnings,
                "  category exceptions.DeprecationWarning",
                "</warnfilter>"))

        zope_conf_additional = options.get('zope-conf-additional', '')

        # logging
        event_log_level = options.get('event-log-level', 'INFO')
        custom_event_log = options.get('event-log-custom', None)
        default_log = os.path.sep.join(('log', self.name + '.log',))
        # log file
        if not custom_event_log:
            event_log_name = options.get('event-log', default_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

        mailinglogger_config = options.get('mailinglogger', '')
        mailinglogger_import = ''
        if mailinglogger_config:
            mailinglogger_config = mailinglogger_config.strip()
            mailinglogger_import = '%import mailinglogger'

        z_log_name = os.path.sep.join(('log', self.name + '-Z2.log'))
        z_log_name = options.get('z2-log', z_log_name)
        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

        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='******' "
                            "host='%(host)s' password='******'")
                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.iteritems()
                                  if not is_rs_option(k)),
                rs_opts='\n'.join(' ' * 8 + ' '.join((k, v))
                                  for k, v in rel_storage.iteritems()
                                  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

        zodb_tmp_storage = options.get('zodb-temporary-storage',
                                       zodb_temporary_storage_template)

        template = 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,
                                    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,
                                    mailinglogger_config = mailinglogger_config,
                                    event_log = event_log,
                                    event_log_level = event_log_level,
                                    access_event_log = access_event_log,
                                    z_log_level = z_log_level,
                                    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)

        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),
                 'plone.recipe.zope2instance.ctl', 'main')]

        if options.get('relative-paths'):
            class zope_conf_path(str):
                def __repr__(self):
                    return str(self)

            zope_conf_path = zope_conf_path(
                        zc.buildout.easy_install._relativitize(
                            zope_conf,
                            options['buildout-directory'] + os.sep,
                            self._relative_paths
                        )
                    )

        arguments = ["-C", zope_conf_path]
        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)
        generated.extend(self._install_scripts(
            os.path.join(options['location'], 'bin'), ws,
            interpreter='interpreter', 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:
            return zc.buildout.easy_install.scripts(
                dest=dest,
                reqs=reqs,
                working_set=working_set,
                executable=options['executable'],
                extra_paths=extra_paths,
                initialization=options['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(
                    '<include package="%s" file="%s" />\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 = "    <demostorage />"

        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, 0700)

        storage = indent(storage, 2)

        return blob_storage_template % (blob_storage, storage)
Example #5
0
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 = True
        self.wsgi_config = os.path.join(options['location'], 'etc', 'wsgi.ini')
        wsgi_opt = options.get('wsgi', 'on')
        if six.PY2 and wsgi_opt.lower() in ('off', 'false', '0'):
            self.wsgi = False
        elif wsgi_opt.lower() not in ('on', 'true', '1'):
            self.wsgi_config = wsgi_opt

        # 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 and wsgi.ini
            # based on options in buildout.cfg
            self.build_zope_conf()
            if self.wsgi:
                self.build_wsgi_ini()

            # Install extra scripts
            installed.extend(self.install_scripts())

            # Add zcml files to package-includes
            self.build_package_includes()
        except Exception:
            # 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')
        debug_exceptions = options.get('debug-exceptions', '')
        if debug_exceptions:
            debug_exceptions = debug_exceptions_template % debug_exceptions
        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
        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 '\n' not 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((
                "<warnfilter>",
                "  action %s" % deprecation_warnings,
                "  category DeprecationWarning",
                "</warnfilter>"))

        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',
            options.get('access-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 'dsn' not in rel_storage:
                # Support zope2instance 1.4 style interpolation for
                # postgresql
                template = ("dbname='%(dbname)s' user='******' "
                            "host='%(host)s' password='******'")
                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)

        if 'zserver-threads' in options:
            warn(
                'option "zserver-threads" is deprecated, please use "threads"',
                DeprecationWarning)
        zserver_threads = options.get(
            '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_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')
            zeo_client_client = options.get('zeo-client-client', '')
            if zeo_client_client:
                zeo_client_client = 'client %s' % zeo_client_client
                zeo_var_dir = options.get('zeo-var', '')
                if not zeo_var_dir:
                    zeo_var_dir = '$(ZEO_TMP)'
                zeo_var_dir = 'var %s' % zeo_var_dir
            else:
                zeo_var_dir = ''
            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,  # noqa: E501
                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,  # noqa: E501
                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', 'on')
        if zodb_tmp_storage.lower() in ('off', 'false', '0'):
            zodb_tmp_storage = ''
        else:
            zodb_tmp_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,
            debug_exceptions=debug_exceptions,
            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')
        with open(zope_conf_path, 'w') as f:
            f.write(zope_conf)

    def build_wsgi_ini(self):
        options = self.options
        wsgi_ini_path = os.path.join(options['location'], 'etc', 'wsgi.ini')
        listen = options.get('http-address', '0.0.0.0:8080')
        fast = 'fast-' if options.get('http-fast-listen') is not None else ''
        if ':' not in listen:
            listen = '0.0.0.0:{}'.format(listen)

        base_dir = self.buildout['buildout']['directory']
        var_dir = options.get('var', os.path.join(base_dir, 'var'))
        default_eventlog = os.path.sep.join(
            (var_dir, 'log', '{}.log'.format(self.name),))
        eventlog_name = options.get('event-log', default_eventlog)
        eventlog_level = options.get('event-log-level', 'INFO')

        if eventlog_name.lower() == 'disable':
            root_handlers = 'console'
            event_handlers = ''
        else:
            root_handlers = 'console, eventlog'
            event_handlers = 'eventlog'

        default_accesslog = os.path.sep.join(
            (var_dir, 'log', '{}-access.log'.format(self.name),))

        accesslog_name = options.get(
            'z2-log',
            options.get('access-log', default_accesslog))
        accesslog_level = options.get(
            'access-log-level',
            options.get('z2-log-level', 'INFO'))

        if accesslog_name.lower() == 'disable':
            pipeline = '\n    '.join(['egg:Zope#httpexceptions', 'zope'])
            event_handlers = ''
        else:
            pipeline = '\n    '.join(
                ['translogger', 'egg:Zope#httpexceptions', 'zope'])
        options = {
            'location': options['location'],
            'http_address': listen,
            'threads': options.get('threads', 4),
            'fast-listen': fast,
            'eventlog_name': eventlog_name,
            'root_handlers': root_handlers,
            'event_handlers': event_handlers,
            'accesslog_name': accesslog_name,
            'pipeline': pipeline,
            'eventlog_level': eventlog_level,
            'accesslog_level': accesslog_level,
        }
        wsgi_ini = wsgi_ini_template % options
        with open(wsgi_ini_path, 'w') as f:
            f.write(wsgi_ini)

    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)]
        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 zopectl_umask:
            arguments.extend(["--umask", int(zopectl_umask, 8)])
        if self.wsgi and self.wsgi_config:
            arguments.extend(['-w', self.wsgi_config])
        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)
        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:
            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 = nocomments_split(zcml)

        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(r'\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(
                    '<include package="%s" file="%s" />\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 = "    <demostorage />"

        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)