==========================
plone.recipe.zope2instance
==========================


This is the doctest for plone.recipe.zope2instance that only runs in Python 2.
It ensures the template works fine with ZServer when wsgi is disabled.

It is based on zc.buildout testing module::

    >>> from __future__ import print_function
    >>> from zc.buildout.testing import *
    >>> from os.path import join
    >>> import sys, os
    >>> options = globals()
    >>> WINDOWS = sys.platform == 'win32'

Let's create a minimum buildout that uses the current
plone.recipe.zope2instance::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance, with a basic zope.conf::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    instancehome $INSTANCEHOME
    %define CLIENTHOME .../sample-buildout/var/instance
    clienthome $CLIENTHOME
    debug-mode off
    security-policy-implementation C
    verbose-security off
    default-zpublisher-encoding utf-8
    http-header-max-length 8192
    zserver-threads 2
    <environment>
        CHAMELEON_CACHE .../var/cache
    </environment>
    <eventlog>
      level INFO
      <logfile>
        path .../sample-buildout/var/log/instance.log
        level INFO
      </logfile>
    </eventlog>
    <logger access>
      level WARN
      <logfile>
        path .../sample-buildout/var/log/instance-Z2.log
        format %(message)s
      </logfile>
    </logger>
    <http-server>
      address 8080
    </http-server>
    <zodb_db main>
        # Main database
        cache-size 30000
    # Blob-enabled FileStorage database
        <blobstorage>
          blob-dir .../sample-buildout/var/blobstorage
          # FileStorage database
          <filestorage>
            path .../sample-buildout/var/filestorage/Data.fs
          </filestorage>
        </blobstorage>
        mount-point /
    </zodb_db>
    <zodb_db temporary>
        # Temporary storage database (for sessions)
        <temporarystorage>
          name temporary storage for sessioning
        </temporarystorage>
        mount-point /temp_folder
        container-class Products.TemporaryFolder.TemporaryContainer
    </zodb_db>
    pid-filename .../sample-buildout/var/instance.pid
    lock-filename .../sample-buildout/var/instance.lock
    python-check-interval 1000
    enable-product-installation off

We should have a blobstorage directory.

    >>> ls('var')
    d  blobstorage
    d  cache
    d  filestorage
    d  instance
    d  log

The blobstorage directory should only be readable by the current user,
otherwise you get a warning when the zope instance starts up.  The
(POSIX) path mode bits should be 0700.

    >>> (os.stat(os.path.join('var', 'blobstorage')).st_mode & 0o077) == 0
    True


FTP and WebDAV
==============

Let's start off by adding an FTP address::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... ftp-address = 8021
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

Our FTP server should be set up now::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <ftp-server>
      # valid key is "address"
      address 8021
    </ftp-server>
    ...

Next we will add a WebDAV server::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... webdav-address = 1980
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

Our WebDAV server should be set up now::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <webdav-source-server>
      address 1980
      force-connection-close off
    </webdav-source-server>
    ...

Next we will add a WebDAV server with force-connection-close on::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... webdav-address = 1980
    ... webdav-force-connection-close = on
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

Our WebDAV server should be set up now::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <webdav-source-server>
      address 1980
      force-connection-close on
    </webdav-source-server>
    ...

DemoStorage
===========

To have a DemoStorage configuration, you can use demo-storage::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... file-storage = newfs/Data.fs
    ... demo-storage = on
    ...
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance, with a basic zope.conf::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <zodb_db main>
        # Main database
        cache-size 30000
    <BLANKLINE>
    # DemoStorage
        <demostorage>
    <BLANKLINE>
        # FileStorage database
        <filestorage>
          path .../sample-buildout/var/newfs/Data.fs
        </filestorage>
    <BLANKLINE>
        </demostorage>
        mount-point /
    </zodb_db>
    ...
    <BLANKLINE>

