source: TI12-security/trunk/NDGSecurity/python/buildout/ndgsecurity/eggs/zc.buildout-1.2.1-py2.5.egg/zc/buildout/tests.py @ 7081

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg-security/TI12-security/trunk/NDGSecurity/python/buildout/ndgsecurity/eggs/zc.buildout-1.2.1-py2.5.egg/zc/buildout/tests.py@7081
Revision 7081, 77.9 KB checked in by pjkersha, 11 years ago (diff)
  • Property svn:keywords set to Id
Line 
1##############################################################################
2#
3# Copyright (c) 2004 Zope Corporation and Contributors.
4# All Rights Reserved.
5#
6# This software is subject to the provisions of the Zope Public License,
7# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
8# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
9# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
11# FOR A PARTICULAR PURPOSE.
12#
13##############################################################################
14"""XXX short summary goes here.
15
16$Id$
17"""
18
19import os, re, shutil, sys, tempfile, unittest, zipfile
20from zope.testing import doctest, renormalizing
21import pkg_resources
22import zc.buildout.testing, zc.buildout.easy_install
23
24import zc.buildout.testselectingpython
25
26os_path_sep = os.path.sep
27if os_path_sep == '\\':
28    os_path_sep *= 2
29
30
31def develop_w_non_setuptools_setup_scripts():
32    """
33We should be able to deal with setup scripts that aren't setuptools based.
34
35    >>> mkdir('foo')
36    >>> write('foo', 'setup.py',
37    ... '''
38    ... from distutils.core import setup
39    ... setup(name="foo")
40    ... ''')
41
42    >>> write('buildout.cfg',
43    ... '''
44    ... [buildout]
45    ... develop = foo
46    ... parts =
47    ... ''')
48
49    >>> print system(join('bin', 'buildout')),
50    Develop: '/sample-buildout/foo'
51
52    >>> ls('develop-eggs')
53    -  foo.egg-link
54    -  zc.recipe.egg.egg-link
55
56    """
57
58def develop_verbose():
59    """
60We should be able to deal with setup scripts that aren't setuptools based.
61
62    >>> mkdir('foo')
63    >>> write('foo', 'setup.py',
64    ... '''
65    ... from setuptools import setup
66    ... setup(name="foo")
67    ... ''')
68
69    >>> write('buildout.cfg',
70    ... '''
71    ... [buildout]
72    ... develop = foo
73    ... parts =
74    ... ''')
75
76    >>> print system(join('bin', 'buildout')+' -vv'), # doctest: +ELLIPSIS
77    Installing...
78    Develop: '/sample-buildout/foo'
79    ...
80    Installed /sample-buildout/foo
81    ...
82
83    >>> ls('develop-eggs')
84    -  foo.egg-link
85    -  zc.recipe.egg.egg-link
86
87    >>> print system(join('bin', 'buildout')+' -vvv'), # doctest: +ELLIPSIS
88    Installing...
89    Develop: '/sample-buildout/foo'
90    in: '/sample-buildout/foo'
91    ... -q develop -mxN -d /sample-buildout/develop-eggs/...
92
93
94    """
95
96def buildout_error_handling():
97    r"""Buildout error handling
98
99Asking for a section that doesn't exist, yields a missing section error:
100
101    >>> import os
102    >>> os.chdir(sample_buildout)
103    >>> import zc.buildout.buildout
104    >>> buildout = zc.buildout.buildout.Buildout('buildout.cfg', [])
105    >>> buildout['eek']
106    Traceback (most recent call last):
107    ...
108    MissingSection: The referenced section, 'eek', was not defined.
109
110Asking for an option that doesn't exist, a MissingOption error is raised:
111
112    >>> buildout['buildout']['eek']
113    Traceback (most recent call last):
114    ...
115    MissingOption: Missing option: buildout:eek
116
117It is an error to create a variable-reference cycle:
118
119    >>> write(sample_buildout, 'buildout.cfg',
120    ... '''
121    ... [buildout]
122    ... parts =
123    ... x = ${buildout:y}
124    ... y = ${buildout:z}
125    ... z = ${buildout:x}
126    ... ''')
127
128    >>> print system(os.path.join(sample_buildout, 'bin', 'buildout')),
129    ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
130    While:
131      Initializing.
132      Getting section buildout.
133      Initializing section buildout.
134      Getting option buildout:y.
135      Getting option buildout:z.
136      Getting option buildout:x.
137      Getting option buildout:y.
138    Error: Circular reference in substitutions.
139
140It is an error to use funny characters in variable refereces:
141
142    >>> write(sample_buildout, 'buildout.cfg',
143    ... '''
144    ... [buildout]
145    ... develop = recipes
146    ... parts = data_dir debug
147    ... x = ${bui$ldout:y}
148    ... ''')
149
150    >>> print system(os.path.join(sample_buildout, 'bin', 'buildout')),
151    While:
152      Initializing.
153      Getting section buildout.
154      Initializing section buildout.
155      Getting option buildout:x.
156    Error: The section name in substitution, ${bui$ldout:y},
157    has invalid characters.
158
159    >>> write(sample_buildout, 'buildout.cfg',
160    ... '''
161    ... [buildout]
162    ... develop = recipes
163    ... parts = data_dir debug
164    ... x = ${buildout:y{z}
165    ... ''')
166
167    >>> print system(os.path.join(sample_buildout, 'bin', 'buildout')),
168    While:
169      Initializing.
170      Getting section buildout.
171      Initializing section buildout.
172      Getting option buildout:x.
173    Error: The option name in substitution, ${buildout:y{z},
174    has invalid characters.
175
176and too have too many or too few colons:
177
178    >>> write(sample_buildout, 'buildout.cfg',
179    ... '''
180    ... [buildout]
181    ... develop = recipes
182    ... parts = data_dir debug
183    ... x = ${parts}
184    ... ''')
185
186    >>> print system(os.path.join(sample_buildout, 'bin', 'buildout')),
187    While:
188      Initializing.
189      Getting section buildout.
190      Initializing section buildout.
191      Getting option buildout:x.
192    Error: The substitution, ${parts},
193    doesn't contain a colon.
194
195    >>> write(sample_buildout, 'buildout.cfg',
196    ... '''
197    ... [buildout]
198    ... develop = recipes
199    ... parts = data_dir debug
200    ... x = ${buildout:y:z}
201    ... ''')
202
203    >>> print system(os.path.join(sample_buildout, 'bin', 'buildout')),
204    While:
205      Initializing.
206      Getting section buildout.
207      Initializing section buildout.
208      Getting option buildout:x.
209    Error: The substitution, ${buildout:y:z},
210    has too many colons.
211
212Al parts have to have a section:
213
214    >>> write(sample_buildout, 'buildout.cfg',
215    ... '''
216    ... [buildout]
217    ... parts = x
218    ... ''')
219
220    >>> print system(os.path.join(sample_buildout, 'bin', 'buildout')),
221    While:
222      Installing.
223      Getting section x.
224    Error: The referenced section, 'x', was not defined.
225
226and all parts have to have a specified recipe:
227
228
229    >>> write(sample_buildout, 'buildout.cfg',
230    ... '''
231    ... [buildout]
232    ... parts = x
233    ...
234    ... [x]
235    ... foo = 1
236    ... ''')
237
238    >>> print system(os.path.join(sample_buildout, 'bin', 'buildout')),
239    While:
240      Installing.
241    Error: Missing option: x:recipe
242
243"""
244
245make_dist_that_requires_setup_py_template = """
246from setuptools import setup
247setup(name=%r, version=%r,
248      install_requires=%r,
249      )
250"""
251
252def make_dist_that_requires(dest, name, requires=[], version=1, egg=''):
253    os.mkdir(os.path.join(dest, name))
254    open(os.path.join(dest, name, 'setup.py'), 'w').write(
255        make_dist_that_requires_setup_py_template
256        % (name, version, requires)
257        )
258
259def show_who_requires_when_there_is_a_conflict():
260    """
261    It's a pain when we require eggs that have requirements that are
262    incompatible. We want the error we get to tell us what is missing.
263
264    Let's make a few develop distros, some of which have incompatible
265    requirements.
266
267    >>> make_dist_that_requires(sample_buildout, 'sampley',
268    ...                         ['demoneeded ==1.0'])
269    >>> make_dist_that_requires(sample_buildout, 'samplez',
270    ...                         ['demoneeded ==1.1'])
271
272    Now, let's create a buildout that requires y and z:
273
274    >>> write('buildout.cfg',
275    ... '''
276    ... [buildout]
277    ... parts = eggs
278    ... develop = sampley samplez
279    ... find-links = %(link_server)s
280    ...
281    ... [eggs]
282    ... recipe = zc.recipe.egg
283    ... eggs = sampley
284    ...        samplez
285    ... ''' % globals())
286
287    >>> print system(buildout),
288    Develop: '/sample-buildout/sampley'
289    Develop: '/sample-buildout/samplez'
290    Installing eggs.
291    Getting distribution for 'demoneeded==1.1'.
292    Got demoneeded 1.1.
293    While:
294      Installing eggs.
295    Error: There is a version conflict.
296    We already have: demoneeded 1.1
297    but sampley 1 requires 'demoneeded==1.0'.
298
299    Here, we see that sampley required an older version of demoneeded.
300    What if we hadn't required sampley ourselves:
301
302    >>> make_dist_that_requires(sample_buildout, 'samplea', ['sampleb'])
303    >>> make_dist_that_requires(sample_buildout, 'sampleb',
304    ...                         ['sampley', 'samplea'])
305    >>> write('buildout.cfg',
306    ... '''
307    ... [buildout]
308    ... parts = eggs
309    ... develop = sampley samplez samplea sampleb
310    ... find-links = %(link_server)s
311    ...
312    ... [eggs]
313    ... recipe = zc.recipe.egg
314    ... eggs = samplea
315    ...        samplez
316    ... ''' % globals())
317
318If we use the verbose switch, we can see where requirements are comning from:
319
320    >>> print system(buildout+' -v'), # doctest: +ELLIPSIS
321    Installing 'zc.buildout', 'setuptools'.
322    We have a develop egg: zc.buildout 1.0.0
323    We have the best distribution that satisfies 'setuptools'.
324    Picked: setuptools = 0.6
325    Develop: '/sample-buildout/sampley'
326    Develop: '/sample-buildout/samplez'
327    Develop: '/sample-buildout/samplea'
328    Develop: '/sample-buildout/sampleb'
329    ...Installing eggs.
330    Installing 'samplea', 'samplez'.
331    We have a develop egg: samplea 1
332    We have a develop egg: samplez 1
333    Getting required 'demoneeded==1.1'
334      required by samplez 1.
335    We have the distribution that satisfies 'demoneeded==1.1'.
336    Getting required 'sampleb'
337      required by samplea 1.
338    We have a develop egg: sampleb 1
339    Getting required 'sampley'
340      required by sampleb 1.
341    We have a develop egg: sampley 1
342    While:
343      Installing eggs.
344    Error: There is a version conflict.
345    We already have: demoneeded 1.1
346    but sampley 1 requires 'demoneeded==1.0'.
347    """
348
349def show_who_requires_missing_distributions():
350    """
351
352    When working with a lot of eggs, which require eggs recursively,
353    it can be hard to tell why we're requireing things we can't find.
354    Fortunately, buildout will tell us who's asking for something that
355    we can't find.
356
357    >>> make_dist_that_requires(sample_buildout, 'sampley', ['demoneeded'])
358    >>> make_dist_that_requires(sample_buildout, 'samplea', ['sampleb'])
359    >>> make_dist_that_requires(sample_buildout, 'sampleb',
360    ...                         ['sampley', 'samplea'])
361    >>> write('buildout.cfg',
362    ... '''
363    ... [buildout]
364    ... parts = eggs
365    ... develop = sampley samplea sampleb
366    ...
367    ... [eggs]
368    ... recipe = zc.recipe.egg
369    ... eggs = samplea
370    ... ''')
371
372    >>> print system(buildout),
373    Develop: '/sample-buildout/sampley'
374    Develop: '/sample-buildout/samplea'
375    Develop: '/sample-buildout/sampleb'
376    Installing eggs.
377    Couldn't find index page for 'demoneeded' (maybe misspelled?)
378    Getting distribution for 'demoneeded'.
379    While:
380      Installing eggs.
381      Getting distribution for 'demoneeded'.
382    Error: Couldn't find a distribution for 'demoneeded'.
383    """
384   
385 
386def test_comparing_saved_options_with_funny_characters():
387    """
388    If an option has newlines, extra/odd spaces or a %, we need to make
389    sure the comparison with the saved value works correctly.
390
391    >>> mkdir(sample_buildout, 'recipes')
392    >>> write(sample_buildout, 'recipes', 'debug.py',
393    ... '''
394    ... class Debug:
395    ...     def __init__(self, buildout, name, options):
396    ...         options['debug'] = \"\"\"  <zodb>
397    ...
398    ...   <filestorage>
399    ...     path foo
400    ...   </filestorage>
401    ...
402    ... </zodb> 
403    ...      \"\"\"
404    ...         options['debug1'] = \"\"\"
405    ... <zodb>
406    ...
407    ...   <filestorage>
408    ...     path foo
409    ...   </filestorage>
410    ...
411    ... </zodb> 
412    ... \"\"\"
413    ...         options['debug2'] = '  x  '
414    ...         options['debug3'] = '42'
415    ...         options['format'] = '%3d'
416    ...
417    ...     def install(self):
418    ...         open('t', 'w').write('t')
419    ...         return 't'
420    ...
421    ...     update = install
422    ... ''')
423
424
425    >>> write(sample_buildout, 'recipes', 'setup.py',
426    ... '''
427    ... from setuptools import setup
428    ... setup(
429    ...     name = "recipes",
430    ...     entry_points = {'zc.buildout': ['default = debug:Debug']},
431    ...     )
432    ... ''')
433
434    >>> write(sample_buildout, 'recipes', 'README.txt', " ")
435
436    >>> write(sample_buildout, 'buildout.cfg',
437    ... '''
438    ... [buildout]
439    ... develop = recipes
440    ... parts = debug
441    ...
442    ... [debug]
443    ... recipe = recipes
444    ... ''')
445
446    >>> os.chdir(sample_buildout)
447    >>> buildout = os.path.join(sample_buildout, 'bin', 'buildout')
448
449    >>> print system(buildout),
450    Develop: '/sample-buildout/recipes'
451    Installing debug.
452
453If we run the buildout again, we shoudn't get a message about
454uninstalling anything because the configuration hasn't changed.
455
456    >>> print system(buildout),
457    Develop: '/sample-buildout/recipes'
458    Updating debug.
459"""
460
461def finding_eggs_as_local_directories():
462    r"""
463It is possible to set up find-links so that we could install from
464a local directory that may contained unzipped eggs.
465
466    >>> src = tmpdir('src')
467    >>> write(src, 'setup.py',
468    ... '''
469    ... from setuptools import setup
470    ... setup(name='demo', py_modules=[''],
471    ...    zip_safe=False, version='1.0', author='bob', url='bob',
472    ...    author_email='bob')
473    ... ''')
474
475    >>> write(src, 't.py', '#\n')
476    >>> write(src, 'README.txt', '')
477    >>> _ = system(join('bin', 'buildout')+' setup ' + src + ' bdist_egg')
478
479Install it so it gets unzipped:
480
481    >>> d1 = tmpdir('d1')
482    >>> ws = zc.buildout.easy_install.install(
483    ...     ['demo'], d1, links=[join(src, 'dist')],
484    ...     )
485
486    >>> ls(d1)
487    d  demo-1.0-py2.4.egg
488
489Then try to install it again:
490
491    >>> d2 = tmpdir('d2')
492    >>> ws = zc.buildout.easy_install.install(
493    ...     ['demo'], d2, links=[d1],
494    ...     )
495
496    >>> ls(d2)
497    d  demo-1.0-py2.4.egg
498
499    """
500
501def make_sure__get_version_works_with_2_digit_python_versions():
502    """
503
504This is a test of an internal function used by higher-level machinery.
505
506We'll start by creating a faux 'python' that executable that prints a
5072-digit version. This is a bit of a pain to do portably. :(
508
509    >>> mkdir('demo')
510    >>> write('demo', 'setup.py',
511    ... '''
512    ... from setuptools import setup
513    ... setup(name='demo',
514    ...       entry_points = {'console_scripts': ['demo = demo:main']},
515    ...       )
516    ... ''')
517    >>> write('demo', 'demo.py',
518    ... '''
519    ... def main():
520    ...     print 'Python 2.5'
521    ... ''')
522
523    >>> write('buildout.cfg',
524    ... '''
525    ... [buildout]
526    ... develop = demo
527    ... parts =
528    ... ''')
529
530    >>> print system(join('bin', 'buildout')),
531    Develop: '/sample-buildout/demo'
532
533    >>> import zc.buildout.easy_install
534    >>> ws = zc.buildout.easy_install.working_set(
535    ...    ['demo'], sys.executable, ['develop-eggs'])
536    >>> bool(zc.buildout.easy_install.scripts(
537    ...      ['demo'], ws, sys.executable, 'bin'))
538    True
539
540    >>> print system(join('bin', 'demo')),
541    Python 2.5
542
543Now, finally, let's test _get_version:
544
545    >>> zc.buildout.easy_install._get_version(join('bin', 'demo'))
546    '2.5'
547
548    """
549
550def create_sections_on_command_line():
551    """
552    >>> write('buildout.cfg',
553    ... '''
554    ... [buildout]
555    ... parts =
556    ... x = ${foo:bar}
557    ... ''')
558
559    >>> print system(buildout + ' foo:bar=1 -vv'), # doctest: +ELLIPSIS
560    Installing 'zc.buildout', 'setuptools'.
561    ...
562    [foo]
563    bar = 1
564    ...
565   
566    """
567
568bootstrap_py = os.path.join(
569       os.path.dirname(
570          os.path.dirname(
571             os.path.dirname(
572                os.path.dirname(zc.buildout.__file__)
573                )
574             )
575          ),
576       'bootstrap', 'bootstrap.py')
577
578if os.path.exists(bootstrap_py):
579    def test_bootstrap_py():
580        """Make sure the bootstrap script actually works
581
582    >>> sample_buildout = tmpdir('sample')
583    >>> os.chdir(sample_buildout)
584    >>> write('buildout.cfg',
585    ... '''
586    ... [buildout]
587    ... parts =
588    ... ''')
589    >>> write('bootstrap.py', open(bootstrap_py).read())
590    >>> print 'X'; print system(
591    ...     zc.buildout.easy_install._safe_arg(sys.executable)+' '+
592    ...     'bootstrap.py'); print 'X' # doctest: +ELLIPSIS
593    X...
594    Creating directory '/sample/bin'.
595    Creating directory '/sample/parts'.
596    Creating directory '/sample/eggs'.
597    Creating directory '/sample/develop-eggs'.
598    Generated script '/sample/bin/buildout'.
599    ...
600
601    >>> ls(sample_buildout)
602    d  bin
603    -  bootstrap.py
604    -  buildout.cfg
605    d  develop-eggs
606    d  eggs
607    d  parts
608
609
610    >>> ls(sample_buildout, 'bin')
611    -  buildout
612
613    >>> print 'X'; ls(sample_buildout, 'eggs') # doctest: +ELLIPSIS
614    X...
615    d  zc.buildout-1.0-py2.4.egg
616
617    """
618
619def test_help():
620    """
621    >>> print system(os.path.join(sample_buildout, 'bin', 'buildout')+' -h'),
622    ... # doctest: +ELLIPSIS
623    Usage: buildout [options] [assignments] [command [command arguments]]
624    <BLANKLINE>
625    Options:
626    <BLANKLINE>
627      -h, --help
628    ...
629
630    >>> print system(os.path.join(sample_buildout, 'bin', 'buildout')
631    ...              +' --help'),
632    ... # doctest: +ELLIPSIS
633    Usage: buildout [options] [assignments] [command [command arguments]]
634    <BLANKLINE>
635    Options:
636    <BLANKLINE>
637      -h, --help
638    ...
639    """
640
641def test_bootstrap_with_extension():
642    """
643We had a problem running a bootstrap with an extension.  Let's make
644sure it is fixed.  Basically, we don't load extensions when
645bootstrapping.
646
647    >>> d = tmpdir('sample-bootstrap')
648   
649    >>> write(d, 'buildout.cfg',
650    ... '''
651    ... [buildout]
652    ... extensions = some_awsome_extension
653    ... parts =
654    ... ''')
655
656    >>> os.chdir(d)
657    >>> print system(os.path.join(sample_buildout, 'bin', 'buildout')
658    ...              + ' bootstrap'),
659    Creating directory '/sample-bootstrap/bin'.
660    Creating directory '/sample-bootstrap/parts'.
661    Creating directory '/sample-bootstrap/eggs'.
662    Creating directory '/sample-bootstrap/develop-eggs'.
663    Generated script '/sample-bootstrap/bin/buildout'.
664    """
665
666
667def bug_92891_bootstrap_crashes_with_egg_recipe_in_buildout_section():
668    """
669    >>> d = tmpdir('sample-bootstrap')
670   
671    >>> write(d, 'buildout.cfg',
672    ... '''
673    ... [buildout]
674    ... parts = buildout
675    ... eggs-directory = eggs
676    ...
677    ... [buildout]
678    ... recipe = zc.recipe.egg
679    ... eggs = zc.buildout
680    ... scripts = buildout=buildout
681    ... ''')
682
683    >>> os.chdir(d)
684    >>> print system(os.path.join(sample_buildout, 'bin', 'buildout')
685    ...              + ' bootstrap'),
686    Creating directory '/sample-bootstrap/bin'.
687    Creating directory '/sample-bootstrap/parts'.
688    Creating directory '/sample-bootstrap/eggs'.
689    Creating directory '/sample-bootstrap/develop-eggs'.
690    Generated script '/sample-bootstrap/bin/buildout'.
691
692    >>> print system(os.path.join('bin', 'buildout')),
693    Unused options for buildout: 'scripts' 'eggs'.
694
695    """
696
697def removing_eggs_from_develop_section_causes_egg_link_to_be_removed():
698    '''
699    >>> cd(sample_buildout)
700
701Create a develop egg:
702
703    >>> mkdir('foo')
704    >>> write('foo', 'setup.py',
705    ... """
706    ... from setuptools import setup
707    ... setup(name='foox')
708    ... """)
709    >>> write('buildout.cfg',
710    ... """
711    ... [buildout]
712    ... develop = foo
713    ... parts =
714    ... """)
715
716    >>> print system(join('bin', 'buildout')),
717    Develop: '/sample-buildout/foo'
718
719    >>> ls('develop-eggs')
720    -  foox.egg-link
721    -  zc.recipe.egg.egg-link
722
723Create another:
724
725    >>> mkdir('bar')
726    >>> write('bar', 'setup.py',
727    ... """
728    ... from setuptools import setup
729    ... setup(name='fooy')
730    ... """)
731    >>> write('buildout.cfg',
732    ... """
733    ... [buildout]
734    ... develop = foo bar
735    ... parts =
736    ... """)
737
738    >>> print system(join('bin', 'buildout')),
739    Develop: '/sample-buildout/foo'
740    Develop: '/sample-buildout/bar'
741
742    >>> ls('develop-eggs')
743    -  foox.egg-link
744    -  fooy.egg-link
745    -  zc.recipe.egg.egg-link
746
747Remove one:
748
749    >>> write('buildout.cfg',
750    ... """
751    ... [buildout]
752    ... develop = bar
753    ... parts =
754    ... """)
755    >>> print system(join('bin', 'buildout')),
756    Develop: '/sample-buildout/bar'
757
758It is gone
759
760    >>> ls('develop-eggs')
761    -  fooy.egg-link
762    -  zc.recipe.egg.egg-link
763
764Remove the other:
765
766    >>> write('buildout.cfg',
767    ... """
768    ... [buildout]
769    ... parts =
770    ... """)
771    >>> print system(join('bin', 'buildout')),
772
773All gone
774
775    >>> ls('develop-eggs')
776    -  zc.recipe.egg.egg-link
777    '''
778
779
780def add_setuptools_to_dependencies_when_namespace_packages():
781    '''   
782Often, a package depends on setuptools soley by virtue of using
783namespace packages. In this situation, package authors often forget to
784declare setuptools as a dependency. This is a mistake, but,
785unfortunately, a common one that we need to work around.  If an egg
786uses namespace packages and does not include setuptools as a depenency,
787we will still include setuptools in the working set.  If we see this for
788a devlop egg, we will also generate a warning.
789
790    >>> mkdir('foo')
791    >>> mkdir('foo', 'src')
792    >>> mkdir('foo', 'src', 'stuff')
793    >>> write('foo', 'src', 'stuff', '__init__.py',
794    ... """__import__('pkg_resources').declare_namespace(__name__)
795    ... """)
796    >>> mkdir('foo', 'src', 'stuff', 'foox')
797    >>> write('foo', 'src', 'stuff', 'foox', '__init__.py', '')
798    >>> write('foo', 'setup.py',
799    ... """
800    ... from setuptools import setup
801    ... setup(name='foox',
802    ...       namespace_packages = ['stuff'],
803    ...       package_dir = {'': 'src'},
804    ...       packages = ['stuff', 'stuff.foox'],
805    ...       )
806    ... """)
807    >>> write('foo', 'README.txt', '')
808   
809    >>> write('buildout.cfg',
810    ... """
811    ... [buildout]
812    ... develop = foo
813    ... parts =
814    ... """)
815
816    >>> print system(join('bin', 'buildout')),
817    Develop: '/sample-buildout/foo'
818
819Now, if we generate a working set using the egg link, we will get a warning
820and we will get setuptools included in the working set.
821
822    >>> import logging, zope.testing.loggingsupport
823    >>> handler = zope.testing.loggingsupport.InstalledHandler(
824    ...        'zc.buildout.easy_install', level=logging.WARNING)
825    >>> logging.getLogger('zc.buildout.easy_install').propagate = False
826   
827    >>> [dist.project_name
828    ...  for dist in zc.buildout.easy_install.working_set(
829    ...    ['foox'], sys.executable,
830    ...    [join(sample_buildout, 'eggs'),
831    ...     join(sample_buildout, 'develop-eggs'),
832    ...     ])]
833    ['foox', 'setuptools']
834
835    >>> print handler
836    zc.buildout.easy_install WARNING
837      Develop distribution: foox 0.0.0
838    uses namespace packages but the distribution does not require setuptools.
839
840    >>> handler.clear()
841
842On the other hand, if we have a regular egg, rather than a develop egg:
843
844    >>> os.remove(join('develop-eggs', 'foox.egg-link'))
845
846    >>> _ = system(join('bin', 'buildout') + ' setup foo bdist_egg -d'
847    ...            + join(sample_buildout, 'eggs'))
848
849    >>> ls('develop-eggs')
850    -  zc.recipe.egg.egg-link
851   
852    >>> ls('eggs') # doctest: +ELLIPSIS
853    -  foox-0.0.0-py2.4.egg
854    ...
855   
856We do not get a warning, but we do get setuptools included in the working set:
857
858    >>> [dist.project_name
859    ...  for dist in zc.buildout.easy_install.working_set(
860    ...    ['foox'], sys.executable,
861    ...    [join(sample_buildout, 'eggs'),
862    ...     join(sample_buildout, 'develop-eggs'),
863    ...     ])]
864    ['foox', 'setuptools']
865
866    >>> print handler,
867
868We get the same behavior if the it is a depedency that uses a
869namespace package.
870
871
872    >>> mkdir('bar')
873    >>> write('bar', 'setup.py',
874    ... """
875    ... from setuptools import setup
876    ... setup(name='bar', install_requires = ['foox'])
877    ... """)
878    >>> write('bar', 'README.txt', '')
879   
880    >>> write('buildout.cfg',
881    ... """
882    ... [buildout]
883    ... develop = foo bar
884    ... parts =
885    ... """)
886
887    >>> print system(join('bin', 'buildout')),
888    Develop: '/sample-buildout/foo'
889    Develop: '/sample-buildout/bar'
890
891    >>> [dist.project_name
892    ...  for dist in zc.buildout.easy_install.working_set(
893    ...    ['bar'], sys.executable,
894    ...    [join(sample_buildout, 'eggs'),
895    ...     join(sample_buildout, 'develop-eggs'),
896    ...     ])]
897    ['bar', 'foox', 'setuptools']
898
899    >>> print handler,
900    zc.buildout.easy_install WARNING
901      Develop distribution: foox 0.0.0
902    uses namespace packages but the distribution does not require setuptools.
903
904
905    >>> logging.getLogger('zc.buildout.easy_install').propagate = True
906    >>> handler.uninstall()
907
908    '''
909
910def develop_preserves_existing_setup_cfg():
911    """
912   
913See "Handling custom build options for extensions in develop eggs" in
914easy_install.txt.  This will be very similar except that we'll have an
915existing setup.cfg:
916
917    >>> write(extdemo, "setup.cfg",
918    ... '''
919    ... # sampe cfg file
920    ...
921    ... [foo]
922    ... bar = 1
923    ...
924    ... [build_ext]
925    ... define = X,Y
926    ... ''')
927
928    >>> mkdir('include')
929    >>> write('include', 'extdemo.h',
930    ... '''
931    ... #define EXTDEMO 42
932    ... ''')
933
934    >>> dest = tmpdir('dest')
935    >>> zc.buildout.easy_install.develop(
936    ...   extdemo, dest,
937    ...   {'include-dirs': os.path.join(sample_buildout, 'include')})
938    '/dest/extdemo.egg-link'
939
940    >>> ls(dest)
941    -  extdemo.egg-link
942
943    >>> cat(extdemo, "setup.cfg")
944    <BLANKLINE>
945    # sampe cfg file
946    <BLANKLINE>
947    [foo]
948    bar = 1
949    <BLANKLINE>
950    [build_ext]
951    define = X,Y
952
953"""
954
955def uninstall_recipes_used_for_removal():
956    """
957Uninstall recipes need to be called when a part is removed too:
958
959    >>> mkdir("recipes")
960    >>> write("recipes", "setup.py",
961    ... '''
962    ... from setuptools import setup
963    ... setup(name='recipes',
964    ...       entry_points={
965    ...          'zc.buildout': ["demo=demo:Install"],
966    ...          'zc.buildout.uninstall': ["demo=demo:uninstall"],
967    ...          })
968    ... ''')
969
970    >>> write("recipes", "demo.py",
971    ... '''
972    ... class Install:
973    ...     def __init__(*args): pass
974    ...     def install(self):
975    ...         print 'installing'
976    ...         return ()
977    ... def uninstall(name, options): print 'uninstalling'
978    ... ''')
979
980    >>> write('buildout.cfg', '''
981    ... [buildout]
982    ... develop = recipes
983    ... parts = demo
984    ... [demo]
985    ... recipe = recipes:demo
986    ... ''')
987
988    >>> print system(join('bin', 'buildout')),
989    Develop: '/sample-buildout/recipes'
990    Installing demo.
991    installing
992
993
994    >>> write('buildout.cfg', '''
995    ... [buildout]
996    ... develop = recipes
997    ... parts = demo
998    ... [demo]
999    ... recipe = recipes:demo
1000    ... x = 1
1001    ... ''')
1002
1003    >>> print system(join('bin', 'buildout')),
1004    Develop: '/sample-buildout/recipes'
1005    Uninstalling demo.
1006    Running uninstall recipe.
1007    uninstalling
1008    Installing demo.
1009    installing
1010
1011
1012    >>> write('buildout.cfg', '''
1013    ... [buildout]
1014    ... develop = recipes
1015    ... parts =
1016    ... ''')
1017
1018    >>> print system(join('bin', 'buildout')),
1019    Develop: '/sample-buildout/recipes'
1020    Uninstalling demo.
1021    Running uninstall recipe.
1022    uninstalling
1023
1024"""
1025
1026def extensions_installed_as_eggs_work_in_offline_mode():
1027    '''
1028    >>> mkdir('demo')
1029
1030    >>> write('demo', 'demo.py',
1031    ... """
1032    ... def ext(buildout):
1033    ...     print 'ext', list(buildout)
1034    ... """)
1035
1036    >>> write('demo', 'setup.py',
1037    ... """
1038    ... from setuptools import setup
1039    ...
1040    ... setup(
1041    ...     name = "demo",
1042    ...     py_modules=['demo'],
1043    ...     entry_points = {'zc.buildout.extension': ['ext = demo:ext']},
1044    ...     )
1045    ... """)
1046
1047    >>> bdist_egg(join(sample_buildout, "demo"), sys.executable,
1048    ...           join(sample_buildout, "eggs"))
1049
1050    >>> write(sample_buildout, 'buildout.cfg',
1051    ... """
1052    ... [buildout]
1053    ... extensions = demo
1054    ... parts =
1055    ... offline = true
1056    ... """)
1057
1058    >>> print system(join(sample_buildout, 'bin', 'buildout')),
1059    ext ['buildout']
1060   
1061
1062    '''
1063
1064def changes_in_svn_or_CVS_dont_affect_sig():
1065    """
1066   
1067If we have a develop recipe, it's signature shouldn't be affected to
1068changes in .svn or CVS directories.
1069
1070    >>> mkdir('recipe')
1071    >>> write('recipe', 'setup.py',
1072    ... '''
1073    ... from setuptools import setup
1074    ... setup(name='recipe',
1075    ...       entry_points={'zc.buildout': ['default=foo:Foo']})
1076    ... ''')
1077    >>> write('recipe', 'foo.py',
1078    ... '''
1079    ... class Foo:
1080    ...     def __init__(*args): pass
1081    ...     def install(*args): return ()
1082    ...     update = install
1083    ... ''')
1084   
1085    >>> write('buildout.cfg',
1086    ... '''
1087    ... [buildout]
1088    ... develop = recipe
1089    ... parts = foo
1090    ...
1091    ... [foo]
1092    ... recipe = recipe
1093    ... ''')
1094
1095
1096    >>> print system(join(sample_buildout, 'bin', 'buildout')),
1097    Develop: '/sample-buildout/recipe'
1098    Installing foo.
1099
1100    >>> mkdir('recipe', '.svn')
1101    >>> mkdir('recipe', 'CVS')
1102    >>> print system(join(sample_buildout, 'bin', 'buildout')),
1103    Develop: '/sample-buildout/recipe'
1104    Updating foo.
1105
1106    >>> write('recipe', '.svn', 'x', '1')
1107    >>> write('recipe', 'CVS', 'x', '1')
1108
1109    >>> print system(join(sample_buildout, 'bin', 'buildout')),
1110    Develop: '/sample-buildout/recipe'
1111    Updating foo.
1112
1113    """
1114
1115if hasattr(os, 'symlink'):
1116    def bug_250537_broken_symlink_doesnt_affect_sig():
1117        """
1118If we have a develop recipe, it's signature shouldn't be affected by
1119broken symlinks, and better yet, computing the hash should not break
1120because of the missing target file.
1121
1122    >>> mkdir('recipe')
1123    >>> write('recipe', 'setup.py',
1124    ... '''
1125    ... from setuptools import setup
1126    ... setup(name='recipe',
1127    ...       entry_points={'zc.buildout': ['default=foo:Foo']})
1128    ... ''')
1129    >>> write('recipe', 'foo.py',
1130    ... '''
1131    ... class Foo:
1132    ...     def __init__(*args): pass
1133    ...     def install(*args): return ()
1134    ...     update = install
1135    ... ''')
1136   
1137    >>> write('buildout.cfg',
1138    ... '''
1139    ... [buildout]
1140    ... develop = recipe
1141    ... parts = foo
1142    ...
1143    ... [foo]
1144    ... recipe = recipe
1145    ... ''')
1146
1147
1148    >>> print system(join(sample_buildout, 'bin', 'buildout')),
1149    Develop: '/sample-buildout/recipe'
1150    Installing foo.
1151
1152    >>> write('recipe', 'some-file', '1')
1153    >>> os.symlink(join('recipe', 'some-file'),
1154    ...            join('recipe', 'another-file'))
1155    >>> ls('recipe')
1156    l  another-file
1157    -  foo.py
1158    -  foo.pyc
1159    d  recipe.egg-info
1160    -  setup.py
1161    -  some-file
1162
1163    >>> remove('recipe', 'some-file')
1164
1165    >>> print system(join(sample_buildout, 'bin', 'buildout')),
1166    Develop: '/sample-buildout/recipe'
1167    Updating foo.
1168
1169    """
1170
1171def o_option_sets_offline():
1172    """
1173    >>> print system(join(sample_buildout, 'bin', 'buildout')+' -vvo'),
1174    ... # doctest: +ELLIPSIS
1175    <BLANKLINE>
1176    ...
1177    offline = true
1178    ...
1179    """
1180
1181def recipe_upgrade():
1182    """
1183
1184The buildout will upgrade recipes in newest (and non-offline) mode.
1185
1186Let's create a recipe egg
1187
1188    >>> mkdir('recipe')
1189    >>> write('recipe', 'recipe.py',
1190    ... '''
1191    ... class Recipe:
1192    ...     def __init__(*a): pass
1193    ...     def install(self):
1194    ...         print 'recipe v1'
1195    ...         return ()
1196    ...     update = install
1197    ... ''')
1198
1199    >>> write('recipe', 'setup.py',
1200    ... '''
1201    ... from setuptools import setup
1202    ... setup(name='recipe', version='1', py_modules=['recipe'],
1203    ...       entry_points={'zc.buildout': ['default = recipe:Recipe']},
1204    ...       )
1205    ... ''')
1206
1207    >>> write('recipe', 'README', '')
1208
1209    >>> print system(buildout+' setup recipe bdist_egg'), # doctest: +ELLIPSIS
1210    Running setup script 'recipe/setup.py'.
1211    ...
1212
1213    >>> rmdir('recipe', 'build')
1214
1215And update our buildout to use it.
1216
1217    >>> write('buildout.cfg',
1218    ... '''
1219    ... [buildout]
1220    ... parts = foo
1221    ... find-links = %s
1222    ...
1223    ... [foo]
1224    ... recipe = recipe
1225    ... ''' % join('recipe', 'dist'))
1226
1227    >>> print system(buildout),
1228    Getting distribution for 'recipe'.
1229    Got recipe 1.
1230    Installing foo.
1231    recipe v1
1232
1233Now, if we update the recipe egg:
1234
1235    >>> write('recipe', 'recipe.py',
1236    ... '''
1237    ... class Recipe:
1238    ...     def __init__(*a): pass
1239    ...     def install(self):
1240    ...         print 'recipe v2'
1241    ...         return ()
1242    ...     update = install
1243    ... ''')
1244
1245    >>> write('recipe', 'setup.py',
1246    ... '''
1247    ... from setuptools import setup
1248    ... setup(name='recipe', version='2', py_modules=['recipe'],
1249    ...       entry_points={'zc.buildout': ['default = recipe:Recipe']},
1250    ...       )
1251    ... ''')
1252
1253
1254    >>> print system(buildout+' setup recipe bdist_egg'), # doctest: +ELLIPSIS
1255    Running setup script 'recipe/setup.py'.
1256    ...
1257
1258We won't get the update if we specify -N:
1259
1260    >>> print system(buildout+' -N'),
1261    Updating foo.
1262    recipe v1
1263
1264or if we use -o:
1265
1266    >>> print system(buildout+' -o'),
1267    Updating foo.
1268    recipe v1
1269
1270But we will if we use neither of these:
1271
1272    >>> print system(buildout),
1273    Getting distribution for 'recipe'.
1274    Got recipe 2.
1275    Uninstalling foo.
1276    Installing foo.
1277    recipe v2
1278
1279We can also select a particular recipe version:
1280
1281    >>> write('buildout.cfg',
1282    ... '''
1283    ... [buildout]
1284    ... parts = foo
1285    ... find-links = %s
1286    ...
1287    ... [foo]
1288    ... recipe = recipe ==1
1289    ... ''' % join('recipe', 'dist'))
1290
1291    >>> print system(buildout),
1292    Uninstalling foo.
1293    Installing foo.
1294    recipe v1
1295   
1296    """
1297
1298def update_adds_to_uninstall_list():
1299    """
1300
1301Paths returned by the update method are added to the list of paths to
1302uninstall
1303
1304    >>> mkdir('recipe')
1305    >>> write('recipe', 'setup.py',
1306    ... '''
1307    ... from setuptools import setup
1308    ... setup(name='recipe',
1309    ...       entry_points={'zc.buildout': ['default = recipe:Recipe']},
1310    ...       )
1311    ... ''')
1312
1313    >>> write('recipe', 'recipe.py',
1314    ... '''
1315    ... import os
1316    ... class Recipe:
1317    ...     def __init__(*_): pass
1318    ...     def install(self):
1319    ...         r = ('a', 'b', 'c')
1320    ...         for p in r: os.mkdir(p)
1321    ...         return r
1322    ...     def update(self):
1323    ...         r = ('c', 'd', 'e')
1324    ...         for p in r:
1325    ...             if not os.path.exists(p):
1326    ...                os.mkdir(p)
1327    ...         return r
1328    ... ''')
1329
1330    >>> write('buildout.cfg',
1331    ... '''
1332    ... [buildout]
1333    ... develop = recipe
1334    ... parts = foo
1335    ...
1336    ... [foo]
1337    ... recipe = recipe
1338    ... ''')
1339
1340    >>> print system(buildout),
1341    Develop: '/sample-buildout/recipe'
1342    Installing foo.
1343
1344    >>> print system(buildout),
1345    Develop: '/sample-buildout/recipe'
1346    Updating foo.
1347
1348    >>> cat('.installed.cfg') # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
1349    [buildout]
1350    ...
1351    [foo]
1352    __buildout_installed__ = a
1353        b
1354        c
1355        d
1356        e
1357    __buildout_signature__ = ...
1358
1359"""
1360
1361def log_when_there_are_not_local_distros():
1362    """
1363    >>> from zope.testing.loggingsupport import InstalledHandler
1364    >>> handler = InstalledHandler('zc.buildout.easy_install')
1365    >>> import logging
1366    >>> logger = logging.getLogger('zc.buildout.easy_install')
1367    >>> old_propogate = logger.propagate
1368    >>> logger.propagate = False
1369
1370    >>> dest = tmpdir('sample-install')
1371    >>> import zc.buildout.easy_install
1372    >>> ws = zc.buildout.easy_install.install(
1373    ...     ['demo==0.2'], dest,
1374    ...     links=[link_server], index=link_server+'index/')
1375
1376    >>> print handler # doctest: +ELLIPSIS
1377    zc.buildout.easy_install DEBUG
1378      Installing 'demo==0.2'.
1379    zc.buildout.easy_install DEBUG
1380      We have no distributions for demo that satisfies 'demo==0.2'.
1381    ...
1382
1383    >>> handler.uninstall()
1384    >>> logger.propagate = old_propogate
1385   
1386    """
1387
1388def internal_errors():
1389    """Internal errors are clearly marked and don't generate tracebacks:
1390
1391    >>> mkdir(sample_buildout, 'recipes')
1392
1393    >>> write(sample_buildout, 'recipes', 'mkdir.py',
1394    ... '''
1395    ... class Mkdir:
1396    ...     def __init__(self, buildout, name, options):
1397    ...         self.name, self.options = name, options
1398    ...         options['path'] = os.path.join(
1399    ...                               buildout['buildout']['directory'],
1400    ...                               options['path'],
1401    ...                               )
1402    ... ''')
1403
1404    >>> write(sample_buildout, 'recipes', 'setup.py',
1405    ... '''
1406    ... from setuptools import setup
1407    ... setup(name = "recipes",
1408    ...       entry_points = {'zc.buildout': ['mkdir = mkdir:Mkdir']},
1409    ...       )
1410    ... ''')
1411
1412    >>> write(sample_buildout, 'buildout.cfg',
1413    ... '''
1414    ... [buildout]
1415    ... develop = recipes
1416    ... parts = data-dir
1417    ...
1418    ... [data-dir]
1419    ... recipe = recipes:mkdir
1420    ... ''')
1421
1422    >>> print system(buildout), # doctest: +ELLIPSIS
1423    Develop: '/sample-buildout/recipes'
1424    While:
1425      Installing.
1426      Getting section data-dir.
1427      Initializing part data-dir.
1428    <BLANKLINE>
1429    An internal error occured due to a bug in either zc.buildout or in a
1430    recipe being used:
1431    Traceback (most recent call last):
1432    ...
1433    NameError: global name 'os' is not defined
1434    """
1435
1436def whine_about_unused_options():
1437    '''
1438
1439    >>> write('foo.py',
1440    ... """
1441    ... class Foo:
1442    ...
1443    ...     def __init__(self, buildout, name, options):
1444    ...         self.name, self.options = name, options
1445    ...         options['x']
1446    ...
1447    ...     def install(self):
1448    ...         self.options['y']
1449    ...         return ()
1450    ... """)
1451
1452    >>> write('setup.py',
1453    ... """
1454    ... from setuptools import setup
1455    ... setup(name = "foo",
1456    ...       entry_points = {'zc.buildout': ['default = foo:Foo']},
1457    ...       )
1458    ... """)
1459
1460    >>> write('buildout.cfg',
1461    ... """
1462    ... [buildout]
1463    ... develop = .
1464    ... parts = foo
1465    ... a = 1
1466    ...
1467    ... [foo]
1468    ... recipe = foo
1469    ... x = 1
1470    ... y = 1
1471    ... z = 1
1472    ... """)
1473
1474    >>> print system(buildout),
1475    Develop: '/sample-buildout/.'
1476    Unused options for buildout: 'a'.
1477    Installing foo.
1478    Unused options for foo: 'z'.
1479    '''
1480
1481def abnormal_exit():
1482    """
1483People sometimes hit control-c while running a builout. We need to make
1484sure that the installed database Isn't corrupted.  To test this, we'll create
1485some evil recipes that exit uncleanly:
1486
1487    >>> mkdir('recipes')
1488    >>> write('recipes', 'recipes.py',
1489    ... '''
1490    ... import os
1491    ...
1492    ... class Clean:
1493    ...     def __init__(*_): pass
1494    ...     def install(_): return ()
1495    ...     def update(_): pass
1496    ...
1497    ... class EvilInstall(Clean):
1498    ...     def install(_): os._exit(1)
1499    ...
1500    ... class EvilUpdate(Clean):
1501    ...     def update(_): os._exit(1)
1502    ... ''')
1503
1504    >>> write('recipes', 'setup.py',
1505    ... '''
1506    ... import setuptools
1507    ... setuptools.setup(name='recipes',
1508    ...    entry_points = {
1509    ...      'zc.buildout': [
1510    ...          'clean = recipes:Clean',
1511    ...          'evil_install = recipes:EvilInstall',
1512    ...          'evil_update = recipes:EvilUpdate',
1513    ...          'evil_uninstall = recipes:Clean',
1514    ...          ],
1515    ...       },
1516    ...     )
1517    ... ''')
1518
1519Now let's look at 3 cases:
1520
15211. We exit during installation after installing some other parts:
1522
1523    >>> write('buildout.cfg',
1524    ... '''
1525    ... [buildout]
1526    ... develop = recipes
1527    ... parts = p1 p2 p3 p4
1528    ...
1529    ... [p1]
1530    ... recipe = recipes:clean
1531    ...
1532    ... [p2]
1533    ... recipe = recipes:clean
1534    ...
1535    ... [p3]
1536    ... recipe = recipes:evil_install
1537    ...
1538    ... [p4]
1539    ... recipe = recipes:clean
1540    ... ''')
1541
1542    >>> print system(buildout),
1543    Develop: '/sample-buildout/recipes'
1544    Installing p1.
1545    Installing p2.
1546    Installing p3.
1547
1548    >>> print system(buildout),
1549    Develop: '/sample-buildout/recipes'
1550    Updating p1.
1551    Updating p2.
1552    Installing p3.
1553
1554    >>> print system(buildout+' buildout:parts='),
1555    Develop: '/sample-buildout/recipes'
1556    Uninstalling p2.
1557    Uninstalling p1.
1558
15592. We exit while updating:
1560
1561    >>> write('buildout.cfg',
1562    ... '''
1563    ... [buildout]
1564    ... develop = recipes
1565    ... parts = p1 p2 p3 p4
1566    ...
1567    ... [p1]
1568    ... recipe = recipes:clean
1569    ...
1570    ... [p2]
1571    ... recipe = recipes:clean
1572    ...
1573    ... [p3]
1574    ... recipe = recipes:evil_update
1575    ...
1576    ... [p4]
1577    ... recipe = recipes:clean
1578    ... ''')
1579
1580    >>> print system(buildout),
1581    Develop: '/sample-buildout/recipes'
1582    Installing p1.
1583    Installing p2.
1584    Installing p3.
1585    Installing p4.
1586
1587    >>> print system(buildout),
1588    Develop: '/sample-buildout/recipes'
1589    Updating p1.
1590    Updating p2.
1591    Updating p3.
1592
1593    >>> print system(buildout+' buildout:parts='),
1594    Develop: '/sample-buildout/recipes'
1595    Uninstalling p2.
1596    Uninstalling p1.
1597    Uninstalling p4.
1598    Uninstalling p3.
1599
16003. We exit while installing or updating after uninstalling:
1601
1602    >>> write('buildout.cfg',
1603    ... '''
1604    ... [buildout]
1605    ... develop = recipes
1606    ... parts = p1 p2 p3 p4
1607    ...
1608    ... [p1]
1609    ... recipe = recipes:evil_update
1610    ...
1611    ... [p2]
1612    ... recipe = recipes:clean
1613    ...
1614    ... [p3]
1615    ... recipe = recipes:clean
1616    ...
1617    ... [p4]
1618    ... recipe = recipes:clean
1619    ... ''')
1620
1621    >>> print system(buildout),
1622    Develop: '/sample-buildout/recipes'
1623    Installing p1.
1624    Installing p2.
1625    Installing p3.
1626    Installing p4.
1627
1628    >>> write('buildout.cfg',
1629    ... '''
1630    ... [buildout]
1631    ... develop = recipes
1632    ... parts = p1 p2 p3 p4
1633    ...
1634    ... [p1]
1635    ... recipe = recipes:evil_update
1636    ...
1637    ... [p2]
1638    ... recipe = recipes:clean
1639    ...
1640    ... [p3]
1641    ... recipe = recipes:clean
1642    ...
1643    ... [p4]
1644    ... recipe = recipes:clean
1645    ... x = 1
1646    ... ''')
1647
1648    >>> print system(buildout),
1649    Develop: '/sample-buildout/recipes'
1650    Uninstalling p4.
1651    Updating p1.
1652
1653    >>> write('buildout.cfg',
1654    ... '''
1655    ... [buildout]
1656    ... develop = recipes
1657    ... parts = p1 p2 p3 p4
1658    ...
1659    ... [p1]
1660    ... recipe = recipes:clean
1661    ...
1662    ... [p2]
1663    ... recipe = recipes:clean
1664    ...
1665    ... [p3]
1666    ... recipe = recipes:clean
1667    ...
1668    ... [p4]
1669    ... recipe = recipes:clean
1670    ... ''')
1671
1672    >>> print system(buildout),
1673    Develop: '/sample-buildout/recipes'
1674    Uninstalling p1.
1675    Installing p1.
1676    Updating p2.
1677    Updating p3.
1678    Installing p4.
1679
1680    """
1681
1682def install_source_dist_with_bad_py():
1683    """
1684
1685    >>> mkdir('badegg')
1686    >>> mkdir('badegg', 'badegg')
1687    >>> write('badegg', 'badegg', '__init__.py', '#\\n')
1688    >>> mkdir('badegg', 'badegg', 'scripts')
1689    >>> write('badegg', 'badegg', 'scripts', '__init__.py', '#\\n')
1690    >>> write('badegg', 'badegg', 'scripts', 'one.py',
1691    ... '''
1692    ... return 1
1693    ... ''')
1694
1695    >>> write('badegg', 'setup.py',
1696    ... '''
1697    ... from setuptools import setup, find_packages
1698    ... setup(
1699    ...     name='badegg',
1700    ...     version='1',
1701    ...     packages = find_packages('.'),
1702    ...     zip_safe=False)
1703    ... ''')
1704
1705    >>> print system(buildout+' setup badegg sdist'), # doctest: +ELLIPSIS
1706    Running setup script 'badegg/setup.py'.
1707    ...
1708   
1709    >>> dist = join('badegg', 'dist')
1710
1711    >>> write('buildout.cfg',
1712    ... '''
1713    ... [buildout]
1714    ... parts = eggs bo
1715    ... find-links = %(dist)s
1716    ...
1717    ... [eggs]
1718    ... recipe = zc.recipe.egg
1719    ... eggs = badegg
1720    ...
1721    ... [bo]
1722    ... recipe = zc.recipe.egg
1723    ... eggs = zc.buildout
1724    ... scripts = buildout=bo
1725    ... ''' % globals())
1726
1727    >>> print system(buildout);print 'X' # doctest: +ELLIPSIS
1728    Installing eggs.
1729    Getting distribution for 'badegg'.
1730    Got badegg 1.
1731    Installing bo.
1732    ...
1733    SyntaxError: ...'return' outside function...
1734    ...
1735    SyntaxError: ...'return' outside function...
1736    ...
1737
1738    >>> ls('eggs') # doctest: +ELLIPSIS
1739    d  badegg-1-py2.4.egg
1740    ...
1741   
1742    >>> ls('bin')
1743    -  bo
1744    -  buildout
1745    """
1746
1747def version_requirements_in_build_honored():
1748    '''
1749
1750    >>> update_extdemo()
1751    >>> dest = tmpdir('sample-install')
1752    >>> mkdir('include')
1753    >>> write('include', 'extdemo.h',
1754    ... """
1755    ... #define EXTDEMO 42
1756    ... """)
1757
1758    >>> zc.buildout.easy_install.build(
1759    ...   'extdemo ==1.4', dest,
1760    ...   {'include-dirs': os.path.join(sample_buildout, 'include')},
1761    ...   links=[link_server], index=link_server+'index/',
1762    ...   newest=False)
1763    ['/sample-install/extdemo-1.4-py2.4-linux-i686.egg']
1764
1765    '''
1766
1767def bug_105081_Specific_egg_versions_are_ignored_when_newer_eggs_are_around():
1768    """
1769    Buildout might ignore a specific egg requirement for a recipe:
1770
1771    - Have a newer version of an egg in your eggs directory
1772    - Use 'recipe==olderversion' in your buildout.cfg to request an
1773      older version
1774
1775    Buildout will go and fetch the older version, but it will *use*
1776    the newer version when installing a part with this recipe.
1777
1778    >>> write('buildout.cfg',
1779    ... '''
1780    ... [buildout]
1781    ... parts = x
1782    ... find-links = %(sample_eggs)s
1783    ...
1784    ... [x]
1785    ... recipe = zc.recipe.egg
1786    ... eggs = demo
1787    ... ''' % globals())
1788
1789    >>> print system(buildout),
1790    Installing x.
1791    Getting distribution for 'demo'.
1792    Got demo 0.4c1.
1793    Getting distribution for 'demoneeded'.
1794    Got demoneeded 1.2c1.
1795    Generated script '/sample-buildout/bin/demo'.
1796
1797    >>> print system(join('bin', 'demo')),
1798    4 2
1799
1800    >>> write('buildout.cfg',
1801    ... '''
1802    ... [buildout]
1803    ... parts = x
1804    ... find-links = %(sample_eggs)s
1805    ...
1806    ... [x]
1807    ... recipe = zc.recipe.egg
1808    ... eggs = demo ==0.1
1809    ... ''' % globals())
1810   
1811    >>> print system(buildout),
1812    Uninstalling x.
1813    Installing x.
1814    Getting distribution for 'demo==0.1'.
1815    Got demo 0.1.
1816    Generated script '/sample-buildout/bin/demo'.
1817
1818    >>> print system(join('bin', 'demo')),
1819    1 2
1820    """
1821
1822if sys.version_info > (2, 4):
1823    def test_exit_codes():
1824        """
1825        >>> import subprocess
1826        >>> def call(s):
1827        ...     p = subprocess.Popen(s, stdin=subprocess.PIPE,
1828        ...                 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
1829        ...     p.stdin.close()
1830        ...     print p.stdout.read()
1831        ...     print 'Exit:', bool(p.wait())
1832       
1833        >>> call(buildout)
1834        <BLANKLINE>
1835        Exit: False
1836
1837        >>> write('buildout.cfg',
1838        ... '''
1839        ... [buildout]
1840        ... parts = x
1841        ... ''')
1842
1843        >>> call(buildout) # doctest: +NORMALIZE_WHITESPACE
1844        While:
1845          Installing.
1846          Getting section x.
1847        Error: The referenced section, 'x', was not defined.
1848        <BLANKLINE>
1849        Exit: True
1850
1851        >>> write('setup.py',
1852        ... '''
1853        ... from setuptools import setup
1854        ... setup(name='zc.buildout.testexit', entry_points={
1855        ...    'zc.buildout': ['default = testexitrecipe:x']})
1856        ... ''')
1857
1858        >>> write('testexitrecipe.py',
1859        ... '''
1860        ... x y
1861        ... ''')
1862
1863        >>> write('buildout.cfg',
1864        ... '''
1865        ... [buildout]
1866        ... parts = x
1867        ... develop = .
1868        ...
1869        ... [x]
1870        ... recipe = zc.buildout.testexit
1871        ... ''')
1872
1873        >>> call(buildout) # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
1874        Develop: '/sample-buildout/.'
1875        While:
1876          Installing.
1877          Getting section x.
1878          Initializing section x.
1879          Loading zc.buildout recipe entry zc.buildout.testexit:default.
1880        <BLANKLINE>
1881        An internal error occured due to a bug in either zc.buildout or in a
1882        recipe being used:
1883        Traceback (most recent call last):
1884        ...
1885             x y
1886               ^
1887         SyntaxError: invalid syntax
1888        <BLANKLINE>
1889        Exit: True
1890        """
1891
1892def bug_59270_recipes_always_start_in_buildout_dir():
1893    """
1894    Recipes can rely on running from buildout directory
1895
1896    >>> mkdir('bad_start')
1897    >>> write('bad_recipe.py',
1898    ... '''
1899    ... import os
1900    ... class Bad:
1901    ...     def __init__(self, *_):
1902    ...         print os.getcwd()
1903    ...     def install(self):
1904    ...         print os.getcwd()
1905    ...         os.chdir('bad_start')
1906    ...         print os.getcwd()
1907    ...         return ()
1908    ... ''')
1909
1910    >>> write('setup.py',
1911    ... '''
1912    ... from setuptools import setup
1913    ... setup(name='bad.test',
1914    ...       entry_points={'zc.buildout': ['default=bad_recipe:Bad']},)
1915    ... ''')
1916   
1917    >>> write('buildout.cfg',
1918    ... '''
1919    ... [buildout]
1920    ... develop = .
1921    ... parts = b1 b2
1922    ... [b1]
1923    ... recipe = bad.test
1924    ... [b2]
1925    ... recipe = bad.test
1926    ... ''')
1927
1928    >>> os.chdir('bad_start')
1929    >>> print system(join(sample_buildout, 'bin', 'buildout')
1930    ...              +' -c '+join(sample_buildout, 'buildout.cfg')),
1931    Develop: '/sample-buildout/.'
1932    /sample-buildout
1933    /sample-buildout
1934    Installing b1.
1935    /sample-buildout
1936    /sample-buildout/bad_start
1937    Installing b2.
1938    /sample-buildout
1939    /sample-buildout/bad_start
1940   
1941    """
1942
1943def bug_61890_file_urls_dont_seem_to_work_in_find_dash_links():
1944    """
1945   
1946    This bug arises from the fact that setuptools is overly restrictive
1947    about file urls, requiring that file urls pointing at directories
1948    must end in a slash.
1949
1950    >>> dest = tmpdir('sample-install')
1951    >>> import zc.buildout.easy_install
1952    >>> sample_eggs = sample_eggs.replace(os.path.sep, '/')
1953    >>> ws = zc.buildout.easy_install.install(
1954    ...     ['demo==0.2'], dest,
1955    ...     links=['file://'+sample_eggs], index=link_server+'index/')
1956
1957
1958    >>> for dist in ws:
1959    ...     print dist
1960    demo 0.2
1961    demoneeded 1.1
1962
1963    >>> ls(dest)
1964    -  demo-0.2-py2.4.egg
1965    -  demoneeded-1.1-py2.4.egg
1966   
1967    """
1968
1969def bug_75607_buildout_should_not_run_if_it_creates_an_empty_buildout_cfg():
1970    """
1971    >>> remove('buildout.cfg')
1972    >>> print system(buildout),
1973    While:
1974      Initializing.
1975    Error: Couldn't open /sample-buildout/buildout.cfg
1976
1977
1978   
1979    """
1980
1981def dealing_with_extremely_insane_dependencies():
1982    r"""
1983   
1984    There was a problem with analysis of dependencies taking a long
1985    time, in part because the analysis would get repeated every time a
1986    package was encountered in a dependency list.  Now, we don't do
1987    the analysis any more:
1988
1989    >>> import os
1990    >>> for i in range(5):
1991    ...     p = 'pack%s' % i
1992    ...     deps = [('pack%s' % j) for j in range(5) if j is not i]
1993    ...     if i == 4:
1994    ...         deps.append('pack5')
1995    ...     mkdir(p)
1996    ...     write(p, 'setup.py',
1997    ...           'from setuptools import setup\n'
1998    ...           'setup(name=%r, install_requires=%r,\n'
1999    ...           '      url="u", author="a", author_email="e")\n'
2000    ...           % (p, deps))
2001
2002    >>> write('buildout.cfg',
2003    ... '''
2004    ... [buildout]
2005    ... develop = pack0 pack1 pack2 pack3 pack4
2006    ... parts = pack1
2007    ...
2008    ... [pack1]
2009    ... recipe = zc.recipe.egg:eggs
2010    ... eggs = pack0
2011    ... ''')
2012
2013    >>> print system(buildout),
2014    Develop: '/sample-buildout/pack0'
2015    Develop: '/sample-buildout/pack1'
2016    Develop: '/sample-buildout/pack2'
2017    Develop: '/sample-buildout/pack3'
2018    Develop: '/sample-buildout/pack4'
2019    Installing pack1.
2020    Couldn't find index page for 'pack5' (maybe misspelled?)
2021    Getting distribution for 'pack5'.
2022    While:
2023      Installing pack1.
2024      Getting distribution for 'pack5'.
2025    Error: Couldn't find a distribution for 'pack5'.
2026
2027    However, if we run in verbose mode, we can see why packages were included:
2028
2029    >>> print system(buildout+' -v'), # doctest: +ELLIPSIS
2030    Installing 'zc.buildout', 'setuptools'.
2031    We have a develop egg: zc.buildout 1.0.0
2032    We have the best distribution that satisfies 'setuptools'.
2033    Picked: setuptools = 0.6
2034    Develop: '/sample-buildout/pack0'
2035    Develop: '/sample-buildout/pack1'
2036    Develop: '/sample-buildout/pack2'
2037    Develop: '/sample-buildout/pack3'
2038    Develop: '/sample-buildout/pack4'
2039    ...Installing pack1.
2040    Installing 'pack0'.
2041    We have a develop egg: pack0 0.0.0
2042    Getting required 'pack4'
2043      required by pack0 0.0.0.
2044    We have a develop egg: pack4 0.0.0
2045    Getting required 'pack3'
2046      required by pack0 0.0.0.
2047      required by pack4 0.0.0.
2048    We have a develop egg: pack3 0.0.0
2049    Getting required 'pack2'
2050      required by pack0 0.0.0.
2051      required by pack3 0.0.0.
2052      required by pack4 0.0.0.
2053    We have a develop egg: pack2 0.0.0
2054    Getting required 'pack1'
2055      required by pack0 0.0.0.
2056      required by pack2 0.0.0.
2057      required by pack3 0.0.0.
2058      required by pack4 0.0.0.
2059    We have a develop egg: pack1 0.0.0
2060    Getting required 'pack5'
2061      required by pack4 0.0.0.
2062    We have no distributions for pack5 that satisfies 'pack5'.
2063    Couldn't find index page for 'pack5' (maybe misspelled?)
2064    Getting distribution for 'pack5'.
2065    While:
2066      Installing pack1.
2067      Getting distribution for 'pack5'.
2068    Error: Couldn't find a distribution for 'pack5'.
2069    """
2070
2071def read_find_links_to_load_extensions():
2072    """
2073We'll create a wacky buildout extension that is just another name for http:
2074
2075    >>> src = tmpdir('src')
2076    >>> write(src, 'wacky_handler.py',
2077    ... '''
2078    ... import urllib2
2079    ... class Wacky(urllib2.HTTPHandler):
2080    ...     wacky_open = urllib2.HTTPHandler.http_open
2081    ... def install(buildout=None):
2082    ...     urllib2.install_opener(urllib2.build_opener(Wacky))
2083    ... ''')
2084    >>> write(src, 'setup.py',
2085    ... '''
2086    ... from setuptools import setup
2087    ... setup(name='wackyextension', version='1',
2088    ...       py_modules=['wacky_handler'],
2089    ...       entry_points = {'zc.buildout.extension':
2090    ...             ['default = wacky_handler:install']
2091    ...             },
2092    ...       )
2093    ... ''')
2094    >>> print system(buildout+' setup '+src+' bdist_egg'),
2095    ... # doctest: +ELLIPSIS
2096    Running setup ...
2097    creating 'dist/wackyextension-1-...
2098
2099Now we'll create a buildout that uses this extension to load other packages:
2100
2101    >>> wacky_server = link_server.replace('http', 'wacky')
2102    >>> dist = 'file://' + join(src, 'dist').replace(os.path.sep, '/')
2103    >>> write('buildout.cfg',
2104    ... '''
2105    ... [buildout]
2106    ... parts = demo
2107    ... extensions = wackyextension
2108    ... find-links = %(wacky_server)s/demoneeded-1.0.zip
2109    ...              %(dist)s
2110    ... [demo]
2111    ... recipe = zc.recipe.egg
2112    ... eggs = demoneeded
2113    ... ''' % globals())
2114
2115When we run the buildout. it will load the extension from the dist
2116directory and then use the wacky extension to load the demo package
2117
2118    >>> print system(buildout),
2119    Getting distribution for 'wackyextension'.
2120    Got wackyextension 1.
2121    Installing demo.
2122    Getting distribution for 'demoneeded'.
2123    Got demoneeded 1.0.
2124   
2125    """
2126
2127def distributions_from_local_find_links_make_it_to_download_cache():
2128    """
2129
2130If we specify a local directory in find links, distors found there
2131need to make it to the download cache.
2132
2133    >>> mkdir('test')
2134    >>> write('test', 'setup.py',
2135    ... '''
2136    ... from setuptools import setup
2137    ... setup(name='foo')
2138    ... ''')
2139
2140    >>> print system(buildout+' setup test bdist_egg'), # doctest: +ELLIPSIS
2141    Running setup script 'test/setup.py'.
2142    ...
2143
2144
2145    >>> mkdir('cache')
2146    >>> old_cache = zc.buildout.easy_install.download_cache('cache')
2147    >>> list(zc.buildout.easy_install.install(['foo'], 'eggs',
2148    ...          links=[join('test', 'dist')])) # doctest: +ELLIPSIS
2149    [foo 0.0.0 ...
2150       
2151    >>> ls('cache')
2152    -  foo-0.0.0-py2.4.egg
2153
2154    >>> _ = zc.buildout.easy_install.download_cache(old_cache)
2155   
2156    """
2157
2158def create_egg(name, version, dest, install_requires=None,
2159               dependency_links=None):
2160    d = tempfile.mkdtemp()
2161    if dest=='available':
2162        extras = dict(x=['x'])
2163    else:
2164        extras = {}
2165    if dependency_links:
2166        links = 'dependency_links = %s, ' % dependency_links
2167    else:
2168        links = ''
2169    if install_requires:
2170        requires = 'install_requires = %s, ' % install_requires
2171    else:
2172        requires = ''
2173    try:
2174        open(os.path.join(d, 'setup.py'), 'w').write(
2175            'from setuptools import setup\n'
2176            'setup(name=%r, version=%r, extras_require=%r, zip_safe=True,\n'
2177            '      %s %s py_modules=["setup"]\n)'
2178            % (name, str(version), extras, requires, links)
2179            )
2180        zc.buildout.testing.bdist_egg(d, sys.executable, os.path.abspath(dest))
2181    finally:
2182        shutil.rmtree(d)
2183
2184def prefer_final_permutation(existing, available):
2185    for d in ('existing', 'available'):
2186        if os.path.exists(d):
2187            shutil.rmtree(d)
2188        os.mkdir(d)
2189    for version in existing:
2190        create_egg('spam', version, 'existing')
2191    for version in available:
2192        create_egg('spam', version, 'available')
2193
2194    zc.buildout.easy_install.clear_index_cache()
2195    [dist] = list(
2196        zc.buildout.easy_install.install(['spam'], 'existing', ['available'],
2197                                         always_unzip=True)
2198        )
2199
2200    if dist.extras:
2201        print 'downloaded', dist.version
2202    else:
2203        print 'had', dist.version
2204    sys.path_importer_cache.clear()
2205
2206def prefer_final():
2207    """
2208This test tests several permutations:
2209
2210Using different version numbers to work around zip impporter cache problems. :(
2211
2212- With prefer final:
2213
2214    - no existing and newer dev available
2215    >>> prefer_final_permutation((), [1, '2a1'])
2216    downloaded 1
2217
2218    - no existing and only dev available
2219    >>> prefer_final_permutation((), ['3a1'])
2220    downloaded 3a1
2221
2222    - final existing and only dev acailable
2223    >>> prefer_final_permutation([4], ['5a1'])
2224    had 4
2225
2226    - final existing and newer final available
2227    >>> prefer_final_permutation([6], [7])
2228    downloaded 7
2229
2230    - final existing and same final available
2231    >>> prefer_final_permutation([8], [8])
2232    had 8
2233
2234    - final existing and older final available
2235    >>> prefer_final_permutation([10], [9])
2236    had 10
2237
2238    - only dev existing and final available
2239    >>> prefer_final_permutation(['12a1'], [11])
2240    downloaded 11
2241
2242    - only dev existing and no final available newer dev available
2243    >>> prefer_final_permutation(['13a1'], ['13a2'])
2244    downloaded 13a2
2245
2246    - only dev existing and no final available older dev available
2247    >>> prefer_final_permutation(['15a1'], ['14a1'])
2248    had 15a1
2249
2250    - only dev existing and no final available same dev available
2251    >>> prefer_final_permutation(['16a1'], ['16a1'])
2252    had 16a1
2253
2254- Without prefer final:
2255
2256    >>> _ = zc.buildout.easy_install.prefer_final(False)
2257
2258    - no existing and newer dev available
2259    >>> prefer_final_permutation((), [18, '19a1'])
2260    downloaded 19a1
2261
2262    - no existing and only dev available
2263    >>> prefer_final_permutation((), ['20a1'])
2264    downloaded 20a1
2265
2266    - final existing and only dev acailable
2267    >>> prefer_final_permutation([21], ['22a1'])
2268    downloaded 22a1
2269
2270    - final existing and newer final available
2271    >>> prefer_final_permutation([23], [24])
2272    downloaded 24
2273
2274    - final existing and same final available
2275    >>> prefer_final_permutation([25], [25])
2276    had 25
2277
2278    - final existing and older final available
2279    >>> prefer_final_permutation([27], [26])
2280    had 27
2281
2282    - only dev existing and final available
2283    >>> prefer_final_permutation(['29a1'], [28])
2284    had 29a1
2285
2286    - only dev existing and no final available newer dev available
2287    >>> prefer_final_permutation(['30a1'], ['30a2'])
2288    downloaded 30a2
2289
2290    - only dev existing and no final available older dev available
2291    >>> prefer_final_permutation(['32a1'], ['31a1'])
2292    had 32a1
2293
2294    - only dev existing and no final available same dev available
2295    >>> prefer_final_permutation(['33a1'], ['33a1'])
2296    had 33a1
2297
2298    >>> _ = zc.buildout.easy_install.prefer_final(True)
2299   
2300    """
2301
2302def buildout_prefer_final_option():
2303    """
2304The prefer-final buildout option can be used for override the default
2305preference for newer distributions.
2306
2307The default is prefer-final = false:
2308
2309    >>> write('buildout.cfg',
2310    ... '''
2311    ... [buildout]
2312    ... parts = eggs
2313    ... find-links = %(link_server)s
2314    ...
2315    ... [eggs]
2316    ... recipe = zc.recipe.egg:eggs
2317    ... eggs = demo
2318    ... ''' % globals())
2319
2320    >>> print system(buildout+' -v'), # doctest: +ELLIPSIS
2321    Installing 'zc.buildout', 'setuptools'.
2322    ...
2323    Picked: demo = 0.4c1
2324    ...
2325    Picked: demoneeded = 1.2c1
2326
2327Here we see that the final versions of demo and demoneeded are used.
2328We get the same behavior if we add prefer-final = false
2329
2330    >>> write('buildout.cfg',
2331    ... '''
2332    ... [buildout]
2333    ... parts = eggs
2334    ... find-links = %(link_server)s
2335    ... prefer-final = false
2336    ...
2337    ... [eggs]
2338    ... recipe = zc.recipe.egg:eggs
2339    ... eggs = demo
2340    ... ''' % globals())
2341
2342    >>> print system(buildout+' -v'), # doctest: +ELLIPSIS
2343    Installing 'zc.buildout', 'setuptools'.
2344    ...
2345    Picked: demo = 0.4c1
2346    ...
2347    Picked: demoneeded = 1.2c1
2348
2349If we specify prefer-final = true, we'll get the newest
2350distributions:
2351
2352    >>> write('buildout.cfg',
2353    ... '''
2354    ... [buildout]
2355    ... parts = eggs
2356    ... find-links = %(link_server)s
2357    ... prefer-final = true
2358    ...
2359    ... [eggs]
2360    ... recipe = zc.recipe.egg:eggs
2361    ... eggs = demo
2362    ... ''' % globals())
2363
2364    >>> print system(buildout+' -v'), # doctest: +ELLIPSIS
2365    Installing 'zc.buildout', 'setuptools'.
2366    ...
2367    Picked: demo = 0.3
2368    ...
2369    Picked: demoneeded = 1.1
2370
2371We get an error if we specify anything but true or false:
2372
2373    >>> write('buildout.cfg',
2374    ... '''
2375    ... [buildout]
2376    ... parts = eggs
2377    ... find-links = %(link_server)s
2378    ... prefer-final = no
2379    ...
2380    ... [eggs]
2381    ... recipe = zc.recipe.egg:eggs
2382    ... eggs = demo
2383    ... ''' % globals())
2384
2385    >>> print system(buildout+' -v'), # doctest: +ELLIPSIS
2386    While:
2387      Initializing.
2388    Error: Invalid value for prefer-final option: no
2389
2390    """
2391
2392def develop_with_modules():
2393    """
2394Distribution setup scripts can import modules in the distribution directory:
2395
2396    >>> mkdir('foo')
2397    >>> write('foo', 'bar.py',
2398    ... '''# empty
2399    ... ''')
2400
2401    >>> write('foo', 'setup.py',
2402    ... '''
2403    ... import bar
2404    ... from setuptools import setup
2405    ... setup(name="foo")
2406    ... ''')
2407
2408    >>> write('buildout.cfg',
2409    ... '''
2410    ... [buildout]
2411    ... develop = foo
2412    ... parts =
2413    ... ''')
2414
2415    >>> print system(join('bin', 'buildout')),
2416    Develop: '/sample-buildout/foo'
2417
2418    >>> ls('develop-eggs')
2419    -  foo.egg-link
2420    -  zc.recipe.egg.egg-link
2421
2422    """
2423
2424def dont_pick_setuptools_if_version_is_specified_when_required_by_src_dist():
2425    """
2426When installing a source distribution, we got setuptools without
2427honoring our version specification.
2428
2429    >>> mkdir('dist')
2430    >>> write('setup.py',
2431    ... '''
2432    ... from setuptools import setup
2433    ... setup(name='foo', version='1', py_modules=['foo'], zip_safe=True)
2434    ... ''')
2435    >>> write('foo.py', '')
2436    >>> _ = system(buildout+' setup . sdist')
2437
2438    >>> write('buildout.cfg',
2439    ... '''
2440    ... [buildout]
2441    ... parts = foo
2442    ... find-links = dist
2443    ... versions = versions
2444    ... allow-picked-versions = false
2445    ...
2446    ... [versions]
2447    ... setuptools = %s
2448    ... foo = 1
2449    ...
2450    ... [foo]
2451    ... recipe = zc.recipe.egg
2452    ... eggs = foo
2453    ... ''' % pkg_resources.working_set.find(
2454    ...    pkg_resources.Requirement.parse('setuptools')).version)
2455
2456    >>> print system(buildout),
2457    Installing foo.
2458    Getting distribution for 'foo==1'.
2459    Got foo 1.
2460   
2461    """
2462
2463def pyc_and_pyo_files_have_correct_paths():
2464    r"""
2465
2466    >>> write('buildout.cfg',
2467    ... '''
2468    ... [buildout]
2469    ... parts = eggs
2470    ... find-links = %(link_server)s
2471    ... unzip = true
2472    ...
2473    ... [eggs]
2474    ... recipe = zc.recipe.egg
2475    ... eggs = demo
2476    ... interpreter = py
2477    ... ''' % globals())
2478
2479    >>> _ = system(buildout)
2480
2481    >>> write('t.py',
2482    ... '''
2483    ... import eggrecipedemo, eggrecipedemoneeded
2484    ... print eggrecipedemo.main.func_code.co_filename
2485    ... print eggrecipedemoneeded.f.func_code.co_filename
2486    ... ''')
2487
2488    >>> print system(join('bin', 'py')+ ' t.py'),
2489    /sample-buildout/eggs/demo-0.4c1-py2.4.egg/eggrecipedemo.py
2490    /sample-buildout/eggs/demoneeded-1.2c1-py2.4.egg/eggrecipedemoneeded.py
2491
2492    >>> import os
2493    >>> for name in os.listdir('eggs'):
2494    ...     if name.startswith('demoneeded'):
2495    ...         ls('eggs', name)
2496    d  EGG-INFO
2497    -  eggrecipedemoneeded.py
2498    -  eggrecipedemoneeded.pyc
2499    -  eggrecipedemoneeded.pyo
2500
2501    """
2502
2503def dont_mess_with_standard_dirs_with_variable_refs():
2504    """
2505    >>> write('buildout.cfg',
2506    ... '''
2507    ... [buildout]
2508    ... eggs-directory = ${buildout:directory}/develop-eggs
2509    ... parts =
2510    ... ''' % globals())
2511    >>> print system(buildout),
2512   
2513    """
2514
2515def expand_shell_patterns_in_develop_paths():
2516    """
2517    Sometimes we want to include a number of eggs in some directory as
2518    develop eggs, without explicitly listing all of them in our
2519    buildout.cfg
2520
2521    >>> make_dist_that_requires(sample_buildout, 'sampley')
2522    >>> make_dist_that_requires(sample_buildout, 'samplez')
2523
2524    Now, let's create a buildout that has a shell pattern that matches
2525    both:
2526
2527    >>> write('buildout.cfg',
2528    ... '''
2529    ... [buildout]
2530    ... parts = eggs
2531    ... develop = sample*
2532    ... find-links = %(link_server)s
2533    ...
2534    ... [eggs]
2535    ... recipe = zc.recipe.egg
2536    ... eggs = sampley
2537    ...        samplez
2538    ... ''' % globals())
2539
2540    We can see that both eggs were found:
2541
2542    >>> print system(buildout),
2543    Develop: '/sample-buildout/sampley'
2544    Develop: '/sample-buildout/samplez'
2545    Installing eggs.
2546
2547    """
2548
2549def warn_users_when_expanding_shell_patterns_yields_no_results():
2550    """
2551    Sometimes shell patterns do not match anything, so we want to warn
2552    our users about it...
2553
2554    >>> make_dist_that_requires(sample_buildout, 'samplea')
2555
2556    So if we have 2 patterns, one that has a matching directory, and
2557    another one that does not
2558
2559    >>> write('buildout.cfg',
2560    ... '''
2561    ... [buildout]
2562    ... parts = eggs
2563    ... develop = samplea grumble*
2564    ... find-links = %(link_server)s
2565    ...
2566    ... [eggs]
2567    ... recipe = zc.recipe.egg
2568    ... eggs = samplea
2569    ... ''' % globals())
2570
2571    We should get one of the eggs, and a warning for the pattern that
2572    did not match anything.
2573
2574    >>> print system(buildout),
2575    Develop: '/sample-buildout/samplea'
2576    Couldn't develop '/sample-buildout/grumble*' (not found)
2577    Installing eggs.
2578
2579    """
2580
2581
2582######################################################################
2583   
2584def create_sample_eggs(test, executable=sys.executable):
2585    write = test.globs['write']
2586    dest = test.globs['sample_eggs']
2587    tmp = tempfile.mkdtemp()
2588    try:
2589        write(tmp, 'README.txt', '')
2590
2591        for i in (0, 1, 2):
2592            write(tmp, 'eggrecipedemoneeded.py', 'y=%s\ndef f():\n  pass' % i)
2593            c1 = i==2 and 'c1' or ''
2594            write(
2595                tmp, 'setup.py',
2596                "from setuptools import setup\n"
2597                "setup(name='demoneeded', py_modules=['eggrecipedemoneeded'],"
2598                " zip_safe=True, version='1.%s%s', author='bob', url='bob', "
2599                "author_email='bob')\n"
2600                % (i, c1)
2601                )
2602            zc.buildout.testing.sdist(tmp, dest)
2603
2604        write(
2605            tmp, 'setup.py',
2606            "from setuptools import setup\n"
2607            "setup(name='other', zip_safe=False, version='1.0', "
2608            "py_modules=['eggrecipedemoneeded'])\n"
2609            )
2610        zc.buildout.testing.bdist_egg(tmp, executable, dest)
2611
2612        os.remove(os.path.join(tmp, 'eggrecipedemoneeded.py'))
2613
2614        for i in (1, 2, 3, 4):
2615            write(
2616                tmp, 'eggrecipedemo.py',
2617                'import eggrecipedemoneeded\n'
2618                'x=%s\n'
2619                'def main(): print x, eggrecipedemoneeded.y\n'
2620                % i)
2621            c1 = i==4 and 'c1' or ''
2622            write(
2623                tmp, 'setup.py',
2624                "from setuptools import setup\n"
2625                "setup(name='demo', py_modules=['eggrecipedemo'],"
2626                " install_requires = 'demoneeded',"
2627                " entry_points={'console_scripts': "
2628                     "['demo = eggrecipedemo:main']},"
2629                " zip_safe=True, version='0.%s%s')\n" % (i, c1)
2630                )
2631            zc.buildout.testing.bdist_egg(tmp, executable, dest)
2632
2633        write(tmp, 'eggrecipebigdemo.py', 'import eggrecipedemo')
2634        write(
2635            tmp, 'setup.py',
2636            "from setuptools import setup\n"
2637            "setup(name='bigdemo', "
2638            " install_requires = 'demo',"
2639            " py_modules=['eggrecipebigdemo'], "
2640            " zip_safe=True, version='0.1')\n"
2641            )
2642        zc.buildout.testing.bdist_egg(tmp, executable, dest)
2643
2644    finally:
2645        shutil.rmtree(tmp)
2646
2647extdemo_c = """
2648#include <Python.h>
2649#include <extdemo.h>
2650
2651static PyMethodDef methods[] = {{NULL}};
2652
2653PyMODINIT_FUNC
2654initextdemo(void)
2655{
2656    PyObject *m;
2657    m = Py_InitModule3("extdemo", methods, "");
2658#ifdef TWO
2659    PyModule_AddObject(m, "val", PyInt_FromLong(2));
2660#else
2661    PyModule_AddObject(m, "val", PyInt_FromLong(EXTDEMO));
2662#endif
2663}
2664"""
2665
2666extdemo_setup_py = """
2667import os
2668from distutils.core import setup, Extension
2669
2670if os.environ.get('test-variable'):
2671    print "Have environment test-variable:", os.environ['test-variable']
2672
2673setup(name = "extdemo", version = "%s", url="http://www.zope.org",
2674      author="Demo", author_email="demo@demo.com",
2675      ext_modules = [Extension('extdemo', ['extdemo.c'])],
2676      )
2677"""
2678
2679def add_source_dist(test, version=1.4):
2680
2681    if 'extdemo' not in test.globs:
2682        test.globs['extdemo'] = test.globs['tmpdir']('extdemo')
2683
2684    tmp = test.globs['extdemo']
2685    write = test.globs['write']
2686    try:
2687        write(tmp, 'extdemo.c', extdemo_c);
2688        write(tmp, 'setup.py', extdemo_setup_py % version);
2689        write(tmp, 'README', "");
2690        write(tmp, 'MANIFEST.in', "include *.c\n");
2691        test.globs['sdist'](tmp, test.globs['sample_eggs'])
2692    except:
2693        shutil.rmtree(tmp)
2694
2695def easy_install_SetUp(test):
2696    zc.buildout.testing.buildoutSetUp(test)
2697    sample_eggs = test.globs['tmpdir']('sample_eggs')
2698    test.globs['sample_eggs'] = sample_eggs
2699    os.mkdir(os.path.join(sample_eggs, 'index'))
2700    create_sample_eggs(test)
2701    add_source_dist(test)
2702    test.globs['link_server'] = test.globs['start_server'](
2703        test.globs['sample_eggs'])
2704    test.globs['update_extdemo'] = lambda : add_source_dist(test, 1.5)
2705    zc.buildout.testing.install_develop('zc.recipe.egg', test)
2706       
2707egg_parse = re.compile('([0-9a-zA-Z_.]+)-([0-9a-zA-Z_.]+)-py(\d[.]\d).egg$'
2708                       ).match
2709def makeNewRelease(project, ws, dest):
2710    dist = ws.find(pkg_resources.Requirement.parse(project))
2711    eggname, oldver, pyver = egg_parse(
2712        os.path.basename(dist.location)
2713        ).groups()
2714    dest = os.path.join(dest, "%s-99.99-py%s.egg" % (eggname, pyver)) 
2715    if os.path.isfile(dist.location):
2716        shutil.copy(dist.location, dest)
2717        zip = zipfile.ZipFile(dest, 'a')
2718        zip.writestr(
2719            'EGG-INFO/PKG-INFO',
2720            zip.read('EGG-INFO/PKG-INFO').replace("Version: %s" % oldver, 
2721                                                  "Version: 99.99")
2722            )
2723        zip.close()
2724    else:
2725        shutil.copytree(dist.location, dest)
2726        info_path = os.path.join(dest, 'EGG-INFO', 'PKG-INFO')
2727        info = open(info_path).read().replace("Version: %s" % oldver, 
2728                                              "Version: 99.99")
2729        open(info_path, 'w').write(info)
2730
2731
2732def updateSetup(test):
2733    zc.buildout.testing.buildoutSetUp(test)
2734    new_releases = test.globs['tmpdir']('new_releases')
2735    test.globs['new_releases'] = new_releases
2736    sample_buildout = test.globs['sample_buildout']
2737    eggs = os.path.join(sample_buildout, 'eggs')
2738
2739    # If the zc.buildout dist is a develo dist, convert it to a
2740    # regular egg in the sample buildout
2741    req = pkg_resources.Requirement.parse('zc.buildout')
2742    dist = pkg_resources.working_set.find(req)
2743    if dist.precedence == pkg_resources.DEVELOP_DIST:
2744        # We have a develop egg, create a real egg for it:
2745        here = os.getcwd()
2746        os.chdir(os.path.dirname(dist.location))
2747        assert os.spawnle(
2748            os.P_WAIT, sys.executable, zc.buildout.easy_install._safe_arg (sys.executable),
2749            os.path.join(os.path.dirname(dist.location), 'setup.py'),
2750            '-q', 'bdist_egg', '-d', eggs,
2751            dict(os.environ,
2752                 PYTHONPATH=pkg_resources.working_set.find(
2753                               pkg_resources.Requirement.parse('setuptools')
2754                               ).location,
2755                 ),
2756            ) == 0
2757        os.chdir(here)
2758        os.remove(os.path.join(eggs, 'zc.buildout.egg-link'))
2759
2760        # Rebuild the buildout script
2761        ws = pkg_resources.WorkingSet([eggs])
2762        ws.require('zc.buildout')
2763        zc.buildout.easy_install.scripts(
2764            ['zc.buildout'], ws, sys.executable,
2765            os.path.join(sample_buildout, 'bin'))
2766    else:
2767        ws = pkg_resources.working_set
2768
2769    # now let's make the new releases
2770    makeNewRelease('zc.buildout', ws, new_releases)
2771    makeNewRelease('setuptools', ws, new_releases)
2772
2773    os.mkdir(os.path.join(new_releases, 'zc.buildout'))
2774    os.mkdir(os.path.join(new_releases, 'setuptools'))
2775
2776
2777
2778normalize_bang = (
2779    re.compile(re.escape('#!'+
2780                         zc.buildout.easy_install._safe_arg(sys.executable))),
2781    '#!/usr/local/bin/python2.4',
2782    )
2783
2784def test_suite():
2785    return unittest.TestSuite((
2786        doctest.DocFileSuite(
2787            'buildout.txt', 'runsetup.txt', 'repeatable.txt', 'setup.txt',
2788            setUp=zc.buildout.testing.buildoutSetUp,
2789            tearDown=zc.buildout.testing.buildoutTearDown,
2790            checker=renormalizing.RENormalizing([
2791               zc.buildout.testing.normalize_path,
2792               zc.buildout.testing.normalize_script,
2793               zc.buildout.testing.normalize_egg_py,
2794               (re.compile('__buildout_signature__ = recipes-\S+'),
2795                '__buildout_signature__ = recipes-SSSSSSSSSSS'),
2796               (re.compile('executable = [\S ]+python\S*', re.I),
2797                'executable = python'),
2798               (re.compile('[-d]  setuptools-\S+[.]egg'), 'setuptools.egg'),
2799               (re.compile('zc.buildout(-\S+)?[.]egg(-link)?'),
2800                'zc.buildout.egg'),
2801               (re.compile('creating \S*setup.cfg'), 'creating setup.cfg'),
2802               (re.compile('hello\%ssetup' % os.path.sep), 'hello/setup'),
2803               (re.compile('Picked: (\S+) = \S+'),
2804                'Picked: \\1 = V.V'),
2805               (re.compile(r'We have a develop egg: zc.buildout (\S+)'),
2806                'We have a develop egg: zc.buildout X.X.'),
2807               (re.compile(r'\\[\\]?'), '/'),
2808               (re.compile('WindowsError'), 'OSError'),
2809               (re.compile(r'\[Error 17\] Cannot create a file '
2810                           r'when that file already exists: '),
2811                '[Errno 17] File exists: '
2812                ),
2813               ])
2814            ),
2815        doctest.DocFileSuite(
2816            'debugging.txt',
2817            setUp=zc.buildout.testing.buildoutSetUp,
2818            tearDown=zc.buildout.testing.buildoutTearDown,
2819            checker=renormalizing.RENormalizing([
2820               zc.buildout.testing.normalize_path,
2821               (re.compile(r'\S+buildout.py'), 'buildout.py'),
2822               (re.compile(r'line \d+'), 'line NNN'),
2823               (re.compile(r'py\(\d+\)'), 'py(NNN)'),
2824               ])
2825            ),
2826
2827        doctest.DocFileSuite(
2828            'update.txt',
2829            setUp=updateSetup,
2830            tearDown=zc.buildout.testing.buildoutTearDown,
2831            checker=renormalizing.RENormalizing([
2832               zc.buildout.testing.normalize_path,
2833               zc.buildout.testing.normalize_script,
2834               zc.buildout.testing.normalize_egg_py,
2835               normalize_bang,
2836               (re.compile('99[.]99'), 'NINETYNINE.NINETYNINE'),
2837               (re.compile('(zc.buildout|setuptools)-\d+[.]\d+\S*'
2838                           '-py\d.\d.egg'),
2839                '\\1.egg'),
2840               (re.compile('(zc.buildout|setuptools)( version)? \d+[.]\d+\S*'),
2841                '\\1 V.V'),
2842               (re.compile('[-d]  setuptools'), '-  setuptools'),
2843               ])
2844            ),
2845       
2846        doctest.DocFileSuite(
2847            'easy_install.txt', 'downloadcache.txt', 'dependencylinks.txt',
2848            'allowhosts.txt', 'unzip.txt',
2849            setUp=easy_install_SetUp,
2850            tearDown=zc.buildout.testing.buildoutTearDown,
2851            checker=renormalizing.RENormalizing([
2852               zc.buildout.testing.normalize_path,
2853               zc.buildout.testing.normalize_script,
2854               zc.buildout.testing.normalize_egg_py,
2855               normalize_bang,
2856               (re.compile('extdemo[.]pyd'), 'extdemo.so'),
2857               (re.compile('[-d]  setuptools-\S+[.]egg'), 'setuptools.egg'),
2858               ]),
2859            ),
2860        doctest.DocTestSuite(
2861            setUp=easy_install_SetUp,
2862            tearDown=zc.buildout.testing.buildoutTearDown,
2863            checker=renormalizing.RENormalizing([
2864               zc.buildout.testing.normalize_path,
2865               zc.buildout.testing.normalize_script,
2866               zc.buildout.testing.normalize_egg_py,
2867               (re.compile("buildout: Running \S*setup.py"),
2868                'buildout: Running setup.py'),
2869               (re.compile('setuptools-\S+-'),
2870                'setuptools.egg'),
2871               (re.compile('zc.buildout-\S+-'),
2872                'zc.buildout.egg'),
2873               (re.compile('File "\S+one.py"'),
2874                'File "one.py"'),
2875               (re.compile(r'We have a develop egg: (\S+) (\S+)'),
2876                r'We have a develop egg: \1 V'),
2877               (re.compile('Picked: setuptools = \S+'),
2878                'Picked: setuptools = V'),
2879               (re.compile(r'\\[\\]?'), '/'),
2880               (re.compile(
2881                   '-q develop -mxN -d "/sample-buildout/develop-eggs'),
2882                   '-q develop -mxN -d /sample-buildout/develop-eggs'
2883                ),
2884                (re.compile(r'^[*]...'), '...'),
2885               ]),
2886            ),
2887        zc.buildout.testselectingpython.test_suite(),
2888        zc.buildout.rmtree.test_suite(),
2889        doctest.DocFileSuite(
2890            'windows.txt',
2891            setUp=zc.buildout.testing.buildoutSetUp,
2892            tearDown=zc.buildout.testing.buildoutTearDown,
2893            checker=renormalizing.RENormalizing([
2894               zc.buildout.testing.normalize_path,
2895               zc.buildout.testing.normalize_script,
2896               zc.buildout.testing.normalize_egg_py,
2897               (re.compile('__buildout_signature__ = recipes-\S+'),
2898                '__buildout_signature__ = recipes-SSSSSSSSSSS'),
2899               (re.compile('[-d]  setuptools-\S+[.]egg'), 'setuptools.egg'),
2900               (re.compile('zc.buildout(-\S+)?[.]egg(-link)?'),
2901                'zc.buildout.egg'),
2902               (re.compile('creating \S*setup.cfg'), 'creating setup.cfg'),
2903               (re.compile('hello\%ssetup' % os.path.sep), 'hello/setup'),
2904               (re.compile('Picked: (\S+) = \S+'),
2905                'Picked: \\1 = V.V'),
2906               (re.compile(r'We have a develop egg: zc.buildout (\S+)'),
2907                'We have a develop egg: zc.buildout X.X.'),
2908               (re.compile(r'\\[\\]?'), '/'),
2909               (re.compile('WindowsError'), 'OSError'),
2910               (re.compile(r'\[Error 17\] Cannot create a file '
2911                           r'when that file already exists: '),
2912                '[Errno 17] File exists: '
2913                ),
2914               ])
2915            ), 
2916        ))
Note: See TracBrowser for help on using the repository browser.