text: # -*- coding: utf-8 -*-
  ##############################################################################
  #
  # Copyright (c) 2004-2009 Zope Foundation and Contributors.
  # All Rights Reserved.
  #
  # This software is subject to the provisions of the Zope Public License,
  # Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
  # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
  # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
  # FOR A PARTICULAR PURPOSE.
  #
  ##############################################################################
  from __future__ import print_function
  import unittest
  
  from zc.buildout.buildout import print_
  from zope.testing import renormalizing, setupstack
  
  import doctest
  import manuel.capture
  import manuel.doctest
  import manuel.testing
  import os
  import pkg_resources
  import re
  import shutil
  import sys
  import tempfile
  import unittest
  import zc.buildout.easy_install
  import zc.buildout.testing
  import zipfile
  
  os_path_sep = os.path.sep
  if os_path_sep == '\\':
      os_path_sep *= 2
  
  
  class TestEasyInstall(unittest.TestCase):
  
      # The contents of a zipped egg, created by setuptools:
      # from setuptools import setup
      # setup(
      #    name='TheProject',
      #    version='3.3',
      # )
      #
      # (we can't run setuptools at runtime, it may not be installed)
      EGG_DATA = (
          b'PK\x03\x04\x14\x00\x00\x00\x08\x00q8\xa8Lg0\xb7ix\x00\x00\x00\xb6\x00'
          b'\x00\x00\x11\x00\x00\x00EGG-INFO/PKG-INFO\xf3M-ILI,I\xd4\rK-*'
          b'\xce\xcc\xcf\xb3R0\xd43\xe0\xf2K\xccM\xb5R\x08\xc9H\r(\xca\xcfJM'
          b'.\xe1\x82\xcb\x1a\xeb\x19s\x05\x97\xe6\xe6&\x16UZ)\x84\xfay\xfb\xf9\x87\xfb'
          b'qy\xe4\xe7\xa6\xea\x16$\xa6\xa7"\x84\x1cKK2\xf2\x8b\xd0\xf9\xba\xa9\xb9\x89'
          b'\x999\x08Q\x9f\xcc\xe4\xd4\xbcb$m.\xa9\xc5\xc9E\x99\x05%`\xbb`\x82\x019\x89%'
          b'i\xf9E\xb9\x08\x11\x00PK\x03\x04\x14\x00\x00\x00\x08\x00q8\xa8L61\xa1'
          b'XL\x00\x00\x00\x87\x00\x00\x00\x14\x00\x00\x00EGG-INFO/SOURCES.txt\x0b\xc9H'
          b'\r(\xca\xcfJM.\xd1KMO\xd7\xcd\xccK\xcb\xd7\x0f\xf0v\xd7\xf5\xf4s'
          b'\xf3\xe7\n\xc1"\x19\xec\x1f\x1a\xe4\xec\x1a\xacWRQ\x82U>%\xb5 5/%5/\xb92>\'3'
          b'/\xbb\x18\xa7\xc2\x92\xfc\x82\xf8\x9c\xd4\xb2\xd4\x1c\x90\n\x00PK\x03'
          b'\x04\x14\x00\x00\x00\x08\x00q8\xa8L\x93\x06\xd72\x03\x00\x00\x00\x01'
          b'\x00\x00\x00\x1d\x00\x00\x00EGG-INFO/dependency_links.txt\xe3\x02\x00P'
          b'K\x03\x04\x14\x00\x00\x00\x08\x00q8\xa8L\x93\x06\xd72\x03\x00\x00'
          b'\x00\x01\x00\x00\x00\x16\x00\x00\x00EGG-INFO/top_level.txt\xe3\x02\x00PK'
          b'\x03\x04\x14\x00\x00\x00\x08\x00q8\xa8L\x93\x06\xd72\x03\x00\x00\x00'
          b'\x01\x00\x00\x00\x11\x00\x00\x00EGG-INFO/zip-safe\xe3\x02\x00PK\x01\x02'
          b'\x14\x03\x14\x00\x00\x00\x08\x00q8\xa8Lg0\xb7ix\x00\x00\x00\xb6\x00\x00\x00'
          b'\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x00EG'
          b'G-INFO/PKG-INFOPK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00q8\xa8L61\xa1XL'
          b'\x00\x00\x00\x87\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00'
          b'\x00\x00\x00\xa4\x81\xa7\x00\x00\x00EGG-INFO/SOURCES.txtPK\x01'
          b'\x02\x14\x03\x14\x00\x00\x00\x08\x00q8\xa8L\x93\x06\xd72\x03\x00\x00'
          b'\x00\x01\x00\x00\x00\x1d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
          b'\x00\xa4\x81%\x01\x00\x00EGG-INFO/dependency_links.txtPK\x01\x02'
          b'\x14\x03\x14\x00\x00\x00\x08\x00q8\xa8L\x93\x06\xd72\x03\x00\x00\x00'
          b'\x01\x00\x00\x00\x16\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
          b'\xa4\x81c\x01\x00\x00EGG-INFO/top_level.txtPK\x01\x02\x14\x03\x14\x00'
          b'\x00\x00\x08\x00q8\xa8L\x93\x06\xd72\x03\x00\x00\x00\x01\x00\x00\x00'
          b'\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x9a\x01\x00\x00EG'
          b'G-INFO/zip-safePK\x05\x06\x00\x00\x00\x00\x05\x00\x05\x00O\x01\x00\x00\xcc'
          b'\x01\x00\x00\x00\x00'
      )
  
      def setUp(self):
          self.cwd = os.getcwd()
          self.temp_dir = tempfile.mkdtemp('.buildouttest')
          self.project_dir = os.path.join(self.temp_dir, 'TheProject')
          self.project_dist_dir = os.path.join(self.temp_dir, 'dist')
          os.mkdir(self.project_dist_dir)
          self.egg_path = os.path.join(self.project_dist_dir, 'TheProject.egg')
          os.mkdir(self.project_dir)
          self.setup_path = os.path.join(self.project_dir, 'setup.py')
          os.chdir(self.temp_dir)
  
      def tearDown(self):
          os.chdir(self.cwd)
          shutil.rmtree(self.temp_dir)
  
      def _make_egg(self):
          with open(self.egg_path, 'wb') as f:
              f.write(self.EGG_DATA)
  
  
      def _get_distro_and_egg_path(self):
          # Returns a distribution with a version of '3.3.0',
          # but an egg with a version of '3.3'
          self._make_egg()
          from distutils.dist import Distribution
          dist = Distribution()
          dist.project_name = 'TheProject'
          dist.version = '3.3.0'
          dist.parsed_version = pkg_resources.parse_version(dist.version)
  
          return dist, self.egg_path
  
      def test_get_matching_dist_in_location_uses_parsed_version(self):
          # https://github.com/buildout/buildout/pull/452
          # An egg built with the version '3.3' should match a distribution
          # looking for '3.3.0'
          dist, location = self._get_distro_and_egg_path()
  
          result = zc.buildout.easy_install._get_matching_dist_in_location(
              dist,
              self.project_dist_dir
          )
          self.assertIsNotNone(result)
          self.assertEqual(result.version, '3.3')
  
      def test_move_to_eggs_dir_and_compile(self):
          # https://github.com/buildout/buildout/pull/452
          # An egg built with the version '3.3' should match a distribution
          # looking for '3.3.0'
  
          dist, location = self._get_distro_and_egg_path()
          dist.location = location
  
          dest = os.path.join(self.temp_dir, 'NewLoc')
  
          result = zc.buildout.easy_install._move_to_eggs_dir_and_compile(
              dist,
              dest
          )
  
          self.assertIsNotNone(result)
          self.assertEqual(result.version, '3.3')
          if zc.buildout.WINDOWS:
              self.assertIn(dest.lower(), result.location)
          else:
              self.assertIn(dest, result.location)
  
  
  def develop_w_non_setuptools_setup_scripts():
      """
  We should be able to deal with setup scripts that aren't setuptools based.
  
      >>> mkdir('foo')
      >>> write('foo', 'setup.py',
      ... '''
      ... from distutils.core import setup
      ... setup(name="foo")
      ... ''')
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... develop = foo
      ... parts =
      ... ''')
  
      >>> print_(system(join('bin', 'buildout')), end='')
      Develop: '/sample-buildout/foo'
  
      >>> ls('develop-eggs')
      -  foo.egg-link
      -  zc.recipe.egg.egg-link
  
      """
  
  def develop_verbose():
      """
  We should be able to deal with setup scripts that aren't setuptools based.
  
      >>> mkdir('foo')
      >>> write('foo', 'setup.py',
      ... '''
      ... from setuptools import setup
      ... setup(name="foo")
      ... ''')
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... develop = foo
      ... parts =
      ... ''')
  
      >>> print_(system(join('bin', 'buildout')+' -vv'), end='')
      ... # doctest: +ELLIPSIS
      Installing...
      Develop: '/sample-buildout/foo'
      ...
      Installed /sample-buildout/foo
      ...
  
      >>> ls('develop-eggs')
      -  foo.egg-link
      -  zc.recipe.egg.egg-link
  
      >>> print_(system(join('bin', 'buildout')+' -vvv'), end='')
      ... # doctest: +ELLIPSIS
      Installing...
      Develop: '/sample-buildout/foo'
      in: '/sample-buildout/foo'
      ... -q develop -mN -d /sample-buildout/develop-eggs/...
  
  
      """
  
  def buildout_error_handling():
      r"""Buildout error handling
  
  Asking for a section that doesn't exist, yields a missing section error:
  
      >>> import os
      >>> os.chdir(sample_buildout)
      >>> import zc.buildout.buildout
      >>> buildout = zc.buildout.buildout.Buildout('buildout.cfg', [])
      >>> buildout['eek']
      Traceback (most recent call last):
      ...
      MissingSection: The referenced section, 'eek', was not defined.
  
  Asking for an option that doesn't exist, a MissingOption error is raised:
  
      >>> buildout['buildout']['eek']
      Traceback (most recent call last):
      ...
      MissingOption: Missing option: buildout:eek
  
  It is an error to create a variable-reference cycle:
  
      >>> write(sample_buildout, 'buildout.cfg',
      ... '''
      ... [buildout]
      ... parts =
      ... x = ${buildout:y}
      ... y = ${buildout:z}
      ... z = ${buildout:x}
      ... ''')
  
      >>> print_(system(os.path.join(sample_buildout, 'bin', 'buildout')),
      ...        end='')
      ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
      While:
        Initializing.
        Getting section buildout.
        Initializing section buildout.
        Getting option buildout:x.
        Getting option buildout:y.
        Getting option buildout:z.
        Getting option buildout:x.
      Error: Circular reference in substitutions.
  
  It is an error to use funny characters in variable references:
  
      >>> write(sample_buildout, 'buildout.cfg',
      ... '''
      ... [buildout]
      ... develop = recipes
      ... parts = data_dir debug
      ... x = ${bui$ldout:y}
      ... ''')
  
      >>> print_(system(os.path.join(sample_buildout, 'bin', 'buildout')),
      ...        end='')
      While:
        Initializing.
        Getting section buildout.
        Initializing section buildout.
        Getting option buildout:x.
      Error: The section name in substitution, ${bui$ldout:y},
      has invalid characters.
  
      >>> write(sample_buildout, 'buildout.cfg',
      ... '''
      ... [buildout]
      ... develop = recipes
      ... parts = data_dir debug
      ... x = ${buildout:y{z}
      ... ''')
  
      >>> print_(system(os.path.join(sample_buildout, 'bin', 'buildout')),
      ...        end='')
      While:
        Initializing.
        Getting section buildout.
        Initializing section buildout.
        Getting option buildout:x.
      Error: The option name in substitution, ${buildout:y{z},
      has invalid characters.
  
  and too have too many or too few colons:
  
      >>> write(sample_buildout, 'buildout.cfg',
      ... '''
      ... [buildout]
      ... develop = recipes
      ... parts = data_dir debug
      ... x = ${parts}
      ... ''')
  
      >>> print_(system(os.path.join(sample_buildout, 'bin', 'buildout')),
      ...        end='')
      While:
        Initializing.
        Getting section buildout.
        Initializing section buildout.
        Getting option buildout:x.
      Error: The substitution, ${parts},
      doesn't contain a colon.
  
      >>> write(sample_buildout, 'buildout.cfg',
      ... '''
      ... [buildout]
      ... develop = recipes
      ... parts = data_dir debug
      ... x = ${buildout:y:z}
      ... ''')
  
      >>> print_(system(os.path.join(sample_buildout, 'bin', 'buildout')),
      ...        end='')
      While:
        Initializing.
        Getting section buildout.
        Initializing section buildout.
        Getting option buildout:x.
      Error: The substitution, ${buildout:y:z},
      has too many colons.
  
  All parts have to have a section:
  
      >>> write(sample_buildout, 'buildout.cfg',
      ... '''
      ... [buildout]
      ... parts = x
      ... ''')
  
      >>> print_(system(os.path.join(sample_buildout, 'bin', 'buildout')),
      ...        end='')
      While:
        Installing.
        Getting section x.
      Error: The referenced section, 'x', was not defined.
  
  and all parts have to have a specified recipe:
  
  
      >>> write(sample_buildout, 'buildout.cfg',
      ... '''
      ... [buildout]
      ... parts = x
      ...
      ... [x]
      ... foo = 1
      ... ''')
  
      >>> print_(system(os.path.join(sample_buildout, 'bin', 'buildout')),
      ...        end='')
      While:
        Installing.
      Error: Missing option: x:recipe
  
  """
  
  make_dist_that_requires_setup_py_template = """
  from setuptools import setup
  setup(name=%r, version=%r,
        install_requires=%r,
        )
  """
  
  def make_dist_that_requires(dest, name, requires=[], version=1, egg=''):
      os.mkdir(os.path.join(dest, name))
      with open(os.path.join(dest, name, 'setup.py'), 'w') as f:
          f.write(
              make_dist_that_requires_setup_py_template
              % (name, version, requires)
          )
  
  def show_who_requires_when_there_is_a_conflict():
      """
  It's a pain when we require eggs that have requirements that are
  incompatible. We want the error we get to tell us what is missing.
  
  Let's make a few develop distros, some of which have incompatible
  requirements.
  
      >>> make_dist_that_requires(sample_buildout, 'sampley',
      ...                         ['demoneeded ==1.0'])
      >>> make_dist_that_requires(sample_buildout, 'samplez',
      ...                         ['demoneeded ==1.1'])
  
  Now, let's create a buildout that requires y and z:
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts = eggs
      ... develop = sampley samplez
      ... find-links = %(link_server)s
      ...
      ... [eggs]
      ... recipe = zc.recipe.egg
      ... eggs = sampley
      ...        samplez
      ... ''' % globals())
  
      >>> print_(system(buildout), end='')
      Develop: '/sample-buildout/sampley'
      Develop: '/sample-buildout/samplez'
      Installing eggs.
      Getting distribution for 'demoneeded==1.1'.
      Got demoneeded 1.1.
      Version and requirements information containing demoneeded:
        Requirement of samplez: demoneeded==1.1
        Requirement of sampley: demoneeded==1.0
      While:
        Installing eggs.
      Error: There is a version conflict.
      We already have: demoneeded 1.1
      but sampley 1 requires 'demoneeded==1.0'.
  
  Here, we see that sampley required an older version of demoneeded. What
  if we hadn't required sampley ourselves:
  
      >>> make_dist_that_requires(sample_buildout, 'samplea', ['sampleb'])
      >>> make_dist_that_requires(sample_buildout, 'sampleb',
      ...                         ['sampley', 'samplea'])
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts = eggs
      ... develop = sampley samplez samplea sampleb
      ... find-links = %(link_server)s
      ...
      ... [eggs]
      ... recipe = zc.recipe.egg
      ... eggs = samplea
      ...        samplez
      ... ''' % globals())
  
  If we use the verbose switch, we can see where requirements are coming from:
  
      >>> print_(system(buildout+' -v'), end='') # doctest: +ELLIPSIS
      Installing 'zc.buildout', 'setuptools'...
      Develop: '/sample-buildout/sampley'
      Develop: '/sample-buildout/samplez'
      Develop: '/sample-buildout/samplea'
      Develop: '/sample-buildout/sampleb'
      ...
      Installing eggs.
      Installing 'samplea', 'samplez'.
      We have a develop egg: samplea 1
      We have a develop egg: samplez 1
      Getting required 'demoneeded==1.1'
        required by samplez 1.
      We have the distribution that satisfies 'demoneeded==1.1'.
      Getting required 'sampleb'
        required by samplea 1.
      We have a develop egg: sampleb 1
      Getting required 'sampley'
        required by sampleb 1.
      We have a develop egg: sampley 1
      Version and requirements information containing demoneeded:
        Requirement of samplez: demoneeded==1.1
        Requirement of sampley: demoneeded==1.0
      While:
        Installing eggs.
      Error: There is a version conflict.
      We already have: demoneeded 1.1
      but sampley 1 requires 'demoneeded==1.0'.
      """
  
  def version_conflict_rendering():
      """
  
  We use the arguments passed by pkg_resources.VersionConflict to construct a
  nice error message:
  
      >>> error = pkg_resources.VersionConflict('pkg1 2.1', 'pkg1 1.0')
      >>> ws = []  # Not relevant for this test
      >>> print_(zc.buildout.easy_install.VersionConflict(
      ...     error, ws)) # doctest: +ELLIPSIS
      There is a version conflict...
  
  But sometimes pkg_resources passes a nicely formatted string itself already.
  Extracting the original arguments fails in that case, so we just show the string.
  
      >>> error = pkg_resources.VersionConflict('pkg1 2.1 is simply wrong')
      >>> ws = []  # Not relevant for this test
      >>> print_(zc.buildout.easy_install.VersionConflict(
      ...     error, ws)) # doctest: +ELLIPSIS
      There is a version conflict.
      pkg1 2.1 is simply wrong
  
      """
  
  def show_who_requires_missing_distributions():
      """
  
  When working with a lot of eggs, which require eggs recursively, it
  can be hard to tell why we're requiring things we can't
  find. Fortunately, buildout will tell us who's asking for something
  that we can't find. when run in verbose mode
  
      >>> make_dist_that_requires(sample_buildout, 'sampley', ['demoneeded'])
      >>> make_dist_that_requires(sample_buildout, 'samplea', ['sampleb'])
      >>> make_dist_that_requires(sample_buildout, 'sampleb',
      ...                         ['sampley', 'samplea'])
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts = eggs
      ... develop = sampley samplea sampleb
      ...
      ... [eggs]
      ... recipe = zc.recipe.egg
      ... eggs = samplea
      ... ''')
  
      >>> print_(system(buildout+' -v'), end='') # doctest: +ELLIPSIS
      Installing ...
      Installing 'samplea'.
      We have a develop egg: samplea 1
      Getting required 'sampleb'
        required by samplea 1.
      We have a develop egg: sampleb 1
      Getting required 'sampley'
        required by sampleb 1.
      We have a develop egg: sampley 1
      Getting required 'demoneeded'
        required by sampley 1.
      We have no distributions for demoneeded that satisfies 'demoneeded'.
      ...
      While:
        Installing eggs.
        Getting distribution for 'demoneeded'.
      Error: Couldn't find a distribution for 'demoneeded'.
      """
  
  def show_who_requires_picked_versions():
      """
  
  The show-picked-versions prints the versions, but it also prints who
  required the picked distributions.
  We do not need to run in verbose mode for that to work:
  
      >>> make_dist_that_requires(sample_buildout, 'sampley', ['demo'])
      >>> make_dist_that_requires(sample_buildout, 'samplea', ['sampleb'])
      >>> make_dist_that_requires(sample_buildout, 'sampleb',
      ...                         ['sampley', 'samplea'])
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... find-links = %(sample_eggs)s
      ... parts = eggs
      ... show-picked-versions = true
      ... develop = sampley samplea sampleb
      ...
      ... [eggs]
      ... recipe = zc.recipe.egg
      ... eggs = samplea
      ... ''' % globals())
      >>> print_(system(buildout), end='') # doctest: +ELLIPSIS
      Develop: ...
      Versions had to be automatically picked.
      The following part definition lists the versions picked:
      [versions]
      <BLANKLINE>
      # Required by:
      # sampley==1
      demo = 0.3
      <BLANKLINE>
      # Required by:
      # demo==0.3
      demoneeded = 1.1
      """
  
  def test_comparing_saved_options_with_funny_characters():
      """
  If an option has newlines, extra/odd spaces or a %, we need to make sure
  the comparison with the saved value works correctly.
  
      >>> mkdir(sample_buildout, 'recipes')
      >>> write(sample_buildout, 'recipes', 'debug.py',
      ... '''
      ... class Debug:
      ...     def __init__(self, buildout, name, options):
      ...         options['debug'] = \"\"\"  <zodb>
      ...
      ...   <filestorage>
      ...     path foo
      ...   </filestorage>
      ...
      ... </zodb>
      ...      \"\"\"
      ...         options['debug1'] = \"\"\"
      ... <zodb>
      ...
      ...   <filestorage>
      ...     path foo
      ...   </filestorage>
      ...
      ... </zodb>
      ... \"\"\"
      ...         options['debug2'] = '  x  '
      ...         options['debug3'] = '42'
      ...         options['format'] = '%3d'
      ...
      ...     def install(self):
      ...         with open('t', 'w') as f: f.write('t')
      ...         return 't'
      ...
      ...     update = install
      ... ''')
  
  
      >>> write(sample_buildout, 'recipes', 'setup.py',
      ... '''
      ... from setuptools import setup
      ... setup(
      ...     name = "recipes",
      ...     entry_points = {'zc.buildout': ['default = debug:Debug']},
      ...     )
      ... ''')
  
      >>> write(sample_buildout, 'recipes', 'README.txt', " ")
  
      >>> write(sample_buildout, 'buildout.cfg',
      ... '''
      ... [buildout]
      ... develop = recipes
      ... parts = debug
      ...
      ... [debug]
      ... recipe = recipes
      ... ''')
  
      >>> os.chdir(sample_buildout)
      >>> buildout = os.path.join(sample_buildout, 'bin', 'buildout')
  
      >>> print_(system(buildout), end='')
      Develop: '/sample-buildout/recipes'
      Installing debug.
  
  If we run the buildout again, we shoudn't get a message about
  uninstalling anything because the configuration hasn't changed.
  
      >>> print_(system(buildout), end='')
      Develop: '/sample-buildout/recipes'
      Updating debug.
  """
  
  def finding_eggs_as_local_directories():
      r"""
  It is possible to set up find-links so that we could install from
  a local directory that may contained unzipped eggs.
  
      >>> src = tmpdir('src')
      >>> write(src, 'setup.py',
      ... '''
      ... from setuptools import setup
      ... setup(name='demo', py_modules=[''],
      ...    zip_safe=False, version='1.0', author='bob', url='bob',
      ...    author_email='bob')
      ... ''')
  
      >>> write(src, 't.py', '#\n')
      >>> write(src, 'README.txt', '')
      >>> _ = system(join('bin', 'buildout')+' setup ' + src + ' bdist_egg')
  
  Install it so it gets unzipped:
  
      >>> d1 = tmpdir('d1')
      >>> ws = zc.buildout.easy_install.install(
      ...     ['demo'], d1, links=[join(src, 'dist')],
      ...     )
  
      >>> ls(d1)
      d  demo-1.0-py2.4.egg
  
  Then try to install it again:
  
      >>> d2 = tmpdir('d2')
      >>> ws = zc.buildout.easy_install.install(
      ...     ['demo'], d2, links=[d1],
      ...     )
  
      >>> ls(d2)
      d  demo-1.0-py2.4.egg
  
      """
  
  def create_sections_on_command_line():
      """
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts =
      ... x = ${foo:bar}
      ... ''')
  
      >>> print_(system(buildout + ' foo:bar=1 -vv'), end='')
      ...        # doctest: +ELLIPSIS
      Installing 'zc.buildout', 'setuptools', 'pip', 'wheel'.
      ...
      [foo]
      bar = 1
      ...
  
      """
  
  def test_help():
      """
      >>> print_(system(os.path.join(sample_buildout, 'bin', 'buildout')+' -h'))
      ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
      Usage: buildout [options] [assignments] [command [command arguments]]
      <BLANKLINE>
      Options:
      <BLANKLINE>
        -c config_file
      <BLANKLINE>
          Specify the path to the buildout configuration file to be used.
          This defaults to the file named "buildout.cfg" in the current
          working directory.
      ...
        -h, --help
      ...
  
      >>> print_(system(os.path.join(sample_buildout, 'bin', 'buildout')
      ...              +' --help'))
      ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
      Usage: buildout [options] [assignments] [command [command arguments]]
      <BLANKLINE>
      Options:
      <BLANKLINE>
        -c config_file
      <BLANKLINE>
          Specify the path to the buildout configuration file to be used.
          This defaults to the file named "buildout.cfg" in the current
          working directory.
      ...
        -h, --help
      ...
      """
  
  def test_version():
      """
      >>> buildout = os.path.join(sample_buildout, 'bin', 'buildout')
      >>> print_(system(buildout+' --version'))
      ... # doctest: +ELLIPSIS
      buildout version ...
  
      """
  
  def test_bootstrap_with_extension():
      """
  We had a problem running a bootstrap with an extension.  Let's make
  sure it is fixed.  Basically, we don't load extensions when
  bootstrapping.
  
      >>> d = tmpdir('sample-bootstrap')
  
      >>> write(d, 'buildout.cfg',
      ... '''
      ... [buildout]
      ... extensions = some_awsome_extension
      ... parts =
      ... ''')
  
      >>> os.chdir(d)
      >>> print_(system(os.path.join(sample_buildout, 'bin', 'buildout')
      ...              + ' bootstrap'), end='')
      Creating directory '/sample-bootstrap/eggs'.
      Creating directory '/sample-bootstrap/bin'.
      Creating directory '/sample-bootstrap/parts'.
      Creating directory '/sample-bootstrap/develop-eggs'.
      Generated script '/sample-bootstrap/bin/buildout'.
      """
  
  
  def bug_92891_bootstrap_crashes_with_egg_recipe_in_buildout_section():
      """
      >>> d = tmpdir('sample-bootstrap')
  
      >>> write(d, 'buildout.cfg',
      ... '''
      ... [buildout]
      ... parts = buildout
      ... eggs-directory = eggs
      ...
      ... [buildout]
      ... recipe = zc.recipe.egg
      ... eggs = zc.buildout
      ... scripts = buildout=buildout
      ... ''')
  
      >>> os.chdir(d)
      >>> print_(system(os.path.join(sample_buildout, 'bin', 'buildout')
      ...              + ' bootstrap'), end='')
      Creating directory '/sample-bootstrap/eggs'.
      Creating directory '/sample-bootstrap/bin'.
      Creating directory '/sample-bootstrap/parts'.
      Creating directory '/sample-bootstrap/develop-eggs'.
      Generated script '/sample-bootstrap/bin/buildout'.
  
      >>> print_(system(os.path.join('bin', 'buildout')), end='')
      Unused options for buildout: 'scripts' 'eggs'.
  
      """
  
  def removing_eggs_from_develop_section_causes_egg_link_to_be_removed():
      '''
      >>> cd(sample_buildout)
  
  Create a develop egg:
  
      >>> mkdir('foo')
      >>> write('foo', 'setup.py',
      ... """
      ... from setuptools import setup
      ... setup(name='foox')
      ... """)
      >>> write('buildout.cfg',
      ... """
      ... [buildout]
      ... develop = foo
      ... parts =
      ... """)
  
      >>> print_(system(join('bin', 'buildout')), end='')
      Develop: '/sample-buildout/foo'
  
      >>> ls('develop-eggs')
      -  foox.egg-link
      -  zc.recipe.egg.egg-link
  
  Create another:
  
      >>> mkdir('bar')
      >>> write('bar', 'setup.py',
      ... """
      ... from setuptools import setup
      ... setup(name='fooy')
      ... """)
      >>> write('buildout.cfg',
      ... """
      ... [buildout]
      ... develop = foo bar
      ... parts =
      ... """)
  
      >>> print_(system(join('bin', 'buildout')), end='')
      Develop: '/sample-buildout/foo'
      Develop: '/sample-buildout/bar'
  
      >>> ls('develop-eggs')
      -  foox.egg-link
      -  fooy.egg-link
      -  zc.recipe.egg.egg-link
  
  Remove one:
  
      >>> write('buildout.cfg',
      ... """
      ... [buildout]
      ... develop = bar
      ... parts =
      ... """)
      >>> print_(system(join('bin', 'buildout')), end='')
      Develop: '/sample-buildout/bar'
  
  It is gone
  
      >>> ls('develop-eggs')
      -  fooy.egg-link
      -  zc.recipe.egg.egg-link
  
  Remove the other:
  
      >>> write('buildout.cfg',
      ... """
      ... [buildout]
      ... parts =
      ... """)
      >>> print_(system(join('bin', 'buildout')), end='')
  
  All gone
  
      >>> ls('develop-eggs')
      -  zc.recipe.egg.egg-link
      '''
  
  
  def add_setuptools_to_dependencies_when_namespace_packages():
      '''
  Often, a package depends on setuptools solely by virtue of using
  namespace packages. In this situation, package authors often forget to
  declare setuptools as a dependency. This is a mistake, but,
  unfortunately, a common one that we need to work around.  If an egg
  uses namespace packages and does not include setuptools as a dependency,
  we will still include setuptools in the working set.  If we see this for
  a develop egg, we will also generate a warning.
  
      >>> mkdir('foo')
      >>> mkdir('foo', 'src')
      >>> mkdir('foo', 'src', 'stuff')
      >>> write('foo', 'src', 'stuff', '__init__.py',
      ... """__import__('pkg_resources').declare_namespace(__name__)
      ... """)
      >>> mkdir('foo', 'src', 'stuff', 'foox')
      >>> write('foo', 'src', 'stuff', 'foox', '__init__.py', '')
      >>> write('foo', 'setup.py',
      ... """
      ... from setuptools import setup
      ... setup(name='foox',
      ...       namespace_packages = ['stuff'],
      ...       package_dir = {'': 'src'},
      ...       packages = ['stuff', 'stuff.foox'],
      ...       )
      ... """)
      >>> write('foo', 'README.txt', '')
  
      >>> write('buildout.cfg',
      ... """
      ... [buildout]
      ... develop = foo
      ... parts =
      ... """)
  
      >>> print_(system(join('bin', 'buildout')), end='')
      Develop: '/sample-buildout/foo'
  
  Now, if we generate a working set using the egg link, we will get a warning
  and we will get setuptools included in the working set.
  
      >>> import logging, zope.testing.loggingsupport
      >>> handler = zope.testing.loggingsupport.InstalledHandler(
      ...        'zc.buildout.easy_install', level=logging.WARNING)
      >>> logging.getLogger('zc.buildout.easy_install').propagate = False
  
      >>> def get_working_set(*project_names):
      ...     paths = [join(sample_buildout, 'eggs'),
      ...              join(sample_buildout, 'develop-eggs')]
      ...     return [
      ...        dist.project_name
      ...        for dist in zc.buildout.easy_install.working_set(
      ...            project_names, sys.executable, paths)
      ...     ]
      >>> get_working_set('foox')
      ['foox', 'setuptools']
  
      >>> print_(handler)
      zc.buildout.easy_install WARNING
        Develop distribution: foox 0.0.0
      uses namespace packages but the distribution does not require setuptools.
  
      >>> handler.clear()
  
  On the other hand, if we have a zipped egg, rather than a develop egg:
  
      >>> os.remove(join('develop-eggs', 'foox.egg-link'))
  
      >>> _ = system(join('bin', 'buildout') + ' setup foo bdist_egg')
      >>> foox_dist = join('foo', 'dist')
      >>> import glob
      >>> [foox_egg] = glob.glob(join(foox_dist, 'foox-*.egg'))
      >>> _ = shutil.copy(foox_egg, join(sample_buildout, 'eggs'))
      >>> ls('develop-eggs')
      -  zc.recipe.egg.egg-link
  
      >>> ls('eggs') # doctest: +ELLIPSIS
      -  foox-0.0.0-py2.4.egg
      -  pip.egg-link
      -  setuptools.egg-link
      -  wheel.egg-link
      -  zc.buildout.egg-link
  
  We do not get a warning, but we do get setuptools included in the working set:
  
      >>> get_working_set('foox')
      ['foox', 'setuptools']
  
      >>> print_(handler, end='')
  
  Likewise for an unzipped egg:
  
      >>> foox_egg_basename = os.path.basename(foox_egg)
      >>> os.remove(join(sample_buildout, 'eggs', foox_egg_basename))
      >>> _ = zc.buildout.easy_install.install(
      ...     ['foox'], join(sample_buildout, 'eggs'), links=[foox_dist],
      ...     index='file://' + foox_dist)
      >>> ls('develop-eggs')
      -  zc.recipe.egg.egg-link
  
      >>> get_working_set('foox')
      ['foox', 'setuptools']
  
      >>> print_(handler, end='')
  
  We get the same behavior if it is a dependency that uses a
  namespace package.
  
  
      >>> mkdir('bar')
      >>> write('bar', 'setup.py',
      ... """
      ... from setuptools import setup
      ... setup(name='bar', install_requires = ['foox'])
      ... """)
      >>> write('bar', 'README.txt', '')
  
      >>> write('buildout.cfg',
      ... """
      ... [buildout]
      ... develop = foo bar
      ... parts =
      ... """)
  
      >>> print_(system(join('bin', 'buildout')), end='')
      Develop: '/sample-buildout/foo'
      Develop: '/sample-buildout/bar'
  
      >>> get_working_set('bar')
      ['bar', 'foox', 'setuptools']
  
      >>> print_(handler, end='')
      zc.buildout.easy_install WARNING
        Develop distribution: foox 0.0.0
      uses namespace packages but the distribution does not require setuptools.
  
  On the other hand, if the distribution uses ``pkgutil.extend_path()`` to
  implement its namespaces, even if just as fallback from the absence of
  ``pkg_resources``, then ``setuptools`` should not be added as requirement to
  its unzipped egg:
  
      >>> foox_installed_egg = join(sample_buildout, 'eggs', foox_egg_basename)
      >>> namespace_init = join(foox_installed_egg, 'stuff', '__init__.py')
      >>> write(namespace_init,
      ... """try:
      ...     __import__('pkg_resources').declare_namespace(__name__)
      ... except ImportError:
      ...     __path__ = __import__('pkgutil').extend_path(__path__, __name__)
      ... """)
  
      >>> os.remove(join('develop-eggs', 'foox.egg-link'))
      >>> os.remove(join('develop-eggs', 'bar.egg-link'))
      >>> get_working_set('foox')
      ['foox']
  
  The same goes for packages using PEP420 namespaces
  
      >>> os.remove(namespace_init)
      >>> get_working_set('foox')
      ['foox']
  
  Cleanup:
  
      >>> logging.getLogger('zc.buildout.easy_install').propagate = True
      >>> handler.uninstall()
  
      '''
  
  def develop_preserves_existing_setup_cfg():
      """
  
  See "Handling custom build options for extensions in develop eggs" in
  easy_install.txt.  This will be very similar except that we'll have an
  existing setup.cfg:
  
      >>> write(extdemo, "setup.cfg",
      ... '''
      ... # sampe cfg file
      ...
      ... [foo]
      ... bar = 1
      ...
      ... [build_ext]
      ... define = X,Y
      ... ''')
  
      >>> mkdir('include')
      >>> write('include', 'extdemo.h',
      ... '''
      ... #define EXTDEMO 42
      ... ''')
  
      >>> dest = tmpdir('dest')
      >>> zc.buildout.easy_install.develop(
      ...   extdemo, dest,
      ...   {'include-dirs': os.path.join(sample_buildout, 'include')})
      '/dest/extdemo.egg-link'
  
      >>> ls(dest)
      -  extdemo.egg-link
  
      >>> cat(extdemo, "setup.cfg")
      <BLANKLINE>
      # sampe cfg file
      <BLANKLINE>
      [foo]
      bar = 1
      <BLANKLINE>
      [build_ext]
      define = X,Y
  
  """
  
  def uninstall_recipes_used_for_removal():
      r"""
  Uninstall recipes need to be called when a part is removed too:
  
      >>> mkdir("recipes")
      >>> write("recipes", "setup.py",
      ... '''
      ... from setuptools import setup
      ... setup(name='recipes',
      ...       entry_points={
      ...          'zc.buildout': ["demo=demo:Install"],
      ...          'zc.buildout.uninstall': ["demo=demo:uninstall"],
      ...          })
      ... ''')
  
      >>> write("recipes", "demo.py",
      ... r'''
      ... import sys
      ... class Install:
      ...     def __init__(*args): pass
      ...     def install(self):
      ...         sys.stdout.write('installing\n')
      ...         return ()
      ... def uninstall(name, options):
      ...     sys.stdout.write('uninstalling\n')
      ... ''')
  
      >>> write('buildout.cfg', '''
      ... [buildout]
      ... develop = recipes
      ... parts = demo
      ... [demo]
      ... recipe = recipes:demo
      ... ''')
  
      >>> print_(system(join('bin', 'buildout')), end='')
      Develop: '/sample-buildout/recipes'
      Installing demo.
      installing
  
  
      >>> write('buildout.cfg', '''
      ... [buildout]
      ... develop = recipes
      ... parts = demo
      ... [demo]
      ... recipe = recipes:demo
      ... x = 1
      ... ''')
  
      >>> print_(system(join('bin', 'buildout')), end='')
      Develop: '/sample-buildout/recipes'
      Uninstalling demo.
      Running uninstall recipe.
      uninstalling
      Installing demo.
      installing
  
  
      >>> write('buildout.cfg', '''
      ... [buildout]
      ... develop = recipes
      ... parts =
      ... ''')
  
      >>> print_(system(join('bin', 'buildout')), end='')
      Develop: '/sample-buildout/recipes'
      Uninstalling demo.
      Running uninstall recipe.
      uninstalling
  
  """
  
  def extensions_installed_as_eggs_work_in_offline_mode():
      '''
      >>> mkdir('demo')
  
      >>> write('demo', 'demo.py',
      ... r"""
      ... import sys
      ... def print_(*args):
      ...     sys.stdout.write(' '.join(map(str, args)) + '\\n')
      ... def ext(buildout):
      ...     print_('ext', sorted(buildout))
      ... """)
  
      >>> write('demo', 'setup.py',
      ... """
      ... from setuptools import setup
      ...
      ... setup(
      ...     name = "demo",
      ...     py_modules=['demo'],
      ...     entry_points = {'zc.buildout.extension': ['ext = demo:ext']},
      ...     )
      ... """)
  
      >>> bdist_egg(join(sample_buildout, "demo"), sys.executable,
      ...           join(sample_buildout, "eggs"))
  
      >>> write(sample_buildout, 'buildout.cfg',
      ... """
      ... [buildout]
      ... extensions = demo
      ... parts =
      ... offline = true
      ... """)
  
      >>> print_(system(join(sample_buildout, 'bin', 'buildout')), end='')
      ext ['buildout', 'versions']
  
  
      '''
  
  def changes_in_svn_or_CVS_dont_affect_sig():
      """
  
  If we have a develop recipe, it's signature shouldn't be affected to
  changes in .git, .svn or CVS directories.
  
      >>> mkdir('recipe')
      >>> write('recipe', 'setup.py',
      ... '''
      ... from setuptools import setup
      ... setup(name='recipe',
      ...       entry_points={'zc.buildout': ['default=foo:Foo']})
      ... ''')
      >>> write('recipe', 'foo.py',
      ... '''
      ... class Foo:
      ...     def __init__(*args): pass
      ...     def install(*args): return ()
      ...     update = install
      ... ''')
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... develop = recipe
      ... parts = foo
      ...
      ... [foo]
      ... recipe = recipe
      ... ''')
  
  
      >>> print_(system(join(sample_buildout, 'bin', 'buildout')), end='')
      Develop: '/sample-buildout/recipe'
      Installing foo.
  
      >>> mkdir('recipe', '.git')
      >>> mkdir('recipe', '.svn')
      >>> mkdir('recipe', 'CVS')
      >>> print_(system(join(sample_buildout, 'bin', 'buildout')), end='')
      Develop: '/sample-buildout/recipe'
      Updating foo.
  
      >>> write('recipe', '.git', 'x', '1')
      >>> write('recipe', '.svn', 'x', '1')
      >>> write('recipe', 'CVS', 'x', '1')
  
      >>> print_(system(join(sample_buildout, 'bin', 'buildout')), end='')
      Develop: '/sample-buildout/recipe'
      Updating foo.
  
      """
  
  if hasattr(os, 'symlink'):
      def bug_250537_broken_symlink_doesnt_affect_sig():
          """
  If we have a develop recipe, it's signature shouldn't be affected by
  broken symlinks, and better yet, computing the hash should not break
  because of the missing target file.
  
      >>> mkdir('recipe')
      >>> write('recipe', 'setup.py',
      ... '''
      ... from setuptools import setup
      ... setup(name='recipe',
      ...       entry_points={'zc.buildout': ['default=foo:Foo']})
      ... ''')
      >>> write('recipe', 'foo.py',
      ... '''
      ... class Foo:
      ...     def __init__(*args): pass
      ...     def install(*args): return ()
      ...     update = install
      ... ''')
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... develop = recipe
      ... parts = foo
      ...
      ... [foo]
      ... recipe = recipe
      ... ''')
  
  
      >>> print_(system(join(sample_buildout, 'bin', 'buildout')), end='')
      Develop: '/sample-buildout/recipe'
      Installing foo.
  
      >>> write('recipe', 'some-file', '1')
      >>> os.symlink(join('recipe', 'some-file'),
      ...            join('recipe', 'another-file'))
      >>> remove('recipe', 'some-file')
  
      >>> print_(system(join(sample_buildout, 'bin', 'buildout')), end='')
      Develop: '/sample-buildout/recipe'
      Updating foo.
  
      """
  
  def unicode_filename_doesnt_break_hash():
      """
  Buildout's _dir_hash() used to break on non-ascii filenames on python 2.
  
      >>> mkdir('héhé')
      >>> write('héhé', 'héhé.py',
      ... '''
      ... print('Example filename from pyramid tests')
      ... ''')
      >>> from zc.buildout.buildout import _dir_hash
      >>> dont_care = _dir_hash('héhé')
  
      """
  
  def o_option_sets_offline():
      """
      >>> print_(system(join(sample_buildout, 'bin', 'buildout')+' -vvo'), end='')
      ... # doctest: +ELLIPSIS
      <BLANKLINE>
      ...
      offline = true
      ...
      """
  
  def recipe_upgrade():
      r"""
  
  The buildout will upgrade recipes in newest (and non-offline) mode.
  
  Let's create a recipe egg
  
      >>> mkdir('recipe')
      >>> write('recipe', 'recipe.py',
      ... r'''
      ... import sys
      ... class Recipe:
      ...     def __init__(*a): pass
      ...     def install(self):
      ...         sys.stdout.write('recipe v1\n')
      ...         return ()
      ...     update = install
      ... ''')
  
      >>> write('recipe', 'setup.py',
      ... '''
      ... from setuptools import setup
      ... setup(name='recipe', version='1', py_modules=['recipe'],
      ...       entry_points={'zc.buildout': ['default = recipe:Recipe']},
      ...       )
      ... ''')
  
      >>> write('recipe', 'README', '')
  
      >>> print_(system(buildout+' setup recipe bdist_egg')) # doctest: +ELLIPSIS
      Running setup script 'recipe/setup.py'.
      ...
  
      >>> rmdir('recipe', 'build')
  
  And update our buildout to use it.
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts = foo
      ... find-links = %s
      ...
      ... [foo]
      ... recipe = recipe
      ... ''' % join('recipe', 'dist'))
  
      >>> print_(system(buildout), end='')
      Getting distribution for 'recipe'.
      Got recipe 1.
      Installing foo.
      recipe v1
  
  Now, if we update the recipe egg:
  
      >>> write('recipe', 'recipe.py',
      ... r'''
      ... import sys
      ... class Recipe:
      ...     def __init__(*a): pass
      ...     def install(self):
      ...         sys.stdout.write('recipe v2\n')
      ...         return ()
      ...     update = install
      ... ''')
  
      >>> write('recipe', 'setup.py',
      ... '''
      ... from setuptools import setup
      ... setup(name='recipe', version='2', py_modules=['recipe'],
      ...       entry_points={'zc.buildout': ['default = recipe:Recipe']},
      ...       )
      ... ''')
  
  
      >>> print_(system(buildout+' setup recipe bdist_egg')) # doctest: +ELLIPSIS
      Running setup script 'recipe/setup.py'.
      ...
  
  We won't get the update if we specify -N:
  
      >>> print_(system(buildout+' -N'), end='')
      Updating foo.
      recipe v1
  
  or if we use -o:
  
      >>> print_(system(buildout+' -o'), end='')
      Updating foo.
      recipe v1
  
  But we will if we use neither of these:
  
      >>> print_(system(buildout), end='')
      Getting distribution for 'recipe'.
      Got recipe 2.
      Uninstalling foo.
      Installing foo.
      recipe v2
  
  We can also select a particular recipe version:
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts = foo
      ... find-links = %s
      ...
      ... [foo]
      ... recipe = recipe ==1
      ... ''' % join('recipe', 'dist'))
  
      >>> print_(system(buildout), end='')
      Uninstalling foo.
      Installing foo.
      recipe v1
  
      """
  
  def update_adds_to_uninstall_list():
      """
  
  Paths returned by the update method are added to the list of paths to
  uninstall
  
      >>> mkdir('recipe')
      >>> write('recipe', 'setup.py',
      ... '''
      ... from setuptools import setup
      ... setup(name='recipe',
      ...       entry_points={'zc.buildout': ['default = recipe:Recipe']},
      ...       )
      ... ''')
  
      >>> write('recipe', 'recipe.py',
      ... '''
      ... import os
      ... class Recipe:
      ...     def __init__(*_): pass
      ...     def install(self):
      ...         r = ('a', 'b', 'c')
      ...         for p in r: os.mkdir(p)
      ...         return r
      ...     def update(self):
      ...         r = ('c', 'd', 'e')
      ...         for p in r:
      ...             if not os.path.exists(p):
      ...                os.mkdir(p)
      ...         return r
      ... ''')
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... develop = recipe
      ... parts = foo
      ...
      ... [foo]
      ... recipe = recipe
      ... ''')
  
      >>> print_(system(buildout), end='')
      Develop: '/sample-buildout/recipe'
      Installing foo.
  
      >>> print_(system(buildout), end='')
      Develop: '/sample-buildout/recipe'
      Updating foo.
  
      >>> cat('.installed.cfg') # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
      [buildout]
      ...
      [foo]
      __buildout_installed__ = a
      	b
      	c
      	d
      	e
      __buildout_signature__ = ...
  
  """
  
  def log_when_there_are_not_local_distros():
      """
      >>> from zope.testing.loggingsupport import InstalledHandler
      >>> handler = InstalledHandler('zc.buildout.easy_install')
      >>> import logging
      >>> logger = logging.getLogger('zc.buildout.easy_install')
      >>> old_propogate = logger.propagate
      >>> logger.propagate = False
  
      >>> dest = tmpdir('sample-install')
      >>> import zc.buildout.easy_install
      >>> ws = zc.buildout.easy_install.install(
      ...     ['demo==0.2'], dest,
      ...     links=[link_server], index=link_server+'index/')
  
      >>> print_(handler) # doctest: +ELLIPSIS
      zc.buildout.easy_install DEBUG
        Installing 'demo==0.2'.
      zc.buildout.easy_install DEBUG
        We have no distributions for demo that satisfies 'demo==0.2'.
      ...
  
      >>> handler.uninstall()
      >>> logger.propagate = old_propogate
  
      """
  
  def internal_errors():
      """Internal errors are clearly marked and don't generate tracebacks:
  
      >>> mkdir(sample_buildout, 'recipes')
  
      >>> write(sample_buildout, 'recipes', 'mkdir.py',
      ... '''
      ... class Mkdir:
      ...     def __init__(self, buildout, name, options):
      ...         self.name, self.options = name, options
      ...         options['path'] = os.path.join(
      ...                               buildout['buildout']['directory'],
      ...                               options['path'],
      ...                               )
      ... ''')
  
      >>> write(sample_buildout, 'recipes', 'setup.py',
      ... '''
      ... from setuptools import setup
      ... setup(name = "recipes",
      ...       entry_points = {'zc.buildout': ['mkdir = mkdir:Mkdir']},
      ...       )
      ... ''')
  
      >>> write(sample_buildout, 'buildout.cfg',
      ... '''
      ... [buildout]
      ... develop = recipes
      ... parts = data-dir
      ...
      ... [data-dir]
      ... recipe = recipes:mkdir
      ... ''')
  
      >>> print_(system(buildout), end='') # doctest: +ELLIPSIS
      Develop: '/sample-buildout/recipes'
      While:
        Installing.
        Getting section data-dir.
        Initializing section data-dir.
      <BLANKLINE>
      An internal error occurred due to a bug in either zc.buildout or in a
      recipe being used:
      Traceback (most recent call last):
      ...
      NameError: global name 'os' is not defined
      """
  
  def whine_about_unused_options():
      '''
  
      >>> write('foo.py',
      ... """
      ... class Foo:
      ...
      ...     def __init__(self, buildout, name, options):
      ...         self.name, self.options = name, options
      ...         options['x']
      ...
      ...     def install(self):
      ...         self.options['y']
      ...         return ()
      ... """)
  
      >>> write('setup.py',
      ... """
      ... from setuptools import setup
      ... setup(name = "foo",
      ...       entry_points = {'zc.buildout': ['default = foo:Foo']},
      ...       )
      ... """)
  
      >>> write('buildout.cfg',
      ... """
      ... [buildout]
      ... develop = .
      ... parts = foo
      ... a = 1
      ...
      ... [foo]
      ... recipe = foo
      ... x = 1
      ... y = 1
      ... z = 1
      ... """)
  
      >>> print_(system(buildout), end='')
      Develop: '/sample-buildout/.'
      Unused options for buildout: 'a'.
      Installing foo.
      Unused options for foo: 'z'.
      '''
  
  def abnormal_exit():
      """
  People sometimes hit control-c while running a builout. We need to make
  sure that the installed database Isn't corrupted.  To test this, we'll create
  some evil recipes that exit uncleanly:
  
      >>> mkdir('recipes')
      >>> write('recipes', 'recipes.py',
      ... '''
      ... import os
      ...
      ... class Clean:
      ...     def __init__(*_): pass
      ...     def install(_): return ()
      ...     def update(_): pass
      ...
      ... class EvilInstall(Clean):
      ...     def install(_): os._exit(1)
      ...
      ... class EvilUpdate(Clean):
      ...     def update(_): os._exit(1)
      ... ''')
  
      >>> write('recipes', 'setup.py',
      ... '''
      ... import setuptools
      ... setuptools.setup(name='recipes',
      ...    entry_points = {
      ...      'zc.buildout': [
      ...          'clean = recipes:Clean',
      ...          'evil_install = recipes:EvilInstall',
      ...          'evil_update = recipes:EvilUpdate',
      ...          'evil_uninstall = recipes:Clean',
      ...          ],
      ...       },
      ...     )
      ... ''')
  
  Now let's look at 3 cases:
  
  1. We exit during installation after installing some other parts:
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... develop = recipes
      ... parts = p1 p2 p3 p4
      ...
      ... [p1]
      ... recipe = recipes:clean
      ...
      ... [p2]
      ... recipe = recipes:clean
      ...
      ... [p3]
      ... recipe = recipes:evil_install
      ...
      ... [p4]
      ... recipe = recipes:clean
      ... ''')
  
      >>> print_(system(buildout), end='')
      Develop: '/sample-buildout/recipes'
      Installing p1.
      Installing p2.
      Installing p3.
  
      >>> print_(system(buildout), end='')
      Develop: '/sample-buildout/recipes'
      Updating p1.
      Updating p2.
      Installing p3.
  
      >>> print_(system(buildout+' buildout:parts='), end='')
      Develop: '/sample-buildout/recipes'
      Uninstalling p2.
      Uninstalling p1.
  
  2. We exit while updating:
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... develop = recipes
      ... parts = p1 p2 p3 p4
      ...
      ... [p1]
      ... recipe = recipes:clean
      ...
      ... [p2]
      ... recipe = recipes:clean
      ...
      ... [p3]
      ... recipe = recipes:evil_update
      ...
      ... [p4]
      ... recipe = recipes:clean
      ... ''')
  
      >>> print_(system(buildout), end='')
      Develop: '/sample-buildout/recipes'
      Installing p1.
      Installing p2.
      Installing p3.
      Installing p4.
  
      >>> print_(system(buildout), end='')
      Develop: '/sample-buildout/recipes'
      Updating p1.
      Updating p2.
      Updating p3.
  
      >>> print_(system(buildout+' buildout:parts='), end='')
      Develop: '/sample-buildout/recipes'
      Uninstalling p2.
      Uninstalling p1.
      Uninstalling p4.
      Uninstalling p3.
  
  3. We exit while installing or updating after uninstalling:
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... develop = recipes
      ... parts = p1 p2 p3 p4
      ...
      ... [p1]
      ... recipe = recipes:evil_update
      ...
      ... [p2]
      ... recipe = recipes:clean
      ...
      ... [p3]
      ... recipe = recipes:clean
      ...
      ... [p4]
      ... recipe = recipes:clean
      ... ''')
  
      >>> print_(system(buildout), end='')
      Develop: '/sample-buildout/recipes'
      Installing p1.
      Installing p2.
      Installing p3.
      Installing p4.
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... develop = recipes
      ... parts = p1 p2 p3 p4
      ...
      ... [p1]
      ... recipe = recipes:evil_update
      ...
      ... [p2]
      ... recipe = recipes:clean
      ...
      ... [p3]
      ... recipe = recipes:clean
      ...
      ... [p4]
      ... recipe = recipes:clean
      ... x = 1
      ... ''')
  
      >>> print_(system(buildout), end='')
      Develop: '/sample-buildout/recipes'
      Uninstalling p4.
      Updating p1.
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... develop = recipes
      ... parts = p1 p2 p3 p4
      ...
      ... [p1]
      ... recipe = recipes:clean
      ...
      ... [p2]
      ... recipe = recipes:clean
      ...
      ... [p3]
      ... recipe = recipes:clean
      ...
      ... [p4]
      ... recipe = recipes:clean
      ... ''')
  
      >>> print_(system(buildout), end='')
      Develop: '/sample-buildout/recipes'
      Uninstalling p1.
      Installing p1.
      Updating p2.
      Updating p3.
      Installing p4.
  
      """
  
  def install_source_dist_with_bad_py():
      r"""
  
      >>> mkdir('badegg')
      >>> mkdir('badegg', 'badegg')
      >>> write('badegg', 'badegg', '__init__.py', '#\\n')
      >>> mkdir('badegg', 'badegg', 'scripts')
      >>> write('badegg', 'badegg', 'scripts', '__init__.py', '#\\n')
      >>> write('badegg', 'badegg', 'scripts', 'one.py',
      ... '''
      ... return 1
      ... ''')
  
      >>> write('badegg', 'setup.py',
      ... '''
      ... from setuptools import setup, find_packages
      ... setup(
      ...     name='badegg',
      ...     version='1',
      ...     packages = find_packages('.'),
      ...     zip_safe=False)
      ... ''')
  
      >>> print_(system(buildout+' setup badegg sdist'), end='') # doctest: +ELLIPSIS
      Running setup script 'badegg/setup.py'.
      ...
  
      >>> dist = join('badegg', 'dist')
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts = eggs bo
      ... find-links = %(dist)s
      ...
      ... [eggs]
      ... recipe = zc.recipe.egg
      ... eggs = badegg
      ...
      ... [bo]
      ... recipe = zc.recipe.egg
      ... eggs = zc.buildout
      ... scripts = buildout=bo
      ... ''' % globals())
  
      >>> print_(system(buildout));print_('X') # doctest: +ELLIPSIS
      Installing eggs.
      Getting distribution for 'badegg'.
      Got badegg 1.
      Installing bo.
      Generated script '/sample-buildout/bin/bo'.
      <BLANKLINE>
      X
  
      >>> ls('eggs') # doctest: +ELLIPSIS
      d  badegg-1-py2.4.egg
      ...
  
      >>> ls('bin')
      -  bo
      -  buildout
      """
  
  def version_requirements_in_build_honored():
      '''
  
      >>> update_extdemo()
      >>> dest = tmpdir('sample-install')
      >>> mkdir('include')
      >>> write('include', 'extdemo.h',
      ... """
      ... #define EXTDEMO 42
      ... """)
  
      >>> zc.buildout.easy_install.build(
      ...   'extdemo ==1.4', dest,
      ...   {'include-dirs': os.path.join(sample_buildout, 'include')},
      ...   links=[link_server], index=link_server+'index/',
      ...   newest=False)
      ['/sample-install/extdemo-1.4-py2.4-linux-i686.egg']
  
      '''
  
  def bug_105081_Specific_egg_versions_are_ignored_when_newer_eggs_are_around():
      """
      Buildout might ignore a specific egg requirement for a recipe:
  
      - Have a newer version of an egg in your eggs directory
      - Use 'recipe==olderversion' in your buildout.cfg to request an
        older version
  
      Buildout will go and fetch the older version, but it will *use*
      the newer version when installing a part with this recipe.
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts = x
      ... find-links = %(sample_eggs)s
      ...
      ... [x]
      ... recipe = zc.recipe.egg
      ... eggs = demo
      ... ''' % globals())
  
      >>> print_(system(buildout), end='')
      Installing x.
      Getting distribution for 'demo'.
      Got demo 0.3.
      Getting distribution for 'demoneeded'.
      Got demoneeded 1.1.
      Generated script '/sample-buildout/bin/demo'.
  
      >>> print_(system(join('bin', 'demo')), end='')
      3 1
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts = x
      ... find-links = %(sample_eggs)s
      ...
      ... [x]
      ... recipe = zc.recipe.egg
      ... eggs = demo ==0.1
      ... ''' % globals())
  
      >>> print_(system(buildout), end='')
      Uninstalling x.
      Installing x.
      Getting distribution for 'demo==0.1'.
      Got demo 0.1.
      Generated script '/sample-buildout/bin/demo'.
  
      >>> print_(system(join('bin', 'demo')), end='')
      1 1
      """
  
  if sys.version_info > (2, 4):
      def test_exit_codes():
          """
          >>> import subprocess
          >>> def call(s):
          ...     p = subprocess.Popen(s, stdin=subprocess.PIPE,
          ...                 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
          ...     p.stdin.close()
          ...     print_(p.stdout.read().decode())
          ...     print_('Exit:', bool(p.wait()))
          ...     p.stdout.close()
  
          >>> call(buildout)
          <BLANKLINE>
          Exit: False
  
          >>> write('buildout.cfg',
          ... '''
          ... [buildout]
          ... parts = x
          ... ''')
  
          >>> call(buildout) # doctest: +NORMALIZE_WHITESPACE
          While:
            Installing.
            Getting section x.
          Error: The referenced section, 'x', was not defined.
          <BLANKLINE>
          Exit: True
  
          >>> write('setup.py',
          ... '''
          ... from setuptools import setup
          ... setup(name='zc.buildout.testexit', entry_points={
          ...    'zc.buildout': ['default = testexitrecipe:x']})
          ... ''')
  
          >>> write('testexitrecipe.py',
          ... '''
          ... x y
          ... ''')
  
          >>> write('buildout.cfg',
          ... '''
          ... [buildout]
          ... parts = x
          ... develop = .
          ...
          ... [x]
          ... recipe = zc.buildout.testexit
          ... ''')
  
          >>> call(buildout) # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
          Develop: '/sample-buildout/.'
          While:
            Installing.
            Getting section x.
            Initializing section x.
            Loading zc.buildout recipe entry zc.buildout.testexit:default.
          <BLANKLINE>
          An internal error occurred due to a bug in either zc.buildout or in a
          recipe being used:
          Traceback (most recent call last):
          ...
               x y
                 ^
           SyntaxError: invalid syntax
          <BLANKLINE>
          Exit: True
          """
  
  def bug_59270_recipes_always_start_in_buildout_dir():
      r"""
      Recipes can rely on running from buildout directory
  
      >>> mkdir('bad_start')
      >>> write('bad_recipe.py',
      ... r'''
      ... import os, sys
      ... def print_(*args):
      ...     sys.stdout.write(' '.join(map(str, args)) + '\n')
      ... class Bad:
      ...     def __init__(self, *_):
      ...         print_(os.getcwd())
      ...     def install(self):
      ...         sys.stdout.write(os.getcwd()+'\n')
      ...         os.chdir('bad_start')
      ...         sys.stdout.write(os.getcwd()+'\n')
      ...         return ()
      ... ''')
  
      >>> write('setup.py',
      ... '''
      ... from setuptools import setup
      ... setup(name='bad.test',
      ...       entry_points={'zc.buildout': ['default=bad_recipe:Bad']},)
      ... ''')
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... develop = .
      ... parts = b1 b2
      ... [b1]
      ... recipe = bad.test
      ... [b2]
      ... recipe = bad.test
      ... ''')
  
      >>> os.chdir('bad_start')
      >>> print_(system(join(sample_buildout, 'bin', 'buildout')
      ...              +' -c '+join(sample_buildout, 'buildout.cfg')), end='')
      Develop: '/sample-buildout/.'
      /sample-buildout
      /sample-buildout
      Installing b1.
      /sample-buildout
      /sample-buildout/bad_start
      Installing b2.
      /sample-buildout
      /sample-buildout/bad_start
      """
  
  def bug_61890_file_urls_dont_seem_to_work_in_find_dash_links():
      """
  
      This bug arises from the fact that setuptools is overly restrictive
      about file urls, requiring that file urls pointing at directories
      must end in a slash.
  
      >>> dest = tmpdir('sample-install')
      >>> import zc.buildout.easy_install
      >>> sample_eggs = sample_eggs.replace(os.path.sep, '/')
      >>> ws = zc.buildout.easy_install.install(
      ...     ['demo==0.2'], dest,
      ...     links=['file://'+sample_eggs], index=link_server+'index/')
  
  
      >>> for dist in ws:
      ...     print_(dist)
      demoneeded 1.1
      demo 0.2
  
      >>> ls(dest)
      d  demo-0.2-py2.4.egg
      d  demoneeded-1.1-py2.4.egg
  
      """
  
  def bug_75607_buildout_should_not_run_if_it_creates_an_empty_buildout_cfg():
      """
      >>> remove('buildout.cfg')
      >>> print_(system(buildout), end='')
      While:
        Initializing.
      Error: Couldn't open /sample-buildout/buildout.cfg
  
  
  
      """
  
  def dealing_with_extremely_insane_dependencies():
      r"""
  
      There was a problem with analysis of dependencies taking a long
      time, in part because the analysis would get repeated every time a
      package was encountered in a dependency list.  Now, we don't do
      the analysis any more:
  
      >>> import os
      >>> for i in range(5):
      ...     p = 'pack%s' % i
      ...     deps = [('pack%s' % j) for j in range(5) if j is not i]
      ...     if i == 4:
      ...         deps.append('pack5')
      ...     mkdir(p)
      ...     write(p, 'setup.py',
      ...           'from setuptools import setup\n'
      ...           'setup(name=%r, install_requires=%r,\n'
      ...           '      url="u", author="a", author_email="e")\n'
      ...           % (p, deps))
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... develop = pack0 pack1 pack2 pack3 pack4
      ... parts = pack1
      ...
      ... [pack1]
      ... recipe = zc.recipe.egg:eggs
      ... eggs = pack0
      ... ''')
  
      >>> print_(system(buildout), end='') # doctest: +ELLIPSIS
      Develop: '/sample-buildout/pack0'
      Develop: '/sample-buildout/pack1'
      Develop: '/sample-buildout/pack2'
      Develop: '/sample-buildout/pack3'
      Develop: '/sample-buildout/pack4'
      Installing pack1.
      ...
      While:
        Installing pack1.
        Getting distribution for 'pack5'.
      Error: Couldn't find a distribution for 'pack5'.
  
      However, if we run in verbose mode, we can see why packages were included:
  
      >>> print_(system(buildout+' -v'), end='') # doctest: +ELLIPSIS
      Installing 'zc.buildout', 'setuptools', 'pip', 'wheel'.
      ...
      Develop: '/sample-buildout/pack0'
      Develop: '/sample-buildout/pack1'
      Develop: '/sample-buildout/pack2'
      Develop: '/sample-buildout/pack3'
      Develop: '/sample-buildout/pack4'
      ...
      Installing pack1.
      Installing 'pack0'.
      We have a develop egg: pack0 0.0.0
      Getting required 'pack4'
        required by pack0 0.0.0.
      We have a develop egg: pack4 0.0.0
      Getting required 'pack3'
        required by pack0 0.0.0.
        required by pack4 0.0.0.
      We have a develop egg: pack3 0.0.0
      Getting required 'pack2'
        required by pack0 0.0.0.
        required by pack3 0.0.0.
        required by pack4 0.0.0.
      We have a develop egg: pack2 0.0.0
      Getting required 'pack1'
        required by pack0 0.0.0.
        required by pack2 0.0.0.
        required by pack3 0.0.0.
        required by pack4 0.0.0.
      We have a develop egg: pack1 0.0.0
      Getting required 'pack5'
        required by pack4 0.0.0.
      We have no distributions for pack5 that satisfies 'pack5'.
      ...
      While:
        Installing pack1.
        Getting distribution for 'pack5'.
      Error: Couldn't find a distribution for 'pack5'.
      """
  
  def read_find_links_to_load_extensions():
      r"""
  We'll create a wacky buildout extension that just announces itself when used:
  
      >>> src = tmpdir('src')
      >>> write(src, 'wacky_handler.py',
      ... '''
      ... import sys
      ... def install(buildout=None):
      ...     sys.stdout.write("I am a wacky extension\\n")
      ... ''')
      >>> write(src, 'setup.py',
      ... '''
      ... from setuptools import setup
      ... setup(name='wackyextension', version='1',
      ...       py_modules=['wacky_handler'],
      ...       entry_points = {'zc.buildout.extension':
      ...             ['default = wacky_handler:install']
      ...             },
      ...       )
      ... ''')
      >>> print_(system(buildout+' setup '+src+' bdist_egg'), end='')
      ... # doctest: +ELLIPSIS
      Running setup ...
      creating 'dist/wackyextension-1-...
  
  Now we'll create a buildout that uses this extension to load other packages:
  
      >>> wacky_server = link_server.replace('http', 'wacky')
      >>> dist = 'file://' + join(src, 'dist').replace(os.path.sep, '/')
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts =
      ... extensions = wackyextension
      ... find-links = %(dist)s
      ... ''' % globals())
  
  When we run the buildout. it will load the extension from the dist
  directory and then use the wacky extension to load the demo package
  
      >>> print_(system(buildout), end='')
      Getting distribution for 'wackyextension'.
      Got wackyextension 1.
      I am a wacky extension
  
      """
  
  def distributions_from_local_find_links_make_it_to_download_cache():
      """
  
  If we specify a local directory in find links, distros found there
  need to make it to the download cache.
  
      >>> mkdir('test')
      >>> write('test', 'setup.py',
      ... '''
      ... from setuptools import setup
      ... setup(name='foo')
      ... ''')
  
      >>> print_(system(buildout+' setup test bdist_egg')) # doctest: +ELLIPSIS
      Running setup script 'test/setup.py'.
      ...
  
  
      >>> mkdir('cache')
      >>> old_cache = zc.buildout.easy_install.download_cache('cache')
      >>> list(zc.buildout.easy_install.install(['foo'], 'eggs',
      ...          links=[join('test', 'dist')])) # doctest: +ELLIPSIS
      [foo 0.0.0 ...
  
      >>> ls('cache')
      -  foo-0.0.0-py2.4.egg
  
      >>> _ = zc.buildout.easy_install.download_cache(old_cache)
  
      """
  
  def create_egg(name, version, dest, install_requires=None,
                 dependency_links=None):
      d = tempfile.mkdtemp()
      if dest=='available':
          extras = dict(x=['x'])
      else:
          extras = {}
      if dependency_links:
          links = 'dependency_links = %s, ' % dependency_links
      else:
          links = ''
      if install_requires:
          requires = 'install_requires = %s, ' % install_requires
      else:
          requires = ''
      try:
          with open(os.path.join(d, 'setup.py'), 'w') as f:
              f.write(
                  'from setuptools import setup\n'
                  'setup(name=%r, version=%r, extras_require=%r, zip_safe=True,\n'
                  '      %s %s py_modules=["setup"]\n)'
                  % (name, str(version), extras, requires, links)
              )
          zc.buildout.testing.bdist_egg(d, sys.executable, os.path.abspath(dest))
      finally:
          shutil.rmtree(d)
  
  def prefer_final_permutation(existing, available):
      for d in ('existing', 'available'):
          if os.path.exists(d):
              shutil.rmtree(d)
          os.mkdir(d)
      for version in existing:
          create_egg('spam', version, 'existing')
      for version in available:
          create_egg('spam', version, 'available')
  
      zc.buildout.easy_install.clear_index_cache()
      [dist] = list(
          zc.buildout.easy_install.install(['spam'], 'existing', ['available'])
          )
  
      if dist.extras:
          print_('downloaded', dist.version)
      else:
          print_('had', dist.version)
      sys.path_importer_cache.clear()
  
  def prefer_final():
      """
  This test tests several permutations:
  
  Using different version numbers to work around zip importer cache problems. :(
  
  - With prefer final:
  
      - no existing and newer dev available
      >>> prefer_final_permutation((), [1, '2a1'])
      downloaded 1
  
      - no existing and only dev available
      >>> prefer_final_permutation((), ['3a1'])
      downloaded 3a1
  
      - final existing and only dev acailable
      >>> prefer_final_permutation([4], ['5a1'])
      had 4
  
      - final existing and newer final available
      >>> prefer_final_permutation([6], [7])
      downloaded 7
  
      - final existing and same final available
      >>> prefer_final_permutation([8], [8])
      had 8
  
      - final existing and older final available
      >>> prefer_final_permutation([10], [9])
      had 10
  
      - only dev existing and final available
      >>> prefer_final_permutation(['12a1'], [11])
      downloaded 11
  
      - only dev existing and no final available newer dev available
      >>> prefer_final_permutation(['13a1'], ['13a2'])
      downloaded 13a2
  
      - only dev existing and no final available older dev available
      >>> prefer_final_permutation(['15a1'], ['14a1'])
      had 15a1
  
      - only dev existing and no final available same dev available
      >>> prefer_final_permutation(['16a1'], ['16a1'])
      had 16a1
  
  - Without prefer final:
  
      >>> _ = zc.buildout.easy_install.prefer_final(False)
  
      - no existing and newer dev available
      >>> prefer_final_permutation((), [18, '19a1'])
      downloaded 19a1
  
      - no existing and only dev available
      >>> prefer_final_permutation((), ['20a1'])
      downloaded 20a1
  
      - final existing and only dev acailable
      >>> prefer_final_permutation([21], ['22a1'])
      downloaded 22a1
  
      - final existing and newer final available
      >>> prefer_final_permutation([23], [24])
      downloaded 24
  
      - final existing and same final available
      >>> prefer_final_permutation([25], [25])
      had 25
  
      - final existing and older final available
      >>> prefer_final_permutation([27], [26])
      had 27
  
      - only dev existing and final available
      >>> prefer_final_permutation(['29a1'], [28])
      had 29a1
  
      - only dev existing and no final available newer dev available
      >>> prefer_final_permutation(['30a1'], ['30a2'])
      downloaded 30a2
  
      - only dev existing and no final available older dev available
      >>> prefer_final_permutation(['32a1'], ['31a1'])
      had 32a1
  
      - only dev existing and no final available same dev available
      >>> prefer_final_permutation(['33a1'], ['33a1'])
      had 33a1
  
      >>> _ = zc.buildout.easy_install.prefer_final(True)
  
      """
  
  def buildout_prefer_final_option():
      """
  The prefer-final buildout option can be used for override the default
  preference for newer distributions.
  
  The default is prefer-final = true:
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts = eggs
      ... find-links = %(link_server)s
      ...
      ... [eggs]
      ... recipe = zc.recipe.egg:eggs
      ... eggs = demo
      ... ''' % globals())
  
      >>> print_(system(buildout+' -v'), end='') # doctest: +ELLIPSIS
      Installing 'zc.buildout', 'setuptools', 'pip', 'wheel'.
      ...
      Picked: demo = 0.3
      ...
      Picked: demoneeded = 1.1
  
  Here we see that the final versions of demo and demoneeded are used.
  We get the same behavior if we add prefer-final = true
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts = eggs
      ... find-links = %(link_server)s
      ... prefer-final = true
      ...
      ... [eggs]
      ... recipe = zc.recipe.egg:eggs
      ... eggs = demo
      ... ''' % globals())
  
      >>> print_(system(buildout+' -v'), end='') # doctest: +ELLIPSIS
      Installing 'zc.buildout', 'setuptools', 'pip', 'wheel'.
      ...
      Picked: demo = 0.3
      ...
      Picked: demoneeded = 1.1
  
  If we specify prefer-final = false, we'll get the newest
  distributions:
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts = eggs
      ... find-links = %(link_server)s
      ... prefer-final = false
      ...
      ... [eggs]
      ... recipe = zc.recipe.egg:eggs
      ... eggs = demo
      ... ''' % globals())
  
      >>> print_(system(buildout+' -v'), end='') # doctest: +ELLIPSIS
      Installing 'zc.buildout', 'setuptools', 'pip', 'wheel'.
      ...
      Picked: demo = 0.4rc1
      ...
      Picked: demoneeded = 1.2rc1
  
  We get an error if we specify anything but true or false:
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts = eggs
      ... find-links = %(link_server)s
      ... prefer-final = no
      ...
      ... [eggs]
      ... recipe = zc.recipe.egg:eggs
      ... eggs = demo
      ... ''' % globals())
  
      >>> print_(system(buildout+' -v'), end='') # doctest: +ELLIPSIS
      While:
        Initializing.
      Error: Invalid value for 'prefer-final' option: 'no'
      """
  
  def wont_downgrade_due_to_prefer_final():
      r"""
      If we install a non-final buildout version, we don't want to
      downgrade just bcause we prefer-final.  If a buildout version
      isn't specified using a versions entry, then buildout's version
      requirement gets set to >=CURRENT_VERSION.
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts =
      ... ''')
  
      >>> [v] = [l.split('= >=', 1)[1].strip()
      ...        for l in system(buildout+' -vv').split('\n')
      ...        if l.startswith('zc.buildout = >=')]
      >>> v == pkg_resources.working_set.find(
      ...         pkg_resources.Requirement.parse('zc.buildout')
      ...         ).version
      True
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts =
      ... [versions]
      ... zc.buildout = >.1
      ... ''')
      >>> [str(l.split('= >', 1)[1].strip())
      ...        for l in system(buildout+' -vv').split('\n')
      ...        if l.startswith('zc.buildout =')]
      ['.1']
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts =
      ... versions = versions
      ... [versions]
      ... zc.buildout = 43
      ... ''')
      >>> print_(system(buildout), end='') # doctest: +ELLIPSIS
      Getting distribution for 'zc.buildout==43'.
      ...
  
      """
  
  def develop_with_modules():
      """
  Distribution setup scripts can import modules in the distribution directory:
  
      >>> mkdir('foo')
      >>> write('foo', 'bar.py',
      ... '''# empty
      ... ''')
  
      >>> write('foo', 'setup.py',
      ... '''
      ... import bar
      ... from setuptools import setup
      ... setup(name="foo")
      ... ''')
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... develop = foo
      ... parts =
      ... ''')
  
      >>> print_(system(join('bin', 'buildout')), end='')
      Develop: '/sample-buildout/foo'
  
      >>> ls('develop-eggs')
      -  foo.egg-link
      -  zc.recipe.egg.egg-link
  
      """
  
  def dont_pick_setuptools_if_version_is_specified_when_required_by_src_dist():
      r"""
  When installing a source distribution, we got setuptools without
  honoring our version specification.
  
      >>> mkdir('dist')
      >>> write('setup.py',
      ... '''
      ... from setuptools import setup
      ... setup(name='foo', version='1', py_modules=['foo'], zip_safe=True)
      ... ''')
      >>> write('foo.py', '')
      >>> _ = system(buildout+' setup . sdist')
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts = foo
      ... find-links = dist
      ... versions = versions
      ... allow-picked-versions = false
      ...
      ... [versions]
      ... wtf = %s
      ... foo = 1
      ...
      ... [foo]
      ... recipe = zc.recipe.egg
      ... eggs = foo
      ... ''' % ('\n'.join(
      ...     '%s = %s' % (d.key, d.version)
      ...     for d in zc.buildout.easy_install.buildout_and_setuptools_dists)))
  
      >>> print_(system(buildout), end='')
      Installing foo.
      Getting distribution for 'foo==1'.
      Got foo 1.
  
      """
  
  def pyc_and_pyo_files_have_correct_paths():
      r"""
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts = eggs
      ... find-links = %(link_server)s
      ...
      ... [eggs]
      ... recipe = zc.recipe.egg
      ... eggs = demo
      ... interpreter = py
      ... ''' % globals())
  
      >>> _ = system(buildout)
  
      >>> write('t.py',
      ... r'''
      ... import eggrecipedemo, eggrecipedemoneeded, sys
      ... if sys.version_info > (3,):
      ...     code = lambda f: f.__code__
      ... else:
      ...     code = lambda f: f.func_code
      ... sys.stdout.write(code(eggrecipedemo.main).co_filename+'\n')
      ... sys.stdout.write(code(eggrecipedemoneeded.f).co_filename+'\n')
      ... ''')
  
      >>> print_(system(join('bin', 'py')+ ' t.py'), end='')
      /sample-buildout/eggs/demo-0.3-py2.4.egg/eggrecipedemo.py
      /sample-buildout/eggs/demoneeded-1.1-py2.4.egg/eggrecipedemoneeded.py
      """
  
  def dont_mess_with_standard_dirs_with_variable_refs():
      """
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... eggs-directory = ${buildout:directory}/develop-eggs
      ... parts =
      ... ''' % globals())
      >>> print_(system(buildout), end='')
  
      """
  
  def expand_shell_patterns_in_develop_paths():
      """
      Sometimes we want to include a number of eggs in some directory as
      develop eggs, without explicitly listing all of them in our
      buildout.cfg
  
      >>> make_dist_that_requires(sample_buildout, 'sampley')
      >>> make_dist_that_requires(sample_buildout, 'samplez')
  
      Now, let's create a buildout that has a shell pattern that matches
      both:
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts = eggs
      ... develop = sample*
      ... find-links = %(link_server)s
      ...
      ... [eggs]
      ... recipe = zc.recipe.egg
      ... eggs = sampley
      ...        samplez
      ... ''' % globals())
  
      We can see that both eggs were found:
  
      >>> print_(system(buildout), end='')
      Develop: '/sample-buildout/sampley'
      Develop: '/sample-buildout/samplez'
      Installing eggs.
  
      """
  
  def warn_users_when_expanding_shell_patterns_yields_no_results():
      """
      Sometimes shell patterns do not match anything, so we want to warn
      our users about it...
  
      >>> make_dist_that_requires(sample_buildout, 'samplea')
  
      So if we have 2 patterns, one that has a matching directory, and
      another one that does not
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts = eggs
      ... develop = samplea grumble*
      ... find-links = %(link_server)s
      ...
      ... [eggs]
      ... recipe = zc.recipe.egg
      ... eggs = samplea
      ... ''' % globals())
  
      We should get one of the eggs, and a warning for the pattern that
      did not match anything.
  
      >>> print_(system(buildout), end='')
      Develop: '/sample-buildout/samplea'
      Couldn't develop '/sample-buildout/grumble*' (not found)
      Installing eggs.
  
      """
  
  def make_sure_versions_dont_cancel_extras():
      """
      There was a bug that caused extras in requirements to be lost.
  
      >>> with open('setup.py', 'w') as f:
      ...    _ = f.write('''
      ... from setuptools import setup
      ... setup(name='extraversiondemo', version='1.0',
      ...       url='x', author='x', author_email='x',
      ...       extras_require=dict(foo=['demo']), py_modules=['t'])
      ... ''')
      >>> open('README', 'w').close()
      >>> open('t.py', 'w').close()
  
      >>> sdist('.', sample_eggs)
      >>> mkdir('dest')
      >>> ws = zc.buildout.easy_install.install(
      ...     ['extraversiondemo[foo]'], 'dest', links=[sample_eggs],
      ...     versions = dict(extraversiondemo='1.0')
      ... )
      >>> sorted(dist.key for dist in ws)
      ['demo', 'demoneeded', 'extraversiondemo']
      """
  
  def increment_buildout_options():
      r"""
      >>> write('b1.cfg', '''
      ... [buildout]
      ... parts = p1
      ... x = 1
      ... y = a
      ...     b
      ...
      ... [p1]
      ... recipe = zc.buildout:debug
      ... foo = ${buildout:x} ${buildout:y}
      ... ''')
  
      >>> write('buildout.cfg', '''
      ... [buildout]
      ... extends = b1.cfg
      ... parts += p2
      ... x += 2
      ... y -= a
      ...
      ... [p2]
      ... <= p1
      ... ''')
  
      >>> print_(system(buildout), end='')
      Installing p1.
        foo='1\n2 b'
        recipe='zc.buildout:debug'
      Installing p2.
        foo='1\n2 b'
        recipe='zc.buildout:debug'
      """
  
  def increment_buildout_with_multiple_extended_files_421022():
      r"""
      >>> write('foo.cfg', '''
      ... [buildout]
      ... foo-option = foo
      ... [other]
      ... foo-option = foo
      ... ''')
      >>> write('bar.cfg', '''
      ... [buildout]
      ... bar-option = bar
      ... [other]
      ... bar-option = bar
      ... ''')
      >>> write('buildout.cfg', '''
      ... [buildout]
      ... parts = p other
      ... extends = bar.cfg foo.cfg
      ... bar-option += baz
      ... foo-option += ham
      ...
      ... [other]
      ... recipe = zc.buildout:debug
      ... bar-option += baz
      ... foo-option += ham
      ...
      ... [p]
      ... recipe = zc.buildout:debug
      ... x = ${buildout:bar-option} ${buildout:foo-option}
      ... ''')
  
      >>> print_(system(buildout), end='')
      Installing p.
        recipe='zc.buildout:debug'
        x='bar\nbaz foo\nham'
      Installing other.
        bar-option='bar\nbaz'
        foo-option='foo\nham'
        recipe='zc.buildout:debug'
      """
  
  def increment_on_command_line():
      r"""
      >>> write('buildout.cfg', '''
      ... [buildout]
      ... parts = p1
      ... x = 1
      ... y = a
      ...     b
      ...
      ... [p1]
      ... recipe = zc.buildout:debug
      ... foo = ${buildout:x} ${buildout:y}
      ...
      ... [p2]
      ... <= p1
      ... ''')
  
      >>> print_(system(buildout+' buildout:parts+=p2 p1:foo+=bar'), end='')
      Installing p1.
        foo='1 a\nb\nbar'
        recipe='zc.buildout:debug'
      Installing p2.
        foo='1 a\nb\nbar'
        recipe='zc.buildout:debug'
      """
  
  def test_constrained_requirement():
      """
      zc.buildout.easy_install._constrained_requirement(constraint, requirement)
  
      Transforms an environment by applying a constraint.
  
      Here's a table of examples:
  
      >>> from zc.buildout.easy_install import IncompatibleConstraintError
      >>> examples = [
      ... # original, constraint, transformed
      ... ('x',        '1',        'x==1'),
      ... ('x>1',      '2',        'x==2'),
      ... ('x>3',      '2',        IncompatibleConstraintError),
      ... ('x>1',      '>2',       'x>1,>2'),
      ... ]
      >>> from zc.buildout.easy_install import _constrained_requirement
      >>> for o, c, e in examples:
      ...     try:
      ...         o = pkg_resources.Requirement.parse(o)
      ...         if isinstance(e, str):
      ...             e = pkg_resources.Requirement.parse(e)
      ...         g = _constrained_requirement(c, o)
      ...     except IncompatibleConstraintError:
      ...         g = IncompatibleConstraintError
      ...     if str(g) != str(e):
      ...         print_('failed', o, c, g, '!=', e)
      """
  
  def test_distutils_scripts_using_import_are_properly_parsed():
      """
      zc.buildout.easy_install._distutils_script(path, dest, script_content, initialization, rsetup):
  
      Creates a script for a distutils based project. In this example for a
      hypothetical code quality checker called 'pyflint' that uses an import
      statement to import its code.
  
      >>> pyflint_script = '''#!/path/to/bin/python
      ... import pyflint.do_something
      ... pyflint.do_something()
      ... '''
      >>> import sys
      >>> original_executable = sys.executable
      >>> sys.executable = 'python'
  
      >>> from zc.buildout.easy_install import _distutils_script
      >>> generated = _distutils_script('\\'/path/test/\\'', 'bin/pyflint', pyflint_script, '', '')
      >>> if sys.platform == 'win32':
      ...     generated == ['bin/pyflint.exe', 'bin/pyflint-script.py']
      ... else:
      ...     generated == ['bin/pyflint']
      True
      >>> if sys.platform == 'win32':
      ...     cat('bin/pyflint-script.py')
      ... else:
      ...     cat('bin/pyflint')
      #!python
      <BLANKLINE>
      <BLANKLINE>
      import sys
      sys.path[0:0] = [
        '/path/test/',
        ]
      <BLANKLINE>
      <BLANKLINE>
      import pyflint.do_something
      pyflint.do_something()
  
      >>> sys.executable = original_executable
      """
  
  def test_distutils_scripts_using_from_are_properly_parsed():
      """
      zc.buildout.easy_install._distutils_script(path, dest, script_content, initialization, rsetup):
  
      Creates a script for a distutils based project. In this example for a
      hypothetical code quality checker called 'pyflint' that uses a from
      statement to import its code.
  
      >>> pyflint_script = '''#!/path/to/bin/python
      ... from pyflint import do_something
      ... do_something()
      ... '''
      >>> import sys
      >>> original_executable = sys.executable
      >>> sys.executable = 'python'
  
      >>> from zc.buildout.easy_install import _distutils_script
      >>> generated = _distutils_script('\\'/path/test/\\'', 'bin/pyflint', pyflint_script, '', '')
      >>> if sys.platform == 'win32':
      ...     generated == ['bin/pyflint.exe', 'bin/pyflint-script.py']
      ... else:
      ...     generated == ['bin/pyflint']
      True
      >>> if sys.platform == 'win32':
      ...     cat('bin/pyflint-script.py')
      ... else:
      ...     cat('bin/pyflint')
      #!python
      <BLANKLINE>
      <BLANKLINE>
      import sys
      sys.path[0:0] = [
        '/path/test/',
        ]
      <BLANKLINE>
      <BLANKLINE>
      from pyflint import do_something
      do_something()
  
      >>> sys.executable = original_executable
      """
  
  
  def want_new_zcrecipeegg():
      """
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts = egg
      ... [egg]
      ... recipe = zc.recipe.egg <2dev
      ... eggs = demo
      ... ''')
      >>> print_(system(join('bin', 'buildout')), end='') # doctest: +ELLIPSIS
      Getting distribution for 'zc.recipe.egg<2dev,>=2.0.6'...
      While:
        Installing.
        Getting section egg.
        Initializing section egg.
        Installing recipe zc.recipe.egg <2dev.
        Getting distribution for 'zc.recipe.egg<2dev,>=2.0.6'.
      Error: Couldn't find a distribution for 'zc.recipe.egg<2dev,>=2.0.6'.
      """
  
  def macro_inheritance_bug():
      """
  
  There was a bug preventing a section from using another section as a macro
  if that section was extended with macros, and both sections were listed as
  parts (phew!).  The following contrived example demonstrates that this
  now works.
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts = foo bar
      ... [base]
      ... recipe = zc.recipe.egg
      ... [foo]
      ... <=base
      ... eggs = zc.buildout
      ... interpreter = python
      ... [bar]
      ... <=foo
      ... interpreter = py
      ... ''')
      >>> print_(system(join('bin', 'buildout')), end='') # doctest: +ELLIPSIS
      Installing foo.
      ...
      Installing bar.
      ...
      >>> ls("./bin")
      -  buildout
      -  py
      -  python
      """
  
  def bootstrap_honors_relative_paths():
      """
      >>> working = tmpdir('working')
      >>> cd(working)
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts =
      ... relative-paths = true
      ... ''')
      >>> _ = system(buildout+' bootstrap')
      >>> cat('bin', 'buildout') # doctest: +ELLIPSIS
      #!/usr/local/bin/python2.7
      <BLANKLINE>
      import os
      <BLANKLINE>
      join = os.path.join
      base = os.path.dirname(os.path.abspath(os.path.realpath(__file__)))
      base = os.path.dirname(base)
      <BLANKLINE>
      import sys
      sys.path[0:0] = [
        ...
        ]
      <BLANKLINE>
      import zc.buildout.buildout
      <BLANKLINE>
      if __name__ == '__main__':
          sys.exit(zc.buildout.buildout.main())
      """
  
  def cant_use_install_from_cache_and_offline_together():
      r"""
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts =
      ... offline = true
      ... install-from-cache = true
      ... ''')
      >>> print_(system(join('bin', 'buildout')), end='') # doctest: +ELLIPSIS
      While:
        Initializing.
      Error: install-from-cache can't be used with offline mode.
      Nothing is installed, even from cache, in offline
      mode, which might better be called 'no-install mode'.
      <BLANKLINE>
      """
  
  def error_installing_in_offline_mode_if_dont_have_needed_dist():
      r"""
      >>> import zc.buildout.easy_install
      >>> ws = zc.buildout.easy_install.install(
      ...     ['demo==0.2'], None,
      ...     links=[link_server], index=link_server+'index/')
      Traceback (most recent call last):
      ...
      UserError: We don't have a distribution for demo==0.2
      and can't install one in offline (no-install) mode.
      <BLANKLINE>
      """
  
  def error_building_in_offline_mode_if_dont_have_needed_dist():
      r"""
      >>> zc.buildout.easy_install.build(
      ...   'extdemo', None,
      ...   {}, links=[link_server], index=link_server+'index/')
      Traceback (most recent call last):
      ...
      UserError: We don't have a distribution for extdemo
      and can't build one in offline (no-install) mode.
      <BLANKLINE>
      """
  
  def test_buildout_section_shorthand_for_command_line_assignments():
      r"""
      >>> write('buildout.cfg', '')
      >>> print_(system(buildout+' parts='), end='') # doctest: +ELLIPSIS
      """
  
  def buildout_honors_umask():
      """
  
      For setting the executable permission, the user's umask is honored:
  
      >>> orig_umask = os.umask(0o077)  # Only user gets permissions.
      >>> zc.buildout.easy_install._execute_permission() == 0o700
      True
      >>> tmp = os.umask(0o022)  # User can write, the rest not.
      >>> zc.buildout.easy_install._execute_permission() == 0o755
      True
      >>> tmp = os.umask(orig_umask)  # Reset umask to the original value.
      """
  
  def parse_with_section_expr():
      r"""
      >>> class Recipe:
      ...     def __init__(self, buildout, *_):
      ...         buildout.parse('''
      ...             [foo : sys.version_info[0] > 0]
      ...             x = 1
      ...             ''')
  
      >>> buildout = zc.buildout.testing.Buildout()
      >>> buildout.parse('''
      ...     [foo : sys.version_info[0] > 0]
      ...     x = 1
      ...     ''')
      >>> buildout.print_options()
      [foo]
      x = 1
  
      """
  
  def test_abi_tag_eggs():
      r"""
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... find-links = %(sample_eggs)s
      ... parts = abi
      ... abi-tag-eggs = true
      ... [abi]
      ... recipe = zc.recipe.egg
      ... eggs = demo
      ... ''' % globals())
      >>> _ = system(join('bin', 'buildout'))
      >>> from zc.buildout.pep425tags import get_abi_tag
      >>> abi_tag = get_abi_tag()
      >>> abi_tag in os.listdir(join(sample_buildout, 'eggs'))
      True
      >>> ls('eggs', abi_tag)
      d  demo-0.3-py3.7.egg
      d  demoneeded-1.1-py3.7.egg
      """
  
  def test_buildout_doesnt_keep_adding_itself_to_versions():
      r"""
      We were constantly writing to versions.cfg for buildout and setuptools
  
      >>> write('buildout.cfg',
      ... '''
      ... [buildout]
      ... parts =
      ... extends = versions.cfg
      ... show-picked-versions = true
      ... update-versions-file = versions.cfg
      ... extends = versions.cfg
      ... ''')
      >>> write('versions.cfg',
      ... '''[versions]
      ... ''')
      >>> _ = system(join('bin', 'buildout'))
      >>> with open('versions.cfg') as f:
      ...     versions = f.read()
      >>> _ = system(join('bin', 'buildout'))
  
      On the first run, some pins were added:
  
      >>> cat('versions.cfg') # doctest: +ELLIPSIS
      [versions]
      >>> _ = system(join('bin', 'buildout'))
      >>> _ = system(join('bin', 'buildout'))
  
      Subsequent runs didn't add additional text:
  
      >>> with open('versions.cfg') as f:
      ...     versions == f.read()
      True
      """
  
  if sys.platform == 'win32':
      del buildout_honors_umask # umask on dohs is academic
  
  ######################################################################
  
  def create_sample_eggs(test, executable=sys.executable):
      assert executable == sys.executable, (executable, sys.executable)
      write = test.globs['write']
      dest = test.globs['sample_eggs']
      tmp = tempfile.mkdtemp()
      try:
          write(tmp, 'README.txt', '')
  
          for i in (0, 1, 2):
              write(tmp, 'eggrecipedemoneeded.py', 'y=%s\ndef f():\n  pass' % i)
              rc1 = i==2 and 'rc1' or ''
              write(
                  tmp, 'setup.py',
                  "from setuptools import setup\n"
                  "setup(name='demoneeded', py_modules=['eggrecipedemoneeded'],"
                  " zip_safe=True, version='1.%s%s', author='bob', url='bob', "
                  "author_email='bob')\n"
                  % (i, rc1)
                  )
              zc.buildout.testing.sdist(tmp, dest)
  
          write(
              tmp, 'distutilsscript',
              '#!/usr/bin/python\n'
              '# -*- coding: utf-8 -*-\n'
              '"""Module docstring."""\n'
              'from __future__ import print_statement\n'
              'import os\n'
              'import sys; sys.stdout.write("distutils!\\n")\n'
              )
          write(
              tmp, 'setup.py',
              "from setuptools import setup\n"
              "setup(name='other', zip_safe=False, version='1.0', "
              "scripts=['distutilsscript'],"
              "py_modules=['eggrecipedemoneeded'])\n"
              )
          zc.buildout.testing.bdist_egg(tmp, sys.executable, dest)
  
          write(
              tmp, 'setup.py',
              "from setuptools import setup\n"
              "setup(name='du_zipped', zip_safe=True, version='1.0', "
              "scripts=['distutilsscript'],"
              "py_modules=['eggrecipedemoneeded'])\n"
              )
          zc.buildout.testing.bdist_egg(tmp, executable, dest)
  
          os.remove(os.path.join(tmp, 'distutilsscript'))
          os.remove(os.path.join(tmp, 'eggrecipedemoneeded.py'))
  
          for i in (1, 2, 3, 4):
              write(
                  tmp, 'eggrecipedemo.py',
                  'import eggrecipedemoneeded, sys\n'
                  'def print_(*a):\n'
                  '    sys.stdout.write(" ".join(map(str, a))+"\\n")\n'
                  'x=%s\n'
                  'def main():\n'
                  '   print_(x, eggrecipedemoneeded.y)\n'
                  % i)
              rc1 = i==4 and 'rc1' or ''
              write(
                  tmp, 'setup.py',
                  "from setuptools import setup\n"
                  "setup(name='demo', py_modules=['eggrecipedemo'],"
                  " install_requires = 'demoneeded',"
                  " entry_points={'console_scripts': "
                       "['demo = eggrecipedemo:main']},"
                  " zip_safe=True, version='0.%s%s')\n" % (i, rc1)
                  )
              zc.buildout.testing.bdist_egg(tmp, dest)
  
          write(tmp, 'mixedcase.py', 'def f():\n  pass')
          write(
              tmp, 'setup.py',
              "from setuptools import setup\n"
              "setup(name='MIXEDCASE', py_modules=['mixedcase'],"
              " author='bob', url='bob', author_email='bob',"
              " install_requires = 'demoneeded',"
              " zip_safe=True, version='0.5')\n"
              )
          zc.buildout.testing.sdist(tmp, dest)
          # rename file to lower case
          # to test issues between file and package name
          curdir = os.getcwd()
          os.chdir(dest)
          for file in os.listdir(dest):
              if "MIXEDCASE" in file:
                  os.rename(file, file.lower())
          os.chdir(curdir)
  
          write(tmp, 'eggrecipebigdemo.py', 'import eggrecipedemo')
          write(
              tmp, 'setup.py',
              "from setuptools import setup\n"
              "setup(name='bigdemo', "
              " install_requires = 'demo',"
              " py_modules=['eggrecipebigdemo'], "
              " zip_safe=True, version='0.1')\n"
              )
          zc.buildout.testing.bdist_egg(tmp, sys.executable, dest)
  
      finally:
          shutil.rmtree(tmp)
  
  extdemo_c2 = """
  #include <Python.h>
  #include <extdemo.h>
  
  static PyMethodDef methods[] = {{NULL}};
  
  PyMODINIT_FUNC
  initextdemo(void)
  {
      PyObject *m;
      m = Py_InitModule3("extdemo", methods, "");
  #ifdef TWO
      PyModule_AddObject(m, "val", PyInt_FromLong(2));
  #else
      PyModule_AddObject(m, "val", PyInt_FromLong(EXTDEMO));
  #endif
  }
  """
  
  extdemo_c3 = """
  #include <Python.h>
  #include <extdemo.h>
  
  static PyMethodDef methods[] = {{NULL}};
  
  #define MOD_DEF(ob, name, doc, methods) \
  	  static struct PyModuleDef moduledef = { \
  	    PyModuleDef_HEAD_INIT, name, doc, -1, methods, }; \
  	  ob = PyModule_Create(&moduledef);
  
  #define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void)
  
  MOD_INIT(extdemo)
  {
      PyObject *m;
  
      MOD_DEF(m, "extdemo", "", methods);
  
  #ifdef TWO
      PyModule_AddObject(m, "val", PyLong_FromLong(2));
  #else
      PyModule_AddObject(m, "val", PyLong_FromLong(EXTDEMO));
  #endif
  
      return m;
  }
  """
  
  extdemo_c = sys.version_info[0] < 3 and extdemo_c2 or extdemo_c3
  
  extdemo_setup_py = r"""
  import os, sys
  from distutils.core import setup, Extension
  
  if os.environ.get('test_environment_variable'):
      print(
          "Have environment test_environment_variable: %%s"
          %% os.environ['test_environment_variable']
      )
  
  setup(name = "extdemo", version = "%s", url="http://www.zope.org",
        author="Demo", author_email="demo@demo.com",
        ext_modules = [Extension('extdemo', ['extdemo.c'])],
        )
  """
  
  def add_source_dist(test, version=1.4):
      if 'extdemo' not in test.globs:
          test.globs['extdemo'] = test.globs['tmpdir']('extdemo')
  
      tmp = test.globs['extdemo']
      write = test.globs['write']
      try:
          write(tmp, 'extdemo.c', extdemo_c);
          write(tmp, 'setup.py', extdemo_setup_py % version);
          write(tmp, 'README', "");
          write(tmp, 'MANIFEST.in', "include *.c\n");
          test.globs['sdist'](tmp, test.globs['sample_eggs'])
      except:
          shutil.rmtree(tmp)
  
  def easy_install_SetUp(test):
      zc.buildout.testing.buildoutSetUp(test)
      sample_eggs = test.globs['tmpdir']('sample_eggs')
      test.globs['sample_eggs'] = sample_eggs
      os.mkdir(os.path.join(sample_eggs, 'index'))
      create_sample_eggs(test)
      add_source_dist(test)
      test.globs['link_server'] = test.globs['start_server'](
          test.globs['sample_eggs'])
      test.globs['update_extdemo'] = lambda : add_source_dist(test, 1.5)
      zc.buildout.testing.install_develop('zc.recipe.egg', test)
  
  def buildout_txt_setup(test):
      zc.buildout.testing.buildoutSetUp(test)
      mkdir = test.globs['mkdir']
      eggs = os.environ['buildout_testing_index_url'][7:]
      test.globs['sample_eggs'] = eggs
      create_sample_eggs(test)
  
      for name in os.listdir(eggs):
          if '-' in name:
              pname = name.split('-')[0]
              if not os.path.exists(os.path.join(eggs, pname)):
                  mkdir(eggs, pname)
              shutil.move(os.path.join(eggs, name),
                          os.path.join(eggs, pname, name))
  
      dist = pkg_resources.working_set.find(
          pkg_resources.Requirement.parse('zc.recipe.egg'))
      mkdir(eggs, 'zc.recipe.egg')
      zc.buildout.testing.sdist(
          os.path.dirname(dist.location),
          os.path.join(eggs, 'zc.recipe.egg'),
          )
  
  egg_parse = re.compile(r'([0-9a-zA-Z_.]+)-([0-9a-zA-Z_.]+)-py(\d[.]\d)$'
                         ).match
  def makeNewRelease(project, ws, dest, version='99.99'):
      dist = ws.find(pkg_resources.Requirement.parse(project))
      eggname, oldver, pyver = egg_parse(dist.egg_name()).groups()
      dest = os.path.join(dest, "%s-%s-py%s.egg" % (eggname, version, pyver))
      if os.path.isfile(dist.location):
          shutil.copy(dist.location, dest)
          zip = zipfile.ZipFile(dest, 'a')
          zip.writestr(
              'EGG-INFO/PKG-INFO',
              ((zip.read('EGG-INFO/PKG-INFO').decode('ISO-8859-1')
                ).replace("Version: %s" % oldver,
                          "Version: %s" % version)
               ).encode('ISO-8859-1')
              )
          zip.close()
      elif dist.location.endswith('site-packages'):
          os.mkdir(dest)
          shutil.copytree(
              os.path.join(dist.location, project),
              os.path.join(dest, project),
          )
          distinfo = '%s-%s.dist-info' % (project, oldver)
          shutil.copytree(
              os.path.join(dist.location, distinfo),
              os.path.join(dest, distinfo),
          )
          info_path = os.path.join(dest, distinfo, 'METADATA')
          with open(info_path) as f:
              info = f.read().replace("Version: %s" % oldver,
                                      "Version: %s" % version)
          with open(info_path, 'w') as f:
              f.write(info)
          new_distinfo = '%s-%s.dist-info' % (project, version)
          os.rename(
              os.path.join(dest, distinfo),
              os.path.join(dest, new_distinfo),
          )
      else:
          shutil.copytree(dist.location, dest)
          info_path = os.path.join(dest, 'EGG-INFO', 'PKG-INFO')
          with open(info_path) as f:
              info = f.read().replace("Version: %s" % oldver,
                                      "Version: %s" % version)
          with open(info_path, 'w') as f:
              f.write(info)
  
  def getWorkingSetWithBuildoutEgg(test):
      sample_buildout = test.globs['sample_buildout']
      eggs = os.path.join(sample_buildout, 'eggs')
  
      # If the zc.buildout dist is a develop dist, convert it to a
      # regular egg in the sample buildout
      req = pkg_resources.Requirement.parse('zc.buildout')
      dist = pkg_resources.working_set.find(req)
      if dist.precedence == pkg_resources.DEVELOP_DIST:
          # We have a develop egg, create a real egg for it:
          here = os.getcwd()
          os.chdir(os.path.dirname(dist.location))
          zc.buildout.easy_install.call_subprocess(
              [sys.executable,
               os.path.join(os.path.dirname(dist.location), 'setup.py'),
               '-q', 'bdist_egg', '-d', eggs],
              env=dict(os.environ,
                       PYTHONPATH=zc.buildout.easy_install.pip_pythonpath,
                       ),
              )
          os.chdir(here)
          os.remove(os.path.join(eggs, 'zc.buildout.egg-link'))
  
          # Rebuild the buildout script
          ws = pkg_resources.WorkingSet([eggs])
          ws.require('zc.buildout')
          zc.buildout.easy_install.scripts(
              ['zc.buildout'], ws, sys.executable,
              os.path.join(sample_buildout, 'bin'))
      else:
          ws = pkg_resources.working_set
      return ws
  
  def updateSetup(test):
      zc.buildout.testing.buildoutSetUp(test)
      new_releases = test.globs['tmpdir']('new_releases')
      test.globs['new_releases'] = new_releases
      ws = getWorkingSetWithBuildoutEgg(test)
      # now let's make the new releases
      # TODO enable new releases of pip wheel setuptools
      # when eggs enforced
      makeNewRelease('zc.buildout', ws, new_releases)
      os.mkdir(os.path.join(new_releases, 'zc.buildout'))
  
  def ancestor(path, level):
      while level > 0:
          path = os.path.dirname(path)
          level -= 1
  
      return path
  
  bootstrap_py = os.path.join(ancestor(__file__, 4), 'bootstrap', 'bootstrap.py')
  
  def bootstrapSetup(test):
      buildout_txt_setup(test)
      test.globs['link_server'] = test.globs['start_server'](
          test.globs['sample_eggs'])
      sample_eggs = test.globs['sample_eggs']
      ws = getWorkingSetWithBuildoutEgg(test)
      makeNewRelease('zc.buildout', ws, sample_eggs, '2.0.0')
      makeNewRelease('zc.buildout', ws, sample_eggs, '22.0.0')
      os.environ['bootstrap-testing-find-links'] = test.globs['link_server']
      test.globs['bootstrap_py'] = bootstrap_py
  
  normalize_bang = (
      re.compile(re.escape('#!'+
                           zc.buildout.easy_install._safe_arg(sys.executable))),
      '#!/usr/local/bin/python2.7',
      )
  
  normalize_S = (
      re.compile(r'#!/usr/local/bin/python2.7 -S'),
      '#!/usr/local/bin/python2.7',
      )
  
  
  def test_suite():
  
      test_suite = [
          manuel.testing.TestSuite(
              manuel.doctest.Manuel() + manuel.capture.Manuel(),
              'configparser.test'),
          manuel.testing.TestSuite(
              manuel.doctest.Manuel(
                  optionflags=doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS,
                  checker=renormalizing.RENormalizing([
                      zc.buildout.testing.normalize_path,
                      zc.buildout.testing.normalize_endings,
                      zc.buildout.testing.normalize_script,
                      zc.buildout.testing.normalize_egg_py,
                      zc.buildout.testing.not_found,
                      zc.buildout.testing.adding_find_link,
                      zc.buildout.testing.python27_warning,
                      zc.buildout.testing.python27_warning_2,
                      # (re.compile(r"Installing 'zc.buildout >=\S+"), ''),
                      (re.compile(r'__buildout_signature__ = recipes-\S+'),
                       '__buildout_signature__ = recipes-SSSSSSSSSSS'),
                      (re.compile(r'executable = [\S ]+python\S*', re.I),
                       'executable = python'),
                      (re.compile(r'[-d]  (setuptools|setuptools)-\S+[.]egg'),
                       'setuptools.egg'),
                      (re.compile(r'pip-\S+[.]egg'), 'pip.egg'),
                      (re.compile(r'wheel-\S+[.]egg'), 'wheel.egg'),
                      (re.compile(r'zc.buildout(-\S+)?[.]egg(-link)?'),
                       'zc.buildout.egg'),
                      (re.compile(r'creating \S*setup.cfg'), 'creating setup.cfg'),
                      (re.compile(r'hello\%ssetup' % os.path.sep), 'hello/setup'),
                      (re.compile(r'Picked: (\S+) = \S+'),
                       'Picked: \\1 = V.V'),
                      (re.compile(r'We have a develop egg: zc.buildout (\S+)'),
                       'We have a develop egg: zc.buildout X.X.'),
                      (re.compile(r'\\[\\]?'), '/'),
                      (re.compile('WindowsError'), 'OSError'),
                      (re.compile(r'\[Error \d+\] Cannot create a file '
                                  r'when that file already exists: '),
                       '[Errno 17] File exists: '
                       ),
                      (re.compile('setuptools'), 'setuptools'),
                      (re.compile(r'Got zc.recipe.egg \S+'), 'Got zc.recipe.egg'),
                      (re.compile(r'zc\.(buildout|recipe\.egg)\s*= >=\S+'),
                       'zc.\\1 = >=1.99'),
                      ])
                  ) + manuel.capture.Manuel(),
              'buildout.txt',
              setUp=buildout_txt_setup,
              tearDown=zc.buildout.testing.buildoutTearDown,
              ),
          doctest.DocFileSuite(
              'runsetup.txt', 'repeatable.txt', 'setup.txt',
              setUp=zc.buildout.testing.buildoutSetUp,
              tearDown=zc.buildout.testing.buildoutTearDown,
              optionflags=doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS,
              checker=renormalizing.RENormalizing([
                 zc.buildout.testing.normalize_path,
                 zc.buildout.testing.normalize_endings,
                 zc.buildout.testing.normalize_script,
                 zc.buildout.testing.normalize_egg_py,
                 zc.buildout.testing.not_found,
                 zc.buildout.testing.adding_find_link,
                 # (re.compile(r"Installing 'zc.buildout >=\S+"), ''),
                 # (re.compile(r"Getting distribution for 'zc.buildout >=\S+"),
                 #  ''),
                 (re.compile(r'__buildout_signature__ = recipes-\S+'),
                  '__buildout_signature__ = recipes-SSSSSSSSSSS'),
                 (re.compile(r'[-d]  setuptools-\S+[.]egg'), 'setuptools.egg'),
                 (re.compile(r'zc.buildout(-\S+)?[.]egg(-link)?'),
                  'zc.buildout.egg'),
                 (re.compile(r'creating \S*setup.cfg'), 'creating setup.cfg'),
                 (re.compile(r'hello\%ssetup' % os.path.sep), 'hello/setup'),
                 (re.compile(r'Picked: (\S+) = \S+'),
                  'Picked: \\1 = V.V'),
                 (re.compile(r'We have a develop egg: zc.buildout (\S+)'),
                  'We have a develop egg: zc.buildout X.X.'),
                 (re.compile(r'\\[\\]?'), '/'),
                 (re.compile(r'WindowsError'), 'OSError'),
                 (re.compile(r'pip = \S+'), 'pip = 20.0.1'),
                 (re.compile(r'setuptools = \S+'), 'setuptools = 46.1.3'),
                 (re.compile(r'\[Error 17\] Cannot create a file '
                             r'when that file already exists: '),
                  '[Errno 17] File exists: '
                  ),
                 (re.compile('executable = %s' % re.escape(sys.executable)),
                  'executable = python'),
                 (re.compile(r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{6}'),
                  'YYYY-MM-DD hh:mm:ss.dddddd'),
                 ]),
              ),
          doctest.DocFileSuite(
              'debugging.txt',
              setUp=zc.buildout.testing.buildoutSetUp,
              tearDown=zc.buildout.testing.buildoutTearDown,
              checker=renormalizing.RENormalizing([
                  zc.buildout.testing.normalize_path,
                  zc.buildout.testing.normalize_endings,
                  zc.buildout.testing.normalize_exception_type_for_python_2_and_3,
                  zc.buildout.testing.not_found,
                  zc.buildout.testing.adding_find_link,
                  (re.compile('zc.buildout.buildout.MissingOption'),
                   'MissingOption'),
                  (re.compile(r'\S+buildout.py'), 'buildout.py'),
                  (re.compile(r'line \d+'), 'line NNN'),
                  (re.compile(r'py\(\d+\)'), 'py(NNN)'),
                  ])
              ),
  
          doctest.DocFileSuite(
              'update.txt',
              setUp=updateSetup,
              tearDown=zc.buildout.testing.buildoutTearDown,
              optionflags=doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS,
              checker=renormalizing.RENormalizing([
                  (re.compile(r'(zc.buildout|setuptools)-\d+[.]\d+\S*'
                              r'-py\d.\d.egg'),
                   '\\1.egg'),
                  zc.buildout.testing.normalize_path,
                  zc.buildout.testing.normalize_endings,
                  zc.buildout.testing.normalize_script,
                  zc.buildout.testing.normalize_egg_py,
                  zc.buildout.testing.not_found,
                  zc.buildout.testing.adding_find_link,
                  normalize_bang,
                  normalize_S,
                  # (re.compile(r"Installing 'zc.buildout >=\S+"), ''),
                  (re.compile(r"Getting distribution for 'zc.buildout>=\S+"),
                   ''),
                  (re.compile('99[.]99'), 'NINETYNINE.NINETYNINE'),
                  (re.compile(
                      r'(zc.buildout|setuptools|pip)( version)? \d+[.]\d+\S*'),
                   '\\1 V.V'),
                  (re.compile('[-d]  setuptools'), '-  setuptools'),
                  (re.compile('[-d]  pip'), '-  pip'),
                  (re.compile('[-d]  wheel'), '-  wheel'),
                  (re.compile(re.escape(os.path.sep)+'+'), '/'),
                 ])
              ),
  
          doctest.DocFileSuite(
              'easy_install.txt', 'downloadcache.txt', 'dependencylinks.txt',
              'allowhosts.txt', 'allow-unknown-extras.txt',
              setUp=easy_install_SetUp,
              tearDown=zc.buildout.testing.buildoutTearDown,
              optionflags=doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS,
              checker=renormalizing.RENormalizing([
                  zc.buildout.testing.normalize_script,
                  zc.buildout.testing.normalize_path,
                  zc.buildout.testing.normalize_endings,
                  zc.buildout.testing.normalize_egg_py,
                  zc.buildout.testing.normalize_exception_type_for_python_2_and_3,
                  zc.buildout.testing.normalize_open_in_generated_script,
                  zc.buildout.testing.adding_find_link,
                  zc.buildout.testing.not_found,
                  zc.buildout.testing.python27_warning,
                  zc.buildout.testing.python27_warning_2,
                  normalize_bang,
                  normalize_S,
                  (re.compile(r'[-d]  setuptools-\S+[.]egg'), 'setuptools.egg'),
                  (re.compile(r'\\[\\]?'), '/'),
                  (re.compile('(\n?)-  ([a-zA-Z_.-]+)\n-  \\2.exe\n'),
                   '\\1-  \\2\n'),
                 ]+(sys.version_info < (2, 5) and [
                    (re.compile('.*No module named runpy.*', re.S), ''),
                    (re.compile('.*usage: pdb.py scriptfile .*', re.S), ''),
                    (re.compile('.*Error: what does not exist.*', re.S), ''),
                    ] or [])),
  
  
              ),
  
          doctest.DocFileSuite(
              'download.txt', 'extends-cache.txt',
              setUp=easy_install_SetUp,
              tearDown=zc.buildout.testing.buildoutTearDown,
              optionflags=doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS,
              checker=renormalizing.RENormalizing([
                zc.buildout.testing.normalize_exception_type_for_python_2_and_3,
                zc.buildout.testing.not_found,
                zc.buildout.testing.adding_find_link,
                (re.compile(' at -?0x[^>]+'), '<MEM ADDRESS>'),
                (re.compile('http://localhost:[0-9]{4,5}/'),
                 'http://localhost/'),
                (re.compile('[0-9a-f]{32}'), '<MD5 CHECKSUM>'),
                zc.buildout.testing.normalize_path,
                zc.buildout.testing.ignore_not_upgrading,
                ]),
              ),
  
          doctest.DocTestSuite(
              setUp=easy_install_SetUp,
              tearDown=zc.buildout.testing.buildoutTearDown,
              checker=renormalizing.RENormalizing([
                  zc.buildout.testing.normalize_path,
                  zc.buildout.testing.normalize_endings,
                  zc.buildout.testing.normalize_script,
                  zc.buildout.testing.normalize_egg_py,
                  zc.buildout.testing.normalize___pycache__,
                  zc.buildout.testing.not_found,
                  zc.buildout.testing.normalize_exception_type_for_python_2_and_3,
                  zc.buildout.testing.adding_find_link,
                  zc.buildout.testing.python27_warning,
                  zc.buildout.testing.python27_warning_2,
                  normalize_bang,
                  (re.compile(r'^(\w+\.)*(Missing\w+: )'), '\2'),
                  (re.compile(r"buildout: Running \S*setup.py"),
                   'buildout: Running setup.py'),
                  (re.compile(r'pip-\S+-'),
                   'pip.egg'),
                  (re.compile(r'setuptools-\S+-'),
                   'setuptools.egg'),
                  (re.compile(r'zc.buildout-\S+-'),
                   'zc.buildout.egg'),
                  (re.compile(r'pip = \S+'), 'pip = 20.0.0'),
                  (re.compile(r'setuptools = \S+'), 'setuptools = 0.7.99'),
                  (re.compile(r'File "\S+one.py"'),
                   'File "one.py"'),
                  (re.compile(r'We have a develop egg: (\S+) (\S+)'),
                   r'We have a develop egg: \1 V'),
                  (re.compile(r'Picked: setuptools = \S+'),
                   'Picked: setuptools = V'),
                  (re.compile('[-d]  pip'), '-  pip'),
                  (re.compile('[-d]  setuptools'), '-  setuptools'),
                  (re.compile(r'\\[\\]?'), '/'),
                  (re.compile(
                      '-q develop -mxN -d "/sample-buildout/develop-eggs'),
                   '-q develop -mxN -d /sample-buildout/develop-eggs'
                   ),
                  (re.compile(r'^[*]...'), '...'),
                  # for
                  # bug_92891
                  # bootstrap_crashes_with_egg_recipe_in_buildout_section
                  (re.compile(r"Unused options for buildout: 'eggs' 'scripts'\."),
                   "Unused options for buildout: 'scripts' 'eggs'."),
                  # Python 3.4 changed the wording of NameErrors
                  (re.compile('NameError: global name'), 'NameError: name'),
                  # fix for test_distutils_scripts_using_import_are_properly_parsed
                  # and test_distutils_scripts_using_from_are_properly_parsed
                  # win32 apparently adds a " around sys.executable
                  (re.compile('#!"python"'), '#!python'),
                  ]),
              ),
          zc.buildout.rmtree.test_suite(),
          doctest.DocFileSuite(
              'windows.txt',
              setUp=zc.buildout.testing.buildoutSetUp,
              tearDown=zc.buildout.testing.buildoutTearDown,
              checker=renormalizing.RENormalizing([
                 zc.buildout.testing.normalize_path,
                 zc.buildout.testing.normalize_endings,
                 zc.buildout.testing.normalize_script,
                 zc.buildout.testing.normalize_egg_py,
                 zc.buildout.testing.not_found,
                 zc.buildout.testing.adding_find_link,
                 (re.compile(r'__buildout_signature__ = recipes-\S+'),
                  '__buildout_signature__ = recipes-SSSSSSSSSSS'),
                 (re.compile(r'[-d]  setuptools-\S+[.]egg'), 'setuptools.egg'),
                 (re.compile(r'zc.buildout(-\S+)?[.]egg(-link)?'),
                  'zc.buildout.egg'),
                 (re.compile(r'creating \S*setup.cfg'), 'creating setup.cfg'),
                 (re.compile(r'hello\%ssetup' % os.path.sep), 'hello/setup'),
                 (re.compile(r'Picked: (\S+) = \S+'),
                  'Picked: \\1 = V.V'),
                 (re.compile(r'We have a develop egg: zc.buildout (\S+)'),
                  'We have a develop egg: zc.buildout X.X.'),
                 (re.compile(r'\\[\\]?'), '/'),
                 (re.compile('WindowsError'), 'OSError'),
                 (re.compile(r'\[Error 17\] Cannot create a file '
                             r'when that file already exists: '),
                  '[Errno 17] File exists: '
                  ),
                 ])
              ),
          doctest.DocFileSuite('testing_bugfix.txt'),
      ]
  
      docdir = os.path.join(ancestor(__file__, 4), 'doc')
      if os.path.exists(docdir) and not sys.platform.startswith('win'):
          # Note that the purpose of the documentation tests are mainly
          # to test the documentation, not to test buildout.
  
          def docSetUp(test):
  
              def write(text, *path):
                  with open(os.path.join(*path), 'w') as f:
                      f.write(text)
  
              test.globs.update(
                  run_buildout=zc.buildout.testing.run_buildout_in_process,
                  yup=lambda cond, orelse='Nope': None if cond else orelse,
                  nope=lambda cond, orelse='Nope': orelse if cond else None,
                  eq=lambda a, b: None if a == b else (a, b),
                  eqs=zc.buildout.testing.eqs,
                  read=zc.buildout.testing.read,
                  write=write,
                  ls=lambda d='.', *rest: os.listdir(os.path.join(d, *rest)),
                  join=os.path.join,
                  clear_here=zc.buildout.testing.clear_here,
                  os=os,
                  )
              setupstack.setUpDirectory(test)
  
          test_suite.append(
              manuel.testing.TestSuite(
                  manuel.doctest.Manuel(
                      optionflags=doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
                      ) + manuel.capture.Manuel(),
                  os.path.join(docdir, 'getting-started.rst'),
                  os.path.join(docdir, 'reference.rst'),
                  os.path.join(docdir, 'topics', 'bootstrapping.rst'),
                  os.path.join(docdir, 'topics', 'implicit-parts.rst'),
                  os.path.join(
                      docdir,
                      'topics', 'variables-extending-and-substitutions.rst'),
                  os.path.join(docdir, 'topics', 'writing-recipes.rst'),
                  os.path.join(docdir, 'topics', 'optimizing.rst'),
                  os.path.join(docdir, 'topics', 'meta-recipes.rst'),
                  setUp=docSetUp, tearDown=setupstack.tearDown
                  ))
  
  
      # adding bootstrap.txt doctest to the suite
      # only if bootstrap.py is present
      if os.path.exists(bootstrap_py):
          test_suite.append(doctest.DocFileSuite(
              'bootstrap.txt', 'bootstrap_cl_settings.test',
              setUp=bootstrapSetup,
              tearDown=zc.buildout.testing.buildoutTearDown,
              checker=renormalizing.RENormalizing([
                 zc.buildout.testing.normalize_path,
                 zc.buildout.testing.normalize_endings,
                 zc.buildout.testing.normalize_script,
                 zc.buildout.testing.not_found,
                 normalize_bang,
                 zc.buildout.testing.adding_find_link,
                 (re.compile('Downloading.*setuptools.*egg\n'), ''),
                 ]),
              ))
  
      test_suite.append(unittest.defaultTestLoader.loadTestsFromName(__name__))
  
      return unittest.TestSuite(test_suite)
  
  if __name__ == '__main__':
      unittest.main()
  