Verify that demostorage can be disable::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... file-storage = newfs/Data.fs
    ... demo-storage = off
    ...
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance, with a basic zope.conf without demostorage::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <zodb_db main>
        # Main database
        cache-size 30000
    <BLANKLINE>
    # Blob-enabled FileStorage database
        <blobstorage>
          blob-dir .../sample-buildout/var/blobstorage
          # FileStorage database
          <filestorage>
            path .../sample-buildout/var/newfs/Data.fs
          </filestorage>
        </blobstorage>
        mount-point /
    </zodb_db>
    ...
    <BLANKLINE>

You can add file storage to the demo-storage to be able to keep
changes::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... file-storage = newfs/Data.fs
    ... demo-storage = on
    ... demo-file-storage = demofs/Data.fs
    ...
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance, with a basic zope.conf::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <zodb_db main>
        # Main database
        cache-size 30000
    <BLANKLINE>
    # DemoStorage
        <demostorage>
    <BLANKLINE>
        # FileStorage database
        <filestorage base>
          path .../sample-buildout/var/newfs/Data.fs
        </filestorage>
    <BLANKLINE>
    <BLANKLINE>
        # FileStorage database
        <filestorage changes>
          path .../sample-buildout/var/demofs/Data.fs
        </filestorage>
    <BLANKLINE>
        </demostorage>
        mount-point /
    </zodb_db>
    ...
    <BLANKLINE>

You can add a blob storage to the demo-storage as well::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... file-storage = newfs/Data.fs
    ... blob-storage = ${buildout:directory}/var/blob
    ... demo-storage = on
    ... demo-file-storage = demofs/Data.fs
    ... demo-blob-storage = ${buildout:directory}/var/demoblob
    ...
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance, with a basic zope.conf::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
        <blobstorage base>
          blob-dir .../sample-buildout/var/blob
          # FileStorage database
          <filestorage>
            path .../sample-buildout/var/newfs/Data.fs
          </filestorage>
        </blobstorage>
    ...
        <blobstorage changes>
          blob-dir .../sample-buildout/var/demoblob
          # FileStorage database
          <filestorage>
            path .../sample-buildout/var/demofs/Data.fs
          </filestorage>
        </blobstorage>
    ...

Finally, you can add only a blob storage. Changes will then not be
persisted on disk, but blob support will be available separately (it's
not supported by the in-memory demostorage)::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... file-storage = newfs/Data.fs
    ... demo-storage = on
    ... demo-blob-storage = ${buildout:directory}/var/demoblob
    ...
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance, with a basic zope.conf::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <zodb_db main>
        # Main database
        cache-size 30000
    <BLANKLINE>
    # DemoStorage
        <demostorage>
    <BLANKLINE>
        # FileStorage database
        <filestorage base>
          path .../sample-buildout/var/newfs/Data.fs
        </filestorage>
    <BLANKLINE>
    <BLANKLINE>
        # Blob-enabled FileStorage database
        <blobstorage changes>
          blob-dir .../sample-buildout/var/demoblob
          <demostorage />
        </blobstorage>
    <BLANKLINE>
        </demostorage>
        mount-point /
    </zodb_db>
    ...


ZlibStorage
===========

To have a ZlibStorage configuration, you can use zlib-storage::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... file-storage = newfs/Data.fs
    ... zlib-storage = active
    ...
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance, with a basic zope.conf::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <zodb_db main>
        # Main database
        cache-size 30000
    <BLANKLINE>
    # Blob-enabled FileStorage database
        <blobstorage>
          blob-dir .../sample-buildout/var/blobstorage
    <BLANKLINE>
          %import zc.zlibstorage
          # ZlibStorage wrapper
          <zlibstorage>
            compress true
    <BLANKLINE>
            # FileStorage database
            <filestorage>
              path .../sample-buildout/var/newfs/Data.fs
            </filestorage>
    <BLANKLINE>
          </zlibstorage>
    <BLANKLINE>
        </blobstorage>
        mount-point /
    </zodb_db>
    ...
    <BLANKLINE>

To have a ZlibStorage configuration with no active compression, you
can set the ``zlib-storage`` option to 'passive'::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... file-storage = newfs/Data.fs
    ... zlib-storage = passive
    ...
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance, with a basic zope.conf::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <zodb_db main>
        # Main database
        cache-size 30000
    <BLANKLINE>
    # Blob-enabled FileStorage database
        <blobstorage>
          blob-dir .../sample-buildout/var/blobstorage
    <BLANKLINE>
          %import zc.zlibstorage
          # ZlibStorage wrapper
          <zlibstorage>
            compress false
    <BLANKLINE>
            # FileStorage database
            <filestorage>
              path .../sample-buildout/var/newfs/Data.fs
            </filestorage>
    <BLANKLINE>
          </zlibstorage>
    <BLANKLINE>
        </blobstorage>
        mount-point /
    </zodb_db>
    ...
    <BLANKLINE>


BeforeStorage
=============

To have a BeforeStorage configuration, you can use before-storage::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... file-storage = newfs/Data.fs
    ... before-storage = now
    ...
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance, with a basic zope.conf::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <zodb_db main>
        # Main database
        cache-size 30000
    <BLANKLINE>
    %import zc.beforestorage
        # BeforeStorage
        <before>
          before now
    <BLANKLINE>
          # Blob-enabled FileStorage database
          <blobstorage>
            blob-dir .../sample-buildout/var/blobstorage
            # FileStorage database
            <filestorage>
              path .../sample-buildout/var/newfs/Data.fs
            </filestorage>
          </blobstorage>
    <BLANKLINE>
        </before>
        mount-point /
    </zodb_db>
    ...
    <BLANKLINE>

The before-storage option can be combined with a demo-storage::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... file-storage = newfs/Data.fs
    ... before-storage = now
    ... demo-storage = on
    ...
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance, with a basic zope.conf::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <zodb_db main>
        # Main database
        cache-size 30000
    <BLANKLINE>
        # DemoStorage
        <demostorage>
    <BLANKLINE>
        %import zc.beforestorage
        # BeforeStorage
        <before>
          before now
    <BLANKLINE>
          # Blob-enabled FileStorage database
          <blobstorage>
            blob-dir .../sample-buildout/var/blobstorage
            # FileStorage database
            <filestorage>
              path .../sample-buildout/var/newfs/Data.fs
            </filestorage>
          </blobstorage>
    <BLANKLINE>
        </before>
    <BLANKLINE>
    <BLANKLINE>
        </demostorage>
        mount-point /
    </zodb_db>
    ...
    <BLANKLINE>

BlobStorage
===========

To have a BlobStorage configuration, you can use blob-storage::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... blob-storage = ${buildout:directory}/var/blob
    ...
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance, with a basic zope.conf::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <zodb_db main>
        # Main database
        cache-size 30000
        # Blob-enabled FileStorage database
        <blobstorage>
          blob-dir .../sample-buildout/var/blob
          # FileStorage database
          <filestorage>
            path .../sample-buildout/var/filestorage/Data.fs
          </filestorage>
        </blobstorage>
        mount-point /
    </zodb_db>
    ...
    <BLANKLINE>


RelStorage
==========

To have a RelStorage configuration, you can use rel-storage::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... rel-storage =
    ...   type postgresql
    ...   dbname zodb
    ...   user tarek
    ...   host example.com
    ...   password secret space
    ...   keep-history false
    ...
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance, with a basic zope.conf::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <zodb_db main>
        # Main database
        cache-size 30000
    %import relstorage
        <relstorage>
            keep-history false
            <postgresql>
                dsn dbname='zodb' user='tarek' host='example.com' password='secret space'
            </postgresql>
        </relstorage>
        mount-point /
    </zodb_db>
    ...
    <BLANKLINE>

ZEO storage
===========

If you want to connect to a zeo server you specify some additional properties
for the plone.recipe.zope2instance recipe.

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... zeo-client = yes
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance, with a basic zope.conf::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <zodb_db main>
        ...
        <zeoclient>
            read-only false
            read-only-fallback false
            blob-dir .../sample-buildout/var/blobcache
            shared-blob-dir no
            server 8100
            storage 1
            name zeostorage
            cache-size 128MB
    <BLANKLINE>
    <BLANKLINE>
    <BLANKLINE>
    <BLANKLINE>
    <BLANKLINE>
        </zeoclient>
        ...
    </zodb_db>
    ...
    <BLANKLINE>

If `zeo-client-client` and other relevant ZEO options such as
`zeo-client-blob-cache-size` and `zeo-client-blob-cache-size-check` are
specified, they should get included in that section as well.

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... zeo-client = yes
    ... zeo-client-client = persistentcache88
    ... min-disconnect-poll = 10
    ... max-disconnect-poll = 20
    ... zeo-client-blob-cache-size = 5GB
    ... zeo-client-blob-cache-size-check = 50
    ... zeo-client-read-only-fallback = true
    ... zeo-var = %(sample_buildout)s/var
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance, with a basic zope.conf::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <zodb_db main>
        ...
        <zeoclient>
            read-only false
            read-only-fallback true
            blob-dir .../sample-buildout/var/blobcache
            shared-blob-dir no
            server 8100
            storage 1
            name zeostorage
            cache-size 128MB
            blob-cache-size 5GB
            blob-cache-size-check 50
    <BLANKLINE>
            var .../sample-buildout/var
            client persistentcache88
            min-disconnect-poll 10
            max-disconnect-poll 20
        </zeoclient>
        ...
    </zodb_db>
    ...
    <BLANKLINE>

Verify that demo-storage is correctly applied

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... zeo-client = yes
    ... demo-storage = yes
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance, with a basic zope.conf::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <zodb_db main>
        ...
        # DemoStorage
        <demostorage>
        # ZEOStorage database
        <zeoclient>
            read-only false
            read-only-fallback false
            server 8100
            storage 1
            name zeostorage
            cache-size 128MB
    <BLANKLINE>
    <BLANKLINE>
    <BLANKLINE>
    <BLANKLINE>
    <BLANKLINE>
        </zeoclient>
        </demostorage>
        ...
    </zodb_db>
    ...
    <BLANKLINE>

Verify that blob-storage is correctly applied

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... zeo-client = yes
    ... blob-storage = ${buildout:directory}/var/blob
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance, with a basic zope.conf::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <zodb_db main>
        ...
    # Blob-enabled ZEOStorage database
        <zeoclient>
          read-only false
          read-only-fallback false
          blob-dir .../sample-buildout/var/blob
          shared-blob-dir no
          server 8100
          storage 1
          name zeostorage
          cache-size 128MB
    <BLANKLINE>
    <BLANKLINE>
    <BLANKLINE>
    <BLANKLINE>
    <BLANKLINE>
        </zeoclient>
        ...
    </zodb_db>
    ...
    <BLANKLINE>

Verify that demo-storage is correctly applied together with
before-storage::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... zeo-client = yes
    ... demo-storage = yes
    ... before-storage = now
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance, with a basic zope.conf::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <zodb_db main>
        # Main database
        cache-size 30000
    <BLANKLINE>
    # DemoStorage
        <demostorage>
    <BLANKLINE>
        %import zc.beforestorage
        # BeforeStorage
        <before>
          before now
        # Blob-enabled ZEOStorage database
          <zeoclient>
            read-only false
            read-only-fallback false
            blob-dir .../sample-buildout/var/blobcache
            shared-blob-dir no
            server 8100
            storage 1
            name zeostorage
            cache-size 128MB
    <BLANKLINE>
    <BLANKLINE>
    <BLANKLINE>
    <BLANKLINE>
    <BLANKLINE>
    <BLANKLINE>
    <BLANKLINE>
          </zeoclient>
        </before>
    <BLANKLINE>
        </demostorage>
        mount-point /
    </zodb_db>
    ...
    <BLANKLINE>

You can get specific zeo server address using `zeo-address`.

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... zeo-client = yes
    ... zeo-address = 127.0.0.1:8101
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance, with a basic zope.conf::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <zodb_db main>
        ...
        <zeoclient>
            read-only false
            read-only-fallback false
            blob-dir .../sample-buildout/var/blobcache
            shared-blob-dir no
            server 127.0.0.1:8101
            storage 1
            name zeostorage
            cache-size 128MB
    <BLANKLINE>
    <BLANKLINE>
    <BLANKLINE>
    <BLANKLINE>
    <BLANKLINE>
        </zeoclient>
        ...
    </zodb_db>
    ...
    <BLANKLINE>

You can also set multiple zeo server addresses using `zeo-address`.

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... zeo-client = yes
    ... zeo-address = 127.0.0.1:8101 127.0.0.1:8102
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance, with a basic zope.conf::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <zodb_db main>
        ...
        <zeoclient>
            read-only false
            read-only-fallback false
            blob-dir .../sample-buildout/var/blobcache
            shared-blob-dir no
            server 127.0.0.1:8101
            server 127.0.0.1:8102
            storage 1
            name zeostorage
            cache-size 128MB
    <BLANKLINE>
    <BLANKLINE>
    <BLANKLINE>
    <BLANKLINE>
    <BLANKLINE>
        </zeoclient>
        ...
    </zodb_db>
    ...
    <BLANKLINE>

Custom storage wrapper
======================

To add custom configuration around the storage,
use the `storage-wrapper` option::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... storage-wrapper =
    ...   <foo>
    ...   %%s
    ...   </foo>
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

Now zope.conf should include the custom storage wrapper::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <zodb_db main>
        ...
        <foo>
            # Blob-enabled FileStorage database
            ...
        </foo>
        ...
    </zodb_db>
    ...
    <BLANKLINE>


Custom Event log
================

`event-log-custom` is a new option that allows you to create
a custom event log section. For example, let's say you want
to use `rotatezlogs`::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ...
    ... event-log-custom =
    ...     %%import iw.rotatezlogs
    ...     <rotatelogfile>
    ...         path %(sample_buildout)s/var/log/event.log
    ...         max-bytes 1MB
    ...         backup-count 5
    ...     </rotatelogfile>
    ...
    ... event-log-level = info
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance, with the custom event log::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <eventlog>
      level info
      %import iw.rotatezlogs
      <rotatelogfile>
        path .../sample-buildout/var/log/event.log
        max-bytes 1MB
        backup-count 5
      </rotatelogfile>
    </eventlog>
    ...
    <BLANKLINE>


Mailing logger
==============

`mailinglogger` allows you to configure mail actions for the event log::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ...
    ... mailinglogger =
    ...     <mailing-logger>
    ...       level error
    ...       flood-level 10
    ...       smtp-server smtp.mydomain.com
    ...       from logger@mydomain.com
    ...       to errors@mydomain.com
    ...       subject [My domain error]
    ...     </mailing-logger>
    ...
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance, with the mailing logger::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    %import mailinglogger
    <eventlog>
      <mailing-logger>
        level error
        flood-level 10
        smtp-server smtp.mydomain.com
        from logger@mydomain.com
        to errors@mydomain.com
        subject [My domain error]
      </mailing-logger>
      level INFO
    ...
    </eventlog>
    ...
    <BLANKLINE>


Custom access log
=================

`access-log-custom` is a new option that allows you to create
a custom event log section. For example, let's say you want
to use `rotatezlogs`::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ...
    ... access-log-custom =
    ...     %%import iw.rotatezlogs
    ...     <rotatelogfile>
    ...         path %(sample_buildout)s/var/log/event.log
    ...         max-bytes 1MB
    ...         backup-count 5
    ...     </rotatelogfile>
    ...
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance, with the custom event log::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <logger access>
      level WARN
      %import iw.rotatezlogs
      <rotatelogfile>
        path .../sample-buildout/var/log/event.log
        max-bytes 1MB
        backup-count 5
      </rotatelogfile>
    </logger>
    ...
    <BLANKLINE>


Disable access log
==================

If we assign `disable` to `z2-log`, the whole <logger access> section
will be omitted::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ...
    ... z2-log = disable
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance, with no access log::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> "logger access" in zope_conf
    False
    >>> "eventlog" in zope_conf
    True


Disable events log
==================

If we assign `disable` to `event-log`, the whole <eventlog> section
will be omitted::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ...
    ... event-log = disable
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance, with no access log::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> "logger access" in zope_conf
    True
    >>> "eventlog" in zope_conf
    False


Custom site.zcml file
=====================

`site-zcml` is a new option that allows you to create a custom site.zcml file.
When this option is used the `zcml` option is ignored. Let's try it::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... # the zcml option will be ignored when a site-zcml option is given
    ... zcml =
    ...       test.example
    ...
    ... site-zcml =
    ...       <configure xmlns="http://namespaces.zope.org/zope"
    ...                  xmlns:five="http://namespaces.zope.org/five">
    ...           <include package="Products.Five" />
    ...           <meta:redefinePermission from="zope2.Public" to="zope.Public" />
    ...           <include package="test.example" />
    ...       </configure>
    ...
    ... ''' % options)

Let's run the buildout::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

Now let's check that we have a zope instance, with the custom site.zcml::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> print(open(os.path.join(instance, 'etc', 'site.zcml')).read())
    <configure xmlns="http://namespaces.zope.org/zope"
               xmlns:five="http://namespaces.zope.org/five">
        <include package="Products.Five" />
        <meta:redefinePermission from="zope2.Public" to="zope.Public" />
        <include package="test.example" />
    </configure>
    <BLANKLINE>


Environment Variables
=====================

We can specify environment variables for Zope.  Sometimes it is
useful to set the TZ variable if our instance will be moving
between several servers::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... template-cache = off
    ... environment-vars = TZ US/Eastern
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

Our environment variables should be set now::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <environment>
      TZ US/Eastern
    </environment>
    ...

Now let's add several environment variables::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... template-cache = off
    ... environment-vars =
    ...     TZ US/Eastern
    ...     TMP /var/tmp
    ...     DISABLE_PTS True
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

Our environment variables should be set now::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> import re
    >>> env_vars = re.compile(r"<environment>\n\s*(?P<vars>.*)\n</environment>", re.M | re.S)
    >>> re.search(env_vars, zope_conf).group('vars')
    'TZ US/Eastern\nTMP /var/tmp\nDISABLE_PTS True'

Several all on one line::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... template-cache = off
    ... environment-vars = TZ US/Eastern TMP /var/tmp DISABLE_PTS True
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

Our environment variables should be set now::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> re.search(env_vars, zope_conf).group('vars')
    'TZ US/Eastern\nTMP /var/tmp\nDISABLE_PTS True'


HTTP server
===========

Check additional options to the HTTP server::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... http-force-connection-close = on
    ... http-fast-listen = off
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

And check it::

    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <http-server>
      address 8080
      force-connection-close on
      # Set to off to defer opening of the HTTP socket until the end of the
      # startup phase:
      fast-listen off
    <BLANKLINE>
    </http-server>
    ...

Configuring ZServer workers is also possible using the 'threads' option:

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... threads = 3
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

And check it::

    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    zserver-threads 3
    ...
    <http-server>
    ...

The 'zserver-threads' option is deprecated but still working:

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... zserver-threads = 3
    ... ''' % options)

Run it::

    >>> print(system(join('bin', 'buildout')))
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

And check it::

    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    zserver-threads 3
    ...
    <http-server>
    ...

Edge Cases
==========

Some Linux distributions of Zope2 don't have the windows scripts.
Let's run a minimal buildout without them to make sure
we don't error::

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

Relative paths in scripts
=========================

The recipe supports the generation of scripts with relative paths.

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... relative-paths = true
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... ''' % options)
    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

Our generated script now has a reference to the relative path.

    >>> import sys
    >>>

    >>> instance_path = join('bin', 'instance')
    >>> if WINDOWS:
    ...     instance_path += '-script.py'
    >>> open(instance_path).read()
    "...base = ...__file__..."

Custom Zope Conf
=================

`zope-conf` is an option that allows you to use a specific Zope config file.

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... zope-conf = /some/path/my.conf
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance script with the custom config file::

    >>> instance_path = join('bin', 'instance')
    >>> if WINDOWS:
    ...     instance_path += '-script.py'
    >>> open(instance_path).read()
    "...plone.recipe.zope2instance.ctl.main(...['-C', '/some/path/my.conf', '-p', '.../bin/interpreter']..."

Custom Zope Conf Imports
========================
`zope-conf-imports` is an option that allows you to import python packages that
define custom zope.conf sections using ZConfig API.

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... zope-conf-imports =
    ...   mailinglogger
    ...   eea.graylogger
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should have a zope instance, with custom imports::

    >>> instance = os.path.join(sample_buildout, 'parts', 'instance')
    >>> zope_conf = open(os.path.join(instance, 'etc', 'zope.conf')).read()
    >>> zope_conf = zope_conf.replace('\\', '/')
    >>> print(zope_conf)
    %import mailinglogger
    %import eea.graylogger
    %define INSTANCEHOME .../sample-buildout/parts/instance
    ...
    <BLANKLINE>

Resources directory
===================

`resources` is an option that allows you to register a
plone.app.theming resources directory.

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... resources = ${buildout:directory}/myresources
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

The directory should have been generated, and zope config created::

    >>> 'myresources' in os.listdir(os.curdir)
    True
    >>> includes_path = join('parts', 'instance', 'etc', 'package-includes')
    >>> ls(includes_path)
    -  998-resources-configure.zcml
    >>> cat(includes_path, '998-resources-configure.zcml')
    <configure xmlns="http://namespaces.zope.org/zope"
               xmlns:plone="http://namespaces.plone.org/plone">
        <include package="plone.resource" file="meta.zcml"/>
        <plone:static directory=".../sample-buildout/myresources"/>
    </configure>


Locales directory
===================

`locales` is an option that allows you to register a
plone.app.theming locales directory.

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... locales = ${buildout:directory}/mylocales
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

The directory should have been generated, and zope config created::

    >>> 'mylocales' in os.listdir(os.curdir)
    True
    >>> includes_path = join('parts', 'instance', 'etc', 'package-includes')
    >>> ls(includes_path)
    -  001-locales-configure.zcml
    >>> cat(includes_path, '001-locales-configure.zcml')
    <configure xmlns="http://namespaces.zope.org/zope"
               xmlns:i18n="http://namespaces.zope.org/i18n">
        <i18n:registerTranslations directory=".../sample-buildout/mylocales" />
    </configure>


Initialization
==============

`initialization` is an option that allows you to add custom Python
code to the initialization process.

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = instance
    ... find-links = %(sample_buildout)s/eggs
    ...
    ... [instance]
    ... recipe = plone.recipe.zope2instance
    ... wsgi = off
    ... eggs =
    ... user = me:me
    ... initialization =
    ...     print('Initialization complete!')
    ... ''' % options)

Let's run it::

    >>> print(system(join('bin', 'buildout'))),
    Uninstalling instance.
    Installing instance.
    Generated script '...instance'.
    Generated interpreter '.../parts/instance/bin/interpreter'...

We should see the given initialization commands included in the instance
script::

    >>> instance = open(os.path.join(sample_buildout, 'bin', 'instance')).read()
    >>> "print('Initialization complete!')" in instance
    True

